Index: sys/compat/linux/linux_misc.c =================================================================== --- sys/compat/linux/linux_misc.c +++ sys/compat/linux/linux_misc.c @@ -1219,6 +1219,7 @@ linux_setgroups(struct thread *td, struct linux_setgroups_args *args) { struct ucred *newcred, *oldcred; + struct credwrap *newcredwrap, *oldcredwrap; l_gid_t *linux_gidset; gid_t *bsd_gidset; int ngrp, error; @@ -1232,10 +1233,12 @@ if (error) goto out; newcred = crget(); + newcredwrap = crwget(newcred); crextend(newcred, ngrp + 1); p = td->td_proc; PROC_LOCK(p); oldcred = p->p_ucred; + oldcredwrap = p->p_credwrap; crcopy(newcred, oldcred); /* @@ -1247,6 +1250,7 @@ if ((error = priv_check_cred(oldcred, PRIV_CRED_SETGROUPS)) != 0) { PROC_UNLOCK(p); crfree(newcred); + crwfree(newcredwrap); goto out; } @@ -1263,9 +1267,10 @@ newcred->cr_ngroups = 1; setsugid(p); - proc_set_cred(p, newcred); + proc_set_cred(p, newcred, newcredwrap); PROC_UNLOCK(p); crfree(oldcred); + crwfree(oldcredwrap); error = 0; out: free(linux_gidset, M_LINUX); Index: sys/compat/linux/linux_uid16.c =================================================================== --- sys/compat/linux/linux_uid16.c +++ sys/compat/linux/linux_uid16.c @@ -160,6 +160,7 @@ linux_setgroups16(struct thread *td, struct linux_setgroups16_args *args) { struct ucred *newcred, *oldcred; + struct credwrap *newcredwrap, *oldcredwrap; l_gid16_t *linux_gidset; gid_t *bsd_gidset; int ngrp, error; @@ -182,9 +183,11 @@ return (error); } newcred = crget(); + newcredwrap = crwget(newcred); p = td->td_proc; PROC_LOCK(p); oldcred = crcopysafe(p, newcred); + oldcredwrap = p->p_credwrap; /* * cr_groups[0] holds egid. Setting the whole set from @@ -195,6 +198,7 @@ if ((error = priv_check_cred(oldcred, PRIV_CRED_SETGROUPS)) != 0) { PROC_UNLOCK(p); crfree(newcred); + crwfree(newcredwrap); LIN_SDT_PROBE1(uid16, linux_setgroups16, priv_check_cred_error, error); @@ -215,9 +219,10 @@ newcred->cr_ngroups = 1; setsugid(td->td_proc); - proc_set_cred(p, newcred); + proc_set_cred(p, newcred, newcredwrap); PROC_UNLOCK(p); crfree(oldcred); + crwfree(oldcredwrap); error = 0; out: free(linux_gidset, M_LINUX); Index: sys/kern/init_main.c =================================================================== --- sys/kern/init_main.c +++ sys/kern/init_main.c @@ -447,6 +447,7 @@ struct proc *p; struct thread *td; struct ucred *newcred; + struct credwrap *newcredwrap; struct uidinfo tmpuinfo; struct loginclass tmplc = { .lc_name = "", @@ -530,6 +531,7 @@ /* Create credentials. */ newcred = crget(); + newcredwrap = crwget(newcred); newcred->cr_ngroups = 1; /* group 0 */ /* A hack to prevent uifind from tripping over NULL pointers. */ curthread->td_ucred = newcred; @@ -805,6 +807,7 @@ { struct fork_req fr; struct ucred *newcred, *oldcred; + struct credwrap *newcredwrap, *oldcredwrap; struct thread *td; int error; @@ -817,11 +820,13 @@ KASSERT(initproc->p_pid == 1, ("create_init: initproc->p_pid != 1")); /* divorce init's credentials from the kernel's */ newcred = crget(); + newcredwrap = crwget(newcred); sx_xlock(&proctree_lock); PROC_LOCK(initproc); initproc->p_flag |= P_SYSTEM | P_INMEM; initproc->p_treeflag |= P_TREE_REAPER; oldcred = initproc->p_ucred; + oldcredwrap = initproc->p_credwrap; crcopy(newcred, oldcred); #ifdef MAC mac_cred_create_init(newcred); @@ -829,13 +834,16 @@ #ifdef AUDIT audit_cred_proc1(newcred); #endif - proc_set_cred(initproc, newcred); + proc_set_cred(initproc, newcred, newcredwrap); td = FIRST_THREAD_IN_PROC(initproc); crfree(td->td_ucred); td->td_ucred = crhold(initproc->p_ucred); + crwfree(td->td_credwrap); + td->td_credwrap = crwhold(initproc->p_credwrap); PROC_UNLOCK(initproc); sx_xunlock(&proctree_lock); crfree(oldcred); + crwfree(oldcredwrap); cpu_fork_kthread_handler(FIRST_THREAD_IN_PROC(initproc), start_init, NULL); } Index: sys/kern/kern_descrip.c =================================================================== --- sys/kern/kern_descrip.c +++ sys/kern/kern_descrip.c @@ -1889,7 +1889,7 @@ fp = uma_zalloc(file_zone, M_WAITOK); bzero(fp, sizeof(*fp)); refcount_init(&fp->f_count, 1); - fp->f_cred = crhold(td->td_ucred); + fp->f_credwrap = crwhold(td->td_credwrap); fp->f_ops = &badfileops; *resultfp = fp; return (0); @@ -2978,7 +2978,7 @@ panic("fdrop: count %d", fp->f_count); error = fo_close(fp, td); atomic_subtract_int(&openfiles, 1); - crfree(fp->f_cred); + crwfree(fp->f_credwrap); free(fp->f_advice, M_FADVISE); uma_zfree(file_zone, fp); Index: sys/kern/kern_exec.c =================================================================== --- sys/kern/kern_exec.c +++ sys/kern/kern_exec.c @@ -359,6 +359,7 @@ struct proc *p = td->td_proc; struct nameidata nd; struct ucred *oldcred; + struct credwrap *oldcredwrap; struct uidinfo *euip = NULL; uintptr_t stack_base; struct image_params image_params, *imgp; @@ -406,6 +407,7 @@ imgp->attr = &attr; imgp->args = args; oldcred = p->p_ucred; + oldcredwrap = p->p_credwrap; orig_osrel = p->p_osrel; orig_fctl0 = p->p_fctl0; @@ -525,6 +527,7 @@ imgp->credential_setid = true; VOP_UNLOCK(imgp->vp, 0); imgp->newcred = crdup(oldcred); + imgp->newcredwrap = crwget(imgp->newcred); if (attr.va_mode & S_ISUID) { euip = uifind(attr.va_uid); change_euid(imgp->newcred, euip); @@ -809,9 +812,11 @@ * Set the new credentials. */ if (imgp->newcred != NULL) { - proc_set_cred(p, imgp->newcred); + proc_set_cred(p, imgp->newcred, imgp->newcredwrap); crfree(oldcred); + crwfree(oldcredwrap); oldcred = NULL; + oldcredwrap = NULL; } /* @@ -924,8 +929,10 @@ SDT_PROBE1(proc, , , exec__failure, error); } - if (imgp->newcred != NULL && oldcred != NULL) + if (imgp->newcred != NULL && oldcred != NULL) { crfree(imgp->newcred); + crwfree(imgp->newcredwrap); + } #ifdef MAC mac_execve_exit(imgp); Index: sys/kern/kern_exit.c =================================================================== --- sys/kern/kern_exit.c +++ sys/kern/kern_exit.c @@ -954,7 +954,8 @@ * Free credentials, arguments, and sigacts. */ crfree(p->p_ucred); - proc_set_cred(p, NULL); + crwfree(p->p_credwrap); + proc_set_cred(p, NULL, NULL); pargs_drop(p->p_args); p->p_args = NULL; sigacts_free(p->p_sigacts); Index: sys/kern/kern_jail.c =================================================================== --- sys/kern/kern_jail.c +++ sys/kern/kern_jail.c @@ -2356,6 +2356,7 @@ { struct proc *p; struct ucred *newcred, *oldcred; + struct credwrap *newcredwrap, *oldcredwrap; int error; /* @@ -2398,10 +2399,12 @@ goto e_revert_osd; newcred = crget(); + newcredwrap = crwget(newcred); PROC_LOCK(p); oldcred = crcopysafe(p, newcred); + oldcredwrap = p->p_credwrap; newcred->cr_prison = pr; - proc_set_cred(p, newcred); + proc_set_cred(p, newcred, newcredwrap); setsugid(p); #ifdef RACCT racct_proc_ucred_changed(p, oldcred, newcred); @@ -2414,6 +2417,7 @@ #endif prison_deref(oldcred->cr_prison, PD_DEREF | PD_DEUREF); crfree(oldcred); + crwfree(oldcredwrap); return (0); e_unlock: Index: sys/kern/kern_loginclass.c =================================================================== --- sys/kern/kern_loginclass.c +++ sys/kern/kern_loginclass.c @@ -212,6 +212,7 @@ char lcname[MAXLOGNAME]; struct loginclass *newlc; struct ucred *newcred, *oldcred; + struct credwrap *newcredwrap, *oldcredwrap; error = priv_check(td, PRIV_PROC_SETLOGINCLASS); if (error != 0) @@ -224,11 +225,13 @@ if (newlc == NULL) return (EINVAL); newcred = crget(); + newcredwrap = crwget(newcred); PROC_LOCK(p); oldcred = crcopysafe(p, newcred); + oldcredwrap = p->p_credwrap; newcred->cr_loginclass = newlc; - proc_set_cred(p, newcred); + proc_set_cred(p, newcred, newcredwrap); #ifdef RACCT racct_proc_ucred_changed(p, oldcred, newcred); crhold(newcred); @@ -240,6 +243,7 @@ #endif loginclass_free(oldcred->cr_loginclass); crfree(oldcred); + crwfree(oldcredwrap); return (0); } Index: sys/kern/kern_prot.c =================================================================== --- sys/kern/kern_prot.c +++ sys/kern/kern_prot.c @@ -83,6 +83,7 @@ #include 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"); @@ -483,6 +484,7 @@ { struct proc *p = td->td_proc; struct ucred *newcred, *oldcred; + struct credwrap *newcredwrap, *oldcredwrap; uid_t uid; struct uidinfo *uip; int error; @@ -490,12 +492,14 @@ uid = uap->uid; AUDIT_ARG_UID(uid); newcred = crget(); + newcredwrap = crwget(newcred); uip = uifind(uid); PROC_LOCK(p); /* * Copy credentials so other references do not see our changes. */ oldcred = crcopysafe(p, newcred); + oldcredwrap = p->p_credwrap; #ifdef MAC error = mac_cred_check_setuid(oldcred, uid); @@ -570,7 +574,7 @@ change_euid(newcred, uip); setsugid(p); } - proc_set_cred(p, newcred); + proc_set_cred(p, newcred, newcredwrap); #ifdef RACCT racct_proc_ucred_changed(p, oldcred, newcred); crhold(newcred); @@ -582,12 +586,14 @@ #endif uifree(uip); crfree(oldcred); + crwfree(oldcredwrap); return (0); fail: PROC_UNLOCK(p); uifree(uip); crfree(newcred); + crwfree(newcredwrap); return (error); } @@ -602,6 +608,7 @@ { struct proc *p = td->td_proc; struct ucred *newcred, *oldcred; + struct credwrap *newcredwrap, *oldcredwrap; uid_t euid; struct uidinfo *euip; int error; @@ -609,12 +616,14 @@ euid = uap->euid; AUDIT_ARG_EUID(euid); newcred = crget(); + newcredwrap = crwget(newcred); euip = uifind(euid); PROC_LOCK(p); /* * Copy credentials so other references do not see our changes. */ oldcred = crcopysafe(p, newcred); + oldcredwrap = p->p_credwrap; #ifdef MAC error = mac_cred_check_seteuid(oldcred, euid); @@ -634,16 +643,18 @@ change_euid(newcred, euip); setsugid(p); } - proc_set_cred(p, newcred); + proc_set_cred(p, newcred, newcredwrap); PROC_UNLOCK(p); uifree(euip); crfree(oldcred); + crwfree(oldcredwrap); return (0); fail: PROC_UNLOCK(p); uifree(euip); crfree(newcred); + crwfree(newcredwrap); return (error); } @@ -658,14 +669,17 @@ { struct proc *p = td->td_proc; struct ucred *newcred, *oldcred; + struct credwrap *newcredwrap, *oldcredwrap; gid_t gid; int error; gid = uap->gid; AUDIT_ARG_GID(gid); newcred = crget(); + newcredwrap = crwget(newcred); PROC_LOCK(p); oldcred = crcopysafe(p, newcred); + oldcredwrap = p->p_credwrap; #ifdef MAC error = mac_cred_check_setgid(oldcred, gid); @@ -734,14 +748,16 @@ change_egid(newcred, gid); setsugid(p); } - proc_set_cred(p, newcred); + proc_set_cred(p, newcred, newcredwrap); PROC_UNLOCK(p); crfree(oldcred); + crwfree(oldcredwrap); return (0); fail: PROC_UNLOCK(p); crfree(newcred); + crwfree(newcredwrap); return (error); } @@ -756,14 +772,17 @@ { struct proc *p = td->td_proc; struct ucred *newcred, *oldcred; + struct credwrap *newcredwrap, *oldcredwrap; gid_t egid; int error; egid = uap->egid; AUDIT_ARG_EGID(egid); newcred = crget(); + newcredwrap = crwget(newcred); PROC_LOCK(p); oldcred = crcopysafe(p, newcred); + oldcredwrap = p->p_credwrap; #ifdef MAC error = mac_cred_check_setegid(oldcred, egid); @@ -780,14 +799,16 @@ change_egid(newcred, egid); setsugid(p); } - proc_set_cred(p, newcred); + proc_set_cred(p, newcred, newcredwrap); PROC_UNLOCK(p); crfree(oldcred); + crwfree(oldcredwrap); return (0); fail: PROC_UNLOCK(p); crfree(newcred); + crwfree(newcredwrap); return (error); } @@ -829,14 +850,17 @@ { struct proc *p = td->td_proc; struct ucred *newcred, *oldcred; + struct credwrap *newcredwrap, *oldcredwrap; int error; MPASS(ngrp <= ngroups_max + 1); AUDIT_ARG_GROUPSET(groups, ngrp); newcred = crget(); + newcredwrap = crwget(newcred); crextend(newcred, ngrp); PROC_LOCK(p); oldcred = crcopysafe(p, newcred); + oldcredwrap = p->p_credwrap; #ifdef MAC error = mac_cred_check_setgroups(oldcred, ngrp, groups); @@ -860,14 +884,16 @@ crsetgroups_locked(newcred, ngrp, groups); } setsugid(p); - proc_set_cred(p, newcred); + proc_set_cred(p, newcred, newcredwrap); PROC_UNLOCK(p); crfree(oldcred); + crwfree(oldcredwrap); return (0); fail: PROC_UNLOCK(p); crfree(newcred); + crwfree(newcredwrap); return (error); } @@ -883,6 +909,7 @@ { struct proc *p = td->td_proc; struct ucred *newcred, *oldcred; + struct credwrap *newcredwrap, *oldcredwrap; uid_t euid, ruid; struct uidinfo *euip, *ruip; int error; @@ -892,10 +919,12 @@ AUDIT_ARG_EUID(euid); AUDIT_ARG_RUID(ruid); newcred = crget(); + newcredwrap = crwget(newcred); euip = uifind(euid); ruip = uifind(ruid); PROC_LOCK(p); oldcred = crcopysafe(p, newcred); + oldcredwrap = p->p_credwrap; #ifdef MAC error = mac_cred_check_setreuid(oldcred, ruid, euid); @@ -923,7 +952,7 @@ change_svuid(newcred, newcred->cr_uid); setsugid(p); } - proc_set_cred(p, newcred); + proc_set_cred(p, newcred, newcredwrap); #ifdef RACCT racct_proc_ucred_changed(p, oldcred, newcred); crhold(newcred); @@ -936,6 +965,7 @@ uifree(ruip); uifree(euip); crfree(oldcred); + crwfree(oldcredwrap); return (0); fail: @@ -943,6 +973,7 @@ uifree(ruip); uifree(euip); crfree(newcred); + crwfree(newcredwrap); return (error); } @@ -958,6 +989,7 @@ { struct proc *p = td->td_proc; struct ucred *newcred, *oldcred; + struct credwrap *newcredwrap, *oldcredwrap; gid_t egid, rgid; int error; @@ -966,8 +998,10 @@ AUDIT_ARG_EGID(egid); AUDIT_ARG_RGID(rgid); newcred = crget(); + newcredwrap = crwget(newcred); PROC_LOCK(p); oldcred = crcopysafe(p, newcred); + oldcredwrap = p->p_credwrap; #ifdef MAC error = mac_cred_check_setregid(oldcred, rgid, egid); @@ -995,14 +1029,16 @@ change_svgid(newcred, newcred->cr_groups[0]); setsugid(p); } - proc_set_cred(p, newcred); + proc_set_cred(p, newcred, newcredwrap); PROC_UNLOCK(p); crfree(oldcred); + crwfree(oldcredwrap); return (0); fail: PROC_UNLOCK(p); crfree(newcred); + crwfree(newcredwrap); return (error); } @@ -1023,6 +1059,7 @@ { struct proc *p = td->td_proc; struct ucred *newcred, *oldcred; + struct credwrap *newcredwrap, *oldcredwrap; uid_t euid, ruid, suid; struct uidinfo *euip, *ruip; int error; @@ -1034,10 +1071,12 @@ AUDIT_ARG_RUID(ruid); AUDIT_ARG_SUID(suid); newcred = crget(); + newcredwrap = crwget(newcred); euip = uifind(euid); ruip = uifind(ruid); PROC_LOCK(p); oldcred = crcopysafe(p, newcred); + oldcredwrap = p->p_credwrap; #ifdef MAC error = mac_cred_check_setresuid(oldcred, ruid, euid, suid); @@ -1069,7 +1108,7 @@ change_svuid(newcred, suid); setsugid(p); } - proc_set_cred(p, newcred); + proc_set_cred(p, newcred, newcredwrap); #ifdef RACCT racct_proc_ucred_changed(p, oldcred, newcred); crhold(newcred); @@ -1082,6 +1121,7 @@ uifree(ruip); uifree(euip); crfree(oldcred); + crwfree(oldcredwrap); return (0); fail: @@ -1089,6 +1129,7 @@ uifree(ruip); uifree(euip); crfree(newcred); + crwfree(newcredwrap); return (error); } @@ -1110,6 +1151,7 @@ { struct proc *p = td->td_proc; struct ucred *newcred, *oldcred; + struct credwrap *newcredwrap, *oldcredwrap; gid_t egid, rgid, sgid; int error; @@ -1120,8 +1162,10 @@ AUDIT_ARG_RGID(rgid); AUDIT_ARG_SGID(sgid); newcred = crget(); + newcredwrap = crwget(newcred); PROC_LOCK(p); oldcred = crcopysafe(p, newcred); + oldcredwrap = p->p_credwrap; #ifdef MAC error = mac_cred_check_setresgid(oldcred, rgid, egid, sgid); @@ -1153,14 +1197,16 @@ change_svgid(newcred, sgid); setsugid(p); } - proc_set_cred(p, newcred); + proc_set_cred(p, newcred, newcredwrap); PROC_UNLOCK(p); crfree(oldcred); + crwfree(oldcredwrap); return (0); fail: PROC_UNLOCK(p); crfree(newcred); + crwfree(newcredwrap); return (error); } @@ -1911,6 +1957,35 @@ } } +struct credwrap * +crwget(struct ucred *cr) +{ + struct credwrap *crw; + + crw = malloc(CACHE_LINE_SIZE, M_CREDWRAP, M_WAITOK); + 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. */ @@ -1918,7 +1993,6 @@ crcopy(struct ucred *dest, struct ucred *src) { - KASSERT(dest->cr_ref == 1, ("crcopy of shared ucred")); bcopy(&src->cr_startcopy, &dest->cr_startcopy, (unsigned)((caddr_t)&src->cr_endcopy - (caddr_t)&src->cr_startcopy)); @@ -1983,6 +2057,7 @@ { p->p_ucred = newcred; + p->p_credwrap = crwget(p->p_ucred); } /* @@ -1996,16 +2071,19 @@ * not be visible anymore). */ 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); - if (newcred == NULL) + MPASS(p->p_credwrap != NULL); + if (newcred == NULL) { MPASS(p->p_state == PRS_ZOMBIE); - else + MPASS(newcredwrap == NULL); + } else PROC_LOCK_ASSERT(p, MA_OWNED); p->p_ucred = newcred; + p->p_credwrap = newcredwrap; if (newcred != NULL) PROC_UPDATE_COW(p); } Index: sys/kern/kern_thread.c =================================================================== --- sys/kern/kern_thread.c +++ sys/kern/kern_thread.c @@ -452,6 +452,7 @@ PROC_LOCK_ASSERT(p, MA_OWNED); newtd->td_ucred = crhold(p->p_ucred); + newtd->td_credwrap = crwhold(p->p_credwrap); newtd->td_limit = lim_hold(p->p_limit); newtd->td_cowgen = p->p_cowgen; } @@ -461,6 +462,7 @@ { newtd->td_ucred = crhold(td->td_ucred); + newtd->td_credwrap = crwhold(td->td_credwrap); newtd->td_limit = lim_hold(td->td_limit); newtd->td_cowgen = td->td_cowgen; } @@ -471,6 +473,8 @@ if (td->td_ucred != NULL) crfree(td->td_ucred); + if (td->td_credwrap != NULL) + crwfree(td->td_credwrap); if (td->td_limit != NULL) lim_free(td->td_limit); } @@ -480,16 +484,22 @@ { struct proc *p; struct ucred *oldcred; + struct credwrap *oldcredwrap; struct plimit *oldlimit; p = td->td_proc; oldcred = NULL; + oldcredwrap = NULL; oldlimit = NULL; PROC_LOCK(p); if (td->td_ucred != p->p_ucred) { oldcred = td->td_ucred; td->td_ucred = crhold(p->p_ucred); } + if (td->td_credwrap != p->p_credwrap) { + oldcredwrap = td->td_credwrap; + td->td_credwrap = crwhold(p->p_credwrap); + } if (td->td_limit != p->p_limit) { oldlimit = td->td_limit; td->td_limit = lim_hold(p->p_limit); @@ -498,6 +508,8 @@ PROC_UNLOCK(p); if (oldcred != NULL) crfree(oldcred); + if (oldcredwrap != NULL) + crwfree(oldcredwrap); if (oldlimit != NULL) lim_free(oldlimit); } Index: sys/kern/sys_capability.c =================================================================== --- sys/kern/sys_capability.c +++ sys/kern/sys_capability.c @@ -102,19 +102,23 @@ sys_cap_enter(struct thread *td, struct cap_enter_args *uap) { struct ucred *newcred, *oldcred; + struct credwrap *newcredwrap, *oldcredwrap; struct proc *p; if (IN_CAPABILITY_MODE(td)) return (0); newcred = crget(); + newcredwrap = crwget(newcred); p = td->td_proc; PROC_LOCK(p); oldcred = crcopysafe(p, newcred); + oldcredwrap = p->p_credwrap; newcred->cr_flags |= CRED_FLAG_CAPMODE; - proc_set_cred(p, newcred); + proc_set_cred(p, newcred, newcredwrap); PROC_UNLOCK(p); crfree(oldcred); + crwfree(oldcredwrap); return (0); } Index: sys/security/audit/audit_syscalls.c =================================================================== --- sys/security/audit/audit_syscalls.c +++ sys/security/audit/audit_syscalls.c @@ -165,6 +165,7 @@ sys_auditon(struct thread *td, struct auditon_args *uap) { struct ucred *cred, *newcred, *oldcred; + struct credwrap *newcredwrap, *oldcredwrap; int error; union auditon_udata udata; struct proc *tp; @@ -478,24 +479,29 @@ if (udata.au_aupinfo.ap_pid < 1) return (ESRCH); newcred = crget(); + newcredwrap = crwget(newcred); if ((tp = pfind(udata.au_aupinfo.ap_pid)) == NULL) { crfree(newcred); + crwfree(newcredwrap); return (ESRCH); } if ((error = p_cansee(td, tp)) != 0) { PROC_UNLOCK(tp); crfree(newcred); + crwfree(newcredwrap); return (error); } oldcred = tp->p_ucred; + oldcredwrap = tp->p_credwrap; crcopy(newcred, oldcred); newcred->cr_audit.ai_mask.am_success = udata.au_aupinfo.ap_mask.am_success; newcred->cr_audit.ai_mask.am_failure = udata.au_aupinfo.ap_mask.am_failure; - proc_set_cred(tp, newcred); + proc_set_cred(tp, newcred, newcredwrap); PROC_UNLOCK(tp); crfree(oldcred); + crwfree(oldcredwrap); break; case A_SETFSIZE: @@ -610,6 +616,7 @@ sys_setauid(struct thread *td, struct setauid_args *uap) { struct ucred *newcred, *oldcred; + struct credwrap *newcredwrap, *oldcredwrap; au_id_t id; int error; @@ -620,8 +627,10 @@ return (error); audit_arg_auid(id); newcred = crget(); + newcredwrap = crwget(newcred); PROC_LOCK(td->td_proc); oldcred = td->td_proc->p_ucred; + oldcredwrap = td->td_proc->p_credwrap; crcopy(newcred, oldcred); #ifdef MAC error = mac_cred_check_setauid(oldcred, id); @@ -632,13 +641,15 @@ if (error) goto fail; newcred->cr_audit.ai_auid = id; - proc_set_cred(td->td_proc, newcred); + proc_set_cred(td->td_proc, newcred, newcredwrap); PROC_UNLOCK(td->td_proc); crfree(oldcred); + crwfree(oldcredwrap); return (0); fail: PROC_UNLOCK(td->td_proc); crfree(newcred); + crwfree(newcredwrap); return (error); } @@ -675,6 +686,7 @@ sys_setaudit(struct thread *td, struct setaudit_args *uap) { struct ucred *newcred, *oldcred; + struct credwrap *newcredwrap, *oldcredwrap; struct auditinfo ai; int error; @@ -685,8 +697,10 @@ return (error); audit_arg_auditinfo(&ai); newcred = crget(); + newcredwrap = crwget(newcred); PROC_LOCK(td->td_proc); oldcred = td->td_proc->p_ucred; + oldcredwrap = td->td_proc->p_credwrap; crcopy(newcred, oldcred); #ifdef MAC error = mac_cred_check_setaudit(oldcred, &ai); @@ -703,13 +717,15 @@ newcred->cr_audit.ai_termid.at_addr[0] = ai.ai_termid.machine; newcred->cr_audit.ai_termid.at_port = ai.ai_termid.port; newcred->cr_audit.ai_termid.at_type = AU_IPv4; - proc_set_cred(td->td_proc, newcred); + proc_set_cred(td->td_proc, newcred, newcredwrap); PROC_UNLOCK(td->td_proc); crfree(oldcred); + crwfree(oldcredwrap); return (0); fail: PROC_UNLOCK(td->td_proc); crfree(newcred); + crwfree(newcredwrap); return (error); } @@ -735,6 +751,7 @@ sys_setaudit_addr(struct thread *td, struct setaudit_addr_args *uap) { struct ucred *newcred, *oldcred; + struct credwrap *newcredwrap, *oldcredwrap; struct auditinfo_addr aia; int error; @@ -748,8 +765,10 @@ aia.ai_termid.at_type != AU_IPv4) return (EINVAL); newcred = crget(); + newcredwrap = crwget(newcred); PROC_LOCK(td->td_proc); oldcred = td->td_proc->p_ucred; + oldcredwrap = td->td_proc->p_credwrap; crcopy(newcred, oldcred); #ifdef MAC error = mac_cred_check_setaudit_addr(oldcred, &aia); @@ -760,13 +779,15 @@ if (error) goto fail; newcred->cr_audit = aia; - proc_set_cred(td->td_proc, newcred); + proc_set_cred(td->td_proc, newcred, newcredwrap); PROC_UNLOCK(td->td_proc); crfree(oldcred); + crwfree(oldcredwrap); return (0); fail: PROC_UNLOCK(td->td_proc); crfree(newcred); + crwfree(newcredwrap); return (error); } Index: sys/security/mac/mac_syscalls.c =================================================================== --- sys/security/mac/mac_syscalls.c +++ sys/security/mac/mac_syscalls.c @@ -167,6 +167,7 @@ sys___mac_set_proc(struct thread *td, struct __mac_set_proc_args *uap) { struct ucred *newcred, *oldcred; + struct credwrap *newcredwrap, *oldcredwrap; struct label *intlabel; struct proc *p; struct mac mac; @@ -198,25 +199,29 @@ goto out; newcred = crget(); + newcredwrap = crwget(newcred); p = td->td_proc; PROC_LOCK(p); oldcred = p->p_ucred; + oldcredwrap = p->p_credwrap; error = mac_cred_check_relabel(oldcred, intlabel); if (error) { PROC_UNLOCK(p); crfree(newcred); + crwfree(newcredwrap); goto out; } setsugid(p); crcopy(newcred, oldcred); mac_cred_relabel(newcred, intlabel); - proc_set_cred(p, newcred); + proc_set_cred(p, newcred, newcredwrap); PROC_UNLOCK(p); crfree(oldcred); + crwfree(oldcredwrap); mac_proc_vm_revoke(td); out: Index: sys/security/mac_lomac/mac_lomac.c =================================================================== --- sys/security/mac_lomac/mac_lomac.c +++ sys/security/mac_lomac/mac_lomac.c @@ -2229,6 +2229,7 @@ struct proc *p = td->td_proc; struct mac_lomac_proc *subj = PSLOT(p->p_label); struct ucred *newcred, *oldcred; + struct credwrap *newcredwrap, *oldcredwrap; int dodrop; mtx_lock(&subj->mtx); @@ -2236,6 +2237,7 @@ dodrop = 0; mtx_unlock(&subj->mtx); newcred = crget(); + newcredwrap = crwget(newcred); /* * Prevent a lock order reversal in mac_proc_vm_revoke; * ideally, the other user of subj->mtx wouldn't be holding @@ -2249,14 +2251,17 @@ */ if ((subj->mac_lomac.ml_flags & MAC_LOMAC_FLAG_UPDATE) == 0) { crfree(newcred); + crwfree(newcredwrap); goto out; } oldcred = p->p_ucred; + oldcredwrap = p->p_credwrap; crcopy(newcred, oldcred); crhold(newcred); lomac_copy(&subj->mac_lomac, SLOT(newcred->cr_label)); - proc_set_cred(p, newcred); + proc_set_cred(p, newcred, newcredwrap); crfree(oldcred); + crwfree(oldcredwrap); dodrop = 1; out: mtx_unlock(&subj->mtx); Index: sys/sys/file.h =================================================================== --- sys/sys/file.h +++ sys/sys/file.h @@ -174,7 +174,7 @@ struct file { void *f_data; /* file descriptor specific data */ struct fileops *f_ops; /* File operations */ - struct ucred *f_cred; /* associated credentials. */ + struct credwrap *f_credwrap; /* associated credentials. */ struct vnode *f_vnode; /* NULL or applicable vnode */ short f_type; /* descriptor type */ short f_vnread_flags; /* (f) Sleep lock for f_offset */ @@ -205,6 +205,7 @@ #define f_cdevpriv f_vnun.fvn_cdevpriv #define f_advice f_vnun.fvn_advice +#define f_cred f_credwrap->crw_ucred #define FOFFSET_LOCKED 0x1 #define FOFFSET_LOCK_WAITING 0x2 Index: sys/sys/imgact.h =================================================================== --- sys/sys/imgact.h +++ sys/sys/imgact.h @@ -89,6 +89,7 @@ u_long stack_sz; u_long eff_stack_sz; struct ucred *newcred; /* new credentials if changing */ + struct credwrap *newcredwrap; bool credential_setid; /* true if becoming setid */ bool textset; u_int map_flags; Index: sys/sys/proc.h =================================================================== --- sys/sys/proc.h +++ sys/sys/proc.h @@ -365,6 +365,7 @@ int td_oncpu; /* (t) Which cpu we are on. */ void *td_lkpi_task; /* LinuxKPI task struct pointer */ int td_pmcpend; + struct credwrap *td_credwrap; /* (k) Reference to credentials. */ #ifdef EPOCH_TRACE SLIST_HEAD(, epoch_tracker) td_epochs; #endif @@ -688,6 +689,7 @@ */ LIST_ENTRY(proc) p_orphan; /* (e) List of orphan processes. */ LIST_HEAD(, proc) p_orphans; /* (e) Pointer to list of orphans. */ + struct credwrap *p_credwrap; /* (c) Process owner's identity wrapper. */ }; #define p_session p_pgrp->pg_session Index: sys/sys/ucred.h =================================================================== --- sys/sys/ucred.h +++ sys/sys/ucred.h @@ -70,6 +70,11 @@ int cr_agroups; /* Available groups */ gid_t cr_smallgroups[XU_NGROUPS]; /* storage for small groups */ }; + +struct credwrap { + u_int crw_ref; + struct ucred *crw_ucred; +}; #define NOCRED ((struct ucred *)0) /* no credential available */ #define FSCRED ((struct ucred *)-1) /* filesystem credential */ #endif /* _KERNEL || _WANT_UCRED */ @@ -112,10 +117,13 @@ struct ucred *crdup(struct ucred *cr); void crextend(struct ucred *cr, int n); void proc_set_cred_init(struct proc *p, struct ucred *cr); -void proc_set_cred(struct proc *p, struct ucred *cr); +void proc_set_cred(struct proc *p, struct ucred *cr, struct credwrap *crw); void crfree(struct ucred *cr); struct ucred *crget(void); struct ucred *crhold(struct ucred *cr); +struct credwrap *crwget(struct ucred *cr); +struct credwrap *crwhold(struct credwrap *crw); +void crwfree(struct credwrap *crw); void cru2x(struct ucred *cr, struct xucred *xcr); void cru2xt(struct thread *td, struct xucred *xcr); void crsetgroups(struct ucred *cr, int n, gid_t *groups);