From: Jerome Marchand <jmarchan@redhat.com> Date: Tue, 29 Jul 2008 09:18:23 +0200 Subject: [misc] null pointer dereference in register_kretprobe Message-id: 488EC43F.9000106@redhat.com O-Subject: [RHEL5.3 Patch] Fix null pointer dereference in register_kretprobe() Bugzilla: 452308 RH-Acked-by: Chuck Ebbert <cebbert@redhat.com> RH-Acked-by: Neil Horman <nhorman@redhat.com> RH-Acked-by: Vitaly Mayatskikh <vmayatsk@redhat.com> RH-Acked-by: Anton Arapov <aarapov@redhat.com> Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=452308 Description: register_kretprobe() does not check that rp->kp.symbol_name is not NULL before calling kprobe_lookup_name() and thus leads to NULL pointer dereference. Upstream status: commit: b2a5cd6938879b5bcfef0a73c28fea84c49519c2 Brew build: http://brewweb.devel.redhat.com/brew/taskinfo?taskID=1406990 Test status: Build on all archs and tested on i686. Regards, Jerome diff --git a/kernel/kprobes.c b/kernel/kprobes.c index d744725..ac07f87 100644 --- a/kernel/kprobes.c +++ b/kernel/kprobes.c @@ -454,6 +454,23 @@ static int __kprobes in_kprobes_functions(unsigned long addr) return -EINVAL; return 0; } +/* +* If we have a symbol_name argument, look it up and add the offset field +* to it. This way, we can specify a relative address to a symbol. +*/ +static kprobe_opcode_t __kprobes *kprobe_addr(struct kprobe *p) +{ + kprobe_opcode_t *addr = p->addr; + if (p->symbol_name) { + if (addr) + return NULL; + kprobe_lookup_name(p->symbol_name, addr); + } + + if (!addr) + return NULL; + return (kprobe_opcode_t *)(((char *)addr) + p->offset); +} static int __kprobes __register_kprobe(struct kprobe *p, unsigned long called_from) @@ -461,21 +478,12 @@ static int __kprobes __register_kprobe(struct kprobe *p, int ret = 0; struct kprobe *old_p; struct module *probed_mod; + kprobe_opcode_t *addr; - /* - * If we have a symbol_name argument look it up, - * and add it to the address. That way the addr - * field can either be global or relative to a symbol. - */ - if (p->symbol_name) { - if (p->addr) - return -EINVAL; - kprobe_lookup_name(p->symbol_name, p->addr); - } - - if (!p->addr) + addr = kprobe_addr(p); + if (!addr) return -EINVAL; - p->addr = (kprobe_opcode_t *)(((char *)p->addr)+ p->offset); + p->addr = addr; if ((!kernel_text_address((unsigned long) p->addr)) || in_kprobes_functions((unsigned long) p->addr)) @@ -756,12 +764,12 @@ static int __kprobes __register_kretprobe(struct kretprobe *rp, int ret = 0; struct kretprobe_instance *inst; int i; - void *addr = rp->kp.addr; + void *addr; if (kretprobe_blacklist_size) { - if (addr == NULL) - kprobe_lookup_name(rp->kp.symbol_name, addr); - addr += rp->kp.offset; + addr = kprobe_addr(&rp->kp); + if (!addr) + return -EINVAL; for (i = 0; kretprobe_blacklist[i].name != NULL; i++) { if (kretprobe_blacklist[i].addr == addr)