From: Greg Kroah-Hartman Date: Mon, 8 Apr 2024 10:34:50 +0000 (+0200) Subject: 6.1-stable patches X-Git-Tag: v5.15.154~36 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=21f7ce28eef15b93a0580f662cfd19e28808ff4d;p=thirdparty%2Fkernel%2Fstable-queue.git 6.1-stable patches 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 --- 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 index 00000000000..40f4121b3cc --- /dev/null +++ b/queue-6.1/riscv-fix-spurious-errors-from-__get-put_kernel_nofault.patch @@ -0,0 +1,44 @@ +From d080a08b06b6266cc3e0e86c5acfd80db937cb6b Mon Sep 17 00:00:00 2001 +From: Samuel Holland +Date: Mon, 11 Mar 2024 19:19:13 -0700 +Subject: riscv: Fix spurious errors from __get/put_kernel_nofault + +From: Samuel Holland + +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 +Reviewed-by: Alexandre Ghiti +Reviewed-by: Charlie Jenkins +Link: https://lore.kernel.org/r/20240312022030.320789-1-samuel.holland@sifive.com +Signed-off-by: Palmer Dabbelt +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 00000000000..29b6b021aee --- /dev/null +++ b/queue-6.1/riscv-process-fix-kernel-gp-leakage.patch @@ -0,0 +1,80 @@ +From d14fa1fcf69db9d070e75f1c4425211fa619dfc8 Mon Sep 17 00:00:00 2001 +From: Stefan O'Rear +Date: Wed, 27 Mar 2024 02:12:58 -0400 +Subject: riscv: process: Fix kernel gp leakage + +From: Stefan O'Rear + +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 +Reviewed-by: Alexandre Ghiti +Link: https://lore.kernel.org/r/20240327061258.2370291-1-sorear@fastmail.com +Signed-off-by: Palmer Dabbelt +Signed-off-by: Greg Kroah-Hartman +--- + 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 + #include + +-register unsigned long gp_in_global __asm__("gp"); +- + #if defined(CONFIG_STACKPROTECTOR) && !defined(CONFIG_STACKPROTECTOR_PER_TASK) + #include + 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 index 00000000000..eea6524db30 --- /dev/null +++ b/queue-6.1/s390-entry-align-system-call-table-on-8-bytes.patch @@ -0,0 +1,33 @@ +From 378ca2d2ad410a1cd5690d06b46c5e2297f4c8c0 Mon Sep 17 00:00:00 2001 +From: Sumanth Korikkar +Date: Tue, 26 Mar 2024 18:12:13 +0100 +Subject: s390/entry: align system call table on 8 bytes + +From: Sumanth Korikkar + +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 +Reviewed-by: Alexander Gordeev +Signed-off-by: Sumanth Korikkar +Signed-off-by: Vasily Gorbik +Signed-off-by: Greg Kroah-Hartman +--- + 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: diff --git a/queue-6.1/series b/queue-6.1/series index 44ed3af1460..c1d1532b3c7 100644 --- a/queue-6.1/series +++ b/queue-6.1/series @@ -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 index 00000000000..9352f963ec9 --- /dev/null +++ b/queue-6.1/smb-client-fix-potential-uaf-in-cifs_debug_files_proc_show.patch @@ -0,0 +1,49 @@ +From ca545b7f0823f19db0f1148d59bc5e1a56634502 Mon Sep 17 00:00:00 2001 +From: Paulo Alcantara +Date: Tue, 2 Apr 2024 16:33:53 -0300 +Subject: smb: client: fix potential UAF in cifs_debug_files_proc_show() + +From: Paulo Alcantara + +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) +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 00000000000..d01b0f8e422 --- /dev/null +++ b/queue-6.1/smb-client-fix-potential-uaf-in-cifs_signal_cifsd_for_reconnect.patch @@ -0,0 +1,31 @@ +From e0e50401cc3921c9eaf1b0e667db174519ea939f Mon Sep 17 00:00:00 2001 +From: Paulo Alcantara +Date: Tue, 2 Apr 2024 16:34:04 -0300 +Subject: smb: client: fix potential UAF in cifs_signal_cifsd_for_reconnect() + +From: Paulo Alcantara + +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) +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 00000000000..e8adbf94fb2 --- /dev/null +++ b/queue-6.1/smb-client-fix-potential-uaf-in-cifs_stats_proc_show.patch @@ -0,0 +1,31 @@ +From 0865ffefea197b437ba78b5dd8d8e256253efd65 Mon Sep 17 00:00:00 2001 +From: Paulo Alcantara +Date: Tue, 2 Apr 2024 16:33:56 -0300 +Subject: smb: client: fix potential UAF in cifs_stats_proc_show() + +From: Paulo Alcantara + +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) +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 00000000000..7abf664c5f4 --- /dev/null +++ b/queue-6.1/smb-client-fix-potential-uaf-in-cifs_stats_proc_write.patch @@ -0,0 +1,31 @@ +From d3da25c5ac84430f89875ca7485a3828150a7e0a Mon Sep 17 00:00:00 2001 +From: Paulo Alcantara +Date: Tue, 2 Apr 2024 16:33:55 -0300 +Subject: smb: client: fix potential UAF in cifs_stats_proc_write() + +From: Paulo Alcantara + +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) +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 00000000000..c9d39060d70 --- /dev/null +++ b/queue-6.1/smb-client-fix-potential-uaf-in-is_valid_oplock_break.patch @@ -0,0 +1,31 @@ +From 69ccf040acddf33a3a85ec0f6b45ef84b0f7ec29 Mon Sep 17 00:00:00 2001 +From: Paulo Alcantara +Date: Tue, 2 Apr 2024 16:34:00 -0300 +Subject: smb: client: fix potential UAF in is_valid_oplock_break() + +From: Paulo Alcantara + +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) +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 00000000000..9566231f545 --- /dev/null +++ b/queue-6.1/smb-client-fix-potential-uaf-in-smb2_is_network_name_deleted.patch @@ -0,0 +1,31 @@ +From 63981561ffd2d4987807df4126f96a11e18b0c1d Mon Sep 17 00:00:00 2001 +From: Paulo Alcantara +Date: Tue, 2 Apr 2024 16:34:02 -0300 +Subject: smb: client: fix potential UAF in smb2_is_network_name_deleted() + +From: Paulo Alcantara + +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) +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 00000000000..83914a6b03a --- /dev/null +++ b/queue-6.1/smb-client-fix-potential-uaf-in-smb2_is_valid_lease_break.patch @@ -0,0 +1,31 @@ +From 705c76fbf726c7a2f6ff9143d4013b18daaaebf1 Mon Sep 17 00:00:00 2001 +From: Paulo Alcantara +Date: Tue, 2 Apr 2024 16:33:58 -0300 +Subject: smb: client: fix potential UAF in smb2_is_valid_lease_break() + +From: Paulo Alcantara + +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) +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 00000000000..d2939b33cb3 --- /dev/null +++ b/queue-6.1/smb-client-fix-potential-uaf-in-smb2_is_valid_oplock_break.patch @@ -0,0 +1,31 @@ +From 22863485a4626ec6ecf297f4cc0aef709bc862e4 Mon Sep 17 00:00:00 2001 +From: Paulo Alcantara +Date: Tue, 2 Apr 2024 16:33:59 -0300 +Subject: smb: client: fix potential UAF in smb2_is_valid_oplock_break() + +From: Paulo Alcantara + +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) +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 00000000000..bba212a51b6 --- /dev/null +++ b/queue-6.1/smb3-retrying-on-failed-server-close.patch @@ -0,0 +1,315 @@ +From 173217bd73365867378b5e75a86f0049e1069ee8 Mon Sep 17 00:00:00 2001 +From: Ritvik Budhiraja +Date: Tue, 2 Apr 2024 14:01:28 -0500 +Subject: smb3: retrying on failed server close + +From: Ritvik Budhiraja + +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 +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + 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);