]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
6.1-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 8 Apr 2024 10:34:50 +0000 (12:34 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 8 Apr 2024 10:34:50 +0000 (12:34 +0200)
added patches:
riscv-fix-spurious-errors-from-__get-put_kernel_nofault.patch
riscv-process-fix-kernel-gp-leakage.patch
s390-entry-align-system-call-table-on-8-bytes.patch
smb-client-fix-potential-uaf-in-cifs_debug_files_proc_show.patch
smb-client-fix-potential-uaf-in-cifs_signal_cifsd_for_reconnect.patch
smb-client-fix-potential-uaf-in-cifs_stats_proc_show.patch
smb-client-fix-potential-uaf-in-cifs_stats_proc_write.patch
smb-client-fix-potential-uaf-in-is_valid_oplock_break.patch
smb-client-fix-potential-uaf-in-smb2_is_network_name_deleted.patch
smb-client-fix-potential-uaf-in-smb2_is_valid_lease_break.patch
smb-client-fix-potential-uaf-in-smb2_is_valid_oplock_break.patch
smb3-retrying-on-failed-server-close.patch

13 files changed:
queue-6.1/riscv-fix-spurious-errors-from-__get-put_kernel_nofault.patch [new file with mode: 0644]
queue-6.1/riscv-process-fix-kernel-gp-leakage.patch [new file with mode: 0644]
queue-6.1/s390-entry-align-system-call-table-on-8-bytes.patch [new file with mode: 0644]
queue-6.1/series
queue-6.1/smb-client-fix-potential-uaf-in-cifs_debug_files_proc_show.patch [new file with mode: 0644]
queue-6.1/smb-client-fix-potential-uaf-in-cifs_signal_cifsd_for_reconnect.patch [new file with mode: 0644]
queue-6.1/smb-client-fix-potential-uaf-in-cifs_stats_proc_show.patch [new file with mode: 0644]
queue-6.1/smb-client-fix-potential-uaf-in-cifs_stats_proc_write.patch [new file with mode: 0644]
queue-6.1/smb-client-fix-potential-uaf-in-is_valid_oplock_break.patch [new file with mode: 0644]
queue-6.1/smb-client-fix-potential-uaf-in-smb2_is_network_name_deleted.patch [new file with mode: 0644]
queue-6.1/smb-client-fix-potential-uaf-in-smb2_is_valid_lease_break.patch [new file with mode: 0644]
queue-6.1/smb-client-fix-potential-uaf-in-smb2_is_valid_oplock_break.patch [new file with mode: 0644]
queue-6.1/smb3-retrying-on-failed-server-close.patch [new file with mode: 0644]

diff --git a/queue-6.1/riscv-fix-spurious-errors-from-__get-put_kernel_nofault.patch b/queue-6.1/riscv-fix-spurious-errors-from-__get-put_kernel_nofault.patch
new file mode 100644 (file)
index 0000000..40f4121
--- /dev/null
@@ -0,0 +1,44 @@
+From d080a08b06b6266cc3e0e86c5acfd80db937cb6b Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel.holland@sifive.com>
+Date: Mon, 11 Mar 2024 19:19:13 -0700
+Subject: riscv: Fix spurious errors from __get/put_kernel_nofault
+
+From: Samuel Holland <samuel.holland@sifive.com>
+
+commit d080a08b06b6266cc3e0e86c5acfd80db937cb6b upstream.
+
+These macros did not initialize __kr_err, so they could fail even if
+the access did not fault.
+
+Cc: stable@vger.kernel.org
+Fixes: d464118cdc41 ("riscv: implement __get_kernel_nofault and __put_user_nofault")
+Signed-off-by: Samuel Holland <samuel.holland@sifive.com>
+Reviewed-by: Alexandre Ghiti <alexghiti@rivosinc.com>
+Reviewed-by: Charlie Jenkins <charlie@rivosinc.com>
+Link: https://lore.kernel.org/r/20240312022030.320789-1-samuel.holland@sifive.com
+Signed-off-by: Palmer Dabbelt <palmer@rivosinc.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/riscv/include/asm/uaccess.h |    4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/arch/riscv/include/asm/uaccess.h
++++ b/arch/riscv/include/asm/uaccess.h
+@@ -319,7 +319,7 @@ unsigned long __must_check clear_user(vo
+ #define __get_kernel_nofault(dst, src, type, err_label)                       \
+ do {                                                                  \
+-      long __kr_err;                                                  \
++      long __kr_err = 0;                                              \
+                                                                       \
+       __get_user_nocheck(*((type *)(dst)), (type *)(src), __kr_err);  \
+       if (unlikely(__kr_err))                                         \
+@@ -328,7 +328,7 @@ do {                                                                       \
+ #define __put_kernel_nofault(dst, src, type, err_label)                       \
+ do {                                                                  \
+-      long __kr_err;                                                  \
++      long __kr_err = 0;                                              \
+                                                                       \
+       __put_user_nocheck(*((type *)(src)), (type *)(dst), __kr_err);  \
+       if (unlikely(__kr_err))                                         \
diff --git a/queue-6.1/riscv-process-fix-kernel-gp-leakage.patch b/queue-6.1/riscv-process-fix-kernel-gp-leakage.patch
new file mode 100644 (file)
index 0000000..29b6b02
--- /dev/null
@@ -0,0 +1,80 @@
+From d14fa1fcf69db9d070e75f1c4425211fa619dfc8 Mon Sep 17 00:00:00 2001
+From: Stefan O'Rear <sorear@fastmail.com>
+Date: Wed, 27 Mar 2024 02:12:58 -0400
+Subject: riscv: process: Fix kernel gp leakage
+
+From: Stefan O'Rear <sorear@fastmail.com>
+
+commit d14fa1fcf69db9d070e75f1c4425211fa619dfc8 upstream.
+
+childregs represents the registers which are active for the new thread
+in user context. For a kernel thread, childregs->gp is never used since
+the kernel gp is not touched by switch_to. For a user mode helper, the
+gp value can be observed in user space after execve or possibly by other
+means.
+
+[From the email thread]
+
+The /* Kernel thread */ comment is somewhat inaccurate in that it is also used
+for user_mode_helper threads, which exec a user process, e.g. /sbin/init or
+when /proc/sys/kernel/core_pattern is a pipe. Such threads do not have
+PF_KTHREAD set and are valid targets for ptrace etc. even before they exec.
+
+childregs is the *user* context during syscall execution and it is observable
+from userspace in at least five ways:
+
+1. kernel_execve does not currently clear integer registers, so the starting
+   register state for PID 1 and other user processes started by the kernel has
+   sp = user stack, gp = kernel __global_pointer$, all other integer registers
+   zeroed by the memset in the patch comment.
+
+   This is a bug in its own right, but I'm unwilling to bet that it is the only
+   way to exploit the issue addressed by this patch.
+
+2. ptrace(PTRACE_GETREGSET): you can PTRACE_ATTACH to a user_mode_helper thread
+   before it execs, but ptrace requires SIGSTOP to be delivered which can only
+   happen at user/kernel boundaries.
+
+3. /proc/*/task/*/syscall: this is perfectly happy to read pt_regs for
+   user_mode_helpers before the exec completes, but gp is not one of the
+   registers it returns.
+
+4. PERF_SAMPLE_REGS_USER: LOCKDOWN_PERF normally prevents access to kernel
+   addresses via PERF_SAMPLE_REGS_INTR, but due to this bug kernel addresses
+   are also exposed via PERF_SAMPLE_REGS_USER which is permitted under
+   LOCKDOWN_PERF. I have not attempted to write exploit code.
+
+5. Much of the tracing infrastructure allows access to user registers. I have
+   not attempted to determine which forms of tracing allow access to user
+   registers without already allowing access to kernel registers.
+
+Fixes: 7db91e57a0ac ("RISC-V: Task implementation")
+Cc: stable@vger.kernel.org
+Signed-off-by: Stefan O'Rear <sorear@fastmail.com>
+Reviewed-by: Alexandre Ghiti <alexghiti@rivosinc.com>
+Link: https://lore.kernel.org/r/20240327061258.2370291-1-sorear@fastmail.com
+Signed-off-by: Palmer Dabbelt <palmer@rivosinc.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/riscv/kernel/process.c |    3 ---
+ 1 file changed, 3 deletions(-)
+
+--- a/arch/riscv/kernel/process.c
++++ b/arch/riscv/kernel/process.c
+@@ -25,8 +25,6 @@
+ #include <asm/thread_info.h>
+ #include <asm/cpuidle.h>
+-register unsigned long gp_in_global __asm__("gp");
+-
+ #if defined(CONFIG_STACKPROTECTOR) && !defined(CONFIG_STACKPROTECTOR_PER_TASK)
+ #include <linux/stackprotector.h>
+ unsigned long __stack_chk_guard __read_mostly;
+@@ -170,7 +168,6 @@ int copy_thread(struct task_struct *p, c
+       if (unlikely(args->fn)) {
+               /* Kernel thread */
+               memset(childregs, 0, sizeof(struct pt_regs));
+-              childregs->gp = gp_in_global;
+               /* Supervisor/Machine, irqs on: */
+               childregs->status = SR_PP | SR_PIE;
diff --git a/queue-6.1/s390-entry-align-system-call-table-on-8-bytes.patch b/queue-6.1/s390-entry-align-system-call-table-on-8-bytes.patch
new file mode 100644 (file)
index 0000000..eea6524
--- /dev/null
@@ -0,0 +1,33 @@
+From 378ca2d2ad410a1cd5690d06b46c5e2297f4c8c0 Mon Sep 17 00:00:00 2001
+From: Sumanth Korikkar <sumanthk@linux.ibm.com>
+Date: Tue, 26 Mar 2024 18:12:13 +0100
+Subject: s390/entry: align system call table on 8 bytes
+
+From: Sumanth Korikkar <sumanthk@linux.ibm.com>
+
+commit 378ca2d2ad410a1cd5690d06b46c5e2297f4c8c0 upstream.
+
+Align system call table on 8 bytes. With sys_call_table entry size
+of 8 bytes that eliminates the possibility of a system call pointer
+crossing cache line boundary.
+
+Cc: stable@kernel.org
+Suggested-by: Ulrich Weigand <ulrich.weigand@de.ibm.com>
+Reviewed-by: Alexander Gordeev <agordeev@linux.ibm.com>
+Signed-off-by: Sumanth Korikkar <sumanthk@linux.ibm.com>
+Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/s390/kernel/entry.S |    1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/arch/s390/kernel/entry.S
++++ b/arch/s390/kernel/entry.S
+@@ -699,6 +699,7 @@ ENDPROC(stack_overflow)
+ .Lthis_cpu:   .short  0
+ .Lstosm_tmp:  .byte   0
+       .section .rodata, "a"
++      .balign 8
+ #define SYSCALL(esame,emu)    .quad __s390x_ ## esame
+       .globl  sys_call_table
+ sys_call_table:
index 44ed3af14600cdf15c333ba0c868623d39d60acf..c1d1532b3c798200d4114d79eab49b852ab2c441 100644 (file)
@@ -119,3 +119,15 @@ of-dynamic-synchronize-of_changeset_destroy-with-the-devlink-removals.patch
 x86-mm-pat-fix-vm_pat-handling-in-cow-mappings.patch
 x86-mce-make-sure-to-grab-mce_sysfs_mutex-in-set_bank.patch
 x86-coco-require-seeding-rng-with-rdrand-on-coco-systems.patch
+s390-entry-align-system-call-table-on-8-bytes.patch
+riscv-fix-spurious-errors-from-__get-put_kernel_nofault.patch
+riscv-process-fix-kernel-gp-leakage.patch
+smb3-retrying-on-failed-server-close.patch
+smb-client-fix-potential-uaf-in-cifs_debug_files_proc_show.patch
+smb-client-fix-potential-uaf-in-cifs_stats_proc_write.patch
+smb-client-fix-potential-uaf-in-cifs_stats_proc_show.patch
+smb-client-fix-potential-uaf-in-smb2_is_valid_oplock_break.patch
+smb-client-fix-potential-uaf-in-smb2_is_valid_lease_break.patch
+smb-client-fix-potential-uaf-in-is_valid_oplock_break.patch
+smb-client-fix-potential-uaf-in-smb2_is_network_name_deleted.patch
+smb-client-fix-potential-uaf-in-cifs_signal_cifsd_for_reconnect.patch
diff --git a/queue-6.1/smb-client-fix-potential-uaf-in-cifs_debug_files_proc_show.patch b/queue-6.1/smb-client-fix-potential-uaf-in-cifs_debug_files_proc_show.patch
new file mode 100644 (file)
index 0000000..9352f96
--- /dev/null
@@ -0,0 +1,49 @@
+From ca545b7f0823f19db0f1148d59bc5e1a56634502 Mon Sep 17 00:00:00 2001
+From: Paulo Alcantara <pc@manguebit.com>
+Date: Tue, 2 Apr 2024 16:33:53 -0300
+Subject: smb: client: fix potential UAF in cifs_debug_files_proc_show()
+
+From: Paulo Alcantara <pc@manguebit.com>
+
+commit ca545b7f0823f19db0f1148d59bc5e1a56634502 upstream.
+
+Skip sessions that are being teared down (status == SES_EXITING) to
+avoid UAF.
+
+Cc: stable@vger.kernel.org
+Signed-off-by: Paulo Alcantara (Red Hat) <pc@manguebit.com>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/smb/client/cifs_debug.c |    2 ++
+ fs/smb/client/cifsglob.h   |   10 ++++++++++
+ 2 files changed, 12 insertions(+)
+
+--- a/fs/smb/client/cifs_debug.c
++++ b/fs/smb/client/cifs_debug.c
+@@ -186,6 +186,8 @@ static int cifs_debug_files_proc_show(st
+       spin_lock(&cifs_tcp_ses_lock);
+       list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) {
+               list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
++                      if (cifs_ses_exiting(ses))
++                              continue;
+                       list_for_each_entry(tcon, &ses->tcon_list, tcon_list) {
+                               spin_lock(&tcon->open_file_lock);
+                               list_for_each_entry(cfile, &tcon->openFileList, tlist) {
+--- a/fs/smb/client/cifsglob.h
++++ b/fs/smb/client/cifsglob.h
+@@ -2178,4 +2178,14 @@ static inline struct scatterlist *cifs_s
+       return sg;
+ }
++static inline bool cifs_ses_exiting(struct cifs_ses *ses)
++{
++      bool ret;
++
++      spin_lock(&ses->ses_lock);
++      ret = ses->ses_status == SES_EXITING;
++      spin_unlock(&ses->ses_lock);
++      return ret;
++}
++
+ #endif        /* _CIFS_GLOB_H */
diff --git a/queue-6.1/smb-client-fix-potential-uaf-in-cifs_signal_cifsd_for_reconnect.patch b/queue-6.1/smb-client-fix-potential-uaf-in-cifs_signal_cifsd_for_reconnect.patch
new file mode 100644 (file)
index 0000000..d01b0f8
--- /dev/null
@@ -0,0 +1,31 @@
+From e0e50401cc3921c9eaf1b0e667db174519ea939f Mon Sep 17 00:00:00 2001
+From: Paulo Alcantara <pc@manguebit.com>
+Date: Tue, 2 Apr 2024 16:34:04 -0300
+Subject: smb: client: fix potential UAF in cifs_signal_cifsd_for_reconnect()
+
+From: Paulo Alcantara <pc@manguebit.com>
+
+commit e0e50401cc3921c9eaf1b0e667db174519ea939f upstream.
+
+Skip sessions that are being teared down (status == SES_EXITING) to
+avoid UAF.
+
+Cc: stable@vger.kernel.org
+Signed-off-by: Paulo Alcantara (Red Hat) <pc@manguebit.com>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/smb/client/connect.c |    2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/fs/smb/client/connect.c
++++ b/fs/smb/client/connect.c
+@@ -216,6 +216,8 @@ cifs_signal_cifsd_for_reconnect(struct T
+       spin_lock(&cifs_tcp_ses_lock);
+       list_for_each_entry(ses, &pserver->smb_ses_list, smb_ses_list) {
++              if (cifs_ses_exiting(ses))
++                      continue;
+               spin_lock(&ses->chan_lock);
+               for (i = 0; i < ses->chan_count; i++) {
+                       spin_lock(&ses->chans[i].server->srv_lock);
diff --git a/queue-6.1/smb-client-fix-potential-uaf-in-cifs_stats_proc_show.patch b/queue-6.1/smb-client-fix-potential-uaf-in-cifs_stats_proc_show.patch
new file mode 100644 (file)
index 0000000..e8adbf9
--- /dev/null
@@ -0,0 +1,31 @@
+From 0865ffefea197b437ba78b5dd8d8e256253efd65 Mon Sep 17 00:00:00 2001
+From: Paulo Alcantara <pc@manguebit.com>
+Date: Tue, 2 Apr 2024 16:33:56 -0300
+Subject: smb: client: fix potential UAF in cifs_stats_proc_show()
+
+From: Paulo Alcantara <pc@manguebit.com>
+
+commit 0865ffefea197b437ba78b5dd8d8e256253efd65 upstream.
+
+Skip sessions that are being teared down (status == SES_EXITING) to
+avoid UAF.
+
+Cc: stable@vger.kernel.org
+Signed-off-by: Paulo Alcantara (Red Hat) <pc@manguebit.com>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/smb/client/cifs_debug.c |    2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/fs/smb/client/cifs_debug.c
++++ b/fs/smb/client/cifs_debug.c
+@@ -648,6 +648,8 @@ static int cifs_stats_proc_show(struct s
+                       }
+ #endif /* STATS2 */
+               list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
++                      if (cifs_ses_exiting(ses))
++                              continue;
+                       list_for_each_entry(tcon, &ses->tcon_list, tcon_list) {
+                               i++;
+                               seq_printf(m, "\n%d) %s", i, tcon->tree_name);
diff --git a/queue-6.1/smb-client-fix-potential-uaf-in-cifs_stats_proc_write.patch b/queue-6.1/smb-client-fix-potential-uaf-in-cifs_stats_proc_write.patch
new file mode 100644 (file)
index 0000000..7abf664
--- /dev/null
@@ -0,0 +1,31 @@
+From d3da25c5ac84430f89875ca7485a3828150a7e0a Mon Sep 17 00:00:00 2001
+From: Paulo Alcantara <pc@manguebit.com>
+Date: Tue, 2 Apr 2024 16:33:55 -0300
+Subject: smb: client: fix potential UAF in cifs_stats_proc_write()
+
+From: Paulo Alcantara <pc@manguebit.com>
+
+commit d3da25c5ac84430f89875ca7485a3828150a7e0a upstream.
+
+Skip sessions that are being teared down (status == SES_EXITING) to
+avoid UAF.
+
+Cc: stable@vger.kernel.org
+Signed-off-by: Paulo Alcantara (Red Hat) <pc@manguebit.com>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/smb/client/cifs_debug.c |    2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/fs/smb/client/cifs_debug.c
++++ b/fs/smb/client/cifs_debug.c
+@@ -568,6 +568,8 @@ static ssize_t cifs_stats_proc_write(str
+                       }
+ #endif /* CONFIG_CIFS_STATS2 */
+                       list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
++                              if (cifs_ses_exiting(ses))
++                                      continue;
+                               list_for_each_entry(tcon, &ses->tcon_list, tcon_list) {
+                                       atomic_set(&tcon->num_smbs_sent, 0);
+                                       spin_lock(&tcon->stat_lock);
diff --git a/queue-6.1/smb-client-fix-potential-uaf-in-is_valid_oplock_break.patch b/queue-6.1/smb-client-fix-potential-uaf-in-is_valid_oplock_break.patch
new file mode 100644 (file)
index 0000000..c9d3906
--- /dev/null
@@ -0,0 +1,31 @@
+From 69ccf040acddf33a3a85ec0f6b45ef84b0f7ec29 Mon Sep 17 00:00:00 2001
+From: Paulo Alcantara <pc@manguebit.com>
+Date: Tue, 2 Apr 2024 16:34:00 -0300
+Subject: smb: client: fix potential UAF in is_valid_oplock_break()
+
+From: Paulo Alcantara <pc@manguebit.com>
+
+commit 69ccf040acddf33a3a85ec0f6b45ef84b0f7ec29 upstream.
+
+Skip sessions that are being teared down (status == SES_EXITING) to
+avoid UAF.
+
+Cc: stable@vger.kernel.org
+Signed-off-by: Paulo Alcantara (Red Hat) <pc@manguebit.com>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/smb/client/misc.c |    2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/fs/smb/client/misc.c
++++ b/fs/smb/client/misc.c
+@@ -476,6 +476,8 @@ is_valid_oplock_break(char *buffer, stru
+       /* look up tcon based on tid & uid */
+       spin_lock(&cifs_tcp_ses_lock);
+       list_for_each_entry(ses, &pserver->smb_ses_list, smb_ses_list) {
++              if (cifs_ses_exiting(ses))
++                      continue;
+               list_for_each_entry(tcon, &ses->tcon_list, tcon_list) {
+                       if (tcon->tid != buf->Tid)
+                               continue;
diff --git a/queue-6.1/smb-client-fix-potential-uaf-in-smb2_is_network_name_deleted.patch b/queue-6.1/smb-client-fix-potential-uaf-in-smb2_is_network_name_deleted.patch
new file mode 100644 (file)
index 0000000..9566231
--- /dev/null
@@ -0,0 +1,31 @@
+From 63981561ffd2d4987807df4126f96a11e18b0c1d Mon Sep 17 00:00:00 2001
+From: Paulo Alcantara <pc@manguebit.com>
+Date: Tue, 2 Apr 2024 16:34:02 -0300
+Subject: smb: client: fix potential UAF in smb2_is_network_name_deleted()
+
+From: Paulo Alcantara <pc@manguebit.com>
+
+commit 63981561ffd2d4987807df4126f96a11e18b0c1d upstream.
+
+Skip sessions that are being teared down (status == SES_EXITING) to
+avoid UAF.
+
+Cc: stable@vger.kernel.org
+Signed-off-by: Paulo Alcantara (Red Hat) <pc@manguebit.com>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/smb/client/smb2ops.c |    2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/fs/smb/client/smb2ops.c
++++ b/fs/smb/client/smb2ops.c
+@@ -2437,6 +2437,8 @@ smb2_is_network_name_deleted(char *buf,
+       spin_lock(&cifs_tcp_ses_lock);
+       list_for_each_entry(ses, &pserver->smb_ses_list, smb_ses_list) {
++              if (cifs_ses_exiting(ses))
++                      continue;
+               list_for_each_entry(tcon, &ses->tcon_list, tcon_list) {
+                       if (tcon->tid == le32_to_cpu(shdr->Id.SyncId.TreeId)) {
+                               spin_lock(&tcon->tc_lock);
diff --git a/queue-6.1/smb-client-fix-potential-uaf-in-smb2_is_valid_lease_break.patch b/queue-6.1/smb-client-fix-potential-uaf-in-smb2_is_valid_lease_break.patch
new file mode 100644 (file)
index 0000000..83914a6
--- /dev/null
@@ -0,0 +1,31 @@
+From 705c76fbf726c7a2f6ff9143d4013b18daaaebf1 Mon Sep 17 00:00:00 2001
+From: Paulo Alcantara <pc@manguebit.com>
+Date: Tue, 2 Apr 2024 16:33:58 -0300
+Subject: smb: client: fix potential UAF in smb2_is_valid_lease_break()
+
+From: Paulo Alcantara <pc@manguebit.com>
+
+commit 705c76fbf726c7a2f6ff9143d4013b18daaaebf1 upstream.
+
+Skip sessions that are being teared down (status == SES_EXITING) to
+avoid UAF.
+
+Cc: stable@vger.kernel.org
+Signed-off-by: Paulo Alcantara (Red Hat) <pc@manguebit.com>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/smb/client/smb2misc.c |    2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/fs/smb/client/smb2misc.c
++++ b/fs/smb/client/smb2misc.c
+@@ -622,6 +622,8 @@ smb2_is_valid_lease_break(char *buffer,
+       /* look up tcon based on tid & uid */
+       spin_lock(&cifs_tcp_ses_lock);
+       list_for_each_entry(ses, &pserver->smb_ses_list, smb_ses_list) {
++              if (cifs_ses_exiting(ses))
++                      continue;
+               list_for_each_entry(tcon, &ses->tcon_list, tcon_list) {
+                       spin_lock(&tcon->open_file_lock);
+                       cifs_stats_inc(
diff --git a/queue-6.1/smb-client-fix-potential-uaf-in-smb2_is_valid_oplock_break.patch b/queue-6.1/smb-client-fix-potential-uaf-in-smb2_is_valid_oplock_break.patch
new file mode 100644 (file)
index 0000000..d2939b3
--- /dev/null
@@ -0,0 +1,31 @@
+From 22863485a4626ec6ecf297f4cc0aef709bc862e4 Mon Sep 17 00:00:00 2001
+From: Paulo Alcantara <pc@manguebit.com>
+Date: Tue, 2 Apr 2024 16:33:59 -0300
+Subject: smb: client: fix potential UAF in smb2_is_valid_oplock_break()
+
+From: Paulo Alcantara <pc@manguebit.com>
+
+commit 22863485a4626ec6ecf297f4cc0aef709bc862e4 upstream.
+
+Skip sessions that are being teared down (status == SES_EXITING) to
+avoid UAF.
+
+Cc: stable@vger.kernel.org
+Signed-off-by: Paulo Alcantara (Red Hat) <pc@manguebit.com>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/smb/client/smb2misc.c |    2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/fs/smb/client/smb2misc.c
++++ b/fs/smb/client/smb2misc.c
+@@ -697,6 +697,8 @@ smb2_is_valid_oplock_break(char *buffer,
+       /* look up tcon based on tid & uid */
+       spin_lock(&cifs_tcp_ses_lock);
+       list_for_each_entry(ses, &pserver->smb_ses_list, smb_ses_list) {
++              if (cifs_ses_exiting(ses))
++                      continue;
+               list_for_each_entry(tcon, &ses->tcon_list, tcon_list) {
+                       spin_lock(&tcon->open_file_lock);
diff --git a/queue-6.1/smb3-retrying-on-failed-server-close.patch b/queue-6.1/smb3-retrying-on-failed-server-close.patch
new file mode 100644 (file)
index 0000000..bba212a
--- /dev/null
@@ -0,0 +1,315 @@
+From 173217bd73365867378b5e75a86f0049e1069ee8 Mon Sep 17 00:00:00 2001
+From: Ritvik Budhiraja <rbudhiraja@microsoft.com>
+Date: Tue, 2 Apr 2024 14:01:28 -0500
+Subject: smb3: retrying on failed server close
+
+From: Ritvik Budhiraja <rbudhiraja@microsoft.com>
+
+commit 173217bd73365867378b5e75a86f0049e1069ee8 upstream.
+
+In the current implementation, CIFS close sends a close to the
+server and does not check for the success of the server close.
+This patch adds functionality to check for server close return
+status and retries in case of an EBUSY or EAGAIN error.
+
+This can help avoid handle leaks
+
+Cc: stable@vger.kernel.org
+Signed-off-by: Ritvik Budhiraja <rbudhiraja@microsoft.com>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/smb/client/cached_dir.c |    6 ++--
+ fs/smb/client/cifsfs.c     |   11 +++++++
+ fs/smb/client/cifsglob.h   |    7 +++--
+ fs/smb/client/file.c       |   63 ++++++++++++++++++++++++++++++++++++++++-----
+ fs/smb/client/smb1ops.c    |    4 +-
+ fs/smb/client/smb2ops.c    |    9 +++---
+ fs/smb/client/smb2pdu.c    |    2 -
+ 7 files changed, 85 insertions(+), 17 deletions(-)
+
+--- a/fs/smb/client/cached_dir.c
++++ b/fs/smb/client/cached_dir.c
+@@ -370,6 +370,7 @@ smb2_close_cached_fid(struct kref *ref)
+ {
+       struct cached_fid *cfid = container_of(ref, struct cached_fid,
+                                              refcount);
++      int rc;
+       spin_lock(&cfid->cfids->cfid_list_lock);
+       if (cfid->on_list) {
+@@ -383,9 +384,10 @@ smb2_close_cached_fid(struct kref *ref)
+       cfid->dentry = NULL;
+       if (cfid->is_open) {
+-              SMB2_close(0, cfid->tcon, cfid->fid.persistent_fid,
++              rc = SMB2_close(0, cfid->tcon, cfid->fid.persistent_fid,
+                          cfid->fid.volatile_fid);
+-              atomic_dec(&cfid->tcon->num_remote_opens);
++              if (rc != -EBUSY && rc != -EAGAIN)
++                      atomic_dec(&cfid->tcon->num_remote_opens);
+       }
+       free_cached_dir(cfid);
+--- a/fs/smb/client/cifsfs.c
++++ b/fs/smb/client/cifsfs.c
+@@ -154,6 +154,7 @@ struct workqueue_struct    *decrypt_wq;
+ struct workqueue_struct       *fileinfo_put_wq;
+ struct workqueue_struct       *cifsoplockd_wq;
+ struct workqueue_struct       *deferredclose_wq;
++struct workqueue_struct       *serverclose_wq;
+ __u32 cifs_lock_secret;
+ /*
+@@ -1866,6 +1867,13 @@ init_cifs(void)
+               goto out_destroy_cifsoplockd_wq;
+       }
++      serverclose_wq = alloc_workqueue("serverclose",
++                                         WQ_FREEZABLE|WQ_MEM_RECLAIM, 0);
++      if (!serverclose_wq) {
++              rc = -ENOMEM;
++              goto out_destroy_serverclose_wq;
++      }
++
+       rc = cifs_init_inodecache();
+       if (rc)
+               goto out_destroy_deferredclose_wq;
+@@ -1940,6 +1948,8 @@ out_destroy_decrypt_wq:
+       destroy_workqueue(decrypt_wq);
+ out_destroy_cifsiod_wq:
+       destroy_workqueue(cifsiod_wq);
++out_destroy_serverclose_wq:
++      destroy_workqueue(serverclose_wq);
+ out_clean_proc:
+       cifs_proc_clean();
+       return rc;
+@@ -1969,6 +1979,7 @@ exit_cifs(void)
+       destroy_workqueue(cifsoplockd_wq);
+       destroy_workqueue(decrypt_wq);
+       destroy_workqueue(fileinfo_put_wq);
++      destroy_workqueue(serverclose_wq);
+       destroy_workqueue(cifsiod_wq);
+       cifs_proc_clean();
+ }
+--- a/fs/smb/client/cifsglob.h
++++ b/fs/smb/client/cifsglob.h
+@@ -389,10 +389,10 @@ struct smb_version_operations {
+       /* set fid protocol-specific info */
+       void (*set_fid)(struct cifsFileInfo *, struct cifs_fid *, __u32);
+       /* close a file */
+-      void (*close)(const unsigned int, struct cifs_tcon *,
++      int (*close)(const unsigned int, struct cifs_tcon *,
+                     struct cifs_fid *);
+       /* close a file, returning file attributes and timestamps */
+-      void (*close_getattr)(const unsigned int xid, struct cifs_tcon *tcon,
++      int (*close_getattr)(const unsigned int xid, struct cifs_tcon *tcon,
+                     struct cifsFileInfo *pfile_info);
+       /* send a flush request to the server */
+       int (*flush)(const unsigned int, struct cifs_tcon *, struct cifs_fid *);
+@@ -1359,6 +1359,7 @@ struct cifsFileInfo {
+       bool invalidHandle:1;   /* file closed via session abend */
+       bool swapfile:1;
+       bool oplock_break_cancelled:1;
++      bool offload:1; /* offload final part of _put to a wq */
+       unsigned int oplock_epoch; /* epoch from the lease break */
+       __u32 oplock_level; /* oplock/lease level from the lease break */
+       int count;
+@@ -1367,6 +1368,7 @@ struct cifsFileInfo {
+       struct cifs_search_info srch_inf;
+       struct work_struct oplock_break; /* work for oplock breaks */
+       struct work_struct put; /* work for the final part of _put */
++      struct work_struct serverclose; /* work for serverclose */
+       struct delayed_work deferred;
+       bool deferred_close_scheduled; /* Flag to indicate close is scheduled */
+       char *symlink_target;
+@@ -2005,6 +2007,7 @@ extern struct workqueue_struct *decrypt_
+ extern struct workqueue_struct *fileinfo_put_wq;
+ extern struct workqueue_struct *cifsoplockd_wq;
+ extern struct workqueue_struct *deferredclose_wq;
++extern struct workqueue_struct *serverclose_wq;
+ extern __u32 cifs_lock_secret;
+ extern mempool_t *cifs_mid_poolp;
+--- a/fs/smb/client/file.c
++++ b/fs/smb/client/file.c
+@@ -330,6 +330,7 @@ cifs_down_write(struct rw_semaphore *sem
+ }
+ static void cifsFileInfo_put_work(struct work_struct *work);
++void serverclose_work(struct work_struct *work);
+ struct cifsFileInfo *cifs_new_fileinfo(struct cifs_fid *fid, struct file *file,
+                                      struct tcon_link *tlink, __u32 oplock,
+@@ -376,6 +377,7 @@ struct cifsFileInfo *cifs_new_fileinfo(s
+       cfile->tlink = cifs_get_tlink(tlink);
+       INIT_WORK(&cfile->oplock_break, cifs_oplock_break);
+       INIT_WORK(&cfile->put, cifsFileInfo_put_work);
++      INIT_WORK(&cfile->serverclose, serverclose_work);
+       INIT_DELAYED_WORK(&cfile->deferred, smb2_deferred_work_close);
+       mutex_init(&cfile->fh_mutex);
+       spin_lock_init(&cfile->file_info_lock);
+@@ -467,6 +469,40 @@ static void cifsFileInfo_put_work(struct
+       cifsFileInfo_put_final(cifs_file);
+ }
++void serverclose_work(struct work_struct *work)
++{
++      struct cifsFileInfo *cifs_file = container_of(work,
++                      struct cifsFileInfo, serverclose);
++
++      struct cifs_tcon *tcon = tlink_tcon(cifs_file->tlink);
++
++      struct TCP_Server_Info *server = tcon->ses->server;
++      int rc = 0;
++      int retries = 0;
++      int MAX_RETRIES = 4;
++
++      do {
++              if (server->ops->close_getattr)
++                      rc = server->ops->close_getattr(0, tcon, cifs_file);
++              else if (server->ops->close)
++                      rc = server->ops->close(0, tcon, &cifs_file->fid);
++
++              if (rc == -EBUSY || rc == -EAGAIN) {
++                      retries++;
++                      msleep(250);
++              }
++      } while ((rc == -EBUSY || rc == -EAGAIN) && (retries < MAX_RETRIES)
++      );
++
++      if (retries == MAX_RETRIES)
++              pr_warn("Serverclose failed %d times, giving up\n", MAX_RETRIES);
++
++      if (cifs_file->offload)
++              queue_work(fileinfo_put_wq, &cifs_file->put);
++      else
++              cifsFileInfo_put_final(cifs_file);
++}
++
+ /**
+  * cifsFileInfo_put - release a reference of file priv data
+  *
+@@ -507,10 +543,13 @@ void _cifsFileInfo_put(struct cifsFileIn
+       struct cifs_fid fid = {};
+       struct cifs_pending_open open;
+       bool oplock_break_cancelled;
++      bool serverclose_offloaded = false;
+       spin_lock(&tcon->open_file_lock);
+       spin_lock(&cifsi->open_file_lock);
+       spin_lock(&cifs_file->file_info_lock);
++
++      cifs_file->offload = offload;
+       if (--cifs_file->count > 0) {
+               spin_unlock(&cifs_file->file_info_lock);
+               spin_unlock(&cifsi->open_file_lock);
+@@ -552,13 +591,20 @@ void _cifsFileInfo_put(struct cifsFileIn
+       if (!tcon->need_reconnect && !cifs_file->invalidHandle) {
+               struct TCP_Server_Info *server = tcon->ses->server;
+               unsigned int xid;
++              int rc = 0;
+               xid = get_xid();
+               if (server->ops->close_getattr)
+-                      server->ops->close_getattr(xid, tcon, cifs_file);
++                      rc = server->ops->close_getattr(xid, tcon, cifs_file);
+               else if (server->ops->close)
+-                      server->ops->close(xid, tcon, &cifs_file->fid);
++                      rc = server->ops->close(xid, tcon, &cifs_file->fid);
+               _free_xid(xid);
++
++              if (rc == -EBUSY || rc == -EAGAIN) {
++                      // Server close failed, hence offloading it as an async op
++                      queue_work(serverclose_wq, &cifs_file->serverclose);
++                      serverclose_offloaded = true;
++              }
+       }
+       if (oplock_break_cancelled)
+@@ -566,10 +612,15 @@ void _cifsFileInfo_put(struct cifsFileIn
+       cifs_del_pending_open(&open);
+-      if (offload)
+-              queue_work(fileinfo_put_wq, &cifs_file->put);
+-      else
+-              cifsFileInfo_put_final(cifs_file);
++      // if serverclose has been offloaded to wq (on failure), it will
++      // handle offloading put as well. If serverclose not offloaded,
++      // we need to handle offloading put here.
++      if (!serverclose_offloaded) {
++              if (offload)
++                      queue_work(fileinfo_put_wq, &cifs_file->put);
++              else
++                      cifsFileInfo_put_final(cifs_file);
++      }
+ }
+ int cifs_open(struct inode *inode, struct file *file)
+--- a/fs/smb/client/smb1ops.c
++++ b/fs/smb/client/smb1ops.c
+@@ -750,11 +750,11 @@ cifs_set_fid(struct cifsFileInfo *cfile,
+       cinode->can_cache_brlcks = CIFS_CACHE_WRITE(cinode);
+ }
+-static void
++static int
+ cifs_close_file(const unsigned int xid, struct cifs_tcon *tcon,
+               struct cifs_fid *fid)
+ {
+-      CIFSSMBClose(xid, tcon, fid->netfid);
++      return CIFSSMBClose(xid, tcon, fid->netfid);
+ }
+ static int
+--- a/fs/smb/client/smb2ops.c
++++ b/fs/smb/client/smb2ops.c
+@@ -1392,14 +1392,14 @@ smb2_set_fid(struct cifsFileInfo *cfile,
+       memcpy(cfile->fid.create_guid, fid->create_guid, 16);
+ }
+-static void
++static int
+ smb2_close_file(const unsigned int xid, struct cifs_tcon *tcon,
+               struct cifs_fid *fid)
+ {
+-      SMB2_close(xid, tcon, fid->persistent_fid, fid->volatile_fid);
++      return SMB2_close(xid, tcon, fid->persistent_fid, fid->volatile_fid);
+ }
+-static void
++static int
+ smb2_close_getattr(const unsigned int xid, struct cifs_tcon *tcon,
+                  struct cifsFileInfo *cfile)
+ {
+@@ -1410,7 +1410,7 @@ smb2_close_getattr(const unsigned int xi
+       rc = __SMB2_close(xid, tcon, cfile->fid.persistent_fid,
+                  cfile->fid.volatile_fid, &file_inf);
+       if (rc)
+-              return;
++              return rc;
+       inode = d_inode(cfile->dentry);
+@@ -1436,6 +1436,7 @@ smb2_close_getattr(const unsigned int xi
+       /* End of file and Attributes should not have to be updated on close */
+       spin_unlock(&inode->i_lock);
++      return rc;
+ }
+ static int
+--- a/fs/smb/client/smb2pdu.c
++++ b/fs/smb/client/smb2pdu.c
+@@ -3452,9 +3452,9 @@ __SMB2_close(const unsigned int xid, str
+                       memcpy(&pbuf->network_open_info,
+                              &rsp->network_open_info,
+                              sizeof(pbuf->network_open_info));
++              atomic_dec(&tcon->num_remote_opens);
+       }
+-      atomic_dec(&tcon->num_remote_opens);
+ close_exit:
+       SMB2_close_free(&rqst);
+       free_rsp_buf(resp_buftype, rsp);