ksmbd: fix use-after-free in __smb2_lease_break_noti()
authorNamjae Jeon <linkinjeon@kernel.org>
Fri, 11 Apr 2025 06:19:46 +0000 (15:19 +0900)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 2 May 2025 05:58:57 +0000 (07:58 +0200)
[ Upstream commit 21a4e47578d44c6b37c4fc4aba8ed7cc8dbb13de ]

Move tcp_transport free to ksmbd_conn_free. If ksmbd connection is
referenced when ksmbd server thread terminates, It will not be freed,
but conn->tcp_transport is freed. __smb2_lease_break_noti can be performed
asynchronously when the connection is disconnected. __smb2_lease_break_noti
calls ksmbd_conn_write, which can cause use-after-free
when conn->ksmbd_transport is already freed.

Cc: stable@vger.kernel.org
Reported-by: Norbert Szetei <norbert@doyensec.com>
Tested-by: Norbert Szetei <norbert@doyensec.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
fs/smb/server/connection.c
fs/smb/server/transport_tcp.c
fs/smb/server/transport_tcp.h

index b0f69cee96a758ccb76819a93c0deef4d3bb8ccc..7aaea71a4f20617dc7f8f8a6025d46a677ebba99 100644 (file)
@@ -39,8 +39,10 @@ void ksmbd_conn_free(struct ksmbd_conn *conn)
        xa_destroy(&conn->sessions);
        kvfree(conn->request_buf);
        kfree(conn->preauth_info);
-       if (atomic_dec_and_test(&conn->refcnt))
+       if (atomic_dec_and_test(&conn->refcnt)) {
+               ksmbd_free_transport(conn->transport);
                kfree(conn);
+       }
 }
 
 /**
index 7f38a3c3f5bd69b86aa250e28c6921c622acfcc1..abedf510899a744a0e8a67004154c066d7472353 100644 (file)
@@ -93,17 +93,21 @@ static struct tcp_transport *alloc_transport(struct socket *client_sk)
        return t;
 }
 
-static void free_transport(struct tcp_transport *t)
+void ksmbd_free_transport(struct ksmbd_transport *kt)
 {
-       kernel_sock_shutdown(t->sock, SHUT_RDWR);
-       sock_release(t->sock);
-       t->sock = NULL;
+       struct tcp_transport *t = TCP_TRANS(kt);
 
-       ksmbd_conn_free(KSMBD_TRANS(t)->conn);
+       sock_release(t->sock);
        kfree(t->iov);
        kfree(t);
 }
 
+static void free_transport(struct tcp_transport *t)
+{
+       kernel_sock_shutdown(t->sock, SHUT_RDWR);
+       ksmbd_conn_free(KSMBD_TRANS(t)->conn);
+}
+
 /**
  * kvec_array_init() - initialize a IO vector segment
  * @new:       IO vector to be initialized
index 8c9aa624cfe3cad9f853a1fc4f878b0acc5b35c9..1e51675ee1b2091a1c404621f1f9bd13798ebd76 100644 (file)
@@ -8,6 +8,7 @@
 
 int ksmbd_tcp_set_interfaces(char *ifc_list, int ifc_list_sz);
 struct interface *ksmbd_find_netdev_name_iface_list(char *netdev_name);
+void ksmbd_free_transport(struct ksmbd_transport *kt);
 int ksmbd_tcp_init(void);
 void ksmbd_tcp_destroy(void);