Commit 124d90be authored by Prasanna S Panchamukhi's avatar Prasanna S Panchamukhi Committed by Linus Torvalds

[PATCH] Kprobes causes NX protection fault on i686 SMP

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: default avatarPrasanna S Panchamukhi <prasanna@in.ibm.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent d1521260
...@@ -58,6 +58,11 @@ static inline int is_IF_modifier(kprobe_opcode_t opcode) ...@@ -58,6 +58,11 @@ static inline int is_IF_modifier(kprobe_opcode_t opcode)
int __kprobes arch_prepare_kprobe(struct kprobe *p) 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)); memcpy(p->ainsn.insn, p->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t));
p->opcode = *p->addr; p->opcode = *p->addr;
return 0; return 0;
...@@ -77,6 +82,13 @@ void __kprobes arch_disarm_kprobe(struct kprobe *p) ...@@ -77,6 +82,13 @@ void __kprobes arch_disarm_kprobe(struct kprobe *p)
(unsigned long) p->addr + sizeof(kprobe_opcode_t)); (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) static inline void save_previous_kprobe(struct kprobe_ctlblk *kcb)
{ {
kcb->prev_kprobe.kp = kprobe_running(); kcb->prev_kprobe.kp = kprobe_running();
...@@ -111,7 +123,7 @@ static inline void prepare_singlestep(struct kprobe *p, struct pt_regs *regs) ...@@ -111,7 +123,7 @@ static inline void prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
if (p->opcode == BREAKPOINT_INSTRUCTION) if (p->opcode == BREAKPOINT_INSTRUCTION)
regs->eip = (unsigned long)p->addr; regs->eip = (unsigned long)p->addr;
else else
regs->eip = (unsigned long)&p->ainsn.insn; regs->eip = (unsigned long)p->ainsn.insn;
} }
/* Called with kretprobe_lock held */ /* Called with kretprobe_lock held */
...@@ -351,7 +363,7 @@ static void __kprobes resume_execution(struct kprobe *p, ...@@ -351,7 +363,7 @@ static void __kprobes resume_execution(struct kprobe *p,
{ {
unsigned long *tos = (unsigned long *)&regs->esp; unsigned long *tos = (unsigned long *)&regs->esp;
unsigned long next_eip = 0; 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; unsigned long orig_eip = (unsigned long)p->addr;
switch (p->ainsn.insn[0]) { switch (p->ainsn.insn[0]) {
......
...@@ -27,6 +27,9 @@ ...@@ -27,6 +27,9 @@
#include <linux/types.h> #include <linux/types.h>
#include <linux/ptrace.h> #include <linux/ptrace.h>
#define __ARCH_WANT_KPROBES_INSN_SLOT
struct kprobe;
struct pt_regs; struct pt_regs;
typedef u8 kprobe_opcode_t; typedef u8 kprobe_opcode_t;
...@@ -40,14 +43,14 @@ typedef u8 kprobe_opcode_t; ...@@ -40,14 +43,14 @@ typedef u8 kprobe_opcode_t;
#define JPROBE_ENTRY(pentry) (kprobe_opcode_t *)pentry #define JPROBE_ENTRY(pentry) (kprobe_opcode_t *)pentry
#define ARCH_SUPPORTS_KRETPROBES #define ARCH_SUPPORTS_KRETPROBES
#define arch_remove_kprobe(p) do {} while (0)
void arch_remove_kprobe(struct kprobe *p);
void kretprobe_trampoline(void); void kretprobe_trampoline(void);
/* Architecture specific copy of original instruction*/ /* Architecture specific copy of original instruction*/
struct arch_specific_insn { struct arch_specific_insn {
/* copy of the original instruction */ /* copy of the original instruction */
kprobe_opcode_t insn[MAX_INSN_SIZE]; kprobe_opcode_t *insn;
}; };
struct prev_kprobe { struct prev_kprobe {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment