Skip to content
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
6e0fb2e
make module_sect_attr and bin_attribute optional
Abyss-W4tcher Apr 15, 2025
5c411a9
determine sect_attrs.attrs subtype dynamically
Abyss-W4tcher Apr 15, 2025
06c9d1f
black formatting
Abyss-W4tcher Apr 15, 2025
267aa2e
sections manual enumeration adjustment
Abyss-W4tcher Apr 15, 2025
aa503c9
sections manual enumeration adjustment
Abyss-W4tcher Apr 15, 2025
311914f
get_sections() sanity check
Abyss-W4tcher May 2, 2025
7e6b46a
add bin_attribute address virtual member
Abyss-W4tcher May 2, 2025
2134d9d
1774: consolidate module helpers
Abyss-W4tcher May 2, 2025
dcbcb96
handle None in _parse_sections caller
Abyss-W4tcher May 2, 2025
635237b
rollback to already patched version
Abyss-W4tcher May 2, 2025
0f22478
add ATTRIBUTE_NAME_MAX_SIZE constant
Abyss-W4tcher May 5, 2025
23e2471
use ATTRIBUTE_NAME_MAX_SIZE constant
Abyss-W4tcher May 5, 2025
6bd2ed6
make binary attributes iteration NULL terminated
Abyss-W4tcher May 5, 2025
907acf3
add dynamically_sized_array_of_pointers() helper
Abyss-W4tcher May 7, 2025
49761b5
use dynamically_sized_array_of_pointers in _get_sect_count
Abyss-W4tcher May 7, 2025
6df8ac2
correct type hinting
Abyss-W4tcher May 7, 2025
ed8af0a
lru_cache get_modules_memory_boundaries()
Abyss-W4tcher May 8, 2025
4009c6b
add section address sanity check
Abyss-W4tcher May 8, 2025
13bf505
leverage the existing Array facility
Abyss-W4tcher May 8, 2025
3dc5569
adjust to the new NULL-terminated processing
Abyss-W4tcher May 8, 2025
d519817
slight readability adjustment
Abyss-W4tcher May 8, 2025
f9fbff4
rollback to 635237b to prevent circular import
Abyss-W4tcher May 8, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion volatility3/framework/symbols/linux/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ def __init__(self, *args, **kwargs) -> None:
self.set_type_class("idr", extensions.IDR)
self.set_type_class("address_space", extensions.address_space)
self.set_type_class("page", extensions.page)
self.set_type_class("module_sect_attr", extensions.module_sect_attr)

# Might not exist in the current symbols
self.optional_set_type_class("module", extensions.module)
Expand All @@ -61,6 +60,8 @@ def __init__(self, *args, **kwargs) -> None:
self.optional_set_type_class("kernel_cap_struct", extensions.kernel_cap_struct)
self.optional_set_type_class("kernel_cap_t", extensions.kernel_cap_t)
self.optional_set_type_class("scatterlist", extensions.scatterlist)
self.optional_set_type_class("module_sect_attr", extensions.module_sect_attr)
self.optional_set_type_class("bin_attribute", extensions.bin_attribute)

# kernels >= 4.18
self.optional_set_type_class("timespec64", extensions.timespec64)
Expand Down
39 changes: 33 additions & 6 deletions volatility3/framework/symbols/linux/extensions/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,16 +180,27 @@ def get_name(self) -> Optional[str]:
return None

def _get_sect_count(self, grp: interfaces.objects.ObjectInterface) -> int:
"""Try to determine the number of valid sections"""
"""Try to determine the number of valid sections. Support for kernels > 6.14-rc1.

Resources:
- https://github.com/torvalds/linux/commit/d8959b947a8dfab1047c6fd5e982808f65717bfe
- https://github.com/torvalds/linux/commit/e0349c46cb4fbbb507fa34476bd70f9c82bad359
"""

if grp.has_member("bin_attrs"):
arr_offset = grp.bin_attrs
else:
arr_offset = grp.attrs

symbol_table_name = self.get_symbol_table_name()
arr = self._context.object(
symbol_table_name + constants.BANG + "array",
layer_name=self.vol.layer_name,
offset=grp.attrs,
offset=arr_offset,
subtype=self._context.symbol_space.get_type(
symbol_table_name + constants.BANG + "pointer"
),
count=25,
count=50,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm always a little nervous about random hard coded numbers. Is this defined anywhere we could find it, is 50 enough, does that number come from source code or how was 50 decided upon?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't have the answer to this question, for now I just duplicated code from modules.py, given the context.

As this is a NULL terminated array of pointers, it would be optimal to iterate over it that way, or even extend current utilities for it like array_of_pointers(null_terminated=True).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we have a number of string functions that do null terminate, but they should all always have a maximum value (otherwise we could just keep running forever). I'm just trying to find out what the appropriate maximum value should be and why (if anyone knows)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any progress on where this value came from? Ideally we'd avoid this the same was as we avoid the other one (or at least comment where the size of the value comes from).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I made a change that makes it a NULL-terminated iteration (just as the structure's design). It is safer to make a NULL-terminated array of pointers iteration, as if it encounters a value that cannot be dereferenced the loop will break immediately.

)

idx = 0
Expand All @@ -199,6 +210,7 @@ def _get_sect_count(self, grp: interfaces.objects.ObjectInterface) -> int:

@functools.cached_property
def number_of_sections(self) -> int:
# Dropped in 6.14-rc1: d8959b947a8dfab1047c6fd5e982808f65717bfe
if self.sect_attrs.has_member("nsections"):
return self.sect_attrs.nsections

Expand All @@ -212,9 +224,7 @@ def get_sections(self) -> Iterable[interfaces.objects.ObjectInterface]:
symbol_table_name + constants.BANG + "array",
layer_name=self.vol.layer_name,
offset=self.sect_attrs.attrs.vol.offset,
subtype=self._context.symbol_space.get_type(
symbol_table_name + constants.BANG + "module_sect_attr"
),
subtype=self.sect_attrs.attrs.vol.subtype,
count=self.number_of_sections,
)

Expand Down Expand Up @@ -3165,3 +3175,20 @@ def get_name(self) -> Optional[str]:
)

return None


class bin_attribute(objects.StructType):
def get_name(self) -> Optional[str]:
"""
Performs extraction of the bin_attribute name
"""
if hasattr(self, "attr"):
try:
return utility.pointer_to_string(self.attr.name, count=32)
except exceptions.InvalidAddressException:
vollog.debug(
f"Invalid attr name for bin_attribute at {self.vol.offset:#x}"
)
return None

return None
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
class ModuleExtract(interfaces.configuration.VersionableInterface):
"""Extracts Linux kernel module structures into an analyzable ELF file"""

_version = (1, 0, 0)
_version = (1, 0, 1)
_required_framework_version = (2, 25, 0)

framework.require_interface_version(*_required_framework_version)
Expand All @@ -60,9 +60,14 @@ def _get_module_section_count(
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=grp.attrs,
offset=arr_offset,
sub_type=kernel.get_type("pointer"),
count=50,
absolute=True,
Expand Down
Loading