Question

I am trying to hook some kernel function for learning purpose, I wrote the simple kernel module below, but for some reasons, the register_kprobe always returns -2. I didn't find nothing about what it says what this error means and have no idea how to continue. At first I thought it is because list_add is an inline function, so I tried replacing it with kvm_create_vm and got the same result. Then I checked the /proc/kallsyms and found that both don't appear there. So I chose kvm_alloc which is exported, and still I get error -2. I also tried alloc_uid but this worked just fine.

My question: What kind of functions can be hooked with kprobes?

#undef __KERNEL__
#define __KERNEL__

#undef MODULE
#define MODULE

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/kprobes.h>
#include <linux/ptrace.h>

MODULE_LICENSE("GPL");

static int pre(struct kprobe *kp, struct pt_regs *regs){
    printk(KERN_INFO "It is working!\n");
    return 0;
}

static struct kprobe kp = {
    .symbol_name = "list_add",
    .pre_handler = pre,
    .post_handler = NULL,
    .fault_handler = NULL
};

int init_module(void){
    printk(KERN_INFO "Hi\n");
    printk(KERN_INFO "register_kprobe: %d\n" , register_kprobe(&kp));
    return 0;
}

void cleanup_module(void){
    unregister_kprobe(&kp);
    printk(KERN_INFO "Bye\n");
}

Edit

The line I stroked through was the main reason I got confused. I miss spelled kvm_alloc, it should be kvmalloc without the underscore. And this function got hooked just fine.

Was it helpful?

Solution 2

A negative return value can usually be interpreted as a negated errno value. Have a look at http://www.virtsync.com/c-error-codes-include-errno or so:

#define ENOENT       2  /* No such file or directory */

So the problem seems to be that register_kprobe could not find something, probably the list_add symbol. Let's dig into the source to figure out why it is that way.

register_kprobe calls kprobe_addr to resolve the symbol name, which in turn calls kprobe_lookup_name, which is a #define for kallsyms_lookup_name. So it seems that you need to get the symbol you want to hook into kallsyms for this to work.

For documentation about kprobes, have a look at Documentation/kprobes.txt in the kernel source tree. About kprobe'ing inline functions, it says:

If you install a probe in an inline-able function, Kprobes makes no attempt to chase down all inline instances of the function and install probes there. gcc may inline a function without being asked, so keep this in mind if you're not seeing the probe hits you expect.

So, it doesn't really work for inlined functions.

Now that we have figured out the problems, let's look for solutions. You'll probably need to recompile your kernel for this though.

First, make sure that the kernel configuration option CONFIG_KALLSYMS_ALL is turned on – that makes sure that kallsyms knows about more symbols. Then, try moving the implementation of list_add into a seperate .c file and adding __attribute__ ((noinline)) to it. That new kernel build is going to be slower, but I think that your kprobe module should work with it.

OTHER TIPS

To probe inlined functions, you need to find all the PC addresses at which their inlined instances live, and plop those addresses into the struct kprobes .addr field. A tool such as systemtap searches DWARF debuginfo for such inlined functions to compute PC addresses. See readelf -w vmlinux; DW_TAG_inlined_subroutine, DW_AT_low_pc etc.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top