ksmbd: fix permission check issue on chown and chmod

When commanding chmod and chown on cifs&ksmbd, ksmbd allows it without file
permissions check. There is code to check it in settattr_prepare.
Instead of setting the inode directly, update the mode and uid/gid
through notify_change.

Signed-off-by: Namjae Jeon <namjae.jeon@samsung.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
This commit is contained in:
Namjae Jeon 2021-08-21 23:26:01 +09:00
parent a9a27d4ab3
commit e70e392fa7
2 changed files with 23 additions and 6 deletions

View File

@ -5861,10 +5861,15 @@ int smb2_set_info(struct ksmbd_work *work)
break; break;
case SMB2_O_INFO_SECURITY: case SMB2_O_INFO_SECURITY:
ksmbd_debug(SMB, "GOT SMB2_O_INFO_SECURITY\n"); ksmbd_debug(SMB, "GOT SMB2_O_INFO_SECURITY\n");
if (ksmbd_override_fsids(work)) {
rc = -ENOMEM;
goto err_out;
}
rc = smb2_set_info_sec(fp, rc = smb2_set_info_sec(fp,
le32_to_cpu(req->AdditionalInformation), le32_to_cpu(req->AdditionalInformation),
req->Buffer, req->Buffer,
le32_to_cpu(req->BufferLength)); le32_to_cpu(req->BufferLength));
ksmbd_revert_fsids(work);
break; break;
default: default:
rc = -EOPNOTSUPP; rc = -EOPNOTSUPP;

View File

@ -1300,6 +1300,7 @@ int set_info_sec(struct ksmbd_conn *conn, struct ksmbd_tree_connect *tcon,
struct smb_fattr fattr = {{0}}; struct smb_fattr fattr = {{0}};
struct inode *inode = d_inode(path->dentry); struct inode *inode = d_inode(path->dentry);
struct user_namespace *user_ns = mnt_user_ns(path->mnt); struct user_namespace *user_ns = mnt_user_ns(path->mnt);
struct iattr newattrs;
fattr.cf_uid = INVALID_UID; fattr.cf_uid = INVALID_UID;
fattr.cf_gid = INVALID_GID; fattr.cf_gid = INVALID_GID;
@ -1309,12 +1310,23 @@ int set_info_sec(struct ksmbd_conn *conn, struct ksmbd_tree_connect *tcon,
if (rc) if (rc)
goto out; goto out;
inode->i_mode = (inode->i_mode & ~0777) | (fattr.cf_mode & 0777); newattrs.ia_valid = ATTR_CTIME;
if (!uid_eq(fattr.cf_uid, INVALID_UID)) if (!uid_eq(fattr.cf_uid, INVALID_UID)) {
inode->i_uid = fattr.cf_uid; newattrs.ia_valid |= ATTR_UID;
if (!gid_eq(fattr.cf_gid, INVALID_GID)) newattrs.ia_uid = fattr.cf_uid;
inode->i_gid = fattr.cf_gid; }
mark_inode_dirty(inode); if (!gid_eq(fattr.cf_gid, INVALID_GID)) {
newattrs.ia_valid |= ATTR_GID;
newattrs.ia_gid = fattr.cf_gid;
}
newattrs.ia_valid |= ATTR_MODE;
newattrs.ia_mode = (inode->i_mode & ~0777) | (fattr.cf_mode & 0777);
inode_lock(inode);
rc = notify_change(user_ns, path->dentry, &newattrs, NULL);
inode_unlock(inode);
if (rc)
goto out;
ksmbd_vfs_remove_acl_xattrs(user_ns, path->dentry); ksmbd_vfs_remove_acl_xattrs(user_ns, path->dentry);
/* Update posix acls */ /* Update posix acls */