Thread (19 messages) 19 messages, 4 authors, 14d ago

Re: [PATCH bpf 05/11] bpf: Reject pkt arguments in mutating subprogs

From: "Emil Tsalapatis" <emil@etsalapatis.com>
Date: 2026-09-16 18:41:08
Also in: bpf

On Wed Sep 16, 2026 at 5:57 AM UTC, Amery Hung wrote:
On Tue, Sep 15, 2026 at 10:10 PM Emil Tsalapatis [off-list ref] wrote:
quoted
The verifier tracks changes in how PTR_TO_PACKET registers'
bounds are modified across subprog boundaries. PTR_TO_PACKET
registers are actually passed as PTR_TO_MEM, which is assumed
valid for the entire call. This is not the case with packet memory,
where a pskb_* call may invalidate its memory region.

Reject BPF code that passes PTR_TO_PACKET pointers to subprogs that
may mutate a packet. We cannot pass the pointer as a true PTR_TO_PACKET
because we would also need to somehow pass the PTR_TO_PACKET_META
or PTR_TO_PACKET_END to the subprog. Since we cannot avoid representing
the pointer in the subprog as PTR_TO_MEM, only permit it if the
subprog is guaranteed not to mutate the packet.
CC Mahe.

Hi Emil,

There is a related but separate issue [1] addressed by 8fe994c80af2
(“bpf: Consolidate function call pkt_access validation”). I think a
long-term solution could be supporting ARG_PTR_TO_PACKET for global
subprograms. For example:

int parse_something(struct __sk_buff *skb, __u16 off,
                    char *data_start __arg_packet, ...);

The verifier could require a real PTR_TO_PACKET at the call site and
verify the global subprogram with a real PTR_TO_PACKET, rather than
converting it to PTR_TO_MEM. This would preserve packet access rules,
allow reads from cgroup_skb programs while rejecting writes in the
callee, and automatically invalidate the argument after calls such as
bpf_skb_pull_data().
Hi Amery,

    that makes sense to me, especially since this is a feature expected
by existing programs. The main issue I see is that since we want to be able
to pass it with subprogs we need to find a way to annotate its current size
(maybe passing it as a __sz that is checked by the verifier to be <= the
range - off of the pointer in the caller?)
[1] https://lore.kernel.org/bpf/aqkhifLvyAhw66jg@gmail.com/#t (local)
quoted
Fixes: 80f281664f5a ("bpf: Support pointers in global func args")
Reported-by: Nicholas Carlini <redacted>
Suggested-by: Nicholas Carlini <redacted>
Signed-off-by: Emil Tsalapatis <emil@etsalapatis.com>
---
 kernel/bpf/verifier.c | 10 ++++++++++
 1 file changed, 10 insertions(+)
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 6c6b8d852..507bc14b4 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -10375,6 +10375,16 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env, int subprog,
                        if (check_mem_reg(env, reg, argno, arg->mem_size, BPF_READ | BPF_WRITE, NULL,
                                          NULL))
                                return -EINVAL;
+                       /*
+                        * PTR_TO_PACKET get passed as PTR_TO_MEM, preventing
+                        * us from adjusting bounds tracking info.
+                        */
+                       if ((reg_is_pkt_pointer_any(reg) || reg_is_dynptr_slice_pkt(reg)) &&
+                           sub->changes_pkt_data) {
+                               bpf_log(log, "%s is a packet pointer, but func#%d may change packet data\n",
+                                               reg_arg_name(env, argno), subprog);
+                               return -EINVAL;
+                       }
                        if (!(arg->arg_type & PTR_MAYBE_NULL) &&
                            (type_may_be_null(reg->type) || bpf_register_is_null(reg))) {
                                bpf_log(log, "%s is expected to be non-NULL\n",
--
2.54.0
  
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help