smb: client: fix compound alignment with encryption
authorPaulo Alcantara <pc@manguebit.org>
Sun, 7 Sep 2025 00:19:29 +0000 (21:19 -0300)
committerSteve French <stfrench@microsoft.com>
Tue, 9 Sep 2025 22:30:11 +0000 (17:30 -0500)
The encryption layer can't handle the padding iovs, so flatten the
compound request into a single buffer with required padding to prevent
the server from dropping the connection when finding unaligned
compound requests.

Fixes: bc925c1216f0 ("smb: client: improve compound padding in encryption")
Signed-off-by: Paulo Alcantara (Red Hat) <pc@manguebit.org>
Reviewed-by: David Howells <dhowells@redhat.com>
Cc: linux-cifs@vger.kernel.org
Cc: stable@vger.kernel.org
Signed-off-by: Steve French <stfrench@microsoft.com>
fs/smb/client/smb2ops.c

index 94b1d7a395d50ad14d7d9792cc9fc9823b9aa64e..9f9955d274cf653116efe556a64fec6a3b31b87c 100644 (file)
@@ -2640,13 +2640,35 @@ smb2_set_next_command(struct cifs_tcon *tcon, struct smb_rqst *rqst)
        }
 
        /* SMB headers in a compound are 8 byte aligned. */
-       if (!IS_ALIGNED(len, 8)) {
-               num_padding = 8 - (len & 7);
+       if (IS_ALIGNED(len, 8))
+               goto out;
+
+       num_padding = 8 - (len & 7);
+       if (smb3_encryption_required(tcon)) {
+               int i;
+
+               /*
+                * Flatten request into a single buffer with required padding as
+                * the encryption layer can't handle the padding iovs.
+                */
+               for (i = 1; i < rqst->rq_nvec; i++) {
+                       memcpy(rqst->rq_iov[0].iov_base +
+                              rqst->rq_iov[0].iov_len,
+                              rqst->rq_iov[i].iov_base,
+                              rqst->rq_iov[i].iov_len);
+                       rqst->rq_iov[0].iov_len += rqst->rq_iov[i].iov_len;
+               }
+               memset(rqst->rq_iov[0].iov_base + rqst->rq_iov[0].iov_len,
+                      0, num_padding);
+               rqst->rq_iov[0].iov_len += num_padding;
+               rqst->rq_nvec = 1;
+       } else {
                rqst->rq_iov[rqst->rq_nvec].iov_base = smb2_padding;
                rqst->rq_iov[rqst->rq_nvec].iov_len = num_padding;
                rqst->rq_nvec++;
-               len += num_padding;
        }
+       len += num_padding;
+out:
        shdr->NextCommand = cpu_to_le32(len);
 }