From 4b76b699ad97f93fd9cf2949e6ab49c526784f3c Mon Sep 17 00:00:00 2001 From: Gustavo Moreira Date: Wed, 30 Oct 2024 09:56:05 +1100 Subject: [PATCH] Linux: hidden_modules: Add docstrings and comments to enhance the documentation of the module verification process. Move the hardcoded values to the linux constants file. --- .../framework/constants/linux/__init__.py | 8 ++++ .../symbols/linux/extensions/__init__.py | 37 ++++++++++++++----- 2 files changed, 36 insertions(+), 9 deletions(-) diff --git a/volatility3/framework/constants/linux/__init__.py b/volatility3/framework/constants/linux/__init__.py index 0567b8574..7c485d3c3 100644 --- a/volatility3/framework/constants/linux/__init__.py +++ b/volatility3/framework/constants/linux/__init__.py @@ -339,3 +339,11 @@ class PT_FLAGS(Flag): def flags(self) -> str: """Returns the ptrace flags string""" return str(self).replace(self.__class__.__name__ + ".", "") + + +# Valid sizes for modules. Note that the Linux kernel does not define these values; they +# are based on empirical observations of typical memory allocations for kernel modules. +# We use this to verify that the found module falls within reasonable limits. +MODULE_MAXIMUM_CORE_SIZE = 20000000 +MODULE_MAXIMUM_CORE_TEXT_SIZE = 20000000 +MODULE_MINIMUM_SIZE = 4096 diff --git a/volatility3/framework/symbols/linux/extensions/__init__.py b/volatility3/framework/symbols/linux/extensions/__init__.py index cc43df8f5..fedb3d96f 100644 --- a/volatility3/framework/symbols/linux/extensions/__init__.py +++ b/volatility3/framework/symbols/linux/extensions/__init__.py @@ -13,12 +13,24 @@ from typing import Generator, Iterable, Iterator, Optional, Tuple, List, Union, from volatility3.framework import constants, exceptions, objects, interfaces, symbols from volatility3.framework.renderers import conversion -from volatility3.framework.constants.linux import SOCK_TYPES, SOCK_FAMILY -from volatility3.framework.constants.linux import IP_PROTOCOLS, IPV6_PROTOCOLS -from volatility3.framework.constants.linux import TCP_STATES, NETLINK_PROTOCOLS -from volatility3.framework.constants.linux import ETH_PROTOCOLS, BLUETOOTH_STATES -from volatility3.framework.constants.linux import BLUETOOTH_PROTOCOLS, SOCKET_STATES -from volatility3.framework.constants.linux import CAPABILITIES, PT_FLAGS +from volatility3.framework.constants.linux import ( + SOCK_TYPES, + SOCK_FAMILY, + IP_PROTOCOLS, + IPV6_PROTOCOLS, + TCP_STATES, + NETLINK_PROTOCOLS, + ETH_PROTOCOLS, + BLUETOOTH_STATES, + BLUETOOTH_PROTOCOLS, + SOCKET_STATES, + CAPABILITIES, + PT_FLAGS, + MODULE_MAXIMUM_CORE_SIZE, + MODULE_MAXIMUM_CORE_TEXT_SIZE, + MODULE_MINIMUM_SIZE, +) + from volatility3.framework.layers import linear from volatility3.framework.objects import utility from volatility3.framework.symbols import generic, linux, intermed @@ -36,16 +48,23 @@ class module(generic.GenericIntelProcess): self._mod_mem_type = None # Initialize _mod_mem_type to None for memoization def is_valid(self): + """Determine whether it is a valid module object by verifying the self-referential + in module_kobject. This also confirms that the module is actively allocated and + not a remnant of freed memory or a failed module load attempt by verifying the + module memory section sizes. + """ layer = self._context.layers[self.vol.layer_name] # Make sure the entire module content is readable if not layer.is_valid(self.vol.offset, self.vol.size): return False core_size = self.get_core_size() + core_text_size = self.get_core_text_size() + init_size = self.get_init_size() if not ( - 1 <= core_size <= 20000000 - and core_size + self.get_init_size() >= 4096 - and 1 <= self.get_core_text_size() <= 20000000 + 0 < core_text_size <= MODULE_MAXIMUM_CORE_TEXT_SIZE + and 0 < core_size <= MODULE_MAXIMUM_CORE_SIZE + and core_size + init_size >= MODULE_MINIMUM_SIZE ): return False