Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Linux adds hlist_head object extension #1314

Conversation

gcmoreira
Copy link
Contributor

@gcmoreira gcmoreira commented Oct 14, 2024

The primary goal of this PR is to fix issue #1313 for kernels version 6.8 and above. However, to achieve this, two additional fixes are also required.

Module.object() fix

Additionally, this PR includes a fix for Module.object() which doesn't allow to create an object even if the symbol type name is from the same symbol table, see here. That makes linux.LinuxUtilities.container_of() to fail when it's called from some places. Additionally, it's inconsistent with other functions that allow the use of the same symbol name even when they are called from the same object.

>>> self.context.symbol_space.get_type('symbol_table_name1!dentry')
<volatility3.framework.objects.templates.ObjectTemplate object at 0x71c7328074c0>

>>> vmlinux.get_type('symbol_table_name1!dentry')
<volatility3.framework.objects.templates.ObjectTemplate object at 0x71c7328074c0>

>>> vmlinux.object(object_type='symbol_table_name1!dentry', offset=container_addr, absolute=True)
Traceback (most recent call last):
...
    raise ValueError(
ValueError: Cannot reference another module when constructing an object

So, Module.object() only works if it's called with only the symbol name i.e. dentry and it creates the full names here:

object_type = self.symbol_table_name + constants.BANG + object_type

But if it's already called with the full symbol name, it fails:

>>> object_type
'symbol_table_name1!dentry'

>>> self.symbol_table_name
'symbol_table_name1'

On the other hand, the exception message doesn’t seem to accurately reflect what it’s checking. It talks about "module" when it's checking the symbol table name. Is this correct @ikelos?

        if constants.BANG not in object_type:
            object_type = self.symbol_table_name + constants.BANG + object_type
        else:
            raise ValueError(
                "Cannot reference another module when constructing an object"
            )

hlist_head object extension

This PR adds a hlist_head object extension that other Linux plugins can benefit from. This resolves issue #1313.

$ python3 ./vol.py \
   -f ./ubuntu2404amd64_6.8.0-41.core \
    linux.pagecache.Files 
Volatility 3 Framework 2.11.0
SuperblockAddr  MountPoint      Device  InodeNum        InodeAddr       FileType        InodePages      CachedPages     FileMode        AccessTime      ModificationTime        ChangeTime      FilePath

0x91f7812e1800  /sys/kernel/security    0:6     1       0x91f781405680  DIR     0       0       drwxr-xr-x      2024-09-18 06:10:26.296421 UTC  2024-09-18 06:10:26.296421 UTC  2024-09-18 06:10:26.296421 UTC  /sys/kernel/security
0x91f7812e1800  /sys/kernel/security    0:6     2431    0x91f783ace780  LNK     0       0       lr--r--r--      2024-09-18 06:10:26.661000 UTC  2024-09-18 06:10:26.661000 UTC  2024-09-18 06:10:26.661000 UTC  /sys/kernel/security/evm -> integrity/evm/evm
0x91f7812e1800  /sys/kernel/security    0:6     2423    0x91f783aa8280  LNK     0       0       lr--r--r--      2024-09-18 06:10:27.828000 UTC  2024-09-18 06:10:26.653000 UTC  2024-09-18 06:10:26.653000 UTC  /sys/kernel/security/ima -> integrity/ima
0x91f7812e1800  /sys/kernel/security    0:6     2421    0x91f783aa9b80  DIR     0       0       drwxr-xr-x      2024-09-18 06:10:26.646000 UTC  2024-09-18 06:10:26.646000 UTC  2024-09-18 06:10:26.646000 UTC  /sys/kernel/security/integrity
0x91f7812e1800  /sys/kernel/security    0:6     2429    0x91f783aa9180  DIR     0       0       drwxr-xr-x      2024-09-18
...

Please, read my comment here:

    This is a doubly linked list; however, it is not circular, so the 'forward' field
    doesn't make sense. Also, the sentinel concept doesn't make sense here either;
    unlike list_head, the head and nodes each have their own distinct types. A list_head
    cannot be a node by itself.

Please avoid adding a forward or sentinel arguments! This list is not designed to be traversed in reverse order. Finding the tail requires O(n).

@ikelos
Copy link
Member

ikelos commented Oct 22, 2024

I think the idea was, that you couldn't ask the module for a fully qualified name, because it should only be returning objects that belong to the module. There should be an additional check that allows constants.BANG as long as it's prepended with the same symbol table name as the module's symbol table.

@ikelos
Copy link
Member

ikelos commented Oct 22, 2024

Seems an awfully strange doubly-linked list, if the links go in crazy directions, but ok, thanks for the heads-up! 5:P

Copy link
Member

@ikelos ikelos left a comment

Choose a reason for hiding this comment

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

Just want to check where member_name comes from but otherwise looks ok?

@@ -245,7 +245,7 @@ def object(
"""
if constants.BANG not in object_type:
object_type = self.symbol_table_name + constants.BANG + object_type
else:
elif not object_type.startswith(self.symbol_table_name + constants.BANG):
Copy link
Member

Choose a reason for hiding this comment

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

Yep, this is probably what it should always have been, sorry I didn't include it first time round!

current = current.next

def __iter__(self) -> Iterator[interfaces.objects.ObjectInterface]:
return self.to_list(self.vol.parent.vol.type_name, self.vol.member_name)
Copy link
Member

Choose a reason for hiding this comment

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

Is member_name defined as part of the type when an hlist_head is constructed? I'm just interested to know what populates this value and what happens if it's not present? This feels a little brittle at the moment...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Unfortunately, it's not. See the contructors here: https://elixir.bootlin.com/linux/v6.11.4/source/include/linux/list.h#L939.
The type is based on the destination variable type in the foreach preprocessor macros here: https://elixir.bootlin.com/linux/v6.11.4/source/include/linux/list.h#L1162

Copy link
Member

Choose a reason for hiding this comment

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

Sooooo, how then does it get into the object's vol dict? 5:)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

oh, sorry, I thought you were talking the struct in the kernel.
Yes, you are right.. good catch! I removed this object's ability to be directly iterable. It needs to be called via to_list() to provide the correct member_name.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

hm I think the same happens with the list_head objects. It requires to explicitly set a member_name, not sure if it's used directly as an iterator somewhere, maybe that's why it never failed.

@ikelos ikelos linked an issue Oct 22, 2024 that may be closed by this pull request
@gcmoreira
Copy link
Contributor Author

Seems an awfully strange doubly-linked list, if the links go in crazy directions, but ok, thanks for the heads-up! 5:P

Hehe, yeah it's an "optimization" to save one pointer in the head... quite a fine-tuned detail, right? :) ... see this comment here:
https://elixir.bootlin.com/linux/v6.11.4/source/include/linux/list.h#L933

In the following sentence they make it clear it's not circular (apart from that they don't mention it).

You lose the ability to access the tail in O(1).

On the other hand, see the description of a circular doubly linked list (list_head):
https://elixir.bootlin.com/linux/v6.11.4/source/include/linux/list.h#L14

…e it can't determine the correct member_name
Copy link
Member

@ikelos ikelos left a comment

Choose a reason for hiding this comment

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

Ok, looks good, thanks! 5:)

@ikelos ikelos merged commit 1500d2e into volatilityfoundation:develop Oct 22, 2024
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Linux: pagecache broken on kernel versions >= 6.8
3 participants