]> www.infradead.org Git - users/hch/misc.git/commitdiff
fs: ensure that *path_locked*() helpers leave passed path pristine
authorChristian Brauner <brauner@kernel.org>
Tue, 15 Apr 2025 10:01:08 +0000 (12:01 +0200)
committerChristian Brauner <brauner@kernel.org>
Wed, 16 Apr 2025 07:33:09 +0000 (09:33 +0200)
The functions currently leaving dangling pointers in the passed-in path
leading to hard to debug bugs in the long run. Ensure that the path is
left in pristine state just like we do in e.g., path_parentat() and
other helpers.

Link: https://lore.kernel.org/20250414-rennt-wimmeln-f186c3a780f1@brauner
Signed-off-by: Christian Brauner <brauner@kernel.org>
fs/namei.c

index 267ac9c22dd27f10d6a2ddb1d7a5e529c0bec281..84a0e0b0111c784fd749308cc64009b66f1da5d3 100644 (file)
@@ -2752,46 +2752,48 @@ static int filename_parentat(int dfd, struct filename *name,
 /* does lookup, returns the object with parent locked */
 static struct dentry *__kern_path_locked(int dfd, struct filename *name, struct path *path)
 {
+       struct path parent_path __free(path_put) = {};
        struct dentry *d;
        struct qstr last;
        int type, error;
 
-       error = filename_parentat(dfd, name, 0, path, &last, &type);
+       error = filename_parentat(dfd, name, 0, &parent_path, &last, &type);
        if (error)
                return ERR_PTR(error);
-       if (unlikely(type != LAST_NORM)) {
-               path_put(path);
+       if (unlikely(type != LAST_NORM))
                return ERR_PTR(-EINVAL);
-       }
-       inode_lock_nested(path->dentry->d_inode, I_MUTEX_PARENT);
-       d = lookup_one_qstr_excl(&last, path->dentry, 0);
+       inode_lock_nested(parent_path.dentry->d_inode, I_MUTEX_PARENT);
+       d = lookup_one_qstr_excl(&last, parent_path.dentry, 0);
        if (IS_ERR(d)) {
-               inode_unlock(path->dentry->d_inode);
-               path_put(path);
+               inode_unlock(parent_path.dentry->d_inode);
+               return d;
        }
+       path->dentry = no_free_ptr(parent_path.dentry);
+       path->mnt = no_free_ptr(parent_path.mnt);
        return d;
 }
 
 struct dentry *kern_path_locked_negative(const char *name, struct path *path)
 {
+       struct path parent_path __free(path_put) = {};
        struct filename *filename __free(putname) = getname_kernel(name);
        struct dentry *d;
        struct qstr last;
        int type, error;
 
-       error = filename_parentat(AT_FDCWD, filename, 0, path, &last, &type);
+       error = filename_parentat(AT_FDCWD, filename, 0, &parent_path, &last, &type);
        if (error)
                return ERR_PTR(error);
-       if (unlikely(type != LAST_NORM)) {
-               path_put(path);
+       if (unlikely(type != LAST_NORM))
                return ERR_PTR(-EINVAL);
-       }
-       inode_lock_nested(path->dentry->d_inode, I_MUTEX_PARENT);
-       d = lookup_one_qstr_excl_raw(&last, path->dentry, 0);
+       inode_lock_nested(parent_path.dentry->d_inode, I_MUTEX_PARENT);
+       d = lookup_one_qstr_excl_raw(&last, parent_path.dentry, 0);
        if (IS_ERR(d)) {
-               inode_unlock(path->dentry->d_inode);
-               path_put(path);
+               inode_unlock(parent_path.dentry->d_inode);
+               return d;
        }
+       path->dentry = no_free_ptr(parent_path.dentry);
+       path->mnt = no_free_ptr(parent_path.mnt);
        return d;
 }