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