register_kprobe() returns EINVAL 在包含结构时没有额外的内存

register_kprobe() returns EINVAL without additional memory on containing struct

我写了一个内核模块(一个字符设备),每当我写入模块时它都会注册新的 KProbes。

我有一个包含 struct kprobe 的结构。当我调用 register_kprobe() 时,它 returns -EINVAL。但是当我向(可能还有一些其他数据类型)添加一个虚拟字符数组时,KProbe 注册成功。

探针注册

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`. */

不工作:

struct my_struct {
     struct kprobe probe;
}

工作:

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;
}

为什么结构中需要这个额外的内存位?

可能是否是未对齐的内存访问,但在这种特殊情况下(我指的是编辑前的原始代码)我怀疑数据未正确初始化。即,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);

因此,如果您确实初始化了 addr 而没有初始化 symbol_name,后者在某些情况下可能是垃圾指针。也就是说,kmalloc() 不会将分配的内存置零,此外,根据请求的大小,它可能会从不同的 中获取合适大小的内存对象(有不同的 pools 来提供不同大小的对象),当你人为地增加结构的大小时,kmalloc() 必须从一个合适的池中分配一个更大的对象。从这个角度来看,这样的对象 可能 偶尔不包含垃圾的可能性很大(因为大块请求的频率较低)。

总而言之,我建议将内存块归零或使用kzalloc()