Add command to display information about kernel modules (#3106)

* merge conflicts

* Fix lint errors

* fix test

* requested changes

* Fix lint errors

* Fix lint errors
pull/3128/head
Allen Chang 6 months ago committed by GitHub
parent dc46ade886
commit 8bddb3d40f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -77,6 +77,7 @@
- [kconfig](kernel/kconfig.md) - Outputs the kernel config (requires CONFIG_IKCONFIG).
- [kdmesg](kernel/kdmesg.md) - Displays the kernel ring buffer (dmesg) contents.
- [klookup](kernel/klookup.md) - Lookup kernel symbols
- [kmod](kernel/kmod.md) - Displays the loaded Linux kernel modules.
- [knft-dump](kernel/knft-dump.md) - Dump all nftables: tables, chains, rules, expressions
- [knft-list-chains](kernel/knft-list-chains.md) - Dump netfilter chains form a specific table
- [knft-list-exprs](kernel/knft-list-exprs.md) - Dump only expressions from specific rule

@ -0,0 +1,23 @@
<!-- THIS PART OF THIS FILE IS AUTOGENERATED. DO NOT MODIFY IT. See scripts/generate-docs.sh -->
# kmod
```text
usage: kmod [-h] [module_name]
```
Displays the loaded Linux kernel modules.
### Positional arguments
|Positional Argument|Help|
| :--- | :--- |
|module_name|A module name substring to filter for|
### Optional arguments
|Short|Long|Help|
| :--- | :--- | :--- |
|-h|--help|show this help message and exit|
<!-- END OF AUTOGENERATED PART. Do not modify this line or the line below, they mark the end of the auto-generated part of the file. If you want to extend the documentation in a way which cannot easily be done by adding to the command help description, write below the following line. -->
<!-- ------------\>8---- ----\>8---- ----\>8------------ -->

@ -909,6 +909,7 @@ def load_commands() -> None:
import pwndbg.commands.kconfig
import pwndbg.commands.kdmesg
import pwndbg.commands.klookup
import pwndbg.commands.kmod
import pwndbg.commands.knft
import pwndbg.commands.ktask
import pwndbg.commands.kversion

@ -0,0 +1,61 @@
"""
Displays information about loaded kernel modules. This command retrieves the list of kernel modules from the `modules` symbol
and displays information about each module. It can filter modules by a substring of their names if provided.
"""
from __future__ import annotations
import argparse
from tabulate import tabulate
import pwndbg.commands
from pwndbg.aglib.kernel.macros import for_each_entry
parser = argparse.ArgumentParser(description="Displays the loaded Linux kernel modules.")
parser.add_argument(
"module_name", nargs="?", type=str, help="A module name substring to filter for"
)
@pwndbg.commands.Command(parser, category=pwndbg.commands.CommandCategory.KERNEL)
@pwndbg.commands.OnlyWhenQemuKernel
@pwndbg.commands.OnlyWhenPagingEnabled
@pwndbg.commands.OnlyWithKernelDebugSyms
def kmod(module_name=None) -> None:
# Look up the address of the `modules` symbol, containing the head of the linked list of kernel modules
modules_head = pwndbg.aglib.symbol.lookup_symbol_addr("modules")
if modules_head is None:
print(
"The modules symbol was not found. This may indicate that the symbol is not available in the current build."
)
return
print(f"Kernel modules address found at {modules_head:#x}.\n")
try:
table = []
headers = ["Address", "Name", "Size", "Used by"]
head = pwndbg.aglib.memory.get_typed_pointer_value("struct list_head", modules_head)
# Iterate through the linked list of modules using for_each_entry
for module in for_each_entry(head, "struct module", "list"):
addr = int(module["mem"][0]["base"])
name = pwndbg.aglib.memory.string(int(module["name"].address)).decode(
"utf-8", errors="ignore"
)
# Calculate runtime memory footprint by summing sizes of MOD_TEXT, MOD_DATA, MOD_RODATA, MOD_RO_AFTER_INIT,
# which excludes initialization sections that are freed after the module load. See `enum mod_mem_type` in kernel source.
size = sum(int(module["mem"][i]["size"]) for i in range(4))
uses = int(module["refcnt"]["counter"]) - 1
# If module_name is provided, filter modules by name substring
if not module_name or module_name in name:
table.append([f"{addr:#x}", name, size, uses])
print(tabulate(table, headers=headers, tablefmt="simple"))
except Exception as e:
print(
f"An error occurred while retrieving kernel modules. It may not be supported by your kernel version or debug symbols: {e}"
)

@ -0,0 +1 @@
from __future__ import annotations

@ -48,6 +48,16 @@ def test_command_kdmesg():
)
def test_command_kmod():
if not pwndbg.aglib.kernel.has_debug_syms():
res = gdb.execute("kmod", to_string=True)
assert "may only be run when debugging a Linux kernel with debug" in res
return
res = gdb.execute("kmod", to_string=True)
assert "Kernel modules address found at" in res or "The modules symbol was not found." in res
def test_command_ktask():
if not pwndbg.aglib.kernel.has_debug_syms():
res = gdb.execute("ktask", to_string=True)

Loading…
Cancel
Save