Commit f40125c0 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag '6.5-rc3-ksmbd-server-fixes' of git://git.samba.org/ksmbd

Pull ksmbd server fixes from Steve French:

 - fixes for two possible out of bounds access (in negotiate, and in
   decrypt msg)

 - fix unsigned compared to zero warning

 - fix path lookup crossing a mountpoint

 - fix case when first compound request is a tree connect

 - fix memory leak if reads are compounded

* tag '6.5-rc3-ksmbd-server-fixes' of git://git.samba.org/ksmbd:
  ksmbd: fix out of bounds in init_smb2_rsp_hdr()
  ksmbd: no response from compound read
  ksmbd: validate session id and tree id in compound request
  ksmbd: fix out of bounds in smb3_decrypt_req()
  ksmbd: check if a mount point is crossed during path lookup
  ksmbd: Fix unsigned expression compared with zero
parents 5f0bc0b0 536bb492
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -353,6 +353,7 @@ enum KSMBD_TREE_CONN_STATUS {
#define KSMBD_SHARE_FLAG_FOLLOW_SYMLINKS	BIT(12)
#define KSMBD_SHARE_FLAG_ACL_XATTR		BIT(13)
#define KSMBD_SHARE_FLAG_UPDATE			BIT(14)
#define KSMBD_SHARE_FLAG_CROSSMNT		BIT(15)

/*
 * Tree connect request flags.
+6 −1
Original line number Diff line number Diff line
@@ -286,6 +286,7 @@ static void handle_ksmbd_work(struct work_struct *wk)
static int queue_ksmbd_work(struct ksmbd_conn *conn)
{
	struct ksmbd_work *work;
	int err;

	work = ksmbd_alloc_work_struct();
	if (!work) {
@@ -297,7 +298,11 @@ static int queue_ksmbd_work(struct ksmbd_conn *conn)
	work->request_buf = conn->request_buf;
	conn->request_buf = NULL;

	ksmbd_init_smb_server(work);
	err = ksmbd_init_smb_server(work);
	if (err) {
		ksmbd_free_work_struct(work);
		return 0;
	}

	ksmbd_conn_enqueue_request(work);
	atomic_inc(&conn->r_count);
+29 −18
Original line number Diff line number Diff line
@@ -87,9 +87,9 @@ struct channel *lookup_chann_list(struct ksmbd_session *sess, struct ksmbd_conn
 */
int smb2_get_ksmbd_tcon(struct ksmbd_work *work)
{
	struct smb2_hdr *req_hdr = smb2_get_msg(work->request_buf);
	struct smb2_hdr *req_hdr = ksmbd_req_buf_next(work);
	unsigned int cmd = le16_to_cpu(req_hdr->Command);
	int tree_id;
	unsigned int tree_id;

	if (cmd == SMB2_TREE_CONNECT_HE ||
	    cmd ==  SMB2_CANCEL_HE ||
@@ -114,7 +114,7 @@ int smb2_get_ksmbd_tcon(struct ksmbd_work *work)
			pr_err("The first operation in the compound does not have tcon\n");
			return -EINVAL;
		}
		if (work->tcon->id != tree_id) {
		if (tree_id != UINT_MAX && work->tcon->id != tree_id) {
			pr_err("tree id(%u) is different with id(%u) in first operation\n",
					tree_id, work->tcon->id);
			return -EINVAL;
@@ -559,9 +559,9 @@ int smb2_allocate_rsp_buf(struct ksmbd_work *work)
 */
int smb2_check_user_session(struct ksmbd_work *work)
{
	struct smb2_hdr *req_hdr = smb2_get_msg(work->request_buf);
	struct smb2_hdr *req_hdr = ksmbd_req_buf_next(work);
	struct ksmbd_conn *conn = work->conn;
	unsigned int cmd = conn->ops->get_cmd_val(work);
	unsigned int cmd = le16_to_cpu(req_hdr->Command);
	unsigned long long sess_id;

	/*
@@ -587,7 +587,7 @@ int smb2_check_user_session(struct ksmbd_work *work)
			pr_err("The first operation in the compound does not have sess\n");
			return -EINVAL;
		}
		if (work->sess->id != sess_id) {
		if (sess_id != ULLONG_MAX && work->sess->id != sess_id) {
			pr_err("session id(%llu) is different with the first operation(%lld)\n",
					sess_id, work->sess->id);
			return -EINVAL;
@@ -2467,8 +2467,9 @@ static void smb2_update_xattrs(struct ksmbd_tree_connect *tcon,
	}
}

static int smb2_creat(struct ksmbd_work *work, struct path *path, char *name,
		      int open_flags, umode_t posix_mode, bool is_dir)
static int smb2_creat(struct ksmbd_work *work, struct path *parent_path,
		      struct path *path, char *name, int open_flags,
		      umode_t posix_mode, bool is_dir)
{
	struct ksmbd_tree_connect *tcon = work->tcon;
	struct ksmbd_share_config *share = tcon->share_conf;
@@ -2495,7 +2496,7 @@ static int smb2_creat(struct ksmbd_work *work, struct path *path, char *name,
			return rc;
	}

	rc = ksmbd_vfs_kern_path_locked(work, name, 0, path, 0);
	rc = ksmbd_vfs_kern_path_locked(work, name, 0, parent_path, path, 0);
	if (rc) {
		pr_err("cannot get linux path (%s), err = %d\n",
		       name, rc);
@@ -2565,7 +2566,7 @@ int smb2_open(struct ksmbd_work *work)
	struct ksmbd_tree_connect *tcon = work->tcon;
	struct smb2_create_req *req;
	struct smb2_create_rsp *rsp;
	struct path path;
	struct path path, parent_path;
	struct ksmbd_share_config *share = tcon->share_conf;
	struct ksmbd_file *fp = NULL;
	struct file *filp = NULL;
@@ -2786,7 +2787,8 @@ int smb2_open(struct ksmbd_work *work)
		goto err_out1;
	}

	rc = ksmbd_vfs_kern_path_locked(work, name, LOOKUP_NO_SYMLINKS, &path, 1);
	rc = ksmbd_vfs_kern_path_locked(work, name, LOOKUP_NO_SYMLINKS,
					&parent_path, &path, 1);
	if (!rc) {
		file_present = true;

@@ -2906,7 +2908,8 @@ int smb2_open(struct ksmbd_work *work)

	/*create file if not present */
	if (!file_present) {
		rc = smb2_creat(work, &path, name, open_flags, posix_mode,
		rc = smb2_creat(work, &parent_path, &path, name, open_flags,
				posix_mode,
				req->CreateOptions & FILE_DIRECTORY_FILE_LE);
		if (rc) {
			if (rc == -ENOENT) {
@@ -3321,8 +3324,9 @@ int smb2_open(struct ksmbd_work *work)

err_out:
	if (file_present || created) {
		inode_unlock(d_inode(path.dentry->d_parent));
		dput(path.dentry);
		inode_unlock(d_inode(parent_path.dentry));
		path_put(&path);
		path_put(&parent_path);
	}
	ksmbd_revert_fsids(work);
err_out1:
@@ -5545,7 +5549,7 @@ static int smb2_create_link(struct ksmbd_work *work,
			    struct nls_table *local_nls)
{
	char *link_name = NULL, *target_name = NULL, *pathname = NULL;
	struct path path;
	struct path path, parent_path;
	bool file_present = false;
	int rc;

@@ -5575,7 +5579,7 @@ static int smb2_create_link(struct ksmbd_work *work,

	ksmbd_debug(SMB, "target name is %s\n", target_name);
	rc = ksmbd_vfs_kern_path_locked(work, link_name, LOOKUP_NO_SYMLINKS,
					&path, 0);
					&parent_path, &path, 0);
	if (rc) {
		if (rc != -ENOENT)
			goto out;
@@ -5605,8 +5609,9 @@ static int smb2_create_link(struct ksmbd_work *work,
		rc = -EINVAL;
out:
	if (file_present) {
		inode_unlock(d_inode(path.dentry->d_parent));
		inode_unlock(d_inode(parent_path.dentry));
		path_put(&path);
		path_put(&parent_path);
	}
	if (!IS_ERR(link_name))
		kfree(link_name);
@@ -6209,6 +6214,11 @@ int smb2_read(struct ksmbd_work *work)
	unsigned int max_read_size = conn->vals->max_read_size;

	WORK_BUFFERS(work, req, rsp);
	if (work->next_smb2_rcv_hdr_off) {
		work->send_no_response = 1;
		err = -EOPNOTSUPP;
		goto out;
	}

	if (test_share_config_flag(work->tcon->share_conf,
				   KSMBD_SHARE_FLAG_PIPE)) {
@@ -8609,7 +8619,8 @@ int smb3_decrypt_req(struct ksmbd_work *work)
	struct smb2_transform_hdr *tr_hdr = smb2_get_msg(buf);
	int rc = 0;

	if (buf_data_size < sizeof(struct smb2_hdr)) {
	if (pdu_length < sizeof(struct smb2_transform_hdr) ||
	    buf_data_size < sizeof(struct smb2_hdr)) {
		pr_err("Transform message is too small (%u)\n",
		       pdu_length);
		return -ECONNABORTED;
+11 −8
Original line number Diff line number Diff line
@@ -388,26 +388,29 @@ static struct smb_version_cmds smb1_server_cmds[1] = {
	[SMB_COM_NEGOTIATE_EX]	= { .proc = smb1_negotiate, },
};

static void init_smb1_server(struct ksmbd_conn *conn)
static int init_smb1_server(struct ksmbd_conn *conn)
{
	conn->ops = &smb1_server_ops;
	conn->cmds = smb1_server_cmds;
	conn->max_cmds = ARRAY_SIZE(smb1_server_cmds);
	return 0;
}

void ksmbd_init_smb_server(struct ksmbd_work *work)
int ksmbd_init_smb_server(struct ksmbd_work *work)
{
	struct ksmbd_conn *conn = work->conn;
	__le32 proto;

	if (conn->need_neg == false)
		return;

	proto = *(__le32 *)((struct smb_hdr *)work->request_buf)->Protocol;
	if (conn->need_neg == false) {
		if (proto == SMB1_PROTO_NUMBER)
		init_smb1_server(conn);
	else
		init_smb3_11_server(conn);
			return -EINVAL;
		return 0;
	}

	if (proto == SMB1_PROTO_NUMBER)
		return init_smb1_server(conn);
	return init_smb3_11_server(conn);
}

int ksmbd_populate_dot_dotdot_entries(struct ksmbd_work *work, int info_level,
+1 −1
Original line number Diff line number Diff line
@@ -427,7 +427,7 @@ bool ksmbd_smb_request(struct ksmbd_conn *conn);

int ksmbd_lookup_dialect_by_id(__le16 *cli_dialects, __le16 dialects_count);

void ksmbd_init_smb_server(struct ksmbd_work *work);
int ksmbd_init_smb_server(struct ksmbd_work *work);

struct ksmbd_kstat;
int ksmbd_populate_dot_dotdot_entries(struct ksmbd_work *work,
Loading