diff options
author | Masami Hiramatsu <mhiramat@redhat.com> | 2008-03-04 17:29:44 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2008-03-04 19:35:19 -0500 |
commit | b2a5cd6938879b5bcfef0a73c28fea84c49519c2 (patch) | |
tree | e2039a9f7a4766dbea703c6ed32db881863efc1d /kernel | |
parent | 1913130553aa231644eb4e955b1a2c533fe33d17 (diff) |
kprobes: fix a null pointer bug in register_kretprobe()
Fix a bug in regiseter_kretprobe() which does not check rp->kp.symbol_name ==
NULL before calling kprobe_lookup_name.
For maintainability, this introduces kprobe_addr helper function which
resolves addr field. It is used by register_kprobe and register_kretprobe.
Signed-off-by: Masami Hiramatsu <mhiramat@redhat.com>
Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com>
Cc: Jim Keniston <jkenisto@us.ibm.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/kprobes.c | 43 |
1 files changed, 26 insertions, 17 deletions
diff --git a/kernel/kprobes.c b/kernel/kprobes.c index e6a61dcbc578..fcfb580c3afc 100644 --- a/kernel/kprobes.c +++ b/kernel/kprobes.c | |||
@@ -498,27 +498,36 @@ static int __kprobes in_kprobes_functions(unsigned long addr) | |||
498 | return 0; | 498 | return 0; |
499 | } | 499 | } |
500 | 500 | ||
501 | /* | ||
502 | * If we have a symbol_name argument, look it up and add the offset field | ||
503 | * to it. This way, we can specify a relative address to a symbol. | ||
504 | */ | ||
505 | static kprobe_opcode_t __kprobes *kprobe_addr(struct kprobe *p) | ||
506 | { | ||
507 | kprobe_opcode_t *addr = p->addr; | ||
508 | if (p->symbol_name) { | ||
509 | if (addr) | ||
510 | return NULL; | ||
511 | kprobe_lookup_name(p->symbol_name, addr); | ||
512 | } | ||
513 | |||
514 | if (!addr) | ||
515 | return NULL; | ||
516 | return (kprobe_opcode_t *)(((char *)addr) + p->offset); | ||
517 | } | ||
518 | |||
501 | static int __kprobes __register_kprobe(struct kprobe *p, | 519 | static int __kprobes __register_kprobe(struct kprobe *p, |
502 | unsigned long called_from) | 520 | unsigned long called_from) |
503 | { | 521 | { |
504 | int ret = 0; | 522 | int ret = 0; |
505 | struct kprobe *old_p; | 523 | struct kprobe *old_p; |
506 | struct module *probed_mod; | 524 | struct module *probed_mod; |
525 | kprobe_opcode_t *addr; | ||
507 | 526 | ||
508 | /* | 527 | addr = kprobe_addr(p); |
509 | * If we have a symbol_name argument look it up, | 528 | if (!addr) |
510 | * and add it to the address. That way the addr | ||
511 | * field can either be global or relative to a symbol. | ||
512 | */ | ||
513 | if (p->symbol_name) { | ||
514 | if (p->addr) | ||
515 | return -EINVAL; | ||
516 | kprobe_lookup_name(p->symbol_name, p->addr); | ||
517 | } | ||
518 | |||
519 | if (!p->addr) | ||
520 | return -EINVAL; | 529 | return -EINVAL; |
521 | p->addr = (kprobe_opcode_t *)(((char *)p->addr)+ p->offset); | 530 | p->addr = addr; |
522 | 531 | ||
523 | if (!kernel_text_address((unsigned long) p->addr) || | 532 | if (!kernel_text_address((unsigned long) p->addr) || |
524 | in_kprobes_functions((unsigned long) p->addr)) | 533 | in_kprobes_functions((unsigned long) p->addr)) |
@@ -721,12 +730,12 @@ int __kprobes register_kretprobe(struct kretprobe *rp) | |||
721 | int ret = 0; | 730 | int ret = 0; |
722 | struct kretprobe_instance *inst; | 731 | struct kretprobe_instance *inst; |
723 | int i; | 732 | int i; |
724 | void *addr = rp->kp.addr; | 733 | void *addr; |
725 | 734 | ||
726 | if (kretprobe_blacklist_size) { | 735 | if (kretprobe_blacklist_size) { |
727 | if (addr == NULL) | 736 | addr = kprobe_addr(&rp->kp); |
728 | kprobe_lookup_name(rp->kp.symbol_name, addr); | 737 | if (!addr) |
729 | addr += rp->kp.offset; | 738 | return -EINVAL; |
730 | 739 | ||
731 | for (i = 0; kretprobe_blacklist[i].name != NULL; i++) { | 740 | for (i = 0; kretprobe_blacklist[i].name != NULL; i++) { |
732 | if (kretprobe_blacklist[i].addr == addr) | 741 | if (kretprobe_blacklist[i].addr == addr) |