summaryrefslogtreecommitdiff
path: root/fs/exec.c
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2020-05-31 15:02:36 -0500
committerEric W. Biederman <ebiederm@xmission.com>2020-05-31 15:02:36 -0500
commit3977e285ee89a94699255dbbf6eeea13889a1083 (patch)
tree378ea4452668d448b0834fd08008a5f81619f1fd /fs/exec.c
parente32f8879019535b899bc3d51f371e17526f208d1 (diff)
parent56305aa9b6fab91a5555a45796b79c1b0a6353d1 (diff)
exec: Remove the recomputation of bprm->cred
Recomputing the uids, gids, capabilities, and related flags each time a new bprm->file is set is error prone and unnecessary. This set of changes splits per_clear temporarily into two separate variables. This is the last change necessary to ensure that everything that is computed from brpm->file in bprm->cred is recomputed every time a new bprm->file is set. Then the code is refactored to compute bprm->cred from bprm->file when the final brpm->file is known, removing the need for recomputation entirely. Doing this in two steps should allow anyone who has problems later to bisect and tell if it was the semantic change or the refactoring that caused them problems. Eric W. Biederman (2): exec: Add a per bprm->file version of per_clear exec: Compute file based creds only once fs/binfmt_misc.c | 2 +- fs/exec.c | 57 ++++++++++++++++++------------------------- include/linux/binfmts.h | 9 ++----- include/linux/lsm_hook_defs.h | 2 +- include/linux/lsm_hooks.h | 22 +++++++++-------- include/linux/security.h | 9 ++++--- security/commoncap.c | 22 +++++++++-------- security/security.c | 4 +-- 8 files changed, 59 insertions(+), 68 deletions(-) Merge branch 'exec-norecompute-v2' into exec-next
Diffstat (limited to 'fs/exec.c')
-rw-r--r--fs/exec.c57
1 files changed, 24 insertions, 33 deletions
diff --git a/fs/exec.c b/fs/exec.c
index c3c879a55d65..e8599236290d 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -72,6 +72,8 @@
#include <trace/events/sched.h>
+static int bprm_creds_from_file(struct linux_binprm *bprm);
+
int suid_dumpable = 0;
static LIST_HEAD(formats);
@@ -1304,6 +1306,11 @@ int begin_new_exec(struct linux_binprm * bprm)
struct task_struct *me = current;
int retval;
+ /* Once we are committed compute the creds */
+ retval = bprm_creds_from_file(bprm);
+ if (retval)
+ return retval;
+
/*
* Ensure all future errors are fatal.
*/
@@ -1364,13 +1371,6 @@ int begin_new_exec(struct linux_binprm * bprm)
*/
do_close_on_exec(me->files);
- /*
- * Once here, prepare_binrpm() will not be called any more, so
- * the final state of setuid/setgid/fscaps can be merged into the
- * secureexec flag.
- */
- bprm->secureexec |= bprm->active_secureexec;
-
if (bprm->secureexec) {
/* Make sure parent cannot signal privileged process. */
me->pdeath_signal = 0;
@@ -1586,29 +1586,21 @@ static void check_unsafe_exec(struct linux_binprm *bprm)
spin_unlock(&p->fs->lock);
}
-static void bprm_fill_uid(struct linux_binprm *bprm)
+static void bprm_fill_uid(struct linux_binprm *bprm, struct file *file)
{
+ /* Handle suid and sgid on files */
struct inode *inode;
unsigned int mode;
kuid_t uid;
kgid_t gid;
- /*
- * Since this can be called multiple times (via prepare_binprm),
- * we must clear any previous work done when setting set[ug]id
- * bits from any earlier bprm->file uses (for example when run
- * first for a setuid script then again for its interpreter).
- */
- bprm->cred->euid = current_euid();
- bprm->cred->egid = current_egid();
-
- if (!mnt_may_suid(bprm->file->f_path.mnt))
+ if (!mnt_may_suid(file->f_path.mnt))
return;
if (task_no_new_privs(current))
return;
- inode = bprm->file->f_path.dentry->d_inode;
+ inode = file->f_path.dentry->d_inode;
mode = READ_ONCE(inode->i_mode);
if (!(mode & (S_ISUID|S_ISGID)))
return;
@@ -1639,8 +1631,20 @@ static void bprm_fill_uid(struct linux_binprm *bprm)
}
/*
+ * Compute brpm->cred based upon the final binary.
+ */
+static int bprm_creds_from_file(struct linux_binprm *bprm)
+{
+ /* Compute creds based on which file? */
+ struct file *file = bprm->execfd_creds ? bprm->executable : bprm->file;
+
+ bprm_fill_uid(bprm, file);
+ return security_bprm_creds_from_file(bprm, file);
+}
+
+/*
* Fill the binprm structure from the inode.
- * Check permissions, then read the first BINPRM_BUF_SIZE bytes
+ * Read the first BINPRM_BUF_SIZE bytes
*
* This may be called multiple times for binary chains (scripts for example).
*/
@@ -1648,19 +1652,6 @@ static int prepare_binprm(struct linux_binprm *bprm)
{
loff_t pos = 0;
- /* 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);
}