summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDuoming Zhou <duoming@zju.edu.cn>2022-03-26 13:43:46 +0300
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2022-04-08 15:23:53 +0300
commit409570a619c1cda2e0fde6018a256b9e3d3ba0ee (patch)
treed2b2075af1ed65b9dd27b02121b052821a7b9fde
parentc416e9bb85a647a12ae22df39ccc62b99f02a365 (diff)
downloadlinux-409570a619c1cda2e0fde6018a256b9e3d3ba0ee.tar.xz
net/x25: Fix null-ptr-deref caused by x25_disconnect
[ Upstream commit 7781607938c8371d4c2b243527430241c62e39c2 ] When the link layer is terminating, x25->neighbour will be set to NULL in x25_disconnect(). As a result, it could cause null-ptr-deref bugs in x25_sendmsg(),x25_recvmsg() and x25_connect(). One of the bugs is shown below. (Thread 1) | (Thread 2) x25_link_terminated() | x25_recvmsg() x25_kill_by_neigh() | ... x25_disconnect() | lock_sock(sk) ... | ... x25->neighbour = NULL //(1) | ... | x25->neighbour->extended //(2) The code sets NULL to x25->neighbour in position (1) and dereferences x25->neighbour in position (2), which could cause null-ptr-deref bug. This patch adds lock_sock() in x25_kill_by_neigh() in order to synchronize with x25_sendmsg(), x25_recvmsg() and x25_connect(). What`s more, the sock held by lock_sock() is not NULL, because it is extracted from x25_list and uses x25_list_lock to synchronize. Fixes: 4becb7ee5b3d ("net/x25: Fix x25_neigh refcnt leak when x25 disconnect") Signed-off-by: Duoming Zhou <duoming@zju.edu.cn> Reviewed-by: Lin Ma <linma@zju.edu.cn> Signed-off-by: David S. Miller <davem@davemloft.net> Signed-off-by: Sasha Levin <sashal@kernel.org>
-rw-r--r--net/x25/af_x25.c11
1 files changed, 8 insertions, 3 deletions
diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c
index 3583354a7d7f..3a171828638b 100644
--- a/net/x25/af_x25.c
+++ b/net/x25/af_x25.c
@@ -1765,10 +1765,15 @@ void x25_kill_by_neigh(struct x25_neigh *nb)
write_lock_bh(&x25_list_lock);
- sk_for_each(s, &x25_list)
- if (x25_sk(s)->neighbour == nb)
+ sk_for_each(s, &x25_list) {
+ if (x25_sk(s)->neighbour == nb) {
+ write_unlock_bh(&x25_list_lock);
+ lock_sock(s);
x25_disconnect(s, ENETUNREACH, 0, 0);
-
+ release_sock(s);
+ write_lock_bh(&x25_list_lock);
+ }
+ }
write_unlock_bh(&x25_list_lock);
/* Remove any related forwards */