diff options
-rw-r--r-- | arch/x86/include/asm/ds.h | 9 | ||||
-rw-r--r-- | arch/x86/include/asm/ptrace.h | 7 | ||||
-rw-r--r-- | arch/x86/kernel/ds.c | 11 | ||||
-rw-r--r-- | arch/x86/kernel/process_32.c | 20 | ||||
-rw-r--r-- | arch/x86/kernel/process_64.c | 20 | ||||
-rw-r--r-- | arch/x86/kernel/ptrace.c | 50 | ||||
-rw-r--r-- | include/linux/ptrace.h | 22 | ||||
-rw-r--r-- | kernel/fork.c | 2 | ||||
-rw-r--r-- | kernel/ptrace.c | 12 |
9 files changed, 121 insertions, 32 deletions
diff --git a/arch/x86/include/asm/ds.h b/arch/x86/include/asm/ds.h index ee0ea3a96c11..a8f672ba100c 100644 --- a/arch/x86/include/asm/ds.h +++ b/arch/x86/include/asm/ds.h | |||
@@ -252,12 +252,21 @@ extern void __cpuinit ds_init_intel(struct cpuinfo_x86 *); | |||
252 | */ | 252 | */ |
253 | extern void ds_switch_to(struct task_struct *prev, struct task_struct *next); | 253 | extern void ds_switch_to(struct task_struct *prev, struct task_struct *next); |
254 | 254 | ||
255 | /* | ||
256 | * Task clone/init and cleanup work | ||
257 | */ | ||
258 | extern void ds_copy_thread(struct task_struct *tsk, struct task_struct *father); | ||
259 | extern void ds_exit_thread(struct task_struct *tsk); | ||
260 | |||
255 | #else /* CONFIG_X86_DS */ | 261 | #else /* CONFIG_X86_DS */ |
256 | 262 | ||
257 | struct cpuinfo_x86; | 263 | struct cpuinfo_x86; |
258 | static inline void __cpuinit ds_init_intel(struct cpuinfo_x86 *ignored) {} | 264 | static inline void __cpuinit ds_init_intel(struct cpuinfo_x86 *ignored) {} |
259 | static inline void ds_switch_to(struct task_struct *prev, | 265 | static inline void ds_switch_to(struct task_struct *prev, |
260 | struct task_struct *next) {} | 266 | struct task_struct *next) {} |
267 | static inline void ds_copy_thread(struct task_struct *tsk, | ||
268 | struct task_struct *father) {} | ||
269 | static inline void ds_exit_thread(struct task_struct *tsk) {} | ||
261 | 270 | ||
262 | #endif /* CONFIG_X86_DS */ | 271 | #endif /* CONFIG_X86_DS */ |
263 | #endif /* _ASM_X86_DS_H */ | 272 | #endif /* _ASM_X86_DS_H */ |
diff --git a/arch/x86/include/asm/ptrace.h b/arch/x86/include/asm/ptrace.h index fbf744215911..6d34d954c228 100644 --- a/arch/x86/include/asm/ptrace.h +++ b/arch/x86/include/asm/ptrace.h | |||
@@ -235,6 +235,13 @@ extern int do_get_thread_area(struct task_struct *p, int idx, | |||
235 | extern int do_set_thread_area(struct task_struct *p, int idx, | 235 | extern int do_set_thread_area(struct task_struct *p, int idx, |
236 | struct user_desc __user *info, int can_allocate); | 236 | struct user_desc __user *info, int can_allocate); |
237 | 237 | ||
238 | extern void x86_ptrace_untrace(struct task_struct *); | ||
239 | extern void x86_ptrace_fork(struct task_struct *child, | ||
240 | unsigned long clone_flags); | ||
241 | |||
242 | #define arch_ptrace_untrace(tsk) x86_ptrace_untrace(tsk) | ||
243 | #define arch_ptrace_fork(child, flags) x86_ptrace_fork(child, flags) | ||
244 | |||
238 | #endif /* __KERNEL__ */ | 245 | #endif /* __KERNEL__ */ |
239 | 246 | ||
240 | #endif /* !__ASSEMBLY__ */ | 247 | #endif /* !__ASSEMBLY__ */ |
diff --git a/arch/x86/kernel/ds.c b/arch/x86/kernel/ds.c index 98d271e60e08..da91701a2348 100644 --- a/arch/x86/kernel/ds.c +++ b/arch/x86/kernel/ds.c | |||
@@ -1017,3 +1017,14 @@ void ds_switch_to(struct task_struct *prev, struct task_struct *next) | |||
1017 | 1017 | ||
1018 | update_debugctlmsr(next->thread.debugctlmsr); | 1018 | update_debugctlmsr(next->thread.debugctlmsr); |
1019 | } | 1019 | } |
1020 | |||
1021 | void ds_copy_thread(struct task_struct *tsk, struct task_struct *father) | ||
1022 | { | ||
1023 | clear_tsk_thread_flag(tsk, TIF_DS_AREA_MSR); | ||
1024 | tsk->thread.ds_ctx = NULL; | ||
1025 | } | ||
1026 | |||
1027 | void ds_exit_thread(struct task_struct *tsk) | ||
1028 | { | ||
1029 | WARN_ON(tsk->thread.ds_ctx); | ||
1030 | } | ||
diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c index 605eff9a8ac0..3ba155d24884 100644 --- a/arch/x86/kernel/process_32.c +++ b/arch/x86/kernel/process_32.c | |||
@@ -60,6 +60,7 @@ | |||
60 | #include <asm/idle.h> | 60 | #include <asm/idle.h> |
61 | #include <asm/syscalls.h> | 61 | #include <asm/syscalls.h> |
62 | #include <asm/smp.h> | 62 | #include <asm/smp.h> |
63 | #include <asm/ds.h> | ||
63 | 64 | ||
64 | asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); | 65 | asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); |
65 | 66 | ||
@@ -251,17 +252,8 @@ void exit_thread(void) | |||
251 | tss->x86_tss.io_bitmap_base = INVALID_IO_BITMAP_OFFSET; | 252 | tss->x86_tss.io_bitmap_base = INVALID_IO_BITMAP_OFFSET; |
252 | put_cpu(); | 253 | put_cpu(); |
253 | } | 254 | } |
254 | #ifdef CONFIG_X86_DS | 255 | |
255 | /* Free any BTS tracers that have not been properly released. */ | 256 | ds_exit_thread(current); |
256 | if (unlikely(current->bts)) { | ||
257 | ds_release_bts(current->bts); | ||
258 | current->bts = NULL; | ||
259 | |||
260 | kfree(current->bts_buffer); | ||
261 | current->bts_buffer = NULL; | ||
262 | current->bts_size = 0; | ||
263 | } | ||
264 | #endif /* CONFIG_X86_DS */ | ||
265 | } | 257 | } |
266 | 258 | ||
267 | void flush_thread(void) | 259 | void flush_thread(void) |
@@ -343,6 +335,12 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp, | |||
343 | kfree(p->thread.io_bitmap_ptr); | 335 | kfree(p->thread.io_bitmap_ptr); |
344 | p->thread.io_bitmap_max = 0; | 336 | p->thread.io_bitmap_max = 0; |
345 | } | 337 | } |
338 | |||
339 | ds_copy_thread(p, current); | ||
340 | |||
341 | clear_tsk_thread_flag(p, TIF_DEBUGCTLMSR); | ||
342 | p->thread.debugctlmsr = 0; | ||
343 | |||
346 | return err; | 344 | return err; |
347 | } | 345 | } |
348 | 346 | ||
diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c index 1cfd2a4bf853..416fb9282f4f 100644 --- a/arch/x86/kernel/process_64.c +++ b/arch/x86/kernel/process_64.c | |||
@@ -53,6 +53,7 @@ | |||
53 | #include <asm/ia32.h> | 53 | #include <asm/ia32.h> |
54 | #include <asm/idle.h> | 54 | #include <asm/idle.h> |
55 | #include <asm/syscalls.h> | 55 | #include <asm/syscalls.h> |
56 | #include <asm/ds.h> | ||
56 | 57 | ||
57 | asmlinkage extern void ret_from_fork(void); | 58 | asmlinkage extern void ret_from_fork(void); |
58 | 59 | ||
@@ -236,17 +237,8 @@ void exit_thread(void) | |||
236 | t->io_bitmap_max = 0; | 237 | t->io_bitmap_max = 0; |
237 | put_cpu(); | 238 | put_cpu(); |
238 | } | 239 | } |
239 | #ifdef CONFIG_X86_DS | 240 | |
240 | /* Free any BTS tracers that have not been properly released. */ | 241 | ds_exit_thread(current); |
241 | if (unlikely(current->bts)) { | ||
242 | ds_release_bts(current->bts); | ||
243 | current->bts = NULL; | ||
244 | |||
245 | kfree(current->bts_buffer); | ||
246 | current->bts_buffer = NULL; | ||
247 | current->bts_size = 0; | ||
248 | } | ||
249 | #endif /* CONFIG_X86_DS */ | ||
250 | } | 242 | } |
251 | 243 | ||
252 | void flush_thread(void) | 244 | void flush_thread(void) |
@@ -376,6 +368,12 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp, | |||
376 | if (err) | 368 | if (err) |
377 | goto out; | 369 | goto out; |
378 | } | 370 | } |
371 | |||
372 | ds_copy_thread(p, me); | ||
373 | |||
374 | clear_tsk_thread_flag(p, TIF_DEBUGCTLMSR); | ||
375 | p->thread.debugctlmsr = 0; | ||
376 | |||
379 | err = 0; | 377 | err = 0; |
380 | out: | 378 | out: |
381 | if (err && p->thread.io_bitmap_ptr) { | 379 | if (err && p->thread.io_bitmap_ptr) { |
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c index 45e9855da2d2..6ad2bb607650 100644 --- a/arch/x86/kernel/ptrace.c +++ b/arch/x86/kernel/ptrace.c | |||
@@ -769,8 +769,47 @@ static int ptrace_bts_size(struct task_struct *child) | |||
769 | 769 | ||
770 | return (trace->ds.top - trace->ds.begin) / trace->ds.size; | 770 | return (trace->ds.top - trace->ds.begin) / trace->ds.size; |
771 | } | 771 | } |
772 | |||
773 | static void ptrace_bts_fork(struct task_struct *tsk) | ||
774 | { | ||
775 | tsk->bts = NULL; | ||
776 | tsk->bts_buffer = NULL; | ||
777 | tsk->bts_size = 0; | ||
778 | tsk->thread.bts_ovfl_signal = 0; | ||
779 | } | ||
780 | |||
781 | static void ptrace_bts_untrace(struct task_struct *child) | ||
782 | { | ||
783 | if (unlikely(child->bts)) { | ||
784 | ds_release_bts(child->bts); | ||
785 | child->bts = NULL; | ||
786 | |||
787 | kfree(child->bts_buffer); | ||
788 | child->bts_buffer = NULL; | ||
789 | child->bts_size = 0; | ||
790 | } | ||
791 | } | ||
792 | |||
793 | static void ptrace_bts_detach(struct task_struct *child) | ||
794 | { | ||
795 | ptrace_bts_untrace(child); | ||
796 | } | ||
797 | #else | ||
798 | static inline void ptrace_bts_fork(struct task_struct *tsk) {} | ||
799 | static inline void ptrace_bts_detach(struct task_struct *child) {} | ||
800 | static inline void ptrace_bts_untrace(struct task_struct *child) {} | ||
772 | #endif /* CONFIG_X86_PTRACE_BTS */ | 801 | #endif /* CONFIG_X86_PTRACE_BTS */ |
773 | 802 | ||
803 | void x86_ptrace_fork(struct task_struct *child, unsigned long clone_flags) | ||
804 | { | ||
805 | ptrace_bts_fork(child); | ||
806 | } | ||
807 | |||
808 | void x86_ptrace_untrace(struct task_struct *child) | ||
809 | { | ||
810 | ptrace_bts_untrace(child); | ||
811 | } | ||
812 | |||
774 | /* | 813 | /* |
775 | * Called by kernel/ptrace.c when detaching.. | 814 | * Called by kernel/ptrace.c when detaching.. |
776 | * | 815 | * |
@@ -782,16 +821,7 @@ void ptrace_disable(struct task_struct *child) | |||
782 | #ifdef TIF_SYSCALL_EMU | 821 | #ifdef TIF_SYSCALL_EMU |
783 | clear_tsk_thread_flag(child, TIF_SYSCALL_EMU); | 822 | clear_tsk_thread_flag(child, TIF_SYSCALL_EMU); |
784 | #endif | 823 | #endif |
785 | #ifdef CONFIG_X86_PTRACE_BTS | 824 | ptrace_bts_detach(child); |
786 | if (child->bts) { | ||
787 | ds_release_bts(child->bts); | ||
788 | child->bts = NULL; | ||
789 | |||
790 | kfree(child->bts_buffer); | ||
791 | child->bts_buffer = NULL; | ||
792 | child->bts_size = 0; | ||
793 | } | ||
794 | #endif /* CONFIG_X86_PTRACE_BTS */ | ||
795 | } | 825 | } |
796 | 826 | ||
797 | #if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION | 827 | #if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION |
diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h index 22641d5d45df..98b93ca4db06 100644 --- a/include/linux/ptrace.h +++ b/include/linux/ptrace.h | |||
@@ -94,6 +94,7 @@ extern void ptrace_notify(int exit_code); | |||
94 | extern void __ptrace_link(struct task_struct *child, | 94 | extern void __ptrace_link(struct task_struct *child, |
95 | struct task_struct *new_parent); | 95 | struct task_struct *new_parent); |
96 | extern void __ptrace_unlink(struct task_struct *child); | 96 | extern void __ptrace_unlink(struct task_struct *child); |
97 | extern void ptrace_fork(struct task_struct *task, unsigned long clone_flags); | ||
97 | #define PTRACE_MODE_READ 1 | 98 | #define PTRACE_MODE_READ 1 |
98 | #define PTRACE_MODE_ATTACH 2 | 99 | #define PTRACE_MODE_ATTACH 2 |
99 | /* Returns 0 on success, -errno on denial. */ | 100 | /* Returns 0 on success, -errno on denial. */ |
@@ -313,6 +314,27 @@ static inline void user_enable_block_step(struct task_struct *task) | |||
313 | #define arch_ptrace_stop(code, info) do { } while (0) | 314 | #define arch_ptrace_stop(code, info) do { } while (0) |
314 | #endif | 315 | #endif |
315 | 316 | ||
317 | #ifndef arch_ptrace_untrace | ||
318 | /* | ||
319 | * Do machine-specific work before untracing child. | ||
320 | * | ||
321 | * This is called for a normal detach as well as from ptrace_exit() | ||
322 | * when the tracing task dies. | ||
323 | * | ||
324 | * Called with write_lock(&tasklist_lock) held. | ||
325 | */ | ||
326 | #define arch_ptrace_untrace(task) do { } while (0) | ||
327 | #endif | ||
328 | |||
329 | #ifndef arch_ptrace_fork | ||
330 | /* | ||
331 | * Do machine-specific work to initialize a new task. | ||
332 | * | ||
333 | * This is called from copy_process(). | ||
334 | */ | ||
335 | #define arch_ptrace_fork(child, clone_flags) do { } while (0) | ||
336 | #endif | ||
337 | |||
316 | extern int task_current_syscall(struct task_struct *target, long *callno, | 338 | extern int task_current_syscall(struct task_struct *target, long *callno, |
317 | unsigned long args[6], unsigned int maxargs, | 339 | unsigned long args[6], unsigned int maxargs, |
318 | unsigned long *sp, unsigned long *pc); | 340 | unsigned long *sp, unsigned long *pc); |
diff --git a/kernel/fork.c b/kernel/fork.c index 7b93da72d4a2..65ce60adc8e8 100644 --- a/kernel/fork.c +++ b/kernel/fork.c | |||
@@ -1096,6 +1096,8 @@ static struct task_struct *copy_process(unsigned long clone_flags, | |||
1096 | #ifdef CONFIG_DEBUG_MUTEXES | 1096 | #ifdef CONFIG_DEBUG_MUTEXES |
1097 | p->blocked_on = NULL; /* not blocked yet */ | 1097 | p->blocked_on = NULL; /* not blocked yet */ |
1098 | #endif | 1098 | #endif |
1099 | if (unlikely(ptrace_reparented(current))) | ||
1100 | ptrace_fork(p, clone_flags); | ||
1099 | 1101 | ||
1100 | /* Perform scheduler related setup. Assign this task to a CPU. */ | 1102 | /* Perform scheduler related setup. Assign this task to a CPU. */ |
1101 | sched_fork(p, clone_flags); | 1103 | sched_fork(p, clone_flags); |
diff --git a/kernel/ptrace.c b/kernel/ptrace.c index 4c8bcd7dd8e0..100a71cfdaba 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c | |||
@@ -25,6 +25,17 @@ | |||
25 | #include <asm/pgtable.h> | 25 | #include <asm/pgtable.h> |
26 | #include <asm/uaccess.h> | 26 | #include <asm/uaccess.h> |
27 | 27 | ||
28 | |||
29 | /* | ||
30 | * Initialize a new task whose father had been ptraced. | ||
31 | * | ||
32 | * Called from copy_process(). | ||
33 | */ | ||
34 | void ptrace_fork(struct task_struct *child, unsigned long clone_flags) | ||
35 | { | ||
36 | arch_ptrace_fork(child, clone_flags); | ||
37 | } | ||
38 | |||
28 | /* | 39 | /* |
29 | * ptrace a task: make the debugger its new parent and | 40 | * ptrace a task: make the debugger its new parent and |
30 | * move it to the ptrace list. | 41 | * move it to the ptrace list. |
@@ -72,6 +83,7 @@ void __ptrace_unlink(struct task_struct *child) | |||
72 | child->parent = child->real_parent; | 83 | child->parent = child->real_parent; |
73 | list_del_init(&child->ptrace_entry); | 84 | list_del_init(&child->ptrace_entry); |
74 | 85 | ||
86 | arch_ptrace_untrace(child); | ||
75 | if (task_is_traced(child)) | 87 | if (task_is_traced(child)) |
76 | ptrace_untrace(child); | 88 | ptrace_untrace(child); |
77 | } | 89 | } |