forked from mirrors/linux
		
	powerpc/hw_breakpoint: Fix oops when destroying hw_breakpoint event
When destroying a hw_breakpoint event, the kernel oopses as follows:
  Unable to handle kernel paging request for data at address 0x00000c07
  NIP [c0000000000291d0] arch_unregister_hw_breakpoint+0x40/0x60
  LR [c00000000020b6b4] release_bp_slot+0x44/0x80
Call chain:
  hw_breakpoint_event_init()
    bp->destroy = bp_perf_event_destroy;
  do_exit()
    perf_event_exit_task()
      perf_event_exit_task_context()
        WRITE_ONCE(child_ctx->task, TASK_TOMBSTONE);
        perf_event_exit_event()
          free_event()
            _free_event()
              bp_perf_event_destroy() // event->destroy(event);
                release_bp_slot()
                  arch_unregister_hw_breakpoint()
perf_event_exit_task_context() sets child_ctx->task as TASK_TOMBSTONE
which is (void *)-1. arch_unregister_hw_breakpoint() tries to fetch
'thread' attribute of 'task' resulting in oops.
Peterz points out that the code shouldn't be using bp->ctx anyway, but
fixing that will require a decent amount of rework. So for now to fix
the oops, check if bp->ctx->task has been set to (void *)-1, before
dereferencing it. We don't use TASK_TOMBSTONE, because that would
require exporting it and it's supposed to be an internal detail.
Fixes: 63b6da39bb ("perf: Fix perf_event_exit_task() race")
Signed-off-by: Ravi Bangoria <ravi.bangoria@linux.vnet.ibm.com>
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
			
			
This commit is contained in:
		
							parent
							
								
									923adb1646
								
							
						
					
					
						commit
						fb822e6076
					
				
					 1 changed files with 2 additions and 1 deletions
				
			
		|  | @ -109,8 +109,9 @@ void arch_unregister_hw_breakpoint(struct perf_event *bp) | ||||||
| 	 * If the breakpoint is unregistered between a hw_breakpoint_handler() | 	 * If the breakpoint is unregistered between a hw_breakpoint_handler() | ||||||
| 	 * and the single_step_dabr_instruction(), then cleanup the breakpoint | 	 * and the single_step_dabr_instruction(), then cleanup the breakpoint | ||||||
| 	 * restoration variables to prevent dangling pointers. | 	 * restoration variables to prevent dangling pointers. | ||||||
|  | 	 * FIXME, this should not be using bp->ctx at all! Sayeth peterz. | ||||||
| 	 */ | 	 */ | ||||||
| 	if (bp->ctx && bp->ctx->task) | 	if (bp->ctx && bp->ctx->task && bp->ctx->task != ((void *)-1L)) | ||||||
| 		bp->ctx->task->thread.last_hit_ubp = NULL; | 		bp->ctx->task->thread.last_hit_ubp = NULL; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Ravi Bangoria
						Ravi Bangoria