fuse: support idmapped ->setattr op
authorAlexander Mikhalitsyn <aleksandr.mikhalitsyn@canonical.com>
Tue, 3 Sep 2024 15:16:19 +0000 (17:16 +0200)
committerMiklos Szeredi <mszeredi@redhat.com>
Wed, 4 Sep 2024 14:51:06 +0000 (16:51 +0200)
Need to translate uid and gid in case of chown(2).

Signed-off-by: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@canonical.com>
Reviewed-by: Christian Brauner <brauner@kernel.org>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
fs/fuse/dir.c
fs/fuse/file.c
fs/fuse/fuse_i.h

index 70ed1c47d7cea1ccb6b27704aad47cbad85575f4..5fa9c99f4d705aba140649a001005f91f642776b 100644 (file)
@@ -1749,17 +1749,29 @@ static bool update_mtime(unsigned ivalid, bool trust_local_mtime)
        return true;
 }
 
-static void iattr_to_fattr(struct fuse_conn *fc, struct iattr *iattr,
-                          struct fuse_setattr_in *arg, bool trust_local_cmtime)
+static void iattr_to_fattr(struct mnt_idmap *idmap, struct fuse_conn *fc,
+                          struct iattr *iattr, struct fuse_setattr_in *arg,
+                          bool trust_local_cmtime)
 {
        unsigned ivalid = iattr->ia_valid;
 
        if (ivalid & ATTR_MODE)
                arg->valid |= FATTR_MODE,   arg->mode = iattr->ia_mode;
-       if (ivalid & ATTR_UID)
-               arg->valid |= FATTR_UID,    arg->uid = from_kuid(fc->user_ns, iattr->ia_uid);
-       if (ivalid & ATTR_GID)
-               arg->valid |= FATTR_GID,    arg->gid = from_kgid(fc->user_ns, iattr->ia_gid);
+
+       if (ivalid & ATTR_UID) {
+               kuid_t fsuid = from_vfsuid(idmap, fc->user_ns, iattr->ia_vfsuid);
+
+               arg->valid |= FATTR_UID;
+               arg->uid = from_kuid(fc->user_ns, fsuid);
+       }
+
+       if (ivalid & ATTR_GID) {
+               kgid_t fsgid = from_vfsgid(idmap, fc->user_ns, iattr->ia_vfsgid);
+
+               arg->valid |= FATTR_GID;
+               arg->gid = from_kgid(fc->user_ns, fsgid);
+       }
+
        if (ivalid & ATTR_SIZE)
                arg->valid |= FATTR_SIZE,   arg->size = iattr->ia_size;
        if (ivalid & ATTR_ATIME) {
@@ -1879,8 +1891,8 @@ int fuse_flush_times(struct inode *inode, struct fuse_file *ff)
  * vmtruncate() doesn't allow for this case, so do the rlimit checking
  * and the actual truncation by hand.
  */
-int fuse_do_setattr(struct dentry *dentry, struct iattr *attr,
-                   struct file *file)
+int fuse_do_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
+                   struct iattr *attr, struct file *file)
 {
        struct inode *inode = d_inode(dentry);
        struct fuse_mount *fm = get_fuse_mount(inode);
@@ -1900,7 +1912,7 @@ int fuse_do_setattr(struct dentry *dentry, struct iattr *attr,
        if (!fc->default_permissions)
                attr->ia_valid |= ATTR_FORCE;
 
-       err = setattr_prepare(&nop_mnt_idmap, dentry, attr);
+       err = setattr_prepare(idmap, dentry, attr);
        if (err)
                return err;
 
@@ -1959,7 +1971,7 @@ int fuse_do_setattr(struct dentry *dentry, struct iattr *attr,
 
        memset(&inarg, 0, sizeof(inarg));
        memset(&outarg, 0, sizeof(outarg));
-       iattr_to_fattr(fc, attr, &inarg, trust_local_cmtime);
+       iattr_to_fattr(idmap, fc, attr, &inarg, trust_local_cmtime);
        if (file) {
                struct fuse_file *ff = file->private_data;
                inarg.valid |= FATTR_FH;
@@ -2094,7 +2106,7 @@ static int fuse_setattr(struct mnt_idmap *idmap, struct dentry *entry,
        if (!attr->ia_valid)
                return 0;
 
-       ret = fuse_do_setattr(entry, attr, file);
+       ret = fuse_do_setattr(idmap, entry, attr, file);
        if (!ret) {
                /*
                 * If filesystem supports acls it may have updated acl xattrs in
index 3c18e90fff07265bbafffaa32493a4901889b6a9..0c33ddf978649f6969c767d270e43627f46d676d 100644 (file)
@@ -2971,7 +2971,7 @@ static void fuse_do_truncate(struct file *file)
        attr.ia_file = file;
        attr.ia_valid |= ATTR_FILE;
 
-       fuse_do_setattr(file_dentry(file), &attr, file);
+       fuse_do_setattr(file_mnt_idmap(file), file_dentry(file), &attr, file);
 }
 
 static inline loff_t fuse_round_up(struct fuse_conn *fc, loff_t off)
index 407ee2542ff589df0c68628301493643a1f41e2b..7dd0661aeab60bcbb624370b4e393b405932a270 100644 (file)
@@ -1324,8 +1324,8 @@ bool fuse_write_update_attr(struct inode *inode, loff_t pos, ssize_t written);
 int fuse_flush_times(struct inode *inode, struct fuse_file *ff);
 int fuse_write_inode(struct inode *inode, struct writeback_control *wbc);
 
-int fuse_do_setattr(struct dentry *dentry, struct iattr *attr,
-                   struct file *file);
+int fuse_do_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
+                   struct iattr *attr, struct file *file);
 
 void fuse_set_initialized(struct fuse_conn *fc);