From: Greg Kroah-Hartman Date: Tue, 22 Apr 2025 09:59:19 +0000 (+0200) Subject: 5.10-stable patches X-Git-Tag: v6.1.135~54 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=08b3f4fee0afcbff6c5cee853c09c23e3f3fde36;p=thirdparty%2Fkernel%2Fstable-queue.git 5.10-stable patches added patches: cifs-fix-uaf-in-cifs_demultiplex_thread.patch smb-client-fix-potential-deadlock-when-releasing-mids.patch smb-client-fix-use-after-free-bug-in-cifs_debug_data_proc_show.patch --- diff --git a/queue-5.10/cifs-fix-uaf-in-cifs_demultiplex_thread.patch b/queue-5.10/cifs-fix-uaf-in-cifs_demultiplex_thread.patch new file mode 100644 index 0000000000..1295fbb0bd --- /dev/null +++ b/queue-5.10/cifs-fix-uaf-in-cifs_demultiplex_thread.patch @@ -0,0 +1,249 @@ +From d527f51331cace562393a8038d870b3e9916686f Mon Sep 17 00:00:00 2001 +From: Zhang Xiaoxu +Date: Tue, 19 Sep 2023 13:38:04 -0500 +Subject: cifs: Fix UAF in cifs_demultiplex_thread() + +From: Zhang Xiaoxu + +commit d527f51331cace562393a8038d870b3e9916686f upstream. + +There is a UAF when xfstests on cifs: + + BUG: KASAN: use-after-free in smb2_is_network_name_deleted+0x27/0x160 + Read of size 4 at addr ffff88810103fc08 by task cifsd/923 + + CPU: 1 PID: 923 Comm: cifsd Not tainted 6.1.0-rc4+ #45 + ... + Call Trace: + + dump_stack_lvl+0x34/0x44 + print_report+0x171/0x472 + kasan_report+0xad/0x130 + kasan_check_range+0x145/0x1a0 + smb2_is_network_name_deleted+0x27/0x160 + cifs_demultiplex_thread.cold+0x172/0x5a4 + kthread+0x165/0x1a0 + ret_from_fork+0x1f/0x30 + + + Allocated by task 923: + kasan_save_stack+0x1e/0x40 + kasan_set_track+0x21/0x30 + __kasan_slab_alloc+0x54/0x60 + kmem_cache_alloc+0x147/0x320 + mempool_alloc+0xe1/0x260 + cifs_small_buf_get+0x24/0x60 + allocate_buffers+0xa1/0x1c0 + cifs_demultiplex_thread+0x199/0x10d0 + kthread+0x165/0x1a0 + ret_from_fork+0x1f/0x30 + + Freed by task 921: + kasan_save_stack+0x1e/0x40 + kasan_set_track+0x21/0x30 + kasan_save_free_info+0x2a/0x40 + ____kasan_slab_free+0x143/0x1b0 + kmem_cache_free+0xe3/0x4d0 + cifs_small_buf_release+0x29/0x90 + SMB2_negotiate+0x8b7/0x1c60 + smb2_negotiate+0x51/0x70 + cifs_negotiate_protocol+0xf0/0x160 + cifs_get_smb_ses+0x5fa/0x13c0 + mount_get_conns+0x7a/0x750 + cifs_mount+0x103/0xd00 + cifs_smb3_do_mount+0x1dd/0xcb0 + smb3_get_tree+0x1d5/0x300 + vfs_get_tree+0x41/0xf0 + path_mount+0x9b3/0xdd0 + __x64_sys_mount+0x190/0x1d0 + do_syscall_64+0x35/0x80 + entry_SYSCALL_64_after_hwframe+0x46/0xb0 + +The UAF is because: + + mount(pid: 921) | cifsd(pid: 923) +-------------------------------|------------------------------- + | cifs_demultiplex_thread +SMB2_negotiate | + cifs_send_recv | + compound_send_recv | + smb_send_rqst | + wait_for_response | + wait_event_state [1] | + | standard_receive3 + | cifs_handle_standard + | handle_mid + | mid->resp_buf = buf; [2] + | dequeue_mid [3] + KILL the process [4] | + resp_iov[i].iov_base = buf | + free_rsp_buf [5] | + | is_network_name_deleted [6] + | callback + +1. After send request to server, wait the response until + mid->mid_state != SUBMITTED; +2. Receive response from server, and set it to mid; +3. Set the mid state to RECEIVED; +4. Kill the process, the mid state already RECEIVED, get 0; +5. Handle and release the negotiate response; +6. UAF. + +It can be easily reproduce with add some delay in [3] - [6]. + +Only sync call has the problem since async call's callback is +executed in cifsd process. + +Add an extra state to mark the mid state to READY before wakeup the +waitter, then it can get the resp safely. + +Fixes: ec637e3ffb6b ("[CIFS] Avoid extra large buffer allocation (and memcpy) in cifs_readpages") +Reviewed-by: Paulo Alcantara (SUSE) +Signed-off-by: Zhang Xiaoxu +Signed-off-by: Steve French +[fs/cifs was moved to fs/smb/client since +38c8a9a52082 ("smb: move client and server files to common directory fs/smb"). +We apply the patch to fs/cifs with some minor context changes.] +Signed-off-by: He Zhe +Signed-off-by: Xiangyu Chen +Signed-off-by: Greg Kroah-Hartman +--- + fs/cifs/cifsglob.h | 1 + + fs/cifs/transport.c | 34 +++++++++++++++++++++++----------- + 2 files changed, 24 insertions(+), 11 deletions(-) + +--- a/fs/cifs/cifsglob.h ++++ b/fs/cifs/cifsglob.h +@@ -1768,6 +1768,7 @@ static inline bool is_retryable_error(in + #define MID_RETRY_NEEDED 8 /* session closed while this request out */ + #define MID_RESPONSE_MALFORMED 0x10 + #define MID_SHUTDOWN 0x20 ++#define MID_RESPONSE_READY 0x40 /* ready for other process handle the rsp */ + + /* Flags */ + #define MID_WAIT_CANCELLED 1 /* Cancelled while waiting for response */ +--- a/fs/cifs/transport.c ++++ b/fs/cifs/transport.c +@@ -47,6 +47,8 @@ + void + cifs_wake_up_task(struct mid_q_entry *mid) + { ++ if (mid->mid_state == MID_RESPONSE_RECEIVED) ++ mid->mid_state = MID_RESPONSE_READY; + wake_up_process(mid->callback_data); + } + +@@ -99,7 +101,8 @@ static void _cifs_mid_q_entry_release(st + struct TCP_Server_Info *server = midEntry->server; + + if (midEntry->resp_buf && (midEntry->mid_flags & MID_WAIT_CANCELLED) && +- midEntry->mid_state == MID_RESPONSE_RECEIVED && ++ (midEntry->mid_state == MID_RESPONSE_RECEIVED || ++ midEntry->mid_state == MID_RESPONSE_READY) && + server->ops->handle_cancelled_mid) + server->ops->handle_cancelled_mid(midEntry, server); + +@@ -733,7 +736,8 @@ wait_for_response(struct TCP_Server_Info + int error; + + error = wait_event_freezekillable_unsafe(server->response_q, +- midQ->mid_state != MID_REQUEST_SUBMITTED); ++ midQ->mid_state != MID_REQUEST_SUBMITTED && ++ midQ->mid_state != MID_RESPONSE_RECEIVED); + if (error < 0) + return -ERESTARTSYS; + +@@ -885,7 +889,7 @@ cifs_sync_mid_result(struct mid_q_entry + + spin_lock(&GlobalMid_Lock); + switch (mid->mid_state) { +- case MID_RESPONSE_RECEIVED: ++ case MID_RESPONSE_READY: + spin_unlock(&GlobalMid_Lock); + return rc; + case MID_RETRY_NEEDED: +@@ -984,6 +988,9 @@ cifs_compound_callback(struct mid_q_entr + credits.instance = server->reconnect_instance; + + add_credits(server, &credits, mid->optype); ++ ++ if (mid->mid_state == MID_RESPONSE_RECEIVED) ++ mid->mid_state = MID_RESPONSE_READY; + } + + static void +@@ -1172,7 +1179,8 @@ compound_send_recv(const unsigned int xi + send_cancel(server, &rqst[i], midQ[i]); + spin_lock(&GlobalMid_Lock); + midQ[i]->mid_flags |= MID_WAIT_CANCELLED; +- if (midQ[i]->mid_state == MID_REQUEST_SUBMITTED) { ++ if (midQ[i]->mid_state == MID_REQUEST_SUBMITTED || ++ midQ[i]->mid_state == MID_RESPONSE_RECEIVED) { + midQ[i]->callback = cifs_cancelled_callback; + cancelled_mid[i] = true; + credits[i].value = 0; +@@ -1193,7 +1201,7 @@ compound_send_recv(const unsigned int xi + } + + if (!midQ[i]->resp_buf || +- midQ[i]->mid_state != MID_RESPONSE_RECEIVED) { ++ midQ[i]->mid_state != MID_RESPONSE_READY) { + rc = -EIO; + cifs_dbg(FYI, "Bad MID state?\n"); + goto out; +@@ -1372,7 +1380,8 @@ SendReceive(const unsigned int xid, stru + if (rc != 0) { + send_cancel(server, &rqst, midQ); + spin_lock(&GlobalMid_Lock); +- if (midQ->mid_state == MID_REQUEST_SUBMITTED) { ++ if (midQ->mid_state == MID_REQUEST_SUBMITTED || ++ midQ->mid_state == MID_RESPONSE_RECEIVED) { + /* no longer considered to be "in-flight" */ + midQ->callback = DeleteMidQEntry; + spin_unlock(&GlobalMid_Lock); +@@ -1389,7 +1398,7 @@ SendReceive(const unsigned int xid, stru + } + + if (!midQ->resp_buf || !out_buf || +- midQ->mid_state != MID_RESPONSE_RECEIVED) { ++ midQ->mid_state != MID_RESPONSE_READY) { + rc = -EIO; + cifs_server_dbg(VFS, "Bad MID state?\n"); + goto out; +@@ -1509,13 +1518,15 @@ SendReceiveBlockingLock(const unsigned i + + /* Wait for a reply - allow signals to interrupt. */ + rc = wait_event_interruptible(server->response_q, +- (!(midQ->mid_state == MID_REQUEST_SUBMITTED)) || ++ (!(midQ->mid_state == MID_REQUEST_SUBMITTED || ++ midQ->mid_state == MID_RESPONSE_RECEIVED)) || + ((server->tcpStatus != CifsGood) && + (server->tcpStatus != CifsNew))); + + /* Were we interrupted by a signal ? */ + if ((rc == -ERESTARTSYS) && +- (midQ->mid_state == MID_REQUEST_SUBMITTED) && ++ (midQ->mid_state == MID_REQUEST_SUBMITTED || ++ midQ->mid_state == MID_RESPONSE_RECEIVED) && + ((server->tcpStatus == CifsGood) || + (server->tcpStatus == CifsNew))) { + +@@ -1545,7 +1556,8 @@ SendReceiveBlockingLock(const unsigned i + if (rc) { + send_cancel(server, &rqst, midQ); + spin_lock(&GlobalMid_Lock); +- if (midQ->mid_state == MID_REQUEST_SUBMITTED) { ++ if (midQ->mid_state == MID_REQUEST_SUBMITTED || ++ midQ->mid_state == MID_RESPONSE_RECEIVED) { + /* no longer considered to be "in-flight" */ + midQ->callback = DeleteMidQEntry; + spin_unlock(&GlobalMid_Lock); +@@ -1563,7 +1575,7 @@ SendReceiveBlockingLock(const unsigned i + return rc; + + /* rcvd frame is ok */ +- if (out_buf == NULL || midQ->mid_state != MID_RESPONSE_RECEIVED) { ++ if (out_buf == NULL || midQ->mid_state != MID_RESPONSE_READY) { + rc = -EIO; + cifs_tcon_dbg(VFS, "Bad MID state?\n"); + goto out; diff --git a/queue-5.10/series b/queue-5.10/series index 8c0cd3a011..32fd358329 100644 --- a/queue-5.10/series +++ b/queue-5.10/series @@ -157,3 +157,6 @@ drm-amd-display-stop-amdgpu_dm-initialize-when-link-nums-greater-than-max_links. drm-amd-display-fix-out-of-bounds-access-in-dcn21_link_encoder_create.patch nvmet-fc-remove-unused-functions.patch smb-client-fix-potential-uaf-in-cifs_debug_files_proc_show.patch +smb-client-fix-use-after-free-bug-in-cifs_debug_data_proc_show.patch +cifs-fix-uaf-in-cifs_demultiplex_thread.patch +smb-client-fix-potential-deadlock-when-releasing-mids.patch diff --git a/queue-5.10/smb-client-fix-potential-deadlock-when-releasing-mids.patch b/queue-5.10/smb-client-fix-potential-deadlock-when-releasing-mids.patch new file mode 100644 index 0000000000..8e05f5ad76 --- /dev/null +++ b/queue-5.10/smb-client-fix-potential-deadlock-when-releasing-mids.patch @@ -0,0 +1,101 @@ +From e6322fd177c6885a21dd4609dc5e5c973d1a2eb7 Mon Sep 17 00:00:00 2001 +From: Paulo Alcantara +Date: Wed, 25 Oct 2023 14:58:35 -0300 +Subject: smb: client: fix potential deadlock when releasing mids + +From: Paulo Alcantara + +commit e6322fd177c6885a21dd4609dc5e5c973d1a2eb7 upstream. + +All release_mid() callers seem to hold a reference of @mid so there is +no need to call kref_put(&mid->refcount, __release_mid) under +@server->mid_lock spinlock. If they don't, then an use-after-free bug +would have occurred anyways. + +By getting rid of such spinlock also fixes a potential deadlock as +shown below + +CPU 0 CPU 1 +------------------------------------------------------------------ +cifs_demultiplex_thread() cifs_debug_data_proc_show() + release_mid() + spin_lock(&server->mid_lock); + spin_lock(&cifs_tcp_ses_lock) + spin_lock(&server->mid_lock) + __release_mid() + smb2_find_smb_tcon() + spin_lock(&cifs_tcp_ses_lock) *deadlock* + +Cc: stable@vger.kernel.org +Signed-off-by: Paulo Alcantara (SUSE) +Signed-off-by: Steve French +[cifs_mid_q_entry_release() is renamed to release_mid() and + _cifs_mid_q_entry_release() is renamed to __release_mid() by + commit 70f08f914a37 ("cifs: remove useless DeleteMidQEntry()") + which is integrated into v6.0, so preserve old names in v5.10.] +Signed-off-by: Cliff Liu +Signed-off-by: He Zhe +Signed-off-by: Greg Kroah-Hartman +--- + fs/cifs/cifsproto.h | 7 ++++++- + fs/cifs/smb2misc.c | 2 +- + fs/cifs/transport.c | 9 +-------- + 3 files changed, 8 insertions(+), 10 deletions(-) + +--- a/fs/cifs/cifsproto.h ++++ b/fs/cifs/cifsproto.h +@@ -85,7 +85,7 @@ extern struct mid_q_entry *AllocMidQEntr + struct TCP_Server_Info *server); + extern void DeleteMidQEntry(struct mid_q_entry *midEntry); + extern void cifs_delete_mid(struct mid_q_entry *mid); +-extern void cifs_mid_q_entry_release(struct mid_q_entry *midEntry); ++void _cifs_mid_q_entry_release(struct kref *refcount); + extern void cifs_wake_up_task(struct mid_q_entry *mid); + extern int cifs_handle_standard(struct TCP_Server_Info *server, + struct mid_q_entry *mid); +@@ -646,4 +646,9 @@ static inline int cifs_create_options(st + return options; + } + ++static inline void cifs_mid_q_entry_release(struct mid_q_entry *midEntry) ++{ ++ kref_put(&midEntry->refcount, _cifs_mid_q_entry_release); ++} ++ + #endif /* _CIFSPROTO_H */ +--- a/fs/cifs/smb2misc.c ++++ b/fs/cifs/smb2misc.c +@@ -780,7 +780,7 @@ __smb2_handle_cancelled_cmd(struct cifs_ + { + struct close_cancelled_open *cancelled; + +- cancelled = kzalloc(sizeof(*cancelled), GFP_ATOMIC); ++ cancelled = kzalloc(sizeof(*cancelled), GFP_KERNEL); + if (!cancelled) + return -ENOMEM; + +--- a/fs/cifs/transport.c ++++ b/fs/cifs/transport.c +@@ -88,7 +88,7 @@ AllocMidQEntry(const struct smb_hdr *smb + return temp; + } + +-static void _cifs_mid_q_entry_release(struct kref *refcount) ++void _cifs_mid_q_entry_release(struct kref *refcount) + { + struct mid_q_entry *midEntry = + container_of(refcount, struct mid_q_entry, refcount); +@@ -168,13 +168,6 @@ static void _cifs_mid_q_entry_release(st + mempool_free(midEntry, cifs_mid_poolp); + } + +-void cifs_mid_q_entry_release(struct mid_q_entry *midEntry) +-{ +- spin_lock(&GlobalMid_Lock); +- kref_put(&midEntry->refcount, _cifs_mid_q_entry_release); +- spin_unlock(&GlobalMid_Lock); +-} +- + void DeleteMidQEntry(struct mid_q_entry *midEntry) + { + cifs_mid_q_entry_release(midEntry); diff --git a/queue-5.10/smb-client-fix-use-after-free-bug-in-cifs_debug_data_proc_show.patch b/queue-5.10/smb-client-fix-use-after-free-bug-in-cifs_debug_data_proc_show.patch new file mode 100644 index 0000000000..8e9bffe147 --- /dev/null +++ b/queue-5.10/smb-client-fix-use-after-free-bug-in-cifs_debug_data_proc_show.patch @@ -0,0 +1,61 @@ +From d328c09ee9f15ee5a26431f5aad7c9239fa85e62 Mon Sep 17 00:00:00 2001 +From: Paulo Alcantara +Date: Tue, 24 Oct 2023 13:49:15 -0300 +Subject: smb: client: fix use-after-free bug in cifs_debug_data_proc_show() + +From: Paulo Alcantara + +commit d328c09ee9f15ee5a26431f5aad7c9239fa85e62 upstream. + +Skip SMB sessions that are being teared down +(e.g. @ses->ses_status == SES_EXITING) in cifs_debug_data_proc_show() +to avoid use-after-free in @ses. + +This fixes the following GPF when reading from /proc/fs/cifs/DebugData +while mounting and umounting + + [ 816.251274] general protection fault, probably for non-canonical + address 0x6b6b6b6b6b6b6d81: 0000 [#1] PREEMPT SMP NOPTI + ... + [ 816.260138] Call Trace: + [ 816.260329] + [ 816.260499] ? die_addr+0x36/0x90 + [ 816.260762] ? exc_general_protection+0x1b3/0x410 + [ 816.261126] ? asm_exc_general_protection+0x26/0x30 + [ 816.261502] ? cifs_debug_tcon+0xbd/0x240 [cifs] + [ 816.261878] ? cifs_debug_tcon+0xab/0x240 [cifs] + [ 816.262249] cifs_debug_data_proc_show+0x516/0xdb0 [cifs] + [ 816.262689] ? seq_read_iter+0x379/0x470 + [ 816.262995] seq_read_iter+0x118/0x470 + [ 816.263291] proc_reg_read_iter+0x53/0x90 + [ 816.263596] ? srso_alias_return_thunk+0x5/0x7f + [ 816.263945] vfs_read+0x201/0x350 + [ 816.264211] ksys_read+0x75/0x100 + [ 816.264472] do_syscall_64+0x3f/0x90 + [ 816.264750] entry_SYSCALL_64_after_hwframe+0x6e/0xd8 + [ 816.265135] RIP: 0033:0x7fd5e669d381 + +Cc: stable@vger.kernel.org +Signed-off-by: Paulo Alcantara (SUSE) +Signed-off-by: Steve French +[ This patch removed lock/unlock operation due to ses_lock is +not present in v5.10 and not ported yet. ses->status is protected +by a global lock, cifs_tcp_ses_lock, in v5.10. ] +Signed-off-by: Xiangyu Chen +Signed-off-by: He Zhe +Signed-off-by: Greg Kroah-Hartman +--- + fs/cifs/cifs_debug.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/fs/cifs/cifs_debug.c ++++ b/fs/cifs/cifs_debug.c +@@ -358,6 +358,8 @@ skip_rdma: + list_for_each(tmp2, &server->smb_ses_list) { + ses = list_entry(tmp2, struct cifs_ses, + smb_ses_list); ++ if (ses->status == CifsExiting) ++ continue; + if ((ses->serverDomain == NULL) || + (ses->serverOS == NULL) || + (ses->serverNOS == NULL)) {