mirror of
https://github.com/volatilityfoundation/volatility3.git
synced 2026-08-17 20:35:40 +02:00
Merge pull request #1827 from SolitudePy/lsof_deleted
Lsof improvements (show deleted as in lsof output) + files_only argument
This commit is contained in:
@@ -110,7 +110,7 @@ class Lsof(plugins.PluginInterface, timeliner.TimeLinerInterface):
|
||||
"""Lists open files for each processes."""
|
||||
|
||||
_required_framework_version = (2, 0, 0)
|
||||
_version = (2, 0, 2)
|
||||
_version = (2, 1, 0)
|
||||
|
||||
@classmethod
|
||||
def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]:
|
||||
@@ -137,6 +137,12 @@ class Lsof(plugins.PluginInterface, timeliner.TimeLinerInterface):
|
||||
element_type=int,
|
||||
optional=True,
|
||||
),
|
||||
requirements.BooleanRequirement(
|
||||
name="files_only",
|
||||
description="Include only file descriptors of type file",
|
||||
optional=True,
|
||||
default=False,
|
||||
),
|
||||
]
|
||||
|
||||
@classmethod
|
||||
@@ -145,6 +151,7 @@ class Lsof(plugins.PluginInterface, timeliner.TimeLinerInterface):
|
||||
context: interfaces.context.ContextInterface,
|
||||
vmlinux_module_name: str,
|
||||
filter_func: Callable[[int], bool] = lambda _: False,
|
||||
include_files_only: bool = False,
|
||||
) -> Iterable[FDInternal]:
|
||||
"""Enumerates open file descriptors in tasks
|
||||
|
||||
@@ -167,16 +174,20 @@ class Lsof(plugins.PluginInterface, timeliner.TimeLinerInterface):
|
||||
linuxutils_symbol_table = task.vol.type_name.split(constants.BANG)[0]
|
||||
|
||||
fd_generator = linux.LinuxUtilities.files_descriptors_for_process(
|
||||
context, linuxutils_symbol_table, task
|
||||
context, linuxutils_symbol_table, task, files_only=include_files_only
|
||||
)
|
||||
|
||||
for fd_fields in fd_generator:
|
||||
yield FDInternal(task=task, fd_fields=fd_fields)
|
||||
|
||||
def _generator(self, pids, vmlinux_module_name):
|
||||
def _generator(self, pids, vmlinux_module_name, include_files_only):
|
||||
filter_func = pslist.PsList.create_pid_filter(pids)
|
||||
|
||||
for fd_internal in self.list_fds(
|
||||
self.context, vmlinux_module_name, filter_func=filter_func
|
||||
self.context,
|
||||
vmlinux_module_name,
|
||||
filter_func=filter_func,
|
||||
include_files_only=include_files_only,
|
||||
):
|
||||
fd_user = fd_internal.to_user()
|
||||
yield (0, dataclasses.astuple(fd_user))
|
||||
@@ -184,6 +195,7 @@ class Lsof(plugins.PluginInterface, timeliner.TimeLinerInterface):
|
||||
def run(self):
|
||||
pids = self.config.get("pid", None)
|
||||
vmlinux_module_name = self.config["kernel"]
|
||||
include_files_only = self.config.get("files_only")
|
||||
|
||||
tree_grid_args = [
|
||||
("PID", int),
|
||||
@@ -201,7 +213,10 @@ class Lsof(plugins.PluginInterface, timeliner.TimeLinerInterface):
|
||||
("Size", int),
|
||||
]
|
||||
return renderers.TreeGrid(
|
||||
tree_grid_args, self._generator(pids, vmlinux_module_name)
|
||||
tree_grid_args,
|
||||
self._generator(
|
||||
pids, vmlinux_module_name, include_files_only=include_files_only
|
||||
),
|
||||
)
|
||||
|
||||
def generate_timeline(self):
|
||||
|
||||
@@ -99,8 +99,10 @@ class LinuxKernelIntermedSymbols(intermed.IntermediateSymbolTable):
|
||||
class LinuxUtilities(interfaces.configuration.VersionableInterface):
|
||||
"""Class with multiple useful linux functions."""
|
||||
|
||||
_version = (2, 3, 1)
|
||||
_version = (2, 4, 0)
|
||||
_required_framework_version = (2, 0, 0)
|
||||
deleted = "(deleted)"
|
||||
smear = "<potentially smeared>"
|
||||
|
||||
framework.require_interface_version(*_required_framework_version)
|
||||
|
||||
@@ -168,6 +170,7 @@ class LinuxUtilities(interfaces.configuration.VersionableInterface):
|
||||
# vfsmnt can be the vfsmount object itself (>=3.3) or a vfsmount * (<3.3)
|
||||
return ""
|
||||
|
||||
inode = dentry.d_inode
|
||||
path_reversed = []
|
||||
smeared = False
|
||||
while (
|
||||
@@ -191,6 +194,7 @@ class LinuxUtilities(interfaces.configuration.VersionableInterface):
|
||||
|
||||
parent = dentry.d_parent
|
||||
dname = dentry.d_name.name_as_str()
|
||||
|
||||
# empty dentry names are most likely
|
||||
# the result of smearing
|
||||
if not dname:
|
||||
@@ -203,7 +207,10 @@ class LinuxUtilities(interfaces.configuration.VersionableInterface):
|
||||
# if there is smear the missing dname will be empty. e.g. if the normal
|
||||
# path would be /foo/bar/baz, but bar is missing due to smear the results
|
||||
# returned here will show /foo//baz. Note the // for the missing dname.
|
||||
return f"<potentially smeared> {path}"
|
||||
return f"{LinuxUtilities.smear} {path}"
|
||||
|
||||
if inode and inode.is_readable() and inode.is_valid() and inode.i_nlink == 0:
|
||||
path = f" {path} {LinuxUtilities.deleted}"
|
||||
return path
|
||||
|
||||
@classmethod
|
||||
@@ -301,7 +308,7 @@ class LinuxUtilities(interfaces.configuration.VersionableInterface):
|
||||
return f"{pre_name}:[{inode.i_ino:d}]"
|
||||
|
||||
@classmethod
|
||||
def path_for_file(cls, context, task, filp) -> str:
|
||||
def path_for_file(cls, context, task, filp, files_only=False) -> str:
|
||||
"""Returns a file (or sock pipe) pathname relative to the task's root directory.
|
||||
|
||||
A 'file' structure doesn't have enough information to properly restore its
|
||||
@@ -340,7 +347,7 @@ class LinuxUtilities(interfaces.configuration.VersionableInterface):
|
||||
except exceptions.InvalidAddressException:
|
||||
dname_is_valid = False
|
||||
|
||||
if dname_is_valid:
|
||||
if dname_is_valid and not files_only:
|
||||
ret = LinuxUtilities._get_new_sock_pipe_path(context, task, filp)
|
||||
else:
|
||||
ret = LinuxUtilities._get_path_file(task, filp)
|
||||
@@ -353,6 +360,7 @@ class LinuxUtilities(interfaces.configuration.VersionableInterface):
|
||||
context: interfaces.context.ContextInterface,
|
||||
symbol_table: str,
|
||||
task: interfaces.objects.ObjectInterface,
|
||||
files_only: bool = False,
|
||||
):
|
||||
try:
|
||||
files = task.files
|
||||
@@ -376,7 +384,9 @@ class LinuxUtilities(interfaces.configuration.VersionableInterface):
|
||||
|
||||
for fd_num, filp in enumerate(fds):
|
||||
if filp and filp.is_readable():
|
||||
full_path = LinuxUtilities.path_for_file(context, task, filp)
|
||||
full_path = LinuxUtilities.path_for_file(
|
||||
context, task, filp, files_only
|
||||
)
|
||||
|
||||
yield fd_num, filp, full_path
|
||||
|
||||
|
||||
Reference in New Issue
Block a user