summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZhiling Zou <roxy520tt@gmail.com>2026-07-18 15:12:50 +0800
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2026-09-02 14:27:28 +0200
commitf00235f9d12301183d61f75fbe4105506f3e5140 (patch)
tree7220cafebbdc83ceb6f68a89eb6d1db216143f34
parented5d9102190c45fc70121c036b0626b740040b75 (diff)
downloadlinux-stable-f00235f9d12301183d61f75fbe4105506f3e5140.tar.gz
linux-stable-f00235f9d12301183d61f75fbe4105506f3e5140.zip
xfrm: drop ESP-in-TCP packets with no ingress device
commit e1d7c5ac1c246ce5775f604515de0a59fbf2116e upstream. ESP-in-TCP receives records through the TCP strparser. handle_esp() restores skb->dev from the saved skb_iif before passing the packet into the XFRM input path. Queued TCP data can be processed after the original ingress device has been removed, for example during veth or net namespace teardown. In that case dev_get_by_index_rcu() returns NULL. The XFRM IPv4 and IPv6 input paths both expect skb->dev to be valid while building the route lookup, so queued ESP-in-TCP data can dereference a NULL device. Drop the packet if the saved ingress device can no longer be resolved. Such a packet can no longer be routed through the normal XFRM receive path, and this preserves the existing behaviour for packets whose ingress device still exists. Fixes: e27cca96cd68 ("xfrm: add espintcp (RFC 8229)") Cc: stable@vger.kernel.org Reported-by: Vega <vega@nebusec.ai> Signed-off-by: Zhiling Zou <roxy520tt@gmail.com> Assisted-by: Codex:gpt-5.4 Reviewed-by: Ren Wei <enjou1224z@gmail.com> Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--net/xfrm/espintcp.c6
1 files changed, 6 insertions, 0 deletions
diff --git a/net/xfrm/espintcp.c b/net/xfrm/espintcp.c
index b16ac695a396..47212b6f917a 100644
--- a/net/xfrm/espintcp.c
+++ b/net/xfrm/espintcp.c
@@ -38,6 +38,11 @@ static void handle_esp(struct sk_buff *skb, struct sock *sk)
rcu_read_lock();
skb->dev = dev_get_by_index_rcu(sock_net(sk), skb->skb_iif);
+ if (!skb->dev) {
+ XFRM_INC_STATS(sock_net(sk), LINUX_MIB_XFRMINERROR);
+ kfree_skb(skb);
+ goto out;
+ }
local_bh_disable();
#if IS_ENABLED(CONFIG_IPV6)
if (sk->sk_family == AF_INET6)
@@ -46,6 +51,7 @@ static void handle_esp(struct sk_buff *skb, struct sock *sk)
#endif
xfrm4_rcv_encap(skb, IPPROTO_ESP, 0, TCP_ENCAP_ESPINTCP);
local_bh_enable();
+out:
rcu_read_unlock();
}