xref: /freebsd/sys/kern/kern_jail.c (revision 1e2a13e62a4d9bfe1f86c3813eec1c0f163e4fb7)
19454b2d8SWarner Losh /*-
2413628a7SBjoern A. Zeeb  * Copyright (c) 1999 Poul-Henning Kamp.
3413628a7SBjoern A. Zeeb  * Copyright (c) 2008 Bjoern A. Zeeb.
4b38ff370SJamie Gritton  * Copyright (c) 2009 James Gritton.
5413628a7SBjoern A. Zeeb  * All rights reserved.
6b9f0b66cSBjoern A. Zeeb  *
7b9f0b66cSBjoern A. Zeeb  * Redistribution and use in source and binary forms, with or without
8b9f0b66cSBjoern A. Zeeb  * modification, are permitted provided that the following conditions
9b9f0b66cSBjoern A. Zeeb  * are met:
10b9f0b66cSBjoern A. Zeeb  * 1. Redistributions of source code must retain the above copyright
11b9f0b66cSBjoern A. Zeeb  *    notice, this list of conditions and the following disclaimer.
12b9f0b66cSBjoern A. Zeeb  * 2. Redistributions in binary form must reproduce the above copyright
13b9f0b66cSBjoern A. Zeeb  *    notice, this list of conditions and the following disclaimer in the
14b9f0b66cSBjoern A. Zeeb  *    documentation and/or other materials provided with the distribution.
15b9f0b66cSBjoern A. Zeeb  *
16b9f0b66cSBjoern A. Zeeb  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17b9f0b66cSBjoern A. Zeeb  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18b9f0b66cSBjoern A. Zeeb  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19b9f0b66cSBjoern A. Zeeb  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20b9f0b66cSBjoern A. Zeeb  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21b9f0b66cSBjoern A. Zeeb  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22b9f0b66cSBjoern A. Zeeb  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23b9f0b66cSBjoern A. Zeeb  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24b9f0b66cSBjoern A. Zeeb  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25b9f0b66cSBjoern A. Zeeb  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26b9f0b66cSBjoern A. Zeeb  * SUCH DAMAGE.
2707901f22SPoul-Henning Kamp  */
2875c13541SPoul-Henning Kamp 
29677b542eSDavid E. O'Brien #include <sys/cdefs.h>
30677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$");
31677b542eSDavid E. O'Brien 
32413628a7SBjoern A. Zeeb #include "opt_ddb.h"
33413628a7SBjoern A. Zeeb #include "opt_inet.h"
34413628a7SBjoern A. Zeeb #include "opt_inet6.h"
3546e3b1cbSPawel Jakub Dawidek #include "opt_mac.h"
3646e3b1cbSPawel Jakub Dawidek 
3775c13541SPoul-Henning Kamp #include <sys/param.h>
3875c13541SPoul-Henning Kamp #include <sys/types.h>
3975c13541SPoul-Henning Kamp #include <sys/kernel.h>
4075c13541SPoul-Henning Kamp #include <sys/systm.h>
4175c13541SPoul-Henning Kamp #include <sys/errno.h>
4275c13541SPoul-Henning Kamp #include <sys/sysproto.h>
4375c13541SPoul-Henning Kamp #include <sys/malloc.h>
44800c9408SRobert Watson #include <sys/priv.h>
4575c13541SPoul-Henning Kamp #include <sys/proc.h>
46b3059e09SRobert Watson #include <sys/taskqueue.h>
4757b4252eSKonstantin Belousov #include <sys/fcntl.h>
4875c13541SPoul-Henning Kamp #include <sys/jail.h>
4901137630SRobert Watson #include <sys/lock.h>
5001137630SRobert Watson #include <sys/mutex.h>
51b38ff370SJamie Gritton #include <sys/osd.h>
52dc68a633SPawel Jakub Dawidek #include <sys/sx.h>
53fd7a8150SMike Barcroft #include <sys/namei.h>
54820a0de9SPawel Jakub Dawidek #include <sys/mount.h>
55fd7a8150SMike Barcroft #include <sys/queue.h>
5675c13541SPoul-Henning Kamp #include <sys/socket.h>
57fd7a8150SMike Barcroft #include <sys/syscallsubr.h>
5883f1e257SRobert Watson #include <sys/sysctl.h>
59fd7a8150SMike Barcroft #include <sys/vnode.h>
60603724d3SBjoern A. Zeeb #include <sys/vimage.h>
6175c13541SPoul-Henning Kamp #include <net/if.h>
6275c13541SPoul-Henning Kamp #include <netinet/in.h>
63413628a7SBjoern A. Zeeb #ifdef DDB
64413628a7SBjoern A. Zeeb #include <ddb/ddb.h>
65413628a7SBjoern A. Zeeb #ifdef INET6
66413628a7SBjoern A. Zeeb #include <netinet6/in6_var.h>
67413628a7SBjoern A. Zeeb #endif /* INET6 */
68413628a7SBjoern A. Zeeb #endif /* DDB */
6975c13541SPoul-Henning Kamp 
70aed55708SRobert Watson #include <security/mac/mac_framework.h>
71aed55708SRobert Watson 
7275c13541SPoul-Henning Kamp MALLOC_DEFINE(M_PRISON, "prison", "Prison structures");
7375c13541SPoul-Henning Kamp 
74d0615c64SAndrew R. Reiter SYSCTL_NODE(_security, OID_AUTO, jail, CTLFLAG_RW, 0,
7583f1e257SRobert Watson     "Jail rules");
7683f1e257SRobert Watson 
7783f1e257SRobert Watson int	jail_set_hostname_allowed = 1;
78d0615c64SAndrew R. Reiter SYSCTL_INT(_security_jail, OID_AUTO, set_hostname_allowed, CTLFLAG_RW,
7983f1e257SRobert Watson     &jail_set_hostname_allowed, 0,
8083f1e257SRobert Watson     "Processes in jail can set their hostnames");
8183f1e257SRobert Watson 
827cadc266SRobert Watson int	jail_socket_unixiproute_only = 1;
83d0615c64SAndrew R. Reiter SYSCTL_INT(_security_jail, OID_AUTO, socket_unixiproute_only, CTLFLAG_RW,
847cadc266SRobert Watson     &jail_socket_unixiproute_only, 0,
85413628a7SBjoern A. Zeeb     "Processes in jail are limited to creating UNIX/IP/route sockets only");
867cadc266SRobert Watson 
87cb1f0db9SRobert Watson int	jail_sysvipc_allowed = 0;
88d0615c64SAndrew R. Reiter SYSCTL_INT(_security_jail, OID_AUTO, sysvipc_allowed, CTLFLAG_RW,
89cb1f0db9SRobert Watson     &jail_sysvipc_allowed, 0,
90cb1f0db9SRobert Watson     "Processes in jail can use System V IPC primitives");
91cb1f0db9SRobert Watson 
92820a0de9SPawel Jakub Dawidek static int jail_enforce_statfs = 2;
93820a0de9SPawel Jakub Dawidek SYSCTL_INT(_security_jail, OID_AUTO, enforce_statfs, CTLFLAG_RW,
94820a0de9SPawel Jakub Dawidek     &jail_enforce_statfs, 0,
95820a0de9SPawel Jakub Dawidek     "Processes in jail cannot see all mounted file systems");
96f08df373SRobert Watson 
975a59cefcSBosko Milekic int	jail_allow_raw_sockets = 0;
985a59cefcSBosko Milekic SYSCTL_INT(_security_jail, OID_AUTO, allow_raw_sockets, CTLFLAG_RW,
995a59cefcSBosko Milekic     &jail_allow_raw_sockets, 0,
1005a59cefcSBosko Milekic     "Prison root can create raw sockets");
1015a59cefcSBosko Milekic 
10279653046SColin Percival int	jail_chflags_allowed = 0;
10379653046SColin Percival SYSCTL_INT(_security_jail, OID_AUTO, chflags_allowed, CTLFLAG_RW,
10479653046SColin Percival     &jail_chflags_allowed, 0,
10579653046SColin Percival     "Processes in jail can alter system file flags");
10679653046SColin Percival 
107f3a8d2f9SPawel Jakub Dawidek int	jail_mount_allowed = 0;
108f3a8d2f9SPawel Jakub Dawidek SYSCTL_INT(_security_jail, OID_AUTO, mount_allowed, CTLFLAG_RW,
109f3a8d2f9SPawel Jakub Dawidek     &jail_mount_allowed, 0,
110f3a8d2f9SPawel Jakub Dawidek     "Processes in jail can mount/unmount jail-friendly file systems");
111f3a8d2f9SPawel Jakub Dawidek 
112413628a7SBjoern A. Zeeb int	jail_max_af_ips = 255;
113413628a7SBjoern A. Zeeb SYSCTL_INT(_security_jail, OID_AUTO, jail_max_af_ips, CTLFLAG_RW,
114413628a7SBjoern A. Zeeb     &jail_max_af_ips, 0,
115413628a7SBjoern A. Zeeb     "Number of IP addresses a jail may have at most per address family");
116413628a7SBjoern A. Zeeb 
1172110d913SXin LI /* allprison, lastprid, and prisoncount are protected by allprison_lock. */
118dc68a633SPawel Jakub Dawidek struct	sx allprison_lock;
119b38ff370SJamie Gritton SX_SYSINIT(allprison_lock, &allprison_lock, "allprison");
120b38ff370SJamie Gritton struct	prisonlist allprison = TAILQ_HEAD_INITIALIZER(allprison);
1212110d913SXin LI int	lastprid = 0;
122fd7a8150SMike Barcroft int	prisoncount = 0;
123fd7a8150SMike Barcroft 
124b38ff370SJamie Gritton static int do_jail_attach(struct thread *td, struct prison *pr);
125b3059e09SRobert Watson static void prison_complete(void *context, int pending);
126b38ff370SJamie Gritton static void prison_deref(struct prison *pr, int flags);
127413628a7SBjoern A. Zeeb #ifdef INET
1288571af59SJamie Gritton static int _prison_check_ip4(struct prison *pr, struct in_addr *ia);
129413628a7SBjoern A. Zeeb #endif
130413628a7SBjoern A. Zeeb #ifdef INET6
1318571af59SJamie Gritton static int _prison_check_ip6(struct prison *pr, struct in6_addr *ia6);
132413628a7SBjoern A. Zeeb #endif
133af7bd9a4SJamie Gritton static int sysctl_jail_list(SYSCTL_HANDLER_ARGS);
134fd7a8150SMike Barcroft 
135b38ff370SJamie Gritton /* Flags for prison_deref */
136b38ff370SJamie Gritton #define	PD_DEREF	0x01
137b38ff370SJamie Gritton #define	PD_DEUREF	0x02
138b38ff370SJamie Gritton #define	PD_LOCKED	0x04
139b38ff370SJamie Gritton #define	PD_LIST_SLOCKED	0x08
140b38ff370SJamie Gritton #define	PD_LIST_XLOCKED	0x10
141fd7a8150SMike Barcroft 
142413628a7SBjoern A. Zeeb #ifdef INET
143413628a7SBjoern A. Zeeb static int
144413628a7SBjoern A. Zeeb qcmp_v4(const void *ip1, const void *ip2)
145413628a7SBjoern A. Zeeb {
146413628a7SBjoern A. Zeeb 	in_addr_t iaa, iab;
147413628a7SBjoern A. Zeeb 
148413628a7SBjoern A. Zeeb 	/*
149413628a7SBjoern A. Zeeb 	 * We need to compare in HBO here to get the list sorted as expected
150413628a7SBjoern A. Zeeb 	 * by the result of the code.  Sorting NBO addresses gives you
151413628a7SBjoern A. Zeeb 	 * interesting results.  If you do not understand, do not try.
152413628a7SBjoern A. Zeeb 	 */
153413628a7SBjoern A. Zeeb 	iaa = ntohl(((const struct in_addr *)ip1)->s_addr);
154413628a7SBjoern A. Zeeb 	iab = ntohl(((const struct in_addr *)ip2)->s_addr);
155413628a7SBjoern A. Zeeb 
156413628a7SBjoern A. Zeeb 	/*
157413628a7SBjoern A. Zeeb 	 * Do not simply return the difference of the two numbers, the int is
158413628a7SBjoern A. Zeeb 	 * not wide enough.
159413628a7SBjoern A. Zeeb 	 */
160413628a7SBjoern A. Zeeb 	if (iaa > iab)
161413628a7SBjoern A. Zeeb 		return (1);
162413628a7SBjoern A. Zeeb 	else if (iaa < iab)
163413628a7SBjoern A. Zeeb 		return (-1);
164413628a7SBjoern A. Zeeb 	else
165413628a7SBjoern A. Zeeb 		return (0);
166413628a7SBjoern A. Zeeb }
167413628a7SBjoern A. Zeeb #endif
168413628a7SBjoern A. Zeeb 
169413628a7SBjoern A. Zeeb #ifdef INET6
170413628a7SBjoern A. Zeeb static int
171413628a7SBjoern A. Zeeb qcmp_v6(const void *ip1, const void *ip2)
172413628a7SBjoern A. Zeeb {
173413628a7SBjoern A. Zeeb 	const struct in6_addr *ia6a, *ia6b;
174413628a7SBjoern A. Zeeb 	int i, rc;
175413628a7SBjoern A. Zeeb 
176413628a7SBjoern A. Zeeb 	ia6a = (const struct in6_addr *)ip1;
177413628a7SBjoern A. Zeeb 	ia6b = (const struct in6_addr *)ip2;
178413628a7SBjoern A. Zeeb 
179413628a7SBjoern A. Zeeb 	rc = 0;
180413628a7SBjoern A. Zeeb 	for (i = 0; rc == 0 && i < sizeof(struct in6_addr); i++) {
181413628a7SBjoern A. Zeeb 		if (ia6a->s6_addr[i] > ia6b->s6_addr[i])
182413628a7SBjoern A. Zeeb 			rc = 1;
183413628a7SBjoern A. Zeeb 		else if (ia6a->s6_addr[i] < ia6b->s6_addr[i])
184413628a7SBjoern A. Zeeb 			rc = -1;
185413628a7SBjoern A. Zeeb 	}
186413628a7SBjoern A. Zeeb 	return (rc);
187413628a7SBjoern A. Zeeb }
188413628a7SBjoern A. Zeeb #endif
189413628a7SBjoern A. Zeeb 
190116734c4SMatthew Dillon /*
1919ddb7954SMike Barcroft  * struct jail_args {
1929ddb7954SMike Barcroft  *	struct jail *jail;
1939ddb7954SMike Barcroft  * };
194116734c4SMatthew Dillon  */
19575c13541SPoul-Henning Kamp int
1969ddb7954SMike Barcroft jail(struct thread *td, struct jail_args *uap)
19775c13541SPoul-Henning Kamp {
198b38ff370SJamie Gritton 	struct iovec optiov[10];
199b38ff370SJamie Gritton 	struct uio opt;
200b38ff370SJamie Gritton 	char *u_path, *u_hostname, *u_name;
201b38ff370SJamie Gritton #ifdef INET
202b38ff370SJamie Gritton 	struct in_addr *u_ip4;
203b38ff370SJamie Gritton #endif
204b38ff370SJamie Gritton #ifdef INET6
205b38ff370SJamie Gritton 	struct in6_addr *u_ip6;
206b38ff370SJamie Gritton #endif
207413628a7SBjoern A. Zeeb 	uint32_t version;
208413628a7SBjoern A. Zeeb 	int error;
209413628a7SBjoern A. Zeeb 
210413628a7SBjoern A. Zeeb 	error = copyin(uap->jail, &version, sizeof(uint32_t));
211413628a7SBjoern A. Zeeb 	if (error)
212413628a7SBjoern A. Zeeb 		return (error);
213413628a7SBjoern A. Zeeb 
214413628a7SBjoern A. Zeeb 	switch (version) {
215413628a7SBjoern A. Zeeb 	case 0:
216413628a7SBjoern A. Zeeb 	{
217b38ff370SJamie Gritton 		/* FreeBSD single IPv4 jails. */
218413628a7SBjoern A. Zeeb 		struct jail_v0 j0;
219413628a7SBjoern A. Zeeb 
220413628a7SBjoern A. Zeeb 		error = copyin(uap->jail, &j0, sizeof(struct jail_v0));
221413628a7SBjoern A. Zeeb 		if (error)
222413628a7SBjoern A. Zeeb 			return (error);
223b38ff370SJamie Gritton 		u_path = malloc(MAXPATHLEN + MAXHOSTNAMELEN, M_TEMP, M_WAITOK);
224b38ff370SJamie Gritton 		u_hostname = u_path + MAXPATHLEN;
225b38ff370SJamie Gritton 		opt.uio_iov = optiov;
226b38ff370SJamie Gritton 		opt.uio_iovcnt = 4;
227b38ff370SJamie Gritton 		opt.uio_offset = -1;
228b38ff370SJamie Gritton 		opt.uio_resid = -1;
229b38ff370SJamie Gritton 		opt.uio_segflg = UIO_SYSSPACE;
230b38ff370SJamie Gritton 		opt.uio_rw = UIO_READ;
231b38ff370SJamie Gritton 		opt.uio_td = td;
232b38ff370SJamie Gritton 		optiov[0].iov_base = "path";
233b38ff370SJamie Gritton 		optiov[0].iov_len = sizeof("path");
234b38ff370SJamie Gritton 		optiov[1].iov_base = u_path;
235b38ff370SJamie Gritton 		error =
236b38ff370SJamie Gritton 		    copyinstr(j0.path, u_path, MAXPATHLEN, &optiov[1].iov_len);
237b38ff370SJamie Gritton 		if (error) {
238b38ff370SJamie Gritton 			free(u_path, M_TEMP);
239b38ff370SJamie Gritton 			return (error);
240b38ff370SJamie Gritton 		}
241b38ff370SJamie Gritton 		optiov[2].iov_base = "host.hostname";
242b38ff370SJamie Gritton 		optiov[2].iov_len = sizeof("host.hostname");
243b38ff370SJamie Gritton 		optiov[3].iov_base = u_hostname;
244b38ff370SJamie Gritton 		error = copyinstr(j0.hostname, u_hostname, MAXHOSTNAMELEN,
245b38ff370SJamie Gritton 		    &optiov[3].iov_len);
246b38ff370SJamie Gritton 		if (error) {
247b38ff370SJamie Gritton 			free(u_path, M_TEMP);
248b38ff370SJamie Gritton 			return (error);
249b38ff370SJamie Gritton 		}
250b38ff370SJamie Gritton #ifdef INET
251b38ff370SJamie Gritton 		optiov[opt.uio_iovcnt].iov_base = "ip4.addr";
252b38ff370SJamie Gritton 		optiov[opt.uio_iovcnt].iov_len = sizeof("ip4.addr");
253b38ff370SJamie Gritton 		opt.uio_iovcnt++;
254b38ff370SJamie Gritton 		optiov[opt.uio_iovcnt].iov_base = &j0.ip_number;
255b38ff370SJamie Gritton 		j0.ip_number = htonl(j0.ip_number);
256b38ff370SJamie Gritton 		optiov[opt.uio_iovcnt].iov_len = sizeof(j0.ip_number);
257b38ff370SJamie Gritton 		opt.uio_iovcnt++;
258b38ff370SJamie Gritton #endif
259413628a7SBjoern A. Zeeb 		break;
260413628a7SBjoern A. Zeeb 	}
261413628a7SBjoern A. Zeeb 
262413628a7SBjoern A. Zeeb 	case 1:
263413628a7SBjoern A. Zeeb 		/*
264413628a7SBjoern A. Zeeb 		 * Version 1 was used by multi-IPv4 jail implementations
265413628a7SBjoern A. Zeeb 		 * that never made it into the official kernel.
266413628a7SBjoern A. Zeeb 		 */
267413628a7SBjoern A. Zeeb 		return (EINVAL);
268413628a7SBjoern A. Zeeb 
269413628a7SBjoern A. Zeeb 	case 2:	/* JAIL_API_VERSION */
270b38ff370SJamie Gritton 	{
271413628a7SBjoern A. Zeeb 		/* FreeBSD multi-IPv4/IPv6,noIP jails. */
272b38ff370SJamie Gritton 		struct jail j;
273b38ff370SJamie Gritton 		size_t tmplen;
274b38ff370SJamie Gritton 
275413628a7SBjoern A. Zeeb 		error = copyin(uap->jail, &j, sizeof(struct jail));
276413628a7SBjoern A. Zeeb 		if (error)
277413628a7SBjoern A. Zeeb 			return (error);
278b38ff370SJamie Gritton 		tmplen = MAXPATHLEN + MAXHOSTNAMELEN + MAXHOSTNAMELEN;
279b38ff370SJamie Gritton #ifdef INET
280b38ff370SJamie Gritton 		if (j.ip4s > jail_max_af_ips)
281b38ff370SJamie Gritton 			return (EINVAL);
282b38ff370SJamie Gritton 		tmplen += j.ip4s * sizeof(struct in_addr);
283b38ff370SJamie Gritton #else
284b38ff370SJamie Gritton 		if (j.ip4s > 0)
285b38ff370SJamie Gritton 			return (EINVAL);
286b38ff370SJamie Gritton #endif
287b38ff370SJamie Gritton #ifdef INET6
288b38ff370SJamie Gritton 		if (j.ip6s > jail_max_af_ips)
289b38ff370SJamie Gritton 			return (EINVAL);
290b38ff370SJamie Gritton 		tmplen += j.ip6s * sizeof(struct in6_addr);
291b38ff370SJamie Gritton #else
292b38ff370SJamie Gritton 		if (j.ip6s > 0)
293b38ff370SJamie Gritton 			return (EINVAL);
294b38ff370SJamie Gritton #endif
295b38ff370SJamie Gritton 		u_path = malloc(tmplen, M_TEMP, M_WAITOK);
296b38ff370SJamie Gritton 		u_hostname = u_path + MAXPATHLEN;
297b38ff370SJamie Gritton 		u_name = u_hostname + MAXHOSTNAMELEN;
298b38ff370SJamie Gritton #ifdef INET
299b38ff370SJamie Gritton 		u_ip4 = (struct in_addr *)(u_name + MAXHOSTNAMELEN);
300b38ff370SJamie Gritton #endif
301b38ff370SJamie Gritton #ifdef INET6
302b38ff370SJamie Gritton #ifdef INET
303b38ff370SJamie Gritton 		u_ip6 = (struct in6_addr *)(u_ip4 + j.ip4s);
304b38ff370SJamie Gritton #else
305b38ff370SJamie Gritton 		u_ip6 = (struct in6_addr *)(u_name + MAXHOSTNAMELEN);
306b38ff370SJamie Gritton #endif
307b38ff370SJamie Gritton #endif
308b38ff370SJamie Gritton 		opt.uio_iov = optiov;
309b38ff370SJamie Gritton 		opt.uio_iovcnt = 4;
310b38ff370SJamie Gritton 		opt.uio_offset = -1;
311b38ff370SJamie Gritton 		opt.uio_resid = -1;
312b38ff370SJamie Gritton 		opt.uio_segflg = UIO_SYSSPACE;
313b38ff370SJamie Gritton 		opt.uio_rw = UIO_READ;
314b38ff370SJamie Gritton 		opt.uio_td = td;
315b38ff370SJamie Gritton 		optiov[0].iov_base = "path";
316b38ff370SJamie Gritton 		optiov[0].iov_len = sizeof("path");
317b38ff370SJamie Gritton 		optiov[1].iov_base = u_path;
318b38ff370SJamie Gritton 		error =
319b38ff370SJamie Gritton 		    copyinstr(j.path, u_path, MAXPATHLEN, &optiov[1].iov_len);
320b38ff370SJamie Gritton 		if (error) {
321b38ff370SJamie Gritton 			free(u_path, M_TEMP);
322b38ff370SJamie Gritton 			return (error);
323b38ff370SJamie Gritton 		}
324b38ff370SJamie Gritton 		optiov[2].iov_base = "host.hostname";
325b38ff370SJamie Gritton 		optiov[2].iov_len = sizeof("host.hostname");
326b38ff370SJamie Gritton 		optiov[3].iov_base = u_hostname;
327b38ff370SJamie Gritton 		error = copyinstr(j.hostname, u_hostname, MAXHOSTNAMELEN,
328b38ff370SJamie Gritton 		    &optiov[3].iov_len);
329b38ff370SJamie Gritton 		if (error) {
330b38ff370SJamie Gritton 			free(u_path, M_TEMP);
331b38ff370SJamie Gritton 			return (error);
332b38ff370SJamie Gritton 		}
333b38ff370SJamie Gritton 		if (j.jailname != NULL) {
334b38ff370SJamie Gritton 			optiov[opt.uio_iovcnt].iov_base = "name";
335b38ff370SJamie Gritton 			optiov[opt.uio_iovcnt].iov_len = sizeof("name");
336b38ff370SJamie Gritton 			opt.uio_iovcnt++;
337b38ff370SJamie Gritton 			optiov[opt.uio_iovcnt].iov_base = u_name;
338b38ff370SJamie Gritton 			error = copyinstr(j.jailname, u_name, MAXHOSTNAMELEN,
339b38ff370SJamie Gritton 			    &optiov[opt.uio_iovcnt].iov_len);
340b38ff370SJamie Gritton 			if (error) {
341b38ff370SJamie Gritton 				free(u_path, M_TEMP);
342b38ff370SJamie Gritton 				return (error);
343b38ff370SJamie Gritton 			}
344b38ff370SJamie Gritton 			opt.uio_iovcnt++;
345b38ff370SJamie Gritton 		}
346b38ff370SJamie Gritton #ifdef INET
347b38ff370SJamie Gritton 		optiov[opt.uio_iovcnt].iov_base = "ip4.addr";
348b38ff370SJamie Gritton 		optiov[opt.uio_iovcnt].iov_len = sizeof("ip4.addr");
349b38ff370SJamie Gritton 		opt.uio_iovcnt++;
350b38ff370SJamie Gritton 		optiov[opt.uio_iovcnt].iov_base = u_ip4;
351b38ff370SJamie Gritton 		optiov[opt.uio_iovcnt].iov_len =
352b38ff370SJamie Gritton 		    j.ip4s * sizeof(struct in_addr);
353b38ff370SJamie Gritton 		error = copyin(j.ip4, u_ip4, optiov[opt.uio_iovcnt].iov_len);
354b38ff370SJamie Gritton 		if (error) {
355b38ff370SJamie Gritton 			free(u_path, M_TEMP);
356b38ff370SJamie Gritton 			return (error);
357b38ff370SJamie Gritton 		}
358b38ff370SJamie Gritton 		opt.uio_iovcnt++;
359b38ff370SJamie Gritton #endif
360b38ff370SJamie Gritton #ifdef INET6
361b38ff370SJamie Gritton 		optiov[opt.uio_iovcnt].iov_base = "ip6.addr";
362b38ff370SJamie Gritton 		optiov[opt.uio_iovcnt].iov_len = sizeof("ip6.addr");
363b38ff370SJamie Gritton 		opt.uio_iovcnt++;
364b38ff370SJamie Gritton 		optiov[opt.uio_iovcnt].iov_base = u_ip6;
365b38ff370SJamie Gritton 		optiov[opt.uio_iovcnt].iov_len =
366b38ff370SJamie Gritton 		    j.ip6s * sizeof(struct in6_addr);
367b38ff370SJamie Gritton 		error = copyin(j.ip6, u_ip6, optiov[opt.uio_iovcnt].iov_len);
368b38ff370SJamie Gritton 		if (error) {
369b38ff370SJamie Gritton 			free(u_path, M_TEMP);
370b38ff370SJamie Gritton 			return (error);
371b38ff370SJamie Gritton 		}
372b38ff370SJamie Gritton 		opt.uio_iovcnt++;
373b38ff370SJamie Gritton #endif
374413628a7SBjoern A. Zeeb 		break;
375b38ff370SJamie Gritton 	}
376413628a7SBjoern A. Zeeb 
377413628a7SBjoern A. Zeeb 	default:
378413628a7SBjoern A. Zeeb 		/* Sci-Fi jails are not supported, sorry. */
379413628a7SBjoern A. Zeeb 		return (EINVAL);
380413628a7SBjoern A. Zeeb 	}
381b38ff370SJamie Gritton 	error = kern_jail_set(td, &opt, JAIL_CREATE | JAIL_ATTACH);
382b38ff370SJamie Gritton 	free(u_path, M_TEMP);
383b38ff370SJamie Gritton 	return (error);
384b38ff370SJamie Gritton }
385b38ff370SJamie Gritton 
386b38ff370SJamie Gritton /*
387b38ff370SJamie Gritton  * struct jail_set_args {
388b38ff370SJamie Gritton  *	struct iovec *iovp;
389b38ff370SJamie Gritton  *	unsigned int iovcnt;
390b38ff370SJamie Gritton  *	int flags;
391b38ff370SJamie Gritton  * };
392b38ff370SJamie Gritton  */
393b38ff370SJamie Gritton int
394b38ff370SJamie Gritton jail_set(struct thread *td, struct jail_set_args *uap)
395b38ff370SJamie Gritton {
396b38ff370SJamie Gritton 	struct uio *auio;
397b38ff370SJamie Gritton 	int error;
398b38ff370SJamie Gritton 
399b38ff370SJamie Gritton 	/* Check that we have an even number of iovecs. */
400b38ff370SJamie Gritton 	if (uap->iovcnt & 1)
401b38ff370SJamie Gritton 		return (EINVAL);
402b38ff370SJamie Gritton 
403b38ff370SJamie Gritton 	error = copyinuio(uap->iovp, uap->iovcnt, &auio);
404b38ff370SJamie Gritton 	if (error)
405b38ff370SJamie Gritton 		return (error);
406b38ff370SJamie Gritton 	error = kern_jail_set(td, auio, uap->flags);
407b38ff370SJamie Gritton 	free(auio, M_IOV);
408b38ff370SJamie Gritton 	return (error);
409413628a7SBjoern A. Zeeb }
410413628a7SBjoern A. Zeeb 
411413628a7SBjoern A. Zeeb int
412b38ff370SJamie Gritton kern_jail_set(struct thread *td, struct uio *optuio, int flags)
413413628a7SBjoern A. Zeeb {
414fd7a8150SMike Barcroft 	struct nameidata nd;
415b38ff370SJamie Gritton #ifdef INET
416b38ff370SJamie Gritton 	struct in_addr *ip4;
417413628a7SBjoern A. Zeeb #endif
418b38ff370SJamie Gritton #ifdef INET6
419b38ff370SJamie Gritton 	struct in6_addr *ip6;
420b38ff370SJamie Gritton #endif
421b38ff370SJamie Gritton 	struct vfsopt *opt;
422b38ff370SJamie Gritton 	struct vfsoptlist *opts;
423b38ff370SJamie Gritton 	struct prison *pr, *deadpr, *tpr;
424b38ff370SJamie Gritton 	struct vnode *root;
425b38ff370SJamie Gritton 	char *errmsg, *host, *name, *p, *path;
426b38ff370SJamie Gritton 	void *op;
427b38ff370SJamie Gritton 	int created, cuflags, error, errmsg_len, errmsg_pos;
428b38ff370SJamie Gritton 	int gotslevel, jid, len;
429b38ff370SJamie Gritton 	int slevel, vfslocked;
430d465a41dSBjoern A. Zeeb #if defined(INET) || defined(INET6)
431b38ff370SJamie Gritton 	int ii;
432413628a7SBjoern A. Zeeb #endif
433413628a7SBjoern A. Zeeb #ifdef INET
434b38ff370SJamie Gritton 	int ip4s;
435413628a7SBjoern A. Zeeb #endif
436b38ff370SJamie Gritton #ifdef INET6
437b38ff370SJamie Gritton 	int ip6s;
438b38ff370SJamie Gritton #endif
439b38ff370SJamie Gritton 	unsigned pr_flags, ch_flags;
440b38ff370SJamie Gritton 	char numbuf[12];
441b38ff370SJamie Gritton 
442b38ff370SJamie Gritton 	error = priv_check(td, PRIV_JAIL_SET);
443b38ff370SJamie Gritton 	if (!error && (flags & JAIL_ATTACH))
444b38ff370SJamie Gritton 		error = priv_check(td, PRIV_JAIL_ATTACH);
445b38ff370SJamie Gritton 	if (error)
44675c13541SPoul-Henning Kamp 		return (error);
447b38ff370SJamie Gritton 	if (flags & ~JAIL_SET_MASK)
448b38ff370SJamie Gritton 		return (EINVAL);
449b38ff370SJamie Gritton 
450b38ff370SJamie Gritton 	/*
451b38ff370SJamie Gritton 	 * Check all the parameters before committing to anything.  Not all
452b38ff370SJamie Gritton 	 * errors can be caught early, but we may as well try.  Also, this
453b38ff370SJamie Gritton 	 * takes care of some expensive stuff (path lookup) before getting
454b38ff370SJamie Gritton 	 * the allprison lock.
455b38ff370SJamie Gritton 	 *
456b38ff370SJamie Gritton 	 * XXX Jails are not filesystems, and jail parameters are not mount
457b38ff370SJamie Gritton 	 *     options.  But it makes more sense to re-use the vfsopt code
458b38ff370SJamie Gritton 	 *     than duplicate it under a different name.
459b38ff370SJamie Gritton 	 */
460b38ff370SJamie Gritton 	error = vfs_buildopts(optuio, &opts);
461b38ff370SJamie Gritton 	if (error)
462b38ff370SJamie Gritton 		return (error);
463b38ff370SJamie Gritton #ifdef INET
464b38ff370SJamie Gritton 	ip4 = NULL;
465b38ff370SJamie Gritton #endif
466b38ff370SJamie Gritton #ifdef INET6
467b38ff370SJamie Gritton 	ip6 = NULL;
468b38ff370SJamie Gritton #endif
469b38ff370SJamie Gritton 
470b38ff370SJamie Gritton 	error = vfs_copyopt(opts, "jid", &jid, sizeof(jid));
471b38ff370SJamie Gritton 	if (error == ENOENT)
472b38ff370SJamie Gritton 		jid = 0;
473b38ff370SJamie Gritton 	else if (error != 0)
474b38ff370SJamie Gritton 		goto done_free;
475b38ff370SJamie Gritton 
476b38ff370SJamie Gritton 	error = vfs_copyopt(opts, "securelevel", &slevel, sizeof(slevel));
477b38ff370SJamie Gritton 	if (error == ENOENT)
478b38ff370SJamie Gritton 		gotslevel = 0;
479b38ff370SJamie Gritton 	else if (error != 0)
480b38ff370SJamie Gritton 		goto done_free;
481b38ff370SJamie Gritton 	else
482b38ff370SJamie Gritton 		gotslevel = 1;
483b38ff370SJamie Gritton 
484b38ff370SJamie Gritton 	pr_flags = ch_flags = 0;
485b38ff370SJamie Gritton 	vfs_flagopt(opts, "persist", &pr_flags, PR_PERSIST);
486b38ff370SJamie Gritton 	vfs_flagopt(opts, "nopersist", &ch_flags, PR_PERSIST);
487b38ff370SJamie Gritton 	ch_flags |= pr_flags;
488b38ff370SJamie Gritton 	if ((flags & (JAIL_CREATE | JAIL_UPDATE | JAIL_ATTACH)) == JAIL_CREATE
489b38ff370SJamie Gritton 	    && !(pr_flags & PR_PERSIST)) {
490b38ff370SJamie Gritton 		error = EINVAL;
491b38ff370SJamie Gritton 		vfs_opterror(opts, "new jail must persist or attach");
492b38ff370SJamie Gritton 		goto done_errmsg;
493b38ff370SJamie Gritton 	}
494b38ff370SJamie Gritton 
495b38ff370SJamie Gritton 	error = vfs_getopt(opts, "name", (void **)&name, &len);
496b38ff370SJamie Gritton 	if (error == ENOENT)
497b38ff370SJamie Gritton 		name = NULL;
498b38ff370SJamie Gritton 	else if (error != 0)
499b38ff370SJamie Gritton 		goto done_free;
500b38ff370SJamie Gritton 	else {
501b38ff370SJamie Gritton 		if (len == 0 || name[len - 1] != '\0') {
502b38ff370SJamie Gritton 			error = EINVAL;
503b38ff370SJamie Gritton 			goto done_free;
504b38ff370SJamie Gritton 		}
505b38ff370SJamie Gritton 		if (len > MAXHOSTNAMELEN) {
506b38ff370SJamie Gritton 			error = ENAMETOOLONG;
507b38ff370SJamie Gritton 			goto done_free;
508b38ff370SJamie Gritton 		}
509b38ff370SJamie Gritton 	}
510b38ff370SJamie Gritton 
511b38ff370SJamie Gritton 	error = vfs_getopt(opts, "host.hostname", (void **)&host, &len);
512b38ff370SJamie Gritton 	if (error == ENOENT)
513b38ff370SJamie Gritton 		host = NULL;
514b38ff370SJamie Gritton 	else if (error != 0)
515b38ff370SJamie Gritton 		goto done_free;
516b38ff370SJamie Gritton 	else {
517b38ff370SJamie Gritton 		if (len == 0 || host[len - 1] != '\0') {
518b38ff370SJamie Gritton 			error = EINVAL;
519b38ff370SJamie Gritton 			goto done_free;
520b38ff370SJamie Gritton 		}
521b38ff370SJamie Gritton 		if (len > MAXHOSTNAMELEN) {
522b38ff370SJamie Gritton 			error = ENAMETOOLONG;
523b38ff370SJamie Gritton 			goto done_free;
524b38ff370SJamie Gritton 		}
525b38ff370SJamie Gritton 	}
526b38ff370SJamie Gritton 
527b38ff370SJamie Gritton #ifdef INET
528b38ff370SJamie Gritton 	error = vfs_getopt(opts, "ip4.addr", &op, &ip4s);
529b38ff370SJamie Gritton 	if (error == ENOENT)
530b38ff370SJamie Gritton 		ip4s = -1;
531b38ff370SJamie Gritton 	else if (error != 0)
532b38ff370SJamie Gritton 		goto done_free;
533b38ff370SJamie Gritton 	else if (ip4s & (sizeof(*ip4) - 1)) {
534b38ff370SJamie Gritton 		error = EINVAL;
535b38ff370SJamie Gritton 		goto done_free;
536b38ff370SJamie Gritton 	} else if (ip4s > 0) {
537b38ff370SJamie Gritton 		ip4s /= sizeof(*ip4);
538b38ff370SJamie Gritton 		if (ip4s > jail_max_af_ips) {
539b38ff370SJamie Gritton 			error = EINVAL;
540b38ff370SJamie Gritton 			vfs_opterror(opts, "too many IPv4 addresses");
541b38ff370SJamie Gritton 			goto done_errmsg;
542b38ff370SJamie Gritton 		}
543b38ff370SJamie Gritton 		ip4 = malloc(ip4s * sizeof(*ip4), M_PRISON, M_WAITOK);
544b38ff370SJamie Gritton 		bcopy(op, ip4, ip4s * sizeof(*ip4));
545b38ff370SJamie Gritton 		/*
546b38ff370SJamie Gritton 		 * IP addresses are all sorted but ip[0] to preserve the
547b38ff370SJamie Gritton 		 * primary IP address as given from userland.  This special IP
548b38ff370SJamie Gritton 		 * is used for unbound outgoing connections as well for
549b38ff370SJamie Gritton 		 * "loopback" traffic.
550b38ff370SJamie Gritton 		 */
551b38ff370SJamie Gritton 		if (ip4s > 1)
552b38ff370SJamie Gritton 			qsort(ip4 + 1, ip4s - 1, sizeof(*ip4), qcmp_v4);
553b38ff370SJamie Gritton 		/*
554b38ff370SJamie Gritton 		 * Check for duplicate addresses and do some simple zero and
555b38ff370SJamie Gritton 		 * broadcast checks. If users give other bogus addresses it is
556b38ff370SJamie Gritton 		 * their problem.
557b38ff370SJamie Gritton 		 *
558b38ff370SJamie Gritton 		 * We do not have to care about byte order for these checks so
559b38ff370SJamie Gritton 		 * we will do them in NBO.
560b38ff370SJamie Gritton 		 */
561b38ff370SJamie Gritton 		for (ii = 0; ii < ip4s; ii++) {
562b38ff370SJamie Gritton 			if (ip4[ii].s_addr == INADDR_ANY ||
563b38ff370SJamie Gritton 			    ip4[ii].s_addr == INADDR_BROADCAST) {
564b38ff370SJamie Gritton 				error = EINVAL;
565b38ff370SJamie Gritton 				goto done_free;
566b38ff370SJamie Gritton 			}
567b38ff370SJamie Gritton 			if ((ii+1) < ip4s &&
568b38ff370SJamie Gritton 			    (ip4[0].s_addr == ip4[ii+1].s_addr ||
569b38ff370SJamie Gritton 			     ip4[ii].s_addr == ip4[ii+1].s_addr)) {
570b38ff370SJamie Gritton 				error = EINVAL;
571b38ff370SJamie Gritton 				goto done_free;
572b38ff370SJamie Gritton 			}
573b38ff370SJamie Gritton 		}
574b38ff370SJamie Gritton 	}
575b38ff370SJamie Gritton #endif
576b38ff370SJamie Gritton 
577b38ff370SJamie Gritton #ifdef INET6
578b38ff370SJamie Gritton 	error = vfs_getopt(opts, "ip6.addr", &op, &ip6s);
579b38ff370SJamie Gritton 	if (error == ENOENT)
580b38ff370SJamie Gritton 		ip6s = -1;
581b38ff370SJamie Gritton 	else if (error != 0)
582b38ff370SJamie Gritton 		goto done_free;
583b38ff370SJamie Gritton 	else if (ip6s & (sizeof(*ip6) - 1)) {
584b38ff370SJamie Gritton 		error = EINVAL;
585b38ff370SJamie Gritton 		goto done_free;
586b38ff370SJamie Gritton 	} else if (ip6s > 0) {
587b38ff370SJamie Gritton 		ip6s /= sizeof(*ip6);
588b38ff370SJamie Gritton 		if (ip6s > jail_max_af_ips) {
589b38ff370SJamie Gritton 			error = EINVAL;
590b38ff370SJamie Gritton 			vfs_opterror(opts, "too many IPv6 addresses");
591b38ff370SJamie Gritton 			goto done_errmsg;
592b38ff370SJamie Gritton 		}
593b38ff370SJamie Gritton 		ip6 = malloc(ip6s * sizeof(*ip6), M_PRISON, M_WAITOK);
594b38ff370SJamie Gritton 		bcopy(op, ip6, ip6s * sizeof(*ip6));
595b38ff370SJamie Gritton 		if (ip6s > 1)
596b38ff370SJamie Gritton 			qsort(ip6 + 1, ip6s - 1, sizeof(*ip6), qcmp_v6);
597b38ff370SJamie Gritton 		for (ii = 0; ii < ip6s; ii++) {
598b38ff370SJamie Gritton 			if (IN6_IS_ADDR_UNSPECIFIED(&ip6[0])) {
599b38ff370SJamie Gritton 				error = EINVAL;
600b38ff370SJamie Gritton 				goto done_free;
601b38ff370SJamie Gritton 			}
602b38ff370SJamie Gritton 			if ((ii+1) < ip6s &&
603b38ff370SJamie Gritton 			    (IN6_ARE_ADDR_EQUAL(&ip6[0], &ip6[ii+1]) ||
604b38ff370SJamie Gritton 			     IN6_ARE_ADDR_EQUAL(&ip6[ii], &ip6[ii+1])))
605b38ff370SJamie Gritton 			{
606b38ff370SJamie Gritton 				error = EINVAL;
607b38ff370SJamie Gritton 				goto done_free;
608b38ff370SJamie Gritton 			}
609b38ff370SJamie Gritton 		}
610b38ff370SJamie Gritton 	}
611b38ff370SJamie Gritton #endif
612b38ff370SJamie Gritton 
613b38ff370SJamie Gritton 	root = NULL;
614b38ff370SJamie Gritton 	error = vfs_getopt(opts, "path", (void **)&path, &len);
615b38ff370SJamie Gritton 	if (error == ENOENT)
616b38ff370SJamie Gritton 		path = NULL;
617b38ff370SJamie Gritton 	else if (error != 0)
618b38ff370SJamie Gritton 		goto done_free;
619b38ff370SJamie Gritton 	else {
620b38ff370SJamie Gritton 		if (flags & JAIL_UPDATE) {
621b38ff370SJamie Gritton 			error = EINVAL;
622b38ff370SJamie Gritton 			vfs_opterror(opts,
623b38ff370SJamie Gritton 			    "path cannot be changed after creation");
624b38ff370SJamie Gritton 			goto done_errmsg;
625b38ff370SJamie Gritton 		}
626b38ff370SJamie Gritton 		if (len == 0 || path[len - 1] != '\0') {
627b38ff370SJamie Gritton 			error = EINVAL;
628b38ff370SJamie Gritton 			goto done_free;
629b38ff370SJamie Gritton 		}
630b38ff370SJamie Gritton 		if (len > MAXPATHLEN) {
631b38ff370SJamie Gritton 			error = ENAMETOOLONG;
632b38ff370SJamie Gritton 			goto done_free;
633b38ff370SJamie Gritton 		}
634b38ff370SJamie Gritton 		if (len < 2 || (len == 2 && path[0] == '/'))
635b38ff370SJamie Gritton 			path = NULL;
636b38ff370SJamie Gritton 		else {
637b38ff370SJamie Gritton 			NDINIT(&nd, LOOKUP, MPSAFE | FOLLOW, UIO_SYSSPACE,
638b38ff370SJamie Gritton 			    path, td);
639b38ff370SJamie Gritton 			error = namei(&nd);
640b38ff370SJamie Gritton 			if (error)
641b38ff370SJamie Gritton 				goto done_free;
642b38ff370SJamie Gritton 			vfslocked = NDHASGIANT(&nd);
643b38ff370SJamie Gritton 			root = nd.ni_vp;
644b38ff370SJamie Gritton 			NDFREE(&nd, NDF_ONLY_PNBUF);
645b38ff370SJamie Gritton 			if (root->v_type != VDIR) {
646b38ff370SJamie Gritton 				error = ENOTDIR;
647b38ff370SJamie Gritton 				vrele(root);
648b38ff370SJamie Gritton 				VFS_UNLOCK_GIANT(vfslocked);
649b38ff370SJamie Gritton 				goto done_free;
650b38ff370SJamie Gritton 			}
651b38ff370SJamie Gritton 			VFS_UNLOCK_GIANT(vfslocked);
652b38ff370SJamie Gritton 		}
653b38ff370SJamie Gritton 	}
654b38ff370SJamie Gritton 
655b38ff370SJamie Gritton 	/*
656b38ff370SJamie Gritton 	 * Grab the allprison lock before letting modules check their
657b38ff370SJamie Gritton 	 * parameters.  Once we have it, do not let go so we'll have a
658b38ff370SJamie Gritton 	 * consistent view of the OSD list.
659b38ff370SJamie Gritton 	 */
660b38ff370SJamie Gritton 	sx_xlock(&allprison_lock);
661b38ff370SJamie Gritton 	error = osd_jail_call(NULL, PR_METHOD_CHECK, opts);
662b38ff370SJamie Gritton 	if (error)
663b38ff370SJamie Gritton 		goto done_unlock_list;
664b38ff370SJamie Gritton 
665b38ff370SJamie Gritton 	/* By now, all parameters should have been noted. */
666b38ff370SJamie Gritton 	TAILQ_FOREACH(opt, opts, link) {
667b38ff370SJamie Gritton 		if (!opt->seen && strcmp(opt->name, "errmsg")) {
668b38ff370SJamie Gritton 			error = EINVAL;
669b38ff370SJamie Gritton 			vfs_opterror(opts, "unknown parameter: %s", opt->name);
670b38ff370SJamie Gritton 			goto done_unlock_list;
671b38ff370SJamie Gritton 		}
672b38ff370SJamie Gritton 	}
673b38ff370SJamie Gritton 
674b38ff370SJamie Gritton 	/*
675b38ff370SJamie Gritton 	 * See if we are creating a new record or updating an existing one.
676b38ff370SJamie Gritton 	 * This abuses the file error codes ENOENT and EEXIST.
677b38ff370SJamie Gritton 	 */
678b38ff370SJamie Gritton 	cuflags = flags & (JAIL_CREATE | JAIL_UPDATE);
679b38ff370SJamie Gritton 	if (!cuflags) {
680b38ff370SJamie Gritton 		error = EINVAL;
681b38ff370SJamie Gritton 		vfs_opterror(opts, "no valid operation (create or update)");
682b38ff370SJamie Gritton 		goto done_unlock_list;
683b38ff370SJamie Gritton 	}
684b38ff370SJamie Gritton 	pr = NULL;
685b38ff370SJamie Gritton 	if (jid != 0) {
686b38ff370SJamie Gritton 		/* See if a requested jid already exists. */
687b38ff370SJamie Gritton 		if (jid < 0) {
688b38ff370SJamie Gritton 			error = EINVAL;
689b38ff370SJamie Gritton 			vfs_opterror(opts, "negative jid");
690b38ff370SJamie Gritton 			goto done_unlock_list;
691b38ff370SJamie Gritton 		}
692b38ff370SJamie Gritton 		pr = prison_find(jid);
693b38ff370SJamie Gritton 		if (pr != NULL) {
694b38ff370SJamie Gritton 			/* Create: jid must not exist. */
695b38ff370SJamie Gritton 			if (cuflags == JAIL_CREATE) {
696b38ff370SJamie Gritton 				mtx_unlock(&pr->pr_mtx);
697b38ff370SJamie Gritton 				error = EEXIST;
698b38ff370SJamie Gritton 				vfs_opterror(opts, "jail %d already exists",
699b38ff370SJamie Gritton 				    jid);
700b38ff370SJamie Gritton 				goto done_unlock_list;
701b38ff370SJamie Gritton 			}
702b38ff370SJamie Gritton 			if (pr->pr_uref == 0) {
703b38ff370SJamie Gritton 				if (!(flags & JAIL_DYING)) {
704b38ff370SJamie Gritton 					mtx_unlock(&pr->pr_mtx);
705b38ff370SJamie Gritton 					error = ENOENT;
706b38ff370SJamie Gritton 					vfs_opterror(opts, "jail %d is dying",
707b38ff370SJamie Gritton 					    jid);
708b38ff370SJamie Gritton 					goto done_unlock_list;
709b38ff370SJamie Gritton 				} else if ((flags & JAIL_ATTACH) ||
710b38ff370SJamie Gritton 				    (pr_flags & PR_PERSIST)) {
711b38ff370SJamie Gritton 					/*
712b38ff370SJamie Gritton 					 * A dying jail might be resurrected
713b38ff370SJamie Gritton 					 * (via attach or persist), but first
714b38ff370SJamie Gritton 					 * it must determine if another jail
715b38ff370SJamie Gritton 					 * has claimed its name.  Accomplish
716b38ff370SJamie Gritton 					 * this by implicitly re-setting the
717b38ff370SJamie Gritton 					 * name.
718b38ff370SJamie Gritton 					 */
719b38ff370SJamie Gritton 					if (name == NULL)
720b38ff370SJamie Gritton 						name = pr->pr_name;
721b38ff370SJamie Gritton 				}
722b38ff370SJamie Gritton 			}
723b38ff370SJamie Gritton 		}
724b38ff370SJamie Gritton 		if (pr == NULL) {
725b38ff370SJamie Gritton 			/* Update: jid must exist. */
726b38ff370SJamie Gritton 			if (cuflags == JAIL_UPDATE) {
727b38ff370SJamie Gritton 				error = ENOENT;
728b38ff370SJamie Gritton 				vfs_opterror(opts, "jail %d not found", jid);
729b38ff370SJamie Gritton 				goto done_unlock_list;
730b38ff370SJamie Gritton 			}
731b38ff370SJamie Gritton 		}
732b38ff370SJamie Gritton 	}
733b38ff370SJamie Gritton 	/*
734b38ff370SJamie Gritton 	 * If the caller provided a name, look for a jail by that name.
735b38ff370SJamie Gritton 	 * This has different semantics for creates and updates keyed by jid
736b38ff370SJamie Gritton 	 * (where the name must not already exist in a different jail),
737b38ff370SJamie Gritton 	 * and updates keyed by the name itself (where the name must exist
738b38ff370SJamie Gritton 	 * because that is the jail being updated).
739b38ff370SJamie Gritton 	 */
740b38ff370SJamie Gritton 	if (name != NULL) {
741b38ff370SJamie Gritton 		if (name[0] != '\0') {
742b38ff370SJamie Gritton 			deadpr = NULL;
743b38ff370SJamie Gritton  name_again:
744b38ff370SJamie Gritton 			TAILQ_FOREACH(tpr, &allprison, pr_list) {
745b38ff370SJamie Gritton 				if (tpr != pr && tpr->pr_ref > 0 &&
746b38ff370SJamie Gritton 				    !strcmp(tpr->pr_name, name)) {
747b38ff370SJamie Gritton 					if (pr == NULL &&
748b38ff370SJamie Gritton 					    cuflags != JAIL_CREATE) {
749b38ff370SJamie Gritton 						mtx_lock(&tpr->pr_mtx);
750b38ff370SJamie Gritton 						if (tpr->pr_ref > 0) {
751b38ff370SJamie Gritton 							/*
752b38ff370SJamie Gritton 							 * Use this jail
753b38ff370SJamie Gritton 							 * for updates.
754b38ff370SJamie Gritton 							 */
755b38ff370SJamie Gritton 							if (tpr->pr_uref > 0) {
756b38ff370SJamie Gritton 								pr = tpr;
757b38ff370SJamie Gritton 								break;
758b38ff370SJamie Gritton 							}
759b38ff370SJamie Gritton 							deadpr = tpr;
760b38ff370SJamie Gritton 						}
761b38ff370SJamie Gritton 						mtx_unlock(&tpr->pr_mtx);
762b38ff370SJamie Gritton 					} else if (tpr->pr_uref > 0) {
763b38ff370SJamie Gritton 						/*
764b38ff370SJamie Gritton 						 * Create, or update(jid):
765b38ff370SJamie Gritton 						 * name must not exist in an
766b38ff370SJamie Gritton 						 * active jail.
767b38ff370SJamie Gritton 						 */
768b38ff370SJamie Gritton 						error = EEXIST;
769b38ff370SJamie Gritton 						if (pr != NULL)
770b38ff370SJamie Gritton 							mtx_unlock(&pr->pr_mtx);
771b38ff370SJamie Gritton 						vfs_opterror(opts,
772b38ff370SJamie Gritton 						   "jail \"%s\" already exists",
773b38ff370SJamie Gritton 						   name);
774b38ff370SJamie Gritton 						goto done_unlock_list;
775b38ff370SJamie Gritton 					}
776b38ff370SJamie Gritton 				}
777b38ff370SJamie Gritton 			}
778b38ff370SJamie Gritton 			/* If no active jail is found, use a dying one. */
779b38ff370SJamie Gritton 			if (deadpr != NULL && pr == NULL) {
780b38ff370SJamie Gritton 				if (flags & JAIL_DYING) {
781b38ff370SJamie Gritton 					mtx_lock(&deadpr->pr_mtx);
782b38ff370SJamie Gritton 					if (deadpr->pr_ref == 0) {
783b38ff370SJamie Gritton 						mtx_unlock(&deadpr->pr_mtx);
784b38ff370SJamie Gritton 						goto name_again;
785b38ff370SJamie Gritton 					}
786b38ff370SJamie Gritton 					pr = deadpr;
787b38ff370SJamie Gritton 				} else if (cuflags == JAIL_UPDATE) {
788b38ff370SJamie Gritton 					error = ENOENT;
789b38ff370SJamie Gritton 					vfs_opterror(opts,
790b38ff370SJamie Gritton 					    "jail \"%s\" is dying", name);
791b38ff370SJamie Gritton 					goto done_unlock_list;
792b38ff370SJamie Gritton 				}
793b38ff370SJamie Gritton 			}
794b38ff370SJamie Gritton 			/* Update: name must exist if no jid. */
795b38ff370SJamie Gritton 			else if (cuflags == JAIL_UPDATE && pr == NULL) {
796b38ff370SJamie Gritton 				error = ENOENT;
797b38ff370SJamie Gritton 				vfs_opterror(opts, "jail \"%s\" not found",
798b38ff370SJamie Gritton 				    name);
799b38ff370SJamie Gritton 				goto done_unlock_list;
800b38ff370SJamie Gritton 			}
801b38ff370SJamie Gritton 		}
802b38ff370SJamie Gritton 	}
803b38ff370SJamie Gritton 	/* Update: must provide a jid or name. */
804b38ff370SJamie Gritton 	else if (cuflags == JAIL_UPDATE && pr == NULL) {
805b38ff370SJamie Gritton 		error = ENOENT;
806b38ff370SJamie Gritton 		vfs_opterror(opts, "update specified no jail");
807b38ff370SJamie Gritton 		goto done_unlock_list;
808b38ff370SJamie Gritton 	}
809b38ff370SJamie Gritton 
810b38ff370SJamie Gritton 	/* If there's no prison to update, create a new one and link it in. */
811b38ff370SJamie Gritton 	if (pr == NULL) {
812b38ff370SJamie Gritton 		created = 1;
813b38ff370SJamie Gritton 		pr = malloc(sizeof(*pr), M_PRISON, M_WAITOK | M_ZERO);
814b38ff370SJamie Gritton 		if (jid == 0) {
815b38ff370SJamie Gritton 			/* Find the next free jid. */
816b38ff370SJamie Gritton 			jid = lastprid + 1;
817b38ff370SJamie Gritton  findnext:
818b38ff370SJamie Gritton 			if (jid == JAIL_MAX)
819b38ff370SJamie Gritton 				jid = 1;
820b38ff370SJamie Gritton 			TAILQ_FOREACH(tpr, &allprison, pr_list) {
821b38ff370SJamie Gritton 				if (tpr->pr_id < jid)
822b38ff370SJamie Gritton 					continue;
823b38ff370SJamie Gritton 				if (tpr->pr_id > jid || tpr->pr_ref == 0) {
824b38ff370SJamie Gritton 					TAILQ_INSERT_BEFORE(tpr, pr, pr_list);
825b38ff370SJamie Gritton 					break;
826b38ff370SJamie Gritton 				}
827b38ff370SJamie Gritton 				if (jid == lastprid) {
828b38ff370SJamie Gritton 					error = EAGAIN;
829b38ff370SJamie Gritton 					vfs_opterror(opts,
830b38ff370SJamie Gritton 					    "no available jail IDs");
831b38ff370SJamie Gritton 					free(pr, M_PRISON);
832b38ff370SJamie Gritton 					goto done_unlock_list;
833b38ff370SJamie Gritton 				}
834b38ff370SJamie Gritton 				jid++;
835b38ff370SJamie Gritton 				goto findnext;
836b38ff370SJamie Gritton 			}
837b38ff370SJamie Gritton 			lastprid = jid;
838b38ff370SJamie Gritton 		} else {
839b38ff370SJamie Gritton 			/*
840b38ff370SJamie Gritton 			 * The jail already has a jid (that did not yet exist),
841b38ff370SJamie Gritton 			 * so just find where to insert it.
842b38ff370SJamie Gritton 			 */
843b38ff370SJamie Gritton 			TAILQ_FOREACH(tpr, &allprison, pr_list)
844b38ff370SJamie Gritton 				if (tpr->pr_id >= jid) {
845b38ff370SJamie Gritton 					TAILQ_INSERT_BEFORE(tpr, pr, pr_list);
846b38ff370SJamie Gritton 					break;
847b38ff370SJamie Gritton 				}
848b38ff370SJamie Gritton 		}
849b38ff370SJamie Gritton 		if (tpr == NULL)
850b38ff370SJamie Gritton 			TAILQ_INSERT_TAIL(&allprison, pr, pr_list);
851b38ff370SJamie Gritton 		prisoncount++;
852b38ff370SJamie Gritton 
853b38ff370SJamie Gritton 		pr->pr_id = jid;
854b38ff370SJamie Gritton 		if (name == NULL)
855b38ff370SJamie Gritton 			name = "";
856b38ff370SJamie Gritton 		if (path == NULL) {
857b38ff370SJamie Gritton 			path = "/";
858b38ff370SJamie Gritton 			root = rootvnode;
859b38ff370SJamie Gritton 			vref(root);
860b38ff370SJamie Gritton 		}
861b38ff370SJamie Gritton 
862b38ff370SJamie Gritton 		mtx_init(&pr->pr_mtx, "jail mutex", NULL, MTX_DEF);
863b38ff370SJamie Gritton 
864b38ff370SJamie Gritton 		/*
865b38ff370SJamie Gritton 		 * Allocate a dedicated cpuset for each jail.
866b38ff370SJamie Gritton 		 * Unlike other initial settings, this may return an erorr.
867b38ff370SJamie Gritton 		 */
868b38ff370SJamie Gritton 		error = cpuset_create_root(td, &pr->pr_cpuset);
869b38ff370SJamie Gritton 		if (error) {
870b38ff370SJamie Gritton 			prison_deref(pr, PD_LIST_XLOCKED);
871b38ff370SJamie Gritton 			goto done_releroot;
872b38ff370SJamie Gritton 		}
873b38ff370SJamie Gritton 
874b38ff370SJamie Gritton 		mtx_lock(&pr->pr_mtx);
875b38ff370SJamie Gritton 		/*
876b38ff370SJamie Gritton 		 * New prisons do not yet have a reference, because we do not
877b38ff370SJamie Gritton 		 * want other to see the incomplete prison once the
878b38ff370SJamie Gritton 		 * allprison_lock is downgraded.
879b38ff370SJamie Gritton 		 */
880b38ff370SJamie Gritton 	} else {
881b38ff370SJamie Gritton 		created = 0;
882b38ff370SJamie Gritton 		/*
883b38ff370SJamie Gritton 		 * Grab a reference for existing prisons, to ensure they
884b38ff370SJamie Gritton 		 * continue to exist for the duration of the call.
885b38ff370SJamie Gritton 		 */
886b38ff370SJamie Gritton 		pr->pr_ref++;
887b38ff370SJamie Gritton 	}
888b38ff370SJamie Gritton 
889b38ff370SJamie Gritton 	/* Do final error checking before setting anything. */
890b38ff370SJamie Gritton 	error = 0;
891b38ff370SJamie Gritton #if defined(INET) || defined(INET6)
892b38ff370SJamie Gritton 	if (
893b38ff370SJamie Gritton #ifdef INET
894b38ff370SJamie Gritton 	    ip4s > 0
895b38ff370SJamie Gritton #ifdef INET6
896b38ff370SJamie Gritton 	    ||
897b38ff370SJamie Gritton #endif
898b38ff370SJamie Gritton #endif
899b38ff370SJamie Gritton #ifdef INET6
900b38ff370SJamie Gritton 	    ip6s > 0
901b38ff370SJamie Gritton #endif
902b38ff370SJamie Gritton 	    )
903b38ff370SJamie Gritton 		/*
904b38ff370SJamie Gritton 		 * Check for conflicting IP addresses.  We permit them if there
905b38ff370SJamie Gritton 		 * is no more than 1 IP on each jail.  If there is a duplicate
906b38ff370SJamie Gritton 		 * on a jail with more than one IP stop checking and return
907b38ff370SJamie Gritton 		 * error.
908b38ff370SJamie Gritton 		 */
909b38ff370SJamie Gritton 		TAILQ_FOREACH(tpr, &allprison, pr_list) {
910b38ff370SJamie Gritton 			if (tpr == pr || tpr->pr_uref == 0)
911b38ff370SJamie Gritton 				continue;
912b38ff370SJamie Gritton #ifdef INET
913b38ff370SJamie Gritton 			if ((ip4s > 0 && tpr->pr_ip4s > 1) ||
914b38ff370SJamie Gritton 			    (ip4s > 1 && tpr->pr_ip4s > 0))
915b38ff370SJamie Gritton 				for (ii = 0; ii < ip4s; ii++)
916b38ff370SJamie Gritton 					if (_prison_check_ip4(tpr,
917b38ff370SJamie Gritton 					    &ip4[ii]) == 0) {
918b38ff370SJamie Gritton 						error = EINVAL;
919b38ff370SJamie Gritton 						vfs_opterror(opts,
920b38ff370SJamie Gritton 						    "IPv4 addresses clash");
921b38ff370SJamie Gritton 						goto done_deref_locked;
922b38ff370SJamie Gritton 					}
923b38ff370SJamie Gritton #endif
924b38ff370SJamie Gritton #ifdef INET6
925b38ff370SJamie Gritton 			if ((ip6s > 0 && tpr->pr_ip6s > 1) ||
926b38ff370SJamie Gritton 			    (ip6s > 1 && tpr->pr_ip6s > 0))
927b38ff370SJamie Gritton 				for (ii = 0; ii < ip6s; ii++)
928b38ff370SJamie Gritton 					if (_prison_check_ip6(tpr,
929b38ff370SJamie Gritton 					    &ip6[ii]) == 0) {
930b38ff370SJamie Gritton 						error = EINVAL;
931b38ff370SJamie Gritton 						vfs_opterror(opts,
932b38ff370SJamie Gritton 						    "IPv6 addresses clash");
933b38ff370SJamie Gritton 						goto done_deref_locked;
934b38ff370SJamie Gritton 					}
935b38ff370SJamie Gritton #endif
936b38ff370SJamie Gritton 		}
937b38ff370SJamie Gritton #endif
938b38ff370SJamie Gritton 	if (error == 0 && name != NULL) {
939b38ff370SJamie Gritton 		/* Give a default name of the jid. */
940b38ff370SJamie Gritton 		if (name[0] == '\0')
941b38ff370SJamie Gritton 			snprintf(name = numbuf, sizeof(numbuf), "%d", jid);
942b38ff370SJamie Gritton 		else if (strtoul(name, &p, 10) != jid && *p == '\0') {
943b38ff370SJamie Gritton 			error = EINVAL;
944b38ff370SJamie Gritton 			vfs_opterror(opts, "name cannot be numeric");
945b38ff370SJamie Gritton 		}
946b38ff370SJamie Gritton 	}
947b38ff370SJamie Gritton 	if (error) {
948b38ff370SJamie Gritton  done_deref_locked:
949b38ff370SJamie Gritton 		/*
950b38ff370SJamie Gritton 		 * Some parameter had an error so do not set anything.
951b38ff370SJamie Gritton 		 * If this is a new jail, it will go away without ever
952b38ff370SJamie Gritton 		 * having been seen.
953b38ff370SJamie Gritton 		 */
954b38ff370SJamie Gritton 		prison_deref(pr, created
955b38ff370SJamie Gritton 		    ? PD_LOCKED | PD_LIST_XLOCKED
956b38ff370SJamie Gritton 		    : PD_DEREF | PD_LOCKED | PD_LIST_XLOCKED);
957b38ff370SJamie Gritton 		goto done_releroot;
958b38ff370SJamie Gritton 	}
959b38ff370SJamie Gritton 
960b38ff370SJamie Gritton 	/* Set the parameters of the prison. */
961b38ff370SJamie Gritton #ifdef INET
962b38ff370SJamie Gritton 	if (ip4s >= 0) {
963b38ff370SJamie Gritton 		pr->pr_ip4s = ip4s;
964b38ff370SJamie Gritton 		free(pr->pr_ip4, M_PRISON);
965b38ff370SJamie Gritton 		pr->pr_ip4 = ip4;
966b38ff370SJamie Gritton 		ip4 = NULL;
967b38ff370SJamie Gritton 	}
968b38ff370SJamie Gritton #endif
969b38ff370SJamie Gritton #ifdef INET6
970b38ff370SJamie Gritton 	if (ip6s >= 0) {
971b38ff370SJamie Gritton 		pr->pr_ip6s = ip6s;
972b38ff370SJamie Gritton 		free(pr->pr_ip6, M_PRISON);
973b38ff370SJamie Gritton 		pr->pr_ip6 = ip6;
974b38ff370SJamie Gritton 		ip6 = NULL;
975b38ff370SJamie Gritton 	}
976b38ff370SJamie Gritton #endif
977b38ff370SJamie Gritton 	if (gotslevel)
978b38ff370SJamie Gritton 		pr->pr_securelevel = slevel;
979b38ff370SJamie Gritton 	if (name != NULL)
980b38ff370SJamie Gritton 		strlcpy(pr->pr_name, name, sizeof(pr->pr_name));
981b38ff370SJamie Gritton 	if (path != NULL) {
982b38ff370SJamie Gritton 		strlcpy(pr->pr_path, path, sizeof(pr->pr_path));
983b38ff370SJamie Gritton 		pr->pr_root = root;
984b38ff370SJamie Gritton 	}
985b38ff370SJamie Gritton 	if (host != NULL)
986b38ff370SJamie Gritton 		strlcpy(pr->pr_host, host, sizeof(pr->pr_host));
987b38ff370SJamie Gritton 	/*
988b38ff370SJamie Gritton 	 * Persistent prisons get an extra reference, and prisons losing their
989b38ff370SJamie Gritton 	 * persist flag lose that reference.  Only do this for existing prisons
990b38ff370SJamie Gritton 	 * for now, so new ones will remain unseen until after the module
991b38ff370SJamie Gritton 	 * handlers have completed.
992b38ff370SJamie Gritton 	 */
993b38ff370SJamie Gritton 	if (!created && (ch_flags & PR_PERSIST & (pr_flags ^ pr->pr_flags))) {
994b38ff370SJamie Gritton 		if (pr_flags & PR_PERSIST) {
995b38ff370SJamie Gritton 			pr->pr_ref++;
996b38ff370SJamie Gritton 			pr->pr_uref++;
997b38ff370SJamie Gritton 		} else {
998b38ff370SJamie Gritton 			pr->pr_ref--;
999b38ff370SJamie Gritton 			pr->pr_uref--;
1000b38ff370SJamie Gritton 		}
1001b38ff370SJamie Gritton 	}
1002b38ff370SJamie Gritton 	pr->pr_flags = (pr->pr_flags & ~ch_flags) | pr_flags;
1003b38ff370SJamie Gritton 	mtx_unlock(&pr->pr_mtx);
1004b38ff370SJamie Gritton 
1005b38ff370SJamie Gritton 	/* Let the modules do their work. */
1006b38ff370SJamie Gritton 	sx_downgrade(&allprison_lock);
1007b38ff370SJamie Gritton 	if (created) {
1008b38ff370SJamie Gritton 		error = osd_jail_call(pr, PR_METHOD_CREATE, opts);
1009b38ff370SJamie Gritton 		if (error) {
1010b38ff370SJamie Gritton 			prison_deref(pr, PD_LIST_SLOCKED);
1011b38ff370SJamie Gritton 			goto done_errmsg;
1012b38ff370SJamie Gritton 		}
1013b38ff370SJamie Gritton 	}
1014b38ff370SJamie Gritton 	error = osd_jail_call(pr, PR_METHOD_SET, opts);
1015b38ff370SJamie Gritton 	if (error) {
1016b38ff370SJamie Gritton 		prison_deref(pr, created
1017b38ff370SJamie Gritton 		    ? PD_LIST_SLOCKED
1018b38ff370SJamie Gritton 		    : PD_DEREF | PD_LIST_SLOCKED);
1019b38ff370SJamie Gritton 		goto done_errmsg;
1020b38ff370SJamie Gritton 	}
1021b38ff370SJamie Gritton 
1022b38ff370SJamie Gritton 	/* Attach this process to the prison if requested. */
1023b38ff370SJamie Gritton 	if (flags & JAIL_ATTACH) {
1024b38ff370SJamie Gritton 		mtx_lock(&pr->pr_mtx);
1025b38ff370SJamie Gritton 		error = do_jail_attach(td, pr);
1026b38ff370SJamie Gritton 		if (error) {
1027b38ff370SJamie Gritton 			vfs_opterror(opts, "attach failed");
1028b38ff370SJamie Gritton 			if (!created)
1029b38ff370SJamie Gritton 				prison_deref(pr, PD_DEREF);
1030b38ff370SJamie Gritton 			goto done_errmsg;
1031b38ff370SJamie Gritton 		}
1032b38ff370SJamie Gritton 	}
1033b38ff370SJamie Gritton 
1034b38ff370SJamie Gritton 	/*
1035b38ff370SJamie Gritton 	 * Now that it is all there, drop the temporary reference from existing
1036b38ff370SJamie Gritton 	 * prisons.  Or add a reference to newly created persistent prisons
1037b38ff370SJamie Gritton 	 * (which was not done earlier so that the prison would not be publicly
1038b38ff370SJamie Gritton 	 * visible).
1039b38ff370SJamie Gritton 	 */
1040b38ff370SJamie Gritton 	if (!created) {
1041b38ff370SJamie Gritton 		prison_deref(pr, (flags & JAIL_ATTACH)
1042b38ff370SJamie Gritton 		    ? PD_DEREF
1043b38ff370SJamie Gritton 		    : PD_DEREF | PD_LIST_SLOCKED);
1044b38ff370SJamie Gritton 	} else {
1045b38ff370SJamie Gritton 		if (pr_flags & PR_PERSIST) {
1046b38ff370SJamie Gritton 			mtx_lock(&pr->pr_mtx);
1047b38ff370SJamie Gritton 			pr->pr_ref++;
1048b38ff370SJamie Gritton 			pr->pr_uref++;
1049b38ff370SJamie Gritton 			mtx_unlock(&pr->pr_mtx);
1050b38ff370SJamie Gritton 		}
1051b38ff370SJamie Gritton 		if (!(flags & JAIL_ATTACH))
1052b38ff370SJamie Gritton 			sx_sunlock(&allprison_lock);
1053b38ff370SJamie Gritton 	}
1054b38ff370SJamie Gritton 	td->td_retval[0] = pr->pr_id;
1055b38ff370SJamie Gritton 	goto done_errmsg;
1056b38ff370SJamie Gritton 
1057b38ff370SJamie Gritton  done_unlock_list:
1058b38ff370SJamie Gritton 	sx_xunlock(&allprison_lock);
1059b38ff370SJamie Gritton  done_releroot:
1060b38ff370SJamie Gritton 	if (root != NULL) {
1061b38ff370SJamie Gritton 		vfslocked = VFS_LOCK_GIANT(root->v_mount);
1062b38ff370SJamie Gritton 		vrele(root);
1063b38ff370SJamie Gritton 		VFS_UNLOCK_GIANT(vfslocked);
1064b38ff370SJamie Gritton 	}
1065b38ff370SJamie Gritton  done_errmsg:
1066b38ff370SJamie Gritton 	if (error) {
1067b38ff370SJamie Gritton 		vfs_getopt(opts, "errmsg", (void **)&errmsg, &errmsg_len);
1068b38ff370SJamie Gritton 		if (errmsg_len > 0) {
1069b38ff370SJamie Gritton 			errmsg_pos = 2 * vfs_getopt_pos(opts, "errmsg") + 1;
1070b38ff370SJamie Gritton 			if (errmsg_pos > 0) {
1071b38ff370SJamie Gritton 				if (optuio->uio_segflg == UIO_SYSSPACE)
1072b38ff370SJamie Gritton 					bcopy(errmsg,
1073b38ff370SJamie Gritton 					   optuio->uio_iov[errmsg_pos].iov_base,
1074b38ff370SJamie Gritton 					   errmsg_len);
1075b38ff370SJamie Gritton 				else
1076b38ff370SJamie Gritton 					copyout(errmsg,
1077b38ff370SJamie Gritton 					   optuio->uio_iov[errmsg_pos].iov_base,
1078b38ff370SJamie Gritton 					   errmsg_len);
1079b38ff370SJamie Gritton 			}
1080b38ff370SJamie Gritton 		}
1081b38ff370SJamie Gritton 	}
1082b38ff370SJamie Gritton  done_free:
1083b38ff370SJamie Gritton #ifdef INET
1084b38ff370SJamie Gritton 	free(ip4, M_PRISON);
1085b38ff370SJamie Gritton #endif
1086b38ff370SJamie Gritton #ifdef INET6
1087b38ff370SJamie Gritton 	free(ip6, M_PRISON);
1088b38ff370SJamie Gritton #endif
1089b38ff370SJamie Gritton 	vfs_freeopts(opts);
1090b38ff370SJamie Gritton 	return (error);
1091b38ff370SJamie Gritton }
1092b38ff370SJamie Gritton 
1093b38ff370SJamie Gritton /*
1094b38ff370SJamie Gritton  * Sysctl nodes to describe jail parameters.  Maximum length of string
1095b38ff370SJamie Gritton  * parameters is returned in the string itself, and the other parameters
1096b38ff370SJamie Gritton  * exist merely to make themselves and their types known.
1097b38ff370SJamie Gritton  */
1098b38ff370SJamie Gritton SYSCTL_NODE(_security_jail, OID_AUTO, param, CTLFLAG_RW, 0,
1099b38ff370SJamie Gritton     "Jail parameters");
1100b38ff370SJamie Gritton 
1101b38ff370SJamie Gritton int
1102b38ff370SJamie Gritton sysctl_jail_param(SYSCTL_HANDLER_ARGS)
1103b38ff370SJamie Gritton {
1104b38ff370SJamie Gritton 	int i;
1105b38ff370SJamie Gritton 	long l;
1106b38ff370SJamie Gritton 	size_t s;
1107b38ff370SJamie Gritton 	char numbuf[12];
1108b38ff370SJamie Gritton 
1109b38ff370SJamie Gritton 	switch (oidp->oid_kind & CTLTYPE)
1110b38ff370SJamie Gritton 	{
1111b38ff370SJamie Gritton 	case CTLTYPE_LONG:
1112b38ff370SJamie Gritton 	case CTLTYPE_ULONG:
1113b38ff370SJamie Gritton 		l = 0;
1114b38ff370SJamie Gritton #ifdef SCTL_MASK32
1115b38ff370SJamie Gritton 		if (!(req->flags & SCTL_MASK32))
1116b38ff370SJamie Gritton #endif
1117b38ff370SJamie Gritton 			return (SYSCTL_OUT(req, &l, sizeof(l)));
1118b38ff370SJamie Gritton 	case CTLTYPE_INT:
1119b38ff370SJamie Gritton 	case CTLTYPE_UINT:
1120b38ff370SJamie Gritton 		i = 0;
1121b38ff370SJamie Gritton 		return (SYSCTL_OUT(req, &i, sizeof(i)));
1122b38ff370SJamie Gritton 	case CTLTYPE_STRING:
1123b38ff370SJamie Gritton 		snprintf(numbuf, sizeof(numbuf), "%d", arg2);
1124b38ff370SJamie Gritton 		return
1125b38ff370SJamie Gritton 		    (sysctl_handle_string(oidp, numbuf, sizeof(numbuf), req));
1126b38ff370SJamie Gritton 	case CTLTYPE_STRUCT:
1127b38ff370SJamie Gritton 		s = (size_t)arg2;
1128b38ff370SJamie Gritton 		return (SYSCTL_OUT(req, &s, sizeof(s)));
1129b38ff370SJamie Gritton 	}
1130b38ff370SJamie Gritton 	return (0);
1131b38ff370SJamie Gritton }
1132b38ff370SJamie Gritton 
1133b38ff370SJamie Gritton SYSCTL_JAIL_PARAM(, jid, CTLTYPE_INT | CTLFLAG_RD, "I", "Jail ID");
1134b38ff370SJamie Gritton SYSCTL_JAIL_PARAM_STRING(, name, CTLFLAG_RW, MAXHOSTNAMELEN, "Jail name");
1135b38ff370SJamie Gritton SYSCTL_JAIL_PARAM(, cpuset, CTLTYPE_INT | CTLFLAG_RD, "I", "Jail cpuset ID");
1136b38ff370SJamie Gritton SYSCTL_JAIL_PARAM_STRING(, path, CTLFLAG_RD, MAXPATHLEN, "Jail root path");
1137b38ff370SJamie Gritton SYSCTL_JAIL_PARAM(, securelevel, CTLTYPE_INT | CTLFLAG_RW,
1138b38ff370SJamie Gritton     "I", "Jail secure level");
1139b38ff370SJamie Gritton SYSCTL_JAIL_PARAM(, persist, CTLTYPE_INT | CTLFLAG_RW,
1140b38ff370SJamie Gritton     "B", "Jail persistence");
1141b38ff370SJamie Gritton SYSCTL_JAIL_PARAM(, dying, CTLTYPE_INT | CTLFLAG_RD,
1142b38ff370SJamie Gritton     "B", "Jail is in the process of shutting down");
1143b38ff370SJamie Gritton 
1144b38ff370SJamie Gritton SYSCTL_JAIL_PARAM_NODE(host, "Jail host info");
1145b38ff370SJamie Gritton SYSCTL_JAIL_PARAM_STRING(_host, hostname, CTLFLAG_RW, MAXHOSTNAMELEN,
1146b38ff370SJamie Gritton     "Jail hostname");
1147b38ff370SJamie Gritton 
1148b38ff370SJamie Gritton #ifdef INET
1149b38ff370SJamie Gritton SYSCTL_JAIL_PARAM_NODE(ip4, "Jail IPv4 address virtualization");
1150b38ff370SJamie Gritton SYSCTL_JAIL_PARAM_STRUCT(_ip4, addr, CTLFLAG_RW, sizeof(struct in_addr),
1151b38ff370SJamie Gritton     "S,in_addr,a", "Jail IPv4 addresses");
1152b38ff370SJamie Gritton #endif
1153b38ff370SJamie Gritton #ifdef INET6
1154b38ff370SJamie Gritton SYSCTL_JAIL_PARAM_NODE(ip6, "Jail IPv6 address virtualization");
1155b38ff370SJamie Gritton SYSCTL_JAIL_PARAM_STRUCT(_ip6, addr, CTLFLAG_RW, sizeof(struct in6_addr),
1156b38ff370SJamie Gritton     "S,in6_addr,a", "Jail IPv6 addresses");
1157b38ff370SJamie Gritton #endif
1158b38ff370SJamie Gritton 
1159b38ff370SJamie Gritton 
1160b38ff370SJamie Gritton /*
1161b38ff370SJamie Gritton  * struct jail_get_args {
1162b38ff370SJamie Gritton  *	struct iovec *iovp;
1163b38ff370SJamie Gritton  *	unsigned int iovcnt;
1164b38ff370SJamie Gritton  *	int flags;
1165b38ff370SJamie Gritton  * };
1166b38ff370SJamie Gritton  */
1167b38ff370SJamie Gritton int
1168b38ff370SJamie Gritton jail_get(struct thread *td, struct jail_get_args *uap)
1169b38ff370SJamie Gritton {
1170b38ff370SJamie Gritton 	struct uio *auio;
1171b38ff370SJamie Gritton 	int error;
1172b38ff370SJamie Gritton 
1173b38ff370SJamie Gritton 	/* Check that we have an even number of iovecs. */
1174b38ff370SJamie Gritton 	if (uap->iovcnt & 1)
1175b38ff370SJamie Gritton 		return (EINVAL);
1176b38ff370SJamie Gritton 
1177b38ff370SJamie Gritton 	error = copyinuio(uap->iovp, uap->iovcnt, &auio);
1178b38ff370SJamie Gritton 	if (error)
1179b38ff370SJamie Gritton 		return (error);
1180b38ff370SJamie Gritton 	error = kern_jail_get(td, auio, uap->flags);
1181b38ff370SJamie Gritton 	if (error == 0)
1182b38ff370SJamie Gritton 		error = copyout(auio->uio_iov, uap->iovp,
1183b38ff370SJamie Gritton 		    uap->iovcnt * sizeof (struct iovec));
1184b38ff370SJamie Gritton 	free(auio, M_IOV);
1185b38ff370SJamie Gritton 	return (error);
1186b38ff370SJamie Gritton }
1187b38ff370SJamie Gritton 
1188b38ff370SJamie Gritton int
1189b38ff370SJamie Gritton kern_jail_get(struct thread *td, struct uio *optuio, int flags)
1190b38ff370SJamie Gritton {
1191b38ff370SJamie Gritton 	struct prison *pr;
1192b38ff370SJamie Gritton 	struct vfsopt *opt;
1193b38ff370SJamie Gritton 	struct vfsoptlist *opts;
1194b38ff370SJamie Gritton 	char *errmsg, *name;
1195b38ff370SJamie Gritton 	int error, errmsg_len, errmsg_pos, i, jid, len, locked, pos;
1196b38ff370SJamie Gritton 
1197b38ff370SJamie Gritton 	if (flags & ~JAIL_GET_MASK)
1198b38ff370SJamie Gritton 		return (EINVAL);
1199b38ff370SJamie Gritton 
1200b38ff370SJamie Gritton 	/* Get the parameter list. */
1201b38ff370SJamie Gritton 	error = vfs_buildopts(optuio, &opts);
1202b38ff370SJamie Gritton 	if (error)
1203b38ff370SJamie Gritton 		return (error);
1204b38ff370SJamie Gritton 	errmsg_pos = vfs_getopt_pos(opts, "errmsg");
1205b38ff370SJamie Gritton 
12061e2a13e6SJamie Gritton 	/* Don't allow a jailed process to see any jails, not even its own. */
12071e2a13e6SJamie Gritton 	if (jailed(td->td_ucred)) {
12081e2a13e6SJamie Gritton 		vfs_opterror(opts, "jail not found");
12091e2a13e6SJamie Gritton 		return (ENOENT);
12101e2a13e6SJamie Gritton 	}
12111e2a13e6SJamie Gritton 
1212b38ff370SJamie Gritton 	/*
1213b38ff370SJamie Gritton 	 * Find the prison specified by one of: lastjid, jid, name.
1214b38ff370SJamie Gritton 	 */
1215b38ff370SJamie Gritton 	sx_slock(&allprison_lock);
1216b38ff370SJamie Gritton 	error = vfs_copyopt(opts, "lastjid", &jid, sizeof(jid));
1217b38ff370SJamie Gritton 	if (error == 0) {
1218b38ff370SJamie Gritton 		TAILQ_FOREACH(pr, &allprison, pr_list) {
1219b38ff370SJamie Gritton 			if (pr->pr_id > jid) {
1220b38ff370SJamie Gritton 				mtx_lock(&pr->pr_mtx);
1221b38ff370SJamie Gritton 				if (pr->pr_ref > 0 &&
1222b38ff370SJamie Gritton 				    (pr->pr_uref > 0 || (flags & JAIL_DYING)))
1223b38ff370SJamie Gritton 					break;
1224b38ff370SJamie Gritton 				mtx_unlock(&pr->pr_mtx);
1225b38ff370SJamie Gritton 			}
1226b38ff370SJamie Gritton 		}
1227b38ff370SJamie Gritton 		if (pr != NULL)
1228b38ff370SJamie Gritton 			goto found_prison;
1229b38ff370SJamie Gritton 		error = ENOENT;
1230b38ff370SJamie Gritton 		vfs_opterror(opts, "no jail after %d", jid);
1231b38ff370SJamie Gritton 		goto done_unlock_list;
1232b38ff370SJamie Gritton 	} else if (error != ENOENT)
1233b38ff370SJamie Gritton 		goto done_unlock_list;
1234b38ff370SJamie Gritton 
1235b38ff370SJamie Gritton 	error = vfs_copyopt(opts, "jid", &jid, sizeof(jid));
1236b38ff370SJamie Gritton 	if (error == 0) {
1237b38ff370SJamie Gritton 		if (jid != 0) {
1238b38ff370SJamie Gritton 			pr = prison_find(jid);
1239b38ff370SJamie Gritton 			if (pr != NULL) {
1240b38ff370SJamie Gritton 				if (pr->pr_uref == 0 && !(flags & JAIL_DYING)) {
1241b38ff370SJamie Gritton 					mtx_unlock(&pr->pr_mtx);
1242b38ff370SJamie Gritton 					error = ENOENT;
1243b38ff370SJamie Gritton 					vfs_opterror(opts, "jail %d is dying",
1244b38ff370SJamie Gritton 					    jid);
1245b38ff370SJamie Gritton 					goto done_unlock_list;
1246b38ff370SJamie Gritton 				}
1247b38ff370SJamie Gritton 				goto found_prison;
1248b38ff370SJamie Gritton 			}
1249b38ff370SJamie Gritton 			error = ENOENT;
1250b38ff370SJamie Gritton 			vfs_opterror(opts, "jail %d not found", jid);
1251b38ff370SJamie Gritton 			goto done_unlock_list;
1252b38ff370SJamie Gritton 		}
1253b38ff370SJamie Gritton 	} else if (error != ENOENT)
1254b38ff370SJamie Gritton 		goto done_unlock_list;
1255b38ff370SJamie Gritton 
1256b38ff370SJamie Gritton 	error = vfs_getopt(opts, "name", (void **)&name, &len);
1257b38ff370SJamie Gritton 	if (error == 0) {
1258b38ff370SJamie Gritton 		if (len == 0 || name[len - 1] != '\0') {
1259b38ff370SJamie Gritton 			error = EINVAL;
1260b38ff370SJamie Gritton 			goto done_unlock_list;
1261b38ff370SJamie Gritton 		}
1262b38ff370SJamie Gritton 		pr = prison_find_name(name);
1263b38ff370SJamie Gritton 		if (pr != NULL) {
1264b38ff370SJamie Gritton 			if (pr->pr_uref == 0 && !(flags & JAIL_DYING)) {
1265b38ff370SJamie Gritton 				mtx_unlock(&pr->pr_mtx);
1266b38ff370SJamie Gritton 				error = ENOENT;
1267b38ff370SJamie Gritton 				vfs_opterror(opts, "jail \"%s\" is dying",
1268b38ff370SJamie Gritton 				    name);
1269b38ff370SJamie Gritton 				goto done_unlock_list;
1270b38ff370SJamie Gritton 			}
1271b38ff370SJamie Gritton 			goto found_prison;
1272b38ff370SJamie Gritton 		}
1273b38ff370SJamie Gritton 		error = ENOENT;
1274b38ff370SJamie Gritton 		vfs_opterror(opts, "jail \"%s\" not found", name);
1275b38ff370SJamie Gritton 		goto done_unlock_list;
1276b38ff370SJamie Gritton 	} else if (error != ENOENT)
1277b38ff370SJamie Gritton 		goto done_unlock_list;
1278b38ff370SJamie Gritton 
1279b38ff370SJamie Gritton 	vfs_opterror(opts, "no jail specified");
1280b38ff370SJamie Gritton 	error = ENOENT;
1281b38ff370SJamie Gritton 	goto done_unlock_list;
1282b38ff370SJamie Gritton 
1283b38ff370SJamie Gritton  found_prison:
1284b38ff370SJamie Gritton 	/* Get the parameters of the prison. */
1285b38ff370SJamie Gritton 	pr->pr_ref++;
1286b38ff370SJamie Gritton 	locked = PD_LOCKED;
1287b38ff370SJamie Gritton 	td->td_retval[0] = pr->pr_id;
1288b38ff370SJamie Gritton 	error = vfs_setopt(opts, "jid", &pr->pr_id, sizeof(pr->pr_id));
1289b38ff370SJamie Gritton 	if (error != 0 && error != ENOENT)
1290b38ff370SJamie Gritton 		goto done_deref;
1291b38ff370SJamie Gritton 	error = vfs_setopts(opts, "name", pr->pr_name);
1292b38ff370SJamie Gritton 	if (error != 0 && error != ENOENT)
1293b38ff370SJamie Gritton 		goto done_deref;
1294b38ff370SJamie Gritton 	error = vfs_setopt(opts, "cpuset", &pr->pr_cpuset->cs_id,
1295b38ff370SJamie Gritton 	    sizeof(pr->pr_cpuset->cs_id));
1296b38ff370SJamie Gritton 	if (error != 0 && error != ENOENT)
1297b38ff370SJamie Gritton 		goto done_deref;
1298b38ff370SJamie Gritton 	error = vfs_setopts(opts, "path", pr->pr_path);
1299b38ff370SJamie Gritton 	if (error != 0 && error != ENOENT)
1300b38ff370SJamie Gritton 		goto done_deref;
1301b38ff370SJamie Gritton #ifdef INET
1302b38ff370SJamie Gritton 	error = vfs_setopt_part(opts, "ip4.addr", pr->pr_ip4,
1303b38ff370SJamie Gritton 	    pr->pr_ip4s * sizeof(*pr->pr_ip4));
1304b38ff370SJamie Gritton 	if (error != 0 && error != ENOENT)
1305b38ff370SJamie Gritton 		goto done_deref;
1306b38ff370SJamie Gritton #endif
1307b38ff370SJamie Gritton #ifdef INET6
1308b38ff370SJamie Gritton 	error = vfs_setopt_part(opts, "ip6.addr", pr->pr_ip6,
1309b38ff370SJamie Gritton 	    pr->pr_ip6s * sizeof(*pr->pr_ip6));
1310b38ff370SJamie Gritton 	if (error != 0 && error != ENOENT)
1311b38ff370SJamie Gritton 		goto done_deref;
1312b38ff370SJamie Gritton #endif
1313b38ff370SJamie Gritton 	error = vfs_setopt(opts, "securelevel", &pr->pr_securelevel,
1314b38ff370SJamie Gritton 	    sizeof(pr->pr_securelevel));
1315b38ff370SJamie Gritton 	if (error != 0 && error != ENOENT)
1316b38ff370SJamie Gritton 		goto done_deref;
1317b38ff370SJamie Gritton 	error = vfs_setopts(opts, "host.hostname", pr->pr_host);
1318b38ff370SJamie Gritton 	if (error != 0 && error != ENOENT)
1319b38ff370SJamie Gritton 		goto done_deref;
1320b38ff370SJamie Gritton 	i = pr->pr_flags & PR_PERSIST ? 1 : 0;
1321b38ff370SJamie Gritton 	error = vfs_setopt(opts, "persist", &i, sizeof(i));
1322b38ff370SJamie Gritton 	if (error != 0 && error != ENOENT)
1323b38ff370SJamie Gritton 		goto done_deref;
1324b38ff370SJamie Gritton 	i = !i;
1325b38ff370SJamie Gritton 	error = vfs_setopt(opts, "nopersist", &i, sizeof(i));
1326b38ff370SJamie Gritton 	if (error != 0 && error != ENOENT)
1327b38ff370SJamie Gritton 		goto done_deref;
1328b38ff370SJamie Gritton 	i = (pr->pr_uref == 0);
1329b38ff370SJamie Gritton 	error = vfs_setopt(opts, "dying", &i, sizeof(i));
1330b38ff370SJamie Gritton 	if (error != 0 && error != ENOENT)
1331b38ff370SJamie Gritton 		goto done_deref;
1332b38ff370SJamie Gritton 	i = !i;
1333b38ff370SJamie Gritton 	error = vfs_setopt(opts, "nodying", &i, sizeof(i));
1334b38ff370SJamie Gritton 	if (error != 0 && error != ENOENT)
1335b38ff370SJamie Gritton 		goto done_deref;
1336b38ff370SJamie Gritton 
1337b38ff370SJamie Gritton 	/* Get the module parameters. */
1338b38ff370SJamie Gritton 	mtx_unlock(&pr->pr_mtx);
1339b38ff370SJamie Gritton 	locked = 0;
1340b38ff370SJamie Gritton 	error = osd_jail_call(pr, PR_METHOD_GET, opts);
1341b38ff370SJamie Gritton 	if (error)
1342b38ff370SJamie Gritton 		goto done_deref;
1343b38ff370SJamie Gritton 	prison_deref(pr, PD_DEREF | PD_LIST_SLOCKED);
1344b38ff370SJamie Gritton 
1345b38ff370SJamie Gritton 	/* By now, all parameters should have been noted. */
1346b38ff370SJamie Gritton 	TAILQ_FOREACH(opt, opts, link) {
1347b38ff370SJamie Gritton 		if (!opt->seen && strcmp(opt->name, "errmsg")) {
1348b38ff370SJamie Gritton 			error = EINVAL;
1349b38ff370SJamie Gritton 			vfs_opterror(opts, "unknown parameter: %s", opt->name);
1350b38ff370SJamie Gritton 			goto done_errmsg;
1351b38ff370SJamie Gritton 		}
1352b38ff370SJamie Gritton 	}
1353b38ff370SJamie Gritton 
1354b38ff370SJamie Gritton 	/* Write the fetched parameters back to userspace. */
1355b38ff370SJamie Gritton 	error = 0;
1356b38ff370SJamie Gritton 	TAILQ_FOREACH(opt, opts, link) {
1357b38ff370SJamie Gritton 		if (opt->pos >= 0 && opt->pos != errmsg_pos) {
1358b38ff370SJamie Gritton 			pos = 2 * opt->pos + 1;
1359b38ff370SJamie Gritton 			optuio->uio_iov[pos].iov_len = opt->len;
1360b38ff370SJamie Gritton 			if (opt->value != NULL) {
1361b38ff370SJamie Gritton 				if (optuio->uio_segflg == UIO_SYSSPACE) {
1362b38ff370SJamie Gritton 					bcopy(opt->value,
1363b38ff370SJamie Gritton 					    optuio->uio_iov[pos].iov_base,
1364b38ff370SJamie Gritton 					    opt->len);
1365b38ff370SJamie Gritton 				} else {
1366b38ff370SJamie Gritton 					error = copyout(opt->value,
1367b38ff370SJamie Gritton 					    optuio->uio_iov[pos].iov_base,
1368b38ff370SJamie Gritton 					    opt->len);
1369b38ff370SJamie Gritton 					if (error)
1370b38ff370SJamie Gritton 						break;
1371b38ff370SJamie Gritton 				}
1372b38ff370SJamie Gritton 			}
1373b38ff370SJamie Gritton 		}
1374b38ff370SJamie Gritton 	}
1375b38ff370SJamie Gritton 	goto done_errmsg;
1376b38ff370SJamie Gritton 
1377b38ff370SJamie Gritton  done_deref:
1378b38ff370SJamie Gritton 	prison_deref(pr, locked | PD_DEREF | PD_LIST_SLOCKED);
1379b38ff370SJamie Gritton 	goto done_errmsg;
1380b38ff370SJamie Gritton 
1381b38ff370SJamie Gritton  done_unlock_list:
1382b38ff370SJamie Gritton 	sx_sunlock(&allprison_lock);
1383b38ff370SJamie Gritton  done_errmsg:
1384b38ff370SJamie Gritton 	if (error && errmsg_pos >= 0) {
1385b38ff370SJamie Gritton 		vfs_getopt(opts, "errmsg", (void **)&errmsg, &errmsg_len);
1386b38ff370SJamie Gritton 		errmsg_pos = 2 * errmsg_pos + 1;
1387b38ff370SJamie Gritton 		if (errmsg_len > 0) {
1388b38ff370SJamie Gritton 			if (optuio->uio_segflg == UIO_SYSSPACE)
1389b38ff370SJamie Gritton 				bcopy(errmsg,
1390b38ff370SJamie Gritton 				    optuio->uio_iov[errmsg_pos].iov_base,
1391b38ff370SJamie Gritton 				    errmsg_len);
1392b38ff370SJamie Gritton 			else
1393b38ff370SJamie Gritton 				copyout(errmsg,
1394b38ff370SJamie Gritton 				    optuio->uio_iov[errmsg_pos].iov_base,
1395b38ff370SJamie Gritton 				    errmsg_len);
1396b38ff370SJamie Gritton 		}
1397b38ff370SJamie Gritton 	}
1398b38ff370SJamie Gritton 	vfs_freeopts(opts);
1399b38ff370SJamie Gritton 	return (error);
1400b38ff370SJamie Gritton }
1401b38ff370SJamie Gritton 
1402b38ff370SJamie Gritton /*
1403b38ff370SJamie Gritton  * struct jail_remove_args {
1404b38ff370SJamie Gritton  *	int jid;
1405b38ff370SJamie Gritton  * };
1406b38ff370SJamie Gritton  */
1407b38ff370SJamie Gritton int
1408b38ff370SJamie Gritton jail_remove(struct thread *td, struct jail_remove_args *uap)
1409b38ff370SJamie Gritton {
1410b38ff370SJamie Gritton 	struct prison *pr;
1411b38ff370SJamie Gritton 	struct proc *p;
1412b38ff370SJamie Gritton 	int deuref, error;
1413b38ff370SJamie Gritton 
1414b38ff370SJamie Gritton 	error = priv_check(td, PRIV_JAIL_REMOVE);
1415b38ff370SJamie Gritton 	if (error)
1416b38ff370SJamie Gritton 		return (error);
1417b38ff370SJamie Gritton 
1418b38ff370SJamie Gritton 	sx_xlock(&allprison_lock);
1419b38ff370SJamie Gritton 	pr = prison_find(uap->jid);
1420b38ff370SJamie Gritton 	if (pr == NULL) {
1421b38ff370SJamie Gritton 		sx_xunlock(&allprison_lock);
1422b38ff370SJamie Gritton 		return (EINVAL);
1423b38ff370SJamie Gritton 	}
1424b38ff370SJamie Gritton 
1425b38ff370SJamie Gritton 	/* If the prison was persistent, it is not anymore. */
1426b38ff370SJamie Gritton 	deuref = 0;
1427b38ff370SJamie Gritton 	if (pr->pr_flags & PR_PERSIST) {
1428b38ff370SJamie Gritton 		pr->pr_ref--;
1429b38ff370SJamie Gritton 		deuref = PD_DEUREF;
1430b38ff370SJamie Gritton 		pr->pr_flags &= ~PR_PERSIST;
1431b38ff370SJamie Gritton 	}
1432b38ff370SJamie Gritton 
1433b38ff370SJamie Gritton 	/* If there are no references left, remove the prison now. */
1434b38ff370SJamie Gritton 	if (pr->pr_ref == 0) {
1435b38ff370SJamie Gritton 		prison_deref(pr,
1436b38ff370SJamie Gritton 		    deuref | PD_DEREF | PD_LOCKED | PD_LIST_XLOCKED);
1437b38ff370SJamie Gritton 		return (0);
1438b38ff370SJamie Gritton 	}
1439b38ff370SJamie Gritton 
1440b38ff370SJamie Gritton 	/*
1441b38ff370SJamie Gritton 	 * Keep a temporary reference to make sure this prison sticks around.
1442b38ff370SJamie Gritton 	 */
1443b38ff370SJamie Gritton 	pr->pr_ref++;
1444b38ff370SJamie Gritton 	mtx_unlock(&pr->pr_mtx);
1445b38ff370SJamie Gritton 	sx_xunlock(&allprison_lock);
1446b38ff370SJamie Gritton 	/*
1447b38ff370SJamie Gritton 	 * Kill all processes unfortunate enough to be attached to this prison.
1448b38ff370SJamie Gritton 	 */
1449b38ff370SJamie Gritton 	sx_slock(&allproc_lock);
1450b38ff370SJamie Gritton 	LIST_FOREACH(p, &allproc, p_list) {
1451b38ff370SJamie Gritton 		PROC_LOCK(p);
1452b38ff370SJamie Gritton 		if (p->p_state != PRS_NEW && p->p_ucred &&
1453b38ff370SJamie Gritton 		    p->p_ucred->cr_prison == pr)
1454b38ff370SJamie Gritton 			psignal(p, SIGKILL);
1455b38ff370SJamie Gritton 		PROC_UNLOCK(p);
1456b38ff370SJamie Gritton 	}
1457b38ff370SJamie Gritton 	sx_sunlock(&allproc_lock);
1458b38ff370SJamie Gritton 	/* Remove the temporary reference. */
1459b38ff370SJamie Gritton 	prison_deref(pr, deuref | PD_DEREF);
1460b38ff370SJamie Gritton 	return (0);
146175c13541SPoul-Henning Kamp }
146275c13541SPoul-Henning Kamp 
14638571af59SJamie Gritton 
1464fd7a8150SMike Barcroft /*
14659ddb7954SMike Barcroft  * struct jail_attach_args {
14669ddb7954SMike Barcroft  *	int jid;
14679ddb7954SMike Barcroft  * };
1468fd7a8150SMike Barcroft  */
1469fd7a8150SMike Barcroft int
14709ddb7954SMike Barcroft jail_attach(struct thread *td, struct jail_attach_args *uap)
1471fd7a8150SMike Barcroft {
1472b38ff370SJamie Gritton 	struct prison *pr;
1473b38ff370SJamie Gritton 	int error;
1474b38ff370SJamie Gritton 
1475b38ff370SJamie Gritton 	error = priv_check(td, PRIV_JAIL_ATTACH);
1476b38ff370SJamie Gritton 	if (error)
1477b38ff370SJamie Gritton 		return (error);
1478b38ff370SJamie Gritton 
1479b38ff370SJamie Gritton 	sx_slock(&allprison_lock);
1480b38ff370SJamie Gritton 	pr = prison_find(uap->jid);
1481b38ff370SJamie Gritton 	if (pr == NULL) {
1482b38ff370SJamie Gritton 		sx_sunlock(&allprison_lock);
1483b38ff370SJamie Gritton 		return (EINVAL);
1484b38ff370SJamie Gritton 	}
1485b38ff370SJamie Gritton 
1486b38ff370SJamie Gritton 	/*
1487b38ff370SJamie Gritton 	 * Do not allow a process to attach to a prison that is not
1488b38ff370SJamie Gritton 	 * considered to be "alive".
1489b38ff370SJamie Gritton 	 */
1490b38ff370SJamie Gritton 	if (pr->pr_uref == 0) {
1491b38ff370SJamie Gritton 		mtx_unlock(&pr->pr_mtx);
1492b38ff370SJamie Gritton 		sx_sunlock(&allprison_lock);
1493b38ff370SJamie Gritton 		return (EINVAL);
1494b38ff370SJamie Gritton 	}
1495b38ff370SJamie Gritton 
1496b38ff370SJamie Gritton 	return (do_jail_attach(td, pr));
1497b38ff370SJamie Gritton }
1498b38ff370SJamie Gritton 
1499b38ff370SJamie Gritton static int
1500b38ff370SJamie Gritton do_jail_attach(struct thread *td, struct prison *pr)
1501b38ff370SJamie Gritton {
1502fd7a8150SMike Barcroft 	struct proc *p;
1503fd7a8150SMike Barcroft 	struct ucred *newcred, *oldcred;
1504453f7d53SChristian S.J. Peron 	int vfslocked, error;
1505fd7a8150SMike Barcroft 
150657f22bd4SJacques Vidrine 	/*
150757f22bd4SJacques Vidrine 	 * XXX: Note that there is a slight race here if two threads
150857f22bd4SJacques Vidrine 	 * in the same privileged process attempt to attach to two
150957f22bd4SJacques Vidrine 	 * different jails at the same time.  It is important for
151057f22bd4SJacques Vidrine 	 * user processes not to do this, or they might end up with
151157f22bd4SJacques Vidrine 	 * a process root from one prison, but attached to the jail
151257f22bd4SJacques Vidrine 	 * of another.
151357f22bd4SJacques Vidrine 	 */
1514fd7a8150SMike Barcroft 	pr->pr_ref++;
1515b38ff370SJamie Gritton 	pr->pr_uref++;
1516fd7a8150SMike Barcroft 	mtx_unlock(&pr->pr_mtx);
1517b38ff370SJamie Gritton 
1518b38ff370SJamie Gritton 	/* Let modules do whatever they need to prepare for attaching. */
1519b38ff370SJamie Gritton 	error = osd_jail_call(pr, PR_METHOD_ATTACH, td);
1520b38ff370SJamie Gritton 	if (error) {
1521b38ff370SJamie Gritton 		prison_deref(pr, PD_DEREF | PD_DEUREF | PD_LIST_SLOCKED);
1522b38ff370SJamie Gritton 		return (error);
1523b38ff370SJamie Gritton 	}
1524dc68a633SPawel Jakub Dawidek 	sx_sunlock(&allprison_lock);
1525fd7a8150SMike Barcroft 
1526413628a7SBjoern A. Zeeb 	/*
1527413628a7SBjoern A. Zeeb 	 * Reparent the newly attached process to this jail.
1528413628a7SBjoern A. Zeeb 	 */
1529b38ff370SJamie Gritton 	p = td->td_proc;
1530413628a7SBjoern A. Zeeb 	error = cpuset_setproc_update_set(p, pr->pr_cpuset);
1531413628a7SBjoern A. Zeeb 	if (error)
1532b38ff370SJamie Gritton 		goto e_revert_osd;
1533413628a7SBjoern A. Zeeb 
1534453f7d53SChristian S.J. Peron 	vfslocked = VFS_LOCK_GIANT(pr->pr_root->v_mount);
1535cb05b60aSAttilio Rao 	vn_lock(pr->pr_root, LK_EXCLUSIVE | LK_RETRY);
1536fd7a8150SMike Barcroft 	if ((error = change_dir(pr->pr_root, td)) != 0)
1537fd7a8150SMike Barcroft 		goto e_unlock;
1538fd7a8150SMike Barcroft #ifdef MAC
153930d239bcSRobert Watson 	if ((error = mac_vnode_check_chroot(td->td_ucred, pr->pr_root)))
1540fd7a8150SMike Barcroft 		goto e_unlock;
1541fd7a8150SMike Barcroft #endif
154222db15c0SAttilio Rao 	VOP_UNLOCK(pr->pr_root, 0);
1543b38ff370SJamie Gritton 	if ((error = change_root(pr->pr_root, td)))
1544b38ff370SJamie Gritton 		goto e_unlock_giant;
1545453f7d53SChristian S.J. Peron 	VFS_UNLOCK_GIANT(vfslocked);
1546fd7a8150SMike Barcroft 
1547fd7a8150SMike Barcroft 	newcred = crget();
1548fd7a8150SMike Barcroft 	PROC_LOCK(p);
1549fd7a8150SMike Barcroft 	oldcred = p->p_ucred;
1550fd7a8150SMike Barcroft 	setsugid(p);
1551fd7a8150SMike Barcroft 	crcopy(newcred, oldcred);
155269c4ee54SJohn Baldwin 	newcred->cr_prison = pr;
1553fd7a8150SMike Barcroft 	p->p_ucred = newcred;
1554fd7a8150SMike Barcroft 	PROC_UNLOCK(p);
1555fd7a8150SMike Barcroft 	crfree(oldcred);
1556fd7a8150SMike Barcroft 	return (0);
1557fd7a8150SMike Barcroft  e_unlock:
155822db15c0SAttilio Rao 	VOP_UNLOCK(pr->pr_root, 0);
1559b38ff370SJamie Gritton  e_unlock_giant:
1560453f7d53SChristian S.J. Peron 	VFS_UNLOCK_GIANT(vfslocked);
1561b38ff370SJamie Gritton  e_revert_osd:
1562b38ff370SJamie Gritton 	/* Tell modules this thread is still in its old jail after all. */
1563b38ff370SJamie Gritton 	(void)osd_jail_call(td->td_ucred->cr_prison, PR_METHOD_ATTACH, td);
1564b38ff370SJamie Gritton 	prison_deref(pr, PD_DEREF | PD_DEUREF);
1565fd7a8150SMike Barcroft 	return (error);
1566fd7a8150SMike Barcroft }
1567fd7a8150SMike Barcroft 
1568fd7a8150SMike Barcroft /*
1569fd7a8150SMike Barcroft  * Returns a locked prison instance, or NULL on failure.
1570fd7a8150SMike Barcroft  */
157154b369c1SPawel Jakub Dawidek struct prison *
1572fd7a8150SMike Barcroft prison_find(int prid)
1573fd7a8150SMike Barcroft {
1574fd7a8150SMike Barcroft 	struct prison *pr;
1575fd7a8150SMike Barcroft 
1576dc68a633SPawel Jakub Dawidek 	sx_assert(&allprison_lock, SX_LOCKED);
1577b38ff370SJamie Gritton 	TAILQ_FOREACH(pr, &allprison, pr_list) {
1578fd7a8150SMike Barcroft 		if (pr->pr_id == prid) {
1579fd7a8150SMike Barcroft 			mtx_lock(&pr->pr_mtx);
1580b38ff370SJamie Gritton 			if (pr->pr_ref > 0)
1581fd7a8150SMike Barcroft 				return (pr);
1582b38ff370SJamie Gritton 			mtx_unlock(&pr->pr_mtx);
1583fd7a8150SMike Barcroft 		}
1584fd7a8150SMike Barcroft 	}
1585fd7a8150SMike Barcroft 	return (NULL);
1586fd7a8150SMike Barcroft }
1587fd7a8150SMike Barcroft 
1588b38ff370SJamie Gritton /*
1589b38ff370SJamie Gritton  * Look for the named prison.  Returns a locked prison or NULL.
1590b38ff370SJamie Gritton  */
1591b38ff370SJamie Gritton struct prison *
1592b38ff370SJamie Gritton prison_find_name(const char *name)
1593b38ff370SJamie Gritton {
1594b38ff370SJamie Gritton 	struct prison *pr, *deadpr;
1595b38ff370SJamie Gritton 
1596b38ff370SJamie Gritton 	sx_assert(&allprison_lock, SX_LOCKED);
1597b38ff370SJamie Gritton  again:
1598b38ff370SJamie Gritton 	deadpr = NULL;
1599b38ff370SJamie Gritton 	TAILQ_FOREACH(pr, &allprison, pr_list) {
1600b38ff370SJamie Gritton 		if (!strcmp(pr->pr_name, name)) {
1601b38ff370SJamie Gritton 			mtx_lock(&pr->pr_mtx);
1602b38ff370SJamie Gritton 			if (pr->pr_ref > 0) {
1603b38ff370SJamie Gritton 				if (pr->pr_uref > 0)
1604b38ff370SJamie Gritton 					return (pr);
1605b38ff370SJamie Gritton 				deadpr = pr;
1606b38ff370SJamie Gritton 			}
1607b38ff370SJamie Gritton 			mtx_unlock(&pr->pr_mtx);
1608b38ff370SJamie Gritton 		}
1609b38ff370SJamie Gritton 	}
1610b38ff370SJamie Gritton 	/* There was no valid prison - perhaps there was a dying one */
1611b38ff370SJamie Gritton 	if (deadpr != NULL) {
1612b38ff370SJamie Gritton 		mtx_lock(&deadpr->pr_mtx);
1613b38ff370SJamie Gritton 		if (deadpr->pr_ref == 0) {
1614b38ff370SJamie Gritton 			mtx_unlock(&deadpr->pr_mtx);
1615b38ff370SJamie Gritton 			goto again;
1616b38ff370SJamie Gritton 		}
1617b38ff370SJamie Gritton 	}
1618b38ff370SJamie Gritton 	return (deadpr);
1619b38ff370SJamie Gritton }
1620b38ff370SJamie Gritton 
1621b38ff370SJamie Gritton /*
1622b38ff370SJamie Gritton  * Remove a prison reference.  If that was the last reference, remove the
1623b38ff370SJamie Gritton  * prison itself - but not in this context in case there are locks held.
1624b38ff370SJamie Gritton  */
162591421ba2SRobert Watson void
16261ba4a712SPawel Jakub Dawidek prison_free_locked(struct prison *pr)
162791421ba2SRobert Watson {
162891421ba2SRobert Watson 
16291ba4a712SPawel Jakub Dawidek 	mtx_assert(&pr->pr_mtx, MA_OWNED);
163091421ba2SRobert Watson 	pr->pr_ref--;
163191421ba2SRobert Watson 	if (pr->pr_ref == 0) {
163201137630SRobert Watson 		mtx_unlock(&pr->pr_mtx);
1633c2cda609SPawel Jakub Dawidek 		TASK_INIT(&pr->pr_task, 0, prison_complete, pr);
1634c2cda609SPawel Jakub Dawidek 		taskqueue_enqueue(taskqueue_thread, &pr->pr_task);
1635c2cda609SPawel Jakub Dawidek 		return;
1636c2cda609SPawel Jakub Dawidek 	}
1637c2cda609SPawel Jakub Dawidek 	mtx_unlock(&pr->pr_mtx);
1638c2cda609SPawel Jakub Dawidek }
1639c2cda609SPawel Jakub Dawidek 
16401ba4a712SPawel Jakub Dawidek void
16411ba4a712SPawel Jakub Dawidek prison_free(struct prison *pr)
16421ba4a712SPawel Jakub Dawidek {
16431ba4a712SPawel Jakub Dawidek 
16441ba4a712SPawel Jakub Dawidek 	mtx_lock(&pr->pr_mtx);
16451ba4a712SPawel Jakub Dawidek 	prison_free_locked(pr);
16461ba4a712SPawel Jakub Dawidek }
16471ba4a712SPawel Jakub Dawidek 
1648c2cda609SPawel Jakub Dawidek static void
1649c2cda609SPawel Jakub Dawidek prison_complete(void *context, int pending)
1650c2cda609SPawel Jakub Dawidek {
1651b38ff370SJamie Gritton 
1652b38ff370SJamie Gritton 	prison_deref((struct prison *)context, 0);
1653b38ff370SJamie Gritton }
1654b38ff370SJamie Gritton 
1655b38ff370SJamie Gritton /*
1656b38ff370SJamie Gritton  * Remove a prison reference (usually).  This internal version assumes no
1657b38ff370SJamie Gritton  * mutexes are held, except perhaps the prison itself.  If there are no more
1658b38ff370SJamie Gritton  * references, release and delist the prison.  On completion, the prison lock
1659b38ff370SJamie Gritton  * and the allprison lock are both unlocked.
1660b38ff370SJamie Gritton  */
1661b38ff370SJamie Gritton static void
1662b38ff370SJamie Gritton prison_deref(struct prison *pr, int flags)
1663b38ff370SJamie Gritton {
1664c2cda609SPawel Jakub Dawidek 	int vfslocked;
1665c2cda609SPawel Jakub Dawidek 
1666b38ff370SJamie Gritton 	if (!(flags & PD_LOCKED))
1667b38ff370SJamie Gritton 		mtx_lock(&pr->pr_mtx);
1668b38ff370SJamie Gritton 	if (flags & PD_DEUREF) {
1669b38ff370SJamie Gritton 		pr->pr_uref--;
1670b38ff370SJamie Gritton 		/* Done if there were only user references to remove. */
1671b38ff370SJamie Gritton 		if (!(flags & PD_DEREF)) {
1672b38ff370SJamie Gritton 			mtx_unlock(&pr->pr_mtx);
1673b38ff370SJamie Gritton 			if (flags & PD_LIST_SLOCKED)
1674b38ff370SJamie Gritton 				sx_sunlock(&allprison_lock);
1675b38ff370SJamie Gritton 			else if (flags & PD_LIST_XLOCKED)
1676b38ff370SJamie Gritton 				sx_xunlock(&allprison_lock);
1677b38ff370SJamie Gritton 			return;
1678b38ff370SJamie Gritton 		}
1679b38ff370SJamie Gritton 	}
1680b38ff370SJamie Gritton 	if (flags & PD_DEREF)
1681b38ff370SJamie Gritton 		pr->pr_ref--;
1682b38ff370SJamie Gritton 	/* If the prison still has references, nothing else to do. */
1683b38ff370SJamie Gritton 	if (pr->pr_ref > 0) {
1684b38ff370SJamie Gritton 		mtx_unlock(&pr->pr_mtx);
1685b38ff370SJamie Gritton 		if (flags & PD_LIST_SLOCKED)
1686b38ff370SJamie Gritton 			sx_sunlock(&allprison_lock);
1687b38ff370SJamie Gritton 		else if (flags & PD_LIST_XLOCKED)
1688b38ff370SJamie Gritton 			sx_xunlock(&allprison_lock);
1689b38ff370SJamie Gritton 		return;
1690b38ff370SJamie Gritton 	}
1691c2cda609SPawel Jakub Dawidek 
1692b38ff370SJamie Gritton 	KASSERT(pr->pr_uref == 0,
1693b38ff370SJamie Gritton 	    ("%s: Trying to remove an active prison (jid=%d).", __func__,
1694b38ff370SJamie Gritton 	    pr->pr_id));
1695b38ff370SJamie Gritton 	mtx_unlock(&pr->pr_mtx);
1696b38ff370SJamie Gritton 	if (flags & PD_LIST_SLOCKED) {
1697b38ff370SJamie Gritton 		if (!sx_try_upgrade(&allprison_lock)) {
1698b38ff370SJamie Gritton 			sx_sunlock(&allprison_lock);
1699c2cda609SPawel Jakub Dawidek 			sx_xlock(&allprison_lock);
1700b38ff370SJamie Gritton 		}
1701b38ff370SJamie Gritton 	} else if (!(flags & PD_LIST_XLOCKED))
1702b38ff370SJamie Gritton 		sx_xlock(&allprison_lock);
1703b38ff370SJamie Gritton 
1704b38ff370SJamie Gritton 	TAILQ_REMOVE(&allprison, pr, pr_list);
1705fd7a8150SMike Barcroft 	prisoncount--;
17061ba4a712SPawel Jakub Dawidek 	sx_xunlock(&allprison_lock);
17071ba4a712SPawel Jakub Dawidek 
1708b38ff370SJamie Gritton 	if (pr->pr_root != NULL) {
1709453f7d53SChristian S.J. Peron 		vfslocked = VFS_LOCK_GIANT(pr->pr_root->v_mount);
1710b3059e09SRobert Watson 		vrele(pr->pr_root);
1711453f7d53SChristian S.J. Peron 		VFS_UNLOCK_GIANT(vfslocked);
1712b38ff370SJamie Gritton 	}
1713b3059e09SRobert Watson 	mtx_destroy(&pr->pr_mtx);
1714413628a7SBjoern A. Zeeb #ifdef INET
1715413628a7SBjoern A. Zeeb 	free(pr->pr_ip4, M_PRISON);
1716413628a7SBjoern A. Zeeb #endif
1717b38ff370SJamie Gritton #ifdef INET6
1718b38ff370SJamie Gritton 	free(pr->pr_ip6, M_PRISON);
1719b38ff370SJamie Gritton #endif
1720b38ff370SJamie Gritton 	if (pr->pr_cpuset != NULL)
1721b38ff370SJamie Gritton 		cpuset_rel(pr->pr_cpuset);
1722b38ff370SJamie Gritton 	osd_jail_exit(pr);
17231ede983cSDag-Erling Smørgrav 	free(pr, M_PRISON);
1724b3059e09SRobert Watson }
1725b3059e09SRobert Watson 
172691421ba2SRobert Watson void
17271ba4a712SPawel Jakub Dawidek prison_hold_locked(struct prison *pr)
17281ba4a712SPawel Jakub Dawidek {
17291ba4a712SPawel Jakub Dawidek 
17301ba4a712SPawel Jakub Dawidek 	mtx_assert(&pr->pr_mtx, MA_OWNED);
17311ba4a712SPawel Jakub Dawidek 	KASSERT(pr->pr_ref > 0,
1732af7bd9a4SJamie Gritton 	    ("Trying to hold dead prison (jid=%d).", pr->pr_id));
17331ba4a712SPawel Jakub Dawidek 	pr->pr_ref++;
17341ba4a712SPawel Jakub Dawidek }
17351ba4a712SPawel Jakub Dawidek 
17361ba4a712SPawel Jakub Dawidek void
173791421ba2SRobert Watson prison_hold(struct prison *pr)
173891421ba2SRobert Watson {
173991421ba2SRobert Watson 
174001137630SRobert Watson 	mtx_lock(&pr->pr_mtx);
17411ba4a712SPawel Jakub Dawidek 	prison_hold_locked(pr);
174201137630SRobert Watson 	mtx_unlock(&pr->pr_mtx);
174301137630SRobert Watson }
174401137630SRobert Watson 
1745413628a7SBjoern A. Zeeb void
1746413628a7SBjoern A. Zeeb prison_proc_hold(struct prison *pr)
174701137630SRobert Watson {
174801137630SRobert Watson 
1749413628a7SBjoern A. Zeeb 	mtx_lock(&pr->pr_mtx);
1750b38ff370SJamie Gritton 	KASSERT(pr->pr_uref > 0,
1751b38ff370SJamie Gritton 	    ("Cannot add a process to a non-alive prison (jid=%d)", pr->pr_id));
1752b38ff370SJamie Gritton 	pr->pr_uref++;
1753413628a7SBjoern A. Zeeb 	mtx_unlock(&pr->pr_mtx);
175475c13541SPoul-Henning Kamp }
175575c13541SPoul-Henning Kamp 
175675c13541SPoul-Henning Kamp void
1757413628a7SBjoern A. Zeeb prison_proc_free(struct prison *pr)
175875c13541SPoul-Henning Kamp {
1759413628a7SBjoern A. Zeeb 
1760413628a7SBjoern A. Zeeb 	mtx_lock(&pr->pr_mtx);
1761b38ff370SJamie Gritton 	KASSERT(pr->pr_uref > 0,
1762b38ff370SJamie Gritton 	    ("Trying to kill a process in a dead prison (jid=%d)", pr->pr_id));
1763b38ff370SJamie Gritton 	prison_deref(pr, PD_DEUREF | PD_LOCKED);
1764413628a7SBjoern A. Zeeb }
1765413628a7SBjoern A. Zeeb 
1766413628a7SBjoern A. Zeeb 
1767413628a7SBjoern A. Zeeb #ifdef INET
1768413628a7SBjoern A. Zeeb /*
1769413628a7SBjoern A. Zeeb  * Pass back primary IPv4 address of this jail.
1770413628a7SBjoern A. Zeeb  *
1771413628a7SBjoern A. Zeeb  * If not jailed return success but do not alter the address.  Caller has to
17728571af59SJamie Gritton  * make sure to initialize it correctly (e.g. INADDR_ANY).
1773413628a7SBjoern A. Zeeb  *
1774b89e82ddSJamie Gritton  * Returns 0 on success, EAFNOSUPPORT if the jail doesn't allow IPv4.
1775b89e82ddSJamie Gritton  * Address returned in NBO.
1776413628a7SBjoern A. Zeeb  */
1777413628a7SBjoern A. Zeeb int
17781cecba0fSBjoern A. Zeeb prison_get_ip4(struct ucred *cred, struct in_addr *ia)
1779413628a7SBjoern A. Zeeb {
1780b38ff370SJamie Gritton 	struct prison *pr;
1781413628a7SBjoern A. Zeeb 
1782413628a7SBjoern A. Zeeb 	KASSERT(cred != NULL, ("%s: cred is NULL", __func__));
1783413628a7SBjoern A. Zeeb 	KASSERT(ia != NULL, ("%s: ia is NULL", __func__));
178475c13541SPoul-Henning Kamp 
178591421ba2SRobert Watson 	if (!jailed(cred))
1786413628a7SBjoern A. Zeeb 		return (0);
1787b38ff370SJamie Gritton 	pr = cred->cr_prison;
1788b38ff370SJamie Gritton 	mtx_lock(&pr->pr_mtx);
1789b38ff370SJamie Gritton 	if (pr->pr_ip4 == NULL) {
1790b38ff370SJamie Gritton 		mtx_unlock(&pr->pr_mtx);
1791b89e82ddSJamie Gritton 		return (EAFNOSUPPORT);
1792b38ff370SJamie Gritton 	}
1793413628a7SBjoern A. Zeeb 
1794b38ff370SJamie Gritton 	ia->s_addr = pr->pr_ip4[0].s_addr;
1795b38ff370SJamie Gritton 	mtx_unlock(&pr->pr_mtx);
1796413628a7SBjoern A. Zeeb 	return (0);
179775c13541SPoul-Henning Kamp }
1798413628a7SBjoern A. Zeeb 
1799413628a7SBjoern A. Zeeb /*
1800413628a7SBjoern A. Zeeb  * Make sure our (source) address is set to something meaningful to this
1801413628a7SBjoern A. Zeeb  * jail.
1802413628a7SBjoern A. Zeeb  *
1803b89e82ddSJamie Gritton  * Returns 0 if not jailed or if address belongs to jail, EADDRNOTAVAIL if
1804b89e82ddSJamie Gritton  * the address doesn't belong, or EAFNOSUPPORT if the jail doesn't allow IPv4.
1805b89e82ddSJamie Gritton  * Address passed in in NBO and returned in NBO.
1806413628a7SBjoern A. Zeeb  */
1807413628a7SBjoern A. Zeeb int
1808413628a7SBjoern A. Zeeb prison_local_ip4(struct ucred *cred, struct in_addr *ia)
1809413628a7SBjoern A. Zeeb {
1810b38ff370SJamie Gritton 	struct prison *pr;
1811413628a7SBjoern A. Zeeb 	struct in_addr ia0;
1812b38ff370SJamie Gritton 	int error;
1813413628a7SBjoern A. Zeeb 
1814413628a7SBjoern A. Zeeb 	KASSERT(cred != NULL, ("%s: cred is NULL", __func__));
1815413628a7SBjoern A. Zeeb 	KASSERT(ia != NULL, ("%s: ia is NULL", __func__));
1816413628a7SBjoern A. Zeeb 
1817413628a7SBjoern A. Zeeb 	if (!jailed(cred))
1818413628a7SBjoern A. Zeeb 		return (0);
1819b38ff370SJamie Gritton 	pr = cred->cr_prison;
1820b38ff370SJamie Gritton 	mtx_lock(&pr->pr_mtx);
1821b38ff370SJamie Gritton 	if (pr->pr_ip4 == NULL) {
1822b38ff370SJamie Gritton 		mtx_unlock(&pr->pr_mtx);
1823b89e82ddSJamie Gritton 		return (EAFNOSUPPORT);
1824b38ff370SJamie Gritton 	}
1825413628a7SBjoern A. Zeeb 
1826413628a7SBjoern A. Zeeb 	ia0.s_addr = ntohl(ia->s_addr);
1827413628a7SBjoern A. Zeeb 	if (ia0.s_addr == INADDR_LOOPBACK) {
1828b38ff370SJamie Gritton 		ia->s_addr = pr->pr_ip4[0].s_addr;
1829b38ff370SJamie Gritton 		mtx_unlock(&pr->pr_mtx);
1830413628a7SBjoern A. Zeeb 		return (0);
1831413628a7SBjoern A. Zeeb 	}
1832413628a7SBjoern A. Zeeb 
1833b89e82ddSJamie Gritton 	if (ia0.s_addr == INADDR_ANY) {
1834413628a7SBjoern A. Zeeb 		/*
1835413628a7SBjoern A. Zeeb 		 * In case there is only 1 IPv4 address, bind directly.
1836413628a7SBjoern A. Zeeb 		 */
1837b38ff370SJamie Gritton 		if (pr->pr_ip4s == 1)
1838b38ff370SJamie Gritton 			ia->s_addr = pr->pr_ip4[0].s_addr;
1839b38ff370SJamie Gritton 		mtx_unlock(&pr->pr_mtx);
1840413628a7SBjoern A. Zeeb 		return (0);
1841413628a7SBjoern A. Zeeb 	}
1842413628a7SBjoern A. Zeeb 
1843b38ff370SJamie Gritton 	error = _prison_check_ip4(pr, ia);
1844b38ff370SJamie Gritton 	mtx_unlock(&pr->pr_mtx);
1845b38ff370SJamie Gritton 	return (error);
1846413628a7SBjoern A. Zeeb }
1847413628a7SBjoern A. Zeeb 
1848413628a7SBjoern A. Zeeb /*
1849413628a7SBjoern A. Zeeb  * Rewrite destination address in case we will connect to loopback address.
1850413628a7SBjoern A. Zeeb  *
1851b89e82ddSJamie Gritton  * Returns 0 on success, EAFNOSUPPORT if the jail doesn't allow IPv4.
1852b89e82ddSJamie Gritton  * Address passed in in NBO and returned in NBO.
1853413628a7SBjoern A. Zeeb  */
1854413628a7SBjoern A. Zeeb int
1855413628a7SBjoern A. Zeeb prison_remote_ip4(struct ucred *cred, struct in_addr *ia)
1856413628a7SBjoern A. Zeeb {
1857b38ff370SJamie Gritton 	struct prison *pr;
1858413628a7SBjoern A. Zeeb 
1859413628a7SBjoern A. Zeeb 	KASSERT(cred != NULL, ("%s: cred is NULL", __func__));
1860413628a7SBjoern A. Zeeb 	KASSERT(ia != NULL, ("%s: ia is NULL", __func__));
1861413628a7SBjoern A. Zeeb 
1862413628a7SBjoern A. Zeeb 	if (!jailed(cred))
1863413628a7SBjoern A. Zeeb 		return (0);
1864b38ff370SJamie Gritton 	pr = cred->cr_prison;
1865b38ff370SJamie Gritton 	mtx_lock(&pr->pr_mtx);
1866b38ff370SJamie Gritton 	if (pr->pr_ip4 == NULL) {
1867b38ff370SJamie Gritton 		mtx_unlock(&pr->pr_mtx);
1868b89e82ddSJamie Gritton 		return (EAFNOSUPPORT);
1869b38ff370SJamie Gritton 	}
1870b89e82ddSJamie Gritton 
1871413628a7SBjoern A. Zeeb 	if (ntohl(ia->s_addr) == INADDR_LOOPBACK) {
1872b38ff370SJamie Gritton 		ia->s_addr = pr->pr_ip4[0].s_addr;
1873b38ff370SJamie Gritton 		mtx_unlock(&pr->pr_mtx);
1874413628a7SBjoern A. Zeeb 		return (0);
1875413628a7SBjoern A. Zeeb 	}
1876413628a7SBjoern A. Zeeb 
1877413628a7SBjoern A. Zeeb 	/*
1878413628a7SBjoern A. Zeeb 	 * Return success because nothing had to be changed.
1879413628a7SBjoern A. Zeeb 	 */
1880b38ff370SJamie Gritton 	mtx_unlock(&pr->pr_mtx);
1881413628a7SBjoern A. Zeeb 	return (0);
1882413628a7SBjoern A. Zeeb }
1883413628a7SBjoern A. Zeeb 
1884413628a7SBjoern A. Zeeb /*
1885b89e82ddSJamie Gritton  * Check if given address belongs to the jail referenced by cred/prison.
1886413628a7SBjoern A. Zeeb  *
1887b89e82ddSJamie Gritton  * Returns 0 if not jailed or if address belongs to jail, EADDRNOTAVAIL if
1888b89e82ddSJamie Gritton  * the address doesn't belong, or EAFNOSUPPORT if the jail doesn't allow IPv4.
1889b89e82ddSJamie Gritton  * Address passed in in NBO.
1890413628a7SBjoern A. Zeeb  */
1891413628a7SBjoern A. Zeeb static int
1892413628a7SBjoern A. Zeeb _prison_check_ip4(struct prison *pr, struct in_addr *ia)
1893413628a7SBjoern A. Zeeb {
1894413628a7SBjoern A. Zeeb 	int i, a, z, d;
1895413628a7SBjoern A. Zeeb 
1896413628a7SBjoern A. Zeeb 	/*
1897413628a7SBjoern A. Zeeb 	 * Check the primary IP.
1898413628a7SBjoern A. Zeeb 	 */
1899413628a7SBjoern A. Zeeb 	if (pr->pr_ip4[0].s_addr == ia->s_addr)
1900b89e82ddSJamie Gritton 		return (0);
1901413628a7SBjoern A. Zeeb 
1902413628a7SBjoern A. Zeeb 	/*
1903413628a7SBjoern A. Zeeb 	 * All the other IPs are sorted so we can do a binary search.
1904413628a7SBjoern A. Zeeb 	 */
1905413628a7SBjoern A. Zeeb 	a = 0;
1906413628a7SBjoern A. Zeeb 	z = pr->pr_ip4s - 2;
1907413628a7SBjoern A. Zeeb 	while (a <= z) {
1908413628a7SBjoern A. Zeeb 		i = (a + z) / 2;
1909413628a7SBjoern A. Zeeb 		d = qcmp_v4(&pr->pr_ip4[i+1], ia);
1910413628a7SBjoern A. Zeeb 		if (d > 0)
1911413628a7SBjoern A. Zeeb 			z = i - 1;
1912413628a7SBjoern A. Zeeb 		else if (d < 0)
1913413628a7SBjoern A. Zeeb 			a = i + 1;
1914413628a7SBjoern A. Zeeb 		else
1915413628a7SBjoern A. Zeeb 			return (0);
191675c13541SPoul-Henning Kamp 	}
191775c13541SPoul-Henning Kamp 
1918b89e82ddSJamie Gritton 	return (EADDRNOTAVAIL);
1919b89e82ddSJamie Gritton }
1920b89e82ddSJamie Gritton 
192175c13541SPoul-Henning Kamp int
1922413628a7SBjoern A. Zeeb prison_check_ip4(struct ucred *cred, struct in_addr *ia)
1923413628a7SBjoern A. Zeeb {
1924b38ff370SJamie Gritton 	struct prison *pr;
1925b38ff370SJamie Gritton 	int error;
1926413628a7SBjoern A. Zeeb 
1927413628a7SBjoern A. Zeeb 	KASSERT(cred != NULL, ("%s: cred is NULL", __func__));
1928413628a7SBjoern A. Zeeb 	KASSERT(ia != NULL, ("%s: ia is NULL", __func__));
1929413628a7SBjoern A. Zeeb 
1930413628a7SBjoern A. Zeeb 	if (!jailed(cred))
1931b89e82ddSJamie Gritton 		return (0);
1932b38ff370SJamie Gritton 	pr = cred->cr_prison;
1933b38ff370SJamie Gritton 	mtx_lock(&pr->pr_mtx);
1934b38ff370SJamie Gritton 	if (pr->pr_ip4 == NULL) {
1935b38ff370SJamie Gritton 		mtx_unlock(&pr->pr_mtx);
1936b89e82ddSJamie Gritton 		return (EAFNOSUPPORT);
1937b38ff370SJamie Gritton 	}
1938413628a7SBjoern A. Zeeb 
1939b38ff370SJamie Gritton 	error = _prison_check_ip4(pr, ia);
1940b38ff370SJamie Gritton 	mtx_unlock(&pr->pr_mtx);
1941b38ff370SJamie Gritton 	return (error);
1942413628a7SBjoern A. Zeeb }
1943413628a7SBjoern A. Zeeb #endif
1944413628a7SBjoern A. Zeeb 
1945413628a7SBjoern A. Zeeb #ifdef INET6
1946413628a7SBjoern A. Zeeb /*
1947413628a7SBjoern A. Zeeb  * Pass back primary IPv6 address for this jail.
1948413628a7SBjoern A. Zeeb  *
1949413628a7SBjoern A. Zeeb  * If not jailed return success but do not alter the address.  Caller has to
19508571af59SJamie Gritton  * make sure to initialize it correctly (e.g. IN6ADDR_ANY_INIT).
1951413628a7SBjoern A. Zeeb  *
1952b89e82ddSJamie Gritton  * Returns 0 on success, EAFNOSUPPORT if the jail doesn't allow IPv6.
1953413628a7SBjoern A. Zeeb  */
1954413628a7SBjoern A. Zeeb int
19551cecba0fSBjoern A. Zeeb prison_get_ip6(struct ucred *cred, struct in6_addr *ia6)
1956413628a7SBjoern A. Zeeb {
1957b38ff370SJamie Gritton 	struct prison *pr;
1958413628a7SBjoern A. Zeeb 
1959413628a7SBjoern A. Zeeb 	KASSERT(cred != NULL, ("%s: cred is NULL", __func__));
1960413628a7SBjoern A. Zeeb 	KASSERT(ia6 != NULL, ("%s: ia6 is NULL", __func__));
1961413628a7SBjoern A. Zeeb 
1962413628a7SBjoern A. Zeeb 	if (!jailed(cred))
1963413628a7SBjoern A. Zeeb 		return (0);
1964b38ff370SJamie Gritton 	pr = cred->cr_prison;
1965b38ff370SJamie Gritton 	mtx_lock(&pr->pr_mtx);
1966b38ff370SJamie Gritton 	if (pr->pr_ip6 == NULL) {
1967b38ff370SJamie Gritton 		mtx_unlock(&pr->pr_mtx);
1968b89e82ddSJamie Gritton 		return (EAFNOSUPPORT);
1969b38ff370SJamie Gritton 	}
1970b89e82ddSJamie Gritton 
1971b38ff370SJamie Gritton 	bcopy(&pr->pr_ip6[0], ia6, sizeof(struct in6_addr));
1972b38ff370SJamie Gritton 	mtx_unlock(&pr->pr_mtx);
1973413628a7SBjoern A. Zeeb 	return (0);
1974413628a7SBjoern A. Zeeb }
1975413628a7SBjoern A. Zeeb 
1976413628a7SBjoern A. Zeeb /*
1977413628a7SBjoern A. Zeeb  * Make sure our (source) address is set to something meaningful to this jail.
1978413628a7SBjoern A. Zeeb  *
1979413628a7SBjoern A. Zeeb  * v6only should be set based on (inp->inp_flags & IN6P_IPV6_V6ONLY != 0)
1980413628a7SBjoern A. Zeeb  * when needed while binding.
1981413628a7SBjoern A. Zeeb  *
1982b89e82ddSJamie Gritton  * Returns 0 if not jailed or if address belongs to jail, EADDRNOTAVAIL if
1983b89e82ddSJamie Gritton  * the address doesn't belong, or EAFNOSUPPORT if the jail doesn't allow IPv6.
1984413628a7SBjoern A. Zeeb  */
1985413628a7SBjoern A. Zeeb int
1986413628a7SBjoern A. Zeeb prison_local_ip6(struct ucred *cred, struct in6_addr *ia6, int v6only)
1987413628a7SBjoern A. Zeeb {
1988b38ff370SJamie Gritton 	struct prison *pr;
1989b38ff370SJamie Gritton 	int error;
1990413628a7SBjoern A. Zeeb 
1991413628a7SBjoern A. Zeeb 	KASSERT(cred != NULL, ("%s: cred is NULL", __func__));
1992413628a7SBjoern A. Zeeb 	KASSERT(ia6 != NULL, ("%s: ia6 is NULL", __func__));
1993413628a7SBjoern A. Zeeb 
1994413628a7SBjoern A. Zeeb 	if (!jailed(cred))
1995413628a7SBjoern A. Zeeb 		return (0);
1996b38ff370SJamie Gritton 	pr = cred->cr_prison;
1997b38ff370SJamie Gritton 	mtx_lock(&pr->pr_mtx);
1998b38ff370SJamie Gritton 	if (pr->pr_ip6 == NULL) {
1999b38ff370SJamie Gritton 		mtx_unlock(&pr->pr_mtx);
2000b89e82ddSJamie Gritton 		return (EAFNOSUPPORT);
2001b38ff370SJamie Gritton 	}
2002b89e82ddSJamie Gritton 
2003413628a7SBjoern A. Zeeb 	if (IN6_IS_ADDR_LOOPBACK(ia6)) {
2004b38ff370SJamie Gritton 		bcopy(&pr->pr_ip6[0], ia6, sizeof(struct in6_addr));
2005b38ff370SJamie Gritton 		mtx_unlock(&pr->pr_mtx);
2006413628a7SBjoern A. Zeeb 		return (0);
2007413628a7SBjoern A. Zeeb 	}
2008413628a7SBjoern A. Zeeb 
2009b89e82ddSJamie Gritton 	if (IN6_IS_ADDR_UNSPECIFIED(ia6)) {
2010413628a7SBjoern A. Zeeb 		/*
2011b89e82ddSJamie Gritton 		 * In case there is only 1 IPv6 address, and v6only is true,
2012b89e82ddSJamie Gritton 		 * then bind directly.
2013413628a7SBjoern A. Zeeb 		 */
2014b38ff370SJamie Gritton 		if (v6only != 0 && pr->pr_ip6s == 1)
2015b38ff370SJamie Gritton 			bcopy(&pr->pr_ip6[0], ia6, sizeof(struct in6_addr));
2016b38ff370SJamie Gritton 		mtx_unlock(&pr->pr_mtx);
2017413628a7SBjoern A. Zeeb 		return (0);
2018413628a7SBjoern A. Zeeb 	}
2019b89e82ddSJamie Gritton 
2020b38ff370SJamie Gritton 	error = _prison_check_ip6(pr, ia6);
2021b38ff370SJamie Gritton 	mtx_unlock(&pr->pr_mtx);
2022b38ff370SJamie Gritton 	return (error);
2023413628a7SBjoern A. Zeeb }
2024413628a7SBjoern A. Zeeb 
2025413628a7SBjoern A. Zeeb /*
2026413628a7SBjoern A. Zeeb  * Rewrite destination address in case we will connect to loopback address.
2027413628a7SBjoern A. Zeeb  *
2028b89e82ddSJamie Gritton  * Returns 0 on success, EAFNOSUPPORT if the jail doesn't allow IPv6.
2029413628a7SBjoern A. Zeeb  */
2030413628a7SBjoern A. Zeeb int
2031413628a7SBjoern A. Zeeb prison_remote_ip6(struct ucred *cred, struct in6_addr *ia6)
2032413628a7SBjoern A. Zeeb {
2033b38ff370SJamie Gritton 	struct prison *pr;
2034413628a7SBjoern A. Zeeb 
2035413628a7SBjoern A. Zeeb 	KASSERT(cred != NULL, ("%s: cred is NULL", __func__));
2036413628a7SBjoern A. Zeeb 	KASSERT(ia6 != NULL, ("%s: ia6 is NULL", __func__));
2037413628a7SBjoern A. Zeeb 
2038413628a7SBjoern A. Zeeb 	if (!jailed(cred))
2039413628a7SBjoern A. Zeeb 		return (0);
2040b38ff370SJamie Gritton 	pr = cred->cr_prison;
2041b38ff370SJamie Gritton 	mtx_lock(&pr->pr_mtx);
2042b38ff370SJamie Gritton 	if (pr->pr_ip6 == NULL) {
2043b38ff370SJamie Gritton 		mtx_unlock(&pr->pr_mtx);
2044b89e82ddSJamie Gritton 		return (EAFNOSUPPORT);
2045b38ff370SJamie Gritton 	}
2046b89e82ddSJamie Gritton 
2047413628a7SBjoern A. Zeeb 	if (IN6_IS_ADDR_LOOPBACK(ia6)) {
2048b38ff370SJamie Gritton 		bcopy(&pr->pr_ip6[0], ia6, sizeof(struct in6_addr));
2049b38ff370SJamie Gritton 		mtx_unlock(&pr->pr_mtx);
2050413628a7SBjoern A. Zeeb 		return (0);
2051413628a7SBjoern A. Zeeb 	}
2052413628a7SBjoern A. Zeeb 
2053413628a7SBjoern A. Zeeb 	/*
2054413628a7SBjoern A. Zeeb 	 * Return success because nothing had to be changed.
2055413628a7SBjoern A. Zeeb 	 */
2056b38ff370SJamie Gritton 	mtx_unlock(&pr->pr_mtx);
2057413628a7SBjoern A. Zeeb 	return (0);
2058413628a7SBjoern A. Zeeb }
2059413628a7SBjoern A. Zeeb 
2060413628a7SBjoern A. Zeeb /*
2061b89e82ddSJamie Gritton  * Check if given address belongs to the jail referenced by cred/prison.
2062413628a7SBjoern A. Zeeb  *
2063b89e82ddSJamie Gritton  * Returns 0 if not jailed or if address belongs to jail, EADDRNOTAVAIL if
2064b89e82ddSJamie Gritton  * the address doesn't belong, or EAFNOSUPPORT if the jail doesn't allow IPv6.
2065413628a7SBjoern A. Zeeb  */
2066413628a7SBjoern A. Zeeb static int
2067413628a7SBjoern A. Zeeb _prison_check_ip6(struct prison *pr, struct in6_addr *ia6)
2068413628a7SBjoern A. Zeeb {
2069413628a7SBjoern A. Zeeb 	int i, a, z, d;
2070413628a7SBjoern A. Zeeb 
2071413628a7SBjoern A. Zeeb 	/*
2072413628a7SBjoern A. Zeeb 	 * Check the primary IP.
2073413628a7SBjoern A. Zeeb 	 */
2074413628a7SBjoern A. Zeeb 	if (IN6_ARE_ADDR_EQUAL(&pr->pr_ip6[0], ia6))
2075b89e82ddSJamie Gritton 		return (0);
2076413628a7SBjoern A. Zeeb 
2077413628a7SBjoern A. Zeeb 	/*
2078413628a7SBjoern A. Zeeb 	 * All the other IPs are sorted so we can do a binary search.
2079413628a7SBjoern A. Zeeb 	 */
2080413628a7SBjoern A. Zeeb 	a = 0;
2081413628a7SBjoern A. Zeeb 	z = pr->pr_ip6s - 2;
2082413628a7SBjoern A. Zeeb 	while (a <= z) {
2083413628a7SBjoern A. Zeeb 		i = (a + z) / 2;
2084413628a7SBjoern A. Zeeb 		d = qcmp_v6(&pr->pr_ip6[i+1], ia6);
2085413628a7SBjoern A. Zeeb 		if (d > 0)
2086413628a7SBjoern A. Zeeb 			z = i - 1;
2087413628a7SBjoern A. Zeeb 		else if (d < 0)
2088413628a7SBjoern A. Zeeb 			a = i + 1;
2089413628a7SBjoern A. Zeeb 		else
2090413628a7SBjoern A. Zeeb 			return (0);
2091413628a7SBjoern A. Zeeb 	}
2092413628a7SBjoern A. Zeeb 
2093b89e82ddSJamie Gritton 	return (EADDRNOTAVAIL);
2094b89e82ddSJamie Gritton }
2095b89e82ddSJamie Gritton 
2096413628a7SBjoern A. Zeeb int
2097413628a7SBjoern A. Zeeb prison_check_ip6(struct ucred *cred, struct in6_addr *ia6)
2098413628a7SBjoern A. Zeeb {
2099b38ff370SJamie Gritton 	struct prison *pr;
2100b38ff370SJamie Gritton 	int error;
2101413628a7SBjoern A. Zeeb 
2102413628a7SBjoern A. Zeeb 	KASSERT(cred != NULL, ("%s: cred is NULL", __func__));
2103413628a7SBjoern A. Zeeb 	KASSERT(ia6 != NULL, ("%s: ia6 is NULL", __func__));
2104413628a7SBjoern A. Zeeb 
2105413628a7SBjoern A. Zeeb 	if (!jailed(cred))
2106b89e82ddSJamie Gritton 		return (0);
2107b38ff370SJamie Gritton 	pr = cred->cr_prison;
2108b38ff370SJamie Gritton 	mtx_lock(&pr->pr_mtx);
2109b38ff370SJamie Gritton 	if (pr->pr_ip6 == NULL) {
2110b38ff370SJamie Gritton 		mtx_unlock(&pr->pr_mtx);
2111b89e82ddSJamie Gritton 		return (EAFNOSUPPORT);
2112b38ff370SJamie Gritton 	}
2113413628a7SBjoern A. Zeeb 
2114b38ff370SJamie Gritton 	error = _prison_check_ip6(pr, ia6);
2115b38ff370SJamie Gritton 	mtx_unlock(&pr->pr_mtx);
2116b38ff370SJamie Gritton 	return (error);
2117413628a7SBjoern A. Zeeb }
2118413628a7SBjoern A. Zeeb #endif
2119413628a7SBjoern A. Zeeb 
2120413628a7SBjoern A. Zeeb /*
2121ca04ba64SJamie Gritton  * Check if a jail supports the given address family.
2122ca04ba64SJamie Gritton  *
2123ca04ba64SJamie Gritton  * Returns 0 if not jailed or the address family is supported, EAFNOSUPPORT
2124ca04ba64SJamie Gritton  * if not.
2125ca04ba64SJamie Gritton  */
2126ca04ba64SJamie Gritton int
2127ca04ba64SJamie Gritton prison_check_af(struct ucred *cred, int af)
2128ca04ba64SJamie Gritton {
2129ca04ba64SJamie Gritton 	int error;
2130ca04ba64SJamie Gritton 
2131ca04ba64SJamie Gritton 	KASSERT(cred != NULL, ("%s: cred is NULL", __func__));
2132ca04ba64SJamie Gritton 
2133ca04ba64SJamie Gritton 
2134ca04ba64SJamie Gritton 	if (!jailed(cred))
2135ca04ba64SJamie Gritton 		return (0);
2136ca04ba64SJamie Gritton 
2137ca04ba64SJamie Gritton 	error = 0;
2138ca04ba64SJamie Gritton 	switch (af)
2139ca04ba64SJamie Gritton 	{
2140ca04ba64SJamie Gritton #ifdef INET
2141ca04ba64SJamie Gritton 	case AF_INET:
2142ca04ba64SJamie Gritton 		if (cred->cr_prison->pr_ip4 == NULL)
2143ca04ba64SJamie Gritton 			error = EAFNOSUPPORT;
2144ca04ba64SJamie Gritton 		break;
2145ca04ba64SJamie Gritton #endif
2146ca04ba64SJamie Gritton #ifdef INET6
2147ca04ba64SJamie Gritton 	case AF_INET6:
2148ca04ba64SJamie Gritton 		if (cred->cr_prison->pr_ip6 == NULL)
2149ca04ba64SJamie Gritton 			error = EAFNOSUPPORT;
2150ca04ba64SJamie Gritton 		break;
2151ca04ba64SJamie Gritton #endif
2152ca04ba64SJamie Gritton 	case AF_LOCAL:
2153ca04ba64SJamie Gritton 	case AF_ROUTE:
2154ca04ba64SJamie Gritton 		break;
2155ca04ba64SJamie Gritton 	default:
2156ca04ba64SJamie Gritton 		if (jail_socket_unixiproute_only)
2157ca04ba64SJamie Gritton 			error = EAFNOSUPPORT;
2158ca04ba64SJamie Gritton 	}
2159ca04ba64SJamie Gritton 	return (error);
2160ca04ba64SJamie Gritton }
2161ca04ba64SJamie Gritton 
2162ca04ba64SJamie Gritton /*
2163413628a7SBjoern A. Zeeb  * Check if given address belongs to the jail referenced by cred (wrapper to
2164413628a7SBjoern A. Zeeb  * prison_check_ip[46]).
2165413628a7SBjoern A. Zeeb  *
2166b89e82ddSJamie Gritton  * Returns 0 if not jailed or if address belongs to jail, EADDRNOTAVAIL if
2167b89e82ddSJamie Gritton  * the address doesn't belong, or EAFNOSUPPORT if the jail doesn't allow
2168b89e82ddSJamie Gritton  * the address family.  IPv4 Address passed in in NBO.
2169413628a7SBjoern A. Zeeb  */
2170413628a7SBjoern A. Zeeb int
217191421ba2SRobert Watson prison_if(struct ucred *cred, struct sockaddr *sa)
217275c13541SPoul-Henning Kamp {
2173413628a7SBjoern A. Zeeb #ifdef INET
21749ddb7954SMike Barcroft 	struct sockaddr_in *sai;
2175413628a7SBjoern A. Zeeb #endif
2176413628a7SBjoern A. Zeeb #ifdef INET6
2177413628a7SBjoern A. Zeeb 	struct sockaddr_in6 *sai6;
2178413628a7SBjoern A. Zeeb #endif
2179b89e82ddSJamie Gritton 	int error;
218075c13541SPoul-Henning Kamp 
2181413628a7SBjoern A. Zeeb 	KASSERT(cred != NULL, ("%s: cred is NULL", __func__));
2182413628a7SBjoern A. Zeeb 	KASSERT(sa != NULL, ("%s: sa is NULL", __func__));
2183413628a7SBjoern A. Zeeb 
2184b89e82ddSJamie Gritton 	error = 0;
2185413628a7SBjoern A. Zeeb 	switch (sa->sa_family)
2186413628a7SBjoern A. Zeeb 	{
2187413628a7SBjoern A. Zeeb #ifdef INET
2188413628a7SBjoern A. Zeeb 	case AF_INET:
21899ddb7954SMike Barcroft 		sai = (struct sockaddr_in *)sa;
2190b89e82ddSJamie Gritton 		error = prison_check_ip4(cred, &sai->sin_addr);
2191413628a7SBjoern A. Zeeb 		break;
2192413628a7SBjoern A. Zeeb #endif
2193413628a7SBjoern A. Zeeb #ifdef INET6
2194413628a7SBjoern A. Zeeb 	case AF_INET6:
2195413628a7SBjoern A. Zeeb 		sai6 = (struct sockaddr_in6 *)sa;
2196b89e82ddSJamie Gritton 		error = prison_check_ip6(cred, &sai6->sin6_addr);
2197413628a7SBjoern A. Zeeb 		break;
2198413628a7SBjoern A. Zeeb #endif
2199413628a7SBjoern A. Zeeb 	default:
2200b89e82ddSJamie Gritton 		if (jailed(cred) && jail_socket_unixiproute_only)
2201b89e82ddSJamie Gritton 			error = EAFNOSUPPORT;
2202413628a7SBjoern A. Zeeb 	}
2203b89e82ddSJamie Gritton 	return (error);
220475c13541SPoul-Henning Kamp }
220591421ba2SRobert Watson 
220691421ba2SRobert Watson /*
220791421ba2SRobert Watson  * Return 0 if jails permit p1 to frob p2, otherwise ESRCH.
220891421ba2SRobert Watson  */
220991421ba2SRobert Watson int
22109ddb7954SMike Barcroft prison_check(struct ucred *cred1, struct ucred *cred2)
221191421ba2SRobert Watson {
221291421ba2SRobert Watson 
221391421ba2SRobert Watson 	if (jailed(cred1)) {
221491421ba2SRobert Watson 		if (!jailed(cred2))
221591421ba2SRobert Watson 			return (ESRCH);
221691421ba2SRobert Watson 		if (cred2->cr_prison != cred1->cr_prison)
221791421ba2SRobert Watson 			return (ESRCH);
221891421ba2SRobert Watson 	}
221929b02909SMarko Zec #ifdef VIMAGE
222029b02909SMarko Zec 	if (cred2->cr_vimage->v_procg != cred1->cr_vimage->v_procg)
222129b02909SMarko Zec 		return (ESRCH);
222229b02909SMarko Zec #endif
222391421ba2SRobert Watson 
222491421ba2SRobert Watson 	return (0);
222591421ba2SRobert Watson }
222691421ba2SRobert Watson 
222791421ba2SRobert Watson /*
222891421ba2SRobert Watson  * Return 1 if the passed credential is in a jail, otherwise 0.
222991421ba2SRobert Watson  */
223091421ba2SRobert Watson int
22319ddb7954SMike Barcroft jailed(struct ucred *cred)
223291421ba2SRobert Watson {
223391421ba2SRobert Watson 
223491421ba2SRobert Watson 	return (cred->cr_prison != NULL);
223591421ba2SRobert Watson }
22369484d0c0SRobert Drehmel 
22379484d0c0SRobert Drehmel /*
22389484d0c0SRobert Drehmel  * Return the correct hostname for the passed credential.
22399484d0c0SRobert Drehmel  */
2240ad1ff099SRobert Drehmel void
22419ddb7954SMike Barcroft getcredhostname(struct ucred *cred, char *buf, size_t size)
22429484d0c0SRobert Drehmel {
22438b615593SMarko Zec 	INIT_VPROCG(cred->cr_vimage->v_procg);
22449484d0c0SRobert Drehmel 
2245ad1ff099SRobert Drehmel 	if (jailed(cred)) {
2246ad1ff099SRobert Drehmel 		mtx_lock(&cred->cr_prison->pr_mtx);
2247e80fb434SRobert Drehmel 		strlcpy(buf, cred->cr_prison->pr_host, size);
2248ad1ff099SRobert Drehmel 		mtx_unlock(&cred->cr_prison->pr_mtx);
22494f7d1876SRobert Watson 	} else {
22504f7d1876SRobert Watson 		mtx_lock(&hostname_mtx);
2251603724d3SBjoern A. Zeeb 		strlcpy(buf, V_hostname, size);
22524f7d1876SRobert Watson 		mtx_unlock(&hostname_mtx);
22534f7d1876SRobert Watson 	}
22549484d0c0SRobert Drehmel }
2255fd7a8150SMike Barcroft 
2256f08df373SRobert Watson /*
2257820a0de9SPawel Jakub Dawidek  * Determine whether the subject represented by cred can "see"
2258820a0de9SPawel Jakub Dawidek  * status of a mount point.
2259820a0de9SPawel Jakub Dawidek  * Returns: 0 for permitted, ENOENT otherwise.
2260820a0de9SPawel Jakub Dawidek  * XXX: This function should be called cr_canseemount() and should be
2261820a0de9SPawel Jakub Dawidek  *      placed in kern_prot.c.
2262f08df373SRobert Watson  */
2263f08df373SRobert Watson int
2264820a0de9SPawel Jakub Dawidek prison_canseemount(struct ucred *cred, struct mount *mp)
2265f08df373SRobert Watson {
2266820a0de9SPawel Jakub Dawidek 	struct prison *pr;
2267820a0de9SPawel Jakub Dawidek 	struct statfs *sp;
2268820a0de9SPawel Jakub Dawidek 	size_t len;
2269f08df373SRobert Watson 
2270820a0de9SPawel Jakub Dawidek 	if (!jailed(cred) || jail_enforce_statfs == 0)
2271820a0de9SPawel Jakub Dawidek 		return (0);
2272820a0de9SPawel Jakub Dawidek 	pr = cred->cr_prison;
2273820a0de9SPawel Jakub Dawidek 	if (pr->pr_root->v_mount == mp)
2274820a0de9SPawel Jakub Dawidek 		return (0);
2275820a0de9SPawel Jakub Dawidek 	if (jail_enforce_statfs == 2)
2276820a0de9SPawel Jakub Dawidek 		return (ENOENT);
2277820a0de9SPawel Jakub Dawidek 	/*
2278820a0de9SPawel Jakub Dawidek 	 * If jail's chroot directory is set to "/" we should be able to see
2279820a0de9SPawel Jakub Dawidek 	 * all mount-points from inside a jail.
2280820a0de9SPawel Jakub Dawidek 	 * This is ugly check, but this is the only situation when jail's
2281820a0de9SPawel Jakub Dawidek 	 * directory ends with '/'.
2282820a0de9SPawel Jakub Dawidek 	 */
2283820a0de9SPawel Jakub Dawidek 	if (strcmp(pr->pr_path, "/") == 0)
2284820a0de9SPawel Jakub Dawidek 		return (0);
2285820a0de9SPawel Jakub Dawidek 	len = strlen(pr->pr_path);
2286820a0de9SPawel Jakub Dawidek 	sp = &mp->mnt_stat;
2287820a0de9SPawel Jakub Dawidek 	if (strncmp(pr->pr_path, sp->f_mntonname, len) != 0)
2288820a0de9SPawel Jakub Dawidek 		return (ENOENT);
2289820a0de9SPawel Jakub Dawidek 	/*
2290820a0de9SPawel Jakub Dawidek 	 * Be sure that we don't have situation where jail's root directory
2291820a0de9SPawel Jakub Dawidek 	 * is "/some/path" and mount point is "/some/pathpath".
2292820a0de9SPawel Jakub Dawidek 	 */
2293820a0de9SPawel Jakub Dawidek 	if (sp->f_mntonname[len] != '\0' && sp->f_mntonname[len] != '/')
2294820a0de9SPawel Jakub Dawidek 		return (ENOENT);
2295f08df373SRobert Watson 	return (0);
2296f08df373SRobert Watson }
2297820a0de9SPawel Jakub Dawidek 
2298820a0de9SPawel Jakub Dawidek void
2299820a0de9SPawel Jakub Dawidek prison_enforce_statfs(struct ucred *cred, struct mount *mp, struct statfs *sp)
2300820a0de9SPawel Jakub Dawidek {
2301820a0de9SPawel Jakub Dawidek 	char jpath[MAXPATHLEN];
2302820a0de9SPawel Jakub Dawidek 	struct prison *pr;
2303820a0de9SPawel Jakub Dawidek 	size_t len;
2304820a0de9SPawel Jakub Dawidek 
2305820a0de9SPawel Jakub Dawidek 	if (!jailed(cred) || jail_enforce_statfs == 0)
2306820a0de9SPawel Jakub Dawidek 		return;
2307820a0de9SPawel Jakub Dawidek 	pr = cred->cr_prison;
2308820a0de9SPawel Jakub Dawidek 	if (prison_canseemount(cred, mp) != 0) {
2309820a0de9SPawel Jakub Dawidek 		bzero(sp->f_mntonname, sizeof(sp->f_mntonname));
2310820a0de9SPawel Jakub Dawidek 		strlcpy(sp->f_mntonname, "[restricted]",
2311820a0de9SPawel Jakub Dawidek 		    sizeof(sp->f_mntonname));
2312820a0de9SPawel Jakub Dawidek 		return;
2313820a0de9SPawel Jakub Dawidek 	}
2314820a0de9SPawel Jakub Dawidek 	if (pr->pr_root->v_mount == mp) {
2315820a0de9SPawel Jakub Dawidek 		/*
2316820a0de9SPawel Jakub Dawidek 		 * Clear current buffer data, so we are sure nothing from
2317820a0de9SPawel Jakub Dawidek 		 * the valid path left there.
2318820a0de9SPawel Jakub Dawidek 		 */
2319820a0de9SPawel Jakub Dawidek 		bzero(sp->f_mntonname, sizeof(sp->f_mntonname));
2320820a0de9SPawel Jakub Dawidek 		*sp->f_mntonname = '/';
2321820a0de9SPawel Jakub Dawidek 		return;
2322820a0de9SPawel Jakub Dawidek 	}
2323820a0de9SPawel Jakub Dawidek 	/*
2324820a0de9SPawel Jakub Dawidek 	 * If jail's chroot directory is set to "/" we should be able to see
2325820a0de9SPawel Jakub Dawidek 	 * all mount-points from inside a jail.
2326820a0de9SPawel Jakub Dawidek 	 */
2327820a0de9SPawel Jakub Dawidek 	if (strcmp(pr->pr_path, "/") == 0)
2328820a0de9SPawel Jakub Dawidek 		return;
2329820a0de9SPawel Jakub Dawidek 	len = strlen(pr->pr_path);
2330820a0de9SPawel Jakub Dawidek 	strlcpy(jpath, sp->f_mntonname + len, sizeof(jpath));
2331820a0de9SPawel Jakub Dawidek 	/*
2332820a0de9SPawel Jakub Dawidek 	 * Clear current buffer data, so we are sure nothing from
2333820a0de9SPawel Jakub Dawidek 	 * the valid path left there.
2334820a0de9SPawel Jakub Dawidek 	 */
2335820a0de9SPawel Jakub Dawidek 	bzero(sp->f_mntonname, sizeof(sp->f_mntonname));
2336820a0de9SPawel Jakub Dawidek 	if (*jpath == '\0') {
2337820a0de9SPawel Jakub Dawidek 		/* Should never happen. */
2338820a0de9SPawel Jakub Dawidek 		*sp->f_mntonname = '/';
2339820a0de9SPawel Jakub Dawidek 	} else {
2340820a0de9SPawel Jakub Dawidek 		strlcpy(sp->f_mntonname, jpath, sizeof(sp->f_mntonname));
2341820a0de9SPawel Jakub Dawidek 	}
2342f08df373SRobert Watson }
2343f08df373SRobert Watson 
2344800c9408SRobert Watson /*
2345800c9408SRobert Watson  * Check with permission for a specific privilege is granted within jail.  We
2346800c9408SRobert Watson  * have a specific list of accepted privileges; the rest are denied.
2347800c9408SRobert Watson  */
2348800c9408SRobert Watson int
2349800c9408SRobert Watson prison_priv_check(struct ucred *cred, int priv)
2350800c9408SRobert Watson {
2351800c9408SRobert Watson 
2352800c9408SRobert Watson 	if (!jailed(cred))
2353800c9408SRobert Watson 		return (0);
2354800c9408SRobert Watson 
2355800c9408SRobert Watson 	switch (priv) {
2356800c9408SRobert Watson 
2357800c9408SRobert Watson 		/*
2358800c9408SRobert Watson 		 * Allow ktrace privileges for root in jail.
2359800c9408SRobert Watson 		 */
2360800c9408SRobert Watson 	case PRIV_KTRACE:
2361800c9408SRobert Watson 
2362c3c1b5e6SRobert Watson #if 0
2363800c9408SRobert Watson 		/*
2364800c9408SRobert Watson 		 * Allow jailed processes to configure audit identity and
2365800c9408SRobert Watson 		 * submit audit records (login, etc).  In the future we may
2366800c9408SRobert Watson 		 * want to further refine the relationship between audit and
2367800c9408SRobert Watson 		 * jail.
2368800c9408SRobert Watson 		 */
2369800c9408SRobert Watson 	case PRIV_AUDIT_GETAUDIT:
2370800c9408SRobert Watson 	case PRIV_AUDIT_SETAUDIT:
2371800c9408SRobert Watson 	case PRIV_AUDIT_SUBMIT:
2372c3c1b5e6SRobert Watson #endif
2373800c9408SRobert Watson 
2374800c9408SRobert Watson 		/*
2375800c9408SRobert Watson 		 * Allow jailed processes to manipulate process UNIX
2376800c9408SRobert Watson 		 * credentials in any way they see fit.
2377800c9408SRobert Watson 		 */
2378800c9408SRobert Watson 	case PRIV_CRED_SETUID:
2379800c9408SRobert Watson 	case PRIV_CRED_SETEUID:
2380800c9408SRobert Watson 	case PRIV_CRED_SETGID:
2381800c9408SRobert Watson 	case PRIV_CRED_SETEGID:
2382800c9408SRobert Watson 	case PRIV_CRED_SETGROUPS:
2383800c9408SRobert Watson 	case PRIV_CRED_SETREUID:
2384800c9408SRobert Watson 	case PRIV_CRED_SETREGID:
2385800c9408SRobert Watson 	case PRIV_CRED_SETRESUID:
2386800c9408SRobert Watson 	case PRIV_CRED_SETRESGID:
2387800c9408SRobert Watson 
2388800c9408SRobert Watson 		/*
2389800c9408SRobert Watson 		 * Jail implements visibility constraints already, so allow
2390800c9408SRobert Watson 		 * jailed root to override uid/gid-based constraints.
2391800c9408SRobert Watson 		 */
2392800c9408SRobert Watson 	case PRIV_SEEOTHERGIDS:
2393800c9408SRobert Watson 	case PRIV_SEEOTHERUIDS:
2394800c9408SRobert Watson 
2395800c9408SRobert Watson 		/*
2396800c9408SRobert Watson 		 * Jail implements inter-process debugging limits already, so
2397800c9408SRobert Watson 		 * allow jailed root various debugging privileges.
2398800c9408SRobert Watson 		 */
2399800c9408SRobert Watson 	case PRIV_DEBUG_DIFFCRED:
2400800c9408SRobert Watson 	case PRIV_DEBUG_SUGID:
2401800c9408SRobert Watson 	case PRIV_DEBUG_UNPRIV:
2402800c9408SRobert Watson 
2403800c9408SRobert Watson 		/*
2404800c9408SRobert Watson 		 * Allow jail to set various resource limits and login
2405800c9408SRobert Watson 		 * properties, and for now, exceed process resource limits.
2406800c9408SRobert Watson 		 */
2407800c9408SRobert Watson 	case PRIV_PROC_LIMIT:
2408800c9408SRobert Watson 	case PRIV_PROC_SETLOGIN:
2409800c9408SRobert Watson 	case PRIV_PROC_SETRLIMIT:
2410800c9408SRobert Watson 
2411800c9408SRobert Watson 		/*
2412800c9408SRobert Watson 		 * System V and POSIX IPC privileges are granted in jail.
2413800c9408SRobert Watson 		 */
2414800c9408SRobert Watson 	case PRIV_IPC_READ:
2415800c9408SRobert Watson 	case PRIV_IPC_WRITE:
2416800c9408SRobert Watson 	case PRIV_IPC_ADMIN:
2417800c9408SRobert Watson 	case PRIV_IPC_MSGSIZE:
2418800c9408SRobert Watson 	case PRIV_MQ_ADMIN:
2419800c9408SRobert Watson 
2420800c9408SRobert Watson 		/*
2421800c9408SRobert Watson 		 * Jail implements its own inter-process limits, so allow
2422800c9408SRobert Watson 		 * root processes in jail to change scheduling on other
2423800c9408SRobert Watson 		 * processes in the same jail.  Likewise for signalling.
2424800c9408SRobert Watson 		 */
2425800c9408SRobert Watson 	case PRIV_SCHED_DIFFCRED:
2426413628a7SBjoern A. Zeeb 	case PRIV_SCHED_CPUSET:
2427800c9408SRobert Watson 	case PRIV_SIGNAL_DIFFCRED:
2428800c9408SRobert Watson 	case PRIV_SIGNAL_SUGID:
2429800c9408SRobert Watson 
2430800c9408SRobert Watson 		/*
2431800c9408SRobert Watson 		 * Allow jailed processes to write to sysctls marked as jail
2432800c9408SRobert Watson 		 * writable.
2433800c9408SRobert Watson 		 */
2434800c9408SRobert Watson 	case PRIV_SYSCTL_WRITEJAIL:
2435800c9408SRobert Watson 
2436800c9408SRobert Watson 		/*
2437800c9408SRobert Watson 		 * Allow root in jail to manage a variety of quota
2438e82d0201SRobert Watson 		 * properties.  These should likely be conditional on a
2439e82d0201SRobert Watson 		 * configuration option.
2440800c9408SRobert Watson 		 */
244195b091d2SRobert Watson 	case PRIV_VFS_GETQUOTA:
244295b091d2SRobert Watson 	case PRIV_VFS_SETQUOTA:
2443800c9408SRobert Watson 
2444800c9408SRobert Watson 		/*
2445800c9408SRobert Watson 		 * Since Jail relies on chroot() to implement file system
2446800c9408SRobert Watson 		 * protections, grant many VFS privileges to root in jail.
2447800c9408SRobert Watson 		 * Be careful to exclude mount-related and NFS-related
2448800c9408SRobert Watson 		 * privileges.
2449800c9408SRobert Watson 		 */
2450800c9408SRobert Watson 	case PRIV_VFS_READ:
2451800c9408SRobert Watson 	case PRIV_VFS_WRITE:
2452800c9408SRobert Watson 	case PRIV_VFS_ADMIN:
2453800c9408SRobert Watson 	case PRIV_VFS_EXEC:
2454800c9408SRobert Watson 	case PRIV_VFS_LOOKUP:
2455800c9408SRobert Watson 	case PRIV_VFS_BLOCKRESERVE:	/* XXXRW: Slightly surprising. */
2456800c9408SRobert Watson 	case PRIV_VFS_CHFLAGS_DEV:
2457800c9408SRobert Watson 	case PRIV_VFS_CHOWN:
2458800c9408SRobert Watson 	case PRIV_VFS_CHROOT:
2459bb531912SPawel Jakub Dawidek 	case PRIV_VFS_RETAINSUGID:
2460800c9408SRobert Watson 	case PRIV_VFS_FCHROOT:
2461800c9408SRobert Watson 	case PRIV_VFS_LINK:
2462800c9408SRobert Watson 	case PRIV_VFS_SETGID:
2463e41966dcSRobert Watson 	case PRIV_VFS_STAT:
2464800c9408SRobert Watson 	case PRIV_VFS_STICKYFILE:
2465800c9408SRobert Watson 		return (0);
2466800c9408SRobert Watson 
2467800c9408SRobert Watson 		/*
2468800c9408SRobert Watson 		 * Depending on the global setting, allow privilege of
2469800c9408SRobert Watson 		 * setting system flags.
2470800c9408SRobert Watson 		 */
2471800c9408SRobert Watson 	case PRIV_VFS_SYSFLAGS:
2472800c9408SRobert Watson 		if (jail_chflags_allowed)
2473800c9408SRobert Watson 			return (0);
2474800c9408SRobert Watson 		else
2475800c9408SRobert Watson 			return (EPERM);
2476800c9408SRobert Watson 
2477800c9408SRobert Watson 		/*
2478f3a8d2f9SPawel Jakub Dawidek 		 * Depending on the global setting, allow privilege of
2479f3a8d2f9SPawel Jakub Dawidek 		 * mounting/unmounting file systems.
2480f3a8d2f9SPawel Jakub Dawidek 		 */
2481f3a8d2f9SPawel Jakub Dawidek 	case PRIV_VFS_MOUNT:
2482f3a8d2f9SPawel Jakub Dawidek 	case PRIV_VFS_UNMOUNT:
2483f3a8d2f9SPawel Jakub Dawidek 	case PRIV_VFS_MOUNT_NONUSER:
248424b0502eSPawel Jakub Dawidek 	case PRIV_VFS_MOUNT_OWNER:
2485f3a8d2f9SPawel Jakub Dawidek 		if (jail_mount_allowed)
2486f3a8d2f9SPawel Jakub Dawidek 			return (0);
2487f3a8d2f9SPawel Jakub Dawidek 		else
2488f3a8d2f9SPawel Jakub Dawidek 			return (EPERM);
2489f3a8d2f9SPawel Jakub Dawidek 
2490f3a8d2f9SPawel Jakub Dawidek 		/*
24914b084056SRobert Watson 		 * Allow jailed root to bind reserved ports and reuse in-use
24924b084056SRobert Watson 		 * ports.
2493800c9408SRobert Watson 		 */
2494800c9408SRobert Watson 	case PRIV_NETINET_RESERVEDPORT:
24954b084056SRobert Watson 	case PRIV_NETINET_REUSEPORT:
2496800c9408SRobert Watson 		return (0);
2497800c9408SRobert Watson 
2498800c9408SRobert Watson 		/*
249979ba3952SBjoern A. Zeeb 		 * Allow jailed root to set certian IPv4/6 (option) headers.
250079ba3952SBjoern A. Zeeb 		 */
250179ba3952SBjoern A. Zeeb 	case PRIV_NETINET_SETHDROPTS:
250279ba3952SBjoern A. Zeeb 		return (0);
250379ba3952SBjoern A. Zeeb 
250479ba3952SBjoern A. Zeeb 		/*
2505800c9408SRobert Watson 		 * Conditionally allow creating raw sockets in jail.
2506800c9408SRobert Watson 		 */
2507800c9408SRobert Watson 	case PRIV_NETINET_RAW:
2508800c9408SRobert Watson 		if (jail_allow_raw_sockets)
2509800c9408SRobert Watson 			return (0);
2510800c9408SRobert Watson 		else
2511800c9408SRobert Watson 			return (EPERM);
2512800c9408SRobert Watson 
2513800c9408SRobert Watson 		/*
2514800c9408SRobert Watson 		 * Since jail implements its own visibility limits on netstat
2515800c9408SRobert Watson 		 * sysctls, allow getcred.  This allows identd to work in
2516800c9408SRobert Watson 		 * jail.
2517800c9408SRobert Watson 		 */
2518800c9408SRobert Watson 	case PRIV_NETINET_GETCRED:
2519800c9408SRobert Watson 		return (0);
2520800c9408SRobert Watson 
2521800c9408SRobert Watson 	default:
2522800c9408SRobert Watson 		/*
2523800c9408SRobert Watson 		 * In all remaining cases, deny the privilege request.  This
2524800c9408SRobert Watson 		 * includes almost all network privileges, many system
2525800c9408SRobert Watson 		 * configuration privileges.
2526800c9408SRobert Watson 		 */
2527800c9408SRobert Watson 		return (EPERM);
2528800c9408SRobert Watson 	}
2529800c9408SRobert Watson }
2530800c9408SRobert Watson 
2531fd7a8150SMike Barcroft static int
2532fd7a8150SMike Barcroft sysctl_jail_list(SYSCTL_HANDLER_ARGS)
2533fd7a8150SMike Barcroft {
2534b38ff370SJamie Gritton 	struct xprison *xp;
2535fd7a8150SMike Barcroft 	struct prison *pr;
2536b38ff370SJamie Gritton #ifdef INET
2537b38ff370SJamie Gritton 	struct in_addr *ip4 = NULL;
2538b38ff370SJamie Gritton 	int ip4s = 0;
2539b38ff370SJamie Gritton #endif
2540b38ff370SJamie Gritton #ifdef INET6
2541b38ff370SJamie Gritton 	struct in_addr *ip6 = NULL;
2542b38ff370SJamie Gritton 	int ip6s = 0;
2543b38ff370SJamie Gritton #endif
2544b38ff370SJamie Gritton 	int error;
2545fd7a8150SMike Barcroft 
25467f4704c0SPawel Jakub Dawidek 	if (jailed(req->td->td_ucred))
2547679a1060SRobert Watson 		return (0);
2548fd7a8150SMike Barcroft 
2549b38ff370SJamie Gritton 	xp = malloc(sizeof(*xp), M_TEMP, M_WAITOK);
2550b38ff370SJamie Gritton 	error = 0;
2551dc68a633SPawel Jakub Dawidek 	sx_slock(&allprison_lock);
2552b38ff370SJamie Gritton 	TAILQ_FOREACH(pr, &allprison, pr_list) {
2553b38ff370SJamie Gritton  again:
2554b38ff370SJamie Gritton 		mtx_lock(&pr->pr_mtx);
2555413628a7SBjoern A. Zeeb #ifdef INET
2556b38ff370SJamie Gritton 		if (pr->pr_ip4s > 0) {
2557b38ff370SJamie Gritton 			if (ip4s < pr->pr_ip4s) {
2558b38ff370SJamie Gritton 				ip4s = pr->pr_ip4s;
2559b38ff370SJamie Gritton 				mtx_unlock(&pr->pr_mtx);
2560b38ff370SJamie Gritton 				ip4 = realloc(ip4, ip4s *
2561b38ff370SJamie Gritton 				    sizeof(struct in_addr), M_TEMP, M_WAITOK);
2562b38ff370SJamie Gritton 				goto again;
2563b38ff370SJamie Gritton 			}
2564b38ff370SJamie Gritton 			bcopy(pr->pr_ip4, ip4,
2565b38ff370SJamie Gritton 			    pr->pr_ip4s * sizeof(struct in_addr));
2566b38ff370SJamie Gritton 		}
2567413628a7SBjoern A. Zeeb #endif
2568413628a7SBjoern A. Zeeb #ifdef INET6
2569b38ff370SJamie Gritton 		if (pr->pr_ip6s > 0) {
2570b38ff370SJamie Gritton 			if (ip6s < pr->pr_ip6s) {
2571b38ff370SJamie Gritton 				ip6s = pr->pr_ip6s;
2572b38ff370SJamie Gritton 				mtx_unlock(&pr->pr_mtx);
2573b38ff370SJamie Gritton 				ip6 = realloc(ip6, ip6s *
2574b38ff370SJamie Gritton 				    sizeof(struct in6_addr), M_TEMP, M_WAITOK);
2575b38ff370SJamie Gritton 				goto again;
2576413628a7SBjoern A. Zeeb 			}
2577b38ff370SJamie Gritton 			bcopy(pr->pr_ip6, ip6,
2578b38ff370SJamie Gritton 			    pr->pr_ip6s * sizeof(struct in6_addr));
2579b38ff370SJamie Gritton 		}
2580b38ff370SJamie Gritton #endif
2581b38ff370SJamie Gritton 		if (pr->pr_ref == 0) {
2582b38ff370SJamie Gritton 			mtx_unlock(&pr->pr_mtx);
2583b38ff370SJamie Gritton 			continue;
2584b38ff370SJamie Gritton 		}
2585b38ff370SJamie Gritton 		bzero(xp, sizeof(*xp));
2586fd7a8150SMike Barcroft 		xp->pr_version = XPRISON_VERSION;
2587fd7a8150SMike Barcroft 		xp->pr_id = pr->pr_id;
2588b38ff370SJamie Gritton 		xp->pr_state = pr->pr_uref > 0
2589b38ff370SJamie Gritton 		    ? PRISON_STATE_ALIVE : PRISON_STATE_DYING;
2590b63b0c65SPawel Jakub Dawidek 		strlcpy(xp->pr_path, pr->pr_path, sizeof(xp->pr_path));
2591b63b0c65SPawel Jakub Dawidek 		strlcpy(xp->pr_host, pr->pr_host, sizeof(xp->pr_host));
2592413628a7SBjoern A. Zeeb 		strlcpy(xp->pr_name, pr->pr_name, sizeof(xp->pr_name));
2593413628a7SBjoern A. Zeeb #ifdef INET
2594413628a7SBjoern A. Zeeb 		xp->pr_ip4s = pr->pr_ip4s;
2595413628a7SBjoern A. Zeeb #endif
2596413628a7SBjoern A. Zeeb #ifdef INET6
2597413628a7SBjoern A. Zeeb 		xp->pr_ip6s = pr->pr_ip6s;
2598413628a7SBjoern A. Zeeb #endif
2599b38ff370SJamie Gritton 		mtx_unlock(&pr->pr_mtx);
2600b38ff370SJamie Gritton 		error = SYSCTL_OUT(req, xp, sizeof(*xp));
2601b38ff370SJamie Gritton 		if (error)
2602b38ff370SJamie Gritton 			break;
2603413628a7SBjoern A. Zeeb #ifdef INET
2604b38ff370SJamie Gritton 		if (xp->pr_ip4s > 0) {
2605b38ff370SJamie Gritton 			error = SYSCTL_OUT(req, ip4,
2606b38ff370SJamie Gritton 			    xp->pr_ip4s * sizeof(struct in_addr));
2607b38ff370SJamie Gritton 			if (error)
2608b38ff370SJamie Gritton 				break;
2609413628a7SBjoern A. Zeeb 		}
2610413628a7SBjoern A. Zeeb #endif
2611413628a7SBjoern A. Zeeb #ifdef INET6
2612b38ff370SJamie Gritton 		if (xp->pr_ip6s > 0) {
2613b38ff370SJamie Gritton 			error = SYSCTL_OUT(req, ip6,
2614b38ff370SJamie Gritton 			    xp->pr_ip6s * sizeof(struct in6_addr));
2615b38ff370SJamie Gritton 			if (error)
2616b38ff370SJamie Gritton 				break;
2617413628a7SBjoern A. Zeeb 		}
2618413628a7SBjoern A. Zeeb #endif
2619fd7a8150SMike Barcroft 	}
2620dc68a633SPawel Jakub Dawidek 	sx_sunlock(&allprison_lock);
2621b38ff370SJamie Gritton 	free(xp, M_TEMP);
2622b38ff370SJamie Gritton #ifdef INET
2623b38ff370SJamie Gritton 	free(ip4, M_TEMP);
2624b38ff370SJamie Gritton #endif
2625b38ff370SJamie Gritton #ifdef INET6
2626b38ff370SJamie Gritton 	free(ip6, M_TEMP);
2627b38ff370SJamie Gritton #endif
2628fd7a8150SMike Barcroft 	return (error);
2629fd7a8150SMike Barcroft }
2630fd7a8150SMike Barcroft 
2631f3b86a5fSEd Schouten SYSCTL_OID(_security_jail, OID_AUTO, list,
2632f3b86a5fSEd Schouten     CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 0,
2633f3b86a5fSEd Schouten     sysctl_jail_list, "S", "List of active jails");
2634461167c2SPawel Jakub Dawidek 
2635461167c2SPawel Jakub Dawidek static int
2636461167c2SPawel Jakub Dawidek sysctl_jail_jailed(SYSCTL_HANDLER_ARGS)
2637461167c2SPawel Jakub Dawidek {
2638461167c2SPawel Jakub Dawidek 	int error, injail;
2639461167c2SPawel Jakub Dawidek 
2640461167c2SPawel Jakub Dawidek 	injail = jailed(req->td->td_ucred);
2641461167c2SPawel Jakub Dawidek 	error = SYSCTL_OUT(req, &injail, sizeof(injail));
2642461167c2SPawel Jakub Dawidek 
2643461167c2SPawel Jakub Dawidek 	return (error);
2644461167c2SPawel Jakub Dawidek }
2645f3b86a5fSEd Schouten SYSCTL_PROC(_security_jail, OID_AUTO, jailed,
2646f3b86a5fSEd Schouten     CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 0,
2647f3b86a5fSEd Schouten     sysctl_jail_jailed, "I", "Process in jail?");
2648413628a7SBjoern A. Zeeb 
2649413628a7SBjoern A. Zeeb #ifdef DDB
2650b38ff370SJamie Gritton 
2651b38ff370SJamie Gritton static void
2652b38ff370SJamie Gritton db_show_prison(struct prison *pr)
2653413628a7SBjoern A. Zeeb {
2654b38ff370SJamie Gritton #if defined(INET) || defined(INET6)
2655b38ff370SJamie Gritton 	int ii;
2656413628a7SBjoern A. Zeeb #endif
2657413628a7SBjoern A. Zeeb #ifdef INET6
2658413628a7SBjoern A. Zeeb 	char ip6buf[INET6_ADDRSTRLEN];
2659413628a7SBjoern A. Zeeb #endif
2660413628a7SBjoern A. Zeeb 
2661b38ff370SJamie Gritton 	db_printf("prison %p:\n", pr);
2662b38ff370SJamie Gritton 	db_printf(" jid             = %d\n", pr->pr_id);
2663b38ff370SJamie Gritton 	db_printf(" name            = %s\n", pr->pr_name);
2664b38ff370SJamie Gritton 	db_printf(" ref             = %d\n", pr->pr_ref);
2665b38ff370SJamie Gritton 	db_printf(" uref            = %d\n", pr->pr_uref);
2666b38ff370SJamie Gritton 	db_printf(" path            = %s\n", pr->pr_path);
2667b38ff370SJamie Gritton 	db_printf(" cpuset          = %d\n", pr->pr_cpuset
2668b38ff370SJamie Gritton 	    ? pr->pr_cpuset->cs_id : -1);
2669b38ff370SJamie Gritton 	db_printf(" root            = %p\n", pr->pr_root);
2670b38ff370SJamie Gritton 	db_printf(" securelevel     = %d\n", pr->pr_securelevel);
2671b38ff370SJamie Gritton 	db_printf(" flags           = %x", pr->pr_flags);
2672b38ff370SJamie Gritton 	if (pr->pr_flags & PR_PERSIST)
2673b38ff370SJamie Gritton 		db_printf(" persist");
2674b38ff370SJamie Gritton 	db_printf("\n");
2675b38ff370SJamie Gritton 	db_printf(" host.hostname   = %s\n", pr->pr_host);
2676413628a7SBjoern A. Zeeb #ifdef INET
2677b38ff370SJamie Gritton 	db_printf(" ip4s            = %d\n", pr->pr_ip4s);
2678b38ff370SJamie Gritton 	for (ii = 0; ii < pr->pr_ip4s; ii++)
2679b38ff370SJamie Gritton 		db_printf(" %s %s\n",
2680b38ff370SJamie Gritton 		    ii == 0 ? "ip4             =" : "                 ",
2681b38ff370SJamie Gritton 		    inet_ntoa(pr->pr_ip4[ii]));
2682413628a7SBjoern A. Zeeb #endif
2683413628a7SBjoern A. Zeeb #ifdef INET6
2684b38ff370SJamie Gritton 	db_printf(" ip6s            = %d\n", pr->pr_ip6s);
2685b38ff370SJamie Gritton 	for (ii = 0; ii < pr->pr_ip6s; ii++)
2686b38ff370SJamie Gritton 		db_printf(" %s %s\n",
2687b38ff370SJamie Gritton 		    ii == 0 ? "ip6             =" : "                 ",
2688b38ff370SJamie Gritton 		    ip6_sprintf(ip6buf, &pr->pr_ip6[ii]));
2689b38ff370SJamie Gritton #endif
2690b38ff370SJamie Gritton }
2691b38ff370SJamie Gritton 
2692b38ff370SJamie Gritton DB_SHOW_COMMAND(prison, db_show_prison_command)
2693b38ff370SJamie Gritton {
2694b38ff370SJamie Gritton 	struct prison *pr;
2695b38ff370SJamie Gritton 
2696b38ff370SJamie Gritton 	if (!have_addr) {
2697b38ff370SJamie Gritton 		/* Show all prisons in the list. */
2698b38ff370SJamie Gritton 		TAILQ_FOREACH(pr, &allprison, pr_list) {
2699b38ff370SJamie Gritton 			db_show_prison(pr);
2700413628a7SBjoern A. Zeeb 			if (db_pager_quit)
2701413628a7SBjoern A. Zeeb 				break;
2702413628a7SBjoern A. Zeeb 		}
2703b38ff370SJamie Gritton 		return;
2704413628a7SBjoern A. Zeeb 	}
2705b38ff370SJamie Gritton 
2706b38ff370SJamie Gritton 	/* Look for a prison with the ID and with references. */
2707b38ff370SJamie Gritton 	TAILQ_FOREACH(pr, &allprison, pr_list)
2708b38ff370SJamie Gritton 		if (pr->pr_id == addr && pr->pr_ref > 0)
2709b38ff370SJamie Gritton 			break;
2710b38ff370SJamie Gritton 	if (pr == NULL)
2711b38ff370SJamie Gritton 		/* Look again, without requiring a reference. */
2712b38ff370SJamie Gritton 		TAILQ_FOREACH(pr, &allprison, pr_list)
2713b38ff370SJamie Gritton 			if (pr->pr_id == addr)
2714b38ff370SJamie Gritton 				break;
2715b38ff370SJamie Gritton 	if (pr == NULL)
2716b38ff370SJamie Gritton 		/* Assume address points to a valid prison. */
2717b38ff370SJamie Gritton 		pr = (struct prison *)addr;
2718b38ff370SJamie Gritton 	db_show_prison(pr);
2719b38ff370SJamie Gritton }
2720b38ff370SJamie Gritton 
2721413628a7SBjoern A. Zeeb #endif /* DDB */
2722