Commit 296c83b5ccc8 for kernel
commit 296c83b5ccc808c080865eb20fd7a477b0355bb7
Author: Eric Dumazet <edumazet@google.com>
Date: Thu Sep 24 00:42:52 2026 +0000
gve: DQO: reject TSO packets with an out of range MSS
gve_prep_tso() notes that the device requires the MSS to be <= 9728,
but does not enforce it, assuming the 9K MTU enforced by the hypervisor
and the 64KB limit on TSO sizes are enough.
This does not hold for packets that were not generated locally.
A guest behind a tap, or any packet socket user, can provide an
arbitrary gso_size in virtio_net_hdr. Layer 2 forwarding does not check
the MTU for GSO packets (is_skb_forwardable()), and gso_features_check()
only bounds skb->len and gso_segs, never gso_size.
Such a packet reaches gve_tx_fill_tso_ctx_desc(), which puts gso_size
into the mss field of the TSO context descriptor. This field is 14 bits
wide, so a gso_size of 16384 is silently turned into an MSS of zero.
Drop these packets from gve_prep_tso(), and make sure that
gve_features_check_dqo() leaves their GSO bits alone: skb_segment()
splits at gso_size regardless of the MTU, so falling back to software
segmentation would give the device non TSO packets bigger than the
9728 bytes it supports.
Note that the device can still be given oversized non TSO packets when
the stack segments in software for other reasons, for instance after
TSO has been disabled with ethtool. This is a generic issue, because
the MTU check is skipped for GSO packets in the forwarding path, and
is addressed separately.
Fixes: a57e5de476be ("gve: DQO: Add TX path")
Signed-off-by: Eric Dumazet <edumazet@google.com>
Reviewed-by: Harshitha Ramamurthy <hramamurthy@google.com>
Link: https://patch.msgid.link/20260924004252.1196328-3-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
diff --git a/drivers/net/ethernet/google/gve/gve_desc_dqo.h b/drivers/net/ethernet/google/gve/gve_desc_dqo.h
index f7786b03c744..d2c86c8eeae2 100644
--- a/drivers/net/ethernet/google/gve/gve_desc_dqo.h
+++ b/drivers/net/ethernet/google/gve/gve_desc_dqo.h
@@ -14,6 +14,11 @@
#define GVE_TX_MAX_HDR_SIZE_DQO 255
#define GVE_TX_MIN_TSO_MSS_DQO 88
+/* HW limit. This also has to fit in the 14 bits of the mss field of
+ * struct gve_tx_tso_context_desc_dqo.
+ */
+#define GVE_TX_MAX_TSO_MSS_DQO 9728
+
#ifndef __LITTLE_ENDIAN_BITFIELD
#error "Only little endian supported"
#endif
diff --git a/drivers/net/ethernet/google/gve/gve_tx_dqo.c b/drivers/net/ethernet/google/gve/gve_tx_dqo.c
index e5fe17b04798..616c1921aebe 100644
--- a/drivers/net/ethernet/google/gve/gve_tx_dqo.c
+++ b/drivers/net/ethernet/google/gve/gve_tx_dqo.c
@@ -577,6 +577,20 @@ static int gve_prep_tso(struct sk_buff *skb)
int header_len;
int err;
+ /* Note: HW requires the total length of the TSO to be <= 262143,
+ * this is enforced by netif_set_tso_max_size().
+ *
+ * MSS (gso_size) can not be trusted: packets forwarded from a tap or
+ * injected by a packet socket can carry an arbitrary value, while the
+ * mss field of the TSO context descriptor is only 14 bits wide.
+ *
+ * A too big MSS is dropped here instead of being rejected from
+ * gve_features_check_dqo(), because software segmentation would
+ * produce packets larger than the device can send.
+ */
+ if (unlikely(shinfo->gso_size > GVE_TX_MAX_TSO_MSS_DQO))
+ return -1;
+
/* Needed because we will modify header. */
err = skb_cow_head(skb, 0);
if (err < 0)
@@ -964,7 +978,17 @@ netdev_features_t gve_features_check_dqo(struct sk_buff *skb,
struct net_device *dev,
netdev_features_t features)
{
- if (skb_is_gso(skb) && !gve_can_send_tso(skb))
+ if (!skb_is_gso(skb))
+ return features;
+
+ /* Keep the GSO bits for a too big MSS, so that gve_prep_tso() drops
+ * the packet: software segmentation would give packets larger than
+ * the device can send.
+ */
+ if (skb_shinfo(skb)->gso_size > GVE_TX_MAX_TSO_MSS_DQO)
+ return features;
+
+ if (!gve_can_send_tso(skb))
return features & ~NETIF_F_GSO_MASK;
return features;