From: Al Viro <viro@ZenIV.linux.org.uk>
To: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Linux Kernel Mailing List <linux-kernel@vger.kernel.org>,
linux-fsdevel <linux-fsdevel@vger.kernel.org>,
"Paul E. McKenney" <paulmck@linux.vnet.ibm.com>,
Mikhail Efremov <sem@altlinux.org>
Subject: [PATCH] missing data dependency barrier in prepend_name()
Date: Mon, 29 Sep 2014 02:06:56 +0100 [thread overview]
Message-ID: <20140929010656.GD7996@ZenIV.linux.org.uk> (raw)
In-Reply-To: <20140928215138.GB7996@ZenIV.linux.org.uk>
On Sun, Sep 28, 2014 at 10:51:38PM +0100, Al Viro wrote:
> Hmm... OK, dentry_cmp() is doing something similar to open-coded
> rcu_dereference(). prepend_name() does not, and I really wonder if
> that's correct...
>
> I'm afraid that the answer is "should've been more careful when switching
> d_path() to RCU", but maybe there's something subtle I'm missing there...
>
> I really hate memory ordering rules on alpha ;-/
AFAICS, prepend_name() is broken on SMP alpha. Disclaimer: I don't have
SMP alpha boxen to reproduce it on. However, it really looks like the race
is real.
CPU1: d_path() on /mnt/ramfs/<255-character>/foo
CPU2: mv /mnt/ramfs/<255-character> /mnt/ramfs/<63-character>
CPU2 does d_alloc(), which allocates an external name, stores the name there
including terminating NUL, does smp_wmb() and stores its address in
dentry->d_name.name. It proceeds to d_add(dentry, NULL) and d_move()
old dentry over to that. ->d_name.name value ends up in that dentry.
In the meanwhile, CPU1 gets to prepend_name() for that dentry. It fetches
->d_name.name and ->d_name.len; the former ends up pointing to new name
(64-byte kmalloc'ed array), the latter - 255 (length of the old name).
Nothing to force the ordering there, and normally that would be OK, since we'd
run into the terminating NUL and stop. Except that it's alpha, and we'd need
a data dependency barrier to guarantee that we see that store of NUL
__d_alloc() has done. In a similar situation dentry_cmp() would survive; it
does explicit smp_read_barrier_depends() after fetching ->d_name.name.
prepend_name() doesn't and it risks walking past the end of kmalloc'ed object
and possibly oops due to taking a page fault in kernel mode.
Cc: stable@vger.kernel.org # 3.12+
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
diff --git a/fs/dcache.c b/fs/dcache.c
index cb25a1a..e7484f9 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -2810,6 +2810,9 @@ static int prepend(char **buffer, int *buflen, const char *str, int namelen)
* the beginning of the name. The sequence number check at the caller will
* retry it again when a d_move() does happen. So any garbage in the buffer
* due to mismatched pointer and length will be discarded.
+ *
+ * Data dependency barrier is needed to make sure that we see that terminating
+ * NUL. Alpha strikes again, film at 11...
*/
static int prepend_name(char **buffer, int *buflen, struct qstr *name)
{
@@ -2817,6 +2820,8 @@ static int prepend_name(char **buffer, int *buflen, struct qstr *name)
u32 dlen = ACCESS_ONCE(name->len);
char *p;
+ smp_read_barrier_depends();
+
*buflen -= dlen + 1;
if (*buflen < 0)
return -ENAMETOOLONG;
next prev parent reply other threads:[~2014-09-29 1:07 UTC|newest]
Thread overview: 37+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-09-24 18:14 [PATCH v2] vfs: Don't exchange "short" filenames unconditionally Mikhail Efremov
2014-09-24 18:55 ` Al Viro
2014-09-24 19:20 ` Linus Torvalds
2014-09-24 19:27 ` Linus Torvalds
2014-09-24 20:18 ` Al Viro
2014-09-25 4:46 ` Al Viro
2014-09-26 16:44 ` Al Viro
2014-09-27 4:45 ` Al Viro
2014-09-27 17:56 ` Linus Torvalds
2014-09-27 18:31 ` Al Viro
2014-09-27 19:16 ` Al Viro
2014-09-27 19:37 ` Linus Torvalds
2014-09-27 19:39 ` Linus Torvalds
2014-09-27 19:49 ` Al Viro
2014-09-27 19:55 ` Linus Torvalds
2014-09-27 21:48 ` [git pull] vfs.git for 3.17-rc7 Al Viro
2014-09-27 19:45 ` [PATCH v2] vfs: Don't exchange "short" filenames unconditionally Al Viro
2014-09-28 7:47 ` Al Viro
2014-09-28 18:05 ` Al Viro
2014-09-28 21:51 ` Al Viro
2014-09-29 1:06 ` Al Viro [this message]
2014-09-29 15:15 ` Linus Torvalds
2014-09-29 15:59 ` Al Viro
2014-09-29 16:07 ` Linus Torvalds
2014-09-29 16:27 ` Al Viro
2014-09-29 17:54 ` Linus Torvalds
2014-09-29 19:04 ` Al Viro
2014-09-29 20:45 ` Linus Torvalds
2014-09-29 18:42 ` Paul E. McKenney
2014-10-01 0:16 ` Al Viro
2014-10-02 5:38 ` Paul E. McKenney
2014-10-02 10:35 ` Chuck Ebbert
2014-10-03 2:11 ` Paul E. McKenney
2014-09-29 13:16 ` Paul E. McKenney
2014-09-29 15:04 ` Al Viro
2014-09-28 15:01 ` Mikhail Efremov
2014-09-26 20:23 ` Al Viro
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20140929010656.GD7996@ZenIV.linux.org.uk \
--to=viro@zeniv.linux.org.uk \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=paulmck@linux.vnet.ibm.com \
--cc=sem@altlinux.org \
--cc=torvalds@linux-foundation.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).