ChangeSet 1.2272, 2005/03/31 08:40:16-08:00, [EMAIL PROTECTED]

        [PATCH] Kprobes: Allow/deny probes on int3/breakpoint instruction?
        
        Kprobes did an improper exit when a probe is inserted on an int3
        instruction.  In case of normal execution of int3/breakpoint 
instruction,
        it oops!.  Probe on an int3 instruction was not handled properly by the
        kprobes, it generated faults after oops!  doing an improper exit with
        holding the lock.  This fix employes a bit different method to handle 
probe
        on an int3/breakpoint instruction.
        
        On execution of an int3/breakpoint instruction (placed by kprobe),
        kprobes_handler() is called which sets it for single stepping in-line(it
        does not matter whether we single step out-of-line/inline since the 
single
        stepping instruction is same).  Now it single steps on int3/breakpoint
        instruction here, entering kprobes_handler() once again.  Kprobes now
        check's the status that it is single stepping and avoids the recursion. 
 It
        runs down through the trap handler and oops messages is seen on the 
console
        since it executed int3/breakpoint instruction.  Here the kprobes single
        stepping handler never gets called.
        
        Is this behaviour acceptable ?  Or should we avoid putting probes on an
        int3 /breakpoint instruction ?  How should it handle such situations?
        Below is the patch to allow probes on an int3/breakpoint instruction.
        
        This patch fixes the above problem by doing a proper exit while avoiding
        recursion.
        
        Signed-off-by: Prasanna S Panchamukhi <[EMAIL PROTECTED]>
        Signed-off-by: Andrew Morton <[EMAIL PROTECTED]>
        Signed-off-by: Linus Torvalds <[EMAIL PROTECTED]>



 i386/kernel/kprobes.c    |   12 +++++++++++-
 ppc64/kernel/kprobes.c   |   12 +++++++++++-
 sparc64/kernel/kprobes.c |   16 ++++++++++++++--
 x86_64/kernel/kprobes.c  |   13 +++++++++++--
 4 files changed, 47 insertions(+), 6 deletions(-)


diff -Nru a/arch/i386/kernel/kprobes.c b/arch/i386/kernel/kprobes.c
--- a/arch/i386/kernel/kprobes.c        2005-03-31 10:20:44 -08:00
+++ b/arch/i386/kernel/kprobes.c        2005-03-31 10:20:44 -08:00
@@ -84,7 +84,11 @@
 {
        regs->eflags |= TF_MASK;
        regs->eflags &= ~IF_MASK;
-       regs->eip = (unsigned long)&p->ainsn.insn;
+       /*single step inline if the instruction is an int3*/
+       if (p->opcode == BREAKPOINT_INSTRUCTION)
+               regs->eip = (unsigned long)p->addr;
+       else
+               regs->eip = (unsigned long)&p->ainsn.insn;
 }
 
 /*
@@ -117,6 +121,12 @@
                   Disarm the probe we just hit, and ignore it. */
                p = get_kprobe(addr);
                if (p) {
+                       if (kprobe_status == KPROBE_HIT_SS) {
+                               regs->eflags &= ~TF_MASK;
+                               regs->eflags |= kprobe_saved_eflags;
+                               unlock_kprobes();
+                               goto no_kprobe;
+                       }
                        disarm_kprobe(p, regs);
                        ret = 1;
                } else {
diff -Nru a/arch/ppc64/kernel/kprobes.c b/arch/ppc64/kernel/kprobes.c
--- a/arch/ppc64/kernel/kprobes.c       2005-03-31 10:20:44 -08:00
+++ b/arch/ppc64/kernel/kprobes.c       2005-03-31 10:20:44 -08:00
@@ -71,7 +71,11 @@
 static inline void prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
 {
        regs->msr |= MSR_SE;
-       regs->nip = (unsigned long)&p->ainsn.insn;
+       /*single step inline if it a breakpoint instruction*/
+       if (p->opcode == BREAKPOINT_INSTRUCTION)
+               regs->nip = (unsigned long)p->addr;
+       else
+               regs->nip = (unsigned long)&p->ainsn.insn;
 }
 
 static inline int kprobe_handler(struct pt_regs *regs)
@@ -86,6 +90,12 @@
                   Disarm the probe we just hit, and ignore it. */
                p = get_kprobe(addr);
                if (p) {
+                       if (kprobe_status == KPROBE_HIT_SS) {
+                               regs->msr &= ~MSR_SE;
+                               regs->msr |= kprobe_saved_msr;
+                               unlock_kprobes();
+                               goto no_kprobe;
+                       }
                        disarm_kprobe(p, regs);
                        ret = 1;
                } else {
diff -Nru a/arch/sparc64/kernel/kprobes.c b/arch/sparc64/kernel/kprobes.c
--- a/arch/sparc64/kernel/kprobes.c     2005-03-31 10:20:44 -08:00
+++ b/arch/sparc64/kernel/kprobes.c     2005-03-31 10:20:44 -08:00
@@ -68,8 +68,14 @@
        current_kprobe_orig_tstate_pil = (regs->tstate & TSTATE_PIL);
        regs->tstate |= TSTATE_PIL;
 
-       regs->tpc = (unsigned long) &p->ainsn.insn[0];
-       regs->tnpc = (unsigned long) &p->ainsn.insn[1];
+       /*single step inline, if it a breakpoint instruction*/
+       if (p->opcode == BREAKPOINT_INSTRUCTION) {
+               regs->tpc = (unsigned long) p->addr;
+               regs->tnpc = current_kprobe_orig_tnpc;
+       } else {
+               regs->tpc = (unsigned long) &p->ainsn.insn[0];
+               regs->tnpc = (unsigned long) &p->ainsn.insn[1];
+       }
 }
 
 static inline void disarm_kprobe(struct kprobe *p, struct pt_regs *regs)
@@ -97,6 +103,12 @@
                 */
                p = get_kprobe(addr);
                if (p) {
+                       if (kprobe_status == KPROBE_HIT_SS) {
+                               regs->tstate = ((regs->tstate & ~TSTATE_PIL) |
+                                       current_kprobe_orig_tstate_pil);
+                               unlock_kprobes();
+                               goto no_kprobe;
+                       }
                        disarm_kprobe(p, regs);
                        ret = 1;
                } else {
diff -Nru a/arch/x86_64/kernel/kprobes.c b/arch/x86_64/kernel/kprobes.c
--- a/arch/x86_64/kernel/kprobes.c      2005-03-31 10:20:44 -08:00
+++ b/arch/x86_64/kernel/kprobes.c      2005-03-31 10:20:44 -08:00
@@ -233,8 +233,11 @@
 {
        regs->eflags |= TF_MASK;
        regs->eflags &= ~IF_MASK;
-
-       regs->rip = (unsigned long)p->ainsn.insn;
+       /*single step inline if the instruction is an int3*/
+       if (p->opcode == BREAKPOINT_INSTRUCTION)
+               regs->rip = (unsigned long)p->addr;
+       else
+               regs->rip = (unsigned long)p->ainsn.insn;
 }
 
 /*
@@ -256,6 +259,12 @@
                   Disarm the probe we just hit, and ignore it. */
                p = get_kprobe(addr);
                if (p) {
+                       if (kprobe_status == KPROBE_HIT_SS) {
+                               regs->eflags &= ~TF_MASK;
+                               regs->eflags |= kprobe_saved_rflags;
+                               unlock_kprobes();
+                               goto no_kprobe;
+                       }
                        disarm_kprobe(p, regs);
                        ret = 1;
                } else {
-
To unsubscribe from this list: send the line "unsubscribe bk-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to