xref: /onnv-gate/usr/src/uts/common/syscall/uid.c (revision 12273:63678502e95e)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
54321Scasper  * Common Development and Distribution License (the "License").
64321Scasper  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*12273SCasper.Dik@Sun.COM  * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
230Sstevel@tonic-gate  */
240Sstevel@tonic-gate 
250Sstevel@tonic-gate /*
260Sstevel@tonic-gate  * 	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T
270Sstevel@tonic-gate  */
280Sstevel@tonic-gate 
290Sstevel@tonic-gate #include <sys/param.h>
300Sstevel@tonic-gate #include <sys/types.h>
310Sstevel@tonic-gate #include <sys/sysmacros.h>
320Sstevel@tonic-gate #include <sys/systm.h>
330Sstevel@tonic-gate #include <sys/tuneable.h>
340Sstevel@tonic-gate #include <sys/cred_impl.h>
350Sstevel@tonic-gate #include <sys/errno.h>
360Sstevel@tonic-gate #include <sys/proc.h>
370Sstevel@tonic-gate #include <sys/signal.h>
380Sstevel@tonic-gate #include <sys/debug.h>
390Sstevel@tonic-gate #include <sys/policy.h>
400Sstevel@tonic-gate #include <sys/zone.h>
414321Scasper #include <sys/sid.h>
420Sstevel@tonic-gate 
430Sstevel@tonic-gate int
setuid(uid_t uid)440Sstevel@tonic-gate setuid(uid_t uid)
450Sstevel@tonic-gate {
464321Scasper 	proc_t *p;
470Sstevel@tonic-gate 	int error;
480Sstevel@tonic-gate 	int do_nocd = 0;
490Sstevel@tonic-gate 	int uidchge = 0;
500Sstevel@tonic-gate 	cred_t	*cr, *newcr;
510Sstevel@tonic-gate 	uid_t oldruid = uid;
520Sstevel@tonic-gate 	zoneid_t zoneid = getzoneid();
534321Scasper 	ksid_t ksid, *ksp;
545771Sjp151216 	zone_t	*zone = crgetzone(CRED());
550Sstevel@tonic-gate 
565771Sjp151216 	if (!VALID_UID(uid, zone))
570Sstevel@tonic-gate 		return (set_errno(EINVAL));
580Sstevel@tonic-gate 
594321Scasper 	if (uid > MAXUID) {
605771Sjp151216 		if (ksid_lookupbyuid(zone, uid, &ksid) != 0)
614321Scasper 			return (set_errno(EINVAL));
624321Scasper 		ksp = &ksid;
634321Scasper 	} else {
644321Scasper 		ksp = NULL;
654321Scasper 	}
660Sstevel@tonic-gate 	/*
670Sstevel@tonic-gate 	 * Need to pre-allocate the new cred structure before grabbing
686134Scasper 	 * the p_crlock mutex.  We can't hold on to the p_crlock for most
696134Scasper 	 * if this though, now that we allow kernel upcalls from the
706134Scasper 	 * policy routines.
710Sstevel@tonic-gate 	 */
724321Scasper 	newcr = cralloc_ksid();
730Sstevel@tonic-gate 
740Sstevel@tonic-gate 	p = ttoproc(curthread);
750Sstevel@tonic-gate 
760Sstevel@tonic-gate retry:
770Sstevel@tonic-gate 	mutex_enter(&p->p_crlock);
786134Scasper retry_locked:
790Sstevel@tonic-gate 	cr = p->p_cred;
806134Scasper 	crhold(cr);
816134Scasper 	mutex_exit(&p->p_crlock);
820Sstevel@tonic-gate 
830Sstevel@tonic-gate 	if ((uid == cr->cr_ruid || uid == cr->cr_suid) &&
840Sstevel@tonic-gate 	    secpolicy_allow_setid(cr, uid, B_TRUE) != 0) {
856134Scasper 		mutex_enter(&p->p_crlock);
866134Scasper 		crfree(cr);
876134Scasper 		if (cr != p->p_cred)
886134Scasper 			goto retry_locked;
890Sstevel@tonic-gate 		error = 0;
900Sstevel@tonic-gate 		crcopy_to(cr, newcr);
910Sstevel@tonic-gate 		p->p_cred = newcr;
920Sstevel@tonic-gate 		newcr->cr_uid = uid;
934321Scasper 		crsetsid(newcr, ksp, KSID_USER);
946134Scasper 		mutex_exit(&p->p_crlock);
950Sstevel@tonic-gate 	} else if ((error = secpolicy_allow_setid(cr, uid, B_FALSE)) == 0) {
966134Scasper 		mutex_enter(&p->p_crlock);
976134Scasper 		crfree(cr);
986134Scasper 		if (cr != p->p_cred)
996134Scasper 			goto retry_locked;
1000Sstevel@tonic-gate 		if (!uidchge && uid != cr->cr_ruid) {
1010Sstevel@tonic-gate 			/*
1020Sstevel@tonic-gate 			 * The ruid of the process is going to change. In order
1030Sstevel@tonic-gate 			 * to avoid a race condition involving the
1040Sstevel@tonic-gate 			 * process-count associated with the newly given ruid,
1050Sstevel@tonic-gate 			 * we increment the count before assigning the
1060Sstevel@tonic-gate 			 * credential to the process.
1070Sstevel@tonic-gate 			 * To do that, we'll have to take pidlock, so we first
1080Sstevel@tonic-gate 			 * release p_crlock.
1090Sstevel@tonic-gate 			 */
1100Sstevel@tonic-gate 			mutex_exit(&p->p_crlock);
1110Sstevel@tonic-gate 			uidchge = 1;
1120Sstevel@tonic-gate 			mutex_enter(&pidlock);
1130Sstevel@tonic-gate 			upcount_inc(uid, zoneid);
1140Sstevel@tonic-gate 			mutex_exit(&pidlock);
1150Sstevel@tonic-gate 			/*
1160Sstevel@tonic-gate 			 * As we released p_crlock we can't rely on the cr
1170Sstevel@tonic-gate 			 * we read. So retry the whole thing.
1180Sstevel@tonic-gate 			 */
1190Sstevel@tonic-gate 			goto retry;
1200Sstevel@tonic-gate 		}
1210Sstevel@tonic-gate 		/*
1220Sstevel@tonic-gate 		 * A privileged process that gives up its privilege
1230Sstevel@tonic-gate 		 * must be marked to produce no core dump.
1240Sstevel@tonic-gate 		 */
1250Sstevel@tonic-gate 		if (cr->cr_uid != uid ||
1260Sstevel@tonic-gate 		    cr->cr_ruid != uid ||
1270Sstevel@tonic-gate 		    cr->cr_suid != uid)
1280Sstevel@tonic-gate 			do_nocd = 1;
1290Sstevel@tonic-gate 		oldruid = cr->cr_ruid;
1300Sstevel@tonic-gate 		crcopy_to(cr, newcr);
1310Sstevel@tonic-gate 		p->p_cred = newcr;
1320Sstevel@tonic-gate 		newcr->cr_ruid = uid;
1330Sstevel@tonic-gate 		newcr->cr_suid = uid;
1340Sstevel@tonic-gate 		newcr->cr_uid = uid;
135*12273SCasper.Dik@Sun.COM 
136*12273SCasper.Dik@Sun.COM 		/* Remove the PRIV_PFEXEC, we changed the real uid. */
137*12273SCasper.Dik@Sun.COM 		if (uidchge)
138*12273SCasper.Dik@Sun.COM 			CR_FLAGS(newcr) &= ~PRIV_PFEXEC;
139*12273SCasper.Dik@Sun.COM 
1404321Scasper 		crsetsid(newcr, ksp, KSID_USER);
1419799SCasper.Dik@Sun.COM 
1429799SCasper.Dik@Sun.COM 		priv_reset_PA(newcr, B_TRUE);
1439799SCasper.Dik@Sun.COM 
1440Sstevel@tonic-gate 		ASSERT(uid != oldruid ? uidchge : 1);
1456134Scasper 		mutex_exit(&p->p_crlock);
1464321Scasper 	} else {
1470Sstevel@tonic-gate 		crfree(newcr);
1486134Scasper 		crfree(cr);
1494321Scasper 		if (ksp != NULL)
1504321Scasper 			ksid_rele(ksp);
1514321Scasper 	}
1520Sstevel@tonic-gate 
1530Sstevel@tonic-gate 	/*
1540Sstevel@tonic-gate 	 * We decrement the number of processes associated with the oldruid
1550Sstevel@tonic-gate 	 * to match the increment above, even if the ruid of the process
1560Sstevel@tonic-gate 	 * did not change or an error occurred (oldruid == uid).
1570Sstevel@tonic-gate 	 */
1580Sstevel@tonic-gate 	if (uidchge) {
1590Sstevel@tonic-gate 		mutex_enter(&pidlock);
1600Sstevel@tonic-gate 		upcount_dec(oldruid, zoneid);
1610Sstevel@tonic-gate 		mutex_exit(&pidlock);
1620Sstevel@tonic-gate 	}
1630Sstevel@tonic-gate 
1640Sstevel@tonic-gate 	if (error == 0) {
1650Sstevel@tonic-gate 		if (do_nocd) {
1660Sstevel@tonic-gate 			mutex_enter(&p->p_lock);
1670Sstevel@tonic-gate 			p->p_flag |= SNOCD;
1680Sstevel@tonic-gate 			mutex_exit(&p->p_lock);
1690Sstevel@tonic-gate 		}
1700Sstevel@tonic-gate 		crset(p, newcr);	/* broadcast to process threads */
1710Sstevel@tonic-gate 		return (0);
1720Sstevel@tonic-gate 	}
1730Sstevel@tonic-gate 	return (set_errno(error));
1740Sstevel@tonic-gate }
1750Sstevel@tonic-gate 
1760Sstevel@tonic-gate int64_t
getuid(void)1770Sstevel@tonic-gate getuid(void)
1780Sstevel@tonic-gate {
1790Sstevel@tonic-gate 	rval_t	r;
1800Sstevel@tonic-gate 	cred_t *cr;
1810Sstevel@tonic-gate 
1820Sstevel@tonic-gate 	cr = curthread->t_cred;
1830Sstevel@tonic-gate 	r.r_val1 = cr->cr_ruid;
1840Sstevel@tonic-gate 	r.r_val2 = cr->cr_uid;
1850Sstevel@tonic-gate 	return (r.r_vals);
1860Sstevel@tonic-gate }
1870Sstevel@tonic-gate 
1880Sstevel@tonic-gate int
seteuid(uid_t uid)1890Sstevel@tonic-gate seteuid(uid_t uid)
1900Sstevel@tonic-gate {
1914321Scasper 	proc_t *p;
1920Sstevel@tonic-gate 	int error = EPERM;
1930Sstevel@tonic-gate 	int do_nocd = 0;
1940Sstevel@tonic-gate 	cred_t	*cr, *newcr;
1954321Scasper 	ksid_t ksid, *ksp;
1965771Sjp151216 	zone_t	*zone = crgetzone(CRED());
1970Sstevel@tonic-gate 
1985771Sjp151216 	if (!VALID_UID(uid, zone))
1990Sstevel@tonic-gate 		return (set_errno(EINVAL));
2000Sstevel@tonic-gate 
2014321Scasper 	if (uid > MAXUID) {
2025771Sjp151216 		if (ksid_lookupbyuid(zone, uid, &ksid) != 0)
2034321Scasper 			return (set_errno(EINVAL));
2044321Scasper 		ksp = &ksid;
2054321Scasper 	} else {
2064321Scasper 		ksp = NULL;
2074321Scasper 	}
2084321Scasper 
2090Sstevel@tonic-gate 	/*
2100Sstevel@tonic-gate 	 * Need to pre-allocate the new cred structure before grabbing
2110Sstevel@tonic-gate 	 * the p_crlock mutex.
2120Sstevel@tonic-gate 	 */
2134321Scasper 	newcr = cralloc_ksid();
2140Sstevel@tonic-gate 	p = ttoproc(curthread);
2150Sstevel@tonic-gate 	mutex_enter(&p->p_crlock);
2166134Scasper retry:
2176134Scasper 	crhold(cr = p->p_cred);
2186134Scasper 	mutex_exit(&p->p_crlock);
2190Sstevel@tonic-gate 
2200Sstevel@tonic-gate 	if (uid == cr->cr_ruid || uid == cr->cr_uid || uid == cr->cr_suid ||
2210Sstevel@tonic-gate 	    (error = secpolicy_allow_setid(cr, uid, B_FALSE)) == 0) {
2220Sstevel@tonic-gate 		/*
2230Sstevel@tonic-gate 		 * A privileged process that makes itself look like a
2240Sstevel@tonic-gate 		 * set-uid process must be marked to produce no core dump,
2250Sstevel@tonic-gate 		 * if the effective uid did changed.
2260Sstevel@tonic-gate 		 */
2276134Scasper 		mutex_enter(&p->p_crlock);
2286134Scasper 		crfree(cr);
2296134Scasper 		if (cr != p->p_cred)
2306134Scasper 			goto retry;
2310Sstevel@tonic-gate 		if (cr->cr_uid != uid && error == 0)
2320Sstevel@tonic-gate 			do_nocd = 1;
2330Sstevel@tonic-gate 		error = 0;
2340Sstevel@tonic-gate 		crcopy_to(cr, newcr);
2350Sstevel@tonic-gate 		p->p_cred = newcr;
2360Sstevel@tonic-gate 		newcr->cr_uid = uid;
2374321Scasper 		crsetsid(newcr, ksp, KSID_USER);
2389799SCasper.Dik@Sun.COM 		priv_reset_PA(newcr, B_FALSE);
2396134Scasper 		mutex_exit(&p->p_crlock);
2400Sstevel@tonic-gate 		if (do_nocd) {
2410Sstevel@tonic-gate 			mutex_enter(&p->p_lock);
2420Sstevel@tonic-gate 			p->p_flag |= SNOCD;
2430Sstevel@tonic-gate 			mutex_exit(&p->p_lock);
2440Sstevel@tonic-gate 		}
2450Sstevel@tonic-gate 		crset(p, newcr);	/* broadcast to process threads */
2460Sstevel@tonic-gate 		return (0);
2470Sstevel@tonic-gate 	}
2486134Scasper 
2496134Scasper 	crfree(newcr);
2506134Scasper 	crfree(cr);
2516134Scasper 	if (ksp != NULL)
2526134Scasper 		ksid_rele(ksp);
2530Sstevel@tonic-gate 	return (set_errno(error));
2540Sstevel@tonic-gate }
2550Sstevel@tonic-gate 
2560Sstevel@tonic-gate /*
2570Sstevel@tonic-gate  * Buy-back from SunOS 4.x
2580Sstevel@tonic-gate  *
2590Sstevel@tonic-gate  * Like setuid() and seteuid() combined -except- that non-root users
2600Sstevel@tonic-gate  * can change cr_ruid to cr_uid, and the semantics of cr_suid are
2610Sstevel@tonic-gate  * subtly different.
2620Sstevel@tonic-gate  */
2630Sstevel@tonic-gate int
setreuid(uid_t ruid,uid_t euid)2640Sstevel@tonic-gate setreuid(uid_t ruid, uid_t euid)
2650Sstevel@tonic-gate {
2660Sstevel@tonic-gate 	proc_t *p;
2670Sstevel@tonic-gate 	int error = 0;
2680Sstevel@tonic-gate 	int do_nocd = 0;
2690Sstevel@tonic-gate 	int uidchge = 0;
2700Sstevel@tonic-gate 	uid_t oldruid = ruid;
2710Sstevel@tonic-gate 	cred_t *cr, *newcr;
2720Sstevel@tonic-gate 	zoneid_t zoneid = getzoneid();
2734321Scasper 	ksid_t ksid, *ksp;
2745771Sjp151216 	zone_t	*zone = crgetzone(CRED());
2750Sstevel@tonic-gate 
2765771Sjp151216 	if ((ruid != -1 && !VALID_UID(ruid, zone)) ||
2775771Sjp151216 	    (euid != -1 && !VALID_UID(euid, zone)))
2780Sstevel@tonic-gate 		return (set_errno(EINVAL));
2790Sstevel@tonic-gate 
2804321Scasper 	if (euid != -1 && euid > MAXUID) {
2815771Sjp151216 		if (ksid_lookupbyuid(zone, euid, &ksid) != 0)
2824321Scasper 			return (set_errno(EINVAL));
2834321Scasper 		ksp = &ksid;
2844321Scasper 	} else {
2854321Scasper 		ksp = NULL;
2864321Scasper 	}
2874321Scasper 
2880Sstevel@tonic-gate 	/*
2890Sstevel@tonic-gate 	 * Need to pre-allocate the new cred structure before grabbing
2900Sstevel@tonic-gate 	 * the p_crlock mutex.
2910Sstevel@tonic-gate 	 */
2924321Scasper 	newcr = cralloc_ksid();
2930Sstevel@tonic-gate 
2940Sstevel@tonic-gate 	p = ttoproc(curthread);
2950Sstevel@tonic-gate 
2960Sstevel@tonic-gate retry:
2970Sstevel@tonic-gate 	mutex_enter(&p->p_crlock);
2986134Scasper retry_locked:
2996134Scasper 	crhold(cr = p->p_cred);
3006134Scasper 	mutex_exit(&p->p_crlock);
3010Sstevel@tonic-gate 
3020Sstevel@tonic-gate 	if (ruid != -1 && ruid != cr->cr_ruid && ruid != cr->cr_uid &&
3030Sstevel@tonic-gate 	    secpolicy_allow_setid(cr, ruid, B_FALSE) != 0) {
3046134Scasper 		mutex_enter(&p->p_crlock);
3056134Scasper 		crfree(cr);
3066134Scasper 		if (cr != p->p_cred)
3076134Scasper 			goto retry_locked;
3080Sstevel@tonic-gate 		error = EPERM;
3090Sstevel@tonic-gate 	} else if (euid != -1 &&
3100Sstevel@tonic-gate 	    euid != cr->cr_ruid && euid != cr->cr_uid &&
3110Sstevel@tonic-gate 	    euid != cr->cr_suid && secpolicy_allow_setid(cr, euid, B_FALSE)) {
3126134Scasper 		mutex_enter(&p->p_crlock);
3136134Scasper 		crfree(cr);
3146134Scasper 		if (cr != p->p_cred)
3156134Scasper 			goto retry_locked;
3160Sstevel@tonic-gate 		error = EPERM;
3170Sstevel@tonic-gate 	} else {
3186134Scasper 		mutex_enter(&p->p_crlock);
3196134Scasper 		crfree(cr);
3206134Scasper 		if (cr != p->p_cred)
3216134Scasper 			goto retry_locked;
3220Sstevel@tonic-gate 		if (!uidchge && ruid != -1 && cr->cr_ruid != ruid) {
3230Sstevel@tonic-gate 			/*
3240Sstevel@tonic-gate 			 * The ruid of the process is going to change. In order
3250Sstevel@tonic-gate 			 * to avoid a race condition involving the
3260Sstevel@tonic-gate 			 * process-count associated with the newly given ruid,
3270Sstevel@tonic-gate 			 * we increment the count before assigning the
3280Sstevel@tonic-gate 			 * credential to the process.
3290Sstevel@tonic-gate 			 * To do that, we'll have to take pidlock, so we first
3300Sstevel@tonic-gate 			 * release p_crlock.
3310Sstevel@tonic-gate 			 */
3320Sstevel@tonic-gate 			mutex_exit(&p->p_crlock);
3330Sstevel@tonic-gate 			uidchge = 1;
3340Sstevel@tonic-gate 			mutex_enter(&pidlock);
3350Sstevel@tonic-gate 			upcount_inc(ruid, zoneid);
3360Sstevel@tonic-gate 			mutex_exit(&pidlock);
3370Sstevel@tonic-gate 			/*
3380Sstevel@tonic-gate 			 * As we released p_crlock we can't rely on the cr
3390Sstevel@tonic-gate 			 * we read. So retry the whole thing.
3400Sstevel@tonic-gate 			 */
3410Sstevel@tonic-gate 			goto retry;
3420Sstevel@tonic-gate 		}
3430Sstevel@tonic-gate 		crhold(cr);
3440Sstevel@tonic-gate 		crcopy_to(cr, newcr);
3450Sstevel@tonic-gate 		p->p_cred = newcr;
3460Sstevel@tonic-gate 
3474321Scasper 		if (euid != -1) {
3480Sstevel@tonic-gate 			newcr->cr_uid = euid;
3494321Scasper 			crsetsid(newcr, ksp, KSID_USER);
3504321Scasper 		}
3510Sstevel@tonic-gate 		if (ruid != -1) {
352*12273SCasper.Dik@Sun.COM 			/* Remove the PRIV_PFEXEC, we changed the real uid. */
353*12273SCasper.Dik@Sun.COM 			if (uidchge)
354*12273SCasper.Dik@Sun.COM 				CR_FLAGS(newcr) &= ~PRIV_PFEXEC;
355*12273SCasper.Dik@Sun.COM 
3560Sstevel@tonic-gate 			oldruid = newcr->cr_ruid;
3570Sstevel@tonic-gate 			newcr->cr_ruid = ruid;
3580Sstevel@tonic-gate 			ASSERT(ruid != oldruid ? uidchge : 1);
3590Sstevel@tonic-gate 		}
3600Sstevel@tonic-gate 		/*
3610Sstevel@tonic-gate 		 * "If the real uid is being changed, or the effective uid is
3620Sstevel@tonic-gate 		 * being changed to a value not equal to the real uid, the
3630Sstevel@tonic-gate 		 * saved uid is set to the new effective uid."
3640Sstevel@tonic-gate 		 */
3650Sstevel@tonic-gate 		if (ruid != -1 ||
3660Sstevel@tonic-gate 		    (euid != -1 && newcr->cr_uid != newcr->cr_ruid))
3670Sstevel@tonic-gate 			newcr->cr_suid = newcr->cr_uid;
3680Sstevel@tonic-gate 		/*
3690Sstevel@tonic-gate 		 * A process that gives up its privilege
3700Sstevel@tonic-gate 		 * must be marked to produce no core dump.
3710Sstevel@tonic-gate 		 */
3720Sstevel@tonic-gate 		if ((cr->cr_uid != newcr->cr_uid ||
3730Sstevel@tonic-gate 		    cr->cr_ruid != newcr->cr_ruid ||
3740Sstevel@tonic-gate 		    cr->cr_suid != newcr->cr_suid))
3750Sstevel@tonic-gate 			do_nocd = 1;
3760Sstevel@tonic-gate 
3779799SCasper.Dik@Sun.COM 		priv_reset_PA(newcr, ruid != -1 && euid != -1 && ruid == euid);
3780Sstevel@tonic-gate 		crfree(cr);
3790Sstevel@tonic-gate 	}
3800Sstevel@tonic-gate 	mutex_exit(&p->p_crlock);
3810Sstevel@tonic-gate 
3820Sstevel@tonic-gate 	/*
3830Sstevel@tonic-gate 	 * We decrement the number of processes associated with the oldruid
3840Sstevel@tonic-gate 	 * to match the increment above, even if the ruid of the process
3850Sstevel@tonic-gate 	 * did not change or an error occurred (oldruid == uid).
3860Sstevel@tonic-gate 	 */
3870Sstevel@tonic-gate 	if (uidchge) {
3880Sstevel@tonic-gate 		ASSERT(oldruid != -1 && ruid != -1);
3890Sstevel@tonic-gate 		mutex_enter(&pidlock);
3900Sstevel@tonic-gate 		upcount_dec(oldruid, zoneid);
3910Sstevel@tonic-gate 		mutex_exit(&pidlock);
3920Sstevel@tonic-gate 	}
3930Sstevel@tonic-gate 
3940Sstevel@tonic-gate 	if (error == 0) {
3950Sstevel@tonic-gate 		if (do_nocd) {
3960Sstevel@tonic-gate 			mutex_enter(&p->p_lock);
3970Sstevel@tonic-gate 			p->p_flag |= SNOCD;
3980Sstevel@tonic-gate 			mutex_exit(&p->p_lock);
3990Sstevel@tonic-gate 		}
4000Sstevel@tonic-gate 		crset(p, newcr);	/* broadcast to process threads */
4010Sstevel@tonic-gate 		return (0);
4020Sstevel@tonic-gate 	}
4030Sstevel@tonic-gate 	crfree(newcr);
4044321Scasper 	if (ksp != NULL)
4054321Scasper 		ksid_rele(ksp);
4060Sstevel@tonic-gate 	return (set_errno(error));
4070Sstevel@tonic-gate }
408