Skip to content

Commit

Permalink
Merge pull request #1412 from gcmoreira/linux_task_parent_pid_fix
Browse files Browse the repository at this point in the history
Linux: Fix task parent pid in several plugins
  • Loading branch information
ikelos authored Dec 17, 2024
2 parents 992ba3e + e035faa commit 7d2f8b2
Show file tree
Hide file tree
Showing 8 changed files with 34 additions and 37 deletions.
2 changes: 1 addition & 1 deletion volatility3/framework/constants/_version.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# We use the SemVer 2.0.0 versioning scheme
VERSION_MAJOR = 2 # Number of releases of the library with a breaking change
VERSION_MINOR = 12 # Number of changes that only add to the interface
VERSION_MINOR = 13 # Number of changes that only add to the interface
VERSION_PATCH = 0 # Number of changes that do not change the interface
VERSION_SUFFIX = ""

Expand Down
6 changes: 3 additions & 3 deletions volatility3/framework/plugins/linux/capabilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ def astuple(self) -> Tuple:
class Capabilities(plugins.PluginInterface):
"""Lists process capabilities"""

_required_framework_version = (2, 0, 0)
_version = (1, 0, 1)
_required_framework_version = (2, 13, 0)
_version = (1, 1, 0)

@classmethod
def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]:
Expand Down Expand Up @@ -136,7 +136,7 @@ def get_task_capabilities(
comm=utility.array_to_string(task.comm),
pid=int(task.pid),
tgid=int(task.tgid),
ppid=int(task.parent.pid),
ppid=int(task.get_parent_pid()),
euid=int(task.cred.euid),
)

Expand Down
14 changes: 3 additions & 11 deletions volatility3/framework/plugins/linux/envars.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
class Envars(plugins.PluginInterface):
"""Lists processes with their environment variables"""

_required_framework_version = (2, 0, 0)
_version = (1, 0, 1)
_required_framework_version = (2, 13, 0)
_version = (1, 1, 0)

@classmethod
def get_requirements(cls):
Expand Down Expand Up @@ -48,15 +48,7 @@ def _generator(self, tasks):

# get process name as string
name = utility.array_to_string(task.comm)

# try and get task parent
try:
ppid = task.parent.pid
except exceptions.InvalidAddressException:
vollog.debug(
f"Unable to read parent pid for task {pid} {name}, setting ppid to 0."
)
ppid = 0
ppid = task.get_parent_pid()

# kernel threads never have an mm as they do not have userland mappings
try:
Expand Down
12 changes: 3 additions & 9 deletions volatility3/framework/plugins/linux/psaux.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
class PsAux(plugins.PluginInterface):
"""Lists processes with their command line arguments"""

_required_framework_version = (2, 0, 0)
_version = (1, 0, 1)
_required_framework_version = (2, 13, 0)
_version = (1, 1, 0)

@classmethod
def get_requirements(cls):
Expand Down Expand Up @@ -98,14 +98,8 @@ def _generator(self, tasks):
# walk the process list and report the arguments
for task in tasks:
pid = task.pid

try:
ppid = task.parent.pid
except exceptions.InvalidAddressException:
ppid = 0

ppid = task.get_parent_pid()
name = utility.array_to_string(task.comm)

args = self._get_command_line_args(task, name)

yield (0, (pid, ppid, name, args))
Expand Down
6 changes: 3 additions & 3 deletions volatility3/framework/plugins/linux/pslist.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
class PsList(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
"""Lists the processes present in a particular linux memory image."""

_required_framework_version = (2, 0, 0)
_version = (3, 0, 0)
_required_framework_version = (2, 13, 0)
_version = (3, 1, 0)

@classmethod
def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]:
Expand Down Expand Up @@ -95,7 +95,7 @@ def get_task_fields(
"""
pid = task.tgid
tid = task.pid
ppid = task.parent.tgid if task.parent else 0
ppid = task.get_parent_pid()
name = utility.array_to_string(task.comm)
start_time = task.get_create_time()
if decorate_comm:
Expand Down
9 changes: 3 additions & 6 deletions volatility3/framework/plugins/linux/psscan.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ class DescExitStateEnum(Enum):
class PsScan(interfaces.plugins.PluginInterface):
"""Scans for processes present in a particular linux image."""

_required_framework_version = (2, 0, 0)
_version = (1, 0, 1)
_required_framework_version = (2, 13, 0)
_version = (1, 1, 0)

@classmethod
def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]:
Expand All @@ -52,10 +52,7 @@ def _get_task_fields(
"""
pid = task.tgid
tid = task.pid
ppid = 0

if task.parent.is_readable():
ppid = task.parent.tgid
ppid = task.get_parent_pid()
name = utility.array_to_string(task.comm)
exit_state = DescExitStateEnum(task.exit_state).name

Expand Down
8 changes: 4 additions & 4 deletions volatility3/framework/plugins/linux/pstree.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ class PsTree(interfaces.plugins.PluginInterface):
"""Plugin for listing processes in a tree based on their parent process
ID."""

_required_framework_version = (2, 0, 0)
_version = (1, 0, 1)
_required_framework_version = (2, 13, 0)
_version = (1, 1, 0)

@classmethod
def get_requirements(cls):
Expand Down Expand Up @@ -56,9 +56,9 @@ def find_level(self, pid: int) -> None:
seen = set([pid])
level = 0
proc = self._tasks.get(pid)
while proc and proc.parent and proc.parent.pid not in seen:
while proc and proc.get_parent_pid() not in seen:
if proc.is_thread_group_leader:
parent_pid = proc.parent.pid
parent_pid = proc.get_parent_pid()
else:
parent_pid = proc.tgid

Expand Down
14 changes: 14 additions & 0 deletions volatility3/framework/symbols/linux/extensions/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -633,6 +633,20 @@ def get_create_time(self) -> datetime.datetime:
# root time namespace, not within the task's own time namespace
return boottime + task_start_time_timedelta

def get_parent_pid(self) -> int:
"""Returns the parent process ID (PPID)
This method replicates the Linux kernel's `getppid` syscall behavior.
Avoid using `task.parent`; instead, use this function for accurate results.
"""

if self.real_parent and self.real_parent.is_readable():
ppid = self.real_parent.pid
else:
ppid = 0

return ppid


class fs_struct(objects.StructType):
def get_root_dentry(self):
Expand Down

0 comments on commit 7d2f8b2

Please sign in to comment.