@@ -2273,6 +2273,11 @@ static int check_nnp_nosuid(const struct linux_binprm *bprm,
av |= PROCESS2__NNP_TRANSITION;
if (nosuid)
av |= PROCESS2__NOSUID_TRANSITION;
+ /*
+ * Only check against the current SELinux namespace
+ * because only the SID in the current namespace
+ * is changed by a transition.
+ */
rc = avc_has_perm(current_selinux_state,
old_tsec->sid, new_tsec->sid,
SECCLASS_PROCESS2, av, NULL);
@@ -2302,6 +2307,7 @@ static int check_nnp_nosuid(const struct linux_binprm *bprm,
static int selinux_bprm_creds_for_exec(struct linux_binprm *bprm)
{
+ const struct cred *cred = current_cred();
const struct task_security_struct *old_tsec;
struct task_security_struct *new_tsec;
struct inode_security_struct *isec;
@@ -2312,7 +2318,7 @@ static int selinux_bprm_creds_for_exec(struct linux_binprm *bprm)
/* SELinux context only depends on initial program or script and not
* the script interpreter */
- old_tsec = selinux_cred(current_cred());
+ old_tsec = selinux_cred(cred);
new_tsec = selinux_cred(bprm->cred);
isec = inode_security(inode);
@@ -2368,12 +2374,23 @@ static int selinux_bprm_creds_for_exec(struct linux_binprm *bprm)
ad.u.file = bprm->file;
if (new_tsec->sid == old_tsec->sid) {
+ /*
+ * Only check against the current SELinux namespace
+ * because only the SID in the current namespace
+ * is changed by a transition.
+ */
rc = avc_has_perm(current_selinux_state,
old_tsec->sid, isec->sid,
SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, &ad);
if (rc)
return rc;
} else {
+ /*
+ * Only check against the current SELinux namespace
+ * because only the SID in the current namespace
+ * is changed by a transition.
+ */
+
/* Check permissions for the transition. */
rc = avc_has_perm(current_selinux_state,
old_tsec->sid, new_tsec->sid,
@@ -2424,6 +2441,19 @@ static int selinux_bprm_creds_for_exec(struct linux_binprm *bprm)
bprm->secureexec |= !!rc;
}
+ /*
+ * If in a non-init namespace, also check the ability of the
+ * ancestors to execute without transitioning since the SID
+ * in ancestor namespaces is NOT modified.
+ */
+ cred = old_tsec->parent_cred;
+ if (cred) {
+ rc = cred_has_perm(cred, isec->sid,
+ SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, &ad);
+ if (rc)
+ return rc;
+ }
+
return 0;
}
@@ -2510,6 +2540,9 @@ static void selinux_bprm_committing_creds(const struct linux_binprm *bprm)
* higher than the default soft limit for cases where the default is
* lower than the hard limit, e.g. RLIMIT_CORE or RLIMIT_STACK.
*/
+ /* Only check against the current namespace because the SID
+ * does not change in the parent.
+ */
rc = avc_has_perm(current_selinux_state,
new_tsec->osid, new_tsec->sid, SECCLASS_PROCESS,
PROCESS__RLIMITINH, NULL);
@@ -2550,6 +2583,9 @@ static void selinux_bprm_committed_creds(const struct linux_binprm *bprm)
* This must occur _after_ the task SID has been updated so that any
* kill done after the flush will be checked against the new SID.
*/
+ /* Only check against the current namespace because the SID
+ * does not change in the parent.
+ */
rc = avc_has_perm(current_selinux_state,
osid, sid, SECCLASS_PROCESS, PROCESS__SIGINH, NULL);
if (rc) {
Update the bprm hook functions for SELinux namespaces. Unlike most of the hook functions, this does not require converting all of the permission checks to use the new helpers that check permissions against the current and all ancestor namespaces. Instead, we only need to check the transition-related permissions against the current namespace since only the SID in that current namespace is changed by a transition. However, we do want to check execute_no_trans against the ancestor namespaces since they are not transitioning; hence, a check is added to the end of selinux_bprm_creds_for_exec() for that purpose. Otherwise, we just document the fact that we are intentionally only checking against the current SELinux namespace for the other checks. Signed-off-by: Stephen Smalley <stephen.smalley.work@gmail.com> --- security/selinux/hooks.c | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-)