Commit e77fe73c authored by Ronnie Sahlberg's avatar Ronnie Sahlberg Committed by Steve French

cifs: we can not use small padding iovs together with encryption

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: default avatarRonnie Sahlberg <lsahlber@redhat.com>
Signed-off-by: default avatarSteve French <stfrench@microsoft.com>
parent 14e92c5d
...@@ -49,7 +49,6 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -49,7 +49,6 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
struct cifs_open_parms oparms; struct cifs_open_parms oparms;
struct cifs_fid fid; struct cifs_fid fid;
struct cifs_ses *ses = tcon->ses; struct cifs_ses *ses = tcon->ses;
struct TCP_Server_Info *server = ses->server;
int num_rqst = 0; int num_rqst = 0;
struct smb_rqst rqst[3]; struct smb_rqst rqst[3];
int resp_buftype[3]; int resp_buftype[3];
...@@ -97,7 +96,7 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -97,7 +96,7 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
if (rc) if (rc)
goto finished; goto finished;
smb2_set_next_command(server, &rqst[num_rqst++], 0); smb2_set_next_command(tcon, &rqst[num_rqst++]);
/* Operation */ /* Operation */
switch (command) { switch (command) {
...@@ -111,7 +110,7 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -111,7 +110,7 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
SMB2_O_INFO_FILE, 0, SMB2_O_INFO_FILE, 0,
sizeof(struct smb2_file_all_info) + sizeof(struct smb2_file_all_info) +
PATH_MAX * 2, 0, NULL); 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++]); smb2_set_related(&rqst[num_rqst++]);
break; break;
case SMB2_OP_DELETE: case SMB2_OP_DELETE:
...@@ -134,7 +133,7 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -134,7 +133,7 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
COMPOUND_FID, current->tgid, COMPOUND_FID, current->tgid,
FILE_DISPOSITION_INFORMATION, FILE_DISPOSITION_INFORMATION,
SMB2_O_INFO_FILE, 0, data, size); 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++]); smb2_set_related(&rqst[num_rqst++]);
break; break;
case SMB2_OP_SET_EOF: case SMB2_OP_SET_EOF:
...@@ -149,7 +148,7 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -149,7 +148,7 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
COMPOUND_FID, current->tgid, COMPOUND_FID, current->tgid,
FILE_END_OF_FILE_INFORMATION, FILE_END_OF_FILE_INFORMATION,
SMB2_O_INFO_FILE, 0, data, size); 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++]); smb2_set_related(&rqst[num_rqst++]);
break; break;
case SMB2_OP_SET_INFO: case SMB2_OP_SET_INFO:
...@@ -165,7 +164,7 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -165,7 +164,7 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
COMPOUND_FID, current->tgid, COMPOUND_FID, current->tgid,
FILE_BASIC_INFORMATION, FILE_BASIC_INFORMATION,
SMB2_O_INFO_FILE, 0, data, size); 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++]); smb2_set_related(&rqst[num_rqst++]);
break; break;
case SMB2_OP_RENAME: case SMB2_OP_RENAME:
...@@ -189,7 +188,7 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -189,7 +188,7 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
COMPOUND_FID, current->tgid, COMPOUND_FID, current->tgid,
FILE_RENAME_INFORMATION, FILE_RENAME_INFORMATION,
SMB2_O_INFO_FILE, 0, data, size); 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++]); smb2_set_related(&rqst[num_rqst++]);
break; break;
case SMB2_OP_HARDLINK: case SMB2_OP_HARDLINK:
...@@ -213,7 +212,7 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -213,7 +212,7 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
COMPOUND_FID, current->tgid, COMPOUND_FID, current->tgid,
FILE_LINK_INFORMATION, FILE_LINK_INFORMATION,
SMB2_O_INFO_FILE, 0, data, size); 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++]); smb2_set_related(&rqst[num_rqst++]);
break; break;
default: default:
...@@ -388,7 +387,6 @@ smb2_set_path_attr(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -388,7 +387,6 @@ smb2_set_path_attr(const unsigned int xid, struct cifs_tcon *tcon,
rc = -ENOMEM; rc = -ENOMEM;
goto smb2_rename_path; goto smb2_rename_path;
} }
rc = smb2_compound_op(xid, tcon, cifs_sb, from_name, access, rc = smb2_compound_op(xid, tcon, cifs_sb, from_name, access,
FILE_OPEN, 0, smb2_to_name, command); FILE_OPEN, 0, smb2_to_name, command);
smb2_rename_path: smb2_rename_path:
......
...@@ -884,7 +884,6 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -884,7 +884,6 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
struct cifs_sb_info *cifs_sb) struct cifs_sb_info *cifs_sb)
{ {
struct cifs_ses *ses = tcon->ses; struct cifs_ses *ses = tcon->ses;
struct TCP_Server_Info *server = ses->server;
__le16 *utf16_path = NULL; __le16 *utf16_path = NULL;
int ea_name_len = strlen(ea_name); int ea_name_len = strlen(ea_name);
int flags = 0; int flags = 0;
...@@ -936,7 +935,7 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -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); rc = SMB2_open_init(tcon, &rqst[0], &oplock, &oparms, utf16_path);
if (rc) if (rc)
goto sea_exit; goto sea_exit;
smb2_set_next_command(ses->server, &rqst[0], 0); smb2_set_next_command(tcon, &rqst[0]);
/* Set Info */ /* Set Info */
...@@ -963,7 +962,7 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -963,7 +962,7 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
COMPOUND_FID, current->tgid, COMPOUND_FID, current->tgid,
FILE_FULL_EA_INFORMATION, FILE_FULL_EA_INFORMATION,
SMB2_O_INFO_FILE, 0, data, size); 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]); smb2_set_related(&rqst[1]);
...@@ -1222,7 +1221,7 @@ smb2_ioctl_query_info(const unsigned int xid, ...@@ -1222,7 +1221,7 @@ smb2_ioctl_query_info(const unsigned int xid,
rc = SMB2_open_init(tcon, &rqst[0], &oplock, &oparms, path); rc = SMB2_open_init(tcon, &rqst[0], &oplock, &oparms, path);
if (rc) if (rc)
goto iqinf_exit; goto iqinf_exit;
smb2_set_next_command(ses->server, &rqst[0], 0); smb2_set_next_command(tcon, &rqst[0]);
/* Query */ /* Query */
memset(&qi_iov, 0, sizeof(qi_iov)); memset(&qi_iov, 0, sizeof(qi_iov));
...@@ -1236,7 +1235,7 @@ smb2_ioctl_query_info(const unsigned int xid, ...@@ -1236,7 +1235,7 @@ smb2_ioctl_query_info(const unsigned int xid,
qi.output_buffer_length, buffer); qi.output_buffer_length, buffer);
if (rc) if (rc)
goto iqinf_exit; goto iqinf_exit;
smb2_set_next_command(ses->server, &rqst[1], 0); smb2_set_next_command(tcon, &rqst[1]);
smb2_set_related(&rqst[1]); smb2_set_related(&rqst[1]);
/* Close */ /* Close */
...@@ -1789,26 +1788,53 @@ smb2_set_related(struct smb_rqst *rqst) ...@@ -1789,26 +1788,53 @@ smb2_set_related(struct smb_rqst *rqst)
char smb2_padding[7] = {0, 0, 0, 0, 0, 0, 0}; char smb2_padding[7] = {0, 0, 0, 0, 0, 0, 0};
void void
smb2_set_next_command(struct TCP_Server_Info *server, struct smb_rqst *rqst, smb2_set_next_command(struct cifs_tcon *tcon, struct smb_rqst *rqst)
bool has_space_for_padding)
{ {
struct smb2_sync_hdr *shdr; 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); unsigned long len = smb_rqst_len(server, rqst);
int i, num_padding;
/* SMB headers in a compound are 8 byte aligned. */ /* SMB headers in a compound are 8 byte aligned. */
if (len & 7) {
if (has_space_for_padding) { /* No padding needed */
len = rqst->rq_iov[rqst->rq_nvec - 1].iov_len; if (!(len & 7))
rqst->rq_iov[rqst->rq_nvec - 1].iov_len = goto finished;
(len + 7) & ~7;
} else { num_padding = 8 - (len & 7);
rqst->rq_iov[rqst->rq_nvec].iov_base = smb2_padding; if (!smb3_encryption_required(tcon)) {
rqst->rq_iov[rqst->rq_nvec].iov_len = 8 - (len & 7); /*
rqst->rq_nvec++; * 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 = (struct smb2_sync_hdr *)(rqst->rq_iov[0].iov_base);
shdr->NextCommand = cpu_to_le32(len); shdr->NextCommand = cpu_to_le32(len);
} }
...@@ -1825,7 +1851,6 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -1825,7 +1851,6 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon,
struct cifs_sb_info *cifs_sb) struct cifs_sb_info *cifs_sb)
{ {
struct cifs_ses *ses = tcon->ses; struct cifs_ses *ses = tcon->ses;
struct TCP_Server_Info *server = ses->server;
int flags = 0; int flags = 0;
struct smb_rqst rqst[3]; struct smb_rqst rqst[3];
int resp_buftype[3]; int resp_buftype[3];
...@@ -1862,7 +1887,7 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -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); rc = SMB2_open_init(tcon, &rqst[0], &oplock, &oparms, utf16_path);
if (rc) if (rc)
goto qic_exit; 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)); memset(&qi_iov, 0, sizeof(qi_iov));
rqst[1].rq_iov = qi_iov; rqst[1].rq_iov = qi_iov;
...@@ -1874,7 +1899,7 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -1874,7 +1899,7 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon,
NULL); NULL);
if (rc) if (rc)
goto qic_exit; goto qic_exit;
smb2_set_next_command(server, &rqst[1], 0); smb2_set_next_command(tcon, &rqst[1]);
smb2_set_related(&rqst[1]); smb2_set_related(&rqst[1]);
memset(&close_iov, 0, sizeof(close_iov)); memset(&close_iov, 0, sizeof(close_iov));
...@@ -2806,7 +2831,7 @@ init_sg(int num_rqst, struct smb_rqst *rqst, u8 *sign) ...@@ -2806,7 +2831,7 @@ init_sg(int num_rqst, struct smb_rqst *rqst, u8 *sign)
smb2_sg_set_buf(&sg[idx++], smb2_sg_set_buf(&sg[idx++],
rqst[i].rq_iov[j].iov_base + skip, rqst[i].rq_iov[j].iov_base + skip,
rqst[i].rq_iov[j].iov_len - skip); rqst[i].rq_iov[j].iov_len - skip);
} }
for (j = 0; j < rqst[i].rq_npages; j++) { for (j = 0; j < rqst[i].rq_npages; j++) {
unsigned int len, offset; unsigned int len, offset;
......
...@@ -116,9 +116,8 @@ extern void smb2_reconnect_server(struct work_struct *work); ...@@ -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 int smb3_crypto_aead_allocate(struct TCP_Server_Info *server);
extern unsigned long smb_rqst_len(struct TCP_Server_Info *server, extern unsigned long smb_rqst_len(struct TCP_Server_Info *server,
struct smb_rqst *rqst); struct smb_rqst *rqst);
extern void smb2_set_next_command(struct TCP_Server_Info *server, extern void smb2_set_next_command(struct cifs_tcon *tcon,
struct smb_rqst *rqst, struct smb_rqst *rqst);
bool has_space_for_padding);
extern void smb2_set_related(struct smb_rqst *rqst); extern void smb2_set_related(struct smb_rqst *rqst);
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment