Skip to content

Instantly share code, notes, and snippets.

@aznashwan
Last active October 16, 2024 16:03
Show Gist options
  • Save aznashwan/32b8b00f0378e341ea29f80d0a4eca44 to your computer and use it in GitHub Desktop.
Save aznashwan/32b8b00f0378e341ea29f80d0a4eca44 to your computer and use it in GitHub Desktop.
bpftrace kfunc probe to log which process loaded a kernel module.
// Simple eBPF kfunc probe to log when any process loads a kernel module.
//
// Works by registering a probe on the `do_init_module` kernel function.
//
// Once installed, the probe will print lines of the format:
// NOTE: $CALLING_PROGRAM_ARGS will be delimited by hex-escaped null byte ('\x00') instead of spaces...
// $NANOSECONDS $USER_ID do_init_module("$MODULE_NAME"):
// $CALLING_PROCESS_PID $CALLING_PROGRAM_ARGS /
// $CALLING_CHILD_PROCESS_NAME($CHILD_PID)
// $CALLING_PARENT_1_PROCESS_NAME($PARENT1_PID)
// $CALLING_PARENT_2_PROCESS_NAME($PARENT2_PID)
// ... (up to 16 calls)
// NOTE: There are a handful of "higher-level" functions which load kernel
// modules, but all end up calling `do_init_module` (or its arch-specific
// equivalent) at some point or another.
// https://man7.org/linux/man-pages/man2/init_module.2.html
kfunc:do_init_module
{
// Cast argument to `struct module` (#include<linux/module.h>)
$mod = (struct module *) args->mod;
$modname = $mod->name;
printf("%llu\t%d\t do_init_module(%s):\n", nsecs, uid, $modname);
// Hackily extract and print full command line for calling process:
// https://github.com/bpftrace/bpftrace/discussions/2116#discussioncomment-1917982
$mm = curtask->mm;
$start = $mm->arg_start;
$end = $mm->arg_end;
// NOTE: args will be delimited by hex-escaped null bytes:
printf("%d %r\n", pid, buf(uptr($start), uptr($end-$start)));
// Hackily unwind `while($temptask->parent)` loop to avoid infinite loop accusations:
// https://stackoverflow.com/a/78699190/3241283
$temptask = curtask;
$t = 0;
while($t == 0)
{
// NOTE: break the "parent loop" if we reach PID1 (init) or PID0 (idle process):
if($temptask->pid <= 1) {break;} printf("\t%s(%d)\n", $temptask->comm, $temptask->pid); $temptask = $temptask->parent; // 1
if($temptask->pid <= 1) {break;} printf("\t%s(%d)\n", $temptask->comm, $temptask->pid); $temptask = $temptask->parent; // 2
if($temptask->pid <= 1) {break;} printf("\t%s(%d)\n", $temptask->comm, $temptask->pid); $temptask = $temptask->parent; // 3
if($temptask->pid <= 1) {break;} printf("\t%s(%d)\n", $temptask->comm, $temptask->pid); $temptask = $temptask->parent; // 4
if($temptask->pid <= 1) {break;} printf("\t%s(%d)\n", $temptask->comm, $temptask->pid); $temptask = $temptask->parent; // 5
if($temptask->pid <= 1) {break;} printf("\t%s(%d)\n", $temptask->comm, $temptask->pid); $temptask = $temptask->parent; // 6
if($temptask->pid <= 1) {break;} printf("\t%s(%d)\n", $temptask->comm, $temptask->pid); $temptask = $temptask->parent; // 7
if($temptask->pid <= 1) {break;} printf("\t%s(%d)\n", $temptask->comm, $temptask->pid); $temptask = $temptask->parent; // 8
if($temptask->pid <= 1) {break;} printf("\t%s(%d)\n", $temptask->comm, $temptask->pid); $temptask = $temptask->parent; // 9
if($temptask->pid <= 1) {break;} printf("\t%s(%d)\n", $temptask->comm, $temptask->pid); $temptask = $temptask->parent; // 10
if($temptask->pid <= 1) {break;} printf("\t%s(%d)\n", $temptask->comm, $temptask->pid); $temptask = $temptask->parent; // 11
if($temptask->pid <= 1) {break;} printf("\t%s(%d)\n", $temptask->comm, $temptask->pid); $temptask = $temptask->parent; // 12
if($temptask->pid <= 1) {break;} printf("\t%s(%d)\n", $temptask->comm, $temptask->pid); $temptask = $temptask->parent; // 13
if($temptask->pid <= 1) {break;} printf("\t%s(%d)\n", $temptask->comm, $temptask->pid); $temptask = $temptask->parent; // 14
if($temptask->pid <= 1) {break;} printf("\t%s(%d)\n", $temptask->comm, $temptask->pid); $temptask = $temptask->parent; // 15
printf("\n\t...");
$t=1;
}
printf("\n\n");
}
@aznashwan
Copy link
Author

Sample output after running modprobe serio_raw:

$ sudo bpftrace probe.bpf 
Attaching 1 probe...
1126360509116	0	 do_init_module(serio_raw):
5373 modprobe\x00serio_raw\x00
	modprobe(5373)
	sudo(5372)
	sudo(5371)
	bash(1030)
	sshd(1029)
	sshd(982)
	sshd(708)

...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment