kernel_optimize_test/arch/nds32/kernel
Sean Christopherson 723acd75a0 perf: Protect perf_guest_cbs with RCU
commit ff083a2d972f56bebfd82409ca62e5dfce950961 upstream.

Protect perf_guest_cbs with RCU to fix multiple possible errors.  Luckily,
all paths that read perf_guest_cbs already require RCU protection, e.g. to
protect the callback chains, so only the direct perf_guest_cbs touchpoints
need to be modified.

Bug #1 is a simple lack of WRITE_ONCE/READ_ONCE behavior to ensure
perf_guest_cbs isn't reloaded between a !NULL check and a dereference.
Fixed via the READ_ONCE() in rcu_dereference().

Bug #2 is that on weakly-ordered architectures, updates to the callbacks
themselves are not guaranteed to be visible before the pointer is made
visible to readers.  Fixed by the smp_store_release() in
rcu_assign_pointer() when the new pointer is non-NULL.

Bug #3 is that, because the callbacks are global, it's possible for
readers to run in parallel with an unregisters, and thus a module
implementing the callbacks can be unloaded while readers are in flight,
resulting in a use-after-free.  Fixed by a synchronize_rcu() call when
unregistering callbacks.

Bug #1 escaped notice because it's extremely unlikely a compiler will
reload perf_guest_cbs in this sequence.  perf_guest_cbs does get reloaded
for future derefs, e.g. for ->is_user_mode(), but the ->is_in_guest()
guard all but guarantees the consumer will win the race, e.g. to nullify
perf_guest_cbs, KVM has to completely exit the guest and teardown down
all VMs before KVM start its module unload / unregister sequence.  This
also makes it all but impossible to encounter bug #3.

Bug #2 has not been a problem because all architectures that register
callbacks are strongly ordered and/or have a static set of callbacks.

But with help, unloading kvm_intel can trigger bug #1 e.g. wrapping
perf_guest_cbs with READ_ONCE in perf_misc_flags() while spamming
kvm_intel module load/unload leads to:

  BUG: kernel NULL pointer dereference, address: 0000000000000000
  #PF: supervisor read access in kernel mode
  #PF: error_code(0x0000) - not-present page
  PGD 0 P4D 0
  Oops: 0000 [#1] PREEMPT SMP
  CPU: 6 PID: 1825 Comm: stress Not tainted 5.14.0-rc2+ #459
  Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 0.0.0 02/06/2015
  RIP: 0010:perf_misc_flags+0x1c/0x70
  Call Trace:
   perf_prepare_sample+0x53/0x6b0
   perf_event_output_forward+0x67/0x160
   __perf_event_overflow+0x52/0xf0
   handle_pmi_common+0x207/0x300
   intel_pmu_handle_irq+0xcf/0x410
   perf_event_nmi_handler+0x28/0x50
   nmi_handle+0xc7/0x260
   default_do_nmi+0x6b/0x170
   exc_nmi+0x103/0x130
   asm_exc_nmi+0x76/0xbf

Fixes: 39447b386c ("perf: Enhance perf to allow for guest statistic collection from host")
Signed-off-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Cc: stable@vger.kernel.org
Link: https://lore.kernel.org/r/20211111020738.2512932-2-seanjc@google.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2022-01-20 09:17:50 +01:00
..
vdso arch: vdso: add vdso linker script to 'targets' instead of extra-y 2020-09-07 21:41:27 +09:00
.gitignore .gitignore: add SPDX License Identifier 2020-03-25 11:50:48 +01:00
asm-offsets.c
atl2c.c nds32: add NULL entry to the end of_device_id array 2018-09-04 14:45:15 +08:00
cacheinfo.c nds32: fix semicolon code style issue 2019-05-07 17:52:10 +08:00
devtree.c nds32: Device tree support 2018-02-22 10:44:34 +08:00
dma.c dma-mapping: merge <linux/dma-noncoherent.h> into <linux/dma-map-ops.h> 2020-10-06 07:07:06 +02:00
ex-entry.S nds32: nds32 FPU port 2018-11-22 18:13:13 +08:00
ex-exit.S sched/rt, nds32: Use CONFIG_PREEMPTION 2019-12-08 14:37:34 +01:00
ex-scall.S nds32: nds32 FPU port 2018-11-22 18:13:13 +08:00
fpu.c treewide: Use fallthrough pseudo-keyword 2020-08-23 17:36:59 -05:00
ftrace.c maccess: rename probe_kernel_{read,write} to copy_{from,to}_kernel_nofault 2020-06-17 10:57:41 -07:00
head.S mm: reorder includes after introduction of linux/pgtable.h 2020-06-09 09:39:13 -07:00
irq.c nds32: IRQ handling 2018-02-22 10:44:32 +08:00
Makefile treewide: Add SPDX license identifier - Makefile/Kconfig 2019-05-21 10:50:46 +02:00
module.c mm: introduce include/linux/pgtable.h 2020-06-09 09:39:13 -07:00
nds32_ksyms.c nds32: don't export low-level cache flushing routines 2019-05-16 14:40:26 +08:00
perf_event_cpu.c perf: Protect perf_guest_cbs with RCU 2022-01-20 09:17:50 +01:00
pm.c nds32: use pgtable-nopmd instead of 4level-fixup 2019-12-04 19:44:15 -08:00
process.c nds32: use uaccess_kernel in show_regs 2020-08-12 10:57:58 -07:00
ptrace.c nds32: switch to ->regset_get() 2020-07-27 14:31:11 -04:00
setup.c h8300, nds32, openrisc: simplify detection of memory extents 2020-10-13 18:38:35 -07:00
signal.c tracehook: clear TIF_NOTIFY_RESUME in tracehook_notify_resume() 2020-10-17 15:04:36 -06:00
sleep.S nds32: nds32 FPU port 2018-11-22 18:13:13 +08:00
stacktrace.c nds32: Add macro definition for offset of lp register on stack 2018-09-04 14:45:19 +08:00
sys_nds32.c nds32: Avoid IEX status being incorrectly modified 2019-05-31 15:23:26 +08:00
syscall_table.c nds32: System calls handling 2018-02-22 10:44:33 +08:00
time.c nds32: Generic timers support 2018-02-22 10:44:34 +08:00
traps.c kernel: rename show_stack_loglvl() => show_stack() 2020-06-09 09:39:13 -07:00
vdso.c mmap locking API: use coccinelle to convert mmap_sem rwsem call sites 2020-06-09 09:39:14 -07:00
vmlinux.lds.S vmlinux.lds.h: Split ELF_DETAILS from STABS_DEBUG 2020-09-01 09:50:35 +02:00