Skip to content

Commit 1eafbd4

Browse files
mokomullSomasundaram Krishnasamy
authored andcommitted
bpf: fix nested bpf tracepoints with per-cpu data
BPF_PROG_TYPE_RAW_TRACEPOINTs can be executed nested on the same CPU, as they do not increment bpf_prog_active while executing. This enables three levels of nesting, to support - a kprobe or raw tp or perf event, - another one of the above that irq context happens to call, and - another one in nmi context (at most one of which may be a kprobe or perf event). Fixes: 20b9d7a ("bpf: avoid excessive stack usage for perf_sample_data") Signed-off-by: Matt Mullins <[email protected]> Acked-by: Andrii Nakryiko <[email protected]> Acked-by: Daniel Borkmann <[email protected]> Signed-off-by: Alexei Starovoitov <[email protected]> (cherry picked from commit 9594dc3) Orabug: 31865809 Signed-off-by: Alan Maguire <[email protected]> Reviewed-by: Liam Merwick <[email protected]> Conflicts: kernel/trace/bpf_trace.c Conflicts are contextual plus the patch addresses nesting for raw tracepoints; raw tracepoint support is not in UEK5 so this portion of the patch isn't relevant. Signed-off-by: Somasundaram Krishnasamy <[email protected]>
1 parent 95c6e82 commit 1eafbd4

File tree

1 file changed

+30
-6
lines changed

1 file changed

+30
-6
lines changed

kernel/trace/bpf_trace.c

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -308,8 +308,6 @@ static const struct bpf_func_proto bpf_perf_event_read_proto = {
308308
.arg2_type = ARG_ANYTHING,
309309
};
310310

311-
static DEFINE_PER_CPU(struct perf_sample_data, bpf_trace_sd);
312-
313311
static __always_inline u64
314312
__bpf_perf_event_output(struct pt_regs *regs, struct bpf_map *map,
315313
u64 flags, struct perf_sample_data *sd)
@@ -341,24 +339,50 @@ __bpf_perf_event_output(struct pt_regs *regs, struct bpf_map *map,
341339
return 0;
342340
}
343341

342+
/*
343+
* Support executing tracepoints in normal, irq, and nmi context that each call
344+
* bpf_perf_event_output
345+
*/
346+
struct bpf_trace_sample_data {
347+
struct perf_sample_data sds[3];
348+
};
349+
350+
static DEFINE_PER_CPU(struct bpf_trace_sample_data, bpf_trace_sds);
351+
static DEFINE_PER_CPU(int, bpf_trace_nest_level);
344352
BPF_CALL_5(bpf_perf_event_output, struct pt_regs *, regs, struct bpf_map *, map,
345353
u64, flags, void *, data, u64, size)
346354
{
347-
struct perf_sample_data *sd = this_cpu_ptr(&bpf_trace_sd);
355+
struct bpf_trace_sample_data *sds = this_cpu_ptr(&bpf_trace_sds);
356+
int nest_level = this_cpu_inc_return(bpf_trace_nest_level);
348357
struct perf_raw_record raw = {
349358
.frag = {
350359
.size = size,
351360
.data = data,
352361
},
353362
};
363+
struct perf_sample_data *sd;
364+
int err;
354365

355-
if (unlikely(flags & ~(BPF_F_INDEX_MASK)))
356-
return -EINVAL;
366+
if (WARN_ON_ONCE(nest_level > ARRAY_SIZE(sds->sds))) {
367+
err = -EBUSY;
368+
goto out;
369+
}
370+
371+
sd = &sds->sds[nest_level - 1];
372+
373+
if (unlikely(flags & ~(BPF_F_INDEX_MASK))) {
374+
err = -EINVAL;
375+
goto out;
376+
}
357377

358378
perf_sample_data_init(sd, 0, 0);
359379
sd->raw = &raw;
360380

361-
return __bpf_perf_event_output(regs, map, flags, sd);
381+
err = __bpf_perf_event_output(regs, map, flags, sd);
382+
383+
out:
384+
this_cpu_dec(bpf_trace_nest_level);
385+
return err;
362386
}
363387

364388
static const struct bpf_func_proto bpf_perf_event_output_proto = {

0 commit comments

Comments
 (0)