FAILED: patch "[PATCH] smb: client: hold server info until cifsd exits" failed to apply to 5.10-stable tree
Subsystems (2)
[email protected]
maintainerThe patch below does not apply to the 5.10-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-5.10.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 '2026110422-graduate-mounting-470e@gregkh' --subject-prefix 'PATCH 5.10.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/cifs/cifsglob.h | 2 ++ fs/cifs/connect.c | 29 +++++++++++++++++++---------- 2 files changed, 21 insertions(+), 10 deletions(-)
fs/cifs/cifsglob.h +2 -0
@@ -25,6 +25,7 @@#include <linux/scatterlist.h> #include <linux/mm.h> #include <linux/mempool.h> +#include <linux/refcount.h> #include <linux/workqueue.h> #include <linux/fcntl.h> #include "cifs_fs_sb.h"
@@ -674,6 +675,7 @@ struct TCP_Server_Info {struct list_head tcp_ses_list;struct list_head smb_ses_list;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/cifs/connect.c +19 -10
@@ -880,6 +880,18 @@ handle_mid(struct mid_q_entry *mid, struct TCP_Server_Info *server,dequeue_mid (mid, malformed); } +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->hostname); +kfree_sensitive (server); +} +static void clean_demultiplex_info (struct TCP_Server_Info *server) {int length;
@@ -964,12 +976,11 @@ static void clean_demultiplex_info(struct TCP_Server_Info *server)*/ } -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
@@ -2496,8 +2507,6 @@ cifs_put_tcp_session(struct TCP_Server_Info *server, int from_reconnect)return ; } -put_net (cifs_net_ns (server)); -list_del_init (&server->tcp_ses_list);spin_unlock (&cifs_tcp_ses_lock);
@@ -2518,16 +2527,13 @@ cifs_put_tcp_session(struct TCP_Server_Info *server, int from_reconnect) server->tcpStatus = CifsExiting;spin_unlock (&GlobalMid_Lock); -cifs_crypto_secmech_release (server);cifs_fscache_release_client_cookie (server); -kfree (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 *
@@ -2548,6 +2554,7 @@ cifs_get_tcp_session(struct smb_vol *volume_info) rc = -ENOMEM ; goto out_err; } +refcount_set (&tcp_ses->obj_refs,1 ); tcp_ses->ops = volume_info->ops; tcp_ses->vals = volume_info->vals;
@@ -2635,6 +2642,8 @@ cifs_get_tcp_session(struct smb_vol *volume_info)* this will succeed. No need for try_module_get(). */ __module_get (THIS_MODULE ); +/* Keep the server alive until the demultiplex thread has exited */ +refcount_inc (&tcp_ses->obj_refs); tcp_ses->tsk =kthread_run (cifs_demultiplex_thread, tcp_ses,"cifsd" );if (IS_ERR (tcp_ses->tsk)) {
Signature · 1 line
2.53.0