Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

tracing: Fix tracing_marker may trigger page fault during preempt_disable

Both tracing_mark_write and tracing_mark_raw_write call
__copy_from_user_inatomic during preempt_disable. But in some case,
__copy_from_user_inatomic may trigger page fault, and will call schedule()
subtly. And if a task is migrated to other cpu, the following warning will
be trigger:
if (RB_WARN_ON(cpu_buffer,
!local_read(&cpu_buffer->committing)))

An example can illustrate this issue:

process flow CPU
---------------------------------------------------------------------

tracing_mark_raw_write(): cpu:0
...
ring_buffer_lock_reserve(): cpu:0
...
cpu = raw_smp_processor_id() cpu:0
cpu_buffer = buffer->buffers[cpu] cpu:0
...
...
__copy_from_user_inatomic(): cpu:0
...
# page fault
do_mem_abort(): cpu:0
...
# Call schedule
schedule() cpu:0
...
# the task schedule to cpu1
__buffer_unlock_commit(): cpu:1
...
ring_buffer_unlock_commit(): cpu:1
...
cpu = raw_smp_processor_id() cpu:1
cpu_buffer = buffer->buffers[cpu] cpu:1

As shown above, the process will acquire cpuid twice and the return values
are not the same.

To fix this problem using copy_from_user_nofault instead of
__copy_from_user_inatomic, as the former performs 'access_ok' before
copying.

Link: https://lore.kernel.org/20250819105152.2766363-1-luogengkun@huaweicloud.com
Fixes: 656c7f0d2d2b ("tracing: Replace kmap with copy_from_user() in trace_marker writing")
Signed-off-by: Luo Gengkun <luogengkun@huaweicloud.com>
Reviewed-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>

authored by

Luo Gengkun and committed by
Steven Rostedt (Google)
3d62ab32 81ac6332

+2 -2
+2 -2
kernel/trace/trace.c
··· 7209 7209 entry = ring_buffer_event_data(event); 7210 7210 entry->ip = ip; 7211 7211 7212 - len = __copy_from_user_inatomic(&entry->buf, ubuf, cnt); 7212 + len = copy_from_user_nofault(&entry->buf, ubuf, cnt); 7213 7213 if (len) { 7214 7214 memcpy(&entry->buf, FAULTED_STR, FAULTED_SIZE); 7215 7215 cnt = FAULTED_SIZE; ··· 7306 7306 7307 7307 entry = ring_buffer_event_data(event); 7308 7308 7309 - len = __copy_from_user_inatomic(&entry->id, ubuf, cnt); 7309 + len = copy_from_user_nofault(&entry->id, ubuf, cnt); 7310 7310 if (len) { 7311 7311 entry->id = -1; 7312 7312 memcpy(&entry->buf, FAULTED_STR, FAULTED_SIZE);