Skip to content

Commit

Permalink
CIFS: Send RFC1001 length in a separate iov
Browse files Browse the repository at this point in the history
In order to simplify further encryption support we need to separate
RFC1001 length and SMB2 header when sending a request. Put the length
field in iov[0] and the rest of the packet into following iovs.

Signed-off-by: Pavel Shilovsky <pshilov@microsoft.com>
  • Loading branch information
Pavel Shilovsky authored and Steve French committed Feb 1, 2017
1 parent fb2036d commit 738f9de
Showing 6 changed files with 174 additions and 95 deletions.
38 changes: 22 additions & 16 deletions fs/cifs/cifsencrypt.c
Original file line number Diff line number Diff line change
@@ -75,24 +75,20 @@ int __cifs_calc_signature(struct smb_rqst *rqst,
struct kvec *iov = rqst->rq_iov;
int n_vec = rqst->rq_nvec;

for (i = 0; i < n_vec; i++) {
if (n_vec < 2 || iov[0].iov_len != 4)
return -EIO;

for (i = 1; i < n_vec; i++) {
if (iov[i].iov_len == 0)
continue;
if (iov[i].iov_base == NULL) {
cifs_dbg(VFS, "null iovec entry\n");
return -EIO;
}
/* The first entry includes a length field (which does not get
signed that occupies the first 4 bytes before the header */
if (i == 0) {
if (iov[0].iov_len <= 8) /* cmd field at offset 9 */
break; /* nothing to sign or corrupt header */
rc = crypto_shash_update(shash,
iov[i].iov_base + 4, iov[i].iov_len - 4);
} else {
rc = crypto_shash_update(shash,
iov[i].iov_base, iov[i].iov_len);
}
if (i == 1 && iov[1].iov_len <= 4)
break; /* nothing to sign or corrupt header */
rc = crypto_shash_update(shash,
iov[i].iov_base, iov[i].iov_len);
if (rc) {
cifs_dbg(VFS, "%s: Could not update with payload\n",
__func__);
@@ -168,6 +164,10 @@ int cifs_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server,
char smb_signature[20];
struct smb_hdr *cifs_pdu = (struct smb_hdr *)rqst->rq_iov[0].iov_base;

if (rqst->rq_iov[0].iov_len != 4 ||
rqst->rq_iov[0].iov_base + 4 != rqst->rq_iov[1].iov_base)
return -EIO;

if ((cifs_pdu == NULL) || (server == NULL))
return -EINVAL;

@@ -209,12 +209,14 @@ int cifs_sign_smbv(struct kvec *iov, int n_vec, struct TCP_Server_Info *server,
int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server,
__u32 *pexpected_response_sequence_number)
{
struct kvec iov;
struct kvec iov[2];

iov.iov_base = cifs_pdu;
iov.iov_len = be32_to_cpu(cifs_pdu->smb_buf_length) + 4;
iov[0].iov_base = cifs_pdu;
iov[0].iov_len = 4;
iov[1].iov_base = (char *)cifs_pdu + 4;
iov[1].iov_len = be32_to_cpu(cifs_pdu->smb_buf_length);

return cifs_sign_smbv(&iov, 1, server,
return cifs_sign_smbv(iov, 2, server,
pexpected_response_sequence_number);
}

@@ -227,6 +229,10 @@ int cifs_verify_signature(struct smb_rqst *rqst,
char what_we_think_sig_should_be[20];
struct smb_hdr *cifs_pdu = (struct smb_hdr *)rqst->rq_iov[0].iov_base;

if (rqst->rq_iov[0].iov_len != 4 ||
rqst->rq_iov[0].iov_base + 4 != rqst->rq_iov[1].iov_base)
return -EIO;

if (cifs_pdu == NULL || server == NULL)
return -EINVAL;

2 changes: 1 addition & 1 deletion fs/cifs/cifsglob.h
Original file line number Diff line number Diff line change
@@ -1119,7 +1119,7 @@ struct cifs_readdata {
int (*read_into_pages)(struct TCP_Server_Info *server,
struct cifs_readdata *rdata,
unsigned int len);
struct kvec iov;
struct kvec iov[2];
unsigned int pagesz;
unsigned int tailsz;
unsigned int credits;
51 changes: 30 additions & 21 deletions fs/cifs/cifssmb.c
Original file line number Diff line number Diff line change
@@ -708,9 +708,9 @@ CIFSSMBEcho(struct TCP_Server_Info *server)
{
ECHO_REQ *smb;
int rc = 0;
struct kvec iov;
struct smb_rqst rqst = { .rq_iov = &iov,
.rq_nvec = 1 };
struct kvec iov[2];
struct smb_rqst rqst = { .rq_iov = iov,
.rq_nvec = 2 };

cifs_dbg(FYI, "In echo request\n");

@@ -725,8 +725,11 @@ CIFSSMBEcho(struct TCP_Server_Info *server)
put_bcc(1, &smb->hdr);
smb->Data[0] = 'a';
inc_rfc1001_len(smb, 3);
iov.iov_base = smb;
iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;

iov[0].iov_len = 4;
iov[0].iov_base = smb;
iov[1].iov_len = get_rfc1002_length(smb);
iov[1].iov_base = (char *)smb + 4;

rc = cifs_call_async(server, &rqst, NULL, cifs_echo_callback,
server, CIFS_ASYNC_OP | CIFS_ECHO_OP);
@@ -1509,10 +1512,12 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
}

/* set up first iov for signature check */
rdata->iov.iov_base = buf;
rdata->iov.iov_len = server->total_read;
cifs_dbg(FYI, "0: iov_base=%p iov_len=%zu\n",
rdata->iov.iov_base, rdata->iov.iov_len);
rdata->iov[0].iov_base = buf;
rdata->iov[0].iov_len = 4;
rdata->iov[1].iov_base = buf + 4;
rdata->iov[1].iov_len = server->total_read - 4;
cifs_dbg(FYI, "0: iov_base=%p iov_len=%u\n",
rdata->iov[0].iov_base, server->total_read);

/* how much data is in the response? */
data_len = server->ops->read_data_length(buf);
@@ -1545,8 +1550,8 @@ cifs_readv_callback(struct mid_q_entry *mid)
struct cifs_readdata *rdata = mid->callback_data;
struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
struct TCP_Server_Info *server = tcon->ses->server;
struct smb_rqst rqst = { .rq_iov = &rdata->iov,
.rq_nvec = 1,
struct smb_rqst rqst = { .rq_iov = rdata->iov,
.rq_nvec = 2,
.rq_pages = rdata->pages,
.rq_npages = rdata->nr_pages,
.rq_pagesz = rdata->pagesz,
@@ -1601,8 +1606,8 @@ cifs_async_readv(struct cifs_readdata *rdata)
READ_REQ *smb = NULL;
int wct;
struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
struct smb_rqst rqst = { .rq_iov = &rdata->iov,
.rq_nvec = 1 };
struct smb_rqst rqst = { .rq_iov = rdata->iov,
.rq_nvec = 2 };

cifs_dbg(FYI, "%s: offset=%llu bytes=%u\n",
__func__, rdata->offset, rdata->bytes);
@@ -1642,8 +1647,10 @@ cifs_async_readv(struct cifs_readdata *rdata)
}

/* 4 for RFC1001 length + 1 for BCC */
rdata->iov.iov_base = smb;
rdata->iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
rdata->iov[0].iov_base = smb;
rdata->iov[0].iov_len = 4;
rdata->iov[1].iov_base = (char *)smb + 4;
rdata->iov[1].iov_len = get_rfc1002_length(smb);

kref_get(&rdata->refcount);
rc = cifs_call_async(tcon->ses->server, &rqst, cifs_readv_receive,
@@ -2096,7 +2103,7 @@ cifs_async_writev(struct cifs_writedata *wdata,
WRITE_REQ *smb = NULL;
int wct;
struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
struct kvec iov;
struct kvec iov[2];
struct smb_rqst rqst = { };

if (tcon->ses->capabilities & CAP_LARGE_FILES) {
@@ -2129,11 +2136,13 @@ cifs_async_writev(struct cifs_writedata *wdata,
cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);

/* 4 for RFC1001 length + 1 for BCC */
iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4 + 1;
iov.iov_base = smb;
iov[0].iov_len = 4;
iov[0].iov_base = smb;
iov[1].iov_len = get_rfc1002_length(smb) + 1;
iov[1].iov_base = (char *)smb + 4;

rqst.rq_iov = &iov;
rqst.rq_nvec = 1;
rqst.rq_iov = iov;
rqst.rq_nvec = 2;
rqst.rq_pages = wdata->pages;
rqst.rq_npages = wdata->nr_pages;
rqst.rq_pagesz = wdata->pagesz;
@@ -2154,7 +2163,7 @@ cifs_async_writev(struct cifs_writedata *wdata,
(struct smb_com_writex_req *)smb;
inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5);
put_bcc(wdata->bytes + 5, &smbw->hdr);
iov.iov_len += 4; /* pad bigger by four bytes */
iov[1].iov_len += 4; /* pad bigger by four bytes */
}

kref_get(&wdata->refcount);
64 changes: 39 additions & 25 deletions fs/cifs/smb2pdu.c
Original file line number Diff line number Diff line change
@@ -2047,9 +2047,9 @@ SMB2_echo(struct TCP_Server_Info *server)
{
struct smb2_echo_req *req;
int rc = 0;
struct kvec iov;
struct smb_rqst rqst = { .rq_iov = &iov,
.rq_nvec = 1 };
struct kvec iov[2];
struct smb_rqst rqst = { .rq_iov = iov,
.rq_nvec = 2 };

cifs_dbg(FYI, "In echo request\n");

@@ -2065,9 +2065,11 @@ SMB2_echo(struct TCP_Server_Info *server)

req->hdr.sync_hdr.CreditRequest = cpu_to_le16(1);

iov.iov_base = (char *)req;
/* 4 for rfc1002 length field */
iov.iov_len = get_rfc1002_length(req) + 4;
iov[0].iov_len = 4;
iov[0].iov_base = (char *)req;
iov[1].iov_len = get_rfc1002_length(req);
iov[1].iov_base = (char *)req + 4;

rc = cifs_call_async(server, &rqst, NULL, smb2_echo_callback, server,
CIFS_ECHO_OP);
@@ -2123,8 +2125,9 @@ SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
* have the end_of_chain boolean set to true.
*/
static int
smb2_new_read_req(struct kvec *iov, struct cifs_io_parms *io_parms,
unsigned int remaining_bytes, int request_type)
smb2_new_read_req(void **buf, unsigned int *total_len,
struct cifs_io_parms *io_parms, unsigned int remaining_bytes,
int request_type)
{
int rc = -EACCES;
struct smb2_read_req *req = NULL;
@@ -2172,9 +2175,9 @@ smb2_new_read_req(struct kvec *iov, struct cifs_io_parms *io_parms,
else
req->RemainingBytes = 0;

iov[0].iov_base = (char *)req;
*buf = req;
/* 4 for rfc1002 length field */
iov[0].iov_len = get_rfc1002_length(req) + 4;
*total_len = get_rfc1002_length(req) + 4;
return rc;
}

@@ -2184,10 +2187,11 @@ smb2_readv_callback(struct mid_q_entry *mid)
struct cifs_readdata *rdata = mid->callback_data;
struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
struct TCP_Server_Info *server = tcon->ses->server;
struct smb2_sync_hdr *shdr = get_sync_hdr(rdata->iov.iov_base);
struct smb2_sync_hdr *shdr =
(struct smb2_sync_hdr *)rdata->iov[1].iov_base;
unsigned int credits_received = 1;
struct smb_rqst rqst = { .rq_iov = &rdata->iov,
.rq_nvec = 1,
struct smb_rqst rqst = { .rq_iov = rdata->iov,
.rq_nvec = 2,
.rq_pages = rdata->pages,
.rq_npages = rdata->nr_pages,
.rq_pagesz = rdata->pagesz,
@@ -2238,17 +2242,18 @@ smb2_readv_callback(struct mid_q_entry *mid)
add_credits(server, credits_received, 0);
}

/* smb2_async_readv - send an async write, and set up mid to handle result */
/* smb2_async_readv - send an async read, and set up mid to handle result */
int
smb2_async_readv(struct cifs_readdata *rdata)
{
int rc, flags = 0;
char *buf;
struct smb2_sync_hdr *shdr;
struct cifs_io_parms io_parms;
struct smb_rqst rqst = { .rq_iov = &rdata->iov,
.rq_nvec = 1 };
struct smb_rqst rqst = { .rq_iov = rdata->iov,
.rq_nvec = 2 };
struct TCP_Server_Info *server;
unsigned int total_len;

cifs_dbg(FYI, "%s: offset=%llu bytes=%u\n",
__func__, rdata->offset, rdata->bytes);
@@ -2262,7 +2267,7 @@ smb2_async_readv(struct cifs_readdata *rdata)

server = io_parms.tcon->ses->server;

rc = smb2_new_read_req(&rdata->iov, &io_parms, 0, 0);
rc = smb2_new_read_req((void **) &buf, &total_len, &io_parms, 0, 0);
if (rc) {
if (rc == -EAGAIN && rdata->credits) {
/* credits was reset by reconnect */
@@ -2275,10 +2280,12 @@ smb2_async_readv(struct cifs_readdata *rdata)
return rc;
}

buf = rdata->iov.iov_base;
shdr = get_sync_hdr(buf);
/* 4 for rfc1002 length field */
rdata->iov.iov_len = get_rfc1002_length(rdata->iov.iov_base) + 4;
rdata->iov[0].iov_len = 4;
rdata->iov[0].iov_base = buf;
rdata->iov[1].iov_len = total_len - 4;
rdata->iov[1].iov_base = buf + 4;

if (rdata->credits) {
shdr->CreditCharge = cpu_to_le16(DIV_ROUND_UP(rdata->bytes,
@@ -2314,12 +2321,17 @@ SMB2_read(const unsigned int xid, struct cifs_io_parms *io_parms,
struct smb2_sync_hdr *shdr;
struct kvec iov[1];
struct kvec rsp_iov;
unsigned int total_len;
char *req;

*nbytes = 0;
rc = smb2_new_read_req(iov, io_parms, 0, 0);
rc = smb2_new_read_req((void **)&req, &total_len, io_parms, 0, 0);
if (rc)
return rc;

iov[0].iov_base = buf;
iov[0].iov_len = total_len;

rc = SendReceive2(xid, io_parms->tcon->ses, iov, 1,
&resp_buftype, CIFS_LOG_ERROR, &rsp_iov);
cifs_small_buf_release(iov[0].iov_base);
@@ -2424,8 +2436,8 @@ smb2_async_writev(struct cifs_writedata *wdata,
struct smb2_sync_hdr *shdr;
struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
struct TCP_Server_Info *server = tcon->ses->server;
struct kvec iov;
struct smb_rqst rqst;
struct kvec iov[2];
struct smb_rqst rqst = { };

rc = small_smb2_init(SMB2_WRITE, tcon, (void **) &req);
if (rc) {
@@ -2455,11 +2467,13 @@ smb2_async_writev(struct cifs_writedata *wdata,
req->RemainingBytes = 0;

/* 4 for rfc1002 length field and 1 for Buffer */
iov.iov_len = get_rfc1002_length(req) + 4 - 1;
iov.iov_base = req;
iov[0].iov_len = 4;
iov[0].iov_base = req;
iov[1].iov_len = get_rfc1002_length(req) - 1;
iov[1].iov_base = (char *)req + 4;

rqst.rq_iov = &iov;
rqst.rq_nvec = 1;
rqst.rq_iov = iov;
rqst.rq_nvec = 2;
rqst.rq_pages = wdata->pages;
rqst.rq_npages = wdata->nr_pages;
rqst.rq_pagesz = wdata->pagesz;
Loading

0 comments on commit 738f9de

Please sign in to comment.