Merge tag '5.10-rc5-smb3-fixes' of git://git.samba.org/sfrench/cifs-2.6
Pull cifs fixes from Steve French: "Four smb3 fixes for stable: one fixes a memleak, the other three address a problem found with decryption offload that can cause a use after free" * tag '5.10-rc5-smb3-fixes' of git://git.samba.org/sfrench/cifs-2.6: smb3: Handle error case during offload read path smb3: Avoid Mid pending list corruption smb3: Call cifs reconnect from demultiplex thread cifs: fix a memleak with modefromsid
This commit is contained in:
@@ -1266,6 +1266,7 @@ cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
|
||||
cifs_dbg(VFS, "%s: error %d getting sec desc\n", __func__, rc);
|
||||
} else if (mode_from_special_sid) {
|
||||
rc = parse_sec_desc(cifs_sb, pntsd, acllen, fattr, true);
|
||||
kfree(pntsd);
|
||||
} else {
|
||||
/* get approximated mode from ACL */
|
||||
rc = parse_sec_desc(cifs_sb, pntsd, acllen, fattr, false);
|
||||
|
||||
+73
-15
@@ -264,7 +264,7 @@ smb2_revert_current_mid(struct TCP_Server_Info *server, const unsigned int val)
|
||||
}
|
||||
|
||||
static struct mid_q_entry *
|
||||
smb2_find_mid(struct TCP_Server_Info *server, char *buf)
|
||||
__smb2_find_mid(struct TCP_Server_Info *server, char *buf, bool dequeue)
|
||||
{
|
||||
struct mid_q_entry *mid;
|
||||
struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)buf;
|
||||
@@ -281,6 +281,10 @@ smb2_find_mid(struct TCP_Server_Info *server, char *buf)
|
||||
(mid->mid_state == MID_REQUEST_SUBMITTED) &&
|
||||
(mid->command == shdr->Command)) {
|
||||
kref_get(&mid->refcount);
|
||||
if (dequeue) {
|
||||
list_del_init(&mid->qhead);
|
||||
mid->mid_flags |= MID_DELETED;
|
||||
}
|
||||
spin_unlock(&GlobalMid_Lock);
|
||||
return mid;
|
||||
}
|
||||
@@ -289,6 +293,18 @@ smb2_find_mid(struct TCP_Server_Info *server, char *buf)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct mid_q_entry *
|
||||
smb2_find_mid(struct TCP_Server_Info *server, char *buf)
|
||||
{
|
||||
return __smb2_find_mid(server, buf, false);
|
||||
}
|
||||
|
||||
static struct mid_q_entry *
|
||||
smb2_find_dequeue_mid(struct TCP_Server_Info *server, char *buf)
|
||||
{
|
||||
return __smb2_find_mid(server, buf, true);
|
||||
}
|
||||
|
||||
static void
|
||||
smb2_dump_detail(void *buf, struct TCP_Server_Info *server)
|
||||
{
|
||||
@@ -4356,7 +4372,8 @@ init_read_bvec(struct page **pages, unsigned int npages, unsigned int data_size,
|
||||
static int
|
||||
handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
|
||||
char *buf, unsigned int buf_len, struct page **pages,
|
||||
unsigned int npages, unsigned int page_data_size)
|
||||
unsigned int npages, unsigned int page_data_size,
|
||||
bool is_offloaded)
|
||||
{
|
||||
unsigned int data_offset;
|
||||
unsigned int data_len;
|
||||
@@ -4378,7 +4395,8 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
|
||||
|
||||
if (server->ops->is_session_expired &&
|
||||
server->ops->is_session_expired(buf)) {
|
||||
cifs_reconnect(server);
|
||||
if (!is_offloaded)
|
||||
cifs_reconnect(server);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -4402,7 +4420,10 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
|
||||
cifs_dbg(FYI, "%s: server returned error %d\n",
|
||||
__func__, rdata->result);
|
||||
/* normal error on read response */
|
||||
dequeue_mid(mid, false);
|
||||
if (is_offloaded)
|
||||
mid->mid_state = MID_RESPONSE_RECEIVED;
|
||||
else
|
||||
dequeue_mid(mid, false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -4426,7 +4447,10 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
|
||||
cifs_dbg(FYI, "%s: data offset (%u) beyond end of smallbuf\n",
|
||||
__func__, data_offset);
|
||||
rdata->result = -EIO;
|
||||
dequeue_mid(mid, rdata->result);
|
||||
if (is_offloaded)
|
||||
mid->mid_state = MID_RESPONSE_MALFORMED;
|
||||
else
|
||||
dequeue_mid(mid, rdata->result);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -4442,21 +4466,30 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
|
||||
cifs_dbg(FYI, "%s: data offset (%u) beyond 1st page of response\n",
|
||||
__func__, data_offset);
|
||||
rdata->result = -EIO;
|
||||
dequeue_mid(mid, rdata->result);
|
||||
if (is_offloaded)
|
||||
mid->mid_state = MID_RESPONSE_MALFORMED;
|
||||
else
|
||||
dequeue_mid(mid, rdata->result);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (data_len > page_data_size - pad_len) {
|
||||
/* data_len is corrupt -- discard frame */
|
||||
rdata->result = -EIO;
|
||||
dequeue_mid(mid, rdata->result);
|
||||
if (is_offloaded)
|
||||
mid->mid_state = MID_RESPONSE_MALFORMED;
|
||||
else
|
||||
dequeue_mid(mid, rdata->result);
|
||||
return 0;
|
||||
}
|
||||
|
||||
rdata->result = init_read_bvec(pages, npages, page_data_size,
|
||||
cur_off, &bvec);
|
||||
if (rdata->result != 0) {
|
||||
dequeue_mid(mid, rdata->result);
|
||||
if (is_offloaded)
|
||||
mid->mid_state = MID_RESPONSE_MALFORMED;
|
||||
else
|
||||
dequeue_mid(mid, rdata->result);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -4471,7 +4504,10 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
|
||||
/* read response payload cannot be in both buf and pages */
|
||||
WARN_ONCE(1, "buf can not contain only a part of read data");
|
||||
rdata->result = -EIO;
|
||||
dequeue_mid(mid, rdata->result);
|
||||
if (is_offloaded)
|
||||
mid->mid_state = MID_RESPONSE_MALFORMED;
|
||||
else
|
||||
dequeue_mid(mid, rdata->result);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -4482,7 +4518,10 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
|
||||
if (length < 0)
|
||||
return length;
|
||||
|
||||
dequeue_mid(mid, false);
|
||||
if (is_offloaded)
|
||||
mid->mid_state = MID_RESPONSE_RECEIVED;
|
||||
else
|
||||
dequeue_mid(mid, false);
|
||||
return length;
|
||||
}
|
||||
|
||||
@@ -4511,15 +4550,34 @@ static void smb2_decrypt_offload(struct work_struct *work)
|
||||
}
|
||||
|
||||
dw->server->lstrp = jiffies;
|
||||
mid = smb2_find_mid(dw->server, dw->buf);
|
||||
mid = smb2_find_dequeue_mid(dw->server, dw->buf);
|
||||
if (mid == NULL)
|
||||
cifs_dbg(FYI, "mid not found\n");
|
||||
else {
|
||||
mid->decrypted = true;
|
||||
rc = handle_read_data(dw->server, mid, dw->buf,
|
||||
dw->server->vals->read_rsp_size,
|
||||
dw->ppages, dw->npages, dw->len);
|
||||
mid->callback(mid);
|
||||
dw->ppages, dw->npages, dw->len,
|
||||
true);
|
||||
if (rc >= 0) {
|
||||
#ifdef CONFIG_CIFS_STATS2
|
||||
mid->when_received = jiffies;
|
||||
#endif
|
||||
mid->callback(mid);
|
||||
} else {
|
||||
spin_lock(&GlobalMid_Lock);
|
||||
if (dw->server->tcpStatus == CifsNeedReconnect) {
|
||||
mid->mid_state = MID_RETRY_NEEDED;
|
||||
spin_unlock(&GlobalMid_Lock);
|
||||
mid->callback(mid);
|
||||
} else {
|
||||
mid->mid_state = MID_REQUEST_SUBMITTED;
|
||||
mid->mid_flags &= ~(MID_DELETED);
|
||||
list_add_tail(&mid->qhead,
|
||||
&dw->server->pending_mid_q);
|
||||
spin_unlock(&GlobalMid_Lock);
|
||||
}
|
||||
}
|
||||
cifs_mid_q_entry_release(mid);
|
||||
}
|
||||
|
||||
@@ -4622,7 +4680,7 @@ non_offloaded_decrypt:
|
||||
(*mid)->decrypted = true;
|
||||
rc = handle_read_data(server, *mid, buf,
|
||||
server->vals->read_rsp_size,
|
||||
pages, npages, len);
|
||||
pages, npages, len, false);
|
||||
}
|
||||
|
||||
free_pages:
|
||||
@@ -4765,7 +4823,7 @@ smb3_handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid)
|
||||
char *buf = server->large_buf ? server->bigbuf : server->smallbuf;
|
||||
|
||||
return handle_read_data(server, mid, buf, server->pdu_size,
|
||||
NULL, 0, 0);
|
||||
NULL, 0, 0, false);
|
||||
}
|
||||
|
||||
static int
|
||||
|
||||
Reference in New Issue
Block a user