diff --git a/volatility3/framework/plugins/linux/pstree.py b/volatility3/framework/plugins/linux/pstree.py index fd28fcbbd..dc4fef4f3 100644 --- a/volatility3/framework/plugins/linux/pstree.py +++ b/volatility3/framework/plugins/linux/pstree.py @@ -52,19 +52,38 @@ class PsTree(interfaces.plugins.PluginInterface): Args: pid: PID to find the level in the hierarchy """ - seen = set([pid]) + seen_ppids = set() + seen_offsets = set() + level = 0 proc = self._tasks.get(pid) - while proc and proc.get_parent_pid() not in seen: + + while proc: + # we don't want swapper in the tree + if proc.pid == 0: + break + if proc.is_thread_group_leader: parent_pid = proc.get_parent_pid() else: parent_pid = proc.tgid + if parent_pid in seen_ppids or proc.vol.offset in seen_offsets: + break + + # only pid 1 (init/systemd) or 2 (kthreadd) should have swapper as a parent + # any other process with a ppid of 0 is smeared or terminated + if parent_pid == 0 and proc.pid > 2: + break + + seen_ppids.add(parent_pid) + seen_offsets.add(proc.vol.offset) + child_list = self._children.setdefault(parent_pid, set()) child_list.add(proc.pid) proc = self._tasks.get(parent_pid) + level += 1 self._levels[pid] = level @@ -110,12 +129,26 @@ class PsTree(interfaces.plugins.PluginInterface): ) yield (self._levels[task_fields.user_tid] - 1, fields) + seen_children = set() + for child_pid in sorted(self._children.get(task_fields.user_tid, [])): + if child_pid in seen_children: + break + seen_children.add(child_pid) + yield from yield_processes(child_pid) + seen_processes = set() + for pid, level in self._levels.items(): if level == 1: - yield from yield_processes(pid) + for fields in yield_processes(pid): + pid = fields[1] + if pid in seen_processes: + break + seen_processes.add(pid) + + yield fields def run(self): filter_func = pslist.PsList.create_pid_filter(self.config.get("pid", None))