This is a note to let you know that I've just added the patch titled
fix races between __d_instantiate() and checks of dentry flags
to the 3.14-stable tree which can be found at:
http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary
The filename of the patch is:
fix-races-between-__d_instantiate-and-checks-of-dentry-flags.patch
and it can be found in the queue-3.14 subdirectory.
If you, or anyone else, feels it should not be added to the stable tree,
please let <[email protected]> know about it.
>From 22213318af7ae265bc6cd8aef2febbc2d69a2440 Mon Sep 17 00:00:00 2001
From: Al Viro <[email protected]>
Date: Sat, 19 Apr 2014 12:30:58 -0400
Subject: fix races between __d_instantiate() and checks of dentry flags
From: Al Viro <[email protected]>
commit 22213318af7ae265bc6cd8aef2febbc2d69a2440 upstream.
in non-lazy walk we need to be careful about dentry switching from
negative to positive - both ->d_flags and ->d_inode are updated,
and in some places we might see only one store. The cases where
dentry has been obtained by dcache lookup with ->i_mutex held on
parent are safe - ->d_lock and ->i_mutex provide all the barriers
we need. However, there are several places where we run into
trouble:
* do_last() fetches ->d_inode, then checks ->d_flags and
assumes that inode won't be NULL unless d_is_negative() is true.
Race with e.g. creat() - we might have fetched the old value of
->d_inode (still NULL) and new value of ->d_flags (already not
DCACHE_MISS_TYPE). Lin Ming has observed and reported the resulting
oops.
* a bunch of places checks ->d_inode for being non-NULL,
then checks ->d_flags for "is it a symlink". Race with symlink(2)
in case if our CPU sees ->d_inode update first - we see non-NULL
there, but ->d_flags still contains DCACHE_MISS_TYPE instead of
DCACHE_SYMLINK_TYPE. Result: false negative on "should we follow
link here?", with subsequent unpleasantness.
Reported-and-tested-by: Lin Ming <[email protected]>
Signed-off-by: Al Viro <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
---
fs/dcache.c | 3 +--
fs/namei.c | 6 +++---
2 files changed, 4 insertions(+), 5 deletions(-)
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -1647,8 +1647,7 @@ static void __d_instantiate(struct dentr
unsigned add_flags = d_flags_for_inode(inode);
spin_lock(&dentry->d_lock);
- dentry->d_flags &= ~DCACHE_ENTRY_TYPE;
- dentry->d_flags |= add_flags;
+ __d_set_type(dentry, add_flags);
if (inode)
hlist_add_head(&dentry->d_alias, &inode->i_dentry);
dentry->d_inode = inode;
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1537,7 +1537,7 @@ static inline int walk_component(struct
inode = path->dentry->d_inode;
}
err = -ENOENT;
- if (!inode)
+ if (!inode || d_is_negative(path->dentry))
goto out_path_put;
if (should_follow_link(path->dentry, follow)) {
@@ -2240,7 +2240,7 @@ mountpoint_last(struct nameidata *nd, st
mutex_unlock(&dir->d_inode->i_mutex);
done:
- if (!dentry->d_inode) {
+ if (!dentry->d_inode || d_is_negative(dentry)) {
error = -ENOENT;
dput(dentry);
goto out;
@@ -2982,7 +2982,7 @@ retry_lookup:
finish_lookup:
/* we _can_ be in RCU mode here */
error = -ENOENT;
- if (d_is_negative(path->dentry)) {
+ if (!inode || d_is_negative(path->dentry)) {
path_to_nameidata(path, nd);
goto out;
}
Patches currently in stable-queue which might be from [email protected]
are
queue-3.14/posix_acl-handle-null-acl-in-posix_acl_equiv_mode.patch
queue-3.14/fs-affs-super.c-bugfix-double-free.patch
queue-3.14/fix-races-between-__d_instantiate-and-checks-of-dentry-flags.patch
queue-3.14/autofs-fix-lockref-lookup.patch
--
To unsubscribe from this list: send the line "unsubscribe stable" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html