Skip to content

Commit

Permalink
cifs: we can not use small padding iovs together with encryption
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Ronnie Sahlberg authored and Steve French committed Dec 31, 2018
1 parent 14e92c5 commit e77fe73
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 33 deletions.
16 changes: 7 additions & 9 deletions fs/cifs/smb2inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -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];
Expand Down Expand Up @@ -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) {
Expand All @@ -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:
Expand All @@ -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:
Expand All @@ -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:
Expand All @@ -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:
Expand All @@ -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:
Expand All @@ -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:
Expand Down Expand Up @@ -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:
Expand Down
67 changes: 46 additions & 21 deletions fs/cifs/smb2ops.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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 */
Expand All @@ -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]);


Expand Down Expand Up @@ -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));
Expand All @@ -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 */
Expand Down Expand Up @@ -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);
}
Expand All @@ -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];
Expand Down Expand Up @@ -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;
Expand All @@ -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));
Expand Down Expand Up @@ -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;
Expand Down
5 changes: 2 additions & 3 deletions fs/cifs/smb2proto.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

/*
Expand Down

0 comments on commit e77fe73

Please sign in to comment.