Index: compat/linux/linux_mib.c
===================================================================
RCS file: /home/ncvs/src/sys/compat/linux/linux_mib.c,v
retrieving revision 1.12
diff -u -r1.12 linux_mib.c
--- compat/linux/linux_mib.c	2001/06/15 08:18:24	1.12
+++ compat/linux/linux_mib.c	2001/09/02 16:16:48
@@ -56,7 +56,7 @@
 	char osname[LINUX_MAX_UTSNAME];
 	int error;
 
-	strcpy(osname, linux_get_osname(req->p));
+	linux_get_osname(req->p, osname);
 	error = sysctl_handle_string(oidp, osname, LINUX_MAX_UTSNAME, req);
 	if (error || req->newptr == NULL)
 		return (error);
@@ -77,7 +77,7 @@
 	char osrelease[LINUX_MAX_UTSNAME];
 	int error;
 
-	strcpy(osrelease, linux_get_osrelease(req->p));
+	linux_get_osrelease(req->p, osrelease);
 	error = sysctl_handle_string(oidp, osrelease, LINUX_MAX_UTSNAME, req);
 	if (error || req->newptr == NULL)
 		return (error);
@@ -111,8 +111,11 @@
 	    0, 0, linux_sysctl_oss_version, "I",
 	    "Linux OSS version");
 
+/*
+ * Returns holding the prison mutex if return non-NULL.
+ */
 static struct linux_prison *
-get_prison(struct proc *p)
+linux_get_prison(struct proc *p)
 {
 	register struct prison *pr;
 	register struct linux_prison *lpr;
@@ -122,30 +125,57 @@
 
 	pr = p->p_ucred->cr_prison;
 
+	/*
+	 * Rather than hold the prison mutex during allocation, check to
+	 * see if we need to allocate while holding the mutex, release it,
+	 * allocate, then once we've allocated the memory, check again to
+	 * see if it's still needed, and set if appropriate.  If it's not,
+	 * we release the mutex again to FREE(), and grab it again so as
+	 * to release holding the lock.
+	 */
+	mtx_lock(pr->pr_mtx);
 	if (pr->pr_linux == NULL) {
+		mtx_unlock(pr->pr_mtx);
 		MALLOC(lpr, struct linux_prison *, sizeof *lpr,
 		    M_PRISON, M_WAITOK|M_ZERO);
-		pr->pr_linux = lpr;
+		mtx_lock(pr->pr_mtx);
+		if (pr->pr_linux == NULL) {
+			pr->pr_linux = lpr;
+		} else {
+			mtx_unlock(pr->pr_mtx);
+			FREE(lpr, M_PRISON);
+			mtx_lock(pr->pr_mtx);
+		}
 	}
 
 	return (pr->pr_linux);
 }
 
-char *
-linux_get_osname(p)
+void
+linux_get_osname(p, dst)
 	struct proc *p;
+	char *dst;
 {
 	register struct prison *pr;
 	register struct linux_prison *lpr;
 
-	pr = p->p_ucred->cr_prison;
-	if (pr != NULL && pr->pr_linux != NULL) {
-		lpr = pr->pr_linux;
-		if (lpr->pr_osname[0])
-			return (lpr->pr_osname);
+	if (p->p_ucred->cr_prison == NULL) {
+		bcopy(linux_osname, dst, LINUX_MAX_UTSNAME);
+		return;
 	}
+
+	pr = p->p_ucred->cr_prison;
 
-	return (linux_osname);
+	mtx_lock(pr->pr_mtx);
+	if (pr->pr_linux != NULL) {
+		if (pr->pr_linux->pr_osname[0]) {
+			bcopy(lpr->pr_osname, dst, LINUX_MAX_UTSNAME);
+			mtx_unlock(pr->pr_mtx);
+			return;
+		}
+	}
+	mtx_unlock(pr->pr_mtx);
+	bcopy(linux_osname, dst, LINUX_MAX_UTSNAME);
 }
 
 int
@@ -155,30 +185,41 @@
 {
 	register struct linux_prison *lpr;
 
-	lpr = get_prison(p);
-	if (lpr != NULL)
+	lpr = linux_get_prison(p);
+	if (lpr != NULL) {
 		strcpy(lpr->pr_osname, osname);
-	else
+		mtx_unlock(p->p_ucred->cr_prison->p_mtx);
+	} else {
 		strcpy(linux_osname, osname);
+	}
 
 	return (0);
 }
 
-char *
-linux_get_osrelease(p)
+void
+linux_get_osrelease(p, dst)
 	struct proc *p;
+	chat *dst;
 {
 	register struct prison *pr;
-	register struct linux_prison *lpr;
 
-	pr = p->p_ucred->cr_prison;
-	if (pr != NULL && pr->pr_linux != NULL) {
-		lpr = pr->pr_linux;
-		if (lpr->pr_osrelease[0])
-			return (lpr->pr_osrelease);
+	if (p->p_ucred->cr_prison == NULL) {
+		bcopy(linux_osrelease, dst, LINUX_MAX_UTSNAME);
+		return;
 	}
 
-	return (linux_osrelease);
+	pr = p->p_ucred->cr_prison;
+
+	mtx_lock(pr->pr_mtx);
+	if (pr->pr_linux != NULL) {
+		if (pr->pr_linux->pr_osrelease[0]) {
+			bcopy(pr->pr_linux->pr_osname, dst, LINUX_MAX_UTSNAME);
+			mtx_unlock(pr->pr_mtx);
+			return;
+		}
+	}
+	mtx_unlock(pr->pr_mtx);
+	bcopy(linux_osrelease, dst, LINUX_MAX_UTSNAME);
 }
 
 int
@@ -188,11 +229,13 @@
 {
 	register struct linux_prison *lpr;
 
-	lpr = get_prison(p);
-	if (lpr != NULL)
+	lpr = linux_get_prison(p);
+	if (lpr != NULL) {
 		strcpy(lpr->pr_osrelease, osrelease);
-	else
+		mtx_unlock(p->p_ucred->cr_prison->pr_mtx);
+	} else {
 		strcpy(linux_osrelease, osrelease);
+	}
 
 	return (0);
 }
@@ -202,16 +245,26 @@
 	struct proc *p;
 {
 	register struct prison *pr;
-	register struct linux_prison *lpr;
+	int version;
 
+	if (p->p_ucred->cr_prison == NULL)
+		return (linux_oss_version);
+
 	pr = p->p_ucred->cr_prison;
-	if (pr != NULL && pr->pr_linux != NULL) {
-		lpr = pr->pr_linux;
-		if (lpr->pr_oss_version)
-			return (lpr->pr_oss_version);
+
+	mtx_lock(pr->pr_mtx);
+	if (pr->pr_linux != NULL) {
+		if (pr->pr_linux->pr_oss_version) {
+			version = pr->pr_linux->pr_oss_version;
+		} else {
+			version = linux_oss_version;
+		}
+	} else {
+		version = linux_oss_version;
 	}
+	mtx_unlock(pr->pr_mtx);
 
-	return (linux_oss_version);
+	return (version);
 }
 
 int
@@ -221,11 +274,13 @@
 {
 	register struct linux_prison *lpr;
 
-	lpr = get_prison(p);
-	if (lpr != NULL)
+	lpr = linux_get_prison(p);
+	if (lpr != NULL) {
 		lpr->pr_oss_version = oss_version;
-	else
+		mtx_unlock(p->p_ucred->cr_prison->pr_mtx);
+	} else {
 		linux_oss_version = oss_version;
+	}
 
 	return (0);
 }
Index: fs/procfs/procfs_status.c
===================================================================
RCS file: /home/ncvs/src/sys/fs/procfs/procfs_status.c,v
retrieving revision 1.32
diff -u -r1.32 procfs_status.c
--- fs/procfs/procfs_status.c	2001/07/05 17:10:43	1.32
+++ fs/procfs/procfs_status.c	2001/09/03 03:04:06
@@ -43,10 +43,10 @@
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/exec.h>
+#include <sys/mutex.h>
 #include <sys/jail.h>
 #include <sys/lock.h>
 #include <sys/malloc.h>
-#include <sys/mutex.h>
 #include <sys/proc.h>
 #include <sys/resourcevar.h>
 #include <sys/tty.h>
@@ -166,11 +166,14 @@
 		DOCHECK();
 	}
 
-	if (jailed(p->p_ucred))
+	if (jailed(p->p_ucred)) {
+		mtx_lock(&p->p_ucred->cr_prison->pr_mtx);
 		ps += snprintf(ps, psbuf + sizeof(psbuf) - ps,
 		    " %s", p->p_ucred->cr_prison->pr_host);
-	else
+		mtx_unlock(&p->p_ucred->cr_prison->pr_mtx);
+	} else {
 		ps += snprintf(ps, psbuf + sizeof(psbuf) - ps, " -");
+	}
 	DOCHECK();
 	ps += snprintf(ps, psbuf + sizeof(psbuf) - ps, "\n");
 	DOCHECK();
Index: kern/kern_jail.c
===================================================================
RCS file: /home/ncvs/src/sys/kern/kern_jail.c,v
retrieving revision 1.12
diff -u -r1.12 kern_jail.c
--- kern/kern_jail.c	2001/09/01 03:04:31	1.12
+++ kern/kern_jail.c	2001/09/03 03:01:57
@@ -19,6 +19,7 @@
 #include <sys/malloc.h>
 #include <sys/proc.h>
 #include <sys/jail.h>
+#include <sys/mutex.h>
 #include <sys/socket.h>
 #include <sys/sysctl.h>
 #include <net/if.h>
@@ -82,10 +83,13 @@
 	error = chroot(p, &ca);
 	if (error)
 		goto bail;
+	pr->pr_ref = 1;
+
+	mtx_init(&pr->pr_mtx, "jail lock", MTX_DEF);
 
+	/* XXX not proc locking safe */
 	p->p_ucred = crcopy(p->p_ucred);
 	p->p_ucred->cr_prison = pr;
-	pr->pr_ref = 1;
 	mtx_unlock(&Giant);
 	return (0);
 
@@ -100,19 +104,34 @@
 prison_free(struct prison *pr)
 {
 
+	mtx_lock(&pr->pr_mtx);
 	pr->pr_ref--;
 	if (pr->pr_ref == 0) {
+		mtx_unlock(&pr->pr_mtx);
+		mtx_destroy(&pr->pr_mtx);
 		if (pr->pr_linux != NULL)
 			FREE(pr->pr_linux, M_PRISON);
 		FREE(pr, M_PRISON);
+		return;
 	}
+	mtx_unlock(&pr->pr_mtx);
+	return;
 }
 
 void
 prison_hold(struct prison *pr)
 {
 
+	mtx_lock(&pr->pr_mtx);
 	pr->pr_ref++;
+	mtx_unlock(&pr->pr_mtx);
+}
+
+u_int32_t
+prison_getip(struct ucred *cred)
+{
+
+	return (cred->cr_prison->pr_ip);
 }
 
 int
Index: kern/kern_mib.c
===================================================================
RCS file: /home/ncvs/src/sys/kern/kern_mib.c,v
retrieving revision 1.43
diff -u -r1.43 kern_mib.c
--- kern/kern_mib.c	2001/07/27 15:52:49	1.43
+++ kern/kern_mib.c	2001/09/03 03:05:31
@@ -45,6 +45,8 @@
 #include <sys/systm.h>
 #include <sys/sysctl.h>
 #include <sys/proc.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
 #include <sys/jail.h>
 #include <sys/smp.h>
 
@@ -150,11 +152,34 @@
 	int error;
 
 	if (jailed(req->p->p_ucred)) {
+		char tmphostname[MAXHOSTNAMELEN];
+
 		if (!jail_set_hostname_allowed && req->newptr)
-			return(EPERM);
-		error = sysctl_handle_string(oidp, 
-		    req->p->p_ucred->cr_prison->pr_host,
+			return (EPERM);
+
+		/*
+		 * Process is in jail, so make a local copy of jail
+		 * hostname to get/set so we don't have to hold the jail
+		 * mutex during the sysctl copyin/copyout activities.
+		 */
+		mtx_lock(&req->p->p_ucred->cr_prison->pr_mtx);
+		bcopy(req->p->p_ucred->cr_prison->pr_host, tmphostname,
+		    MAXHOSTNAMELEN);
+		mtx_unlock(&req->p->p_ucred->cr_prison->pr_mtx);
+
+		error = sysctl_handle_string(oidp, tmphostname,
 		    sizeof req->p->p_ucred->cr_prison->pr_host, req);
+
+		if (req->newptr && error == 0) {
+			/*
+			 * Copy the locally set hostname to the jail, if
+			 * appropriate.
+			 */
+			mtx_lock(&req->p->p_ucred->cr_prison->pr_mtx);
+			bcopy(tmphostname, req->p->p_ucred->cr_prison->pr_host,
+			    MAXHOSTNAMELEN);
+			mtx_unlock(&req->p->p_ucred->cr_prison->pr_mtx);
+		}
 	} else
 		error = sysctl_handle_string(oidp, 
 		    hostname, sizeof hostname, req);
Index: netinet/in_pcb.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet/in_pcb.c,v
retrieving revision 1.87
diff -u -r1.87 in_pcb.c
--- netinet/in_pcb.c	2001/08/04 17:10:13	1.87
+++ netinet/in_pcb.c	2001/09/02 15:23:58
@@ -508,7 +508,7 @@
 	cred = inp->inp_socket->so_cred;
 	if (inp->inp_laddr.s_addr == INADDR_ANY && jailed(cred)) {
 		bzero(&sa, sizeof (sa));
-		sa.sin_addr.s_addr = htonl(cred->cr_prison->pr_ip);
+		sa.sin_addr.s_addr = htonl(prison_getip(cred->cr_prison));
 		sa.sin_len=sizeof (sa);
 		sa.sin_family = AF_INET;
 		error = in_pcbbind(inp, (struct sockaddr *)&sa, p);
@@ -1054,7 +1054,7 @@
 {
 	if (!jailed(p->p_ucred))
 		return (0);
-	if (ntohl(inp->inp_laddr.s_addr) == p->p_ucred->cr_prison->pr_ip)
+	if (ntohl(inp->inp_laddr.s_addr) == prison_getip(p->p_ucred))
 		return (0);
 	return (1);
 }
Index: sys/jail.h
===================================================================
RCS file: /home/ncvs/src/sys/sys/jail.h,v
retrieving revision 1.11
diff -u -r1.11 jail.h
--- sys/jail.h	2001/02/21 06:39:57	1.11
+++ sys/jail.h	2001/09/03 03:02:17
@@ -35,19 +35,25 @@
  * ucreds's of the inmates.  pr_ref keeps track of them and is used to
  * delete the struture when the last inmate is dead.
  *
- * XXX: Note: this structure needs a mutex to protect the reference count
- * and other mutable fields (pr_host, pr_linux).
+ * Lock key:
+ *   (p) locked by pr_mutex
+ *   (c) set only during creation before the structure is shared, no mutex
+ *       required to read
  */
-
+struct mtx;
 struct prison {
-	int		pr_ref;
-	char 		pr_host[MAXHOSTNAMELEN];
-	u_int32_t	pr_ip;
-	void		*pr_linux;
+	int		 pr_ref;			/* (p) refcount */
+	char 		 pr_host[MAXHOSTNAMELEN];	/* (p) jail hostname */
+	u_int32_t	 pr_ip;				/* (c) ip addr host
+							 * byte order */
+	void		*pr_linux;			/* (p) linux abi */
+	struct mtx	pr_mtx;
 };
 
 /*
  * Sysctl-set variables that determine global jail policy
+ *
+ * XXX MIB entries will need to be protected by a mutex.
  */
 extern int	jail_set_hostname_allowed;
 extern int	jail_socket_unixiproute_only;
@@ -61,6 +67,7 @@
 int jailed __P((struct ucred *cred));
 int prison_check __P((struct ucred *cred1, struct ucred *cred2));
 void prison_free __P((struct prison *pr));
+u_int32_t prison_getip __P((struct ucred *cred));
 void prison_hold __P((struct prison *pr));
 int prison_if __P((struct ucred *cred, struct sockaddr *sa));
 int prison_ip __P((struct ucred *cred, int flag, u_int32_t *ip));
