diff options
Diffstat (limited to 'arch/x86/kernel/process_32.c')
-rw-r--r-- | arch/x86/kernel/process_32.c | 26 |
1 files changed, 2 insertions, 24 deletions
diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c index 209e74801763..d5bd3132ee70 100644 --- a/arch/x86/kernel/process_32.c +++ b/arch/x86/kernel/process_32.c | |||
@@ -59,7 +59,6 @@ | |||
59 | #include <asm/syscalls.h> | 59 | #include <asm/syscalls.h> |
60 | #include <asm/ds.h> | 60 | #include <asm/ds.h> |
61 | #include <asm/debugreg.h> | 61 | #include <asm/debugreg.h> |
62 | #include <asm/hw_breakpoint.h> | ||
63 | 62 | ||
64 | asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); | 63 | asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); |
65 | 64 | ||
@@ -264,9 +263,8 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, | |||
264 | p->thread.io_bitmap_ptr = NULL; | 263 | p->thread.io_bitmap_ptr = NULL; |
265 | tsk = current; | 264 | tsk = current; |
266 | err = -ENOMEM; | 265 | err = -ENOMEM; |
267 | if (unlikely(test_tsk_thread_flag(tsk, TIF_DEBUG))) | 266 | |
268 | if (copy_thread_hw_breakpoint(tsk, p, clone_flags)) | 267 | memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps)); |
269 | goto out; | ||
270 | 268 | ||
271 | if (unlikely(test_tsk_thread_flag(tsk, TIF_IO_BITMAP))) { | 269 | if (unlikely(test_tsk_thread_flag(tsk, TIF_IO_BITMAP))) { |
272 | p->thread.io_bitmap_ptr = kmemdup(tsk->thread.io_bitmap_ptr, | 270 | p->thread.io_bitmap_ptr = kmemdup(tsk->thread.io_bitmap_ptr, |
@@ -287,13 +285,10 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, | |||
287 | err = do_set_thread_area(p, -1, | 285 | err = do_set_thread_area(p, -1, |
288 | (struct user_desc __user *)childregs->si, 0); | 286 | (struct user_desc __user *)childregs->si, 0); |
289 | 287 | ||
290 | out: | ||
291 | if (err && p->thread.io_bitmap_ptr) { | 288 | if (err && p->thread.io_bitmap_ptr) { |
292 | kfree(p->thread.io_bitmap_ptr); | 289 | kfree(p->thread.io_bitmap_ptr); |
293 | p->thread.io_bitmap_max = 0; | 290 | p->thread.io_bitmap_max = 0; |
294 | } | 291 | } |
295 | if (err) | ||
296 | flush_thread_hw_breakpoint(p); | ||
297 | 292 | ||
298 | clear_tsk_thread_flag(p, TIF_DS_AREA_MSR); | 293 | clear_tsk_thread_flag(p, TIF_DS_AREA_MSR); |
299 | p->thread.ds_ctx = NULL; | 294 | p->thread.ds_ctx = NULL; |
@@ -437,23 +432,6 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) | |||
437 | lazy_load_gs(next->gs); | 432 | lazy_load_gs(next->gs); |
438 | 433 | ||
439 | percpu_write(current_task, next_p); | 434 | percpu_write(current_task, next_p); |
440 | /* | ||
441 | * There's a problem with moving the arch_install_thread_hw_breakpoint() | ||
442 | * call before current is updated. Suppose a kernel breakpoint is | ||
443 | * triggered in between the two, the hw-breakpoint handler will see that | ||
444 | * the 'current' task does not have TIF_DEBUG flag set and will think it | ||
445 | * is leftover from an old task (lazy switching) and will erase it. Then | ||
446 | * until the next context switch, no user-breakpoints will be installed. | ||
447 | * | ||
448 | * The real problem is that it's impossible to update both current and | ||
449 | * physical debug registers at the same instant, so there will always be | ||
450 | * a window in which they disagree and a breakpoint might get triggered. | ||
451 | * Since we use lazy switching, we are forced to assume that a | ||
452 | * disagreement means that current is correct and the exception is due | ||
453 | * to lazy debug register switching. | ||
454 | */ | ||
455 | if (unlikely(test_tsk_thread_flag(next_p, TIF_DEBUG))) | ||
456 | arch_install_thread_hw_breakpoint(next_p); | ||
457 | 435 | ||
458 | return prev_p; | 436 | return prev_p; |
459 | } | 437 | } |