• Prateek Sood's avatar
    tracing: Fix race in perf_trace_buf initialization · 6b1340cc
    Prateek Sood authored
    A race condition exists while initialiazing perf_trace_buf from
    perf_trace_init() and perf_kprobe_init().
    
          CPU0                                        CPU1
    perf_trace_init()
      mutex_lock(&event_mutex)
        perf_trace_event_init()
          perf_trace_event_reg()
            total_ref_count == 0
    	buf = alloc_percpu()
            perf_trace_buf[i] = buf
            tp_event->class->reg() //fails       perf_kprobe_init()
    	goto fail                              perf_trace_event_init()
                                                     perf_trace_event_reg()
            fail:
    	  total_ref_count == 0
    
                                                       total_ref_count == 0
                                                       buf = alloc_percpu()
                                                       perf_trace_buf[i] = buf
                                                       tp_event->class->reg()
                                                       total_ref_count++
    
              free_percpu(perf_trace_buf[i])
              perf_trace_buf[i] = NULL
    
    Any subsequent call to perf_trace_event_reg() will observe total_ref_count > 0,
    causing the perf_trace_buf to be always NULL. This can result in perf_trace_buf
    getting accessed from perf_trace_buf_alloc() without being initialized. Acquiring
    event_mutex in perf_kprobe_init() before calling perf_trace_event_init() should
    fix this race.
    
    The race caused the following bug:
    
     Unable to handle kernel paging request at virtual address 0000003106f2003c
     Mem abort info:
       ESR = 0x96000045
       Exception class = DABT (current EL), IL = 32 bits
       SET = 0, FnV = 0
       EA = 0, S1PTW = 0
     Data abort info:
       ISV = 0, ISS = 0x00000045
       CM = 0, WnR = 1
     user pgtable: 4k pages, 39-bit VAs, pgdp = ffffffc034b9b000
     [0000003106f2003c] pgd=0000000000000000, pud=0000000000000000
     Internal error: Oops: 96000045 [#1] PREEMPT SMP
     Process syz-executor (pid: 18393, stack limit = 0xffffffc093190000)
     pstate: 80400005 (Nzcv daif +PAN -UAO)
     pc : __memset+0x20/0x1ac
     lr : memset+0x3c/0x50
     sp : ffffffc09319fc50
    
      __memset+0x20/0x1ac
      perf_trace_buf_alloc+0x140/0x1a0
      perf_trace_sys_enter+0x158/0x310
      syscall_trace_enter+0x348/0x7c0
      el0_svc_common+0x11c/0x368
      el0_svc_handler+0x12c/0x198
      el0_svc+0x8/0xc
    
    Ramdumps showed the following:
      total_ref_count = 3
      perf_trace_buf = (
          0x0 -> NULL,
          0x0 -> NULL,
          0x0 -> NULL,
          0x0 -> NULL)
    
    Link: http://lkml.kernel.org/r/1571120245-4186-1-git-send-email-prsood@codeaurora.org
    
    Cc: stable@vger.kernel.org
    Fixes: e12f03d7 ("perf/core: Implement the 'perf_kprobe' PMU")
    Acked-by: default avatarSong Liu <songliubraving@fb.com>
    Signed-off-by: default avatarPrateek Sood <prsood@codeaurora.org>
    Signed-off-by: default avatarSteven Rostedt (VMware) <rostedt@goodmis.org>
    6b1340cc
trace_event_perf.c 12 KB