summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--security/selinux/hooks.c59
1 files changed, 47 insertions, 12 deletions
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index b0e940497e23..6c90d491fab4 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2097,6 +2097,41 @@ static int selinux_vm_enough_memory(struct mm_struct *mm, long pages)
/* binprm security operations */
+static int check_nnp_nosuid(const struct linux_binprm *bprm,
+ const struct task_security_struct *old_tsec,
+ const struct task_security_struct *new_tsec)
+{
+ int nnp = (bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS);
+ int nosuid = (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID);
+ int rc;
+
+ if (!nnp && !nosuid)
+ return 0; /* neither NNP nor nosuid */
+
+ if (new_tsec->sid == old_tsec->sid)
+ return 0; /* No change in credentials */
+
+ /*
+ * The only transitions we permit under NNP or nosuid
+ * are transitions to bounded SIDs, i.e. SIDs that are
+ * guaranteed to only be allowed a subset of the permissions
+ * of the current SID.
+ */
+ rc = security_bounded_transition(old_tsec->sid, new_tsec->sid);
+ if (rc) {
+ /*
+ * On failure, preserve the errno values for NNP vs nosuid.
+ * NNP: Operation not permitted for caller.
+ * nosuid: Permission denied to file.
+ */
+ if (nnp)
+ return -EPERM;
+ else
+ return -EACCES;
+ }
+ return 0;
+}
+
static int selinux_bprm_set_creds(struct linux_binprm *bprm)
{
const struct task_security_struct *old_tsec;
@@ -2133,14 +2168,10 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm)
/* Reset exec SID on execve. */
new_tsec->exec_sid = 0;
- /*
- * Minimize confusion: if no_new_privs or nosuid and a
- * transition is explicitly requested, then fail the exec.
- */
- if (bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS)
- return -EPERM;
- if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)
- return -EACCES;
+ /* Fail on NNP or nosuid if not an allowed transition. */
+ rc = check_nnp_nosuid(bprm, old_tsec, new_tsec);
+ if (rc)
+ return rc;
} else {
/* Check for a default transition on this program. */
rc = security_transition_sid(old_tsec->sid, isec->sid,
@@ -2148,15 +2179,19 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm)
&new_tsec->sid);
if (rc)
return rc;
+
+ /*
+ * Fallback to old SID on NNP or nosuid if not an allowed
+ * transition.
+ */
+ rc = check_nnp_nosuid(bprm, old_tsec, new_tsec);
+ if (rc)
+ new_tsec->sid = old_tsec->sid;
}
ad.type = LSM_AUDIT_DATA_PATH;
ad.u.path = bprm->file->f_path;
- if ((bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) ||
- (bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS))
- new_tsec->sid = old_tsec->sid;
-
if (new_tsec->sid == old_tsec->sid) {
rc = avc_has_perm(old_tsec->sid, isec->sid,
SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, &ad);