Skip to content

Commit 07183aa

Browse files
committed
tracing: Fix trace_marker copy link list updates
When the "copy_trace_marker" option is enabled for an instance, anything written into /sys/kernel/tracing/trace_marker is also copied into that instances buffer. When the option is set, that instance's trace_array descriptor is added to the marker_copies link list. This list is protected by RCU, as all iterations uses an RCU protected list traversal. When the instance is deleted, all the flags that were enabled are cleared. This also clears the copy_trace_marker flag and removes the trace_array descriptor from the list. The issue is after the flags are called, a direct call to update_marker_trace() is performed to clear the flag. This function returns true if the state of the flag changed and false otherwise. If it returns true here, synchronize_rcu() is called to make sure all readers see that its removed from the list. But since the flag was already cleared, the state does not change and the synchronization is never called, leaving a possible UAF bug. Move the clearing of all flags below the updating of the copy_trace_marker option which then makes sure the synchronization is performed. Also use the flag for checking the state in update_marker_trace() instead of looking at if the list is empty. Cc: [email protected] Cc: Masami Hiramatsu <[email protected]> Cc: Mathieu Desnoyers <[email protected]> Link: https://patch.msgid.link/[email protected] Fixes: 7b382ef ("tracing: Allow the top level trace_marker to write into another instances") Reported-by: Sasha Levin <[email protected]> Closes: https://lore.kernel.org/all/[email protected]/ Signed-off-by: Steven Rostedt (Google) <[email protected]>
1 parent edca33a commit 07183aa

1 file changed

Lines changed: 10 additions & 9 deletions

File tree

kernel/trace/trace.c

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -555,18 +555,18 @@ static bool update_marker_trace(struct trace_array *tr, int enabled)
555555
lockdep_assert_held(&event_mutex);
556556

557557
if (enabled) {
558-
if (!list_empty(&tr->marker_list))
558+
if (tr->trace_flags & TRACE_ITER(COPY_MARKER))
559559
return false;
560560

561561
list_add_rcu(&tr->marker_list, &marker_copies);
562562
tr->trace_flags |= TRACE_ITER(COPY_MARKER);
563563
return true;
564564
}
565565

566-
if (list_empty(&tr->marker_list))
566+
if (!(tr->trace_flags & TRACE_ITER(COPY_MARKER)))
567567
return false;
568568

569-
list_del_init(&tr->marker_list);
569+
list_del_rcu(&tr->marker_list);
570570
tr->trace_flags &= ~TRACE_ITER(COPY_MARKER);
571571
return true;
572572
}
@@ -9761,18 +9761,19 @@ static int __remove_instance(struct trace_array *tr)
97619761

97629762
list_del(&tr->list);
97639763

9764-
/* Disable all the flags that were enabled coming in */
9765-
for (i = 0; i < TRACE_FLAGS_MAX_SIZE; i++) {
9766-
if ((1ULL << i) & ZEROED_TRACE_FLAGS)
9767-
set_tracer_flag(tr, 1ULL << i, 0);
9768-
}
9769-
97709764
if (printk_trace == tr)
97719765
update_printk_trace(&global_trace);
97729766

9767+
/* Must be done before disabling all the flags */
97739768
if (update_marker_trace(tr, 0))
97749769
synchronize_rcu();
97759770

9771+
/* Disable all the flags that were enabled coming in */
9772+
for (i = 0; i < TRACE_FLAGS_MAX_SIZE; i++) {
9773+
if ((1ULL << i) & ZEROED_TRACE_FLAGS)
9774+
set_tracer_flag(tr, 1ULL << i, 0);
9775+
}
9776+
97769777
tracing_set_nop(tr);
97779778
clear_ftrace_function_probes(tr);
97789779
event_trace_del_tracer(tr);

0 commit comments

Comments
 (0)