Re: [PATCH v2 3/8] exec: Convert security_bprm_set_creds into security_bprm_repopulate_creds

2020-05-20 Thread Kees Cook
On Wed, May 20, 2020 at 03:22:38PM -0500, Eric W. Biederman wrote:
> Kees Cook  writes:
> 
> > On Tue, May 19, 2020 at 02:03:23PM -0500, Eric W. Biederman wrote:
> >> Kees Cook  writes:
> >> 
> >> > On Mon, May 18, 2020 at 07:31:14PM -0500, Eric W. Biederman wrote:
> >> >> [...]
> >> >> diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h
> >> >> index d1217fcdedea..8605ab4a0f89 100644
> >> >> --- a/include/linux/binfmts.h
> >> >> +++ b/include/linux/binfmts.h
> >> >> @@ -27,10 +27,10 @@ struct linux_binprm {
> >> >> unsigned long argmin; /* rlimit marker for copy_strings() */
> >> >> unsigned int
> >> >> /*
> >> >> -* True if most recent call to cap_bprm_set_creds
> >> >> +* True if most recent call to security_bprm_set_creds
> >> >>  * resulted in elevated privileges.
> >> >>  */
> >> >> -   cap_elevated:1,
> >> >> +   active_secureexec:1,
> >> >
> >> > Also, I'd like it if this comment could be made more verbose as well, for
> >> > anyone trying to understand the binfmt execution flow for the first time.
> >> > Perhaps:
> >> >
> >> >  /*
> >> >   * Must be set True during the any call to
> >> >   * bprm_set_creds hook where the execution would
> >> >   * reuslt in elevated privileges. (The hook can be
> >> >   * called multiple times during nested interpreter
> >> >   * resolution across binfmt_script, binfmt_misc, etc).
> >> >   */
> >> Well it is not during but after the call that it becomes true.
> >> I think most recent covers the case of multiple calls.
> >
> > I'm thinking of an LSM writing reading these comments to decide what
> > they need to do to the flags, so it's a direction to them to set it to
> > true if they have determined that privilege was gained. (Though in
> > theory, this is all moot since only the commoncap hook cares.)
> 
> The comments for an LSM writer are in include/linux/lsm_hooks.h
> 
>  * @bprm_repopulate_creds:
>  *Assuming that the relevant bits of @bprm->cred->security have been
>  *previously set, examine @bprm->file and regenerate them.  This is
>  *so that the credentials derived from the interpreter the code is
>  *actually going to run are used rather than credentials derived
>  *from a script.  This done because the interpreter binary needs to
>  *reopen script, and may end up opening something completely different.
>  *This hook may also optionally check permissions (e.g. for
>  *transitions between security domains).
>  *The hook must set @bprm->active_secureexec to 1 if AT_SECURE should be 
> set to
>  *request libc enable secure mode.
>  *@bprm contains the linux_binprm structure.
>  *Return 0 if the hook is successful and permission is granted.
> 
> I hope that is detailed enough.
> 
> I will leave the rest of the comments for the maintainer of the code.
> 
> I really don't think we should duplicate the prescriptive comments in
> multiple locations.

Okay, that's fair enough. Thanks!

-- 
Kees Cook


Re: [PATCH v2 3/8] exec: Convert security_bprm_set_creds into security_bprm_repopulate_creds

2020-05-20 Thread Eric W. Biederman
Kees Cook  writes:

> On Tue, May 19, 2020 at 02:03:23PM -0500, Eric W. Biederman wrote:
>> Kees Cook  writes:
>> 
>> > On Mon, May 18, 2020 at 07:31:14PM -0500, Eric W. Biederman wrote:
>> >> [...]
>> >> diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h
>> >> index d1217fcdedea..8605ab4a0f89 100644
>> >> --- a/include/linux/binfmts.h
>> >> +++ b/include/linux/binfmts.h
>> >> @@ -27,10 +27,10 @@ struct linux_binprm {
>> >>   unsigned long argmin; /* rlimit marker for copy_strings() */
>> >>   unsigned int
>> >>   /*
>> >> -  * True if most recent call to cap_bprm_set_creds
>> >> +  * True if most recent call to security_bprm_set_creds
>> >>* resulted in elevated privileges.
>> >>*/
>> >> - cap_elevated:1,
>> >> + active_secureexec:1,
>> >
>> > Also, I'd like it if this comment could be made more verbose as well, for
>> > anyone trying to understand the binfmt execution flow for the first time.
>> > Perhaps:
>> >
>> >/*
>> > * Must be set True during the any call to
>> > * bprm_set_creds hook where the execution would
>> > * reuslt in elevated privileges. (The hook can be
>> > * called multiple times during nested interpreter
>> > * resolution across binfmt_script, binfmt_misc, etc).
>> > */
>> Well it is not during but after the call that it becomes true.
>> I think most recent covers the case of multiple calls.
>
> I'm thinking of an LSM writing reading these comments to decide what
> they need to do to the flags, so it's a direction to them to set it to
> true if they have determined that privilege was gained. (Though in
> theory, this is all moot since only the commoncap hook cares.)

The comments for an LSM writer are in include/linux/lsm_hooks.h

 * @bprm_repopulate_creds:
 *  Assuming that the relevant bits of @bprm->cred->security have been
 *  previously set, examine @bprm->file and regenerate them.  This is
 *  so that the credentials derived from the interpreter the code is
 *  actually going to run are used rather than credentials derived
 *  from a script.  This done because the interpreter binary needs to
 *  reopen script, and may end up opening something completely different.
 *  This hook may also optionally check permissions (e.g. for
 *  transitions between security domains).
 *  The hook must set @bprm->active_secureexec to 1 if AT_SECURE should be 
set to
 *  request libc enable secure mode.
 *  @bprm contains the linux_binprm structure.
 *  Return 0 if the hook is successful and permission is granted.

I hope that is detailed enough.

I will leave the rest of the comments for the maintainer of the code.

I really don't think we should duplicate the prescriptive comments in
multiple locations.

Eric


Re: [PATCH v2 3/8] exec: Convert security_bprm_set_creds into security_bprm_repopulate_creds

2020-05-20 Thread Eric W. Biederman
James Morris  writes:

> On Mon, 18 May 2020, Eric W. Biederman wrote:
>
>> diff --git a/fs/exec.c b/fs/exec.c
>> index 9e70da47f8d9..8e3b93d51d31 100644
>> --- a/fs/exec.c
>> +++ b/fs/exec.c
>> @@ -1366,7 +1366,7 @@ int begin_new_exec(struct linux_binprm * bprm)
>>   * the final state of setuid/setgid/fscaps can be merged into the
>>   * secureexec flag.
>>   */
>> -bprm->secureexec |= bprm->cap_elevated;
>> +bprm->secureexec |= bprm->active_secureexec;
>
> Which kernel tree are these patches for? Seems like begin_new_exec() is 
> from a prerequisite patchset.

The base is:
git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace.git 
exec-next

I should have mentioned.  I am several round deep in cleaning up exec
already.

begin_new_exec is essentially forget_old_exec.

Eric




Re: [PATCH v2 3/8] exec: Convert security_bprm_set_creds into security_bprm_repopulate_creds

2020-05-19 Thread James Morris
On Mon, 18 May 2020, Eric W. Biederman wrote:

> diff --git a/fs/exec.c b/fs/exec.c
> index 9e70da47f8d9..8e3b93d51d31 100644
> --- a/fs/exec.c
> +++ b/fs/exec.c
> @@ -1366,7 +1366,7 @@ int begin_new_exec(struct linux_binprm * bprm)
>* the final state of setuid/setgid/fscaps can be merged into the
>* secureexec flag.
>*/
> - bprm->secureexec |= bprm->cap_elevated;
> + bprm->secureexec |= bprm->active_secureexec;

Which kernel tree are these patches for? Seems like begin_new_exec() is 
from a prerequisite patchset.


-- 
James Morris




Re: [PATCH v2 3/8] exec: Convert security_bprm_set_creds into security_bprm_repopulate_creds

2020-05-19 Thread Kees Cook
On Tue, May 19, 2020 at 02:03:23PM -0500, Eric W. Biederman wrote:
> Kees Cook  writes:
> 
> > On Mon, May 18, 2020 at 07:31:14PM -0500, Eric W. Biederman wrote:
> >> [...]
> >> diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h
> >> index d1217fcdedea..8605ab4a0f89 100644
> >> --- a/include/linux/binfmts.h
> >> +++ b/include/linux/binfmts.h
> >> @@ -27,10 +27,10 @@ struct linux_binprm {
> >>unsigned long argmin; /* rlimit marker for copy_strings() */
> >>unsigned int
> >>/*
> >> -   * True if most recent call to cap_bprm_set_creds
> >> +   * True if most recent call to security_bprm_set_creds
> >> * resulted in elevated privileges.
> >> */
> >> -  cap_elevated:1,
> >> +  active_secureexec:1,
> >
> > Also, I'd like it if this comment could be made more verbose as well, for
> > anyone trying to understand the binfmt execution flow for the first time.
> > Perhaps:
> >
> > /*
> >  * Must be set True during the any call to
> >  * bprm_set_creds hook where the execution would
> >  * reuslt in elevated privileges. (The hook can be
> >  * called multiple times during nested interpreter
> >  * resolution across binfmt_script, binfmt_misc, etc).
> >  */
> Well it is not during but after the call that it becomes true.
> I think most recent covers the case of multiple calls.

I'm thinking of an LSM writing reading these comments to decide what
they need to do to the flags, so it's a direction to them to set it to
true if they have determined that privilege was gained. (Though in
theory, this is all moot since only the commoncap hook cares.)

> I think having the loop explicitly in the code a few patches
> later makes it clear that there is a loop dealing with interpreters.
> 
> Conciseness has a virtue in that it is easy to absorb.  Seeing
> active says most recent and secureexec does not is enough to ask
> questions and look at the code.

I still think a hint about the nature of nested exec resolution would be
nice in here somewhere, especially given that this value is zeroed
before each call to the hook.

-- 
Kees Cook


Re: [PATCH v2 3/8] exec: Convert security_bprm_set_creds into security_bprm_repopulate_creds

2020-05-19 Thread Eric W. Biederman
Kees Cook  writes:

> On Mon, May 18, 2020 at 07:31:14PM -0500, Eric W. Biederman wrote:
>> 
>> Rename bprm->cap_elevated to bprm->active_secureexec and initialize it
>> in prepare_binprm instead of in cap_bprm_set_creds.  Initializing
>> bprm->active_secureexec in prepare_binprm allows multiple
>> implementations of security_bprm_repopulate_creds to play nicely with
>> each other.
>> 
>> Rename security_bprm_set_creds to security_bprm_reopulate_creds to
>> emphasize that this path recomputes part of bprm->cred.  This
>> recomputation avoids the time of check vs time of use problems that
>> are inherent in unix #! interpreters.
>> 
>> In short two renames and a move in the location of initializing
>> bprm->active_secureexec.
>
> I like this much better than the direct call to the capabilities hook.
> Thanks!
>
> Reviewed-by: Kees Cook 
>
> One nit is a bikeshed on the name "active_secureexec", since
> the word "active" isn't really associated with any other part of the
> binfmt logic. It's supposed to be "latest state from the binfmt loop",
> so instead of "active", I considered these words that I also didn't
> like: "current", "this", "recent", and "now". Is "latest" better than
> "active"? Probably not.

I had pretty much the same problem.  Active at least conveys that it
is still malleable and might change.

>> [...]
>> diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h
>> index d1217fcdedea..8605ab4a0f89 100644
>> --- a/include/linux/binfmts.h
>> +++ b/include/linux/binfmts.h
>> @@ -27,10 +27,10 @@ struct linux_binprm {
>>  unsigned long argmin; /* rlimit marker for copy_strings() */
>>  unsigned int
>>  /*
>> - * True if most recent call to cap_bprm_set_creds
>> + * True if most recent call to security_bprm_set_creds
>>   * resulted in elevated privileges.
>>   */
>> -cap_elevated:1,
>> +active_secureexec:1,
>
> Also, I'd like it if this comment could be made more verbose as well, for
> anyone trying to understand the binfmt execution flow for the first time.
> Perhaps:
>
>   /*
>* Must be set True during the any call to
>* bprm_set_creds hook where the execution would
>* reuslt in elevated privileges. (The hook can be
>* called multiple times during nested interpreter
>* resolution across binfmt_script, binfmt_misc, etc).
>*/
Well it is not during but after the call that it becomes true.
I think most recent covers the case of multiple calls.

I think having the loop explicitly in the code a few patches
later makes it clear that there is a loop dealing with interpreters.

Conciseness has a virtue in that it is easy to absorb.  Seeing
active says most recent and secureexec does not is enough to ask
questions and look at the code.

Eric



Re: [PATCH v2 3/8] exec: Convert security_bprm_set_creds into security_bprm_repopulate_creds

2020-05-19 Thread Kees Cook
On Mon, May 18, 2020 at 07:31:14PM -0500, Eric W. Biederman wrote:
> 
> Rename bprm->cap_elevated to bprm->active_secureexec and initialize it
> in prepare_binprm instead of in cap_bprm_set_creds.  Initializing
> bprm->active_secureexec in prepare_binprm allows multiple
> implementations of security_bprm_repopulate_creds to play nicely with
> each other.
> 
> Rename security_bprm_set_creds to security_bprm_reopulate_creds to
> emphasize that this path recomputes part of bprm->cred.  This
> recomputation avoids the time of check vs time of use problems that
> are inherent in unix #! interpreters.
> 
> In short two renames and a move in the location of initializing
> bprm->active_secureexec.

I like this much better than the direct call to the capabilities hook.
Thanks!

Reviewed-by: Kees Cook 

One nit is a bikeshed on the name "active_secureexec", since
the word "active" isn't really associated with any other part of the
binfmt logic. It's supposed to be "latest state from the binfmt loop",
so instead of "active", I considered these words that I also didn't
like: "current", "this", "recent", and "now". Is "latest" better than
"active"? Probably not.

> [...]
> diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h
> index d1217fcdedea..8605ab4a0f89 100644
> --- a/include/linux/binfmts.h
> +++ b/include/linux/binfmts.h
> @@ -27,10 +27,10 @@ struct linux_binprm {
>   unsigned long argmin; /* rlimit marker for copy_strings() */
>   unsigned int
>   /*
> -  * True if most recent call to cap_bprm_set_creds
> +  * True if most recent call to security_bprm_set_creds
>* resulted in elevated privileges.
>*/
> - cap_elevated:1,
> + active_secureexec:1,

Also, I'd like it if this comment could be made more verbose as well, for
anyone trying to understand the binfmt execution flow for the first time.
Perhaps:

/*
 * Must be set True during the any call to
 * bprm_set_creds hook where the execution would
 * reuslt in elevated privileges. (The hook can be
 * called multiple times during nested interpreter
 * resolution across binfmt_script, binfmt_misc, etc).
 */


-- 
Kees Cook


[PATCH v2 3/8] exec: Convert security_bprm_set_creds into security_bprm_repopulate_creds

2020-05-18 Thread Eric W. Biederman


Rename bprm->cap_elevated to bprm->active_secureexec and initialize it
in prepare_binprm instead of in cap_bprm_set_creds.  Initializing
bprm->active_secureexec in prepare_binprm allows multiple
implementations of security_bprm_repopulate_creds to play nicely with
each other.

Rename security_bprm_set_creds to security_bprm_reopulate_creds to
emphasize that this path recomputes part of bprm->cred.  This
recomputation avoids the time of check vs time of use problems that
are inherent in unix #! interpreters.

In short two renames and a move in the location of initializing
bprm->active_secureexec.

Signed-off-by: "Eric W. Biederman" 
---
 fs/exec.c | 8 
 include/linux/binfmts.h   | 4 ++--
 include/linux/lsm_hook_defs.h | 2 +-
 include/linux/lsm_hooks.h | 4 ++--
 include/linux/security.h  | 8 
 security/commoncap.c  | 9 -
 security/security.c   | 4 ++--
 7 files changed, 19 insertions(+), 20 deletions(-)

diff --git a/fs/exec.c b/fs/exec.c
index 9e70da47f8d9..8e3b93d51d31 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1366,7 +1366,7 @@ int begin_new_exec(struct linux_binprm * bprm)
 * the final state of setuid/setgid/fscaps can be merged into the
 * secureexec flag.
 */
-   bprm->secureexec |= bprm->cap_elevated;
+   bprm->secureexec |= bprm->active_secureexec;
 
if (bprm->secureexec) {
/* Make sure parent cannot signal privileged process. */
@@ -1634,10 +1634,10 @@ int prepare_binprm(struct linux_binprm *bprm)
int retval;
loff_t pos = 0;
 
+   /* Recompute parts of bprm->cred based on bprm->file */
+   bprm->active_secureexec = 0;
bprm_fill_uid(bprm);
-
-   /* fill in binprm security blob */
-   retval = security_bprm_set_creds(bprm);
+   retval = security_bprm_repopulate_creds(bprm);
if (retval)
return retval;
 
diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h
index d1217fcdedea..8605ab4a0f89 100644
--- a/include/linux/binfmts.h
+++ b/include/linux/binfmts.h
@@ -27,10 +27,10 @@ struct linux_binprm {
unsigned long argmin; /* rlimit marker for copy_strings() */
unsigned int
/*
-* True if most recent call to cap_bprm_set_creds
+* True if most recent call to security_bprm_set_creds
 * resulted in elevated privileges.
 */
-   cap_elevated:1,
+   active_secureexec:1,
/*
 * Set by bprm_creds_for_exec hook to indicate a
 * privilege-gaining exec has happened. Used to set
diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
index aab0695f41df..1e295ba12c0d 100644
--- a/include/linux/lsm_hook_defs.h
+++ b/include/linux/lsm_hook_defs.h
@@ -50,7 +50,7 @@ LSM_HOOK(int, 0, settime, const struct timespec64 *ts,
 const struct timezone *tz)
 LSM_HOOK(int, 0, vm_enough_memory, struct mm_struct *mm, long pages)
 LSM_HOOK(int, 0, bprm_creds_for_exec, struct linux_binprm *bprm)
-LSM_HOOK(int, 0, bprm_set_creds, struct linux_binprm *bprm)
+LSM_HOOK(int, 0, bprm_repopulate_creds, struct linux_binprm *bprm)
 LSM_HOOK(int, 0, bprm_check_security, struct linux_binprm *bprm)
 LSM_HOOK(void, LSM_RET_VOID, bprm_committing_creds, struct linux_binprm *bprm)
 LSM_HOOK(void, LSM_RET_VOID, bprm_committed_creds, struct linux_binprm *bprm)
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index c719af37df20..d618ecc4d660 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -44,7 +44,7 @@
  * request libc enable secure mode.
  * @bprm contains the linux_binprm structure.
  * Return 0 if the hook is successful and permission is granted.
- * @bprm_set_creds:
+ * @bprm_repopulate_creds:
  * Assuming that the relevant bits of @bprm->cred->security have been
  * previously set, examine @bprm->file and regenerate them.  This is
  * so that the credentials derived from the interpreter the code is
@@ -53,7 +53,7 @@
  * reopen script, and may end up opening something completely different.
  * This hook may also optionally check permissions (e.g. for
  * transitions between security domains).
- * The hook must set @bprm->cap_elevated to 1 if AT_SECURE should be set to
+ * The hook must set @bprm->active_secureexec to 1 if AT_SECURE should be 
set to
  * request libc enable secure mode.
  * @bprm contains the linux_binprm structure.
  * Return 0 if the hook is successful and permission is granted.
diff --git a/include/linux/security.h b/include/linux/security.h
index 1bd7a6582775..d23f078eb589 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -140,7 +140,7 @@ extern int cap_capset(struct cred *new, const struct cred 
*old,
  const kernel_cap_t *effective,
  const kernel_cap_t *inheritable,