Commit 95c607d9 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs

Pull vfs fixes from Al Viro:
 "A couple of fixes for bugs caught while digging in fs/namei.c.  The
  first one is this cycle regression, the second is 3.11 and later"

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
  path_openat(): fix double fput()
  namei: d_is_negative() should be checked before ->d_seq validation
parents af647288 f15133df
...@@ -1415,6 +1415,7 @@ static int lookup_fast(struct nameidata *nd, ...@@ -1415,6 +1415,7 @@ static int lookup_fast(struct nameidata *nd,
*/ */
if (nd->flags & LOOKUP_RCU) { if (nd->flags & LOOKUP_RCU) {
unsigned seq; unsigned seq;
bool negative;
dentry = __d_lookup_rcu(parent, &nd->last, &seq); dentry = __d_lookup_rcu(parent, &nd->last, &seq);
if (!dentry) if (!dentry)
goto unlazy; goto unlazy;
...@@ -1424,8 +1425,11 @@ static int lookup_fast(struct nameidata *nd, ...@@ -1424,8 +1425,11 @@ static int lookup_fast(struct nameidata *nd,
* the dentry name information from lookup. * the dentry name information from lookup.
*/ */
*inode = dentry->d_inode; *inode = dentry->d_inode;
negative = d_is_negative(dentry);
if (read_seqcount_retry(&dentry->d_seq, seq)) if (read_seqcount_retry(&dentry->d_seq, seq))
return -ECHILD; return -ECHILD;
if (negative)
return -ENOENT;
/* /*
* This sequence count validates that the parent had no * This sequence count validates that the parent had no
...@@ -1472,6 +1476,10 @@ static int lookup_fast(struct nameidata *nd, ...@@ -1472,6 +1476,10 @@ static int lookup_fast(struct nameidata *nd,
goto need_lookup; goto need_lookup;
} }
if (unlikely(d_is_negative(dentry))) {
dput(dentry);
return -ENOENT;
}
path->mnt = mnt; path->mnt = mnt;
path->dentry = dentry; path->dentry = dentry;
err = follow_managed(path, nd->flags); err = follow_managed(path, nd->flags);
...@@ -1583,10 +1591,10 @@ static inline int walk_component(struct nameidata *nd, struct path *path, ...@@ -1583,10 +1591,10 @@ static inline int walk_component(struct nameidata *nd, struct path *path,
goto out_err; goto out_err;
inode = path->dentry->d_inode; inode = path->dentry->d_inode;
err = -ENOENT;
if (d_is_negative(path->dentry))
goto out_path_put;
} }
err = -ENOENT;
if (d_is_negative(path->dentry))
goto out_path_put;
if (should_follow_link(path->dentry, follow)) { if (should_follow_link(path->dentry, follow)) {
if (nd->flags & LOOKUP_RCU) { if (nd->flags & LOOKUP_RCU) {
...@@ -3036,14 +3044,13 @@ static int do_last(struct nameidata *nd, struct path *path, ...@@ -3036,14 +3044,13 @@ static int do_last(struct nameidata *nd, struct path *path,
BUG_ON(nd->flags & LOOKUP_RCU); BUG_ON(nd->flags & LOOKUP_RCU);
inode = path->dentry->d_inode; inode = path->dentry->d_inode;
finish_lookup:
/* we _can_ be in RCU mode here */
error = -ENOENT; error = -ENOENT;
if (d_is_negative(path->dentry)) { if (d_is_negative(path->dentry)) {
path_to_nameidata(path, nd); path_to_nameidata(path, nd);
goto out; goto out;
} }
finish_lookup:
/* we _can_ be in RCU mode here */
if (should_follow_link(path->dentry, !symlink_ok)) { if (should_follow_link(path->dentry, !symlink_ok)) {
if (nd->flags & LOOKUP_RCU) { if (nd->flags & LOOKUP_RCU) {
if (unlikely(nd->path.mnt != path->mnt || if (unlikely(nd->path.mnt != path->mnt ||
...@@ -3226,7 +3233,7 @@ static struct file *path_openat(int dfd, struct filename *pathname, ...@@ -3226,7 +3233,7 @@ static struct file *path_openat(int dfd, struct filename *pathname,
if (unlikely(file->f_flags & __O_TMPFILE)) { if (unlikely(file->f_flags & __O_TMPFILE)) {
error = do_tmpfile(dfd, pathname, nd, flags, op, file, &opened); error = do_tmpfile(dfd, pathname, nd, flags, op, file, &opened);
goto out; goto out2;
} }
error = path_init(dfd, pathname, flags, nd); error = path_init(dfd, pathname, flags, nd);
...@@ -3256,6 +3263,7 @@ static struct file *path_openat(int dfd, struct filename *pathname, ...@@ -3256,6 +3263,7 @@ static struct file *path_openat(int dfd, struct filename *pathname,
} }
out: out:
path_cleanup(nd); path_cleanup(nd);
out2:
if (!(opened & FILE_OPENED)) { if (!(opened & FILE_OPENED)) {
BUG_ON(!error); BUG_ON(!error);
put_filp(file); put_filp(file);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment