linux-fsdevel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Sasha Levin <sasha.levin@oracle.com>
To: Al Viro <viro@ZenIV.linux.org.uk>
Cc: linux-fsdevel <linux-fsdevel@vger.kernel.org>,
	bfields@redhat.com, mszeredi@suse.cz,
	"Eric W. Biederman" <ebiederm@xmission.com>,
	hch@lst.de, Dave Jones <davej@redhat.com>,
	LKML <linux-kernel@vger.kernel.org>
Subject: Re: dcache: NULL ptr deref in dentry_kill
Date: Mon, 06 Oct 2014 00:39:16 -0400	[thread overview]
Message-ID: <54321CF4.9070101@oracle.com> (raw)
In-Reply-To: <20141006042517.GB7996@ZenIV.linux.org.uk>

On 10/06/2014 12:25 AM, Al Viro wrote:
> On Sun, Oct 05, 2014 at 11:42:40PM -0400, Sasha Levin wrote:
>> On 10/05/2014 11:13 PM, Al Viro wrote:
>>> On Sun, Oct 05, 2014 at 08:27:47PM -0400, Sasha Levin wrote:
>>>
>>>> [  434.580818] BUG: unable to handle kernel NULL pointer dereference at 0000000000000090
>>>> [  434.582208] IP: do_raw_spin_trylock (./arch/x86/include/asm/spinlock.h:108 kernel/locking/spinlock_debug.c:143)
>>> [snip]
>>> spin_lock((void *)0x90)
>>>> [  434.590025] ? _raw_spin_trylock (include/linux/spinlock_api_smp.h:89 kernel/locking/spinlock.c:135)
>>>> [  434.590025] ? lockref_put_or_lock (lib/lockref.c:131)
>>>> [  434.590025] dput (fs/dcache.c:513 fs/dcache.c:616)
>>>
>>> ummm...  lockref_put_or_lock(&dentry->d_lockref) ending up with 0x90 passed
>>> to lockref_put_or_lock()...  What offset does d_lockref have on your build?
>>
>> 0x90
> 
> Huh???  It means that we got to that lockref_put_or_lock with dentry == NULL.
> But that makes no sense at all - we have
> void dput(struct dentry *dentry)
> {
>         if (unlikely(!dentry))
>                 return;
> 
> repeat:
>         if (lockref_put_or_lock(&dentry->d_lockref))
>                 return;
> 	...
> and the only branch to repeat: is
>         if (dentry)
>                 goto repeat;
> 
> If we get to that lockref_put_or_lock() with dentry == NULL, something's
> very wrong with compiler.  And the only other lockref_put_or_lock() in
> there is
>                 while (dentry && !lockref_put_or_lock(&dentry->d_lockref)) {
> which would also make NULL dentry a miscompile.
> 
> Could you put fs/dcache.s for your build on some anonftp?  That really
> smells like compiler breakage; had the address it tried to access been
> close but not equal to that offsetof(), we would be dealing with bogus
> ->f_path.dentry (close to, but not quite NULL).  As it is, it looks like
> dput() somehow getting to that line with NULL dentry, which should've
> been prevented by the checks there...

I think you've misread the stack trace. The lockref_put_or_lock isn't reliable
(probably just a derelict from the previous, successful call to it), and the
stack trace's reliable symbols takes us elsewhere.

Stack trace shows that:

[  434.590025] dput (fs/dcache.c:513 fs/dcache.c:616)
[  434.590025] __fput (fs/file_table.c:235)
[  434.590025] ____fput (fs/file_table.c:253)

Looking at fs/dcache.c:616 we see:

	kill_it:
	        dentry = dentry_kill(dentry); <=== This
        	if (dentry)
                	goto repeat;

And within dentry_kill() (fs/dcache.c:513):

        if (!IS_ROOT(dentry)) {
                parent = dentry->d_parent;
                if (unlikely(!spin_trylock(&parent->d_lock))) { <=== here
                        if (inode)
                                spin_unlock(&inode->i_lock);
                        goto failed;

We're trying to deref a NULL 'parent'.

Looking at git history, this check was slightly changed to remove the
'parent != NULL' condition in e55fd01154 ("split dentry_kill()"):

	-       }
	        if (!IS_ROOT(dentry))
	                parent = dentry->d_parent;
	-       if (parent && !spin_trylock(&parent->d_lock)) {
	-               if (inode)
	-                       spin_unlock(&inode->i_lock);
	[...]
	+       if (!IS_ROOT(dentry)) {
	+               parent = dentry->d_parent;
	+               if (unlikely(!spin_trylock(&parent->d_lock))) {
	+                       if (inode)
	+                               spin_unlock(&inode->i_lock);
	+                       goto failed;
	+               }
	+       }

So this is a case where dentry is not root, but has parent set to NULL.

Although I don't see how that can happen.


Thanks,
Sasha

  reply	other threads:[~2014-10-06  4:39 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-10-06  0:27 dcache: NULL ptr deref in dentry_kill Sasha Levin
2014-10-06  3:13 ` Al Viro
2014-10-06  3:42   ` Sasha Levin
2014-10-06  4:25     ` Al Viro
2014-10-06  4:39       ` Sasha Levin [this message]
2014-10-06  5:35         ` 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=54321CF4.9070101@oracle.com \
    --to=sasha.levin@oracle.com \
    --cc=bfields@redhat.com \
    --cc=davej@redhat.com \
    --cc=ebiederm@xmission.com \
    --cc=hch@lst.de \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mszeredi@suse.cz \
    --cc=viro@ZenIV.linux.org.uk \
    /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).