Skip to content

Commit

Permalink
[PATCH] Kprobes causes NX protection fault on i686 SMP
Browse files Browse the repository at this point in the history
Fix a problem seen on i686 machine with NX support where the instruction
could not be single stepped because of NX bit set on the memory pages
allocated by kprobes module.  This patch provides allocation of instruction
solt so that the processor can execute the instruction from that location
similar to x86_64 architecture.  Thanks to Bibo and Masami for testing this
patch.

Signed-off-by: Prasanna S Panchamukhi <prasanna@in.ibm.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
  • Loading branch information
Prasanna S Panchamukhi authored and Linus Torvalds committed Feb 24, 2006
1 parent d152126 commit 124d90b
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 4 deletions.
16 changes: 14 additions & 2 deletions arch/i386/kernel/kprobes.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@ static inline int is_IF_modifier(kprobe_opcode_t opcode)

int __kprobes arch_prepare_kprobe(struct kprobe *p)
{
/* insn: must be on special executable page on i386. */
p->ainsn.insn = get_insn_slot();
if (!p->ainsn.insn)
return -ENOMEM;

memcpy(p->ainsn.insn, p->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t));
p->opcode = *p->addr;
return 0;
Expand All @@ -77,6 +82,13 @@ void __kprobes arch_disarm_kprobe(struct kprobe *p)
(unsigned long) p->addr + sizeof(kprobe_opcode_t));
}

void __kprobes arch_remove_kprobe(struct kprobe *p)
{
down(&kprobe_mutex);
free_insn_slot(p->ainsn.insn);
up(&kprobe_mutex);
}

static inline void save_previous_kprobe(struct kprobe_ctlblk *kcb)
{
kcb->prev_kprobe.kp = kprobe_running();
Expand Down Expand Up @@ -111,7 +123,7 @@ static inline void prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
if (p->opcode == BREAKPOINT_INSTRUCTION)
regs->eip = (unsigned long)p->addr;
else
regs->eip = (unsigned long)&p->ainsn.insn;
regs->eip = (unsigned long)p->ainsn.insn;
}

/* Called with kretprobe_lock held */
Expand Down Expand Up @@ -351,7 +363,7 @@ static void __kprobes resume_execution(struct kprobe *p,
{
unsigned long *tos = (unsigned long *)&regs->esp;
unsigned long next_eip = 0;
unsigned long copy_eip = (unsigned long)&p->ainsn.insn;
unsigned long copy_eip = (unsigned long)p->ainsn.insn;
unsigned long orig_eip = (unsigned long)p->addr;

switch (p->ainsn.insn[0]) {
Expand Down
7 changes: 5 additions & 2 deletions include/asm-i386/kprobes.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@
#include <linux/types.h>
#include <linux/ptrace.h>

#define __ARCH_WANT_KPROBES_INSN_SLOT

struct kprobe;
struct pt_regs;

typedef u8 kprobe_opcode_t;
Expand All @@ -40,14 +43,14 @@ typedef u8 kprobe_opcode_t;

#define JPROBE_ENTRY(pentry) (kprobe_opcode_t *)pentry
#define ARCH_SUPPORTS_KRETPROBES
#define arch_remove_kprobe(p) do {} while (0)

void arch_remove_kprobe(struct kprobe *p);
void kretprobe_trampoline(void);

/* Architecture specific copy of original instruction*/
struct arch_specific_insn {
/* copy of the original instruction */
kprobe_opcode_t insn[MAX_INSN_SIZE];
kprobe_opcode_t *insn;
};

struct prev_kprobe {
Expand Down

0 comments on commit 124d90b

Please sign in to comment.