selinux: Permit bounded transitions under NO_NEW_PRIVS or NOSUID.
If the callee SID is bounded by the caller SID, then allowing the transition to occur poses no risk of privilege escalation and we can therefore safely allow the transition to occur. Add this exemption for both the case where a transition was explicitly requested by the application and the case where an automatic transition is defined in policy. Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov> Reviewed-by: Andy Lutomirski <luto@amacapital.net> Signed-off-by: Paul Moore <pmoore@redhat.com>
This commit is contained in:
Родитель
aa9e0de81b
Коммит
7b0d0b40cd
|
@ -2097,6 +2097,41 @@ static int selinux_vm_enough_memory(struct mm_struct *mm, long pages)
|
||||||
|
|
||||||
/* binprm security operations */
|
/* 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)
|
static int selinux_bprm_set_creds(struct linux_binprm *bprm)
|
||||||
{
|
{
|
||||||
const struct task_security_struct *old_tsec;
|
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. */
|
/* Reset exec SID on execve. */
|
||||||
new_tsec->exec_sid = 0;
|
new_tsec->exec_sid = 0;
|
||||||
|
|
||||||
/*
|
/* Fail on NNP or nosuid if not an allowed transition. */
|
||||||
* Minimize confusion: if no_new_privs or nosuid and a
|
rc = check_nnp_nosuid(bprm, old_tsec, new_tsec);
|
||||||
* transition is explicitly requested, then fail the exec.
|
if (rc)
|
||||||
*/
|
return rc;
|
||||||
if (bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS)
|
|
||||||
return -EPERM;
|
|
||||||
if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)
|
|
||||||
return -EACCES;
|
|
||||||
} else {
|
} else {
|
||||||
/* Check for a default transition on this program. */
|
/* Check for a default transition on this program. */
|
||||||
rc = security_transition_sid(old_tsec->sid, isec->sid,
|
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);
|
&new_tsec->sid);
|
||||||
if (rc)
|
if (rc)
|
||||||
return 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.type = LSM_AUDIT_DATA_PATH;
|
||||||
ad.u.path = bprm->file->f_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) {
|
if (new_tsec->sid == old_tsec->sid) {
|
||||||
rc = avc_has_perm(old_tsec->sid, isec->sid,
|
rc = avc_has_perm(old_tsec->sid, isec->sid,
|
||||||
SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, &ad);
|
SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, &ad);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче