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

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
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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
Original line number Diff line number Diff line
@@ -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,6 +4395,7 @@ 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)) {
		if (!is_offloaded)
			cifs_reconnect(server);
		return -1;
	}
@@ -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",
			 __func__, rdata->result);
		/* normal error on read response */
		if (is_offloaded)
			mid->mid_state = MID_RESPONSE_RECEIVED;
		else
			dequeue_mid(mid, false);
		return 0;
	}
@@ -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",
			 __func__, data_offset);
		rdata->result = -EIO;
		if (is_offloaded)
			mid->mid_state = MID_RESPONSE_MALFORMED;
		else
			dequeue_mid(mid, rdata->result);
		return 0;
	}
@@ -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",
				 __func__, data_offset);
			rdata->result = -EIO;
			if (is_offloaded)
				mid->mid_state = MID_RESPONSE_MALFORMED;
			else
				dequeue_mid(mid, rdata->result);
			return 0;
		}
@@ -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) {
			/* data_len is corrupt -- discard frame */
			rdata->result = -EIO;
			if (is_offloaded)
				mid->mid_state = MID_RESPONSE_MALFORMED;
			else
				dequeue_mid(mid, rdata->result);
			return 0;
		}
@@ -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,
					       cur_off, &bvec);
		if (rdata->result != 0) {
			if (is_offloaded)
				mid->mid_state = MID_RESPONSE_MALFORMED;
			else
				dequeue_mid(mid, rdata->result);
			return 0;
		}
@@ -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 */
		WARN_ONCE(1, "buf can not contain only a part of read data");
		rdata->result = -EIO;
		if (is_offloaded)
			mid->mid_state = MID_RESPONSE_MALFORMED;
		else
			dequeue_mid(mid, rdata->result);
		return 0;
	}
@@ -4482,6 +4518,9 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
	if (length < 0)
		return length;

	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);
				      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