aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86_64
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86_64')
-rw-r--r--arch/x86_64/kernel/kprobes.c62
1 files changed, 55 insertions, 7 deletions
diff --git a/arch/x86_64/kernel/kprobes.c b/arch/x86_64/kernel/kprobes.c
index 218e015c3195..accbff3fec49 100644
--- a/arch/x86_64/kernel/kprobes.c
+++ b/arch/x86_64/kernel/kprobes.c
@@ -37,10 +37,12 @@
37#include <linux/string.h> 37#include <linux/string.h>
38#include <linux/slab.h> 38#include <linux/slab.h>
39#include <linux/preempt.h> 39#include <linux/preempt.h>
40#include <linux/module.h>
40 41
41#include <asm/cacheflush.h> 42#include <asm/cacheflush.h>
42#include <asm/pgtable.h> 43#include <asm/pgtable.h>
43#include <asm/kdebug.h> 44#include <asm/kdebug.h>
45#include <asm/uaccess.h>
44 46
45void jprobe_return_end(void); 47void jprobe_return_end(void);
46static void __kprobes arch_copy_kprobe(struct kprobe *p); 48static void __kprobes arch_copy_kprobe(struct kprobe *p);
@@ -578,16 +580,62 @@ int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr)
578{ 580{
579 struct kprobe *cur = kprobe_running(); 581 struct kprobe *cur = kprobe_running();
580 struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); 582 struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
583 const struct exception_table_entry *fixup;
581 584
582 if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr)) 585 switch(kcb->kprobe_status) {
583 return 1; 586 case KPROBE_HIT_SS:
584 587 case KPROBE_REENTER:
585 if (kcb->kprobe_status & KPROBE_HIT_SS) { 588 /*
586 resume_execution(cur, regs, kcb); 589 * We are here because the instruction being single
590 * stepped caused a page fault. We reset the current
591 * kprobe and the rip points back to the probe address
592 * and allow the page fault handler to continue as a
593 * normal page fault.
594 */
595 regs->rip = (unsigned long)cur->addr;
587 regs->eflags |= kcb->kprobe_old_rflags; 596 regs->eflags |= kcb->kprobe_old_rflags;
588 597 if (kcb->kprobe_status == KPROBE_REENTER)
589 reset_current_kprobe(); 598 restore_previous_kprobe(kcb);
599 else
600 reset_current_kprobe();
590 preempt_enable_no_resched(); 601 preempt_enable_no_resched();
602 break;
603 case KPROBE_HIT_ACTIVE:
604 case KPROBE_HIT_SSDONE:
605 /*
606 * We increment the nmissed count for accounting,
607 * we can also use npre/npostfault count for accouting
608 * these specific fault cases.
609 */
610 kprobes_inc_nmissed_count(cur);
611
612 /*
613 * We come here because instructions in the pre/post
614 * handler caused the page_fault, this could happen
615 * if handler tries to access user space by
616 * copy_from_user(), get_user() etc. Let the
617 * user-specified handler try to fix it first.
618 */
619 if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr))
620 return 1;
621
622 /*
623 * In case the user-specified fault handler returned
624 * zero, try to fix up.
625 */
626 fixup = search_exception_tables(regs->rip);
627 if (fixup) {
628 regs->rip = fixup->fixup;
629 return 1;
630 }
631
632 /*
633 * fixup() could not handle it,
634 * Let do_page_fault() fix it.
635 */
636 break;
637 default:
638 break;
591 } 639 }
592 return 0; 640 return 0;
593} 641}