CVE-2023-53368
Fecha de publicación:
17/09/2025
*** Pendiente de traducción *** In the Linux kernel, the following vulnerability has been resolved:<br />
<br />
tracing: Fix race issue between cpu buffer write and swap<br />
<br />
Warning happened in rb_end_commit() at code:<br />
if (RB_WARN_ON(cpu_buffer, !local_read(&cpu_buffer->committing)))<br />
<br />
WARNING: CPU: 0 PID: 139 at kernel/trace/ring_buffer.c:3142<br />
rb_commit+0x402/0x4a0<br />
Call Trace:<br />
ring_buffer_unlock_commit+0x42/0x250<br />
trace_buffer_unlock_commit_regs+0x3b/0x250<br />
trace_event_buffer_commit+0xe5/0x440<br />
trace_event_buffer_reserve+0x11c/0x150<br />
trace_event_raw_event_sched_switch+0x23c/0x2c0<br />
__traceiter_sched_switch+0x59/0x80<br />
__schedule+0x72b/0x1580<br />
schedule+0x92/0x120<br />
worker_thread+0xa0/0x6f0<br />
<br />
It is because the race between writing event into cpu buffer and swapping<br />
cpu buffer through file per_cpu/cpu0/snapshot:<br />
<br />
Write on CPU 0 Swap buffer by per_cpu/cpu0/snapshot on CPU 1<br />
-------- --------<br />
tracing_snapshot_write()<br />
[...]<br />
<br />
ring_buffer_lock_reserve()<br />
cpu_buffer = buffer->buffers[cpu]; // 1. Suppose find &#39;cpu_buffer_a&#39;;<br />
[...]<br />
rb_reserve_next_event()<br />
[...]<br />
<br />
ring_buffer_swap_cpu()<br />
if (local_read(&cpu_buffer_a->committing))<br />
goto out_dec;<br />
if (local_read(&cpu_buffer_b->committing))<br />
goto out_dec;<br />
buffer_a->buffers[cpu] = cpu_buffer_b;<br />
buffer_b->buffers[cpu] = cpu_buffer_a;<br />
// 2. cpu_buffer has swapped here.<br />
<br />
rb_start_commit(cpu_buffer);<br />
if (unlikely(READ_ONCE(cpu_buffer->buffer)<br />
!= buffer)) { // 3. This check passed due to &#39;cpu_buffer->buffer&#39;<br />
[...] // has not changed here.<br />
return NULL;<br />
}<br />
cpu_buffer_b->buffer = buffer_a;<br />
cpu_buffer_a->buffer = buffer_b;<br />
[...]<br />
<br />
// 4. Reserve event from &#39;cpu_buffer_a&#39;.<br />
<br />
ring_buffer_unlock_commit()<br />
[...]<br />
cpu_buffer = buffer->buffers[cpu]; // 5. Now find &#39;cpu_buffer_b&#39; !!!<br />
rb_commit(cpu_buffer)<br />
rb_end_commit() // 6. WARN for the wrong &#39;committing&#39; state !!!<br />
<br />
Based on above analysis, we can easily reproduce by following testcase:<br />
``` bash<br />
#!/bin/bash<br />
<br />
dmesg -n 7<br />
sysctl -w kernel.panic_on_warn=1<br />
TR=/sys/kernel/tracing<br />
echo 7 > ${TR}/buffer_size_kb<br />
echo "sched:sched_switch" > ${TR}/set_event<br />
while [ true ]; do<br />
echo 1 > ${TR}/per_cpu/cpu0/snapshot<br />
done &<br />
while [ true ]; do<br />
echo 1 > ${TR}/per_cpu/cpu0/snapshot<br />
done &<br />
while [ true ]; do<br />
echo 1 > ${TR}/per_cpu/cpu0/snapshot<br />
done &<br />
```<br />
<br />
To fix it, IIUC, we can use smp_call_function_single() to do the swap on<br />
the target cpu where the buffer is located, so that above race would be<br />
avoided.
Gravedad: Pendiente de análisis
Última modificación:
17/09/2025