Skip to content

Commit

Permalink
Merge tag '4.18-rc3-smb3fixes' of git://git.samba.org/sfrench/cifs-2.6
Browse files Browse the repository at this point in the history
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
  • Loading branch information
torvalds committed Jul 8, 2018
2 parents 4f572ef + 729c0c9 commit b2d44d1
Show file tree
Hide file tree
Showing 14 changed files with 132 additions and 54 deletions.
3 changes: 2 additions & 1 deletion fs/cifs/cifsglob.h
Original file line number Diff line number Diff line change
Expand Up @@ -423,7 +423,7 @@ struct smb_version_operations {
void (*set_oplock_level)(struct cifsInodeInfo *, __u32, unsigned int,
bool *);
/* 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 */
__u8 (*parse_lease_buf)(void *buf, unsigned int *epoch, char *lkey);
ssize_t (*copychunk_range)(const unsigned int,
Expand Down Expand Up @@ -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 */
struct mid_q_entry {
struct list_head qhead; /* mids waiting on reply from this server */
struct kref refcount;
struct TCP_Server_Info *server; /* server corresponding to this mid */
__u64 mid; /* multiplex id */
__u32 pid; /* process id */
Expand Down
1 change: 1 addition & 0 deletions fs/cifs/cifsproto.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ extern struct mid_q_entry *AllocMidQEntry(const struct smb_hdr *smb_buffer,
struct TCP_Server_Info *server);
extern void DeleteMidQEntry(struct mid_q_entry *midEntry);
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 int cifs_handle_standard(struct TCP_Server_Info *server,
struct mid_q_entry *mid);
Expand Down
10 changes: 8 additions & 2 deletions fs/cifs/cifssmb.c
Original file line number Diff line number Diff line change
Expand Up @@ -157,8 +157,14 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
* greater than cifs socket timeout which is 7 seconds
*/
while (server->tcpStatus == CifsNeedReconnect) {
wait_event_interruptible_timeout(server->response_q,
(server->tcpStatus != CifsNeedReconnect), 10 * HZ);
rc = wait_event_interruptible_timeout(server->response_q,
(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? */
if (server->tcpStatus != CifsNeedReconnect)
Expand Down
8 changes: 7 additions & 1 deletion fs/cifs/connect.c
Original file line number Diff line number Diff line change
Expand Up @@ -924,6 +924,7 @@ cifs_demultiplex_thread(void *p)
server->pdu_size = next_offset;
}

mid_entry = NULL;
if (server->ops->is_transform_hdr &&
server->ops->receive_transform &&
server->ops->is_transform_hdr(buf)) {
Expand All @@ -938,8 +939,11 @@ cifs_demultiplex_thread(void *p)
length = mid_entry->receive(server, mid_entry);
}

if (length < 0)
if (length < 0) {
if (mid_entry)
cifs_mid_q_entry_release(mid_entry);
continue;
}

if (server->large_buf)
buf = server->bigbuf;
Expand All @@ -956,6 +960,8 @@ cifs_demultiplex_thread(void *p)

if (!mid_entry->multiRsp || mid_entry->multiEnd)
mid_entry->callback(mid_entry);

cifs_mid_q_entry_release(mid_entry);
} else if (server->ops->is_oplock_break &&
server->ops->is_oplock_break(buf, server)) {
cifs_dbg(FYI, "Received oplock break\n");
Expand Down
1 change: 1 addition & 0 deletions fs/cifs/smb1ops.c
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ cifs_find_mid(struct TCP_Server_Info *server, char *buffer)
if (compare_mid(mid->mid, buf) &&
mid->mid_state == MID_REQUEST_SUBMITTED &&
le16_to_cpu(mid->command) == buf->Command) {
kref_get(&mid->refcount);
spin_unlock(&GlobalMid_Lock);
return mid;
}
Expand Down
11 changes: 4 additions & 7 deletions fs/cifs/smb2file.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms,
int rc;
__le16 *smb2_path;
struct smb2_file_all_info *smb2_data = NULL;
__u8 smb2_oplock[17];
__u8 smb2_oplock;
struct cifs_fid *fid = oparms->fid;
struct network_resiliency_req nr_ioctl_req;

Expand All @@ -59,12 +59,9 @@ smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms,
}

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)
memcpy(smb2_oplock + 1, fid->lease_key, SMB2_LEASE_KEY_SIZE);

rc = SMB2_open(xid, oparms, smb2_path, smb2_oplock, smb2_data, NULL,
rc = SMB2_open(xid, oparms, smb2_path, &smb2_oplock, smb2_data, NULL,
NULL);
if (rc)
goto out;
Expand Down Expand Up @@ -101,7 +98,7 @@ smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms,
move_smb2_info_to_cifs(buf, smb2_data);
}

*oplock = *smb2_oplock;
*oplock = smb2_oplock;
out:
kfree(smb2_data);
kfree(smb2_path);
Expand Down
14 changes: 7 additions & 7 deletions fs/cifs/smb2ops.c
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@ smb2_find_mid(struct TCP_Server_Info *server, char *buf)
if ((mid->mid == wire_mid) &&
(mid->mid_state == MID_REQUEST_SUBMITTED) &&
(mid->command == shdr->Command)) {
kref_get(&mid->refcount);
spin_unlock(&GlobalMid_Lock);
return mid;
}
Expand Down Expand Up @@ -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,
len);
kfree(ea);

SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);

return rc;
Expand Down Expand Up @@ -2219,8 +2222,7 @@ smb2_create_lease_buf(u8 *lease_key, u8 oplock)
if (!buf)
return NULL;

buf->lcontext.LeaseKeyLow = cpu_to_le64(*((u64 *)lease_key));
buf->lcontext.LeaseKeyHigh = cpu_to_le64(*((u64 *)(lease_key + 8)));
memcpy(&buf->lcontext.LeaseKey, lease_key, SMB2_LEASE_KEY_SIZE);
buf->lcontext.LeaseState = map_oplock_to_lease(oplock);

buf->ccontext.DataOffset = cpu_to_le16(offsetof
Expand All @@ -2246,8 +2248,7 @@ smb3_create_lease_buf(u8 *lease_key, u8 oplock)
if (!buf)
return NULL;

buf->lcontext.LeaseKeyLow = cpu_to_le64(*((u64 *)lease_key));
buf->lcontext.LeaseKeyHigh = cpu_to_le64(*((u64 *)(lease_key + 8)));
memcpy(&buf->lcontext.LeaseKey, lease_key, SMB2_LEASE_KEY_SIZE);
buf->lcontext.LeaseState = map_oplock_to_lease(oplock);

buf->ccontext.DataOffset = cpu_to_le16(offsetof
Expand Down Expand Up @@ -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)
return SMB2_OPLOCK_LEVEL_NOCHANGE;
if (lease_key)
memcpy(lease_key, &lc->lcontext.LeaseKeyLow,
SMB2_LEASE_KEY_SIZE);
memcpy(lease_key, &lc->lcontext.LeaseKey, SMB2_LEASE_KEY_SIZE);
return le32_to_cpu(lc->lcontext.LeaseState);
}

Expand Down Expand Up @@ -2521,7 +2521,7 @@ smb3_init_transform_rq(struct TCP_Server_Info *server, struct smb_rqst *new_rq,
if (!tr_hdr)
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_transform_hdr(tr_hdr, orig_len, old_rq);
Expand Down
32 changes: 21 additions & 11 deletions fs/cifs/smb2pdu.c
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ smb2_hdr_assemble(struct smb2_sync_hdr *shdr, __le16 smb2_cmd,
static int
smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon)
{
int rc = 0;
int rc;
struct nls_table *nls_codepage;
struct cifs_ses *ses;
struct TCP_Server_Info *server;
Expand All @@ -166,10 +166,10 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon)
* for those three - in the calling routine.
*/
if (tcon == NULL)
return rc;
return 0;

if (smb2_command == SMB2_TREE_CONNECT)
return rc;
return 0;

if (tcon->tidStatus == CifsExiting) {
/*
Expand Down Expand Up @@ -212,8 +212,14 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon)
return -EAGAIN;
}

wait_event_interruptible_timeout(server->response_q,
(server->tcpStatus != CifsNeedReconnect), 10 * HZ);
rc = wait_event_interruptible_timeout(server->response_q,
(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? */
if (server->tcpStatus != CifsNeedReconnect)
Expand All @@ -231,7 +237,7 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon)
}

if (!tcon->ses->need_reconnect && !tcon->need_reconnect)
return rc;
return 0;

nls_codepage = load_nls_default();

Expand Down Expand Up @@ -340,7 +346,10 @@ smb2_plain_req_init(__le16 smb2_command, struct cifs_tcon *tcon,
return rc;

/* 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) {
/* BB should we add a retry in here if not a writepage? */
return -ENOMEM;
Expand Down Expand Up @@ -1707,12 +1716,12 @@ parse_lease_state(struct TCP_Server_Info *server, struct smb2_create_rsp *rsp,

static int
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;
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)
return -ENOMEM;
iov[num].iov_len = server->vals->create_lease_size;
Expand Down Expand Up @@ -2172,7 +2181,8 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
*oplock == SMB2_OPLOCK_LEVEL_NONE)
req->RequestedOplockLevel = *oplock;
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) {
cifs_small_buf_release(req);
kfree(copy_path);
Expand Down Expand Up @@ -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,
&rsp_iov);
cifs_small_buf_release(req);
cifs_buf_release(req);
rsp = (struct smb2_set_info_rsp *)rsp_iov.iov_base;

if (rc != 0) {
Expand Down
6 changes: 2 additions & 4 deletions fs/cifs/smb2pdu.h
Original file line number Diff line number Diff line change
Expand Up @@ -678,16 +678,14 @@ struct create_context {
#define SMB2_LEASE_KEY_SIZE 16

struct lease_context {
__le64 LeaseKeyLow;
__le64 LeaseKeyHigh;
u8 LeaseKey[SMB2_LEASE_KEY_SIZE];
__le32 LeaseState;
__le32 LeaseFlags;
__le64 LeaseDuration;
} __packed;

struct lease_context_v2 {
__le64 LeaseKeyLow;
__le64 LeaseKeyHigh;
u8 LeaseKey[SMB2_LEASE_KEY_SIZE];
__le32 LeaseState;
__le32 LeaseFlags;
__le64 LeaseDuration;
Expand Down
4 changes: 2 additions & 2 deletions fs/cifs/smb2proto.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,8 @@ extern int smb2_unlock_range(struct cifsFileInfo *cfile,
extern int smb2_push_mandatory_locks(struct cifsFileInfo *cfile);
extern void smb2_reconnect_server(struct work_struct *work);
extern int smb3_crypto_aead_allocate(struct TCP_Server_Info *server);
extern unsigned long
smb2_rqst_len(struct smb_rqst *rqst, bool skip_rfc1002_marker);
extern unsigned long smb_rqst_len(struct TCP_Server_Info *server,
struct smb_rqst *rqst);

/*
* SMB2 Worker functions - most of protocol specific implementation details
Expand Down
Loading

0 comments on commit b2d44d1

Please sign in to comment.