cifs: we can not use small padding iovs together with encryption
authorRonnie Sahlberg <lsahlber@redhat.com>
Mon, 31 Dec 2018 03:43:40 +0000 (13:43 +1000)
committerSteve French <stfrench@microsoft.com>
Mon, 31 Dec 2018 06:58:52 +0000 (00:58 -0600)
We can not append small padding buffers as separate iovs when encryption is
used. For this case we must flatten the request into a single buffer
containing both the data from all the iovs as well as the padding bytes.

This is at least needed for 4.20 as well due to compounding changes.

CC: Stable <stable@vger.kernel.org>
Signed-off-by: Ronnie Sahlberg <lsahlber@redhat.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
fs/cifs/smb2inode.c
fs/cifs/smb2ops.c
fs/cifs/smb2proto.h

index a8999f930b224ec6d6af2d74479270a43a000f56..f14533da3a9328d459073177e970974a6037f550 100644 (file)
@@ -49,7 +49,6 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
        struct cifs_open_parms oparms;
        struct cifs_fid fid;
        struct cifs_ses *ses = tcon->ses;
-       struct TCP_Server_Info *server = ses->server;
        int num_rqst = 0;
        struct smb_rqst rqst[3];
        int resp_buftype[3];
@@ -97,7 +96,7 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
        if (rc)
                goto finished;
 
-       smb2_set_next_command(server, &rqst[num_rqst++], 0);
+       smb2_set_next_command(tcon, &rqst[num_rqst++]);
 
        /* Operation */
        switch (command) {
@@ -111,7 +110,7 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
                                SMB2_O_INFO_FILE, 0,
                                sizeof(struct smb2_file_all_info) +
                                          PATH_MAX * 2, 0, NULL);
-               smb2_set_next_command(server, &rqst[num_rqst], 0);
+               smb2_set_next_command(tcon, &rqst[num_rqst]);
                smb2_set_related(&rqst[num_rqst++]);
                break;
        case SMB2_OP_DELETE:
@@ -134,7 +133,7 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
                                        COMPOUND_FID, current->tgid,
                                        FILE_DISPOSITION_INFORMATION,
                                        SMB2_O_INFO_FILE, 0, data, size);
-               smb2_set_next_command(server, &rqst[num_rqst], 1);
+               smb2_set_next_command(tcon, &rqst[num_rqst]);
                smb2_set_related(&rqst[num_rqst++]);
                break;
        case SMB2_OP_SET_EOF:
@@ -149,7 +148,7 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
                                        COMPOUND_FID, current->tgid,
                                        FILE_END_OF_FILE_INFORMATION,
                                        SMB2_O_INFO_FILE, 0, data, size);
-               smb2_set_next_command(server, &rqst[num_rqst], 0);
+               smb2_set_next_command(tcon, &rqst[num_rqst]);
                smb2_set_related(&rqst[num_rqst++]);
                break;
        case SMB2_OP_SET_INFO:
@@ -165,7 +164,7 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
                                        COMPOUND_FID, current->tgid,
                                        FILE_BASIC_INFORMATION,
                                        SMB2_O_INFO_FILE, 0, data, size);
-               smb2_set_next_command(server, &rqst[num_rqst], 0);
+               smb2_set_next_command(tcon, &rqst[num_rqst]);
                smb2_set_related(&rqst[num_rqst++]);
                break;
        case SMB2_OP_RENAME:
@@ -189,7 +188,7 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
                                        COMPOUND_FID, current->tgid,
                                        FILE_RENAME_INFORMATION,
                                        SMB2_O_INFO_FILE, 0, data, size);
-               smb2_set_next_command(server, &rqst[num_rqst], 0);
+               smb2_set_next_command(tcon, &rqst[num_rqst]);
                smb2_set_related(&rqst[num_rqst++]);
                break;
        case SMB2_OP_HARDLINK:
@@ -213,7 +212,7 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
                                        COMPOUND_FID, current->tgid,
                                        FILE_LINK_INFORMATION,
                                        SMB2_O_INFO_FILE, 0, data, size);
-               smb2_set_next_command(server, &rqst[num_rqst], 0);
+               smb2_set_next_command(tcon, &rqst[num_rqst]);
                smb2_set_related(&rqst[num_rqst++]);
                break;
        default:
@@ -388,7 +387,6 @@ smb2_set_path_attr(const unsigned int xid, struct cifs_tcon *tcon,
                rc = -ENOMEM;
                goto smb2_rename_path;
        }
-
        rc = smb2_compound_op(xid, tcon, cifs_sb, from_name, access,
                              FILE_OPEN, 0, smb2_to_name, command);
 smb2_rename_path:
index 6c99a146fcec7f6f510ab31775f4858dbc7ca213..33100ef74d7f1df2556094bd4e319d5e5a009b4e 100644 (file)
@@ -884,7 +884,6 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
            struct cifs_sb_info *cifs_sb)
 {
        struct cifs_ses *ses = tcon->ses;
-       struct TCP_Server_Info *server = ses->server;
        __le16 *utf16_path = NULL;
        int ea_name_len = strlen(ea_name);
        int flags = 0;
@@ -936,7 +935,7 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
        rc = SMB2_open_init(tcon, &rqst[0], &oplock, &oparms, utf16_path);
        if (rc)
                goto sea_exit;
-       smb2_set_next_command(ses->server, &rqst[0], 0);
+       smb2_set_next_command(tcon, &rqst[0]);
 
 
        /* Set Info */
@@ -963,7 +962,7 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
                                COMPOUND_FID, current->tgid,
                                FILE_FULL_EA_INFORMATION,
                                SMB2_O_INFO_FILE, 0, data, size);
-       smb2_set_next_command(server, &rqst[1], 0);
+       smb2_set_next_command(tcon, &rqst[1]);
        smb2_set_related(&rqst[1]);
 
 
@@ -1222,7 +1221,7 @@ smb2_ioctl_query_info(const unsigned int xid,
        rc = SMB2_open_init(tcon, &rqst[0], &oplock, &oparms, path);
        if (rc)
                goto iqinf_exit;
-       smb2_set_next_command(ses->server, &rqst[0], 0);
+       smb2_set_next_command(tcon, &rqst[0]);
 
        /* Query */
        memset(&qi_iov, 0, sizeof(qi_iov));
@@ -1236,7 +1235,7 @@ smb2_ioctl_query_info(const unsigned int xid,
                                  qi.output_buffer_length, buffer);
        if (rc)
                goto iqinf_exit;
-       smb2_set_next_command(ses->server, &rqst[1], 0);
+       smb2_set_next_command(tcon, &rqst[1]);
        smb2_set_related(&rqst[1]);
 
        /* Close */
@@ -1789,26 +1788,53 @@ smb2_set_related(struct smb_rqst *rqst)
 char smb2_padding[7] = {0, 0, 0, 0, 0, 0, 0};
 
 void
-smb2_set_next_command(struct TCP_Server_Info *server, struct smb_rqst *rqst,
-                     bool has_space_for_padding)
+smb2_set_next_command(struct cifs_tcon *tcon, struct smb_rqst *rqst)
 {
        struct smb2_sync_hdr *shdr;
+       struct cifs_ses *ses = tcon->ses;
+       struct TCP_Server_Info *server = ses->server;
        unsigned long len = smb_rqst_len(server, rqst);
+       int i, num_padding;
 
        /* SMB headers in a compound are 8 byte aligned. */
-       if (len & 7) {
-               if (has_space_for_padding) {
-                       len = rqst->rq_iov[rqst->rq_nvec - 1].iov_len;
-                       rqst->rq_iov[rqst->rq_nvec - 1].iov_len =
-                               (len + 7) & ~7;
-               } else {
-                       rqst->rq_iov[rqst->rq_nvec].iov_base = smb2_padding;
-                       rqst->rq_iov[rqst->rq_nvec].iov_len = 8 - (len & 7);
-                       rqst->rq_nvec++;
+
+       /* No padding needed */
+       if (!(len & 7))
+               goto finished;
+
+       num_padding = 8 - (len & 7);
+       if (!smb3_encryption_required(tcon)) {
+               /*
+                * If we do not have encryption then we can just add an extra
+                * iov for the padding.
+                */
+               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;
+       } else {
+               /*
+                * We can not add a small padding iov for the encryption case
+                * because the encryption framework can not handle the padding
+                * iovs.
+                * We have to flatten this into a single buffer and add
+                * the padding to it.
+                */
+               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;
                }
-               len = smb_rqst_len(server, rqst);
+               memset(rqst->rq_iov[0].iov_base + rqst->rq_iov[0].iov_len,
+                      0, num_padding);
+               rqst->rq_iov[0].iov_len += num_padding;
+               len += num_padding;
+               rqst->rq_nvec = 1;
        }
 
+ finished:
        shdr = (struct smb2_sync_hdr *)(rqst->rq_iov[0].iov_base);
        shdr->NextCommand = cpu_to_le32(len);
 }
@@ -1825,7 +1851,6 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon,
                         struct cifs_sb_info *cifs_sb)
 {
        struct cifs_ses *ses = tcon->ses;
-       struct TCP_Server_Info *server = ses->server;
        int flags = 0;
        struct smb_rqst rqst[3];
        int resp_buftype[3];
@@ -1862,7 +1887,7 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon,
        rc = SMB2_open_init(tcon, &rqst[0], &oplock, &oparms, utf16_path);
        if (rc)
                goto qic_exit;
-       smb2_set_next_command(server, &rqst[0], 0);
+       smb2_set_next_command(tcon, &rqst[0]);
 
        memset(&qi_iov, 0, sizeof(qi_iov));
        rqst[1].rq_iov = qi_iov;
@@ -1874,7 +1899,7 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon,
                                  NULL);
        if (rc)
                goto qic_exit;
-       smb2_set_next_command(server, &rqst[1], 0);
+       smb2_set_next_command(tcon, &rqst[1]);
        smb2_set_related(&rqst[1]);
 
        memset(&close_iov, 0, sizeof(close_iov));
@@ -2806,7 +2831,7 @@ init_sg(int num_rqst, struct smb_rqst *rqst, u8 *sign)
                        smb2_sg_set_buf(&sg[idx++],
                                        rqst[i].rq_iov[j].iov_base + skip,
                                        rqst[i].rq_iov[j].iov_len - skip);
-               }
+                       }
 
                for (j = 0; j < rqst[i].rq_npages; j++) {
                        unsigned int len, offset;
index 4029ee037ab4fd20d737b90e97cefea234cd7737..87733b27a65fef06c137e0782a04ab1151064ca6 100644 (file)
@@ -116,9 +116,8 @@ extern void smb2_reconnect_server(struct work_struct *work);
 extern int smb3_crypto_aead_allocate(struct TCP_Server_Info *server);
 extern unsigned long smb_rqst_len(struct TCP_Server_Info *server,
                                  struct smb_rqst *rqst);
-extern void smb2_set_next_command(struct TCP_Server_Info *server,
-                                 struct smb_rqst *rqst,
-                                 bool has_space_for_padding);
+extern void smb2_set_next_command(struct cifs_tcon *tcon,
+                                 struct smb_rqst *rqst);
 extern void smb2_set_related(struct smb_rqst *rqst);
 
 /*