diff options
author | truckman <truckman@FreeBSD.org> | 2000-09-05 22:11:13 +0000 |
---|---|---|
committer | truckman <truckman@FreeBSD.org> | 2000-09-05 22:11:13 +0000 |
commit | 0575d8a3f9479a36221dabd7a8ba8c2dfdf8d4dc (patch) | |
tree | 8c7e5bf5d0e9e0c6cb7fd6854e645d80831d7971 /sys/kern/kern_prot.c | |
parent | f91fd40feebbd40ce508814370c744e8d33c5b12 (diff) | |
download | FreeBSD-src-0575d8a3f9479a36221dabd7a8ba8c2dfdf8d4dc.zip FreeBSD-src-0575d8a3f9479a36221dabd7a8ba8c2dfdf8d4dc.tar.gz |
Remove uidinfo hash table lookup and maintenance out of chgproccnt() and
chgsbsize(), which are called rather frequently and may be called from an
interrupt context in the case of chgsbsize(). Instead, do the hash table
lookup and maintenance when credentials are changed, which is a lot less
frequent. Add pointers to the uidinfo structures to the ucred and pcred
structures for fast access. Pass a pointer to the credential to chgproccnt()
and chgsbsize() instead of passing the uid. Add a reference count to the
uidinfo structure and use it to decide when to free the structure rather
than freeing the structure when the resource consumption drops to zero.
Move the resource tracking code from kern_proc.c to kern_resource.c. Move
some duplicate code sequences in kern_prot.c to separate helper functions.
Change KASSERTs in this code to unconditional tests and calls to panic().
Diffstat (limited to 'sys/kern/kern_prot.c')
-rw-r--r-- | sys/kern/kern_prot.c | 90 |
1 files changed, 70 insertions, 20 deletions
diff --git a/sys/kern/kern_prot.c b/sys/kern/kern_prot.c index 4ce571d..8c21107 100644 --- a/sys/kern/kern_prot.c +++ b/sys/kern/kern_prot.c @@ -53,10 +53,13 @@ #include <sys/proc.h> #include <sys/malloc.h> #include <sys/pioctl.h> +#include <sys/resourcevar.h> #include <sys/sysctl.h> static MALLOC_DEFINE(M_CRED, "cred", "credentials"); +static void change_ruid(struct proc *p, uid_t ruid); + #ifndef _SYS_SYSPROTO_H_ struct getpid_args { int dummy; @@ -427,18 +430,16 @@ setuid(p, uap) #endif { /* - * Transfer proc count to new user. + * Set the real uid and transfer proc count to new user. */ if (uid != pc->p_ruid) { - (void)chgproccnt(pc->p_ruid, -1, 0); - (void)chgproccnt(uid, 1, 0); + change_ruid(p, uid); + setsugid(p); } /* * Set real uid */ if (uid != pc->p_ruid) { - pc->p_ruid = uid; - setsugid(p); } /* * Set saved uid @@ -458,8 +459,7 @@ setuid(p, uap) * Copy credentials so other references do not see our changes. */ if (pc->pc_ucred->cr_uid != uid) { - pc->pc_ucred = crcopy(pc->pc_ucred); - pc->pc_ucred->cr_uid = uid; + change_euid(p, uid); setsugid(p); } return (0); @@ -490,8 +490,7 @@ seteuid(p, uap) * not see our changes. */ if (pc->pc_ucred->cr_uid != euid) { - pc->pc_ucred = crcopy(pc->pc_ucred); - pc->pc_ucred->cr_uid = euid; + change_euid(p, euid); setsugid(p); } return (0); @@ -674,14 +673,11 @@ setreuid(p, uap) return (error); if (euid != (uid_t)-1 && pc->pc_ucred->cr_uid != euid) { - pc->pc_ucred = crcopy(pc->pc_ucred); - pc->pc_ucred->cr_uid = euid; + change_euid(p, euid); setsugid(p); } if (ruid != (uid_t)-1 && pc->p_ruid != ruid) { - (void)chgproccnt(pc->p_ruid, -1, 0); - (void)chgproccnt(ruid, 1, 0); - pc->p_ruid = ruid; + change_ruid(p, ruid); setsugid(p); } if ((ruid != (uid_t)-1 || pc->pc_ucred->cr_uid != pc->p_ruid) && @@ -767,14 +763,11 @@ setresuid(p, uap) (error = suser_xxx(0, p, PRISON_ROOT)) != 0) return (error); if (euid != (uid_t)-1 && pc->pc_ucred->cr_uid != euid) { - pc->pc_ucred = crcopy(pc->pc_ucred); - pc->pc_ucred->cr_uid = euid; + change_euid(p, euid); setsugid(p); } if (ruid != (uid_t)-1 && pc->p_ruid != ruid) { - (void)chgproccnt(pc->p_ruid, -1, 0); - (void)chgproccnt(ruid, 1, 0); - pc->p_ruid = ruid; + change_ruid(p, ruid); setsugid(p); } if (suid != (uid_t)-1 && pc->p_svuid != suid) { @@ -1157,8 +1150,16 @@ void crfree(cr) struct ucred *cr; { - if (--cr->cr_ref == 0) + if (--cr->cr_ref == 0) { + /* + * Some callers of crget(), such as nfs_statfs(), + * allocate a temporary credential, but don't + * allocate a uidinfo structure. + */ + if (cr->cr_uidinfo != NULL) + uifree(cr->cr_uidinfo); FREE((caddr_t)cr, M_CRED); + } } /* @@ -1174,6 +1175,7 @@ crcopy(cr) return (cr); newcr = crget(); *newcr = *cr; + uihold(newcr->cr_uidinfo); crfree(cr); newcr->cr_ref = 1; return (newcr); @@ -1190,6 +1192,7 @@ crdup(cr) newcr = crget(); *newcr = *cr; + uihold(newcr->cr_uidinfo); newcr->cr_ref = 1; return (newcr); } @@ -1253,3 +1256,50 @@ setsugid(p) if (!(p->p_pfsflags & PF_ISUGID)) p->p_stops = 0; } + +/* + * Helper function to change the effective uid of a process + */ +void +change_euid(p, euid) + struct proc *p; + uid_t euid; +{ + struct pcred *pc; + struct uidinfo *uip; + + pc = p->p_cred; + /* + * crcopy is essentially a NOP if ucred has a reference count + * of 1, which is true if it has already been copied. + */ + pc->pc_ucred = crcopy(pc->pc_ucred); + uip = pc->pc_ucred->cr_uidinfo; + pc->pc_ucred->cr_uid = euid; + pc->pc_ucred->cr_uidinfo = uifind(euid); + uifree(uip); +} + +/* + * Helper function to change the real uid of a process + * + * The per-uid process count for this process is transfered from + * the old uid to the new uid. + */ +static void +change_ruid(p, ruid) + struct proc *p; + uid_t ruid; +{ + struct pcred *pc; + struct uidinfo *uip; + + pc = p->p_cred; + (void)chgproccnt(pc->p_uidinfo, -1, 0); + uip = pc->p_uidinfo; + /* It is assumed that pcred is not shared between processes */ + pc->p_ruid = ruid; + pc->p_uidinfo = uifind(ruid); + (void)chgproccnt(pc->p_uidinfo, 1, 0); + uifree(uip); +} |