From 28e71cb51cdfcbc0f37ef8011a5a1c7a49423faf Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 28 Apr 2026 13:53:50 -0700 Subject: [PATCH 1/3] psp: validate protocol before mutating skb in psp_dev_encapsulate() Code checkers / AI scans will complain that we have already modified the packet by the time we realize that protocol is not IP. Move the skb->protocol check to before skb_push()/memmove() so that the skb is not left in a corrupted state when the function returns false for an unsupported protocol. psp_dev_rcv() follows similar pattern. Today this path is unreachable because both in-tree callers (mlx5 and netdevsim) only reach psp_dev_encapsulate() from TCP socket TX paths where skb->protocol is always ETH_P_IP or ETH_P_IPV6, and both drop the skb on a false return, anyway. Reviewed-by: Eric Dumazet Reviewed-by: Willem de Bruijn Link: https://patch.msgid.link/20260428205352.1247325-2-kuba@kernel.org Signed-off-by: Jakub Kicinski --- net/psp/psp_main.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/net/psp/psp_main.c b/net/psp/psp_main.c index 9508b6c38003..652ec8a9c8a4 100644 --- a/net/psp/psp_main.c +++ b/net/psp/psp_main.c @@ -228,6 +228,10 @@ bool psp_dev_encapsulate(struct net *net, struct sk_buff *skb, __be32 spi, u32 ethr_len = skb_mac_header_len(skb); u32 bufflen = ethr_len + network_len; + if (skb->protocol != htons(ETH_P_IP) && + skb->protocol != htons(ETH_P_IPV6)) + return false; + if (skb_cow_head(skb, PSP_ENCAP_HLEN)) return false; @@ -243,11 +247,9 @@ bool psp_dev_encapsulate(struct net *net, struct sk_buff *skb, __be32 spi, ip_hdr(skb)->check = 0; ip_hdr(skb)->check = ip_fast_csum((u8 *)ip_hdr(skb), ip_hdr(skb)->ihl); - } else if (skb->protocol == htons(ETH_P_IPV6)) { + } else { ipv6_hdr(skb)->nexthdr = IPPROTO_UDP; be16_add_cpu(&ipv6_hdr(skb)->payload_len, PSP_ENCAP_HLEN); - } else { - return false; } skb_set_inner_ipproto(skb, IPPROTO_TCP); From 5637fcb11c9128283db598ff398924d910c73143 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 28 Apr 2026 13:53:51 -0700 Subject: [PATCH 2/3] psp: add a comment about a psp_dev add netlink notification In psp_dev_create(), the DEV_ADD_NTF netlink notification is sent before the device is published to the netdev via rcu_assign_pointer(). IIRC this is intentional because a single PSP device is expected to be shared with multiple netdevs. So we are trying to default to not having the netdev info. We can change it if someone complains but for now just add a comment that it's intentional. Reviewed-by: Willem de Bruijn Link: https://patch.msgid.link/20260428205352.1247325-3-kuba@kernel.org Signed-off-by: Jakub Kicinski --- net/psp/psp_main.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/psp/psp_main.c b/net/psp/psp_main.c index 652ec8a9c8a4..f069117c867a 100644 --- a/net/psp/psp_main.c +++ b/net/psp/psp_main.c @@ -90,6 +90,10 @@ psp_dev_create(struct net_device *netdev, mutex_lock(&psd->lock); mutex_unlock(&psp_devs_lock); + /* notify before netdev assignment + * There's no strong reason for it, but thinking is to avoid creating + * implicit expectations about the PSP dev <> netdev relationship. + */ psp_nl_notify_dev(psd, PSP_CMD_DEV_ADD_NTF); rcu_assign_pointer(netdev->psp_dev, psd); From c2b22277ad897d21341f502f87fccd905ff4e207 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 28 Apr 2026 13:53:52 -0700 Subject: [PATCH 3/3] psp: validate IPv4 header fields in psp_dev_rcv() psp_dev_rcv() is called from the NIC driver's RX completion path before the frame reaches ip_rcv_core(), so the IP header has not been validated in SW, yet. We expect that the device has done all this validation, but let's also add the SW checks, to avoid surprises. Reviewed-by: Eric Dumazet Reviewed-by: Willem de Bruijn Link: https://patch.msgid.link/20260428205352.1247325-4-kuba@kernel.org Signed-off-by: Jakub Kicinski --- net/psp/psp_main.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/net/psp/psp_main.c b/net/psp/psp_main.c index f069117c867a..524978dfb8fd 100644 --- a/net/psp/psp_main.c +++ b/net/psp/psp_main.c @@ -300,6 +300,9 @@ int psp_dev_rcv(struct sk_buff *skb, u16 dev_id, u8 generation, bool strip_icv) if (proto == htons(ETH_P_IP)) { struct iphdr *iph = (struct iphdr *)(skb->data + l2_hlen); + if (unlikely(iph->ihl < 5)) + return -EINVAL; + is_udp = iph->protocol == IPPROTO_UDP; l3_hlen = iph->ihl * 4; if (l3_hlen != sizeof(struct iphdr) && @@ -335,6 +338,9 @@ int psp_dev_rcv(struct sk_buff *skb, u16 dev_id, u8 generation, bool strip_icv) if (proto == htons(ETH_P_IP)) { struct iphdr *iph = (struct iphdr *)(skb->data + l2_hlen); + if (unlikely(ntohs(iph->tot_len) < l3_hlen + encap)) + return -EINVAL; + iph->protocol = psph->nexthdr; iph->tot_len = htons(ntohs(iph->tot_len) - encap); iph->check = 0; @@ -342,6 +348,9 @@ int psp_dev_rcv(struct sk_buff *skb, u16 dev_id, u8 generation, bool strip_icv) } else { struct ipv6hdr *ipv6h = (struct ipv6hdr *)(skb->data + l2_hlen); + if (unlikely(ntohs(ipv6h->payload_len) < encap)) + return -EINVAL; + ipv6h->nexthdr = psph->nexthdr; ipv6h->payload_len = htons(ntohs(ipv6h->payload_len) - encap); }