mirror of
https://github.com/torvalds/linux.git
synced 2026-09-14 16:10:02 +02:00
The following sequence may leads race between event_define_fields()
and update_event_fields():
CPU0 (loads module A) CPU1 (loads module B)
=============================== ===============================
load_module(A) load_module(B)
notifier_call_chain notifier_call_chain
trace_module_notify trace_module_notify
mutex_lock(&event_mutex) trace_event_update_all()
trace_module_add_events(A) down_write(&trace_event_sem)
__register_event(call_A)
__add_event_to_tracers(call_A)
event_define_fields(call_A)
for each f: list_for_each_entry(field,
list_add(&f->link, &class->fields, link)
&class->fields) field = class->fields->next;
Where access to the class->fields is not protected by the event_mutex in
trace_event_update_all().
This produces the following panic:
Unable to handle kernel access ... at virtual address 0000000000000018
pc : update_event_fields+0xf8/0x368
Call trace:
update_event_fields+0xf8/0x368
trace_event_update_all+0x7c/0x2b4
trace_module_notify+0x4c/0x1dc
notifier_call_chain+0x84/0x168
blocking_notifier_call_chain_robust+0x64/0xd4
load_module+0x10c8/0x123c
__arm64_sys_finit_module+0x230/0x31c
Fix by taking event_mutex in trace_event_update_all() before
trace_event_sem.
Cc: stable@vger.kernel.org
Fixes:
|
||
|---|---|---|
| .. | ||
| rv | ||
| blktrace.c | ||
| bpf_trace.c | ||
| bpf_trace.h | ||
| error_report-traces.c | ||
| fgraph.c | ||
| fprobe.c | ||
| ftrace_internal.h | ||
| ftrace.c | ||
| Kconfig | ||
| kprobe_event_gen_test.c | ||
| Makefile | ||
| pid_list.c | ||
| pid_list.h | ||
| power-traces.c | ||
| preemptirq_delay_test.c | ||
| remote_test_events.h | ||
| remote_test.c | ||
| rethook.c | ||
| ring_buffer_benchmark.c | ||
| ring_buffer.c | ||
| rpm-traces.c | ||
| simple_ring_buffer.c | ||
| synth_event_gen_test.c | ||
| trace_benchmark.c | ||
| trace_benchmark.h | ||
| trace_boot.c | ||
| trace_branch.c | ||
| trace_btf.c | ||
| trace_btf.h | ||
| trace_clock.c | ||
| trace_dynevent.c | ||
| trace_dynevent.h | ||
| trace_entries.h | ||
| trace_eprobe.c | ||
| trace_event_perf.c | ||
| trace_events_filter_test.h | ||
| trace_events_filter.c | ||
| trace_events_hist.c | ||
| trace_events_inject.c | ||
| trace_events_synth.c | ||
| trace_events_trigger.c | ||
| trace_events_user.c | ||
| trace_events.c | ||
| trace_export.c | ||
| trace_fprobe.c | ||
| trace_functions_graph.c | ||
| trace_functions.c | ||
| trace_hwlat.c | ||
| trace_irqsoff.c | ||
| trace_kdb.c | ||
| trace_kprobe_selftest.c | ||
| trace_kprobe_selftest.h | ||
| trace_kprobe.c | ||
| trace_mmiotrace.c | ||
| trace_nop.c | ||
| trace_osnoise.c | ||
| trace_output.c | ||
| trace_output.h | ||
| trace_pid.c | ||
| trace_preemptirq.c | ||
| trace_printk.c | ||
| trace_probe_kernel.h | ||
| trace_probe_tmpl.h | ||
| trace_probe.c | ||
| trace_probe.h | ||
| trace_recursion_record.c | ||
| trace_remote.c | ||
| trace_sched_switch.c | ||
| trace_sched_wakeup.c | ||
| trace_selftest_dynamic.c | ||
| trace_selftest.c | ||
| trace_seq.c | ||
| trace_snapshot.c | ||
| trace_stack.c | ||
| trace_stat.c | ||
| trace_stat.h | ||
| trace_synth.h | ||
| trace_syscalls.c | ||
| trace_uprobe.c | ||
| trace.c | ||
| trace.h | ||
| tracing_map.c | ||
| tracing_map.h | ||
| undefsyms_base.c | ||