Skip to content

Commit 08536fd

Browse files
committed
Improve process tree generation visited node detection
This addresses issue #1
1 parent a30db21 commit 08536fd

File tree

1 file changed

+29
-8
lines changed

1 file changed

+29
-8
lines changed

overlay.py

+29-8
Original file line numberDiff line numberDiff line change
@@ -661,17 +661,18 @@ def gen_process_tree(self):
661661
# Technically the kernel can have a ton of processes, but we only consider one in our graph
662662
self.processes["kernel_0"] = ProcessNode(kernel_subject, None, {'/kernel' : {}}, 0)
663663

664-
# (parent, child)
665-
stack = [(self.processes["kernel_0"], init_subject)]
664+
# (parent_process, parent_exe, child_subject)
665+
stack = [(self.processes["kernel_0"], "/kernel", init_subject)]
666666

667667
### Propagate subject permissions by simulating fork/exec
668668
# Depth-first traversal
669669

670670
pid = 1
671671

672672
while len(stack):
673-
parent_process, child_subject = stack.pop()
674-
visited |= set([child_subject])
673+
parent_process, parent_exe, child_subject = stack.pop()
674+
# only visit an edge on the subject graph once
675+
visited |= set([(parent_process.subject, parent_exe, child_subject)])
675676

676677
# No backing files? Go away
677678
if len(child_subject.backing_files) == 0:
@@ -692,13 +693,26 @@ def gen_process_tree(self):
692693

693694
for fn, f in sorted(backing_files_resolved.items()):
694695
fc = f["selinux"]
695-
exec_rule_parent = None
696-
exec_rule_child = None
696+
exec_rule_parent = False
697+
exec_rule_child = False
698+
dyntransition = False
699+
transition = False
697700

698701
if fc.type in G[parent_process.subject.sid.type]:
699702
exec_rule_parent = "execute_no_trans" in G[parent_process.subject.sid.type][fc.type][0]
700703
if fc.type in G[child_subject.sid.type]:
701704
exec_rule_child = "execute_no_trans" in G[child_subject.sid.type][fc.type][0]["perms"]
705+
if child_subject.sid.type in G[parent_process.subject.sid.type]:
706+
parent_child_edge = G[parent_process.subject.sid.type][child_subject.sid.type][0]["perms"]
707+
dyntransition = "dyntransition" in parent_child_edge
708+
transition = "transition" in parent_child_edge
709+
710+
# if only dyntransitions, child exe doesn't change, so make sure child processes respect that
711+
if dyntransition and not transition:
712+
(fn_parent, _), = parent_process.exe.items()
713+
714+
if fn_parent != fn:
715+
continue
702716

703717
# Conservatively assume the parent
704718
new_process = ProcessNode(child_subject, parent_process, {fn : f}, pid)
@@ -711,8 +725,15 @@ def gen_process_tree(self):
711725
pid += 1
712726

713727
for child in sorted(child_subject.children, key=lambda x: str(x.sid.type)):
714-
if child not in visited or (child.sid.type == "crash_dump" and child_subject.sid.type in ["zygote"]):
715-
stack += [(new_process, child)]
728+
edge = (new_process, fn, child)
729+
edge_query = (new_process.subject, fn, child)
730+
731+
cycle = new_process.subject == child
732+
733+
# TODO: refactor special casing to networkx.algorithms.traversal.edgedfs.edge_dfs
734+
# We are _trying_ to avoid cycles while visiting every edge. This needs more work
735+
if edge_query not in visited or (child.sid.type == "crash_dump" and not cycle) or child.sid.type.startswith("system_server"):
736+
stack += [edge]
716737

717738
def simulate_process_permissions(self):
718739
# Special cases for android

0 commit comments

Comments
 (0)