From: Al Viro <viro@ZenIV.linux.org.uk>
To: Sinan Kaya <okaya@codeaurora.org>
Cc: timur@codeaurora.org, cov@codeaurora.org,
linux-arm-msm@vger.kernel.org,
linux-arm-kernel@lists.infradead.org,
Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
linux-kernel@vger.kernel.org
Subject: Re: [PATCH] Revert "debugfs: ->d_parent is never NULL or negative"
Date: Thu, 6 Oct 2016 23:37:29 +0100 [thread overview]
Message-ID: <20161006223729.GO19539@ZenIV.linux.org.uk> (raw)
In-Reply-To: <20161006220050.GN19539@ZenIV.linux.org.uk>
On Thu, Oct 06, 2016 at 11:00:51PM +0100, Al Viro wrote:
> On Thu, Oct 06, 2016 at 05:41:34PM -0400, Sinan Kaya wrote:
> > On 10/6/2016 5:37 PM, Al Viro wrote:
> > > On Thu, Oct 06, 2016 at 05:30:29PM -0400, Sinan Kaya wrote:
> > >> This reverts commit acc29fb8f792 ("debugfs: ->d_parent is never NULL or
> > >> negative") as it breaks the debugfs_remove_recursive API as show in the
> > >> callstack below.
> > >
> > > NAK. Fix your code, don't break global asserts.
> > >
> >
> > I can fix the code if you tell me what the problem is:
>
> Getting dentries with NULL ->d_parent should never, ever happen. Find the
> place where such a beast appears and you've got your problem.
>
> The same goes for negative dentries with children. Again, if your code
> triggers such a situation, find where it does so and you've found a bug.
> More than one, at that.
Note that there are exactly 4 places where ->d_parent of some struct
dentry is modified, all in fs/dcache.c.
1) __d_alloc() sets ->d_parent of new instance pointing to the instance
itself and does so before anyone else could observe that dentry. That's
the only allocator of struct dentry - all of them start their life when
returned by it. With non-NULL value of ->d_parent.
2) d_alloc() sets it to given (non-NULL) parent. Note that it has
already dereferenced that parent (spin_lock(&parent->d_lock) a couple of
lines prior to that), so it would've oopsed before it reached that assignment
if it was passed NULL as parent.
3) d_alloc_cursor() - ditto, only there it had been an access to parent->d_sb.
4) __d_move() does
dentry->d_parent = target->d_parent;
target->d_parent = target;
in one case and
swap(dentry->d_parent, target->d_parent);
in another. The values had either already been in ->d_parent of another
instance prior to that or are guaranteed to be non-NULL since we'd just
survived dereferencing them.
If you ever get NULL in ->d_parent of struct dentry instance, you are
practically certain to have a dangling pointer to memory that used to
contain a struct dentry at some point but got freed and reused since then.
Any such case is a bug, and this check only papers over that bug - after all,
we might have very well reused it for anything whatsoever, with arbitrary
values ending up in it.
As for the negatives...
* if ->d_parent points to something other than dentry itself,
it contributes to ->d_count of parent
* positive dentry can only be turned into negative if the
caller of d_delete() is holding the only reference to it
* any code setting ->d_parent to another dentry does so only when
the parent to be is known to be positive at the moment.
So if you get a dentry with negative parent passed to it, the only way
it could happen (aside of outright memory corruption) is that dentry
you are passing has ->d_parent pointing to *itself* (and had never been
made positive). If that can legitimately happen, the proper test is
IS_ROOT(dentry) && !dentry->d_inode, and I strongly suspect that the
second part is irrelevant. But I would really like to see what leads
to that - I don't see any way for debugfs_create_{file,dir}() et.al. to
return a detached (or negative, for that matter) dentry.
are
WARNING: multiple messages have this Message-ID (diff)
From: viro@ZenIV.linux.org.uk (Al Viro)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH] Revert "debugfs: ->d_parent is never NULL or negative"
Date: Thu, 6 Oct 2016 23:37:29 +0100 [thread overview]
Message-ID: <20161006223729.GO19539@ZenIV.linux.org.uk> (raw)
In-Reply-To: <20161006220050.GN19539@ZenIV.linux.org.uk>
On Thu, Oct 06, 2016 at 11:00:51PM +0100, Al Viro wrote:
> On Thu, Oct 06, 2016 at 05:41:34PM -0400, Sinan Kaya wrote:
> > On 10/6/2016 5:37 PM, Al Viro wrote:
> > > On Thu, Oct 06, 2016 at 05:30:29PM -0400, Sinan Kaya wrote:
> > >> This reverts commit acc29fb8f792 ("debugfs: ->d_parent is never NULL or
> > >> negative") as it breaks the debugfs_remove_recursive API as show in the
> > >> callstack below.
> > >
> > > NAK. Fix your code, don't break global asserts.
> > >
> >
> > I can fix the code if you tell me what the problem is:
>
> Getting dentries with NULL ->d_parent should never, ever happen. Find the
> place where such a beast appears and you've got your problem.
>
> The same goes for negative dentries with children. Again, if your code
> triggers such a situation, find where it does so and you've found a bug.
> More than one, at that.
Note that there are exactly 4 places where ->d_parent of some struct
dentry is modified, all in fs/dcache.c.
1) __d_alloc() sets ->d_parent of new instance pointing to the instance
itself and does so before anyone else could observe that dentry. That's
the only allocator of struct dentry - all of them start their life when
returned by it. With non-NULL value of ->d_parent.
2) d_alloc() sets it to given (non-NULL) parent. Note that it has
already dereferenced that parent (spin_lock(&parent->d_lock) a couple of
lines prior to that), so it would've oopsed before it reached that assignment
if it was passed NULL as parent.
3) d_alloc_cursor() - ditto, only there it had been an access to parent->d_sb.
4)?__d_move() does
dentry->d_parent = target->d_parent;
target->d_parent = target;
in one case and
swap(dentry->d_parent, target->d_parent);
in another. The values had either already been in ->d_parent of another
instance prior to that or are guaranteed to be non-NULL since we'd just
survived dereferencing them.
If you ever get NULL in ->d_parent of struct dentry instance, you are
practically certain to have a dangling pointer to memory that used to
contain a struct dentry at some point but got freed and reused since then.
Any such case is a bug, and this check only papers over that bug - after all,
we might have very well reused it for anything whatsoever, with arbitrary
values ending up in it.
As for the negatives...
* if ->d_parent points to something other than dentry itself,
it contributes to ->d_count of parent
* positive dentry can only be turned into negative if the
caller of d_delete() is holding the only reference to it
* any code setting ->d_parent to another dentry does so only when
the parent to be is known to be positive at the moment.
So if you get a dentry with negative parent passed to it, the only way
it could happen (aside of outright memory corruption) is that dentry
you are passing has ->d_parent pointing to *itself* (and had never been
made positive). If that can legitimately happen, the proper test is
IS_ROOT(dentry) && !dentry->d_inode, and I strongly suspect that the
second part is irrelevant. But I would really like to see what leads
to that - I don't see any way for debugfs_create_{file,dir}() et.al. to
return a detached (or negative, for that matter) dentry.
are
next prev parent reply other threads:[~2016-10-06 22:37 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-10-06 21:30 [PATCH] Revert "debugfs: ->d_parent is never NULL or negative" Sinan Kaya
2016-10-06 21:30 ` Sinan Kaya
2016-10-06 21:37 ` Al Viro
2016-10-06 21:37 ` Al Viro
2016-10-06 21:41 ` Sinan Kaya
2016-10-06 21:41 ` Sinan Kaya
2016-10-06 21:56 ` Sinan Kaya
2016-10-06 21:56 ` Sinan Kaya
2016-10-06 22:11 ` Sinan Kaya
2016-10-06 22:11 ` Sinan Kaya
2016-10-06 22:00 ` Al Viro
2016-10-06 22:00 ` Al Viro
2016-10-06 22:37 ` Al Viro [this message]
2016-10-06 22:37 ` Al Viro
2016-10-06 22:41 ` Al Viro
2016-10-06 22:41 ` Al Viro
2016-10-06 23:21 ` Sinan Kaya
2016-10-06 23:21 ` Sinan Kaya
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=20161006223729.GO19539@ZenIV.linux.org.uk \
--to=viro@zeniv.linux.org.uk \
--cc=cov@codeaurora.org \
--cc=gregkh@linuxfoundation.org \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-arm-msm@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=okaya@codeaurora.org \
--cc=timur@codeaurora.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.