forked from Minki/linux
Four smb3 fixes for stable
-----BEGIN PGP SIGNATURE----- iQGzBAABCgAdFiEE6fsu8pdIjtWE/DpLiiy9cAdyT1EFAl+9eV4ACgkQiiy9cAdy T1EXOAv+JF6QZiwB6TELiusDLw+6UWpT7CcT1guL+eSrFVYEPIhqF4V4QXY0oA0Y F8jTpHxEx8wdECAPPNGHh/a4E+Y1vV/W8Nv5DkglAwjeXAD2Y84VAp8hH890jnn0 M8I9qdnbfSodRueshpKScRPHbfp4Smlz1BR9R0syk7T7TmCy8aKNwYN1lBy5Nf9f ICMn1F5e9z4nX43NJIwzO+NSPehtLm8ULFZER/pQ+tGDhwXTdFc9HPzfu0ZoYbEO zADjmY4PItVYRINnWBntEBLYcAFeAB0finPTP2kCfXfRDF5cPgElp84F3Uro7se5 bioboePO+bUS0jigIiP3qZ7zTHEdJoICsiJzVGmDZYsawK3MAwamp2EH3axAr4B/ h4LULgN7nCatPW5lMo3/3EPZXVbXVTOYIB2REtqJugK8USQ9+v9SMLNT/qWn0GE5 bzZoZ22wkHEOn4EIxYSCX4tgj9cJ2v9B/0NMpTQLTECKBQi3iV32GxLglvMwZru6 eWKL5tZj =lxdD -----END PGP SIGNATURE----- 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:
commit
127c501a03
@ -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);
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user