Skip to content

Commit 226f4a4

Browse files
DoLoveCatklassert
authored andcommitted
xfrm: nat_keepalive: avoid double free on send error
nat_keepalive_send() frees the keepalive skb whenever the IPv4 or IPv6 send helper reports an error. That cleanup is only correct before the skb is handed to the output path. Once ip_build_and_send_pkt() or ip6_xmit() takes ownership, the networking stack may already have consumed the skb before returning an error, so freeing it again is unsafe. Handle the pre-handoff failure cases inside nat_keepalive_send_ipv4() and nat_keepalive_send_ipv6(), where the caller still owns the skb, and keep nat_keepalive_send() responsible only for family dispatch and the unsupported-family cleanup path. Fixes: f531d13 ("xfrm: support sending NAT keepalives in ESP in UDP states") Cc: stable@vger.kernel.org Reported-by: Yuan Tan <yuantan098@gmail.com> Reported-by: Xin Liu <bird@lzu.edu.cn> Signed-off-by: Qianyu Luo <qianyuluo3@gmail.com> Signed-off-by: Ren Wei <n05ec@lzu.edu.cn> Reviewed-by: Eyal Birger <eyal.birger@gmail.com> Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
1 parent 3f4c391 commit 226f4a4

1 file changed

Lines changed: 9 additions & 6 deletions

File tree

net/xfrm/xfrm_nat_keepalive.c

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,10 @@ static int nat_keepalive_send_ipv4(struct sk_buff *skb,
5555
ka->encap_sport, sock_net_uid(net, NULL));
5656

5757
rt = ip_route_output_key(net, &fl4);
58-
if (IS_ERR(rt))
58+
if (IS_ERR(rt)) {
59+
kfree_skb(skb);
5960
return PTR_ERR(rt);
61+
}
6062

6163
skb_dst_set(skb, &rt->dst);
6264

@@ -101,6 +103,7 @@ static int nat_keepalive_send_ipv6(struct sk_buff *skb,
101103
dst = ip6_dst_lookup_flow(net, sk, &fl6, NULL);
102104
if (IS_ERR(dst)) {
103105
local_unlock_nested_bh(&nat_keepalive_sk_ipv6.bh_lock);
106+
kfree_skb(skb);
104107
return PTR_ERR(dst);
105108
}
106109

@@ -118,7 +121,6 @@ static void nat_keepalive_send(struct nat_keepalive *ka)
118121
sizeof(struct ipv6hdr)) +
119122
sizeof(struct udphdr);
120123
const u8 nat_ka_payload = 0xFF;
121-
int err = -EAFNOSUPPORT;
122124
struct sk_buff *skb;
123125
struct udphdr *uh;
124126

@@ -140,16 +142,17 @@ static void nat_keepalive_send(struct nat_keepalive *ka)
140142

141143
switch (ka->family) {
142144
case AF_INET:
143-
err = nat_keepalive_send_ipv4(skb, ka);
145+
nat_keepalive_send_ipv4(skb, ka);
144146
break;
145147
#if IS_ENABLED(CONFIG_IPV6)
146148
case AF_INET6:
147-
err = nat_keepalive_send_ipv6(skb, ka, uh);
149+
nat_keepalive_send_ipv6(skb, ka, uh);
148150
break;
149151
#endif
150-
}
151-
if (err)
152+
default:
152153
kfree_skb(skb);
154+
break;
155+
}
153156
}
154157

155158
struct nat_keepalive_work_ctx {

0 commit comments

Comments
 (0)