Skip to content

Commit b402651

Browse files
Prasanna S PanchamukhiLinus Torvalds
authored andcommitted
[PATCH] kprobes: fix broken fault handling for i386
Provide proper kprobes fault handling, if a user-specified pre/post handlers tries to access user address space, through copy_from_user(), get_user() etc. The user-specified fault handler gets called only if the fault occurs while executing user-specified handlers. In such a case user-specified handler is allowed to fix it first, later if the user-specifed fault handler does not fix it, we try to fix it by calling fix_exception(). The user-specified handler will not be called if the fault happens when single stepping the original instruction, instead we reset the current probe and allow the system page fault handler to fix it up. Signed-off-by: Prasanna S Panchamukhi <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent 2326c77 commit b402651

File tree

1 file changed

+50
-7
lines changed

1 file changed

+50
-7
lines changed

arch/i386/kernel/kprobes.c

Lines changed: 50 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
#include <asm/cacheflush.h>
3636
#include <asm/kdebug.h>
3737
#include <asm/desc.h>
38+
#include <asm/uaccess.h>
3839

3940
void jprobe_return_end(void);
4041

@@ -547,15 +548,57 @@ static inline int kprobe_fault_handler(struct pt_regs *regs, int trapnr)
547548
struct kprobe *cur = kprobe_running();
548549
struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
549550

550-
if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr))
551-
return 1;
552-
553-
if (kcb->kprobe_status & KPROBE_HIT_SS) {
554-
resume_execution(cur, regs, kcb);
551+
switch(kcb->kprobe_status) {
552+
case KPROBE_HIT_SS:
553+
case KPROBE_REENTER:
554+
/*
555+
* We are here because the instruction being single
556+
* stepped caused a page fault. We reset the current
557+
* kprobe and the eip points back to the probe address
558+
* and allow the page fault handler to continue as a
559+
* normal page fault.
560+
*/
561+
regs->eip = (unsigned long)cur->addr;
555562
regs->eflags |= kcb->kprobe_old_eflags;
556-
557-
reset_current_kprobe();
563+
if (kcb->kprobe_status == KPROBE_REENTER)
564+
restore_previous_kprobe(kcb);
565+
else
566+
reset_current_kprobe();
558567
preempt_enable_no_resched();
568+
break;
569+
case KPROBE_HIT_ACTIVE:
570+
case KPROBE_HIT_SSDONE:
571+
/*
572+
* We increment the nmissed count for accounting,
573+
* we can also use npre/npostfault count for accouting
574+
* these specific fault cases.
575+
*/
576+
kprobes_inc_nmissed_count(cur);
577+
578+
/*
579+
* We come here because instructions in the pre/post
580+
* handler caused the page_fault, this could happen
581+
* if handler tries to access user space by
582+
* copy_from_user(), get_user() etc. Let the
583+
* user-specified handler try to fix it first.
584+
*/
585+
if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr))
586+
return 1;
587+
588+
/*
589+
* In case the user-specified fault handler returned
590+
* zero, try to fix up.
591+
*/
592+
if (fixup_exception(regs))
593+
return 1;
594+
595+
/*
596+
* fixup_exception() could not handle it,
597+
* Let do_page_fault() fix it.
598+
*/
599+
break;
600+
default:
601+
break;
559602
}
560603
return 0;
561604
}

0 commit comments

Comments
 (0)