|
@@ -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);
|