--- /dev/null
+From 05946d4b7a7349ae58bfa2d51ae832e64a394c2d Mon Sep 17 00:00:00 2001
+From: Vincent Whitchurch <vincent.whitchurch@axis.com>
+Date: Wed, 10 Mar 2021 13:20:40 +0100
+Subject: cifs: Fix preauth hash corruption
+
+From: Vincent Whitchurch <vincent.whitchurch@axis.com>
+
+commit 05946d4b7a7349ae58bfa2d51ae832e64a394c2d upstream.
+
+smb311_update_preauth_hash() uses the shash in server->secmech without
+appropriate locking, and this can lead to sessions corrupting each
+other's preauth hashes.
+
+The following script can easily trigger the problem:
+
+ #!/bin/sh -e
+
+ NMOUNTS=10
+ for i in $(seq $NMOUNTS);
+ mkdir -p /tmp/mnt$i
+ umount /tmp/mnt$i 2>/dev/null || :
+ done
+ while :; do
+ for i in $(seq $NMOUNTS); do
+ mount -t cifs //192.168.0.1/test /tmp/mnt$i -o ... &
+ done
+ wait
+ for i in $(seq $NMOUNTS); do
+ umount /tmp/mnt$i
+ done
+ done
+
+Usually within seconds this leads to one or more of the mounts failing
+with the following errors, and a "Bad SMB2 signature for message" is
+seen in the server logs:
+
+ CIFS: VFS: \\192.168.0.1 failed to connect to IPC (rc=-13)
+ CIFS: VFS: cifs_mount failed w/return code = -13
+
+Fix it by holding the server mutex just like in the other places where
+the shashes are used.
+
+Fixes: 8bd68c6e47abff34e4 ("CIFS: implement v3.11 preauth integrity")
+Signed-off-by: Vincent Whitchurch <vincent.whitchurch@axis.com>
+CC: <stable@vger.kernel.org>
+Reviewed-by: Aurelien Aptel <aaptel@suse.com>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+[aaptel: backport to kernel without CIFS_SESS_OP]
+Signed-off-by: Aurelien Aptel <aaptel@suse.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/cifs/transport.c | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+--- a/fs/cifs/transport.c
++++ b/fs/cifs/transport.c
+@@ -1134,9 +1134,12 @@ compound_send_recv(const unsigned int xi
+ /*
+ * Compounding is never used during session establish.
+ */
+- if ((ses->status == CifsNew) || (optype & CIFS_NEG_OP))
++ if ((ses->status == CifsNew) || (optype & CIFS_NEG_OP)) {
++ mutex_lock(&server->srv_mutex);
+ smb311_update_preauth_hash(ses, rqst[0].rq_iov,
+ rqst[0].rq_nvec);
++ mutex_unlock(&server->srv_mutex);
++ }
+
+ for (i = 0; i < num_rqst; i++) {
+ rc = wait_for_response(server, midQ[i]);
+@@ -1204,7 +1207,9 @@ compound_send_recv(const unsigned int xi
+ .iov_base = resp_iov[0].iov_base,
+ .iov_len = resp_iov[0].iov_len
+ };
++ mutex_lock(&server->srv_mutex);
+ smb311_update_preauth_hash(ses, &iov, 1);
++ mutex_unlock(&server->srv_mutex);
+ }
+
+ out: