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

bpf: Move out synchronize_rcu_tasks_trace from mutex CS

Commit ef1b808e3b7c ("bpf: Fix UAF via mismatching bpf_prog/attachment
RCU flavors") resolved a possible UAF issue in uprobes that attach
non-sleepable bpf prog by explicitly waiting for a tasks-trace-RCU grace
period. But, in the current implementation, synchronize_rcu_tasks_trace
is included within the mutex critical section, which increases the
length of the critical section and may affect performance. So let's move
out synchronize_rcu_tasks_trace from mutex CS.

Signed-off-by: Pu Lehui <pulehui@huawei.com>
Reviewed-by: Jiri Olsa <jolsa@kernel.org>
Link: https://lore.kernel.org/r/20250104013946.1111785-1-pulehui@huaweicloud.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>

authored by

Pu Lehui and committed by
Alexei Starovoitov
ca3c4f64 b8b1e300

+13 -8
+13 -8
kernel/trace/bpf_trace.c
··· 2245 2245 { 2246 2246 struct bpf_prog_array *old_array; 2247 2247 struct bpf_prog_array *new_array; 2248 + struct bpf_prog *prog = NULL; 2248 2249 int ret; 2249 2250 2250 2251 mutex_lock(&bpf_event_mutex); ··· 2266 2265 } 2267 2266 2268 2267 put: 2269 - /* 2270 - * It could be that the bpf_prog is not sleepable (and will be freed 2271 - * via normal RCU), but is called from a point that supports sleepable 2272 - * programs and uses tasks-trace-RCU. 2273 - */ 2274 - synchronize_rcu_tasks_trace(); 2275 - 2276 - bpf_prog_put(event->prog); 2268 + prog = event->prog; 2277 2269 event->prog = NULL; 2278 2270 2279 2271 unlock: 2280 2272 mutex_unlock(&bpf_event_mutex); 2273 + 2274 + if (prog) { 2275 + /* 2276 + * It could be that the bpf_prog is not sleepable (and will be freed 2277 + * via normal RCU), but is called from a point that supports sleepable 2278 + * programs and uses tasks-trace-RCU. 2279 + */ 2280 + synchronize_rcu_tasks_trace(); 2281 + 2282 + bpf_prog_put(prog); 2283 + } 2281 2284 } 2282 2285 2283 2286 int perf_event_query_prog_array(struct perf_event *event, void __user *info)