Commit b2d44d14 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag '4.18-rc3-smb3fixes' of git://git.samba.org/sfrench/cifs-2.6

Pull cifs fixes from Steve French:
 "Five smb3/cifs fixes for stable (including for some leaks and memory
  overwrites) and also a few fixes for recent regressions in packet
  signing.

  Additional testing at the recent SMB3 test event, and some good work
  by Paulo and others spotted the issues fixed here. In addition to my
  xfstest runs on these, Aurelien and Stefano did additional test runs
  to verify this set"

* tag '4.18-rc3-smb3fixes' of git://git.samba.org/sfrench/cifs-2.6:
  cifs: Fix stack out-of-bounds in smb{2,3}_create_lease_buf()
  cifs: Fix infinite loop when using hard mount option
  cifs: Fix slab-out-of-bounds in send_set_info() on SMB2 ACE setting
  cifs: Fix memory leak in smb2_set_ea()
  cifs: fix SMB1 breakage
  cifs: Fix validation of signed data in smb2
  cifs: Fix validation of signed data in smb3+
  cifs: Fix use after free of a mid_q_entry
parents 4f572efd 729c0c9d
...@@ -423,7 +423,7 @@ struct smb_version_operations { ...@@ -423,7 +423,7 @@ struct smb_version_operations {
void (*set_oplock_level)(struct cifsInodeInfo *, __u32, unsigned int, void (*set_oplock_level)(struct cifsInodeInfo *, __u32, unsigned int,
bool *); bool *);
/* create lease context buffer for CREATE request */ /* create lease context buffer for CREATE request */
char * (*create_lease_buf)(u8 *, u8); char * (*create_lease_buf)(u8 *lease_key, u8 oplock);
/* parse lease context buffer and return oplock/epoch info */ /* parse lease context buffer and return oplock/epoch info */
__u8 (*parse_lease_buf)(void *buf, unsigned int *epoch, char *lkey); __u8 (*parse_lease_buf)(void *buf, unsigned int *epoch, char *lkey);
ssize_t (*copychunk_range)(const unsigned int, ssize_t (*copychunk_range)(const unsigned int,
...@@ -1416,6 +1416,7 @@ typedef int (mid_handle_t)(struct TCP_Server_Info *server, ...@@ -1416,6 +1416,7 @@ typedef int (mid_handle_t)(struct TCP_Server_Info *server,
/* one of these for every pending CIFS request to the server */ /* one of these for every pending CIFS request to the server */
struct mid_q_entry { struct mid_q_entry {
struct list_head qhead; /* mids waiting on reply from this server */ struct list_head qhead; /* mids waiting on reply from this server */
struct kref refcount;
struct TCP_Server_Info *server; /* server corresponding to this mid */ struct TCP_Server_Info *server; /* server corresponding to this mid */
__u64 mid; /* multiplex id */ __u64 mid; /* multiplex id */
__u32 pid; /* process id */ __u32 pid; /* process id */
......
...@@ -82,6 +82,7 @@ extern struct mid_q_entry *AllocMidQEntry(const struct smb_hdr *smb_buffer, ...@@ -82,6 +82,7 @@ extern struct mid_q_entry *AllocMidQEntry(const struct smb_hdr *smb_buffer,
struct TCP_Server_Info *server); struct TCP_Server_Info *server);
extern void DeleteMidQEntry(struct mid_q_entry *midEntry); extern void DeleteMidQEntry(struct mid_q_entry *midEntry);
extern void cifs_delete_mid(struct mid_q_entry *mid); extern void cifs_delete_mid(struct mid_q_entry *mid);
extern void cifs_mid_q_entry_release(struct mid_q_entry *midEntry);
extern void cifs_wake_up_task(struct mid_q_entry *mid); extern void cifs_wake_up_task(struct mid_q_entry *mid);
extern int cifs_handle_standard(struct TCP_Server_Info *server, extern int cifs_handle_standard(struct TCP_Server_Info *server,
struct mid_q_entry *mid); struct mid_q_entry *mid);
......
...@@ -157,8 +157,14 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command) ...@@ -157,8 +157,14 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
* greater than cifs socket timeout which is 7 seconds * greater than cifs socket timeout which is 7 seconds
*/ */
while (server->tcpStatus == CifsNeedReconnect) { while (server->tcpStatus == CifsNeedReconnect) {
wait_event_interruptible_timeout(server->response_q, rc = wait_event_interruptible_timeout(server->response_q,
(server->tcpStatus != CifsNeedReconnect), 10 * HZ); (server->tcpStatus != CifsNeedReconnect),
10 * HZ);
if (rc < 0) {
cifs_dbg(FYI, "%s: aborting reconnect due to a received"
" signal by the process\n", __func__);
return -ERESTARTSYS;
}
/* are we still trying to reconnect? */ /* are we still trying to reconnect? */
if (server->tcpStatus != CifsNeedReconnect) if (server->tcpStatus != CifsNeedReconnect)
......
...@@ -924,6 +924,7 @@ cifs_demultiplex_thread(void *p) ...@@ -924,6 +924,7 @@ cifs_demultiplex_thread(void *p)
server->pdu_size = next_offset; server->pdu_size = next_offset;
} }
mid_entry = NULL;
if (server->ops->is_transform_hdr && if (server->ops->is_transform_hdr &&
server->ops->receive_transform && server->ops->receive_transform &&
server->ops->is_transform_hdr(buf)) { server->ops->is_transform_hdr(buf)) {
...@@ -938,8 +939,11 @@ cifs_demultiplex_thread(void *p) ...@@ -938,8 +939,11 @@ cifs_demultiplex_thread(void *p)
length = mid_entry->receive(server, mid_entry); length = mid_entry->receive(server, mid_entry);
} }
if (length < 0) if (length < 0) {
if (mid_entry)
cifs_mid_q_entry_release(mid_entry);
continue; continue;
}
if (server->large_buf) if (server->large_buf)
buf = server->bigbuf; buf = server->bigbuf;
...@@ -956,6 +960,8 @@ cifs_demultiplex_thread(void *p) ...@@ -956,6 +960,8 @@ cifs_demultiplex_thread(void *p)
if (!mid_entry->multiRsp || mid_entry->multiEnd) if (!mid_entry->multiRsp || mid_entry->multiEnd)
mid_entry->callback(mid_entry); mid_entry->callback(mid_entry);
cifs_mid_q_entry_release(mid_entry);
} else if (server->ops->is_oplock_break && } else if (server->ops->is_oplock_break &&
server->ops->is_oplock_break(buf, server)) { server->ops->is_oplock_break(buf, server)) {
cifs_dbg(FYI, "Received oplock break\n"); cifs_dbg(FYI, "Received oplock break\n");
......
...@@ -107,6 +107,7 @@ cifs_find_mid(struct TCP_Server_Info *server, char *buffer) ...@@ -107,6 +107,7 @@ cifs_find_mid(struct TCP_Server_Info *server, char *buffer)
if (compare_mid(mid->mid, buf) && if (compare_mid(mid->mid, buf) &&
mid->mid_state == MID_REQUEST_SUBMITTED && mid->mid_state == MID_REQUEST_SUBMITTED &&
le16_to_cpu(mid->command) == buf->Command) { le16_to_cpu(mid->command) == buf->Command) {
kref_get(&mid->refcount);
spin_unlock(&GlobalMid_Lock); spin_unlock(&GlobalMid_Lock);
return mid; return mid;
} }
......
...@@ -41,7 +41,7 @@ smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms, ...@@ -41,7 +41,7 @@ smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms,
int rc; int rc;
__le16 *smb2_path; __le16 *smb2_path;
struct smb2_file_all_info *smb2_data = NULL; struct smb2_file_all_info *smb2_data = NULL;
__u8 smb2_oplock[17]; __u8 smb2_oplock;
struct cifs_fid *fid = oparms->fid; struct cifs_fid *fid = oparms->fid;
struct network_resiliency_req nr_ioctl_req; struct network_resiliency_req nr_ioctl_req;
...@@ -59,12 +59,9 @@ smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms, ...@@ -59,12 +59,9 @@ smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms,
} }
oparms->desired_access |= FILE_READ_ATTRIBUTES; oparms->desired_access |= FILE_READ_ATTRIBUTES;
*smb2_oplock = SMB2_OPLOCK_LEVEL_BATCH; smb2_oplock = SMB2_OPLOCK_LEVEL_BATCH;
if (oparms->tcon->ses->server->capabilities & SMB2_GLOBAL_CAP_LEASING) rc = SMB2_open(xid, oparms, smb2_path, &smb2_oplock, smb2_data, NULL,
memcpy(smb2_oplock + 1, fid->lease_key, SMB2_LEASE_KEY_SIZE);
rc = SMB2_open(xid, oparms, smb2_path, smb2_oplock, smb2_data, NULL,
NULL); NULL);
if (rc) if (rc)
goto out; goto out;
...@@ -101,7 +98,7 @@ smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms, ...@@ -101,7 +98,7 @@ smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms,
move_smb2_info_to_cifs(buf, smb2_data); move_smb2_info_to_cifs(buf, smb2_data);
} }
*oplock = *smb2_oplock; *oplock = smb2_oplock;
out: out:
kfree(smb2_data); kfree(smb2_data);
kfree(smb2_path); kfree(smb2_path);
......
...@@ -203,6 +203,7 @@ smb2_find_mid(struct TCP_Server_Info *server, char *buf) ...@@ -203,6 +203,7 @@ smb2_find_mid(struct TCP_Server_Info *server, char *buf)
if ((mid->mid == wire_mid) && if ((mid->mid == wire_mid) &&
(mid->mid_state == MID_REQUEST_SUBMITTED) && (mid->mid_state == MID_REQUEST_SUBMITTED) &&
(mid->command == shdr->Command)) { (mid->command == shdr->Command)) {
kref_get(&mid->refcount);
spin_unlock(&GlobalMid_Lock); spin_unlock(&GlobalMid_Lock);
return mid; return mid;
} }
...@@ -855,6 +856,8 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -855,6 +856,8 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
rc = SMB2_set_ea(xid, tcon, fid.persistent_fid, fid.volatile_fid, ea, rc = SMB2_set_ea(xid, tcon, fid.persistent_fid, fid.volatile_fid, ea,
len); len);
kfree(ea);
SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid); SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
return rc; return rc;
...@@ -2219,8 +2222,7 @@ smb2_create_lease_buf(u8 *lease_key, u8 oplock) ...@@ -2219,8 +2222,7 @@ smb2_create_lease_buf(u8 *lease_key, u8 oplock)
if (!buf) if (!buf)
return NULL; return NULL;
buf->lcontext.LeaseKeyLow = cpu_to_le64(*((u64 *)lease_key)); memcpy(&buf->lcontext.LeaseKey, lease_key, SMB2_LEASE_KEY_SIZE);
buf->lcontext.LeaseKeyHigh = cpu_to_le64(*((u64 *)(lease_key + 8)));
buf->lcontext.LeaseState = map_oplock_to_lease(oplock); buf->lcontext.LeaseState = map_oplock_to_lease(oplock);
buf->ccontext.DataOffset = cpu_to_le16(offsetof buf->ccontext.DataOffset = cpu_to_le16(offsetof
...@@ -2246,8 +2248,7 @@ smb3_create_lease_buf(u8 *lease_key, u8 oplock) ...@@ -2246,8 +2248,7 @@ smb3_create_lease_buf(u8 *lease_key, u8 oplock)
if (!buf) if (!buf)
return NULL; return NULL;
buf->lcontext.LeaseKeyLow = cpu_to_le64(*((u64 *)lease_key)); memcpy(&buf->lcontext.LeaseKey, lease_key, SMB2_LEASE_KEY_SIZE);
buf->lcontext.LeaseKeyHigh = cpu_to_le64(*((u64 *)(lease_key + 8)));
buf->lcontext.LeaseState = map_oplock_to_lease(oplock); buf->lcontext.LeaseState = map_oplock_to_lease(oplock);
buf->ccontext.DataOffset = cpu_to_le16(offsetof buf->ccontext.DataOffset = cpu_to_le16(offsetof
...@@ -2284,8 +2285,7 @@ smb3_parse_lease_buf(void *buf, unsigned int *epoch, char *lease_key) ...@@ -2284,8 +2285,7 @@ smb3_parse_lease_buf(void *buf, unsigned int *epoch, char *lease_key)
if (lc->lcontext.LeaseFlags & SMB2_LEASE_FLAG_BREAK_IN_PROGRESS) if (lc->lcontext.LeaseFlags & SMB2_LEASE_FLAG_BREAK_IN_PROGRESS)
return SMB2_OPLOCK_LEVEL_NOCHANGE; return SMB2_OPLOCK_LEVEL_NOCHANGE;
if (lease_key) if (lease_key)
memcpy(lease_key, &lc->lcontext.LeaseKeyLow, memcpy(lease_key, &lc->lcontext.LeaseKey, SMB2_LEASE_KEY_SIZE);
SMB2_LEASE_KEY_SIZE);
return le32_to_cpu(lc->lcontext.LeaseState); return le32_to_cpu(lc->lcontext.LeaseState);
} }
...@@ -2521,7 +2521,7 @@ smb3_init_transform_rq(struct TCP_Server_Info *server, struct smb_rqst *new_rq, ...@@ -2521,7 +2521,7 @@ smb3_init_transform_rq(struct TCP_Server_Info *server, struct smb_rqst *new_rq,
if (!tr_hdr) if (!tr_hdr)
goto err_free_iov; goto err_free_iov;
orig_len = smb2_rqst_len(old_rq, false); orig_len = smb_rqst_len(server, old_rq);
/* fill the 2nd iov with a transform header */ /* fill the 2nd iov with a transform header */
fill_transform_hdr(tr_hdr, orig_len, old_rq); fill_transform_hdr(tr_hdr, orig_len, old_rq);
......
...@@ -155,7 +155,7 @@ smb2_hdr_assemble(struct smb2_sync_hdr *shdr, __le16 smb2_cmd, ...@@ -155,7 +155,7 @@ smb2_hdr_assemble(struct smb2_sync_hdr *shdr, __le16 smb2_cmd,
static int static int
smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon) smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon)
{ {
int rc = 0; int rc;
struct nls_table *nls_codepage; struct nls_table *nls_codepage;
struct cifs_ses *ses; struct cifs_ses *ses;
struct TCP_Server_Info *server; struct TCP_Server_Info *server;
...@@ -166,10 +166,10 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon) ...@@ -166,10 +166,10 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon)
* for those three - in the calling routine. * for those three - in the calling routine.
*/ */
if (tcon == NULL) if (tcon == NULL)
return rc; return 0;
if (smb2_command == SMB2_TREE_CONNECT) if (smb2_command == SMB2_TREE_CONNECT)
return rc; return 0;
if (tcon->tidStatus == CifsExiting) { if (tcon->tidStatus == CifsExiting) {
/* /*
...@@ -212,8 +212,14 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon) ...@@ -212,8 +212,14 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon)
return -EAGAIN; return -EAGAIN;
} }
wait_event_interruptible_timeout(server->response_q, rc = wait_event_interruptible_timeout(server->response_q,
(server->tcpStatus != CifsNeedReconnect), 10 * HZ); (server->tcpStatus != CifsNeedReconnect),
10 * HZ);
if (rc < 0) {
cifs_dbg(FYI, "%s: aborting reconnect due to a received"
" signal by the process\n", __func__);
return -ERESTARTSYS;
}
/* are we still trying to reconnect? */ /* are we still trying to reconnect? */
if (server->tcpStatus != CifsNeedReconnect) if (server->tcpStatus != CifsNeedReconnect)
...@@ -231,7 +237,7 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon) ...@@ -231,7 +237,7 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon)
} }
if (!tcon->ses->need_reconnect && !tcon->need_reconnect) if (!tcon->ses->need_reconnect && !tcon->need_reconnect)
return rc; return 0;
nls_codepage = load_nls_default(); nls_codepage = load_nls_default();
...@@ -340,7 +346,10 @@ smb2_plain_req_init(__le16 smb2_command, struct cifs_tcon *tcon, ...@@ -340,7 +346,10 @@ smb2_plain_req_init(__le16 smb2_command, struct cifs_tcon *tcon,
return rc; return rc;
/* BB eventually switch this to SMB2 specific small buf size */ /* BB eventually switch this to SMB2 specific small buf size */
*request_buf = cifs_small_buf_get(); if (smb2_command == SMB2_SET_INFO)
*request_buf = cifs_buf_get();
else
*request_buf = cifs_small_buf_get();
if (*request_buf == NULL) { if (*request_buf == NULL) {
/* BB should we add a retry in here if not a writepage? */ /* BB should we add a retry in here if not a writepage? */
return -ENOMEM; return -ENOMEM;
...@@ -1707,12 +1716,12 @@ parse_lease_state(struct TCP_Server_Info *server, struct smb2_create_rsp *rsp, ...@@ -1707,12 +1716,12 @@ parse_lease_state(struct TCP_Server_Info *server, struct smb2_create_rsp *rsp,
static int static int
add_lease_context(struct TCP_Server_Info *server, struct kvec *iov, add_lease_context(struct TCP_Server_Info *server, struct kvec *iov,
unsigned int *num_iovec, __u8 *oplock) unsigned int *num_iovec, u8 *lease_key, __u8 *oplock)
{ {
struct smb2_create_req *req = iov[0].iov_base; struct smb2_create_req *req = iov[0].iov_base;
unsigned int num = *num_iovec; unsigned int num = *num_iovec;
iov[num].iov_base = server->ops->create_lease_buf(oplock+1, *oplock); iov[num].iov_base = server->ops->create_lease_buf(lease_key, *oplock);
if (iov[num].iov_base == NULL) if (iov[num].iov_base == NULL)
return -ENOMEM; return -ENOMEM;
iov[num].iov_len = server->vals->create_lease_size; iov[num].iov_len = server->vals->create_lease_size;
...@@ -2172,7 +2181,8 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, ...@@ -2172,7 +2181,8 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
*oplock == SMB2_OPLOCK_LEVEL_NONE) *oplock == SMB2_OPLOCK_LEVEL_NONE)
req->RequestedOplockLevel = *oplock; req->RequestedOplockLevel = *oplock;
else { else {
rc = add_lease_context(server, iov, &n_iov, oplock); rc = add_lease_context(server, iov, &n_iov,
oparms->fid->lease_key, oplock);
if (rc) { if (rc) {
cifs_small_buf_release(req); cifs_small_buf_release(req);
kfree(copy_path); kfree(copy_path);
...@@ -3720,7 +3730,7 @@ send_set_info(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -3720,7 +3730,7 @@ send_set_info(const unsigned int xid, struct cifs_tcon *tcon,
rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags,
&rsp_iov); &rsp_iov);
cifs_small_buf_release(req); cifs_buf_release(req);
rsp = (struct smb2_set_info_rsp *)rsp_iov.iov_base; rsp = (struct smb2_set_info_rsp *)rsp_iov.iov_base;
if (rc != 0) { if (rc != 0) {
......
...@@ -678,16 +678,14 @@ struct create_context { ...@@ -678,16 +678,14 @@ struct create_context {
#define SMB2_LEASE_KEY_SIZE 16 #define SMB2_LEASE_KEY_SIZE 16
struct lease_context { struct lease_context {
__le64 LeaseKeyLow; u8 LeaseKey[SMB2_LEASE_KEY_SIZE];
__le64 LeaseKeyHigh;
__le32 LeaseState; __le32 LeaseState;
__le32 LeaseFlags; __le32 LeaseFlags;
__le64 LeaseDuration; __le64 LeaseDuration;
} __packed; } __packed;
struct lease_context_v2 { struct lease_context_v2 {
__le64 LeaseKeyLow; u8 LeaseKey[SMB2_LEASE_KEY_SIZE];
__le64 LeaseKeyHigh;
__le32 LeaseState; __le32 LeaseState;
__le32 LeaseFlags; __le32 LeaseFlags;
__le64 LeaseDuration; __le64 LeaseDuration;
......
...@@ -113,8 +113,8 @@ extern int smb2_unlock_range(struct cifsFileInfo *cfile, ...@@ -113,8 +113,8 @@ extern int smb2_unlock_range(struct cifsFileInfo *cfile,
extern int smb2_push_mandatory_locks(struct cifsFileInfo *cfile); extern int smb2_push_mandatory_locks(struct cifsFileInfo *cfile);
extern void smb2_reconnect_server(struct work_struct *work); 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 extern unsigned long smb_rqst_len(struct TCP_Server_Info *server,
smb2_rqst_len(struct smb_rqst *rqst, bool skip_rfc1002_marker); struct smb_rqst *rqst);
/* /*
* SMB2 Worker functions - most of protocol specific implementation details * SMB2 Worker functions - most of protocol specific implementation details
......
...@@ -173,6 +173,8 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) ...@@ -173,6 +173,8 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
struct kvec *iov = rqst->rq_iov; struct kvec *iov = rqst->rq_iov;
struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)iov[0].iov_base; struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)iov[0].iov_base;
struct cifs_ses *ses; struct cifs_ses *ses;
struct shash_desc *shash = &server->secmech.sdeschmacsha256->shash;
struct smb_rqst drqst;
ses = smb2_find_smb_ses(server, shdr->SessionId); ses = smb2_find_smb_ses(server, shdr->SessionId);
if (!ses) { if (!ses) {
...@@ -190,21 +192,39 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) ...@@ -190,21 +192,39 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
} }
rc = crypto_shash_setkey(server->secmech.hmacsha256, rc = crypto_shash_setkey(server->secmech.hmacsha256,
ses->auth_key.response, SMB2_NTLMV2_SESSKEY_SIZE); ses->auth_key.response, SMB2_NTLMV2_SESSKEY_SIZE);
if (rc) { if (rc) {
cifs_dbg(VFS, "%s: Could not update with response\n", __func__); cifs_dbg(VFS, "%s: Could not update with response\n", __func__);
return rc; return rc;
} }
rc = crypto_shash_init(&server->secmech.sdeschmacsha256->shash); rc = crypto_shash_init(shash);
if (rc) { if (rc) {
cifs_dbg(VFS, "%s: Could not init sha256", __func__); cifs_dbg(VFS, "%s: Could not init sha256", __func__);
return rc; return rc;
} }
rc = __cifs_calc_signature(rqst, server, sigptr, /*
&server->secmech.sdeschmacsha256->shash); * For SMB2+, __cifs_calc_signature() expects to sign only the actual
* data, that is, iov[0] should not contain a rfc1002 length.
*
* Sign the rfc1002 length prior to passing the data (iov[1-N]) down to
* __cifs_calc_signature().
*/
drqst = *rqst;
if (drqst.rq_nvec >= 2 && iov[0].iov_len == 4) {
rc = crypto_shash_update(shash, iov[0].iov_base,
iov[0].iov_len);
if (rc) {
cifs_dbg(VFS, "%s: Could not update with payload\n",
__func__);
return rc;
}
drqst.rq_iov++;
drqst.rq_nvec--;
}
rc = __cifs_calc_signature(&drqst, server, sigptr, shash);
if (!rc) if (!rc)
memcpy(shdr->Signature, sigptr, SMB2_SIGNATURE_SIZE); memcpy(shdr->Signature, sigptr, SMB2_SIGNATURE_SIZE);
...@@ -408,12 +428,14 @@ generate_smb311signingkey(struct cifs_ses *ses) ...@@ -408,12 +428,14 @@ generate_smb311signingkey(struct cifs_ses *ses)
int int
smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
{ {
int rc = 0; int rc;
unsigned char smb3_signature[SMB2_CMACAES_SIZE]; unsigned char smb3_signature[SMB2_CMACAES_SIZE];
unsigned char *sigptr = smb3_signature; unsigned char *sigptr = smb3_signature;
struct kvec *iov = rqst->rq_iov; struct kvec *iov = rqst->rq_iov;
struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)iov[0].iov_base; struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)iov[0].iov_base;
struct cifs_ses *ses; struct cifs_ses *ses;
struct shash_desc *shash = &server->secmech.sdesccmacaes->shash;
struct smb_rqst drqst;
ses = smb2_find_smb_ses(server, shdr->SessionId); ses = smb2_find_smb_ses(server, shdr->SessionId);
if (!ses) { if (!ses) {
...@@ -425,8 +447,7 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) ...@@ -425,8 +447,7 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
memset(shdr->Signature, 0x0, SMB2_SIGNATURE_SIZE); memset(shdr->Signature, 0x0, SMB2_SIGNATURE_SIZE);
rc = crypto_shash_setkey(server->secmech.cmacaes, rc = crypto_shash_setkey(server->secmech.cmacaes,
ses->smb3signingkey, SMB2_CMACAES_SIZE); ses->smb3signingkey, SMB2_CMACAES_SIZE);
if (rc) { if (rc) {
cifs_dbg(VFS, "%s: Could not set key for cmac aes\n", __func__); cifs_dbg(VFS, "%s: Could not set key for cmac aes\n", __func__);
return rc; return rc;
...@@ -437,15 +458,33 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) ...@@ -437,15 +458,33 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
* so unlike smb2 case we do not have to check here if secmech are * so unlike smb2 case we do not have to check here if secmech are
* initialized * initialized
*/ */
rc = crypto_shash_init(&server->secmech.sdesccmacaes->shash); rc = crypto_shash_init(shash);
if (rc) { if (rc) {
cifs_dbg(VFS, "%s: Could not init cmac aes\n", __func__); cifs_dbg(VFS, "%s: Could not init cmac aes\n", __func__);
return rc; return rc;
} }
rc = __cifs_calc_signature(rqst, server, sigptr, /*
&server->secmech.sdesccmacaes->shash); * For SMB2+, __cifs_calc_signature() expects to sign only the actual
* data, that is, iov[0] should not contain a rfc1002 length.
*
* Sign the rfc1002 length prior to passing the data (iov[1-N]) down to
* __cifs_calc_signature().
*/
drqst = *rqst;
if (drqst.rq_nvec >= 2 && iov[0].iov_len == 4) {
rc = crypto_shash_update(shash, iov[0].iov_base,
iov[0].iov_len);
if (rc) {
cifs_dbg(VFS, "%s: Could not update with payload\n",
__func__);
return rc;
}
drqst.rq_iov++;
drqst.rq_nvec--;
}
rc = __cifs_calc_signature(&drqst, server, sigptr, shash);
if (!rc) if (!rc)
memcpy(shdr->Signature, sigptr, SMB2_SIGNATURE_SIZE); memcpy(shdr->Signature, sigptr, SMB2_SIGNATURE_SIZE);
...@@ -548,6 +587,7 @@ smb2_mid_entry_alloc(const struct smb2_sync_hdr *shdr, ...@@ -548,6 +587,7 @@ smb2_mid_entry_alloc(const struct smb2_sync_hdr *shdr,
temp = mempool_alloc(cifs_mid_poolp, GFP_NOFS); temp = mempool_alloc(cifs_mid_poolp, GFP_NOFS);
memset(temp, 0, sizeof(struct mid_q_entry)); memset(temp, 0, sizeof(struct mid_q_entry));
kref_init(&temp->refcount);
temp->mid = le64_to_cpu(shdr->MessageId); temp->mid = le64_to_cpu(shdr->MessageId);
temp->pid = current->pid; temp->pid = current->pid;
temp->command = shdr->Command; /* Always LE */ temp->command = shdr->Command; /* Always LE */
......
...@@ -2083,8 +2083,9 @@ int smbd_recv(struct smbd_connection *info, struct msghdr *msg) ...@@ -2083,8 +2083,9 @@ int smbd_recv(struct smbd_connection *info, struct msghdr *msg)
* rqst: the data to write * rqst: the data to write
* return value: 0 if successfully write, otherwise error code * return value: 0 if successfully write, otherwise error code
*/ */
int smbd_send(struct smbd_connection *info, struct smb_rqst *rqst) int smbd_send(struct TCP_Server_Info *server, struct smb_rqst *rqst)
{ {
struct smbd_connection *info = server->smbd_conn;
struct kvec vec; struct kvec vec;
int nvecs; int nvecs;
int size; int size;
...@@ -2118,7 +2119,7 @@ int smbd_send(struct smbd_connection *info, struct smb_rqst *rqst) ...@@ -2118,7 +2119,7 @@ int smbd_send(struct smbd_connection *info, struct smb_rqst *rqst)
* rq_tailsz to PAGE_SIZE when the buffer has multiple pages and * rq_tailsz to PAGE_SIZE when the buffer has multiple pages and
* ends at page boundary * ends at page boundary
*/ */
buflen = smb2_rqst_len(rqst, true); buflen = smb_rqst_len(server, rqst);
if (buflen + sizeof(struct smbd_data_transfer) > if (buflen + sizeof(struct smbd_data_transfer) >
info->max_fragmented_send_size) { info->max_fragmented_send_size) {
......
...@@ -292,7 +292,7 @@ void smbd_destroy(struct smbd_connection *info); ...@@ -292,7 +292,7 @@ void smbd_destroy(struct smbd_connection *info);
/* Interface for carrying upper layer I/O through send/recv */ /* Interface for carrying upper layer I/O through send/recv */
int smbd_recv(struct smbd_connection *info, struct msghdr *msg); int smbd_recv(struct smbd_connection *info, struct msghdr *msg);
int smbd_send(struct smbd_connection *info, struct smb_rqst *rqst); int smbd_send(struct TCP_Server_Info *server, struct smb_rqst *rqst);
enum mr_state { enum mr_state {
MR_READY, MR_READY,
...@@ -332,7 +332,7 @@ static inline void *smbd_get_connection( ...@@ -332,7 +332,7 @@ static inline void *smbd_get_connection(
static inline int smbd_reconnect(struct TCP_Server_Info *server) {return -1; } static inline int smbd_reconnect(struct TCP_Server_Info *server) {return -1; }
static inline void smbd_destroy(struct smbd_connection *info) {} static inline void smbd_destroy(struct smbd_connection *info) {}
static inline int smbd_recv(struct smbd_connection *info, struct msghdr *msg) {return -1; } static inline int smbd_recv(struct smbd_connection *info, struct msghdr *msg) {return -1; }
static inline int smbd_send(struct smbd_connection *info, struct smb_rqst *rqst) {return -1; } static inline int smbd_send(struct TCP_Server_Info *server, struct smb_rqst *rqst) {return -1; }
#endif #endif
#endif #endif
...@@ -61,6 +61,7 @@ AllocMidQEntry(const struct smb_hdr *smb_buffer, struct TCP_Server_Info *server) ...@@ -61,6 +61,7 @@ AllocMidQEntry(const struct smb_hdr *smb_buffer, struct TCP_Server_Info *server)
temp = mempool_alloc(cifs_mid_poolp, GFP_NOFS); temp = mempool_alloc(cifs_mid_poolp, GFP_NOFS);
memset(temp, 0, sizeof(struct mid_q_entry)); memset(temp, 0, sizeof(struct mid_q_entry));
kref_init(&temp->refcount);
temp->mid = get_mid(smb_buffer); temp->mid = get_mid(smb_buffer);
temp->pid = current->pid; temp->pid = current->pid;
temp->command = cpu_to_le16(smb_buffer->Command); temp->command = cpu_to_le16(smb_buffer->Command);
...@@ -82,6 +83,21 @@ AllocMidQEntry(const struct smb_hdr *smb_buffer, struct TCP_Server_Info *server) ...@@ -82,6 +83,21 @@ AllocMidQEntry(const struct smb_hdr *smb_buffer, struct TCP_Server_Info *server)
return temp; return temp;
} }
static void _cifs_mid_q_entry_release(struct kref *refcount)
{
struct mid_q_entry *mid = container_of(refcount, struct mid_q_entry,
refcount);
mempool_free(mid, cifs_mid_poolp);
}
void cifs_mid_q_entry_release(struct mid_q_entry *midEntry)
{
spin_lock(&GlobalMid_Lock);
kref_put(&midEntry->refcount, _cifs_mid_q_entry_release);
spin_unlock(&GlobalMid_Lock);
}
void void
DeleteMidQEntry(struct mid_q_entry *midEntry) DeleteMidQEntry(struct mid_q_entry *midEntry)
{ {
...@@ -110,7 +126,7 @@ DeleteMidQEntry(struct mid_q_entry *midEntry) ...@@ -110,7 +126,7 @@ DeleteMidQEntry(struct mid_q_entry *midEntry)
} }
} }
#endif #endif
mempool_free(midEntry, cifs_mid_poolp); cifs_mid_q_entry_release(midEntry);
} }
void void
...@@ -202,14 +218,15 @@ smb_send_kvec(struct TCP_Server_Info *server, struct msghdr *smb_msg, ...@@ -202,14 +218,15 @@ smb_send_kvec(struct TCP_Server_Info *server, struct msghdr *smb_msg,
} }
unsigned long unsigned long
smb2_rqst_len(struct smb_rqst *rqst, bool skip_rfc1002_marker) smb_rqst_len(struct TCP_Server_Info *server, struct smb_rqst *rqst)
{ {
unsigned int i; unsigned int i;
struct kvec *iov; struct kvec *iov;
int nvec; int nvec;
unsigned long buflen = 0; unsigned long buflen = 0;
if (skip_rfc1002_marker && rqst->rq_iov[0].iov_len == 4) { if (server->vals->header_preamble_size == 0 &&
rqst->rq_nvec >= 2 && rqst->rq_iov[0].iov_len == 4) {
iov = &rqst->rq_iov[1]; iov = &rqst->rq_iov[1];
nvec = rqst->rq_nvec - 1; nvec = rqst->rq_nvec - 1;
} else { } else {
...@@ -260,7 +277,7 @@ __smb_send_rqst(struct TCP_Server_Info *server, int num_rqst, ...@@ -260,7 +277,7 @@ __smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
__be32 rfc1002_marker; __be32 rfc1002_marker;
if (cifs_rdma_enabled(server) && server->smbd_conn) { if (cifs_rdma_enabled(server) && server->smbd_conn) {
rc = smbd_send(server->smbd_conn, rqst); rc = smbd_send(server, rqst);
goto smbd_done; goto smbd_done;
} }
if (ssocket == NULL) if (ssocket == NULL)
...@@ -271,7 +288,7 @@ __smb_send_rqst(struct TCP_Server_Info *server, int num_rqst, ...@@ -271,7 +288,7 @@ __smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
(char *)&val, sizeof(val)); (char *)&val, sizeof(val));
for (j = 0; j < num_rqst; j++) for (j = 0; j < num_rqst; j++)
send_length += smb2_rqst_len(&rqst[j], true); send_length += smb_rqst_len(server, &rqst[j]);
rfc1002_marker = cpu_to_be32(send_length); rfc1002_marker = cpu_to_be32(send_length);
/* Generate a rfc1002 marker for SMB2+ */ /* Generate a rfc1002 marker for SMB2+ */
......
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