Commit 99ec1ed7 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag '6.4-rc6-smb3-server-fixes' of git://git.samba.org/ksmbd

Pull smb server fixes from Steve French:
 "Four smb3 server fixes, all also for stable:

   - fix potential oops in parsing compounded requests

   - fix various paths (mkdir, create etc) where mnt_want_write was not
     checked first

   - fix slab out of bounds in check_message and write"

* tag '6.4-rc6-smb3-server-fixes' of git://git.samba.org/ksmbd:
  ksmbd: validate session id and tree id in the compound request
  ksmbd: fix out-of-bound read in smb2_write
  ksmbd: add mnt_want_write to ksmbd vfs functions
  ksmbd: validate command payload size
parents 692b7dc8 5005bcb4
Loading
Loading
Loading
Loading
+20 −13
Original line number Diff line number Diff line
@@ -185,16 +185,24 @@ static void __handle_ksmbd_work(struct ksmbd_work *work,
		goto send;
	}

	do {
		if (conn->ops->check_user_session) {
			rc = conn->ops->check_user_session(work);
			if (rc < 0) {
			command = conn->ops->get_cmd_val(work);
				if (rc == -EINVAL)
					conn->ops->set_rsp_status(work,
						STATUS_INVALID_PARAMETER);
				else
					conn->ops->set_rsp_status(work,
						STATUS_USER_SESSION_DELETED);
				goto send;
			} else if (rc > 0) {
				rc = conn->ops->get_ksmbd_tcon(work);
				if (rc < 0) {
					if (rc == -EINVAL)
						conn->ops->set_rsp_status(work,
							STATUS_INVALID_PARAMETER);
					else
						conn->ops->set_rsp_status(work,
							STATUS_NETWORK_NAME_DELETED);
					goto send;
@@ -202,7 +210,6 @@ static void __handle_ksmbd_work(struct ksmbd_work *work,
			}
		}

	do {
		rc = __process_request(work, conn, &command);
		if (rc == SERVER_HANDLER_ABORT)
			break;
+20 −13
Original line number Diff line number Diff line
@@ -351,9 +351,16 @@ int ksmbd_smb2_check_message(struct ksmbd_work *work)
	int command;
	__u32 clc_len;  /* calculated length */
	__u32 len = get_rfc1002_len(work->request_buf);
	__u32 req_struct_size, next_cmd = le32_to_cpu(hdr->NextCommand);

	if (le32_to_cpu(hdr->NextCommand) > 0)
		len = le32_to_cpu(hdr->NextCommand);
	if ((u64)work->next_smb2_rcv_hdr_off + next_cmd > len) {
		pr_err("next command(%u) offset exceeds smb msg size\n",
				next_cmd);
		return 1;
	}

	if (next_cmd > 0)
		len = next_cmd;
	else if (work->next_smb2_rcv_hdr_off)
		len -= work->next_smb2_rcv_hdr_off;

@@ -373,15 +380,7 @@ int ksmbd_smb2_check_message(struct ksmbd_work *work)
	}

	if (smb2_req_struct_sizes[command] != pdu->StructureSize2) {
		if (command != SMB2_OPLOCK_BREAK_HE &&
		    (hdr->Status == 0 || pdu->StructureSize2 != SMB2_ERROR_STRUCTURE_SIZE2_LE)) {
			/* error packets have 9 byte structure size */
			ksmbd_debug(SMB,
				    "Illegal request size %u for command %d\n",
				    le16_to_cpu(pdu->StructureSize2), command);
			return 1;
		} else if (command == SMB2_OPLOCK_BREAK_HE &&
			   hdr->Status == 0 &&
		if (command == SMB2_OPLOCK_BREAK_HE &&
		    le16_to_cpu(pdu->StructureSize2) != OP_BREAK_STRUCT_SIZE_20 &&
		    le16_to_cpu(pdu->StructureSize2) != OP_BREAK_STRUCT_SIZE_21) {
			/* special case for SMB2.1 lease break message */
@@ -392,6 +391,14 @@ int ksmbd_smb2_check_message(struct ksmbd_work *work)
		}
	}

	req_struct_size = le16_to_cpu(pdu->StructureSize2) +
		__SMB2_HEADER_STRUCTURE_SIZE;
	if (command == SMB2_LOCK_HE)
		req_struct_size -= sizeof(struct smb2_lock_element);

	if (req_struct_size > len + 1)
		return 1;

	if (smb2_calc_size(hdr, &clc_len))
		return 1;

+50 −20
Original line number Diff line number Diff line
@@ -91,7 +91,6 @@ int smb2_get_ksmbd_tcon(struct ksmbd_work *work)
	unsigned int cmd = le16_to_cpu(req_hdr->Command);
	int tree_id;

	work->tcon = NULL;
	if (cmd == SMB2_TREE_CONNECT_HE ||
	    cmd ==  SMB2_CANCEL_HE ||
	    cmd ==  SMB2_LOGOFF_HE) {
@@ -105,10 +104,28 @@ int smb2_get_ksmbd_tcon(struct ksmbd_work *work)
	}

	tree_id = le32_to_cpu(req_hdr->Id.SyncId.TreeId);

	/*
	 * If request is not the first in Compound request,
	 * Just validate tree id in header with work->tcon->id.
	 */
	if (work->next_smb2_rcv_hdr_off) {
		if (!work->tcon) {
			pr_err("The first operation in the compound does not have tcon\n");
			return -EINVAL;
		}
		if (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;
		}
		return 1;
	}

	work->tcon = ksmbd_tree_conn_lookup(work->sess, tree_id);
	if (!work->tcon) {
		pr_err("Invalid tid %d\n", tree_id);
		return -EINVAL;
		return -ENOENT;
	}

	return 1;
@@ -547,7 +564,6 @@ int smb2_check_user_session(struct ksmbd_work *work)
	unsigned int cmd = conn->ops->get_cmd_val(work);
	unsigned long long sess_id;

	work->sess = NULL;
	/*
	 * SMB2_ECHO, SMB2_NEGOTIATE, SMB2_SESSION_SETUP command do not
	 * require a session id, so no need to validate user session's for
@@ -558,15 +574,33 @@ int smb2_check_user_session(struct ksmbd_work *work)
		return 0;

	if (!ksmbd_conn_good(conn))
		return -EINVAL;
		return -EIO;

	sess_id = le64_to_cpu(req_hdr->SessionId);

	/*
	 * If request is not the first in Compound request,
	 * Just validate session id in header with work->sess->id.
	 */
	if (work->next_smb2_rcv_hdr_off) {
		if (!work->sess) {
			pr_err("The first operation in the compound does not have sess\n");
			return -EINVAL;
		}
		if (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;
		}
		return 1;
	}

	/* Check for validity of user session */
	work->sess = ksmbd_session_lookup_all(conn, sess_id);
	if (work->sess)
		return 1;
	ksmbd_debug(SMB, "Invalid user session, Uid %llu\n", sess_id);
	return -EINVAL;
	return -ENOENT;
}

static void destroy_previous_session(struct ksmbd_conn *conn,
@@ -2249,7 +2283,7 @@ static int smb2_set_ea(struct smb2_ea_info *eabuf, unsigned int buf_len,
			/* delete the EA only when it exits */
			if (rc > 0) {
				rc = ksmbd_vfs_remove_xattr(idmap,
							    path->dentry,
							    path,
							    attr_name);

				if (rc < 0) {
@@ -2263,8 +2297,7 @@ static int smb2_set_ea(struct smb2_ea_info *eabuf, unsigned int buf_len,
			/* if the EA doesn't exist, just do nothing. */
			rc = 0;
		} else {
			rc = ksmbd_vfs_setxattr(idmap,
						path->dentry, attr_name, value,
			rc = ksmbd_vfs_setxattr(idmap, path, attr_name, value,
						le16_to_cpu(eabuf->EaValueLength), 0);
			if (rc < 0) {
				ksmbd_debug(SMB,
@@ -2321,8 +2354,7 @@ static noinline int smb2_set_stream_name_xattr(const struct path *path,
		return -EBADF;
	}

	rc = ksmbd_vfs_setxattr(idmap, path->dentry,
				xattr_stream_name, NULL, 0, 0);
	rc = ksmbd_vfs_setxattr(idmap, path, xattr_stream_name, NULL, 0, 0);
	if (rc < 0)
		pr_err("Failed to store XATTR stream name :%d\n", rc);
	return 0;
@@ -2350,7 +2382,7 @@ static int smb2_remove_smb_xattrs(const struct path *path)
		if (!strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN) &&
		    !strncmp(&name[XATTR_USER_PREFIX_LEN], STREAM_PREFIX,
			     STREAM_PREFIX_LEN)) {
			err = ksmbd_vfs_remove_xattr(idmap, path->dentry,
			err = ksmbd_vfs_remove_xattr(idmap, path,
						     name);
			if (err)
				ksmbd_debug(SMB, "remove xattr failed : %s\n",
@@ -2397,8 +2429,7 @@ static void smb2_new_xattrs(struct ksmbd_tree_connect *tcon, const struct path *
	da.flags = XATTR_DOSINFO_ATTRIB | XATTR_DOSINFO_CREATE_TIME |
		XATTR_DOSINFO_ITIME;

	rc = ksmbd_vfs_set_dos_attrib_xattr(mnt_idmap(path->mnt),
					    path->dentry, &da);
	rc = ksmbd_vfs_set_dos_attrib_xattr(mnt_idmap(path->mnt), path, &da);
	if (rc)
		ksmbd_debug(SMB, "failed to store file attribute into xattr\n");
}
@@ -2972,7 +3003,7 @@ int smb2_open(struct ksmbd_work *work)
		struct inode *inode = d_inode(path.dentry);

		posix_acl_rc = ksmbd_vfs_inherit_posix_acl(idmap,
							   path.dentry,
							   &path,
							   d_inode(path.dentry->d_parent));
		if (posix_acl_rc)
			ksmbd_debug(SMB, "inherit posix acl failed : %d\n", posix_acl_rc);
@@ -2988,7 +3019,7 @@ int smb2_open(struct ksmbd_work *work)
			if (rc) {
				if (posix_acl_rc)
					ksmbd_vfs_set_init_posix_acl(idmap,
								     path.dentry);
								     &path);

				if (test_share_config_flag(work->tcon->share_conf,
							   KSMBD_SHARE_FLAG_ACL_XATTR)) {
@@ -3028,7 +3059,7 @@ int smb2_open(struct ksmbd_work *work)

					rc = ksmbd_vfs_set_sd_xattr(conn,
								    idmap,
								    path.dentry,
								    &path,
								    pntsd,
								    pntsd_size);
					kfree(pntsd);
@@ -5464,7 +5495,7 @@ static int smb2_rename(struct ksmbd_work *work,
			goto out;

		rc = ksmbd_vfs_setxattr(file_mnt_idmap(fp->filp),
					fp->filp->f_path.dentry,
					&fp->filp->f_path,
					xattr_stream_name,
					NULL, 0, 0);
		if (rc < 0) {
@@ -5629,8 +5660,7 @@ static int set_file_basic_info(struct ksmbd_file *fp,
		da.flags = XATTR_DOSINFO_ATTRIB | XATTR_DOSINFO_CREATE_TIME |
			XATTR_DOSINFO_ITIME;

		rc = ksmbd_vfs_set_dos_attrib_xattr(idmap,
						    filp->f_path.dentry, &da);
		rc = ksmbd_vfs_set_dos_attrib_xattr(idmap, &filp->f_path, &da);
		if (rc)
			ksmbd_debug(SMB,
				    "failed to restore file attribute in EA\n");
@@ -7485,7 +7515,7 @@ static inline int fsctl_set_sparse(struct ksmbd_work *work, u64 id,

		da.attr = le32_to_cpu(fp->f_ci->m_fattr);
		ret = ksmbd_vfs_set_dos_attrib_xattr(idmap,
						     fp->filp->f_path.dentry, &da);
						     &fp->filp->f_path, &da);
		if (ret)
			fp->f_ci->m_fattr = old_fattr;
	}
+4 −6
Original line number Diff line number Diff line
@@ -1162,8 +1162,7 @@ int smb_inherit_dacl(struct ksmbd_conn *conn,
			pntsd_size += sizeof(struct smb_acl) + nt_size;
		}

		ksmbd_vfs_set_sd_xattr(conn, idmap,
				       path->dentry, pntsd, pntsd_size);
		ksmbd_vfs_set_sd_xattr(conn, idmap, path, pntsd, pntsd_size);
		kfree(pntsd);
	}

@@ -1383,7 +1382,7 @@ int set_info_sec(struct ksmbd_conn *conn, struct ksmbd_tree_connect *tcon,
	newattrs.ia_valid |= ATTR_MODE;
	newattrs.ia_mode = (inode->i_mode & ~0777) | (fattr.cf_mode & 0777);

	ksmbd_vfs_remove_acl_xattrs(idmap, path->dentry);
	ksmbd_vfs_remove_acl_xattrs(idmap, path);
	/* Update posix acls */
	if (IS_ENABLED(CONFIG_FS_POSIX_ACL) && fattr.cf_dacls) {
		rc = set_posix_acl(idmap, path->dentry,
@@ -1414,9 +1413,8 @@ int set_info_sec(struct ksmbd_conn *conn, struct ksmbd_tree_connect *tcon,

	if (test_share_config_flag(tcon->share_conf, KSMBD_SHARE_FLAG_ACL_XATTR)) {
		/* Update WinACL in xattr */
		ksmbd_vfs_remove_sd_xattrs(idmap, path->dentry);
		ksmbd_vfs_set_sd_xattr(conn, idmap,
				       path->dentry, pntsd, ntsd_len);
		ksmbd_vfs_remove_sd_xattrs(idmap, path);
		ksmbd_vfs_set_sd_xattr(conn, idmap, path, pntsd, ntsd_len);
	}

out:
+93 −24
Original line number Diff line number Diff line
@@ -170,6 +170,10 @@ int ksmbd_vfs_create(struct ksmbd_work *work, const char *name, umode_t mode)
		return err;
	}

	err = mnt_want_write(path.mnt);
	if (err)
		goto out_err;

	mode |= S_IFREG;
	err = vfs_create(mnt_idmap(path.mnt), d_inode(path.dentry),
			 dentry, mode, true);
@@ -179,6 +183,9 @@ int ksmbd_vfs_create(struct ksmbd_work *work, const char *name, umode_t mode)
	} else {
		pr_err("File(%s): creation failed (err:%d)\n", name, err);
	}
	mnt_drop_write(path.mnt);

out_err:
	done_path_create(&path, dentry);
	return err;
}
@@ -209,30 +216,35 @@ int ksmbd_vfs_mkdir(struct ksmbd_work *work, const char *name, umode_t mode)
		return err;
	}

	err = mnt_want_write(path.mnt);
	if (err)
		goto out_err2;

	idmap = mnt_idmap(path.mnt);
	mode |= S_IFDIR;
	err = vfs_mkdir(idmap, d_inode(path.dentry), dentry, mode);
	if (err) {
		goto out;
	} else if (d_unhashed(dentry)) {
	if (!err && d_unhashed(dentry)) {
		struct dentry *d;

		d = lookup_one(idmap, dentry->d_name.name, dentry->d_parent,
			       dentry->d_name.len);
		if (IS_ERR(d)) {
			err = PTR_ERR(d);
			goto out;
			goto out_err1;
		}
		if (unlikely(d_is_negative(d))) {
			dput(d);
			err = -ENOENT;
			goto out;
			goto out_err1;
		}

		ksmbd_vfs_inherit_owner(work, d_inode(path.dentry), d_inode(d));
		dput(d);
	}
out:

out_err1:
	mnt_drop_write(path.mnt);
out_err2:
	done_path_create(&path, dentry);
	if (err)
		pr_err("mkdir(%s): creation failed (err:%d)\n", name, err);
@@ -443,7 +455,7 @@ static int ksmbd_vfs_stream_write(struct ksmbd_file *fp, char *buf, loff_t *pos,
	memcpy(&stream_buf[*pos], buf, count);

	err = ksmbd_vfs_setxattr(idmap,
				 fp->filp->f_path.dentry,
				 &fp->filp->f_path,
				 fp->stream.name,
				 (void *)stream_buf,
				 size,
@@ -589,6 +601,10 @@ int ksmbd_vfs_remove_file(struct ksmbd_work *work, const struct path *path)
		goto out_err;
	}

	err = mnt_want_write(path->mnt);
	if (err)
		goto out_err;

	idmap = mnt_idmap(path->mnt);
	if (S_ISDIR(d_inode(path->dentry)->i_mode)) {
		err = vfs_rmdir(idmap, d_inode(parent), path->dentry);
@@ -599,6 +615,7 @@ int ksmbd_vfs_remove_file(struct ksmbd_work *work, const struct path *path)
		if (err)
			ksmbd_debug(VFS, "unlink failed, err %d\n", err);
	}
	mnt_drop_write(path->mnt);

out_err:
	ksmbd_revert_fsids(work);
@@ -644,11 +661,16 @@ int ksmbd_vfs_link(struct ksmbd_work *work, const char *oldname,
		goto out3;
	}

	err = mnt_want_write(newpath.mnt);
	if (err)
		goto out3;

	err = vfs_link(oldpath.dentry, mnt_idmap(newpath.mnt),
		       d_inode(newpath.dentry),
		       dentry, NULL);
	if (err)
		ksmbd_debug(VFS, "vfs_link failed err %d\n", err);
	mnt_drop_write(newpath.mnt);

out3:
	done_path_create(&newpath, dentry);
@@ -694,6 +716,10 @@ int ksmbd_vfs_rename(struct ksmbd_work *work, const struct path *old_path,
		goto out2;
	}

	err = mnt_want_write(old_path->mnt);
	if (err)
		goto out2;

	trap = lock_rename_child(old_child, new_path.dentry);

	old_parent = dget(old_child->d_parent);
@@ -757,6 +783,7 @@ int ksmbd_vfs_rename(struct ksmbd_work *work, const struct path *old_path,
out3:
	dput(old_parent);
	unlock_rename(old_parent, new_path.dentry);
	mnt_drop_write(old_path->mnt);
out2:
	path_put(&new_path);

@@ -897,19 +924,24 @@ ssize_t ksmbd_vfs_getxattr(struct mnt_idmap *idmap,
 * Return:	0 on success, otherwise error
 */
int ksmbd_vfs_setxattr(struct mnt_idmap *idmap,
		       struct dentry *dentry, const char *attr_name,
		       const struct path *path, const char *attr_name,
		       void *attr_value, size_t attr_size, int flags)
{
	int err;

	err = mnt_want_write(path->mnt);
	if (err)
		return err;

	err = vfs_setxattr(idmap,
			   dentry,
			   path->dentry,
			   attr_name,
			   attr_value,
			   attr_size,
			   flags);
	if (err)
		ksmbd_debug(VFS, "setxattr failed, err %d\n", err);
	mnt_drop_write(path->mnt);
	return err;
}

@@ -1013,9 +1045,18 @@ int ksmbd_vfs_fqar_lseek(struct ksmbd_file *fp, loff_t start, loff_t length,
}

int ksmbd_vfs_remove_xattr(struct mnt_idmap *idmap,
			   struct dentry *dentry, char *attr_name)
			   const struct path *path, char *attr_name)
{
	return vfs_removexattr(idmap, dentry, attr_name);
	int err;

	err = mnt_want_write(path->mnt);
	if (err)
		return err;

	err = vfs_removexattr(idmap, path->dentry, attr_name);
	mnt_drop_write(path->mnt);

	return err;
}

int ksmbd_vfs_unlink(struct file *filp)
@@ -1024,6 +1065,10 @@ int ksmbd_vfs_unlink(struct file *filp)
	struct dentry *dir, *dentry = filp->f_path.dentry;
	struct mnt_idmap *idmap = file_mnt_idmap(filp);

	err = mnt_want_write(filp->f_path.mnt);
	if (err)
		return err;

	dir = dget_parent(dentry);
	err = ksmbd_vfs_lock_parent(dir, dentry);
	if (err)
@@ -1041,6 +1086,7 @@ int ksmbd_vfs_unlink(struct file *filp)
		ksmbd_debug(VFS, "failed to delete, err %d\n", err);
out:
	dput(dir);
	mnt_drop_write(filp->f_path.mnt);

	return err;
}
@@ -1244,13 +1290,13 @@ struct dentry *ksmbd_vfs_kern_path_create(struct ksmbd_work *work,
}

int ksmbd_vfs_remove_acl_xattrs(struct mnt_idmap *idmap,
				struct dentry *dentry)
				const struct path *path)
{
	char *name, *xattr_list = NULL;
	ssize_t xattr_list_len;
	int err = 0;

	xattr_list_len = ksmbd_vfs_listxattr(dentry, &xattr_list);
	xattr_list_len = ksmbd_vfs_listxattr(path->dentry, &xattr_list);
	if (xattr_list_len < 0) {
		goto out;
	} else if (!xattr_list_len) {
@@ -1258,6 +1304,10 @@ int ksmbd_vfs_remove_acl_xattrs(struct mnt_idmap *idmap,
		goto out;
	}

	err = mnt_want_write(path->mnt);
	if (err)
		goto out;

	for (name = xattr_list; name - xattr_list < xattr_list_len;
	     name += strlen(name) + 1) {
		ksmbd_debug(SMB, "%s, len %zd\n", name, strlen(name));
@@ -1266,25 +1316,26 @@ int ksmbd_vfs_remove_acl_xattrs(struct mnt_idmap *idmap,
			     sizeof(XATTR_NAME_POSIX_ACL_ACCESS) - 1) ||
		    !strncmp(name, XATTR_NAME_POSIX_ACL_DEFAULT,
			     sizeof(XATTR_NAME_POSIX_ACL_DEFAULT) - 1)) {
			err = vfs_remove_acl(idmap, dentry, name);
			err = vfs_remove_acl(idmap, path->dentry, name);
			if (err)
				ksmbd_debug(SMB,
					    "remove acl xattr failed : %s\n", name);
		}
	}
	mnt_drop_write(path->mnt);

out:
	kvfree(xattr_list);
	return err;
}

int ksmbd_vfs_remove_sd_xattrs(struct mnt_idmap *idmap,
			       struct dentry *dentry)
int ksmbd_vfs_remove_sd_xattrs(struct mnt_idmap *idmap, const struct path *path)
{
	char *name, *xattr_list = NULL;
	ssize_t xattr_list_len;
	int err = 0;

	xattr_list_len = ksmbd_vfs_listxattr(dentry, &xattr_list);
	xattr_list_len = ksmbd_vfs_listxattr(path->dentry, &xattr_list);
	if (xattr_list_len < 0) {
		goto out;
	} else if (!xattr_list_len) {
@@ -1297,7 +1348,7 @@ int ksmbd_vfs_remove_sd_xattrs(struct mnt_idmap *idmap,
		ksmbd_debug(SMB, "%s, len %zd\n", name, strlen(name));

		if (!strncmp(name, XATTR_NAME_SD, XATTR_NAME_SD_LEN)) {
			err = ksmbd_vfs_remove_xattr(idmap, dentry, name);
			err = ksmbd_vfs_remove_xattr(idmap, path, name);
			if (err)
				ksmbd_debug(SMB, "remove xattr failed : %s\n", name);
		}
@@ -1374,13 +1425,14 @@ static struct xattr_smb_acl *ksmbd_vfs_make_xattr_posix_acl(struct mnt_idmap *id

int ksmbd_vfs_set_sd_xattr(struct ksmbd_conn *conn,
			   struct mnt_idmap *idmap,
			   struct dentry *dentry,
			   const struct path *path,
			   struct smb_ntsd *pntsd, int len)
{
	int rc;
	struct ndr sd_ndr = {0}, acl_ndr = {0};
	struct xattr_ntacl acl = {0};
	struct xattr_smb_acl *smb_acl, *def_smb_acl = NULL;
	struct dentry *dentry = path->dentry;
	struct inode *inode = d_inode(dentry);

	acl.version = 4;
@@ -1432,7 +1484,7 @@ int ksmbd_vfs_set_sd_xattr(struct ksmbd_conn *conn,
		goto out;
	}

	rc = ksmbd_vfs_setxattr(idmap, dentry,
	rc = ksmbd_vfs_setxattr(idmap, path,
				XATTR_NAME_SD, sd_ndr.data,
				sd_ndr.offset, 0);
	if (rc < 0)
@@ -1522,7 +1574,7 @@ int ksmbd_vfs_get_sd_xattr(struct ksmbd_conn *conn,
}

int ksmbd_vfs_set_dos_attrib_xattr(struct mnt_idmap *idmap,
				   struct dentry *dentry,
				   const struct path *path,
				   struct xattr_dos_attrib *da)
{
	struct ndr n;
@@ -1532,7 +1584,7 @@ int ksmbd_vfs_set_dos_attrib_xattr(struct mnt_idmap *idmap,
	if (err)
		return err;

	err = ksmbd_vfs_setxattr(idmap, dentry, XATTR_NAME_DOS_ATTRIBUTE,
	err = ksmbd_vfs_setxattr(idmap, path, XATTR_NAME_DOS_ATTRIBUTE,
				 (void *)n.data, n.offset, 0);
	if (err)
		ksmbd_debug(SMB, "failed to store dos attribute in xattr\n");
@@ -1769,10 +1821,11 @@ void ksmbd_vfs_posix_lock_unblock(struct file_lock *flock)
}

int ksmbd_vfs_set_init_posix_acl(struct mnt_idmap *idmap,
				 struct dentry *dentry)
				 struct path *path)
{
	struct posix_acl_state acl_state;
	struct posix_acl *acls;
	struct dentry *dentry = path->dentry;
	struct inode *inode = d_inode(dentry);
	int rc;

@@ -1802,6 +1855,11 @@ int ksmbd_vfs_set_init_posix_acl(struct mnt_idmap *idmap,
		return -ENOMEM;
	}
	posix_state_to_acl(&acl_state, acls->a_entries);

	rc = mnt_want_write(path->mnt);
	if (rc)
		goto out_err;

	rc = set_posix_acl(idmap, dentry, ACL_TYPE_ACCESS, acls);
	if (rc < 0)
		ksmbd_debug(SMB, "Set posix acl(ACL_TYPE_ACCESS) failed, rc : %d\n",
@@ -1813,16 +1871,20 @@ int ksmbd_vfs_set_init_posix_acl(struct mnt_idmap *idmap,
			ksmbd_debug(SMB, "Set posix acl(ACL_TYPE_DEFAULT) failed, rc : %d\n",
				    rc);
	}
	mnt_drop_write(path->mnt);

out_err:
	free_acl_state(&acl_state);
	posix_acl_release(acls);
	return rc;
}

int ksmbd_vfs_inherit_posix_acl(struct mnt_idmap *idmap,
				struct dentry *dentry, struct inode *parent_inode)
				struct path *path, struct inode *parent_inode)
{
	struct posix_acl *acls;
	struct posix_acl_entry *pace;
	struct dentry *dentry = path->dentry;
	struct inode *inode = d_inode(dentry);
	int rc, i;

@@ -1841,6 +1903,10 @@ int ksmbd_vfs_inherit_posix_acl(struct mnt_idmap *idmap,
		}
	}

	rc = mnt_want_write(path->mnt);
	if (rc)
		goto out_err;

	rc = set_posix_acl(idmap, dentry, ACL_TYPE_ACCESS, acls);
	if (rc < 0)
		ksmbd_debug(SMB, "Set posix acl(ACL_TYPE_ACCESS) failed, rc : %d\n",
@@ -1852,6 +1918,9 @@ int ksmbd_vfs_inherit_posix_acl(struct mnt_idmap *idmap,
			ksmbd_debug(SMB, "Set posix acl(ACL_TYPE_DEFAULT) failed, rc : %d\n",
				    rc);
	}
	mnt_drop_write(path->mnt);

out_err:
	posix_acl_release(acls);
	return rc;
}
Loading