ovl: handle idmappings for layer lookup
authorChristian Brauner <brauner@kernel.org>
Mon, 4 Apr 2022 10:51:52 +0000 (12:51 +0200)
committerMiklos Szeredi <mszeredi@redhat.com>
Thu, 28 Apr 2022 14:31:12 +0000 (16:31 +0200)
Make the two places where lookup helpers can be called either on lower
or upper layers take the mount's idmapping into account. To this end we
pass down the mount in struct ovl_lookup_data. It can later also be used
to construct struct path for various other helpers. This is needed to
support idmapped base layers with overlay.

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/export.c
fs/overlayfs/namei.c
fs/overlayfs/readdir.c

index ebde05c9cf62e8e5a69fc87fb62c6431c434b8dc..2eada97bbd23fbd845bc384f6853cf31e51448a3 100644 (file)
@@ -391,6 +391,11 @@ static struct dentry *ovl_lookup_real_one(struct dentry *connected,
         * pointer because we hold no lock on the real dentry.
         */
        take_dentry_name_snapshot(&name, real);
+       /*
+        * No mnt_userns handling here: it's an internal lookup.  Could skip
+        * permission checking altogether, but for now just use non-mnt_userns
+        * transformed ids.
+        */
        this = lookup_one_len(name.name.name, connected, name.name.len);
        release_dentry_name_snapshot(&name);
        err = PTR_ERR(this);
index 0bd7ce41d8481b4eec1d9066b064a6b60739e2a6..65c4346a5b4312602eb98e19947690bf780003d6 100644 (file)
@@ -199,11 +199,12 @@ static bool ovl_is_opaquedir(struct ovl_fs *ofs, struct path *path)
        return ovl_path_check_dir_xattr(ofs, path, OVL_XATTR_OPAQUE);
 }
 
-static struct dentry *ovl_lookup_positive_unlocked(const char *name,
+static struct dentry *ovl_lookup_positive_unlocked(struct ovl_lookup_data *d,
+                                                  const char *name,
                                                   struct dentry *base, int len,
                                                   bool drop_negative)
 {
-       struct dentry *ret = lookup_one_len_unlocked(name, base, len);
+       struct dentry *ret = lookup_one_unlocked(mnt_user_ns(d->mnt), name, base, len);
 
        if (!IS_ERR(ret) && d_flags_negative(smp_load_acquire(&ret->d_flags))) {
                if (drop_negative && ret->d_lockref.count == 1) {
@@ -229,7 +230,7 @@ static int ovl_lookup_single(struct dentry *base, struct ovl_lookup_data *d,
        int err;
        bool last_element = !post[0];
 
-       this = ovl_lookup_positive_unlocked(name, base, namelen, drop_negative);
+       this = ovl_lookup_positive_unlocked(d, name, base, namelen, drop_negative);
        if (IS_ERR(this)) {
                err = PTR_ERR(this);
                this = NULL;
@@ -709,7 +710,8 @@ struct dentry *ovl_lookup_index(struct ovl_fs *ofs, struct dentry *upper,
        if (err)
                return ERR_PTR(err);
 
-       index = lookup_positive_unlocked(name.name, ofs->indexdir, name.len);
+       index = lookup_one_positive_unlocked(ovl_upper_mnt_userns(ofs), name.name,
+                                            ofs->indexdir, name.len);
        if (IS_ERR(index)) {
                err = PTR_ERR(index);
                if (err == -ENOENT) {
@@ -1174,8 +1176,8 @@ bool ovl_lower_positive(struct dentry *dentry)
                struct dentry *this;
                struct dentry *lowerdir = poe->lowerstack[i].dentry;
 
-               this = lookup_positive_unlocked(name->name, lowerdir,
-                                              name->len);
+               this = lookup_one_positive_unlocked(mnt_user_ns(poe->lowerstack[i].layer->mnt),
+                                                  name->name, lowerdir, name->len);
                if (IS_ERR(this)) {
                        switch (PTR_ERR(this)) {
                        case -ENOENT:
index 1d06222a496cc1aa385b29fc0299f69115b62250..78f62cc1797becb9caac4d1842a5278f81cf2f71 100644 (file)
@@ -264,11 +264,11 @@ static int ovl_fill_merge(struct dir_context *ctx, const char *name,
                return ovl_fill_lowest(rdd, name, namelen, offset, ino, d_type);
 }
 
-static int ovl_check_whiteouts(struct dentry *dir, struct ovl_readdir_data *rdd)
+static int ovl_check_whiteouts(struct path *path, struct ovl_readdir_data *rdd)
 {
        int err;
        struct ovl_cache_entry *p;
-       struct dentry *dentry;
+       struct dentry *dentry, *dir = path->dentry;
        const struct cred *old_cred;
 
        old_cred = ovl_override_creds(rdd->dentry->d_sb);
@@ -278,7 +278,7 @@ static int ovl_check_whiteouts(struct dentry *dir, struct ovl_readdir_data *rdd)
                while (rdd->first_maybe_whiteout) {
                        p = rdd->first_maybe_whiteout;
                        rdd->first_maybe_whiteout = p->next_maybe_whiteout;
-                       dentry = lookup_one_len(p->name, dir, p->len);
+                       dentry = lookup_one(mnt_user_ns(path->mnt), p->name, dir, p->len);
                        if (!IS_ERR(dentry)) {
                                p->is_whiteout = ovl_is_whiteout(dentry);
                                dput(dentry);
@@ -312,7 +312,7 @@ static inline int ovl_dir_read(struct path *realpath,
        } while (!err && rdd->count);
 
        if (!err && rdd->first_maybe_whiteout && rdd->dentry)
-               err = ovl_check_whiteouts(realpath->dentry, rdd);
+               err = ovl_check_whiteouts(realpath, rdd);
 
        fput(realfile);
 
@@ -479,7 +479,7 @@ static int ovl_cache_update_ino(struct path *path, struct ovl_cache_entry *p)
                        goto get;
                }
        }
-       this = lookup_one_len(p->name, dir, p->len);
+       this = lookup_one(mnt_user_ns(path->mnt), p->name, dir, p->len);
        if (IS_ERR_OR_NULL(this) || !this->d_inode) {
                /* Mark a stale entry */
                p->is_whiteout = true;