Date: Tue, 18 Jun 2002 22:54:17 -0700 (PDT) From: Don Lewis <dl-freebsd@catspoiler.org> To: bright@mu.org Cc: nate@root.org, current@FreeBSD.ORG Subject: Re: Suggested fixes for uidinfo "would sleep" messages Message-ID: <200206190554.g5J5sGM1064829@gw.catspoiler.org> In-Reply-To: <20020618194828.GC12139@elvis.mu.org>
next in thread | previous in thread | raw e-mail | index | archive | help
On 18 Jun, Alfred Perlstein wrote: > * Nate Lawson <nate@root.org> [020618 12:17] wrote: >> As with others on the list, I've been getting a lot of witness complaints: >> >> ../../../vm/uma_core.c:1327: could sleep with "process lock" locked from >> ../../../kern/kern_prot.c:511 >> ../../../vm/uma_core.c:1327: could sleep with "process lock" locked from >> ../../../kern/kern_prot.c:613 >> >> Basically, every time cron runs, it does a setuid() or seteuid(), which >> calls change_ruid or change_euid which call uifree and uifind (which does >> the malloc with M_WAITOK while holding PROC_LOCK). > ... >> Is anyone else working on a fix? > > The code should not be holding proc locks over ui*() calls. I finally got tired of seeing these messages. Since I haven't seen anybody post a patch, I bit the bullet and cranked one out. It could use some examination to make sure that the reference counts are handled properly and there aren't any leaks. I'm not terribly happy about having to unhide the uidinfo stuff and expose it to the users of change_{r,e}uid(), and I don't like allocating memory before checking permissions, but it looks like the alternatives are worse. Index: sys/alpha/osf1/osf1_misc.c =================================================================== RCS file: /home/ncvs/src/sys/alpha/osf1/osf1_misc.c,v retrieving revision 1.30 diff -u -r1.30 osf1_misc.c --- sys/alpha/osf1/osf1_misc.c 13 Apr 2002 23:11:22 -0000 1.30 +++ sys/alpha/osf1/osf1_misc.c 18 Jun 2002 19:11:50 -0000 @@ -1056,17 +1056,20 @@ 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 @@ 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 @@ } } 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); } Index: sys/kern/kern_exec.c =================================================================== RCS file: /home/ncvs/src/sys/kern/kern_exec.c,v retrieving revision 1.164 diff -u -r1.164 kern_exec.c --- sys/kern/kern_exec.c 7 Jun 2002 05:41:27 -0000 1.164 +++ sys/kern/kern_exec.c 18 Jun 2002 19:09:06 -0000 @@ -128,6 +128,7 @@ 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 @@ * 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 @@ */ 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 @@ /* * Free any resources malloc'd earlier that we didn't use. */ + uifree(euip); if (newcred == NULL) crfree(oldcred); else Index: sys/kern/kern_prot.c =================================================================== RCS file: /home/ncvs/src/sys/kern/kern_prot.c,v retrieving revision 1.156 diff -u -r1.156 kern_prot.c --- sys/kern/kern_prot.c 19 May 2002 00:14:48 -0000 1.156 +++ sys/kern/kern_prot.c 18 Jun 2002 18:50:01 -0000 @@ -503,11 +503,13 @@ 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 @@ #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 @@ * 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 @@ /* * 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 @@ 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 @@ */ 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 @@ 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 @@ 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 @@ } p->p_ucred = newcred; PROC_UNLOCK(p); + uifree(ruip); + uifree(euip); crfree(oldcred); mtx_unlock(&Giant); return (0); @@ -975,6 +992,7 @@ 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 @@ 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 @@ 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 @@ 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 @@ } p->p_ucred = newcred; PROC_UNLOCK(p); + uifree(ruip); + uifree(euip); crfree(oldcred); mtx_unlock(&Giant); return (0); @@ -1874,12 +1898,13 @@ * 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; } /*- @@ -1904,13 +1929,14 @@ * 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); } Index: sys/sys/ucred.h =================================================================== RCS file: /home/ncvs/src/sys/sys/ucred.h,v retrieving revision 1.34 diff -u -r1.34 ucred.h --- sys/sys/ucred.h 7 Apr 2002 03:59:31 -0000 1.34 +++ sys/sys/ucred.h 18 Jun 2002 18:50:31 -0000 @@ -85,9 +85,9 @@ #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); To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-current" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200206190554.g5J5sGM1064829>