bpf: Allow new DECAP flags and add guard rails

Add checks to require shrink-only decap, reject conflicting decap flag
combinations, and verify removed length is sufficient for claimed header
decapsulation.

Co-developed-by: Max Tottenham <mtottenh@akamai.com>
Co-developed-by: Anna Glasgall <aglasgal@akamai.com>
Signed-off-by: Max Tottenham <mtottenh@akamai.com>
Signed-off-by: Anna Glasgall <aglasgal@akamai.com>
Signed-off-by: Nick Hudson <nhudson@akamai.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Reviewed-by: Willem de Bruijn <willemb@google.com>
Link: https://lore.kernel.org/bpf/20260812083115.73100-5-nhudson@akamai.com
This commit is contained in:
Nick Hudson 2026-08-12 09:31:13 +01:00 committed by Daniel Borkmann
parent da199070bc
commit 3a39c214fd

View File

@ -56,6 +56,7 @@
#include <net/sock_reuseport.h>
#include <net/busy_poll.h>
#include <net/tcp.h>
#include <net/gre.h>
#include <net/xfrm.h>
#include <net/udp.h>
#include <linux/bpf_trace.h>
@ -3572,6 +3573,12 @@ static u32 bpf_skb_net_base_len(const struct sk_buff *skb)
#define BPF_F_ADJ_ROOM_DECAP_L3_MASK (BPF_F_ADJ_ROOM_DECAP_L3_IPV4 | \
BPF_F_ADJ_ROOM_DECAP_L3_IPV6)
#define BPF_F_ADJ_ROOM_DECAP_L4_MASK (BPF_F_ADJ_ROOM_DECAP_L4_UDP | \
BPF_F_ADJ_ROOM_DECAP_L4_GRE)
#define BPF_F_ADJ_ROOM_DECAP_IPXIP_MASK (BPF_F_ADJ_ROOM_DECAP_IPXIP4 | \
BPF_F_ADJ_ROOM_DECAP_IPXIP6)
#define BPF_F_ADJ_ROOM_ENCAP_MASK (BPF_F_ADJ_ROOM_ENCAP_L3_MASK | \
BPF_F_ADJ_ROOM_ENCAP_L4_GRE | \
BPF_F_ADJ_ROOM_ENCAP_L4_UDP | \
@ -3579,7 +3586,9 @@ static u32 bpf_skb_net_base_len(const struct sk_buff *skb)
BPF_F_ADJ_ROOM_ENCAP_L2( \
BPF_ADJ_ROOM_ENCAP_L2_MASK))
#define BPF_F_ADJ_ROOM_DECAP_MASK (BPF_F_ADJ_ROOM_DECAP_L3_MASK)
#define BPF_F_ADJ_ROOM_DECAP_MASK (BPF_F_ADJ_ROOM_DECAP_L3_MASK | \
BPF_F_ADJ_ROOM_DECAP_L4_MASK | \
BPF_F_ADJ_ROOM_DECAP_IPXIP_MASK)
#define BPF_F_ADJ_ROOM_MASK (BPF_F_ADJ_ROOM_FIXED_GSO | \
BPF_F_ADJ_ROOM_ENCAP_MASK | \
@ -3827,6 +3836,8 @@ BPF_CALL_4(bpf_skb_adjust_room, struct sk_buff *, skb, s32, len_diff,
}
if (flags & BPF_F_ADJ_ROOM_DECAP_MASK) {
u32 len_decap_min = 0;
if (!shrink)
return -EINVAL;
@ -3835,6 +3846,37 @@ BPF_CALL_4(bpf_skb_adjust_room, struct sk_buff *, skb, s32, len_diff,
BPF_F_ADJ_ROOM_DECAP_L3_MASK)
return -EINVAL;
if ((flags & BPF_F_ADJ_ROOM_DECAP_L4_MASK) ==
BPF_F_ADJ_ROOM_DECAP_L4_MASK)
return -EINVAL;
if ((flags & BPF_F_ADJ_ROOM_DECAP_IPXIP_MASK) ==
BPF_F_ADJ_ROOM_DECAP_IPXIP_MASK)
return -EINVAL;
/* Reject mutually exclusive decap tunnel type flags. */
if ((flags & BPF_F_ADJ_ROOM_DECAP_L4_MASK) &&
(flags & BPF_F_ADJ_ROOM_DECAP_IPXIP_MASK))
return -EINVAL;
if (flags & BPF_F_ADJ_ROOM_DECAP_L4_MASK)
len_decap_min += bpf_skb_net_base_len(skb);
if (flags & BPF_F_ADJ_ROOM_DECAP_L4_UDP)
len_decap_min += sizeof(struct udphdr);
if (flags & BPF_F_ADJ_ROOM_DECAP_L4_GRE)
len_decap_min += sizeof(struct gre_base_hdr);
if (flags & BPF_F_ADJ_ROOM_DECAP_IPXIP4)
len_decap_min += sizeof(struct iphdr);
if (flags & BPF_F_ADJ_ROOM_DECAP_IPXIP6)
len_decap_min += sizeof(struct ipv6hdr);
if (len_diff_abs < len_decap_min)
return -EINVAL;
if (flags & BPF_F_ADJ_ROOM_DECAP_L3_IPV4)
len_min = sizeof(struct iphdr);