[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-Id: <20220326104346.91790-1-duoming@zju.edu.cn>
Date: Sat, 26 Mar 2022 18:43:46 +0800
From: Duoming Zhou <duoming@....edu.cn>
To: linux-x25@...r.kernel.org
Cc: netdev@...r.kernel.org, linux-kernel@...r.kernel.org,
ms@....tdt.de, davem@...emloft.net, kuba@...nel.org,
pabeni@...hat.com, tanxin.ctf@...il.com, xiyuyang19@...an.edu.cn,
linma@....edu.cn, Duoming Zhou <duoming@....edu.cn>
Subject: [PATCH net V2] net/x25: Fix null-ptr-deref caused by x25_disconnect
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@....edu.cn>
Reviewed-by: Lin Ma <linma@....edu.cn>
---
Changes in V2:
- Add lock_sock() in x25_kill_by_neigh().
- Make commit message more clearer.
net/x25/af_x25.c | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c
index 3583354a7d7..3a171828638 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 */
--
2.17.1
Powered by blists - more mailing lists