Commit b8bff599 authored by Eric W. Biederman's avatar Eric W. Biederman
Browse files

exec: Factor security_bprm_creds_for_exec out of security_bprm_set_creds

Today security_bprm_set_creds has several implementations:
apparmor_bprm_set_creds, cap_bprm_set_creds, selinux_bprm_set_creds,
smack_bprm_set_creds, and tomoyo_bprm_set_creds.

Except for cap_bprm_set_creds they all test bprm->called_set_creds and
return immediately if it is true.  The function cap_bprm_set_creds
ignores bprm->calld_sed_creds entirely.

Create a new LSM hook security_bprm_creds_for_exec that is called just
before prepare_binprm in __do_execve_file, resulting in a LSM hook
that is called exactly once for the entire of exec.  Modify the bits
of security_bprm_set_creds that only want to be called once per exec
into security_bprm_creds_for_exec, leaving only cap_bprm_set_creds
behind.

Remove bprm->called_set_creds all of it's former users have been moved
to security_bprm_creds_for_exec.

Add or upate comments a appropriate to bring them up to date and
to reflect this change.

Link: https://lkml.kernel.org/r/87v9kszrzh.fsf_-_@x220.int.ebiederm.org


Acked-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
Acked-by: Casey Schaufler <casey@schaufler-ca.com> # For the LSM and Smack bits
Reviewed-by: default avatarKees Cook <keescook@chromium.org>
Signed-off-by: default avatar"Eric W. Biederman" <ebiederm@xmission.com>
parent 87b047d2
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
@@ -1640,7 +1640,6 @@ int prepare_binprm(struct linux_binprm *bprm)
	retval = security_bprm_set_creds(bprm);
	if (retval)
		return retval;
	bprm->called_set_creds = 1;

	memset(bprm->buf, 0, BINPRM_BUF_SIZE);
	return kernel_read(bprm->file, bprm->buf, BINPRM_BUF_SIZE, &pos);
@@ -1855,6 +1854,11 @@ static int __do_execve_file(int fd, struct filename *filename,
	if (retval < 0)
		goto out;

	/* Set the unchanging part of bprm->cred */
	retval = security_bprm_creds_for_exec(bprm);
	if (retval)
		goto out;

	retval = prepare_binprm(bprm);
	if (retval < 0)
		goto out;
+5 −13
Original line number Diff line number Diff line
@@ -27,22 +27,14 @@ struct linux_binprm {
	unsigned long argmin; /* rlimit marker for copy_strings() */
	unsigned int
		/*
		 * True after the bprm_set_creds hook has been called once
		 * (multiple calls can be made via prepare_binprm() for
		 * binfmt_script/misc).
		 */
		called_set_creds:1,
		/*
		 * True if most recent call to the commoncaps bprm_set_creds
		 * hook (due to multiple prepare_binprm() calls from the
		 * binfmt_script/misc handlers) resulted in elevated
		 * privileges.
		 * True if most recent call to cap_bprm_set_creds
		 * resulted in elevated privileges.
		 */
		cap_elevated:1,
		/*
		 * Set by bprm_set_creds hook to indicate a privilege-gaining
		 * exec has happened. Used to sanitize execution environment
		 * and to set AT_SECURE auxv for glibc.
		 * Set by bprm_creds_for_exec hook to indicate a
		 * privilege-gaining exec has happened. Used to set
		 * AT_SECURE auxv for glibc.
		 */
		secureexec:1,
		/*
+1 −0
Original line number Diff line number Diff line
@@ -49,6 +49,7 @@ LSM_HOOK(int, 0, syslog, int type)
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_check_security, struct linux_binprm *bprm)
LSM_HOOK(void, LSM_RET_VOID, bprm_committing_creds, struct linux_binprm *bprm)
+28 −22
Original line number Diff line number Diff line
@@ -34,40 +34,46 @@
 *
 * Security hooks for program execution operations.
 *
 * @bprm_creds_for_exec:
 *	If the setup in prepare_exec_creds did not setup @bprm->cred->security
 *	properly for executing @bprm->file, update the LSM's portion of
 *	@bprm->cred->security to be what commit_creds needs to install for the
 *	new program.  This hook may also optionally check permissions
 *	(e.g. for transitions between security domains).
 *	The hook must set @bprm->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.
 * @bprm_set_creds:
 *	Save security information in the bprm->security field, typically based
 *	on information about the bprm->file, for later use by the apply_creds
 *	hook.  This hook may also optionally check permissions (e.g. for
 *	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).
 *	This hook may be called multiple times during a single execve, e.g. for
 *	interpreters.  The hook can tell whether it has already been called by
 *	checking to see if @bprm->security is non-NULL.  If so, then the hook
 *	may decide either to retain the security information saved earlier or
 *	to replace it.  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.
 *	The hook must set @bprm->cap_elevated 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.
 * @bprm_check_security:
 *	This hook mediates the point when a search for a binary handler will
 *	begin.  It allows a check the @bprm->security value which is set in the
 *	preceding set_creds call.  The primary difference from set_creds is
 *	that the argv list and envp list are reliably available in @bprm.  This
 *	hook may be called multiple times during a single execve; and in each
 *	pass set_creds is called first.
 *	begin.  It allows a check against the @bprm->cred->security value
 *	which was set in the preceding creds_for_exec call.  The argv list and
 *	envp list are reliably available in @bprm.  This hook may be called
 *	multiple times during a single execve.
 *	@bprm contains the linux_binprm structure.
 *	Return 0 if the hook is successful and permission is granted.
 * @bprm_committing_creds:
 *	Prepare to install the new security attributes of a process being
 *	transformed by an execve operation, based on the old credentials
 *	pointed to by @current->cred and the information set in @bprm->cred by
 *	the bprm_set_creds hook.  @bprm points to the linux_binprm structure.
 *	This hook is a good place to perform state changes on the process such
 *	as closing open file descriptors to which access will no longer be
 *	granted when the attributes are changed.  This is called immediately
 *	before commit_creds().
 *	the bprm_creds_for_exec hook.  @bprm points to the linux_binprm
 *	structure.  This hook is a good place to perform state changes on the
 *	process such as closing open file descriptors to which access will no
 *	longer be granted when the attributes are changed.  This is called
 *	immediately before commit_creds().
 * @bprm_committed_creds:
 *	Tidy up after the installation of the new security attributes of a
 *	process being transformed by an execve operation.  The new credentials
+6 −0
Original line number Diff line number Diff line
@@ -276,6 +276,7 @@ int security_quota_on(struct dentry *dentry);
int security_syslog(int type);
int security_settime64(const struct timespec64 *ts, const struct timezone *tz);
int security_vm_enough_memory_mm(struct mm_struct *mm, long pages);
int security_bprm_creds_for_exec(struct linux_binprm *bprm);
int security_bprm_set_creds(struct linux_binprm *bprm);
int security_bprm_check(struct linux_binprm *bprm);
void security_bprm_committing_creds(struct linux_binprm *bprm);
@@ -569,6 +570,11 @@ static inline int security_vm_enough_memory_mm(struct mm_struct *mm, long pages)
	return __vm_enough_memory(mm, pages, cap_vm_enough_memory(mm, pages));
}

static inline int security_bprm_creds_for_exec(struct linux_binprm *bprm)
{
	return 0;
}

static inline int security_bprm_set_creds(struct linux_binprm *bprm)
{
	return cap_bprm_set_creds(bprm);
Loading