1774: consolidate module helpers

This commit is contained in:
Abyss Watcher
2025-11-20 13:19:34 +01:00
parent 70dfa09b26
commit d8518b3878
@@ -38,56 +38,11 @@ vollog = logging.getLogger(__name__)
class ModuleExtract(interfaces.configuration.VersionableInterface):
"""Extracts Linux kernel module structures into an analyzable ELF file"""
_version = (1, 0, 1)
_version = (1, 0, 2)
_required_framework_version = (2, 25, 0)
framework.require_interface_version(*_required_framework_version)
@classmethod
def _get_module_section_count(
cls,
context: interfaces.context.ContextInterface,
vmlinux_name: str,
module: extensions.module,
grp: interfaces.objects.ObjectInterface,
) -> int:
"""
Used to manually determine the section count for kernels that do not track
this count directly within the attribute structures
"""
kernel = context.modules[vmlinux_name]
count = 0
try:
if grp.has_member("bin_attrs"):
arr_offset = grp.bin_attrs
else:
arr_offset = grp.attrs
array = kernel.object(
object_type="array",
offset=arr_offset,
sub_type=kernel.get_type("pointer"),
count=50,
absolute=True,
)
# Walk up to 50 sections counting until we reach the end or a page fault
for sect in array:
if sect.vol.offset == 0:
break
count += 1
except exceptions.InvalidAddressException:
# Use whatever count we reached before the error
vollog.debug(
f"Exception hit counting sections for module at {module.vol.offset:#x}"
)
return count
@classmethod
def _find_section(
cls, section_lookups: List[Tuple[str, int, int, int]], sym_address: int
@@ -266,54 +221,6 @@ class ModuleExtract(interfaces.configuration.VersionableInterface):
return sym_table_data
@classmethod
def _enumerate_original_sections(
cls,
context: interfaces.context.ContextInterface,
vmlinux_name: str,
module: extensions.module,
) -> Optional[Dict[int, str]]:
"""
Enumerates the module's sections as maintained by the kernel after load time
'Early' sections like .init.text and .init.data are discarded after module
initialization, so they are not expected to be in memory during extraction
"""
if hasattr(module.sect_attrs, "nsections"):
num_sections = module.sect_attrs.nsections
else:
num_sections = cls._get_module_section_count(
context, vmlinux_name, module.sect_attrs.grp
)
if num_sections > 1024 or num_sections == 0:
vollog.debug(
f"Invalid number of sections ({num_sections}) for module at offset {module.vol.offset:#x}"
)
return None
vmlinux = context.modules[vmlinux_name]
# This is declared as a zero sized array, so we create ourselves
attribute_type = module.sect_attrs.attrs.vol.subtype
sect_array = vmlinux.object(
object_type="array",
subtype=attribute_type,
offset=module.sect_attrs.attrs.vol.offset,
count=num_sections,
absolute=True,
)
sections: Dict[int, str] = {}
# for each section, gather its name and address
for index, section in enumerate(sect_array):
name = section.get_name()
sections[section.address] = name
return sections
@classmethod
def _parse_sections(
cls,
@@ -330,10 +237,12 @@ class ModuleExtract(interfaces.configuration.VersionableInterface):
The data of .strtab is read directly off the module structure and not its section
as the section from the original module has no meaning after loading as the kernel does not reference it.
"""
original_sections = cls._enumerate_original_sections(
context, vmlinux_name, module
)
if original_sections is None:
original_sections = {}
for index, section in enumerate(module.get_sections()):
name = section.get_name()
original_sections[section.address] = name
if not original_sections:
return None
kernel = context.modules[vmlinux_name]