Kenpachi Kenpachi - 3 years ago 193
Linux Question

register_kprobe() returns EINVAL without additional memory on containing struct

I've written a kernel module (a character device) that registers new KProbes whenever I write to the module.

I have a structure that contains

struct kprobe
. When I call
register_kprobe()
, it returns
-EINVAL
. But when I add a dummy character array to the (possibly some other data types as well), the KProbe registration succeeds.

Probe Registration



struct my_struct *container = kmalloc(sizeof(struct my_struct));
(container->probe).addr = (kprobe_opcode_t *) kallsyms_lookup_name("my_exported_fn"); /* my_exported_fn is in code section */
(container->probe).pre_handler = Pre_Handler;
(container->probe).post_handler = Post_Handler;
register_probe(&container->probe);
/* Returns -EINVAL if my_struct contains only `struct kprobe`. */


Not working:



struct my_struct {
struct kprobe probe;
}


Working:



struct my_struct {
char dummy[512]; /* At 512, it gets consistently registered. At 256, sometimes (maybe one out of 5 - 10 times get registered) */
struct kprobe probe;
}


Why does it need this extra bit of memory to be present in the struct?

Answer Source

This could be unaligned memory access or not, but in this particular case (I mean your original code before the edit) I suspect that the data is not properly initialised. Namely, register_kprobe() calls kprobe_addr() function which in turn implies the following check:

if ((symbol_name && addr) || (!symbol_name && !addr))
    goto invalid;
...
invalid:
    return ERR_PTR(-EINVAL);

So, if you indeed initialise addr and don't initialise symbol_name, the latter could be a garbage pointer under certain circumstances. Namely, kmalloc() doesn't zeroise allocated memory and, furthermore, depending on requested size, it may take memory object of a suitable size from a different pool (there are different pools to provide objects of different sizes), and when you artificially increase the size of the struct, kmalloc() has to allocate a larger object from a suitable pool. From this perspective, the probability is that such an object may not contain garbage by occasion (since larger chunks are requested less often).

All in all, I suggest zeroising the memory chunk or using kzalloc().

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download