mbox series

[GIT,PULL] security changes for v6.9-rc3

Message ID 20240402141145.2685631-1-roberto.sassu@huaweicloud.com
State New
Headers show
Series [GIT,PULL] security changes for v6.9-rc3 | expand

Pull-request

https://github.com/linux-integrity/linux.git tags/security-mknod-6.9-rc3

Message

Roberto Sassu April 2, 2024, 2:11 p.m. UTC
From: Roberto Sassu <roberto.sassu@huawei.com>

Hi Linus,

A single bug fix to address a kernel panic in the newly introduced function
security_path_post_mknod.

PS: sorry for the email mismatch, @huawei.com emails resent from the
    mailing list are classified by Gmail as spam, we are working on
    fixing it.

Thanks,

Roberto


The following changes since commit 39cd87c4eb2b893354f3b850f916353f2658ae6f:

  Linux 6.9-rc2 (2024-03-31 14:32:39 -0700)

are available in the Git repository at:

  https://github.com/linux-integrity/linux.git tags/security-mknod-6.9-rc3

for you to fetch changes up to 991c999d8dc76261623c44f9076e427045053427:

  security: Handle dentries without inode in security_path_post_mknod() (2024-04-02 15:27:46 +0200)

----------------------------------------------------------------
security-mknod-6.9-rc3

Fixes a kernel panic in the newly introduced function
security_path_post_mknod(). (Not all dentries have an inode attached to
them.)

----------------------------------------------------------------
Roberto Sassu (1):
      security: Handle dentries without inode in security_path_post_mknod()

 security/integrity/evm/evm_main.c | 6 ++++--
 security/integrity/ima/ima_main.c | 5 +++--
 security/security.c               | 5 ++++-
 3 files changed, 11 insertions(+), 5 deletions(-)

Comments

Linus Torvalds April 2, 2024, 7:39 p.m. UTC | #1
On Tue, 2 Apr 2024 at 07:12, Roberto Sassu
<roberto.sassu@huaweicloud.com> wrote:
> A single bug fix to address a kernel panic in the newly introduced function
> security_path_post_mknod.

So I've pulled from you before, but I still don't have a signature
chain for your key (not that I can even find the key itself, much less
a signature chain).

Last time I pulled, it was after having everybody else just verify the
actual commit.

This time, the commit looks like a valid "avoid NULL", but I have to
say that I also think the security layer code in question is ENTIRELY
WRONG.

IOW, as far as I can tell, the mknod() system call may indeed leave
the dentry unhashed, and rely on anybody who then wants to use the new
special file to just do a "lookup()" to actually use it.

HOWEVER.

That also means that the whole notion of "post_path_mknod() is
complete and utter hoghwash. There is not anything that the security
layer can possibly validly do.

End result: instead of checking the 'inode' for NULL, I think the
right fix is to remove that meaningless security hook. It cannot do
anything sane, since one option is always 'the inode hasn't been
initialized yet".

Put another way: any security hook that checks inode in
security_path_post_mknod() seems simply buggy.

But if we really want to do this ("if mknod creates a positive dentry,
I won't see it in lookup, so I want to appraise it now"), then we
should just deal with this in the generic layer with some hack like
this:

  --- a/security/security.c
  +++ b/security/security.c
  @@ -1801,7 +1801,8 @@ EXPORT_SYMBOL(security_path_mknod);
    */
   void security_path_post_mknod(struct mnt_idmap *idmap, struct dentry *dentry)
   {
  -     if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
  +     struct inode *inode = d_backing_inode(dentry);
  +     if (unlikely(!inode || IS_PRIVATE(inode)))
                return;
        call_void_hook(path_post_mknod, idmap, dentry);
   }

and IMA and EVM would have to do any validation at lookup() time for
the cases where the dentry wasn't hashed by ->mknod.

Anyway, all of this is to say that I don't feel like I can pull this without
 (a) more acks by people
and
 (b) explanations for why the simpler fix to just
security_path_post_mknod() isn't the right fix.

                 Linus
Linus Torvalds April 2, 2024, 7:57 p.m. UTC | #2
On Tue, 2 Apr 2024 at 12:39, Linus Torvalds
<torvalds@linux-foundation.org> wrote:
>

>    void security_path_post_mknod(struct mnt_idmap *idmap, struct dentry *dentry)
>    {
>   -     if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
>   +     struct inode *inode = d_backing_inode(dentry);
>   +     if (unlikely(!inode || IS_PRIVATE(inode)))
>                 return;
>         call_void_hook(path_post_mknod, idmap, dentry);

Hmm. We do have other hooks that get called for this case.

For fsnotify_create() we actually have a comment about this:

 * fsnotify_create - 'name' was linked in
 *
 * Caller must make sure that dentry->d_name is stable.
 * Note: some filesystems (e.g. kernfs) leave @dentry negative and instantiate
 * ->d_inode later

and audit_inode_child() ends up having a

        if (inode)
                handle_one(inode);

in it.

So in other cases we do handle the NULL, but it does seem like the
other cases actually do validaly want to deal with this (ie the
fsnotify case will say "the directory that mknod was done in was
changed" even if it doesn't know what the change is.

But for the security case, it really doesn't seem to make much sense
to check a mknod() that you don't know the result of.

I do wonder if that "!inode" test might also be more specific with
"d_unhashed(dentry)". But that would only make sense if we moved this
test from security_path_post_mknod() into the caller itself, ie we
could possibly do something like this instead (or in addition to):

  -     if (error)
  -             goto out2;
  -     security_path_post_mknod(idmap, dentry);
  +     if (!error && !d_unhashed(dentry))
  +             security_path_post_mknod(idmap, dentry);

which might also be sensible.

Al? Anybody?

                Linus
Paul Moore April 2, 2024, 8:27 p.m. UTC | #3
On Tue, Apr 2, 2024 at 3:39 PM Linus Torvalds
<torvalds@linux-foundation.org> wrote:
>

...

> But if we really want to do this ("if mknod creates a positive dentry,
> I won't see it in lookup, so I want to appraise it now"), then we
> should just deal with this in the generic layer with some hack like
> this:
>
>   --- a/security/security.c
>   +++ b/security/security.c
>   @@ -1801,7 +1801,8 @@ EXPORT_SYMBOL(security_path_mknod);
>     */
>    void security_path_post_mknod(struct mnt_idmap *idmap, struct dentry *dentry)
>    {
>   -     if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
>   +     struct inode *inode = d_backing_inode(dentry);
>   +     if (unlikely(!inode || IS_PRIVATE(inode)))
>                 return;
>         call_void_hook(path_post_mknod, idmap, dentry);
>    }

Other than your snippet wrapping both the inode/NULL and
inode/IS_PRIVATE checks with an unlikely(), that's what Roberto
submitted (his patch only wrapped the inode/IS_PRIVATE with unlikely).
Paul Moore April 2, 2024, 8:28 p.m. UTC | #4
On Tue, Apr 2, 2024 at 4:27 PM Paul Moore <paul@paul-moore.com> wrote:
> On Tue, Apr 2, 2024 at 3:39 PM Linus Torvalds
> <torvalds@linux-foundation.org> wrote:
> >
>
> ...
>
> > But if we really want to do this ("if mknod creates a positive dentry,
> > I won't see it in lookup, so I want to appraise it now"), then we
> > should just deal with this in the generic layer with some hack like
> > this:
> >
> >   --- a/security/security.c
> >   +++ b/security/security.c
> >   @@ -1801,7 +1801,8 @@ EXPORT_SYMBOL(security_path_mknod);
> >     */
> >    void security_path_post_mknod(struct mnt_idmap *idmap, struct dentry *dentry)
> >    {
> >   -     if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
> >   +     struct inode *inode = d_backing_inode(dentry);
> >   +     if (unlikely(!inode || IS_PRIVATE(inode)))
> >                 return;
> >         call_void_hook(path_post_mknod, idmap, dentry);
> >    }
>
> Other than your snippet wrapping both the inode/NULL and
> inode/IS_PRIVATE checks with an unlikely(), that's what Roberto
> submitted (his patch only wrapped the inode/IS_PRIVATE with unlikely).

Nevermind, I missed the obvious OR / AND diff ... sorry for the noise.
Al Viro April 2, 2024, 9 p.m. UTC | #5
On Tue, Apr 02, 2024 at 12:57:28PM -0700, Linus Torvalds wrote:

> So in other cases we do handle the NULL, but it does seem like the
> other cases actually do validaly want to deal with this (ie the
> fsnotify case will say "the directory that mknod was done in was
> changed" even if it doesn't know what the change is.
> 
> But for the security case, it really doesn't seem to make much sense
> to check a mknod() that you don't know the result of.
> 
> I do wonder if that "!inode" test might also be more specific with
> "d_unhashed(dentry)". But that would only make sense if we moved this
> test from security_path_post_mknod() into the caller itself, ie we
> could possibly do something like this instead (or in addition to):
> 
>   -     if (error)
>   -             goto out2;
>   -     security_path_post_mknod(idmap, dentry);
>   +     if (!error && !d_unhashed(dentry))
>   +             security_path_post_mknod(idmap, dentry);
> 
> which might also be sensible.
> 
> Al? Anybody?

Several things here:

	1) location of that hook is wrong.  It's really "how do we catch
file creation that does not come through open() - yes, you can use
mknod(2) for that".  It should've been after the call of vfs_create(),
not the entire switch.  LSM folks have a disturbing fondness of inserting
hooks in various places, but IMO this one has no business being where
they'd placed it.  Bikeshedding regarding the name/arguments/etc. for
that thing is, IMO, not interesting...

	2) the only ->mknod() instance in the tree that tries to leave
dentry unhashed negative on success is CIFS (and only one case in it).
From conversation with CIFS folks it's actually cheaper to instantiate
in that case as well - leaving instantiation to the next lookup will
cost several extra roundtrips for no good reason.

	3) documentation (in vfs.rst) is way too vague.  The actual
rules are
	* ->create() must instantiate on success
	* ->mkdir() is allowed to return unhashed negative on success and
it might be forced to do so in some cases.  If a caller of vfs_mkdir()
wants the damn thing positive, it should account for such possibility and do
a lookup.  Normal callers don't care; see e.g. nfsd and overlayfs for example
of those that do.
	* ->mknod() is interesting - historically it had been "may leave
unhashed negative", but e.g. unix_bind() expected that it won't do so;
the reason it didn't blow up for CIFS is that this case (SFU) of their mknod()
does not support FIFOs and sockets anyway.  Considering how few instances
try to make use of that option and how it doesn't actually save them
anything, I would prefer to declare that ->mknod() should act as ->create().
	* ->symlink() - not sure; there are instances that make use of that
option (coda and hostfs).  OTOH, the only callers of vfs_symlink() that
care either way are nfsd and overlayfs, and neither is usable with coda
or hostfs...  Could go either way, but we need to say it clearly in the
docs, whichever way we choose.
Linus Torvalds April 2, 2024, 9:35 p.m. UTC | #6
On Tue, 2 Apr 2024 at 14:00, Al Viro <viro@zeniv.linux.org.uk> wrote:
>
>         1) location of that hook is wrong.  It's really "how do we catch
> file creation that does not come through open() - yes, you can use
> mknod(2) for that".  It should've been after the call of vfs_create(),
> not the entire switch.  LSM folks have a disturbing fondness of inserting
> hooks in various places, but IMO this one has no business being where
> they'd placed it.  Bikeshedding regarding the name/arguments/etc. for
> that thing is, IMO, not interesting...

Hmm. I guess that's right - for a non-file node, there's nothing that
the security layer can really check after-the-fact anyway.

It's not like you can attest the contents of a character device or whatever...

>         2) the only ->mknod() instance in the tree that tries to leave
> dentry unhashed negative on success is CIFS (and only one case in it).
> From conversation with CIFS folks it's actually cheaper to instantiate
> in that case as well - leaving instantiation to the next lookup will
> cost several extra roundtrips for no good reason.

Ack.

>         3) documentation (in vfs.rst) is way too vague.  The actual
> rules are
>         * ->create() must instantiate on success
>         * ->mkdir() is allowed to return unhashed negative on success and
> it might be forced to do so in some cases.  If a caller of vfs_mkdir()
> wants the damn thing positive, it should account for such possibility and do
> a lookup.  Normal callers don't care; see e.g. nfsd and overlayfs for example
> of those that do.
>         * ->mknod() is interesting - historically it had been "may leave
> unhashed negative", but e.g. unix_bind() expected that it won't do so;
> the reason it didn't blow up for CIFS is that this case (SFU) of their mknod()
> does not support FIFOs and sockets anyway.  Considering how few instances
> try to make use of that option and how it doesn't actually save them
> anything, I would prefer to declare that ->mknod() should act as ->create().
>         * ->symlink() - not sure; there are instances that make use of that
> option (coda and hostfs).  OTOH, the only callers of vfs_symlink() that
> care either way are nfsd and overlayfs, and neither is usable with coda
> or hostfs...  Could go either way, but we need to say it clearly in the
> docs, whichever way we choose.

Fair enough.

Anyway, it does sound like maybe the minimal fix would be just that
"move it into the
                case 0: case S_IFREG:
path".

Although if somebody already has the cifs patch to just do the
d_instantiate() for mknod, that might be even better.

I will leave this in more competent hands for now.

Let the bike-shedding commence,

               Linus
Paul Moore April 2, 2024, 9:36 p.m. UTC | #7
On Tue, Apr 2, 2024 at 5:00 PM Al Viro <viro@zeniv.linux.org.uk> wrote:
> On Tue, Apr 02, 2024 at 12:57:28PM -0700, Linus Torvalds wrote:
>
> > So in other cases we do handle the NULL, but it does seem like the
> > other cases actually do validaly want to deal with this (ie the
> > fsnotify case will say "the directory that mknod was done in was
> > changed" even if it doesn't know what the change is.
> >
> > But for the security case, it really doesn't seem to make much sense
> > to check a mknod() that you don't know the result of.
> >
> > I do wonder if that "!inode" test might also be more specific with
> > "d_unhashed(dentry)". But that would only make sense if we moved this
> > test from security_path_post_mknod() into the caller itself, ie we
> > could possibly do something like this instead (or in addition to):
> >
> >   -     if (error)
> >   -             goto out2;
> >   -     security_path_post_mknod(idmap, dentry);
> >   +     if (!error && !d_unhashed(dentry))
> >   +             security_path_post_mknod(idmap, dentry);
> >
> > which might also be sensible.
> >
> > Al? Anybody?
>
> Several things here:
>
>         1) location of that hook is wrong.  It's really "how do we catch
> file creation that does not come through open() - yes, you can use
> mknod(2) for that".  It should've been after the call of vfs_create(),
> not the entire switch.  LSM folks have a disturbing fondness of inserting
> hooks in various places, but IMO this one has no business being where
> they'd placed it.

I know it's everyone's favorite hobby to bash the LSM and LSM devs,
but it's important to note that we don't add hooks without working
with the associated subsystem devs to get approval.  In the cases
where we don't get an explicit ACK, there is an on-list approval, or
several ignored on-list attempts over weeks/months/years.  We want to
be good neighbors.

Roberto's original patch which converted from the IMA/EVM hook to the
LSM hook was ACK'd by the VFS folks.

Regardless, Roberto if it isn't obvious by now, just move the hook
back to where it was prior to v6.9-rc1.
Al Viro April 2, 2024, 10:42 p.m. UTC | #8
On Tue, Apr 02, 2024 at 05:36:30PM -0400, Paul Moore wrote:

> >         1) location of that hook is wrong.  It's really "how do we catch
> > file creation that does not come through open() - yes, you can use
> > mknod(2) for that".  It should've been after the call of vfs_create(),
> > not the entire switch.  LSM folks have a disturbing fondness of inserting
> > hooks in various places, but IMO this one has no business being where
> > they'd placed it.
> 
> I know it's everyone's favorite hobby to bash the LSM and LSM devs,
> but it's important to note that we don't add hooks without working
> with the associated subsystem devs to get approval.  In the cases
> where we don't get an explicit ACK, there is an on-list approval, or
> several ignored on-list attempts over weeks/months/years.  We want to
> be good neighbors.
> 
> Roberto's original patch which converted from the IMA/EVM hook to the
> LSM hook was ACK'd by the VFS folks.
> 
> Regardless, Roberto if it isn't obvious by now, just move the hook
> back to where it was prior to v6.9-rc1.

The root cause is in the too vague documentation - it's very easy to
misread as "->mknod() must call d_instantiate()", so the authors of
that patchset and reviewers of the same had missed the subtlety
involved.  No arguments about that.

Unkind comments about the LSM folks' tendency to shove hooks in
places where they make no sense had been brought by many things,
the most recent instance being this:
	However, I thought, since we were promoting it as an LSM hook,
	we should be as generic possible, and support more usages than
	what was needed for IMA.
(https://lore.kernel.org/all/3441a4a1140944f5b418b70f557bca72@huawei.com/)

I'm not blaming Roberto - that really seems to be the general attitude
around LSM;  I've seen a _lot_ of "it doesn't matter if it makes any sense,
somebody might figure out some use for the data we have at that point in
control flow, eventually if not now" kind of responses over the years.
IME asking what this or that hook is for and what it expects from the objects
passed to it gets treated as invalid question.  Which invites treating
hooks as black boxes...
Paul Moore April 3, 2024, 2:21 a.m. UTC | #9
On Tue, Apr 2, 2024 at 6:42 PM Al Viro <viro@zeniv.linux.org.uk> wrote:
> On Tue, Apr 02, 2024 at 05:36:30PM -0400, Paul Moore wrote:
>
> > >         1) location of that hook is wrong.  It's really "how do we catch
> > > file creation that does not come through open() - yes, you can use
> > > mknod(2) for that".  It should've been after the call of vfs_create(),
> > > not the entire switch.  LSM folks have a disturbing fondness of inserting
> > > hooks in various places, but IMO this one has no business being where
> > > they'd placed it.
> >
> > I know it's everyone's favorite hobby to bash the LSM and LSM devs,
> > but it's important to note that we don't add hooks without working
> > with the associated subsystem devs to get approval.  In the cases
> > where we don't get an explicit ACK, there is an on-list approval, or
> > several ignored on-list attempts over weeks/months/years.  We want to
> > be good neighbors.
> >
> > Roberto's original patch which converted from the IMA/EVM hook to the
> > LSM hook was ACK'd by the VFS folks.
> >
> > Regardless, Roberto if it isn't obvious by now, just move the hook
> > back to where it was prior to v6.9-rc1.
>
> The root cause is in the too vague documentation - it's very easy to
> misread as "->mknod() must call d_instantiate()", so the authors of
> that patchset and reviewers of the same had missed the subtlety
> involved.  No arguments about that.
>
> Unkind comments about the LSM folks' tendency to shove hooks in
> places where they make no sense had been brought by many things,
> the most recent instance being this:
>         However, I thought, since we were promoting it as an LSM hook,
>         we should be as generic possible, and support more usages than
>         what was needed for IMA.
> (https://lore.kernel.org/all/3441a4a1140944f5b418b70f557bca72@huawei.com/)
>
> I'm not blaming Roberto - that really seems to be the general attitude
> around LSM;  I've seen a _lot_ of "it doesn't matter if it makes any sense,
> somebody might figure out some use for the data we have at that point in
> control flow, eventually if not now" kind of responses over the years.
> IME asking what this or that hook is for and what it expects from the objects
> passed to it gets treated as invalid question.

It's rather common for subsystems to push back on the number LSM
hooks, which ends up resulting in patterns where LSM hooks are placed
in as wide a scope as possible both to satisfy the requirements of the
individual subsystems as well as the LSM's requirements on coverage.
Clearly documenting hooks, their inputs, return values, constraints,
etc. is important and we need to have those discussions as part of the
hook.  This is a big part of why we CC the subsystems when adding new
hooks and why I make sure we get an ACK or some other approval for a
subsystem maintainer before we merge a new hook.  Is the system
perfect, no, clearly not, but I don't believe it is for a lack of
trying or any ill intent on the part of the LSM devs.  We recently
restored the LSM hook comment blocks in security/security.c (long
story), I would gladly welcome any comments/edits/suggestions you, or
anyone else may have, about the docs there - I will be the first to
admit those docs have rotted quite a bit (once again, long story).  If
you have corrections, notes, or constraints that should be added
please let me know and/or send patches.  Similarly, if you're aware of
any hooks which are ill advised and/or poorly placed, let us know so
we can work together to fix things.

I'm serious Al.  These aren't just words in an email.  I realize you
don't have a lot of free cycles, but if you do have feedback on any of
those things above, I'm listening.

I *really* want to see better collaboration between various subsystems
and the LSMs; that's part of why I get annoyed with LSM bashing,
leaving the LSM devs out of security/LSM related threads, etc. it only
helps keep the divide up between the groups which is bad for all of
us.
Eric W. Biederman April 9, 2024, 5:37 p.m. UTC | #10
Paul Moore <paul@paul-moore.com> writes:

> I know it's everyone's favorite hobby to bash the LSM and LSM devs,
> but it's important to note that we don't add hooks without working
> with the associated subsystem devs to get approval.

Hah!!!!

> In the cases
> where we don't get an explicit ACK, there is an on-list approval, or
> several ignored on-list attempts over weeks/months/years.  We want to
> be good neighbors.

Hah!!!!

You merged a LSM hook that is only good for breaking chrome's sandbox,
over my expressed objections.  After I tested and verified that
is what it does.

I asked for testing. None was done.  It was claimed that no
security sensitive code would ever fail to check and deal with
all return codes, so no testing was necessary.  Then later a
whole bunch of security sensitive code that didn't was found.

The only redeeming grace has been that no-one ever actually uses
that misbegotten security hook.

P.S.  Sorry for this off topic rant but sheesh.   At least from
my perspective you deserve plenty of bashing.

Eric
Paul Moore April 9, 2024, 8:14 p.m. UTC | #11
On Tue, Apr 9, 2024 at 1:38 PM Eric W. Biederman <ebiederm@xmission.com> wrote:
> Paul Moore <paul@paul-moore.com> writes:
>
> > I know it's everyone's favorite hobby to bash the LSM and LSM devs,
> > but it's important to note that we don't add hooks without working
> > with the associated subsystem devs to get approval.
>
> Hah!!!!
>
> > In the cases
> > where we don't get an explicit ACK, there is an on-list approval, or
> > several ignored on-list attempts over weeks/months/years.  We want to
> > be good neighbors.
>
> Hah!!!!
>
> You merged a LSM hook that is only good for breaking chrome's sandbox,
> over my expressed objections.  After I tested and verified that
> is what it does.
>
> I asked for testing. None was done.  It was claimed that no
> security sensitive code would ever fail to check and deal with
> all return codes, so no testing was necessary.  Then later a
> whole bunch of security sensitive code that didn't was found.
>
> The only redeeming grace has been that no-one ever actually uses
> that misbegotten security hook.
>
> P.S.  Sorry for this off topic rant but sheesh.   At least from
> my perspective you deserve plenty of bashing.

Just in case people are reading this email and don't recall the
security_create_user_ns() hook discussions from 2022, I would suggest
reading those old threads and drawing your own conclusions.  A lore
link is below:

https://lore.kernel.org/linux-security-module/?q=s%3Asecurity_create_user_ns