lists.openwall.net | lists / announce owl-users owl-dev john-users john-dev passwdqc-users yescrypt popa3d-users / oss-security kernel-hardening musl sabotage tlsify passwords / crypt-dev xvendor / Bugtraq Full-Disclosure linux-kernel linux-netdev linux-ext4 linux-hardening PHC | |
Open Source and information security mailing list archives
| ||
|
Date: Sun, 26 Oct 2014 11:56:08 -0700 From: Linus Torvalds <torvalds@...ux-foundation.org> To: Al Viro <viro@...iv.linux.org.uk> Cc: Sasha Levin <sasha.levin@...cle.com>, linux-fsdevel <linux-fsdevel@...r.kernel.org>, LKML <linux-kernel@...r.kernel.org>, Dave Jones <davej@...hat.com>, "Eric W. Biederman" <ebiederm@...ssion.com> Subject: Re: fs: lockup on rename_mutex in fs/dcache.c:1035 On Sat, Oct 25, 2014 at 8:57 PM, Al Viro <viro@...iv.linux.org.uk> wrote: > [context for Linus] > > Fuzzer has triggered deadlock in d_walk() with rename_lock taken twice. > AFAICS, the plausible scenario is > (child->d_flags & DCACHE_DENTRY_KILLED) || > triggering while ascending to parent, on the pass with rename_lock already > held exclusive. In that case we go to rename_retry and either return without > unlocking rename_lock, or try to take in exclusive one more time, again > without unlocking it first. Your patch looks fine, and I don't think we can livelock - because we always set 'seq' to 1 if we retry, and that causes us to get the exclusive lock, so we'd better not then enter the retry loop again. Although I guess not only renames cause it - looks like we get to that mis-named "rename_retry" for a deletion too according to the comment. Although I'm not sure that comment is correct - I don't think we change d_parent for deletes, do we? So at a quick glance, the one-liner patch looks fine. That said, I really detest how that code is written. Especially if the rename_retry really can only happen once, I get the feeling that we would be *much* better off doing this explicitly with a wrapper function, and do something like void d_walk(,..) { /* Try non-exclusive first */ seq = read_seqbegin(lock); retry = __d_walk(.. seq); if (retry) { read_seqlock_excl(lock); // lock->seqcount is now guaranteed stable retry = __d_walk(.. lock->seqcount); read_sequnlock_excl(lock); WARN_ON_ONCE(retry, "Really?"); } } or whatever. But maybe I'm missing some reason why the above is just crazy, and I'm a moron. Entirely possible. Linus -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@...r.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Powered by blists - more mailing lists