I'm trying to install kprobes/kretprobes on some kernel functions from a LKM. In this case I tried following function, as you can see they are marked as t
in kallsyms
,
// Kernel version : 6.8.0-45-generic #45~22.04.1-Ubuntu SMP PREEMPT_DYNAMIC Wed Sep 11 15:25:05 UTC 2 x86_64 x86_64 x86_64 GNU/Linux
ffffffff99e64820 t kprobe_seq_start
ffffffff99e64850 t kprobe_seq_next
ffffffff99e64890 t kprobe_seq_stop
My code does work on kernel 5.x and 6.x kernels, but when tried on 3.x and 2.6.32+ the register_kprobe()
function return -22. Below is the output of kallsyms
in 3.x which remains the same down to 2.6.32.
// 3.10.0-1160.119.1.el7.x86_64 #1 SMP Tue Jun 4 14:43:51 UTC 2024 x86_64 x86_64 x86_64 GNU/Linux
[user@localhost ~]$ sudo cat /proc/kallsyms | grep kprobe_seq
ffffffffab7bfe70 t kprobe_seq_start
ffffffffab7bfe90 t kprobe_seq_next
ffffffffab7bfec0 t kprobe_seq_stop
The code that im trying is below,
#include <linux/kprobes.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/version.h>
static struct kretprobe kretseqnext =
{
.handler = kprobe_seq_ret_handler,
.kp.symbol_name = "...",
};
static int kprobe_seq_ret_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
{
set_return_value(regs, 0);
return 0;
}
static int __init kprobe_init(void)
{
int ret;
ret = register_kretprobe(&kretseqnext);
if (ret < 0) {
printk("Failed registering kretprobe kprobe_seq_next %d\n", ret);
return ret;
}
printk("Registering kprobe_seq_next\n");
return 0;
}
static void __exit kprobe_exit(void)
{
unregister_kretprobe(&kretseqnext);
printk("Unregistering kretprobe kprobe_seq_next\n");
}
And the Makefile,
obj-m += gap.o
KBUILD_CFLAGS += -Wno-unused-function
CCFLAG-y := -g -O3 -flto -march=native -mtune=native -fomit-frame-pointer -funroll-loops -finline-functions
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
I also tried to resolve the address of kprobe_seq_next()
and tried to set kprobe based on the address rather than the symbol name. But the result is still the same.
Linux kernel has special __kprobes
attribute for mark functions, which are not intended to be intercepted via kprobe mechanism. Different reasons could be behind such intention. E.g. intercepting a function which by itself implements the interception mechanism would lead to infinite recursion.
In the kernel 2.6.32 the function kprobe_seq_start
has __kprobes
mark (kernel/kprobes.c:1281):
static void __kprobes *kprobe_seq_start(struct seq_file *f, loff_t *pos)
so any attempt to intercept it automatically fails.