From 3f9780d62dd1112ca15b5ae73568d29d42ccc950 Mon Sep 17 00:00:00 2001 From: Chris Mason Date: Sun, 1 Nov 2026 19:05:22 +0000 Subject: [PATCH] bpf, cgroup: Keep the skb network offset signed cgroup_skb progs see a packet from its network header. While they run, __cgroup_bpf_run_filter_skb() moves skb->data there. It assumes that the network header is not after skb->data. It negates skb_network_offset(skb) and pushes skb->data by this offset. The offset is an unsigned int. But ip6mr_cache_report() and bpf_lwt_xmit_reroute() can pass an skb that has data before the network header. Then the offset wraps. On a 64-bit kernel skb->data is then far below skb->head. skb->len has 32 bits and wraps to the correct value, thus only skb->data is wrong. A read of packet data faults or gets other memory. Keep the offset in an int. Pull skb->data when the network header is after it. Otherwise push it, as today. Fixes: 3007098494be ("cgroup: add support for eBPF programs") Signed-off-by: Chris Mason Signed-off-by: Alexei Starovoitov Link: https://patch.msgid.link/20261101190535.1454146-15-alexei.starovoitov@gmail.com --- kernel/bpf/cgroup.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/kernel/bpf/cgroup.c b/kernel/bpf/cgroup.c index ca681d626c9e..57a785241d42 100644 --- a/kernel/bpf/cgroup.c +++ b/kernel/bpf/cgroup.c @@ -1790,7 +1790,7 @@ int __cgroup_bpf_run_filter_skb(struct sock *sk, struct sk_buff *skb, enum cgroup_bpf_attach_type atype) { - unsigned int offset = -skb_network_offset(skb); + int offset = skb_network_offset(skb); struct sock *save_sk; void *saved_data_end; struct cgroup *cgrp; @@ -1802,7 +1802,15 @@ int __cgroup_bpf_run_filter_skb(struct sock *sk, cgrp = sock_cgroup_ptr(&sk->sk_cgrp_data); save_sk = skb->sk; skb->sk = sk; - __skb_push(skb, offset); + + /* + * The program sees the packet from its network header on, on + * whichever side of skb->data that header lies. + */ + if (offset > 0) + __skb_pull(skb, offset); + else + __skb_push(skb, -offset); /* compute pointers for the bpf prog */ bpf_compute_and_save_data_end(skb, &saved_data_end); @@ -1844,7 +1852,10 @@ int __cgroup_bpf_run_filter_skb(struct sock *sk, ret = -EFAULT; } bpf_restore_data_end(skb, saved_data_end); - __skb_pull(skb, offset); + if (offset > 0) + __skb_push(skb, offset); + else + __skb_pull(skb, -offset); skb->sk = save_sk; return ret;