Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

jprobes: make jprobes a little safer for users

I realise jprobes are a razor-blades-included type of interface, but that
doesn't mean we can't try and make them safer to use. This guy I know once
wrote code like this:

struct jprobe jp = { .kp.symbol_name = "foo", .entry = "jprobe_foo" };

And then his kernel exploded. Oops.

This patch adds an arch hook, arch_deref_entry_point() (I don't like it
either) which takes the void * in a struct jprobe, and gives back the text
address that it represents.

We can then use that in register_jprobe() to check that the entry point we're
passed is actually in the kernel text, rather than just some random value.

Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
Cc: Prasanna S Panchamukhi <prasanna@in.ibm.com>
Acked-by: Ananth N Mavinakayanahalli <ananth@in.ibm.com>
Cc: Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
Cc: David S. Miller <davem@davemloft.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Michael Ellerman and committed by
Linus Torvalds
3d7e3382 9e367d85

+24 -4
+6 -1
arch/ia64/kernel/kprobes.c
··· 936 936 return; 937 937 } 938 938 939 + unsigned long arch_deref_entry_point(void *entry) 940 + { 941 + return ((struct fnptr *)entry)->ip; 942 + } 943 + 939 944 int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) 940 945 { 941 946 struct jprobe *jp = container_of(p, struct jprobe, kp); 942 - unsigned long addr = ((struct fnptr *)(jp->entry))->ip; 947 + unsigned long addr = arch_deref_entry_point(jp->entry); 943 948 struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); 944 949 struct param_bsp_cfm pa; 945 950 int bytes;
+8 -3
arch/powerpc/kernel/kprobes.c
··· 492 492 return ret; 493 493 } 494 494 495 + #ifdef CONFIG_PPC64 496 + unsigned long arch_deref_entry_point(void *entry) 497 + { 498 + return (unsigned long)(((func_descr_t *)entry)->entry); 499 + } 500 + #endif 501 + 495 502 int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) 496 503 { 497 504 struct jprobe *jp = container_of(p, struct jprobe, kp); ··· 507 500 memcpy(&kcb->jprobe_saved_regs, regs, sizeof(struct pt_regs)); 508 501 509 502 /* setup return addr to the jprobe handler routine */ 503 + regs->nip = arch_deref_entry_point(jp->entry); 510 504 #ifdef CONFIG_PPC64 511 - regs->nip = (unsigned long)(((func_descr_t *)jp->entry)->entry); 512 505 regs->gpr[2] = (unsigned long)(((func_descr_t *)jp->entry)->toc); 513 - #else 514 - regs->nip = (unsigned long)jp->entry; 515 506 #endif 516 507 517 508 return 1;
+1
include/linux/kprobes.h
··· 214 214 int register_jprobe(struct jprobe *p); 215 215 void unregister_jprobe(struct jprobe *p); 216 216 void jprobe_return(void); 217 + unsigned long arch_deref_entry_point(void *); 217 218 218 219 int register_kretprobe(struct kretprobe *rp); 219 220 void unregister_kretprobe(struct kretprobe *rp);
+9
kernel/kprobes.c
··· 675 675 .priority = 0x7fffffff /* we need to be notified first */ 676 676 }; 677 677 678 + unsigned long __weak arch_deref_entry_point(void *entry) 679 + { 680 + return (unsigned long)entry; 681 + } 678 682 679 683 int __kprobes register_jprobe(struct jprobe *jp) 680 684 { 685 + unsigned long addr = arch_deref_entry_point(jp->entry); 686 + 687 + if (!kernel_text_address(addr)) 688 + return -EINVAL; 689 + 681 690 /* Todo: Verify probepoint is a function entry point */ 682 691 jp->kp.pre_handler = setjmp_pre_handler; 683 692 jp->kp.break_handler = longjmp_break_handler;