diff --git a/sys/kern/kern_prot.c b/sys/kern/kern_prot.c
index 578770ec3fff..c4d6433a7478 100644
--- a/sys/kern/kern_prot.c
+++ b/sys/kern/kern_prot.c
@@ -526,9 +526,10 @@ setuid(struct thread *td, struct setuid_args *uap)
 	uid_t uid;
 	int error;
 
-	uid = uap->uid;
 	mtx_lock(&Giant);
-	error = 0;
+	uid = uap->uid;
+	newcred = crget();
+	PROC_LOCK(p);
 	oldcred = p->p_ucred;
 
 	/*
@@ -555,10 +556,14 @@ setuid(struct thread *td, struct setuid_args *uap)
 #ifdef POSIX_APPENDIX_B_4_2_2	/* Use BSD-compat clause from B.4.2.2 */
 	    uid != oldcred->cr_uid &&		/* allow setuid(geteuid()) */
 #endif
-	    (error = suser_cred(oldcred, PRISON_ROOT)) != 0)
-		goto done2;
+	    (error = suser_cred(oldcred, PRISON_ROOT)) != 0) {
+		PROC_UNLOCK(p);
+		crfree(newcred);
+		mtx_unlock(&Giant);
+		return (error);
+	}
 
-	newcred = crdup(oldcred);
+	crcopy(newcred, oldcred);
 #ifdef _POSIX_SAVED_IDS
 	/*
 	 * Do we have "appropriate privileges" (are we root or uid == euid)
@@ -600,10 +605,10 @@ setuid(struct thread *td, struct setuid_args *uap)
 		setsugid(p);
 	}
 	p->p_ucred = newcred;
+	PROC_UNLOCK(p);
 	crfree(oldcred);
-done2:
 	mtx_unlock(&Giant);
-	return (error);
+	return (0);
 }
 
 #ifndef _SYS_SYSPROTO_H_
@@ -625,26 +630,31 @@ seteuid(struct thread *td, struct seteuid_args *uap)
 
 	euid = uap->euid;
 	mtx_lock(&Giant);
-	error = 0;
+	newcred = crget();
+	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)
-		goto done2;
+	    (error = suser_cred(oldcred, PRISON_ROOT)) != 0) {
+		PROC_UNLOCK(p);
+		crfree(newcred);
+		mtx_unlock(&Giant);
+		return (error);
+	}
 	/*
 	 * Everything's okay, do it.  Copy credentials so other references do
 	 * not see our changes.
 	 */
-	newcred = crdup(oldcred);
+	crcopy(newcred, oldcred);
 	if (oldcred->cr_uid != euid) {
 		change_euid(newcred, euid);
 		setsugid(p);
 	}
 	p->p_ucred = newcred;
+	PROC_UNLOCK(p);
 	crfree(oldcred);
-done2:
 	mtx_unlock(&Giant);
-	return (error);
+	return (0);
 }
 
 #ifndef _SYS_SYSPROTO_H_
@@ -666,7 +676,8 @@ setgid(struct thread *td, struct setgid_args *uap)
 
 	gid = uap->gid;
 	mtx_lock(&Giant);
-	error = 0;
+	newcred = crget();
+	PROC_LOCK(p);
 	oldcred = p->p_ucred;
 
 	/*
@@ -687,10 +698,14 @@ setgid(struct thread *td, struct setgid_args *uap)
 #ifdef POSIX_APPENDIX_B_4_2_2	/* Use BSD-compat clause from B.4.2.2 */
 	    gid != oldcred->cr_groups[0] && /* allow setgid(getegid()) */
 #endif
-	    (error = suser_cred(oldcred, PRISON_ROOT)) != 0)
-		goto done2;
+	    (error = suser_cred(oldcred, PRISON_ROOT)) != 0) {
+		PROC_UNLOCK(p);
+		crfree(newcred);
+		mtx_unlock(&Giant);
+		return (error);
+	}
 
-	newcred = crdup(oldcred);
+	crcopy(newcred, oldcred);
 #ifdef _POSIX_SAVED_IDS
 	/*
 	 * Do we have "appropriate privileges" (are we root or gid == egid)
@@ -731,10 +746,10 @@ setgid(struct thread *td, struct setgid_args *uap)
 		setsugid(p);
 	}
 	p->p_ucred = newcred;
+	PROC_UNLOCK(p);
 	crfree(oldcred);
-done2:
 	mtx_unlock(&Giant);
-	return (error);
+	return (0);
 }
 
 #ifndef _SYS_SYSPROTO_H_
@@ -756,22 +771,27 @@ setegid(struct thread *td, struct setegid_args *uap)
 
 	egid = uap->egid;
 	mtx_lock(&Giant);
-	error = 0;
+	newcred = crget();
+	PROC_LOCK(p);
 	oldcred = p->p_ucred;
 	if (egid != oldcred->cr_rgid &&		/* allow setegid(getgid()) */
 	    egid != oldcred->cr_svgid &&	/* allow setegid(saved gid) */
-	    (error = suser_cred(oldcred, PRISON_ROOT)) != 0)
-		goto done2;
-	newcred = crdup(oldcred);
+	    (error = suser_cred(oldcred, PRISON_ROOT)) != 0) {
+		PROC_UNLOCK(p);
+		crfree(newcred);
+		mtx_unlock(&Giant);
+		return (error);
+	}
+	crcopy(newcred, oldcred);
 	if (oldcred->cr_groups[0] != egid) {
 		change_egid(newcred, egid);
 		setsugid(p);
 	}
 	p->p_ucred = newcred;
+	PROC_UNLOCK(p);
 	crfree(oldcred);
-done2:
 	mtx_unlock(&Giant);
-	return (error);
+	return (0);
 }
 
 #ifndef _SYS_SYSPROTO_H_
@@ -788,24 +808,39 @@ int
 setgroups(struct thread *td, struct setgroups_args *uap)
 {
 	struct proc *p = td->td_proc;
-	struct ucred *newcred, *oldcred;
+	struct ucred *newcred, *tempcred, *oldcred;
 	u_int ngrp;
 	int error;
 
 	ngrp = uap->gidsetsize;
+	if (ngrp > NGROUPS)
+		return (EINVAL);
 	mtx_lock(&Giant);
-	oldcred = p->p_ucred;
-	if ((error = suser_cred(oldcred, PRISON_ROOT)) != 0)
-		goto done2;
-	if (ngrp > NGROUPS) {
-		error = EINVAL;
-		goto done2;
+	tempcred = crget();
+	error = copyin((caddr_t)uap->gidset, (caddr_t)tempcred->cr_groups,
+	    ngrp * sizeof(gid_t));
+	if (error != 0) {
+		crfree(tempcred);
+		mtx_unlock(&Giant);
+		return (error);
 	}
+	newcred = crget();
+	PROC_LOCK(p);
+	oldcred = p->p_ucred;
+	error = suser_cred(oldcred, PRISON_ROOT);
+	if (error) {
+		PROC_UNLOCK(p);
+		crfree(newcred);
+		crfree(tempcred);
+		mtx_unlock(&Giant);
+		return (error);
+	}
+		
 	/*
 	 * XXX A little bit lazy here.  We could test if anything has
 	 * changed before crcopy() and setting P_SUGID.
 	 */
-	newcred = crdup(oldcred);
+	crcopy(newcred, oldcred);
 	if (ngrp < 1) {
 		/*
 		 * setgroups(0, NULL) is a legitimate way of clearing the
@@ -815,19 +850,17 @@ setgroups(struct thread *td, struct setgroups_args *uap)
 		 */
 		newcred->cr_ngroups = 1;
 	} else {
-		if ((error = copyin((caddr_t)uap->gidset,
-		    (caddr_t)newcred->cr_groups, ngrp * sizeof(gid_t)))) {
-			crfree(newcred);
-			goto done2;
-		}
+		bcopy(tempcred->cr_groups, newcred->cr_groups,
+		    ngrp * sizeof(gid_t));
 		newcred->cr_ngroups = ngrp;
 	}
 	setsugid(p);
 	p->p_ucred = newcred;
+	PROC_UNLOCK(p);
+	crfree(tempcred);
 	crfree(oldcred);
-done2:
 	mtx_unlock(&Giant);
-	return (error);
+	return (0);
 }
 
 #ifndef _SYS_SYSPROTO_H_
@@ -851,15 +884,20 @@ setreuid(register struct thread *td, struct setreuid_args *uap)
 	euid = uap->euid;
 	ruid = uap->ruid;
 	mtx_lock(&Giant);
-	error = 0;
+	newcred = crget();
+	PROC_LOCK(p);
 	oldcred = p->p_ucred;
 	if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid &&
 	      ruid != oldcred->cr_svuid) ||
 	     (euid != (uid_t)-1 && euid != oldcred->cr_uid &&
 	      euid != oldcred->cr_ruid && euid != oldcred->cr_svuid)) &&
-	    (error = suser_cred(oldcred, PRISON_ROOT)) != 0)
-		goto done2;
-	newcred = crdup(oldcred);
+	    (error = suser_cred(oldcred, PRISON_ROOT)) != 0) {
+		PROC_UNLOCK(p);
+		crfree(newcred);
+		mtx_unlock(&Giant);
+		return (error);
+	}
+	crcopy(newcred, oldcred);
 	if (euid != (uid_t)-1 && oldcred->cr_uid != euid) {
 		change_euid(newcred, euid);
 		setsugid(p);
@@ -874,10 +912,10 @@ setreuid(register struct thread *td, struct setreuid_args *uap)
 		setsugid(p);
 	}
 	p->p_ucred = newcred;
+	PROC_UNLOCK(p);
 	crfree(oldcred);
-done2:
 	mtx_unlock(&Giant);
-	return (error);
+	return (0);
 }
 
 #ifndef _SYS_SYSPROTO_H_
@@ -901,15 +939,21 @@ setregid(register struct thread *td, struct setregid_args *uap)
 	egid = uap->egid;
 	rgid = uap->rgid;
 	mtx_lock(&Giant);
-	error = 0;
+	newcred = crget();
+	PROC_LOCK(p);
 	oldcred = p->p_ucred;
 	if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid &&
 	    rgid != oldcred->cr_svgid) ||
 	     (egid != (gid_t)-1 && egid != oldcred->cr_groups[0] &&
 	     egid != oldcred->cr_rgid && egid != oldcred->cr_svgid)) &&
-	    (error = suser_cred(oldcred, PRISON_ROOT)) != 0)
-		goto done2;
-	newcred = crdup(oldcred);
+	    (error = suser_cred(oldcred, PRISON_ROOT)) != 0) {
+		PROC_UNLOCK(p);
+		crfree(newcred);
+		mtx_unlock(&Giant);
+		return (error);
+	}
+
+	crcopy(newcred, oldcred);
 	if (egid != (gid_t)-1 && oldcred->cr_groups[0] != egid) {
 		change_egid(newcred, egid);
 		setsugid(p);
@@ -924,10 +968,10 @@ setregid(register struct thread *td, struct setregid_args *uap)
 		setsugid(p);
 	}
 	p->p_ucred = newcred;
+	PROC_UNLOCK(p);
 	crfree(oldcred);
-done2:
 	mtx_unlock(&Giant);
-	return (error);
+	return (0);
 }
 
 /*
@@ -958,6 +1002,8 @@ setresuid(register struct thread *td, struct setresuid_args *uap)
 	ruid = uap->ruid;
 	suid = uap->suid;
 	mtx_lock(&Giant);
+	newcred = crget();
+	PROC_LOCK(p);
 	oldcred = p->p_ucred;
 	if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid &&
 	     ruid != oldcred->cr_svuid &&
@@ -968,9 +1014,14 @@ setresuid(register struct thread *td, struct setresuid_args *uap)
 	     (suid != (uid_t)-1 && suid != oldcred->cr_ruid &&
 	    suid != oldcred->cr_svuid &&
 	      suid != oldcred->cr_uid)) &&
-	    (error = suser_cred(oldcred, PRISON_ROOT)) != 0)
-		goto done2;
-	newcred = crdup(oldcred);
+	    (error = suser_cred(oldcred, PRISON_ROOT)) != 0) {
+		PROC_UNLOCK(p);
+		crfree(newcred);
+		mtx_unlock(&Giant);
+		return (error);
+	}
+
+	crcopy(newcred, oldcred);
 	if (euid != (uid_t)-1 && oldcred->cr_uid != euid) {
 		change_euid(newcred, euid);
 		setsugid(p);
@@ -984,11 +1035,10 @@ setresuid(register struct thread *td, struct setresuid_args *uap)
 		setsugid(p);
 	}
 	p->p_ucred = newcred;
+	PROC_UNLOCK(p);
 	crfree(oldcred);
-	error = 0;
-done2:
 	mtx_unlock(&Giant);
-	return (error);
+	return (0);
 }
 
 /*
@@ -1019,6 +1069,8 @@ setresgid(register struct thread *td, struct setresgid_args *uap)
 	rgid = uap->rgid;
 	sgid = uap->sgid;
 	mtx_lock(&Giant);
+	newcred = crget();
+	PROC_LOCK(p);
 	oldcred = p->p_ucred;
 	if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid &&
 	      rgid != oldcred->cr_svgid &&
@@ -1029,9 +1081,14 @@ setresgid(register struct thread *td, struct setresgid_args *uap)
 	     (sgid != (gid_t)-1 && sgid != oldcred->cr_rgid &&
 	      sgid != oldcred->cr_svgid &&
 	      sgid != oldcred->cr_groups[0])) &&
-	    (error = suser_cred(oldcred, PRISON_ROOT)) != 0)
-		goto done2;
-	newcred = crdup(oldcred);
+	    (error = suser_cred(oldcred, PRISON_ROOT)) != 0) {
+		PROC_UNLOCK(p);
+		crfree(newcred);
+		mtx_unlock(&Giant);
+		return (error);
+	}
+
+	crcopy(newcred, oldcred);
 	if (egid != (gid_t)-1 && oldcred->cr_groups[0] != egid) {
 		change_egid(newcred, egid);
 		setsugid(p);
@@ -1045,11 +1102,10 @@ setresgid(register struct thread *td, struct setresgid_args *uap)
 		setsugid(p);
 	}
 	p->p_ucred = newcred;
+	PROC_UNLOCK(p);
 	crfree(oldcred);
-	error = 0;
-done2:
 	mtx_unlock(&Giant);
-	return (error);
+	return (0);
 }
 
 #ifndef _SYS_SYSPROTO_H_
@@ -1147,27 +1203,27 @@ int
 __setugid(struct thread *td, struct __setugid_args *uap)
 {
 #ifdef REGRESSION
-	int error;
+	struct proc *p;
 
-	mtx_lock(&Giant);
-	error = 0;
+	p = td->td_proc;
 	switch (uap->flag) {
 	case 0:
-		PROC_LOCK(td->td_proc);
-		td->td_proc->p_flag &= ~P_SUGID;
-		PROC_UNLOCK(td->td_proc);
-		break;
+		mtx_lock(&Giant);
+		PROC_LOCK(p);
+		p->p_flag &= ~P_SUGID;
+		PROC_UNLOCK(p);
+		mtx_unlock(&Giant);
+		return (0);
 	case 1:
-		PROC_LOCK(td->td_proc);
-		td->td_proc->p_flag |= P_SUGID;
-		PROC_UNLOCK(td->td_proc);
-		break;
+		mtx_lock(&Giant);
+		PROC_LOCK(p);
+		p->p_flag |= P_SUGID;
+		PROC_UNLOCK(p);
+		mtx_unlock(&Giant);
+		return (0);
 	default:
-		error = EINVAL;
-		break;
+		return (EINVAL);
 	}
-	mtx_unlock(&Giant);
-	return (error);
 #else /* !REGRESSION */
 
 	return (ENOSYS);
@@ -1799,9 +1855,9 @@ setlogin(struct thread *td, struct setlogin_args *uap)
 	int error;
 	char logintmp[MAXLOGNAME];
 
-	mtx_lock(&Giant);
-	if ((error = suser_cred(td->td_ucred, PRISON_ROOT)) != 0)
-		goto done2;
+	error = suser_cred(td->td_ucred, PRISON_ROOT);
+	if (error)
+		return (error);
 	error = copyinstr((caddr_t) uap->namebuf, (caddr_t) logintmp,
 	    sizeof(logintmp), (size_t *)0);
 	if (error == ENAMETOOLONG)
@@ -1814,8 +1870,6 @@ setlogin(struct thread *td, struct setlogin_args *uap)
 		SESS_UNLOCK(p->p_session);
 		PROC_UNLOCK(p);
 	}
-done2:
-	mtx_unlock(&Giant);
 	return (error);
 }