mirror of
https://github.com/volatilityfoundation/volatility3.git
synced 2026-09-12 12:47:39 +02:00
Merge pull request #1921 from Abyss-W4tcher/issue_1920_slow_addrspace_scan
Improve Intel layer's address space scanning
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
# We use the SemVer 2.0.0 versioning scheme
|
||||
VERSION_MAJOR = 2 # Number of releases of the library with a breaking change
|
||||
VERSION_MINOR = 27 # Number of changes that only add to the interface
|
||||
VERSION_PATCH = 0 # Number of changes that do not change the interface
|
||||
VERSION_PATCH = 1 # Number of changes that do not change the interface
|
||||
VERSION_SUFFIX = ""
|
||||
|
||||
PACKAGE_VERSION = (
|
||||
|
||||
@@ -38,7 +38,7 @@ class Intel(linear.LinearlyMappedLayer):
|
||||
# NOTE: _maxphyaddr is MAXPHYADDR as defined in the Intel specs *NOT* the maximum physical address
|
||||
_maxphyaddr = 32
|
||||
_maxvirtaddr = _maxphyaddr
|
||||
_structure = [("page directory", 10, False), ("page table", 10, True)]
|
||||
_structure = [("page directory", 10, True), ("page table", 10, False)]
|
||||
_direct_metadata = collections.ChainMap(
|
||||
{"architecture": "Intel32"},
|
||||
{"mapped": True},
|
||||
@@ -221,18 +221,6 @@ class Intel(linear.LinearlyMappedLayer):
|
||||
entry,
|
||||
"Page Fault at entry " + hex(entry) + " in table " + name,
|
||||
)
|
||||
# Check if we're a large page
|
||||
if large_page and (entry & self._PAGE_PSE):
|
||||
# Mask off the PAT bit
|
||||
if entry & self._PAGE_PAT_LARGE:
|
||||
entry -= self._PAGE_PAT_LARGE
|
||||
# We're a large page, the rest is finished below
|
||||
# If we want to implement PSE-36, it would need to be done here
|
||||
break
|
||||
# Figure out how much of the offset we should be using
|
||||
start = position
|
||||
position -= size
|
||||
index = self._mask(page_address, start, position + 1) >> (position + 1)
|
||||
|
||||
# Grab the base address of the table we'll be getting the next entry from
|
||||
base_address = self._mask(
|
||||
@@ -249,6 +237,11 @@ class Intel(linear.LinearlyMappedLayer):
|
||||
"Page Fault at entry " + hex(entry) + " in table " + name,
|
||||
)
|
||||
|
||||
# Figure out how much of the offset we should be using
|
||||
start = position
|
||||
position -= size
|
||||
index = self._mask(page_address, start, position + 1) >> (position + 1)
|
||||
|
||||
# Read the data for the next entry
|
||||
entry_data_start = index << self._index_shift
|
||||
entry_data = table[entry_data_start : entry_data_start + self._entry_size]
|
||||
@@ -262,14 +255,26 @@ class Intel(linear.LinearlyMappedLayer):
|
||||
# Read out the new entry from memory
|
||||
(entry,) = struct.unpack(self._entry_format, entry_data)
|
||||
|
||||
# Check if we're a large page
|
||||
if large_page and (entry & self._PAGE_PSE):
|
||||
# Mask off the PAT bit
|
||||
if entry & self._PAGE_PAT_LARGE:
|
||||
entry -= self._PAGE_PAT_LARGE
|
||||
# We're a large page, the rest is finished below
|
||||
# If we want to implement PSE-36, it would need to be done here
|
||||
break
|
||||
|
||||
return entry, position
|
||||
|
||||
@functools.lru_cache(maxsize=1025)
|
||||
def _get_valid_table(self, base_address: int) -> Optional[bytes]:
|
||||
"""Extracts the table, validates it and returns it if it's valid."""
|
||||
table = self._context.layers.read(
|
||||
self._base_layer, base_address, self.page_size
|
||||
)
|
||||
try:
|
||||
table = self._context.layers.read(
|
||||
self._base_layer, base_address, self.page_size
|
||||
)
|
||||
except exceptions.InvalidAddressException:
|
||||
return None
|
||||
|
||||
# If the table is entirely duplicates, then mark the whole table as bad
|
||||
if table == table[: self._entry_size] * self._entry_number:
|
||||
@@ -371,12 +376,18 @@ class Intel(linear.LinearlyMappedLayer):
|
||||
yield offset, length, mapped_offset, length, layer_name
|
||||
return None
|
||||
while length > 0:
|
||||
skip_mask = None
|
||||
try:
|
||||
chunk_offset, page_size, layer_name = self._translate(offset)
|
||||
chunk_size = min(page_size - (chunk_offset % page_size), length)
|
||||
# Page align the chunk size value
|
||||
chunk_size = min(page_size - (offset % page_size), length)
|
||||
if not self._context.layers[layer_name].is_valid(
|
||||
chunk_offset, chunk_size
|
||||
):
|
||||
# Virtual -> physical is contiguous in the chunk_size range.
|
||||
# If we fail, we can jump directly to the end as we know all bytes in between
|
||||
# aren't mapped (virtually and) physically anyway.
|
||||
skip_mask = chunk_size - 1
|
||||
raise exceptions.InvalidAddressException(
|
||||
layer_name=layer_name, invalid_address=chunk_offset
|
||||
)
|
||||
@@ -386,12 +397,13 @@ class Intel(linear.LinearlyMappedLayer):
|
||||
) as excp:
|
||||
if not ignore_errors:
|
||||
raise
|
||||
# We can jump more if we know where the page fault failed
|
||||
if isinstance(excp, exceptions.PagedInvalidAddressException):
|
||||
mask = (1 << excp.invalid_bits) - 1
|
||||
else:
|
||||
mask = (1 << self._page_size_in_bits) - 1
|
||||
length_diff = mask + 1 - (offset & mask)
|
||||
if skip_mask is None:
|
||||
# We can jump more if we know where the page fault occured
|
||||
if isinstance(excp, exceptions.PagedInvalidAddressException):
|
||||
skip_mask = (1 << excp.invalid_bits) - 1
|
||||
else:
|
||||
skip_mask = (1 << self._page_size_in_bits) - 1
|
||||
length_diff = skip_mask + 1 - (offset & skip_mask)
|
||||
length -= length_diff
|
||||
offset += length_diff
|
||||
else:
|
||||
@@ -429,7 +441,7 @@ class IntelPAE(Intel):
|
||||
_structure = [
|
||||
("page directory pointer", 2, False),
|
||||
("page directory", 9, True),
|
||||
("page table", 9, True),
|
||||
("page table", 9, False),
|
||||
]
|
||||
_direct_metadata = collections.ChainMap({"pae": True}, Intel._direct_metadata)
|
||||
|
||||
@@ -449,7 +461,7 @@ class Intel32e(Intel):
|
||||
("page map layer 4", 9, False),
|
||||
("page directory pointer", 9, True),
|
||||
("page directory", 9, True),
|
||||
("page table", 9, True),
|
||||
("page table", 9, False),
|
||||
]
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user