Skip to content

Commit 0dd8d3a

Browse files
authored
Merge pull request #1827 from SolitudePy/lsof_deleted
Lsof improvements (show deleted as in lsof output) + files_only argument
2 parents 2dbc06f + eb79008 commit 0dd8d3a

File tree

2 files changed

+35
-10
lines changed

2 files changed

+35
-10
lines changed

volatility3/framework/plugins/linux/lsof.py

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ class Lsof(plugins.PluginInterface, timeliner.TimeLinerInterface):
110110
"""Lists open files for each processes."""
111111

112112
_required_framework_version = (2, 0, 0)
113-
_version = (2, 0, 2)
113+
_version = (2, 1, 0)
114114

115115
@classmethod
116116
def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]:
@@ -137,6 +137,12 @@ def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]
137137
element_type=int,
138138
optional=True,
139139
),
140+
requirements.BooleanRequirement(
141+
name="files_only",
142+
description="Include only file descriptors of type file",
143+
optional=True,
144+
default=False,
145+
),
140146
]
141147

142148
@classmethod
@@ -145,6 +151,7 @@ def list_fds(
145151
context: interfaces.context.ContextInterface,
146152
vmlinux_module_name: str,
147153
filter_func: Callable[[int], bool] = lambda _: False,
154+
include_files_only: bool = False,
148155
) -> Iterable[FDInternal]:
149156
"""Enumerates open file descriptors in tasks
150157
@@ -167,23 +174,28 @@ def list_fds(
167174
linuxutils_symbol_table = task.vol.type_name.split(constants.BANG)[0]
168175

169176
fd_generator = linux.LinuxUtilities.files_descriptors_for_process(
170-
context, linuxutils_symbol_table, task
177+
context, linuxutils_symbol_table, task, files_only=include_files_only
171178
)
172179

173180
for fd_fields in fd_generator:
174181
yield FDInternal(task=task, fd_fields=fd_fields)
175182

176-
def _generator(self, pids, vmlinux_module_name):
183+
def _generator(self, pids, vmlinux_module_name, include_files_only):
177184
filter_func = pslist.PsList.create_pid_filter(pids)
185+
178186
for fd_internal in self.list_fds(
179-
self.context, vmlinux_module_name, filter_func=filter_func
187+
self.context,
188+
vmlinux_module_name,
189+
filter_func=filter_func,
190+
include_files_only=include_files_only,
180191
):
181192
fd_user = fd_internal.to_user()
182193
yield (0, dataclasses.astuple(fd_user))
183194

184195
def run(self):
185196
pids = self.config.get("pid", None)
186197
vmlinux_module_name = self.config["kernel"]
198+
include_files_only = self.config.get("files_only")
187199

188200
tree_grid_args = [
189201
("PID", int),
@@ -201,7 +213,10 @@ def run(self):
201213
("Size", int),
202214
]
203215
return renderers.TreeGrid(
204-
tree_grid_args, self._generator(pids, vmlinux_module_name)
216+
tree_grid_args,
217+
self._generator(
218+
pids, vmlinux_module_name, include_files_only=include_files_only
219+
),
205220
)
206221

207222
def generate_timeline(self):

volatility3/framework/symbols/linux/__init__.py

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,10 @@ def __init__(self, *args, **kwargs) -> None:
9999
class LinuxUtilities(interfaces.configuration.VersionableInterface):
100100
"""Class with multiple useful linux functions."""
101101

102-
_version = (2, 3, 1)
102+
_version = (2, 4, 0)
103103
_required_framework_version = (2, 0, 0)
104+
deleted = "(deleted)"
105+
smear = "<potentially smeared>"
104106

105107
framework.require_interface_version(*_required_framework_version)
106108

@@ -168,6 +170,7 @@ def do_get_path(cls, rdentry, rmnt, dentry, vfsmnt) -> Union[None, str]:
168170
# vfsmnt can be the vfsmount object itself (>=3.3) or a vfsmount * (<3.3)
169171
return ""
170172

173+
inode = dentry.d_inode
171174
path_reversed = []
172175
smeared = False
173176
while (
@@ -191,6 +194,7 @@ def do_get_path(cls, rdentry, rmnt, dentry, vfsmnt) -> Union[None, str]:
191194

192195
parent = dentry.d_parent
193196
dname = dentry.d_name.name_as_str()
197+
194198
# empty dentry names are most likely
195199
# the result of smearing
196200
if not dname:
@@ -203,7 +207,10 @@ def do_get_path(cls, rdentry, rmnt, dentry, vfsmnt) -> Union[None, str]:
203207
# if there is smear the missing dname will be empty. e.g. if the normal
204208
# path would be /foo/bar/baz, but bar is missing due to smear the results
205209
# returned here will show /foo//baz. Note the // for the missing dname.
206-
return f"<potentially smeared> {path}"
210+
return f"{LinuxUtilities.smear} {path}"
211+
212+
if inode and inode.is_readable() and inode.is_valid() and inode.i_nlink == 0:
213+
path = f" {path} {LinuxUtilities.deleted}"
207214
return path
208215

209216
@classmethod
@@ -301,7 +308,7 @@ def _get_new_sock_pipe_path(cls, context, task, filp) -> str:
301308
return f"{pre_name}:[{inode.i_ino:d}]"
302309

303310
@classmethod
304-
def path_for_file(cls, context, task, filp) -> str:
311+
def path_for_file(cls, context, task, filp, files_only=False) -> str:
305312
"""Returns a file (or sock pipe) pathname relative to the task's root directory.
306313
307314
A 'file' structure doesn't have enough information to properly restore its
@@ -340,7 +347,7 @@ def path_for_file(cls, context, task, filp) -> str:
340347
except exceptions.InvalidAddressException:
341348
dname_is_valid = False
342349

343-
if dname_is_valid:
350+
if dname_is_valid and not files_only:
344351
ret = LinuxUtilities._get_new_sock_pipe_path(context, task, filp)
345352
else:
346353
ret = LinuxUtilities._get_path_file(task, filp)
@@ -353,6 +360,7 @@ def files_descriptors_for_process(
353360
context: interfaces.context.ContextInterface,
354361
symbol_table: str,
355362
task: interfaces.objects.ObjectInterface,
363+
files_only: bool = False,
356364
):
357365
try:
358366
files = task.files
@@ -376,7 +384,9 @@ def files_descriptors_for_process(
376384

377385
for fd_num, filp in enumerate(fds):
378386
if filp and filp.is_readable():
379-
full_path = LinuxUtilities.path_for_file(context, task, filp)
387+
full_path = LinuxUtilities.path_for_file(
388+
context, task, filp, files_only
389+
)
380390

381391
yield fd_num, filp, full_path
382392

0 commit comments

Comments
 (0)