clinuxlinux-kernelkprobe

can't kprobe "t" functions


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.


Solution

  • 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.