Commit 55ddcff7 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag '6.17-rc1-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6

Pull smb client fixes from Steve French:

 - Fix unlink race and rename races

 - SMB3.1.1 compression fix

 - Avoid unneeded strlen calls in cifs_get_spnego_key

 - Fix slab out of bounds in parse_server_interfaces()

 - Fix mid leak and server buffer leak

 - smbdirect send error path fix

 - update internal version #

 - Fix unneeded response time update in negotiate protocol

* tag '6.17-rc1-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6:
  smb: client: remove redundant lstrp update in negotiate protocol
  cifs: update internal version number
  smb: client: don't wait for info->send_pending == 0 on error
  smb: client: fix mid_q_entry memleak leak with per-mid locking
  smb3: fix for slab out of bounds on mount to ksmbd
  cifs: avoid extra calls to strlen() in cifs_get_spnego_key()
  cifs: Fix collect_sample() to handle any iterator type
  smb: client: fix race with concurrent opens in rename(2)
  smb: client: fix race with concurrent opens in unlink(2)
parents d7ee5bdc e19d8dd6
Loading
Loading
Loading
Loading
+18 −29
Original line number Diff line number Diff line
@@ -124,55 +124,44 @@ cifs_get_spnego_key(struct cifs_ses *sesInfo,
	dp = description;
	/* start with version and hostname portion of UNC string */
	spnego_key = ERR_PTR(-EINVAL);
	sprintf(dp, "ver=0x%x;host=%s;", CIFS_SPNEGO_UPCALL_VERSION,
	dp += sprintf(dp, "ver=0x%x;host=%s;", CIFS_SPNEGO_UPCALL_VERSION,
		      hostname);
	dp = description + strlen(description);

	/* add the server address */
	if (server->dstaddr.ss_family == AF_INET)
		sprintf(dp, "ip4=%pI4", &sa->sin_addr);
		dp += sprintf(dp, "ip4=%pI4", &sa->sin_addr);
	else if (server->dstaddr.ss_family == AF_INET6)
		sprintf(dp, "ip6=%pI6", &sa6->sin6_addr);
		dp += sprintf(dp, "ip6=%pI6", &sa6->sin6_addr);
	else
		goto out;

	dp = description + strlen(description);

	/* for now, only sec=krb5 and sec=mskrb5 and iakerb are valid */
	if (server->sec_kerberos)
		sprintf(dp, ";sec=krb5");
		dp += sprintf(dp, ";sec=krb5");
	else if (server->sec_mskerberos)
		sprintf(dp, ";sec=mskrb5");
		dp += sprintf(dp, ";sec=mskrb5");
	else if (server->sec_iakerb)
		sprintf(dp, ";sec=iakerb");
		dp += sprintf(dp, ";sec=iakerb");
	else {
		cifs_dbg(VFS, "unknown or missing server auth type, use krb5\n");
		sprintf(dp, ";sec=krb5");
		dp += sprintf(dp, ";sec=krb5");
	}

	dp = description + strlen(description);
	sprintf(dp, ";uid=0x%x",
	dp += sprintf(dp, ";uid=0x%x",
		      from_kuid_munged(&init_user_ns, sesInfo->linux_uid));

	dp = description + strlen(description);
	sprintf(dp, ";creduid=0x%x",
	dp += sprintf(dp, ";creduid=0x%x",
		from_kuid_munged(&init_user_ns, sesInfo->cred_uid));

	if (sesInfo->user_name) {
		dp = description + strlen(description);
		sprintf(dp, ";user=%s", sesInfo->user_name);
	}
	if (sesInfo->user_name)
		dp += sprintf(dp, ";user=%s", sesInfo->user_name);

	dp = description + strlen(description);
	sprintf(dp, ";pid=0x%x", current->pid);
	dp += sprintf(dp, ";pid=0x%x", current->pid);

	if (sesInfo->upcall_target == UPTARGET_MOUNT) {
		dp = description + strlen(description);
		sprintf(dp, ";upcall_target=mount");
	} else {
		dp = description + strlen(description);
		sprintf(dp, ";upcall_target=app");
	}
	if (sesInfo->upcall_target == UPTARGET_MOUNT)
		dp += sprintf(dp, ";upcall_target=mount");
	else
		dp += sprintf(dp, ";upcall_target=app");

	cifs_dbg(FYI, "key description = %s\n", description);
	saved_cred = override_creds(spnego_cred);
+2 −2
Original line number Diff line number Diff line
@@ -145,6 +145,6 @@ extern const struct export_operations cifs_export_ops;
#endif /* CONFIG_CIFS_NFSD_EXPORT */

/* when changing internal version - update following two lines at same time */
#define SMB3_PRODUCT_BUILD 55
#define CIFS_VERSION   "2.55"
#define SMB3_PRODUCT_BUILD 56
#define CIFS_VERSION   "2.56"
#endif				/* _CIFSFS_H */
+21 −0
Original line number Diff line number Diff line
@@ -1732,6 +1732,7 @@ struct mid_q_entry {
	int mid_rc;		/* rc for MID_RC */
	__le16 command;		/* smb command code */
	unsigned int optype;	/* operation type */
	spinlock_t mid_lock;
	bool wait_cancelled:1;  /* Cancelled while waiting for response */
	bool deleted_from_q:1;  /* Whether Mid has been dequeued frem pending_mid_q */
	bool large_buf:1;	/* if valid response, is pointer to large buf */
@@ -2036,6 +2037,9 @@ require use of the stronger protocol */
 * cifsFileInfo->file_info_lock	cifsFileInfo->count		cifs_new_fileinfo
 *				->invalidHandle			initiate_cifs_search
 *				->oplock_break_cancelled
 * mid_q_entry->mid_lock	mid_q_entry->callback           alloc_mid
 *								smb2_mid_entry_alloc
 *				(Any fields of mid_q_entry that will need protection)
 ****************************************************************************/

#ifdef DECLARE_GLOBALS_HERE
@@ -2375,6 +2379,23 @@ static inline bool cifs_netbios_name(const char *name, size_t namelen)
	return ret;
}

/*
 * Execute mid callback atomically - ensures callback runs exactly once
 * and prevents sleeping in atomic context.
 */
static inline void mid_execute_callback(struct mid_q_entry *mid)
{
	void (*callback)(struct mid_q_entry *mid);

	spin_lock(&mid->mid_lock);
	callback = mid->callback;
	mid->callback = NULL;  /* Mark as executed, */
	spin_unlock(&mid->mid_lock);

	if (callback)
		callback(mid);
}

#define CIFS_REPARSE_SUPPORT(tcon) \
	((tcon)->posix_extensions || \
	 (le32_to_cpu((tcon)->fsAttrInfo.Attributes) & \
+9 −10
Original line number Diff line number Diff line
@@ -46,6 +46,7 @@ alloc_mid(const struct smb_hdr *smb_buffer, struct TCP_Server_Info *server)
	temp = mempool_alloc(cifs_mid_poolp, GFP_NOFS);
	memset(temp, 0, sizeof(struct mid_q_entry));
	kref_init(&temp->refcount);
	spin_lock_init(&temp->mid_lock);
	temp->mid = get_mid(smb_buffer);
	temp->pid = current->pid;
	temp->command = cpu_to_le16(smb_buffer->Command);
@@ -345,16 +346,15 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
	rc = wait_for_response(server, midQ);
	if (rc != 0) {
		send_cancel(server, &rqst, midQ);
		spin_lock(&server->mid_queue_lock);
		if (midQ->mid_state == MID_REQUEST_SUBMITTED ||
		    midQ->mid_state == MID_RESPONSE_RECEIVED) {
		spin_lock(&midQ->mid_lock);
		if (midQ->callback) {
			/* no longer considered to be "in-flight" */
			midQ->callback = release_mid;
			spin_unlock(&server->mid_queue_lock);
			spin_unlock(&midQ->mid_lock);
			add_credits(server, &credits, 0);
			return rc;
		}
		spin_unlock(&server->mid_queue_lock);
		spin_unlock(&midQ->mid_lock);
	}

	rc = cifs_sync_mid_result(midQ, server);
@@ -527,15 +527,14 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
		rc = wait_for_response(server, midQ);
		if (rc) {
			send_cancel(server, &rqst, midQ);
			spin_lock(&server->mid_queue_lock);
			if (midQ->mid_state == MID_REQUEST_SUBMITTED ||
			    midQ->mid_state == MID_RESPONSE_RECEIVED) {
			spin_lock(&midQ->mid_lock);
			if (midQ->callback) {
				/* no longer considered to be "in-flight" */
				midQ->callback = release_mid;
				spin_unlock(&server->mid_queue_lock);
				spin_unlock(&midQ->mid_lock);
				return rc;
			}
			spin_unlock(&server->mid_queue_lock);
			spin_unlock(&midQ->mid_lock);
		}

		/* We got the response - restart system call. */
+21 −50
Original line number Diff line number Diff line
@@ -155,58 +155,29 @@ static int cmp_bkt(const void *_a, const void *_b)
}

/*
 * TODO:
 * Support other iter types, if required.
 * Only ITER_XARRAY is supported for now.
 * Collect some 2K samples with 2K gaps between.
 */
static int collect_sample(const struct iov_iter *iter, ssize_t max, u8 *sample)
static int collect_sample(const struct iov_iter *source, ssize_t max, u8 *sample)
{
	struct folio *folios[16], *folio;
	unsigned int nr, i, j, npages;
	loff_t start = iter->xarray_start + iter->iov_offset;
	pgoff_t last, index = start / PAGE_SIZE;
	size_t len, off, foff;
	void *p;
	int s = 0;

	last = (start + max - 1) / PAGE_SIZE;
	do {
		nr = xa_extract(iter->xarray, (void **)folios, index, last, ARRAY_SIZE(folios),
				XA_PRESENT);
		if (nr == 0)
			return -EIO;

		for (i = 0; i < nr; i++) {
			folio = folios[i];
			npages = folio_nr_pages(folio);
			foff = start - folio_pos(folio);
			off = foff % PAGE_SIZE;

			for (j = foff / PAGE_SIZE; j < npages; j++) {
				size_t len2;

				len = min_t(size_t, max, PAGE_SIZE - off);
				len2 = min_t(size_t, len, SZ_2K);

				p = kmap_local_page(folio_page(folio, j));
				memcpy(&sample[s], p, len2);
				kunmap_local(p);

				s += len2;

				if (len2 < SZ_2K || s >= max - SZ_2K)
					return s;
	struct iov_iter iter = *source;
	size_t s = 0;

				max -= len;
				if (max <= 0)
					return s;
	while (iov_iter_count(&iter) >= SZ_2K) {
		size_t part = umin(umin(iov_iter_count(&iter), SZ_2K), max);
		size_t n;

				start += len;
				off = 0;
				index++;
			}
		n = copy_from_iter(sample + s, part, &iter);
		if (n != part)
			return -EFAULT;

		s += n;
		max -= n;

		if (iov_iter_count(&iter) < PAGE_SIZE - SZ_2K)
			break;

		iov_iter_advance(&iter, SZ_2K);
	}
	} while (nr == ARRAY_SIZE(folios));

	return s;
}
Loading