public inbox for linux-xfs@vger.kernel.org
 help / color / mirror / Atom feed
From: Yumei Huang <yuhuang@redhat.com>
To: Dave Chinner <david@fromorbit.com>
Cc: Brian Foster <bfoster@redhat.com>, linux-xfs@vger.kernel.org
Subject: Re: XFS: Assertion failed
Date: Fri, 15 Jan 2021 03:36:40 -0500 (EST)	[thread overview]
Message-ID: <1914065699.64814368.1610699800882.JavaMail.zimbra@redhat.com> (raw)
In-Reply-To: <20210114212102.GM331610@dread.disaster.area>



----- Original Message -----
> From: "Dave Chinner" <david@fromorbit.com>
> To: "Brian Foster" <bfoster@redhat.com>
> Cc: "Yumei Huang" <yuhuang@redhat.com>, linux-xfs@vger.kernel.org
> Sent: Friday, January 15, 2021 5:21:02 AM
> Subject: Re: XFS: Assertion failed
> 
> On Thu, Jan 14, 2021 at 12:29:28PM -0500, Brian Foster wrote:
> > On Thu, Jan 14, 2021 at 05:20:29AM -0500, Yumei Huang wrote:
> > > Hit the issue when doing syzkaller test with kernel 5.11.0-rc3(65f0d241).
> > > The C reproducer is attached.
> > > 
> > > Steps to Reproduce:
> > > 1. # gcc -pthread -o reproducer reproducer.c
> > > 2. # ./reproducer
> > > 
> > > 
> > > Test results:
> > > [  131.726790] XFS: Assertion failed: (iattr->ia_valid &
> > > (ATTR_UID|ATTR_GID|ATTR_ATIME|ATTR_ATIME_SET|
> > > ATTR_MTIME_SET|ATTR_KILL_PRIV|ATTR_TIMES_SET)) == 0, file:
> > > fs/xfs/xfs_iops.c, line: 849
> > > [  131.743687] ------------[ cut here ]------------
> > 
> > Some quick initial analysis from a run of the reproducer... It looks
> > like it calls into xfs_setattr_size() with ATTR_KILL_PRIV set in
> > ->ia_valid. This appears to originate in the VFS via handle_truncate()
> > -> do_truncate() -> dentry_needs_remove_privs().
> > 
> > An strace of the reproducer shows the following calls:
> > 
> > ...
> > [pid  1524] creat("./file0", 010)       = 3
> > ...
> > [pid  1524] fsetxattr(3, "security.capability",
> > "\0\0\0\3b\27\0\0\10\0\0\0\2\0\0\0\377\377\377\377\0\356\0", 24, 0
> > <unfinished ...>
> > ...
> > [pid  1524] creat("./file0", 010 <unfinished ...>
> > ...
> > 
> > So I'm guessing there's an attempt to open this file with O_TRUNC with
> > this particular xattr set (unexpectedly?). Indeed, after the reproducer
> > leaves file01 around with the xattr, a subsequent xfs_io -c "open -t
> > ..." attempt triggers the assert again, and then the xattr disappears.
> > I'd have to dig more into the associated vfs code to grok the expected
> > behavior and whether there's a problem here..
> 
> Changing the size of the inode is is all that xfs_setattr_size()
> should be doing. Stripping capability attributes should have been
> already been done by the generic setattr code before we get to
> xfs_setattr_size(), so ATTR_KILL_PRIV should not be set at that
> point.
> 
> notify_change() used to always strip ATTR_KILL_PRIV from ia_valid
> when it sets up the flags necessary to strip privileges in the
> ->setattr callout. But it doesn't appear to do so always anymore:
> 
>         if (ia_valid & ATTR_KILL_PRIV) {
>                 error = security_inode_need_killpriv(dentry);
>                 if (error < 0)
>                         return error;
>                 if (error == 0)
>                         ia_valid = attr->ia_valid &= ~ATTR_KILL_PRIV;
>         }
> 
> If ATTR_KILL_PRIV is still set, this implies
> security_inode_need_killpriv() returned > 0 for some reason. I'm
> assuming that this code ran:
> 
> security_inode_need_killpriv()
>   call_int_hook(inode_need_killpriv, 0, dentry);
> 
> And the only implemented hook is this:
> 
> LSM_HOOK_INIT(inode_need_killpriv, cap_inode_need_killpriv),
> 
> /**
>  * cap_inode_need_killpriv - Determine if inode change affects privileges
>  * @dentry: The inode/dentry in being changed with change marked
>  ATTR_KILL_PRIV
>  *
>  * Determine if an inode having a change applied that's marked ATTR_KILL_PRIV
>  * affects the security markings on that inode, and if it is, should
>  * inode_killpriv() be invoked or the change rejected.
>  *
>  * Returns 1 if security.capability has a value, meaning inode_killpriv()
>  * is required, 0 otherwise, meaning inode_killpriv() is not required.
>  */
> int cap_inode_need_killpriv(struct dentry *dentry)
> {
>         struct inode *inode = d_backing_inode(dentry);
>         int error;
>                                                                                  
>         error = __vfs_getxattr(dentry, inode, XATTR_NAME_CAPS, NULL, 0);
>         return error > 0;
> }
> 
> And that's the xattr that the reproducer is setting. So, smoking
> gun.
> 
> we've done a lookup on the security.capability xattr which it
> found so notify_change() does not clear ATTR_KILL_PRIV. The xattr
> gets killed in setattr_prepare() but it does not clear
> ATTR_KILL_PRIV, and hence we hit the assert faili when we get into
> xfs_setattr_size.
> 
> Looks like a regression introduced in 2016 by:
> 
> commit 030b533c4fd4d2ec3402363323de4bb2983c9cee
> Author: Jan Kara <jack@suse.cz>
> Date:   Thu May 26 17:21:32 2016 +0200
> 
>     fs: Avoid premature clearing of capabilities
>     
>     Currently, notify_change() clears capabilities or IMA attributes by
>     calling security_inode_killpriv() before calling into ->setattr. Thus it
>     happens before any other permission checks in inode_change_ok() and user
>     is thus allowed to trigger clearing of capabilities or IMA attributes
>     for any file he can look up e.g. by calling chown for that file. This is
>     unexpected and can lead to user DoSing a system.
>     
>     Fix the problem by calling security_inode_killpriv() at the end of
>     inode_change_ok() instead of from notify_change(). At that moment we are
>     sure user has permissions to do the requested change.
>     
>     References: CVE-2015-1350
>     Reviewed-by: Christoph Hellwig <hch@lst.de>
>     Signed-off-by: Jan Kara <jack@suse.cz>
> 
> The bug is harmless, it will only trigger the assert on debug XFS
> kernels, but otherwise ATTR_KILL_PRIV is not checked/used by
> xfs_setattr_size.
> 
> Removing ATTR_KILL_PRIV from the assert is probably all that is
> needed. Can you write a patch for that, Yumei?

Sure, I will send the patch soon.


Best Regards,

Yumei Huang

> 
> Cheers,
> 
> Dave.
> --
> Dave Chinner
> david@fromorbit.com
> 
> 


      reply	other threads:[~2021-01-15  8:38 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <1599642077.64707510.1610619249861.JavaMail.zimbra@redhat.com>
2021-01-14 10:20 ` XFS: Assertion failed Yumei Huang
2021-01-14 17:29   ` Brian Foster
2021-01-14 18:24     ` Brian Foster
2021-01-14 19:33       ` Eric Sandeen
2021-01-14 21:21     ` Dave Chinner
2021-01-15  8:36       ` Yumei Huang [this message]

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=1914065699.64814368.1610699800882.JavaMail.zimbra@redhat.com \
    --to=yuhuang@redhat.com \
    --cc=bfoster@redhat.com \
    --cc=david@fromorbit.com \
    --cc=linux-xfs@vger.kernel.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