diff options
Diffstat (limited to 'kernel/kprobes.c')
-rw-r--r-- | kernel/kprobes.c | 60 |
1 files changed, 30 insertions, 30 deletions
diff --git a/kernel/kprobes.c b/kernel/kprobes.c index 5016bfb682b9..a55bfadfd766 100644 --- a/kernel/kprobes.c +++ b/kernel/kprobes.c | |||
@@ -518,20 +518,20 @@ static inline void copy_kprobe(struct kprobe *old_p, struct kprobe *p) | |||
518 | } | 518 | } |
519 | 519 | ||
520 | /* | 520 | /* |
521 | * Add the new probe to old_p->list. Fail if this is the | 521 | * Add the new probe to ap->list. Fail if this is the |
522 | * second jprobe at the address - two jprobes can't coexist | 522 | * second jprobe at the address - two jprobes can't coexist |
523 | */ | 523 | */ |
524 | static int __kprobes add_new_kprobe(struct kprobe *old_p, struct kprobe *p) | 524 | static int __kprobes add_new_kprobe(struct kprobe *ap, struct kprobe *p) |
525 | { | 525 | { |
526 | if (p->break_handler) { | 526 | if (p->break_handler) { |
527 | if (old_p->break_handler) | 527 | if (ap->break_handler) |
528 | return -EEXIST; | 528 | return -EEXIST; |
529 | list_add_tail_rcu(&p->list, &old_p->list); | 529 | list_add_tail_rcu(&p->list, &ap->list); |
530 | old_p->break_handler = aggr_break_handler; | 530 | ap->break_handler = aggr_break_handler; |
531 | } else | 531 | } else |
532 | list_add_rcu(&p->list, &old_p->list); | 532 | list_add_rcu(&p->list, &ap->list); |
533 | if (p->post_handler && !old_p->post_handler) | 533 | if (p->post_handler && !ap->post_handler) |
534 | old_p->post_handler = aggr_post_handler; | 534 | ap->post_handler = aggr_post_handler; |
535 | return 0; | 535 | return 0; |
536 | } | 536 | } |
537 | 537 | ||
@@ -544,6 +544,7 @@ static inline void add_aggr_kprobe(struct kprobe *ap, struct kprobe *p) | |||
544 | copy_kprobe(p, ap); | 544 | copy_kprobe(p, ap); |
545 | flush_insn_slot(ap); | 545 | flush_insn_slot(ap); |
546 | ap->addr = p->addr; | 546 | ap->addr = p->addr; |
547 | ap->flags = p->flags; | ||
547 | ap->pre_handler = aggr_pre_handler; | 548 | ap->pre_handler = aggr_pre_handler; |
548 | ap->fault_handler = aggr_fault_handler; | 549 | ap->fault_handler = aggr_fault_handler; |
549 | /* We don't care the kprobe which has gone. */ | 550 | /* We don't care the kprobe which has gone. */ |
@@ -566,44 +567,43 @@ static int __kprobes register_aggr_kprobe(struct kprobe *old_p, | |||
566 | struct kprobe *p) | 567 | struct kprobe *p) |
567 | { | 568 | { |
568 | int ret = 0; | 569 | int ret = 0; |
569 | struct kprobe *ap; | 570 | struct kprobe *ap = old_p; |
570 | 571 | ||
571 | if (kprobe_gone(old_p)) { | 572 | if (old_p->pre_handler != aggr_pre_handler) { |
573 | /* If old_p is not an aggr_probe, create new aggr_kprobe. */ | ||
574 | ap = kzalloc(sizeof(struct kprobe), GFP_KERNEL); | ||
575 | if (!ap) | ||
576 | return -ENOMEM; | ||
577 | add_aggr_kprobe(ap, old_p); | ||
578 | } | ||
579 | |||
580 | if (kprobe_gone(ap)) { | ||
572 | /* | 581 | /* |
573 | * Attempting to insert new probe at the same location that | 582 | * Attempting to insert new probe at the same location that |
574 | * had a probe in the module vaddr area which already | 583 | * had a probe in the module vaddr area which already |
575 | * freed. So, the instruction slot has already been | 584 | * freed. So, the instruction slot has already been |
576 | * released. We need a new slot for the new probe. | 585 | * released. We need a new slot for the new probe. |
577 | */ | 586 | */ |
578 | ret = arch_prepare_kprobe(old_p); | 587 | ret = arch_prepare_kprobe(ap); |
579 | if (ret) | 588 | if (ret) |
589 | /* | ||
590 | * Even if fail to allocate new slot, don't need to | ||
591 | * free aggr_probe. It will be used next time, or | ||
592 | * freed by unregister_kprobe. | ||
593 | */ | ||
580 | return ret; | 594 | return ret; |
581 | } | 595 | /* Clear gone flag to prevent allocating new slot again. */ |
582 | if (old_p->pre_handler == aggr_pre_handler) { | 596 | ap->flags &= ~KPROBE_FLAG_GONE; |
583 | copy_kprobe(old_p, p); | ||
584 | ret = add_new_kprobe(old_p, p); | ||
585 | ap = old_p; | ||
586 | } else { | ||
587 | ap = kzalloc(sizeof(struct kprobe), GFP_KERNEL); | ||
588 | if (!ap) { | ||
589 | if (kprobe_gone(old_p)) | ||
590 | arch_remove_kprobe(old_p); | ||
591 | return -ENOMEM; | ||
592 | } | ||
593 | add_aggr_kprobe(ap, old_p); | ||
594 | copy_kprobe(ap, p); | ||
595 | ret = add_new_kprobe(ap, p); | ||
596 | } | ||
597 | if (kprobe_gone(old_p)) { | ||
598 | /* | 597 | /* |
599 | * If the old_p has gone, its breakpoint has been disarmed. | 598 | * If the old_p has gone, its breakpoint has been disarmed. |
600 | * We have to arm it again after preparing real kprobes. | 599 | * We have to arm it again after preparing real kprobes. |
601 | */ | 600 | */ |
602 | ap->flags &= ~KPROBE_FLAG_GONE; | ||
603 | if (kprobe_enabled) | 601 | if (kprobe_enabled) |
604 | arch_arm_kprobe(ap); | 602 | arch_arm_kprobe(ap); |
605 | } | 603 | } |
606 | return ret; | 604 | |
605 | copy_kprobe(ap, p); | ||
606 | return add_new_kprobe(ap, p); | ||
607 | } | 607 | } |
608 | 608 | ||
609 | static int __kprobes in_kprobes_functions(unsigned long addr) | 609 | static int __kprobes in_kprobes_functions(unsigned long addr) |