From edc2b1da779887c74ade799574efc5819906598f Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 9 Jul 2018 16:27:23 -0400 Subject: make path_init() unconditionally paired with terminate_walk() including the failure exits Acked-by: Linus Torvalds Signed-off-by: Al Viro --- fs/namei.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/fs/namei.c b/fs/namei.c index 8311dce1c649..1b5c58ad4113 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -2125,12 +2125,15 @@ OK: } } +/* must be paired with terminate_walk() */ static const char *path_init(struct nameidata *nd, unsigned flags) { const char *s = nd->name->name; if (!*s) flags &= ~LOOKUP_RCU; + if (flags & LOOKUP_RCU) + rcu_read_lock(); nd->last_type = LAST_ROOT; /* if there are only slashes... */ nd->flags = flags | LOOKUP_JUMPED | LOOKUP_PARENT; @@ -2143,7 +2146,6 @@ static const char *path_init(struct nameidata *nd, unsigned flags) nd->path = nd->root; nd->inode = inode; if (flags & LOOKUP_RCU) { - rcu_read_lock(); nd->seq = __read_seqcount_begin(&nd->path.dentry->d_seq); nd->root_seq = nd->seq; nd->m_seq = read_seqbegin(&mount_lock); @@ -2159,21 +2161,15 @@ static const char *path_init(struct nameidata *nd, unsigned flags) nd->m_seq = read_seqbegin(&mount_lock); if (*s == '/') { - if (flags & LOOKUP_RCU) - rcu_read_lock(); set_root(nd); if (likely(!nd_jump_root(nd))) return s; - nd->root.mnt = NULL; - rcu_read_unlock(); return ERR_PTR(-ECHILD); } else if (nd->dfd == AT_FDCWD) { if (flags & LOOKUP_RCU) { struct fs_struct *fs = current->fs; unsigned seq; - rcu_read_lock(); - do { seq = read_seqcount_begin(&fs->seq); nd->path = fs->pwd; @@ -2195,16 +2191,13 @@ static const char *path_init(struct nameidata *nd, unsigned flags) dentry = f.file->f_path.dentry; - if (*s) { - if (!d_can_lookup(dentry)) { - fdput(f); - return ERR_PTR(-ENOTDIR); - } + if (*s && unlikely(!d_can_lookup(dentry))) { + fdput(f); + return ERR_PTR(-ENOTDIR); } nd->path = f.file->f_path; if (flags & LOOKUP_RCU) { - rcu_read_lock(); nd->inode = nd->path.dentry->d_inode; nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq); } else { @@ -2272,8 +2265,10 @@ static int path_lookupat(struct nameidata *nd, unsigned flags, struct path *path const char *s = path_init(nd, flags); int err; - if (IS_ERR(s)) + if (IS_ERR(s)) { + terminate_walk(nd); return PTR_ERR(s); + } if (unlikely(flags & LOOKUP_DOWN)) { err = handle_lookup_down(nd); @@ -2337,8 +2332,10 @@ static int path_parentat(struct nameidata *nd, unsigned flags, { const char *s = path_init(nd, flags); int err; - if (IS_ERR(s)) + if (IS_ERR(s)) { + terminate_walk(nd); return PTR_ERR(s); + } err = link_path_walk(s, nd); if (!err) err = complete_walk(nd); @@ -2666,8 +2663,10 @@ path_mountpoint(struct nameidata *nd, unsigned flags, struct path *path) { const char *s = path_init(nd, flags); int err; - if (IS_ERR(s)) + if (IS_ERR(s)) { + terminate_walk(nd); return PTR_ERR(s); + } while (!(err = link_path_walk(s, nd)) && (err = mountpoint_last(nd)) > 0) { s = trailing_symlink(nd); @@ -3512,6 +3511,7 @@ static struct file *path_openat(struct nameidata *nd, s = path_init(nd, flags); if (IS_ERR(s)) { + terminate_walk(nd); fput(file); return ERR_CAST(s); } -- cgit v1.2.3