ksmbd: fix permission check issue on chown and chmod
authorNamjae Jeon <namjae.jeon@samsung.com>
Sat, 21 Aug 2021 14:26:01 +0000 (23:26 +0900)
committerNamjae Jeon <namjae.jeon@samsung.com>
Sat, 21 Aug 2021 14:26:34 +0000 (23:26 +0900)
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>
fs/ksmbd/smb2pdu.c
fs/ksmbd/smbacl.c

index 0131997..d329ea4 100644 (file)
@@ -5861,10 +5861,15 @@ int smb2_set_info(struct ksmbd_work *work)
                break;
        case SMB2_O_INFO_SECURITY:
                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,
                                       le32_to_cpu(req->AdditionalInformation),
                                       req->Buffer,
                                       le32_to_cpu(req->BufferLength));
+               ksmbd_revert_fsids(work);
                break;
        default:
                rc = -EOPNOTSUPP;
index 20455d8..5456e3a 100644 (file)
@@ -1300,6 +1300,7 @@ int set_info_sec(struct ksmbd_conn *conn, struct ksmbd_tree_connect *tcon,
        struct smb_fattr fattr = {{0}};
        struct inode *inode = d_inode(path->dentry);
        struct user_namespace *user_ns = mnt_user_ns(path->mnt);
+       struct iattr newattrs;
 
        fattr.cf_uid = INVALID_UID;
        fattr.cf_gid = INVALID_GID;
@@ -1309,12 +1310,23 @@ int set_info_sec(struct ksmbd_conn *conn, struct ksmbd_tree_connect *tcon,
        if (rc)
                goto out;
 
-       inode->i_mode = (inode->i_mode & ~0777) | (fattr.cf_mode & 0777);
-       if (!uid_eq(fattr.cf_uid, INVALID_UID))
-               inode->i_uid = fattr.cf_uid;
-       if (!gid_eq(fattr.cf_gid, INVALID_GID))
-               inode->i_gid = fattr.cf_gid;
-       mark_inode_dirty(inode);
+       newattrs.ia_valid = ATTR_CTIME;
+       if (!uid_eq(fattr.cf_uid, INVALID_UID)) {
+               newattrs.ia_valid |= ATTR_UID;
+               newattrs.ia_uid = fattr.cf_uid;
+       }
+       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);
        /* Update posix acls */