Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

[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
Loading
Loading
Loading
Loading
+14 −2
Original line number Diff line number Diff line
@@ -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;
@@ -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();
@@ -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 */
@@ -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]) {
+5 −2
Original line number Diff line number Diff line
@@ -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;
@@ -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 {