All of lore.kernel.org
 help / color / mirror / Atom feed
From: Kees Cook <keescook@chromium.org>
To: "Eric W. Biederman" <ebiederm@xmission.com>
Cc: linux-kernel@vger.kernel.org,
	Linus Torvalds <torvalds@linux-foundation.org>,
	Oleg Nesterov <oleg@redhat.com>, Jann Horn <jannh@google.com>,
	Greg Ungerer <gerg@linux-m68k.org>, Rob Landley <rob@landley.net>,
	Bernd Edlinger <bernd.edlinger@hotmail.de>,
	linux-fsdevel@vger.kernel.org, Al Viro <viro@ZenIV.linux.org.uk>,
	Alexey Dobriyan <adobriyan@gmail.com>,
	Andrew Morton <akpm@linux-foundation.org>,
	Casey Schaufler <casey@schaufler-ca.com>,
	linux-security-module@vger.kernel.org,
	James Morris <jmorris@namei.org>,
	"Serge E. Hallyn" <serge@hallyn.com>,
	Andy Lutomirski <luto@amacapital.net>
Subject: Re: [PATCH 2/5] exec: Directly call security_bprm_set_creds from __do_execve_file
Date: Mon, 11 May 2020 14:18:22 -0700	[thread overview]
Message-ID: <202005111245.6E390B46@keescook> (raw)
In-Reply-To: <87y2pytnvq.fsf@x220.int.ebiederm.org>

On Mon, May 11, 2020 at 11:52:41AM -0500, Eric W. Biederman wrote:
> Kees Cook <keescook@chromium.org> writes:
> 
> > On Sat, May 09, 2020 at 02:41:17PM -0500, Eric W. Biederman wrote:
> >> 
> >> Now that security_bprm_set_creds is no longer responsible for calling
> >> cap_bprm_set_creds, security_bprm_set_creds only does something for
> >> the primary file that is being executed (not any interpreters it may
> >> have).  Therefore call security_bprm_set_creds from __do_execve_file,
> >> instead of from prepare_binprm so that it is only called once, and
> >> remove the now unnecessary called_set_creds field of struct binprm.
> >> 
> >> Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
> >> ---
> >>  fs/exec.c                  | 11 +++++------
> >>  include/linux/binfmts.h    |  6 ------
> >>  security/apparmor/domain.c |  3 ---
> >>  security/selinux/hooks.c   |  2 --
> >>  security/smack/smack_lsm.c |  3 ---
> >>  security/tomoyo/tomoyo.c   |  6 ------
> >>  6 files changed, 5 insertions(+), 26 deletions(-)
> >> 
> >> diff --git a/fs/exec.c b/fs/exec.c
> >> index 765bfd51a546..635b5085050c 100644
> >> --- a/fs/exec.c
> >> +++ b/fs/exec.c
> >> @@ -1635,12 +1635,6 @@ int prepare_binprm(struct linux_binprm *bprm)
> >>  
> >>  	bprm_fill_uid(bprm);
> >>  
> >> -	/* fill in binprm security blob */
> >> -	retval = security_bprm_set_creds(bprm);
> >> -	if (retval)
> >> -		return retval;
> >> -	bprm->called_set_creds = 1;
> >> -
> >>  	retval = cap_bprm_set_creds(bprm);
> >>  	if (retval)
> >>  		return retval;
> >> @@ -1858,6 +1852,11 @@ static int __do_execve_file(int fd, struct filename *filename,
> >>  	if (retval < 0)
> >>  		goto out;
> >>  
> >> +	/* fill in binprm security blob */
> >> +	retval = security_bprm_set_creds(bprm);
> >> +	if (retval)
> >> +		goto out;
> >> +
> >>  	retval = prepare_binprm(bprm);
> >>  	if (retval < 0)
> >>  		goto out;
> >> 
> >
> > Here I go with a Sunday night review, so hopefully I'm thinking better
> > than Friday night's review, but I *think* this patch is broken from
> > the LSM sense of the world in that security_bprm_set_creds() is getting
> > called _before_ the creds actually get fully set (in prepare_binprm()
> > by the calls to bprm_fill_uid(), cap_bprm_set_creds(), and
> > check_unsafe_exec()).
> >
> > As a specific example, see the setting of LSM_UNSAFE_NO_NEW_PRIVS in
> > bprm->unsafe during check_unsafe_exec(), which must happen after
> > bprm_fill_uid(bprm) and cap_bprm_set_creds(bprm), to have a "true" view
> > of the execution privileges. Apparmor checks for this flag in its
> > security_bprm_set_creds() hook. Similarly do selinux, smack, etc...
> 
> I think you are getting prepare_binprm confused with prepare_bprm_creds.
> Understandable given the similarity of their names.

I fixated on a bad example, having confused myself about when
check_unsafe_exec() happens. My original concern (with the bad example)
was that the LSM is having security_bprm_set_creds() called before the
new cred in bprm->cred has been initialized with all the correct uid/gid,
caps, and associated flags.

But anything associated with capabilities should be confined to the
commoncap LSM, though there is "leakage" into the uid/gid states and some
bprm state (more on this later). That said, as you also found, I can't
find any LSM that examines those fields of the cred (I had stopped this
research last night when I saw check_unsafe_exec() and confused myself);
they're all looking at other bprm state not associated with caps and uid
changes (file, unsafe_exec, security field of new cred, etc). So that's
very good! That means we've actually kept a bright line between things
here -- whew.

> > The security_bprm_set_creds() boundary for LSM is to see the "final"
> > state of the process privileges, and that needs to happen after
> > bprm_fill_uid(), cap_bprm_set_creds(), and check_unsafe_exec() have all
> > finished.
> >
> > So, as it stands, I don't think this will work, but perhaps it can still
> > be rearranged to avoid the called_set_creds silliness. I'll look more
> > this week...
> 
> If you look at the flow of the code in __do_execve_file before this
> change it is:
> 
> 	prepare_bprm_creds()
>         check_unsafe_exec()
> 
> 	...
> 
>         prepare_binprm()
>         	bprm_file_uid()

(bprm_fill_uid(), but yes)

>                 	bprm->cred->euid = current_euid()
>                         bprm->cred->egid = current_egid()
> 		security_bprm_set_creds()
>                 	for_each_lsm()
>                         	lsm->bprm_set_creds()
>                                 	if (called_set_creds)
>                                         	return;
>                                         ...
> 		bprm->called_set_creds = 1;
> 	...
> 
> 	exec_binprm()
>         	search_binary_handler()
>                 	security_bprm_check()
>                         	tomoyo_bprm_check_security()
>                                 ima_bprm_check()
>    			load_script()
>                         	prepare_binprm()
>                                 	/* called_set_creds already == 1 */
>                                 	bprm_file_uid()
>                                         security_bprm_set_creds()
> 			                	for_each_lsm()
> 			                        	lsm->bprm_set_creds()
> 		                                	if (called_set_creds)
>                 		                        	return;
>                                 		        ...
>                                 search_binary_handler()
>                                 	security_bprm_check_security()
>                                         load_elf_binary()
>                                         	...
>                                                 setup_new_exec
>                                                 ...
> 
> 
> Assuming you are executing a shell script.
> 
> Now bprm_file_uid is written with the assumption that it will be called
> multiple times and it reinitializes all of it's variables each time.

Right -- and the same is true for cap_bprm_set_creds() (in that
it needs to be run multiple times and depends on the work done in
bprm_fill_uid()). If we encounter a future use-case for having other
LSMs call out here multiple time, we can introduce a new LSM hook.

> As you can see in above the implementations of bprm_set_creds() only
> really execute before called_set_creds is set, aka the first time.
> They in no way see the final state.
> 
> Further when I looked as those hooks they were not looking at the values
> set by bprm_file_uid at all.  There were busy with the values their
> they needed to set in that hook for their particular lsm.

Agreed (though I'd love some other LSM eyes on this conclusion).

> So while in theory I can see the danger of moving above bprm_file_uid
> I don't see anything in practice that would be a problem.
> 
> Further by moving the call of security_bprm_set_creds out of
> prepare_binprm int __do_execve_file just before the call of
> prepare_binprm I am just moving the call above binprm_fill_uid
> and nothing else.
> 
> So I think you just confused prepare_bprm_creds with prepare_binprm.
> As most of your criticisms appear valid in that case.  Can you take a
> second look?

So, in earlier attempts to clean up code near all this, I removed the
LSM's bprm_secureexec hook, which only commoncap was using to impart
details about privilege elevation. I switched the semantics to having LSMs
set bprm->secureexec to true (but never to zero). Since commoncap's idea
of "was I elevated?" might repeatedly change, I had to store its results
"privately" in the bprm, which got us cap_elevated (in 46d98eb4e1d2):

c425e189ffd7 ("binfmt: Introduce secureexec flag")
993b3ab0642e ("apparmor: Refactor to remove bprm_secureexec hook")
62874c3adf70 ("selinux: Refactor to remove bprm_secureexec hook")
46d98eb4e1d2 ("commoncap: Refactor to remove bprm_secureexec hook")
ee67ae7ef6ff ("commoncap: Move cap_elevated calculation into bprm_set_creds")
2af622802696 ("LSM: drop bprm_secureexec hook")

So, given the special-case nature of capabilities here, this does seem
to be the right choice (assuming we're not missing something in the
other LSMs). As such, I think the comment for cap_elevated needs to be
updated to reflect the change to function call flow, and to specify it
cannot be used by the other LSMs. Maybe something like:

               /*
                * True if most recent call to cap_bprm_set_creds()
                * (due to multiple prepare_binprm() calls from the
                * binfmt_script/misc handlers) resulted in elevated
                * privileges. This is used internally by fs/exec.c
		* to set bprm->secureexec.
                */
               cap_elevated:1,

And that brings us to naming. Whee. I think we should make the following
name changes:

bprm_fill_uid      ->	bprm_establish_privileges
cap_bprm_set_creds ->	cap_establish_privileges

Finally, I think we should update the comment on bprm_set_creds (which,
actually, I think is the correct name now) to something like:

 * @bprm_set_creds:
 *	Save security information in the @bprm->cred->security field,
 *	typically based on information about the bprm->file, for later
 *	use during the @bprm_committing_creds hook. Specifically
 *	the credentials themselves (uid, gid, etc), are not finalized
 *	yet and must not be examined until the @bprm_committing_creds
 *	hook.
 *      This hook is called once, after the creds structure has been
 *	allocated.
 *      The hook must set @bprm->secureexec to 1 if a "secure exec"
 *	has happened as a result of this hook call. The flag is used to
 *      indicate the need for a sanitized execution environment, and is
 *      also passed in the ELF auxiliary table on the initial stack to
 *      indicate whether libc should enable secure mode.
 *	This hook may also optionally check LSM-specific permissions
 *	(e.g. for transitions between security domains).
 *      @bprm contains the linux_binprm structure.
 *      Return 0 if the hook is successful and permission is granted.

-Kees

-- 
Kees Cook

  reply	other threads:[~2020-05-11 21:18 UTC|newest]

Thread overview: 149+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-05-05 19:39 exec: Promised cleanups after introducing exec_update_mutex Eric W. Biederman
2020-05-05 19:41 ` [PATCH 1/7] binfmt: Move install_exec_creds after setup_new_exec to match binfmt_elf Eric W. Biederman
2020-05-05 20:45   ` Kees Cook
2020-05-06 12:42   ` Greg Ungerer
2020-05-06 12:56     ` Eric W. Biederman
2020-05-05 19:41 ` [PATCH 2/7] exec: Make unlocking exec_update_mutex explict Eric W. Biederman
2020-05-05 20:46   ` Kees Cook
2020-05-05 19:42 ` [PATCH 3/7] exec: Rename the flag called_exec_mmap point_of_no_return Eric W. Biederman
2020-05-05 20:49   ` Kees Cook
2020-05-05 19:43 ` [PATCH 4/7] exec: Merge install_exec_creds into setup_new_exec Eric W. Biederman
2020-05-05 20:50   ` Kees Cook
2020-05-05 19:44 ` [PATCH 5/7] exec: In setup_new_exec cache current in the local variable me Eric W. Biederman
2020-05-05 20:51   ` Kees Cook
2020-05-05 19:45 ` [PATCH 6/7] exec: Move most of setup_new_exec into flush_old_exec Eric W. Biederman
2020-05-05 21:29   ` Kees Cook
2020-05-06 14:57     ` Eric W. Biederman
2020-05-06 15:30       ` Kees Cook
2020-05-07 19:51         ` Eric W. Biederman
2020-05-07 21:51     ` Eric W. Biederman
2020-05-08  5:50       ` Kees Cook
2020-05-05 19:46 ` [PATCH 7/7] exec: Rename flush_old_exec begin_new_exec Eric W. Biederman
2020-05-05 21:30   ` Kees Cook
2020-05-06 12:41 ` exec: Promised cleanups after introducing exec_update_mutex Greg Ungerer
2020-05-08 18:43 ` [PATCH 0/6] exec: Trivial cleanups for exec Eric W. Biederman
2020-05-08 18:44   ` [PATCH 1/6] exec: Move the comment from above de_thread to above unshare_sighand Eric W. Biederman
2020-05-09  5:02     ` Kees Cook
2020-05-08 18:44   ` [PATCH 2/6] exec: Fix spelling of search_binary_handler in a comment Eric W. Biederman
2020-05-09  5:03     ` Kees Cook
2020-05-08 18:45   ` [PATCH 3/6] exec: Stop open coding mutex_lock_killable of cred_guard_mutex Eric W. Biederman
2020-05-09  5:08     ` Kees Cook
2020-05-09 19:18     ` Linus Torvalds
2020-05-09 19:57       ` Eric W. Biederman
2020-05-10 20:33       ` Kees Cook
2020-05-08 18:45   ` [PATCH 4/6] exec: Run sync_mm_rss before taking exec_update_mutex Eric W. Biederman
2020-05-09  5:15     ` Kees Cook
2020-05-09 14:17       ` Eric W. Biederman
2020-05-08 18:47   ` [PATCH 5/6] exec: Move handling of the point of no return to the top level Eric W. Biederman
2020-05-09  5:31     ` Kees Cook
2020-05-09 13:39       ` Eric W. Biederman
2020-05-08 18:48   ` [PATCH 6/6] exec: Set the point of no return sooner Eric W. Biederman
2020-05-09  5:33     ` Kees Cook
2020-05-09 19:40   ` [PATCH 0/5] exec: Control flow simplifications Eric W. Biederman
2020-05-09 19:40     ` [PATCH 1/5] exec: Call cap_bprm_set_creds directly from prepare_binprm Eric W. Biederman
2020-05-09 20:04       ` Linus Torvalds
2020-05-09 19:41     ` [PATCH 2/5] exec: Directly call security_bprm_set_creds from __do_execve_file Eric W. Biederman
2020-05-09 20:07       ` Linus Torvalds
2020-05-09 20:12         ` Eric W. Biederman
2020-05-09 20:19           ` Linus Torvalds
2020-05-11  3:15       ` Kees Cook
2020-05-11 16:52         ` Eric W. Biederman
2020-05-11 21:18           ` Kees Cook [this message]
2020-05-09 19:41     ` [PATCH 3/5] exec: Remove recursion from search_binary_handler Eric W. Biederman
2020-05-09 20:16       ` Linus Torvalds
2020-05-10  4:22       ` Tetsuo Handa
2020-05-10 19:38         ` Linus Torvalds
2020-05-11 14:33           ` Eric W. Biederman
2020-05-11 19:10             ` Rob Landley
2020-05-13 21:59               ` Eric W. Biederman
2020-05-14 18:46                 ` Rob Landley
2020-05-11 21:55             ` Kees Cook
2020-05-12 18:42               ` Eric W. Biederman
2020-05-12 19:25                 ` Kees Cook
2020-05-12 20:31                   ` Eric W. Biederman
2020-05-12 23:08                     ` Kees Cook
2020-05-12 23:47                       ` Kees Cook
2020-05-12 23:51                         ` Kees Cook
2020-05-14 14:56                           ` Eric W. Biederman
2020-05-14 16:56                             ` Casey Schaufler
2020-05-14 17:02                               ` Eric W. Biederman
2020-05-13  0:20                 ` Linus Torvalds
2020-05-13  2:39                   ` Rob Landley
2020-05-13 19:51                     ` Linus Torvalds
2020-05-14 16:49                   ` Eric W. Biederman
2020-05-09 19:42     ` [PATCH 4/5] exec: Allow load_misc_binary to call prepare_binfmt unconditionally Eric W. Biederman
2020-05-11 22:09       ` Kees Cook
2020-05-09 19:42     ` [PATCH 5/5] exec: Move the call of prepare_binprm into search_binary_handler Eric W. Biederman
2020-05-11 22:24       ` Kees Cook
2020-05-19  0:29     ` [PATCH v2 0/8] exec: Control flow simplifications Eric W. Biederman
2020-05-19  0:29       ` [PATCH v2 1/8] exec: Teach prepare_exec_creds how exec treats uids & gids Eric W. Biederman
2020-05-19 18:03         ` Kees Cook
2020-05-19 18:28           ` Linus Torvalds
2020-05-19 18:57             ` Eric W. Biederman
2020-05-19  0:30       ` [PATCH v2 2/8] exec: Factor security_bprm_creds_for_exec out of security_bprm_set_creds Eric W. Biederman
2020-05-19 15:34         ` Casey Schaufler
2020-05-19 18:10         ` Kees Cook
2020-05-19 21:28           ` James Morris
2020-05-19  0:31       ` [PATCH v2 3/8] exec: Convert security_bprm_set_creds into security_bprm_repopulate_creds Eric W. Biederman
2020-05-19 18:21         ` Kees Cook
2020-05-19 19:03           ` Eric W. Biederman
2020-05-19 19:14             ` Kees Cook
2020-05-20 20:22               ` Eric W. Biederman
2020-05-20 20:53                 ` Kees Cook
2020-05-19 21:52         ` James Morris
2020-05-20 12:40           ` Eric W. Biederman
2020-05-19  0:31       ` [PATCH v2 4/8] exec: Allow load_misc_binary to call prepare_binfmt unconditionally Eric W. Biederman
2020-05-19 18:27         ` Kees Cook
2020-05-19 19:08           ` Eric W. Biederman
2020-05-19 19:17             ` Kees Cook
2020-05-19  0:32       ` [PATCH v2 5/8] exec: Move the call of prepare_binprm into search_binary_handler Eric W. Biederman
2020-05-19 18:27         ` Kees Cook
2020-05-19 21:30         ` James Morris
2020-05-19  0:33       ` [PATCH v2 6/8] exec/binfmt_script: Don't modify bprm->buf and then return -ENOEXEC Eric W. Biederman
2020-05-19 19:08         ` Kees Cook
2020-05-19 19:19           ` Eric W. Biederman
2020-05-19  0:33       ` [PATCH v2 7/8] exec: Generic execfd support Eric W. Biederman
2020-05-19 19:46         ` Kees Cook
2020-05-19 19:54           ` Linus Torvalds
2020-05-19 20:20             ` Eric W. Biederman
2020-05-19 21:59         ` Rob Landley
2020-05-20 16:05           ` Eric W. Biederman
2020-05-21 22:50             ` Rob Landley
2020-05-22  3:28               ` Eric W. Biederman
2020-05-22  4:51                 ` Rob Landley
2020-05-22 13:35                   ` Eric W. Biederman
2020-05-19  0:34       ` [PATCH v2 8/8] exec: Remove recursion from search_binary_handler Eric W. Biederman
2020-05-19 20:37         ` Kees Cook
2020-05-19  1:25       ` [PATCH v2 0/8] exec: Control flow simplifications Linus Torvalds
2020-05-19 21:55       ` Kees Cook
2020-05-20 13:02         ` Eric W. Biederman
2020-05-20 22:12       ` Eric W. Biederman
2020-05-20 23:43         ` Kees Cook
2020-05-21 11:53           ` Eric W. Biederman
2020-05-28 15:38       ` [PATCH 0/11] exec: cred calculation simplifications Eric W. Biederman
2020-05-28 15:41         ` [PATCH 01/11] exec: Reduce bprm->per_clear to a single bit Eric W. Biederman
2020-05-28 19:04           ` Linus Torvalds
2020-05-28 19:17             ` Eric W. Biederman
2020-05-28 15:42         ` [PATCH 02/11] exec: Introduce active_per_clear the per file version of per_clear Eric W. Biederman
2020-05-28 19:05           ` Linus Torvalds
2020-05-28 15:42         ` [PATCH 03/11] exec: Compute file based creds only once Eric W. Biederman
2020-05-28 15:43         ` [PATCH 04/11] exec: Move uid/gid handling from creds_from_file into bprm_fill_uid Eric W. Biederman
2020-05-28 15:44         ` Eric W. Biederman
2020-05-28 15:44         ` [PATCH 05/11] exec: In bprm_fill_uid use CAP_SETGID to see if a gid change is safe Eric W. Biederman
2020-05-28 15:48         ` [PATCH 06/11] exec: Don't set secureexec when the uid or gid changes are abandoned Eric W. Biederman
2020-05-28 15:48         ` [PATCH 07/11] exec: Set saved, fs, and effective ids together in bprm_fill_uid Eric W. Biederman
2020-05-28 15:49         ` [PATCH 08/11] exec: In bprm_fill_uid remove unnecessary no new privs check Eric W. Biederman
2020-05-28 15:49         ` [PATCH 09/11] exec: In bprm_fill_uid only set per_clear when honoring suid or sgid Eric W. Biederman
2020-05-28 19:08           ` Linus Torvalds
2020-05-28 19:21             ` Eric W. Biederman
2020-05-28 15:50         ` [PATCH 10/11] exec: In bprm_fill_uid set secureexec at same time as per_clear Eric W. Biederman
2020-05-28 15:50         ` [PATCH 11/11] exec: Remove the label after_setid from bprm_fill_uid Eric W. Biederman
2020-05-29 16:45         ` [PATCH 0/2] exec: Remove the computation of bprm->cred Eric W. Biederman
2020-05-29 16:46           ` [PATCH 1/2] exec: Add a per bprm->file version of per_clear Eric W. Biederman
2020-05-29 21:06             ` Kees Cook
2020-05-30  3:23               ` Eric W. Biederman
2020-05-30  5:14                 ` Kees Cook
2020-05-29 16:47           ` [PATCH 2/2] exec: Compute file based creds only once Eric W. Biederman
2020-05-29 21:24             ` Kees Cook
2020-05-30  3:28               ` Eric W. Biederman
2020-05-30  5:18                 ` Kees Cook

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=202005111245.6E390B46@keescook \
    --to=keescook@chromium.org \
    --cc=adobriyan@gmail.com \
    --cc=akpm@linux-foundation.org \
    --cc=bernd.edlinger@hotmail.de \
    --cc=casey@schaufler-ca.com \
    --cc=ebiederm@xmission.com \
    --cc=gerg@linux-m68k.org \
    --cc=jannh@google.com \
    --cc=jmorris@namei.org \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-security-module@vger.kernel.org \
    --cc=luto@amacapital.net \
    --cc=oleg@redhat.com \
    --cc=rob@landley.net \
    --cc=serge@hallyn.com \
    --cc=torvalds@linux-foundation.org \
    --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 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.