From: Ananth N Mavinakayanahalli Anil discovered that this patch has a case where, on powerpc, we potentially end up dereferencing a NULL pointer. I have fixed that part and updated the patch. In an effort to make kprobe modules more portable, here is a patch that: o Introduces the "symbol_name" field to struct kprobe. The symbol->address resolution now happens in the kernel in an architecture agnostic manner. o Introduces the "offset" field to struct kprobe to allow a user to specify an offset into a symbol. o The legacy mechanism of specifying the kprobe.addr is still supported. However, if both the kprobe.addr and kprobe.symbol_name are specified, probe registration fails with an -EINVAL. o The symbol resolution code uses kallsyms_lookup_name(). So CONFIG_KPROBES now depends on CONFIG_KALLSYMS o Apparantly kprobe modules were the only legitimate out-of-tree user of the kallsyms_lookup_name() EXPORT. Now that the symbol resolution happens in-kernel, remove the EXPORT as suggested by Christoph Hellwig o Modify tcp_probe.c that uses the kprobe interface so as to make it work on multiple platforms (in its earlier form, the code wouldn't work, say, on powerpc) Signed-off-by: Ananth N Mavinakayanahalli Signed-off-by: Prasanna S Panchamukhi Signed-off-by: Christoph Hellwig Signed-off-by: Anil S Keshavamurthy Signed-off-by: Andrew Morton --- include/asm-powerpc/kprobes.h | 16 ++++++++++++++-- kernel/kprobes.c | 6 +++--- 2 files changed, 17 insertions(+), 5 deletions(-) diff -puN include/asm-powerpc/kprobes.h~kprobes-make-kprobe-modules-more-portable-update include/asm-powerpc/kprobes.h --- a/include/asm-powerpc/kprobes.h~kprobes-make-kprobe-modules-more-portable-update +++ a/include/asm-powerpc/kprobes.h @@ -44,8 +44,20 @@ typedef unsigned int kprobe_opcode_t; #define IS_TDI(instr) (((instr) & 0xfc000000) == 0x08000000) #define IS_TWI(instr) (((instr) & 0xfc000000) == 0x0c000000) -#define kprobe_lookup_name(name) \ - (*((kprobe_opcode_t **)kallsyms_lookup_name(name))) +/* + * 64bit powerpc uses function descriptors. + * Handle cases where: + * - User passes a <.symbol> + * - User passes a + * - User passes a non-existant symbol, kallsyms_lookup_name + * returns 0. Don't deref the NULL pointer in that case + */ +#define kprobe_lookup_name(name, addr) \ +{ \ + addr = (kprobe_opcode_t *)kallsyms_lookup_name(name); \ + if (!(name[0] == '.') && addr) \ + addr = *(kprobe_opcode_t **)addr; \ +} #define JPROBE_ENTRY(pentry) (kprobe_opcode_t *)((func_descr_t *)pentry) diff -puN kernel/kprobes.c~kprobes-make-kprobe-modules-more-portable-update kernel/kprobes.c --- a/kernel/kprobes.c~kprobes-make-kprobe-modules-more-portable-update +++ a/kernel/kprobes.c @@ -52,8 +52,8 @@ * so this must be overridable. */ #ifndef kprobe_lookup_name -#define kprobe_lookup_name(name) \ - ((kprobe_opcode_t *)(kallsyms_lookup_name(name))) +#define kprobe_lookup_name(name, addr) \ + addr = ((kprobe_opcode_t *)(kallsyms_lookup_name(name))) #endif static struct hlist_head kprobe_table[KPROBE_TABLE_SIZE]; @@ -466,7 +466,7 @@ static int __kprobes __register_kprobe(s if (p->symbol_name) { if (p->addr) return -EINVAL; - p->addr = kprobe_lookup_name(p->symbol_name); + kprobe_lookup_name(p->symbol_name, p->addr); } if (!p->addr) _