]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
ovl: refactor ovl_iterate() and port to cred guard
authorChristian Brauner <brauner@kernel.org>
Mon, 17 Nov 2025 09:33:56 +0000 (10:33 +0100)
committerChristian Brauner <brauner@kernel.org>
Wed, 19 Nov 2025 20:58:23 +0000 (21:58 +0100)
factor out ovl_iterate_merged() and move some code into
ovl_iterate_real() for easier use of the scoped ovl cred guard.

Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Link: https://patch.msgid.link/20251117-work-ovl-cred-guard-v4-25-b31603935724@kernel.org
Signed-off-by: Christian Brauner <brauner@kernel.org>
fs/overlayfs/readdir.c

index 2e345d39b1936d11cd6c6353576da4b2ad862f53..e285194306cca89ca2c2c5502dbd10a08ba4a52b 100644 (file)
@@ -832,36 +832,12 @@ static int ovl_iterate_real(struct file *file, struct dir_context *ctx)
        return err;
 }
 
-
-static int ovl_iterate(struct file *file, struct dir_context *ctx)
+static int ovl_iterate_merged(struct file *file, struct dir_context *ctx)
 {
        struct ovl_dir_file *od = file->private_data;
        struct dentry *dentry = file->f_path.dentry;
-       struct ovl_fs *ofs = OVL_FS(dentry->d_sb);
        struct ovl_cache_entry *p;
-       const struct cred *old_cred;
-       int err;
-
-       old_cred = ovl_override_creds(dentry->d_sb);
-       if (!ctx->pos)
-               ovl_dir_reset(file);
-
-       if (od->is_real) {
-               /*
-                * If parent is merge, then need to adjust d_ino for '..', if
-                * dir is impure then need to adjust d_ino for copied up
-                * entries.
-                */
-               if (ovl_xino_bits(ofs) ||
-                   (ovl_same_fs(ofs) &&
-                    (ovl_is_impure_dir(file) ||
-                     OVL_TYPE_MERGE(ovl_path_type(dentry->d_parent))))) {
-                       err = ovl_iterate_real(file, ctx);
-               } else {
-                       err = iterate_dir(od->realfile, ctx);
-               }
-               goto out;
-       }
+       int err = 0;
 
        if (!od->cache) {
                struct ovl_dir_cache *cache;
@@ -869,7 +845,7 @@ static int ovl_iterate(struct file *file, struct dir_context *ctx)
                cache = ovl_cache_get(dentry);
                err = PTR_ERR(cache);
                if (IS_ERR(cache))
-                       goto out;
+                       return err;
 
                od->cache = cache;
                ovl_seek_cursor(od, ctx->pos);
@@ -881,7 +857,7 @@ static int ovl_iterate(struct file *file, struct dir_context *ctx)
                        if (!p->ino || p->check_xwhiteout) {
                                err = ovl_cache_update(&file->f_path, p, !p->ino);
                                if (err)
-                                       goto out;
+                                       return err;
                        }
                }
                /* ovl_cache_update() sets is_whiteout on stale entry */
@@ -892,12 +868,50 @@ static int ovl_iterate(struct file *file, struct dir_context *ctx)
                od->cursor = p->l_node.next;
                ctx->pos++;
        }
-       err = 0;
-out:
-       ovl_revert_creds(old_cred);
        return err;
 }
 
+static bool ovl_need_adjust_d_ino(struct file *file)
+{
+       struct dentry *dentry = file->f_path.dentry;
+       struct ovl_fs *ofs = OVL_FS(dentry->d_sb);
+
+       /* If parent is merge, then need to adjust d_ino for '..' */
+       if (ovl_xino_bits(ofs))
+               return true;
+
+       /* Can't do consistent inode numbering */
+       if (!ovl_same_fs(ofs))
+               return false;
+
+       /* If dir is impure then need to adjust d_ino for copied up entries */
+       if (ovl_is_impure_dir(file) ||
+           OVL_TYPE_MERGE(ovl_path_type(dentry->d_parent)))
+               return true;
+
+       /* Pure: no need to adjust d_ino */
+       return false;
+}
+
+
+static int ovl_iterate(struct file *file, struct dir_context *ctx)
+{
+       struct ovl_dir_file *od = file->private_data;
+
+       if (!ctx->pos)
+               ovl_dir_reset(file);
+
+       with_ovl_creds(file_dentry(file)->d_sb) {
+               if (!od->is_real)
+                       return ovl_iterate_merged(file, ctx);
+
+               if (ovl_need_adjust_d_ino(file))
+                       return ovl_iterate_real(file, ctx);
+
+               return iterate_dir(od->realfile, ctx);
+       }
+}
+
 static loff_t ovl_dir_llseek(struct file *file, loff_t offset, int origin)
 {
        loff_t res;