mirror of
https://github.com/volatilityfoundation/volatility3.git
synced 2026-09-09 19:27:39 +02:00
linux: page_cache plugin: lazy file initialization and avoid redundant inode page cache walk during dumps not showing output with dumping to file.
This commit is contained in:
@@ -8,7 +8,7 @@ import datetime
|
||||
from dataclasses import dataclass, astuple
|
||||
from typing import List, Set, Type, Iterable
|
||||
|
||||
from volatility3.framework import renderers, interfaces
|
||||
from volatility3.framework import renderers, interfaces, exceptions
|
||||
from volatility3.framework.renderers import format_hints
|
||||
from volatility3.framework.interfaces import plugins
|
||||
from volatility3.framework.configuration import requirements
|
||||
@@ -453,16 +453,18 @@ class InodePages(plugins.PluginInterface):
|
||||
# created, saving both disk space and I/O time.
|
||||
# Additionally, using the page index will guarantee that each page is written at the
|
||||
# appropriate file position.
|
||||
inode_size = inode.i_size
|
||||
try:
|
||||
with open_method(filename) as f:
|
||||
inode_size = inode.i_size
|
||||
f.truncate(inode_size)
|
||||
|
||||
file_initialized = False
|
||||
with open_method(filename) as file_obj:
|
||||
for page_idx, page_content in inode.get_contents():
|
||||
current_fp = page_idx * vmlinux_layer.page_size
|
||||
max_length = inode_size - current_fp
|
||||
page_bytes = page_content[:max_length]
|
||||
if current_fp + len(page_bytes) > inode_size:
|
||||
page_bytes_len = min(max_length, len(page_content))
|
||||
if (
|
||||
current_fp >= inode_size
|
||||
or current_fp + page_bytes_len > inode_size
|
||||
):
|
||||
vollog.error(
|
||||
"Page out of file bounds: inode 0x%x, inode size %d, page index %d",
|
||||
inode.vol.offset,
|
||||
@@ -470,10 +472,20 @@ class InodePages(plugins.PluginInterface):
|
||||
page_idx,
|
||||
)
|
||||
continue
|
||||
page_bytes = page_content[:page_bytes_len]
|
||||
|
||||
f.seek(current_fp)
|
||||
f.write(page_bytes)
|
||||
if not file_initialized:
|
||||
# Lazy initialization to avoid truncating the file until we are
|
||||
# certain there is something to write
|
||||
file_obj.truncate(inode_size)
|
||||
file_initialized = True
|
||||
|
||||
file_obj.seek(current_fp)
|
||||
file_obj.write(page_bytes)
|
||||
except exceptions.LinuxPageCacheException:
|
||||
vollog.error(
|
||||
f"Error dumping cached pages for inode at {inode.vol.offset:#x}"
|
||||
)
|
||||
except OSError as e:
|
||||
vollog.error("Unable to write to file (%s): %s", filename, e)
|
||||
|
||||
@@ -514,31 +526,44 @@ class InodePages(plugins.PluginInterface):
|
||||
return None
|
||||
|
||||
inode_size = inode.i_size
|
||||
for page_obj in inode.get_pages():
|
||||
page_vaddr = page_obj.vol.offset
|
||||
page_paddr = page_obj.to_paddr()
|
||||
page_mapping_addr = page_obj.mapping
|
||||
page_index = int(page_obj.index)
|
||||
page_file_offset = page_index * vmlinux_layer.page_size
|
||||
dump_safe = (
|
||||
page_file_offset < inode_size
|
||||
and page_mapping_addr
|
||||
and page_mapping_addr.is_readable()
|
||||
)
|
||||
page_flags_list = page_obj.get_flags_list()
|
||||
page_flags = ",".join([x.replace("PG_", "") for x in page_flags_list])
|
||||
fields = (
|
||||
page_vaddr,
|
||||
page_paddr,
|
||||
page_mapping_addr,
|
||||
page_index,
|
||||
dump_safe,
|
||||
page_flags,
|
||||
)
|
||||
if not self.config["dump"]:
|
||||
try:
|
||||
for page_obj in inode.get_pages():
|
||||
if page_obj.mapping != inode.i_mapping:
|
||||
vollog.warning(
|
||||
f"Cached page at {page_obj.vol.offset:#x} has a mismatched address space with the inode. Skipping page"
|
||||
)
|
||||
continue
|
||||
page_vaddr = page_obj.vol.offset
|
||||
page_paddr = page_obj.to_paddr()
|
||||
page_mapping_addr = page_obj.mapping
|
||||
page_index = int(page_obj.index)
|
||||
page_file_offset = page_index * vmlinux_layer.page_size
|
||||
dump_safe = (
|
||||
page_file_offset < inode_size
|
||||
and page_mapping_addr
|
||||
and page_mapping_addr.is_readable()
|
||||
)
|
||||
page_flags_list = page_obj.get_flags_list()
|
||||
page_flags = ",".join(
|
||||
[x.replace("PG_", "") for x in page_flags_list]
|
||||
)
|
||||
fields = (
|
||||
page_vaddr,
|
||||
page_paddr,
|
||||
page_mapping_addr,
|
||||
page_index,
|
||||
dump_safe,
|
||||
page_flags,
|
||||
)
|
||||
|
||||
yield 0, fields
|
||||
yield 0, fields
|
||||
except exceptions.LinuxPageCacheException:
|
||||
vollog.warning(
|
||||
f"Page cache for inode at {inode.vol.offset:#x} is corrupt"
|
||||
)
|
||||
|
||||
if self.config["dump"]:
|
||||
else:
|
||||
open_method = self.open
|
||||
inode_address = inode.vol.offset
|
||||
filename = open_method.sanitize_filename(f"inode_0x{inode_address:x}.dmp")
|
||||
|
||||
Reference in New Issue
Block a user