diff options
author | Prasanna S Panchamukhi <prasanna@in.ibm.com> | 2005-09-06 18:19:27 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-09-07 19:57:59 -0400 |
commit | 3d97ae5b958855ac007b6f56a0f94ab8ade09e9e (patch) | |
tree | 6258b62fdbf4fcc7086e86d920e23609022d0881 | |
parent | d0aaff9796c3310326d10da44fc0faed352a1d29 (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.S | 13 | ||||
-rw-r--r-- | arch/i386/kernel/kprobes.c | 29 | ||||
-rw-r--r-- | arch/i386/kernel/traps.c | 12 | ||||
-rw-r--r-- | arch/i386/kernel/vmlinux.lds.S | 1 | ||||
-rw-r--r-- | arch/i386/mm/fault.c | 4 |
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 | ||
510 | ENTRY(debug) | 510 | KPROBE_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 | ||
594 | ENTRY(int3) | 594 | KPROBE_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 | ||
602 | ENTRY(overflow) | 603 | ENTRY(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 | ||
634 | ENTRY(general_protection) | 635 | KPROBE_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 | ||
638 | ENTRY(alignment_check) | 640 | ENTRY(alignment_check) |
639 | pushl $do_alignment_check | 641 | pushl $do_alignment_check |
640 | jmp error_code | 642 | jmp error_code |
641 | 643 | ||
642 | ENTRY(page_fault) | 644 | KPROBE_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 |
647 | ENTRY(machine_check) | 650 | ENTRY(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 | ||
65 | int arch_prepare_kprobe(struct kprobe *p) | 65 | int __kprobes arch_prepare_kprobe(struct kprobe *p) |
66 | { | 66 | { |
67 | return 0; | 67 | return 0; |
68 | } | 68 | } |
69 | 69 | ||
70 | void arch_copy_kprobe(struct kprobe *p) | 70 | void __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 | ||
76 | void arch_arm_kprobe(struct kprobe *p) | 76 | void __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 | ||
83 | void arch_disarm_kprobe(struct kprobe *p) | 83 | void __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 | ||
90 | void arch_remove_kprobe(struct kprobe *p) | 90 | void __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 | ||
130 | void arch_prepare_kretprobe(struct kretprobe *rp, struct pt_regs *regs) | 130 | void __kprobes arch_prepare_kretprobe(struct kretprobe *rp, |
131 | struct pt_regs *regs) | ||
131 | { | 132 | { |
132 | unsigned long *sara = (unsigned long *)®s->esp; | 133 | unsigned long *sara = (unsigned long *)®s->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 | */ |
153 | static int kprobe_handler(struct pt_regs *regs) | 154 | static 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 | */ |
262 | int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) | 263 | int __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 | */ |
341 | static void resume_execution(struct kprobe *p, struct pt_regs *regs) | 342 | static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs) |
342 | { | 343 | { |
343 | unsigned long *tos = (unsigned long *)®s->esp; | 344 | unsigned long *tos = (unsigned long *)®s->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 | */ |
447 | int kprobe_exceptions_notify(struct notifier_block *self, unsigned long val, | 448 | int __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 | ||
476 | int setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) | 477 | int __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 | ||
498 | void jprobe_return(void) | 499 | void __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 | ||
509 | int longjmp_break_handler(struct kprobe *p, struct pt_regs *regs) | 510 | int __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 | ||
366 | static void do_trap(int trapnr, int signr, char *str, int vm86, | 366 | static 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) | |||
460 | DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, 0) | 461 | DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, 0) |
461 | DO_ERROR_INFO(32, SIGSEGV, "iret exception", iret_error, ILL_BADSTK, 0) | 462 | DO_ERROR_INFO(32, SIGSEGV, "iret exception", iret_error, ILL_BADSTK, 0) |
462 | 463 | ||
463 | fastcall void do_general_protection(struct pt_regs * regs, long error_code) | 464 | fastcall 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) | |||
676 | EXPORT_SYMBOL_GPL(unset_nmi_callback); | 678 | EXPORT_SYMBOL_GPL(unset_nmi_callback); |
677 | 679 | ||
678 | #ifdef CONFIG_KPROBES | 680 | #ifdef CONFIG_KPROBES |
679 | fastcall void do_int3(struct pt_regs *regs, long error_code) | 681 | fastcall 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 | */ |
713 | fastcall void do_debug(struct pt_regs * regs, long error_code) | 715 | fastcall 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 | */ |
226 | fastcall void do_page_fault(struct pt_regs *regs, unsigned long error_code) | 227 | fastcall 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; |