Skip to content

Commit f2c67a3

Browse files
olsajiriAlexei Starovoitov
authored andcommitted
bpf: Disable preemption in bpf_perf_event_output
The nesting protection in bpf_perf_event_output relies on disabled preemption, which is guaranteed for kprobes and tracepoints. However bpf_perf_event_output can be also called from uprobes context through bpf_prog_run_array_sleepable function which disables migration, but keeps preemption enabled. This can cause task to be preempted by another one inside the nesting protection and lead eventually to two tasks using same perf_sample_data buffer and cause crashes like: kernel tried to execute NX-protected page - exploit attempt? (uid: 0) BUG: unable to handle page fault for address: ffffffff82be3eea ... Call Trace: ? __die+0x1f/0x70 ? page_fault_oops+0x176/0x4d0 ? exc_page_fault+0x132/0x230 ? asm_exc_page_fault+0x22/0x30 ? perf_output_sample+0x12b/0x910 ? perf_event_output+0xd0/0x1d0 ? bpf_perf_event_output+0x162/0x1d0 ? bpf_prog_c6271286d9a4c938_krava1+0x76/0x87 ? __uprobe_perf_func+0x12b/0x540 ? uprobe_dispatcher+0x2c4/0x430 ? uprobe_notify_resume+0x2da/0xce0 ? atomic_notifier_call_chain+0x7b/0x110 ? exit_to_user_mode_prepare+0x13e/0x290 ? irqentry_exit_to_user_mode+0x5/0x30 ? asm_exc_int3+0x35/0x40 Fixing this by disabling preemption in bpf_perf_event_output. Cc: stable@vger.kernel.org Fixes: 8c7dcb8 ("bpf: implement sleepable uprobes by chaining gps") Acked-by: Hou Tao <houtao1@huawei.com> Signed-off-by: Jiri Olsa <jolsa@kernel.org> Link: https://lore.kernel.org/r/20230725084206.580930-2-jolsa@kernel.org Signed-off-by: Alexei Starovoitov <ast@kernel.org>
1 parent 284779d commit f2c67a3

File tree

1 file changed

+7
-4
lines changed

1 file changed

+7
-4
lines changed

kernel/trace/bpf_trace.c

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -661,16 +661,19 @@ static DEFINE_PER_CPU(int, bpf_trace_nest_level);
661661
BPF_CALL_5(bpf_perf_event_output, struct pt_regs *, regs, struct bpf_map *, map,
662662
u64, flags, void *, data, u64, size)
663663
{
664-
struct bpf_trace_sample_data *sds = this_cpu_ptr(&bpf_trace_sds);
665-
int nest_level = this_cpu_inc_return(bpf_trace_nest_level);
664+
struct bpf_trace_sample_data *sds;
666665
struct perf_raw_record raw = {
667666
.frag = {
668667
.size = size,
669668
.data = data,
670669
},
671670
};
672671
struct perf_sample_data *sd;
673-
int err;
672+
int nest_level, err;
673+
674+
preempt_disable();
675+
sds = this_cpu_ptr(&bpf_trace_sds);
676+
nest_level = this_cpu_inc_return(bpf_trace_nest_level);
674677

675678
if (WARN_ON_ONCE(nest_level > ARRAY_SIZE(sds->sds))) {
676679
err = -EBUSY;
@@ -688,9 +691,9 @@ BPF_CALL_5(bpf_perf_event_output, struct pt_regs *, regs, struct bpf_map *, map,
688691
perf_sample_save_raw_data(sd, &raw);
689692

690693
err = __bpf_perf_event_output(regs, map, flags, sd);
691-
692694
out:
693695
this_cpu_dec(bpf_trace_nest_level);
696+
preempt_enable();
694697
return err;
695698
}
696699

0 commit comments

Comments
 (0)