Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 19 Feb 2003 22:56:57 +0100 (CET)
From:      Pawel Jakub Dawidek <nick@garage.freebsd.pl>
To:        FreeBSD-gnats-submit@FreeBSD.org
Subject:   kern/48471: Private IPC for every jail. [PATCH]
Message-ID:  <20030219215657.34DEB3ABB3B@milla.ask33.net>

next in thread | raw e-mail | index | archive | help

>Number:         48471
>Category:       kern
>Synopsis:       Private IPC for every jail. [PATCH]
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Wed Feb 19 14:00:11 PST 2003
>Closed-Date:
>Last-Modified:
>Originator:     Pawel Jakub Dawidek
>Release:        FreeBSD 4.7-STABLE i386
>Organization:
cerb team
>Environment:
System: FreeBSD milla.ask33.net 4.7-STABLE FreeBSD 4.7-STABLE #12: Fri Jan 10 12:53:26 CET 2003 root@milla.ask33.net:/usr/obj/usr/src/sys/MILLA i386

>Description:
	At present IPC functionality is turned off by default (it could be
	turned on by setting sysctl jail.sysvipc_allowed to 1), because
	memory zones are shared between main host and every jail.
	For this reason many applications that use IPC can't be secure
	jailed.
	Attached patches provide as follows:
	- private memory zones for main host and every jail,
	- adds some sysctls and now ipcs(1) don't have to be set-gid
	  on kmem group, because it don't use kvm(3) library anymore,
	- sysctl jail.sysvipc_allowed is now turned on by default,
	Only functionality was changed, but there have to be many style
	of old code fixes.
	I could port those patches on 5.x if FreeBSD team will be interested.

>How-To-Repeat:

>Fix:

===> kernel patch

diff -ru /sys/compat/linux/linux_ipc.c sys/compat/linux/linux_ipc.c
--- /sys/compat/linux/linux_ipc.c	Wed Feb 19 19:29:13 2003
+++ sys/compat/linux/linux_ipc.c	Wed Feb 19 18:02:21 2003
@@ -25,7 +25,7 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
- * $FreeBSD: src/sys/compat/linux/linux_ipc.c,v 1.17.2.3 2001/11/05 19:08:22 marcel Exp $
+ * $FreeBSD$
  */
 
 #include <sys/param.h>
@@ -34,6 +34,7 @@
 #include <sys/proc.h>
 #include <sys/sem.h>
 #include <sys/shm.h>
+#include <sys/jail.h>
 
 #include <machine/../linux/linux.h>
 #include <machine/../linux/linux_proto.h>
@@ -222,6 +223,12 @@
 	int error;
 	union semun *unptr;
 	caddr_t sg;
+	struct sempriv *sp;
+
+	if (p->p_prison == NULL)
+		sp = &mainsem;
+	else
+		sp = &p->p_prison->pr_sem;
 
 	sg = stackgap_init();
 
@@ -278,7 +285,7 @@
 						sizeof(linux_seminfo) );
 		if (error)
 			return error;
-		bcopy(&seminfo, &linux_seminfo, sizeof(linux_seminfo) );
+		bcopy(&sp->seminfo, &linux_seminfo, sizeof(linux_seminfo) );
 /* XXX BSD equivalent?
 #define used_semids 10
 #define used_sems 10
@@ -289,7 +296,7 @@
 						sizeof(linux_seminfo) );
 		if (error)
 			return error;
-		p->p_retval[0] = seminfo.semmni;
+		p->p_retval[0] = sp->seminfo.semmni;
 		return 0;			/* No need for __semctl call */
 	case LINUX_GETALL:
 		/* FALLTHROUGH */
diff -ru /sys/kern/kern_exit.c sys/kern/kern_exit.c
--- /sys/kern/kern_exit.c	Wed Feb 19 19:29:13 2003
+++ sys/kern/kern_exit.c	Wed Feb 19 18:38:38 2003
@@ -36,11 +36,12 @@
  * SUCH DAMAGE.
  *
  *	@(#)kern_exit.c	8.7 (Berkeley) 2/12/94
- * $FreeBSD: src/sys/kern/kern_exit.c,v 1.92.2.11 2003/01/13 22:51:16 dillon Exp $
+ * $FreeBSD$
  */
 
 #include "opt_compat.h"
 #include "opt_ktrace.h"
+#include "opt_sysvipc.h"
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -57,6 +58,7 @@
 #include <sys/ptrace.h>
 #include <sys/acct.h>		/* for acct_process() function prototype */
 #include <sys/filedesc.h>
+#include <sys/msg.h>
 #include <sys/shm.h>
 #include <sys/sem.h>
 #include <sys/aio.h>
@@ -510,6 +512,15 @@
 			if (p->p_prison && !--p->p_prison->pr_ref) {
 				if (p->p_prison->pr_linux != NULL)
 					FREE(p->p_prison->pr_linux, M_PRISON);
+#ifdef SYSVMSG
+				msgclear(p->p_prison);
+#endif
+#ifdef SYSVSEM
+				semclear(p->p_prison);
+#endif
+#ifdef SYSVSHM
+				shmclear(p->p_prison);
+#endif
 				FREE(p->p_prison, M_PRISON);
 			}
 
diff -ru /sys/kern/kern_jail.c sys/kern/kern_jail.c
--- /sys/kern/kern_jail.c	Wed Feb 19 19:29:13 2003
+++ sys/kern/kern_jail.c	Wed Feb 19 19:29:09 2003
@@ -6,10 +6,12 @@
  * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
  * ----------------------------------------------------------------------------
  *
- * $FreeBSD: src/sys/kern/kern_jail.c,v 1.6.2.3 2001/08/17 01:00:26 rwatson Exp $
+ * $FreeBSD$
  *
  */
 
+#include "opt_sysvipc.h"
+
 #include <sys/param.h>
 #include <sys/types.h>
 #include <sys/kernel.h>
@@ -21,6 +23,9 @@
 #include <sys/jail.h>
 #include <sys/socket.h>
 #include <sys/sysctl.h>
+#include <sys/msg.h>
+#include <sys/sem.h>
+#include <sys/shm.h>
 #include <net/if.h>
 #include <netinet/in.h>
 
@@ -39,10 +44,12 @@
     &jail_socket_unixiproute_only, 0,
     "Processes in jail are limited to creating UNIX/IPv4/route sockets only");
 
-int	jail_sysvipc_allowed = 0;
+#if defined(SYSVMSG) || defined(SYSVSEM) || defined(SYSVSHM)
+int	jail_sysvipc_allowed = 1;
 SYSCTL_INT(_jail, OID_AUTO, sysvipc_allowed, CTLFLAG_RW,
     &jail_sysvipc_allowed, 0,
     "Processes in jail can use System V IPC primitives");
+#endif
 
 int
 jail(p, uap)
@@ -75,7 +82,32 @@
 	error = chroot(p, &ca);
 	if (error)
 		goto bail;
-
+#ifdef SYSVMSG
+	error = msginit(pr);
+	if (error != 0)
+		goto bail;
+#endif
+#ifdef SYSVSEM
+	error = seminit(pr);
+	if (error != 0) {
+#ifdef SYSVMSG
+		msgclear(pr);
+#endif
+		goto bail;
+	}
+#endif
+#ifdef SYSVSHM
+	error = shminit(pr);
+	if (error != 0) {
+#ifdef SYSVMSG
+		msgclear(pr);
+#endif
+#ifdef SYSVSEM
+		semclear(pr);
+#endif
+		goto bail;
+	}
+#endif
 	pr->pr_ref++;
 	p->p_prison = pr;
 	p->p_flag |= P_JAILED;
diff -ru /sys/kern/sysv_msg.c sys/kern/sysv_msg.c
--- /sys/kern/sysv_msg.c	Wed Feb 19 19:29:13 2003
+++ sys/kern/sysv_msg.c	Wed Feb 19 18:27:23 2003
@@ -1,9 +1,10 @@
-/* $FreeBSD: src/sys/kern/sysv_msg.c,v 1.23.2.5 2002/12/31 08:54:53 maxim Exp $ */
+/* $FreeBSD$ */
 
 /*
  * Implementation of SVID messages
  *
  * Author:  Daniel Boulet
+ * Jailed by: Pawel Jakub Dawidek <nick@garage.freebsd.pl>
  *
  * Copyright 1993 Daniel Boulet and RTMX Inc.
  *
@@ -34,8 +35,6 @@
 
 static MALLOC_DEFINE(M_MSG, "msg", "SVID compatible message queues");
 
-static void msginit __P((void *));
-
 #define MSG_DEBUG
 #undef MSG_DEBUG_OK
 
@@ -47,15 +46,6 @@
 	(sy_call_t *)msgsnd, (sy_call_t *)msgrcv
 };
 
-struct msg {
-	struct	msg *msg_next;	/* next msg in the chain */
-	long	msg_type;	/* type of this message */
-    				/* >0 -> type of this message */
-    				/* 0 -> free header */
-	u_short	msg_ts;		/* size of this message */
-	short	msg_spot;	/* location of start of msg in buffer */
-};
-
 
 #ifndef MSGSSZ
 #define MSGSSZ	8		/* Each segment must be 2^N long */
@@ -75,26 +65,6 @@
 #endif
 
 /*
- * Based on the configuration parameters described in an SVR2 (yes, two)
- * config(1m) man page.
- *
- * Each message is broken up and stored in segments that are msgssz bytes
- * long.  For efficiency reasons, this should be a power of two.  Also,
- * it doesn't make sense if it is less than 8 or greater than about 256.
- * Consequently, msginit in kern/sysv_msg.c checks that msgssz is a power of
- * two between 8 and 1024 inclusive (and panic's if it isn't).
- */
-struct msginfo msginfo = {
-                MSGMAX,         /* max chars in a message */
-                MSGMNI,         /* # of message queue identifiers */
-                MSGMNB,         /* max chars in a queue */
-                MSGTQL,         /* max messages in system */
-                MSGSSZ,         /* size of a message segment */
-                		/* (must be small power of 2 greater than 4) */
-                MSGSEG          /* number of message segments */
-};
-
-/*
  * macros to convert between msqid_ds's and msqid's.
  * (specific to this implementation)
  */
@@ -106,41 +76,68 @@
  * The rest of this file is specific to this particular implementation.
  */
 
-struct msgmap {
-	short	next;		/* next segment in buffer */
-    				/* -1 -> available */
-    				/* 0..(MSGSEG-1) -> index of next segment */
-};
-
 #define MSG_LOCKED	01000	/* Is this msqid_ds locked? */
 
-static int nfree_msgmaps;	/* # of free map entries */
-static short free_msgmaps;	/* head of linked list of free map entries */
-static struct msg *free_msghdrs;/* list of free msg headers */
-static char *msgpool;		/* MSGMAX byte long msg buffer pool */
-static struct msgmap *msgmaps;	/* MSGSEG msgmap structures */
-static struct msg *msghdrs;	/* MSGTQL msg headers */
-static struct msqid_ds *msqids;	/* MSGMNI msqid_ds struct's */
+/* Global struct for main system, all jails have its own. */
+struct msgpriv mainmsg;
 
-static void
-msginit(dummy)
-	void *dummy;
+int
+msginit(struct prison *pr)
 {
 	register int i;
+	struct msgpriv *mp;
+	int error;
 
-	msginfo.msgmax = msginfo.msgseg * msginfo.msgssz;
-	msgpool = malloc(msginfo.msgmax, M_MSG, M_WAITOK);
-	if (msgpool == NULL)
-		panic("msgpool is NULL");
-	msgmaps = malloc(sizeof(struct msgmap) * msginfo.msgseg, M_MSG, M_WAITOK);
-	if (msgmaps == NULL)
-		panic("msgmaps is NULL");
-	msghdrs = malloc(sizeof(struct msg) * msginfo.msgtql, M_MSG, M_WAITOK);
-	if (msghdrs == NULL)
-		panic("msghdrs is NULL");
-	msqids = malloc(sizeof(struct msqid_ds) * msginfo.msgmni, M_MSG, M_WAITOK);
-	if (msqids == NULL)
-		panic("msqids is NULL");
+	if (pr == NULL)
+		mp = &mainmsg;
+	else
+		mp = &pr->pr_msg;
+
+	mp->msginfo.msgmax = MSGMAX;
+	mp->msginfo.msgmni = MSGMNI;
+	mp->msginfo.msgmnb = MSGMNB;
+	mp->msginfo.msgtql = MSGTQL;
+	mp->msginfo.msgssz = MSGSSZ;
+	mp->msginfo.msgseg = MSGSEG;
+
+	mp->msginfo.msgmax = mp->msginfo.msgseg * mp->msginfo.msgssz;
+	mp->msgpool = malloc(mp->msginfo.msgmax, M_MSG, M_WAITOK);
+	if (mp->msgpool == NULL) {
+		if (pr == NULL)
+			panic("msgpool is NULL");
+		else
+			return (ENOMEM);
+	}
+	mp->msgmaps = malloc(sizeof(struct msgmap) * mp->msginfo.msgseg, M_MSG,
+	    M_WAITOK);
+	if (mp->msgmaps == NULL) {
+		if (pr == NULL)
+			panic("msgmaps is NULL");
+		else {
+			error = ENOMEM;
+			goto fail_msgmaps;
+		}
+	}
+	mp->msghdrs = malloc(sizeof(struct msg) * mp->msginfo.msgtql, M_MSG,
+	    M_WAITOK);
+	if (mp->msghdrs == NULL) {
+		if (pr == NULL)
+			panic("msghdrs is NULL");
+		else {
+			error = ENOMEM;
+			goto fail_msghdrs;
+		}
+	}
+	mp->msqids = malloc(sizeof(struct msqid_ds) * mp->msginfo.msgmni, M_MSG,
+	    M_WAITOK);
+	if (mp->msqids == NULL) {
+		if (pr == NULL)
+			panic("msqids is NULL");
+		else {
+			error = ENOMEM;
+			goto fail_msqids;
+		}
+	}
 
 	/*
 	 * msginfo.msgssz should be a power of two for efficiency reasons.
@@ -149,49 +146,88 @@
 	 */
 
 	i = 8;
-	while (i < 1024 && i != msginfo.msgssz)
+	while (i < 1024 && i != mp->msginfo.msgssz)
 		i <<= 1;
-    	if (i != msginfo.msgssz) {
-		printf("msginfo.msgssz=%d (0x%x)\n", msginfo.msgssz,
-		    msginfo.msgssz);
-		panic("msginfo.msgssz not a small power of 2");
+    	if (i != mp->msginfo.msgssz) {
+		printf("msginfo.msgssz=%d (0x%x)\n", mp->msginfo.msgssz,
+		    mp->msginfo.msgssz);
+		if (pr == NULL)
+			panic("msginfo.msgssz not a small power of 2");
+		else {
+			error = EINVAL;
+			goto all;
+		}
 	}
 
-	if (msginfo.msgseg > 32767) {
-		printf("msginfo.msgseg=%d\n", msginfo.msgseg);
-		panic("msginfo.msgseg > 32767");
+	if (mp->msginfo.msgseg > 32767) {
+		printf("msginfo.msgseg=%d\n", mp->msginfo.msgseg);
+		if (pr == NULL)
+			panic("msginfo.msgseg > 32767");
+		else {
+			error = EINVAL;
+			goto all;
+		}
 	}
 
-	if (msgmaps == NULL)
-		panic("msgmaps is NULL");
+	if (mp->msgmaps == NULL) {
+		if (pr == NULL)
+			panic("msgmaps is NULL");
+		else {
+			error = EFAULT;
+			goto all;
+		}
+	}
 
-	for (i = 0; i < msginfo.msgseg; i++) {
+	for (i = 0; i < mp->msginfo.msgseg; i++) {
 		if (i > 0)
-			msgmaps[i-1].next = i;
-		msgmaps[i].next = -1;	/* implies entry is available */
+			mp->msgmaps[i-1].next = i;
+		mp->msgmaps[i].next = -1;	/* implies entry is available */
 	}
-	free_msgmaps = 0;
-	nfree_msgmaps = msginfo.msgseg;
+	mp->free_msgmaps = 0;
+	mp->nfree_msgmaps = mp->msginfo.msgseg;
 
-	if (msghdrs == NULL)
-		panic("msghdrs is NULL");
+	if (mp->msghdrs == NULL) {
+		if (pr == NULL)
+			panic("msghdrs is NULL");
+		else {
+			error = EFAULT;
+			goto all;
+		}
+	}
 
-	for (i = 0; i < msginfo.msgtql; i++) {
-		msghdrs[i].msg_type = 0;
+	for (i = 0; i < mp->msginfo.msgtql; i++) {
+		mp->msghdrs[i].msg_type = 0;
 		if (i > 0)
-			msghdrs[i-1].msg_next = &msghdrs[i];
-		msghdrs[i].msg_next = NULL;
+			mp->msghdrs[i-1].msg_next = &mp->msghdrs[i];
+		mp->msghdrs[i].msg_next = NULL;
     	}
-	free_msghdrs = &msghdrs[0];
+	mp->free_msghdrs = &mp->msghdrs[0];
 
-	if (msqids == NULL)
-		panic("msqids is NULL");
+	if (mp->msqids == NULL) {
+		if (pr == NULL)
+			panic("msqids is NULL");
+		else {
+			error = EFAULT;
+			goto all;
+		}
+	}
 
-	for (i = 0; i < msginfo.msgmni; i++) {
-		msqids[i].msg_qbytes = 0;	/* implies entry is available */
-		msqids[i].msg_perm.seq = 0;	/* reset to a known value */
-		msqids[i].msg_perm.mode = 0;
+	for (i = 0; i < mp->msginfo.msgmni; i++) {
+		mp->msqids[i].msg_qbytes = 0;	/* implies entry is available */
+		mp->msqids[i].msg_perm.seq = 0;	/* reset to a known value */
+		mp->msqids[i].msg_perm.mode = 0;
 	}
+
+	return (0);
+all:
+fail_msqids:
+	free(mp->msghdrs, M_MSG);
+fail_msghdrs:
+	free(mp->msgmaps, M_MSG);
+fail_msgmaps:
+	free(mp->msgpool, M_MSG);
+
+	return (error);
 }
 SYSINIT(sysv_msg, SI_SUB_SYSV_MSG, SI_ORDER_FIRST, msginit, NULL)
 
@@ -224,24 +260,34 @@
 msg_freehdr(msghdr)
 	struct msg *msghdr;
 {
+	struct msgpriv *mp;
+
+	KASSERT(curproc != NULL, ("msg_freehdr: curproc is NULL"));
+	if (curproc->p_prison == NULL)
+		mp = &mainmsg;
+	else
+		mp = &curproc->p_prison->pr_msg;
+
 	while (msghdr->msg_ts > 0) {
 		short next;
-		if (msghdr->msg_spot < 0 || msghdr->msg_spot >= msginfo.msgseg)
+		if (msghdr->msg_spot < 0 ||
+		    msghdr->msg_spot >= mp->msginfo.msgseg) {
 			panic("msghdr->msg_spot out of range");
-		next = msgmaps[msghdr->msg_spot].next;
-		msgmaps[msghdr->msg_spot].next = free_msgmaps;
-		free_msgmaps = msghdr->msg_spot;
-		nfree_msgmaps++;
+		}
+		next = mp->msgmaps[msghdr->msg_spot].next;
+		mp->msgmaps[msghdr->msg_spot].next = mp->free_msgmaps;
+		mp->free_msgmaps = msghdr->msg_spot;
+		mp->nfree_msgmaps++;
 		msghdr->msg_spot = next;
-		if (msghdr->msg_ts >= msginfo.msgssz)
-			msghdr->msg_ts -= msginfo.msgssz;
+		if (msghdr->msg_ts >= mp->msginfo.msgssz)
+			msghdr->msg_ts -= mp->msginfo.msgssz;
 		else
 			msghdr->msg_ts = 0;
 	}
 	if (msghdr->msg_spot != -1)
 		panic("msghdr->msg_spot != -1");
-	msghdr->msg_next = free_msghdrs;
-	free_msghdrs = msghdr;
+	msghdr->msg_next = mp->free_msghdrs;
+	mp->free_msghdrs = msghdr;
 }
 
 #ifndef _SYS_SYSPROTO_H_
@@ -263,6 +309,7 @@
 	int rval, eval;
 	struct msqid_ds msqbuf;
 	register struct msqid_ds *msqptr;
+	struct msgpriv *mp;
 
 #ifdef MSG_DEBUG_OK
 	printf("call to msgctl(%d, %d, 0x%x)\n", msqid, cmd, user_msqptr);
@@ -271,17 +318,22 @@
 	if (!jail_sysvipc_allowed && p->p_prison != NULL)
 		return (ENOSYS);
 
+	if (p->p_prison == NULL)
+		mp = &mainmsg;
+	else
+		mp = &p->p_prison->pr_msg;
+
 	msqid = IPCID_TO_IX(msqid);
 
-	if (msqid < 0 || msqid >= msginfo.msgmni) {
+	if (msqid < 0 || msqid >= mp->msginfo.msgmni) {
 #ifdef MSG_DEBUG_OK
 		printf("msqid (%d) out of range (0<=msqid<%d)\n", msqid,
-		    msginfo.msgmni);
+		    mp->msginfo.msgmni);
 #endif
 		return(EINVAL);
 	}
 
-	msqptr = &msqids[msqid];
+	msqptr = &mp->msqids[msqid];
 
 	if (msqptr->msg_qbytes == 0) {
 #ifdef MSG_DEBUG_OK
@@ -341,12 +393,13 @@
 			if (eval)
 				return(eval);
 		}
-		if (msqbuf.msg_qbytes > msginfo.msgmnb) {
+		if (msqbuf.msg_qbytes > mp->msginfo.msgmnb) {
 #ifdef MSG_DEBUG_OK
 			printf("can't increase msg_qbytes beyond %d (truncating)\n",
-			    msginfo.msgmnb);
+			    mp->msginfo.msgmnb);
 #endif
-			msqbuf.msg_qbytes = msginfo.msgmnb;	/* silently restrict qbytes to system limit */
+			/* silently restrict qbytes to system limit */
+			msqbuf.msg_qbytes = mp->msginfo.msgmnb;
 		}
 		if (msqbuf.msg_qbytes == 0) {
 #ifdef MSG_DEBUG_OK
@@ -402,6 +455,7 @@
 	int msgflg = uap->msgflg;
 	struct ucred *cred = p->p_ucred;
 	register struct msqid_ds *msqptr = NULL;
+	struct msgpriv *mp;
 
 #ifdef MSG_DEBUG_OK
 	printf("msgget(0x%x, 0%o)\n", key, msgflg);
@@ -410,14 +464,19 @@
 	if (!jail_sysvipc_allowed && p->p_prison != NULL)
 		return (ENOSYS);
 
+	if (p->p_prison == NULL)
+		mp = &mainmsg;
+	else
+		mp = &p->p_prison->pr_msg;
+
 	if (key != IPC_PRIVATE) {
-		for (msqid = 0; msqid < msginfo.msgmni; msqid++) {
-			msqptr = &msqids[msqid];
+		for (msqid = 0; msqid < mp->msginfo.msgmni; msqid++) {
+			msqptr = &mp->msqids[msqid];
 			if (msqptr->msg_qbytes != 0 &&
 			    msqptr->msg_perm.key == key)
 				break;
 		}
-		if (msqid < msginfo.msgmni) {
+		if (msqid < mp->msginfo.msgmni) {
 #ifdef MSG_DEBUG_OK
 			printf("found public key\n");
 #endif
@@ -442,19 +501,19 @@
 	printf("need to allocate the msqid_ds\n");
 #endif
 	if (key == IPC_PRIVATE || (msgflg & IPC_CREAT)) {
-		for (msqid = 0; msqid < msginfo.msgmni; msqid++) {
+		for (msqid = 0; msqid < mp->msginfo.msgmni; msqid++) {
 			/*
 			 * Look for an unallocated and unlocked msqid_ds.
 			 * msqid_ds's can be locked by msgsnd or msgrcv while
 			 * they are copying the message in/out.  We can't
 			 * re-use the entry until they release it.
 			 */
-			msqptr = &msqids[msqid];
+			msqptr = &mp->msqids[msqid];
 			if (msqptr->msg_qbytes == 0 &&
 			    (msqptr->msg_perm.mode & MSG_LOCKED) == 0)
 				break;
 		}
-		if (msqid == msginfo.msgmni) {
+		if (msqid == mp->msginfo.msgmni) {
 #ifdef MSG_DEBUG_OK
 			printf("no more msqid_ds's available\n");
 #endif
@@ -475,7 +534,7 @@
 		msqptr->msg_last = NULL;
 		msqptr->msg_cbytes = 0;
 		msqptr->msg_qnum = 0;
-		msqptr->msg_qbytes = msginfo.msgmnb;
+		msqptr->msg_qbytes = mp->msginfo.msgmnb;
 		msqptr->msg_lspid = 0;
 		msqptr->msg_lrpid = 0;
 		msqptr->msg_stime = 0;
@@ -516,6 +575,7 @@
 	register struct msqid_ds *msqptr;
 	register struct msg *msghdr;
 	short next;
+	struct msgpriv *mp;
 
 #ifdef MSG_DEBUG_OK
 	printf("call to msgsnd(%d, 0x%x, %d, %d)\n", msqid, user_msgp, msgsz,
@@ -525,17 +585,22 @@
 	if (!jail_sysvipc_allowed && p->p_prison != NULL)
 		return (ENOSYS);
 
+	if (p->p_prison == NULL)
+		mp = &mainmsg;
+	else
+		mp = &p->p_prison->pr_msg;
+
 	msqid = IPCID_TO_IX(msqid);
 
-	if (msqid < 0 || msqid >= msginfo.msgmni) {
+	if (msqid < 0 || msqid >= mp->msginfo.msgmni) {
 #ifdef MSG_DEBUG_OK
 		printf("msqid (%d) out of range (0<=msqid<%d)\n", msqid,
-		    msginfo.msgmni);
+		    mp->msginfo.msgmni);
 #endif
 		return(EINVAL);
 	}
 
-	msqptr = &msqids[msqid];
+	msqptr = &mp->msqids[msqid];
 	if (msqptr->msg_qbytes == 0) {
 #ifdef MSG_DEBUG_OK
 		printf("no such message queue id\n");
@@ -556,10 +621,10 @@
 		return(eval);
 	}
 
-	segs_needed = (msgsz + msginfo.msgssz - 1) / msginfo.msgssz;
+	segs_needed = (msgsz + mp->msginfo.msgssz - 1) / mp->msginfo.msgssz;
 #ifdef MSG_DEBUG_OK
-	printf("msgsz=%d, msgssz=%d, segs_needed=%d\n", msgsz, msginfo.msgssz,
-	    segs_needed);
+	printf("msgsz=%d, msgssz=%d, segs_needed=%d\n", msgsz,
+	    mp->msginfo.msgssz, segs_needed);
 #endif
 	for (;;) {
 		int need_more_resources = 0;
@@ -588,13 +653,13 @@
 #endif
 			need_more_resources = 1;
 		}
-		if (segs_needed > nfree_msgmaps) {
+		if (segs_needed > mp->nfree_msgmaps) {
 #ifdef MSG_DEBUG_OK
 			printf("segs_needed > nfree_msgmaps\n");
 #endif
 			need_more_resources = 1;
 		}
-		if (free_msghdrs == NULL) {
+		if (mp->free_msghdrs == NULL) {
 #ifdef MSG_DEBUG_OK
 			printf("no more msghdrs\n");
 #endif
@@ -668,11 +733,11 @@
 
 	if (msqptr->msg_perm.mode & MSG_LOCKED)
 		panic("msg_perm.mode & MSG_LOCKED");
-	if (segs_needed > nfree_msgmaps)
+	if (segs_needed > mp->nfree_msgmaps)
 		panic("segs_needed > nfree_msgmaps");
 	if (msgsz + msqptr->msg_cbytes > msqptr->msg_qbytes)
 		panic("msgsz + msg_cbytes > msg_qbytes");
-	if (free_msghdrs == NULL)
+	if (mp->free_msghdrs == NULL)
 		panic("no more msghdrs");
 
 	/*
@@ -688,8 +753,8 @@
 	 * Allocate a message header
 	 */
 
-	msghdr = free_msghdrs;
-	free_msghdrs = msghdr->msg_next;
+	msghdr = mp->free_msghdrs;
+	mp->free_msghdrs = msghdr->msg_next;
 	msghdr->msg_spot = -1;
 	msghdr->msg_ts = msgsz;
 
@@ -698,21 +763,21 @@
 	 */
 
 	while (segs_needed > 0) {
-		if (nfree_msgmaps <= 0)
+		if (mp->nfree_msgmaps <= 0)
 			panic("not enough msgmaps");
-		if (free_msgmaps == -1)
+		if (mp->free_msgmaps == -1)
 			panic("nil free_msgmaps");
-		next = free_msgmaps;
+		next = mp->free_msgmaps;
 		if (next <= -1)
 			panic("next too low #1");
-		if (next >= msginfo.msgseg)
+		if (next >= mp->msginfo.msgseg)
 			panic("next out of range #1");
 #ifdef MSG_DEBUG_OK
 		printf("allocating segment %d to message\n", next);
 #endif
-		free_msgmaps = msgmaps[next].next;
-		nfree_msgmaps--;
-		msgmaps[next].next = msghdr->msg_spot;
+		mp->free_msgmaps = mp->msgmaps[next].next;
+		mp->nfree_msgmaps--;
+		mp->msgmaps[next].next = msghdr->msg_spot;
 		msghdr->msg_spot = next;
 		segs_needed--;
 	}
@@ -754,16 +819,16 @@
 	next = msghdr->msg_spot;
 	while (msgsz > 0) {
 		size_t tlen;
-		if (msgsz > msginfo.msgssz)
-			tlen = msginfo.msgssz;
+		if (msgsz > mp->msginfo.msgssz)
+			tlen = mp->msginfo.msgssz;
 		else
 			tlen = msgsz;
 		if (next <= -1)
 			panic("next too low #2");
-		if (next >= msginfo.msgseg)
+		if (next >= mp->msginfo.msgseg)
 			panic("next out of range #2");
-		if ((eval = copyin(user_msgp, &msgpool[next * msginfo.msgssz],
-		    tlen)) != 0) {
+		if ((eval = copyin(user_msgp,
+		    &mp->msgpool[next * mp->msginfo.msgssz], tlen)) != 0) {
 #ifdef MSG_DEBUG_OK
 			printf("error %d copying in message segment\n", eval);
 #endif
@@ -774,7 +839,7 @@
 		}
 		msgsz -= tlen;
 		user_msgp = (char *)user_msgp + tlen;
-		next = msgmaps[next].next;
+		next = mp->msgmaps[next].next;
 	}
 	if (next != -1)
 		panic("didn't use all the msg segments");
@@ -843,6 +908,7 @@
 	register struct msg *msghdr;
 	int eval;
 	short next;
+	struct msgpriv *mp;
 
 #ifdef MSG_DEBUG_OK
 	printf("call to msgrcv(%d, 0x%x, %d, %ld, %d)\n", msqid, user_msgp,
@@ -852,17 +918,22 @@
 	if (!jail_sysvipc_allowed && p->p_prison != NULL)
 		return (ENOSYS);
 
+	if (p->p_prison == NULL)
+		mp = &mainmsg;
+	else
+		mp = &p->p_prison->pr_msg;
+
 	msqid = IPCID_TO_IX(msqid);
 
-	if (msqid < 0 || msqid >= msginfo.msgmni) {
+	if (msqid < 0 || msqid >= mp->msginfo.msgmni) {
 #ifdef MSG_DEBUG_OK
 		printf("msqid (%d) out of range (0<=msqid<%d)\n", msqid,
-		    msginfo.msgmni);
+		    mp->msginfo.msgmni);
 #endif
 		return(EINVAL);
 	}
 
-	msqptr = &msqids[msqid];
+	msqptr = &mp->msqids[msqid];
 	if (msqptr->msg_qbytes == 0) {
 #ifdef MSG_DEBUG_OK
 		printf("no such message queue id\n");
@@ -1065,18 +1136,18 @@
 	 */
 
 	next = msghdr->msg_spot;
-	for (len = 0; len < msgsz; len += msginfo.msgssz) {
+	for (len = 0; len < msgsz; len += mp->msginfo.msgssz) {
 		size_t tlen;
 
-		if (msgsz - len > msginfo.msgssz)
-			tlen = msginfo.msgssz;
+		if (msgsz - len > mp->msginfo.msgssz)
+			tlen = mp->msginfo.msgssz;
 		else
 			tlen = msgsz - len;
 		if (next <= -1)
 			panic("next too low #3");
-		if (next >= msginfo.msgseg)
+		if (next >= mp->msginfo.msgseg)
 			panic("next out of range #3");
-		eval = copyout((caddr_t)&msgpool[next * msginfo.msgssz],
+		eval = copyout((caddr_t)&mp->msgpool[next * mp->msginfo.msgssz],
 		    user_msgp, tlen);
 		if (eval != 0) {
 #ifdef MSG_DEBUG_OK
@@ -1088,7 +1159,7 @@
 			return(eval);
 		}
 		user_msgp = (char *)user_msgp + tlen;
-		next = msgmaps[next].next;
+		next = mp->msgmaps[next].next;
 	}
 
 	/*
@@ -1101,24 +1172,155 @@
 	return(0);
 }
 
-static int
-sysctl_msqids(SYSCTL_HANDLER_ARGS)
+void
+msgclear(struct prison *pr)
 {
+	struct msgpriv *mp;
 
-	return (SYSCTL_OUT(req, msqids,
-	    sizeof(struct msqid_ds) * msginfo.msgmni));
+	if (pr == NULL)
+		mp = &mainmsg;
+	else
+		mp = &pr->pr_msg;
+
+	free(mp->msgpool, M_MSG);
+	free(mp->msgmaps, M_MSG);
+	free(mp->msghdrs, M_MSG);
+	free(mp->msqids, M_MSG);
 }
 
-TUNABLE_INT("kern.ipc.msgseg", &msginfo.msgseg);
-TUNABLE_INT("kern.ipc.msgssz", &msginfo.msgssz);
-TUNABLE_INT("kern.ipc.msgmni", &msginfo.msgmni);
+/* XXX: Should it stay? */
+TUNABLE_INT("kern.ipc.msgseg", &mainmsg.msginfo.msgseg);
+TUNABLE_INT("kern.ipc.msgssz", &mainmsg.msginfo.msgssz);
+TUNABLE_INT("kern.ipc.msgmni", &mainmsg.msginfo.msgmni);
 
 SYSCTL_DECL(_kern_ipc);
-SYSCTL_INT(_kern_ipc, OID_AUTO, msgmax, CTLFLAG_RD, &msginfo.msgmax, 0, "");
-SYSCTL_INT(_kern_ipc, OID_AUTO, msgmni, CTLFLAG_RD, &msginfo.msgmni, 0, "");
-SYSCTL_INT(_kern_ipc, OID_AUTO, msgmnb, CTLFLAG_RD, &msginfo.msgmnb, 0, "");
-SYSCTL_INT(_kern_ipc, OID_AUTO, msgtql, CTLFLAG_RD, &msginfo.msgtql, 0, "");
-SYSCTL_INT(_kern_ipc, OID_AUTO, msgssz, CTLFLAG_RD, &msginfo.msgssz, 0, "");
-SYSCTL_INT(_kern_ipc, OID_AUTO, msgseg, CTLFLAG_RD, &msginfo.msgseg, 0, "");
+
+static int
+sysctl_msqids(SYSCTL_HANDLER_ARGS)
+{
+	struct msgpriv *mp;
+
+	if (req->p->p_prison == NULL)
+		mp = &mainmsg;
+	else
+		mp = &req->p->p_prison->pr_msg;
+
+	return (SYSCTL_OUT(req, mp->msqids,
+	    sizeof(struct msqid_ds) * mp->msginfo.msgmni));
+}
 SYSCTL_PROC(_kern_ipc, OID_AUTO, msqids, CTLFLAG_RD,
     NULL, 0, sysctl_msqids, "", "Message queue IDs");
+
+static int
+sysctl_msginfo(SYSCTL_HANDLER_ARGS)
+{
+	struct msgpriv *mp;
+
+	if (req->p->p_prison == NULL)
+		mp = &mainmsg;
+	else
+		mp = &req->p->p_prison->pr_msg;
+
+	return (sysctl_handle_opaque(oidp, &mp->msginfo, sizeof(struct msginfo),
+	    req));
+}
+SYSCTL_PROC(_kern_ipc, OID_AUTO, msginfo, CTLTYPE_STRUCT | CTLFLAG_RD, 0, 0,
+    sysctl_msginfo, "S,msginfo","");
+
+#define	IPC_MSGMAX	0
+#define	IPC_MSGMNI	1
+#define	IPC_MSGMNB	2
+#define	IPC_MSGTQL	3
+#define	IPC_MSGSSZ	4
+#define	IPC_MSGSEG	5
+
+static int
+sysctl_msginfo_val(struct sysctl_oid *oidp, struct sysctl_req *req, u_int type)
+{
+	int *msginfo;
+	struct msgpriv *mp;
+
+	if (req->p->p_prison == NULL)
+		mp = &mainmsg;
+	else
+		mp = &req->p->p_prison->pr_msg;
+
+	switch (type) {
+	case IPC_MSGMAX:
+		msginfo = &mp->msginfo.msgmax;
+		break;
+	case IPC_MSGMNI:
+		msginfo = &mp->msginfo.msgmni;
+		break;
+	case IPC_MSGMNB:
+		msginfo = &mp->msginfo.msgmnb;
+		break;
+	case IPC_MSGTQL:
+		msginfo = &mp->msginfo.msgtql;
+		break;
+	case IPC_MSGSSZ:
+		msginfo = &mp->msginfo.msgssz;
+		break;
+	case IPC_MSGSEG:
+		msginfo = &mp->msginfo.msgseg;
+		break;
+	default:
+		panic("unknown msg type");
+	}
+
+	return (sysctl_handle_int(oidp, msginfo, 0, req));
+}
+
+static int
+sysctl_msginfo_msgmax(SYSCTL_HANDLER_ARGS)
+{
+
+	return (sysctl_msginfo_val(oidp, req, IPC_MSGMAX));
+}
+SYSCTL_PROC(_kern_ipc, OID_AUTO, msgmax, CTLTYPE_INT|CTLFLAG_RD, 0, 0,
+    sysctl_msginfo_msgmax, "IU", "");
+
+static int
+sysctl_msginfo_msgmni(SYSCTL_HANDLER_ARGS)
+{
+
+	return (sysctl_msginfo_val(oidp, req, IPC_MSGMNI));
+}
+SYSCTL_PROC(_kern_ipc, OID_AUTO, msgmni, CTLTYPE_INT|CTLFLAG_RD, 0, 0,
+    sysctl_msginfo_msgmni, "IU", "");
+
+static int
+sysctl_msginfo_msgmnb(SYSCTL_HANDLER_ARGS)
+{
+
+	return (sysctl_msginfo_val(oidp, req, IPC_MSGMNB));
+}
+SYSCTL_PROC(_kern_ipc, OID_AUTO, msgmnb, CTLTYPE_INT|CTLFLAG_RD, 0, 0,
+    sysctl_msginfo_msgmnb, "IU", "");
+
+static int
+sysctl_msginfo_msgtql(SYSCTL_HANDLER_ARGS)
+{
+
+	return (sysctl_msginfo_val(oidp, req, IPC_MSGTQL));
+}
+SYSCTL_PROC(_kern_ipc, OID_AUTO, msgtql, CTLTYPE_INT|CTLFLAG_RD, 0, 0,
+    sysctl_msginfo_msgtql, "IU", "");
+
+static int
+sysctl_msginfo_msgssz(SYSCTL_HANDLER_ARGS)
+{
+
+	return (sysctl_msginfo_val(oidp, req, IPC_MSGSSZ));
+}
+SYSCTL_PROC(_kern_ipc, OID_AUTO, msgssz, CTLTYPE_INT|CTLFLAG_RD, 0, 0,
+    sysctl_msginfo_msgssz, "IU", "");
+
+static int
+sysctl_msginfo_msgseg(SYSCTL_HANDLER_ARGS)
+{
+
+	return (sysctl_msginfo_val(oidp, req, IPC_MSGSEG));
+}
+SYSCTL_PROC(_kern_ipc, OID_AUTO, msgseg, CTLTYPE_INT|CTLFLAG_RD, 0, 0,
+    sysctl_msginfo_msgseg, "IU", "");
diff -ru /sys/kern/sysv_sem.c sys/kern/sysv_sem.c
--- /sys/kern/sysv_sem.c	Wed Feb 19 19:29:13 2003
+++ sys/kern/sysv_sem.c	Wed Feb 19 18:27:06 2003
@@ -1,9 +1,10 @@
-/* $FreeBSD: src/sys/kern/sysv_sem.c,v 1.24.2.8 2002/10/22 20:45:03 fjoe Exp $ */
+/* $FreeBSD$ */
 
 /*
  * Implementation of SVID semaphores
  *
  * Author:  Daniel Boulet
+ * Jailed by: Pawel Jakub Dawidek <nick@garage.freebsd.pl>
  *
  * This software is provided ``AS IS'' without any warranties of any kind.
  */
@@ -23,8 +24,6 @@
 
 static MALLOC_DEFINE(M_SEM, "sem", "SVID compatible semaphores");
 
-static void seminit __P((void *));
-
 #ifndef _SYS_SYSPROTO_H_
 struct __semctl_args;
 int __semctl __P((struct proc *p, struct __semctl_args *uap));
@@ -45,33 +44,6 @@
 	(sy_call_t *)semop
 };
 
-static int	semtot = 0;
-static struct semid_ds *sema;	/* semaphore id pool */
-static struct sem *sem;		/* semaphore pool */
-static struct sem_undo *semu_list; /* list of active undo structures */
-static int	*semu;		/* undo structure pool */
-
-struct sem {
-	u_short	semval;		/* semaphore value */
-	pid_t	sempid;		/* pid of last operation */
-	u_short	semncnt;	/* # awaiting semval > cval */
-	u_short	semzcnt;	/* # awaiting semval = 0 */
-};
-
-/*
- * Undo structure (one per process)
- */
-struct sem_undo {
-	struct	sem_undo *un_next;	/* ptr to next active undo structure */
-	struct	proc *un_proc;		/* owner of this structure */
-	short	un_cnt;			/* # of active entries */
-	struct undo {
-		short	un_adjval;	/* adjust on exit values */
-		short	un_num;		/* semaphore # */
-		int	un_id;		/* semid */
-	} un_ent[1];			/* undo entries */
-};
-
 /*
  * Configuration parameters
  */
@@ -115,46 +87,7 @@
 /*
  * Macro to find a particular sem_undo vector
  */
-#define SEMU(ix)	((struct sem_undo *)(((intptr_t)semu)+ix * seminfo.semusz))
-
-/*
- * semaphore info struct
- */
-struct seminfo seminfo = {
-                SEMMAP,         /* # of entries in semaphore map */
-                SEMMNI,         /* # of semaphore identifiers */
-                SEMMNS,         /* # of semaphores in system */
-                SEMMNU,         /* # of undo structures in system */
-                SEMMSL,         /* max # of semaphores per id */
-                SEMOPM,         /* max # of operations per semop call */
-                SEMUME,         /* max # of undo entries per process */
-                SEMUSZ,         /* size in bytes of undo structure */
-                SEMVMX,         /* semaphore maximum value */
-                SEMAEM          /* adjust on exit max value */
-};
-
-TUNABLE_INT("kern.ipc.semmap", &seminfo.semmap);
-TUNABLE_INT("kern.ipc.semmni", &seminfo.semmni);
-TUNABLE_INT("kern.ipc.semmns", &seminfo.semmns);
-TUNABLE_INT("kern.ipc.semmnu", &seminfo.semmnu);
-TUNABLE_INT("kern.ipc.semmsl", &seminfo.semmsl);
-TUNABLE_INT("kern.ipc.semopm", &seminfo.semopm);
-TUNABLE_INT("kern.ipc.semume", &seminfo.semume);
-TUNABLE_INT("kern.ipc.semusz", &seminfo.semusz);
-TUNABLE_INT("kern.ipc.semvmx", &seminfo.semvmx);
-TUNABLE_INT("kern.ipc.semaem", &seminfo.semaem);
-
-SYSCTL_DECL(_kern_ipc);
-SYSCTL_INT(_kern_ipc, OID_AUTO, semmap, CTLFLAG_RW, &seminfo.semmap, 0, "");
-SYSCTL_INT(_kern_ipc, OID_AUTO, semmni, CTLFLAG_RD, &seminfo.semmni, 0, "");
-SYSCTL_INT(_kern_ipc, OID_AUTO, semmns, CTLFLAG_RD, &seminfo.semmns, 0, "");
-SYSCTL_INT(_kern_ipc, OID_AUTO, semmnu, CTLFLAG_RD, &seminfo.semmnu, 0, "");
-SYSCTL_INT(_kern_ipc, OID_AUTO, semmsl, CTLFLAG_RW, &seminfo.semmsl, 0, "");
-SYSCTL_INT(_kern_ipc, OID_AUTO, semopm, CTLFLAG_RD, &seminfo.semopm, 0, "");
-SYSCTL_INT(_kern_ipc, OID_AUTO, semume, CTLFLAG_RD, &seminfo.semume, 0, "");
-SYSCTL_INT(_kern_ipc, OID_AUTO, semusz, CTLFLAG_RD, &seminfo.semusz, 0, "");
-SYSCTL_INT(_kern_ipc, OID_AUTO, semvmx, CTLFLAG_RW, &seminfo.semvmx, 0, "");
-SYSCTL_INT(_kern_ipc, OID_AUTO, semaem, CTLFLAG_RW, &seminfo.semaem, 0, "");
+#define SEMU(ix)	((struct sem_undo *)(((intptr_t)sp->semu)+ix * sp->seminfo.semusz))
 
 #if 0
 RO seminfo.semmap	/* SEMMAP unused */
@@ -169,31 +102,79 @@
 RO seminfo.semaem	/* SEMAEM unused - user param */
 #endif
 
-static void
-seminit(dummy)
-	void *dummy;
+/* Global struct for main system, all jails have its own. */
+struct sempriv mainsem;
+
+int
+seminit(struct prison *pr)
 {
 	register int i;
+	struct sempriv *sp;
+	int error;
+
+	if (pr == NULL)
+		sp = &mainsem;
+	else
+		sp = &pr->pr_sem;
+
+	sp->semtot = 0;
+
+	sp->seminfo.semmap = SEMMAP;
+	sp->seminfo.semmni = SEMMNI;
+	sp->seminfo.semmns = SEMMNS;
+	sp->seminfo.semmnu = SEMMNU;
+	sp->seminfo.semmsl = SEMMSL;
+	sp->seminfo.semopm = SEMOPM;
+	sp->seminfo.semume = SEMUME;
+	sp->seminfo.semusz = SEMUSZ;
+	sp->seminfo.semvmx = SEMVMX;
+	sp->seminfo.semaem = SEMAEM;
+
+	sp->sem = malloc(sizeof(struct sem) * sp->seminfo.semmns, M_SEM, M_WAITOK);
+	if (sp->sem == NULL) {
+		if (pr == NULL)
+			panic("sem is NULL");
+		else
+			return (ENOMEM);
+	}
 
-	sem = malloc(sizeof(struct sem) * seminfo.semmns, M_SEM, M_WAITOK);
-	if (sem == NULL)
-		panic("sem is NULL");
-	sema = malloc(sizeof(struct semid_ds) * seminfo.semmni, M_SEM, M_WAITOK);
-	if (sema == NULL)
-		panic("sema is NULL");
-	semu = malloc(seminfo.semmnu * seminfo.semusz, M_SEM, M_WAITOK);
-	if (semu == NULL)
-		panic("semu is NULL");
-
-	for (i = 0; i < seminfo.semmni; i++) {
-		sema[i].sem_base = 0;
-		sema[i].sem_perm.mode = 0;
+	sp->sema = malloc(sizeof(struct semid_ds) * sp->seminfo.semmni, M_SEM, M_WAITOK);
+	if (sp->sema == NULL) {
+		if (pr == NULL)
+			panic("sema is NULL");
+		else {
+			error = ENOMEM;
+			goto fail_sema;
+		}
+	}
+
+	sp->semu = malloc(sp->seminfo.semmnu * sp->seminfo.semusz, M_SEM, M_WAITOK);
+	if (sp->semu == NULL) {
+		if (pr == NULL)
+			panic("semu is NULL");
+		else {
+			error = ENOMEM;
+			goto fail_semu;
+		}
 	}
-	for (i = 0; i < seminfo.semmnu; i++) {
+
+	for (i = 0; i < sp->seminfo.semmni; i++) {
+		sp->sema[i].sem_base = 0;
+		sp->sema[i].sem_perm.mode = 0;
+	}
+	for (i = 0; i < sp->seminfo.semmnu; i++) {
 		register struct sem_undo *suptr = SEMU(i);
 		suptr->un_proc = NULL;
 	}
-	semu_list = NULL;
+	sp->semu_list = NULL;
+
+	return (0);
+fail_sema:
+	free(sp->sem, M_SEM);
+fail_semu:
+	free(sp->sema, M_SEM);
+
+	return (error);
 }
 SYSINIT(sysv_sem, SI_SUB_SYSV_SEM, SI_ORDER_FIRST, seminit, NULL)
 
@@ -234,6 +215,12 @@
 	register struct sem_undo *suptr;
 	register struct sem_undo **supptr;
 	int attempt;
+	struct sempriv *sp;
+
+	if (p->p_prison == NULL)
+		sp = &mainsem;
+	else
+		sp = &p->p_prison->pr_sem;
 
 	/*
 	 * Try twice to allocate something.
@@ -247,11 +234,11 @@
 		 * Fill it in and return it if we find one.
 		 */
 
-		for (i = 0; i < seminfo.semmnu; i++) {
+		for (i = 0; i < sp->seminfo.semmnu; i++) {
 			suptr = SEMU(i);
 			if (suptr->un_proc == NULL) {
-				suptr->un_next = semu_list;
-				semu_list = suptr;
+				suptr->un_next = sp->semu_list;
+				sp->semu_list = suptr;
 				suptr->un_cnt = 0;
 				suptr->un_proc = p;
 				return(suptr);
@@ -267,7 +254,7 @@
 			/* All the structures are in use - try to free some */
 			int did_something = 0;
 
-			supptr = &semu_list;
+			supptr = &sp->semu_list;
 			while ((suptr = *supptr) != NULL) {
 				if (suptr->un_cnt == 0)  {
 					suptr->un_proc = NULL;
@@ -306,13 +293,19 @@
 	register struct sem_undo *suptr;
 	register struct undo *sunptr;
 	int i;
+	struct sempriv *sp;
+
+	if (p->p_prison == NULL)
+		sp = &mainsem;
+	else
+		sp = &p->p_prison->pr_sem;
 
 	/* Look for and remember the sem_undo if the caller doesn't provide
 	   it */
 
 	suptr = *supptr;
 	if (suptr == NULL) {
-		for (suptr = semu_list; suptr != NULL;
+		for (suptr = sp->semu_list; suptr != NULL;
 		    suptr = suptr->un_next) {
 			if (suptr->un_proc == p) {
 				*supptr = suptr;
@@ -353,7 +346,7 @@
 	/* Didn't find the right entry - create it */
 	if (adjval == 0)
 		return(0);
-	if (suptr->un_cnt != seminfo.semume) {
+	if (suptr->un_cnt != sp->seminfo.semume) {
 		sunptr = &suptr->un_ent[suptr->un_cnt];
 		suptr->un_cnt++;
 		sunptr->un_adjval = adjval;
@@ -368,8 +361,14 @@
 	int semid, semnum;
 {
 	register struct sem_undo *suptr;
+	struct sempriv *sp;
+
+	if (curproc->p_prison == NULL)
+		sp = &mainsem;
+	else
+		sp = &curproc->p_prison->pr_sem;
 
-	for (suptr = semu_list; suptr != NULL; suptr = suptr->un_next) {
+	for (suptr = sp->semu_list; suptr != NULL; suptr = suptr->un_next) {
 		register struct undo *sunptr = &suptr->un_ent[0];
 		register int i = 0;
 
@@ -417,6 +416,7 @@
 	int i, rval, eval;
 	struct semid_ds sbuf;
 	register struct semid_ds *semaptr;
+	struct sempriv *sp;
 
 #ifdef SEM_DEBUG
 	printf("call to semctl(%d, %d, %d, 0x%x)\n", semid, semnum, cmd, arg);
@@ -425,11 +425,16 @@
 	if (!jail_sysvipc_allowed && p->p_prison != NULL)
 		return (ENOSYS);
 
+	if (p->p_prison == NULL)
+		sp = &mainsem;
+	else
+		sp = &p->p_prison->pr_sem;
+
 	semid = IPCID_TO_IX(semid);
-	if (semid < 0 || semid >= seminfo.semmni)
+	if (semid < 0 || semid >= sp->seminfo.semmni)
 		return(EINVAL);
 
-	semaptr = &sema[semid];
+	semaptr = &sp->sema[semid];
 	if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0 ||
 	    semaptr->sem_perm.seq != IPCID_TO_SEQ(uap->semid))
 		return(EINVAL);
@@ -443,13 +448,13 @@
 			return(eval);
 		semaptr->sem_perm.cuid = cred->cr_uid;
 		semaptr->sem_perm.uid = cred->cr_uid;
-		semtot -= semaptr->sem_nsems;
-		for (i = semaptr->sem_base - sem; i < semtot; i++)
-			sem[i] = sem[i + semaptr->sem_nsems];
-		for (i = 0; i < seminfo.semmni; i++) {
-			if ((sema[i].sem_perm.mode & SEM_ALLOC) &&
-			    sema[i].sem_base > semaptr->sem_base)
-				sema[i].sem_base -= semaptr->sem_nsems;
+		sp->semtot -= semaptr->sem_nsems;
+		for (i = semaptr->sem_base - sp->sem; i < sp->semtot; i++)
+			sp->sem[i] = sp->sem[i + semaptr->sem_nsems];
+		for (i = 0; i < sp->seminfo.semmni; i++) {
+			if ((sp->sema[i].sem_perm.mode & SEM_ALLOC) &&
+			    sp->sema[i].sem_base > semaptr->sem_base)
+				sp->sema[i].sem_base -= semaptr->sem_nsems;
 		}
 		semaptr->sem_perm.mode = 0;
 		semundo_clear(semid, -1);
@@ -580,6 +585,7 @@
 	int nsems = uap->nsems;
 	int semflg = uap->semflg;
 	struct ucred *cred = p->p_ucred;
+	struct sempriv *sp;
 
 #ifdef SEM_DEBUG
 	printf("semget(0x%x, %d, 0%o)\n", key, nsems, semflg);
@@ -588,20 +594,25 @@
 	if (!jail_sysvipc_allowed && p->p_prison != NULL)
 		return (ENOSYS);
 
+	if (p->p_prison == NULL)
+		sp = &mainsem;
+	else
+		sp = &p->p_prison->pr_sem;
+
 	if (key != IPC_PRIVATE) {
-		for (semid = 0; semid < seminfo.semmni; semid++) {
-			if ((sema[semid].sem_perm.mode & SEM_ALLOC) &&
-			    sema[semid].sem_perm.key == key)
+		for (semid = 0; semid < sp->seminfo.semmni; semid++) {
+			if ((sp->sema[semid].sem_perm.mode & SEM_ALLOC) &&
+			    sp->sema[semid].sem_perm.key == key)
 				break;
 		}
-		if (semid < seminfo.semmni) {
+		if (semid < sp->seminfo.semmni) {
 #ifdef SEM_DEBUG
 			printf("found public key\n");
 #endif
-			if ((eval = ipcperm(p, &sema[semid].sem_perm,
+			if ((eval = ipcperm(p, &sp->sema[semid].sem_perm,
 			    semflg & 0700)))
 				return(eval);
-			if (nsems > 0 && sema[semid].sem_nsems < nsems) {
+			if (nsems > 0 && sp->sema[semid].sem_nsems < nsems) {
 #ifdef SEM_DEBUG
 				printf("too small\n");
 #endif
@@ -621,25 +632,25 @@
 	printf("need to allocate the semid_ds\n");
 #endif
 	if (key == IPC_PRIVATE || (semflg & IPC_CREAT)) {
-		if (nsems <= 0 || nsems > seminfo.semmsl) {
+		if (nsems <= 0 || nsems > sp->seminfo.semmsl) {
 #ifdef SEM_DEBUG
 			printf("nsems out of range (0<%d<=%d)\n", nsems,
-			    seminfo.semmsl);
+			    sp->seminfo.semmsl);
 #endif
 			return(EINVAL);
 		}
-		if (nsems > seminfo.semmns - semtot) {
+		if (nsems > sp->seminfo.semmns - sp->semtot) {
 #ifdef SEM_DEBUG
 			printf("not enough semaphores left (need %d, got %d)\n",
-			    nsems, seminfo.semmns - semtot);
+			    nsems, sp->seminfo.semmns - sp->semtot);
 #endif
 			return(ENOSPC);
 		}
-		for (semid = 0; semid < seminfo.semmni; semid++) {
-			if ((sema[semid].sem_perm.mode & SEM_ALLOC) == 0)
+		for (semid = 0; semid < sp->seminfo.semmni; semid++) {
+			if ((sp->sema[semid].sem_perm.mode & SEM_ALLOC) == 0)
 				break;
 		}
-		if (semid == seminfo.semmni) {
+		if (semid == sp->seminfo.semmni) {
 #ifdef SEM_DEBUG
 			printf("no more semid_ds's available\n");
 #endif
@@ -648,24 +659,24 @@
 #ifdef SEM_DEBUG
 		printf("semid %d is available\n", semid);
 #endif
-		sema[semid].sem_perm.key = key;
-		sema[semid].sem_perm.cuid = cred->cr_uid;
-		sema[semid].sem_perm.uid = cred->cr_uid;
-		sema[semid].sem_perm.cgid = cred->cr_gid;
-		sema[semid].sem_perm.gid = cred->cr_gid;
-		sema[semid].sem_perm.mode = (semflg & 0777) | SEM_ALLOC;
-		sema[semid].sem_perm.seq =
-		    (sema[semid].sem_perm.seq + 1) & 0x7fff;
-		sema[semid].sem_nsems = nsems;
-		sema[semid].sem_otime = 0;
-		sema[semid].sem_ctime = time_second;
-		sema[semid].sem_base = &sem[semtot];
-		semtot += nsems;
-		bzero(sema[semid].sem_base,
-		    sizeof(sema[semid].sem_base[0])*nsems);
+		sp->sema[semid].sem_perm.key = key;
+		sp->sema[semid].sem_perm.cuid = cred->cr_uid;
+		sp->sema[semid].sem_perm.uid = cred->cr_uid;
+		sp->sema[semid].sem_perm.cgid = cred->cr_gid;
+		sp->sema[semid].sem_perm.gid = cred->cr_gid;
+		sp->sema[semid].sem_perm.mode = (semflg & 0777) | SEM_ALLOC;
+		sp->sema[semid].sem_perm.seq =
+		    (sp->sema[semid].sem_perm.seq + 1) & 0x7fff;
+		sp->sema[semid].sem_nsems = nsems;
+		sp->sema[semid].sem_otime = 0;
+		sp->sema[semid].sem_ctime = time_second;
+		sp->sema[semid].sem_base = &sp->sem[sp->semtot];
+		sp->semtot += nsems;
+		bzero(sp->sema[semid].sem_base,
+		    sizeof(sp->sema[semid].sem_base[0])*nsems);
 #ifdef SEM_DEBUG
-		printf("sembase = 0x%x, next = 0x%x\n", sema[semid].sem_base,
-		    &sem[semtot]);
+		printf("sembase = 0x%x, next = 0x%x\n", sp->sema[semid].sem_base,
+		    &sp->sem[sp->semtot]);
 #endif
 	} else {
 #ifdef SEM_DEBUG
@@ -675,7 +686,7 @@
 	}
 
 found:
-	p->p_retval[0] = IXSEQ_TO_IPCID(semid, sema[semid].sem_perm);
+	p->p_retval[0] = IXSEQ_TO_IPCID(semid, sp->sema[semid].sem_perm);
 	return(0);
 }
 
@@ -701,6 +712,7 @@
 	struct sem_undo *suptr = NULL;
 	int i, j, eval;
 	int do_wakeup, do_undos;
+	struct sempriv *sp;
 
 #ifdef SEM_DEBUG
 	printf("call to semop(%d, 0x%x, %u)\n", semid, sops, nsops);
@@ -709,12 +721,17 @@
 	if (!jail_sysvipc_allowed && p->p_prison != NULL)
 		return (ENOSYS);
 
+	if (p->p_prison == NULL)
+		sp = &mainsem;
+	else
+		sp = &p->p_prison->pr_sem;
+
 	semid = IPCID_TO_IX(semid);	/* Convert back to zero origin */
 
-	if (semid < 0 || semid >= seminfo.semmni)
+	if (semid < 0 || semid >= sp->seminfo.semmni)
 		return(EINVAL);
 
-	semaptr = &sema[semid];
+	semaptr = &sp->sema[semid];
 	if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0)
 		return(EINVAL);
 	if (semaptr->sem_perm.seq != IPCID_TO_SEQ(uap->semid))
@@ -951,6 +968,12 @@
 	register struct sem_undo *suptr;
 	register struct sem_undo **supptr;
 	int did_something;
+	struct sempriv *sp;
+
+	if (p->p_prison == NULL)
+		sp = &mainsem;
+	else
+		sp = &p->p_prison->pr_sem;
 
 	did_something = 0;
 
@@ -959,7 +982,7 @@
 	 * associated with this process.
 	 */
 
-	for (supptr = &semu_list; (suptr = *supptr) != NULL;
+	for (supptr = &sp->semu_list; (suptr = *supptr) != NULL;
 	    supptr = &suptr->un_next) {
 		if (suptr->un_proc == p)
 			break;
@@ -985,7 +1008,7 @@
 			int adjval = suptr->un_ent[ix].un_adjval;
 			struct semid_ds *semaptr;
 
-			semaptr = &sema[semid];
+			semaptr = &sp->sema[semid];
 			if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0)
 				panic("semexit - semid not allocated");
 			if (semnum >= semaptr->sem_nsems)
@@ -1024,3 +1047,213 @@
 	suptr->un_proc = NULL;
 	*supptr = suptr->un_next;
 }
+
+void
+semclear(struct prison *pr)
+{
+	struct sempriv *sp;
+
+	if (pr == NULL)
+		sp = &mainsem;
+	else
+		sp = &pr->pr_sem;
+
+	free(sp->sem, M_SEM);
+	free(sp->sema, M_SEM);
+	free(sp->semu, M_SEM);
+}
+
+TUNABLE_INT("kern.ipc.semmap", &mainsem.seminfo.semmap);
+TUNABLE_INT("kern.ipc.semmni", &mainsem.seminfo.semmni);
+TUNABLE_INT("kern.ipc.semmns", &mainsem.seminfo.semmns);
+TUNABLE_INT("kern.ipc.semmnu", &mainsem.seminfo.semmnu);
+TUNABLE_INT("kern.ipc.semmsl", &mainsem.seminfo.semmsl);
+TUNABLE_INT("kern.ipc.semopm", &mainsem.seminfo.semopm);
+TUNABLE_INT("kern.ipc.semume", &mainsem.seminfo.semume);
+TUNABLE_INT("kern.ipc.semusz", &mainsem.seminfo.semusz);
+TUNABLE_INT("kern.ipc.semvmx", &mainsem.seminfo.semvmx);
+TUNABLE_INT("kern.ipc.semaem", &mainsem.seminfo.semaem);
+
+SYSCTL_DECL(_kern_ipc);
+
+static int
+sysctl_sema(SYSCTL_HANDLER_ARGS)
+{
+	struct sempriv *sp;
+
+	if (req->p->p_prison == NULL)
+		sp = &mainsem;
+	else
+		sp = &req->p->p_prison->pr_sem;
+
+	return (SYSCTL_OUT(req, sp->sema,
+	    sizeof(struct semid_ds) * sp->seminfo.semmni));
+}
+SYSCTL_PROC(_kern_ipc, OID_AUTO, sema, CTLFLAG_RD,
+    NULL, 0, sysctl_sema, "", "Semaphores IDs");
+
+static int
+sysctl_seminfo(SYSCTL_HANDLER_ARGS)
+{
+	struct sempriv *sp;
+
+	if (req->p->p_prison == NULL)
+		sp = &mainsem;
+	else
+		sp = &req->p->p_prison->pr_sem;
+
+	return (sysctl_handle_opaque(oidp, &sp->seminfo, sizeof(struct seminfo),
+	    req));
+}
+SYSCTL_PROC(_kern_ipc, OID_AUTO, seminfo, CTLTYPE_STRUCT | CTLFLAG_RD, 0, 0,
+    sysctl_seminfo, "S,seminfo","");
+
+#define	IPC_SEMMAP	0
+#define	IPC_SEMMNI	1
+#define	IPC_SEMMNS	2
+#define	IPC_SEMMNU	3
+#define	IPC_SEMMSL	4
+#define	IPC_SEMOPM	5
+#define	IPC_SEMUME	6
+#define	IPC_SEMUSZ	7
+#define	IPC_SEMVMX	8
+#define	IPC_SEMAEM	9
+
+static int
+sysctl_seminfo_val(struct sysctl_oid *oidp, struct sysctl_req *req, u_int type)
+{
+	int *seminfo;
+	struct sempriv *sp;
+
+	if (req->p->p_prison == NULL)
+		sp = &mainsem;
+	else
+		sp = &req->p->p_prison->pr_sem;
+
+	switch (type) {
+	case IPC_SEMMAP:
+		seminfo = &sp->seminfo.semmap;
+		break;
+	case IPC_SEMMNI:
+		seminfo = &sp->seminfo.semmni;
+		break;
+	case IPC_SEMMNS:
+		seminfo = &sp->seminfo.semmns;
+		break;
+	case IPC_SEMMNU:
+		seminfo = &sp->seminfo.semmnu;
+		break;
+	case IPC_SEMMSL:
+		seminfo = &sp->seminfo.semmsl;
+		break;
+	case IPC_SEMOPM:
+		seminfo = &sp->seminfo.semopm;
+		break;
+	case IPC_SEMUME:
+		seminfo = &sp->seminfo.semume;
+		break;
+	case IPC_SEMUSZ:
+		seminfo = &sp->seminfo.semume;
+		break;
+	case IPC_SEMVMX:
+		seminfo = &sp->seminfo.semvmx;
+		break;
+	case IPC_SEMAEM:
+		seminfo = &sp->seminfo.semaem;
+		break;
+	default:
+		panic("unknown sem type");
+	}
+
+	return (sysctl_handle_int(oidp, seminfo, 0, req));
+}
+
+static int
+sysctl_seminfo_semmap(SYSCTL_HANDLER_ARGS)
+{
+
+	return (sysctl_seminfo_val(oidp, req, IPC_SEMMAP));
+}
+SYSCTL_PROC(_kern_ipc, OID_AUTO, semmap, CTLTYPE_INT | CTLFLAG_RD, 0, 0,
+    sysctl_seminfo_semmap, "IU", "");
+
+static int
+sysctl_seminfo_semmni(SYSCTL_HANDLER_ARGS)
+{
+
+	return (sysctl_seminfo_val(oidp, req, IPC_SEMMNI));
+}
+SYSCTL_PROC(_kern_ipc, OID_AUTO, semmni, CTLTYPE_INT | CTLFLAG_RD, 0, 0,
+    sysctl_seminfo_semmni, "IU", "");
+
+static int
+sysctl_seminfo_semmns(SYSCTL_HANDLER_ARGS)
+{
+
+	return (sysctl_seminfo_val(oidp, req, IPC_SEMMNS));
+}
+SYSCTL_PROC(_kern_ipc, OID_AUTO, semmns, CTLTYPE_INT | CTLFLAG_RD, 0, 0,
+    sysctl_seminfo_semmns, "IU", "");
+
+static int
+sysctl_seminfo_semmnu(SYSCTL_HANDLER_ARGS)
+{
+
+	return (sysctl_seminfo_val(oidp, req, IPC_SEMMNU));
+}
+SYSCTL_PROC(_kern_ipc, OID_AUTO, semmnu, CTLTYPE_INT | CTLFLAG_RD, 0, 0,
+    sysctl_seminfo_semmnu, "IU", "");
+
+static int
+sysctl_seminfo_semmsl(SYSCTL_HANDLER_ARGS)
+{
+
+	return (sysctl_seminfo_val(oidp, req, IPC_SEMMSL));
+}
+SYSCTL_PROC(_kern_ipc, OID_AUTO, semmsl, CTLTYPE_INT | CTLFLAG_RD, 0, 0,
+    sysctl_seminfo_semmsl, "IU", "");
+
+static int
+sysctl_seminfo_semopm(SYSCTL_HANDLER_ARGS)
+{
+
+	return (sysctl_seminfo_val(oidp, req, IPC_SEMOPM));
+}
+SYSCTL_PROC(_kern_ipc, OID_AUTO, semopm, CTLTYPE_INT | CTLFLAG_RD, 0, 0,
+    sysctl_seminfo_semopm, "IU", "");
+
+static int
+sysctl_seminfo_semume(SYSCTL_HANDLER_ARGS)
+{
+
+	return (sysctl_seminfo_val(oidp, req, IPC_SEMUME));
+}
+SYSCTL_PROC(_kern_ipc, OID_AUTO, semume, CTLTYPE_INT | CTLFLAG_RD, 0, 0,
+    sysctl_seminfo_semume, "IU", "");
+
+static int
+sysctl_seminfo_semusz(SYSCTL_HANDLER_ARGS)
+{
+
+	return (sysctl_seminfo_val(oidp, req, IPC_SEMUSZ));
+}
+SYSCTL_PROC(_kern_ipc, OID_AUTO, semusz, CTLTYPE_INT | CTLFLAG_RD, 0, 0,
+    sysctl_seminfo_semusz, "IU", "");
+
+static int
+sysctl_seminfo_semvmx(SYSCTL_HANDLER_ARGS)
+{
+
+	return (sysctl_seminfo_val(oidp, req, IPC_SEMVMX));
+}
+SYSCTL_PROC(_kern_ipc, OID_AUTO, semvmx, CTLTYPE_INT | CTLFLAG_RD, 0, 0,
+    sysctl_seminfo_semvmx, "IU", "");
+
+static int
+sysctl_seminfo_semaem(SYSCTL_HANDLER_ARGS)
+{
+
+	return (sysctl_seminfo_val(oidp, req, IPC_SEMAEM));
+}
+SYSCTL_PROC(_kern_ipc, OID_AUTO, semaem, CTLTYPE_INT | CTLFLAG_RD, 0, 0,
+    sysctl_seminfo_semaem, "IU", "");
diff -ru /sys/kern/sysv_shm.c sys/kern/sysv_shm.c
--- /sys/kern/sysv_shm.c	Wed Feb 19 19:29:13 2003
+++ sys/kern/sysv_shm.c	Wed Feb 19 18:27:12 2003
@@ -1,8 +1,9 @@
-/* $FreeBSD: src/sys/kern/sysv_shm.c,v 1.45.2.6 2002/10/22 20:45:03 fjoe Exp $ */
+/* $FreeBSD$ */
 /*	$NetBSD: sysv_shm.c,v 1.23 1994/07/04 23:25:12 glass Exp $	*/
 
 /*
  * Copyright (c) 1994 Adam Glass and Charles Hannum.  All rights reserved.
+ * Jailed by: Pawel Jakub Dawidek <nick@garage.freebsd.pl>
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -76,9 +77,6 @@
 #define	SHMSEG_ALLOCATED	0x0800
 #define	SHMSEG_WANTED		0x1000
 
-static int shm_last_free, shm_nused, shm_committed, shmalloced;
-static struct shmid_ds	*shmsegs;
-
 struct shm_handle {
 	/* vm_offset_t kva; */
 	vm_object_t shm_object;
@@ -94,7 +92,6 @@
 static struct shmid_ds *shm_find_segment_by_shmid __P((int));
 static int shm_delete_mapping __P((struct proc *, struct shmmap_state *));
 static void shmrealloc __P((void));
-static void shminit __P((void *));
 
 /*
  * Tuneable values
@@ -118,39 +115,24 @@
 #define	SHMALL	(SHMMAXPGS)
 #endif
 
-struct	shminfo shminfo = {
-	SHMMAX,
-	SHMMIN,
-	SHMMNI,
-	SHMSEG,
-	SHMALL
-};
-
-static int shm_use_phys;
-
-TUNABLE_INT("kern.ipc.shmmin", &shminfo.shmmin);
-TUNABLE_INT("kern.ipc.shmmni", &shminfo.shmmni);
-TUNABLE_INT("kern.ipc.shmseg", &shminfo.shmseg);
-TUNABLE_INT("kern.ipc.shmmaxpgs", &shminfo.shmall);
-TUNABLE_INT("kern.ipc.shm_use_phys", &shm_use_phys);
-
-SYSCTL_DECL(_kern_ipc);
-SYSCTL_INT(_kern_ipc, OID_AUTO, shmmax, CTLFLAG_RW, &shminfo.shmmax, 0, "");
-SYSCTL_INT(_kern_ipc, OID_AUTO, shmmin, CTLFLAG_RW, &shminfo.shmmin, 0, "");
-SYSCTL_INT(_kern_ipc, OID_AUTO, shmmni, CTLFLAG_RD, &shminfo.shmmni, 0, "");
-SYSCTL_INT(_kern_ipc, OID_AUTO, shmseg, CTLFLAG_RW, &shminfo.shmseg, 0, "");
-SYSCTL_INT(_kern_ipc, OID_AUTO, shmall, CTLFLAG_RW, &shminfo.shmall, 0, "");
-SYSCTL_INT(_kern_ipc, OID_AUTO, shm_use_phys, CTLFLAG_RW, &shm_use_phys, 0, "");
+/* Global struct for main system, all jails have its own. */
+struct shmpriv mainshm;
 
 static int
 shm_find_segment_by_key(key)
 	key_t key;
 {
 	int i;
+	struct shmpriv *sp;
 
-	for (i = 0; i < shmalloced; i++)
-		if ((shmsegs[i].shm_perm.mode & SHMSEG_ALLOCATED) &&
-		    shmsegs[i].shm_perm.key == key)
+	if (curproc->p_prison == NULL)
+		sp = &mainshm;
+	else
+		sp = &curproc->p_prison->pr_shm;
+
+	for (i = 0; i < sp->shmalloced; i++)
+		if ((sp->shmsegs[i].shm_perm.mode & SHMSEG_ALLOCATED) &&
+		    sp->shmsegs[i].shm_perm.key == key)
 			return i;
 	return -1;
 }
@@ -161,11 +143,17 @@
 {
 	int segnum;
 	struct shmid_ds *shmseg;
+	struct shmpriv *sp;
+
+	if (curproc->p_prison == NULL)
+		sp = &mainshm;
+	else
+		sp = &curproc->p_prison->pr_shm;
 
 	segnum = IPCID_TO_IX(shmid);
-	if (segnum < 0 || segnum >= shmalloced)
+	if (segnum < 0 || segnum >= sp->shmalloced)
 		return NULL;
-	shmseg = &shmsegs[segnum];
+	shmseg = &sp->shmsegs[segnum];
 	if ((shmseg->shm_perm.mode & (SHMSEG_ALLOCATED | SHMSEG_REMOVED))
 	    != SHMSEG_ALLOCATED ||
 	    shmseg->shm_perm.seq != IPCID_TO_SEQ(shmid))
@@ -179,14 +167,20 @@
 {
 	struct shm_handle *shm_handle;
 	size_t size;
+	struct shmpriv *sp;
+
+	if (curproc->p_prison == NULL)
+		sp = &mainshm;
+	else
+		sp = &curproc->p_prison->pr_shm;
 
 	shm_handle = shmseg->shm_internal;
 	vm_object_deallocate(shm_handle->shm_object);
 	free((caddr_t)shm_handle, M_SHM);
 	shmseg->shm_internal = NULL;
 	size = round_page(shmseg->shm_segsz);
-	shm_committed -= btoc(size);
-	shm_nused--;
+	sp->shm_committed -= btoc(size);
+	sp->shm_nused--;
 	shmseg->shm_perm.mode = SHMSEG_FREE;
 }
 
@@ -198,9 +192,15 @@
 	struct shmid_ds *shmseg;
 	int segnum, result;
 	size_t size;
+	struct shmpriv *sp;
+
+	if (p->p_prison == NULL)
+		sp = &mainshm;
+	else
+		sp = &p->p_prison->pr_shm;
 
 	segnum = IPCID_TO_IX(shmmap_s->shmid);
-	shmseg = &shmsegs[segnum];
+	shmseg = &sp->shmsegs[segnum];
 	size = round_page(shmseg->shm_segsz);
 	result = vm_map_remove(&p->p_vmspace->vm_map, shmmap_s->va, shmmap_s->va + size);
 	if (result != KERN_SUCCESS)
@@ -210,7 +210,7 @@
 	if ((--shmseg->shm_nattch <= 0) &&
 	    (shmseg->shm_perm.mode & SHMSEG_REMOVED)) {
 		shm_deallocate_segment(shmseg);
-		shm_last_free = segnum;
+		sp->shm_last_free = segnum;
 	}
 	return 0;
 }
@@ -228,18 +228,24 @@
 {
 	struct shmmap_state *shmmap_s;
 	int i;
+	struct shmpriv *sp;
 
 	if (!jail_sysvipc_allowed && p->p_prison != NULL)
 		return (ENOSYS);
 
+	if (p->p_prison == NULL)
+		sp = &mainshm;
+	else
+		sp = &p->p_prison->pr_shm;
+
 	shmmap_s = (struct shmmap_state *)p->p_vmspace->vm_shm;
  	if (shmmap_s == NULL)
  	    return EINVAL;
-	for (i = 0; i < shminfo.shmseg; i++, shmmap_s++)
+	for (i = 0; i < sp->shminfo.shmseg; i++, shmmap_s++)
 		if (shmmap_s->shmid != -1 &&
 		    shmmap_s->va == (vm_offset_t)uap->shmaddr)
 			break;
-	if (i == shminfo.shmseg)
+	if (i == sp->shminfo.shmseg)
 		return EINVAL;
 	return shm_delete_mapping(p, shmmap_s);
 }
@@ -265,15 +271,21 @@
 	vm_prot_t prot;
 	vm_size_t size;
 	int rv;
+	struct shmpriv *sp;
 
 	if (!jail_sysvipc_allowed && p->p_prison != NULL)
 		return (ENOSYS);
 
+	if (p->p_prison == NULL)
+		sp = &mainshm;
+	else
+		sp = &p->p_prison->pr_shm;
+
 	shmmap_s = (struct shmmap_state *)p->p_vmspace->vm_shm;
 	if (shmmap_s == NULL) {
-		size = shminfo.shmseg * sizeof(struct shmmap_state);
+		size = sp->shminfo.shmseg * sizeof(struct shmmap_state);
 		shmmap_s = malloc(size, M_SHM, M_WAITOK);
-		for (i = 0; i < shminfo.shmseg; i++)
+		for (i = 0; i < sp->shminfo.shmseg; i++)
 			shmmap_s[i].shmid = -1;
 		p->p_vmspace->vm_shm = (caddr_t)shmmap_s;
 	}
@@ -284,12 +296,12 @@
 	    (uap->shmflg & SHM_RDONLY) ? IPC_R : IPC_R|IPC_W);
 	if (error)
 		return error;
-	for (i = 0; i < shminfo.shmseg; i++) {
+	for (i = 0; i < sp->shminfo.shmseg; i++) {
 		if (shmmap_s->shmid == -1)
 			break;
 		shmmap_s++;
 	}
-	if (i >= shminfo.shmseg)
+	if (i >= sp->shminfo.shmseg)
 		return EMFILE;
 	size = round_page(shmseg->shm_segsz);
 #ifdef VM_PROT_READ_IS_EXEC
@@ -410,10 +422,16 @@
 	int error;
 	struct shmid_ds inbuf;
 	struct shmid_ds *shmseg;
+	struct shmpriv *sp;
 
 	if (!jail_sysvipc_allowed && p->p_prison != NULL)
 		return (ENOSYS);
 
+	if (p->p_prison == NULL)
+		sp = &mainshm;
+	else
+		sp = &p->p_prison->pr_shm;
+
 	shmseg = shm_find_segment_by_shmid(uap->shmid);
 	if (shmseg == NULL)
 		return EINVAL;
@@ -448,7 +466,7 @@
 		shmseg->shm_perm.mode |= SHMSEG_REMOVED;
 		if (shmseg->shm_nattch <= 0) {
 			shm_deallocate_segment(shmseg);
-			shm_last_free = IPCID_TO_IX(uap->shmid);
+			sp->shm_last_free = IPCID_TO_IX(uap->shmid);
 		}
 		break;
 #if 0
@@ -478,8 +496,14 @@
 {
 	struct shmid_ds *shmseg;
 	int error;
+	struct shmpriv *sp;
+
+	if (p->p_prison == NULL)
+		sp = &mainshm;
+	else
+		sp = &p->p_prison->pr_shm;
 
-	shmseg = &shmsegs[segnum];
+	shmseg = &sp->shmsegs[segnum];
 	if (shmseg->shm_perm.mode & SHMSEG_REMOVED) {
 		/*
 		 * This segment is in the process of being allocated.  Wait
@@ -513,27 +537,33 @@
 	struct ucred *cred = p->p_ucred;
 	struct shmid_ds *shmseg;
 	struct shm_handle *shm_handle;
+	struct shmpriv *sp;
+
+	if (p->p_prison == NULL)
+		sp = &mainshm;
+	else
+		sp = &p->p_prison->pr_shm;
 
-	if (uap->size < shminfo.shmmin || uap->size > shminfo.shmmax)
+	if (uap->size < sp->shminfo.shmmin || uap->size > sp->shminfo.shmmax)
 		return EINVAL;
-	if (shm_nused >= shminfo.shmmni) /* any shmids left? */
+	if (sp->shm_nused >= sp->shminfo.shmmni) /* any shmids left? */
 		return ENOSPC;
 	size = round_page(uap->size);
-	if (shm_committed + btoc(size) > shminfo.shmall)
+	if (sp->shm_committed + btoc(size) > sp->shminfo.shmall)
 		return ENOMEM;
-	if (shm_last_free < 0) {
+	if (sp->shm_last_free < 0) {
 		shmrealloc();	/* maybe expand the shmsegs[] array */
-		for (i = 0; i < shmalloced; i++)
-			if (shmsegs[i].shm_perm.mode & SHMSEG_FREE)
+		for (i = 0; i < sp->shmalloced; i++)
+			if (sp->shmsegs[i].shm_perm.mode & SHMSEG_FREE)
 				break;
-		if (i == shmalloced)
+		if (i == sp->shmalloced)
 			return ENOSPC;
 		segnum = i;
 	} else  {
-		segnum = shm_last_free;
-		shm_last_free = -1;
+		segnum = sp->shm_last_free;
+		sp->shm_last_free = -1;
 	}
-	shmseg = &shmsegs[segnum];
+	shmseg = &sp->shmsegs[segnum];
 	/*
 	 * In case we sleep in malloc(), mark the segment present but deleted
 	 * so that noone else tries to create the same key.
@@ -549,7 +579,7 @@
 	 * We make sure that we have allocated a pager before we need
 	 * to.
 	 */
-	if (shm_use_phys) {
+	if (sp->shm_use_phys) {
 		shm_handle->shm_object =
 		    vm_pager_allocate(OBJT_PHYS, 0, size, VM_PROT_DEFAULT, 0);
 	} else {
@@ -569,8 +599,8 @@
 	shmseg->shm_lpid = shmseg->shm_nattch = 0;
 	shmseg->shm_atime = shmseg->shm_dtime = 0;
 	shmseg->shm_ctime = time_second;
-	shm_committed += btoc(size);
-	shm_nused++;
+	sp->shm_committed += btoc(size);
+	sp->shm_nused++;
 	if (shmseg->shm_perm.mode & SHMSEG_WANTED) {
 		/*
 		 * Somebody else wanted this key while we were asleep.  Wake
@@ -636,14 +666,20 @@
 	struct shmmap_state *shmmap_s;
 	size_t size;
 	int i;
+	struct shmpriv *sp;
 
-	size = shminfo.shmseg * sizeof(struct shmmap_state);
+	if (p1->p_prison == NULL)
+		sp = &mainshm;
+	else
+		sp = &p1->p_prison->pr_shm;
+
+	size = sp->shminfo.shmseg * sizeof(struct shmmap_state);
 	shmmap_s = malloc(size, M_SHM, M_WAITOK);
 	bcopy((caddr_t)p1->p_vmspace->vm_shm, (caddr_t)shmmap_s, size);
 	p2->p_vmspace->vm_shm = (caddr_t)shmmap_s;
-	for (i = 0; i < shminfo.shmseg; i++, shmmap_s++)
+	for (i = 0; i < sp->shminfo.shmseg; i++, shmmap_s++)
 		if (shmmap_s->shmid != -1)
-			shmsegs[IPCID_TO_IX(shmmap_s->shmid)].shm_nattch++;
+			sp->shmsegs[IPCID_TO_IX(shmmap_s->shmid)].shm_nattch++;
 }
 
 void
@@ -652,9 +688,15 @@
 {
 	struct shmmap_state *shmmap_s;
 	int i;
+	struct shmpriv *sp;
+
+	if (p->p_prison == NULL)
+		sp = &mainshm;
+	else
+		sp = &p->p_prison->pr_shm;
 
 	shmmap_s = (struct shmmap_state *)p->p_vmspace->vm_shm;
-	for (i = 0; i < shminfo.shmseg; i++, shmmap_s++)
+	for (i = 0; i < sp->shminfo.shmseg; i++, shmmap_s++)
 		if (shmmap_s->shmid != -1)
 			shm_delete_mapping(p, shmmap_s);
 	free((caddr_t)p->p_vmspace->vm_shm, M_SHM);
@@ -666,41 +708,217 @@
 {
 	int i;
 	struct shmid_ds *newsegs;
+	struct shmpriv *sp;
+
+	if (curproc->p_prison == NULL)
+		sp = &mainshm;
+	else
+		sp = &curproc->p_prison->pr_shm;
 
-	if (shmalloced >= shminfo.shmmni)
+	if (sp->shmalloced >= sp->shminfo.shmmni)
 		return;
 
-	newsegs = malloc(shminfo.shmmni * sizeof(*newsegs), M_SHM, M_WAITOK);
+	newsegs = malloc(sp->shminfo.shmmni * sizeof(*newsegs), M_SHM,
+	    M_WAITOK);
 	if (newsegs == NULL)
 		return;
-	for (i = 0; i < shmalloced; i++)
-		bcopy(&shmsegs[i], &newsegs[i], sizeof(newsegs[0]));
-	for (; i < shminfo.shmmni; i++) {
-		shmsegs[i].shm_perm.mode = SHMSEG_FREE;
-		shmsegs[i].shm_perm.seq = 0;
-	}
-	free(shmsegs, M_SHM);
-	shmsegs = newsegs;
-	shmalloced = shminfo.shmmni;
+	for (i = 0; i < sp->shmalloced; i++)
+		bcopy(&sp->shmsegs[i], &newsegs[i], sizeof(newsegs[0]));
+	for (; i < sp->shminfo.shmmni; i++) {
+		sp->shmsegs[i].shm_perm.mode = SHMSEG_FREE;
+		sp->shmsegs[i].shm_perm.seq = 0;
+	}
+	free(sp->shmsegs, M_SHM);
+	sp->shmsegs = newsegs;
+	sp->shmalloced = sp->shminfo.shmmni;
 }
 
-static void
-shminit(dummy)
-	void *dummy;
+int
+shminit(struct prison *pr)
 {
+	struct shmpriv *sp;
 	int i;
 
-	shminfo.shmmax = shminfo.shmall * PAGE_SIZE;
-	shmalloced = shminfo.shmmni;
-	shmsegs = malloc(shmalloced * sizeof(shmsegs[0]), M_SHM, M_WAITOK);
-	if (shmsegs == NULL)
-		panic("cannot allocate initial memory for sysvshm");
-	for (i = 0; i < shmalloced; i++) {
-		shmsegs[i].shm_perm.mode = SHMSEG_FREE;
-		shmsegs[i].shm_perm.seq = 0;
-	}
-	shm_last_free = 0;
-	shm_nused = 0;
-	shm_committed = 0;
+	if (pr == NULL)
+		sp = &mainshm;
+	else
+		sp = &pr->pr_shm;
+
+	sp->shminfo.shmmax = SHMMAX;
+	sp->shminfo.shmmin = SHMMIN;
+	sp->shminfo.shmmni = SHMMNI;
+	sp->shminfo.shmseg = SHMSEG;
+	sp->shminfo.shmall = SHMALL;
+
+	sp->shminfo.shmmax = sp->shminfo.shmall * PAGE_SIZE;
+	sp->shmalloced = sp->shminfo.shmmni;
+	sp->shmsegs = malloc(sp->shmalloced * sizeof(sp->shmsegs[0]), M_SHM,
+	    M_WAITOK);
+	if (sp->shmsegs == NULL) {
+		if (pr == NULL)
+			panic("cannot allocate initial memory for sysvshm");
+		else
+			return (ENOMEM);
+	}
+	for (i = 0; i < sp->shmalloced; i++) {
+		sp->shmsegs[i].shm_perm.mode = SHMSEG_FREE;
+		sp->shmsegs[i].shm_perm.seq = 0;
+	}
+	sp->shm_last_free = 0;
+	sp->shm_nused = 0;
+	sp->shm_committed = 0;
+
+	return (0);
 }
 SYSINIT(sysv_shm, SI_SUB_SYSV_SHM, SI_ORDER_FIRST, shminit, NULL);
+
+void
+shmclear(struct prison *pr)
+{
+	struct shmpriv *sp;
+
+	if (pr == NULL)
+		sp = &mainshm;
+	else
+		sp = &pr->pr_shm;
+
+	free(sp->shmsegs, M_SHM);
+}
+
+TUNABLE_INT("kern.ipc.shmmin", &mainshm.shminfo.shmmin);
+TUNABLE_INT("kern.ipc.shmmni", &mainshm.shminfo.shmmni);
+TUNABLE_INT("kern.ipc.shmseg", &mainshm.shminfo.shmseg);
+TUNABLE_INT("kern.ipc.shmmaxpgs", &mainshm.shminfo.shmall);
+TUNABLE_INT("kern.ipc.shm_use_phys", &mainshm.shm_use_phys);
+
+SYSCTL_DECL(_kern_ipc);
+
+static int
+sysctl_shmsegs(SYSCTL_HANDLER_ARGS)
+{
+	struct shmpriv *sp;
+
+	if (req->p->p_prison == NULL)
+		sp = &mainshm;
+	else
+		sp = &req->p->p_prison->pr_shm;
+
+	return (SYSCTL_OUT(req, sp->shmsegs,
+	    sizeof(struct shmid_ds) * sp->shminfo.shmmni));
+}
+SYSCTL_PROC(_kern_ipc, OID_AUTO, shmsegs, CTLFLAG_RD,
+    NULL, 0, sysctl_shmsegs, "", "Shared memory IDs");
+
+static int
+sysctl_shminfo(SYSCTL_HANDLER_ARGS)
+{
+	struct shmpriv *sp;
+
+	if (req->p->p_prison == NULL)
+		sp = &mainshm;
+	else
+		sp = &req->p->p_prison->pr_shm;
+
+	return (sysctl_handle_opaque(oidp, &sp->shminfo, sizeof(struct shminfo),
+	    req));
+}
+SYSCTL_PROC(_kern_ipc, OID_AUTO, shminfo, CTLTYPE_STRUCT | CTLFLAG_RD, 0, 0,
+    sysctl_shminfo, "S,shminfo","");
+
+#define	IPC_SHMMAX	0
+#define	IPC_SHMMIN	1
+#define	IPC_SHMMNI	2
+#define	IPC_SHMSEG	3
+#define	IPC_SHMALL	4
+#define	IPC_SHM_USE_PHYS 5
+
+static int
+sysctl_shminfo_val(struct sysctl_oid *oidp, struct sysctl_req *req, u_int type)
+{
+	int *shminfo;
+	struct shmpriv *sp;
+
+	if (req->p->p_prison == NULL)
+		sp = &mainshm;
+	else
+		sp = &req->p->p_prison->pr_shm;
+
+	switch (type) {
+	case IPC_SHMMAX:
+		shminfo = &sp->shminfo.shmmax;
+		break;
+	case IPC_SHMMIN:
+		shminfo = &sp->shminfo.shmmin;
+		break;
+	case IPC_SHMMNI:
+		shminfo = &sp->shminfo.shmmni;
+		break;
+	case IPC_SHMSEG:
+		shminfo = &sp->shminfo.shmseg;
+		break;
+	case IPC_SHMALL:
+		shminfo = &sp->shminfo.shmall;
+		break;
+	case IPC_SHM_USE_PHYS:
+		shminfo = &sp->shm_use_phys;
+		break;
+	default:
+		panic("unknown shm type");
+	}
+
+	return (sysctl_handle_int(oidp, shminfo, 0, req));
+}
+
+static int
+sysctl_shminfo_shmmax(SYSCTL_HANDLER_ARGS)
+{
+
+	return (sysctl_shminfo_val(oidp, req, IPC_SHMMAX));
+}
+SYSCTL_PROC(_kern_ipc, OID_AUTO, shmmax, CTLTYPE_INT | CTLFLAG_RW, 0, 0,
+    sysctl_shminfo_shmmax, "IU", "");
+
+static int
+sysctl_shminfo_shmmin(SYSCTL_HANDLER_ARGS)
+{
+
+	return (sysctl_shminfo_val(oidp, req, IPC_SHMMIN));
+}
+SYSCTL_PROC(_kern_ipc, OID_AUTO, shmmin, CTLTYPE_INT | CTLFLAG_RW, 0, 0,
+    sysctl_shminfo_shmmin, "IU", "");
+
+static int
+sysctl_shminfo_shmmni(SYSCTL_HANDLER_ARGS)
+{
+
+	return (sysctl_shminfo_val(oidp, req, IPC_SHMMNI));
+}
+SYSCTL_PROC(_kern_ipc, OID_AUTO, shmmni, CTLTYPE_INT | CTLFLAG_RD, 0, 0,
+    sysctl_shminfo_shmmni, "IU", "");
+
+static int
+sysctl_shminfo_shmseg(SYSCTL_HANDLER_ARGS)
+{
+
+	return (sysctl_shminfo_val(oidp, req, IPC_SHMSEG));
+}
+SYSCTL_PROC(_kern_ipc, OID_AUTO, shmseg, CTLTYPE_INT | CTLFLAG_RW, 0, 0,
+    sysctl_shminfo_shmseg, "IU", "");
+
+static int
+sysctl_shminfo_shmall(SYSCTL_HANDLER_ARGS)
+{
+
+	return (sysctl_shminfo_val(oidp, req, IPC_SHMALL));
+}
+SYSCTL_PROC(_kern_ipc, OID_AUTO, shmall, CTLTYPE_INT | CTLFLAG_RW, 0, 0,
+    sysctl_shminfo_shmall, "IU", "");
+
+static int
+sysctl_shminfo_shm_use_phys(SYSCTL_HANDLER_ARGS)
+{
+
+	return (sysctl_shminfo_val(oidp, req, IPC_SHM_USE_PHYS));
+}
+SYSCTL_PROC(_kern_ipc, OID_AUTO, shm_use_phys, CTLTYPE_INT | CTLFLAG_RW, 0, 0,
+    sysctl_shminfo_shm_use_phys, "IU", "");
diff -ru /sys/svr4/svr4_misc.c sys/svr4/svr4_misc.c
--- /sys/svr4/svr4_misc.c	Wed Feb 19 19:29:13 2003
+++ sys/svr4/svr4_misc.c	Wed Feb 19 18:39:19 2003
@@ -25,7 +25,7 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  * 
- * $FreeBSD: src/sys/svr4/svr4_misc.c,v 1.13.2.7 2003/01/14 21:33:58 dillon Exp $
+ * $FreeBSD$
  */
 
 /*
@@ -35,6 +35,8 @@
  * handled here.
  */
 
+#include "opt_sysvipc.h"
+
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/namei.h>
@@ -58,6 +60,7 @@
 #include <sys/fcntl.h>
 #include <sys/sem.h>
 #include <sys/msg.h>
+#include <sys/jail.h>
 #include <sys/ptrace.h>
 #include <vm/vm_zone.h>
 
@@ -726,21 +729,34 @@
 	case SVR4_CONFIG_DELAYTIMER_MAX:
 		*retval = 0;	/* No delaytimer support */
 		break;
+#ifdef SYSVMSG
 	case SVR4_CONFIG_MQ_OPEN_MAX:
-		*retval = msginfo.msgmni;
+		if (p->p_prison == NULL)
+			*retval = mainmsg.msginfo.msgmni;
+		else
+			*retval = p->p_prison->pr_msg.msginfo.msgmni;
 		break;
+#endif
 	case SVR4_CONFIG_MQ_PRIO_MAX:
 		*retval = 0;	/* XXX: Don't know */
 		break;
 	case SVR4_CONFIG_RTSIG_MAX:
 		*retval = 0;
 		break;
+#ifdef SYSVSEM
 	case SVR4_CONFIG_SEM_NSEMS_MAX:
-		*retval = seminfo.semmni;
+		if (p->p_prison == NULL)
+			*retval = mainsem.seminfo.semmni;
+		else
+			*retval = p->p_prison->pr_sem.seminfo.semmni;
 		break;
 	case SVR4_CONFIG_SEM_VALUE_MAX:
-		*retval = seminfo.semvmx;
+		if (p->p_prison == NULL)
+			*retval = mainsem.seminfo.semvmx;
+		else
+			*retval = p->p_prison->pr_sem.seminfo.semvmx;
 		break;
+#endif
 	case SVR4_CONFIG_SIGQUEUE_MAX:
 		*retval = 0;	/* XXX: Don't know */
 		break;
diff -ru /sys/sys/jail.h sys/sys/jail.h
--- /sys/sys/jail.h	Wed Feb 19 19:29:13 2003
+++ sys/sys/jail.h	Wed Feb 19 18:24:53 2003
@@ -6,7 +6,7 @@
  * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
  * ----------------------------------------------------------------------------
  *
- * $FreeBSD: src/sys/sys/jail.h,v 1.8.2.2 2000/11/01 17:58:06 rwatson Exp $
+ * $FreeBSD$
  *
  */
 
@@ -26,6 +26,10 @@
 
 #else /* _KERNEL */
 
+#include <sys/msg.h>
+#include <sys/sem.h>
+#include <sys/shm.h>
+
 #ifdef MALLOC_DECLARE
 MALLOC_DECLARE(M_PRISON);
 #endif
@@ -41,6 +45,15 @@
 	char 		pr_host[MAXHOSTNAMELEN];
 	u_int32_t	pr_ip;
 	void		*pr_linux;
+#ifdef SYSVMSG
+	struct msgpriv	pr_msg;
+#endif
+#ifdef SYSVSEM
+	struct sempriv	pr_sem;
+#endif
+#ifdef SYSVSHM
+	struct shmpriv	pr_shm;
+#endif
 };
 
 /*
diff -ru /sys/sys/msg.h sys/sys/msg.h
--- /sys/sys/msg.h	Wed Feb 19 19:29:13 2003
+++ sys/sys/msg.h	Wed Feb 19 14:15:43 2003
@@ -32,7 +32,14 @@
 
 #define MSG_NOERROR	010000		/* don't complain about too long msgs */
 
-struct msg;
+struct msg {
+	struct	msg *msg_next;	/* next msg in the chain */
+	long	msg_type;	/* type of this message */
+    				/* >0 -> type of this message */
+    				/* 0 -> free header */
+	u_short	msg_ts;		/* size of this message */
+	short	msg_spot;	/* location of start of msg in buffer */
+};
 
 struct msqid_ds {
 	struct	ipc_perm msg_perm;	/* msg queue permission bits */
@@ -87,7 +94,29 @@
 		msgssz,		/* size of a message segment (see notes above) */
 		msgseg;		/* number of message segments */
 };
-extern struct msginfo	msginfo;
+
+struct msgmap {
+	short	next;	/* next segment in buffer */
+			/* -1 -> available */
+			/* 0..(MSGSEG-1) -> index of next segment */
+};
+
+struct msgpriv {
+	struct msginfo	 msginfo;
+	int		 nfree_msgmaps;	/* # of free map entries */
+	short		 free_msgmaps;	/* head of linked list of
+					   free map entries */
+	struct msg	*free_msghdrs;	/* list of free msg headers */
+	char		*msgpool;	/* MSGMAX byte long msg buffer pool */
+	struct msgmap	*msgmaps;	/* MSGSEG msgmap structures */
+	struct msg	*msghdrs;	/* MSGTQL msg headers */
+	struct msqid_ds	*msqids;	/* MSGMNI msqid_ds struct's */
+};
+extern struct msgpriv mainmsg;
+
+struct prison;
+int msginit(struct prison *pr);
+void msgclear(struct prison *pr);
 #endif
 
 #ifndef _KERNEL
diff -ru /sys/sys/sem.h sys/sys/sem.h
--- /sys/sys/sem.h	Wed Feb 19 19:29:13 2003
+++ sys/sys/sem.h	Wed Feb 19 15:30:11 2003
@@ -1,4 +1,4 @@
-/* $FreeBSD: src/sys/sys/sem.h,v 1.20.2.2 2000/08/04 22:31:10 peter Exp $ */
+/* $FreeBSD$ */
 /*	$NetBSD: sem.h,v 1.5 1994/06/29 06:45:15 cgd Exp $	*/
 
 /*
@@ -67,6 +67,27 @@
 
 #ifdef _KERNEL
 
+struct sem {
+	u_short	semval;		/* semaphore value */
+	pid_t	sempid;		/* pid of last operation */
+	u_short	semncnt;	/* # awaiting semval > cval */
+	u_short	semzcnt;	/* # awaiting semval = 0 */
+};
+
+/*
+ * Undo structure (one per process)
+ */
+struct sem_undo {
+	struct	sem_undo *un_next;	/* ptr to next active undo structure */
+	struct	proc *un_proc;		/* owner of this structure */
+	short	un_cnt;			/* # of active entries */
+	struct undo {
+		short	un_adjval;	/* adjust on exit values */
+		short	un_num;		/* semaphore # */
+		int	un_id;		/* semid */
+	} un_ent[1];			/* undo entries */
+};
+
 /*
  * semaphore info struct
  */
@@ -82,12 +103,24 @@
 		semvmx,		/* semaphore maximum value */
 		semaem;		/* adjust on exit max value */
 };
-extern struct seminfo	seminfo;
 
 /* internal "mode" bits */
 #define	SEM_ALLOC	01000	/* semaphore is allocated */
 #define	SEM_DEST	02000	/* semaphore will be destroyed on last detach */
 
+struct sempriv {
+	struct seminfo	seminfo;
+	int		semtot;
+	struct semid_ds	*sema;		/* semaphore id pool */
+	struct sem	*sem;		/* semaphore pool */
+	struct sem_undo	*semu_list;	/* list of active undo structures */
+	int		*semu;		/* undo structure pool */
+};
+extern struct sempriv mainsem;
+
+struct prison;
+int	seminit(struct prison *pr);
+void	semclear(struct prison *pr);
 /*
  * Process sem_undo vectors at proc exit.
  */
diff -ru /sys/sys/shm.h sys/sys/shm.h
--- /sys/sys/shm.h	Wed Feb 19 19:29:13 2003
+++ sys/sys/shm.h	Wed Feb 19 15:42:22 2003
@@ -1,4 +1,4 @@
-/* $FreeBSD: src/sys/sys/shm.h,v 1.14 1999/12/29 04:24:46 peter Exp $ */
+/* $FreeBSD$ */
 /*	$NetBSD: shm.h,v 1.15 1994/06/29 06:45:17 cgd Exp $	*/
 
 /*
@@ -76,13 +76,24 @@
 		shmseg,		/* max shared memory segments per process */
 		shmall;		/* max amount of shared memory (pages) */
 };
-extern struct shminfo	shminfo;
-extern struct shmid_ds	*shmsegs;
 
-struct proc;
+struct shmpriv {
+	struct shminfo	 shminfo;
+	struct shmid_ds	*shmsegs;
+	int		 shm_last_free;
+	int		 shm_nused;
+	int		 shm_committed;
+	int		 shmalloced;
+	int		 shm_use_phys;
+};
+extern struct shmpriv mainshm;
 
+struct proc;
 void	shmexit __P((struct proc *));
 void	shmfork __P((struct proc *, struct proc *));
+struct prison;
+int	shminit(struct prison *pr);
+void	shmclear(struct prison *pr);
 #else /* !_KERNEL */
 
 #include <sys/cdefs.h>


===> ipcs(1) patch

diff -ru /usr/src/usr.bin/ipcs/Makefile usr.bin/ipcs/Makefile
--- /usr/src/usr.bin/ipcs/Makefile	Wed Feb 19 19:29:14 2003
+++ usr.bin/ipcs/Makefile	Wed Feb 19 18:58:06 2003
@@ -1,9 +1,6 @@
-# $FreeBSD: src/usr.bin/ipcs/Makefile,v 1.5 1999/08/28 01:02:15 peter Exp $
+# $FreeBSD$
 
 PROG=	ipcs
-BINGRP=	kmem
-BINMODE= 2555
-DPADD+=	${LIBKVM}
-LDADD+=	-lkvm
+BINMODE= 555
 
 .include <bsd.prog.mk>
diff -ru /usr/src/usr.bin/ipcs/ipcs.c usr.bin/ipcs/ipcs.c
--- /usr/src/usr.bin/ipcs/ipcs.c	Wed Feb 19 19:29:14 2003
+++ usr.bin/ipcs/ipcs.c	Wed Feb 19 18:57:07 2003
@@ -27,12 +27,11 @@
 
 #ifndef lint
 static const char rcsid[] =
-  "$FreeBSD: src/usr.bin/ipcs/ipcs.c,v 1.12.2.3 2001/07/30 10:16:41 dd Exp $";
+  "$FreeBSD$";
 #endif /* not lint */
 
 #include <err.h>
 #include <fcntl.h>
-#include <kvm.h>
 #include <nlist.h>
 #include <paths.h>
 #include <stdio.h>
@@ -44,6 +43,7 @@
 #include <sys/param.h>
 #include <sys/time.h>
 #include <sys/proc.h>
+#include <sys/sysctl.h>
 #define _KERNEL
 #include <sys/ipc.h>
 #include <sys/sem.h>
@@ -59,26 +59,6 @@
 
 void	usage __P((void));
 
-static struct nlist symbols[] = {
-	{"_sema"},
-#define X_SEMA		0
-	{"_seminfo"},
-#define X_SEMINFO	1
-	{"_semu"},
-#define X_SEMU		2
-	{"_msginfo"},
-#define X_MSGINFO	3
-	{"_msqids"},
-#define X_MSQIDS	4
-	{"_shminfo"},
-#define X_SHMINFO	5
-	{"_shmsegs"},
-#define X_SHMSEGS	6
-	{NULL}
-};
-
-static kvm_t *kd;
-
 char   *
 fmt_perm(mode)
 	u_short mode;
@@ -135,10 +115,10 @@
 {
 	int     display = SHMINFO | MSGINFO | SEMINFO;
 	int     option = 0;
-	char   *core = NULL, *namelist = NULL;
+	size_t	size;
 	int     i;
 
-	while ((i = getopt(argc, argv, "MmQqSsabC:cN:optT")) != -1)
+	while ((i = getopt(argc, argv, "MmQqSsab:c:optT")) != -1)
 		switch (i) {
 		case 'M':
 			display = SHMTOTAL;
@@ -167,15 +147,9 @@
 		case 'b':
 			option |= BIGGEST;
 			break;
-		case 'C':
-			core = optarg;
-			break;
 		case 'c':
 			option |= CREATOR;
 			break;
-		case 'N':
-			namelist = optarg;
-			break;
 		case 'o':
 			option |= OUTSTANDING;
 			break;
@@ -189,35 +163,14 @@
 			usage();
 		}
 
-	/*
-	 * Discard setgid privileges if not the running kernel so that bad
-	 * guys can't print interesting stuff from kernel memory.
-	 */
-	if (namelist != NULL || core != NULL)
-		setgid(getgid());
-
-	if ((kd = kvm_open(namelist, core, NULL, O_RDONLY, "ipcs")) == NULL)
-		exit(1);
-
-	switch (kvm_nlist(kd, symbols)) {
-	case 0:
-		break;
-	case -1:
-		errx(1, "unable to read kernel symbol table");
-	default:
-#ifdef notdef		/* they'll be told more civilly later */
-		warnx("nlist failed");
-		for (i = 0; symbols[i].n_name != NULL; i++)
-			if (symbols[i].n_value == 0)
-				warnx("symbol %s not found",
-				    symbols[i].n_name);
-		break;
-#endif
-	}
-
-	if ((display & (MSGINFO | MSGTOTAL)) &&
-	    kvm_read(kd, symbols[X_MSGINFO].n_value, &msginfo, sizeof(msginfo))== sizeof(msginfo)) {
-
+	if (display & (MSGINFO | MSGTOTAL)) {
+		size = sizeof(struct msginfo);
+		if (sysctlbyname("kern.ipc.msginfo", &msginfo, &size, NULL,
+		    NULL) != 0) {
+			fprintf(stderr, "SVID messages facility not configured "
+			    "in the system\n");
+			goto shm;
+		}
 		if (display & MSGTOTAL) {
 			printf("msginfo:\n");
 			printf("\tmsgmax: %6d\t(max characters in a message)\n",
@@ -233,12 +186,21 @@
 			printf("\tmsgseg: %6d\t(# of message segments in system)\n\n",
 			    msginfo.msgseg);
 		}
-		if (display & MSGINFO) {
-			struct msqid_ds *xmsqids;
 
-			kvm_read(kd, symbols[X_MSQIDS].n_value, &msqids, sizeof(msqids));
-			xmsqids = malloc(sizeof(struct msqid_ds) * msginfo.msgmni);
-			kvm_read(kd, (u_long) msqids, xmsqids, sizeof(struct msqid_ds) * msginfo.msgmni);
+		if (display & MSGINFO) {
+			size = sizeof(struct msqid_ds) * msginfo.msgmni;
+			msqids = malloc(size);
+			if (msqids == NULL) {
+				fprintf(stderr, "No memory.\n");
+				exit(1);
+			}
+			if (sysctlbyname("kern.ipc.msqids", msqids, &size, NULL,
+			    NULL) != 0) {
+				fprintf(stderr, "SVID messages facility not "
+				    "configured in the system\n");
+				free(msqids);
+				goto shm;
+			}
 
 			printf("Message Queues:\n");
 			printf("T     ID     KEY        MODE       OWNER    GROUP");
@@ -254,10 +216,10 @@
 				printf("   STIME    RTIME    CTIME");
 			printf("\n");
 			for (i = 0; i < msginfo.msgmni; i += 1) {
-				if (xmsqids[i].msg_qbytes != 0) {
+				if (msqids[i].msg_qbytes != 0) {
 					char    stime_buf[100], rtime_buf[100],
 					        ctime_buf[100];
-					struct msqid_ds *msqptr = &xmsqids[i];
+					struct msqid_ds *msqptr = &msqids[i];
 
 					cvt_time(msqptr->msg_stime, stime_buf);
 					cvt_time(msqptr->msg_rtime, rtime_buf);
@@ -265,7 +227,7 @@
 
 					printf("q %6d %10d %s %8s %8s",
 					    IXSEQ_TO_IPCID(i, msqptr->msg_perm),
-					    msqptr->msg_perm.key,
+					    (int)msqptr->msg_perm.key,
 					    fmt_perm(msqptr->msg_perm.mode),
 					    user_from_uid(msqptr->msg_perm.uid, 0),
 					    group_from_gid(msqptr->msg_perm.gid, 0));
@@ -276,12 +238,12 @@
 						    group_from_gid(msqptr->msg_perm.cgid, 0));
 
 					if (option & OUTSTANDING)
-						printf(" %6d %6d",
+						printf(" %6ld %6ld",
 						    msqptr->msg_cbytes,
 						    msqptr->msg_qnum);
 
 					if (option & BIGGEST)
-						printf(" %6d",
+						printf(" %6ld",
 						    msqptr->msg_qbytes);
 
 					if (option & PID)
@@ -300,13 +262,16 @@
 			}
 			printf("\n");
 		}
-	} else
-		if (display & (MSGINFO | MSGTOTAL)) {
-			fprintf(stderr,
-			    "SVID messages facility not configured in the system\n");
+	}
+shm:
+	if (display & (SHMINFO | SHMTOTAL)) {
+		size = sizeof(struct shminfo);
+		if (sysctlbyname("kern.ipc.shminfo", &shminfo, &size, NULL,
+		    NULL) != 0) {
+			fprintf(stderr, "SVID shared memory facility not "
+			    "configured in the system\n");
+			goto sem;
 		}
-	if ((display & (SHMINFO | SHMTOTAL)) &&
-	    kvm_read(kd, symbols[X_SHMINFO].n_value, &shminfo, sizeof(shminfo))) {
 		if (display & SHMTOTAL) {
 			printf("shminfo:\n");
 			printf("\tshmmax: %7d\t(max shared memory segment size)\n",
@@ -321,12 +286,19 @@
 			    shminfo.shmall);
 		}
 		if (display & SHMINFO) {
-			struct shmid_ds *xshmids;
-
-			kvm_read(kd, symbols[X_SHMSEGS].n_value, &shmsegs, sizeof(shmsegs));
-			xshmids = malloc(sizeof(struct shmid_ds) * shminfo.shmmni);
-			kvm_read(kd, (u_long) shmsegs, xshmids, sizeof(struct shmid_ds) *
-			    shminfo.shmmni);
+			size = sizeof(struct shmid_ds) * shminfo.shmmni;
+			shmsegs = malloc(size);
+			if (shmsegs == NULL) {
+				fprintf(stderr, "No memory.\n");
+				exit(1);
+			}
+			if (sysctlbyname("kern.ipc.shmsegs", shmsegs, &size, NULL,
+			    NULL) != 0) {
+				fprintf(stderr, "SVID shared memory facility "
+				    "not configured in the system\n");
+				free(shmsegs);
+				goto sem;
+			}
 
 			printf("Shared Memory:\n");
 			printf("T     ID     KEY        MODE       OWNER    GROUP");
@@ -342,10 +314,10 @@
 				printf("   ATIME    DTIME    CTIME");
 			printf("\n");
 			for (i = 0; i < shminfo.shmmni; i += 1) {
-				if (xshmids[i].shm_perm.mode & 0x0800) {
+				if (shmsegs[i].shm_perm.mode & 0x0800) {
 					char    atime_buf[100], dtime_buf[100],
 					        ctime_buf[100];
-					struct shmid_ds *shmptr = &xshmids[i];
+					struct shmid_ds *shmptr = &shmsegs[i];
 
 					cvt_time(shmptr->shm_atime, atime_buf);
 					cvt_time(shmptr->shm_dtime, dtime_buf);
@@ -353,7 +325,7 @@
 
 					printf("m %6d %10d %s %8s %8s",
 					    IXSEQ_TO_IPCID(i, shmptr->shm_perm),
-					    shmptr->shm_perm.key,
+					    (int)shmptr->shm_perm.key,
 					    fmt_perm(shmptr->shm_perm.mode),
 					    user_from_uid(shmptr->shm_perm.uid, 0),
 					    group_from_gid(shmptr->shm_perm.gid, 0));
@@ -387,15 +359,16 @@
 			}
 			printf("\n");
 		}
-	} else
-		if (display & (SHMINFO | SHMTOTAL)) {
-			fprintf(stderr,
-			    "SVID shared memory facility not configured in the system\n");
+	}
+sem:
+	if (display & (SEMINFO | SEMTOTAL)) {
+		size = sizeof(struct seminfo);
+		if (sysctlbyname("kern.ipc.seminfo", &seminfo, &size, NULL,
+		    NULL) != 0) {
+			fprintf(stderr, "SVID semaphores facility not "
+			    "configured in the system\n");
+			exit(0);
 		}
-	if ((display & (SEMINFO | SEMTOTAL)) &&
-	    kvm_read(kd, symbols[X_SEMINFO].n_value, &seminfo, sizeof(seminfo))) {
-		struct semid_ds *xsema;
-
 		if (display & SEMTOTAL) {
 			printf("seminfo:\n");
 			printf("\tsemmap: %6d\t(# of entries in semaphore map)\n",
@@ -419,10 +392,21 @@
 			printf("\tsemaem: %6d\t(adjust on exit max value)\n\n",
 			    seminfo.semaem);
 		}
+
 		if (display & SEMINFO) {
-			kvm_read(kd, symbols[X_SEMA].n_value, &sema, sizeof(sema));
-			xsema = malloc(sizeof(struct semid_ds) * seminfo.semmni);
-			kvm_read(kd, (u_long) sema, xsema, sizeof(struct semid_ds) * seminfo.semmni);
+			size = sizeof(struct semid_ds) * seminfo.semmni;
+			sema = malloc(size);
+			if (sema == NULL) {
+				fprintf(stderr, "No memory.\n");
+				exit(1);
+			}
+			if (sysctlbyname("kern.ipc.sema", sema, &size, NULL,
+			    NULL) != 0) {
+				fprintf(stderr, "SVID semaphores facility not "
+				    "configured in the system\n");
+				free(sema);
+				exit(0);
+			}
 
 			printf("Semaphores:\n");
 			printf("T     ID     KEY        MODE       OWNER    GROUP");
@@ -434,16 +418,16 @@
 				printf("   OTIME    CTIME");
 			printf("\n");
 			for (i = 0; i < seminfo.semmni; i += 1) {
-				if ((xsema[i].sem_perm.mode & SEM_ALLOC) != 0) {
+				if ((sema[i].sem_perm.mode & SEM_ALLOC) != 0) {
 					char    ctime_buf[100], otime_buf[100];
-					struct semid_ds *semaptr = &xsema[i];
+					struct semid_ds *semaptr = &sema[i];
 
 					cvt_time(semaptr->sem_otime, otime_buf);
 					cvt_time(semaptr->sem_ctime, ctime_buf);
 
 					printf("s %6d %10d %s %8s %8s",
 					    IXSEQ_TO_IPCID(i, semaptr->sem_perm),
-					    semaptr->sem_perm.key,
+					    (int)semaptr->sem_perm.key,
 					    fmt_perm(semaptr->sem_perm.mode),
 					    user_from_uid(semaptr->sem_perm.uid, 0),
 					    group_from_gid(semaptr->sem_perm.gid, 0));
@@ -468,11 +452,7 @@
 
 			printf("\n");
 		}
-	} else
-		if (display & (SEMINFO | SEMTOTAL)) {
-			fprintf(stderr, "SVID semaphores facility not configured in the system\n");
-		}
-	kvm_close(kd);
+	}
 
 	exit(0);
 }
>Release-Note:
>Audit-Trail:
>Unformatted:

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-bugs" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20030219215657.34DEB3ABB3B>