]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
ovl: fix regression caused by lookup helpers API changes
authorAmir Goldstein <amir73il@gmail.com>
Thu, 5 Jun 2025 10:15:30 +0000 (12:15 +0200)
committerChristian Brauner <brauner@kernel.org>
Thu, 5 Jun 2025 11:17:08 +0000 (13:17 +0200)
The lookup helpers API was changed by merge of vfs-6.16-rc1.async.dir to
pass a non-const qstr pointer argument to lookup_one*() helpers.

All of the callers of this API were changed to pass a pointer to temp
copy of qstr, except overlays that was passing a const pointer to
dentry->d_name that was changed to pass a non-const copy instead
when doing a lookup in lower layer which is not the fs of said dentry.

This wrong use of the API caused a regression in fstest overlay/012.

Fix the regression by making a non-const copy of dentry->d_name prior
to calling the lookup API, but the API should be fixed to not allow this
class of bugs.

Cc: NeilBrown <neilb@suse.de>
Fixes: 5741909697a3 ("VFS: improve interface for lookup_one functions")
Fixes: 390e34bc1490 ("VFS: change lookup_one_common and lookup_noperm_common to take a qstr")
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Link: https://lore.kernel.org/20250605101530.2336320-1-amir73il@gmail.com
Signed-off-by: Christian Brauner <brauner@kernel.org>
fs/overlayfs/namei.c

index bf722daf19a952ed75edd5e9f9cac9286ae5e50d..f75c49ceb460d40f0194cd1e3a3bde79c9e9e9f2 100644 (file)
@@ -1371,7 +1371,7 @@ out:
 bool ovl_lower_positive(struct dentry *dentry)
 {
        struct ovl_entry *poe = OVL_E(dentry->d_parent);
-       struct qstr *name = &dentry->d_name;
+       const struct qstr *name = &dentry->d_name;
        const struct cred *old_cred;
        unsigned int i;
        bool positive = false;
@@ -1394,9 +1394,15 @@ bool ovl_lower_positive(struct dentry *dentry)
                struct dentry *this;
                struct ovl_path *parentpath = &ovl_lowerstack(poe)[i];
 
+               /*
+                * We need to make a non-const copy of dentry->d_name,
+                * because lookup_one_positive_unlocked() will hash name
+                * with parentpath base, which is on another (lower fs).
+                */
                this = lookup_one_positive_unlocked(
                                mnt_idmap(parentpath->layer->mnt),
-                               name, parentpath->dentry);
+                               &QSTR_LEN(name->name, name->len),
+                               parentpath->dentry);
                if (IS_ERR(this)) {
                        switch (PTR_ERR(this)) {
                        case -ENOENT: