]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
ovl: add ovl_override_creator_creds cred guard
authorChristian Brauner <brauner@kernel.org>
Mon, 17 Nov 2025 09:34:38 +0000 (10:34 +0100)
committerChristian Brauner <brauner@kernel.org>
Wed, 19 Nov 2025 20:58:26 +0000 (21:58 +0100)
The current code to override credentials for creation operations is
pretty difficult to understand. We effectively override the credentials
twice:

(1) override with the mounter's credentials
(2) copy the mounts credentials and override the fs{g,u}id with the inode {u,g}id

And then we elide the revert because it would be an idempotent revert.
That elision doesn't buy us anything anymore though because I've made it
all work without any reference counting anyway. All it does is mix the
two credential overrides together.

We can use a cleanup guard to clarify the creation codepaths and make
them easier to understand.

This just introduces the cleanup guard keeping the patch reviewable.
We'll convert the caller in follow-up patches and then drop the
duplicated code.

Link: https://patch.msgid.link/20251117-work-ovl-cred-guard-prepare-v2-1-bd1c97a36d7b@kernel.org
Reviewed-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Christian Brauner <brauner@kernel.org>
fs/overlayfs/dir.c

index 8e8ede6a1217ff8df4d9ea6b97237adecafdff59..c61976180a83e0f7bdb5f36b621fd50c8bab8a7a 100644 (file)
@@ -581,6 +581,42 @@ out_cleanup_unlocked:
        goto out_dput;
 }
 
+static const struct cred *ovl_override_creator_creds(struct dentry *dentry, struct inode *inode, umode_t mode)
+{
+       int err;
+
+       if (WARN_ON_ONCE(current->cred != ovl_creds(dentry->d_sb)))
+               return ERR_PTR(-EINVAL);
+
+       CLASS(prepare_creds, override_cred)();
+       if (!override_cred)
+               return ERR_PTR(-ENOMEM);
+
+       override_cred->fsuid = inode->i_uid;
+       override_cred->fsgid = inode->i_gid;
+
+       err = security_dentry_create_files_as(dentry, mode, &dentry->d_name,
+                                             current->cred, override_cred);
+       if (err)
+               return ERR_PTR(err);
+
+       return override_creds(no_free_ptr(override_cred));
+}
+
+static void ovl_revert_creator_creds(const struct cred *old_cred)
+{
+       const struct cred *override_cred;
+
+       override_cred = revert_creds(old_cred);
+       put_cred(override_cred);
+}
+
+DEFINE_CLASS(ovl_override_creator_creds,
+            const struct cred *,
+            if (!IS_ERR_OR_NULL(_T)) ovl_revert_creator_creds(_T),
+            ovl_override_creator_creds(dentry, inode, mode),
+            struct dentry *dentry, struct inode *inode, umode_t mode)
+
 static const struct cred *ovl_setup_cred_for_create(struct dentry *dentry,
                                                    struct inode *inode,
                                                    umode_t mode,