fs: ensure that *path_locked*() helpers leave passed path pristine

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>

+18 -16
+18 -16
fs/namei.c
··· 2752 2752 /* does lookup, returns the object with parent locked */ 2753 2753 static struct dentry *__kern_path_locked(int dfd, struct filename *name, struct path *path) 2754 2754 { 2755 + struct path parent_path __free(path_put) = {}; 2755 2756 struct dentry *d; 2756 2757 struct qstr last; 2757 2758 int type, error; 2758 2759 2759 - error = filename_parentat(dfd, name, 0, path, &last, &type); 2760 + error = filename_parentat(dfd, name, 0, &parent_path, &last, &type); 2760 2761 if (error) 2761 2762 return ERR_PTR(error); 2762 - if (unlikely(type != LAST_NORM)) { 2763 - path_put(path); 2763 + if (unlikely(type != LAST_NORM)) 2764 2764 return ERR_PTR(-EINVAL); 2765 - } 2766 - inode_lock_nested(path->dentry->d_inode, I_MUTEX_PARENT); 2767 - d = lookup_one_qstr_excl(&last, path->dentry, 0); 2765 + inode_lock_nested(parent_path.dentry->d_inode, I_MUTEX_PARENT); 2766 + d = lookup_one_qstr_excl(&last, parent_path.dentry, 0); 2768 2767 if (IS_ERR(d)) { 2769 - inode_unlock(path->dentry->d_inode); 2770 - path_put(path); 2768 + inode_unlock(parent_path.dentry->d_inode); 2769 + return d; 2771 2770 } 2771 + path->dentry = no_free_ptr(parent_path.dentry); 2772 + path->mnt = no_free_ptr(parent_path.mnt); 2772 2773 return d; 2773 2774 } 2774 2775 2775 2776 struct dentry *kern_path_locked_negative(const char *name, struct path *path) 2776 2777 { 2778 + struct path parent_path __free(path_put) = {}; 2777 2779 struct filename *filename __free(putname) = getname_kernel(name); 2778 2780 struct dentry *d; 2779 2781 struct qstr last; 2780 2782 int type, error; 2781 2783 2782 - error = filename_parentat(AT_FDCWD, filename, 0, path, &last, &type); 2784 + error = filename_parentat(AT_FDCWD, filename, 0, &parent_path, &last, &type); 2783 2785 if (error) 2784 2786 return ERR_PTR(error); 2785 - if (unlikely(type != LAST_NORM)) { 2786 - path_put(path); 2787 + if (unlikely(type != LAST_NORM)) 2787 2788 return ERR_PTR(-EINVAL); 2788 - } 2789 - inode_lock_nested(path->dentry->d_inode, I_MUTEX_PARENT); 2790 - d = lookup_one_qstr_excl_raw(&last, path->dentry, 0); 2789 + inode_lock_nested(parent_path.dentry->d_inode, I_MUTEX_PARENT); 2790 + d = lookup_one_qstr_excl_raw(&last, parent_path.dentry, 0); 2791 2791 if (IS_ERR(d)) { 2792 - inode_unlock(path->dentry->d_inode); 2793 - path_put(path); 2792 + inode_unlock(parent_path.dentry->d_inode); 2793 + return d; 2794 2794 } 2795 + path->dentry = no_free_ptr(parent_path.dentry); 2796 + path->mnt = no_free_ptr(parent_path.mnt); 2795 2797 return d; 2796 2798 } 2797 2799