• J
    perf/x86/intel: Fix race in intel_pmu_disable_event() · 6f55967a
    Jiri Olsa 提交于
    New race in x86_pmu_stop() was introduced by replacing the
    atomic __test_and_clear_bit() of cpuc->active_mask by separate
    test_bit() and __clear_bit() calls in the following commit:
    
      3966c3fe ("x86/perf/amd: Remove need to check "running" bit in NMI handler")
    
    The race causes panic for PEBS events with enabled callchains:
    
      BUG: unable to handle kernel NULL pointer dereference at 0000000000000000
      ...
      RIP: 0010:perf_prepare_sample+0x8c/0x530
      Call Trace:
       <NMI>
       perf_event_output_forward+0x2a/0x80
       __perf_event_overflow+0x51/0xe0
       handle_pmi_common+0x19e/0x240
       intel_pmu_handle_irq+0xad/0x170
       perf_event_nmi_handler+0x2e/0x50
       nmi_handle+0x69/0x110
       default_do_nmi+0x3e/0x100
       do_nmi+0x11a/0x180
       end_repeat_nmi+0x16/0x1a
      RIP: 0010:native_write_msr+0x6/0x20
      ...
       </NMI>
       intel_pmu_disable_event+0x98/0xf0
       x86_pmu_stop+0x6e/0xb0
       x86_pmu_del+0x46/0x140
       event_sched_out.isra.97+0x7e/0x160
      ...
    
    The event is configured to make samples from PEBS drain code,
    but when it's disabled, we'll go through NMI path instead,
    where data->callchain will not get allocated and we'll crash:
    
              x86_pmu_stop
                test_bit(hwc->idx, cpuc->active_mask)
                intel_pmu_disable_event(event)
                {
                  ...
                  intel_pmu_pebs_disable(event);
                  ...
    
    EVENT OVERFLOW ->  <NMI>
                         intel_pmu_handle_irq
                           handle_pmi_common
       TEST PASSES ->        test_bit(bit, cpuc->active_mask))
                               perf_event_overflow
                                 perf_prepare_sample
                                 {
                                   ...
                                   if (!(sample_type & __PERF_SAMPLE_CALLCHAIN_EARLY))
                                         data->callchain = perf_callchain(event, regs);
    
             CRASH ->              size += data->callchain->nr;
                                 }
                       </NMI>
                  ...
                  x86_pmu_disable_event(event)
                }
    
                __clear_bit(hwc->idx, cpuc->active_mask);
    
    Fixing this by disabling the event itself before setting
    off the PEBS bit.
    Signed-off-by: NJiri Olsa <jolsa@kernel.org>
    Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
    Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
    Cc: David Arcari <darcari@redhat.com>
    Cc: Jiri Olsa <jolsa@redhat.com>
    Cc: Lendacky Thomas <Thomas.Lendacky@amd.com>
    Cc: Linus Torvalds <torvalds@linux-foundation.org>
    Cc: Peter Zijlstra <peterz@infradead.org>
    Cc: Stephane Eranian <eranian@google.com>
    Cc: Thomas Gleixner <tglx@linutronix.de>
    Cc: Vince Weaver <vincent.weaver@maine.edu>
    Fixes: 3966c3fe ("x86/perf/amd: Remove need to check "running" bit in NMI handler")
    Link: http://lkml.kernel.org/r/20190504151556.31031-1-jolsa@kernel.orgSigned-off-by: NIngo Molnar <mingo@kernel.org>
    6f55967a
core.c 134.7 KB