]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
5.9-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 27 Nov 2020 15:49:32 +0000 (16:49 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 27 Nov 2020 15:49:32 +0000 (16:49 +0100)
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

queue-5.9/cifs-fix-a-memleak-with-modefromsid.patch [new file with mode: 0644]
queue-5.9/mm-fix-vm_bug_on-pagetail-and-bug_on-pagewriteback.patch [new file with mode: 0644]
queue-5.9/s390-fix-fpu-restore-in-entry.s.patch [new file with mode: 0644]
queue-5.9/series
queue-5.9/smb3-avoid-mid-pending-list-corruption.patch [new file with mode: 0644]
queue-5.9/smb3-call-cifs-reconnect-from-demultiplex-thread.patch [new file with mode: 0644]
queue-5.9/smb3-handle-error-case-during-offload-read-path.patch [new file with mode: 0644]

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 (file)
index 0000000..2b33c7b
--- /dev/null
@@ -0,0 +1,52 @@
+From 98128572084c3dd8067f48bb588aa3733d1355b5 Mon Sep 17 00:00:00 2001
+From: Namjae Jeon <namjae.jeon@samsung.com>
+Date: Mon, 9 Nov 2020 17:35:33 +0900
+Subject: cifs: fix a memleak with modefromsid
+
+From: Namjae Jeon <namjae.jeon@samsung.com>
+
+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 <stable@vger.kernel.org> # v5.4+
+Signed-off-by: Namjae Jeon <namjae.jeon@samsung.com>
+Reviewed-by: Aurelien Aptel <aaptel@suse.com>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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 (file)
index 0000000..3fcda26
--- /dev/null
@@ -0,0 +1,123 @@
+From 073861ed77b6b957c3c8d54a11dc503f7d986ceb Mon Sep 17 00:00:00 2001
+From: Hugh Dickins <hughd@google.com>
+Date: Tue, 24 Nov 2020 08:46:43 -0800
+Subject: mm: fix VM_BUG_ON(PageTail) and BUG_ON(PageWriteback)
+
+From: Hugh Dickins <hughd@google.com>
+
+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 <cai@lca.pw>
+Fixes: 2a9127fcf229 ("mm: rewrite wait_on_page_bit_common() logic")
+Signed-off-by: Hugh Dickins <hughd@google.com>
+Cc: stable@vger.kernel.org # v5.8+
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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 (file)
index 0000000..062babe
--- /dev/null
@@ -0,0 +1,72 @@
+From 1179f170b6f0af7bb0b3b7628136eaac450ddf31 Mon Sep 17 00:00:00 2001
+From: Sven Schnelle <svens@linux.ibm.com>
+Date: Fri, 20 Nov 2020 14:17:52 +0100
+Subject: s390: fix fpu restore in entry.S
+
+From: Sven Schnelle <svens@linux.ibm.com>
+
+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: <stable@vger.kernel.org> # 5.8
+Fixes: 0b0ed657fe00 ("s390: remove critical section cleanup from entry.S")
+Reported-by: Pierre Morel <pmorel@linux.ibm.com>
+Signed-off-by: Sven Schnelle <svens@linux.ibm.com>
+Acked-by: Christian Borntraeger <borntraeger@de.ibm.com>
+Reviewed-by: Heiko Carstens <hca@linux.ibm.com>
+Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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)
index e61fd89de61528cfb368cb3b6c3b9dc57a9cce6c..bced0701f95edfe816ced33d8b6799e4ef74f3f9 100644 (file)
@@ -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 (file)
index 0000000..cf61c97
--- /dev/null
@@ -0,0 +1,160 @@
+From ac873aa3dc21707c47db5db6608b38981c731afe Mon Sep 17 00:00:00 2001
+From: Rohith Surabattula <rohiths@microsoft.com>
+Date: Thu, 29 Oct 2020 05:03:10 +0000
+Subject: smb3: Avoid Mid pending list corruption
+
+From: Rohith Surabattula <rohiths@microsoft.com>
+
+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 <rohiths@microsoft.com>
+Reviewed-by: Pavel Shilovsky <pshilov@microsoft.com>
+CC: Stable <stable@vger.kernel.org> #5.4+
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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 (file)
index 0000000..f990402
--- /dev/null
@@ -0,0 +1,101 @@
+From de9ac0a6e9efdffc8cde18781f48fb56ca4157b7 Mon Sep 17 00:00:00 2001
+From: Rohith Surabattula <rohiths@microsoft.com>
+Date: Wed, 28 Oct 2020 13:42:21 +0000
+Subject: smb3: Call cifs reconnect from demultiplex thread
+
+From: Rohith Surabattula <rohiths@microsoft.com>
+
+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 <rohiths@microsoft.com>
+Reviewed-by: Pavel Shilovsky <pshilov@microsoft.com>
+CC: Stable <stable@vger.kernel.org> #5.4+
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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 (file)
index 0000000..685fbfb
--- /dev/null
@@ -0,0 +1,56 @@
+From 1254100030b3377e8302f9c75090ab191d73ee7c Mon Sep 17 00:00:00 2001
+From: Rohith Surabattula <rohiths@microsoft.com>
+Date: Thu, 29 Oct 2020 06:07:56 +0000
+Subject: smb3: Handle error case during offload read path
+
+From: Rohith Surabattula <rohiths@microsoft.com>
+
+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 <rohiths@microsoft.com>
+Reviewed-by: Pavel Shilovsky <pshilov@microsoft.com>
+CC: Stable <stable@vger.kernel.org> #5.4+
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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);
+       }