All of lore.kernel.org
 help / color / mirror / Atom feed
From: Andy Lutomirski <luto@kernel.org>
To: Konstantin Khlebnikov <koct9i@gmail.com>
Cc: Willy Tarreau <w@1wt.eu>, Kees Cook <keescook@chromium.org>,
	Alexander Viro <viro@zeniv.linux.org.uk>,
	"linux-mm@kvack.org" <linux-mm@kvack.org>,
	Andrew Morton <akpm@linux-foundation.org>,
	yalin wang <yalin.wang2010@gmail.com>,
	Linux Kernel Mailing List <linux-kernel@vger.kernel.org>,
	Jan Kara <jack@suse.cz>
Subject: should_remove_suid capable check is busted
Date: Tue, 19 Jan 2016 11:26:50 -0800	[thread overview]
Message-ID: <CALCETrXvyguKpRsyBC_6AGOxzSdMZ43Q5w_3zzAThsm+R91LSg@mail.gmail.com> (raw)

On Jan 14, 2016 10:36 PM, "Konstantin Khlebnikov" <koct9i@gmail.com> wrote:
>
> On Fri, Jan 15, 2016 at 9:18 AM, Andy Lutomirski <luto@amacapital.net> wrote:
> > While we're at it:
> >
> > int should_remove_suid(struct dentry *dentry)
> > {
> >         umode_t mode = d_inode(dentry)->i_mode;
> >         int kill = 0;
> >
> >         /* suid always must be killed */
> >         if (unlikely(mode & S_ISUID))
> >                 kill = ATTR_KILL_SUID;
> >
> >         /*
> >          * sgid without any exec bits is just a mandatory locking mark; leave
> >          * it alone.  If some exec bits are set, it's a real sgid; kill it.
> >          */
> >         if (unlikely((mode & S_ISGID) && (mode & S_IXGRP)))
> >                 kill |= ATTR_KILL_SGID;
> >
> >         if (unlikely(kill && !capable(CAP_FSETID) && S_ISREG(mode)))
> >                 return kill;
> >
> >         return 0;
> > }
> > EXPORT_SYMBOL(should_remove_suid);
> >
> > Oh wait, is that an implicit use of current_cred in vfs_write?  No, it
> > couldn't be.  Kernel developers *never* make that mistake.
> >
> > This is, of course, totally fucked because this function doesn't have
> > access to a struct file and therefore can't see f_cred.  I'm not going
> > to look in to this right now, but I swear I saw an exploit that took
> > advantage of this bug recently.  Anyone want to try to fix it?
>
> Good point. it's here since 2.3.43.
> As I see file->f_cred is reachable in all places.

Nope, vfs_truncate doesn't have f_cred reachable.  All other call sites are fine

And here's the reference:

http://www.halfdog.net/Security/2015/SetgidDirectoryPrivilegeEscalation/

Seriously, can we get away with removing the capable() check outright?
 nfs already explicitly ignores capabilities for this purpose, and in
my opinion having a security decision on write depend the FSETID
capability is just BS.  I'm a bit afraid of breaking some package
manager, though.

What a clusterfsck.

--Andy

>
> >
> > FWIW, posix says (man 3p write):
> >
> >        Upon  successful  completion,  where  nbyte  is greater than 0, write()
> >        shall mark for update the last data modification and last  file  status
> >        change  timestamps  of the file, and if the file is a regular file, the
> >        S_ISUID and S_ISGID bits of the file mode may be cleared.
> >
> > so maybe the thing to do is just drop the capable check entirely and
> > cross our fingers that nothing was relying on it.
> >
> > --Andy
> >

WARNING: multiple messages have this Message-ID (diff)
From: Andy Lutomirski <luto@kernel.org>
To: Konstantin Khlebnikov <koct9i@gmail.com>
Cc: Willy Tarreau <w@1wt.eu>, Kees Cook <keescook@chromium.org>,
	Alexander Viro <viro@zeniv.linux.org.uk>,
	"linux-mm@kvack.org" <linux-mm@kvack.org>,
	Andrew Morton <akpm@linux-foundation.org>,
	yalin wang <yalin.wang2010@gmail.com>,
	Linux Kernel Mailing List <linux-kernel@vger.kernel.org>,
	Jan Kara <jack@suse.cz>
Subject: should_remove_suid capable check is busted
Date: Tue, 19 Jan 2016 11:26:50 -0800	[thread overview]
Message-ID: <CALCETrXvyguKpRsyBC_6AGOxzSdMZ43Q5w_3zzAThsm+R91LSg@mail.gmail.com> (raw)

On Jan 14, 2016 10:36 PM, "Konstantin Khlebnikov" <koct9i@gmail.com> wrote:
>
> On Fri, Jan 15, 2016 at 9:18 AM, Andy Lutomirski <luto@amacapital.net> wrote:
> > While we're at it:
> >
> > int should_remove_suid(struct dentry *dentry)
> > {
> >         umode_t mode = d_inode(dentry)->i_mode;
> >         int kill = 0;
> >
> >         /* suid always must be killed */
> >         if (unlikely(mode & S_ISUID))
> >                 kill = ATTR_KILL_SUID;
> >
> >         /*
> >          * sgid without any exec bits is just a mandatory locking mark; leave
> >          * it alone.  If some exec bits are set, it's a real sgid; kill it.
> >          */
> >         if (unlikely((mode & S_ISGID) && (mode & S_IXGRP)))
> >                 kill |= ATTR_KILL_SGID;
> >
> >         if (unlikely(kill && !capable(CAP_FSETID) && S_ISREG(mode)))
> >                 return kill;
> >
> >         return 0;
> > }
> > EXPORT_SYMBOL(should_remove_suid);
> >
> > Oh wait, is that an implicit use of current_cred in vfs_write?  No, it
> > couldn't be.  Kernel developers *never* make that mistake.
> >
> > This is, of course, totally fucked because this function doesn't have
> > access to a struct file and therefore can't see f_cred.  I'm not going
> > to look in to this right now, but I swear I saw an exploit that took
> > advantage of this bug recently.  Anyone want to try to fix it?
>
> Good point. it's here since 2.3.43.
> As I see file->f_cred is reachable in all places.

Nope, vfs_truncate doesn't have f_cred reachable.  All other call sites are fine

And here's the reference:

http://www.halfdog.net/Security/2015/SetgidDirectoryPrivilegeEscalation/

Seriously, can we get away with removing the capable() check outright?
 nfs already explicitly ignores capabilities for this purpose, and in
my opinion having a security decision on write depend the FSETID
capability is just BS.  I'm a bit afraid of breaking some package
manager, though.

What a clusterfsck.

--Andy

>
> >
> > FWIW, posix says (man 3p write):
> >
> >        Upon  successful  completion,  where  nbyte  is greater than 0, write()
> >        shall mark for update the last data modification and last  file  status
> >        change  timestamps  of the file, and if the file is a regular file, the
> >        S_ISUID and S_ISGID bits of the file mode may be cleared.
> >
> > so maybe the thing to do is just drop the capable check entirely and
> > cross our fingers that nothing was relying on it.
> >
> > --Andy
> >

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>

             reply	other threads:[~2016-01-19 19:27 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-01-19 19:26 Andy Lutomirski [this message]
2016-01-19 19:26 ` should_remove_suid capable check is busted Andy Lutomirski

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=CALCETrXvyguKpRsyBC_6AGOxzSdMZ43Q5w_3zzAThsm+R91LSg@mail.gmail.com \
    --to=luto@kernel.org \
    --cc=akpm@linux-foundation.org \
    --cc=jack@suse.cz \
    --cc=keescook@chromium.org \
    --cc=koct9i@gmail.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    --cc=viro@zeniv.linux.org.uk \
    --cc=w@1wt.eu \
    --cc=yalin.wang2010@gmail.com \
    /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.