[PATCH net v4 1/7] net/mlx5e: psp: drop ipv6 packets with extension headers

From
Todd Freed <hidden>
Date
2026-11-03 00:11:58
Also in
linux-kselftest
Reply to
Todd Freed, 2026-11-03
mlx5e_psp_handle_tx_skb() uses psp_dev_encapsulate() to insert the
udp+psp headers and rewrite the nexthdr of the fixed l3 header to udp.

if the packet is an ipv6 packet with extension headers, udp+psp is
placed after them, but the nexthdr indicating the l4 proto is on the
last extension header in the chain, not in the fixed header. therefore
this produces a malformed packet.

in addition to being malformed, with mlx5 this kind of packet goes out
unencrypted. since the tx association encodes intent to send encrypted
packets, drop such packets instead.

a psp tcp socket emits such packets if certain socket options are set on
it (e.g. IPV6_DSTOPTS). refusing the combination of such socket options
with psp association would be helpful but is not implemented here. since
extension headers can also come from a route the datapath check is
needed anyway.

Fixes: e5a1861a298e ("net/mlx5e: Implement PSP Tx data path")
Signed-off-by: Todd Freed <redacted>
---
 .../mellanox/mlx5/core/en_accel/psp_rxtx.c     | 18 ++++++++++++++++--
 net/psp/psp_main.c                             |  1 +
 2 files changed, 17 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/psp_rxtx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/psp_rxtx.c
index 348fd7a96261..c9829a124c53 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/psp_rxtx.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/psp_rxtx.c
@@ -160,6 +160,19 @@ void mlx5e_psp_handle_tx_wqe(struct mlx5e_tx_wqe *wqe,
 	inlseg->byte_count = cpu_to_be32(psp_st->tailen | MLX5_INLINE_SEG);
 }
 
+/* psp_dev_encapsulate() inserts udp+psp at the transport header, rewrites the
+ * protocol of the fixed l3 header to udp, and writes tcp as the psp next
+ * header. thus tcp must directly follow the fixed header.
+ */
+static bool mlx5e_psp_l4_is_tcp(const struct sk_buff *skb)
+{
+	if (skb->protocol == htons(ETH_P_IP))
+		return ip_hdr(skb)->protocol == IPPROTO_TCP;
+	if (skb->protocol == htons(ETH_P_IPV6))
+		return ipv6_hdr(skb)->nexthdr == IPPROTO_TCP;
+	return false;
+}
+
 bool mlx5e_psp_handle_tx_skb(struct net_device *netdev,
 			     struct sk_buff *skb,
 			     struct mlx5e_accel_tx_psp_state *psp_st)
@@ -170,8 +183,9 @@ bool mlx5e_psp_handle_tx_skb(struct net_device *netdev,
 	if (!mlx5e_psp_set_state(priv, skb, psp_st))
 		return true;
 
-	/* psp_encap of the packet */
-	if (!psp_dev_encapsulate(net, skb, psp_st->spi, psp_st->ver, 0)) {
+	/* psp_encap of the packet. only tcp right after the ip header */
+	if (unlikely(!mlx5e_psp_l4_is_tcp(skb)) ||
+	    !psp_dev_encapsulate(net, skb, psp_st->spi, psp_st->ver, 0)) {
 		kfree_skb_reason(skb, SKB_DROP_REASON_PSP_OUTPUT);
 		atomic_inc(&priv->psp->tx_drop);
 		return false;
diff --git a/net/psp/psp_main.c b/net/psp/psp_main.c
index c9c1a8826b7f..5049ed400be0 100644
--- a/net/psp/psp_main.c
+++ b/net/psp/psp_main.c
@@ -272,6 +272,7 @@ bool psp_dev_encapsulate(struct net *net, struct sk_buff *skb, __be32 spi,
 		ip_hdr(skb)->check =
 			ip_fast_csum((u8 *)ip_hdr(skb), ip_hdr(skb)->ihl);
 	} else {
+		/* assumes there are no ipv6 extension headers */
 		ipv6_hdr(skb)->nexthdr = IPPROTO_UDP;
 		be16_add_cpu(&ipv6_hdr(skb)->payload_len, PSP_ENCAP_HLEN);
 	}
-- 
2.53.0-Meta
Thread (15 messages) 15 messages, 2 authors, last reply 10h ago
Keyboard shortcuts
hback out one level
jnext message in thread / next series-diff position
kprevious message in thread / previous series-diff position
ldrill in
Escclose help / fold thread tree
?toggle this help