diff --git a/volatility3/framework/plugins/linux/lsof.py b/volatility3/framework/plugins/linux/lsof.py index c1de48c1a..fa9d2bf61 100644 --- a/volatility3/framework/plugins/linux/lsof.py +++ b/volatility3/framework/plugins/linux/lsof.py @@ -21,7 +21,6 @@ class Lsof(plugins.PluginInterface, timeliner.TimeLinerInterface): """Lists all memory maps for all processes.""" _required_framework_version = (2, 0, 0) - _version = (2, 0, 0) @classmethod @@ -53,7 +52,7 @@ class Lsof(plugins.PluginInterface, timeliner.TimeLinerInterface): symbol_table: str, filter_func: Callable[[int], bool] = lambda _: False, ): - linuxutils_symbol_table = None # type: ignore + linuxutils_symbol_table = None for task in pslist.PsList.list_tasks(context, symbol_table, filter_func): if linuxutils_symbol_table is None: if constants.BANG not in task.vol.type_name: @@ -71,21 +70,17 @@ class Lsof(plugins.PluginInterface, timeliner.TimeLinerInterface): fd_num, filp, full_path = fd_fields inode_metadata = linux.LinuxUtilities.get_inode_metadata(context, filp) try: - inode_num, file_size, imode, ctime, mtime, atime = next( + inode_num, itype, file_size, imode, ctime, mtime, atime = next( inode_metadata ) except Exception as e: vollog.warning( f"Can't get inode metadata for file descriptor {fd_num}: {e}" ) - # Yield NotAvailableValue for each field in case of an exception - inode_num = renderers.NotAvailableValue() - file_size = renderers.NotAvailableValue() - imode = renderers.NotAvailableValue() - ctime = renderers.NotAvailableValue() - mtime = renderers.NotAvailableValue() - atime = renderers.NotAvailableValue() - yield pid, task_comm, task, fd_num, filp, full_path, inode_num, imode, ctime, mtime, atime, file_size + inode_num = itype = file_size = imode = ctime = mtime = atime = ( + renderers.NotAvailableValue() + ) + yield pid, task_comm, task, fd_num, filp, full_path, inode_num, itype, imode, ctime, mtime, atime, file_size def _generator(self, pids, symbol_table): filter_func = pslist.PsList.create_pid_filter(pids) @@ -100,6 +95,7 @@ class Lsof(plugins.PluginInterface, timeliner.TimeLinerInterface): filp, full_path, inode_num, + itype, imode, ctime, mtime, @@ -112,6 +108,7 @@ class Lsof(plugins.PluginInterface, timeliner.TimeLinerInterface): fd_num, full_path, inode_num, + itype, imode, ctime, mtime, @@ -130,6 +127,7 @@ class Lsof(plugins.PluginInterface, timeliner.TimeLinerInterface): ("FD", int), ("Path", str), ("Inode", int), + ("Type", str), ("Mode", str), ("Changed", datetime.datetime), ("Modified", datetime.datetime), @@ -144,6 +142,6 @@ class Lsof(plugins.PluginInterface, timeliner.TimeLinerInterface): for row in self._generator(pids, symbol_table): _depth, row_data = row description = f'Process {row_data[1]} ({row_data[0]}) Open "{row_data[3]}"' - yield description, timeliner.TimeLinerType.CHANGED, row_data[6] - yield description, timeliner.TimeLinerType.MODIFIED, row_data[7] - yield description, timeliner.TimeLinerType.ACCESSED, row_data[8] + yield description, timeliner.TimeLinerType.CHANGED, row_data[7] + yield description, timeliner.TimeLinerType.MODIFIED, row_data[8] + yield description, timeliner.TimeLinerType.ACCESSED, row_data[9] diff --git a/volatility3/framework/symbols/linux/__init__.py b/volatility3/framework/symbols/linux/__init__.py index a96fe9d2f..d52c43dae 100644 --- a/volatility3/framework/symbols/linux/__init__.py +++ b/volatility3/framework/symbols/linux/__init__.py @@ -280,23 +280,19 @@ class LinuxUtilities(interfaces.configuration.VersionableInterface): A helper function that gets the inodes metadata from a file descriptor """ dentry = filp.get_dentry() - if dentry != 0: + if dentry: inode_object = dentry.d_inode - inode_num = inode_object.i_ino - file_size = inode_object.i_size # file size in bytes - imode = stat.filemode(inode_object.i_mode) # file type & Permissions - - # Timestamps - ctime = datetime.datetime.fromtimestamp( - inode_object.i_ctime.tv_sec - ) # last change time - mtime = datetime.datetime.fromtimestamp( - inode_object.i_mtime.tv_sec - ) # last modify time - atime = datetime.datetime.fromtimestamp( - inode_object.i_atime.tv_sec - ) # last access time - yield inode_num, file_size, imode, ctime, mtime, atime + if inode_object and inode_object.is_valid(): + itype = inode_object.get_inode_type() or "?" + yield ( + inode_object.i_ino, + itype, + inode_object.i_size, + inode_object.get_file_mode(), + inode_object.get_change_time(), + inode_object.get_modification_time(), + inode_object.get_access_time(), + ) @classmethod def mask_mods_list( diff --git a/volatility3/framework/symbols/linux/extensions/__init__.py b/volatility3/framework/symbols/linux/extensions/__init__.py index 05679523f..0ee6e7d95 100644 --- a/volatility3/framework/symbols/linux/extensions/__init__.py +++ b/volatility3/framework/symbols/linux/extensions/__init__.py @@ -1820,6 +1820,16 @@ class inode(objects.StructType): """Returns True if the sticky bit is set""" return (self.i_mode & stat.S_ISVTX) != 0 + @property + def is_whiteout(self) -> bool: + """Returns True if the inode is a whiteout""" + return (self.i_mode & 0o140000) == 0o140000 + + @property + def is_overlay(self) -> bool: + """Returns True if the inode is an overlay""" + return (self.i_mode & 0o40000) == 0o40000 + def get_inode_type(self) -> Union[str, None]: """Returns inode type name @@ -1840,6 +1850,10 @@ class inode(objects.StructType): return "CHR" elif self.is_block: return "BLK" + elif self.is_whiteout: + return "WHT" + elif self.is_overlay: + return "OVL" else: return None