aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPrasanna S Panchamukhi <prasanna@in.ibm.com>2005-09-06 18:19:27 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2005-09-07 19:57:59 -0400
commit3d97ae5b958855ac007b6f56a0f94ab8ade09e9e (patch)
tree6258b62fdbf4fcc7086e86d920e23609022d0881
parentd0aaff9796c3310326d10da44fc0faed352a1d29 (diff)
[PATCH] kprobes: prevent possible race conditions i386 changes
This patch contains the i386 architecture specific changes to prevent the possible race conditions. 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>
-rw-r--r--arch/i386/kernel/entry.S13
-rw-r--r--arch/i386/kernel/kprobes.c29
-rw-r--r--arch/i386/kernel/traps.c12
-rw-r--r--arch/i386/kernel/vmlinux.lds.S1
-rw-r--r--arch/i386/mm/fault.c4
5 files changed, 34 insertions, 25 deletions
diff --git a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S
index abb909793efc..3aad03839660 100644
--- a/arch/i386/kernel/entry.S
+++ b/arch/i386/kernel/entry.S
@@ -507,7 +507,7 @@ label: \
507 pushl $__KERNEL_CS; \ 507 pushl $__KERNEL_CS; \
508 pushl $sysenter_past_esp 508 pushl $sysenter_past_esp
509 509
510ENTRY(debug) 510KPROBE_ENTRY(debug)
511 cmpl $sysenter_entry,(%esp) 511 cmpl $sysenter_entry,(%esp)
512 jne debug_stack_correct 512 jne debug_stack_correct
513 FIX_STACK(12, debug_stack_correct, debug_esp_fix_insn) 513 FIX_STACK(12, debug_stack_correct, debug_esp_fix_insn)
@@ -518,7 +518,7 @@ debug_stack_correct:
518 movl %esp,%eax # pt_regs pointer 518 movl %esp,%eax # pt_regs pointer
519 call do_debug 519 call do_debug
520 jmp ret_from_exception 520 jmp ret_from_exception
521 521 .previous .text
522/* 522/*
523 * NMI is doubly nasty. It can happen _while_ we're handling 523 * NMI is doubly nasty. It can happen _while_ we're handling
524 * a debug fault, and the debug fault hasn't yet been able to 524 * a debug fault, and the debug fault hasn't yet been able to
@@ -591,13 +591,14 @@ nmi_16bit_stack:
591 .long 1b,iret_exc 591 .long 1b,iret_exc
592.previous 592.previous
593 593
594ENTRY(int3) 594KPROBE_ENTRY(int3)
595 pushl $-1 # mark this as an int 595 pushl $-1 # mark this as an int
596 SAVE_ALL 596 SAVE_ALL
597 xorl %edx,%edx # zero error code 597 xorl %edx,%edx # zero error code
598 movl %esp,%eax # pt_regs pointer 598 movl %esp,%eax # pt_regs pointer
599 call do_int3 599 call do_int3
600 jmp ret_from_exception 600 jmp ret_from_exception
601 .previous .text
601 602
602ENTRY(overflow) 603ENTRY(overflow)
603 pushl $0 604 pushl $0
@@ -631,17 +632,19 @@ ENTRY(stack_segment)
631 pushl $do_stack_segment 632 pushl $do_stack_segment
632 jmp error_code 633 jmp error_code
633 634
634ENTRY(general_protection) 635KPROBE_ENTRY(general_protection)
635 pushl $do_general_protection 636 pushl $do_general_protection
636 jmp error_code 637 jmp error_code
638 .previous .text
637 639
638ENTRY(alignment_check) 640ENTRY(alignment_check)
639 pushl $do_alignment_check 641 pushl $do_alignment_check
640 jmp error_code 642 jmp error_code
641 643
642ENTRY(page_fault) 644KPROBE_ENTRY(page_fault)
643 pushl $do_page_fault 645 pushl $do_page_fault
644 jmp error_code 646 jmp error_code
647 .previous .text
645 648
646#ifdef CONFIG_X86_MCE 649#ifdef CONFIG_X86_MCE
647ENTRY(machine_check) 650ENTRY(machine_check)
diff --git a/arch/i386/kernel/kprobes.c b/arch/i386/kernel/kprobes.c
index a6d8c45961d3..7fb5a6f4a563 100644
--- a/arch/i386/kernel/kprobes.c
+++ b/arch/i386/kernel/kprobes.c
@@ -62,32 +62,32 @@ static inline int is_IF_modifier(kprobe_opcode_t opcode)
62 return 0; 62 return 0;
63} 63}
64 64
65int arch_prepare_kprobe(struct kprobe *p) 65int __kprobes arch_prepare_kprobe(struct kprobe *p)
66{ 66{
67 return 0; 67 return 0;
68} 68}
69 69
70void arch_copy_kprobe(struct kprobe *p) 70void __kprobes arch_copy_kprobe(struct kprobe *p)
71{ 71{
72 memcpy(p->ainsn.insn, p->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t)); 72 memcpy(p->ainsn.insn, p->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t));
73 p->opcode = *p->addr; 73 p->opcode = *p->addr;
74} 74}
75 75
76void arch_arm_kprobe(struct kprobe *p) 76void __kprobes arch_arm_kprobe(struct kprobe *p)
77{ 77{
78 *p->addr = BREAKPOINT_INSTRUCTION; 78 *p->addr = BREAKPOINT_INSTRUCTION;
79 flush_icache_range((unsigned long) p->addr, 79 flush_icache_range((unsigned long) p->addr,
80 (unsigned long) p->addr + sizeof(kprobe_opcode_t)); 80 (unsigned long) p->addr + sizeof(kprobe_opcode_t));
81} 81}
82 82
83void arch_disarm_kprobe(struct kprobe *p) 83void __kprobes arch_disarm_kprobe(struct kprobe *p)
84{ 84{
85 *p->addr = p->opcode; 85 *p->addr = p->opcode;
86 flush_icache_range((unsigned long) p->addr, 86 flush_icache_range((unsigned long) p->addr,
87 (unsigned long) p->addr + sizeof(kprobe_opcode_t)); 87 (unsigned long) p->addr + sizeof(kprobe_opcode_t));
88} 88}
89 89
90void arch_remove_kprobe(struct kprobe *p) 90void __kprobes arch_remove_kprobe(struct kprobe *p)
91{ 91{
92} 92}
93 93
@@ -127,7 +127,8 @@ static inline void prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
127 regs->eip = (unsigned long)&p->ainsn.insn; 127 regs->eip = (unsigned long)&p->ainsn.insn;
128} 128}
129 129
130void arch_prepare_kretprobe(struct kretprobe *rp, struct pt_regs *regs) 130void __kprobes arch_prepare_kretprobe(struct kretprobe *rp,
131 struct pt_regs *regs)
131{ 132{
132 unsigned long *sara = (unsigned long *)&regs->esp; 133 unsigned long *sara = (unsigned long *)&regs->esp;
133 struct kretprobe_instance *ri; 134 struct kretprobe_instance *ri;
@@ -150,7 +151,7 @@ void arch_prepare_kretprobe(struct kretprobe *rp, struct pt_regs *regs)
150 * Interrupts are disabled on entry as trap3 is an interrupt gate and they 151 * Interrupts are disabled on entry as trap3 is an interrupt gate and they
151 * remain disabled thorough out this function. 152 * remain disabled thorough out this function.
152 */ 153 */
153static int kprobe_handler(struct pt_regs *regs) 154static int __kprobes kprobe_handler(struct pt_regs *regs)
154{ 155{
155 struct kprobe *p; 156 struct kprobe *p;
156 int ret = 0; 157 int ret = 0;
@@ -259,7 +260,7 @@ no_kprobe:
259/* 260/*
260 * Called when we hit the probe point at kretprobe_trampoline 261 * Called when we hit the probe point at kretprobe_trampoline
261 */ 262 */
262int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) 263int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
263{ 264{
264 struct kretprobe_instance *ri = NULL; 265 struct kretprobe_instance *ri = NULL;
265 struct hlist_head *head; 266 struct hlist_head *head;
@@ -338,7 +339,7 @@ int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
338 * that is atop the stack is the address following the copied instruction. 339 * that is atop the stack is the address following the copied instruction.
339 * We need to make it the address following the original instruction. 340 * We need to make it the address following the original instruction.
340 */ 341 */
341static void resume_execution(struct kprobe *p, struct pt_regs *regs) 342static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs)
342{ 343{
343 unsigned long *tos = (unsigned long *)&regs->esp; 344 unsigned long *tos = (unsigned long *)&regs->esp;
344 unsigned long next_eip = 0; 345 unsigned long next_eip = 0;
@@ -444,8 +445,8 @@ static inline int kprobe_fault_handler(struct pt_regs *regs, int trapnr)
444/* 445/*
445 * Wrapper routine to for handling exceptions. 446 * Wrapper routine to for handling exceptions.
446 */ 447 */
447int kprobe_exceptions_notify(struct notifier_block *self, unsigned long val, 448int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
448 void *data) 449 unsigned long val, void *data)
449{ 450{
450 struct die_args *args = (struct die_args *)data; 451 struct die_args *args = (struct die_args *)data;
451 switch (val) { 452 switch (val) {
@@ -473,7 +474,7 @@ int kprobe_exceptions_notify(struct notifier_block *self, unsigned long val,
473 return NOTIFY_DONE; 474 return NOTIFY_DONE;
474} 475}
475 476
476int setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) 477int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
477{ 478{
478 struct jprobe *jp = container_of(p, struct jprobe, kp); 479 struct jprobe *jp = container_of(p, struct jprobe, kp);
479 unsigned long addr; 480 unsigned long addr;
@@ -495,7 +496,7 @@ int setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
495 return 1; 496 return 1;
496} 497}
497 498
498void jprobe_return(void) 499void __kprobes jprobe_return(void)
499{ 500{
500 preempt_enable_no_resched(); 501 preempt_enable_no_resched();
501 asm volatile (" xchgl %%ebx,%%esp \n" 502 asm volatile (" xchgl %%ebx,%%esp \n"
@@ -506,7 +507,7 @@ void jprobe_return(void)
506 (jprobe_saved_esp):"memory"); 507 (jprobe_saved_esp):"memory");
507} 508}
508 509
509int longjmp_break_handler(struct kprobe *p, struct pt_regs *regs) 510int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
510{ 511{
511 u8 *addr = (u8 *) (regs->eip - 1); 512 u8 *addr = (u8 *) (regs->eip - 1);
512 unsigned long stack_addr = (unsigned long)jprobe_saved_esp; 513 unsigned long stack_addr = (unsigned long)jprobe_saved_esp;
diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c
index 029bf94cda7d..09a58cb6daa7 100644
--- a/arch/i386/kernel/traps.c
+++ b/arch/i386/kernel/traps.c
@@ -363,8 +363,9 @@ static inline void die_if_kernel(const char * str, struct pt_regs * regs, long e
363 die(str, regs, err); 363 die(str, regs, err);
364} 364}
365 365
366static void do_trap(int trapnr, int signr, char *str, int vm86, 366static void __kprobes do_trap(int trapnr, int signr, char *str, int vm86,
367 struct pt_regs * regs, long error_code, siginfo_t *info) 367 struct pt_regs * regs, long error_code,
368 siginfo_t *info)
368{ 369{
369 struct task_struct *tsk = current; 370 struct task_struct *tsk = current;
370 tsk->thread.error_code = error_code; 371 tsk->thread.error_code = error_code;
@@ -460,7 +461,8 @@ DO_ERROR(12, SIGBUS, "stack segment", stack_segment)
460DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, 0) 461DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, 0)
461DO_ERROR_INFO(32, SIGSEGV, "iret exception", iret_error, ILL_BADSTK, 0) 462DO_ERROR_INFO(32, SIGSEGV, "iret exception", iret_error, ILL_BADSTK, 0)
462 463
463fastcall void do_general_protection(struct pt_regs * regs, long error_code) 464fastcall void __kprobes do_general_protection(struct pt_regs * regs,
465 long error_code)
464{ 466{
465 int cpu = get_cpu(); 467 int cpu = get_cpu();
466 struct tss_struct *tss = &per_cpu(init_tss, cpu); 468 struct tss_struct *tss = &per_cpu(init_tss, cpu);
@@ -676,7 +678,7 @@ void unset_nmi_callback(void)
676EXPORT_SYMBOL_GPL(unset_nmi_callback); 678EXPORT_SYMBOL_GPL(unset_nmi_callback);
677 679
678#ifdef CONFIG_KPROBES 680#ifdef CONFIG_KPROBES
679fastcall void do_int3(struct pt_regs *regs, long error_code) 681fastcall void __kprobes do_int3(struct pt_regs *regs, long error_code)
680{ 682{
681 if (notify_die(DIE_INT3, "int3", regs, error_code, 3, SIGTRAP) 683 if (notify_die(DIE_INT3, "int3", regs, error_code, 3, SIGTRAP)
682 == NOTIFY_STOP) 684 == NOTIFY_STOP)
@@ -710,7 +712,7 @@ fastcall void do_int3(struct pt_regs *regs, long error_code)
710 * find every occurrence of the TF bit that could be saved away even 712 * find every occurrence of the TF bit that could be saved away even
711 * by user code) 713 * by user code)
712 */ 714 */
713fastcall void do_debug(struct pt_regs * regs, long error_code) 715fastcall void __kprobes do_debug(struct pt_regs * regs, long error_code)
714{ 716{
715 unsigned int condition; 717 unsigned int condition;
716 struct task_struct *tsk = current; 718 struct task_struct *tsk = current;
diff --git a/arch/i386/kernel/vmlinux.lds.S b/arch/i386/kernel/vmlinux.lds.S
index 761972f8cb6c..13b9c62cbbb4 100644
--- a/arch/i386/kernel/vmlinux.lds.S
+++ b/arch/i386/kernel/vmlinux.lds.S
@@ -22,6 +22,7 @@ SECTIONS
22 *(.text) 22 *(.text)
23 SCHED_TEXT 23 SCHED_TEXT
24 LOCK_TEXT 24 LOCK_TEXT
25 KPROBES_TEXT
25 *(.fixup) 26 *(.fixup)
26 *(.gnu.warning) 27 *(.gnu.warning)
27 } = 0x9090 28 } = 0x9090
diff --git a/arch/i386/mm/fault.c b/arch/i386/mm/fault.c
index 411b8500ad1b..9edd4485b91e 100644
--- a/arch/i386/mm/fault.c
+++ b/arch/i386/mm/fault.c
@@ -21,6 +21,7 @@
21#include <linux/vt_kern.h> /* For unblank_screen() */ 21#include <linux/vt_kern.h> /* For unblank_screen() */
22#include <linux/highmem.h> 22#include <linux/highmem.h>
23#include <linux/module.h> 23#include <linux/module.h>
24#include <linux/kprobes.h>
24 25
25#include <asm/system.h> 26#include <asm/system.h>
26#include <asm/uaccess.h> 27#include <asm/uaccess.h>
@@ -223,7 +224,8 @@ fastcall void do_invalid_op(struct pt_regs *, unsigned long);
223 * bit 1 == 0 means read, 1 means write 224 * bit 1 == 0 means read, 1 means write
224 * bit 2 == 0 means kernel, 1 means user-mode 225 * bit 2 == 0 means kernel, 1 means user-mode
225 */ 226 */
226fastcall void do_page_fault(struct pt_regs *regs, unsigned long error_code) 227fastcall void __kprobes do_page_fault(struct pt_regs *regs,
228 unsigned long error_code)
227{ 229{
228 struct task_struct *tsk; 230 struct task_struct *tsk;
229 struct mm_struct *mm; 231 struct mm_struct *mm;