Blob Blame History Raw
From: Jesper Dangaard Brouer <brouer@redhat.com>
Date: Tue, 9 Feb 2021 14:38:09 +0100
Subject: bpf: Remove MTU check in __bpf_skb_max_len
Patch-mainline: v5.12-rc1
Git-commit: 6306c1189e77a513bf02720450bb43bd4ba5d8ae
References: bsc#1192045 CVE-2021-0941

Multiple BPF-helpers that can manipulate/increase the size of the SKB uses
__bpf_skb_max_len() as the max-length. This function limit size against
the current net_device MTU (skb->dev->mtu).

When a BPF-prog grow the packet size, then it should not be limited to the
MTU. The MTU is a transmit limitation, and software receiving this packet
should be allowed to increase the size. Further more, current MTU check in
__bpf_skb_max_len uses the MTU from ingress/current net_device, which in
case of redirects uses the wrong net_device.

This patch keeps a sanity max limit of SKB_MAX_ALLOC (16KiB). The real limit
is elsewhere in the system. Jesper's testing[1] showed it was not possible
to exceed 8KiB when expanding the SKB size via BPF-helper. The limiting
factor is the define KMALLOC_MAX_CACHE_SIZE which is 8192 for
SLUB-allocator (CONFIG_SLUB) in-case PAGE_SIZE is 4096. This define is
in-effect due to this being called from softirq context see code
__gfp_pfmemalloc_flags() and __do_kmalloc_node(). Jakub's testing showed
that frames above 16KiB can cause NICs to reset (but not crash). Keep this
sanity limit at this level as memory layer can differ based on kernel
config.

[1] https://github.com/xdp-project/bpf-examples/tree/master/MTU-tests

Signed-off-by: Jesper Dangaard Brouer <brouer@redhat.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: John Fastabend <john.fastabend@gmail.com>
Link: https://lore.kernel.org/bpf/161287788936.790810.2937823995775097177.stgit@firesoul
Acked-by: Shung-Hsi Yu <shung-hsi.yu@suse.com>
---
syu: Dropped patching of bpf_skb_adjust_room() since it does not exists without
backporting of 2be7e212d541 ("bpf: add bpf_skb_adjust_room helper").
---
 net/core/filter.c |    9 +++------
 1 file changed, 3 insertions(+), 6 deletions(-)

--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -2749,6 +2749,8 @@ static u32 __bpf_skb_min_len(const struc
 	return min_len;
 }
 
+#define BPF_SKB_MAX_LEN SKB_MAX_ALLOC
+
 static int bpf_skb_grow_rcsum(struct sk_buff *skb, unsigned int new_len)
 {
 	unsigned int old_len = skb->len;
@@ -2768,7 +2770,7 @@ static int bpf_skb_trim_rcsum(struct sk_
 static inline int __bpf_skb_change_tail(struct sk_buff *skb, u32 new_len,
 					u64 flags)
 {
-	u32 max_len = __bpf_skb_max_len(skb);
+	u32 max_len = BPF_SKB_MAX_LEN;
 	u32 min_len = __bpf_skb_min_len(skb);
 	int ret;
 
@@ -2844,7 +2846,7 @@ static const struct bpf_func_proto sk_sk
 static inline int __bpf_skb_change_head(struct sk_buff *skb, u32 head_room,
 					u64 flags)
 {
-	u32 max_len = __bpf_skb_max_len(skb);
+	u32 max_len = BPF_SKB_MAX_LEN;
 	u32 new_len = skb->len + head_room;
 	int ret;