mirror of
https://github.com/volatilityfoundation/volatility3.git
synced 2026-08-17 20:35:40 +02:00
Fix bugs in kallsyms and the related pscallstack found in testing and switch calls to deprecated functions
This commit is contained in:
@@ -106,6 +106,8 @@ class Kallsyms(plugins.PluginInterface):
|
||||
|
||||
for symbols_generator in symbol_generators:
|
||||
for kassymbol in symbols_generator:
|
||||
if not kassymbol:
|
||||
continue
|
||||
# Symbol sizes are calculated using the address of the next non-aliased
|
||||
# symbol or the end of the kernel text area _end/_etext. However, some kernel
|
||||
# symbols are located beyond that area, which causes this method to fail for
|
||||
|
||||
@@ -118,9 +118,15 @@ class PsCallStack(plugins.PluginInterface):
|
||||
current_sp = rsp_start
|
||||
idx = 0
|
||||
while current_sp < task_top_of_stack:
|
||||
stack_value_bytes = task_layer.read(current_sp, pointer_size)
|
||||
try:
|
||||
stack_value_bytes = task_layer.read(current_sp, pointer_size)
|
||||
except exceptions.InvalidAddressException:
|
||||
break
|
||||
stack_value = int.from_bytes(stack_value_bytes, byteorder=byte_order)
|
||||
|
||||
if not stack_value:
|
||||
idx += 1
|
||||
current_sp += pointer_size
|
||||
continue
|
||||
kassymbol = kas.lookup_address(stack_value)
|
||||
sp_address = current_sp & vmlinux_layer.address_mask
|
||||
stack_value &= vmlinux_layer.address_mask
|
||||
|
||||
@@ -1994,7 +1994,10 @@ class bpf_prog(objects.StructType):
|
||||
# 'prog_aux' was added in kernels 3.18
|
||||
return None
|
||||
|
||||
return self.aux.get_name()
|
||||
try:
|
||||
return self.aux.get_name()
|
||||
except exceptions.InvalidAddressException:
|
||||
return None
|
||||
|
||||
def bpf_jit_binary_hdr_address(self) -> int:
|
||||
"""Return the jitted BPF program start address
|
||||
@@ -2056,11 +2059,13 @@ class bpf_prog_aux(objects.StructType):
|
||||
# 'name' was added in kernels 4.15
|
||||
return None
|
||||
|
||||
if not self.name:
|
||||
try:
|
||||
if not self.name:
|
||||
return None
|
||||
return utility.array_to_string(self.name)
|
||||
except exceptions.InvalidAddressException:
|
||||
return None
|
||||
|
||||
return utility.array_to_string(self.name)
|
||||
|
||||
|
||||
class cred(objects.StructType):
|
||||
# struct cred was added in kernels 2.6.29
|
||||
@@ -2996,7 +3001,9 @@ class latch_tree_root(objects.StructType):
|
||||
rb_node = rb_node_ptr.dereference()
|
||||
lt_node = self._get_lt_node_from_rb_node(rb_node, idx)
|
||||
c = comp_function(key, lt_node)
|
||||
if c < 0:
|
||||
if c is None:
|
||||
return None
|
||||
elif c < 0:
|
||||
rb_node_ptr = rb_node.rb_left
|
||||
elif c > 0:
|
||||
rb_node_ptr = rb_node.rb_right
|
||||
|
||||
@@ -6,12 +6,12 @@ import functools
|
||||
import logging
|
||||
from typing import Iterator, List, Optional, Tuple
|
||||
|
||||
import volatility3.framework.symbols.linux.utilities.modules as linux_utilities_modules
|
||||
from volatility3.framework import constants, exceptions, interfaces
|
||||
from volatility3.framework.configuration import requirements
|
||||
from volatility3.framework.constants import linux as linux_constants
|
||||
from volatility3.framework.objects import utility
|
||||
from volatility3.framework.symbols import linux
|
||||
from volatility3.plugins.linux import lsmod
|
||||
|
||||
vollog = logging.getLogger(__name__)
|
||||
|
||||
@@ -304,28 +304,35 @@ class Kallsyms(interfaces.configuration.VersionableInterface):
|
||||
@classmethod
|
||||
def _assert_versions(cls) -> None:
|
||||
"""Verify versions of shared dependencies"""
|
||||
lsmod_version_required = (2, 0, 0)
|
||||
linux_utilities_modules_version_required = (3, 0, 0)
|
||||
if not requirements.VersionRequirement.matches_required(
|
||||
lsmod_version_required, lsmod.Lsmod.version
|
||||
linux_utilities_modules_version_required,
|
||||
linux_utilities_modules.Modules.version,
|
||||
):
|
||||
raise exceptions.VolatilityException(
|
||||
"Lsmod version not suitable: "
|
||||
f"required {lsmod_version_required} found {lsmod.Lsmod.version}",
|
||||
"linux_utilities_modules.Modules version not suitable: "
|
||||
f"required {linux_utilities_modules_version_required} found {linux_utilities_modules.Modules.version}",
|
||||
)
|
||||
|
||||
return None
|
||||
|
||||
def _read_bytes(self, address: int, size: int) -> bytes:
|
||||
def _read_bytes(self, address: int, size: int) -> Optional[bytes]:
|
||||
layer = self._context.layers[self._layer_name]
|
||||
return layer.read(address, size).decode()
|
||||
try:
|
||||
return layer.read(address, size).decode()
|
||||
except exceptions.InvalidAddressException:
|
||||
return None
|
||||
|
||||
def _read_int(self, address: int, size: int, signed: bool = False) -> int:
|
||||
def _read_int(self, address: int, size: int, signed: bool = False) -> Optional[int]:
|
||||
layer = self._context.layers[self._layer_name]
|
||||
return int.from_bytes(
|
||||
layer.read(address, size),
|
||||
byteorder=self._endian,
|
||||
signed=signed,
|
||||
)
|
||||
try:
|
||||
return int.from_bytes(
|
||||
layer.read(address, size),
|
||||
byteorder=self._endian,
|
||||
signed=signed,
|
||||
)
|
||||
except exceptions.InvalidAddressException:
|
||||
return None
|
||||
|
||||
def _bootstrap(self) -> None:
|
||||
layer = self._context.layers[self._layer_name]
|
||||
@@ -402,7 +409,20 @@ class Kallsyms(interfaces.configuration.VersionableInterface):
|
||||
"""
|
||||
current_offset = 0
|
||||
for sym_idx in range(self._kallsyms_num_syms):
|
||||
kassymbol, compressed_length = self._get_symbol(current_offset, sym_idx)
|
||||
try:
|
||||
kassymbol, compressed_length = self._get_symbol(current_offset, sym_idx)
|
||||
except exceptions.InvalidAddressException:
|
||||
vollog.debug(
|
||||
f"Unable to reconstruct core symbol at offset {current_offset:#x} and index {sym_idx}"
|
||||
)
|
||||
continue
|
||||
|
||||
if compressed_length is None:
|
||||
vollog.debug(
|
||||
f"Unable to reconstruct compressed_length at offset {current_offset:#x} and index {sym_idx}"
|
||||
)
|
||||
break
|
||||
|
||||
if kassymbol:
|
||||
yield kassymbol
|
||||
|
||||
@@ -485,7 +505,7 @@ class Kallsyms(interfaces.configuration.VersionableInterface):
|
||||
)
|
||||
return kassymbolbasic, compressed_length
|
||||
|
||||
def _get_symbol_address_by_index(self, index: int) -> int:
|
||||
def _get_symbol_address_by_index(self, index: int) -> Optional[int]:
|
||||
"""Return symbol address based on the symbol index in the kallsyms arrays.
|
||||
Based on kallsyms_sym_address()
|
||||
|
||||
@@ -502,6 +522,8 @@ class Kallsyms(interfaces.configuration.VersionableInterface):
|
||||
signed_int_size = 4
|
||||
sym_offset_ptr = self._kallsyms_offsets_address + (index * signed_int_size)
|
||||
sym_addr = self._read_int(sym_offset_ptr, signed_int_size, signed=True)
|
||||
if sym_addr is None:
|
||||
return None
|
||||
|
||||
if sym_addr < 0:
|
||||
# Negative offsets are relative to kallsyms_relative_base - 1
|
||||
@@ -517,35 +539,56 @@ class Kallsyms(interfaces.configuration.VersionableInterface):
|
||||
self._long_size,
|
||||
signed=False,
|
||||
)
|
||||
if kallsyms_address is None:
|
||||
return None
|
||||
|
||||
return kallsyms_address & layer.address_mask
|
||||
else:
|
||||
raise exceptions.VolatilityException("Unsupported kernel")
|
||||
|
||||
@functools.lru_cache
|
||||
def _get_symbol_pos(self, address: int) -> Tuple[int, int]:
|
||||
def _get_symbol_pos(self, address: int) -> Optional[Tuple[int, int]]:
|
||||
"""Returns the symbol position in the kallsyms arrays and its size."""
|
||||
low = 0
|
||||
high = self._kallsyms_num_syms
|
||||
|
||||
while high - low > 1:
|
||||
mid = low + (high - low) // 2
|
||||
if self._get_symbol_address_by_index(mid) <= address:
|
||||
symbol_index = self._get_symbol_address_by_index(mid)
|
||||
if symbol_index is None:
|
||||
return None, None
|
||||
elif symbol_index <= address:
|
||||
low = mid
|
||||
else:
|
||||
high = mid
|
||||
|
||||
# prevent accidental bleed through
|
||||
symbol_index = None
|
||||
|
||||
# Search for the first aliased symbol. *Aliased symbols* are symbols with the same address.
|
||||
while low and self._get_symbol_address_by_index(
|
||||
low - 1
|
||||
) == self._get_symbol_address_by_index(low):
|
||||
low -= 1
|
||||
while low:
|
||||
symbol_index = self._get_symbol_address_by_index(low - 1)
|
||||
if symbol_index is None:
|
||||
return None, None
|
||||
|
||||
if symbol_index == self._get_symbol_address_by_index(low):
|
||||
low -= 1
|
||||
else:
|
||||
break
|
||||
|
||||
symbol_start = self._get_symbol_address_by_index(low)
|
||||
if symbol_start is None:
|
||||
return None, None
|
||||
|
||||
symbol_end = 0
|
||||
|
||||
# Search for next non-aliased symbol.
|
||||
for idx in range(low + 1, self._kallsyms_num_syms):
|
||||
if self._get_symbol_address_by_index(idx) > symbol_start:
|
||||
symbol_index = self._get_symbol_address_by_index(idx)
|
||||
if symbol_index is None:
|
||||
return None, None
|
||||
|
||||
if symbol_index > symbol_start:
|
||||
symbol_end = self._get_symbol_address_by_index(idx)
|
||||
break
|
||||
|
||||
@@ -664,6 +707,8 @@ class Kallsyms(interfaces.configuration.VersionableInterface):
|
||||
return None
|
||||
|
||||
pos, sym_size = self._get_symbol_pos(address)
|
||||
if pos is None:
|
||||
return None
|
||||
offset = self._get_symbol_offset(pos)
|
||||
sym_address = self._get_symbol_address_by_index(pos)
|
||||
kassymbolbasic, _compressed_length = self._expand_symbol(offset)
|
||||
@@ -855,7 +900,9 @@ class Kallsyms(interfaces.configuration.VersionableInterface):
|
||||
self,
|
||||
) -> List[Tuple[interfaces.objects.ObjectInterface, int, int]]:
|
||||
modules_region = []
|
||||
for module in lsmod.Lsmod.list_modules(self._context, self._module_name):
|
||||
for module in linux_utilities_modules.Modules.list_modules(
|
||||
self._context, self._module_name
|
||||
):
|
||||
minimum_address, maximum_address = module.get_module_address_boundaries()
|
||||
module_region = module, minimum_address, maximum_address
|
||||
modules_region.append(module_region)
|
||||
@@ -923,21 +970,35 @@ class Kallsyms(interfaces.configuration.VersionableInterface):
|
||||
return self._search_module_by_address(address)
|
||||
|
||||
@functools.lru_cache
|
||||
def _get_type_cache(self, name: str):
|
||||
def _get_type_cache(self, name: str) -> Optional[interfaces.objects.Template]:
|
||||
vmlinux = self._context.modules[self._module_name]
|
||||
return vmlinux.get_type(name)
|
||||
try:
|
||||
return vmlinux.get_type(name)
|
||||
except exceptions.SymbolError:
|
||||
return None
|
||||
|
||||
def _mod_tree_comp(
|
||||
self, address: int, latch_tree_node: interfaces.objects.ObjectInterface
|
||||
) -> int:
|
||||
) -> Optional[int]:
|
||||
vmlinux = self._context.modules[self._module_name]
|
||||
|
||||
module_memory_mtn_offset = self._get_type_cache(
|
||||
"module_memory"
|
||||
).relative_child_offset("mtn")
|
||||
mod_tree_node_mod_offset = self._get_type_cache(
|
||||
"mod_tree_node"
|
||||
).relative_child_offset("mod")
|
||||
module_memory_mtn = self._get_type_cache("module_memory")
|
||||
if not module_memory_mtn:
|
||||
vollog.debug(
|
||||
"`module_memory` symbol not present in the symbol table. Cannot proceed."
|
||||
)
|
||||
return None
|
||||
|
||||
module_memory_mtn_offset = module_memory_mtn.relative_child_offset("mtn")
|
||||
|
||||
mod_tree_node_mod = self._get_type_cache("mod_tree_node")
|
||||
if not mod_tree_node_mod:
|
||||
vollog.debug(
|
||||
"`mod_tree_node` symbol not present in the symbol table. Cannot proceed."
|
||||
)
|
||||
return None
|
||||
|
||||
mod_tree_node_mod_offset = mod_tree_node_mod.relative_child_offset("mod")
|
||||
|
||||
module_memory_offset = (
|
||||
latch_tree_node.vol.offset
|
||||
@@ -1087,7 +1148,9 @@ class Kallsyms(interfaces.configuration.VersionableInterface):
|
||||
KASSymbol objects
|
||||
"""
|
||||
layer = self._context.layers[self._layer_name]
|
||||
for module in lsmod.Lsmod.list_modules(self._context, self._module_name):
|
||||
for module in linux_utilities_modules.Modules.list_modules(
|
||||
self._context, self._module_name
|
||||
):
|
||||
module_name = utility.array_to_string(module.name)
|
||||
for elf_sym_idx, elf_sym_obj in enumerate(module.get_symbols()):
|
||||
sym_name = elf_sym_obj.get_name()
|
||||
@@ -1254,21 +1317,24 @@ class Kallsyms(interfaces.configuration.VersionableInterface):
|
||||
# this function will still be able to gather the symbols.
|
||||
bpf_kallsyms_list = vmlinux.object_from_symbol("bpf_kallsyms")
|
||||
for elem in bpf_kallsyms_list.to_list(list_type_symname, list_head_member):
|
||||
# See kernel's bpf_get_kallsym()
|
||||
if list_type == "bpf_ksym":
|
||||
# kernels >= 5.8
|
||||
bpf_ksym = elem
|
||||
sym_name = utility.array_to_string(bpf_ksym.name)
|
||||
sym_addr = bpf_ksym.start
|
||||
sym_size = bpf_ksym.end - bpf_ksym.start
|
||||
else:
|
||||
# list_type == "bpf_prog_aux" 3.18 <= kernels < 5.8
|
||||
bpf_prog_aux = elem
|
||||
bpf_prog = bpf_prog_aux.prog
|
||||
sym_name = bpf_prog.get_name()
|
||||
sym_addr = bpf_prog.bpf_func
|
||||
sym_start, sym_end = bpf_prog.get_address_region()
|
||||
sym_size = sym_end - sym_start
|
||||
try:
|
||||
# See kernel's bpf_get_kallsym()
|
||||
if list_type == "bpf_ksym":
|
||||
# kernels >= 5.8
|
||||
bpf_ksym = elem
|
||||
sym_name = utility.array_to_string(bpf_ksym.name)
|
||||
sym_addr = bpf_ksym.start
|
||||
sym_size = bpf_ksym.end - bpf_ksym.start
|
||||
else:
|
||||
# list_type == "bpf_prog_aux" 3.18 <= kernels < 5.8
|
||||
bpf_prog_aux = elem
|
||||
bpf_prog = bpf_prog_aux.prog
|
||||
sym_name = bpf_prog.get_name()
|
||||
sym_addr = bpf_prog.bpf_func
|
||||
sym_start, sym_end = bpf_prog.get_address_region()
|
||||
sym_size = sym_end - sym_start
|
||||
except exceptions.InvalidAddressException:
|
||||
continue
|
||||
|
||||
# The following are also hardcoded in the Linux kernel
|
||||
# see kernel's get_ksymbol_bpf(), bpf_get_kallsym() and BPF_SYM_ELF_TYPE
|
||||
@@ -1322,7 +1388,7 @@ class Kallsyms(interfaces.configuration.VersionableInterface):
|
||||
sym_size = symbol_end - symbol_start
|
||||
elif vmlinux.has_type("latch_tree_root") and vmlinux.get_type(
|
||||
"bpf_prog_aux"
|
||||
).child_template("ksym_tnode"):
|
||||
).has_member("ksym_tnode"):
|
||||
# For 4.11 <= kernels < 5.7
|
||||
# latch_tree_root was added in kernels 4.2 ade3f510f93a5613b672febe88eff8ea7f1c63b7
|
||||
# BPF kallsyms support was added in kernels 4.11 74451e66d516c55e309e8d89a4a1e7596e46aacd
|
||||
|
||||
Reference in New Issue
Block a user