summaryrefslogtreecommitdiff
path: root/kernel/bpf/stackmap.c
diff options
context:
space:
mode:
authorAlexei Starovoitov <ast@kernel.org>2026-11-02 00:10:40 +0000
committerAlexei Starovoitov <ast@kernel.org>2026-11-02 00:10:41 +0000
commit714b7112017fc7f8b2afabccf562acdb12d2ea7d (patch)
treef49c1ce081d19372c077ffb4e227753a3eecbd6e /kernel/bpf/stackmap.c
parent1d55411e8b677c67de7a20618d95dc114796de26 (diff)
parentee36c9aa44ef300cd651074bd97552b229337f85 (diff)
Merge branch 'bpf-fixes-for-the-verifier-arena-skb-and-lwt-helpers'
Alexei Starovoitov says: ==================== bpf: Fixes for the verifier, arena, skb and lwt helpers From: Alexei Starovoitov <ast@kernel.org> These patches fix bugs in BPF: patches area ------- ---------------------------------------------------------------- 01-02 stack traces: the limit of the trace length 03-07 arena: the range of mmap() and of bpf_arena_free_pages() 08-12 arguments of kfuncs and of extension progs 13 cgroup detach: the permission check 14 cgroup skb progs: the network offset 15 bpf_skb_adjust_room(): the limit of gso_size 16-24 lwt and seg6local End.BPF progs: pushed headers, skb->cb, dst 25-27 skb offsets when a helper adds or removes room 10 of the patches are from Chris Mason and Josef Bacik. Patches 07 and 12 are selftests. Signed-off-by: Alexei Starovoitov <ast@kernel.org> ==================== Link: https://patch.msgid.link/20261101190535.1454146-1-alexei.starovoitov@gmail.com Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Diffstat (limited to 'kernel/bpf/stackmap.c')
-rw-r--r--kernel/bpf/stackmap.c33
1 files changed, 23 insertions, 10 deletions
diff --git a/kernel/bpf/stackmap.c b/kernel/bpf/stackmap.c
index f7e8d766d128..a19126f5db02 100644
--- a/kernel/bpf/stackmap.c
+++ b/kernel/bpf/stackmap.c
@@ -522,12 +522,14 @@ static int stackid_init(struct stackid *stackid, struct bpf_map *map,
u32 skip = flags & BPF_F_SKIP_FIELD_MASK;
u32 max_depth;
+ max_depth = stack_map_calculate_max_depth(map->value_size, stack_map_data_size(map), flags);
+ /* trace_nr can be above max_depth and max_depth below skip: clamp first */
+ trace_nr = min_t(u32, trace_nr, max_depth);
if (trace_nr <= skip)
/* skipping more than usable stack trace */
return -EFAULT;
- max_depth = stack_map_calculate_max_depth(map->value_size, stack_map_data_size(map), flags);
- stackid->nr = min_t(u32, trace_nr - skip, max_depth - skip);
+ stackid->nr = trace_nr - skip;
stackid->len = stackid->nr * sizeof(u64);
stackid->ips = trace->ip + skip;
stackid->hash = jhash2((const u32 *)stackid->ips, stackid->len / sizeof(u32), 0);
@@ -642,7 +644,8 @@ BPF_CALL_3(bpf_get_stackid, struct pt_regs *, regs, struct bpf_map *, map,
/* couldn't fetch the stack trace */
return -EFAULT;
- err = stackid_fastpath(&stackid, map, trace, trace->nr, flags);
+ /* the entry is released already, an NMI can change trace->nr */
+ err = stackid_fastpath(&stackid, map, trace, READ_ONCE(trace->nr), flags);
if (err != -ENOENT)
return err;
@@ -822,14 +825,20 @@ static long __bpf_get_stack(struct pt_regs *regs, struct task_struct *task,
crosstask, false, 0);
}
- if (unlikely(!trace) || trace->nr < skip) {
- if (may_fault)
- rcu_read_unlock();
- preempt_enable();
- goto err_fault;
- }
+ if (unlikely(!trace))
+ goto err_unlock;
- trace_nr = callchain_store(trace, trace->nr, buf, elem_size, flags);
+ /*
+ * trace->nr can be above max_depth. The per-CPU entry is released
+ * already: a tracing program or an NMI which takes a callchain in the
+ * same context before the copy below reuses it. And the unwinders of
+ * PowerPC store context markers on top of max_depth.
+ */
+ trace_nr = min_t(u32, READ_ONCE(trace->nr), max_depth);
+ if (trace_nr < skip)
+ goto err_unlock;
+
+ trace_nr = callchain_store(trace, trace_nr, buf, elem_size, flags);
/* trace should not be dereferenced after this point */
if (may_fault)
@@ -838,6 +847,10 @@ static long __bpf_get_stack(struct pt_regs *regs, struct task_struct *task,
return callchain_finalize(buf, size, trace_nr, elem_size, flags, may_fault);
+err_unlock:
+ if (may_fault)
+ rcu_read_unlock();
+ preempt_enable();
err_fault:
err = -EFAULT;
clear: