Takashi Iwai 028130
From 7d8a3a477b3e25ada8dc71d22048c2ea417209a0 Mon Sep 17 00:00:00 2001
Takashi Iwai 028130
From: Duoming Zhou <duoming@zju.edu.cn>
Takashi Iwai 028130
Date: Mon, 30 May 2022 23:21:58 +0800
Takashi Iwai 028130
Subject: [PATCH] ax25: Fix ax25 session cleanup problems
Takashi Iwai 028130
Git-commit: 7d8a3a477b3e25ada8dc71d22048c2ea417209a0
Takashi Iwai 028130
Patch-mainline: v5.19-rc1
Takashi Iwai 028130
References: git-fixes
Takashi Iwai 028130
Takashi Iwai 028130
[ backport note: replaced dev_{hold,put}_track() without _track -- tiwai ]
Takashi Iwai 028130
Takashi Iwai 028130
There are session cleanup problems in ax25_release() and
Takashi Iwai 028130
ax25_disconnect(). If we setup a session and then disconnect,
Takashi Iwai 028130
the disconnected session is still in "LISTENING" state that
Takashi Iwai 028130
is shown below.
Takashi Iwai 028130
Takashi Iwai 028130
Active AX.25 sockets
Takashi Iwai 028130
Dest       Source     Device  State        Vr/Vs    Send-Q  Recv-Q
Takashi Iwai 028130
DL9SAU-4   DL9SAU-3   ???     LISTENING    000/000  0       0
Takashi Iwai 028130
DL9SAU-3   DL9SAU-4   ???     LISTENING    000/000  0       0
Takashi Iwai 028130
Takashi Iwai 028130
The first reason is caused by del_timer_sync() in ax25_release().
Takashi Iwai 028130
The timers of ax25 are used for correct session cleanup. If we use
Takashi Iwai 028130
ax25_release() to close ax25 sessions and ax25_dev is not null,
Takashi Iwai 028130
the del_timer_sync() functions in ax25_release() will execute.
Takashi Iwai 028130
As a result, the sessions could not be cleaned up correctly,
Takashi Iwai 028130
because the timers have stopped.
Takashi Iwai 028130
Takashi Iwai 028130
In order to solve this problem, this patch adds a device_up flag
Takashi Iwai 028130
in ax25_dev in order to judge whether the device is up. If there
Takashi Iwai 028130
are sessions to be cleaned up, the del_timer_sync() in
Takashi Iwai 028130
ax25_release() will not execute. What's more, we add ax25_cb_del()
Takashi Iwai 028130
in ax25_kill_by_device(), because the timers have been stopped
Takashi Iwai 028130
and there are no functions that could delete ax25_cb if we do not
Takashi Iwai 028130
call ax25_release(). Finally, we reorder the position of
Takashi Iwai 028130
ax25_list_lock in ax25_cb_del() in order to synchronize among
Takashi Iwai 028130
different functions that call ax25_cb_del().
Takashi Iwai 028130
Takashi Iwai 028130
The second reason is caused by improper check in ax25_disconnect().
Takashi Iwai 028130
The incoming ax25 sessions which ax25->sk is null will close
Takashi Iwai 028130
heartbeat timer, because the check "if(!ax25->sk || ..)" is
Takashi Iwai 028130
satisfied. As a result, the session could not be cleaned up properly.
Takashi Iwai 028130
Takashi Iwai 028130
In order to solve this problem, this patch changes the improper
Takashi Iwai 028130
check to "if(ax25->sk && ..)" in ax25_disconnect().
Takashi Iwai 028130
Takashi Iwai 028130
What`s more, the ax25_disconnect() may be called twice, which is
Takashi Iwai 028130
not necessary. For example, ax25_kill_by_device() calls
Takashi Iwai 028130
ax25_disconnect() and sets ax25->state to AX25_STATE_0, but
Takashi Iwai 028130
ax25_release() calls ax25_disconnect() again.
Takashi Iwai 028130
Takashi Iwai 028130
In order to solve this problem, this patch add a check in
Takashi Iwai 028130
ax25_release(). If the flag of ax25->sk equals to SOCK_DEAD,
Takashi Iwai 028130
the ax25_disconnect() in ax25_release() should not be executed.
Takashi Iwai 028130
Takashi Iwai 028130
Fixes: 82e31755e55f ("ax25: Fix UAF bugs in ax25 timers")
Takashi Iwai 028130
Fixes: 8a367e74c012 ("ax25: Fix segfault after sock connection timeout")
Takashi Iwai 028130
Reported-and-tested-by: Thomas Osterried <thomas@osterried.de>
Takashi Iwai 028130
Signed-off-by: Duoming Zhou <duoming@zju.edu.cn>
Takashi Iwai 028130
Link: https://lore.kernel.org/r/20220530152158.108619-1-duoming@zju.edu.cn
Takashi Iwai 028130
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Takashi Iwai 028130
Acked-by: Takashi Iwai <tiwai@suse.de>
Takashi Iwai 028130
Takashi Iwai 028130
---
Takashi Iwai 028130
 include/net/ax25.h   |    1 +
Takashi Iwai 028130
 net/ax25/af_ax25.c   |   27 +++++++++++++++++----------
Takashi Iwai 028130
 net/ax25/ax25_dev.c  |    1 +
Takashi Iwai 028130
 net/ax25/ax25_subr.c |    2 +-
Takashi Iwai 028130
 4 files changed, 20 insertions(+), 11 deletions(-)
Takashi Iwai 028130
Takashi Iwai 028130
--- a/include/net/ax25.h
Takashi Iwai 028130
+++ b/include/net/ax25.h
Takashi Iwai 028130
@@ -237,6 +237,7 @@ typedef struct ax25_dev {
Takashi Iwai 028130
 	ax25_dama_info		dama;
Takashi Iwai 028130
 #endif
Takashi Iwai 028130
 	refcount_t		refcount;
Takashi Iwai 028130
+	bool device_up;
Takashi Iwai 028130
 } ax25_dev;
Takashi Iwai 028130
 
Takashi Iwai 028130
 typedef struct ax25_cb {
Takashi Iwai 028130
--- a/net/ax25/af_ax25.c
Takashi Iwai 028130
+++ b/net/ax25/af_ax25.c
Takashi Iwai 028130
@@ -62,12 +62,12 @@ static void ax25_free_sock(struct sock *
Takashi Iwai 028130
  */
Takashi Iwai 028130
 static void ax25_cb_del(ax25_cb *ax25)
Takashi Iwai 028130
 {
Takashi Iwai 028130
+	spin_lock_bh(&ax25_list_lock);
Takashi Iwai 028130
 	if (!hlist_unhashed(&ax25->ax25_node)) {
Takashi Iwai 028130
-		spin_lock_bh(&ax25_list_lock);
Takashi Iwai 028130
 		hlist_del_init(&ax25->ax25_node);
Takashi Iwai 028130
-		spin_unlock_bh(&ax25_list_lock);
Takashi Iwai 028130
 		ax25_cb_put(ax25);
Takashi Iwai 028130
 	}
Takashi Iwai 028130
+	spin_unlock_bh(&ax25_list_lock);
Takashi Iwai 028130
 }
Takashi Iwai 028130
 
Takashi Iwai 028130
 /*
Takashi Iwai 028130
@@ -81,6 +81,7 @@ static void ax25_kill_by_device(struct n
Takashi Iwai 028130
 
Takashi Iwai 028130
 	if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL)
Takashi Iwai 028130
 		return;
Takashi Iwai 028130
+	ax25_dev->device_up = false;
Takashi Iwai 028130
 
Takashi Iwai 028130
 	spin_lock_bh(&ax25_list_lock);
Takashi Iwai 028130
 again:
Takashi Iwai 028130
@@ -91,6 +92,7 @@ again:
Takashi Iwai 028130
 				spin_unlock_bh(&ax25_list_lock);
Takashi Iwai 028130
 				ax25_disconnect(s, ENETUNREACH);
Takashi Iwai 028130
 				s->ax25_dev = NULL;
Takashi Iwai 028130
+				ax25_cb_del(s);
Takashi Iwai 028130
 				spin_lock_bh(&ax25_list_lock);
Takashi Iwai 028130
 				goto again;
Takashi Iwai 028130
 			}
Takashi Iwai 028130
@@ -103,6 +105,7 @@ again:
Takashi Iwai 028130
 				dev_put(ax25_dev->dev);
Takashi Iwai 028130
 				ax25_dev_put(ax25_dev);
Takashi Iwai 028130
 			}
Takashi Iwai 028130
+			ax25_cb_del(s);
Takashi Iwai 028130
 			release_sock(sk);
Takashi Iwai 028130
 			spin_lock_bh(&ax25_list_lock);
Takashi Iwai 028130
 			sock_put(sk);
Takashi Iwai 028130
@@ -995,9 +998,11 @@ static int ax25_release(struct socket *s
Takashi Iwai 028130
 	if (sk->sk_type == SOCK_SEQPACKET) {
Takashi Iwai 028130
 		switch (ax25->state) {
Takashi Iwai 028130
 		case AX25_STATE_0:
Takashi Iwai 028130
-			release_sock(sk);
Takashi Iwai 028130
-			ax25_disconnect(ax25, 0);
Takashi Iwai 028130
-			lock_sock(sk);
Takashi Iwai 028130
+			if (!sock_flag(ax25->sk, SOCK_DEAD)) {
Takashi Iwai 028130
+				release_sock(sk);
Takashi Iwai 028130
+				ax25_disconnect(ax25, 0);
Takashi Iwai 028130
+				lock_sock(sk);
Takashi Iwai 028130
+			}
Takashi Iwai 028130
 			ax25_destroy_socket(ax25);
Takashi Iwai 028130
 			break;
Takashi Iwai 028130
 
Takashi Iwai 028130
@@ -1053,11 +1058,13 @@ static int ax25_release(struct socket *s
Takashi Iwai 028130
 		ax25_destroy_socket(ax25);
Takashi Iwai 028130
 	}
Takashi Iwai 028130
 	if (ax25_dev) {
Takashi Iwai 028130
-		del_timer_sync(&ax25->timer);
Takashi Iwai 028130
-		del_timer_sync(&ax25->t1timer);
Takashi Iwai 028130
-		del_timer_sync(&ax25->t2timer);
Takashi Iwai 028130
-		del_timer_sync(&ax25->t3timer);
Takashi Iwai 028130
-		del_timer_sync(&ax25->idletimer);
Takashi Iwai 028130
+		if (!ax25_dev->device_up) {
Takashi Iwai 028130
+			del_timer_sync(&ax25->timer);
Takashi Iwai 028130
+			del_timer_sync(&ax25->t1timer);
Takashi Iwai 028130
+			del_timer_sync(&ax25->t2timer);
Takashi Iwai 028130
+			del_timer_sync(&ax25->t3timer);
Takashi Iwai 028130
+			del_timer_sync(&ax25->idletimer);
Takashi Iwai 028130
+		}
Takashi Iwai 028130
 		dev_put(ax25_dev->dev);
Takashi Iwai 028130
 		ax25_dev_put(ax25_dev);
Takashi Iwai 028130
 	}
Takashi Iwai 028130
--- a/net/ax25/ax25_dev.c
Takashi Iwai 028130
+++ b/net/ax25/ax25_dev.c
Takashi Iwai 028130
@@ -62,6 +62,7 @@ void ax25_dev_device_up(struct net_devic
Takashi Iwai 028130
 	ax25_dev->dev     = dev;
Takashi Iwai 028130
 	dev_hold(dev);
Takashi Iwai 028130
 	ax25_dev->forward = NULL;
Takashi Iwai 028130
+	ax25_dev->device_up = true;
Takashi Iwai 028130
 
Takashi Iwai 028130
 	ax25_dev->values[AX25_VALUES_IPDEFMODE] = AX25_DEF_IPDEFMODE;
Takashi Iwai 028130
 	ax25_dev->values[AX25_VALUES_AXDEFMODE] = AX25_DEF_AXDEFMODE;
Takashi Iwai 028130
--- a/net/ax25/ax25_subr.c
Takashi Iwai 028130
+++ b/net/ax25/ax25_subr.c
Takashi Iwai 028130
@@ -268,7 +268,7 @@ void ax25_disconnect(ax25_cb *ax25, int
Takashi Iwai 028130
 		del_timer_sync(&ax25->t3timer);
Takashi Iwai 028130
 		del_timer_sync(&ax25->idletimer);
Takashi Iwai 028130
 	} else {
Takashi Iwai 028130
-		if (!ax25->sk || !sock_flag(ax25->sk, SOCK_DESTROY))
Takashi Iwai 028130
+		if (ax25->sk && !sock_flag(ax25->sk, SOCK_DESTROY))
Takashi Iwai 028130
 			ax25_stop_heartbeat(ax25);
Takashi Iwai 028130
 		ax25_stop_t1timer(ax25);
Takashi Iwai 028130
 		ax25_stop_t2timer(ax25);