All of lore.kernel.org
 help / color / mirror / Atom feed
From: Ibrahim Hashimov <security@auditcode.ai>
To: ms@dev.tdt.de, davem@davemloft.net, edumazet@google.com,
	kuba@kernel.org, pabeni@redhat.com
Cc: horms@kernel.org, linma@zju.edu.cn, duoming@zju.edu.cn,
	linux-x25@vger.kernel.org, netdev@vger.kernel.org,
	linux-kernel@vger.kernel.org, stable@vger.kernel.org
Subject: [PATCH net] net: x25: fix use-after-free in x25_kill_by_neigh()
Date: Mon, 20 Jul 2026 22:27:18 +0200	[thread overview]
Message-ID: <20260720202718.13934-1-security@auditcode.ai> (raw)

x25_kill_by_neigh() walks x25_list under x25_list_lock and, for each
socket whose neighbour matches the one going down, drops the list lock,
calls lock_sock()/x25_disconnect()/release_sock() on the socket
(x25_disconnect() can sleep and must not be called with a bh-disabled
spinlock held), and then re-acquires x25_list_lock before continuing the
sk_for_each() walk. No reference is taken on the socket before the list
lock is dropped.

A concurrent close() of that same socket runs x25_release() ->
__x25_destroy_socket() -> x25_remove_socket() (unlinks it from x25_list)
-> eventually the final sock_put(), which frees the kmalloc-2k sock
object. If this happens while x25_kill_by_neigh() has dropped
x25_list_lock, both the lock_sock(s) call right after the unlock and,
once x25_list_lock is re-taken, the sk_for_each() walk's implicit read of
s->sk_node.next can dereference the freed socket.

Reproduced on a v6.19 KASAN kernel under -smp 4 with a killer thread
free-running NETDEV_DOWN toggles (driving x25_device_event() ->
x25_kill_by_neigh()) against several threads closing/recreating
neighbour-bound AF_X25 sockets: KASAN slab-use-after-free in
x25_kill_by_neigh()+0xfd/0x110, "Read of size 8" at offset 104 into a
freed kmalloc-2k object -- exactly the sk->sk_node.next field of the
socket concurrently freed by close(). 145 splats fired over roughly
64,400 kill rounds in the racing configuration; a serialized control run
(single kill, sockets closed sequentially, no concurrent free) produced
zero KASAN reports. With this patch applied the same free-running
reproducer no longer triggers the report.

Fix this the same way the rest of net/x25 protects a socket found by
walking x25_list under x25_list_lock (see x25_find_listener() and
__x25_find_socket(), which sock_hold() the socket before dropping the
list lock): take a reference on the socket before dropping x25_list_lock,
and release it with sock_put() once lock_sock() / x25_disconnect() /
release_sock() are done. Since a concurrent x25_remove_socket() can still
unlink the socket from x25_list (and reinitialize its list node) while
the lock is dropped, simply re-acquiring x25_list_lock and resuming the
sk_for_each() walk from the old s is not safe either way, so restart the
scan from the head of x25_list instead of trying to resume it.
x25_disconnect() clears x25_sk(s)->neighbour, so the just-handled socket
will not match nb again and the restarted scan makes forward progress on
each pass.

Fixes: 7781607938c8 ("net/x25: Fix null-ptr-deref caused by x25_disconnect")
Cc: stable@vger.kernel.org
Signed-off-by: Ibrahim Hashimov <security@auditcode.ai>
Assisted-by: AuditCode-AI:2026.07
---
 net/x25/af_x25.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c
index c31d2af5dd22..725d35596e3f 100644
--- a/net/x25/af_x25.c
+++ b/net/x25/af_x25.c
@@ -1768,15 +1768,18 @@ void x25_kill_by_neigh(struct x25_neigh *nb)
 {
 	struct sock *s;
 
+restart:
 	write_lock_bh(&x25_list_lock);
 
 	sk_for_each(s, &x25_list) {
 		if (x25_sk(s)->neighbour == nb) {
+			sock_hold(s);
 			write_unlock_bh(&x25_list_lock);
 			lock_sock(s);
 			x25_disconnect(s, ENETUNREACH, 0, 0);
 			release_sock(s);
-			write_lock_bh(&x25_list_lock);
+			sock_put(s);
+			goto restart;
 		}
 	}
 	write_unlock_bh(&x25_list_lock);
-- 
2.50.1 (Apple Git-155)


                 reply	other threads:[~2026-07-20 20:27 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260720202718.13934-1-security@auditcode.ai \
    --to=security@auditcode.ai \
    --cc=davem@davemloft.net \
    --cc=duoming@zju.edu.cn \
    --cc=edumazet@google.com \
    --cc=horms@kernel.org \
    --cc=kuba@kernel.org \
    --cc=linma@zju.edu.cn \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-x25@vger.kernel.org \
    --cc=ms@dev.tdt.de \
    --cc=netdev@vger.kernel.org \
    --cc=pabeni@redhat.com \
    --cc=stable@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.