ovl: use ovl_do_notify_change() wrapper
authorChristian Brauner <brauner@kernel.org>
Mon, 4 Apr 2022 10:51:48 +0000 (12:51 +0200)
committerMiklos Szeredi <mszeredi@redhat.com>
Thu, 28 Apr 2022 14:31:11 +0000 (16:31 +0200)
Introduce ovl_do_notify_change() as a simple wrapper around
notify_change() to support idmapped layers. The helper mirrors other
ovl_do_*() helpers that operate on the upper layers.

When changing ownership of an upper object the intended ownership needs
to be mapped according to the upper layer's idmapping. This mapping is
the inverse to the mapping applied when copying inode information from
an upper layer to the corresponding overlay inode. So e.g., when an
upper mount maps files that are stored on-disk as owned by id 1001 to
1000 this means that calling stat on this object from an idmapped mount
will report the file as being owned by id 1000. Consequently in order to
change ownership of an object in this filesystem so it appears as being
owned by id 1000 in the upper idmapped layer it needs to store id 1001
on disk. The mnt mapping helpers take care of this.

All idmapping helpers are nops when no idmapped base layers are used.

Cc: <linux-unionfs@vger.kernel.org>
Tested-by: Giuseppe Scrivano <gscrivan@redhat.com>
Reviewed-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Christian Brauner (Microsoft) <brauner@kernel.org>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
fs/overlayfs/copy_up.c
fs/overlayfs/dir.c
fs/overlayfs/inode.c
fs/overlayfs/overlayfs.h
fs/overlayfs/super.c

index b6cd3fbd783712e0b20d2631eb9603065ff90497..2860ab3ccc6b39f0e1613867ec277f26ceccbda1 100644 (file)
@@ -300,7 +300,7 @@ static int ovl_set_size(struct ovl_fs *ofs,
                .ia_size = stat->size,
        };
 
-       return notify_change(&init_user_ns, upperdentry, &attr, NULL);
+       return ovl_do_notify_change(ofs, upperdentry, &attr);
 }
 
 static int ovl_set_timestamps(struct ovl_fs *ofs, struct dentry *upperdentry,
@@ -313,7 +313,7 @@ static int ovl_set_timestamps(struct ovl_fs *ofs, struct dentry *upperdentry,
                .ia_mtime = stat->mtime,
        };
 
-       return notify_change(&init_user_ns, upperdentry, &attr, NULL);
+       return ovl_do_notify_change(ofs, upperdentry, &attr);
 }
 
 int ovl_set_attr(struct ovl_fs *ofs, struct dentry *upperdentry,
@@ -326,7 +326,7 @@ int ovl_set_attr(struct ovl_fs *ofs, struct dentry *upperdentry,
                        .ia_valid = ATTR_MODE,
                        .ia_mode = stat->mode,
                };
-               err = notify_change(&init_user_ns, upperdentry, &attr, NULL);
+               err = ovl_do_notify_change(ofs, upperdentry, &attr);
        }
        if (!err) {
                struct iattr attr = {
@@ -334,7 +334,7 @@ int ovl_set_attr(struct ovl_fs *ofs, struct dentry *upperdentry,
                        .ia_uid = stat->uid,
                        .ia_gid = stat->gid,
                };
-               err = notify_change(&init_user_ns, upperdentry, &attr, NULL);
+               err = ovl_do_notify_change(ofs, upperdentry, &attr);
        }
        if (!err)
                ovl_set_timestamps(ofs, upperdentry, stat);
index 3a870bc8366c762386b27a70d0c233bcb8392607..8f7917474ee25c88052a4e56f6ab8e3657acd7d9 100644 (file)
@@ -514,7 +514,7 @@ static int ovl_create_over_whiteout(struct dentry *dentry, struct inode *inode,
                        .ia_mode = cattr->mode,
                };
                inode_lock(newdentry->d_inode);
-               err = notify_change(&init_user_ns, newdentry, &attr, NULL);
+               err = ovl_do_notify_change(ofs, newdentry, &attr);
                inode_unlock(newdentry->d_inode);
                if (err)
                        goto out_cleanup;
index 40210d6d451de0cc5f7113c64185acf7ce88d79c..4527bb8d52ea92e1fab2709e6a17f75e32cb3329 100644 (file)
@@ -21,6 +21,7 @@ int ovl_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
                struct iattr *attr)
 {
        int err;
+       struct ovl_fs *ofs = OVL_FS(dentry->d_sb);
        bool full_copy_up = false;
        struct dentry *upperdentry;
        const struct cred *old_cred;
@@ -77,7 +78,7 @@ int ovl_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
 
                inode_lock(upperdentry->d_inode);
                old_cred = ovl_override_creds(dentry->d_sb);
-               err = notify_change(&init_user_ns, upperdentry, attr, NULL);
+               err = ovl_do_notify_change(ofs, upperdentry, attr);
                revert_creds(old_cred);
                if (!err)
                        ovl_copyattr(upperdentry->d_inode, dentry->d_inode);
index d6405c2046ed160a4780d0680f255937ab45a3c0..bc81f279b170b7f8c0613a82013e8e87eeceb7eb 100644 (file)
@@ -122,6 +122,35 @@ static inline const char *ovl_xattr(struct ovl_fs *ofs, enum ovl_xattr ox)
        return ovl_xattr_table[ox][ofs->config.userxattr];
 }
 
+/*
+ * When changing ownership of an upper object map the intended ownership
+ * according to the upper layer's idmapping. When an upper mount idmaps files
+ * that are stored on-disk as owned by id 1001 to id 1000 this means stat on
+ * this object will report it as being owned by id 1000 when calling stat via
+ * the upper mount.
+ * In order to change ownership of an object so stat reports id 1000 when
+ * called on an idmapped upper mount the value written to disk - i.e., the
+ * value stored in ia_*id - must 1001. The mount mapping helper will thus take
+ * care to map 1000 to 1001.
+ * The mnt idmapping helpers are nops if the upper layer isn't idmapped.
+ */
+static inline int ovl_do_notify_change(struct ovl_fs *ofs,
+                                      struct dentry *upperdentry,
+                                      struct iattr *attr)
+{
+       struct user_namespace *upper_mnt_userns = ovl_upper_mnt_userns(ofs);
+       struct user_namespace *fs_userns = i_user_ns(d_inode(upperdentry));
+
+       if (attr->ia_valid & ATTR_UID)
+               attr->ia_uid = mapped_kuid_user(upper_mnt_userns,
+                                               fs_userns, attr->ia_uid);
+       if (attr->ia_valid & ATTR_GID)
+               attr->ia_gid = mapped_kgid_user(upper_mnt_userns,
+                                               fs_userns, attr->ia_gid);
+
+       return notify_change(upper_mnt_userns, upperdentry, attr, NULL);
+}
+
 static inline int ovl_do_rmdir(struct ovl_fs *ofs,
                               struct inode *dir, struct dentry *dentry)
 {
index 307a36af7b4fed747c04f9df3a6c7e1afa587bb9..432ef060d2ab807491747a071e6c10fe52619078 100644 (file)
@@ -821,7 +821,7 @@ retry:
 
                /* Clear any inherited mode bits */
                inode_lock(work->d_inode);
-               err = notify_change(&init_user_ns, work, &attr, NULL);
+               err = ovl_do_notify_change(ofs, work, &attr);
                inode_unlock(work->d_inode);
                if (err)
                        goto out_dput;