Skip to content

Commit ccb5581

Browse files
authored
Merge pull request #1542 from gcmoreira/linux_parity_release_harden_process_listing
linux: Ensure task listing functions yield only valid tasks
2 parents 8859d0a + 7fc2af5 commit ccb5581

File tree

2 files changed

+46
-1
lines changed

2 files changed

+46
-1
lines changed

volatility3/framework/plugins/linux/pslist.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ class PsList(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
3434
"""Lists the processes present in a particular linux memory image."""
3535

3636
_required_framework_version = (2, 13, 0)
37-
_version = (4, 0, 0)
37+
_version = (4, 1, 0)
3838

3939
@classmethod
4040
def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]:
@@ -250,6 +250,9 @@ def list_tasks(
250250

251251
# Note that the init_task itself is not yielded, since "ps" also never shows it.
252252
for task in init_task.tasks:
253+
if not task.is_valid():
254+
continue
255+
253256
if filter_func(task):
254257
continue
255258

volatility3/framework/symbols/linux/extensions/__init__.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,46 @@ def section_strtab(self):
307307

308308

309309
class task_struct(generic.GenericIntelProcess):
310+
def is_valid(self) -> bool:
311+
layer = self._context.layers[self.vol.layer_name]
312+
# Make sure the entire task content is readable
313+
if not layer.is_valid(self.vol.offset, self.vol.size):
314+
return False
315+
316+
if self.pid < 0 or self.tgid < 0:
317+
return False
318+
319+
if self.has_member("signal") and not (
320+
self.signal and self.signal.is_readable()
321+
):
322+
return False
323+
324+
if self.has_member("nsproxy") and not (
325+
self.nsproxy and self.nsproxy.is_readable()
326+
):
327+
return False
328+
329+
if self.has_member("real_parent") and not (
330+
self.real_parent and self.real_parent.is_readable()
331+
):
332+
return False
333+
334+
if (
335+
self.has_member("active_mm")
336+
and self.active_mm
337+
and not self.active_mm.is_readable()
338+
):
339+
return False
340+
341+
if self.mm:
342+
if not self.mm.is_readable():
343+
return False
344+
345+
if self.mm != self.active_mm:
346+
return False
347+
348+
return True
349+
310350
def add_process_layer(
311351
self, config_prefix: Optional[str] = None, preferred_name: Optional[str] = None
312352
) -> Optional[str]:
@@ -401,6 +441,8 @@ def get_threads(self) -> Iterable[interfaces.objects.ObjectInterface]:
401441
tasks_iterable = self._get_tasks_iterable()
402442
threads_seen = set([self.vol.offset])
403443
for task in tasks_iterable:
444+
if not task.is_valid():
445+
continue
404446
if task.vol.offset not in threads_seen:
405447
threads_seen.add(task.vol.offset)
406448
yield task

0 commit comments

Comments
 (0)