svn commit: r191673 - in head: lib/libc/sys sys/cddl/compat/opensolaris/kern sys/compat/freebsd32 sys/kern sys/sys

Jamie Gritton jamie at FreeBSD.org
Wed Apr 29 21:14:17 UTC 2009


Author: jamie
Date: Wed Apr 29 21:14:15 2009
New Revision: 191673
URL: http://svn.freebsd.org/changeset/base/191673

Log:
  Introduce the extensible jail framework, using the same "name=value"
  interface as nmount(2).  Three new system calls are added:
  * jail_set, to create jails and change the parameters of existing jails.
    This replaces jail(2).
  * jail_get, to read the parameters of existing jails.  This replaces the
    security.jail.list sysctl.
  * jail_remove to kill off a jail's processes and remove the jail.
  Most jail parameters may now be changed after creation, and jails may be
  set to exist without any attached processes.  The current jail(2) system
  call still exists, though it is now a stub to jail_set(2).
  
  Approved by:	bz (mentor)

Modified:
  head/lib/libc/sys/Makefile.inc
  head/lib/libc/sys/Symbol.map
  head/lib/libc/sys/jail.2
  head/sys/cddl/compat/opensolaris/kern/opensolaris_zone.c
  head/sys/compat/freebsd32/freebsd32_misc.c
  head/sys/compat/freebsd32/syscalls.master
  head/sys/kern/kern_jail.c
  head/sys/kern/kern_osd.c
  head/sys/kern/syscalls.master
  head/sys/sys/jail.h
  head/sys/sys/osd.h
  head/sys/sys/priv.h
  head/sys/sys/syscallsubr.h

Modified: head/lib/libc/sys/Makefile.inc
==============================================================================
--- head/lib/libc/sys/Makefile.inc	Wed Apr 29 19:19:13 2009	(r191672)
+++ head/lib/libc/sys/Makefile.inc	Wed Apr 29 21:14:15 2009	(r191673)
@@ -137,7 +137,10 @@ MLINKS+=getsockopt.2 setsockopt.2
 MLINKS+=gettimeofday.2 settimeofday.2
 MLINKS+=getuid.2 geteuid.2
 MLINKS+=intro.2 errno.2
-MLINKS+=jail.2 jail_attach.2
+MLINKS+=jail.2 jail_attach.2 \
+	jail.2 jail_get.2 \
+	jail.2 jail_remove.2 \
+	jail.2 jail_set.2
 MLINKS+=kldunload.2 kldunloadf.2
 MLINKS+=kqueue.2 kevent.2
 MLINKS+=link.2 linkat.2

Modified: head/lib/libc/sys/Symbol.map
==============================================================================
--- head/lib/libc/sys/Symbol.map	Wed Apr 29 19:19:13 2009	(r191672)
+++ head/lib/libc/sys/Symbol.map	Wed Apr 29 21:14:15 2009	(r191673)
@@ -344,6 +344,9 @@ FBSD_1.1 {
 	fexecve;
 	fstatat;
 	futimesat;
+	jail_get;
+	jail_set;
+	jail_remove;
 	linkat;
 	mkdirat;
 	mkfifoat;

Modified: head/lib/libc/sys/jail.2
==============================================================================
--- head/lib/libc/sys/jail.2	Wed Apr 29 19:19:13 2009	(r191672)
+++ head/lib/libc/sys/jail.2	Wed Apr 29 21:14:15 2009	(r191673)
@@ -1,4 +1,5 @@
 .\" Copyright (c) 1999 Poul-Henning Kamp.
+.\" Copyright (c) 2009 James Gritton.
 .\" All rights reserved.
 .\"
 .\" Redistribution and use in source and binary forms, with or without
@@ -24,12 +25,16 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd January 6, 2009
+.Dd April 29, 2009
 .Dt JAIL 2
 .Os
 .Sh NAME
-.Nm jail , jail_attach
-.Nd imprison current process and future descendants
+.Nm jail ,
+.Nm jail_get ,
+.Nm jail_set ,
+.Nm jail_remove ,
+.Nm jail_attach
+.Nd create and manage system jails
 .Sh LIBRARY
 .Lb libc
 .Sh SYNOPSIS
@@ -39,6 +44,13 @@
 .Fn jail "struct jail *jail"
 .Ft int
 .Fn jail_attach "int jid"
+.Ft int
+.Fn jail_remove "int jid"
+.In sys/uio.h
+.Ft int
+.Fn jail_get "struct iovec *iov" "u_int niov" "int flags"
+.Ft int
+.Fn jail_set "struct iovec *iov" "u_int niov" "int flags"
 .Sh DESCRIPTION
 The
 .Fn jail
@@ -94,20 +106,147 @@ pointers can be set to an arrays of IPv4
 the prison, or NULL if none.
 IPv4 addresses must be in network byte order.
 .Pp
+This is equivalent to the
+.Fn jail_set
+system call (see below), with the parameters
+.Va path ,
+.Va host.hostname ,
+.Va name ,
+.Va ip4.addr ,
+and
+.Va ip6.addr ,
+and with the
+.Dv JAIL_ATTACH
+flag.
+.Pp
+The
+.Fn jail_set
+system call creates a new jail, or modifies an existing one, and optionally
+locks the current process in it.
+Jail parameters are passed as an array of name-value pairs in the array
+.Fa iov ,
+containing
+.Fa niov
+elements.
+Parameter names are a null-terminated string, and values may be strings,
+integers, or other arbitrary data.
+Some parameters are boolean, and do not have a value (their length is zero)
+but are set by the name alone with or without a
+.Dq no
+prefix, e.g.
+.Va persist
+or
+.Va nopersist .
+Any parameters not set will be given default values, generally based on
+the current environment.
+.Pp
+Jails have a set of core parameters, and modules can add their own jail
+parameters.
+The current set of available parameters, and their formats, can be
+retrieved via the
+.Va security.jail.param
+sysctl MIB entry.
+Notable parameters include those mentioned in the
+.Fn jail
+description above, as well as
+.Va jid
+and
+.Va name ,
+which identify the jail being created or modified.
+See
+.Xr jail 8
+for more information on the core jail parameters.
+.Pp
+The
+.Fa flags
+arguments consists of one or more of the following flags:
+.Bl -tag -width indent
+.It Dv JAIL_CREATE
+Create a new jail.
+If a
+.Va jid
+or
+.Va name
+parameters exists, they must not refer to an existing jail.
+.It Dv JAIL_UPDATE
+Modify an existing jail.
+One of the
+.Va jid
+or
+.Va name
+parameters must exist, and must refer to an existing jail.
+If both
+.Dv JAIL_CREATE
+and
+.Dv JAIL_UPDATE
+are set, a jail will be created if it does not yet exist, and modified if it
+does exist.
+.It Dv JAIL_ATTACH
+In addition to creating or modifying the jail, attach the current process to
+it, as with the
+.Fn jail_attach
+system call.
+.It Dv JAIL_DYING
+Allow setting a jail that is in the process of being removed.
+.El
+.Pp
+The
+.Fn jail_get
+system call retrieves jail parameters, using the same name-value list as
+.Fn jail_set
+in the
+.Fa iov
+and
+.Fa niov
+arguments.
+The jail to read can be specified by either
+.Va jid
+or
+.Va name
+by including those parameters in the list.
+If they are included but are not intended to be the search key, they
+should be cleared (zero and the empty string respectively).
+.Pp
+The special parameter
+.Va lastjid
+can be used to retrieve a list of all jails.
+It will fetch the jail with the jid above and closest to the passed value.
+The first jail (usually but not always jid 1) can be found by passing a
+.Va lastjid
+of zero.
+.Pp
+The
+.Fa flags
+arguments consists of one or more following flags:
+.Bl -tag -width indent
+.It Dv JAIL_DYING
+Allow getting a jail that is in the process of being removed.
+.El
+.Pp
 The
 .Fn jail_attach
 system call attaches the current process to an existing jail,
 identified by
 .Fa jid .
+.Pp
+The
+.Fn jail_remove
+system call removes the jail identified by
+.Fa jid .
+It will kill all processes belonging to the jail, and remove any children
+of that jail.
 .Sh RETURN VALUES
 If successful,
-.Fn jail
-returns a non-negative integer, termed the jail identifier (JID).
-It returns \-1 on failure, and sets
+.Fn jail ,
+.Fn jail_set ,
+and
+.Fn jail_get
+return a non-negative integer, termed the jail identifier (JID).
+They return \-1 on failure, and set
 .Va errno
 to indicate the error.
 .Pp
-.Rv -std jail_attach
+.Rv -std jail_attach jail_remove
 .Sh PRISON?
 Once a process has been put in a prison, it and its descendants cannot escape
 the prison.
@@ -152,15 +291,111 @@ The
 system call
 will fail if:
 .Bl -tag -width Er
+.It Bq Er EPERM
+This process is not allowed to create a jail.
+.It Bq Er EFAULT
+.Fa jail
+points to an address outside the allocated address space of the process.
 .It Bq Er EINVAL
 The version number of the argument is not correct.
 .It Bq Er EAGAIN
 No free JID could be found.
 .El
 .Pp
+The
+.Fn jail_set
+system call
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EPERM
+This process is not allowed to create a jail.
+.It Bq Er EPERM
+A jail parameter was set to a less restrictive value then the current
+environment.
+.It Bq Er EFAULT
+.Fa Iov ,
+or one of the addresses contained within it,
+points to an address outside the allocated address space of the process.
+.It Bq Er ENOENT
+The jail referred to by a
+.Va jid
+or
+.Va name
+parameter does not exist, and the
+.Dv JAIL_CREATE
+flag is not set.
+.It Bq Er EEXIST
+The jail referred to by a
+.Va jid
+or
+.Va name
+parameter exists, and the
+.Dv JAIL_UPDATE
+flag is not set.
+.It Bq Er EINVAL
+A supplied parameter is the wrong size.
+.It Bq Er EINVAL
+A supplied parameter is out of range.
+.It Bq Er EINVAL
+A supplied string parameter is not null-terminated.
+.It Bq Er EINVAL
+A supplied parameter name does not match any known parameters.
+.It Bq Er EINVAL
+One of the
+.Dv JAIL_CREATE
+or
+.Dv JAIL_UPDATE
+flags is not set.
+.It Bq Er ENAMETOOLONG
+A supplied string parameter is longer than allowed.
+.It Bq Er EAGAIN
+There are no jail IDs left.
+.El
+.Pp
+The
+.Fn jail_get
+system call
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EFAULT
+.Fa Iov ,
+or one of the addresses contained within it,
+points to an address outside the allocated address space of the process.
+.It Bq Er ENOENT
+The jail referred to by a
+.Va jid
+or
+.Va name
+parameter does not exist.
+.It Bq Er ENOENT
+The
+.Va lastjid
+parameter is greater than the highest current jail ID.
+.It Bq Er EINVAL
+A supplied parameter is the wrong size.
+.It Bq Er EINVAL
+A supplied parameter name does not match any known parameters.
+.El
+.Pp
+The
+.Fn jail_attach
+and
+.Fn jail_remove
+system calls
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The jail specified by
+.Fa jid
+does not exist.
+.El
+.Pp
 Further
-.Fn jail
-calls
+.Fn jail ,
+.Fn jail_set ,
+and
+.Fn jail_attach
+call
 .Xr chroot 2
 internally, so it can fail for all the same reasons.
 Please consult the
@@ -168,7 +403,8 @@ Please consult the
 manual page for details.
 .Sh SEE ALSO
 .Xr chdir 2 ,
-.Xr chroot 2
+.Xr chroot 2 ,
+.Xr jail 8
 .Sh HISTORY
 The
 .Fn jail
@@ -178,6 +414,13 @@ The
 .Fn jail_attach
 system call appeared in
 .Fx 5.1 .
+The
+.Fn jail_set ,
+.Fn jail_get ,
+and
+.Fn jail_remove
+system calls appeared in
+.Fx 8.0 .
 .Sh AUTHORS
 The jail feature was written by
 .An Poul-Henning Kamp
@@ -185,3 +428,5 @@ for R&D Associates
 .Dq Li http://www.rndassociates.com/
 who contributed it to
 .Fx .
+.An James Gritton
+added the extensible jail parameters.

Modified: head/sys/cddl/compat/opensolaris/kern/opensolaris_zone.c
==============================================================================
--- head/sys/cddl/compat/opensolaris/kern/opensolaris_zone.c	Wed Apr 29 19:19:13 2009	(r191672)
+++ head/sys/cddl/compat/opensolaris/kern/opensolaris_zone.c	Wed Apr 29 21:14:15 2009	(r191673)
@@ -233,7 +233,7 @@ static void
 zone_sysinit(void *arg __unused)
 {
 
-	zone_slot = osd_jail_register(zone_destroy);
+	zone_slot = osd_jail_register(zone_destroy, NULL);
 }
 
 static void

Modified: head/sys/compat/freebsd32/freebsd32_misc.c
==============================================================================
--- head/sys/compat/freebsd32/freebsd32_misc.c	Wed Apr 29 19:19:13 2009	(r191672)
+++ head/sys/compat/freebsd32/freebsd32_misc.c	Wed Apr 29 21:14:15 2009	(r191673)
@@ -28,6 +28,8 @@
 __FBSDID("$FreeBSD$");
 
 #include "opt_compat.h"
+#include "opt_inet.h"
+#include "opt_inet6.h"
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -76,6 +78,10 @@ __FBSDID("$FreeBSD$");
 #include <sys/sem.h>
 #include <sys/shm.h>
 
+#ifdef INET
+#include <netinet/in.h>
+#endif
+
 #include <vm/vm.h>
 #include <vm/vm_kern.h>
 #include <vm/vm_param.h>
@@ -106,6 +112,8 @@ CTASSERT(sizeof(struct msghdr32) == 28);
 CTASSERT(sizeof(struct stat32) == 96);
 CTASSERT(sizeof(struct sigaction32) == 24);
 
+extern int jail_max_af_ips;
+
 static int freebsd32_kevent_copyout(void *arg, struct kevent *kevp, int count);
 static int freebsd32_kevent_copyin(void *arg, struct kevent *kevp, int count);
 
@@ -2036,9 +2044,17 @@ freebsd32_sysctl(struct thread *td, stru
 int
 freebsd32_jail(struct thread *td, struct freebsd32_jail_args *uap)
 {
+	struct iovec optiov[10];
+	struct uio opt;
+	char *u_path, *u_hostname, *u_name;
+#ifdef INET
+	struct in_addr *u_ip4;
+#endif
+#ifdef INET6
+	struct in6_addr *u_ip6;
+#endif
 	uint32_t version;
 	int error;
-	struct jail j;
 
 	error = copyin(uap->jail, &version, sizeof(uint32_t));
 	if (error)
@@ -2050,14 +2066,45 @@ freebsd32_jail(struct thread *td, struct
 		/* FreeBSD single IPv4 jails. */
 		struct jail32_v0 j32_v0;
 
-		bzero(&j, sizeof(struct jail));
 		error = copyin(uap->jail, &j32_v0, sizeof(struct jail32_v0));
 		if (error)
 			return (error);
-		CP(j32_v0, j, version);
-		PTRIN_CP(j32_v0, j, path);
-		PTRIN_CP(j32_v0, j, hostname);
-		j.ip4s = j32_v0.ip_number;
+		u_path = malloc(MAXPATHLEN + MAXHOSTNAMELEN, M_TEMP, M_WAITOK);
+		u_hostname = u_path + MAXPATHLEN;
+		opt.uio_iov = optiov;
+		opt.uio_iovcnt = 4;
+		opt.uio_offset = -1;
+		opt.uio_resid = -1;
+		opt.uio_segflg = UIO_SYSSPACE;
+		opt.uio_rw = UIO_READ;
+		opt.uio_td = td;
+		optiov[0].iov_base = "path";
+		optiov[0].iov_len = sizeof("path");
+		optiov[1].iov_base = u_path;
+		error = copyinstr(PTRIN(j32_v0.path), u_path, MAXPATHLEN,
+		    &optiov[1].iov_len);
+		if (error) {
+			free(u_path, M_TEMP);
+			return (error);
+		}
+		optiov[2].iov_base = "host.hostname";
+		optiov[2].iov_len = sizeof("host.hostname");
+		optiov[3].iov_base = u_hostname;
+		error = copyinstr(PTRIN(j32_v0.hostname), u_hostname,
+		    MAXHOSTNAMELEN, &optiov[3].iov_len);
+		if (error) {
+			free(u_path, M_TEMP);
+			return (error);
+		}
+#ifdef INET
+		optiov[opt.uio_iovcnt].iov_base = "ip4.addr";
+		optiov[opt.uio_iovcnt].iov_len = sizeof("ip4.addr");
+		opt.uio_iovcnt++;
+		optiov[opt.uio_iovcnt].iov_base = &j32_v0.ip_number;
+		j32_v0.ip_number = htonl(j32_v0.ip_number);
+		optiov[opt.uio_iovcnt].iov_len = sizeof(j32_v0.ip_number);
+		opt.uio_iovcnt++;
+#endif
 		break;
 	}
 
@@ -2072,18 +2119,109 @@ freebsd32_jail(struct thread *td, struct
 	{
 		/* FreeBSD multi-IPv4/IPv6,noIP jails. */
 		struct jail32 j32;
+		size_t tmplen;
 
 		error = copyin(uap->jail, &j32, sizeof(struct jail32));
 		if (error)
 			return (error);
-		CP(j32, j, version);
-		PTRIN_CP(j32, j, path);
-		PTRIN_CP(j32, j, hostname);
-		PTRIN_CP(j32, j, jailname);
-		CP(j32, j, ip4s);
-		CP(j32, j, ip6s);
-		PTRIN_CP(j32, j, ip4);
-		PTRIN_CP(j32, j, ip6);
+		tmplen = MAXPATHLEN + MAXHOSTNAMELEN + MAXHOSTNAMELEN;
+#ifdef INET
+		if (j32.ip4s > jail_max_af_ips)
+			return (EINVAL);
+		tmplen += j32.ip4s * sizeof(struct in_addr);
+#else
+		if (j32.ip4s > 0)
+			return (EINVAL);
+#endif
+#ifdef INET6
+		if (j32.ip6s > jail_max_af_ips)
+			return (EINVAL);
+		tmplen += j32.ip6s * sizeof(struct in6_addr);
+#else
+		if (j32.ip6s > 0)
+			return (EINVAL);
+#endif
+		u_path = malloc(tmplen, M_TEMP, M_WAITOK);
+		u_hostname = u_path + MAXPATHLEN;
+		u_name = u_hostname + MAXHOSTNAMELEN;
+#ifdef INET
+		u_ip4 =  (struct in_addr *)(u_name + MAXHOSTNAMELEN);
+#endif
+#ifdef INET6
+#ifdef INET
+		u_ip6 = (struct in6_addr *)(u_ip4 + j32.ip4s);
+#else
+		u_ip6 = (struct in6_addr *)(u_name + MAXHOSTNAMELEN);
+#endif
+#endif
+		opt.uio_iov = optiov;
+		opt.uio_iovcnt = 4;
+		opt.uio_offset = -1;
+		opt.uio_resid = -1;
+		opt.uio_segflg = UIO_SYSSPACE;
+		opt.uio_rw = UIO_READ;
+		opt.uio_td = td;
+		optiov[0].iov_base = "path";
+		optiov[0].iov_len = sizeof("path");
+		optiov[1].iov_base = u_path;
+		error = copyinstr(PTRIN(j32.path), u_path, MAXPATHLEN,
+		    &optiov[1].iov_len);
+		if (error) {
+			free(u_path, M_TEMP);
+			return (error);
+		}
+		optiov[2].iov_base = "host.hostname";
+		optiov[2].iov_len = sizeof("host.hostname");
+		optiov[3].iov_base = u_hostname;
+		error = copyinstr(PTRIN(j32.hostname), u_hostname,
+		    MAXHOSTNAMELEN, &optiov[3].iov_len);
+		if (error) {
+			free(u_path, M_TEMP);
+			return (error);
+		}
+		if (PTRIN(j32.jailname) != NULL) {
+			optiov[opt.uio_iovcnt].iov_base = "name";
+			optiov[opt.uio_iovcnt].iov_len = sizeof("name");
+			opt.uio_iovcnt++;
+			optiov[opt.uio_iovcnt].iov_base = u_name;
+			error = copyinstr(PTRIN(j32.jailname), u_name,
+			    MAXHOSTNAMELEN, &optiov[opt.uio_iovcnt].iov_len);
+			if (error) {
+				free(u_path, M_TEMP);
+				return (error);
+			}
+			opt.uio_iovcnt++;
+		}
+#ifdef INET
+		optiov[opt.uio_iovcnt].iov_base = "ip4.addr";
+		optiov[opt.uio_iovcnt].iov_len = sizeof("ip4.addr");
+		opt.uio_iovcnt++;
+		optiov[opt.uio_iovcnt].iov_base = u_ip4;
+		optiov[opt.uio_iovcnt].iov_len =
+		    j32.ip4s * sizeof(struct in_addr);
+		error = copyin(PTRIN(j32.ip4), u_ip4,
+		    optiov[opt.uio_iovcnt].iov_len);
+		if (error) {
+			free(u_path, M_TEMP);
+			return (error);
+		}
+		opt.uio_iovcnt++;
+#endif
+#ifdef INET6
+		optiov[opt.uio_iovcnt].iov_base = "ip6.addr";
+		optiov[opt.uio_iovcnt].iov_len = sizeof("ip6.addr");
+		opt.uio_iovcnt++;
+		optiov[opt.uio_iovcnt].iov_base = u_ip6;
+		optiov[opt.uio_iovcnt].iov_len =
+		    j32.ip6s * sizeof(struct in6_addr);
+		error = copyin(PTRIN(j32.ip6), u_ip6,
+		    optiov[opt.uio_iovcnt].iov_len);
+		if (error) {
+			free(u_path, M_TEMP);
+			return (error);
+		}
+		opt.uio_iovcnt++;
+#endif
 		break;
 	}
 
@@ -2091,7 +2229,54 @@ freebsd32_jail(struct thread *td, struct
 		/* Sci-Fi jails are not supported, sorry. */
 		return (EINVAL);
 	}
-	return (kern_jail(td, &j));
+	error = kern_jail_set(td, &opt, JAIL_CREATE | JAIL_ATTACH);
+	free(u_path, M_TEMP);
+	return (error);
+}
+
+int
+freebsd32_jail_set(struct thread *td, struct freebsd32_jail_set_args *uap)
+{
+	struct uio *auio;
+	int error;
+
+	/* Check that we have an even number of iovecs. */
+	if (uap->iovcnt & 1)
+		return (EINVAL);
+
+	error = freebsd32_copyinuio(uap->iovp, uap->iovcnt, &auio);
+	if (error)
+		return (error);
+	error = kern_jail_set(td, auio, uap->flags);
+	free(auio, M_IOV);
+	return (error);
+}
+
+int
+freebsd32_jail_get(struct thread *td, struct freebsd32_jail_get_args *uap)
+{
+	struct iovec32 iov32;
+	struct uio *auio;
+	int error, i;
+
+	/* Check that we have an even number of iovecs. */
+	if (uap->iovcnt & 1)
+		return (EINVAL);
+
+	error = freebsd32_copyinuio(uap->iovp, uap->iovcnt, &auio);
+	if (error)
+		return (error);
+	error = kern_jail_get(td, auio, uap->flags);
+	if (error == 0)
+		for (i = 0; i < uap->iovcnt; i++) {
+			PTROUT_CP(auio->uio_iov[i], iov32, iov_base);
+			CP(auio->uio_iov[i], iov32, iov_len);
+			error = copyout(&iov32, uap->iovp + i, sizeof(iov32));
+			if (error != 0)
+				break;
+		}
+	free(auio, M_IOV);
+	return (error);
 }
 
 int

Modified: head/sys/compat/freebsd32/syscalls.master
==============================================================================
--- head/sys/compat/freebsd32/syscalls.master	Wed Apr 29 19:19:13 2009	(r191672)
+++ head/sys/compat/freebsd32/syscalls.master	Wed Apr 29 21:14:15 2009	(r191673)
@@ -870,3 +870,8 @@
 504	AUE_POSIX_OPENPT	NOPROTO	{ int posix_openpt(int flags); }
 ; 505 is initialised by the kgssapi code, if present.
 505	AUE_NULL	UNIMPL	gssd_syscall
+506	AUE_NULL	STD	{ int freebsd32_jail_get(struct iovec32 *iovp, \
+				    unsigned int iovcnt, int flags); }
+507	AUE_NULL	STD	{ int freebsd32_jail_set(struct iovec32 *iovp, \
+				    unsigned int iovcnt, int flags); }
+508	AUE_NULL	NOPROTO	{ int jail_remove(int jid); }

Modified: head/sys/kern/kern_jail.c
==============================================================================
--- head/sys/kern/kern_jail.c	Wed Apr 29 19:19:13 2009	(r191672)
+++ head/sys/kern/kern_jail.c	Wed Apr 29 21:14:15 2009	(r191673)
@@ -1,6 +1,7 @@
 /*-
  * Copyright (c) 1999 Poul-Henning Kamp.
  * Copyright (c) 2008 Bjoern A. Zeeb.
+ * Copyright (c) 2009 James Gritton.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -47,6 +48,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/jail.h>
 #include <sys/lock.h>
 #include <sys/mutex.h>
+#include <sys/osd.h>
 #include <sys/sx.h>
 #include <sys/namei.h>
 #include <sys/mount.h>
@@ -56,7 +58,6 @@ __FBSDID("$FreeBSD$");
 #include <sys/sysctl.h>
 #include <sys/vnode.h>
 #include <sys/vimage.h>
-#include <sys/osd.h>
 #include <net/if.h>
 #include <netinet/in.h>
 #ifdef DDB
@@ -114,13 +115,15 @@ SYSCTL_INT(_security_jail, OID_AUTO, jai
     "Number of IP addresses a jail may have at most per address family");
 
 /* allprison, lastprid, and prisoncount are protected by allprison_lock. */
-struct	prisonlist allprison;
 struct	sx allprison_lock;
+SX_SYSINIT(allprison_lock, &allprison_lock, "allprison");
+struct	prisonlist allprison = TAILQ_HEAD_INITIALIZER(allprison);
 int	lastprid = 0;
 int	prisoncount = 0;
 
-static void init_prison(void *);
+static int do_jail_attach(struct thread *td, struct prison *pr);
 static void prison_complete(void *context, int pending);
+static void prison_deref(struct prison *pr, int flags);
 #ifdef INET
 static int _prison_check_ip4(struct prison *pr, struct in_addr *ia);
 #endif
@@ -129,15 +132,12 @@ static int _prison_check_ip6(struct pris
 #endif
 static int sysctl_jail_list(SYSCTL_HANDLER_ARGS);
 
-static void
-init_prison(void *data __unused)
-{
-
-	sx_init(&allprison_lock, "allprison");
-	LIST_INIT(&allprison);
-}
-
-SYSINIT(prison, SI_SUB_INTRINSIC, SI_ORDER_ANY, init_prison, NULL);
+/* Flags for prison_deref */
+#define	PD_DEREF	0x01
+#define	PD_DEUREF	0x02
+#define	PD_LOCKED	0x04
+#define	PD_LIST_SLOCKED	0x08
+#define	PD_LIST_XLOCKED	0x10
 
 #ifdef INET
 static int
@@ -187,411 +187,1279 @@ qcmp_v6(const void *ip1, const void *ip2
 }
 #endif
 
-#if defined(INET) || defined(INET6)
-static int
-prison_check_conflicting_ips(struct prison *p)
+/*
+ * struct jail_args {
+ *	struct jail *jail;
+ * };
+ */
+int
+jail(struct thread *td, struct jail_args *uap)
 {
-	struct prison *pr;
-	int i;
+	struct iovec optiov[10];
+	struct uio opt;
+	char *u_path, *u_hostname, *u_name;
+#ifdef INET
+	struct in_addr *u_ip4;
+#endif
+#ifdef INET6
+	struct in6_addr *u_ip6;
+#endif
+	uint32_t version;
+	int error;
 
-	sx_assert(&allprison_lock, SX_LOCKED);
+	error = copyin(uap->jail, &version, sizeof(uint32_t));
+	if (error)
+		return (error);
 
-	if (p->pr_ip4s == 0 && p->pr_ip6s == 0)
-		return (0);
+	switch (version) {
+	case 0:
+	{
+		/* FreeBSD single IPv4 jails. */
+		struct jail_v0 j0;
 
-	LIST_FOREACH(pr, &allprison, pr_list) {
-		/*
-		 * Skip 'dying' prisons to avoid problems when
-		 * restarting multi-IP jails.
-		 */
-		if (pr->pr_state == PRISON_STATE_DYING)
-			continue;
+		error = copyin(uap->jail, &j0, sizeof(struct jail_v0));
+		if (error)
+			return (error);
+		u_path = malloc(MAXPATHLEN + MAXHOSTNAMELEN, M_TEMP, M_WAITOK);
+		u_hostname = u_path + MAXPATHLEN;
+		opt.uio_iov = optiov;
+		opt.uio_iovcnt = 4;
+		opt.uio_offset = -1;
+		opt.uio_resid = -1;
+		opt.uio_segflg = UIO_SYSSPACE;
+		opt.uio_rw = UIO_READ;
+		opt.uio_td = td;
+		optiov[0].iov_base = "path";
+		optiov[0].iov_len = sizeof("path");
+		optiov[1].iov_base = u_path;
+		error =
+		    copyinstr(j0.path, u_path, MAXPATHLEN, &optiov[1].iov_len);
+		if (error) {
+			free(u_path, M_TEMP);
+			return (error);
+		}
+		optiov[2].iov_base = "host.hostname";
+		optiov[2].iov_len = sizeof("host.hostname");
+		optiov[3].iov_base = u_hostname;
+		error = copyinstr(j0.hostname, u_hostname, MAXHOSTNAMELEN,
+		    &optiov[3].iov_len);
+		if (error) {
+			free(u_path, M_TEMP);
+			return (error);
+		}
+#ifdef INET
+		optiov[opt.uio_iovcnt].iov_base = "ip4.addr";
+		optiov[opt.uio_iovcnt].iov_len = sizeof("ip4.addr");
+		opt.uio_iovcnt++;
+		optiov[opt.uio_iovcnt].iov_base = &j0.ip_number;
+		j0.ip_number = htonl(j0.ip_number);
+		optiov[opt.uio_iovcnt].iov_len = sizeof(j0.ip_number);
+		opt.uio_iovcnt++;
+#endif
+		break;
+	}
 
+	case 1:
 		/*
-		 * We permit conflicting IPs if there is no
-		 * more than 1 IP on eeach jail.
-		 * In case there is one duplicate on a jail with
-		 * more than one IP stop checking and return error.
+		 * Version 1 was used by multi-IPv4 jail implementations
+		 * that never made it into the official kernel.
 		 */
+		return (EINVAL);
+
+	case 2:	/* JAIL_API_VERSION */
+	{
+		/* FreeBSD multi-IPv4/IPv6,noIP jails. */
+		struct jail j;
+		size_t tmplen;
+
+		error = copyin(uap->jail, &j, sizeof(struct jail));
+		if (error)
+			return (error);
+		tmplen = MAXPATHLEN + MAXHOSTNAMELEN + MAXHOSTNAMELEN;
+#ifdef INET
+		if (j.ip4s > jail_max_af_ips)
+			return (EINVAL);
+		tmplen += j.ip4s * sizeof(struct in_addr);
+#else
+		if (j.ip4s > 0)
+			return (EINVAL);
+#endif
+#ifdef INET6
+		if (j.ip6s > jail_max_af_ips)
+			return (EINVAL);
+		tmplen += j.ip6s * sizeof(struct in6_addr);
+#else
+		if (j.ip6s > 0)
+			return (EINVAL);
+#endif
+		u_path = malloc(tmplen, M_TEMP, M_WAITOK);
+		u_hostname = u_path + MAXPATHLEN;
+		u_name = u_hostname + MAXHOSTNAMELEN;
+#ifdef INET
+		u_ip4 = (struct in_addr *)(u_name + MAXHOSTNAMELEN);
+#endif
+#ifdef INET6
 #ifdef INET
-		if ((p->pr_ip4s >= 1 && pr->pr_ip4s > 1) ||
-		    (p->pr_ip4s > 1 && pr->pr_ip4s >= 1)) {
-			for (i = 0; i < p->pr_ip4s; i++) {
-				if (_prison_check_ip4(pr, &p->pr_ip4[i]) == 0)
-					return (EINVAL);
+		u_ip6 = (struct in6_addr *)(u_ip4 + j.ip4s);
+#else
+		u_ip6 = (struct in6_addr *)(u_name + MAXHOSTNAMELEN);
+#endif
+#endif
+		opt.uio_iov = optiov;
+		opt.uio_iovcnt = 4;
+		opt.uio_offset = -1;
+		opt.uio_resid = -1;
+		opt.uio_segflg = UIO_SYSSPACE;
+		opt.uio_rw = UIO_READ;
+		opt.uio_td = td;
+		optiov[0].iov_base = "path";
+		optiov[0].iov_len = sizeof("path");
+		optiov[1].iov_base = u_path;
+		error =
+		    copyinstr(j.path, u_path, MAXPATHLEN, &optiov[1].iov_len);
+		if (error) {
+			free(u_path, M_TEMP);
+			return (error);
+		}
+		optiov[2].iov_base = "host.hostname";
+		optiov[2].iov_len = sizeof("host.hostname");
+		optiov[3].iov_base = u_hostname;
+		error = copyinstr(j.hostname, u_hostname, MAXHOSTNAMELEN,
+		    &optiov[3].iov_len);
+		if (error) {
+			free(u_path, M_TEMP);
+			return (error);
+		}
+		if (j.jailname != NULL) {
+			optiov[opt.uio_iovcnt].iov_base = "name";
+			optiov[opt.uio_iovcnt].iov_len = sizeof("name");
+			opt.uio_iovcnt++;
+			optiov[opt.uio_iovcnt].iov_base = u_name;
+			error = copyinstr(j.jailname, u_name, MAXHOSTNAMELEN,
+			    &optiov[opt.uio_iovcnt].iov_len);
+			if (error) {
+				free(u_path, M_TEMP);
+				return (error);
 			}
+			opt.uio_iovcnt++;
+		}
+#ifdef INET
+		optiov[opt.uio_iovcnt].iov_base = "ip4.addr";
+		optiov[opt.uio_iovcnt].iov_len = sizeof("ip4.addr");
+		opt.uio_iovcnt++;
+		optiov[opt.uio_iovcnt].iov_base = u_ip4;
+		optiov[opt.uio_iovcnt].iov_len =
+		    j.ip4s * sizeof(struct in_addr);
+		error = copyin(j.ip4, u_ip4, optiov[opt.uio_iovcnt].iov_len);
+		if (error) {
+			free(u_path, M_TEMP);
+			return (error);
 		}
+		opt.uio_iovcnt++;
 #endif
 #ifdef INET6
-		if ((p->pr_ip6s >= 1 && pr->pr_ip6s > 1) ||
-		    (p->pr_ip6s > 1 && pr->pr_ip6s >= 1)) {
-			for (i = 0; i < p->pr_ip6s; i++) {
-				if (_prison_check_ip6(pr, &p->pr_ip6[i]) == 0)
-					return (EINVAL);
-			}
+		optiov[opt.uio_iovcnt].iov_base = "ip6.addr";
+		optiov[opt.uio_iovcnt].iov_len = sizeof("ip6.addr");
+		opt.uio_iovcnt++;
+		optiov[opt.uio_iovcnt].iov_base = u_ip6;
+		optiov[opt.uio_iovcnt].iov_len =
+		    j.ip6s * sizeof(struct in6_addr);
+		error = copyin(j.ip6, u_ip6, optiov[opt.uio_iovcnt].iov_len);
+		if (error) {
+			free(u_path, M_TEMP);
+			return (error);
 		}
+		opt.uio_iovcnt++;
 #endif
+		break;
 	}
 
-	return (0);
+	default:
+		/* Sci-Fi jails are not supported, sorry. */
+		return (EINVAL);
+	}
+	error = kern_jail_set(td, &opt, JAIL_CREATE | JAIL_ATTACH);
+	free(u_path, M_TEMP);
+	return (error);
 }
 
-static int
-jail_copyin_ips(struct jail *j)
+/*
+ * struct jail_set_args {
+ *	struct iovec *iovp;
+ *	unsigned int iovcnt;
+ *	int flags;
+ * };
+ */
+int
+jail_set(struct thread *td, struct jail_set_args *uap)
 {
+	struct uio *auio;
+	int error;
+
+	/* Check that we have an even number of iovecs. */
+	if (uap->iovcnt & 1)
+		return (EINVAL);
+
+	error = copyinuio(uap->iovp, uap->iovcnt, &auio);
+	if (error)
+		return (error);
+	error = kern_jail_set(td, auio, uap->flags);
+	free(auio, M_IOV);
+	return (error);
+}
+
+int
+kern_jail_set(struct thread *td, struct uio *optuio, int flags)
+{
+	struct nameidata nd;
 #ifdef INET
 	struct in_addr *ip4;
 #endif
 #ifdef INET6
 	struct in6_addr *ip6;
 #endif
-	int error, i;
+	struct vfsopt *opt;
+	struct vfsoptlist *opts;
+	struct prison *pr, *deadpr, *tpr;
+	struct vnode *root;

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-head mailing list