Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 12 Jun 2006 09:48:26 -0300
From:      "Roberto Lima" <betogigi@gmail.com>
To:        freebsd-hackers@freebsd.org
Subject:   Re: Jail-Aware Scheduling
Message-ID:  <d69013b30606120548u29174b80w3ab6d1b9edeef62d@mail.gmail.com>

index | next in thread | raw e-mail

[-- Attachment #1 --]
Hi all, i have a patch from freebsd 4.x not developed for me, but this
is very good for appreciate and or upgrade the patch for versions 5.x
6.x or current. This use sysctl oids to limit memory ram and cpu use.

Regards and sorry for my bad english,
Roberto Lima.

[-- Attachment #2 --]
diff -ur src.virgin/sys/kern/kern_fork.c src.dirty/sys/kern/kern_fork.c
--- src.virgin/sys/kern/kern_fork.c	Mon Dec  9 19:33:44 2002
+++ src.dirty/sys/kern/kern_fork.c	Thu Feb 27 17:38:32 2003
@@ -120,6 +120,11 @@
 	int error;
 	struct proc *p2;
 
+	error = jail_check_resources(td);
+	if (error) {
+		return error;
+	}
+		
 	mtx_lock(&Giant);
 	error = fork1(td, RFFDG | RFPROC, 0, &p2);
 	if (error == 0) {
@@ -142,6 +147,11 @@
 	int error;
 	struct proc *p2;
 
+	error = jail_check_resources(td);
+	if (error) {
+		return error;
+	}
+
 	mtx_lock(&Giant);
 	error = fork1(td, RFFDG | RFPROC | RFPPWAIT | RFMEM, 0, &p2);
 	if (error == 0) {
@@ -162,6 +172,11 @@
 {
 	int error;
 	struct proc *p2;
+
+	error = jail_check_resources(td);
+	if (error) {
+		return error;
+	}
 
 	/* Don't allow kernel only flags. */
 	if ((uap->flags & RFKERNELONLY) != 0)
diff -ur src.virgin/sys/kern/kern_jail.c src.dirty/sys/kern/kern_jail.c
--- src.virgin/sys/kern/kern_jail.c	Thu Dec 19 02:40:10 2002
+++ src.dirty/sys/kern/kern_jail.c	Sat Mar 22 13:25:39 2003
@@ -18,6 +18,11 @@
 #include <sys/sysproto.h>
 #include <sys/malloc.h>
 #include <sys/proc.h>
+#include <vm/vm.h>
+#include <vm/vm_extern.h>
+#include <vm/vm_page.h>
+#include <vm/vm_object.h>
+#include <vm/vm_map.h>
 #include <sys/jail.h>
 #include <sys/lock.h>
 #include <sys/mutex.h>
@@ -25,6 +30,10 @@
 #include <sys/sysctl.h>
 #include <net/if.h>
 #include <netinet/in.h>
+#include <sys/sbuf.h>
+#include <sys/sched.h>
+#include <sys/vnode.h>
+#include <sys/mount.h>
 
 MALLOC_DEFINE(M_PRISON, "prison", "Prison structures");
 
@@ -49,6 +58,118 @@
     &jail_sysvipc_allowed, 0,
     "Processes in jail can use System V IPC primitives");
 
+int jail_quotas_allowed = 0;
+SYSCTL_INT(_security_jail, OID_AUTO, quotas_allowed, CTLFLAG_RW, &jail_quotas_allowed, 0,
+    "Processes have access to the quota system.");
+
+int	jail_hide_processes = 0;
+SYSCTL_INT(_security_jail, OID_AUTO, hide_processes, CTLFLAG_RW,
+    &jail_hide_processes, 0,
+    "Processes in jail are not visible outside the jail (except to root)");
+
+int	jail_hide_files = 0;
+SYSCTL_INT(_security_jail, OID_AUTO, hide_files, CTLFLAG_RW,
+    &jail_hide_files, 0,
+    "Files in jail are not visible outside the jail (except to root)");
+
+struct jails firstjail = LIST_HEAD_INITIALIZER(jails);
+
+SYSCTL_NODE(, OID_AUTO, jail, CTLFLAG_RD, 0, "jail parameters");
+SYSCTL_NODE(_jail, OID_AUTO, jails, CTLFLAG_RD, 0, "per-jail settings");
+
+int jail_ipv4addr_sysctl(SYSCTL_HANDLER_ARGS);
+
+int
+jail_ipv4addr_sysctl(SYSCTL_HANDLER_ARGS)
+{
+	int error, i = 0, j = 0, k, ipmode;
+	char buf[1024], *tmpptr, *tmpbuf, *tmpbuf2;
+	struct prison *pr = (struct prison*)(oidp->oid_arg1);
+	u_int32_t *ips_new;
+	in_addr_t addr;
+	struct sbuf *sb;
+	struct in_addr inaddr;
+	unsigned long ipelement[4];
+
+	/* Spit out all IP addresses in jail. */
+	sb = sbuf_new(NULL, NULL, 1024, SBUF_AUTOEXTEND);
+	for (i = 0; i < pr->pr_nips; i++) {
+		inaddr.s_addr = ntohl(pr->pr_ips[i]);
+		sbuf_printf(sb, "%s", inet_ntoa(inaddr));
+		if (i != pr->pr_nips - 1) {
+			sbuf_printf(sb, ",");
+		}
+	}
+	sbuf_finish(sb);
+	strlcpy(buf, sbuf_data(sb), sizeof(buf));
+	error = sysctl_handle_string(oidp, &buf[0], sizeof(buf), req);
+	sbuf_delete(sb);
+
+	if (error == 0 && req->newptr != NULL) {
+		if (buf[0] == '+' || (buf[0] >= 48 && buf[0] <= 57)) {
+			ipmode = 0;
+			MALLOC(ips_new, u_int32_t *, sizeof(u_int32_t) * (pr->pr_nips + 1), M_PRISON, M_WAITOK);
+			memcpy(ips_new, pr->pr_ips, sizeof(u_int32_t) * (pr->pr_nips));
+		} else if (buf[0] == '-') {
+			ipmode = 1;
+			if (pr->pr_nips == 1) {
+				return EINVAL;
+			}
+			MALLOC(ips_new, u_int32_t *, sizeof(u_int32_t) * (pr->pr_nips - 1), M_PRISON, M_WAITOK);
+		} else {
+			return EINVAL;
+		}
+
+		/* Simulate inet_aton *sigh*. */
+		tmpptr = (char*)&addr;
+		if (buf[0] == '+' || buf[0] == '-') {
+			tmpbuf2 = buf + 1;
+		} else {
+			tmpbuf2 = buf;
+		}
+		tmpbuf = tmpbuf2;
+		while(*tmpbuf) {
+			/* First pass: replace '.' with '\0'. */
+			if (*tmpbuf == '.') {
+				i++;
+				*tmpbuf = '\0';
+			}
+			tmpbuf++;
+		}
+		tmpbuf = tmpbuf2;
+		for(j = 0; j <= i; j++) {
+			/* Second pass: fill addr. */
+			ipelement[j] = strtoul(tmpbuf, NULL, 10);
+			k = strlen(tmpbuf);
+			tmpbuf += k + 1;
+		}
+		addr = ipelement[3];
+		addr |= (ipelement[0] << 24) | (ipelement[1] << 16) | (ipelement[2] << 8);
+
+		/* Perform add/delete */
+		mtx_lock(&pr->pr_mtx);
+		if (ipmode == 0) {
+			ips_new[pr->pr_nips] = addr;
+			pr->pr_nips++;
+		} else {
+			i = 0;
+			for (j = 0; j < pr->pr_nips; j++) {
+				if (addr != pr->pr_ips[j]) {
+					ips_new[i] = pr->pr_ips[j];
+					i++;
+				}
+			}
+			pr->pr_nips--;
+		}
+		FREE(pr->pr_ips, M_PRISON);
+		pr->pr_ips = ips_new;
+		mtx_unlock(&pr->pr_mtx);
+
+	}
+
+	return error;
+}
+
 /*
  * MPSAFE
  */
@@ -60,16 +181,18 @@
 	} */ *uap;
 {
 	struct proc *p = td->td_proc;
-	int error;
+	int error, size = 0;
 	struct prison *pr;
 	struct jail j;
 	struct chroot_args ca;
 	struct ucred *newcred = NULL, *oldcred;
+	struct jailelement *tmpelement;
+	char *tmpString;
 
 	error = copyin(uap->jail, &j, sizeof j);
 	if (error)
 		return (error);
-	if (j.version != 0)
+	if (j.version != 1)
 		return (EINVAL);
 
 	MALLOC(pr, struct prison *, sizeof *pr , M_PRISON, M_WAITOK | M_ZERO);
@@ -85,7 +208,16 @@
 	if (error)
 		goto bail;
 	newcred = crget();
-	pr->pr_ip = j.ip_number;
+
+	MALLOC(pr->pr_ips, u_int32_t *, sizeof(u_int32_t) * j.nips, M_PRISON,
+	    M_WAITOK);
+	error = copyin(j.ips, pr->pr_ips, sizeof(u_int32_t) * j.nips);
+	if (error) {
+		FREE(pr->pr_ips, M_PRISON);
+		goto bail;
+	}
+	pr->pr_nips = j.nips;
+
 	PROC_LOCK(p);
 	/* Implicitly fail if already in jail.  */
 	error = suser_cred(p->p_ucred, 0);
@@ -96,6 +228,48 @@
 	p->p_ucred = newcred;
 	p->p_ucred->cr_prison = pr;
 	pr->pr_ref = 1;
+
+	/* Add jail to list. */
+	MALLOC(tmpelement, struct jailelement*, sizeof(struct jailelement), M_PRISON, M_WAITOK | M_ZERO);
+	tmpelement->pr = pr;
+	MALLOC(tmpelement->chroot_path, char *, strlen(j.path) + 1, M_PRISON, M_WAITOK);
+	copyinstr(j.path, tmpelement->chroot_path, strlen(j.path) + 1, &size);
+	LIST_INSERT_HEAD(&firstjail, tmpelement, pointers);
+
+	/* Add sysctls. */
+	strcpy(pr->pr_host_oid, pr->pr_host);
+	tmpString = pr->pr_host_oid;
+	while(*tmpString) {
+		if (*tmpString == '.') {
+			*tmpString = '_';
+		}
+		tmpString++;
+	}
+	
+	sysctl_ctx_init(&pr->jd_sysctltree);
+	pr->jd_sysctltreetop = SYSCTL_ADD_NODE(&pr->jd_sysctltree,
+		SYSCTL_STATIC_CHILDREN(_jail_jails), OID_AUTO,
+		pr->pr_host_oid, CTLFLAG_RD, 0, "jail hostname");
+	SYSCTL_ADD_INT(&pr->jd_sysctltree, SYSCTL_CHILDREN(pr->jd_sysctltreetop), OID_AUTO, "allow_raw_sockets", 
+		CTLFLAG_RW, &pr->jail_settings.allow_raw_sockets, 0, "Allow raw sockets in jail?");
+	SYSCTL_ADD_INT(&pr->jd_sysctltree, SYSCTL_CHILDREN(pr->jd_sysctltreetop), OID_AUTO, "allow_ipfw", 
+		CTLFLAG_RW, &pr->jail_settings.allow_ipfw, 0, "Allow ipfw use?");
+	SYSCTL_ADD_INT(&pr->jd_sysctltree, SYSCTL_CHILDREN(pr->jd_sysctltreetop), OID_AUTO, "max_ram", 
+		CTLFLAG_RW, &pr->jail_settings.max_ram, 0, "Maximum RAM allowed for jail (0 = unlimited)");
+	SYSCTL_ADD_INT(&pr->jd_sysctltree, SYSCTL_CHILDREN(pr->jd_sysctltreetop), OID_AUTO, "max_cpu", 
+		CTLFLAG_RW, &pr->jail_settings.max_cpu, 0, "Maximum CPU allowed for jail (0 = unlimited)");
+	SYSCTL_ADD_INT(&pr->jd_sysctltree, SYSCTL_CHILDREN(pr->jd_sysctltreetop), OID_AUTO, "max_procs", 
+		CTLFLAG_RW, &pr->jail_settings.max_procs, 0, "Maximum number of processes allowed for jail (0 = unlimited)");
+	SYSCTL_ADD_INT(&pr->jd_sysctltree, SYSCTL_CHILDREN(pr->jd_sysctltreetop), OID_AUTO, "procs_used", 
+		CTLFLAG_RD, &pr->jail_settings.procs_used, 0, "Number of processes running");
+	SYSCTL_ADD_INT(&pr->jd_sysctltree, SYSCTL_CHILDREN(pr->jd_sysctltreetop), OID_AUTO, "ram_used", 
+		CTLFLAG_RD, &pr->jail_settings.ram_used, 0, "Amount of RAM used");
+	SYSCTL_ADD_INT(&pr->jd_sysctltree, SYSCTL_CHILDREN(pr->jd_sysctltreetop), OID_AUTO, "cpu_used", 
+		CTLFLAG_RD, &pr->jail_settings.cpu_used, 0, "Amount of CPU used");
+	SYSCTL_ADD_PROC(&pr->jd_sysctltree, SYSCTL_CHILDREN(pr->jd_sysctltreetop), OID_AUTO, 
+		"ipv4addr", CTLTYPE_STRING | CTLFLAG_RW, pr, sizeof (struct prison), jail_ipv4addr_sysctl,
+		"A", "List of IPv4 addresses in jail.");
+
 	PROC_UNLOCK(p);
 	crfree(oldcred);
 	return (0);
@@ -107,17 +281,157 @@
 	return (error);
 }
 
+int
+jail_calctotalused(pr)
+	struct prison *pr;
+{
+	struct proc *process;
+	u_int totalram = 0;
+	u_int numprocs = 0;
+
+	/* Go through every process in the system and calculate 
+	   the amount of CPU and RAM used. */
+	FOREACH_PROC_IN_SYSTEM(process) {
+		if (!jailed(process->p_ucred)) {
+			continue;
+		}
+
+		if (process->p_ucred->cr_prison != pr) {
+			continue;
+		}
+
+		numprocs++;
+		totalram += process->p_vmspace->vm_tsize + process->p_vmspace->vm_dsize
+		    + process->p_vmspace->vm_ssize;
+	}
+
+	mtx_lock(&pr->pr_mtx);
+	pr->jail_settings.ram_used = totalram * PAGE_SIZE;
+	pr->jail_settings.procs_used = numprocs;
+	mtx_unlock(&pr->pr_mtx);
+
+	return 0;
+}
+
+/* This is from print.c in /usr/src/bin/ps. */
+#define fxtofl(fixpt)   ((double)(fixpt) / FSCALE)
+
+void
+jail_update_cpu(void)
+{
+	struct proc *p;
+	struct jailelement *element;
+	struct thread *td;
+
+	/* If no jails exist, exit function. */
+	if (!firstjail.lh_first) {
+		return;
+	}
+
+	/* Clear jail CPU counters. */
+	LIST_FOREACH(element, &firstjail, pointers) {
+		element->pr->jail_settings.cpu_used = 0;
+	}
+
+	/* Check all processes for CPU usage. */
+	FOREACH_PROC_IN_SYSTEM(p) {
+		FOREACH_THREAD_IN_PROC(p, td) {
+			if (td->td_kse && td->td_ucred->cr_prison) {
+				td->td_ucred->cr_prison->jail_settings.cpu_used += 
+				    fxtofl(sched_pctcpu(td->td_kse)) * 100.0;
+			}
+		}
+	}
+
+	/* Exit function. */
+	return;
+}
+
+int
+jail_check_cpu(uc)
+	struct ucred *uc;
+{
+	if (uc->cr_prison && uc->cr_prison->jail_settings.cpu_used >= 
+	    uc->cr_prison->jail_settings.max_cpu && uc->cr_prison->jail_settings.max_cpu > 0) {
+		return 1;
+	} else {
+		return 0;
+	}
+}
+
+int
+jail_check_resources(td)
+	struct thread *td;
+{
+	struct prison *pr = td->td_proc->p_ucred->cr_prison;
+        
+	if (pr) {
+		/* Ensure jail isn't using more than it is allocated. */ 
+		jail_calctotalused(pr);
+		if (pr->jail_settings.max_ram > 0 && 
+		    pr->jail_settings.ram_used > pr->jail_settings.max_ram) {
+			return ENOMEM;
+		} else if (pr->jail_settings.max_procs > 0 &&
+		    pr->jail_settings.procs_used > pr->jail_settings.max_procs) {
+			return EAGAIN;
+		} else if (pr->jail_settings.max_cpu > 0 &&  
+		    pr->jail_settings.cpu_used > pr->jail_settings.max_cpu) {    
+			return EAGAIN;
+		}
+	}
+
+	return 0;
+}
+
+int
+jail_check_fileperm(vp, cred, td)
+	struct vnode *vp;
+	struct ucred *cred;
+	struct thread *td;
+{
+	struct jailelement *element;
+
+	/* If file is in a running jail, and jail_hide_files = 1, deny permission
+	   to all but root. */
+	if (jail_hide_files && !cred->cr_prison && cred->cr_uid > 0) {
+		LIST_FOREACH(element, &firstjail, pointers) {
+			if (!strncmp(vp->v_mount->mnt_stat.f_mntonname, element->chroot_path,
+			    strlen(element->chroot_path))) {
+				return EACCES;
+			}
+		} 
+	}
+
+	return 0;
+}
+
 void
 prison_free(struct prison *pr)
 {
+	struct jailelement *element;
 
 	mtx_lock(&pr->pr_mtx);
 	pr->pr_ref--;
 	if (pr->pr_ref == 0) {
 		mtx_unlock(&pr->pr_mtx);
 		mtx_destroy(&pr->pr_mtx);
+
+		/* Remove jail from list. */
+		LIST_FOREACH(element, &firstjail, pointers) {
+			if (element->pr == pr) {
+				LIST_REMOVE(element, pointers);
+				break;
+			}
+		}
+
 		if (pr->pr_linux != NULL)
 			FREE(pr->pr_linux, M_PRISON);
+		FREE(pr->pr_ips, M_PRISON);
+
+		/* Remove sysctls. */
+		pr->jd_sysctltreetop = NULL;
+		sysctl_ctx_free(&pr->jd_sysctltree);
+
 		FREE(pr, M_PRISON);
 		return;
 	}
@@ -137,7 +451,7 @@
 prison_getip(struct ucred *cred)
 {
 
-	return (cred->cr_prison->pr_ip);
+	return (cred->cr_prison->pr_ips[0]);
 }
 
 int
@@ -152,20 +466,16 @@
 	else
 		tmp = ntohl(*ip);
 	if (tmp == INADDR_ANY) {
-		if (flag) 
-			*ip = cred->cr_prison->pr_ip;
-		else
-			*ip = htonl(cred->cr_prison->pr_ip);
 		return (0);
 	}
 	if (tmp == INADDR_LOOPBACK) {
 		if (flag)
-			*ip = cred->cr_prison->pr_ip;
+			*ip = cred->cr_prison->pr_ips[0];
 		else
-			*ip = htonl(cred->cr_prison->pr_ip);
+			*ip = htonl(cred->cr_prison->pr_ips[0]);
 		return (0);
 	}
-	if (cred->cr_prison->pr_ip != tmp)
+	if (!prison_check_ip(cred->cr_prison, tmp))
 		return (1);
 	return (0);
 }
@@ -183,9 +493,9 @@
 		tmp = ntohl(*ip);
 	if (tmp == INADDR_LOOPBACK) {
 		if (flag)
-			*ip = cred->cr_prison->pr_ip;
+			*ip = cred->cr_prison->pr_ips[0];
 		else
-			*ip = htonl(cred->cr_prison->pr_ip);
+			*ip = htonl(cred->cr_prison->pr_ips[0]);
 		return;
 	}
 	return;
@@ -201,7 +511,7 @@
 		ok = 1;
 	else if (sai->sin_family != AF_INET)
 		ok = 0;
-	else if (cred->cr_prison->pr_ip != ntohl(sai->sin_addr.s_addr))
+	else if (!prison_check_ip(cred->cr_prison, ntohl(sai->sin_addr.s_addr)))
 		ok = 1;
 	else
 		ok = 0;
@@ -221,6 +531,12 @@
 			return (ESRCH);
 		if (cred2->cr_prison != cred1->cr_prison)
 			return (ESRCH);
+	} else {
+		/* This is necessary because it appears if a process is running in
+		   a jail and the process is running under the same UID as the user,
+		   kill() will actually kill it. */
+		if (jailed(cred2) && cred1->cr_ruid != 0 && jail_hide_processes)
+			return (ESRCH);
 	}
 
 	return (0);
@@ -254,4 +570,20 @@
 	}
 	else
 		strlcpy(buf, hostname, size);
+}
+
+/*
+ * Returns 1 if the IP exists in the jail.
+ */
+int
+prison_check_ip(struct prison *pr, u_int32_t ip)
+{
+	register u_int i;
+
+	for (i = 0; i < pr->pr_nips; ++i) {
+		if (pr->pr_ips[i] == ip)
+			return (1);
+	}
+
+	return (0);
 }
diff -ur src.virgin/sys/kern/kern_switch.c src.dirty/sys/kern/kern_switch.c
--- src.virgin/sys/kern/kern_switch.c	Mon Oct 14 14:43:02 2002
+++ src.dirty/sys/kern/kern_switch.c	Thu Feb 27 17:38:32 2003
@@ -98,6 +98,7 @@
 #include <sys/proc.h>
 #include <sys/queue.h>
 #include <sys/sched.h>
+#include <sys/jail.h>
 #include <machine/critical.h>
 
 CTASSERT((RQB_BPW * RQB_LEN) == RQ_NQS);
@@ -241,6 +242,10 @@
 			original->td_kse = NULL;
 		original = owner;
 
+		if (TD_IS_JSLEEP(owner) && jail_check_cpu(owner->td_ucred) == 0) {
+			/* Wake it up. */
+			TD_CLR_JSLEEP(owner);
+		}
 		if (TD_CAN_RUN(owner)) {
 			/*
 			 * If the owner thread is now runnable,  run it..
@@ -379,6 +384,13 @@
 	struct ksegrp *kg;
 	struct thread *td2;
 	struct thread *tda;
+
+	if (td->td_ucred && jail_check_cpu(td->td_ucred) == 1) {
+		/* Don't add to run queue. Put it to sleep. Exit function. */
+		TD_SET_JSLEEP(td);
+		td->td_ucred->cr_prison->resched = 1;
+		return;
+	}
 
 	CTR1(KTR_RUNQ, "setrunqueue: td%p", td);
 	mtx_assert(&sched_lock, MA_OWNED);
diff -ur src.virgin/sys/kern/sched_4bsd.c src.dirty/sys/kern/sched_4bsd.c
--- src.virgin/sys/kern/sched_4bsd.c	Thu Nov 21 02:30:55 2002
+++ src.dirty/sys/kern/sched_4bsd.c	Thu Feb 27 17:38:32 2003
@@ -42,6 +42,7 @@
 #include <sys/systm.h>
 #include <sys/kernel.h>
 #include <sys/ktr.h>
+#include <sys/jail.h>
 #include <sys/lock.h>
 #include <sys/mutex.h>
 #include <sys/proc.h>
@@ -116,7 +117,7 @@
 {
 
 	mtx_assert(&sched_lock, MA_OWNED);
-	if (td->td_priority < curthread->td_priority)
+	if (td->td_priority < curthread->td_priority || td->td_ucred->cr_prison)
 		curthread->td_kse->ke_flags |= KEF_NEEDRESCHED;
 }
 
@@ -241,12 +242,29 @@
 	struct kse *ke;
 	struct ksegrp *kg;
 	int realstathz;
-	int awake;
+	int awake, checked_status = 0;
 
 	realstathz = stathz ? stathz : hz;
 	sx_slock(&allproc_lock);
 	FOREACH_PROC_IN_SYSTEM(p) {
 		mtx_lock_spin(&sched_lock);
+		if (p->p_ucred->cr_prison) {
+			if (!jail_check_cpu(p->p_ucred)) {
+				mtx_unlock_spin(&sched_lock);
+				FOREACH_THREAD_IN_PROC(p, td) {
+					if (TD_IS_JSLEEP(td)) {
+						TD_CLR_JSLEEP(td);
+						setrunqueue(td);
+					}
+				}
+				mtx_lock_spin(&sched_lock);
+			}
+			if (checked_status == 0) {
+				jail_update_cpu();
+				checked_status = 1;
+			}
+		}
+
 		p->p_swtime++;
 		FOREACH_KSEGRP_IN_PROC(p, kg) { 
 			awake = 0;
diff -ur src.virgin/sys/kern/sysv_ipc.c src.dirty/sys/kern/sysv_ipc.c
--- src.virgin/sys/kern/sysv_ipc.c	Mon Apr  1 14:31:00 2002
+++ src.dirty/sys/kern/sysv_ipc.c	Thu Feb 27 17:38:32 2003
@@ -78,6 +78,11 @@
 {
 	struct ucred *cred = td->td_ucred;
 
+	/* Check for jail match. */
+	if (cred->cr_prison != perm->pr) {
+		return EACCES;
+	}
+
 	/* Check for user match. */
 	if (cred->cr_uid != perm->cuid && cred->cr_uid != perm->uid) {
 		if (mode & IPC_M)
diff -ur src.virgin/sys/kern/sysv_msg.c src.dirty/sys/kern/sysv_msg.c
--- src.virgin/sys/kern/sysv_msg.c	Sun Dec 15 06:54:55 2002
+++ src.dirty/sys/kern/sysv_msg.c	Thu Feb 27 17:38:32 2003
@@ -435,6 +435,7 @@
 		msqptr->msg_perm.gid = msqbuf.msg_perm.gid;	/* change the owner */
 		msqptr->msg_perm.mode = (msqptr->msg_perm.mode & ~0777) |
 		    (msqbuf.msg_perm.mode & 0777);
+		msqptr->msg_perm.pr = td->td_ucred->cr_prison;
 		msqptr->msg_qbytes = msqbuf.msg_qbytes;
 		msqptr->msg_ctime = time_second;
 		break;
@@ -539,6 +540,7 @@
 		msqptr->msg_perm.mode = (msgflg & 0777);
 		/* Make sure that the returned msqid is unique */
 		msqptr->msg_perm.seq = (msqptr->msg_perm.seq + 1) & 0x7fff;
+		msqptr->msg_perm.pr = td->td_ucred->cr_prison;
 		msqptr->msg_first = NULL;
 		msqptr->msg_last = NULL;
 		msqptr->msg_cbytes = 0;
diff -ur src.virgin/sys/kern/sysv_sem.c src.dirty/sys/kern/sysv_sem.c
--- src.virgin/sys/kern/sysv_sem.c	Fri Oct 18 20:07:35 2002
+++ src.dirty/sys/kern/sysv_sem.c	Thu Feb 27 17:38:32 2003
@@ -585,6 +585,7 @@
 		semaptr->sem_perm.mode = (semaptr->sem_perm.mode & ~0777) |
 		    (sbuf.sem_perm.mode & 0777);
 		semaptr->sem_ctime = time_second;
+		semaptr->sem_perm.pr = td->td_ucred->cr_prison;
 		break;
 
 	case IPC_STAT:
@@ -832,6 +833,7 @@
 		sema[semid].sem_perm.mode = (semflg & 0777) | SEM_ALLOC;
 		sema[semid].sem_perm.seq =
 		    (sema[semid].sem_perm.seq + 1) & 0x7fff;
+		sema[semid].sem_perm.pr = cred->cr_prison;
 		sema[semid].sem_nsems = nsems;
 		sema[semid].sem_otime = 0;
 		sema[semid].sem_ctime = time_second;
diff -ur src.virgin/sys/kern/sysv_shm.c src.dirty/sys/kern/sysv_shm.c
--- src.virgin/sys/kern/sysv_shm.c	Wed Aug 14 20:10:12 2002
+++ src.dirty/sys/kern/sysv_shm.c	Thu Feb 27 17:38:32 2003
@@ -226,6 +226,11 @@
 
 	segnum = IPCID_TO_IX(shmmap_s->shmid);
 	shmseg = &shmsegs[segnum];
+	/* Check jail permissions. */
+	if (p->p_ucred->cr_prison != shmseg->shm_perm.pr) {
+		return(EACCES);
+	}
+
 	size = round_page(shmseg->shm_segsz);
 	result = vm_map_remove(&p->p_vmspace->vm_map, shmmap_s->va,
 	    shmmap_s->va + size);
@@ -538,6 +543,7 @@
 		    (shmseg->shm_perm.mode & ~ACCESSPERMS) |
 		    (inbuf.shm_perm.mode & ACCESSPERMS);
 		shmseg->shm_ctime = time_second;
+		shmseg->shm_perm.pr = td->td_ucred->cr_prison;
 		break;
 	case IPC_RMID:
 		error = ipcperm(td, &shmseg->shm_perm, IPC_M);
@@ -645,6 +651,7 @@
 	shmseg->shm_perm.mode = SHMSEG_ALLOCATED | SHMSEG_REMOVED;
 	shmseg->shm_perm.key = uap->key;
 	shmseg->shm_perm.seq = (shmseg->shm_perm.seq + 1) & 0x7fff;
+	shmseg->shm_perm.pr = td->td_ucred->cr_prison;
 	shm_handle = (struct shm_handle *)
 	    malloc(sizeof(struct shm_handle), M_SHM, M_WAITOK);
 	shmid = IXSEQ_TO_IPCID(segnum, shmseg->shm_perm);
@@ -673,6 +680,7 @@
 	shmseg->shm_lpid = shmseg->shm_nattch = 0;
 	shmseg->shm_atime = shmseg->shm_dtime = 0;
 	shmseg->shm_ctime = time_second;
+	shmseg->shm_perm.pr = td->td_ucred->cr_prison;
 	shm_committed += btoc(size);
 	shm_nused++;
 	if (shmseg->shm_perm.mode & SHMSEG_WANTED) {
diff -ur src.virgin/sys/kern/vfs_syscalls.c src.dirty/sys/kern/vfs_syscalls.c
--- src.virgin/sys/kern/vfs_syscalls.c	Mon Jan  6 14:20:54 2003
+++ src.dirty/sys/kern/vfs_syscalls.c	Mon Mar  3 07:53:27 2003
@@ -158,7 +158,8 @@
 }
 
 /* XXX PRISON: could be per prison flag */
-static int prison_quotas;
+/*static int prison_quotas;*/
+extern int jail_quotas_allowed;
 #if 0
 SYSCTL_INT(_kern_prison, OID_AUTO, quotas, CTLFLAG_RW, &prison_quotas, 0, "");
 #endif
@@ -189,7 +190,7 @@
 	int error;
 	struct nameidata nd;
 
-	if (jailed(td->td_ucred) && !prison_quotas)
+	if (jailed(td->td_ucred) && !jail_quotas_allowed)
 		return (EPERM);
 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, td);
 	if ((error = namei(&nd)) != 0)
@@ -311,6 +312,8 @@
 	int flags;
 };
 #endif
+extern struct jails firstjail;
+
 int
 getfsstat(td, uap)
 	struct thread *td;
@@ -324,6 +327,7 @@
 	register struct statfs *sp;
 	caddr_t sfsp;
 	long count, maxcount, error;
+	struct statfs *tmpsp;
 
 	maxcount = uap->bufsize / sizeof(struct statfs);
 	sfsp = (caddr_t)uap->buf;
@@ -356,7 +360,35 @@
 				continue;
 			}
 			sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
-			error = copyout(sp, sfsp, sizeof(*sp));
+
+			/* If jailed, only return the mountpoints that are in the jail. */
+			if (td->td_proc->p_ucred->cr_prison) {
+				struct jailelement *element;
+				LIST_FOREACH(element, &firstjail, pointers) {
+					if (element->pr == td->td_proc->p_ucred->cr_prison) {
+						break;
+					}
+				}
+				if (!strncmp(element->chroot_path, sp->f_mntonname, 
+				  strlen(element->chroot_path))) {
+					MALLOC(tmpsp, struct statfs *, sizeof(struct statfs), M_PRISON, M_WAITOK);
+					memcpy(tmpsp, sp, sizeof(struct statfs));
+					strcpy(tmpsp->f_mntonname, sp->f_mntonname + strlen(element->chroot_path));
+					if (strlen(tmpsp->f_mntonname) == 0) {
+						/* Root mount. */
+						strcpy(tmpsp->f_mntonname, "/");
+					}
+					error = copyout(tmpsp, sfsp, sizeof(*tmpsp));
+					FREE(tmpsp, M_PRISON);
+				} else {
+					mtx_lock(&mountlist_mtx);
+					nmp = TAILQ_NEXT(mp, mnt_list);
+					vfs_unbusy(mp, td);
+					continue;
+				}
+			} else {
+				error = copyout(sp, sfsp, sizeof(*sp));
+			}
 			if (error) {
 				vfs_unbusy(mp, td);
 				return (error);
@@ -1423,6 +1455,7 @@
 			flags |= VWRITE;
 		if (user_flags & X_OK)
 			flags |= VEXEC;
+
 #ifdef MAC
 		error = mac_check_vnode_access(cred, vp, flags);
 		if (error)
diff -ur src.virgin/sys/netinet/in_pcb.c src.dirty/sys/netinet/in_pcb.c
--- src.virgin/sys/netinet/in_pcb.c	Fri Nov  8 16:50:32 2002
+++ src.dirty/sys/netinet/in_pcb.c	Sun Mar  2 19:57:40 2003
@@ -296,7 +296,7 @@
 			    !IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) {
 				t = in_pcblookup_local(inp->inp_pcbinfo,
 				    sin->sin_addr, lport,
-				    prison ? 0 :  INPLOOKUP_WILDCARD);
+				    prison ? 0 :  INPLOOKUP_WILDCARD, prison ? td : NULL);
 				if (t &&
 				    (ntohl(sin->sin_addr.s_addr) != INADDR_ANY ||
 				     ntohl(t->inp_laddr.s_addr) != INADDR_ANY ||
@@ -319,7 +319,7 @@
 			    prison_ip(td->td_ucred, 0, &sin->sin_addr.s_addr))
 				return (EADDRNOTAVAIL);
 			t = in_pcblookup_local(pcbinfo, sin->sin_addr,
-			    lport, prison ? 0 : wild);
+			    lport, prison ? 0 : wild, prison ? td : NULL);
 			if (t &&
 			    (reuseport & t->inp_socket->so_options) == 0) {
 #if defined(INET6)
@@ -340,6 +340,9 @@
 		ushort first, last;
 		int count;
 
+		if (laddr.s_addr == INADDR_ANY && td->td_ucred->cr_prison)
+			laddr.s_addr = htonl(prison_getip(td->td_ucred));
+
 		if (laddr.s_addr != INADDR_ANY)
 			if (prison_ip(td->td_ucred, 0, &laddr.s_addr))
 				return (EINVAL);
@@ -381,7 +384,7 @@
 					*lastport = first;
 				lport = htons(*lastport);
 			} while (in_pcblookup_local(pcbinfo, laddr, lport,
-			    wild));
+			    wild, wild ? NULL : td));
 		} else {
 			/*
 			 * counting up
@@ -396,7 +399,7 @@
 					*lastport = first;
 				lport = htons(*lastport);
 			} while (in_pcblookup_local(pcbinfo, laddr, lport,
-			    wild));
+			    wild, wild ? NULL : td));
 		}
 	}
 	if (prison_ip(td->td_ucred, 0, &laddr.s_addr))
@@ -519,9 +522,13 @@
 		 * and the primary interface supports broadcast,
 		 * choose the broadcast address for that interface.
 		 */
-		if (faddr.s_addr == INADDR_ANY)
-			faddr = IA_SIN(TAILQ_FIRST(&in_ifaddrhead))->sin_addr;
-		else if (faddr.s_addr == (u_long)INADDR_BROADCAST &&
+		if (faddr.s_addr == INADDR_ANY) {
+			if (jailed(cred)) {
+				faddr.s_addr = htonl(prison_getip(cred));
+			} else {
+				faddr = IA_SIN(TAILQ_FIRST(&in_ifaddrhead))->sin_addr;
+			}
+		} else if (faddr.s_addr == (u_long)INADDR_BROADCAST &&
 		    (TAILQ_FIRST(&in_ifaddrhead)->ia_ifp->if_flags &
 		    IFF_BROADCAST))
 			faddr = satosin(&TAILQ_FIRST(
@@ -876,11 +883,12 @@
  * Lookup a PCB based on the local address and port.
  */
 struct inpcb *
-in_pcblookup_local(pcbinfo, laddr, lport_arg, wild_okay)
+in_pcblookup_local(pcbinfo, laddr, lport_arg, wild_okay, td)
 	struct inpcbinfo *pcbinfo;
 	struct in_addr laddr;
 	u_int lport_arg;
 	int wild_okay;
+	struct thread *td;
 {
 	register struct inpcb *inp;
 	int matchwild = 3, wildcard;
@@ -900,11 +908,18 @@
 #endif
 			if (inp->inp_faddr.s_addr == INADDR_ANY &&
 			    inp->inp_laddr.s_addr == laddr.s_addr &&
-			    inp->inp_lport == lport) {
+			    inp->inp_lport == lport && 
+			    (laddr.s_addr != INADDR_ANY || !td->td_ucred->cr_prison)) {
 				/*
 				 * Found.
 				 */
 				return (inp);
+			} else if (td->td_ucred->cr_prison &&
+			    td->td_ucred->cr_prison == inp->inp_socket->so_cred->cr_prison &&
+			    inp->inp_faddr.s_addr == INADDR_ANY &&
+			    inp->inp_laddr.s_addr == laddr.s_addr &&
+			    inp->inp_lport == lport) {
+				return (inp);
 			}
 		}
 		/*
@@ -1005,12 +1020,24 @@
 
 		head = &pcbinfo->hashbase[INP_PCBHASH(INADDR_ANY, lport, 0, pcbinfo->hashmask)];
 		LIST_FOREACH(inp, head, inp_hash) {
+			if (inp->inp_socket->so_cred->cr_prison &&
+			    inp->inp_lport == lport &&
+			    inp->inp_laddr.s_addr == INADDR_ANY) {
+				if (prison_check_ip(inp->inp_socket->so_cred->cr_prison, ntohl(laddr.s_addr))) {
+					return (inp);
+				}
+			}
+		}
+
+		head = &pcbinfo->hashbase[INP_PCBHASH(INADDR_ANY, lport, 0, pcbinfo->hashmask)];
+		LIST_FOREACH(inp, head, inp_hash) {
 #ifdef INET6
 			if ((inp->inp_vflag & INP_IPV4) == 0)
 				continue;
 #endif
 			if (inp->inp_faddr.s_addr == INADDR_ANY &&
-			    inp->inp_lport == lport) {
+			    inp->inp_lport == lport &&
+			    !inp->inp_socket->so_cred->cr_prison) {
 				if (ifp && ifp->if_type == IFT_FAITH &&
 				    (inp->inp_flags & INP_FAITH) == 0)
 					continue;
@@ -1019,11 +1046,14 @@
 				else if (inp->inp_laddr.s_addr == INADDR_ANY) {
 #if defined(INET6)
 					if (INP_CHECK_SOCKAF(inp->inp_socket,
-							     AF_INET6))
+							     AF_INET6)) {
 						local_wild_mapped = inp;
-					else
+					} else {
+#endif /* defined(INET6) */
+						local_wild = inp;
+#if defined(INET6)
+					}
 #endif /* defined(INET6) */
-					local_wild = inp;
 				}
 			}
 		}
@@ -1145,7 +1175,7 @@
 {
 	if (!jailed(td->td_ucred))
 		return (0);
-	if (ntohl(inp->inp_laddr.s_addr) == prison_getip(td->td_ucred))
+	if (prison_check_ip(td->td_ucred->cr_prison, ntohl(inp->inp_laddr.s_addr)))
 		return (0);
 	return (1);
 }
diff -ur src.virgin/sys/netinet/in_pcb.h src.dirty/sys/netinet/in_pcb.h
--- src.virgin/sys/netinet/in_pcb.h	Tue Nov 12 13:44:38 2002
+++ src.dirty/sys/netinet/in_pcb.h	Thu Feb 27 17:38:33 2003
@@ -339,7 +339,7 @@
 int	in_pcbinshash(struct inpcb *);
 struct inpcb *
 	in_pcblookup_local(struct inpcbinfo *,
-	    struct in_addr, u_int, int);
+	    struct in_addr, u_int, int, struct thread *);
 struct inpcb *
 	in_pcblookup_hash(struct inpcbinfo *, struct in_addr, u_int,
 	    struct in_addr, u_int, int, struct ifnet *);
diff -ur src.virgin/sys/netinet/ip_fw.c src.dirty/sys/netinet/ip_fw.c
--- src.virgin/sys/netinet/ip_fw.c	Sat Jun 22 05:51:02 2002
+++ src.dirty/sys/netinet/ip_fw.c	Sat Mar 22 13:36:09 2003
@@ -64,6 +64,8 @@
 
 #include <netinet/if_ether.h> /* XXX ethertype_ip */
 
+#include <sys/jail.h>
+
 static int fw_debug = 1;
 #ifdef IPFIREWALL_VERBOSE
 static int fw_verbose = 1;
@@ -2010,6 +2012,11 @@
 	}
 
 	error = 0;
+
+	/* If allow_ipfw is not enabled, return an error. */
+	if (sopt->sopt_td->td_ucred->cr_prison && !sopt->sopt_td->td_ucred->cr_prison->jail_settings.allow_ipfw) {
+		return EPERM;
+	}
 
 	switch (sopt->sopt_name) {
 	case IP_FW_GET:
diff -ur src.virgin/sys/netinet/ip_fw2.c src.dirty/sys/netinet/ip_fw2.c
--- src.virgin/sys/netinet/ip_fw2.c	Sun Dec 15 06:57:43 2002
+++ src.dirty/sys/netinet/ip_fw2.c	Sun Mar 23 10:05:37 2003
@@ -77,6 +77,8 @@
 
 #include <machine/in_cksum.h>	/* XXX for in_cksum */
 
+#include <sys/jail.h>
+
 /*
  * XXX This one should go in sys/mbuf.h. It is used to avoid that
  * a firewall-generated packet loops forever through the firewall.
@@ -2440,6 +2442,34 @@
 	return EINVAL;
 }
 
+static int
+check_ipfw_jail(struct thread *td, struct ip_fw *rule)
+{
+	ipfw_insn_ip *ip_cmd;
+	ipfw_insn *cmd;
+
+	/* Jailed? */
+	if (!td->td_ucred->cr_prison) {
+		return 0;
+	}
+
+	/* Default rule? */
+	if (rule->rulenum == IPFW_DEFAULT_RULE) {
+		return 0;
+	}
+
+	/* Check all IP addresses in opcode list. */
+	for (cmd = rule->cmd; cmd != ACTION_PTR(rule); cmd++) {
+		if (cmd->opcode == O_IP_DST || cmd->opcode == O_IP_SRC) {
+			ip_cmd = (ipfw_insn_ip*)(cmd);
+			if (prison_check_ip(td->td_ucred->cr_prison, htonl(ip_cmd->addr.s_addr))) {
+				return 0;
+			}
+		}
+	}
+
+	return EPERM;
+}
 
 /**
  * {set|get}sockopt parser.
@@ -2471,6 +2501,11 @@
 
 	error = 0;
 
+        /* If allow_ipfw is not enabled, return an error. */
+	if (sopt->sopt_td->td_ucred->cr_prison && !sopt->sopt_td->td_ucred->cr_prison->jail_settings.allow_ipfw) {
+		return EPERM;
+	}
+
 	switch (sopt->sopt_name) {
 	case IP_FW_GET:
 		/*
@@ -2498,10 +2533,12 @@
 
 		bp = buf;
 		for (rule = layer3_chain; rule ; rule = rule->next) {
-			int i = RULESIZE(rule);
-			bcopy(rule, bp, i);
-			((struct ip_fw *)bp)->set_disable = set_disable;
-			bp = (struct ip_fw *)((char *)bp + i);
+			if (!check_ipfw_jail(sopt->sopt_td, rule)) {
+				int i = RULESIZE(rule);
+				bcopy(rule, bp, i);
+				((struct ip_fw *)bp)->set_disable = set_disable;
+				bp = (struct ip_fw *)((char *)bp + i);
+			}
 		}
 		if (ipfw_dyn_v) {
 			int i;
@@ -2547,7 +2584,10 @@
 		 * the list to point to the default rule, and then freeing
 		 * the old list without the need for a lock.
 		 */
-
+		if (sopt->sopt_td->td_ucred->cr_prison) {
+			error = EPERM;
+			break;
+		}
 		s = splimp();
 		free_chain(&layer3_chain, 0 /* keep default rule */);
 		splx(s);
@@ -2561,6 +2601,10 @@
 		if (error || (error = check_ipfw_struct(rule, size)))
 			break;
 
+		/* Check and make sure IP addresses are valid (if jailed). */
+		error = check_ipfw_jail(sopt->sopt_td, rule);
+		if (error) break;
+
 		error = add_rule(&layer3_chain, rule);
 		size = RULESIZE(rule);
 		if (!error && sopt->sopt_dir == SOPT_GET)
@@ -2584,6 +2628,9 @@
 			2*sizeof(u_int32_t), sizeof(u_int32_t));
 		if (error)
 			break;
+		error = check_ipfw_jail(sopt->sopt_td, (struct ip_fw*)rule_buf);
+		if (error)
+			break;
 		size = sopt->sopt_valsize;
 		if (size == sizeof(u_int32_t))	/* delete or reassign */
 			error = del_entry(&layer3_chain, rule_buf[0]);
@@ -2605,7 +2652,22 @@
 		    if (error)
 			break;
 		}
-		error = zero_entry(rulenum, sopt->sopt_name == IP_FW_RESETLOG);
+
+		if (sopt->sopt_td->td_ucred->cr_prison) {
+			/* We have to do this slightly differently. rulenum can't be
+			   a rule that's outside the jail. */
+			for (rule = layer3_chain; rule ; rule = rule->next) {
+				if (rule->rulenum == rulenum || rulenum == 0) {
+					if (!check_ipfw_jail(sopt->sopt_td, rule)) {
+						zero_entry(rule->rulenum, sopt->sopt_name == IP_FW_RESETLOG);
+					} else {
+						continue;
+					}
+				}
+			}
+		} else {
+			error = zero_entry(rulenum, sopt->sopt_name == IP_FW_RESETLOG);
+		}
 		break;
 
 	default:
diff -ur src.virgin/sys/netinet/raw_ip.c src.dirty/sys/netinet/raw_ip.c
--- src.virgin/sys/netinet/raw_ip.c	Wed Nov 20 12:00:54 2002
+++ src.dirty/sys/netinet/raw_ip.c	Sat Mar 22 12:19:46 2003
@@ -78,6 +78,8 @@
 #include <netinet6/ipsec.h>
 #endif /*IPSEC*/
 
+#include <sys/jail.h>
+
 struct	inpcbhead ripcb;
 struct	inpcbinfo ripcbinfo;
 
@@ -528,12 +530,20 @@
 {
 	struct inpcb *inp;
 	int error, s;
+	struct prison *saved = NULL;
 
 	inp = sotoinpcb(so);
 	if (inp)
 		panic("rip_attach");
-	if (td && (error = suser(td)) != 0)
+	if (td && td->td_ucred->cr_prison && td->td_ucred->cr_prison->jail_settings.allow_raw_sockets) {
+		saved = td->td_ucred->cr_prison;
+		td->td_ucred->cr_prison = NULL;
+	}
+	if (td && (error = suser(td)) != 0) {
+		td->td_ucred->cr_prison = saved;
 		return error;
+	}
+	td->td_ucred->cr_prison = saved;
 
 	if (proto >= IPPROTO_MAX || proto < 0)
 		return EPROTONOSUPPORT;
diff -ur src.virgin/sys/netinet6/in6_pcb.c src.dirty/sys/netinet6/in6_pcb.c
--- src.virgin/sys/netinet6/in6_pcb.c	Tue Oct 15 20:25:05 2002
+++ src.dirty/sys/netinet6/in6_pcb.c	Thu Feb 27 17:38:33 2003
@@ -213,7 +213,7 @@
 					in6_sin6_2_sin(&sin, sin6);
 					t = in_pcblookup_local(pcbinfo,
 						sin.sin_addr, lport,
-						INPLOOKUP_WILDCARD);
+						INPLOOKUP_WILDCARD, NULL);
 					if (t &&
 					    (so->so_cred->cr_uid !=
 					     t->inp_socket->so_cred->cr_uid) &&
@@ -234,7 +234,7 @@
 
 				in6_sin6_2_sin(&sin, sin6);
 				t = in_pcblookup_local(pcbinfo, sin.sin_addr,
-						       lport, wild);
+						       lport, wild, wild ? NULL : td);
 				if (t &&
 				    (reuseport & t->inp_socket->so_options)
 				    == 0 &&
diff -ur src.virgin/sys/sys/ipc.h src.dirty/sys/sys/ipc.h
--- src.virgin/sys/sys/ipc.h	Mon Oct 14 14:50:41 2002
+++ src.dirty/sys/sys/ipc.h	Thu Feb 27 17:38:33 2003
@@ -84,6 +84,7 @@
 	ushort	mode;	/* r/w permission */
 	ushort	seq;	/* sequence # (to generate unique msg/sem/shm id) */
 	key_t	key;	/* user specified msg/sem/shm key */
+	struct prison *pr;	/* For jail control. */
 };
 
 #if __BSD_VISIBLE
diff -ur src.virgin/sys/sys/jail.h src.dirty/sys/sys/jail.h
--- src.virgin/sys/sys/jail.h	Sun May  5 21:13:08 2002
+++ src.dirty/sys/sys/jail.h	Sat Mar 22 13:34:12 2003
@@ -17,7 +17,8 @@
 	u_int32_t	version;
 	char		*path;
 	char		*hostname;
-	u_int32_t	ip_number;
+	u_int32_t	*ips;
+	u_int		nips;
 };
 
 #ifndef _KERNEL
@@ -29,6 +30,9 @@
 #include <sys/queue.h>
 #include <sys/_lock.h>
 #include <sys/_mutex.h>
+#include <sys/sysctl.h>
+
+struct vnode;
 
 #ifdef MALLOC_DECLARE
 MALLOC_DECLARE(M_PRISON);
@@ -48,10 +52,26 @@
 struct prison {
 	int		 pr_ref;			/* (p) refcount */
 	char 		 pr_host[MAXHOSTNAMELEN];	/* (p) jail hostname */
-	u_int32_t	 pr_ip;				/* (c) ip addr host */
+	u_int32_t	 *pr_ips;			/* (c) ip addr host */
+	u_int		pr_nips;
 	void		*pr_linux;			/* (p) linux abi */
 	int		 pr_securelevel;		/* (p) securelevel */
 	struct mtx	 pr_mtx;
+	u_int		pr_numprocs;
+	struct {
+		u_int max_ram;
+		u_int max_cpu;
+		u_int max_procs;
+		u_int ram_used;
+		u_int procs_used;
+		u_int cpu_used;
+		u_int allow_raw_sockets;
+		u_int allow_ipfw;
+	} jail_settings;
+	char pr_host_oid[MAXHOSTNAMELEN];
+	struct sysctl_ctx_list jd_sysctltree;
+	struct sysctl_oid *jd_sysctltreetop;
+	int resched;
 };
 
 /*
@@ -64,6 +84,17 @@
 extern int	jail_sysvipc_allowed;
 
 /*
+ * List of jails (for jail_attach(), et. al.)
+ */
+struct jailelement {
+	struct prison *pr;				/* Prison element */
+	char *chroot_path;				/* Path to chroot to. */
+	LIST_ENTRY(jailelement) pointers;
+};
+
+LIST_HEAD(jails, jailelement);
+
+/*
  * Kernel support functions for jail().
  */
 struct ucred;
@@ -77,6 +108,12 @@
 int prison_if(struct ucred *cred, struct sockaddr *sa);
 int prison_ip(struct ucred *cred, int flag, u_int32_t *ip);
 void prison_remote_ip(struct ucred *cred, int flags, u_int32_t *ip);
+int prison_check_ip(struct prison *pr, u_int32_t ip);
+int jail_calctotalused(struct prison *pr);
+int jail_check_resources(struct thread *td);
+int jail_check_cpu(struct ucred *uc);
+void jail_update_cpu(void);
+int jail_check_fileperm(struct vnode *vp, struct ucred *cred, struct thread *td);
 
 #endif /* !_KERNEL */
 #endif /* !_SYS_JAIL_H_ */
diff -ur src.virgin/sys/sys/proc.h src.dirty/sys/sys/proc.h
--- src.virgin/sys/sys/proc.h	Mon Dec  9 19:33:45 2002
+++ src.dirty/sys/sys/proc.h	Thu Feb 27 17:38:33 2003
@@ -347,6 +347,7 @@
 #define	TDI_LOCK	0x08	/* Stopped on a lock. */
 #define	TDI_IWAIT	0x10	/* Awaiting interrupt. */
 #define	TDI_LOAN	0x20	/* bound thread's KSE is lent */
+#define TDI_JSLEEP	0x40	/* Jail suspension due to high CPU. */
 
 #define	TD_IS_SLEEPING(td)	((td)->td_inhibitors & TDI_SLEEPING)
 #define	TD_ON_SLEEPQ(td)	((td)->td_wchan != NULL)
@@ -355,6 +356,7 @@
 #define	TD_ON_LOCK(td)		((td)->td_inhibitors & TDI_LOCK)
 #define	TD_LENT(td)		((td)->td_inhibitors & TDI_LOAN)
 #define	TD_AWAITING_INTR(td)	((td)->td_inhibitors & TDI_IWAIT)
+#define TD_IS_JSLEEP(td)	((td)->td_inhibitors & TDI_JSLEEP)
 #define	TD_IS_RUNNING(td)	((td)->td_state == TDS_RUNNING)
 #define	TD_ON_RUNQ(td)		((td)->td_state == TDS_RUNQ)
 #define	TD_CAN_RUN(td)		((td)->td_state == TDS_CAN_RUN)
@@ -377,6 +379,7 @@
 #define	TD_SET_SUSPENDED(td)	TD_SET_INHIB((td), TDI_SUSPENDED)
 #define	TD_SET_IWAIT(td)	TD_SET_INHIB((td), TDI_IWAIT)
 #define	TD_SET_LOAN(td)		TD_SET_INHIB((td), TDI_LOAN)
+#define TD_SET_JSLEEP(td)	TD_SET_INHIB((td), TDI_JSLEEP)
 
 #define	TD_CLR_SLEEPING(td)	TD_CLR_INHIB((td), TDI_SLEEPING)
 #define	TD_CLR_SWAPPED(td)	TD_CLR_INHIB((td), TDI_SWAPPED)
@@ -384,6 +387,7 @@
 #define	TD_CLR_SUSPENDED(td)	TD_CLR_INHIB((td), TDI_SUSPENDED)
 #define	TD_CLR_IWAIT(td)	TD_CLR_INHIB((td), TDI_IWAIT)
 #define	TD_CLR_LOAN(td)		TD_CLR_INHIB((td), TDI_LOAN)
+#define TD_CLR_JSLEEP(td)	TD_CLR_INHIB((td), TDI_JSLEEP)
 
 #define	TD_SET_RUNNING(td)	do {(td)->td_state = TDS_RUNNING; } while (0)
 #define	TD_SET_RUNQ(td)		do {(td)->td_state = TDS_RUNQ; } while (0)
diff -ur src.virgin/sys/ufs/ufs/ufs_vnops.c src.dirty/sys/ufs/ufs/ufs_vnops.c
--- src.virgin/sys/ufs/ufs/ufs_vnops.c	Sun Oct 27 11:09:49 2002
+++ src.dirty/sys/ufs/ufs/ufs_vnops.c	Mon Mar  3 07:57:17 2003
@@ -62,6 +62,7 @@
 #include <sys/conf.h>
 #include <sys/acl.h>
 #include <sys/mac.h>
+#include <sys/jail.h>
 
 #include <machine/mutex.h>
 
@@ -339,6 +340,12 @@
 	struct acl *acl;
 	size_t len;
 #endif
+
+	/* Do special jail checking, if necessary. */
+	error = jail_check_fileperm(vp, ap->a_cred, ap->a_td);
+	if (error) {
+		return error;
+	}
 
 	/*
 	 * Disallow write attempts on read-only filesystems;
diff -ur src.virgin/usr.sbin/jail/jail.c src.dirty/usr.sbin/jail/jail.c
--- src.virgin/usr.sbin/jail/jail.c	Mon Apr 22 07:44:43 2002
+++ src.dirty/usr.sbin/jail/jail.c	Thu Feb 27 17:38:33 2003
@@ -26,28 +26,68 @@
 main(int argc, char **argv)
 {
 	struct jail j;
-	int i;
+	int i, k, m, c = 1;
 	struct in_addr in;
+	char *tempstring, ipstring[16];
 
-	if (argc < 5) 
-		errx(1, "usage: %s path hostname ip-number command ...\n",
+	if (argc < 5) {
+		errx(1, "Usage: %s path hostname ip1[,ip2[...]] command ...\n",
 		    argv[0]);
+	}
+
 	i = chdir(argv[1]);
 	if (i)
 		err(1, "chdir %s", argv[1]);
 	memset(&j, 0, sizeof(j));
-	j.version = 0;
+	j.version = 1;
 	j.path = argv[1];
 	j.hostname = argv[2];
-	i = inet_aton(argv[3], &in);
-	if (!i)
-		errx(1, "Couldn't make sense of ip-number\n");
-	j.ip_number = ntohl(in.s_addr);
+
+	/* Feb. 1, 2003 (MS): Determine how many IP addresses user passed to jail. This
+	   is important later for filling in j.nips and for allocating the proper amount
+	   of memory. */
+	tempstring = argv[3];
+	while(*tempstring) {
+		if (*tempstring == ',') c++;
+		tempstring++;
+	}
+	j.nips = c;
+
+	/* Allocate RAM, depending on number of IP addresses passed. */
+	j.ips = (u_int32_t *)malloc(sizeof(u_int32_t) * c);
+	if (j.ips == NULL) {
+		errx(1, "malloc() issue, line 56 (/usr/src/usr.sbin/jail/jail.c). Possible lack of RAM or software bug.");
+	}
+
+	/* Copy each IP into the array.
+	   Note (MS, 02/01/2003): 4.x version used strtok(), a dangerous programming construct. */
+	tempstring = argv[3];
+	m = 0;
+	while (*tempstring) {
+		k = 0;
+		while (1) {
+			if (*(tempstring+k) == ',' || *(tempstring+k) == '\0') {
+				strncpy(ipstring, tempstring, k);
+				ipstring[k] = '\0';
+				i = inet_aton(ipstring, &in);
+				if (!i) {
+					free(j.ips);
+					errx(1, "Couldn't make sense of IP address %s", ipstring);
+				}
+				j.ips[m++] = ntohl(in.s_addr);
+				break;
+			}
+			k++;
+		}
+		tempstring = tempstring + k;
+		if (*tempstring == ',') tempstring++;
+	}
+		
 	i = jail(&j);
 	if (i)
-		err(1, "Imprisonment failed");
+		errx(1, "Imprisonment failed");
 	i = execv(argv[4], argv + 4);
 	if (i)
-		err(1, "execv(%s)", argv[4]);
+		errx(1, "execv(%s)", argv[4]);
 	exit (0);
 }
help

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