Squish the "could sleep with process lock" messages caused by calling
uifind() with a proc lock held. change_ruid() and change_euid() have been modified to take a uidinfo structure which will be pre-allocated by callers, they will then call uihold() on the uidinfo structure so that the caller's logic is simplified. This allows one to call uifind() before locking the proc struct and thereby avoid a potential blocking allocation with the proc lock held. This may need revisiting, perhaps keeping a spare uidinfo allocated per process to handle this situation or re-examining if the proc lock needs to be held over the entire operation of changing real or effective user id. Submitted by: Don Lewis <dl-freebsd@catspoiler.org>
This commit is contained in:
parent
08d68d18e0
commit
1419eacb86
@ -1056,17 +1056,20 @@ osf1_setuid(td, uap)
|
||||
struct proc *p;
|
||||
int error;
|
||||
uid_t uid;
|
||||
struct uidinfo *uip;
|
||||
struct ucred *newcred, *oldcred;
|
||||
|
||||
p = td->td_proc;
|
||||
uid = SCARG(uap, uid);
|
||||
newcred = crget();
|
||||
uip = uifind(uid);
|
||||
PROC_LOCK(p);
|
||||
oldcred = p->p_ucred;
|
||||
|
||||
if ((error = suser_cred(p->p_ucred, PRISON_ROOT)) != 0 &&
|
||||
uid != oldcred->cr_ruid && uid != oldcred->cr_svuid) {
|
||||
PROC_UNLOCK(p);
|
||||
uifree(uip);
|
||||
crfree(newcred);
|
||||
return (error);
|
||||
}
|
||||
@ -1074,7 +1077,7 @@ osf1_setuid(td, uap)
|
||||
crcopy(newcred, oldcred);
|
||||
if (error == 0) {
|
||||
if (uid != oldcred->cr_ruid) {
|
||||
change_ruid(newcred, uid);
|
||||
change_ruid(newcred, uip);
|
||||
setsugid(p);
|
||||
}
|
||||
if (oldcred->cr_svuid != uid) {
|
||||
@ -1083,11 +1086,12 @@ osf1_setuid(td, uap)
|
||||
}
|
||||
}
|
||||
if (newcred->cr_uid != uid) {
|
||||
change_euid(newcred, uid);
|
||||
change_euid(newcred, uip);
|
||||
setsugid(p);
|
||||
}
|
||||
p->p_ucred = newcred;
|
||||
PROC_UNLOCK(p);
|
||||
uifree(uip);
|
||||
crfree(oldcred);
|
||||
return (0);
|
||||
}
|
||||
|
@ -128,6 +128,7 @@ execve(td, uap)
|
||||
struct proc *p = td->td_proc;
|
||||
struct nameidata nd, *ndp;
|
||||
struct ucred *newcred = NULL, *oldcred;
|
||||
struct uidinfo *euip;
|
||||
register_t *stack_base;
|
||||
int error, len, i;
|
||||
struct image_params image_params, *imgp;
|
||||
@ -303,6 +304,7 @@ execve(td, uap)
|
||||
* Malloc things before we need locks.
|
||||
*/
|
||||
newcred = crget();
|
||||
euip = uifind(attr.va_uid);
|
||||
i = imgp->endargs - imgp->stringbase;
|
||||
if (ps_arg_cache_limit >= i + sizeof(struct pargs))
|
||||
newargs = pargs_alloc(i);
|
||||
@ -390,7 +392,7 @@ execve(td, uap)
|
||||
*/
|
||||
crcopy(newcred, oldcred);
|
||||
if (attr.va_mode & VSUID)
|
||||
change_euid(newcred, attr.va_uid);
|
||||
change_euid(newcred, euip);
|
||||
if (attr.va_mode & VSGID)
|
||||
change_egid(newcred, attr.va_gid);
|
||||
setugidsafety(td);
|
||||
@ -472,6 +474,7 @@ execve(td, uap)
|
||||
/*
|
||||
* Free any resources malloc'd earlier that we didn't use.
|
||||
*/
|
||||
uifree(euip);
|
||||
if (newcred == NULL)
|
||||
crfree(oldcred);
|
||||
else
|
||||
|
@ -503,11 +503,13 @@ setuid(struct thread *td, struct setuid_args *uap)
|
||||
struct proc *p = td->td_proc;
|
||||
struct ucred *newcred, *oldcred;
|
||||
uid_t uid;
|
||||
struct uidinfo *uip;
|
||||
int error;
|
||||
|
||||
mtx_lock(&Giant);
|
||||
uid = uap->uid;
|
||||
newcred = crget();
|
||||
uip = uifind(uid);
|
||||
PROC_LOCK(p);
|
||||
oldcred = p->p_ucred;
|
||||
|
||||
@ -537,11 +539,15 @@ setuid(struct thread *td, struct setuid_args *uap)
|
||||
#endif
|
||||
(error = suser_cred(oldcred, PRISON_ROOT)) != 0) {
|
||||
PROC_UNLOCK(p);
|
||||
uifree(uip);
|
||||
crfree(newcred);
|
||||
mtx_unlock(&Giant);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy credentials so other references do not see our changes.
|
||||
*/
|
||||
crcopy(newcred, oldcred);
|
||||
#ifdef _POSIX_SAVED_IDS
|
||||
/*
|
||||
@ -559,7 +565,7 @@ setuid(struct thread *td, struct setuid_args *uap)
|
||||
* Set the real uid and transfer proc count to new user.
|
||||
*/
|
||||
if (uid != oldcred->cr_ruid) {
|
||||
change_ruid(newcred, uid);
|
||||
change_ruid(newcred, uip);
|
||||
setsugid(p);
|
||||
}
|
||||
/*
|
||||
@ -577,14 +583,14 @@ setuid(struct thread *td, struct setuid_args *uap)
|
||||
|
||||
/*
|
||||
* In all permitted cases, we are changing the euid.
|
||||
* Copy credentials so other references do not see our changes.
|
||||
*/
|
||||
if (uid != oldcred->cr_uid) {
|
||||
change_euid(newcred, uid);
|
||||
change_euid(newcred, uip);
|
||||
setsugid(p);
|
||||
}
|
||||
p->p_ucred = newcred;
|
||||
PROC_UNLOCK(p);
|
||||
uifree(uip);
|
||||
crfree(oldcred);
|
||||
mtx_unlock(&Giant);
|
||||
return (0);
|
||||
@ -605,17 +611,20 @@ seteuid(struct thread *td, struct seteuid_args *uap)
|
||||
struct proc *p = td->td_proc;
|
||||
struct ucred *newcred, *oldcred;
|
||||
uid_t euid;
|
||||
struct uidinfo *euip;
|
||||
int error;
|
||||
|
||||
euid = uap->euid;
|
||||
mtx_lock(&Giant);
|
||||
newcred = crget();
|
||||
euip = uifind(euid);
|
||||
PROC_LOCK(p);
|
||||
oldcred = p->p_ucred;
|
||||
if (euid != oldcred->cr_ruid && /* allow seteuid(getuid()) */
|
||||
euid != oldcred->cr_svuid && /* allow seteuid(saved uid) */
|
||||
(error = suser_cred(oldcred, PRISON_ROOT)) != 0) {
|
||||
PROC_UNLOCK(p);
|
||||
uifree(euip);
|
||||
crfree(newcred);
|
||||
mtx_unlock(&Giant);
|
||||
return (error);
|
||||
@ -626,11 +635,12 @@ seteuid(struct thread *td, struct seteuid_args *uap)
|
||||
*/
|
||||
crcopy(newcred, oldcred);
|
||||
if (oldcred->cr_uid != euid) {
|
||||
change_euid(newcred, euid);
|
||||
change_euid(newcred, euip);
|
||||
setsugid(p);
|
||||
}
|
||||
p->p_ucred = newcred;
|
||||
PROC_UNLOCK(p);
|
||||
uifree(euip);
|
||||
crfree(oldcred);
|
||||
mtx_unlock(&Giant);
|
||||
return (0);
|
||||
@ -858,12 +868,15 @@ setreuid(register struct thread *td, struct setreuid_args *uap)
|
||||
struct proc *p = td->td_proc;
|
||||
struct ucred *newcred, *oldcred;
|
||||
uid_t euid, ruid;
|
||||
struct uidinfo *euip, *ruip;
|
||||
int error;
|
||||
|
||||
euid = uap->euid;
|
||||
ruid = uap->ruid;
|
||||
mtx_lock(&Giant);
|
||||
newcred = crget();
|
||||
euip = uifind(euid);
|
||||
ruip = uifind(ruid);
|
||||
PROC_LOCK(p);
|
||||
oldcred = p->p_ucred;
|
||||
if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid &&
|
||||
@ -872,17 +885,19 @@ setreuid(register struct thread *td, struct setreuid_args *uap)
|
||||
euid != oldcred->cr_ruid && euid != oldcred->cr_svuid)) &&
|
||||
(error = suser_cred(oldcred, PRISON_ROOT)) != 0) {
|
||||
PROC_UNLOCK(p);
|
||||
uifree(ruip);
|
||||
uifree(euip);
|
||||
crfree(newcred);
|
||||
mtx_unlock(&Giant);
|
||||
return (error);
|
||||
}
|
||||
crcopy(newcred, oldcred);
|
||||
if (euid != (uid_t)-1 && oldcred->cr_uid != euid) {
|
||||
change_euid(newcred, euid);
|
||||
change_euid(newcred, euip);
|
||||
setsugid(p);
|
||||
}
|
||||
if (ruid != (uid_t)-1 && oldcred->cr_ruid != ruid) {
|
||||
change_ruid(newcred, ruid);
|
||||
change_ruid(newcred, ruip);
|
||||
setsugid(p);
|
||||
}
|
||||
if ((ruid != (uid_t)-1 || newcred->cr_uid != newcred->cr_ruid) &&
|
||||
@ -892,6 +907,8 @@ setreuid(register struct thread *td, struct setreuid_args *uap)
|
||||
}
|
||||
p->p_ucred = newcred;
|
||||
PROC_UNLOCK(p);
|
||||
uifree(ruip);
|
||||
uifree(euip);
|
||||
crfree(oldcred);
|
||||
mtx_unlock(&Giant);
|
||||
return (0);
|
||||
@ -975,6 +992,7 @@ setresuid(register struct thread *td, struct setresuid_args *uap)
|
||||
struct proc *p = td->td_proc;
|
||||
struct ucred *newcred, *oldcred;
|
||||
uid_t euid, ruid, suid;
|
||||
struct uidinfo *euip, *ruip;
|
||||
int error;
|
||||
|
||||
euid = uap->euid;
|
||||
@ -982,6 +1000,8 @@ setresuid(register struct thread *td, struct setresuid_args *uap)
|
||||
suid = uap->suid;
|
||||
mtx_lock(&Giant);
|
||||
newcred = crget();
|
||||
euip = uifind(euid);
|
||||
ruip = uifind(ruid);
|
||||
PROC_LOCK(p);
|
||||
oldcred = p->p_ucred;
|
||||
if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid &&
|
||||
@ -995,6 +1015,8 @@ setresuid(register struct thread *td, struct setresuid_args *uap)
|
||||
suid != oldcred->cr_uid)) &&
|
||||
(error = suser_cred(oldcred, PRISON_ROOT)) != 0) {
|
||||
PROC_UNLOCK(p);
|
||||
uifree(ruip);
|
||||
uifree(euip);
|
||||
crfree(newcred);
|
||||
mtx_unlock(&Giant);
|
||||
return (error);
|
||||
@ -1002,11 +1024,11 @@ setresuid(register struct thread *td, struct setresuid_args *uap)
|
||||
|
||||
crcopy(newcred, oldcred);
|
||||
if (euid != (uid_t)-1 && oldcred->cr_uid != euid) {
|
||||
change_euid(newcred, euid);
|
||||
change_euid(newcred, euip);
|
||||
setsugid(p);
|
||||
}
|
||||
if (ruid != (uid_t)-1 && oldcred->cr_ruid != ruid) {
|
||||
change_ruid(newcred, ruid);
|
||||
change_ruid(newcred, ruip);
|
||||
setsugid(p);
|
||||
}
|
||||
if (suid != (uid_t)-1 && oldcred->cr_svuid != suid) {
|
||||
@ -1015,6 +1037,8 @@ setresuid(register struct thread *td, struct setresuid_args *uap)
|
||||
}
|
||||
p->p_ucred = newcred;
|
||||
PROC_UNLOCK(p);
|
||||
uifree(ruip);
|
||||
uifree(euip);
|
||||
crfree(oldcred);
|
||||
mtx_unlock(&Giant);
|
||||
return (0);
|
||||
@ -1876,12 +1900,13 @@ setsugid(struct proc *p)
|
||||
* duration of the call.
|
||||
*/
|
||||
void
|
||||
change_euid(struct ucred *newcred, uid_t euid)
|
||||
change_euid(struct ucred *newcred, struct uidinfo *euip)
|
||||
{
|
||||
|
||||
newcred->cr_uid = euid;
|
||||
newcred->cr_uid = euip->ui_uid;
|
||||
uihold(euip);
|
||||
uifree(newcred->cr_uidinfo);
|
||||
newcred->cr_uidinfo = uifind(euid);
|
||||
newcred->cr_uidinfo = euip;
|
||||
}
|
||||
|
||||
/*-
|
||||
@ -1906,13 +1931,14 @@ change_egid(struct ucred *newcred, gid_t egid)
|
||||
* duration of the call.
|
||||
*/
|
||||
void
|
||||
change_ruid(struct ucred *newcred, uid_t ruid)
|
||||
change_ruid(struct ucred *newcred, struct uidinfo *ruip)
|
||||
{
|
||||
|
||||
(void)chgproccnt(newcred->cr_ruidinfo, -1, 0);
|
||||
newcred->cr_ruid = ruid;
|
||||
newcred->cr_ruid = ruip->ui_uid;
|
||||
uihold(ruip);
|
||||
uifree(newcred->cr_ruidinfo);
|
||||
newcred->cr_ruidinfo = uifind(ruid);
|
||||
newcred->cr_ruidinfo = ruip;
|
||||
(void)chgproccnt(newcred->cr_ruidinfo, 1, 0);
|
||||
}
|
||||
|
||||
|
@ -85,9 +85,9 @@ void cred_free_thread(struct thread *td);
|
||||
#endif
|
||||
void cred_update_thread(struct thread *td);
|
||||
void change_egid(struct ucred *newcred, gid_t egid);
|
||||
void change_euid(struct ucred *newcred, uid_t euid);
|
||||
void change_euid(struct ucred *newcred, struct uidinfo *euip);
|
||||
void change_rgid(struct ucred *newcred, gid_t rgid);
|
||||
void change_ruid(struct ucred *newcred, uid_t ruid);
|
||||
void change_ruid(struct ucred *newcred, struct uidinfo *ruip);
|
||||
void change_svgid(struct ucred *newcred, gid_t svgid);
|
||||
void change_svuid(struct ucred *newcred, uid_t svuid);
|
||||
void crcopy(struct ucred *dest, struct ucred *src);
|
||||
|
Loading…
Reference in New Issue
Block a user