summaryrefslogtreecommitdiffstats
path: root/net/key
diff options
context:
space:
mode:
authorCong Wang2019-01-31 22:05:49 +0100
committerGreg Kroah-Hartman2019-04-20 09:16:03 +0200
commitbbbe47463da924160966d528c40182264b869a61 (patch)
tree5291009e4b07483cc505947e850d9f72ebc9a0c2 /net/key
parentnet/rds: fix warn in rds_message_alloc_sgs (diff)
downloadkernel-qcow2-linux-bbbe47463da924160966d528c40182264b869a61.tar.gz
kernel-qcow2-linux-bbbe47463da924160966d528c40182264b869a61.tar.xz
kernel-qcow2-linux-bbbe47463da924160966d528c40182264b869a61.zip
xfrm: destroy xfrm_state synchronously on net exit path
[ Upstream commit f75a2804da391571563c4b6b29e7797787332673 ] xfrm_state_put() moves struct xfrm_state to the GC list and schedules the GC work to clean it up. On net exit call path, xfrm_state_flush() is called to clean up and xfrm_flush_gc() is called to wait for the GC work to complete before exit. However, this doesn't work because one of the ->destructor(), ipcomp_destroy(), schedules the same GC work again inside the GC work. It is hard to wait for such a nested async callback. This is also why syzbot still reports the following warning: WARNING: CPU: 1 PID: 33 at net/ipv6/xfrm6_tunnel.c:351 xfrm6_tunnel_net_exit+0x2cb/0x500 net/ipv6/xfrm6_tunnel.c:351 ... ops_exit_list.isra.0+0xb0/0x160 net/core/net_namespace.c:153 cleanup_net+0x51d/0xb10 net/core/net_namespace.c:551 process_one_work+0xd0c/0x1ce0 kernel/workqueue.c:2153 worker_thread+0x143/0x14a0 kernel/workqueue.c:2296 kthread+0x357/0x430 kernel/kthread.c:246 ret_from_fork+0x3a/0x50 arch/x86/entry/entry_64.S:352 In fact, it is perfectly fine to bypass GC and destroy xfrm_state synchronously on net exit call path, because it is in process context and doesn't need a work struct to do any blocking work. This patch introduces xfrm_state_put_sync() which simply bypasses GC, and lets its callers to decide whether to use this synchronous version. On net exit path, xfrm_state_fini() and xfrm6_tunnel_net_exit() use it. And, as ipcomp_destroy() itself is blocking, it can use xfrm_state_put_sync() directly too. Also rename xfrm_state_gc_destroy() to ___xfrm_state_destroy() to reflect this change. Fixes: b48c05ab5d32 ("xfrm: Fix warning in xfrm6_tunnel_net_exit.") Reported-and-tested-by: syzbot+e9aebef558e3ed673934@syzkaller.appspotmail.com Cc: Steffen Klassert <steffen.klassert@secunet.com> Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com> Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com> Signed-off-by: Sasha Levin <sashal@kernel.org>
Diffstat (limited to 'net/key')
-rw-r--r--net/key/af_key.c2
1 files changed, 1 insertions, 1 deletions
diff --git a/net/key/af_key.c b/net/key/af_key.c
index 7da629d59717..7d4bed955060 100644
--- a/net/key/af_key.c
+++ b/net/key/af_key.c
@@ -1773,7 +1773,7 @@ static int pfkey_flush(struct sock *sk, struct sk_buff *skb, const struct sadb_m
if (proto == 0)
return -EINVAL;
- err = xfrm_state_flush(net, proto, true);
+ err = xfrm_state_flush(net, proto, true, false);
err2 = unicast_flush_resp(sk, hdr);
if (err || err2) {
if (err == -ESRCH) /* empty table - go quietly */