I have been learning and experimenting with kernel probes(both kprobes and kretprobes) recently and today I managed to make it work for Ubuntu 22.04 kernel 5.x(which is the kernel I use on my development machine) and Debian 12.5 kernel 6.x which is a VM I have and it worked without any issue.
I started to check some older kernels 3.x and 4.x, so I installed CentOS 7 with kernel 3.10.0.1160.119.el7.x86_64…
This is where the problem start. First of all the naming of the syscalls was different in kernel 3.x. For example __x64_sys_getdents64
is now sys_getdents64
(there is also SyS_getdents64
I really don’t know the difference).
[user@localhost ~]$ cat /proc/kallsyms | grep getdents
0000000000000000 T SyS_getdents
0000000000000000 T sys_getdents
0000000000000000 T SyS_getdents64
0000000000000000 T sys_getdents64
0000000000000000 T compat_sys_getdents
0000000000000000 T compat_sys_getdents64
...
So I changed the code and installed the kretprobe on sys_getdents64
.
I could install kernel probes successfully according to the return address of register_kretprobe
but my handlers are not getting called. To narrow down the problem, I wrote a simplified version of my code,
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/kprobes.h>
static int entry_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
{
printk(KERN_INFO "entry_handler: getdents64 calledn");
return 0;
}
static int ret_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
{
printk(KERN_INFO "ret_handler: getdents64 returnedn");
return 0;
}
static struct kretprobe my_kretprobe = {
.handler = ret_handler,
.entry_handler = entry_handler,
.maxactive = 20,
};
static int __init kretprobe_init(void)
{
int ret;
my_kretprobe.kp.symbol_name = "sys_getdents64";
ret = register_kretprobe(&my_kretprobe);
if (ret < 0) {
printk(KERN_INFO "register_kretprobe failed, returned %dn", ret);
return -1;
}
printk(KERN_INFO "Planted return probe at %s: %pn",
my_kretprobe.kp.symbol_name, my_kretprobe.kp.addr);
return 0;
}
static void __exit kretprobe_exit(void)
{
unregister_kretprobe(&my_kretprobe);
printk(KERN_INFO "kretprobe at %p unregisteredn", my_kretprobe.kp.addr);
}
module_init(kretprobe_init)
module_exit(kretprobe_exit)
MODULE_LICENSE("GPL");
and building it with following Makefile,
obj-m += lkmtest.o
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 get the following output from the Makefile,
make
make -C /lib/modules/3.10.0-1160.119.1.el7.x86_64/build M=/home/user/test modules
make[1]: Entering directory `/usr/src/kernels/3.10.0-1160.119.1.el7.x86_64'
CC [M] /home/user/test/lkmtest.o
Building modules, stage 2.
MODPOST 1 modules
CC /home/user/test/lkmtest.mod.o
LD [M] /home/user/test/lkmtest.ko
make[1]: Leaving directory `/usr/src/kernels/3.10.0-1160.119.1.el7.x86_64'
after insmod lkmtest.ko
I do get the following confirmation in dmesg
[ 225.686827] Planted return probe at SyS_getdents64: ffffffffa3c722e0
But no matter what I do I don’t see the message in printk
of kretprobe handler! I tried ls
of different directories, run top
but no sign of any message from probe handler in dmesg
logs.
I don’t have any goal to make any product or something. I’m just using my free time at work to learn about linux kernel and linux kernel internals and experiment.
After trying different stuff to limit of my knowledge and some articles on the web I couldn’t spot the issue myself so I’m here to get some professional help.
Thanks,
Jelal