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