From: Greg Kroah-Hartman Date: Fri, 27 Nov 2020 15:49:32 +0000 (+0100) Subject: 5.9-stable patches X-Git-Tag: v4.4.247~35^2 X-Git-Url: http://git.ipfire.org/gitweb/?a=commitdiff_plain;h=ad7ae90076875146cec1ab26fc5bc0a0e52875e2;p=thirdparty%2Fkernel%2Fstable-queue.git 5.9-stable patches added patches: cifs-fix-a-memleak-with-modefromsid.patch mm-fix-vm_bug_on-pagetail-and-bug_on-pagewriteback.patch s390-fix-fpu-restore-in-entry.s.patch smb3-avoid-mid-pending-list-corruption.patch smb3-call-cifs-reconnect-from-demultiplex-thread.patch smb3-handle-error-case-during-offload-read-path.patch --- diff --git a/queue-5.9/cifs-fix-a-memleak-with-modefromsid.patch b/queue-5.9/cifs-fix-a-memleak-with-modefromsid.patch new file mode 100644 index 00000000000..2b33c7bb137 --- /dev/null +++ b/queue-5.9/cifs-fix-a-memleak-with-modefromsid.patch @@ -0,0 +1,52 @@ +From 98128572084c3dd8067f48bb588aa3733d1355b5 Mon Sep 17 00:00:00 2001 +From: Namjae Jeon +Date: Mon, 9 Nov 2020 17:35:33 +0900 +Subject: cifs: fix a memleak with modefromsid + +From: Namjae Jeon + +commit 98128572084c3dd8067f48bb588aa3733d1355b5 upstream. + +kmemleak reported a memory leak allocated in query_info() when cifs is +working with modefromsid. + + backtrace: + [<00000000aeef6a1e>] slab_post_alloc_hook+0x58/0x510 + [<00000000b2f7a440>] __kmalloc+0x1a0/0x390 + [<000000006d470ebc>] query_info+0x5b5/0x700 [cifs] + [<00000000bad76ce0>] SMB2_query_acl+0x2b/0x30 [cifs] + [<000000001fa09606>] get_smb2_acl_by_path+0x2f3/0x720 [cifs] + [<000000001b6ebab7>] get_smb2_acl+0x75/0x90 [cifs] + [<00000000abf43904>] cifs_acl_to_fattr+0x13b/0x1d0 [cifs] + [<00000000a5372ec3>] cifs_get_inode_info+0x4cd/0x9a0 [cifs] + [<00000000388e0a04>] cifs_revalidate_dentry_attr+0x1cd/0x510 [cifs] + [<0000000046b6b352>] cifs_getattr+0x8a/0x260 [cifs] + [<000000007692c95e>] vfs_getattr_nosec+0xa1/0xc0 + [<00000000cbc7d742>] vfs_getattr+0x36/0x40 + [<00000000de8acf67>] vfs_statx_fd+0x4a/0x80 + [<00000000a58c6adb>] __do_sys_newfstat+0x31/0x70 + [<00000000300b3b4e>] __x64_sys_newfstat+0x16/0x20 + [<000000006d8e9c48>] do_syscall_64+0x37/0x80 + +This patch add missing kfree for pntsd when mounting modefromsid option. + +Cc: Stable # v5.4+ +Signed-off-by: Namjae Jeon +Reviewed-by: Aurelien Aptel +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman + +--- + fs/cifs/cifsacl.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/fs/cifs/cifsacl.c ++++ b/fs/cifs/cifsacl.c +@@ -1266,6 +1266,7 @@ cifs_acl_to_fattr(struct cifs_sb_info *c + cifs_dbg(VFS, "%s: error %d getting sec desc\n", __func__, rc); + } else if (mode_from_special_sid) { + rc = parse_sec_desc(cifs_sb, pntsd, acllen, fattr, true); ++ kfree(pntsd); + } else { + /* get approximated mode from ACL */ + rc = parse_sec_desc(cifs_sb, pntsd, acllen, fattr, false); diff --git a/queue-5.9/mm-fix-vm_bug_on-pagetail-and-bug_on-pagewriteback.patch b/queue-5.9/mm-fix-vm_bug_on-pagetail-and-bug_on-pagewriteback.patch new file mode 100644 index 00000000000..3fcda2659c2 --- /dev/null +++ b/queue-5.9/mm-fix-vm_bug_on-pagetail-and-bug_on-pagewriteback.patch @@ -0,0 +1,123 @@ +From 073861ed77b6b957c3c8d54a11dc503f7d986ceb Mon Sep 17 00:00:00 2001 +From: Hugh Dickins +Date: Tue, 24 Nov 2020 08:46:43 -0800 +Subject: mm: fix VM_BUG_ON(PageTail) and BUG_ON(PageWriteback) + +From: Hugh Dickins + +commit 073861ed77b6b957c3c8d54a11dc503f7d986ceb upstream. + +Twice now, when exercising ext4 looped on shmem huge pages, I have crashed +on the PF_ONLY_HEAD check inside PageWaiters(): ext4_finish_bio() calling +end_page_writeback() calling wake_up_page() on tail of a shmem huge page, +no longer an ext4 page at all. + +The problem is that PageWriteback is not accompanied by a page reference +(as the NOTE at the end of test_clear_page_writeback() acknowledges): as +soon as TestClearPageWriteback has been done, that page could be removed +from page cache, freed, and reused for something else by the time that +wake_up_page() is reached. + +https://lore.kernel.org/linux-mm/20200827122019.GC14765@casper.infradead.org/ +Matthew Wilcox suggested avoiding or weakening the PageWaiters() tail +check; but I'm paranoid about even looking at an unreferenced struct page, +lest its memory might itself have already been reused or hotremoved (and +wake_up_page_bit() may modify that memory with its ClearPageWaiters()). + +Then on crashing a second time, realized there's a stronger reason against +that approach. If my testing just occasionally crashes on that check, +when the page is reused for part of a compound page, wouldn't it be much +more common for the page to get reused as an order-0 page before reaching +wake_up_page()? And on rare occasions, might that reused page already be +marked PageWriteback by its new user, and already be waited upon? What +would that look like? + +It would look like BUG_ON(PageWriteback) after wait_on_page_writeback() +in write_cache_pages() (though I have never seen that crash myself). + +Matthew Wilcox explaining this to himself: + "page is allocated, added to page cache, dirtied, writeback starts, + + --- thread A --- + filesystem calls end_page_writeback() + test_clear_page_writeback() + --- context switch to thread B --- + truncate_inode_pages_range() finds the page, it doesn't have writeback set, + we delete it from the page cache. Page gets reallocated, dirtied, writeback + starts again. Then we call write_cache_pages(), see + PageWriteback() set, call wait_on_page_writeback() + --- context switch back to thread A --- + wake_up_page(page, PG_writeback); + ... thread B is woken, but because the wakeup was for the old use of + the page, PageWriteback is still set. + + Devious" + +And prior to 2a9127fcf229 ("mm: rewrite wait_on_page_bit_common() logic") +this would have been much less likely: before that, wake_page_function()'s +non-exclusive case would stop walking and not wake if it found Writeback +already set again; whereas now the non-exclusive case proceeds to wake. + +I have not thought of a fix that does not add a little overhead: the +simplest fix is for end_page_writeback() to get_page() before calling +test_clear_page_writeback(), then put_page() after wake_up_page(). + +Was there a chance of missed wakeups before, since a page freed before +reaching wake_up_page() would have PageWaiters cleared? I think not, +because each waiter does hold a reference on the page. This bug comes +when the old use of the page, the one we do TestClearPageWriteback on, +had *no* waiters, so no additional page reference beyond the page cache +(and whoever racily freed it). The reuse of the page has a waiter +holding a reference, and its own PageWriteback set; but the belated +wake_up_page() has woken the reuse to hit that BUG_ON(PageWriteback). + +Reported-by: syzbot+3622cea378100f45d59f@syzkaller.appspotmail.com +Reported-by: Qian Cai +Fixes: 2a9127fcf229 ("mm: rewrite wait_on_page_bit_common() logic") +Signed-off-by: Hugh Dickins +Cc: stable@vger.kernel.org # v5.8+ +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + +--- + mm/filemap.c | 8 ++++++++ + mm/page-writeback.c | 6 ------ + 2 files changed, 8 insertions(+), 6 deletions(-) + +--- a/mm/filemap.c ++++ b/mm/filemap.c +@@ -1464,11 +1464,19 @@ void end_page_writeback(struct page *pag + rotate_reclaimable_page(page); + } + ++ /* ++ * Writeback does not hold a page reference of its own, relying ++ * on truncation to wait for the clearing of PG_writeback. ++ * But here we must make sure that the page is not freed and ++ * reused before the wake_up_page(). ++ */ ++ get_page(page); + if (!test_clear_page_writeback(page)) + BUG(); + + smp_mb__after_atomic(); + wake_up_page(page, PG_writeback); ++ put_page(page); + } + EXPORT_SYMBOL(end_page_writeback); + +--- a/mm/page-writeback.c ++++ b/mm/page-writeback.c +@@ -2754,12 +2754,6 @@ int test_clear_page_writeback(struct pag + } else { + ret = TestClearPageWriteback(page); + } +- /* +- * NOTE: Page might be free now! Writeback doesn't hold a page +- * reference on its own, it relies on truncation to wait for +- * the clearing of PG_writeback. The below can only access +- * page state that is static across allocation cycles. +- */ + if (ret) { + dec_lruvec_state(lruvec, NR_WRITEBACK); + dec_zone_page_state(page, NR_ZONE_WRITE_PENDING); diff --git a/queue-5.9/s390-fix-fpu-restore-in-entry.s.patch b/queue-5.9/s390-fix-fpu-restore-in-entry.s.patch new file mode 100644 index 00000000000..062babe0339 --- /dev/null +++ b/queue-5.9/s390-fix-fpu-restore-in-entry.s.patch @@ -0,0 +1,72 @@ +From 1179f170b6f0af7bb0b3b7628136eaac450ddf31 Mon Sep 17 00:00:00 2001 +From: Sven Schnelle +Date: Fri, 20 Nov 2020 14:17:52 +0100 +Subject: s390: fix fpu restore in entry.S + +From: Sven Schnelle + +commit 1179f170b6f0af7bb0b3b7628136eaac450ddf31 upstream. + +We need to disable interrupts in load_fpu_regs(). Otherwise an +interrupt might come in after the registers are loaded, but before +CIF_FPU is cleared in load_fpu_regs(). When the interrupt returns, +CIF_FPU will be cleared and the registers will never be restored. + +The entry.S code usually saves the interrupt state in __SF_EMPTY on the +stack when disabling/restoring interrupts. sie64a however saves the pointer +to the sie control block in __SF_SIE_CONTROL, which references the same +location. This is non-obvious to the reader. To avoid thrashing the sie +control block pointer in load_fpu_regs(), move the __SIE_* offsets eight +bytes after __SF_EMPTY on the stack. + +Cc: # 5.8 +Fixes: 0b0ed657fe00 ("s390: remove critical section cleanup from entry.S") +Reported-by: Pierre Morel +Signed-off-by: Sven Schnelle +Acked-by: Christian Borntraeger +Reviewed-by: Heiko Carstens +Signed-off-by: Heiko Carstens +Signed-off-by: Greg Kroah-Hartman + +--- + arch/s390/kernel/asm-offsets.c | 10 +++++----- + arch/s390/kernel/entry.S | 2 ++ + 2 files changed, 7 insertions(+), 5 deletions(-) + +--- a/arch/s390/kernel/asm-offsets.c ++++ b/arch/s390/kernel/asm-offsets.c +@@ -53,11 +53,11 @@ int main(void) + /* stack_frame offsets */ + OFFSET(__SF_BACKCHAIN, stack_frame, back_chain); + OFFSET(__SF_GPRS, stack_frame, gprs); +- OFFSET(__SF_EMPTY, stack_frame, empty1); +- OFFSET(__SF_SIE_CONTROL, stack_frame, empty1[0]); +- OFFSET(__SF_SIE_SAVEAREA, stack_frame, empty1[1]); +- OFFSET(__SF_SIE_REASON, stack_frame, empty1[2]); +- OFFSET(__SF_SIE_FLAGS, stack_frame, empty1[3]); ++ OFFSET(__SF_EMPTY, stack_frame, empty1[0]); ++ OFFSET(__SF_SIE_CONTROL, stack_frame, empty1[1]); ++ OFFSET(__SF_SIE_SAVEAREA, stack_frame, empty1[2]); ++ OFFSET(__SF_SIE_REASON, stack_frame, empty1[3]); ++ OFFSET(__SF_SIE_FLAGS, stack_frame, empty1[4]); + BLANK(); + /* timeval/timezone offsets for use by vdso */ + OFFSET(__VDSO_UPD_COUNT, vdso_data, tb_update_count); +--- a/arch/s390/kernel/entry.S ++++ b/arch/s390/kernel/entry.S +@@ -1072,6 +1072,7 @@ EXPORT_SYMBOL(save_fpu_regs) + * %r4 + */ + load_fpu_regs: ++ stnsm __SF_EMPTY(%r15),0xfc + lg %r4,__LC_CURRENT + aghi %r4,__TASK_thread + TSTMSK __LC_CPU_FLAGS,_CIF_FPU +@@ -1103,6 +1104,7 @@ load_fpu_regs: + .Lload_fpu_regs_done: + ni __LC_CPU_FLAGS+7,255-_CIF_FPU + .Lload_fpu_regs_exit: ++ ssm __SF_EMPTY(%r15) + BR_EX %r14 + .Lload_fpu_regs_end: + ENDPROC(load_fpu_regs) diff --git a/queue-5.9/series b/queue-5.9/series index e61fd89de61..bced0701f95 100644 --- a/queue-5.9/series +++ b/queue-5.9/series @@ -4,3 +4,9 @@ spi-bcm-qspi-fix-use-after-free-on-unbind.patch spi-bcm2835-fix-use-after-free-on-unbind.patch ipv4-use-is_enabled-instead-of-ifdef.patch rtc-pcf2127-fix-a-bug-when-not-specify-interrupts-property.patch +s390-fix-fpu-restore-in-entry.s.patch +mm-fix-vm_bug_on-pagetail-and-bug_on-pagewriteback.patch +smb3-call-cifs-reconnect-from-demultiplex-thread.patch +smb3-avoid-mid-pending-list-corruption.patch +smb3-handle-error-case-during-offload-read-path.patch +cifs-fix-a-memleak-with-modefromsid.patch diff --git a/queue-5.9/smb3-avoid-mid-pending-list-corruption.patch b/queue-5.9/smb3-avoid-mid-pending-list-corruption.patch new file mode 100644 index 00000000000..cf61c975476 --- /dev/null +++ b/queue-5.9/smb3-avoid-mid-pending-list-corruption.patch @@ -0,0 +1,160 @@ +From ac873aa3dc21707c47db5db6608b38981c731afe Mon Sep 17 00:00:00 2001 +From: Rohith Surabattula +Date: Thu, 29 Oct 2020 05:03:10 +0000 +Subject: smb3: Avoid Mid pending list corruption + +From: Rohith Surabattula + +commit ac873aa3dc21707c47db5db6608b38981c731afe upstream. + +When reconnect happens Mid queue can be corrupted when both +demultiplex and offload thread try to dequeue the MID from the +pending list. + +These patches address a problem found during decryption offload: + CIFS: VFS: trying to dequeue a deleted mid +that could cause a refcount use after free: + Workqueue: smb3decryptd smb2_decrypt_offload [cifs] + +Signed-off-by: Rohith Surabattula +Reviewed-by: Pavel Shilovsky +CC: Stable #5.4+ +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman + +--- + fs/cifs/smb2ops.c | 55 +++++++++++++++++++++++++++++++++++++++++++++--------- + 1 file changed, 46 insertions(+), 9 deletions(-) + +--- a/fs/cifs/smb2ops.c ++++ b/fs/cifs/smb2ops.c +@@ -262,7 +262,7 @@ smb2_revert_current_mid(struct TCP_Serve + } + + static struct mid_q_entry * +-smb2_find_mid(struct TCP_Server_Info *server, char *buf) ++__smb2_find_mid(struct TCP_Server_Info *server, char *buf, bool dequeue) + { + struct mid_q_entry *mid; + struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)buf; +@@ -279,6 +279,10 @@ smb2_find_mid(struct TCP_Server_Info *se + (mid->mid_state == MID_REQUEST_SUBMITTED) && + (mid->command == shdr->Command)) { + kref_get(&mid->refcount); ++ if (dequeue) { ++ list_del_init(&mid->qhead); ++ mid->mid_flags |= MID_DELETED; ++ } + spin_unlock(&GlobalMid_Lock); + return mid; + } +@@ -287,6 +291,18 @@ smb2_find_mid(struct TCP_Server_Info *se + return NULL; + } + ++static struct mid_q_entry * ++smb2_find_mid(struct TCP_Server_Info *server, char *buf) ++{ ++ return __smb2_find_mid(server, buf, false); ++} ++ ++static struct mid_q_entry * ++smb2_find_dequeue_mid(struct TCP_Server_Info *server, char *buf) ++{ ++ return __smb2_find_mid(server, buf, true); ++} ++ + static void + smb2_dump_detail(void *buf, struct TCP_Server_Info *server) + { +@@ -4260,7 +4276,10 @@ handle_read_data(struct TCP_Server_Info + cifs_dbg(FYI, "%s: server returned error %d\n", + __func__, rdata->result); + /* normal error on read response */ +- dequeue_mid(mid, false); ++ if (is_offloaded) ++ mid->mid_state = MID_RESPONSE_RECEIVED; ++ else ++ dequeue_mid(mid, false); + return 0; + } + +@@ -4284,7 +4303,10 @@ handle_read_data(struct TCP_Server_Info + cifs_dbg(FYI, "%s: data offset (%u) beyond end of smallbuf\n", + __func__, data_offset); + rdata->result = -EIO; +- dequeue_mid(mid, rdata->result); ++ if (is_offloaded) ++ mid->mid_state = MID_RESPONSE_MALFORMED; ++ else ++ dequeue_mid(mid, rdata->result); + return 0; + } + +@@ -4300,21 +4322,30 @@ handle_read_data(struct TCP_Server_Info + cifs_dbg(FYI, "%s: data offset (%u) beyond 1st page of response\n", + __func__, data_offset); + rdata->result = -EIO; +- dequeue_mid(mid, rdata->result); ++ if (is_offloaded) ++ mid->mid_state = MID_RESPONSE_MALFORMED; ++ else ++ dequeue_mid(mid, rdata->result); + return 0; + } + + if (data_len > page_data_size - pad_len) { + /* data_len is corrupt -- discard frame */ + rdata->result = -EIO; +- dequeue_mid(mid, rdata->result); ++ if (is_offloaded) ++ mid->mid_state = MID_RESPONSE_MALFORMED; ++ else ++ dequeue_mid(mid, rdata->result); + return 0; + } + + rdata->result = init_read_bvec(pages, npages, page_data_size, + cur_off, &bvec); + if (rdata->result != 0) { +- dequeue_mid(mid, rdata->result); ++ if (is_offloaded) ++ mid->mid_state = MID_RESPONSE_MALFORMED; ++ else ++ dequeue_mid(mid, rdata->result); + return 0; + } + +@@ -4329,7 +4360,10 @@ handle_read_data(struct TCP_Server_Info + /* read response payload cannot be in both buf and pages */ + WARN_ONCE(1, "buf can not contain only a part of read data"); + rdata->result = -EIO; +- dequeue_mid(mid, rdata->result); ++ if (is_offloaded) ++ mid->mid_state = MID_RESPONSE_MALFORMED; ++ else ++ dequeue_mid(mid, rdata->result); + return 0; + } + +@@ -4340,7 +4374,10 @@ handle_read_data(struct TCP_Server_Info + if (length < 0) + return length; + +- dequeue_mid(mid, false); ++ if (is_offloaded) ++ mid->mid_state = MID_RESPONSE_RECEIVED; ++ else ++ dequeue_mid(mid, false); + return length; + } + +@@ -4369,7 +4406,7 @@ static void smb2_decrypt_offload(struct + } + + dw->server->lstrp = jiffies; +- mid = smb2_find_mid(dw->server, dw->buf); ++ mid = smb2_find_dequeue_mid(dw->server, dw->buf); + if (mid == NULL) + cifs_dbg(FYI, "mid not found\n"); + else { diff --git a/queue-5.9/smb3-call-cifs-reconnect-from-demultiplex-thread.patch b/queue-5.9/smb3-call-cifs-reconnect-from-demultiplex-thread.patch new file mode 100644 index 00000000000..f990402e6ff --- /dev/null +++ b/queue-5.9/smb3-call-cifs-reconnect-from-demultiplex-thread.patch @@ -0,0 +1,101 @@ +From de9ac0a6e9efdffc8cde18781f48fb56ca4157b7 Mon Sep 17 00:00:00 2001 +From: Rohith Surabattula +Date: Wed, 28 Oct 2020 13:42:21 +0000 +Subject: smb3: Call cifs reconnect from demultiplex thread + +From: Rohith Surabattula + +commit de9ac0a6e9efdffc8cde18781f48fb56ca4157b7 upstream. + +cifs_reconnect needs to be called only from demultiplex thread. +skip cifs_reconnect in offload thread. So, cifs_reconnect will be +called by demultiplex thread in subsequent request. + +These patches address a problem found during decryption offload: + CIFS: VFS: trying to dequeue a deleted mid +that can cause a refcount use after free: + +[ 1271.389453] Workqueue: smb3decryptd smb2_decrypt_offload [cifs] +[ 1271.389456] RIP: 0010:refcount_warn_saturate+0xae/0xf0 +[ 1271.389457] Code: fa 1d 6a 01 01 e8 c7 44 b1 ff 0f 0b 5d c3 80 3d e7 1d 6a 01 00 75 91 48 c7 c7 d8 be 1d a2 c6 05 d7 1d 6a 01 01 e8 a7 44 b1 ff <0f> 0b 5d c3 80 3d c5 1d 6a 01 00 0f 85 6d ff ff ff 48 c7 c7 30 bf +[ 1271.389458] RSP: 0018:ffffa4cdc1f87e30 EFLAGS: 00010286 +[ 1271.389458] RAX: 0000000000000000 RBX: ffff9974d2809f00 RCX: ffff9974df898cc8 +[ 1271.389459] RDX: 00000000ffffffd8 RSI: 0000000000000027 RDI: ffff9974df898cc0 +[ 1271.389460] RBP: ffffa4cdc1f87e30 R08: 0000000000000004 R09: 00000000000002c0 +[ 1271.389460] R10: 0000000000000000 R11: 0000000000000001 R12: ffff9974b7fdb5c0 +[ 1271.389461] R13: ffff9974d2809f00 R14: ffff9974ccea0a80 R15: ffff99748e60db80 +[ 1271.389462] FS: 0000000000000000(0000) GS:ffff9974df880000(0000) knlGS:0000000000000000 +[ 1271.389462] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +[ 1271.389463] CR2: 000055c60f344fe4 CR3: 0000001031a3c002 CR4: 00000000003706e0 +[ 1271.389465] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 +[ 1271.389465] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 +[ 1271.389466] Call Trace: +[ 1271.389483] cifs_mid_q_entry_release+0xce/0x110 [cifs] +[ 1271.389499] smb2_decrypt_offload+0xa9/0x1c0 [cifs] +[ 1271.389501] process_one_work+0x1e8/0x3b0 +[ 1271.389503] worker_thread+0x50/0x370 +[ 1271.389504] kthread+0x12f/0x150 +[ 1271.389506] ? process_one_work+0x3b0/0x3b0 +[ 1271.389507] ? __kthread_bind_mask+0x70/0x70 +[ 1271.389509] ret_from_fork+0x22/0x30 + +Signed-off-by: Rohith Surabattula +Reviewed-by: Pavel Shilovsky +CC: Stable #5.4+ +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman + +--- + fs/cifs/smb2ops.c | 13 ++++++++----- + 1 file changed, 8 insertions(+), 5 deletions(-) + +--- a/fs/cifs/smb2ops.c ++++ b/fs/cifs/smb2ops.c +@@ -4212,7 +4212,8 @@ init_read_bvec(struct page **pages, unsi + static int + handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid, + char *buf, unsigned int buf_len, struct page **pages, +- unsigned int npages, unsigned int page_data_size) ++ unsigned int npages, unsigned int page_data_size, ++ bool is_offloaded) + { + unsigned int data_offset; + unsigned int data_len; +@@ -4234,7 +4235,8 @@ handle_read_data(struct TCP_Server_Info + + if (server->ops->is_session_expired && + server->ops->is_session_expired(buf)) { +- cifs_reconnect(server); ++ if (!is_offloaded) ++ cifs_reconnect(server); + return -1; + } + +@@ -4374,7 +4376,8 @@ static void smb2_decrypt_offload(struct + mid->decrypted = true; + rc = handle_read_data(dw->server, mid, dw->buf, + dw->server->vals->read_rsp_size, +- dw->ppages, dw->npages, dw->len); ++ dw->ppages, dw->npages, dw->len, ++ true); + mid->callback(mid); + cifs_mid_q_entry_release(mid); + } +@@ -4478,7 +4481,7 @@ non_offloaded_decrypt: + (*mid)->decrypted = true; + rc = handle_read_data(server, *mid, buf, + server->vals->read_rsp_size, +- pages, npages, len); ++ pages, npages, len, false); + } + + free_pages: +@@ -4621,7 +4624,7 @@ smb3_handle_read_data(struct TCP_Server_ + char *buf = server->large_buf ? server->bigbuf : server->smallbuf; + + return handle_read_data(server, mid, buf, server->pdu_size, +- NULL, 0, 0); ++ NULL, 0, 0, false); + } + + static int diff --git a/queue-5.9/smb3-handle-error-case-during-offload-read-path.patch b/queue-5.9/smb3-handle-error-case-during-offload-read-path.patch new file mode 100644 index 00000000000..685fbfb5569 --- /dev/null +++ b/queue-5.9/smb3-handle-error-case-during-offload-read-path.patch @@ -0,0 +1,56 @@ +From 1254100030b3377e8302f9c75090ab191d73ee7c Mon Sep 17 00:00:00 2001 +From: Rohith Surabattula +Date: Thu, 29 Oct 2020 06:07:56 +0000 +Subject: smb3: Handle error case during offload read path + +From: Rohith Surabattula + +commit 1254100030b3377e8302f9c75090ab191d73ee7c upstream. + +Mid callback needs to be called only when valid data is +read into pages. + +These patches address a problem found during decryption offload: + CIFS: VFS: trying to dequeue a deleted mid +that could cause a refcount use after free: + Workqueue: smb3decryptd smb2_decrypt_offload [cifs] + +Signed-off-by: Rohith Surabattula +Reviewed-by: Pavel Shilovsky +CC: Stable #5.4+ +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman + +--- + fs/cifs/smb2ops.c | 20 +++++++++++++++++++- + 1 file changed, 19 insertions(+), 1 deletion(-) + +--- a/fs/cifs/smb2ops.c ++++ b/fs/cifs/smb2ops.c +@@ -4415,7 +4415,25 @@ static void smb2_decrypt_offload(struct + dw->server->vals->read_rsp_size, + dw->ppages, dw->npages, dw->len, + true); +- mid->callback(mid); ++ if (rc >= 0) { ++#ifdef CONFIG_CIFS_STATS2 ++ mid->when_received = jiffies; ++#endif ++ mid->callback(mid); ++ } else { ++ spin_lock(&GlobalMid_Lock); ++ if (dw->server->tcpStatus == CifsNeedReconnect) { ++ mid->mid_state = MID_RETRY_NEEDED; ++ spin_unlock(&GlobalMid_Lock); ++ mid->callback(mid); ++ } else { ++ mid->mid_state = MID_REQUEST_SUBMITTED; ++ mid->mid_flags &= ~(MID_DELETED); ++ list_add_tail(&mid->qhead, ++ &dw->server->pending_mid_q); ++ spin_unlock(&GlobalMid_Lock); ++ } ++ } + cifs_mid_q_entry_release(mid); + } +