summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXin Long <lucien.xin@gmail.com>2021-04-06 05:45:23 +0300
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2021-04-14 09:47:23 +0300
commit67f7aba24445293c05e8879f77c1326b2be89587 (patch)
treef83f234b2a7be4e1c8198f3002f270c0ceef62e1
parent42a4b202f851e089e1c6ec9fc3f35bcc21444811 (diff)
downloadlinux-67f7aba24445293c05e8879f77c1326b2be89587.tar.xz
tipc: increment the tmp aead refcnt before attaching it
[ Upstream commit 2a2403ca3add03f542f6b34bef9f74649969b06d ] Li Shuang found a NULL pointer dereference crash in her testing: [] BUG: unable to handle kernel NULL pointer dereference at 0000000000000020 [] RIP: 0010:tipc_crypto_rcv_complete+0xc8/0x7e0 [tipc] [] Call Trace: [] <IRQ> [] tipc_crypto_rcv+0x2d9/0x8f0 [tipc] [] tipc_rcv+0x2fc/0x1120 [tipc] [] tipc_udp_recv+0xc6/0x1e0 [tipc] [] udpv6_queue_rcv_one_skb+0x16a/0x460 [] udp6_unicast_rcv_skb.isra.35+0x41/0xa0 [] ip6_protocol_deliver_rcu+0x23b/0x4c0 [] ip6_input+0x3d/0xb0 [] ipv6_rcv+0x395/0x510 [] __netif_receive_skb_core+0x5fc/0xc40 This is caused by NULL returned by tipc_aead_get(), and then crashed when dereferencing it later in tipc_crypto_rcv_complete(). This might happen when tipc_crypto_rcv_complete() is called by two threads at the same time: the tmp attached by tipc_crypto_key_attach() in one thread may be released by the one attached by that in the other thread. This patch is to fix it by incrementing the tmp's refcnt before attaching it instead of calling tipc_aead_get() after attaching it. Fixes: fc1b6d6de220 ("tipc: introduce TIPC encryption & authentication") Reported-by: Li Shuang <shuali@redhat.com> Signed-off-by: Xin Long <lucien.xin@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net> Signed-off-by: Sasha Levin <sashal@kernel.org>
-rw-r--r--net/tipc/crypto.c3
1 files changed, 2 insertions, 1 deletions
diff --git a/net/tipc/crypto.c b/net/tipc/crypto.c
index f4fca8f7f63f..97710ce36047 100644
--- a/net/tipc/crypto.c
+++ b/net/tipc/crypto.c
@@ -1941,12 +1941,13 @@ static void tipc_crypto_rcv_complete(struct net *net, struct tipc_aead *aead,
goto rcv;
if (tipc_aead_clone(&tmp, aead) < 0)
goto rcv;
+ WARN_ON(!refcount_inc_not_zero(&tmp->refcnt));
if (tipc_crypto_key_attach(rx, tmp, ehdr->tx_key, false) < 0) {
tipc_aead_free(&tmp->rcu);
goto rcv;
}
tipc_aead_put(aead);
- aead = tipc_aead_get(tmp);
+ aead = tmp;
}
if (unlikely(err)) {