FAILED: patch "[PATCH] smb: client: hold server info until cifsd exits" failed to apply to 6.1-stable tree
Subsystems (2)
[email protected]
maintainerThe patch below does not apply to the 6.1-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.1.y
git checkout FETCH_HEAD
git cherry-pick -x 482c117c6dbeee382790168af10959810450ab09
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026110421-avatar-written-3163@gregkh' --subject-prefix 'PATCH 6.1.y' 'HEAD^..'
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 482c117c6dbeee382790168af10959810450ab09 Mon Sep 17 00:00:00 2001
From: Eduard Zateev <[email protected]>
Date: Tue, 20 Oct 2026 21:45:45 +0200
Subject: [PATCH] smb: client: hold server info until cifsd exits
The last session reference can be dropped while the cifsd demultiplex thread is still running clean_demultiplex_info(). That thread frees TCP_Server_Info there, racing with cifs_put_tcp_session() as it releases the server crypto state. syzbot reported a KASAN use-after-free in cifs_crypto_secmech_release().
Keep an object reference for the cifsd thread. Defer final crypto, session-key, network namespace, string, and structure cleanup until both the last session reference and the thread reference are dropped. Drop the thread reference after clean_demultiplex_info() has finished using the server.
Build-tested with ARCH=arm64 and W=1 for fs/smb/client/connect.o. The KASAN reproducer was not run on the patched kernel.
fs/smb/client/cifsglob.h +2 -0
@@ -16,6 +16,7 @@#include <linux/scatterlist.h> #include <linux/mm.h> #include <linux/mempool.h> +#include <linux/refcount.h> #include <linux/workqueue.h> #include <linux/utsname.h> #include <linux/sched/mm.h>
@@ -681,6 +682,7 @@ struct TCP_Server_Info {spinlock_t srv_lock;/* protect anything here that is not protected */ __u64 conn_id;/* connection identifier (useful for debugging) */ int srv_count;/* reference counter */ +refcount_t obj_refs;/* struct lifetime: srv_count users + cifsd */ int rfc1001_sessinit;/* whether to estasblish netbios session */ bool with_rfc1001;/* if netbios session is used */ /* 15 character server name + 0x20 16th byte indicating type = srv */
fs/smb/client/connect.c +21 -12
@@ -1083,6 +1083,19 @@ cifs_enable_signing(struct TCP_Server_Info *server, bool mnt_sign_required)return 0 ; } +static void cifs_tcp_server_put (struct TCP_Server_Info *server) +{ +if (!refcount_dec_and_test (&server->obj_refs)) +return ; + +cifs_crypto_secmech_release (server); +kfree_sensitive (server->session_key.response); +put_net (cifs_net_ns (server)); +kfree (server->leaf_fullpath); +kfree (server->hostname); +kfree_sensitive (server); +} + static noinline_for_stack voidclean_demultiplex_info (struct TCP_Server_Info *server) {
@@ -1168,14 +1181,11 @@ clean_demultiplex_info(struct TCP_Server_Info *server)*/ } -put_net (cifs_net_ns (server)); -kfree (server->leaf_fullpath); -kfree (server->hostname); -kfree_sensitive (server); - length =atomic_dec_return (&tcpSesAllocCount);if (length >0 )mempool_resize (cifs_req_poolp, length + cifs_min_rcv); + +cifs_tcp_server_put (server); } static int
@@ -1751,7 +1761,7 @@ cifs_put_tcp_session(struct TCP_Server_Info *server, int from_reconnect)else cancel_delayed_work_sync (&server->reconnect); -/* For secondary channels, we pick up ref-count on the primary server */ +/* For secondary channels, drop the reference on the primary server */ if (SERVER_IS_CHAN (server))cifs_put_tcp_session (server->primary_server, from_reconnect);
@@ -1759,15 +1769,11 @@ cifs_put_tcp_session(struct TCP_Server_Info *server, int from_reconnect) server->tcpStatus = CifsExiting;spin_unlock (&server->srv_lock); -cifs_crypto_secmech_release (server); - -kfree_sensitive (server->session_key.response); - server->session_key.response =NULL ; - server->session_key.len =0 ; - task =xchg (&server->tsk,NULL );if (task)send_sig (SIGKILL , task,1 ); + +cifs_tcp_server_put (server); } struct TCP_Server_Info *
@@ -1789,6 +1795,7 @@ cifs_get_tcp_session(struct smb3_fs_context *ctx, rc = -ENOMEM ; goto out_err; } +refcount_set (&tcp_ses->obj_refs,1 ); tcp_ses->hostname =kstrdup (ctx->server_hostname,GFP_KERNEL );if (!tcp_ses->hostname) {
@@ -1927,6 +1934,8 @@ smbd_connected:module_put (THIS_MODULE ); goto out_err_crypto_release; } +/* Keep the server alive until the demultiplex thread has exited */ +refcount_inc (&tcp_ses->obj_refs);/* thread created, put it on the list */ spin_lock (&cifs_tcp_ses_lock);list_add (&tcp_ses->tcp_ses_list, &cifs_tcp_ses_list);
Sasha Levin
maintainerPATCH 1/1 smb: client: hold server info until cifsd exits
From: Eduard Zateev <[email protected]>
[ Upstream commit 482c117c6dbeee382790168af10959810450ab09 ]
The last session reference can be dropped while the cifsd demultiplex thread is still running clean_demultiplex_info(). That thread frees TCP_Server_Info there, racing with cifs_put_tcp_session() as it releases the server crypto state. syzbot reported a KASAN use-after-free in cifs_crypto_secmech_release().
Keep an object reference for the cifsd thread. Defer final crypto, session-key, network namespace, string, and structure cleanup until both the last session reference and the thread reference are dropped. Drop the thread reference after clean_demultiplex_info() has finished using the server.
Build-tested with ARCH=arm64 and W=1 for fs/smb/client/connect.o. The KASAN reproducer was not run on the patched kernel.
--- fs/smb/client/cifsglob.h | 2 ++ fs/smb/client/connect.c | 38 +++++++++++++++++++++++--------------- 2 files changed, 25 insertions(+), 15 deletions(-)
fs/smb/client/cifsglob.h +2 -0
@@ -16,6 +16,7 @@#include <linux/scatterlist.h> #include <linux/mm.h> #include <linux/mempool.h> +#include <linux/refcount.h> #include <linux/workqueue.h> #include <linux/utsname.h> #include <linux/sched/mm.h>
@@ -589,6 +590,7 @@ struct TCP_Server_Info {spinlock_t srv_lock;/* protect anything here that is not protected */ __u64 conn_id;/* connection identifier (useful for debugging) */ int srv_count;/* reference counter */ +refcount_t obj_refs;/* struct lifetime: srv_count users + cifsd */ /* 15 character server name + 0x20 16th byte indicating type = srv */ char server_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL ];struct smb_version_operations *ops;
fs/smb/client/connect.c +23 -15
@@ -984,6 +984,21 @@ cifs_enable_signing(struct TCP_Server_Info *server, bool mnt_sign_required)return 0 ; } +static void cifs_tcp_server_put (struct TCP_Server_Info *server) +{ +if (!refcount_dec_and_test (&server->obj_refs)) +return ; + +cifs_crypto_secmech_release (server); +kfree_sensitive (server->session_key.response); +put_net (cifs_net_ns (server)); +#ifdef CONFIG_CIFS_DFS_UPCALL +kfree (server->origin_fullpath); +kfree (server->leaf_fullpath); +#endif +kfree (server->hostname); +kfree_sensitive (server); +}static void clean_demultiplex_info (struct TCP_Server_Info *server) {
@@ -1070,17 +1085,11 @@ static void clean_demultiplex_info(struct TCP_Server_Info *server)*/ } -put_net (cifs_net_ns (server)); -#ifdef CONFIG_CIFS_DFS_UPCALL -kfree (server->origin_fullpath); -kfree (server->leaf_fullpath); -#endif -kfree (server->hostname); -kfree (server); - length =atomic_dec_return (&tcpSesAllocCount);if (length >0 )mempool_resize (cifs_req_poolp, length + cifs_min_rcv); + +cifs_tcp_server_put (server); } static int
@@ -1669,7 +1678,7 @@ cifs_put_tcp_session(struct TCP_Server_Info *server, int from_reconnect)list_del_init (&server->tcp_ses_list);spin_unlock (&cifs_tcp_ses_lock); -/* For secondary channels, we pick up ref-count on the primary server */ +/* For secondary channels, drop the reference on the primary server */ if (CIFS_SERVER_IS_CHAN (server))cifs_put_tcp_session (server->primary_server, from_reconnect);
@@ -1690,15 +1699,11 @@ cifs_put_tcp_session(struct TCP_Server_Info *server, int from_reconnect) server->tcpStatus = CifsExiting;spin_unlock (&server->srv_lock); -cifs_crypto_secmech_release (server); - -kfree_sensitive (server->session_key.response); - server->session_key.response =NULL ; - server->session_key.len =0 ; - task =xchg (&server->tsk,NULL );if (task)send_sig (SIGKILL , task,1 ); + +cifs_tcp_server_put (server); } struct TCP_Server_Info *
@@ -1720,6 +1725,7 @@ cifs_get_tcp_session(struct smb3_fs_context *ctx, rc = -ENOMEM ; goto out_err; } +refcount_set (&tcp_ses->obj_refs,1 ); tcp_ses->hostname =kstrdup (ctx->server_hostname,GFP_KERNEL );if (!tcp_ses->hostname) {
@@ -1849,6 +1855,8 @@ cifs_get_tcp_session(struct smb3_fs_context *ctx,module_put (THIS_MODULE ); goto out_err_crypto_release; } +/* Keep the server alive until the demultiplex thread has exited */ +refcount_inc (&tcp_ses->obj_refs);/* thread created, put it on the list */ spin_lock (&cifs_tcp_ses_lock);list_add (&tcp_ses->tcp_ses_list, &cifs_tcp_ses_list);
Signature · 1 line
2.53.0