Changeset View
Changeset View
Standalone View
Standalone View
sys/kern/kern_prot.c
Show First 20 Lines • Show All 77 Lines • ▼ Show 20 Lines | |||||
FEATURE(regression, | FEATURE(regression, | ||||
"Kernel support for interfaces necessary for regression testing (SECURITY RISK!)"); | "Kernel support for interfaces necessary for regression testing (SECURITY RISK!)"); | ||||
#endif | #endif | ||||
#include <security/audit/audit.h> | #include <security/audit/audit.h> | ||||
#include <security/mac/mac_framework.h> | #include <security/mac/mac_framework.h> | ||||
static MALLOC_DEFINE(M_CRED, "cred", "credentials"); | static MALLOC_DEFINE(M_CRED, "cred", "credentials"); | ||||
static MALLOC_DEFINE(M_CREDWRAP, "credwrap", "credentials wrapper"); | |||||
SYSCTL_NODE(_security, OID_AUTO, bsd, CTLFLAG_RW, 0, "BSD security policy"); | SYSCTL_NODE(_security, OID_AUTO, bsd, CTLFLAG_RW, 0, "BSD security policy"); | ||||
static void crsetgroups_locked(struct ucred *cr, int ngrp, | static void crsetgroups_locked(struct ucred *cr, int ngrp, | ||||
gid_t *groups); | gid_t *groups); | ||||
#ifndef _SYS_SYSPROTO_H_ | #ifndef _SYS_SYSPROTO_H_ | ||||
struct getpid_args { | struct getpid_args { | ||||
▲ Show 20 Lines • Show All 384 Lines • ▼ Show 20 Lines | |||||
}; | }; | ||||
#endif | #endif | ||||
/* ARGSUSED */ | /* ARGSUSED */ | ||||
int | int | ||||
sys_setuid(struct thread *td, struct setuid_args *uap) | sys_setuid(struct thread *td, struct setuid_args *uap) | ||||
{ | { | ||||
struct proc *p = td->td_proc; | struct proc *p = td->td_proc; | ||||
struct ucred *newcred, *oldcred; | struct ucred *newcred, *oldcred; | ||||
struct credwrap *newcredwrap, *oldcredwrap; | |||||
uid_t uid; | uid_t uid; | ||||
struct uidinfo *uip; | struct uidinfo *uip; | ||||
int error; | int error; | ||||
uid = uap->uid; | uid = uap->uid; | ||||
AUDIT_ARG_UID(uid); | AUDIT_ARG_UID(uid); | ||||
newcred = crget(); | newcred = crget(); | ||||
newcredwrap = crwget(newcred); | |||||
uip = uifind(uid); | uip = uifind(uid); | ||||
PROC_LOCK(p); | PROC_LOCK(p); | ||||
/* | /* | ||||
* Copy credentials so other references do not see our changes. | * Copy credentials so other references do not see our changes. | ||||
*/ | */ | ||||
oldcred = crcopysafe(p, newcred); | oldcred = crcopysafe(p, newcred); | ||||
oldcredwrap = p->p_credwrap; | |||||
#ifdef MAC | #ifdef MAC | ||||
error = mac_cred_check_setuid(oldcred, uid); | error = mac_cred_check_setuid(oldcred, uid); | ||||
if (error) | if (error) | ||||
goto fail; | goto fail; | ||||
#endif | #endif | ||||
/* | /* | ||||
▲ Show 20 Lines • Show All 58 Lines • ▼ Show 20 Lines | #endif | ||||
/* | /* | ||||
* In all permitted cases, we are changing the euid. | * In all permitted cases, we are changing the euid. | ||||
*/ | */ | ||||
if (uid != oldcred->cr_uid) { | if (uid != oldcred->cr_uid) { | ||||
change_euid(newcred, uip); | change_euid(newcred, uip); | ||||
setsugid(p); | setsugid(p); | ||||
} | } | ||||
proc_set_cred(p, newcred); | proc_set_cred(p, newcred, newcredwrap); | ||||
#ifdef RACCT | #ifdef RACCT | ||||
racct_proc_ucred_changed(p, oldcred, newcred); | racct_proc_ucred_changed(p, oldcred, newcred); | ||||
crhold(newcred); | crhold(newcred); | ||||
#endif | #endif | ||||
PROC_UNLOCK(p); | PROC_UNLOCK(p); | ||||
#ifdef RCTL | #ifdef RCTL | ||||
rctl_proc_ucred_changed(p, newcred); | rctl_proc_ucred_changed(p, newcred); | ||||
crfree(newcred); | crfree(newcred); | ||||
#endif | #endif | ||||
uifree(uip); | uifree(uip); | ||||
crfree(oldcred); | crfree(oldcred); | ||||
crwfree(oldcredwrap); | |||||
return (0); | return (0); | ||||
fail: | fail: | ||||
PROC_UNLOCK(p); | PROC_UNLOCK(p); | ||||
uifree(uip); | uifree(uip); | ||||
crfree(newcred); | crfree(newcred); | ||||
crwfree(newcredwrap); | |||||
return (error); | return (error); | ||||
} | } | ||||
#ifndef _SYS_SYSPROTO_H_ | #ifndef _SYS_SYSPROTO_H_ | ||||
struct seteuid_args { | struct seteuid_args { | ||||
uid_t euid; | uid_t euid; | ||||
}; | }; | ||||
#endif | #endif | ||||
/* ARGSUSED */ | /* ARGSUSED */ | ||||
int | int | ||||
sys_seteuid(struct thread *td, struct seteuid_args *uap) | sys_seteuid(struct thread *td, struct seteuid_args *uap) | ||||
{ | { | ||||
struct proc *p = td->td_proc; | struct proc *p = td->td_proc; | ||||
struct ucred *newcred, *oldcred; | struct ucred *newcred, *oldcred; | ||||
struct credwrap *newcredwrap, *oldcredwrap; | |||||
uid_t euid; | uid_t euid; | ||||
struct uidinfo *euip; | struct uidinfo *euip; | ||||
int error; | int error; | ||||
euid = uap->euid; | euid = uap->euid; | ||||
AUDIT_ARG_EUID(euid); | AUDIT_ARG_EUID(euid); | ||||
newcred = crget(); | newcred = crget(); | ||||
newcredwrap = crwget(newcred); | |||||
euip = uifind(euid); | euip = uifind(euid); | ||||
PROC_LOCK(p); | PROC_LOCK(p); | ||||
/* | /* | ||||
* Copy credentials so other references do not see our changes. | * Copy credentials so other references do not see our changes. | ||||
*/ | */ | ||||
oldcred = crcopysafe(p, newcred); | oldcred = crcopysafe(p, newcred); | ||||
oldcredwrap = p->p_credwrap; | |||||
#ifdef MAC | #ifdef MAC | ||||
error = mac_cred_check_seteuid(oldcred, euid); | error = mac_cred_check_seteuid(oldcred, euid); | ||||
if (error) | if (error) | ||||
goto fail; | goto fail; | ||||
#endif | #endif | ||||
if (euid != oldcred->cr_ruid && /* allow seteuid(getuid()) */ | if (euid != oldcred->cr_ruid && /* allow seteuid(getuid()) */ | ||||
euid != oldcred->cr_svuid && /* allow seteuid(saved uid) */ | euid != oldcred->cr_svuid && /* allow seteuid(saved uid) */ | ||||
(error = priv_check_cred(oldcred, PRIV_CRED_SETEUID)) != 0) | (error = priv_check_cred(oldcred, PRIV_CRED_SETEUID)) != 0) | ||||
goto fail; | goto fail; | ||||
/* | /* | ||||
* Everything's okay, do it. | * Everything's okay, do it. | ||||
*/ | */ | ||||
if (oldcred->cr_uid != euid) { | if (oldcred->cr_uid != euid) { | ||||
change_euid(newcred, euip); | change_euid(newcred, euip); | ||||
setsugid(p); | setsugid(p); | ||||
} | } | ||||
proc_set_cred(p, newcred); | proc_set_cred(p, newcred, newcredwrap); | ||||
PROC_UNLOCK(p); | PROC_UNLOCK(p); | ||||
uifree(euip); | uifree(euip); | ||||
crfree(oldcred); | crfree(oldcred); | ||||
crwfree(oldcredwrap); | |||||
return (0); | return (0); | ||||
fail: | fail: | ||||
PROC_UNLOCK(p); | PROC_UNLOCK(p); | ||||
uifree(euip); | uifree(euip); | ||||
crfree(newcred); | crfree(newcred); | ||||
crwfree(newcredwrap); | |||||
return (error); | return (error); | ||||
} | } | ||||
#ifndef _SYS_SYSPROTO_H_ | #ifndef _SYS_SYSPROTO_H_ | ||||
struct setgid_args { | struct setgid_args { | ||||
gid_t gid; | gid_t gid; | ||||
}; | }; | ||||
#endif | #endif | ||||
/* ARGSUSED */ | /* ARGSUSED */ | ||||
int | int | ||||
sys_setgid(struct thread *td, struct setgid_args *uap) | sys_setgid(struct thread *td, struct setgid_args *uap) | ||||
{ | { | ||||
struct proc *p = td->td_proc; | struct proc *p = td->td_proc; | ||||
struct ucred *newcred, *oldcred; | struct ucred *newcred, *oldcred; | ||||
struct credwrap *newcredwrap, *oldcredwrap; | |||||
gid_t gid; | gid_t gid; | ||||
int error; | int error; | ||||
gid = uap->gid; | gid = uap->gid; | ||||
AUDIT_ARG_GID(gid); | AUDIT_ARG_GID(gid); | ||||
newcred = crget(); | newcred = crget(); | ||||
newcredwrap = crwget(newcred); | |||||
PROC_LOCK(p); | PROC_LOCK(p); | ||||
oldcred = crcopysafe(p, newcred); | oldcred = crcopysafe(p, newcred); | ||||
oldcredwrap = p->p_credwrap; | |||||
#ifdef MAC | #ifdef MAC | ||||
error = mac_cred_check_setgid(oldcred, gid); | error = mac_cred_check_setgid(oldcred, gid); | ||||
if (error) | if (error) | ||||
goto fail; | goto fail; | ||||
#endif | #endif | ||||
/* | /* | ||||
▲ Show 20 Lines • Show All 52 Lines • ▼ Show 20 Lines | #endif | ||||
/* | /* | ||||
* In all cases permitted cases, we are changing the egid. | * In all cases permitted cases, we are changing the egid. | ||||
* Copy credentials so other references do not see our changes. | * Copy credentials so other references do not see our changes. | ||||
*/ | */ | ||||
if (oldcred->cr_groups[0] != gid) { | if (oldcred->cr_groups[0] != gid) { | ||||
change_egid(newcred, gid); | change_egid(newcred, gid); | ||||
setsugid(p); | setsugid(p); | ||||
} | } | ||||
proc_set_cred(p, newcred); | proc_set_cred(p, newcred, newcredwrap); | ||||
PROC_UNLOCK(p); | PROC_UNLOCK(p); | ||||
crfree(oldcred); | crfree(oldcred); | ||||
crwfree(oldcredwrap); | |||||
return (0); | return (0); | ||||
fail: | fail: | ||||
PROC_UNLOCK(p); | PROC_UNLOCK(p); | ||||
crfree(newcred); | crfree(newcred); | ||||
crwfree(newcredwrap); | |||||
return (error); | return (error); | ||||
} | } | ||||
#ifndef _SYS_SYSPROTO_H_ | #ifndef _SYS_SYSPROTO_H_ | ||||
struct setegid_args { | struct setegid_args { | ||||
gid_t egid; | gid_t egid; | ||||
}; | }; | ||||
#endif | #endif | ||||
/* ARGSUSED */ | /* ARGSUSED */ | ||||
int | int | ||||
sys_setegid(struct thread *td, struct setegid_args *uap) | sys_setegid(struct thread *td, struct setegid_args *uap) | ||||
{ | { | ||||
struct proc *p = td->td_proc; | struct proc *p = td->td_proc; | ||||
struct ucred *newcred, *oldcred; | struct ucred *newcred, *oldcred; | ||||
struct credwrap *newcredwrap, *oldcredwrap; | |||||
gid_t egid; | gid_t egid; | ||||
int error; | int error; | ||||
egid = uap->egid; | egid = uap->egid; | ||||
AUDIT_ARG_EGID(egid); | AUDIT_ARG_EGID(egid); | ||||
newcred = crget(); | newcred = crget(); | ||||
newcredwrap = crwget(newcred); | |||||
PROC_LOCK(p); | PROC_LOCK(p); | ||||
oldcred = crcopysafe(p, newcred); | oldcred = crcopysafe(p, newcred); | ||||
oldcredwrap = p->p_credwrap; | |||||
#ifdef MAC | #ifdef MAC | ||||
error = mac_cred_check_setegid(oldcred, egid); | error = mac_cred_check_setegid(oldcred, egid); | ||||
if (error) | if (error) | ||||
goto fail; | goto fail; | ||||
#endif | #endif | ||||
if (egid != oldcred->cr_rgid && /* allow setegid(getgid()) */ | if (egid != oldcred->cr_rgid && /* allow setegid(getgid()) */ | ||||
egid != oldcred->cr_svgid && /* allow setegid(saved gid) */ | egid != oldcred->cr_svgid && /* allow setegid(saved gid) */ | ||||
(error = priv_check_cred(oldcred, PRIV_CRED_SETEGID)) != 0) | (error = priv_check_cred(oldcred, PRIV_CRED_SETEGID)) != 0) | ||||
goto fail; | goto fail; | ||||
if (oldcred->cr_groups[0] != egid) { | if (oldcred->cr_groups[0] != egid) { | ||||
change_egid(newcred, egid); | change_egid(newcred, egid); | ||||
setsugid(p); | setsugid(p); | ||||
} | } | ||||
proc_set_cred(p, newcred); | proc_set_cred(p, newcred, newcredwrap); | ||||
PROC_UNLOCK(p); | PROC_UNLOCK(p); | ||||
crfree(oldcred); | crfree(oldcred); | ||||
crwfree(oldcredwrap); | |||||
return (0); | return (0); | ||||
fail: | fail: | ||||
PROC_UNLOCK(p); | PROC_UNLOCK(p); | ||||
crfree(newcred); | crfree(newcred); | ||||
crwfree(newcredwrap); | |||||
return (error); | return (error); | ||||
} | } | ||||
#ifndef _SYS_SYSPROTO_H_ | #ifndef _SYS_SYSPROTO_H_ | ||||
struct setgroups_args { | struct setgroups_args { | ||||
u_int gidsetsize; | u_int gidsetsize; | ||||
gid_t *gidset; | gid_t *gidset; | ||||
}; | }; | ||||
Show All 25 Lines | sys_setgroups(struct thread *td, struct setgroups_args *uap) | ||||
return (error); | return (error); | ||||
} | } | ||||
int | int | ||||
kern_setgroups(struct thread *td, u_int ngrp, gid_t *groups) | kern_setgroups(struct thread *td, u_int ngrp, gid_t *groups) | ||||
{ | { | ||||
struct proc *p = td->td_proc; | struct proc *p = td->td_proc; | ||||
struct ucred *newcred, *oldcred; | struct ucred *newcred, *oldcred; | ||||
struct credwrap *newcredwrap, *oldcredwrap; | |||||
int error; | int error; | ||||
MPASS(ngrp <= ngroups_max + 1); | MPASS(ngrp <= ngroups_max + 1); | ||||
AUDIT_ARG_GROUPSET(groups, ngrp); | AUDIT_ARG_GROUPSET(groups, ngrp); | ||||
newcred = crget(); | newcred = crget(); | ||||
newcredwrap = crwget(newcred); | |||||
crextend(newcred, ngrp); | crextend(newcred, ngrp); | ||||
PROC_LOCK(p); | PROC_LOCK(p); | ||||
oldcred = crcopysafe(p, newcred); | oldcred = crcopysafe(p, newcred); | ||||
oldcredwrap = p->p_credwrap; | |||||
#ifdef MAC | #ifdef MAC | ||||
error = mac_cred_check_setgroups(oldcred, ngrp, groups); | error = mac_cred_check_setgroups(oldcred, ngrp, groups); | ||||
if (error) | if (error) | ||||
goto fail; | goto fail; | ||||
#endif | #endif | ||||
error = priv_check_cred(oldcred, PRIV_CRED_SETGROUPS); | error = priv_check_cred(oldcred, PRIV_CRED_SETGROUPS); | ||||
if (error) | if (error) | ||||
goto fail; | goto fail; | ||||
if (ngrp == 0) { | if (ngrp == 0) { | ||||
/* | /* | ||||
* setgroups(0, NULL) is a legitimate way of clearing the | * setgroups(0, NULL) is a legitimate way of clearing the | ||||
* groups vector on non-BSD systems (which generally do not | * groups vector on non-BSD systems (which generally do not | ||||
* have the egid in the groups[0]). We risk security holes | * have the egid in the groups[0]). We risk security holes | ||||
* when running non-BSD software if we do not do the same. | * when running non-BSD software if we do not do the same. | ||||
*/ | */ | ||||
newcred->cr_ngroups = 1; | newcred->cr_ngroups = 1; | ||||
} else { | } else { | ||||
crsetgroups_locked(newcred, ngrp, groups); | crsetgroups_locked(newcred, ngrp, groups); | ||||
} | } | ||||
setsugid(p); | setsugid(p); | ||||
proc_set_cred(p, newcred); | proc_set_cred(p, newcred, newcredwrap); | ||||
PROC_UNLOCK(p); | PROC_UNLOCK(p); | ||||
crfree(oldcred); | crfree(oldcred); | ||||
crwfree(oldcredwrap); | |||||
return (0); | return (0); | ||||
fail: | fail: | ||||
PROC_UNLOCK(p); | PROC_UNLOCK(p); | ||||
crfree(newcred); | crfree(newcred); | ||||
crwfree(newcredwrap); | |||||
return (error); | return (error); | ||||
} | } | ||||
#ifndef _SYS_SYSPROTO_H_ | #ifndef _SYS_SYSPROTO_H_ | ||||
struct setreuid_args { | struct setreuid_args { | ||||
uid_t ruid; | uid_t ruid; | ||||
uid_t euid; | uid_t euid; | ||||
}; | }; | ||||
#endif | #endif | ||||
/* ARGSUSED */ | /* ARGSUSED */ | ||||
int | int | ||||
sys_setreuid(struct thread *td, struct setreuid_args *uap) | sys_setreuid(struct thread *td, struct setreuid_args *uap) | ||||
{ | { | ||||
struct proc *p = td->td_proc; | struct proc *p = td->td_proc; | ||||
struct ucred *newcred, *oldcred; | struct ucred *newcred, *oldcred; | ||||
struct credwrap *newcredwrap, *oldcredwrap; | |||||
uid_t euid, ruid; | uid_t euid, ruid; | ||||
struct uidinfo *euip, *ruip; | struct uidinfo *euip, *ruip; | ||||
int error; | int error; | ||||
euid = uap->euid; | euid = uap->euid; | ||||
ruid = uap->ruid; | ruid = uap->ruid; | ||||
AUDIT_ARG_EUID(euid); | AUDIT_ARG_EUID(euid); | ||||
AUDIT_ARG_RUID(ruid); | AUDIT_ARG_RUID(ruid); | ||||
newcred = crget(); | newcred = crget(); | ||||
newcredwrap = crwget(newcred); | |||||
euip = uifind(euid); | euip = uifind(euid); | ||||
ruip = uifind(ruid); | ruip = uifind(ruid); | ||||
PROC_LOCK(p); | PROC_LOCK(p); | ||||
oldcred = crcopysafe(p, newcred); | oldcred = crcopysafe(p, newcred); | ||||
oldcredwrap = p->p_credwrap; | |||||
#ifdef MAC | #ifdef MAC | ||||
error = mac_cred_check_setreuid(oldcred, ruid, euid); | error = mac_cred_check_setreuid(oldcred, ruid, euid); | ||||
if (error) | if (error) | ||||
goto fail; | goto fail; | ||||
#endif | #endif | ||||
if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid && | if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid && | ||||
Show All 11 Lines | if (ruid != (uid_t)-1 && oldcred->cr_ruid != ruid) { | ||||
change_ruid(newcred, ruip); | change_ruid(newcred, ruip); | ||||
setsugid(p); | setsugid(p); | ||||
} | } | ||||
if ((ruid != (uid_t)-1 || newcred->cr_uid != newcred->cr_ruid) && | if ((ruid != (uid_t)-1 || newcred->cr_uid != newcred->cr_ruid) && | ||||
newcred->cr_svuid != newcred->cr_uid) { | newcred->cr_svuid != newcred->cr_uid) { | ||||
change_svuid(newcred, newcred->cr_uid); | change_svuid(newcred, newcred->cr_uid); | ||||
setsugid(p); | setsugid(p); | ||||
} | } | ||||
proc_set_cred(p, newcred); | proc_set_cred(p, newcred, newcredwrap); | ||||
#ifdef RACCT | #ifdef RACCT | ||||
racct_proc_ucred_changed(p, oldcred, newcred); | racct_proc_ucred_changed(p, oldcred, newcred); | ||||
crhold(newcred); | crhold(newcred); | ||||
#endif | #endif | ||||
PROC_UNLOCK(p); | PROC_UNLOCK(p); | ||||
#ifdef RCTL | #ifdef RCTL | ||||
rctl_proc_ucred_changed(p, newcred); | rctl_proc_ucred_changed(p, newcred); | ||||
crfree(newcred); | crfree(newcred); | ||||
#endif | #endif | ||||
uifree(ruip); | uifree(ruip); | ||||
uifree(euip); | uifree(euip); | ||||
crfree(oldcred); | crfree(oldcred); | ||||
crwfree(oldcredwrap); | |||||
return (0); | return (0); | ||||
fail: | fail: | ||||
PROC_UNLOCK(p); | PROC_UNLOCK(p); | ||||
uifree(ruip); | uifree(ruip); | ||||
uifree(euip); | uifree(euip); | ||||
crfree(newcred); | crfree(newcred); | ||||
crwfree(newcredwrap); | |||||
return (error); | return (error); | ||||
} | } | ||||
#ifndef _SYS_SYSPROTO_H_ | #ifndef _SYS_SYSPROTO_H_ | ||||
struct setregid_args { | struct setregid_args { | ||||
gid_t rgid; | gid_t rgid; | ||||
gid_t egid; | gid_t egid; | ||||
}; | }; | ||||
#endif | #endif | ||||
/* ARGSUSED */ | /* ARGSUSED */ | ||||
int | int | ||||
sys_setregid(struct thread *td, struct setregid_args *uap) | sys_setregid(struct thread *td, struct setregid_args *uap) | ||||
{ | { | ||||
struct proc *p = td->td_proc; | struct proc *p = td->td_proc; | ||||
struct ucred *newcred, *oldcred; | struct ucred *newcred, *oldcred; | ||||
struct credwrap *newcredwrap, *oldcredwrap; | |||||
gid_t egid, rgid; | gid_t egid, rgid; | ||||
int error; | int error; | ||||
egid = uap->egid; | egid = uap->egid; | ||||
rgid = uap->rgid; | rgid = uap->rgid; | ||||
AUDIT_ARG_EGID(egid); | AUDIT_ARG_EGID(egid); | ||||
AUDIT_ARG_RGID(rgid); | AUDIT_ARG_RGID(rgid); | ||||
newcred = crget(); | newcred = crget(); | ||||
newcredwrap = crwget(newcred); | |||||
PROC_LOCK(p); | PROC_LOCK(p); | ||||
oldcred = crcopysafe(p, newcred); | oldcred = crcopysafe(p, newcred); | ||||
oldcredwrap = p->p_credwrap; | |||||
#ifdef MAC | #ifdef MAC | ||||
error = mac_cred_check_setregid(oldcred, rgid, egid); | error = mac_cred_check_setregid(oldcred, rgid, egid); | ||||
if (error) | if (error) | ||||
goto fail; | goto fail; | ||||
#endif | #endif | ||||
if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid && | if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid && | ||||
Show All 11 Lines | if (rgid != (gid_t)-1 && oldcred->cr_rgid != rgid) { | ||||
change_rgid(newcred, rgid); | change_rgid(newcred, rgid); | ||||
setsugid(p); | setsugid(p); | ||||
} | } | ||||
if ((rgid != (gid_t)-1 || newcred->cr_groups[0] != newcred->cr_rgid) && | if ((rgid != (gid_t)-1 || newcred->cr_groups[0] != newcred->cr_rgid) && | ||||
newcred->cr_svgid != newcred->cr_groups[0]) { | newcred->cr_svgid != newcred->cr_groups[0]) { | ||||
change_svgid(newcred, newcred->cr_groups[0]); | change_svgid(newcred, newcred->cr_groups[0]); | ||||
setsugid(p); | setsugid(p); | ||||
} | } | ||||
proc_set_cred(p, newcred); | proc_set_cred(p, newcred, newcredwrap); | ||||
PROC_UNLOCK(p); | PROC_UNLOCK(p); | ||||
crfree(oldcred); | crfree(oldcred); | ||||
crwfree(oldcredwrap); | |||||
return (0); | return (0); | ||||
fail: | fail: | ||||
PROC_UNLOCK(p); | PROC_UNLOCK(p); | ||||
crfree(newcred); | crfree(newcred); | ||||
crwfree(newcredwrap); | |||||
return (error); | return (error); | ||||
} | } | ||||
/* | /* | ||||
* setresuid(ruid, euid, suid) is like setreuid except control over the saved | * setresuid(ruid, euid, suid) is like setreuid except control over the saved | ||||
* uid is explicit. | * uid is explicit. | ||||
*/ | */ | ||||
#ifndef _SYS_SYSPROTO_H_ | #ifndef _SYS_SYSPROTO_H_ | ||||
struct setresuid_args { | struct setresuid_args { | ||||
uid_t ruid; | uid_t ruid; | ||||
uid_t euid; | uid_t euid; | ||||
uid_t suid; | uid_t suid; | ||||
}; | }; | ||||
#endif | #endif | ||||
/* ARGSUSED */ | /* ARGSUSED */ | ||||
int | int | ||||
sys_setresuid(struct thread *td, struct setresuid_args *uap) | sys_setresuid(struct thread *td, struct setresuid_args *uap) | ||||
{ | { | ||||
struct proc *p = td->td_proc; | struct proc *p = td->td_proc; | ||||
struct ucred *newcred, *oldcred; | struct ucred *newcred, *oldcred; | ||||
struct credwrap *newcredwrap, *oldcredwrap; | |||||
uid_t euid, ruid, suid; | uid_t euid, ruid, suid; | ||||
struct uidinfo *euip, *ruip; | struct uidinfo *euip, *ruip; | ||||
int error; | int error; | ||||
euid = uap->euid; | euid = uap->euid; | ||||
ruid = uap->ruid; | ruid = uap->ruid; | ||||
suid = uap->suid; | suid = uap->suid; | ||||
AUDIT_ARG_EUID(euid); | AUDIT_ARG_EUID(euid); | ||||
AUDIT_ARG_RUID(ruid); | AUDIT_ARG_RUID(ruid); | ||||
AUDIT_ARG_SUID(suid); | AUDIT_ARG_SUID(suid); | ||||
newcred = crget(); | newcred = crget(); | ||||
newcredwrap = crwget(newcred); | |||||
euip = uifind(euid); | euip = uifind(euid); | ||||
ruip = uifind(ruid); | ruip = uifind(ruid); | ||||
PROC_LOCK(p); | PROC_LOCK(p); | ||||
oldcred = crcopysafe(p, newcred); | oldcred = crcopysafe(p, newcred); | ||||
oldcredwrap = p->p_credwrap; | |||||
#ifdef MAC | #ifdef MAC | ||||
error = mac_cred_check_setresuid(oldcred, ruid, euid, suid); | error = mac_cred_check_setresuid(oldcred, ruid, euid, suid); | ||||
if (error) | if (error) | ||||
goto fail; | goto fail; | ||||
#endif | #endif | ||||
if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid && | if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid && | ||||
Show All 15 Lines | #endif | ||||
if (ruid != (uid_t)-1 && oldcred->cr_ruid != ruid) { | if (ruid != (uid_t)-1 && oldcred->cr_ruid != ruid) { | ||||
change_ruid(newcred, ruip); | change_ruid(newcred, ruip); | ||||
setsugid(p); | setsugid(p); | ||||
} | } | ||||
if (suid != (uid_t)-1 && oldcred->cr_svuid != suid) { | if (suid != (uid_t)-1 && oldcred->cr_svuid != suid) { | ||||
change_svuid(newcred, suid); | change_svuid(newcred, suid); | ||||
setsugid(p); | setsugid(p); | ||||
} | } | ||||
proc_set_cred(p, newcred); | proc_set_cred(p, newcred, newcredwrap); | ||||
#ifdef RACCT | #ifdef RACCT | ||||
racct_proc_ucred_changed(p, oldcred, newcred); | racct_proc_ucred_changed(p, oldcred, newcred); | ||||
crhold(newcred); | crhold(newcred); | ||||
#endif | #endif | ||||
PROC_UNLOCK(p); | PROC_UNLOCK(p); | ||||
#ifdef RCTL | #ifdef RCTL | ||||
rctl_proc_ucred_changed(p, newcred); | rctl_proc_ucred_changed(p, newcred); | ||||
crfree(newcred); | crfree(newcred); | ||||
#endif | #endif | ||||
uifree(ruip); | uifree(ruip); | ||||
uifree(euip); | uifree(euip); | ||||
crfree(oldcred); | crfree(oldcred); | ||||
crwfree(oldcredwrap); | |||||
return (0); | return (0); | ||||
fail: | fail: | ||||
PROC_UNLOCK(p); | PROC_UNLOCK(p); | ||||
uifree(ruip); | uifree(ruip); | ||||
uifree(euip); | uifree(euip); | ||||
crfree(newcred); | crfree(newcred); | ||||
crwfree(newcredwrap); | |||||
return (error); | return (error); | ||||
} | } | ||||
/* | /* | ||||
* setresgid(rgid, egid, sgid) is like setregid except control over the saved | * setresgid(rgid, egid, sgid) is like setregid except control over the saved | ||||
* gid is explicit. | * gid is explicit. | ||||
*/ | */ | ||||
#ifndef _SYS_SYSPROTO_H_ | #ifndef _SYS_SYSPROTO_H_ | ||||
struct setresgid_args { | struct setresgid_args { | ||||
gid_t rgid; | gid_t rgid; | ||||
gid_t egid; | gid_t egid; | ||||
gid_t sgid; | gid_t sgid; | ||||
}; | }; | ||||
#endif | #endif | ||||
/* ARGSUSED */ | /* ARGSUSED */ | ||||
int | int | ||||
sys_setresgid(struct thread *td, struct setresgid_args *uap) | sys_setresgid(struct thread *td, struct setresgid_args *uap) | ||||
{ | { | ||||
struct proc *p = td->td_proc; | struct proc *p = td->td_proc; | ||||
struct ucred *newcred, *oldcred; | struct ucred *newcred, *oldcred; | ||||
struct credwrap *newcredwrap, *oldcredwrap; | |||||
gid_t egid, rgid, sgid; | gid_t egid, rgid, sgid; | ||||
int error; | int error; | ||||
egid = uap->egid; | egid = uap->egid; | ||||
rgid = uap->rgid; | rgid = uap->rgid; | ||||
sgid = uap->sgid; | sgid = uap->sgid; | ||||
AUDIT_ARG_EGID(egid); | AUDIT_ARG_EGID(egid); | ||||
AUDIT_ARG_RGID(rgid); | AUDIT_ARG_RGID(rgid); | ||||
AUDIT_ARG_SGID(sgid); | AUDIT_ARG_SGID(sgid); | ||||
newcred = crget(); | newcred = crget(); | ||||
newcredwrap = crwget(newcred); | |||||
PROC_LOCK(p); | PROC_LOCK(p); | ||||
oldcred = crcopysafe(p, newcred); | oldcred = crcopysafe(p, newcred); | ||||
oldcredwrap = p->p_credwrap; | |||||
#ifdef MAC | #ifdef MAC | ||||
error = mac_cred_check_setresgid(oldcred, rgid, egid, sgid); | error = mac_cred_check_setresgid(oldcred, rgid, egid, sgid); | ||||
if (error) | if (error) | ||||
goto fail; | goto fail; | ||||
#endif | #endif | ||||
if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid && | if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid && | ||||
Show All 15 Lines | #endif | ||||
if (rgid != (gid_t)-1 && oldcred->cr_rgid != rgid) { | if (rgid != (gid_t)-1 && oldcred->cr_rgid != rgid) { | ||||
change_rgid(newcred, rgid); | change_rgid(newcred, rgid); | ||||
setsugid(p); | setsugid(p); | ||||
} | } | ||||
if (sgid != (gid_t)-1 && oldcred->cr_svgid != sgid) { | if (sgid != (gid_t)-1 && oldcred->cr_svgid != sgid) { | ||||
change_svgid(newcred, sgid); | change_svgid(newcred, sgid); | ||||
setsugid(p); | setsugid(p); | ||||
} | } | ||||
proc_set_cred(p, newcred); | proc_set_cred(p, newcred, newcredwrap); | ||||
PROC_UNLOCK(p); | PROC_UNLOCK(p); | ||||
crfree(oldcred); | crfree(oldcred); | ||||
crwfree(oldcredwrap); | |||||
return (0); | return (0); | ||||
fail: | fail: | ||||
PROC_UNLOCK(p); | PROC_UNLOCK(p); | ||||
crfree(newcred); | crfree(newcred); | ||||
crwfree(newcredwrap); | |||||
return (error); | return (error); | ||||
} | } | ||||
#ifndef _SYS_SYSPROTO_H_ | #ifndef _SYS_SYSPROTO_H_ | ||||
struct getresuid_args { | struct getresuid_args { | ||||
uid_t *ruid; | uid_t *ruid; | ||||
uid_t *euid; | uid_t *euid; | ||||
uid_t *suid; | uid_t *suid; | ||||
▲ Show 20 Lines • Show All 734 Lines • ▼ Show 20 Lines | #ifdef MAC | ||||
mac_cred_destroy(cr); | mac_cred_destroy(cr); | ||||
#endif | #endif | ||||
if (cr->cr_groups != cr->cr_smallgroups) | if (cr->cr_groups != cr->cr_smallgroups) | ||||
free(cr->cr_groups, M_CRED); | free(cr->cr_groups, M_CRED); | ||||
free(cr, M_CRED); | free(cr, M_CRED); | ||||
} | } | ||||
} | } | ||||
struct credwrap * | |||||
crwget(struct ucred *cr) | |||||
{ | |||||
struct credwrap *crw; | |||||
crw = malloc(CACHE_LINE_SIZE, M_CREDWRAP, M_WAITOK); | |||||
kib: This is somewhat beyond even the 'just a hack' level. Please use sizeof(struct credwrap) there… | |||||
refcount_init(&crw->crw_ref, 1); | |||||
crw->crw_ucred = crhold(cr); | |||||
return (crw); | |||||
} | |||||
struct credwrap * | |||||
crwhold(struct credwrap *crw) | |||||
{ | |||||
refcount_acquire(&crw->crw_ref); | |||||
return (crw); | |||||
} | |||||
void | |||||
crwfree(struct credwrap *crw) | |||||
{ | |||||
if (refcount_release(&crw->crw_ref)) { | |||||
crfree(crw->crw_ucred); | |||||
free(crw, M_CREDWRAP); | |||||
} | |||||
} | |||||
/* | /* | ||||
* Copy a ucred's contents from a template. Does not block. | * Copy a ucred's contents from a template. Does not block. | ||||
*/ | */ | ||||
void | void | ||||
crcopy(struct ucred *dest, struct ucred *src) | crcopy(struct ucred *dest, struct ucred *src) | ||||
{ | { | ||||
KASSERT(dest->cr_ref == 1, ("crcopy of shared ucred")); | |||||
bcopy(&src->cr_startcopy, &dest->cr_startcopy, | bcopy(&src->cr_startcopy, &dest->cr_startcopy, | ||||
(unsigned)((caddr_t)&src->cr_endcopy - | (unsigned)((caddr_t)&src->cr_endcopy - | ||||
(caddr_t)&src->cr_startcopy)); | (caddr_t)&src->cr_startcopy)); | ||||
crsetgroups(dest, src->cr_ngroups, src->cr_groups); | crsetgroups(dest, src->cr_ngroups, src->cr_groups); | ||||
uihold(dest->cr_uidinfo); | uihold(dest->cr_uidinfo); | ||||
uihold(dest->cr_ruidinfo); | uihold(dest->cr_ruidinfo); | ||||
prison_hold(dest->cr_prison); | prison_hold(dest->cr_prison); | ||||
loginclass_hold(dest->cr_loginclass); | loginclass_hold(dest->cr_loginclass); | ||||
▲ Show 20 Lines • Show All 48 Lines • ▼ Show 20 Lines | |||||
* Set initial process credentials. | * Set initial process credentials. | ||||
* Callers are responsible for providing the reference for provided credentials. | * Callers are responsible for providing the reference for provided credentials. | ||||
*/ | */ | ||||
void | void | ||||
proc_set_cred_init(struct proc *p, struct ucred *newcred) | proc_set_cred_init(struct proc *p, struct ucred *newcred) | ||||
{ | { | ||||
p->p_ucred = newcred; | p->p_ucred = newcred; | ||||
p->p_credwrap = crwget(p->p_ucred); | |||||
} | } | ||||
/* | /* | ||||
* Change process credentials. | * Change process credentials. | ||||
* Callers are responsible for providing the reference for passed credentials | * Callers are responsible for providing the reference for passed credentials | ||||
* and for freeing old ones. | * and for freeing old ones. | ||||
* | * | ||||
* Process has to be locked except when it does not have credentials (as it | * Process has to be locked except when it does not have credentials (as it | ||||
* should not be visible just yet) or when newcred is NULL (as this can be | * should not be visible just yet) or when newcred is NULL (as this can be | ||||
* only used when the process is about to be freed, at which point it should | * only used when the process is about to be freed, at which point it should | ||||
* not be visible anymore). | * not be visible anymore). | ||||
*/ | */ | ||||
void | void | ||||
proc_set_cred(struct proc *p, struct ucred *newcred) | proc_set_cred(struct proc *p, struct ucred *newcred, struct credwrap *newcredwrap) | ||||
{ | { | ||||
MPASS(p->p_ucred != NULL); | MPASS(p->p_ucred != NULL); | ||||
if (newcred == NULL) | MPASS(p->p_credwrap != NULL); | ||||
if (newcred == NULL) { | |||||
MPASS(p->p_state == PRS_ZOMBIE); | MPASS(p->p_state == PRS_ZOMBIE); | ||||
else | MPASS(newcredwrap == NULL); | ||||
} else | |||||
PROC_LOCK_ASSERT(p, MA_OWNED); | PROC_LOCK_ASSERT(p, MA_OWNED); | ||||
p->p_ucred = newcred; | p->p_ucred = newcred; | ||||
p->p_credwrap = newcredwrap; | |||||
if (newcred != NULL) | if (newcred != NULL) | ||||
PROC_UPDATE_COW(p); | PROC_UPDATE_COW(p); | ||||
} | } | ||||
struct ucred * | struct ucred * | ||||
crcopysafe(struct proc *p, struct ucred *cr) | crcopysafe(struct proc *p, struct ucred *cr) | ||||
{ | { | ||||
struct ucred *oldcred; | struct ucred *oldcred; | ||||
▲ Show 20 Lines • Show All 268 Lines • Show Last 20 Lines |
This is somewhat beyond even the 'just a hack' level. Please use sizeof(struct credwrap) there, if needed, extend the structure so tail fills the whole cache line.