Commit 127c501a authored by Linus Torvalds's avatar Linus Torvalds

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
parents 073861ed 12541000
...@@ -1266,6 +1266,7 @@ cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr, ...@@ -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); cifs_dbg(VFS, "%s: error %d getting sec desc\n", __func__, rc);
} else if (mode_from_special_sid) { } else if (mode_from_special_sid) {
rc = parse_sec_desc(cifs_sb, pntsd, acllen, fattr, true); rc = parse_sec_desc(cifs_sb, pntsd, acllen, fattr, true);
kfree(pntsd);
} else { } else {
/* get approximated mode from ACL */ /* get approximated mode from ACL */
rc = parse_sec_desc(cifs_sb, pntsd, acllen, fattr, false); 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) ...@@ -264,7 +264,7 @@ smb2_revert_current_mid(struct TCP_Server_Info *server, const unsigned int val)
} }
static struct mid_q_entry * 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 mid_q_entry *mid;
struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)buf; struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)buf;
...@@ -281,6 +281,10 @@ smb2_find_mid(struct TCP_Server_Info *server, char *buf) ...@@ -281,6 +281,10 @@ smb2_find_mid(struct TCP_Server_Info *server, char *buf)
(mid->mid_state == MID_REQUEST_SUBMITTED) && (mid->mid_state == MID_REQUEST_SUBMITTED) &&
(mid->command == shdr->Command)) { (mid->command == shdr->Command)) {
kref_get(&mid->refcount); kref_get(&mid->refcount);
if (dequeue) {
list_del_init(&mid->qhead);
mid->mid_flags |= MID_DELETED;
}
spin_unlock(&GlobalMid_Lock); spin_unlock(&GlobalMid_Lock);
return mid; return mid;
} }
...@@ -289,6 +293,18 @@ smb2_find_mid(struct TCP_Server_Info *server, char *buf) ...@@ -289,6 +293,18 @@ smb2_find_mid(struct TCP_Server_Info *server, char *buf)
return NULL; 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 static void
smb2_dump_detail(void *buf, struct TCP_Server_Info *server) 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, ...@@ -4356,7 +4372,8 @@ init_read_bvec(struct page **pages, unsigned int npages, unsigned int data_size,
static int static int
handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid, handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
char *buf, unsigned int buf_len, struct page **pages, 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_offset;
unsigned int data_len; unsigned int data_len;
...@@ -4378,6 +4395,7 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid, ...@@ -4378,6 +4395,7 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
if (server->ops->is_session_expired && if (server->ops->is_session_expired &&
server->ops->is_session_expired(buf)) { server->ops->is_session_expired(buf)) {
if (!is_offloaded)
cifs_reconnect(server); cifs_reconnect(server);
return -1; return -1;
} }
...@@ -4402,6 +4420,9 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid, ...@@ -4402,6 +4420,9 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
cifs_dbg(FYI, "%s: server returned error %d\n", cifs_dbg(FYI, "%s: server returned error %d\n",
__func__, rdata->result); __func__, rdata->result);
/* normal error on read response */ /* normal error on read response */
if (is_offloaded)
mid->mid_state = MID_RESPONSE_RECEIVED;
else
dequeue_mid(mid, false); dequeue_mid(mid, false);
return 0; return 0;
} }
...@@ -4426,6 +4447,9 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid, ...@@ -4426,6 +4447,9 @@ 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", cifs_dbg(FYI, "%s: data offset (%u) beyond end of smallbuf\n",
__func__, data_offset); __func__, data_offset);
rdata->result = -EIO; rdata->result = -EIO;
if (is_offloaded)
mid->mid_state = MID_RESPONSE_MALFORMED;
else
dequeue_mid(mid, rdata->result); dequeue_mid(mid, rdata->result);
return 0; return 0;
} }
...@@ -4442,6 +4466,9 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid, ...@@ -4442,6 +4466,9 @@ 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", cifs_dbg(FYI, "%s: data offset (%u) beyond 1st page of response\n",
__func__, data_offset); __func__, data_offset);
rdata->result = -EIO; rdata->result = -EIO;
if (is_offloaded)
mid->mid_state = MID_RESPONSE_MALFORMED;
else
dequeue_mid(mid, rdata->result); dequeue_mid(mid, rdata->result);
return 0; return 0;
} }
...@@ -4449,6 +4476,9 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid, ...@@ -4449,6 +4476,9 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
if (data_len > page_data_size - pad_len) { if (data_len > page_data_size - pad_len) {
/* data_len is corrupt -- discard frame */ /* data_len is corrupt -- discard frame */
rdata->result = -EIO; rdata->result = -EIO;
if (is_offloaded)
mid->mid_state = MID_RESPONSE_MALFORMED;
else
dequeue_mid(mid, rdata->result); dequeue_mid(mid, rdata->result);
return 0; return 0;
} }
...@@ -4456,6 +4486,9 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid, ...@@ -4456,6 +4486,9 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
rdata->result = init_read_bvec(pages, npages, page_data_size, rdata->result = init_read_bvec(pages, npages, page_data_size,
cur_off, &bvec); cur_off, &bvec);
if (rdata->result != 0) { if (rdata->result != 0) {
if (is_offloaded)
mid->mid_state = MID_RESPONSE_MALFORMED;
else
dequeue_mid(mid, rdata->result); dequeue_mid(mid, rdata->result);
return 0; return 0;
} }
...@@ -4471,6 +4504,9 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid, ...@@ -4471,6 +4504,9 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
/* read response payload cannot be in both buf and pages */ /* read response payload cannot be in both buf and pages */
WARN_ONCE(1, "buf can not contain only a part of read data"); WARN_ONCE(1, "buf can not contain only a part of read data");
rdata->result = -EIO; rdata->result = -EIO;
if (is_offloaded)
mid->mid_state = MID_RESPONSE_MALFORMED;
else
dequeue_mid(mid, rdata->result); dequeue_mid(mid, rdata->result);
return 0; return 0;
} }
...@@ -4482,6 +4518,9 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid, ...@@ -4482,6 +4518,9 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
if (length < 0) if (length < 0)
return length; return length;
if (is_offloaded)
mid->mid_state = MID_RESPONSE_RECEIVED;
else
dequeue_mid(mid, false); dequeue_mid(mid, false);
return length; return length;
} }
...@@ -4511,15 +4550,34 @@ static void smb2_decrypt_offload(struct work_struct *work) ...@@ -4511,15 +4550,34 @@ static void smb2_decrypt_offload(struct work_struct *work)
} }
dw->server->lstrp = jiffies; dw->server->lstrp = jiffies;
mid = smb2_find_mid(dw->server, dw->buf); mid = smb2_find_dequeue_mid(dw->server, dw->buf);
if (mid == NULL) if (mid == NULL)
cifs_dbg(FYI, "mid not found\n"); cifs_dbg(FYI, "mid not found\n");
else { else {
mid->decrypted = true; mid->decrypted = true;
rc = handle_read_data(dw->server, mid, dw->buf, rc = handle_read_data(dw->server, mid, dw->buf,
dw->server->vals->read_rsp_size, dw->server->vals->read_rsp_size,
dw->ppages, dw->npages, dw->len); dw->ppages, dw->npages, dw->len,
true);
if (rc >= 0) {
#ifdef CONFIG_CIFS_STATS2
mid->when_received = jiffies;
#endif
mid->callback(mid); 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); cifs_mid_q_entry_release(mid);
} }
...@@ -4622,7 +4680,7 @@ receive_encrypted_read(struct TCP_Server_Info *server, struct mid_q_entry **mid, ...@@ -4622,7 +4680,7 @@ receive_encrypted_read(struct TCP_Server_Info *server, struct mid_q_entry **mid,
(*mid)->decrypted = true; (*mid)->decrypted = true;
rc = handle_read_data(server, *mid, buf, rc = handle_read_data(server, *mid, buf,
server->vals->read_rsp_size, server->vals->read_rsp_size,
pages, npages, len); pages, npages, len, false);
} }
free_pages: free_pages:
...@@ -4765,7 +4823,7 @@ smb3_handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid) ...@@ -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; char *buf = server->large_buf ? server->bigbuf : server->smallbuf;
return handle_read_data(server, mid, buf, server->pdu_size, return handle_read_data(server, mid, buf, server->pdu_size,
NULL, 0, 0); NULL, 0, 0, false);
} }
static int static int
......
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