diff options
author | Prasanna S Panchamukhi <prasanna@in.ibm.com> | 2006-02-24 16:04:08 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-02-24 17:31:37 -0500 |
commit | 124d90be62343f71bbb7a6b4a907b5584181e6d5 (patch) | |
tree | 6e9a53f6bee52bb551724ec29e7710a656fbb187 /arch/i386/kernel/kprobes.c | |
parent | d1521260f57d70d0ba86d2a309ec1ce7979be2fc (diff) |
[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: Prasanna S Panchamukhi <prasanna@in.ibm.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch/i386/kernel/kprobes.c')
-rw-r--r-- | arch/i386/kernel/kprobes.c | 16 |
1 files changed, 14 insertions, 2 deletions
diff --git a/arch/i386/kernel/kprobes.c b/arch/i386/kernel/kprobes.c index 6483eeb1a4e8..694a13997637 100644 --- a/arch/i386/kernel/kprobes.c +++ b/arch/i386/kernel/kprobes.c | |||
@@ -58,6 +58,11 @@ static inline int is_IF_modifier(kprobe_opcode_t opcode) | |||
58 | 58 | ||
59 | int __kprobes arch_prepare_kprobe(struct kprobe *p) | 59 | int __kprobes arch_prepare_kprobe(struct kprobe *p) |
60 | { | 60 | { |
61 | /* insn: must be on special executable page on i386. */ | ||
62 | p->ainsn.insn = get_insn_slot(); | ||
63 | if (!p->ainsn.insn) | ||
64 | return -ENOMEM; | ||
65 | |||
61 | memcpy(p->ainsn.insn, p->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t)); | 66 | memcpy(p->ainsn.insn, p->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t)); |
62 | p->opcode = *p->addr; | 67 | p->opcode = *p->addr; |
63 | return 0; | 68 | return 0; |
@@ -77,6 +82,13 @@ void __kprobes arch_disarm_kprobe(struct kprobe *p) | |||
77 | (unsigned long) p->addr + sizeof(kprobe_opcode_t)); | 82 | (unsigned long) p->addr + sizeof(kprobe_opcode_t)); |
78 | } | 83 | } |
79 | 84 | ||
85 | void __kprobes arch_remove_kprobe(struct kprobe *p) | ||
86 | { | ||
87 | down(&kprobe_mutex); | ||
88 | free_insn_slot(p->ainsn.insn); | ||
89 | up(&kprobe_mutex); | ||
90 | } | ||
91 | |||
80 | static inline void save_previous_kprobe(struct kprobe_ctlblk *kcb) | 92 | static inline void save_previous_kprobe(struct kprobe_ctlblk *kcb) |
81 | { | 93 | { |
82 | kcb->prev_kprobe.kp = kprobe_running(); | 94 | kcb->prev_kprobe.kp = kprobe_running(); |
@@ -111,7 +123,7 @@ static inline void prepare_singlestep(struct kprobe *p, struct pt_regs *regs) | |||
111 | if (p->opcode == BREAKPOINT_INSTRUCTION) | 123 | if (p->opcode == BREAKPOINT_INSTRUCTION) |
112 | regs->eip = (unsigned long)p->addr; | 124 | regs->eip = (unsigned long)p->addr; |
113 | else | 125 | else |
114 | regs->eip = (unsigned long)&p->ainsn.insn; | 126 | regs->eip = (unsigned long)p->ainsn.insn; |
115 | } | 127 | } |
116 | 128 | ||
117 | /* Called with kretprobe_lock held */ | 129 | /* Called with kretprobe_lock held */ |
@@ -351,7 +363,7 @@ static void __kprobes resume_execution(struct kprobe *p, | |||
351 | { | 363 | { |
352 | unsigned long *tos = (unsigned long *)®s->esp; | 364 | unsigned long *tos = (unsigned long *)®s->esp; |
353 | unsigned long next_eip = 0; | 365 | unsigned long next_eip = 0; |
354 | unsigned long copy_eip = (unsigned long)&p->ainsn.insn; | 366 | unsigned long copy_eip = (unsigned long)p->ainsn.insn; |
355 | unsigned long orig_eip = (unsigned long)p->addr; | 367 | unsigned long orig_eip = (unsigned long)p->addr; |
356 | 368 | ||
357 | switch (p->ainsn.insn[0]) { | 369 | switch (p->ainsn.insn[0]) { |