aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPrasanna S Panchamukhi <prasanna@in.ibm.com>2005-09-06 18:19:28 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2005-09-07 19:57:59 -0400
commit0f2fbdcbb041f9087da42f8ac2e81f2817098d2a (patch)
tree3f54f91ca6972c6567cfe529b33fafb622b2d51c
parent3d97ae5b958855ac007b6f56a0f94ab8ade09e9e (diff)
[PATCH] kprobes: prevent possible race conditions x86_64 changes
This patch contains the x86_64 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/x86_64/kernel/entry.S12
-rw-r--r--arch/x86_64/kernel/kprobes.c35
-rw-r--r--arch/x86_64/kernel/traps.c14
-rw-r--r--arch/x86_64/kernel/vmlinux.lds.S1
-rw-r--r--arch/x86_64/mm/fault.c4
5 files changed, 39 insertions, 27 deletions
diff --git a/arch/x86_64/kernel/entry.S b/arch/x86_64/kernel/entry.S
index 096d470e280f..be51dbe1f75e 100644
--- a/arch/x86_64/kernel/entry.S
+++ b/arch/x86_64/kernel/entry.S
@@ -784,8 +784,9 @@ ENTRY(execve)
784 ret 784 ret
785 CFI_ENDPROC 785 CFI_ENDPROC
786 786
787ENTRY(page_fault) 787KPROBE_ENTRY(page_fault)
788 errorentry do_page_fault 788 errorentry do_page_fault
789 .previous .text
789 790
790ENTRY(coprocessor_error) 791ENTRY(coprocessor_error)
791 zeroentry do_coprocessor_error 792 zeroentry do_coprocessor_error
@@ -797,13 +798,14 @@ ENTRY(device_not_available)
797 zeroentry math_state_restore 798 zeroentry math_state_restore
798 799
799 /* runs on exception stack */ 800 /* runs on exception stack */
800ENTRY(debug) 801KPROBE_ENTRY(debug)
801 CFI_STARTPROC 802 CFI_STARTPROC
802 pushq $0 803 pushq $0
803 CFI_ADJUST_CFA_OFFSET 8 804 CFI_ADJUST_CFA_OFFSET 8
804 paranoidentry do_debug 805 paranoidentry do_debug
805 jmp paranoid_exit 806 jmp paranoid_exit
806 CFI_ENDPROC 807 CFI_ENDPROC
808 .previous .text
807 809
808 /* runs on exception stack */ 810 /* runs on exception stack */
809ENTRY(nmi) 811ENTRY(nmi)
@@ -854,8 +856,9 @@ paranoid_schedule:
854 jmp paranoid_userspace 856 jmp paranoid_userspace
855 CFI_ENDPROC 857 CFI_ENDPROC
856 858
857ENTRY(int3) 859KPROBE_ENTRY(int3)
858 zeroentry do_int3 860 zeroentry do_int3
861 .previous .text
859 862
860ENTRY(overflow) 863ENTRY(overflow)
861 zeroentry do_overflow 864 zeroentry do_overflow
@@ -892,8 +895,9 @@ ENTRY(stack_segment)
892 jmp paranoid_exit 895 jmp paranoid_exit
893 CFI_ENDPROC 896 CFI_ENDPROC
894 897
895ENTRY(general_protection) 898KPROBE_ENTRY(general_protection)
896 errorentry do_general_protection 899 errorentry do_general_protection
900 .previous .text
897 901
898ENTRY(alignment_check) 902ENTRY(alignment_check)
899 errorentry do_alignment_check 903 errorentry do_alignment_check
diff --git a/arch/x86_64/kernel/kprobes.c b/arch/x86_64/kernel/kprobes.c
index 5c6dc7051482..c21cceaea275 100644
--- a/arch/x86_64/kernel/kprobes.c
+++ b/arch/x86_64/kernel/kprobes.c
@@ -74,7 +74,7 @@ static inline int is_IF_modifier(kprobe_opcode_t *insn)
74 return 0; 74 return 0;
75} 75}
76 76
77int arch_prepare_kprobe(struct kprobe *p) 77int __kprobes arch_prepare_kprobe(struct kprobe *p)
78{ 78{
79 /* insn: must be on special executable page on x86_64. */ 79 /* insn: must be on special executable page on x86_64. */
80 up(&kprobe_mutex); 80 up(&kprobe_mutex);
@@ -189,7 +189,7 @@ static inline s32 *is_riprel(u8 *insn)
189 return NULL; 189 return NULL;
190} 190}
191 191
192void arch_copy_kprobe(struct kprobe *p) 192void __kprobes arch_copy_kprobe(struct kprobe *p)
193{ 193{
194 s32 *ripdisp; 194 s32 *ripdisp;
195 memcpy(p->ainsn.insn, p->addr, MAX_INSN_SIZE); 195 memcpy(p->ainsn.insn, p->addr, MAX_INSN_SIZE);
@@ -215,21 +215,21 @@ void arch_copy_kprobe(struct kprobe *p)
215 p->opcode = *p->addr; 215 p->opcode = *p->addr;
216} 216}
217 217
218void arch_arm_kprobe(struct kprobe *p) 218void __kprobes arch_arm_kprobe(struct kprobe *p)
219{ 219{
220 *p->addr = BREAKPOINT_INSTRUCTION; 220 *p->addr = BREAKPOINT_INSTRUCTION;
221 flush_icache_range((unsigned long) p->addr, 221 flush_icache_range((unsigned long) p->addr,
222 (unsigned long) p->addr + sizeof(kprobe_opcode_t)); 222 (unsigned long) p->addr + sizeof(kprobe_opcode_t));
223} 223}
224 224
225void arch_disarm_kprobe(struct kprobe *p) 225void __kprobes arch_disarm_kprobe(struct kprobe *p)
226{ 226{
227 *p->addr = p->opcode; 227 *p->addr = p->opcode;
228 flush_icache_range((unsigned long) p->addr, 228 flush_icache_range((unsigned long) p->addr,
229 (unsigned long) p->addr + sizeof(kprobe_opcode_t)); 229 (unsigned long) p->addr + sizeof(kprobe_opcode_t));
230} 230}
231 231
232void arch_remove_kprobe(struct kprobe *p) 232void __kprobes arch_remove_kprobe(struct kprobe *p)
233{ 233{
234 up(&kprobe_mutex); 234 up(&kprobe_mutex);
235 free_insn_slot(p->ainsn.insn); 235 free_insn_slot(p->ainsn.insn);
@@ -261,7 +261,7 @@ static inline void set_current_kprobe(struct kprobe *p, struct pt_regs *regs)
261 kprobe_saved_rflags &= ~IF_MASK; 261 kprobe_saved_rflags &= ~IF_MASK;
262} 262}
263 263
264static void prepare_singlestep(struct kprobe *p, struct pt_regs *regs) 264static void __kprobes prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
265{ 265{
266 regs->eflags |= TF_MASK; 266 regs->eflags |= TF_MASK;
267 regs->eflags &= ~IF_MASK; 267 regs->eflags &= ~IF_MASK;
@@ -272,7 +272,8 @@ static void prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
272 regs->rip = (unsigned long)p->ainsn.insn; 272 regs->rip = (unsigned long)p->ainsn.insn;
273} 273}
274 274
275void arch_prepare_kretprobe(struct kretprobe *rp, struct pt_regs *regs) 275void __kprobes arch_prepare_kretprobe(struct kretprobe *rp,
276 struct pt_regs *regs)
276{ 277{
277 unsigned long *sara = (unsigned long *)regs->rsp; 278 unsigned long *sara = (unsigned long *)regs->rsp;
278 struct kretprobe_instance *ri; 279 struct kretprobe_instance *ri;
@@ -295,7 +296,7 @@ void arch_prepare_kretprobe(struct kretprobe *rp, struct pt_regs *regs)
295 * Interrupts are disabled on entry as trap3 is an interrupt gate and they 296 * Interrupts are disabled on entry as trap3 is an interrupt gate and they
296 * remain disabled thorough out this function. 297 * remain disabled thorough out this function.
297 */ 298 */
298int kprobe_handler(struct pt_regs *regs) 299int __kprobes kprobe_handler(struct pt_regs *regs)
299{ 300{
300 struct kprobe *p; 301 struct kprobe *p;
301 int ret = 0; 302 int ret = 0;
@@ -399,7 +400,7 @@ no_kprobe:
399/* 400/*
400 * Called when we hit the probe point at kretprobe_trampoline 401 * Called when we hit the probe point at kretprobe_trampoline
401 */ 402 */
402int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) 403int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
403{ 404{
404 struct kretprobe_instance *ri = NULL; 405 struct kretprobe_instance *ri = NULL;
405 struct hlist_head *head; 406 struct hlist_head *head;
@@ -478,7 +479,7 @@ int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
478 * that is atop the stack is the address following the copied instruction. 479 * that is atop the stack is the address following the copied instruction.
479 * We need to make it the address following the original instruction. 480 * We need to make it the address following the original instruction.
480 */ 481 */
481static void resume_execution(struct kprobe *p, struct pt_regs *regs) 482static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs)
482{ 483{
483 unsigned long *tos = (unsigned long *)regs->rsp; 484 unsigned long *tos = (unsigned long *)regs->rsp;
484 unsigned long next_rip = 0; 485 unsigned long next_rip = 0;
@@ -536,7 +537,7 @@ static void resume_execution(struct kprobe *p, struct pt_regs *regs)
536 * Interrupts are disabled on entry as trap1 is an interrupt gate and they 537 * Interrupts are disabled on entry as trap1 is an interrupt gate and they
537 * remain disabled thoroughout this function. And we hold kprobe lock. 538 * remain disabled thoroughout this function. And we hold kprobe lock.
538 */ 539 */
539int post_kprobe_handler(struct pt_regs *regs) 540int __kprobes post_kprobe_handler(struct pt_regs *regs)
540{ 541{
541 if (!kprobe_running()) 542 if (!kprobe_running())
542 return 0; 543 return 0;
@@ -571,7 +572,7 @@ out:
571} 572}
572 573
573/* Interrupts disabled, kprobe_lock held. */ 574/* Interrupts disabled, kprobe_lock held. */
574int kprobe_fault_handler(struct pt_regs *regs, int trapnr) 575int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr)
575{ 576{
576 if (current_kprobe->fault_handler 577 if (current_kprobe->fault_handler
577 && current_kprobe->fault_handler(current_kprobe, regs, trapnr)) 578 && current_kprobe->fault_handler(current_kprobe, regs, trapnr))
@@ -590,8 +591,8 @@ int kprobe_fault_handler(struct pt_regs *regs, int trapnr)
590/* 591/*
591 * Wrapper routine for handling exceptions. 592 * Wrapper routine for handling exceptions.
592 */ 593 */
593int kprobe_exceptions_notify(struct notifier_block *self, unsigned long val, 594int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
594 void *data) 595 unsigned long val, void *data)
595{ 596{
596 struct die_args *args = (struct die_args *)data; 597 struct die_args *args = (struct die_args *)data;
597 switch (val) { 598 switch (val) {
@@ -619,7 +620,7 @@ int kprobe_exceptions_notify(struct notifier_block *self, unsigned long val,
619 return NOTIFY_DONE; 620 return NOTIFY_DONE;
620} 621}
621 622
622int setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) 623int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
623{ 624{
624 struct jprobe *jp = container_of(p, struct jprobe, kp); 625 struct jprobe *jp = container_of(p, struct jprobe, kp);
625 unsigned long addr; 626 unsigned long addr;
@@ -640,7 +641,7 @@ int setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
640 return 1; 641 return 1;
641} 642}
642 643
643void jprobe_return(void) 644void __kprobes jprobe_return(void)
644{ 645{
645 preempt_enable_no_resched(); 646 preempt_enable_no_resched();
646 asm volatile (" xchg %%rbx,%%rsp \n" 647 asm volatile (" xchg %%rbx,%%rsp \n"
@@ -651,7 +652,7 @@ void jprobe_return(void)
651 (jprobe_saved_rsp):"memory"); 652 (jprobe_saved_rsp):"memory");
652} 653}
653 654
654int longjmp_break_handler(struct kprobe *p, struct pt_regs *regs) 655int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
655{ 656{
656 u8 *addr = (u8 *) (regs->rip - 1); 657 u8 *addr = (u8 *) (regs->rip - 1);
657 unsigned long stack_addr = (unsigned long)jprobe_saved_rsp; 658 unsigned long stack_addr = (unsigned long)jprobe_saved_rsp;
diff --git a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c
index 6ead433a3885..f238d6078a5a 100644
--- a/arch/x86_64/kernel/traps.c
+++ b/arch/x86_64/kernel/traps.c
@@ -29,6 +29,7 @@
29#include <linux/module.h> 29#include <linux/module.h>
30#include <linux/moduleparam.h> 30#include <linux/moduleparam.h>
31#include <linux/nmi.h> 31#include <linux/nmi.h>
32#include <linux/kprobes.h>
32 33
33#include <asm/system.h> 34#include <asm/system.h>
34#include <asm/uaccess.h> 35#include <asm/uaccess.h>
@@ -419,8 +420,9 @@ void die_nmi(char *str, struct pt_regs *regs)
419 do_exit(SIGSEGV); 420 do_exit(SIGSEGV);
420} 421}
421 422
422static void do_trap(int trapnr, int signr, char *str, 423static void __kprobes do_trap(int trapnr, int signr, char *str,
423 struct pt_regs * regs, long error_code, siginfo_t *info) 424 struct pt_regs * regs, long error_code,
425 siginfo_t *info)
424{ 426{
425 conditional_sti(regs); 427 conditional_sti(regs);
426 428
@@ -504,7 +506,8 @@ DO_ERROR(18, SIGSEGV, "reserved", reserved)
504DO_ERROR(12, SIGBUS, "stack segment", stack_segment) 506DO_ERROR(12, SIGBUS, "stack segment", stack_segment)
505DO_ERROR( 8, SIGSEGV, "double fault", double_fault) 507DO_ERROR( 8, SIGSEGV, "double fault", double_fault)
506 508
507asmlinkage void do_general_protection(struct pt_regs * regs, long error_code) 509asmlinkage void __kprobes do_general_protection(struct pt_regs * regs,
510 long error_code)
508{ 511{
509 conditional_sti(regs); 512 conditional_sti(regs);
510 513
@@ -622,7 +625,7 @@ asmlinkage void default_do_nmi(struct pt_regs *regs)
622 io_check_error(reason, regs); 625 io_check_error(reason, regs);
623} 626}
624 627
625asmlinkage void do_int3(struct pt_regs * regs, long error_code) 628asmlinkage void __kprobes do_int3(struct pt_regs * regs, long error_code)
626{ 629{
627 if (notify_die(DIE_INT3, "int3", regs, error_code, 3, SIGTRAP) == NOTIFY_STOP) { 630 if (notify_die(DIE_INT3, "int3", regs, error_code, 3, SIGTRAP) == NOTIFY_STOP) {
628 return; 631 return;
@@ -653,7 +656,8 @@ asmlinkage struct pt_regs *sync_regs(struct pt_regs *eregs)
653} 656}
654 657
655/* runs on IST stack. */ 658/* runs on IST stack. */
656asmlinkage void do_debug(struct pt_regs * regs, unsigned long error_code) 659asmlinkage void __kprobes do_debug(struct pt_regs * regs,
660 unsigned long error_code)
657{ 661{
658 unsigned long condition; 662 unsigned long condition;
659 struct task_struct *tsk = current; 663 struct task_struct *tsk = current;
diff --git a/arch/x86_64/kernel/vmlinux.lds.S b/arch/x86_64/kernel/vmlinux.lds.S
index 2a94f9b60b2d..d4abb07af52d 100644
--- a/arch/x86_64/kernel/vmlinux.lds.S
+++ b/arch/x86_64/kernel/vmlinux.lds.S
@@ -21,6 +21,7 @@ SECTIONS
21 *(.text) 21 *(.text)
22 SCHED_TEXT 22 SCHED_TEXT
23 LOCK_TEXT 23 LOCK_TEXT
24 KPROBES_TEXT
24 *(.fixup) 25 *(.fixup)
25 *(.gnu.warning) 26 *(.gnu.warning)
26 } = 0x9090 27 } = 0x9090
diff --git a/arch/x86_64/mm/fault.c b/arch/x86_64/mm/fault.c
index ca914c3bd49c..816732d8858c 100644
--- a/arch/x86_64/mm/fault.c
+++ b/arch/x86_64/mm/fault.c
@@ -23,6 +23,7 @@
23#include <linux/vt_kern.h> /* For unblank_screen() */ 23#include <linux/vt_kern.h> /* For unblank_screen() */
24#include <linux/compiler.h> 24#include <linux/compiler.h>
25#include <linux/module.h> 25#include <linux/module.h>
26#include <linux/kprobes.h>
26 27
27#include <asm/system.h> 28#include <asm/system.h>
28#include <asm/uaccess.h> 29#include <asm/uaccess.h>
@@ -294,7 +295,8 @@ int exception_trace = 1;
294 * bit 2 == 0 means kernel, 1 means user-mode 295 * bit 2 == 0 means kernel, 1 means user-mode
295 * bit 3 == 1 means fault was an instruction fetch 296 * bit 3 == 1 means fault was an instruction fetch
296 */ 297 */
297asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code) 298asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,
299 unsigned long error_code)
298{ 300{
299 struct task_struct *tsk; 301 struct task_struct *tsk;
300 struct mm_struct *mm; 302 struct mm_struct *mm;