I'm learning Linux Kernel programming and I'm learning kernel probes. I tried to install kprobe on getdents64()
syscall and read it's arguments but I always get -1
in the third argument, count. I tried different codes and searched and read several sources but couldn't find the solution.
Here is the prototype of getdents64()
syscall,
// https://elixir.bootlin.com/linux/latest/source/tools/include/nolibc/sys.h#L366
int getdents64(int fd, struct linux_dirent64 *dirp, int count)
Below is the output of /proc/kallsyms
,
user@xubun2204:~$ sudo grep getdents /proc/kallsyms
[sudo] password for user:
ffffffff955b7c70 T __ia32_compat_sys_getdents
ffffffff955b83c0 T __ia32_sys_getdents64
ffffffff955b84e0 T __ia32_sys_getdents
ffffffff955b8920 T __x64_compat_sys_getdents
ffffffff955b8a40 T __x64_sys_getdents64
ffffffff955b8b60 T __x64_sys_getdents
ffffffff9723f620 d event_exit__getdents64
ffffffff9723f6c0 d event_enter__getdents64
ffffffff9723f760 d __syscall_meta__getdents64
ffffffff9723f7a0 d args__getdents64
ffffffff9723f7c0 d types__getdents64
ffffffff9723f7e0 d event_exit__getdents
ffffffff9723f880 d event_enter__getdents
ffffffff9723f920 d __syscall_meta__getdents
ffffffff9723f960 d args__getdents
ffffffff9723f980 d types__getdents
ffffffff97702f00 d __event_exit__getdents64
ffffffff97702f08 d __event_enter__getdents64
ffffffff97702f10 d __event_exit__getdents
ffffffff97702f18 d __event_enter__getdents
ffffffff977059a8 d __p_syscall_meta__getdents64
ffffffff977059b0 d __p_syscall_meta__getdents
ffffffff97708fb0 d _eil_addr___x64_compat_sys_getdents
ffffffff97708fc0 d _eil_addr___ia32_compat_sys_getdents
ffffffff97708ff0 d _eil_addr___ia32_sys_getdents64
ffffffff97709000 d _eil_addr___x64_sys_getdents64
ffffffff97709010 d _eil_addr___ia32_sys_getdents
ffffffff97709020 d _eil_addr___x64_sys_getdents
and below is part of my code,
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/kprobes.h>
#include <linux/unistd.h>
static struct kprobe kp;
static int handler_pre(struct kprobe *p, struct pt_regs *regs)
{
// Access the third argument of the getdents64 syscall on x86_64
unsigned long count = regs->dx;
printk("kprobe: getdents64 called with count = %ld\n", count);
return 0;
}
static int __init kprobe_init(void)
{
kp.pre_handler = handler_pre;
kp.symbol_name = "__x64_sys_getdents64";
if (register_kprobe(&kp) < 0) {
printk("register_kprobe failed\n");
return -1;
}
printk("kprobe registered\n");
return 0;
}
static void __exit kprobe_exit(void)
{
unregister_kprobe(&kp);
printk("kprobe unregistered\n");
}
module_init(kprobe_init)
module_exit(kprobe_exit)
MODULE_LICENSE("GPL");
I'm building it with the following Makefile,
obj-m += hidproc.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
After building the project I load it with insmod and then check the kernel logs,
# insmod hidproc.ko
# tail -f /var/log/kern.log
kprobe registered
kprobe: getdents64 called with count = -1
kprobe: getdents64 called with count = -1
kprobe: getdents64 called with count = -1
kprobe: getdents64 called with count = -1
kprobe: getdents64 called with count = -1
kprobe: getdents64 called with count = -1
kprobe: getdents64 called with count = -1
kprobe: getdents64 called with count = -1
kprobe unregistered
Finally I'm running XUbuntu 22.04 running Linux xubun2204 5.15.0-107-generic #117-Ubuntu SMP Fri Apr 26 12:26:49 UTC 2024 x86_64 x86_64 x86_64 GNU/Linux
.
How can I hook into a Linux syscall with kprobe and successfully read the arguments? The third argument is an integer and should be passed by value.
I tried to think of anything I could provide to have a good an acceptable question by the community and up to stackoverflow standards, if there is any shortcoming please let me know.
Thank you
@Luke's answer was correct. You need to dereference the second pt_struct that is passed to the probe handler for syscall arguments.
unsigned long count = ((struct pt_regs*)regs->di)->dx;
I tried this on Ubuntu 22.04 and 24.04 with kernel 5.x and 6.x and worked fine.
Thanks