summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2020-05-16 06:02:54 -0500
committerEric W. Biederman <ebiederm@xmission.com>2020-05-21 10:16:57 -0500
commita16b3357b2b8e910bb614254d8a7e84d2bd59b4c (patch)
treed0a003e8cc8555bb5c87f38bc0a64addd21dd176
parent112b7147592e8f46bd1da4f961773e6d974f38a8 (diff)
downloadlinux-a16b3357b2b8e910bb614254d8a7e84d2bd59b4c.tar.gz
linux-a16b3357b2b8e910bb614254d8a7e84d2bd59b4c.tar.bz2
linux-a16b3357b2b8e910bb614254d8a7e84d2bd59b4c.zip
exec: Allow load_misc_binary to call prepare_binprm unconditionally
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>
-rw-r--r--fs/binfmt_misc.c15
-rw-r--r--fs/exec.c19
-rw-r--r--include/linux/binfmts.h2
3 files changed, 17 insertions, 19 deletions
diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c
index cdb45829354d..264829745d6f 100644
--- a/fs/binfmt_misc.c
+++ b/fs/binfmt_misc.c
@@ -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;
diff --git a/fs/exec.c b/fs/exec.c
index 8e3b93d51d31..028e0e323af5 100644
--- 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);
diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h
index 8605ab4a0f89..dbb5614d62a2 100644
--- a/include/linux/binfmts.h
+++ b/include/linux/binfmts.h
@@ -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.