Commit 80ae5fb2 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'v6.15-rc5-ksmbd-server-fixes' of git://git.samba.org/ksmbd

Pull smb server fixes from Steve French:

 - Fix UAF closing file table (e.g. in tree disconnect)

 - Fix potential out of bounds write

 - Fix potential memory leak parsing lease state in open

 - Fix oops in rename with empty target

* tag 'v6.15-rc5-ksmbd-server-fixes' of git://git.samba.org/ksmbd:
  ksmbd: Fix UAF in __close_file_table_ids
  ksmbd: prevent out-of-bounds stream writes by validating *pos
  ksmbd: fix memory leak in parse_lease_state()
  ksmbd: prevent rename with empty string
parents d76bb1eb 36991c1c
Loading
Loading
Loading
Loading
+5 −2
Original line number Diff line number Diff line
@@ -1496,7 +1496,7 @@ struct lease_ctx_info *parse_lease_state(void *open_req)

		if (le16_to_cpu(cc->DataOffset) + le32_to_cpu(cc->DataLength) <
		    sizeof(struct create_lease_v2) - 4)
			return NULL;
			goto err_out;

		memcpy(lreq->lease_key, lc->lcontext.LeaseKey, SMB2_LEASE_KEY_SIZE);
		lreq->req_state = lc->lcontext.LeaseState;
@@ -1512,7 +1512,7 @@ struct lease_ctx_info *parse_lease_state(void *open_req)

		if (le16_to_cpu(cc->DataOffset) + le32_to_cpu(cc->DataLength) <
		    sizeof(struct create_lease))
			return NULL;
			goto err_out;

		memcpy(lreq->lease_key, lc->lcontext.LeaseKey, SMB2_LEASE_KEY_SIZE);
		lreq->req_state = lc->lcontext.LeaseState;
@@ -1521,6 +1521,9 @@ struct lease_ctx_info *parse_lease_state(void *open_req)
		lreq->version = 1;
	}
	return lreq;
err_out:
	kfree(lreq);
	return NULL;
}

/**
+5 −0
Original line number Diff line number Diff line
@@ -633,6 +633,11 @@ smb2_get_name(const char *src, const int maxlen, struct nls_table *local_nls)
		return name;
	}

	if (*name == '\0') {
		kfree(name);
		return ERR_PTR(-EINVAL);
	}

	if (*name == '\\') {
		pr_err("not allow directory name included leading slash\n");
		kfree(name);
+7 −0
Original line number Diff line number Diff line
@@ -426,6 +426,13 @@ static int ksmbd_vfs_stream_write(struct ksmbd_file *fp, char *buf, loff_t *pos,
		goto out;
	}

	if (v_len <= *pos) {
		pr_err("stream write position %lld is out of bounds (stream length: %zd)\n",
				*pos, v_len);
		err = -EINVAL;
		goto out;
	}

	if (v_len < size) {
		wbuf = kvzalloc(size, KSMBD_DEFAULT_GFP);
		if (!wbuf) {
+26 −7
Original line number Diff line number Diff line
@@ -661,21 +661,40 @@ __close_file_table_ids(struct ksmbd_file_table *ft,
		       bool (*skip)(struct ksmbd_tree_connect *tcon,
				    struct ksmbd_file *fp))
{
	unsigned int			id;
	struct ksmbd_file *fp;
	unsigned int id = 0;
	int num = 0;

	idr_for_each_entry(ft->idr, fp, id) {
		if (skip(tcon, fp))
	while (1) {
		write_lock(&ft->lock);
		fp = idr_get_next(ft->idr, &id);
		if (!fp) {
			write_unlock(&ft->lock);
			break;
		}

		if (skip(tcon, fp) ||
		    !atomic_dec_and_test(&fp->refcount)) {
			id++;
			write_unlock(&ft->lock);
			continue;
		}

		set_close_state_blocked_works(fp);
		idr_remove(ft->idr, fp->volatile_id);
		fp->volatile_id = KSMBD_NO_FID;
		write_unlock(&ft->lock);

		down_write(&fp->f_ci->m_lock);
		list_del_init(&fp->node);
		up_write(&fp->f_ci->m_lock);

		if (!atomic_dec_and_test(&fp->refcount))
			continue;
		__ksmbd_close_fd(ft, fp);

		num++;
		id++;
	}

	return num;
}