From 2cc4f8d05bc430e3670bdacaac03a4ce69c7d1a8 Mon Sep 17 00:00:00 2001
From: Joris GIOVANNANGELI <joris@giovannangeli.fr>
Date: Wed, 31 Jul 2013 14:45:55 +0200
Subject: [PATCH] kernel: change proc_token by per process token to protect
 p_ucred

---
 sys/kern/kern_prot.c | 86 +++++++++++++++++++++++++++++++---------------------
 1 file changed, 52 insertions(+), 34 deletions(-)

diff --git a/sys/kern/kern_prot.c b/sys/kern/kern_prot.c
index a2d5ba2..9c2b58a 100644
--- a/sys/kern/kern_prot.c
+++ b/sys/kern/kern_prot.c
@@ -102,14 +102,20 @@ sys_lwp_gettid(struct lwp_gettid_args *uap)
 /* 
  * Get process group ID; note that POSIX getpgrp takes no parameter 
  *
- * MPSAFE XXX pgrp
+ * MPSAFE
  */
 int
 sys_getpgrp(struct getpgrp_args *uap)
 {
 	struct proc *p = curproc;
 
+	/*
+	 * hold p_token to protect p_pgrp, because p_pgrp can be NULL
+	 * if we race setpgid
+	 */
+	lwkt_gettoken_shared(&p->p_token);
 	uap->sysmsg_result = p->p_pgrp->pg_id;
+	lwkt_reltoken(&p->p_token);
 	return (0);
 }
 
@@ -133,9 +139,11 @@ sys_getpgid(struct getpgid_args *uap)
 		if (pt == NULL)
 			error = ESRCH;
 	}
-	/* XXX MPSAFE on pgrp? */
-	if (error == 0)
+	if (error == 0) {
+		lwkt_gettoken_shared(&pt->p_token);
 		uap->sysmsg_result = pt->p_pgrp->pg_id;
+		lwkt_reltoken(&pt->p_token);
+	}
 	if (pt)
 		PRELE(pt);
 	return (error);
@@ -372,7 +380,7 @@ sys_setuid(struct setuid_args *uap)
 	uid_t uid;
 	int error;
 
-	lwkt_gettoken(&proc_token);
+	lwkt_gettoken(&p->p_token);
 	cr = p->p_ucred;
 
 	/*
@@ -446,7 +454,7 @@ sys_setuid(struct setuid_args *uap)
 	}
 	error = 0;
 done:
-	lwkt_reltoken(&proc_token);
+	lwkt_reltoken(&p->p_token);
 	return (error);
 }
 
@@ -458,7 +466,7 @@ sys_seteuid(struct seteuid_args *uap)
 	uid_t euid;
 	int error;
 
-	lwkt_gettoken(&proc_token);
+	lwkt_gettoken(&p->p_token);
 	cr = p->p_ucred;
 	euid = uap->euid;
 	if (euid != cr->cr_ruid &&		/* allow seteuid(getuid()) */
@@ -476,7 +484,7 @@ sys_seteuid(struct seteuid_args *uap)
 		change_euid(euid);
 		setsugid();
 	}
-	lwkt_reltoken(&proc_token);
+	lwkt_reltoken(&p->p_token);
 	return (0);
 }
 
@@ -488,7 +496,7 @@ sys_setgid(struct setgid_args *uap)
 	gid_t gid;
 	int error;
 
-	lwkt_gettoken(&proc_token);
+	lwkt_gettoken(&p->p_token);
 	cr = p->p_ucred;
 
 	/*
@@ -558,7 +566,7 @@ sys_setgid(struct setgid_args *uap)
 	}
 	error = 0;
 done:
-	lwkt_reltoken(&proc_token);
+	lwkt_reltoken(&p->p_token);
 	return (error);
 }
 
@@ -570,7 +578,7 @@ sys_setegid(struct setegid_args *uap)
 	gid_t egid;
 	int error;
 
-	lwkt_gettoken(&proc_token);
+	lwkt_gettoken(&p->p_token);
 	cr = p->p_ucred;
 	egid = uap->egid;
 	if (egid != cr->cr_rgid &&		/* allow setegid(getgid()) */
@@ -585,7 +593,7 @@ sys_setegid(struct setegid_args *uap)
 	}
 	error = 0;
 done:
-	lwkt_reltoken(&proc_token);
+	lwkt_reltoken(&p->p_token);
 	return (error);
 }
 
@@ -597,7 +605,7 @@ sys_setgroups(struct setgroups_args *uap)
 	u_int ngrp;
 	int error;
 
-	lwkt_gettoken(&proc_token);
+	lwkt_gettoken(&p->p_token);
 	cr = p->p_ucred;
 
 	if ((error = priv_check_cred(cr, PRIV_CRED_SETGROUPS, 0)))
@@ -630,7 +638,7 @@ sys_setgroups(struct setgroups_args *uap)
 	setsugid();
 	error = 0;
 done:
-	lwkt_reltoken(&proc_token);
+	lwkt_reltoken(&p->p_token);
 	return (error);
 }
 
@@ -642,7 +650,7 @@ sys_setreuid(struct setreuid_args *uap)
 	uid_t ruid, euid;
 	int error;
 
-	lwkt_gettoken(&proc_token);
+	lwkt_gettoken(&p->p_token);
 	cr = p->p_ucred;
 
 	ruid = uap->ruid;
@@ -670,7 +678,7 @@ sys_setreuid(struct setreuid_args *uap)
 	}
 	error = 0;
 done:
-	lwkt_reltoken(&proc_token);
+	lwkt_reltoken(&p->p_token);
 	return (error);
 }
 
@@ -682,7 +690,7 @@ sys_setregid(struct setregid_args *uap)
 	gid_t rgid, egid;
 	int error;
 
-	lwkt_gettoken(&proc_token);
+	lwkt_gettoken(&p->p_token);
 	cr = p->p_ucred;
 
 	rgid = uap->rgid;
@@ -712,7 +720,7 @@ sys_setregid(struct setregid_args *uap)
 	}
 	error = 0;
 done:
-	lwkt_reltoken(&proc_token);
+	lwkt_reltoken(&p->p_token);
 	return (error);
 }
 
@@ -728,7 +736,7 @@ sys_setresuid(struct setresuid_args *uap)
 	uid_t ruid, euid, suid;
 	int error;
 
-	lwkt_gettoken(&proc_token);
+	lwkt_gettoken(&p->p_token);
 	cr = p->p_ucred;
 
 	ruid = uap->ruid;
@@ -758,7 +766,7 @@ sys_setresuid(struct setresuid_args *uap)
 	}
 	error = 0;
 done:
-	lwkt_reltoken(&proc_token);
+	lwkt_reltoken(&p->p_token);
 	return (error);
 }
 
@@ -774,7 +782,7 @@ sys_setresgid(struct setresgid_args *uap)
 	gid_t rgid, egid, sgid;
 	int error;
 
-	lwkt_gettoken(&proc_token);
+	lwkt_gettoken(&p->p_token);
 	cr = p->p_ucred;
 	rgid = uap->rgid;
 	egid = uap->egid;
@@ -806,7 +814,7 @@ sys_setresgid(struct setresgid_args *uap)
 	}
 	error = 0;
 done:
-	lwkt_reltoken(&proc_token);
+	lwkt_reltoken(&p->p_token);
 	return (error);
 }
 
@@ -816,9 +824,11 @@ sys_getresuid(struct getresuid_args *uap)
 	struct proc *p = curproc;
 	struct ucred *cr;
 	int error1 = 0, error2 = 0, error3 = 0;
+	
+	lwkt_gettoken_shared(&p->p_token);
+	cr = crhold(p->p_ucred);
+	lwkt_reltoken(&p->p_token);
 
-	lwkt_gettoken(&proc_token);
-	cr = p->p_ucred;
 	if (uap->ruid)
 		error1 = copyout((caddr_t)&cr->cr_ruid,
 		    (caddr_t)uap->ruid, sizeof(cr->cr_ruid));
@@ -828,7 +838,7 @@ sys_getresuid(struct getresuid_args *uap)
 	if (uap->suid)
 		error3 = copyout((caddr_t)&cr->cr_svuid,
 		    (caddr_t)uap->suid, sizeof(cr->cr_svuid));
-	lwkt_reltoken(&proc_token);
+	crfree(cr);
 	return error1 ? error1 : (error2 ? error2 : error3);
 }
 
@@ -839,9 +849,14 @@ int
 sys_getresgid(struct getresgid_args *uap)
 {
 	struct ucred *cr;
+	struct proc *p = curproc;
 	int error1 = 0, error2 = 0, error3 = 0;
 
-	cr = curthread->td_ucred;
+	lwkt_gettoken_shared(&p->p_token);
+	cr = p->p_ucred;
+	crhold(cr);
+	lwkt_reltoken(&p->p_token);
+
 	if (uap->rgid)
 		error1 = copyout(&cr->cr_rgid, uap->rgid,
 				 sizeof(cr->cr_rgid));
@@ -851,6 +866,7 @@ sys_getresgid(struct getresgid_args *uap)
 	if (uap->sgid)
 		error3 = copyout(&cr->cr_svgid, uap->sgid,
 				 sizeof(cr->cr_svgid));
+	crfree(cr);
 	return error1 ? error1 : (error2 ? error2 : error3);
 }
 
@@ -1162,9 +1178,9 @@ sys_getlogin(struct getlogin_args *uap)
 	if (uap->namelen > MAXLOGNAME)		/* namelen is unsigned */
 		uap->namelen = MAXLOGNAME;
 	bzero(buf, sizeof(buf));
-	lwkt_gettoken(&proc_token);
+	lwkt_gettoken_shared(&p->p_token);
 	bcopy(p->p_pgrp->pg_session->s_login, buf, uap->namelen);
-	lwkt_reltoken(&proc_token);
+	lwkt_reltoken(&p->p_token);
 
 	error = copyout(buf, uap->namebuf, uap->namelen);
 	return (error);
@@ -1176,26 +1192,26 @@ sys_getlogin(struct getlogin_args *uap)
 int
 sys_setlogin(struct setlogin_args *uap)
 {
-	struct thread *td = curthread;
-	struct proc *p;
+	struct proc *p = curproc;
 	struct ucred *cred;
 	char buf[MAXLOGNAME];
 	int error;
 
-	cred = td->td_ucred;
-	p = td->td_proc;
+	lwkt_gettoken(&p->p_token);
+	cred = p->p_ucred;
 
 	if ((error = priv_check_cred(cred, PRIV_PROC_SETLOGIN, 0)))
-		return (error);
+		goto done;
 	bzero(buf, sizeof(buf));
+
 	error = copyinstr(uap->namebuf, buf, sizeof(buf), NULL);
 	if (error == ENAMETOOLONG)
 		error = EINVAL;
 	if (error == 0) {
-		lwkt_gettoken(&proc_token);
 		memcpy(p->p_pgrp->pg_session->s_login, buf, sizeof(buf));
-		lwkt_reltoken(&proc_token);
 	}
+done:
+	lwkt_reltoken(&p->p_token);
 	return (error);
 }
 
@@ -1235,6 +1251,8 @@ change_euid(uid_t euid)
  *
  * The per-uid process count for this process is transfered from
  * the old uid to the new uid.
+ *
+ * Requires curproc->p_token to be held.
  */
 struct ucred *
 change_ruid(uid_t ruid)
-- 
1.8.3.4

