exec: Allow load_misc_binary to call prepare_binprm unconditionally
authorEric W. Biederman <ebiederm@xmission.com>
Sat, 16 May 2020 11:02:54 +0000 (06:02 -0500)
committerEric W. Biederman <ebiederm@xmission.com>
Thu, 21 May 2020 15:16:57 +0000 (10:16 -0500)
Add a flag preserve_creds that binfmt_misc can set to prevent
credentials from being updated.  This allows binfmt_misc to always
call prepare_binprm.  Allowing the credential computation logic to be
consolidated.

Not replacing the credentials with the interpreters credentials is
safe because because an open file descriptor to the executable is
passed to the interpreter.   As the interpreter does not need to
reopen the executable it is guaranteed to see the same file that
exec sees.

Ref: c407c033de84 ("[PATCH] binfmt_misc: improve calculation of interpreter's credentials")
Link: https://lkml.kernel.org/r/87imgszrwo.fsf_-_@x220.int.ebiederm.org
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Reviewed-by: Kees Cook <keescook@chromium.org>
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
fs/binfmt_misc.c
fs/exec.c
include/linux/binfmts.h

index cdb45829354d9f6db769ac0d83db44fed57c919e..264829745d6fcf6970eb4b5e3b4cfa05f5f5a070 100644 (file)
@@ -218,19 +218,10 @@ static int load_misc_binary(struct linux_binprm *bprm)
                goto error;
 
        bprm->file = interp_file;
-       if (fmt->flags & MISC_FMT_CREDENTIALS) {
-               loff_t pos = 0;
-
-               /*
-                * No need to call prepare_binprm(), it's already been
-                * done.  bprm->buf is stale, update from interp_file.
-                */
-               memset(bprm->buf, 0, BINPRM_BUF_SIZE);
-               retval = kernel_read(bprm->file, bprm->buf, BINPRM_BUF_SIZE,
-                               &pos);
-       } else
-               retval = prepare_binprm(bprm);
+       if (fmt->flags & MISC_FMT_CREDENTIALS)
+               bprm->preserve_creds = 1;
 
+       retval = prepare_binprm(bprm);
        if (retval < 0)
                goto error;
 
index 8e3b93d51d31e1e812b2acc7e984305d75ce236d..028e0e323af5347a431da6cd14b365e65d1bdbed 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1631,15 +1631,20 @@ static void bprm_fill_uid(struct linux_binprm *bprm)
  */
 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);
-       retval = security_bprm_repopulate_creds(bprm);
-       if (retval)
-               return retval;
+       /* Can the interpreter get to the executable without races? */
+       if (!bprm->preserve_creds) {
+               int retval;
+
+               /* Recompute parts of bprm->cred based on bprm->file */
+               bprm->active_secureexec = 0;
+               bprm_fill_uid(bprm);
+               retval = security_bprm_repopulate_creds(bprm);
+               if (retval)
+                       return retval;
+       }
+       bprm->preserve_creds = 0;
 
        memset(bprm->buf, 0, BINPRM_BUF_SIZE);
        return kernel_read(bprm->file, bprm->buf, BINPRM_BUF_SIZE, &pos);
index 8605ab4a0f890e230c87946692b54c8662a72bb6..dbb5614d62a25ce7254b700c5469021b5faaef45 100644 (file)
@@ -26,6 +26,8 @@ struct linux_binprm {
        unsigned long p; /* current top of mem */
        unsigned long argmin; /* rlimit marker for copy_strings() */
        unsigned int
+               /* It is safe to use the creds of a script (see binfmt_misc) */
+               preserve_creds:1,
                /*
                 * True if most recent call to security_bprm_set_creds
                 * resulted in elevated privileges.