summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Brauner <brauner@kernel.org>2025-04-15 12:01:08 +0200
committerChristian Brauner <brauner@kernel.org>2025-04-16 09:33:09 +0200
commita681b7c17dd21d5aa0da391ceb27a2007ba970a4 (patch)
tree5de50d71cf319e33ca3744713d2972e5b058c056
parentc86b300b1ea35959a6e2a63a6497226a6ea90b67 (diff)
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>
-rw-r--r--fs/namei.c34
1 files changed, 18 insertions, 16 deletions
diff --git a/fs/namei.c b/fs/namei.c
index 267ac9c22dd27..84a0e0b0111c7 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -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;
}