On 2025/1/3 23:22, Jiri Olsa wrote:
On Tue, Dec 31, 2024 at 03:35:09AM +0000, Pu Lehui wrote:
From: Pu Lehui <pulehui@xxxxxxxxxx>
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@xxxxxxxxxx>
---
kernel/trace/bpf_trace.c | 18 +++++++++++-------
1 file changed, 11 insertions(+), 7 deletions(-)
diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
index 48db147c6c7d..30ef8a6f5ca2 100644
--- a/kernel/trace/bpf_trace.c
+++ b/kernel/trace/bpf_trace.c
@@ -2245,12 +2245,15 @@ void perf_event_detach_bpf_prog(struct perf_event *event)
{
struct bpf_prog_array *old_array;
struct bpf_prog_array *new_array;
+ struct bpf_prog *prog;
int ret;
mutex_lock(&bpf_event_mutex);
- if (!event->prog)
- goto unlock;
+ if (!event->prog) {
+ mutex_unlock(&bpf_event_mutex);
+ return;
+ }
old_array = bpf_event_rcu_dereference(event->tp_event->prog_array);
if (!old_array)
@@ -2265,6 +2268,11 @@ void perf_event_detach_bpf_prog(struct perf_event *event)
}
put:
+ prog = event->prog;
+ event->prog = NULL;
+
+ mutex_unlock(&bpf_event_mutex);
+
/*
* It could be that the bpf_prog is not sleepable (and will be freed
* via normal RCU), but is called from a point that supports sleepable
@@ -2272,11 +2280,7 @@ void perf_event_detach_bpf_prog(struct perf_event *event)
*/
synchronize_rcu_tasks_trace();
- bpf_prog_put(event->prog);
- event->prog = NULL;
-
-unlock:
- mutex_unlock(&bpf_event_mutex);
+ bpf_prog_put(prog);
}
int perf_event_query_prog_array(struct perf_event *event, void __user *info)
--
2.34.1
would something like below be simpler? (not tested)
jirka
---
diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
index 973104f861e9..a4c0efa3a26e 100644
--- a/kernel/trace/bpf_trace.c
+++ b/kernel/trace/bpf_trace.c
@@ -2246,6 +2246,7 @@ void perf_event_detach_bpf_prog(struct perf_event *event)
{
struct bpf_prog_array *old_array;
struct bpf_prog_array *new_array;
+ struct bpf_prog *prog = NULL;
int ret;
mutex_lock(&bpf_event_mutex);
@@ -2266,18 +2267,22 @@ void perf_event_detach_bpf_prog(struct perf_event *event)
}
put:
- /*
- * It could be that the bpf_prog is not sleepable (and will be freed
- * via normal RCU), but is called from a point that supports sleepable
- * programs and uses tasks-trace-RCU.
- */
- synchronize_rcu_tasks_trace();
-
- bpf_prog_put(event->prog);
+ prog = event->prog;
event->prog = NULL;
unlock:
mutex_unlock(&bpf_event_mutex);
+
+ if (prog) {
+ /*
+ * It could be that the bpf_prog is not sleepable (and will be freed
+ * via normal RCU), but is called from a point that supports sleepable
+ * programs and uses tasks-trace-RCU.
+ */
+ synchronize_rcu_tasks_trace();
+
+ bpf_prog_put(prog);
+ }
}
int perf_event_query_prog_array(struct perf_event *event, void __user *info)
Thanks for review. It looks better, will send it soon.