]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
5.15-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 10 Sep 2024 07:30:28 +0000 (09:30 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 10 Sep 2024 07:30:28 +0000 (09:30 +0200)
added patches:
gso-fix-dodgy-bit-handling-for-gso_udp_l4.patch
net-change-maximum-number-of-udp-segments-to-128.patch
net-drop-bad-gso-csum_start-and-offset-in-virtio_net_hdr.patch
net-more-strict-virtio_net_hdr_gso_udp_l4-validation.patch

queue-5.15/gso-fix-dodgy-bit-handling-for-gso_udp_l4.patch [new file with mode: 0644]
queue-5.15/net-change-maximum-number-of-udp-segments-to-128.patch [new file with mode: 0644]
queue-5.15/net-drop-bad-gso-csum_start-and-offset-in-virtio_net_hdr.patch [new file with mode: 0644]
queue-5.15/net-more-strict-virtio_net_hdr_gso_udp_l4-validation.patch [new file with mode: 0644]
queue-5.15/series

diff --git a/queue-5.15/gso-fix-dodgy-bit-handling-for-gso_udp_l4.patch b/queue-5.15/gso-fix-dodgy-bit-handling-for-gso_udp_l4.patch
new file mode 100644 (file)
index 0000000..830791a
--- /dev/null
@@ -0,0 +1,61 @@
+From willemdebruijn.kernel@gmail.com Mon Sep  9 20:25:15 2024
+From: Willem de Bruijn <willemdebruijn.kernel@gmail.com>
+Date: Mon,  9 Sep 2024 14:22:47 -0400
+Subject: gso: fix dodgy bit handling for GSO_UDP_L4
+To: stable@vger.kernel.org
+Cc: netdev@vger.kernel.org, gregkh@linuxfoundation.org, christian@theune.cc, mathieu.tortuyaux@gmail.com, Yan Zhai <yan@cloudflare.com>, Willem de Bruijn <willemdebruijn.kernel@gmail.com>, Willem de Bruijn <willemb@google.com>, Jason Wang <jasowang@redhat.com>, "David S. Miller" <davem@davemloft.net>
+Message-ID: <20240909182506.270136-4-willemdebruijn.kernel@gmail.com>
+
+From: Yan Zhai <yan@cloudflare.com>
+
+[ Upstream commit 9840036786d90cea11a90d1f30b6dc003b34ee67 ]
+
+Commit 1fd54773c267 ("udp: allow header check for dodgy GSO_UDP_L4
+packets.") checks DODGY bit for UDP, but for packets that can be fed
+directly to the device after gso_segs reset, it actually falls through
+to fragmentation:
+
+https://lore.kernel.org/all/CAJPywTKDdjtwkLVUW6LRA2FU912qcDmQOQGt2WaDo28KzYDg+A@mail.gmail.com/
+
+This change restores the expected behavior of GSO_UDP_L4 packets.
+
+Fixes: 1fd54773c267 ("udp: allow header check for dodgy GSO_UDP_L4 packets.")
+Suggested-by: Willem de Bruijn <willemdebruijn.kernel@gmail.com>
+Signed-off-by: Yan Zhai <yan@cloudflare.com>
+Reviewed-by: Willem de Bruijn <willemb@google.com>
+Acked-by: Jason Wang <jasowang@redhat.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+
+[5.15 stable: clean backport]
+Signed-off-by: Willem de Bruijn <willemb@google.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/ipv4/udp_offload.c |   13 ++++++++++---
+ 1 file changed, 10 insertions(+), 3 deletions(-)
+
+--- a/net/ipv4/udp_offload.c
++++ b/net/ipv4/udp_offload.c
+@@ -272,13 +272,20 @@ struct sk_buff *__udp_gso_segment(struct
+       __sum16 check;
+       __be16 newlen;
+-      if (skb_shinfo(gso_skb)->gso_type & SKB_GSO_FRAGLIST)
+-              return __udp_gso_segment_list(gso_skb, features, is_ipv6);
+-
+       mss = skb_shinfo(gso_skb)->gso_size;
+       if (gso_skb->len <= sizeof(*uh) + mss)
+               return ERR_PTR(-EINVAL);
++      if (skb_gso_ok(gso_skb, features | NETIF_F_GSO_ROBUST)) {
++              /* Packet is from an untrusted source, reset gso_segs. */
++              skb_shinfo(gso_skb)->gso_segs = DIV_ROUND_UP(gso_skb->len - sizeof(*uh),
++                                                           mss);
++              return NULL;
++      }
++
++      if (skb_shinfo(gso_skb)->gso_type & SKB_GSO_FRAGLIST)
++              return __udp_gso_segment_list(gso_skb, features, is_ipv6);
++
+       skb_pull(gso_skb, sizeof(*uh));
+       /* clear destructor to avoid skb_segment assigning it to tail */
diff --git a/queue-5.15/net-change-maximum-number-of-udp-segments-to-128.patch b/queue-5.15/net-change-maximum-number-of-udp-segments-to-128.patch
new file mode 100644 (file)
index 0000000..efce3ba
--- /dev/null
@@ -0,0 +1,71 @@
+From stable+bounces-74079-greg=kroah.com@vger.kernel.org Mon Sep  9 20:25:31 2024
+From: Willem de Bruijn <willemdebruijn.kernel@gmail.com>
+Date: Mon,  9 Sep 2024 14:22:46 -0400
+Subject: net: change maximum number of UDP segments to 128
+To: stable@vger.kernel.org
+Cc: netdev@vger.kernel.org, gregkh@linuxfoundation.org, christian@theune.cc, mathieu.tortuyaux@gmail.com, Yuri Benditovich <yuri.benditovich@daynix.com>, Willem de Bruijn <willemb@google.com>, "David S. Miller" <davem@davemloft.net>
+Message-ID: <20240909182506.270136-3-willemdebruijn.kernel@gmail.com>
+
+From: Yuri Benditovich <yuri.benditovich@daynix.com>
+
+[ Upstream commit 1382e3b6a3500c245e5278c66d210c02926f804f ]
+
+The commit fc8b2a619469
+("net: more strict VIRTIO_NET_HDR_GSO_UDP_L4 validation")
+adds check of potential number of UDP segments vs
+UDP_MAX_SEGMENTS in linux/virtio_net.h.
+After this change certification test of USO guest-to-guest
+transmit on Windows driver for virtio-net device fails,
+for example with packet size of ~64K and mss of 536 bytes.
+In general the USO should not be more restrictive than TSO.
+Indeed, in case of unreasonably small mss a lot of segments
+can cause queue overflow and packet loss on the destination.
+Limit of 128 segments is good for any practical purpose,
+with minimal meaningful mss of 536 the maximal UDP packet will
+be divided to ~120 segments.
+The number of segments for UDP packets is validated vs
+UDP_MAX_SEGMENTS also in udp.c (v4,v6), this does not affect
+quest-to-guest path but does affect packets sent to host, for
+example.
+It is important to mention that UDP_MAX_SEGMENTS is kernel-only
+define and not available to user mode socket applications.
+In order to request MSS smaller than MTU the applications
+just uses setsockopt with SOL_UDP and UDP_SEGMENT and there is
+no limitations on socket API level.
+
+Fixes: fc8b2a619469 ("net: more strict VIRTIO_NET_HDR_GSO_UDP_L4 validation")
+Signed-off-by: Yuri Benditovich <yuri.benditovich@daynix.com>
+Reviewed-by: Willem de Bruijn <willemb@google.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+
+[5.15-stable: fix conflict with neighboring but unrelated code from
+              e2a4392b61f6 ("udp: introduce udp->udp_flags")
+Signed-off-by: Willem de Bruijn <willemb@google.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/linux/udp.h                  |    2 +-
+ tools/testing/selftests/net/udpgso.c |    2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+--- a/include/linux/udp.h
++++ b/include/linux/udp.h
+@@ -94,7 +94,7 @@ struct udp_sock {
+       int             forward_deficit;
+ };
+-#define UDP_MAX_SEGMENTS      (1 << 6UL)
++#define UDP_MAX_SEGMENTS      (1 << 7UL)
+ static inline struct udp_sock *udp_sk(const struct sock *sk)
+ {
+--- a/tools/testing/selftests/net/udpgso.c
++++ b/tools/testing/selftests/net/udpgso.c
+@@ -34,7 +34,7 @@
+ #endif
+ #ifndef UDP_MAX_SEGMENTS
+-#define UDP_MAX_SEGMENTS      (1 << 6UL)
++#define UDP_MAX_SEGMENTS      (1 << 7UL)
+ #endif
+ #define CONST_MTU_TEST        1500
diff --git a/queue-5.15/net-drop-bad-gso-csum_start-and-offset-in-virtio_net_hdr.patch b/queue-5.15/net-drop-bad-gso-csum_start-and-offset-in-virtio_net_hdr.patch
new file mode 100644 (file)
index 0000000..5dd4cca
--- /dev/null
@@ -0,0 +1,153 @@
+From willemdebruijn.kernel@gmail.com Mon Sep  9 20:25:16 2024
+From: Willem de Bruijn <willemdebruijn.kernel@gmail.com>
+Date: Mon,  9 Sep 2024 14:22:48 -0400
+Subject: net: drop bad gso csum_start and offset in virtio_net_hdr
+To: stable@vger.kernel.org
+Cc: netdev@vger.kernel.org, gregkh@linuxfoundation.org, christian@theune.cc, mathieu.tortuyaux@gmail.com, Willem de Bruijn <willemb@google.com>, Jakub Kicinski <kuba@kernel.org>
+Message-ID: <20240909182506.270136-5-willemdebruijn.kernel@gmail.com>
+
+From: Willem de Bruijn <willemb@google.com>
+
+[ Upstream commit 89add40066f9ed9abe5f7f886fe5789ff7e0c50e ]
+
+Tighten csum_start and csum_offset checks in virtio_net_hdr_to_skb
+for GSO packets.
+
+The function already checks that a checksum requested with
+VIRTIO_NET_HDR_F_NEEDS_CSUM is in skb linear. But for GSO packets
+this might not hold for segs after segmentation.
+
+Syzkaller demonstrated to reach this warning in skb_checksum_help
+
+       offset = skb_checksum_start_offset(skb);
+       ret = -EINVAL;
+       if (WARN_ON_ONCE(offset >= skb_headlen(skb)))
+
+By injecting a TSO packet:
+
+WARNING: CPU: 1 PID: 3539 at net/core/dev.c:3284 skb_checksum_help+0x3d0/0x5b0
+ ip_do_fragment+0x209/0x1b20 net/ipv4/ip_output.c:774
+ ip_finish_output_gso net/ipv4/ip_output.c:279 [inline]
+ __ip_finish_output+0x2bd/0x4b0 net/ipv4/ip_output.c:301
+ iptunnel_xmit+0x50c/0x930 net/ipv4/ip_tunnel_core.c:82
+ ip_tunnel_xmit+0x2296/0x2c70 net/ipv4/ip_tunnel.c:813
+ __gre_xmit net/ipv4/ip_gre.c:469 [inline]
+ ipgre_xmit+0x759/0xa60 net/ipv4/ip_gre.c:661
+ __netdev_start_xmit include/linux/netdevice.h:4850 [inline]
+ netdev_start_xmit include/linux/netdevice.h:4864 [inline]
+ xmit_one net/core/dev.c:3595 [inline]
+ dev_hard_start_xmit+0x261/0x8c0 net/core/dev.c:3611
+ __dev_queue_xmit+0x1b97/0x3c90 net/core/dev.c:4261
+ packet_snd net/packet/af_packet.c:3073 [inline]
+
+The geometry of the bad input packet at tcp_gso_segment:
+
+[   52.003050][ T8403] skb len=12202 headroom=244 headlen=12093 tailroom=0
+[   52.003050][ T8403] mac=(168,24) mac_len=24 net=(192,52) trans=244
+[   52.003050][ T8403] shinfo(txflags=0 nr_frags=1 gso(size=1552 type=3 segs=0))
+[   52.003050][ T8403] csum(0x60000c7 start=199 offset=1536
+ip_summed=3 complete_sw=0 valid=0 level=0)
+
+Mitigate with stricter input validation.
+
+csum_offset: for GSO packets, deduce the correct value from gso_type.
+This is already done for USO. Extend it to TSO. Let UFO be:
+udp[46]_ufo_fragment ignores these fields and always computes the
+checksum in software.
+
+csum_start: finding the real offset requires parsing to the transport
+header. Do not add a parser, use existing segmentation parsing. Thanks
+to SKB_GSO_DODGY, that also catches bad packets that are hw offloaded.
+Again test both TSO and USO. Do not test UFO for the above reason, and
+do not test UDP tunnel offload.
+
+GSO packet are almost always CHECKSUM_PARTIAL. USO packets may be
+CHECKSUM_NONE since commit 10154dbded6d6 ("udp: Allow GSO transmit
+from devices with no checksum offload"), but then still these fields
+are initialized correctly in udp4_hwcsum/udp6_hwcsum_outgoing. So no
+need to test for ip_summed == CHECKSUM_PARTIAL first.
+
+This revises an existing fix mentioned in the Fixes tag, which broke
+small packets with GSO offload, as detected by kselftests.
+
+Link: https://syzkaller.appspot.com/bug?extid=e1db31216c789f552871
+Link: https://lore.kernel.org/netdev/20240723223109.2196886-1-kuba@kernel.org
+Fixes: e269d79c7d35 ("net: missing check virtio")
+Cc: stable@vger.kernel.org
+Signed-off-by: Willem de Bruijn <willemb@google.com>
+Link: https://patch.msgid.link/20240729201108.1615114-1-willemdebruijn.kernel@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+
+[5.15 stable: clean backport]
+Signed-off-by: Willem de Bruijn <willemb@google.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/linux/virtio_net.h |   16 +++++-----------
+ net/ipv4/tcp_offload.c     |    3 +++
+ net/ipv4/udp_offload.c     |    4 ++++
+ 3 files changed, 12 insertions(+), 11 deletions(-)
+
+--- a/include/linux/virtio_net.h
++++ b/include/linux/virtio_net.h
+@@ -51,7 +51,6 @@ static inline int virtio_net_hdr_to_skb(
+       unsigned int thlen = 0;
+       unsigned int p_off = 0;
+       unsigned int ip_proto;
+-      u64 ret, remainder, gso_size;
+       if (hdr->gso_type != VIRTIO_NET_HDR_GSO_NONE) {
+               switch (hdr->gso_type & ~VIRTIO_NET_HDR_GSO_ECN) {
+@@ -88,16 +87,6 @@ static inline int virtio_net_hdr_to_skb(
+               u32 off = __virtio16_to_cpu(little_endian, hdr->csum_offset);
+               u32 needed = start + max_t(u32, thlen, off + sizeof(__sum16));
+-              if (hdr->gso_size) {
+-                      gso_size = __virtio16_to_cpu(little_endian, hdr->gso_size);
+-                      ret = div64_u64_rem(skb->len, gso_size, &remainder);
+-                      if (!(ret && (hdr->gso_size > needed) &&
+-                                              ((remainder > needed) || (remainder == 0)))) {
+-                              return -EINVAL;
+-                      }
+-                      skb_shinfo(skb)->tx_flags |= SKBFL_SHARED_FRAG;
+-              }
+-
+               if (!pskb_may_pull(skb, needed))
+                       return -EINVAL;
+@@ -170,6 +159,11 @@ retry:
+                       if (gso_type != SKB_GSO_UDP_L4)
+                               return -EINVAL;
+                       break;
++              case SKB_GSO_TCPV4:
++              case SKB_GSO_TCPV6:
++                      if (skb->csum_offset != offsetof(struct tcphdr, check))
++                              return -EINVAL;
++                      break;
+               }
+               /* Kernel has a special handling for GSO_BY_FRAGS. */
+--- a/net/ipv4/tcp_offload.c
++++ b/net/ipv4/tcp_offload.c
+@@ -71,6 +71,9 @@ struct sk_buff *tcp_gso_segment(struct s
+       if (thlen < sizeof(*th))
+               goto out;
++      if (unlikely(skb_checksum_start(skb) != skb_transport_header(skb)))
++              goto out;
++
+       if (!pskb_may_pull(skb, thlen))
+               goto out;
+--- a/net/ipv4/udp_offload.c
++++ b/net/ipv4/udp_offload.c
+@@ -276,6 +276,10 @@ struct sk_buff *__udp_gso_segment(struct
+       if (gso_skb->len <= sizeof(*uh) + mss)
+               return ERR_PTR(-EINVAL);
++      if (unlikely(skb_checksum_start(gso_skb) !=
++                   skb_transport_header(gso_skb)))
++              return ERR_PTR(-EINVAL);
++
+       if (skb_gso_ok(gso_skb, features | NETIF_F_GSO_ROBUST)) {
+               /* Packet is from an untrusted source, reset gso_segs. */
+               skb_shinfo(gso_skb)->gso_segs = DIV_ROUND_UP(gso_skb->len - sizeof(*uh),
diff --git a/queue-5.15/net-more-strict-virtio_net_hdr_gso_udp_l4-validation.patch b/queue-5.15/net-more-strict-virtio_net_hdr_gso_udp_l4-validation.patch
new file mode 100644 (file)
index 0000000..c0a36cc
--- /dev/null
@@ -0,0 +1,89 @@
+From stable+bounces-74078-greg=kroah.com@vger.kernel.org Mon Sep  9 20:25:27 2024
+From: Willem de Bruijn <willemdebruijn.kernel@gmail.com>
+Date: Mon,  9 Sep 2024 14:22:45 -0400
+Subject: net: more strict VIRTIO_NET_HDR_GSO_UDP_L4 validation
+To: stable@vger.kernel.org
+Cc: netdev@vger.kernel.org, gregkh@linuxfoundation.org, christian@theune.cc, mathieu.tortuyaux@gmail.com, Willem de Bruijn <willemb@google.com>, syzbot+01cdbc31e9c0ae9b33ac@syzkaller.appspotmail.com, syzbot+c99d835ff081ca30f986@syzkaller.appspotmail.com, Eric Dumazet <edumazet@google.com>, Jason Wang <jasowang@redhat.com>, "David S. Miller" <davem@davemloft.net>
+Message-ID: <20240909182506.270136-2-willemdebruijn.kernel@gmail.com>
+
+From: Willem de Bruijn <willemb@google.com>
+
+[ Upstream commit fc8b2a619469378717e7270d2a4e1ef93c585f7a ]
+
+Syzbot reported two new paths to hit an internal WARNING using the
+new virtio gso type VIRTIO_NET_HDR_GSO_UDP_L4.
+
+    RIP: 0010:skb_checksum_help+0x4a2/0x600 net/core/dev.c:3260
+    skb len=64521 gso_size=344
+and
+
+    RIP: 0010:skb_warn_bad_offload+0x118/0x240 net/core/dev.c:3262
+
+Older virtio types have historically had loose restrictions, leading
+to many entirely impractical fuzzer generated packets causing
+problems deep in the kernel stack. Ideally, we would have had strict
+validation for all types from the start.
+
+New virtio types can have tighter validation. Limit UDP GSO packets
+inserted via virtio to the same limits imposed by the UDP_SEGMENT
+socket interface:
+
+1. must use checksum offload
+2. checksum offload matches UDP header
+3. no more segments than UDP_MAX_SEGMENTS
+4. UDP GSO does not take modifier flags, notably SKB_GSO_TCP_ECN
+
+Fixes: 860b7f27b8f7 ("linux/virtio_net.h: Support USO offload in vnet header.")
+Reported-by: syzbot+01cdbc31e9c0ae9b33ac@syzkaller.appspotmail.com
+Closes: https://lore.kernel.org/netdev/0000000000005039270605eb0b7f@google.com/
+Reported-by: syzbot+c99d835ff081ca30f986@syzkaller.appspotmail.com
+Closes: https://lore.kernel.org/netdev/0000000000005426680605eb0b9f@google.com/
+Signed-off-by: Willem de Bruijn <willemb@google.com>
+Reviewed-by: Eric Dumazet <edumazet@google.com>
+Acked-by: Jason Wang <jasowang@redhat.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+
+[5.15 stable: clean backport]
+Signed-off-by: Willem de Bruijn <willemb@google.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/linux/virtio_net.h |   19 ++++++++++++++++---
+ 1 file changed, 16 insertions(+), 3 deletions(-)
+
+--- a/include/linux/virtio_net.h
++++ b/include/linux/virtio_net.h
+@@ -3,8 +3,8 @@
+ #define _LINUX_VIRTIO_NET_H
+ #include <linux/if_vlan.h>
++#include <linux/udp.h>
+ #include <uapi/linux/tcp.h>
+-#include <uapi/linux/udp.h>
+ #include <uapi/linux/virtio_net.h>
+ static inline bool virtio_net_hdr_match_proto(__be16 protocol, __u8 gso_type)
+@@ -155,9 +155,22 @@ retry:
+               unsigned int nh_off = p_off;
+               struct skb_shared_info *shinfo = skb_shinfo(skb);
+-              /* UFO may not include transport header in gso_size. */
+-              if (gso_type & SKB_GSO_UDP)
++              switch (gso_type & ~SKB_GSO_TCP_ECN) {
++              case SKB_GSO_UDP:
++                      /* UFO may not include transport header in gso_size. */
+                       nh_off -= thlen;
++                      break;
++              case SKB_GSO_UDP_L4:
++                      if (!(hdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM))
++                              return -EINVAL;
++                      if (skb->csum_offset != offsetof(struct udphdr, check))
++                              return -EINVAL;
++                      if (skb->len - p_off > gso_size * UDP_MAX_SEGMENTS)
++                              return -EINVAL;
++                      if (gso_type != SKB_GSO_UDP_L4)
++                              return -EINVAL;
++                      break;
++              }
+               /* Kernel has a special handling for GSO_BY_FRAGS. */
+               if (gso_size == GSO_BY_FRAGS)
index 8a5a1fef41444a5d94454317b499b60a37d87636..236d6ffcb405e02e1baae182b0f146a49df0cf2a 100644 (file)
@@ -204,3 +204,7 @@ asoc-sunxi-sun4i-i2s-fix-lrclk-polarity-in-i2s-mode.patch
 drm-i915-fence-mark-debug_fence_init_onstack-with-__.patch
 drm-i915-fence-mark-debug_fence_free-with-__maybe_un.patch
 gpio-rockchip-fix-of-node-leak-in-probe.patch
+net-more-strict-virtio_net_hdr_gso_udp_l4-validation.patch
+net-change-maximum-number-of-udp-segments-to-128.patch
+gso-fix-dodgy-bit-handling-for-gso_udp_l4.patch
+net-drop-bad-gso-csum_start-and-offset-in-virtio_net_hdr.patch