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

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
...@@ -185,24 +185,31 @@ static void __handle_ksmbd_work(struct ksmbd_work *work, ...@@ -185,24 +185,31 @@ static void __handle_ksmbd_work(struct ksmbd_work *work,
goto send; goto send;
} }
if (conn->ops->check_user_session) { do {
rc = conn->ops->check_user_session(work); if (conn->ops->check_user_session) {
if (rc < 0) { rc = conn->ops->check_user_session(work);
command = conn->ops->get_cmd_val(work);
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 < 0) {
conn->ops->set_rsp_status(work, if (rc == -EINVAL)
STATUS_NETWORK_NAME_DELETED); conn->ops->set_rsp_status(work,
STATUS_INVALID_PARAMETER);
else
conn->ops->set_rsp_status(work,
STATUS_USER_SESSION_DELETED);
goto send; 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;
}
} }
} }
}
do {
rc = __process_request(work, conn, &command); rc = __process_request(work, conn, &command);
if (rc == SERVER_HANDLER_ABORT) if (rc == SERVER_HANDLER_ABORT)
break; break;
......
...@@ -351,9 +351,16 @@ int ksmbd_smb2_check_message(struct ksmbd_work *work) ...@@ -351,9 +351,16 @@ int ksmbd_smb2_check_message(struct ksmbd_work *work)
int command; int command;
__u32 clc_len; /* calculated length */ __u32 clc_len; /* calculated length */
__u32 len = get_rfc1002_len(work->request_buf); __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) if ((u64)work->next_smb2_rcv_hdr_off + next_cmd > len) {
len = le32_to_cpu(hdr->NextCommand); 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) else if (work->next_smb2_rcv_hdr_off)
len -= work->next_smb2_rcv_hdr_off; len -= work->next_smb2_rcv_hdr_off;
...@@ -373,17 +380,9 @@ int ksmbd_smb2_check_message(struct ksmbd_work *work) ...@@ -373,17 +380,9 @@ int ksmbd_smb2_check_message(struct ksmbd_work *work)
} }
if (smb2_req_struct_sizes[command] != pdu->StructureSize2) { if (smb2_req_struct_sizes[command] != pdu->StructureSize2) {
if (command != SMB2_OPLOCK_BREAK_HE && if (command == SMB2_OPLOCK_BREAK_HE &&
(hdr->Status == 0 || pdu->StructureSize2 != SMB2_ERROR_STRUCTURE_SIZE2_LE)) { le16_to_cpu(pdu->StructureSize2) != OP_BREAK_STRUCT_SIZE_20 &&
/* error packets have 9 byte structure size */ le16_to_cpu(pdu->StructureSize2) != OP_BREAK_STRUCT_SIZE_21) {
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 &&
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 */ /* special case for SMB2.1 lease break message */
ksmbd_debug(SMB, ksmbd_debug(SMB,
"Illegal request size %d for oplock break\n", "Illegal request size %d for oplock break\n",
...@@ -392,6 +391,14 @@ int ksmbd_smb2_check_message(struct ksmbd_work *work) ...@@ -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)) if (smb2_calc_size(hdr, &clc_len))
return 1; return 1;
......
...@@ -91,7 +91,6 @@ int smb2_get_ksmbd_tcon(struct ksmbd_work *work) ...@@ -91,7 +91,6 @@ int smb2_get_ksmbd_tcon(struct ksmbd_work *work)
unsigned int cmd = le16_to_cpu(req_hdr->Command); unsigned int cmd = le16_to_cpu(req_hdr->Command);
int tree_id; int tree_id;
work->tcon = NULL;
if (cmd == SMB2_TREE_CONNECT_HE || if (cmd == SMB2_TREE_CONNECT_HE ||
cmd == SMB2_CANCEL_HE || cmd == SMB2_CANCEL_HE ||
cmd == SMB2_LOGOFF_HE) { cmd == SMB2_LOGOFF_HE) {
...@@ -105,10 +104,28 @@ int smb2_get_ksmbd_tcon(struct ksmbd_work *work) ...@@ -105,10 +104,28 @@ int smb2_get_ksmbd_tcon(struct ksmbd_work *work)
} }
tree_id = le32_to_cpu(req_hdr->Id.SyncId.TreeId); 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); work->tcon = ksmbd_tree_conn_lookup(work->sess, tree_id);
if (!work->tcon) { if (!work->tcon) {
pr_err("Invalid tid %d\n", tree_id); pr_err("Invalid tid %d\n", tree_id);
return -EINVAL; return -ENOENT;
} }
return 1; return 1;
...@@ -547,7 +564,6 @@ int smb2_check_user_session(struct ksmbd_work *work) ...@@ -547,7 +564,6 @@ int smb2_check_user_session(struct ksmbd_work *work)
unsigned int cmd = conn->ops->get_cmd_val(work); unsigned int cmd = conn->ops->get_cmd_val(work);
unsigned long long sess_id; unsigned long long sess_id;
work->sess = NULL;
/* /*
* SMB2_ECHO, SMB2_NEGOTIATE, SMB2_SESSION_SETUP command do not * SMB2_ECHO, SMB2_NEGOTIATE, SMB2_SESSION_SETUP command do not
* require a session id, so no need to validate user session's for * 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) ...@@ -558,15 +574,33 @@ int smb2_check_user_session(struct ksmbd_work *work)
return 0; return 0;
if (!ksmbd_conn_good(conn)) if (!ksmbd_conn_good(conn))
return -EINVAL; return -EIO;
sess_id = le64_to_cpu(req_hdr->SessionId); 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 */ /* Check for validity of user session */
work->sess = ksmbd_session_lookup_all(conn, sess_id); work->sess = ksmbd_session_lookup_all(conn, sess_id);
if (work->sess) if (work->sess)
return 1; return 1;
ksmbd_debug(SMB, "Invalid user session, Uid %llu\n", sess_id); ksmbd_debug(SMB, "Invalid user session, Uid %llu\n", sess_id);
return -EINVAL; return -ENOENT;
} }
static void destroy_previous_session(struct ksmbd_conn *conn, 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, ...@@ -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 */ /* delete the EA only when it exits */
if (rc > 0) { if (rc > 0) {
rc = ksmbd_vfs_remove_xattr(idmap, rc = ksmbd_vfs_remove_xattr(idmap,
path->dentry, path,
attr_name); attr_name);
if (rc < 0) { if (rc < 0) {
...@@ -2263,8 +2297,7 @@ static int smb2_set_ea(struct smb2_ea_info *eabuf, unsigned int buf_len, ...@@ -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. */ /* if the EA doesn't exist, just do nothing. */
rc = 0; rc = 0;
} else { } else {
rc = ksmbd_vfs_setxattr(idmap, rc = ksmbd_vfs_setxattr(idmap, path, attr_name, value,
path->dentry, attr_name, value,
le16_to_cpu(eabuf->EaValueLength), 0); le16_to_cpu(eabuf->EaValueLength), 0);
if (rc < 0) { if (rc < 0) {
ksmbd_debug(SMB, ksmbd_debug(SMB,
...@@ -2321,8 +2354,7 @@ static noinline int smb2_set_stream_name_xattr(const struct path *path, ...@@ -2321,8 +2354,7 @@ static noinline int smb2_set_stream_name_xattr(const struct path *path,
return -EBADF; return -EBADF;
} }
rc = ksmbd_vfs_setxattr(idmap, path->dentry, rc = ksmbd_vfs_setxattr(idmap, path, xattr_stream_name, NULL, 0, 0);
xattr_stream_name, NULL, 0, 0);
if (rc < 0) if (rc < 0)
pr_err("Failed to store XATTR stream name :%d\n", rc); pr_err("Failed to store XATTR stream name :%d\n", rc);
return 0; return 0;
...@@ -2350,7 +2382,7 @@ static int smb2_remove_smb_xattrs(const struct path *path) ...@@ -2350,7 +2382,7 @@ static int smb2_remove_smb_xattrs(const struct path *path)
if (!strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN) && if (!strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN) &&
!strncmp(&name[XATTR_USER_PREFIX_LEN], STREAM_PREFIX, !strncmp(&name[XATTR_USER_PREFIX_LEN], STREAM_PREFIX,
STREAM_PREFIX_LEN)) { STREAM_PREFIX_LEN)) {
err = ksmbd_vfs_remove_xattr(idmap, path->dentry, err = ksmbd_vfs_remove_xattr(idmap, path,
name); name);
if (err) if (err)
ksmbd_debug(SMB, "remove xattr failed : %s\n", 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 * ...@@ -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 | da.flags = XATTR_DOSINFO_ATTRIB | XATTR_DOSINFO_CREATE_TIME |
XATTR_DOSINFO_ITIME; XATTR_DOSINFO_ITIME;
rc = ksmbd_vfs_set_dos_attrib_xattr(mnt_idmap(path->mnt), rc = ksmbd_vfs_set_dos_attrib_xattr(mnt_idmap(path->mnt), path, &da);
path->dentry, &da);
if (rc) if (rc)
ksmbd_debug(SMB, "failed to store file attribute into xattr\n"); ksmbd_debug(SMB, "failed to store file attribute into xattr\n");
} }
...@@ -2972,7 +3003,7 @@ int smb2_open(struct ksmbd_work *work) ...@@ -2972,7 +3003,7 @@ int smb2_open(struct ksmbd_work *work)
struct inode *inode = d_inode(path.dentry); struct inode *inode = d_inode(path.dentry);
posix_acl_rc = ksmbd_vfs_inherit_posix_acl(idmap, posix_acl_rc = ksmbd_vfs_inherit_posix_acl(idmap,
path.dentry, &path,
d_inode(path.dentry->d_parent)); d_inode(path.dentry->d_parent));
if (posix_acl_rc) if (posix_acl_rc)
ksmbd_debug(SMB, "inherit posix acl failed : %d\n", 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) ...@@ -2988,7 +3019,7 @@ int smb2_open(struct ksmbd_work *work)
if (rc) { if (rc) {
if (posix_acl_rc) if (posix_acl_rc)
ksmbd_vfs_set_init_posix_acl(idmap, ksmbd_vfs_set_init_posix_acl(idmap,
path.dentry); &path);
if (test_share_config_flag(work->tcon->share_conf, if (test_share_config_flag(work->tcon->share_conf,
KSMBD_SHARE_FLAG_ACL_XATTR)) { KSMBD_SHARE_FLAG_ACL_XATTR)) {
...@@ -3028,7 +3059,7 @@ int smb2_open(struct ksmbd_work *work) ...@@ -3028,7 +3059,7 @@ int smb2_open(struct ksmbd_work *work)
rc = ksmbd_vfs_set_sd_xattr(conn, rc = ksmbd_vfs_set_sd_xattr(conn,
idmap, idmap,
path.dentry, &path,
pntsd, pntsd,
pntsd_size); pntsd_size);
kfree(pntsd); kfree(pntsd);
...@@ -5464,7 +5495,7 @@ static int smb2_rename(struct ksmbd_work *work, ...@@ -5464,7 +5495,7 @@ static int smb2_rename(struct ksmbd_work *work,
goto out; goto out;
rc = ksmbd_vfs_setxattr(file_mnt_idmap(fp->filp), rc = ksmbd_vfs_setxattr(file_mnt_idmap(fp->filp),
fp->filp->f_path.dentry, &fp->filp->f_path,
xattr_stream_name, xattr_stream_name,
NULL, 0, 0); NULL, 0, 0);
if (rc < 0) { if (rc < 0) {
...@@ -5629,8 +5660,7 @@ static int set_file_basic_info(struct ksmbd_file *fp, ...@@ -5629,8 +5660,7 @@ static int set_file_basic_info(struct ksmbd_file *fp,
da.flags = XATTR_DOSINFO_ATTRIB | XATTR_DOSINFO_CREATE_TIME | da.flags = XATTR_DOSINFO_ATTRIB | XATTR_DOSINFO_CREATE_TIME |
XATTR_DOSINFO_ITIME; XATTR_DOSINFO_ITIME;
rc = ksmbd_vfs_set_dos_attrib_xattr(idmap, rc = ksmbd_vfs_set_dos_attrib_xattr(idmap, &filp->f_path, &da);
filp->f_path.dentry, &da);
if (rc) if (rc)
ksmbd_debug(SMB, ksmbd_debug(SMB,
"failed to restore file attribute in EA\n"); "failed to restore file attribute in EA\n");
...@@ -7485,7 +7515,7 @@ static inline int fsctl_set_sparse(struct ksmbd_work *work, u64 id, ...@@ -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); da.attr = le32_to_cpu(fp->f_ci->m_fattr);
ret = ksmbd_vfs_set_dos_attrib_xattr(idmap, ret = ksmbd_vfs_set_dos_attrib_xattr(idmap,
fp->filp->f_path.dentry, &da); &fp->filp->f_path, &da);
if (ret) if (ret)
fp->f_ci->m_fattr = old_fattr; fp->f_ci->m_fattr = old_fattr;
} }
......
...@@ -1162,8 +1162,7 @@ int smb_inherit_dacl(struct ksmbd_conn *conn, ...@@ -1162,8 +1162,7 @@ int smb_inherit_dacl(struct ksmbd_conn *conn,
pntsd_size += sizeof(struct smb_acl) + nt_size; pntsd_size += sizeof(struct smb_acl) + nt_size;
} }
ksmbd_vfs_set_sd_xattr(conn, idmap, ksmbd_vfs_set_sd_xattr(conn, idmap, path, pntsd, pntsd_size);
path->dentry, pntsd, pntsd_size);
kfree(pntsd); kfree(pntsd);
} }
...@@ -1383,7 +1382,7 @@ int set_info_sec(struct ksmbd_conn *conn, struct ksmbd_tree_connect *tcon, ...@@ -1383,7 +1382,7 @@ int set_info_sec(struct ksmbd_conn *conn, struct ksmbd_tree_connect *tcon,
newattrs.ia_valid |= ATTR_MODE; newattrs.ia_valid |= ATTR_MODE;
newattrs.ia_mode = (inode->i_mode & ~0777) | (fattr.cf_mode & 0777); 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 */ /* Update posix acls */
if (IS_ENABLED(CONFIG_FS_POSIX_ACL) && fattr.cf_dacls) { if (IS_ENABLED(CONFIG_FS_POSIX_ACL) && fattr.cf_dacls) {
rc = set_posix_acl(idmap, path->dentry, rc = set_posix_acl(idmap, path->dentry,
...@@ -1414,9 +1413,8 @@ int set_info_sec(struct ksmbd_conn *conn, struct ksmbd_tree_connect *tcon, ...@@ -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)) { if (test_share_config_flag(tcon->share_conf, KSMBD_SHARE_FLAG_ACL_XATTR)) {
/* Update WinACL in xattr */ /* Update WinACL in xattr */
ksmbd_vfs_remove_sd_xattrs(idmap, path->dentry); ksmbd_vfs_remove_sd_xattrs(idmap, path);
ksmbd_vfs_set_sd_xattr(conn, idmap, ksmbd_vfs_set_sd_xattr(conn, idmap, path, pntsd, ntsd_len);
path->dentry, pntsd, ntsd_len);
} }
out: out:
......
...@@ -170,6 +170,10 @@ int ksmbd_vfs_create(struct ksmbd_work *work, const char *name, umode_t mode) ...@@ -170,6 +170,10 @@ int ksmbd_vfs_create(struct ksmbd_work *work, const char *name, umode_t mode)
return err; return err;
} }
err = mnt_want_write(path.mnt);
if (err)
goto out_err;
mode |= S_IFREG; mode |= S_IFREG;
err = vfs_create(mnt_idmap(path.mnt), d_inode(path.dentry), err = vfs_create(mnt_idmap(path.mnt), d_inode(path.dentry),
dentry, mode, true); dentry, mode, true);
...@@ -179,6 +183,9 @@ int ksmbd_vfs_create(struct ksmbd_work *work, const char *name, umode_t mode) ...@@ -179,6 +183,9 @@ int ksmbd_vfs_create(struct ksmbd_work *work, const char *name, umode_t mode)
} else { } else {
pr_err("File(%s): creation failed (err:%d)\n", name, err); pr_err("File(%s): creation failed (err:%d)\n", name, err);
} }
mnt_drop_write(path.mnt);
out_err:
done_path_create(&path, dentry); done_path_create(&path, dentry);
return err; return err;
} }
...@@ -209,30 +216,35 @@ int ksmbd_vfs_mkdir(struct ksmbd_work *work, const char *name, umode_t mode) ...@@ -209,30 +216,35 @@ int ksmbd_vfs_mkdir(struct ksmbd_work *work, const char *name, umode_t mode)
return err; return err;
} }
err = mnt_want_write(path.mnt);
if (err)
goto out_err2;
idmap = mnt_idmap(path.mnt); idmap = mnt_idmap(path.mnt);
mode |= S_IFDIR; mode |= S_IFDIR;
err = vfs_mkdir(idmap, d_inode(path.dentry), dentry, mode); err = vfs_mkdir(idmap, d_inode(path.dentry), dentry, mode);
if (err) { if (!err && d_unhashed(dentry)) {
goto out;
} else if (d_unhashed(dentry)) {
struct dentry *d; struct dentry *d;
d = lookup_one(idmap, dentry->d_name.name, dentry->d_parent, d = lookup_one(idmap, dentry->d_name.name, dentry->d_parent,
dentry->d_name.len); dentry->d_name.len);
if (IS_ERR(d)) { if (IS_ERR(d)) {
err = PTR_ERR(d); err = PTR_ERR(d);
goto out; goto out_err1;
} }
if (unlikely(d_is_negative(d))) { if (unlikely(d_is_negative(d))) {
dput(d); dput(d);
err = -ENOENT; err = -ENOENT;
goto out; goto out_err1;
} }
ksmbd_vfs_inherit_owner(work, d_inode(path.dentry), d_inode(d)); ksmbd_vfs_inherit_owner(work, d_inode(path.dentry), d_inode(d));
dput(d); dput(d);
} }
out:
out_err1:
mnt_drop_write(path.mnt);
out_err2:
done_path_create(&path, dentry); done_path_create(&path, dentry);
if (err) if (err)
pr_err("mkdir(%s): creation failed (err:%d)\n", name, 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, ...@@ -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); memcpy(&stream_buf[*pos], buf, count);
err = ksmbd_vfs_setxattr(idmap, err = ksmbd_vfs_setxattr(idmap,
fp->filp->f_path.dentry, &fp->filp->f_path,
fp->stream.name, fp->stream.name,
(void *)stream_buf, (void *)stream_buf,
size, size,
...@@ -589,6 +601,10 @@ int ksmbd_vfs_remove_file(struct ksmbd_work *work, const struct path *path) ...@@ -589,6 +601,10 @@ int ksmbd_vfs_remove_file(struct ksmbd_work *work, const struct path *path)
goto out_err; goto out_err;
} }
err = mnt_want_write(path->mnt);
if (err)
goto out_err;
idmap = mnt_idmap(path->mnt); idmap = mnt_idmap(path->mnt);
if (S_ISDIR(d_inode(path->dentry)->i_mode)) { if (S_ISDIR(d_inode(path->dentry)->i_mode)) {
err = vfs_rmdir(idmap, d_inode(parent), path->dentry); 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) ...@@ -599,6 +615,7 @@ int ksmbd_vfs_remove_file(struct ksmbd_work *work, const struct path *path)
if (err) if (err)
ksmbd_debug(VFS, "unlink failed, err %d\n", err); ksmbd_debug(VFS, "unlink failed, err %d\n", err);
} }
mnt_drop_write(path->mnt);
out_err: out_err:
ksmbd_revert_fsids(work); ksmbd_revert_fsids(work);
...@@ -644,11 +661,16 @@ int ksmbd_vfs_link(struct ksmbd_work *work, const char *oldname, ...@@ -644,11 +661,16 @@ int ksmbd_vfs_link(struct ksmbd_work *work, const char *oldname,
goto out3; goto out3;
} }
err = mnt_want_write(newpath.mnt);
if (err)
goto out3;
err = vfs_link(oldpath.dentry, mnt_idmap(newpath.mnt), err = vfs_link(oldpath.dentry, mnt_idmap(newpath.mnt),
d_inode(newpath.dentry), d_inode(newpath.dentry),
dentry, NULL); dentry, NULL);
if (err) if (err)
ksmbd_debug(VFS, "vfs_link failed err %d\n", err); ksmbd_debug(VFS, "vfs_link failed err %d\n", err);
mnt_drop_write(newpath.mnt);
out3: out3:
done_path_create(&newpath, dentry); done_path_create(&newpath, dentry);
...@@ -694,6 +716,10 @@ int ksmbd_vfs_rename(struct ksmbd_work *work, const struct path *old_path, ...@@ -694,6 +716,10 @@ int ksmbd_vfs_rename(struct ksmbd_work *work, const struct path *old_path,
goto out2; goto out2;
} }
err = mnt_want_write(old_path->mnt);
if (err)
goto out2;
trap = lock_rename_child(old_child, new_path.dentry); trap = lock_rename_child(old_child, new_path.dentry);
old_parent = dget(old_child->d_parent); old_parent = dget(old_child->d_parent);
...@@ -757,6 +783,7 @@ int ksmbd_vfs_rename(struct ksmbd_work *work, const struct path *old_path, ...@@ -757,6 +783,7 @@ int ksmbd_vfs_rename(struct ksmbd_work *work, const struct path *old_path,
out3: out3:
dput(old_parent); dput(old_parent);
unlock_rename(old_parent, new_path.dentry); unlock_rename(old_parent, new_path.dentry);
mnt_drop_write(old_path->mnt);
out2: out2:
path_put(&new_path); path_put(&new_path);
...@@ -897,19 +924,24 @@ ssize_t ksmbd_vfs_getxattr(struct mnt_idmap *idmap, ...@@ -897,19 +924,24 @@ ssize_t ksmbd_vfs_getxattr(struct mnt_idmap *idmap,
* Return: 0 on success, otherwise error * Return: 0 on success, otherwise error
*/ */
int ksmbd_vfs_setxattr(struct mnt_idmap *idmap, 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) void *attr_value, size_t attr_size, int flags)
{ {
int err; int err;
err = mnt_want_write(path->mnt);
if (err)
return err;
err = vfs_setxattr(idmap, err = vfs_setxattr(idmap,
dentry, path->dentry,
attr_name, attr_name,
attr_value, attr_value,
attr_size, attr_size,
flags); flags);
if (err) if (err)
ksmbd_debug(VFS, "setxattr failed, err %d\n", err); ksmbd_debug(VFS, "setxattr failed, err %d\n", err);
mnt_drop_write(path->mnt);
return err; return err;
} }
...@@ -1013,9 +1045,18 @@ int ksmbd_vfs_fqar_lseek(struct ksmbd_file *fp, loff_t start, loff_t length, ...@@ -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, 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) int ksmbd_vfs_unlink(struct file *filp)
...@@ -1024,6 +1065,10 @@ 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 dentry *dir, *dentry = filp->f_path.dentry;
struct mnt_idmap *idmap = file_mnt_idmap(filp); struct mnt_idmap *idmap = file_mnt_idmap(filp);
err = mnt_want_write(filp->f_path.mnt);
if (err)
return err;
dir = dget_parent(dentry); dir = dget_parent(dentry);
err = ksmbd_vfs_lock_parent(dir, dentry); err = ksmbd_vfs_lock_parent(dir, dentry);
if (err) if (err)
...@@ -1041,6 +1086,7 @@ int ksmbd_vfs_unlink(struct file *filp) ...@@ -1041,6 +1086,7 @@ int ksmbd_vfs_unlink(struct file *filp)
ksmbd_debug(VFS, "failed to delete, err %d\n", err); ksmbd_debug(VFS, "failed to delete, err %d\n", err);
out: out:
dput(dir); dput(dir);
mnt_drop_write(filp->f_path.mnt);
return err; return err;
} }
...@@ -1244,13 +1290,13 @@ struct dentry *ksmbd_vfs_kern_path_create(struct ksmbd_work *work, ...@@ -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, int ksmbd_vfs_remove_acl_xattrs(struct mnt_idmap *idmap,
struct dentry *dentry) const struct path *path)
{ {
char *name, *xattr_list = NULL; char *name, *xattr_list = NULL;
ssize_t xattr_list_len; ssize_t xattr_list_len;
int err = 0; 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) { if (xattr_list_len < 0) {
goto out; goto out;
} else if (!xattr_list_len) { } else if (!xattr_list_len) {
...@@ -1258,6 +1304,10 @@ int ksmbd_vfs_remove_acl_xattrs(struct mnt_idmap *idmap, ...@@ -1258,6 +1304,10 @@ int ksmbd_vfs_remove_acl_xattrs(struct mnt_idmap *idmap,
goto out; goto out;
} }
err = mnt_want_write(path->mnt);
if (err)
goto out;
for (name = xattr_list; name - xattr_list < xattr_list_len; for (name = xattr_list; name - xattr_list < xattr_list_len;
name += strlen(name) + 1) { name += strlen(name) + 1) {
ksmbd_debug(SMB, "%s, len %zd\n", name, strlen(name)); ksmbd_debug(SMB, "%s, len %zd\n", name, strlen(name));
...@@ -1266,25 +1316,26 @@ int ksmbd_vfs_remove_acl_xattrs(struct mnt_idmap *idmap, ...@@ -1266,25 +1316,26 @@ int ksmbd_vfs_remove_acl_xattrs(struct mnt_idmap *idmap,
sizeof(XATTR_NAME_POSIX_ACL_ACCESS) - 1) || sizeof(XATTR_NAME_POSIX_ACL_ACCESS) - 1) ||
!strncmp(name, XATTR_NAME_POSIX_ACL_DEFAULT, !strncmp(name, XATTR_NAME_POSIX_ACL_DEFAULT,
sizeof(XATTR_NAME_POSIX_ACL_DEFAULT) - 1)) { sizeof(XATTR_NAME_POSIX_ACL_DEFAULT) - 1)) {
err = vfs_remove_acl(idmap, dentry, name); err = vfs_remove_acl(idmap, path->dentry, name);
if (err) if (err)
ksmbd_debug(SMB, ksmbd_debug(SMB,
"remove acl xattr failed : %s\n", name); "remove acl xattr failed : %s\n", name);
} }
} }
mnt_drop_write(path->mnt);
out: out:
kvfree(xattr_list); kvfree(xattr_list);
return err; return err;
} }
int ksmbd_vfs_remove_sd_xattrs(struct mnt_idmap *idmap, int ksmbd_vfs_remove_sd_xattrs(struct mnt_idmap *idmap, const struct path *path)
struct dentry *dentry)
{ {
char *name, *xattr_list = NULL; char *name, *xattr_list = NULL;
ssize_t xattr_list_len; ssize_t xattr_list_len;
int err = 0; 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) { if (xattr_list_len < 0) {
goto out; goto out;
} else if (!xattr_list_len) { } else if (!xattr_list_len) {
...@@ -1297,7 +1348,7 @@ int ksmbd_vfs_remove_sd_xattrs(struct mnt_idmap *idmap, ...@@ -1297,7 +1348,7 @@ int ksmbd_vfs_remove_sd_xattrs(struct mnt_idmap *idmap,
ksmbd_debug(SMB, "%s, len %zd\n", name, strlen(name)); ksmbd_debug(SMB, "%s, len %zd\n", name, strlen(name));
if (!strncmp(name, XATTR_NAME_SD, XATTR_NAME_SD_LEN)) { 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) if (err)
ksmbd_debug(SMB, "remove xattr failed : %s\n", name); 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 ...@@ -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, int ksmbd_vfs_set_sd_xattr(struct ksmbd_conn *conn,
struct mnt_idmap *idmap, struct mnt_idmap *idmap,
struct dentry *dentry, const struct path *path,
struct smb_ntsd *pntsd, int len) struct smb_ntsd *pntsd, int len)
{ {
int rc; int rc;
struct ndr sd_ndr = {0}, acl_ndr = {0}; struct ndr sd_ndr = {0}, acl_ndr = {0};
struct xattr_ntacl acl = {0}; struct xattr_ntacl acl = {0};
struct xattr_smb_acl *smb_acl, *def_smb_acl = NULL; struct xattr_smb_acl *smb_acl, *def_smb_acl = NULL;
struct dentry *dentry = path->dentry;
struct inode *inode = d_inode(dentry); struct inode *inode = d_inode(dentry);
acl.version = 4; acl.version = 4;
...@@ -1432,7 +1484,7 @@ int ksmbd_vfs_set_sd_xattr(struct ksmbd_conn *conn, ...@@ -1432,7 +1484,7 @@ int ksmbd_vfs_set_sd_xattr(struct ksmbd_conn *conn,
goto out; goto out;
} }
rc = ksmbd_vfs_setxattr(idmap, dentry, rc = ksmbd_vfs_setxattr(idmap, path,
XATTR_NAME_SD, sd_ndr.data, XATTR_NAME_SD, sd_ndr.data,
sd_ndr.offset, 0); sd_ndr.offset, 0);
if (rc < 0) if (rc < 0)
...@@ -1522,7 +1574,7 @@ int ksmbd_vfs_get_sd_xattr(struct ksmbd_conn *conn, ...@@ -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, int ksmbd_vfs_set_dos_attrib_xattr(struct mnt_idmap *idmap,
struct dentry *dentry, const struct path *path,
struct xattr_dos_attrib *da) struct xattr_dos_attrib *da)
{ {
struct ndr n; struct ndr n;
...@@ -1532,7 +1584,7 @@ int ksmbd_vfs_set_dos_attrib_xattr(struct mnt_idmap *idmap, ...@@ -1532,7 +1584,7 @@ int ksmbd_vfs_set_dos_attrib_xattr(struct mnt_idmap *idmap,
if (err) if (err)
return 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); (void *)n.data, n.offset, 0);
if (err) if (err)
ksmbd_debug(SMB, "failed to store dos attribute in xattr\n"); 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) ...@@ -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, 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_state acl_state;
struct posix_acl *acls; struct posix_acl *acls;
struct dentry *dentry = path->dentry;
struct inode *inode = d_inode(dentry); struct inode *inode = d_inode(dentry);
int rc; int rc;
...@@ -1802,6 +1855,11 @@ int ksmbd_vfs_set_init_posix_acl(struct mnt_idmap *idmap, ...@@ -1802,6 +1855,11 @@ int ksmbd_vfs_set_init_posix_acl(struct mnt_idmap *idmap,
return -ENOMEM; return -ENOMEM;
} }
posix_state_to_acl(&acl_state, acls->a_entries); 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); rc = set_posix_acl(idmap, dentry, ACL_TYPE_ACCESS, acls);
if (rc < 0) if (rc < 0)
ksmbd_debug(SMB, "Set posix acl(ACL_TYPE_ACCESS) failed, rc : %d\n", 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, ...@@ -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", ksmbd_debug(SMB, "Set posix acl(ACL_TYPE_DEFAULT) failed, rc : %d\n",
rc); rc);
} }
mnt_drop_write(path->mnt);
out_err:
free_acl_state(&acl_state); free_acl_state(&acl_state);
posix_acl_release(acls); posix_acl_release(acls);
return rc; return rc;
} }
int ksmbd_vfs_inherit_posix_acl(struct mnt_idmap *idmap, 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 *acls;
struct posix_acl_entry *pace; struct posix_acl_entry *pace;
struct dentry *dentry = path->dentry;
struct inode *inode = d_inode(dentry); struct inode *inode = d_inode(dentry);
int rc, i; int rc, i;
...@@ -1841,6 +1903,10 @@ int ksmbd_vfs_inherit_posix_acl(struct mnt_idmap *idmap, ...@@ -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); rc = set_posix_acl(idmap, dentry, ACL_TYPE_ACCESS, acls);
if (rc < 0) if (rc < 0)
ksmbd_debug(SMB, "Set posix acl(ACL_TYPE_ACCESS) failed, rc : %d\n", 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, ...@@ -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", ksmbd_debug(SMB, "Set posix acl(ACL_TYPE_DEFAULT) failed, rc : %d\n",
rc); rc);
} }
mnt_drop_write(path->mnt);
out_err:
posix_acl_release(acls); posix_acl_release(acls);
return rc; return rc;
} }
...@@ -108,12 +108,12 @@ ssize_t ksmbd_vfs_casexattr_len(struct mnt_idmap *idmap, ...@@ -108,12 +108,12 @@ ssize_t ksmbd_vfs_casexattr_len(struct mnt_idmap *idmap,
struct dentry *dentry, char *attr_name, struct dentry *dentry, char *attr_name,
int attr_name_len); int attr_name_len);
int ksmbd_vfs_setxattr(struct mnt_idmap *idmap, 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); void *attr_value, size_t attr_size, int flags);
int ksmbd_vfs_xattr_stream_name(char *stream_name, char **xattr_stream_name, int ksmbd_vfs_xattr_stream_name(char *stream_name, char **xattr_stream_name,
size_t *xattr_stream_name_size, int s_type); size_t *xattr_stream_name_size, int s_type);
int ksmbd_vfs_remove_xattr(struct mnt_idmap *idmap, int ksmbd_vfs_remove_xattr(struct mnt_idmap *idmap,
struct dentry *dentry, char *attr_name); const struct path *path, char *attr_name);
int ksmbd_vfs_kern_path_locked(struct ksmbd_work *work, char *name, int ksmbd_vfs_kern_path_locked(struct ksmbd_work *work, char *name,
unsigned int flags, struct path *path, unsigned int flags, struct path *path,
bool caseless); bool caseless);
...@@ -139,26 +139,25 @@ void ksmbd_vfs_posix_lock_wait(struct file_lock *flock); ...@@ -139,26 +139,25 @@ void ksmbd_vfs_posix_lock_wait(struct file_lock *flock);
int ksmbd_vfs_posix_lock_wait_timeout(struct file_lock *flock, long timeout); int ksmbd_vfs_posix_lock_wait_timeout(struct file_lock *flock, long timeout);
void ksmbd_vfs_posix_lock_unblock(struct file_lock *flock); void ksmbd_vfs_posix_lock_unblock(struct file_lock *flock);
int ksmbd_vfs_remove_acl_xattrs(struct mnt_idmap *idmap, int ksmbd_vfs_remove_acl_xattrs(struct mnt_idmap *idmap,
struct dentry *dentry); const struct path *path);
int ksmbd_vfs_remove_sd_xattrs(struct mnt_idmap *idmap, int ksmbd_vfs_remove_sd_xattrs(struct mnt_idmap *idmap, const struct path *path);
struct dentry *dentry);
int ksmbd_vfs_set_sd_xattr(struct ksmbd_conn *conn, int ksmbd_vfs_set_sd_xattr(struct ksmbd_conn *conn,
struct mnt_idmap *idmap, struct mnt_idmap *idmap,
struct dentry *dentry, const struct path *path,
struct smb_ntsd *pntsd, int len); struct smb_ntsd *pntsd, int len);
int ksmbd_vfs_get_sd_xattr(struct ksmbd_conn *conn, int ksmbd_vfs_get_sd_xattr(struct ksmbd_conn *conn,
struct mnt_idmap *idmap, struct mnt_idmap *idmap,
struct dentry *dentry, struct dentry *dentry,
struct smb_ntsd **pntsd); struct smb_ntsd **pntsd);
int ksmbd_vfs_set_dos_attrib_xattr(struct mnt_idmap *idmap, int ksmbd_vfs_set_dos_attrib_xattr(struct mnt_idmap *idmap,
struct dentry *dentry, const struct path *path,
struct xattr_dos_attrib *da); struct xattr_dos_attrib *da);
int ksmbd_vfs_get_dos_attrib_xattr(struct mnt_idmap *idmap, int ksmbd_vfs_get_dos_attrib_xattr(struct mnt_idmap *idmap,
struct dentry *dentry, struct dentry *dentry,
struct xattr_dos_attrib *da); struct xattr_dos_attrib *da);
int ksmbd_vfs_set_init_posix_acl(struct mnt_idmap *idmap, int ksmbd_vfs_set_init_posix_acl(struct mnt_idmap *idmap,
struct dentry *dentry); struct path *path);
int ksmbd_vfs_inherit_posix_acl(struct mnt_idmap *idmap, int ksmbd_vfs_inherit_posix_acl(struct mnt_idmap *idmap,
struct dentry *dentry, struct path *path,
struct inode *parent_inode); struct inode *parent_inode);
#endif /* __KSMBD_VFS_H__ */ #endif /* __KSMBD_VFS_H__ */
...@@ -252,7 +252,7 @@ static void __ksmbd_inode_close(struct ksmbd_file *fp) ...@@ -252,7 +252,7 @@ static void __ksmbd_inode_close(struct ksmbd_file *fp)
if (ksmbd_stream_fd(fp) && (ci->m_flags & S_DEL_ON_CLS_STREAM)) { if (ksmbd_stream_fd(fp) && (ci->m_flags & S_DEL_ON_CLS_STREAM)) {
ci->m_flags &= ~S_DEL_ON_CLS_STREAM; ci->m_flags &= ~S_DEL_ON_CLS_STREAM;
err = ksmbd_vfs_remove_xattr(file_mnt_idmap(filp), err = ksmbd_vfs_remove_xattr(file_mnt_idmap(filp),
filp->f_path.dentry, &filp->f_path,
fp->stream.name); fp->stream.name);
if (err) if (err)
pr_err("remove xattr failed : %s\n", pr_err("remove xattr failed : %s\n",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment