xref: /freebsd/sys/kern/kern_jail.c (revision b89e82dd87dec9034c8b7f1a01524dceea11ff49)
19454b2d8SWarner Losh /*-
2413628a7SBjoern A. Zeeb  * Copyright (c) 1999 Poul-Henning Kamp.
3413628a7SBjoern A. Zeeb  * Copyright (c) 2008 Bjoern A. Zeeb.
4413628a7SBjoern A. Zeeb  * All rights reserved.
5b9f0b66cSBjoern A. Zeeb  *
6b9f0b66cSBjoern A. Zeeb  * Redistribution and use in source and binary forms, with or without
7b9f0b66cSBjoern A. Zeeb  * modification, are permitted provided that the following conditions
8b9f0b66cSBjoern A. Zeeb  * are met:
9b9f0b66cSBjoern A. Zeeb  * 1. Redistributions of source code must retain the above copyright
10b9f0b66cSBjoern A. Zeeb  *    notice, this list of conditions and the following disclaimer.
11b9f0b66cSBjoern A. Zeeb  * 2. Redistributions in binary form must reproduce the above copyright
12b9f0b66cSBjoern A. Zeeb  *    notice, this list of conditions and the following disclaimer in the
13b9f0b66cSBjoern A. Zeeb  *    documentation and/or other materials provided with the distribution.
14b9f0b66cSBjoern A. Zeeb  *
15b9f0b66cSBjoern A. Zeeb  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16b9f0b66cSBjoern A. Zeeb  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17b9f0b66cSBjoern A. Zeeb  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18b9f0b66cSBjoern A. Zeeb  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19b9f0b66cSBjoern A. Zeeb  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20b9f0b66cSBjoern A. Zeeb  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21b9f0b66cSBjoern A. Zeeb  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22b9f0b66cSBjoern A. Zeeb  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23b9f0b66cSBjoern A. Zeeb  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24b9f0b66cSBjoern A. Zeeb  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25b9f0b66cSBjoern A. Zeeb  * SUCH DAMAGE.
2607901f22SPoul-Henning Kamp  */
2775c13541SPoul-Henning Kamp 
28677b542eSDavid E. O'Brien #include <sys/cdefs.h>
29677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$");
30677b542eSDavid E. O'Brien 
31413628a7SBjoern A. Zeeb #include "opt_ddb.h"
32413628a7SBjoern A. Zeeb #include "opt_inet.h"
33413628a7SBjoern A. Zeeb #include "opt_inet6.h"
3446e3b1cbSPawel Jakub Dawidek #include "opt_mac.h"
3546e3b1cbSPawel Jakub Dawidek 
3675c13541SPoul-Henning Kamp #include <sys/param.h>
3775c13541SPoul-Henning Kamp #include <sys/types.h>
3875c13541SPoul-Henning Kamp #include <sys/kernel.h>
3975c13541SPoul-Henning Kamp #include <sys/systm.h>
4075c13541SPoul-Henning Kamp #include <sys/errno.h>
4175c13541SPoul-Henning Kamp #include <sys/sysproto.h>
4275c13541SPoul-Henning Kamp #include <sys/malloc.h>
43800c9408SRobert Watson #include <sys/priv.h>
4475c13541SPoul-Henning Kamp #include <sys/proc.h>
45b3059e09SRobert Watson #include <sys/taskqueue.h>
4657b4252eSKonstantin Belousov #include <sys/fcntl.h>
4775c13541SPoul-Henning Kamp #include <sys/jail.h>
4801137630SRobert Watson #include <sys/lock.h>
4901137630SRobert Watson #include <sys/mutex.h>
50dc68a633SPawel Jakub Dawidek #include <sys/sx.h>
51fd7a8150SMike Barcroft #include <sys/namei.h>
52820a0de9SPawel Jakub Dawidek #include <sys/mount.h>
53fd7a8150SMike Barcroft #include <sys/queue.h>
5475c13541SPoul-Henning Kamp #include <sys/socket.h>
55fd7a8150SMike Barcroft #include <sys/syscallsubr.h>
5683f1e257SRobert Watson #include <sys/sysctl.h>
57fd7a8150SMike Barcroft #include <sys/vnode.h>
58603724d3SBjoern A. Zeeb #include <sys/vimage.h>
591ba4a712SPawel Jakub Dawidek #include <sys/osd.h>
6075c13541SPoul-Henning Kamp #include <net/if.h>
6175c13541SPoul-Henning Kamp #include <netinet/in.h>
62413628a7SBjoern A. Zeeb #ifdef DDB
63413628a7SBjoern A. Zeeb #include <ddb/ddb.h>
64413628a7SBjoern A. Zeeb #ifdef INET6
65413628a7SBjoern A. Zeeb #include <netinet6/in6_var.h>
66413628a7SBjoern A. Zeeb #endif /* INET6 */
67413628a7SBjoern A. Zeeb #endif /* DDB */
6875c13541SPoul-Henning Kamp 
69aed55708SRobert Watson #include <security/mac/mac_framework.h>
70aed55708SRobert Watson 
7175c13541SPoul-Henning Kamp MALLOC_DEFINE(M_PRISON, "prison", "Prison structures");
7275c13541SPoul-Henning Kamp 
73d0615c64SAndrew R. Reiter SYSCTL_NODE(_security, OID_AUTO, jail, CTLFLAG_RW, 0,
7483f1e257SRobert Watson     "Jail rules");
7583f1e257SRobert Watson 
7683f1e257SRobert Watson int	jail_set_hostname_allowed = 1;
77d0615c64SAndrew R. Reiter SYSCTL_INT(_security_jail, OID_AUTO, set_hostname_allowed, CTLFLAG_RW,
7883f1e257SRobert Watson     &jail_set_hostname_allowed, 0,
7983f1e257SRobert Watson     "Processes in jail can set their hostnames");
8083f1e257SRobert Watson 
817cadc266SRobert Watson int	jail_socket_unixiproute_only = 1;
82d0615c64SAndrew R. Reiter SYSCTL_INT(_security_jail, OID_AUTO, socket_unixiproute_only, CTLFLAG_RW,
837cadc266SRobert Watson     &jail_socket_unixiproute_only, 0,
84413628a7SBjoern A. Zeeb     "Processes in jail are limited to creating UNIX/IP/route sockets only");
857cadc266SRobert Watson 
86cb1f0db9SRobert Watson int	jail_sysvipc_allowed = 0;
87d0615c64SAndrew R. Reiter SYSCTL_INT(_security_jail, OID_AUTO, sysvipc_allowed, CTLFLAG_RW,
88cb1f0db9SRobert Watson     &jail_sysvipc_allowed, 0,
89cb1f0db9SRobert Watson     "Processes in jail can use System V IPC primitives");
90cb1f0db9SRobert Watson 
91820a0de9SPawel Jakub Dawidek static int jail_enforce_statfs = 2;
92820a0de9SPawel Jakub Dawidek SYSCTL_INT(_security_jail, OID_AUTO, enforce_statfs, CTLFLAG_RW,
93820a0de9SPawel Jakub Dawidek     &jail_enforce_statfs, 0,
94820a0de9SPawel Jakub Dawidek     "Processes in jail cannot see all mounted file systems");
95f08df373SRobert Watson 
965a59cefcSBosko Milekic int	jail_allow_raw_sockets = 0;
975a59cefcSBosko Milekic SYSCTL_INT(_security_jail, OID_AUTO, allow_raw_sockets, CTLFLAG_RW,
985a59cefcSBosko Milekic     &jail_allow_raw_sockets, 0,
995a59cefcSBosko Milekic     "Prison root can create raw sockets");
1005a59cefcSBosko Milekic 
10179653046SColin Percival int	jail_chflags_allowed = 0;
10279653046SColin Percival SYSCTL_INT(_security_jail, OID_AUTO, chflags_allowed, CTLFLAG_RW,
10379653046SColin Percival     &jail_chflags_allowed, 0,
10479653046SColin Percival     "Processes in jail can alter system file flags");
10579653046SColin Percival 
106f3a8d2f9SPawel Jakub Dawidek int	jail_mount_allowed = 0;
107f3a8d2f9SPawel Jakub Dawidek SYSCTL_INT(_security_jail, OID_AUTO, mount_allowed, CTLFLAG_RW,
108f3a8d2f9SPawel Jakub Dawidek     &jail_mount_allowed, 0,
109f3a8d2f9SPawel Jakub Dawidek     "Processes in jail can mount/unmount jail-friendly file systems");
110f3a8d2f9SPawel Jakub Dawidek 
111413628a7SBjoern A. Zeeb int	jail_max_af_ips = 255;
112413628a7SBjoern A. Zeeb SYSCTL_INT(_security_jail, OID_AUTO, jail_max_af_ips, CTLFLAG_RW,
113413628a7SBjoern A. Zeeb     &jail_max_af_ips, 0,
114413628a7SBjoern A. Zeeb     "Number of IP addresses a jail may have at most per address family");
115413628a7SBjoern A. Zeeb 
1162110d913SXin LI /* allprison, lastprid, and prisoncount are protected by allprison_lock. */
1172110d913SXin LI struct	prisonlist allprison;
118dc68a633SPawel Jakub Dawidek struct	sx allprison_lock;
1192110d913SXin LI int	lastprid = 0;
120fd7a8150SMike Barcroft int	prisoncount = 0;
121fd7a8150SMike Barcroft 
122fd7a8150SMike Barcroft static void		 init_prison(void *);
123b3059e09SRobert Watson static void		 prison_complete(void *context, int pending);
124fd7a8150SMike Barcroft static int		 sysctl_jail_list(SYSCTL_HANDLER_ARGS);
125413628a7SBjoern A. Zeeb #ifdef INET
126413628a7SBjoern A. Zeeb static int		_prison_check_ip4(struct prison *, struct in_addr *);
127413628a7SBjoern A. Zeeb #endif
128413628a7SBjoern A. Zeeb #ifdef INET6
129413628a7SBjoern A. Zeeb static int		_prison_check_ip6(struct prison *, struct in6_addr *);
130413628a7SBjoern A. Zeeb #endif
131fd7a8150SMike Barcroft 
132fd7a8150SMike Barcroft static void
133fd7a8150SMike Barcroft init_prison(void *data __unused)
134fd7a8150SMike Barcroft {
135fd7a8150SMike Barcroft 
1362110d913SXin LI 	sx_init(&allprison_lock, "allprison");
1372110d913SXin LI 	LIST_INIT(&allprison);
138fd7a8150SMike Barcroft }
139fd7a8150SMike Barcroft 
140fd7a8150SMike Barcroft SYSINIT(prison, SI_SUB_INTRINSIC, SI_ORDER_ANY, init_prison, NULL);
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 
190413628a7SBjoern A. Zeeb #if defined(INET) || defined(INET6)
191413628a7SBjoern A. Zeeb static int
192413628a7SBjoern A. Zeeb prison_check_conflicting_ips(struct prison *p)
193413628a7SBjoern A. Zeeb {
194413628a7SBjoern A. Zeeb 	struct prison *pr;
195413628a7SBjoern A. Zeeb 	int i;
196413628a7SBjoern A. Zeeb 
197413628a7SBjoern A. Zeeb 	sx_assert(&allprison_lock, SX_LOCKED);
198413628a7SBjoern A. Zeeb 
199413628a7SBjoern A. Zeeb 	if (p->pr_ip4s == 0 && p->pr_ip6s == 0)
200413628a7SBjoern A. Zeeb 		return (0);
201413628a7SBjoern A. Zeeb 
202413628a7SBjoern A. Zeeb 	LIST_FOREACH(pr, &allprison, pr_list) {
203413628a7SBjoern A. Zeeb 		/*
204413628a7SBjoern A. Zeeb 		 * Skip 'dying' prisons to avoid problems when
205413628a7SBjoern A. Zeeb 		 * restarting multi-IP jails.
206413628a7SBjoern A. Zeeb 		 */
207413628a7SBjoern A. Zeeb 		if (pr->pr_state == PRISON_STATE_DYING)
208413628a7SBjoern A. Zeeb 			continue;
209413628a7SBjoern A. Zeeb 
210413628a7SBjoern A. Zeeb 		/*
211413628a7SBjoern A. Zeeb 		 * We permit conflicting IPs if there is no
212413628a7SBjoern A. Zeeb 		 * more than 1 IP on eeach jail.
213413628a7SBjoern A. Zeeb 		 * In case there is one duplicate on a jail with
214413628a7SBjoern A. Zeeb 		 * more than one IP stop checking and return error.
215413628a7SBjoern A. Zeeb 		 */
216413628a7SBjoern A. Zeeb #ifdef INET
217413628a7SBjoern A. Zeeb 		if ((p->pr_ip4s >= 1 && pr->pr_ip4s > 1) ||
218413628a7SBjoern A. Zeeb 		    (p->pr_ip4s > 1 && pr->pr_ip4s >= 1)) {
219413628a7SBjoern A. Zeeb 			for (i = 0; i < p->pr_ip4s; i++) {
220b89e82ddSJamie Gritton 				if (_prison_check_ip4(pr, &p->pr_ip4[i]) == 0)
221413628a7SBjoern A. Zeeb 					return (EINVAL);
222413628a7SBjoern A. Zeeb 			}
223413628a7SBjoern A. Zeeb 		}
224413628a7SBjoern A. Zeeb #endif
225413628a7SBjoern A. Zeeb #ifdef INET6
226413628a7SBjoern A. Zeeb 		if ((p->pr_ip6s >= 1 && pr->pr_ip6s > 1) ||
227413628a7SBjoern A. Zeeb 		    (p->pr_ip6s > 1 && pr->pr_ip6s >= 1)) {
228413628a7SBjoern A. Zeeb 			for (i = 0; i < p->pr_ip6s; i++) {
229b89e82ddSJamie Gritton 				if (_prison_check_ip6(pr, &p->pr_ip6[i]) == 0)
230413628a7SBjoern A. Zeeb 					return (EINVAL);
231413628a7SBjoern A. Zeeb 			}
232413628a7SBjoern A. Zeeb 		}
233413628a7SBjoern A. Zeeb #endif
234413628a7SBjoern A. Zeeb 	}
235413628a7SBjoern A. Zeeb 
236413628a7SBjoern A. Zeeb 	return (0);
237413628a7SBjoern A. Zeeb }
238413628a7SBjoern A. Zeeb 
239413628a7SBjoern A. Zeeb static int
240413628a7SBjoern A. Zeeb jail_copyin_ips(struct jail *j)
241413628a7SBjoern A. Zeeb {
242413628a7SBjoern A. Zeeb #ifdef INET
243413628a7SBjoern A. Zeeb 	struct in_addr  *ip4;
244413628a7SBjoern A. Zeeb #endif
245413628a7SBjoern A. Zeeb #ifdef INET6
246413628a7SBjoern A. Zeeb 	struct in6_addr *ip6;
247413628a7SBjoern A. Zeeb #endif
248413628a7SBjoern A. Zeeb 	int error, i;
249413628a7SBjoern A. Zeeb 
250413628a7SBjoern A. Zeeb 	/*
251413628a7SBjoern A. Zeeb 	 * Copy in addresses, check for duplicate addresses and do some
252413628a7SBjoern A. Zeeb 	 * simple 0 and broadcast checks. If users give other bogus addresses
253413628a7SBjoern A. Zeeb 	 * it is their problem.
254413628a7SBjoern A. Zeeb 	 *
255413628a7SBjoern A. Zeeb 	 * IP addresses are all sorted but ip[0] to preserve the primary IP
256413628a7SBjoern A. Zeeb 	 * address as given from userland.  This special IP is used for
257413628a7SBjoern A. Zeeb 	 * unbound outgoing connections as well for "loopback" traffic.
258413628a7SBjoern A. Zeeb 	 */
259413628a7SBjoern A. Zeeb #ifdef INET
260413628a7SBjoern A. Zeeb 	ip4 = NULL;
261413628a7SBjoern A. Zeeb #endif
262413628a7SBjoern A. Zeeb #ifdef INET6
263413628a7SBjoern A. Zeeb 	ip6 = NULL;
264413628a7SBjoern A. Zeeb #endif
265413628a7SBjoern A. Zeeb #ifdef INET
266413628a7SBjoern A. Zeeb 	if (j->ip4s > 0) {
267413628a7SBjoern A. Zeeb 		ip4 = (struct in_addr *)malloc(j->ip4s * sizeof(struct in_addr),
268413628a7SBjoern A. Zeeb 		    M_PRISON, M_WAITOK | M_ZERO);
269413628a7SBjoern A. Zeeb 		error = copyin(j->ip4, ip4, j->ip4s * sizeof(struct in_addr));
270413628a7SBjoern A. Zeeb 		if (error)
271413628a7SBjoern A. Zeeb 			goto e_free_ip;
272413628a7SBjoern A. Zeeb 		/* Sort all but the first IPv4 address. */
273413628a7SBjoern A. Zeeb 		if (j->ip4s > 1)
274413628a7SBjoern A. Zeeb 			qsort((ip4 + 1), j->ip4s - 1,
275413628a7SBjoern A. Zeeb 			    sizeof(struct in_addr), qcmp_v4);
276413628a7SBjoern A. Zeeb 
277413628a7SBjoern A. Zeeb 		/*
278413628a7SBjoern A. Zeeb 		 * We do not have to care about byte order for these checks
279413628a7SBjoern A. Zeeb 		 * so we will do them in NBO.
280413628a7SBjoern A. Zeeb 		 */
281413628a7SBjoern A. Zeeb 		for (i=0; i<j->ip4s; i++) {
282413628a7SBjoern A. Zeeb 			if (ip4[i].s_addr == htonl(INADDR_ANY) ||
283413628a7SBjoern A. Zeeb 			    ip4[i].s_addr == htonl(INADDR_BROADCAST)) {
284413628a7SBjoern A. Zeeb 				error = EINVAL;
285413628a7SBjoern A. Zeeb 				goto e_free_ip;
286413628a7SBjoern A. Zeeb 			}
287413628a7SBjoern A. Zeeb 			if ((i+1) < j->ip4s &&
288413628a7SBjoern A. Zeeb 			    (ip4[0].s_addr == ip4[i+1].s_addr ||
289413628a7SBjoern A. Zeeb 			    ip4[i].s_addr == ip4[i+1].s_addr)) {
290413628a7SBjoern A. Zeeb 				error = EINVAL;
291413628a7SBjoern A. Zeeb 				goto e_free_ip;
292413628a7SBjoern A. Zeeb 			}
293413628a7SBjoern A. Zeeb 		}
294413628a7SBjoern A. Zeeb 
295413628a7SBjoern A. Zeeb 		j->ip4 = ip4;
296bc971b2cSPeter Holm 	} else
297bc971b2cSPeter Holm 		j->ip4 = NULL;
298413628a7SBjoern A. Zeeb #endif
299413628a7SBjoern A. Zeeb #ifdef INET6
300413628a7SBjoern A. Zeeb 	if (j->ip6s > 0) {
301413628a7SBjoern A. Zeeb 		ip6 = (struct in6_addr *)malloc(j->ip6s * sizeof(struct in6_addr),
302413628a7SBjoern A. Zeeb 		    M_PRISON, M_WAITOK | M_ZERO);
303413628a7SBjoern A. Zeeb 		error = copyin(j->ip6, ip6, j->ip6s * sizeof(struct in6_addr));
304413628a7SBjoern A. Zeeb 		if (error)
305413628a7SBjoern A. Zeeb 			goto e_free_ip;
306413628a7SBjoern A. Zeeb 		/* Sort all but the first IPv6 address. */
307413628a7SBjoern A. Zeeb 		if (j->ip6s > 1)
308413628a7SBjoern A. Zeeb 			qsort((ip6 + 1), j->ip6s - 1,
309413628a7SBjoern A. Zeeb 			    sizeof(struct in6_addr), qcmp_v6);
310413628a7SBjoern A. Zeeb 		for (i=0; i<j->ip6s; i++) {
311413628a7SBjoern A. Zeeb 			if (IN6_IS_ADDR_UNSPECIFIED(&ip6[i])) {
312413628a7SBjoern A. Zeeb 				error = EINVAL;
313413628a7SBjoern A. Zeeb 				goto e_free_ip;
314413628a7SBjoern A. Zeeb 			}
315413628a7SBjoern A. Zeeb 			if ((i+1) < j->ip6s &&
316413628a7SBjoern A. Zeeb 			    (IN6_ARE_ADDR_EQUAL(&ip6[0], &ip6[i+1]) ||
317413628a7SBjoern A. Zeeb 			    IN6_ARE_ADDR_EQUAL(&ip6[i], &ip6[i+1]))) {
318413628a7SBjoern A. Zeeb 				error = EINVAL;
319413628a7SBjoern A. Zeeb 				goto e_free_ip;
320413628a7SBjoern A. Zeeb 			}
321413628a7SBjoern A. Zeeb 		}
322413628a7SBjoern A. Zeeb 
323413628a7SBjoern A. Zeeb 		j->ip6 = ip6;
324bc971b2cSPeter Holm 	} else
325bc971b2cSPeter Holm 		j->ip6 = NULL;
326413628a7SBjoern A. Zeeb #endif
327413628a7SBjoern A. Zeeb 	return (0);
328413628a7SBjoern A. Zeeb 
329413628a7SBjoern A. Zeeb e_free_ip:
330413628a7SBjoern A. Zeeb #ifdef INET6
331413628a7SBjoern A. Zeeb 	free(ip6, M_PRISON);
332413628a7SBjoern A. Zeeb #endif
333413628a7SBjoern A. Zeeb #ifdef INET
334413628a7SBjoern A. Zeeb 	free(ip4, M_PRISON);
335413628a7SBjoern A. Zeeb #endif
336413628a7SBjoern A. Zeeb 	return (error);
337413628a7SBjoern A. Zeeb }
338413628a7SBjoern A. Zeeb #endif /* INET || INET6 */
339413628a7SBjoern A. Zeeb 
340413628a7SBjoern A. Zeeb static int
341413628a7SBjoern A. Zeeb jail_handle_ips(struct jail *j)
342413628a7SBjoern A. Zeeb {
343413628a7SBjoern A. Zeeb #if defined(INET) || defined(INET6)
344413628a7SBjoern A. Zeeb 	int error;
345413628a7SBjoern A. Zeeb #endif
346413628a7SBjoern A. Zeeb 
347413628a7SBjoern A. Zeeb 	/*
348413628a7SBjoern A. Zeeb 	 * Finish conversion for older versions, copyin and setup IPs.
349413628a7SBjoern A. Zeeb 	 */
350413628a7SBjoern A. Zeeb 	switch (j->version) {
351413628a7SBjoern A. Zeeb 	case 0:
352413628a7SBjoern A. Zeeb 	{
353413628a7SBjoern A. Zeeb #ifdef INET
354413628a7SBjoern A. Zeeb 		/* FreeBSD single IPv4 jails. */
355413628a7SBjoern A. Zeeb 		struct in_addr *ip4;
356413628a7SBjoern A. Zeeb 
357413628a7SBjoern A. Zeeb 		if (j->ip4s == INADDR_ANY || j->ip4s == INADDR_BROADCAST)
358413628a7SBjoern A. Zeeb 			return (EINVAL);
359413628a7SBjoern A. Zeeb 		ip4 = (struct in_addr *)malloc(sizeof(struct in_addr),
360413628a7SBjoern A. Zeeb 		    M_PRISON, M_WAITOK | M_ZERO);
361413628a7SBjoern A. Zeeb 
362413628a7SBjoern A. Zeeb 		/*
363413628a7SBjoern A. Zeeb 		 * Jail version 0 still used HBO for the IPv4 address.
364413628a7SBjoern A. Zeeb 		 */
365413628a7SBjoern A. Zeeb 		ip4->s_addr = htonl(j->ip4s);
366413628a7SBjoern A. Zeeb 		j->ip4s = 1;
367413628a7SBjoern A. Zeeb 		j->ip4 = ip4;
368413628a7SBjoern A. Zeeb 		break;
369413628a7SBjoern A. Zeeb #else
370413628a7SBjoern A. Zeeb 		return (EINVAL);
371413628a7SBjoern A. Zeeb #endif
372413628a7SBjoern A. Zeeb 	}
373413628a7SBjoern A. Zeeb 
374413628a7SBjoern A. Zeeb 	case 1:
375413628a7SBjoern A. Zeeb 		/*
376413628a7SBjoern A. Zeeb 		 * Version 1 was used by multi-IPv4 jail implementations
377413628a7SBjoern A. Zeeb 		 * that never made it into the official kernel.
378413628a7SBjoern A. Zeeb 		 * We should never hit this here; jail() should catch it.
379413628a7SBjoern A. Zeeb 		 */
380413628a7SBjoern A. Zeeb 		return (EINVAL);
381413628a7SBjoern A. Zeeb 
382413628a7SBjoern A. Zeeb 	case 2:	/* JAIL_API_VERSION */
383413628a7SBjoern A. Zeeb 		/* FreeBSD multi-IPv4/IPv6,noIP jails. */
384413628a7SBjoern A. Zeeb #if defined(INET) || defined(INET6)
385413628a7SBjoern A. Zeeb #ifdef INET
386413628a7SBjoern A. Zeeb 		if (j->ip4s > jail_max_af_ips)
387413628a7SBjoern A. Zeeb 			return (EINVAL);
388413628a7SBjoern A. Zeeb #else
389413628a7SBjoern A. Zeeb 		if (j->ip4s != 0)
390413628a7SBjoern A. Zeeb 			return (EINVAL);
391413628a7SBjoern A. Zeeb #endif
392413628a7SBjoern A. Zeeb #ifdef INET6
393413628a7SBjoern A. Zeeb 		if (j->ip6s > jail_max_af_ips)
394413628a7SBjoern A. Zeeb 			return (EINVAL);
395413628a7SBjoern A. Zeeb #else
396413628a7SBjoern A. Zeeb 		if (j->ip6s != 0)
397413628a7SBjoern A. Zeeb 			return (EINVAL);
398413628a7SBjoern A. Zeeb #endif
399413628a7SBjoern A. Zeeb 		error = jail_copyin_ips(j);
400413628a7SBjoern A. Zeeb 		if (error)
401413628a7SBjoern A. Zeeb 			return (error);
402413628a7SBjoern A. Zeeb #endif
403413628a7SBjoern A. Zeeb 		break;
404413628a7SBjoern A. Zeeb 
405413628a7SBjoern A. Zeeb 	default:
406413628a7SBjoern A. Zeeb 		/* Sci-Fi jails are not supported, sorry. */
407413628a7SBjoern A. Zeeb 		return (EINVAL);
408413628a7SBjoern A. Zeeb 	}
409413628a7SBjoern A. Zeeb 
410413628a7SBjoern A. Zeeb 	return (0);
411413628a7SBjoern A. Zeeb }
412413628a7SBjoern A. Zeeb 
413413628a7SBjoern A. Zeeb 
414116734c4SMatthew Dillon /*
4159ddb7954SMike Barcroft  * struct jail_args {
4169ddb7954SMike Barcroft  *	struct jail *jail;
4179ddb7954SMike Barcroft  * };
418116734c4SMatthew Dillon  */
41975c13541SPoul-Henning Kamp int
4209ddb7954SMike Barcroft jail(struct thread *td, struct jail_args *uap)
42175c13541SPoul-Henning Kamp {
422413628a7SBjoern A. Zeeb 	uint32_t version;
423413628a7SBjoern A. Zeeb 	int error;
424413628a7SBjoern A. Zeeb 	struct jail j;
425413628a7SBjoern A. Zeeb 
426413628a7SBjoern A. Zeeb 	error = copyin(uap->jail, &version, sizeof(uint32_t));
427413628a7SBjoern A. Zeeb 	if (error)
428413628a7SBjoern A. Zeeb 		return (error);
429413628a7SBjoern A. Zeeb 
430413628a7SBjoern A. Zeeb 	switch (version) {
431413628a7SBjoern A. Zeeb 	case 0:
432413628a7SBjoern A. Zeeb 		/* FreeBSD single IPv4 jails. */
433413628a7SBjoern A. Zeeb 	{
434413628a7SBjoern A. Zeeb 		struct jail_v0 j0;
435413628a7SBjoern A. Zeeb 
436413628a7SBjoern A. Zeeb 		bzero(&j, sizeof(struct jail));
437413628a7SBjoern A. Zeeb 		error = copyin(uap->jail, &j0, sizeof(struct jail_v0));
438413628a7SBjoern A. Zeeb 		if (error)
439413628a7SBjoern A. Zeeb 			return (error);
440413628a7SBjoern A. Zeeb 		j.version = j0.version;
441413628a7SBjoern A. Zeeb 		j.path = j0.path;
442413628a7SBjoern A. Zeeb 		j.hostname = j0.hostname;
443413628a7SBjoern A. Zeeb 		j.ip4s = j0.ip_number;
444413628a7SBjoern A. Zeeb 		break;
445413628a7SBjoern A. Zeeb 	}
446413628a7SBjoern A. Zeeb 
447413628a7SBjoern A. Zeeb 	case 1:
448413628a7SBjoern A. Zeeb 		/*
449413628a7SBjoern A. Zeeb 		 * Version 1 was used by multi-IPv4 jail implementations
450413628a7SBjoern A. Zeeb 		 * that never made it into the official kernel.
451413628a7SBjoern A. Zeeb 		 */
452413628a7SBjoern A. Zeeb 		return (EINVAL);
453413628a7SBjoern A. Zeeb 
454413628a7SBjoern A. Zeeb 	case 2:	/* JAIL_API_VERSION */
455413628a7SBjoern A. Zeeb 		/* FreeBSD multi-IPv4/IPv6,noIP jails. */
456413628a7SBjoern A. Zeeb 		error = copyin(uap->jail, &j, sizeof(struct jail));
457413628a7SBjoern A. Zeeb 		if (error)
458413628a7SBjoern A. Zeeb 			return (error);
459413628a7SBjoern A. Zeeb 		break;
460413628a7SBjoern A. Zeeb 
461413628a7SBjoern A. Zeeb 	default:
462413628a7SBjoern A. Zeeb 		/* Sci-Fi jails are not supported, sorry. */
463413628a7SBjoern A. Zeeb 		return (EINVAL);
464413628a7SBjoern A. Zeeb 	}
465413628a7SBjoern A. Zeeb 	return (kern_jail(td, &j));
466413628a7SBjoern A. Zeeb }
467413628a7SBjoern A. Zeeb 
468413628a7SBjoern A. Zeeb int
469413628a7SBjoern A. Zeeb kern_jail(struct thread *td, struct jail *j)
470413628a7SBjoern A. Zeeb {
471fd7a8150SMike Barcroft 	struct nameidata nd;
4722110d913SXin LI 	struct prison *pr, *tpr;
473fd7a8150SMike Barcroft 	struct jail_attach_args jaa;
4742110d913SXin LI 	int vfslocked, error, tryprid;
47575c13541SPoul-Henning Kamp 
476413628a7SBjoern A. Zeeb 	KASSERT(j != NULL, ("%s: j is NULL", __func__));
477413628a7SBjoern A. Zeeb 
478413628a7SBjoern A. Zeeb 	/* Handle addresses - convert old structs, copyin, check IPs. */
479413628a7SBjoern A. Zeeb 	error = jail_handle_ips(j);
48075c13541SPoul-Henning Kamp 	if (error)
481a2f2b3afSJohn Baldwin 		return (error);
482a2f2b3afSJohn Baldwin 
483413628a7SBjoern A. Zeeb 	/* Allocate struct prison and fill it with life. */
4841ede983cSDag-Erling Smørgrav 	pr = malloc(sizeof(*pr), M_PRISON, M_WAITOK | M_ZERO);
4856008862bSJohn Baldwin 	mtx_init(&pr->pr_mtx, "jail mutex", NULL, MTX_DEF);
486fd7a8150SMike Barcroft 	pr->pr_ref = 1;
487413628a7SBjoern A. Zeeb 	error = copyinstr(j->path, &pr->pr_path, sizeof(pr->pr_path), NULL);
488fd7a8150SMike Barcroft 	if (error)
489fd7a8150SMike Barcroft 		goto e_killmtx;
490453f7d53SChristian S.J. Peron 	NDINIT(&nd, LOOKUP, MPSAFE | FOLLOW | LOCKLEAF, UIO_SYSSPACE,
491453f7d53SChristian S.J. Peron 	    pr->pr_path, td);
492fd7a8150SMike Barcroft 	error = namei(&nd);
493453f7d53SChristian S.J. Peron 	if (error)
494fd7a8150SMike Barcroft 		goto e_killmtx;
495453f7d53SChristian S.J. Peron 	vfslocked = NDHASGIANT(&nd);
496fd7a8150SMike Barcroft 	pr->pr_root = nd.ni_vp;
49722db15c0SAttilio Rao 	VOP_UNLOCK(nd.ni_vp, 0);
498fd7a8150SMike Barcroft 	NDFREE(&nd, NDF_ONLY_PNBUF);
499453f7d53SChristian S.J. Peron 	VFS_UNLOCK_GIANT(vfslocked);
500413628a7SBjoern A. Zeeb 	error = copyinstr(j->hostname, &pr->pr_host, sizeof(pr->pr_host), NULL);
50175c13541SPoul-Henning Kamp 	if (error)
502fd7a8150SMike Barcroft 		goto e_dropvnref;
503413628a7SBjoern A. Zeeb 	if (j->jailname != NULL) {
504413628a7SBjoern A. Zeeb 		error = copyinstr(j->jailname, &pr->pr_name,
505413628a7SBjoern A. Zeeb 		    sizeof(pr->pr_name), NULL);
506413628a7SBjoern A. Zeeb 		if (error)
507413628a7SBjoern A. Zeeb 			goto e_dropvnref;
508413628a7SBjoern A. Zeeb 	}
509413628a7SBjoern A. Zeeb 	if (j->ip4s > 0) {
510413628a7SBjoern A. Zeeb 		pr->pr_ip4 = j->ip4;
511413628a7SBjoern A. Zeeb 		pr->pr_ip4s = j->ip4s;
512413628a7SBjoern A. Zeeb 	}
513413628a7SBjoern A. Zeeb #ifdef INET6
514413628a7SBjoern A. Zeeb 	if (j->ip6s > 0) {
515413628a7SBjoern A. Zeeb 		pr->pr_ip6 = j->ip6;
516413628a7SBjoern A. Zeeb 		pr->pr_ip6s = j->ip6s;
517413628a7SBjoern A. Zeeb 	}
518413628a7SBjoern A. Zeeb #endif
519fd7a8150SMike Barcroft 	pr->pr_linux = NULL;
520fd7a8150SMike Barcroft 	pr->pr_securelevel = securelevel;
5211ba4a712SPawel Jakub Dawidek 	bzero(&pr->pr_osd, sizeof(pr->pr_osd));
522fd7a8150SMike Barcroft 
523413628a7SBjoern A. Zeeb 	/*
524413628a7SBjoern A. Zeeb 	 * Pre-set prison state to ALIVE upon cration.  This is needed so we
525413628a7SBjoern A. Zeeb 	 * can later attach the process to it, etc (avoiding another extra
526413628a7SBjoern A. Zeeb 	 * state for ther process of creation, complicating things).
527413628a7SBjoern A. Zeeb 	 */
528413628a7SBjoern A. Zeeb 	pr->pr_state = PRISON_STATE_ALIVE;
529413628a7SBjoern A. Zeeb 
530413628a7SBjoern A. Zeeb 	/* Allocate a dedicated cpuset for each jail. */
531413628a7SBjoern A. Zeeb 	error = cpuset_create_root(td, &pr->pr_cpuset);
532413628a7SBjoern A. Zeeb 	if (error)
533413628a7SBjoern A. Zeeb 		goto e_dropvnref;
534413628a7SBjoern A. Zeeb 
535dc68a633SPawel Jakub Dawidek 	sx_xlock(&allprison_lock);
536413628a7SBjoern A. Zeeb 	/* Make sure we cannot run into problems with ambiguous bind()ings. */
537d465a41dSBjoern A. Zeeb #if defined(INET) || defined(INET6)
538413628a7SBjoern A. Zeeb 	error = prison_check_conflicting_ips(pr);
539413628a7SBjoern A. Zeeb 	if (error) {
540413628a7SBjoern A. Zeeb 		sx_xunlock(&allprison_lock);
541413628a7SBjoern A. Zeeb 		goto e_dropcpuset;
542413628a7SBjoern A. Zeeb 	}
543d465a41dSBjoern A. Zeeb #endif
544413628a7SBjoern A. Zeeb 
545413628a7SBjoern A. Zeeb 	/* Determine next pr_id and add prison to allprison list. */
5462110d913SXin LI 	tryprid = lastprid + 1;
5472110d913SXin LI 	if (tryprid == JAIL_MAX)
5482110d913SXin LI 		tryprid = 1;
5492110d913SXin LI next:
5502110d913SXin LI 	LIST_FOREACH(tpr, &allprison, pr_list) {
5512110d913SXin LI 		if (tpr->pr_id == tryprid) {
5522110d913SXin LI 			tryprid++;
5532110d913SXin LI 			if (tryprid == JAIL_MAX) {
5542110d913SXin LI 				sx_xunlock(&allprison_lock);
5552110d913SXin LI 				error = EAGAIN;
556413628a7SBjoern A. Zeeb 				goto e_dropcpuset;
5572110d913SXin LI 			}
5582110d913SXin LI 			goto next;
5592110d913SXin LI 		}
5602110d913SXin LI 	}
5612110d913SXin LI 	pr->pr_id = jaa.jid = lastprid = tryprid;
562fd7a8150SMike Barcroft 	LIST_INSERT_HEAD(&allprison, pr, pr_list);
563fd7a8150SMike Barcroft 	prisoncount++;
5641ba4a712SPawel Jakub Dawidek 	sx_xunlock(&allprison_lock);
565fd7a8150SMike Barcroft 
566fd7a8150SMike Barcroft 	error = jail_attach(td, &jaa);
567a2f2b3afSJohn Baldwin 	if (error)
568fd7a8150SMike Barcroft 		goto e_dropprref;
569fd7a8150SMike Barcroft 	mtx_lock(&pr->pr_mtx);
570fd7a8150SMike Barcroft 	pr->pr_ref--;
571fd7a8150SMike Barcroft 	mtx_unlock(&pr->pr_mtx);
572fd7a8150SMike Barcroft 	td->td_retval[0] = jaa.jid;
57375c13541SPoul-Henning Kamp 	return (0);
574fd7a8150SMike Barcroft e_dropprref:
575dc68a633SPawel Jakub Dawidek 	sx_xlock(&allprison_lock);
576fd7a8150SMike Barcroft 	LIST_REMOVE(pr, pr_list);
577fd7a8150SMike Barcroft 	prisoncount--;
5781ba4a712SPawel Jakub Dawidek 	sx_xunlock(&allprison_lock);
579413628a7SBjoern A. Zeeb e_dropcpuset:
580413628a7SBjoern A. Zeeb 	cpuset_rel(pr->pr_cpuset);
581fd7a8150SMike Barcroft e_dropvnref:
582453f7d53SChristian S.J. Peron 	vfslocked = VFS_LOCK_GIANT(pr->pr_root->v_mount);
583fd7a8150SMike Barcroft 	vrele(pr->pr_root);
584453f7d53SChristian S.J. Peron 	VFS_UNLOCK_GIANT(vfslocked);
585fd7a8150SMike Barcroft e_killmtx:
586894db7b0SMaxime Henrion 	mtx_destroy(&pr->pr_mtx);
5871ede983cSDag-Erling Smørgrav 	free(pr, M_PRISON);
588413628a7SBjoern A. Zeeb #ifdef INET6
589413628a7SBjoern A. Zeeb 	free(j->ip6, M_PRISON);
590413628a7SBjoern A. Zeeb #endif
591413628a7SBjoern A. Zeeb #ifdef INET
592413628a7SBjoern A. Zeeb 	free(j->ip4, M_PRISON);
593413628a7SBjoern A. Zeeb #endif
59475c13541SPoul-Henning Kamp 	return (error);
59575c13541SPoul-Henning Kamp }
59675c13541SPoul-Henning Kamp 
597fd7a8150SMike Barcroft /*
5989ddb7954SMike Barcroft  * struct jail_attach_args {
5999ddb7954SMike Barcroft  *	int jid;
6009ddb7954SMike Barcroft  * };
601fd7a8150SMike Barcroft  */
602fd7a8150SMike Barcroft int
6039ddb7954SMike Barcroft jail_attach(struct thread *td, struct jail_attach_args *uap)
604fd7a8150SMike Barcroft {
605fd7a8150SMike Barcroft 	struct proc *p;
606fd7a8150SMike Barcroft 	struct ucred *newcred, *oldcred;
607fd7a8150SMike Barcroft 	struct prison *pr;
608453f7d53SChristian S.J. Peron 	int vfslocked, error;
609fd7a8150SMike Barcroft 
61057f22bd4SJacques Vidrine 	/*
61157f22bd4SJacques Vidrine 	 * XXX: Note that there is a slight race here if two threads
61257f22bd4SJacques Vidrine 	 * in the same privileged process attempt to attach to two
61357f22bd4SJacques Vidrine 	 * different jails at the same time.  It is important for
61457f22bd4SJacques Vidrine 	 * user processes not to do this, or they might end up with
61557f22bd4SJacques Vidrine 	 * a process root from one prison, but attached to the jail
61657f22bd4SJacques Vidrine 	 * of another.
61757f22bd4SJacques Vidrine 	 */
618800c9408SRobert Watson 	error = priv_check(td, PRIV_JAIL_ATTACH);
61957f22bd4SJacques Vidrine 	if (error)
62057f22bd4SJacques Vidrine 		return (error);
621fd7a8150SMike Barcroft 
62257f22bd4SJacques Vidrine 	p = td->td_proc;
623dc68a633SPawel Jakub Dawidek 	sx_slock(&allprison_lock);
624fd7a8150SMike Barcroft 	pr = prison_find(uap->jid);
625fd7a8150SMike Barcroft 	if (pr == NULL) {
626dc68a633SPawel Jakub Dawidek 		sx_sunlock(&allprison_lock);
627fd7a8150SMike Barcroft 		return (EINVAL);
628fd7a8150SMike Barcroft 	}
629413628a7SBjoern A. Zeeb 
630413628a7SBjoern A. Zeeb 	/*
631413628a7SBjoern A. Zeeb 	 * Do not allow a process to attach to a prison that is not
632413628a7SBjoern A. Zeeb 	 * considered to be "ALIVE".
633413628a7SBjoern A. Zeeb 	 */
634413628a7SBjoern A. Zeeb 	if (pr->pr_state != PRISON_STATE_ALIVE) {
635413628a7SBjoern A. Zeeb 		mtx_unlock(&pr->pr_mtx);
636413628a7SBjoern A. Zeeb 		sx_sunlock(&allprison_lock);
637413628a7SBjoern A. Zeeb 		return (EINVAL);
638413628a7SBjoern A. Zeeb 	}
639fd7a8150SMike Barcroft 	pr->pr_ref++;
640fd7a8150SMike Barcroft 	mtx_unlock(&pr->pr_mtx);
641dc68a633SPawel Jakub Dawidek 	sx_sunlock(&allprison_lock);
642fd7a8150SMike Barcroft 
643413628a7SBjoern A. Zeeb 	/*
644413628a7SBjoern A. Zeeb 	 * Reparent the newly attached process to this jail.
645413628a7SBjoern A. Zeeb 	 */
646413628a7SBjoern A. Zeeb 	error = cpuset_setproc_update_set(p, pr->pr_cpuset);
647413628a7SBjoern A. Zeeb 	if (error)
648413628a7SBjoern A. Zeeb 		goto e_unref;
649413628a7SBjoern A. Zeeb 
650453f7d53SChristian S.J. Peron 	vfslocked = VFS_LOCK_GIANT(pr->pr_root->v_mount);
651cb05b60aSAttilio Rao 	vn_lock(pr->pr_root, LK_EXCLUSIVE | LK_RETRY);
652fd7a8150SMike Barcroft 	if ((error = change_dir(pr->pr_root, td)) != 0)
653fd7a8150SMike Barcroft 		goto e_unlock;
654fd7a8150SMike Barcroft #ifdef MAC
65530d239bcSRobert Watson 	if ((error = mac_vnode_check_chroot(td->td_ucred, pr->pr_root)))
656fd7a8150SMike Barcroft 		goto e_unlock;
657fd7a8150SMike Barcroft #endif
65822db15c0SAttilio Rao 	VOP_UNLOCK(pr->pr_root, 0);
659fd7a8150SMike Barcroft 	change_root(pr->pr_root, td);
660453f7d53SChristian S.J. Peron 	VFS_UNLOCK_GIANT(vfslocked);
661fd7a8150SMike Barcroft 
662fd7a8150SMike Barcroft 	newcred = crget();
663fd7a8150SMike Barcroft 	PROC_LOCK(p);
664fd7a8150SMike Barcroft 	oldcred = p->p_ucred;
665fd7a8150SMike Barcroft 	setsugid(p);
666fd7a8150SMike Barcroft 	crcopy(newcred, oldcred);
66769c4ee54SJohn Baldwin 	newcred->cr_prison = pr;
668fd7a8150SMike Barcroft 	p->p_ucred = newcred;
669413628a7SBjoern A. Zeeb 	prison_proc_hold(pr);
670fd7a8150SMike Barcroft 	PROC_UNLOCK(p);
671fd7a8150SMike Barcroft 	crfree(oldcred);
672fd7a8150SMike Barcroft 	return (0);
673fd7a8150SMike Barcroft e_unlock:
67422db15c0SAttilio Rao 	VOP_UNLOCK(pr->pr_root, 0);
675453f7d53SChristian S.J. Peron 	VFS_UNLOCK_GIANT(vfslocked);
676413628a7SBjoern A. Zeeb e_unref:
677fd7a8150SMike Barcroft 	mtx_lock(&pr->pr_mtx);
678fd7a8150SMike Barcroft 	pr->pr_ref--;
679fd7a8150SMike Barcroft 	mtx_unlock(&pr->pr_mtx);
680fd7a8150SMike Barcroft 	return (error);
681fd7a8150SMike Barcroft }
682fd7a8150SMike Barcroft 
683fd7a8150SMike Barcroft /*
684fd7a8150SMike Barcroft  * Returns a locked prison instance, or NULL on failure.
685fd7a8150SMike Barcroft  */
68654b369c1SPawel Jakub Dawidek struct prison *
687fd7a8150SMike Barcroft prison_find(int prid)
688fd7a8150SMike Barcroft {
689fd7a8150SMike Barcroft 	struct prison *pr;
690fd7a8150SMike Barcroft 
691dc68a633SPawel Jakub Dawidek 	sx_assert(&allprison_lock, SX_LOCKED);
692fd7a8150SMike Barcroft 	LIST_FOREACH(pr, &allprison, pr_list) {
693fd7a8150SMike Barcroft 		if (pr->pr_id == prid) {
694fd7a8150SMike Barcroft 			mtx_lock(&pr->pr_mtx);
695c2cda609SPawel Jakub Dawidek 			if (pr->pr_ref == 0) {
696c2cda609SPawel Jakub Dawidek 				mtx_unlock(&pr->pr_mtx);
697c2cda609SPawel Jakub Dawidek 				break;
698c2cda609SPawel Jakub Dawidek 			}
699fd7a8150SMike Barcroft 			return (pr);
700fd7a8150SMike Barcroft 		}
701fd7a8150SMike Barcroft 	}
702fd7a8150SMike Barcroft 	return (NULL);
703fd7a8150SMike Barcroft }
704fd7a8150SMike Barcroft 
70591421ba2SRobert Watson void
7061ba4a712SPawel Jakub Dawidek prison_free_locked(struct prison *pr)
70791421ba2SRobert Watson {
70891421ba2SRobert Watson 
7091ba4a712SPawel Jakub Dawidek 	mtx_assert(&pr->pr_mtx, MA_OWNED);
71091421ba2SRobert Watson 	pr->pr_ref--;
71191421ba2SRobert Watson 	if (pr->pr_ref == 0) {
71201137630SRobert Watson 		mtx_unlock(&pr->pr_mtx);
713c2cda609SPawel Jakub Dawidek 		TASK_INIT(&pr->pr_task, 0, prison_complete, pr);
714c2cda609SPawel Jakub Dawidek 		taskqueue_enqueue(taskqueue_thread, &pr->pr_task);
715c2cda609SPawel Jakub Dawidek 		return;
716c2cda609SPawel Jakub Dawidek 	}
717c2cda609SPawel Jakub Dawidek 	mtx_unlock(&pr->pr_mtx);
718c2cda609SPawel Jakub Dawidek }
719c2cda609SPawel Jakub Dawidek 
7201ba4a712SPawel Jakub Dawidek void
7211ba4a712SPawel Jakub Dawidek prison_free(struct prison *pr)
7221ba4a712SPawel Jakub Dawidek {
7231ba4a712SPawel Jakub Dawidek 
7241ba4a712SPawel Jakub Dawidek 	mtx_lock(&pr->pr_mtx);
7251ba4a712SPawel Jakub Dawidek 	prison_free_locked(pr);
7261ba4a712SPawel Jakub Dawidek }
7271ba4a712SPawel Jakub Dawidek 
728c2cda609SPawel Jakub Dawidek static void
729c2cda609SPawel Jakub Dawidek prison_complete(void *context, int pending)
730c2cda609SPawel Jakub Dawidek {
731c2cda609SPawel Jakub Dawidek 	struct prison *pr;
732c2cda609SPawel Jakub Dawidek 	int vfslocked;
733c2cda609SPawel Jakub Dawidek 
734c2cda609SPawel Jakub Dawidek 	pr = (struct prison *)context;
735c2cda609SPawel Jakub Dawidek 
736c2cda609SPawel Jakub Dawidek 	sx_xlock(&allprison_lock);
737264de85eSPawel Jakub Dawidek 	LIST_REMOVE(pr, pr_list);
738fd7a8150SMike Barcroft 	prisoncount--;
7391ba4a712SPawel Jakub Dawidek 	sx_xunlock(&allprison_lock);
7401ba4a712SPawel Jakub Dawidek 
741413628a7SBjoern A. Zeeb 	cpuset_rel(pr->pr_cpuset);
742413628a7SBjoern A. Zeeb 
7431ba4a712SPawel Jakub Dawidek 	/* Free all OSD associated to this jail. */
7441ba4a712SPawel Jakub Dawidek 	osd_jail_exit(pr);
745b3059e09SRobert Watson 
746453f7d53SChristian S.J. Peron 	vfslocked = VFS_LOCK_GIANT(pr->pr_root->v_mount);
747b3059e09SRobert Watson 	vrele(pr->pr_root);
748453f7d53SChristian S.J. Peron 	VFS_UNLOCK_GIANT(vfslocked);
749b3059e09SRobert Watson 
750b3059e09SRobert Watson 	mtx_destroy(&pr->pr_mtx);
7511ede983cSDag-Erling Smørgrav 	free(pr->pr_linux, M_PRISON);
752413628a7SBjoern A. Zeeb #ifdef INET6
753413628a7SBjoern A. Zeeb 	free(pr->pr_ip6, M_PRISON);
754413628a7SBjoern A. Zeeb #endif
755413628a7SBjoern A. Zeeb #ifdef INET
756413628a7SBjoern A. Zeeb 	free(pr->pr_ip4, M_PRISON);
757413628a7SBjoern A. Zeeb #endif
7581ede983cSDag-Erling Smørgrav 	free(pr, M_PRISON);
759b3059e09SRobert Watson }
760b3059e09SRobert Watson 
76191421ba2SRobert Watson void
7621ba4a712SPawel Jakub Dawidek prison_hold_locked(struct prison *pr)
7631ba4a712SPawel Jakub Dawidek {
7641ba4a712SPawel Jakub Dawidek 
7651ba4a712SPawel Jakub Dawidek 	mtx_assert(&pr->pr_mtx, MA_OWNED);
7661ba4a712SPawel Jakub Dawidek 	KASSERT(pr->pr_ref > 0,
7671ba4a712SPawel Jakub Dawidek 	    ("Trying to hold dead prison (id=%d).", pr->pr_id));
7681ba4a712SPawel Jakub Dawidek 	pr->pr_ref++;
7691ba4a712SPawel Jakub Dawidek }
7701ba4a712SPawel Jakub Dawidek 
7711ba4a712SPawel Jakub Dawidek void
77291421ba2SRobert Watson prison_hold(struct prison *pr)
77391421ba2SRobert Watson {
77491421ba2SRobert Watson 
77501137630SRobert Watson 	mtx_lock(&pr->pr_mtx);
7761ba4a712SPawel Jakub Dawidek 	prison_hold_locked(pr);
77701137630SRobert Watson 	mtx_unlock(&pr->pr_mtx);
77801137630SRobert Watson }
77901137630SRobert Watson 
780413628a7SBjoern A. Zeeb void
781413628a7SBjoern A. Zeeb prison_proc_hold(struct prison *pr)
78201137630SRobert Watson {
78301137630SRobert Watson 
784413628a7SBjoern A. Zeeb 	mtx_lock(&pr->pr_mtx);
785413628a7SBjoern A. Zeeb 	KASSERT(pr->pr_state == PRISON_STATE_ALIVE,
786413628a7SBjoern A. Zeeb 	    ("Cannot add a process to a non-alive prison (id=%d).", pr->pr_id));
787413628a7SBjoern A. Zeeb 	pr->pr_nprocs++;
788413628a7SBjoern A. Zeeb 	mtx_unlock(&pr->pr_mtx);
78975c13541SPoul-Henning Kamp }
79075c13541SPoul-Henning Kamp 
79175c13541SPoul-Henning Kamp void
792413628a7SBjoern A. Zeeb prison_proc_free(struct prison *pr)
79375c13541SPoul-Henning Kamp {
794413628a7SBjoern A. Zeeb 
795413628a7SBjoern A. Zeeb 	mtx_lock(&pr->pr_mtx);
796413628a7SBjoern A. Zeeb 	KASSERT(pr->pr_state == PRISON_STATE_ALIVE && pr->pr_nprocs > 0,
797413628a7SBjoern A. Zeeb 	    ("Trying to kill a process in a dead prison (id=%d).", pr->pr_id));
798413628a7SBjoern A. Zeeb 	pr->pr_nprocs--;
799413628a7SBjoern A. Zeeb 	if (pr->pr_nprocs == 0)
800413628a7SBjoern A. Zeeb 		pr->pr_state = PRISON_STATE_DYING;
801413628a7SBjoern A. Zeeb 	mtx_unlock(&pr->pr_mtx);
802413628a7SBjoern A. Zeeb }
803413628a7SBjoern A. Zeeb 
804413628a7SBjoern A. Zeeb 
805413628a7SBjoern A. Zeeb #ifdef INET
806413628a7SBjoern A. Zeeb /*
807413628a7SBjoern A. Zeeb  * Pass back primary IPv4 address of this jail.
808413628a7SBjoern A. Zeeb  *
809413628a7SBjoern A. Zeeb  * If not jailed return success but do not alter the address.  Caller has to
810b89e82ddSJamie Gritton  * make sure to intialize it correctly (e.g. INADDR_ANY).
811413628a7SBjoern A. Zeeb  *
812b89e82ddSJamie Gritton  * Returns 0 on success, EAFNOSUPPORT if the jail doesn't allow IPv4.
813b89e82ddSJamie Gritton  * Address returned in NBO.
814413628a7SBjoern A. Zeeb  */
815413628a7SBjoern A. Zeeb int
8161cecba0fSBjoern A. Zeeb prison_get_ip4(struct ucred *cred, struct in_addr *ia)
817413628a7SBjoern A. Zeeb {
818413628a7SBjoern A. Zeeb 
819413628a7SBjoern A. Zeeb 	KASSERT(cred != NULL, ("%s: cred is NULL", __func__));
820413628a7SBjoern A. Zeeb 	KASSERT(ia != NULL, ("%s: ia is NULL", __func__));
82175c13541SPoul-Henning Kamp 
82291421ba2SRobert Watson 	if (!jailed(cred))
823413628a7SBjoern A. Zeeb 		/* Do not change address passed in. */
824413628a7SBjoern A. Zeeb 		return (0);
825413628a7SBjoern A. Zeeb 
826413628a7SBjoern A. Zeeb 	if (cred->cr_prison->pr_ip4 == NULL)
827b89e82ddSJamie Gritton 		return (EAFNOSUPPORT);
828413628a7SBjoern A. Zeeb 
829413628a7SBjoern A. Zeeb 	ia->s_addr = cred->cr_prison->pr_ip4[0].s_addr;
830413628a7SBjoern A. Zeeb 	return (0);
83175c13541SPoul-Henning Kamp }
832413628a7SBjoern A. Zeeb 
833413628a7SBjoern A. Zeeb /*
834413628a7SBjoern A. Zeeb  * Make sure our (source) address is set to something meaningful to this
835413628a7SBjoern A. Zeeb  * jail.
836413628a7SBjoern A. Zeeb  *
837b89e82ddSJamie Gritton  * Returns 0 if not jailed or if address belongs to jail, EADDRNOTAVAIL if
838b89e82ddSJamie Gritton  * the address doesn't belong, or EAFNOSUPPORT if the jail doesn't allow IPv4.
839b89e82ddSJamie Gritton  * Address passed in in NBO and returned in NBO.
840413628a7SBjoern A. Zeeb  */
841413628a7SBjoern A. Zeeb int
842413628a7SBjoern A. Zeeb prison_local_ip4(struct ucred *cred, struct in_addr *ia)
843413628a7SBjoern A. Zeeb {
844413628a7SBjoern A. Zeeb 	struct in_addr ia0;
845413628a7SBjoern A. Zeeb 
846413628a7SBjoern A. Zeeb 	KASSERT(cred != NULL, ("%s: cred is NULL", __func__));
847413628a7SBjoern A. Zeeb 	KASSERT(ia != NULL, ("%s: ia is NULL", __func__));
848413628a7SBjoern A. Zeeb 
849413628a7SBjoern A. Zeeb 	if (!jailed(cred))
850413628a7SBjoern A. Zeeb 		return (0);
851413628a7SBjoern A. Zeeb 	if (cred->cr_prison->pr_ip4 == NULL)
852b89e82ddSJamie Gritton 		return (EAFNOSUPPORT);
853413628a7SBjoern A. Zeeb 
854413628a7SBjoern A. Zeeb 	ia0.s_addr = ntohl(ia->s_addr);
855413628a7SBjoern A. Zeeb 	if (ia0.s_addr == INADDR_LOOPBACK) {
856413628a7SBjoern A. Zeeb 		ia->s_addr = cred->cr_prison->pr_ip4[0].s_addr;
857413628a7SBjoern A. Zeeb 		return (0);
858413628a7SBjoern A. Zeeb 	}
859413628a7SBjoern A. Zeeb 
860b89e82ddSJamie Gritton 	if (ia0.s_addr == INADDR_ANY) {
861413628a7SBjoern A. Zeeb 		/*
862413628a7SBjoern A. Zeeb 		 * In case there is only 1 IPv4 address, bind directly.
863413628a7SBjoern A. Zeeb 		 */
864b89e82ddSJamie Gritton 		if (cred->cr_prison->pr_ip4s == 1)
865413628a7SBjoern A. Zeeb 			ia->s_addr = cred->cr_prison->pr_ip4[0].s_addr;
866413628a7SBjoern A. Zeeb 		return (0);
867413628a7SBjoern A. Zeeb 	}
868413628a7SBjoern A. Zeeb 
869b89e82ddSJamie Gritton 	return (_prison_check_ip4(cred->cr_prison, ia));
870413628a7SBjoern A. Zeeb }
871413628a7SBjoern A. Zeeb 
872413628a7SBjoern A. Zeeb /*
873413628a7SBjoern A. Zeeb  * Rewrite destination address in case we will connect to loopback address.
874413628a7SBjoern A. Zeeb  *
875b89e82ddSJamie Gritton  * Returns 0 on success, EAFNOSUPPORT if the jail doesn't allow IPv4.
876b89e82ddSJamie Gritton  * Address passed in in NBO and returned in NBO.
877413628a7SBjoern A. Zeeb  */
878413628a7SBjoern A. Zeeb int
879413628a7SBjoern A. Zeeb prison_remote_ip4(struct ucred *cred, struct in_addr *ia)
880413628a7SBjoern A. Zeeb {
881413628a7SBjoern A. Zeeb 
882413628a7SBjoern A. Zeeb 	KASSERT(cred != NULL, ("%s: cred is NULL", __func__));
883413628a7SBjoern A. Zeeb 	KASSERT(ia != NULL, ("%s: ia is NULL", __func__));
884413628a7SBjoern A. Zeeb 
885413628a7SBjoern A. Zeeb 	if (!jailed(cred))
886413628a7SBjoern A. Zeeb 		return (0);
887413628a7SBjoern A. Zeeb 	if (cred->cr_prison->pr_ip4 == NULL)
888b89e82ddSJamie Gritton 		return (EAFNOSUPPORT);
889b89e82ddSJamie Gritton 
890413628a7SBjoern A. Zeeb 	if (ntohl(ia->s_addr) == INADDR_LOOPBACK) {
891413628a7SBjoern A. Zeeb 		ia->s_addr = cred->cr_prison->pr_ip4[0].s_addr;
892413628a7SBjoern A. Zeeb 		return (0);
893413628a7SBjoern A. Zeeb 	}
894413628a7SBjoern A. Zeeb 
895413628a7SBjoern A. Zeeb 	/*
896413628a7SBjoern A. Zeeb 	 * Return success because nothing had to be changed.
897413628a7SBjoern A. Zeeb 	 */
898413628a7SBjoern A. Zeeb 	return (0);
899413628a7SBjoern A. Zeeb }
900413628a7SBjoern A. Zeeb 
901413628a7SBjoern A. Zeeb /*
902b89e82ddSJamie Gritton  * Check if given address belongs to the jail referenced by cred/prison.
903413628a7SBjoern A. Zeeb  *
904b89e82ddSJamie Gritton  * Returns 0 if not jailed or if address belongs to jail, EADDRNOTAVAIL if
905b89e82ddSJamie Gritton  * the address doesn't belong, or EAFNOSUPPORT if the jail doesn't allow IPv4.
906b89e82ddSJamie Gritton  * Address passed in in NBO.
907413628a7SBjoern A. Zeeb  */
908413628a7SBjoern A. Zeeb static int
909413628a7SBjoern A. Zeeb _prison_check_ip4(struct prison *pr, struct in_addr *ia)
910413628a7SBjoern A. Zeeb {
911413628a7SBjoern A. Zeeb 	int i, a, z, d;
912413628a7SBjoern A. Zeeb 
913413628a7SBjoern A. Zeeb 	/*
914413628a7SBjoern A. Zeeb 	 * Check the primary IP.
915413628a7SBjoern A. Zeeb 	 */
916413628a7SBjoern A. Zeeb 	if (pr->pr_ip4[0].s_addr == ia->s_addr)
917b89e82ddSJamie Gritton 		return (0);
918413628a7SBjoern A. Zeeb 
919413628a7SBjoern A. Zeeb 	/*
920413628a7SBjoern A. Zeeb 	 * All the other IPs are sorted so we can do a binary search.
921413628a7SBjoern A. Zeeb 	 */
922413628a7SBjoern A. Zeeb 	a = 0;
923413628a7SBjoern A. Zeeb 	z = pr->pr_ip4s - 2;
924413628a7SBjoern A. Zeeb 	while (a <= z) {
925413628a7SBjoern A. Zeeb 		i = (a + z) / 2;
926413628a7SBjoern A. Zeeb 		d = qcmp_v4(&pr->pr_ip4[i+1], ia);
927413628a7SBjoern A. Zeeb 		if (d > 0)
928413628a7SBjoern A. Zeeb 			z = i - 1;
929413628a7SBjoern A. Zeeb 		else if (d < 0)
930413628a7SBjoern A. Zeeb 			a = i + 1;
931413628a7SBjoern A. Zeeb 		else
932413628a7SBjoern A. Zeeb 			return (0);
93375c13541SPoul-Henning Kamp 	}
93475c13541SPoul-Henning Kamp 
935b89e82ddSJamie Gritton 	return (EADDRNOTAVAIL);
936b89e82ddSJamie Gritton }
937b89e82ddSJamie Gritton 
93875c13541SPoul-Henning Kamp int
939413628a7SBjoern A. Zeeb prison_check_ip4(struct ucred *cred, struct in_addr *ia)
940413628a7SBjoern A. Zeeb {
941413628a7SBjoern A. Zeeb 
942413628a7SBjoern A. Zeeb 	KASSERT(cred != NULL, ("%s: cred is NULL", __func__));
943413628a7SBjoern A. Zeeb 	KASSERT(ia != NULL, ("%s: ia is NULL", __func__));
944413628a7SBjoern A. Zeeb 
945413628a7SBjoern A. Zeeb 	if (!jailed(cred))
946b89e82ddSJamie Gritton 		return (0);
947b89e82ddSJamie Gritton 	if (cred->cr_prison->pr_ip4 == NULL)
948b89e82ddSJamie Gritton 		return (EAFNOSUPPORT);
949413628a7SBjoern A. Zeeb 
950413628a7SBjoern A. Zeeb 	return (_prison_check_ip4(cred->cr_prison, ia));
951413628a7SBjoern A. Zeeb }
952413628a7SBjoern A. Zeeb #endif
953413628a7SBjoern A. Zeeb 
954413628a7SBjoern A. Zeeb #ifdef INET6
955413628a7SBjoern A. Zeeb /*
956413628a7SBjoern A. Zeeb  * Pass back primary IPv6 address for this jail.
957413628a7SBjoern A. Zeeb  *
958413628a7SBjoern A. Zeeb  * If not jailed return success but do not alter the address.  Caller has to
959b89e82ddSJamie Gritton  * make sure to intialize it correctly (e.g. IN6ADDR_ANY_INIT).
960413628a7SBjoern A. Zeeb  *
961b89e82ddSJamie Gritton  * Returns 0 on success, EAFNOSUPPORT if the jail doesn't allow IPv6.
962413628a7SBjoern A. Zeeb  */
963413628a7SBjoern A. Zeeb int
9641cecba0fSBjoern A. Zeeb prison_get_ip6(struct ucred *cred, struct in6_addr *ia6)
965413628a7SBjoern A. Zeeb {
966413628a7SBjoern A. Zeeb 
967413628a7SBjoern A. Zeeb 	KASSERT(cred != NULL, ("%s: cred is NULL", __func__));
968413628a7SBjoern A. Zeeb 	KASSERT(ia6 != NULL, ("%s: ia6 is NULL", __func__));
969413628a7SBjoern A. Zeeb 
970413628a7SBjoern A. Zeeb 	if (!jailed(cred))
971413628a7SBjoern A. Zeeb 		return (0);
972413628a7SBjoern A. Zeeb 	if (cred->cr_prison->pr_ip6 == NULL)
973b89e82ddSJamie Gritton 		return (EAFNOSUPPORT);
974b89e82ddSJamie Gritton 
975413628a7SBjoern A. Zeeb 	bcopy(&cred->cr_prison->pr_ip6[0], ia6, sizeof(struct in6_addr));
976413628a7SBjoern A. Zeeb 	return (0);
977413628a7SBjoern A. Zeeb }
978413628a7SBjoern A. Zeeb 
979413628a7SBjoern A. Zeeb /*
980413628a7SBjoern A. Zeeb  * Make sure our (source) address is set to something meaningful to this jail.
981413628a7SBjoern A. Zeeb  *
982413628a7SBjoern A. Zeeb  * v6only should be set based on (inp->inp_flags & IN6P_IPV6_V6ONLY != 0)
983413628a7SBjoern A. Zeeb  * when needed while binding.
984413628a7SBjoern A. Zeeb  *
985b89e82ddSJamie Gritton  * Returns 0 if not jailed or if address belongs to jail, EADDRNOTAVAIL if
986b89e82ddSJamie Gritton  * the address doesn't belong, or EAFNOSUPPORT if the jail doesn't allow IPv6.
987413628a7SBjoern A. Zeeb  */
988413628a7SBjoern A. Zeeb int
989413628a7SBjoern A. Zeeb prison_local_ip6(struct ucred *cred, struct in6_addr *ia6, int v6only)
990413628a7SBjoern A. Zeeb {
991413628a7SBjoern A. Zeeb 
992413628a7SBjoern A. Zeeb 	KASSERT(cred != NULL, ("%s: cred is NULL", __func__));
993413628a7SBjoern A. Zeeb 	KASSERT(ia6 != NULL, ("%s: ia6 is NULL", __func__));
994413628a7SBjoern A. Zeeb 
995413628a7SBjoern A. Zeeb 	if (!jailed(cred))
996413628a7SBjoern A. Zeeb 		return (0);
997413628a7SBjoern A. Zeeb 	if (cred->cr_prison->pr_ip6 == NULL)
998b89e82ddSJamie Gritton 		return (EAFNOSUPPORT);
999b89e82ddSJamie Gritton 
1000413628a7SBjoern A. Zeeb 	if (IN6_IS_ADDR_LOOPBACK(ia6)) {
1001413628a7SBjoern A. Zeeb 		bcopy(&cred->cr_prison->pr_ip6[0], ia6,
1002413628a7SBjoern A. Zeeb 		    sizeof(struct in6_addr));
1003413628a7SBjoern A. Zeeb 		return (0);
1004413628a7SBjoern A. Zeeb 	}
1005413628a7SBjoern A. Zeeb 
1006b89e82ddSJamie Gritton 	if (IN6_IS_ADDR_UNSPECIFIED(ia6)) {
1007413628a7SBjoern A. Zeeb 		/*
1008b89e82ddSJamie Gritton 		 * In case there is only 1 IPv6 address, and v6only is true,
1009b89e82ddSJamie Gritton 		 * then bind directly.
1010413628a7SBjoern A. Zeeb 		 */
1011b89e82ddSJamie Gritton 		if (v6only != 0 && cred->cr_prison->pr_ip6s == 1)
1012413628a7SBjoern A. Zeeb 			bcopy(&cred->cr_prison->pr_ip6[0], ia6,
1013413628a7SBjoern A. Zeeb 			    sizeof(struct in6_addr));
1014413628a7SBjoern A. Zeeb 		return (0);
1015413628a7SBjoern A. Zeeb 	}
1016b89e82ddSJamie Gritton 
1017b89e82ddSJamie Gritton 	return (_prison_check_ip6(cred->cr_prison, ia6));
1018413628a7SBjoern A. Zeeb }
1019413628a7SBjoern A. Zeeb 
1020413628a7SBjoern A. Zeeb /*
1021413628a7SBjoern A. Zeeb  * Rewrite destination address in case we will connect to loopback address.
1022413628a7SBjoern A. Zeeb  *
1023b89e82ddSJamie Gritton  * Returns 0 on success, EAFNOSUPPORT if the jail doesn't allow IPv6.
1024413628a7SBjoern A. Zeeb  */
1025413628a7SBjoern A. Zeeb int
1026413628a7SBjoern A. Zeeb prison_remote_ip6(struct ucred *cred, struct in6_addr *ia6)
1027413628a7SBjoern A. Zeeb {
1028413628a7SBjoern A. Zeeb 
1029413628a7SBjoern A. Zeeb 	KASSERT(cred != NULL, ("%s: cred is NULL", __func__));
1030413628a7SBjoern A. Zeeb 	KASSERT(ia6 != NULL, ("%s: ia6 is NULL", __func__));
1031413628a7SBjoern A. Zeeb 
1032413628a7SBjoern A. Zeeb 	if (!jailed(cred))
1033413628a7SBjoern A. Zeeb 		return (0);
1034413628a7SBjoern A. Zeeb 	if (cred->cr_prison->pr_ip6 == NULL)
1035b89e82ddSJamie Gritton 		return (EAFNOSUPPORT);
1036b89e82ddSJamie Gritton 
1037413628a7SBjoern A. Zeeb 	if (IN6_IS_ADDR_LOOPBACK(ia6)) {
1038413628a7SBjoern A. Zeeb 		bcopy(&cred->cr_prison->pr_ip6[0], ia6,
1039413628a7SBjoern A. Zeeb 		    sizeof(struct in6_addr));
1040413628a7SBjoern A. Zeeb 		return (0);
1041413628a7SBjoern A. Zeeb 	}
1042413628a7SBjoern A. Zeeb 
1043413628a7SBjoern A. Zeeb 	/*
1044413628a7SBjoern A. Zeeb 	 * Return success because nothing had to be changed.
1045413628a7SBjoern A. Zeeb 	 */
1046413628a7SBjoern A. Zeeb 	return (0);
1047413628a7SBjoern A. Zeeb }
1048413628a7SBjoern A. Zeeb 
1049413628a7SBjoern A. Zeeb /*
1050b89e82ddSJamie Gritton  * Check if given address belongs to the jail referenced by cred/prison.
1051413628a7SBjoern A. Zeeb  *
1052b89e82ddSJamie Gritton  * Returns 0 if not jailed or if address belongs to jail, EADDRNOTAVAIL if
1053b89e82ddSJamie Gritton  * the address doesn't belong, or EAFNOSUPPORT if the jail doesn't allow IPv6.
1054413628a7SBjoern A. Zeeb  */
1055413628a7SBjoern A. Zeeb static int
1056413628a7SBjoern A. Zeeb _prison_check_ip6(struct prison *pr, struct in6_addr *ia6)
1057413628a7SBjoern A. Zeeb {
1058413628a7SBjoern A. Zeeb 	int i, a, z, d;
1059413628a7SBjoern A. Zeeb 
1060413628a7SBjoern A. Zeeb 	/*
1061413628a7SBjoern A. Zeeb 	 * Check the primary IP.
1062413628a7SBjoern A. Zeeb 	 */
1063413628a7SBjoern A. Zeeb 	if (IN6_ARE_ADDR_EQUAL(&pr->pr_ip6[0], ia6))
1064b89e82ddSJamie Gritton 		return (0);
1065413628a7SBjoern A. Zeeb 
1066413628a7SBjoern A. Zeeb 	/*
1067413628a7SBjoern A. Zeeb 	 * All the other IPs are sorted so we can do a binary search.
1068413628a7SBjoern A. Zeeb 	 */
1069413628a7SBjoern A. Zeeb 	a = 0;
1070413628a7SBjoern A. Zeeb 	z = pr->pr_ip6s - 2;
1071413628a7SBjoern A. Zeeb 	while (a <= z) {
1072413628a7SBjoern A. Zeeb 		i = (a + z) / 2;
1073413628a7SBjoern A. Zeeb 		d = qcmp_v6(&pr->pr_ip6[i+1], ia6);
1074413628a7SBjoern A. Zeeb 		if (d > 0)
1075413628a7SBjoern A. Zeeb 			z = i - 1;
1076413628a7SBjoern A. Zeeb 		else if (d < 0)
1077413628a7SBjoern A. Zeeb 			a = i + 1;
1078413628a7SBjoern A. Zeeb 		else
1079413628a7SBjoern A. Zeeb 			return (0);
1080413628a7SBjoern A. Zeeb 	}
1081413628a7SBjoern A. Zeeb 
1082b89e82ddSJamie Gritton 	return (EADDRNOTAVAIL);
1083b89e82ddSJamie Gritton }
1084b89e82ddSJamie Gritton 
1085413628a7SBjoern A. Zeeb int
1086413628a7SBjoern A. Zeeb prison_check_ip6(struct ucred *cred, struct in6_addr *ia6)
1087413628a7SBjoern A. Zeeb {
1088413628a7SBjoern A. Zeeb 
1089413628a7SBjoern A. Zeeb 	KASSERT(cred != NULL, ("%s: cred is NULL", __func__));
1090413628a7SBjoern A. Zeeb 	KASSERT(ia6 != NULL, ("%s: ia6 is NULL", __func__));
1091413628a7SBjoern A. Zeeb 
1092413628a7SBjoern A. Zeeb 	if (!jailed(cred))
1093b89e82ddSJamie Gritton 		return (0);
1094b89e82ddSJamie Gritton 	if (cred->cr_prison->pr_ip6 == NULL)
1095b89e82ddSJamie Gritton 		return (EAFNOSUPPORT);
1096413628a7SBjoern A. Zeeb 
1097413628a7SBjoern A. Zeeb 	return (_prison_check_ip6(cred->cr_prison, ia6));
1098413628a7SBjoern A. Zeeb }
1099413628a7SBjoern A. Zeeb #endif
1100413628a7SBjoern A. Zeeb 
1101413628a7SBjoern A. Zeeb /*
1102413628a7SBjoern A. Zeeb  * Check if given address belongs to the jail referenced by cred (wrapper to
1103413628a7SBjoern A. Zeeb  * prison_check_ip[46]).
1104413628a7SBjoern A. Zeeb  *
1105b89e82ddSJamie Gritton  * Returns 0 if not jailed or if address belongs to jail, EADDRNOTAVAIL if
1106b89e82ddSJamie Gritton  * the address doesn't belong, or EAFNOSUPPORT if the jail doesn't allow
1107b89e82ddSJamie Gritton  * the address family.  IPv4 Address passed in in NBO.
1108413628a7SBjoern A. Zeeb  */
1109413628a7SBjoern A. Zeeb int
111091421ba2SRobert Watson prison_if(struct ucred *cred, struct sockaddr *sa)
111175c13541SPoul-Henning Kamp {
1112413628a7SBjoern A. Zeeb #ifdef INET
11139ddb7954SMike Barcroft 	struct sockaddr_in *sai;
1114413628a7SBjoern A. Zeeb #endif
1115413628a7SBjoern A. Zeeb #ifdef INET6
1116413628a7SBjoern A. Zeeb 	struct sockaddr_in6 *sai6;
1117413628a7SBjoern A. Zeeb #endif
1118b89e82ddSJamie Gritton 	int error;
111975c13541SPoul-Henning Kamp 
1120413628a7SBjoern A. Zeeb 	KASSERT(cred != NULL, ("%s: cred is NULL", __func__));
1121413628a7SBjoern A. Zeeb 	KASSERT(sa != NULL, ("%s: sa is NULL", __func__));
1122413628a7SBjoern A. Zeeb 
1123b89e82ddSJamie Gritton 	error = 0;
1124413628a7SBjoern A. Zeeb 	switch (sa->sa_family)
1125413628a7SBjoern A. Zeeb 	{
1126413628a7SBjoern A. Zeeb #ifdef INET
1127413628a7SBjoern A. Zeeb 	case AF_INET:
11289ddb7954SMike Barcroft 		sai = (struct sockaddr_in *)sa;
1129b89e82ddSJamie Gritton 		error = prison_check_ip4(cred, &sai->sin_addr);
1130413628a7SBjoern A. Zeeb 		break;
1131413628a7SBjoern A. Zeeb #endif
1132413628a7SBjoern A. Zeeb #ifdef INET6
1133413628a7SBjoern A. Zeeb 	case AF_INET6:
1134413628a7SBjoern A. Zeeb 		sai6 = (struct sockaddr_in6 *)sa;
1135b89e82ddSJamie Gritton 		error = prison_check_ip6(cred, &sai6->sin6_addr);
1136413628a7SBjoern A. Zeeb 		break;
1137413628a7SBjoern A. Zeeb #endif
1138413628a7SBjoern A. Zeeb 	default:
1139b89e82ddSJamie Gritton 		if (jailed(cred) && jail_socket_unixiproute_only)
1140b89e82ddSJamie Gritton 			error = EAFNOSUPPORT;
1141413628a7SBjoern A. Zeeb 	}
1142b89e82ddSJamie Gritton 	return (error);
114375c13541SPoul-Henning Kamp }
114491421ba2SRobert Watson 
114591421ba2SRobert Watson /*
114691421ba2SRobert Watson  * Return 0 if jails permit p1 to frob p2, otherwise ESRCH.
114791421ba2SRobert Watson  */
114891421ba2SRobert Watson int
11499ddb7954SMike Barcroft prison_check(struct ucred *cred1, struct ucred *cred2)
115091421ba2SRobert Watson {
115191421ba2SRobert Watson 
115291421ba2SRobert Watson 	if (jailed(cred1)) {
115391421ba2SRobert Watson 		if (!jailed(cred2))
115491421ba2SRobert Watson 			return (ESRCH);
115591421ba2SRobert Watson 		if (cred2->cr_prison != cred1->cr_prison)
115691421ba2SRobert Watson 			return (ESRCH);
115791421ba2SRobert Watson 	}
115891421ba2SRobert Watson 
115991421ba2SRobert Watson 	return (0);
116091421ba2SRobert Watson }
116191421ba2SRobert Watson 
116291421ba2SRobert Watson /*
116391421ba2SRobert Watson  * Return 1 if the passed credential is in a jail, otherwise 0.
116491421ba2SRobert Watson  */
116591421ba2SRobert Watson int
11669ddb7954SMike Barcroft jailed(struct ucred *cred)
116791421ba2SRobert Watson {
116891421ba2SRobert Watson 
116991421ba2SRobert Watson 	return (cred->cr_prison != NULL);
117091421ba2SRobert Watson }
11719484d0c0SRobert Drehmel 
11729484d0c0SRobert Drehmel /*
11739484d0c0SRobert Drehmel  * Return the correct hostname for the passed credential.
11749484d0c0SRobert Drehmel  */
1175ad1ff099SRobert Drehmel void
11769ddb7954SMike Barcroft getcredhostname(struct ucred *cred, char *buf, size_t size)
11779484d0c0SRobert Drehmel {
11788b615593SMarko Zec 	INIT_VPROCG(cred->cr_vimage->v_procg);
11799484d0c0SRobert Drehmel 
1180ad1ff099SRobert Drehmel 	if (jailed(cred)) {
1181ad1ff099SRobert Drehmel 		mtx_lock(&cred->cr_prison->pr_mtx);
1182e80fb434SRobert Drehmel 		strlcpy(buf, cred->cr_prison->pr_host, size);
1183ad1ff099SRobert Drehmel 		mtx_unlock(&cred->cr_prison->pr_mtx);
11844f7d1876SRobert Watson 	} else {
11854f7d1876SRobert Watson 		mtx_lock(&hostname_mtx);
1186603724d3SBjoern A. Zeeb 		strlcpy(buf, V_hostname, size);
11874f7d1876SRobert Watson 		mtx_unlock(&hostname_mtx);
11884f7d1876SRobert Watson 	}
11899484d0c0SRobert Drehmel }
1190fd7a8150SMike Barcroft 
1191f08df373SRobert Watson /*
1192820a0de9SPawel Jakub Dawidek  * Determine whether the subject represented by cred can "see"
1193820a0de9SPawel Jakub Dawidek  * status of a mount point.
1194820a0de9SPawel Jakub Dawidek  * Returns: 0 for permitted, ENOENT otherwise.
1195820a0de9SPawel Jakub Dawidek  * XXX: This function should be called cr_canseemount() and should be
1196820a0de9SPawel Jakub Dawidek  *      placed in kern_prot.c.
1197f08df373SRobert Watson  */
1198f08df373SRobert Watson int
1199820a0de9SPawel Jakub Dawidek prison_canseemount(struct ucred *cred, struct mount *mp)
1200f08df373SRobert Watson {
1201820a0de9SPawel Jakub Dawidek 	struct prison *pr;
1202820a0de9SPawel Jakub Dawidek 	struct statfs *sp;
1203820a0de9SPawel Jakub Dawidek 	size_t len;
1204f08df373SRobert Watson 
1205820a0de9SPawel Jakub Dawidek 	if (!jailed(cred) || jail_enforce_statfs == 0)
1206820a0de9SPawel Jakub Dawidek 		return (0);
1207820a0de9SPawel Jakub Dawidek 	pr = cred->cr_prison;
1208820a0de9SPawel Jakub Dawidek 	if (pr->pr_root->v_mount == mp)
1209820a0de9SPawel Jakub Dawidek 		return (0);
1210820a0de9SPawel Jakub Dawidek 	if (jail_enforce_statfs == 2)
1211820a0de9SPawel Jakub Dawidek 		return (ENOENT);
1212820a0de9SPawel Jakub Dawidek 	/*
1213820a0de9SPawel Jakub Dawidek 	 * If jail's chroot directory is set to "/" we should be able to see
1214820a0de9SPawel Jakub Dawidek 	 * all mount-points from inside a jail.
1215820a0de9SPawel Jakub Dawidek 	 * This is ugly check, but this is the only situation when jail's
1216820a0de9SPawel Jakub Dawidek 	 * directory ends with '/'.
1217820a0de9SPawel Jakub Dawidek 	 */
1218820a0de9SPawel Jakub Dawidek 	if (strcmp(pr->pr_path, "/") == 0)
1219820a0de9SPawel Jakub Dawidek 		return (0);
1220820a0de9SPawel Jakub Dawidek 	len = strlen(pr->pr_path);
1221820a0de9SPawel Jakub Dawidek 	sp = &mp->mnt_stat;
1222820a0de9SPawel Jakub Dawidek 	if (strncmp(pr->pr_path, sp->f_mntonname, len) != 0)
1223820a0de9SPawel Jakub Dawidek 		return (ENOENT);
1224820a0de9SPawel Jakub Dawidek 	/*
1225820a0de9SPawel Jakub Dawidek 	 * Be sure that we don't have situation where jail's root directory
1226820a0de9SPawel Jakub Dawidek 	 * is "/some/path" and mount point is "/some/pathpath".
1227820a0de9SPawel Jakub Dawidek 	 */
1228820a0de9SPawel Jakub Dawidek 	if (sp->f_mntonname[len] != '\0' && sp->f_mntonname[len] != '/')
1229820a0de9SPawel Jakub Dawidek 		return (ENOENT);
1230f08df373SRobert Watson 	return (0);
1231f08df373SRobert Watson }
1232820a0de9SPawel Jakub Dawidek 
1233820a0de9SPawel Jakub Dawidek void
1234820a0de9SPawel Jakub Dawidek prison_enforce_statfs(struct ucred *cred, struct mount *mp, struct statfs *sp)
1235820a0de9SPawel Jakub Dawidek {
1236820a0de9SPawel Jakub Dawidek 	char jpath[MAXPATHLEN];
1237820a0de9SPawel Jakub Dawidek 	struct prison *pr;
1238820a0de9SPawel Jakub Dawidek 	size_t len;
1239820a0de9SPawel Jakub Dawidek 
1240820a0de9SPawel Jakub Dawidek 	if (!jailed(cred) || jail_enforce_statfs == 0)
1241820a0de9SPawel Jakub Dawidek 		return;
1242820a0de9SPawel Jakub Dawidek 	pr = cred->cr_prison;
1243820a0de9SPawel Jakub Dawidek 	if (prison_canseemount(cred, mp) != 0) {
1244820a0de9SPawel Jakub Dawidek 		bzero(sp->f_mntonname, sizeof(sp->f_mntonname));
1245820a0de9SPawel Jakub Dawidek 		strlcpy(sp->f_mntonname, "[restricted]",
1246820a0de9SPawel Jakub Dawidek 		    sizeof(sp->f_mntonname));
1247820a0de9SPawel Jakub Dawidek 		return;
1248820a0de9SPawel Jakub Dawidek 	}
1249820a0de9SPawel Jakub Dawidek 	if (pr->pr_root->v_mount == mp) {
1250820a0de9SPawel Jakub Dawidek 		/*
1251820a0de9SPawel Jakub Dawidek 		 * Clear current buffer data, so we are sure nothing from
1252820a0de9SPawel Jakub Dawidek 		 * the valid path left there.
1253820a0de9SPawel Jakub Dawidek 		 */
1254820a0de9SPawel Jakub Dawidek 		bzero(sp->f_mntonname, sizeof(sp->f_mntonname));
1255820a0de9SPawel Jakub Dawidek 		*sp->f_mntonname = '/';
1256820a0de9SPawel Jakub Dawidek 		return;
1257820a0de9SPawel Jakub Dawidek 	}
1258820a0de9SPawel Jakub Dawidek 	/*
1259820a0de9SPawel Jakub Dawidek 	 * If jail's chroot directory is set to "/" we should be able to see
1260820a0de9SPawel Jakub Dawidek 	 * all mount-points from inside a jail.
1261820a0de9SPawel Jakub Dawidek 	 */
1262820a0de9SPawel Jakub Dawidek 	if (strcmp(pr->pr_path, "/") == 0)
1263820a0de9SPawel Jakub Dawidek 		return;
1264820a0de9SPawel Jakub Dawidek 	len = strlen(pr->pr_path);
1265820a0de9SPawel Jakub Dawidek 	strlcpy(jpath, sp->f_mntonname + len, sizeof(jpath));
1266820a0de9SPawel Jakub Dawidek 	/*
1267820a0de9SPawel Jakub Dawidek 	 * Clear current buffer data, so we are sure nothing from
1268820a0de9SPawel Jakub Dawidek 	 * the valid path left there.
1269820a0de9SPawel Jakub Dawidek 	 */
1270820a0de9SPawel Jakub Dawidek 	bzero(sp->f_mntonname, sizeof(sp->f_mntonname));
1271820a0de9SPawel Jakub Dawidek 	if (*jpath == '\0') {
1272820a0de9SPawel Jakub Dawidek 		/* Should never happen. */
1273820a0de9SPawel Jakub Dawidek 		*sp->f_mntonname = '/';
1274820a0de9SPawel Jakub Dawidek 	} else {
1275820a0de9SPawel Jakub Dawidek 		strlcpy(sp->f_mntonname, jpath, sizeof(sp->f_mntonname));
1276820a0de9SPawel Jakub Dawidek 	}
1277f08df373SRobert Watson }
1278f08df373SRobert Watson 
1279800c9408SRobert Watson /*
1280800c9408SRobert Watson  * Check with permission for a specific privilege is granted within jail.  We
1281800c9408SRobert Watson  * have a specific list of accepted privileges; the rest are denied.
1282800c9408SRobert Watson  */
1283800c9408SRobert Watson int
1284800c9408SRobert Watson prison_priv_check(struct ucred *cred, int priv)
1285800c9408SRobert Watson {
1286800c9408SRobert Watson 
1287800c9408SRobert Watson 	if (!jailed(cred))
1288800c9408SRobert Watson 		return (0);
1289800c9408SRobert Watson 
1290800c9408SRobert Watson 	switch (priv) {
1291800c9408SRobert Watson 
1292800c9408SRobert Watson 		/*
1293800c9408SRobert Watson 		 * Allow ktrace privileges for root in jail.
1294800c9408SRobert Watson 		 */
1295800c9408SRobert Watson 	case PRIV_KTRACE:
1296800c9408SRobert Watson 
1297c3c1b5e6SRobert Watson #if 0
1298800c9408SRobert Watson 		/*
1299800c9408SRobert Watson 		 * Allow jailed processes to configure audit identity and
1300800c9408SRobert Watson 		 * submit audit records (login, etc).  In the future we may
1301800c9408SRobert Watson 		 * want to further refine the relationship between audit and
1302800c9408SRobert Watson 		 * jail.
1303800c9408SRobert Watson 		 */
1304800c9408SRobert Watson 	case PRIV_AUDIT_GETAUDIT:
1305800c9408SRobert Watson 	case PRIV_AUDIT_SETAUDIT:
1306800c9408SRobert Watson 	case PRIV_AUDIT_SUBMIT:
1307c3c1b5e6SRobert Watson #endif
1308800c9408SRobert Watson 
1309800c9408SRobert Watson 		/*
1310800c9408SRobert Watson 		 * Allow jailed processes to manipulate process UNIX
1311800c9408SRobert Watson 		 * credentials in any way they see fit.
1312800c9408SRobert Watson 		 */
1313800c9408SRobert Watson 	case PRIV_CRED_SETUID:
1314800c9408SRobert Watson 	case PRIV_CRED_SETEUID:
1315800c9408SRobert Watson 	case PRIV_CRED_SETGID:
1316800c9408SRobert Watson 	case PRIV_CRED_SETEGID:
1317800c9408SRobert Watson 	case PRIV_CRED_SETGROUPS:
1318800c9408SRobert Watson 	case PRIV_CRED_SETREUID:
1319800c9408SRobert Watson 	case PRIV_CRED_SETREGID:
1320800c9408SRobert Watson 	case PRIV_CRED_SETRESUID:
1321800c9408SRobert Watson 	case PRIV_CRED_SETRESGID:
1322800c9408SRobert Watson 
1323800c9408SRobert Watson 		/*
1324800c9408SRobert Watson 		 * Jail implements visibility constraints already, so allow
1325800c9408SRobert Watson 		 * jailed root to override uid/gid-based constraints.
1326800c9408SRobert Watson 		 */
1327800c9408SRobert Watson 	case PRIV_SEEOTHERGIDS:
1328800c9408SRobert Watson 	case PRIV_SEEOTHERUIDS:
1329800c9408SRobert Watson 
1330800c9408SRobert Watson 		/*
1331800c9408SRobert Watson 		 * Jail implements inter-process debugging limits already, so
1332800c9408SRobert Watson 		 * allow jailed root various debugging privileges.
1333800c9408SRobert Watson 		 */
1334800c9408SRobert Watson 	case PRIV_DEBUG_DIFFCRED:
1335800c9408SRobert Watson 	case PRIV_DEBUG_SUGID:
1336800c9408SRobert Watson 	case PRIV_DEBUG_UNPRIV:
1337800c9408SRobert Watson 
1338800c9408SRobert Watson 		/*
1339800c9408SRobert Watson 		 * Allow jail to set various resource limits and login
1340800c9408SRobert Watson 		 * properties, and for now, exceed process resource limits.
1341800c9408SRobert Watson 		 */
1342800c9408SRobert Watson 	case PRIV_PROC_LIMIT:
1343800c9408SRobert Watson 	case PRIV_PROC_SETLOGIN:
1344800c9408SRobert Watson 	case PRIV_PROC_SETRLIMIT:
1345800c9408SRobert Watson 
1346800c9408SRobert Watson 		/*
1347800c9408SRobert Watson 		 * System V and POSIX IPC privileges are granted in jail.
1348800c9408SRobert Watson 		 */
1349800c9408SRobert Watson 	case PRIV_IPC_READ:
1350800c9408SRobert Watson 	case PRIV_IPC_WRITE:
1351800c9408SRobert Watson 	case PRIV_IPC_ADMIN:
1352800c9408SRobert Watson 	case PRIV_IPC_MSGSIZE:
1353800c9408SRobert Watson 	case PRIV_MQ_ADMIN:
1354800c9408SRobert Watson 
1355800c9408SRobert Watson 		/*
1356800c9408SRobert Watson 		 * Jail implements its own inter-process limits, so allow
1357800c9408SRobert Watson 		 * root processes in jail to change scheduling on other
1358800c9408SRobert Watson 		 * processes in the same jail.  Likewise for signalling.
1359800c9408SRobert Watson 		 */
1360800c9408SRobert Watson 	case PRIV_SCHED_DIFFCRED:
1361413628a7SBjoern A. Zeeb 	case PRIV_SCHED_CPUSET:
1362800c9408SRobert Watson 	case PRIV_SIGNAL_DIFFCRED:
1363800c9408SRobert Watson 	case PRIV_SIGNAL_SUGID:
1364800c9408SRobert Watson 
1365800c9408SRobert Watson 		/*
1366800c9408SRobert Watson 		 * Allow jailed processes to write to sysctls marked as jail
1367800c9408SRobert Watson 		 * writable.
1368800c9408SRobert Watson 		 */
1369800c9408SRobert Watson 	case PRIV_SYSCTL_WRITEJAIL:
1370800c9408SRobert Watson 
1371800c9408SRobert Watson 		/*
1372800c9408SRobert Watson 		 * Allow root in jail to manage a variety of quota
1373e82d0201SRobert Watson 		 * properties.  These should likely be conditional on a
1374e82d0201SRobert Watson 		 * configuration option.
1375800c9408SRobert Watson 		 */
137695b091d2SRobert Watson 	case PRIV_VFS_GETQUOTA:
137795b091d2SRobert Watson 	case PRIV_VFS_SETQUOTA:
1378800c9408SRobert Watson 
1379800c9408SRobert Watson 		/*
1380800c9408SRobert Watson 		 * Since Jail relies on chroot() to implement file system
1381800c9408SRobert Watson 		 * protections, grant many VFS privileges to root in jail.
1382800c9408SRobert Watson 		 * Be careful to exclude mount-related and NFS-related
1383800c9408SRobert Watson 		 * privileges.
1384800c9408SRobert Watson 		 */
1385800c9408SRobert Watson 	case PRIV_VFS_READ:
1386800c9408SRobert Watson 	case PRIV_VFS_WRITE:
1387800c9408SRobert Watson 	case PRIV_VFS_ADMIN:
1388800c9408SRobert Watson 	case PRIV_VFS_EXEC:
1389800c9408SRobert Watson 	case PRIV_VFS_LOOKUP:
1390800c9408SRobert Watson 	case PRIV_VFS_BLOCKRESERVE:	/* XXXRW: Slightly surprising. */
1391800c9408SRobert Watson 	case PRIV_VFS_CHFLAGS_DEV:
1392800c9408SRobert Watson 	case PRIV_VFS_CHOWN:
1393800c9408SRobert Watson 	case PRIV_VFS_CHROOT:
1394bb531912SPawel Jakub Dawidek 	case PRIV_VFS_RETAINSUGID:
1395800c9408SRobert Watson 	case PRIV_VFS_FCHROOT:
1396800c9408SRobert Watson 	case PRIV_VFS_LINK:
1397800c9408SRobert Watson 	case PRIV_VFS_SETGID:
1398e41966dcSRobert Watson 	case PRIV_VFS_STAT:
1399800c9408SRobert Watson 	case PRIV_VFS_STICKYFILE:
1400800c9408SRobert Watson 		return (0);
1401800c9408SRobert Watson 
1402800c9408SRobert Watson 		/*
1403800c9408SRobert Watson 		 * Depending on the global setting, allow privilege of
1404800c9408SRobert Watson 		 * setting system flags.
1405800c9408SRobert Watson 		 */
1406800c9408SRobert Watson 	case PRIV_VFS_SYSFLAGS:
1407800c9408SRobert Watson 		if (jail_chflags_allowed)
1408800c9408SRobert Watson 			return (0);
1409800c9408SRobert Watson 		else
1410800c9408SRobert Watson 			return (EPERM);
1411800c9408SRobert Watson 
1412800c9408SRobert Watson 		/*
1413f3a8d2f9SPawel Jakub Dawidek 		 * Depending on the global setting, allow privilege of
1414f3a8d2f9SPawel Jakub Dawidek 		 * mounting/unmounting file systems.
1415f3a8d2f9SPawel Jakub Dawidek 		 */
1416f3a8d2f9SPawel Jakub Dawidek 	case PRIV_VFS_MOUNT:
1417f3a8d2f9SPawel Jakub Dawidek 	case PRIV_VFS_UNMOUNT:
1418f3a8d2f9SPawel Jakub Dawidek 	case PRIV_VFS_MOUNT_NONUSER:
141924b0502eSPawel Jakub Dawidek 	case PRIV_VFS_MOUNT_OWNER:
1420f3a8d2f9SPawel Jakub Dawidek 		if (jail_mount_allowed)
1421f3a8d2f9SPawel Jakub Dawidek 			return (0);
1422f3a8d2f9SPawel Jakub Dawidek 		else
1423f3a8d2f9SPawel Jakub Dawidek 			return (EPERM);
1424f3a8d2f9SPawel Jakub Dawidek 
1425f3a8d2f9SPawel Jakub Dawidek 		/*
14264b084056SRobert Watson 		 * Allow jailed root to bind reserved ports and reuse in-use
14274b084056SRobert Watson 		 * ports.
1428800c9408SRobert Watson 		 */
1429800c9408SRobert Watson 	case PRIV_NETINET_RESERVEDPORT:
14304b084056SRobert Watson 	case PRIV_NETINET_REUSEPORT:
1431800c9408SRobert Watson 		return (0);
1432800c9408SRobert Watson 
1433800c9408SRobert Watson 		/*
143479ba3952SBjoern A. Zeeb 		 * Allow jailed root to set certian IPv4/6 (option) headers.
143579ba3952SBjoern A. Zeeb 		 */
143679ba3952SBjoern A. Zeeb 	case PRIV_NETINET_SETHDROPTS:
143779ba3952SBjoern A. Zeeb 		return (0);
143879ba3952SBjoern A. Zeeb 
143979ba3952SBjoern A. Zeeb 		/*
1440800c9408SRobert Watson 		 * Conditionally allow creating raw sockets in jail.
1441800c9408SRobert Watson 		 */
1442800c9408SRobert Watson 	case PRIV_NETINET_RAW:
1443800c9408SRobert Watson 		if (jail_allow_raw_sockets)
1444800c9408SRobert Watson 			return (0);
1445800c9408SRobert Watson 		else
1446800c9408SRobert Watson 			return (EPERM);
1447800c9408SRobert Watson 
1448800c9408SRobert Watson 		/*
1449800c9408SRobert Watson 		 * Since jail implements its own visibility limits on netstat
1450800c9408SRobert Watson 		 * sysctls, allow getcred.  This allows identd to work in
1451800c9408SRobert Watson 		 * jail.
1452800c9408SRobert Watson 		 */
1453800c9408SRobert Watson 	case PRIV_NETINET_GETCRED:
1454800c9408SRobert Watson 		return (0);
1455800c9408SRobert Watson 
1456800c9408SRobert Watson 	default:
1457800c9408SRobert Watson 		/*
1458800c9408SRobert Watson 		 * In all remaining cases, deny the privilege request.  This
1459800c9408SRobert Watson 		 * includes almost all network privileges, many system
1460800c9408SRobert Watson 		 * configuration privileges.
1461800c9408SRobert Watson 		 */
1462800c9408SRobert Watson 		return (EPERM);
1463800c9408SRobert Watson 	}
1464800c9408SRobert Watson }
1465800c9408SRobert Watson 
1466fd7a8150SMike Barcroft static int
1467fd7a8150SMike Barcroft sysctl_jail_list(SYSCTL_HANDLER_ARGS)
1468fd7a8150SMike Barcroft {
1469fd7a8150SMike Barcroft 	struct xprison *xp, *sxp;
1470fd7a8150SMike Barcroft 	struct prison *pr;
1471413628a7SBjoern A. Zeeb 	char *p;
1472413628a7SBjoern A. Zeeb 	size_t len;
1473fd7a8150SMike Barcroft 	int count, error;
1474fd7a8150SMike Barcroft 
14757f4704c0SPawel Jakub Dawidek 	if (jailed(req->td->td_ucred))
1476679a1060SRobert Watson 		return (0);
1477fd7a8150SMike Barcroft 
1478dc68a633SPawel Jakub Dawidek 	sx_slock(&allprison_lock);
1479dc68a633SPawel Jakub Dawidek 	if ((count = prisoncount) == 0) {
1480dc68a633SPawel Jakub Dawidek 		sx_sunlock(&allprison_lock);
1481fd7a8150SMike Barcroft 		return (0);
1482dc68a633SPawel Jakub Dawidek 	}
1483fd7a8150SMike Barcroft 
1484413628a7SBjoern A. Zeeb 	len = sizeof(*xp) * count;
1485413628a7SBjoern A. Zeeb 	LIST_FOREACH(pr, &allprison, pr_list) {
1486413628a7SBjoern A. Zeeb #ifdef INET
1487413628a7SBjoern A. Zeeb 		len += pr->pr_ip4s * sizeof(struct in_addr);
1488413628a7SBjoern A. Zeeb #endif
1489413628a7SBjoern A. Zeeb #ifdef INET6
1490413628a7SBjoern A. Zeeb 		len += pr->pr_ip6s * sizeof(struct in6_addr);
1491413628a7SBjoern A. Zeeb #endif
1492413628a7SBjoern A. Zeeb 	}
1493413628a7SBjoern A. Zeeb 
1494413628a7SBjoern A. Zeeb 	sxp = xp = malloc(len, M_TEMP, M_WAITOK | M_ZERO);
1495fd7a8150SMike Barcroft 
1496fd7a8150SMike Barcroft 	LIST_FOREACH(pr, &allprison, pr_list) {
1497fd7a8150SMike Barcroft 		xp->pr_version = XPRISON_VERSION;
1498fd7a8150SMike Barcroft 		xp->pr_id = pr->pr_id;
1499413628a7SBjoern A. Zeeb 		xp->pr_state = pr->pr_state;
1500413628a7SBjoern A. Zeeb 		xp->pr_cpusetid = pr->pr_cpuset->cs_id;
1501b63b0c65SPawel Jakub Dawidek 		strlcpy(xp->pr_path, pr->pr_path, sizeof(xp->pr_path));
1502b63b0c65SPawel Jakub Dawidek 		mtx_lock(&pr->pr_mtx);
1503b63b0c65SPawel Jakub Dawidek 		strlcpy(xp->pr_host, pr->pr_host, sizeof(xp->pr_host));
1504413628a7SBjoern A. Zeeb 		strlcpy(xp->pr_name, pr->pr_name, sizeof(xp->pr_name));
1505fd7a8150SMike Barcroft 		mtx_unlock(&pr->pr_mtx);
1506413628a7SBjoern A. Zeeb #ifdef INET
1507413628a7SBjoern A. Zeeb 		xp->pr_ip4s = pr->pr_ip4s;
1508413628a7SBjoern A. Zeeb #endif
1509413628a7SBjoern A. Zeeb #ifdef INET6
1510413628a7SBjoern A. Zeeb 		xp->pr_ip6s = pr->pr_ip6s;
1511413628a7SBjoern A. Zeeb #endif
1512413628a7SBjoern A. Zeeb 		p = (char *)(xp + 1);
1513413628a7SBjoern A. Zeeb #ifdef INET
1514413628a7SBjoern A. Zeeb 		if (pr->pr_ip4s > 0) {
1515413628a7SBjoern A. Zeeb 			bcopy(pr->pr_ip4, (struct in_addr *)p,
1516413628a7SBjoern A. Zeeb 			    pr->pr_ip4s * sizeof(struct in_addr));
1517413628a7SBjoern A. Zeeb 			p += (pr->pr_ip4s * sizeof(struct in_addr));
1518413628a7SBjoern A. Zeeb 		}
1519413628a7SBjoern A. Zeeb #endif
1520413628a7SBjoern A. Zeeb #ifdef INET6
1521413628a7SBjoern A. Zeeb 		if (pr->pr_ip6s > 0) {
1522413628a7SBjoern A. Zeeb 			bcopy(pr->pr_ip6, (struct in6_addr *)p,
1523413628a7SBjoern A. Zeeb 			    pr->pr_ip6s * sizeof(struct in6_addr));
1524413628a7SBjoern A. Zeeb 			p += (pr->pr_ip6s * sizeof(struct in6_addr));
1525413628a7SBjoern A. Zeeb 		}
1526413628a7SBjoern A. Zeeb #endif
1527413628a7SBjoern A. Zeeb 		xp = (struct xprison *)p;
1528fd7a8150SMike Barcroft 	}
1529dc68a633SPawel Jakub Dawidek 	sx_sunlock(&allprison_lock);
1530fd7a8150SMike Barcroft 
1531413628a7SBjoern A. Zeeb 	error = SYSCTL_OUT(req, sxp, len);
1532fd7a8150SMike Barcroft 	free(sxp, M_TEMP);
1533fd7a8150SMike Barcroft 	return (error);
1534fd7a8150SMike Barcroft }
1535fd7a8150SMike Barcroft 
1536f3b86a5fSEd Schouten SYSCTL_OID(_security_jail, OID_AUTO, list,
1537f3b86a5fSEd Schouten     CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 0,
1538f3b86a5fSEd Schouten     sysctl_jail_list, "S", "List of active jails");
1539461167c2SPawel Jakub Dawidek 
1540461167c2SPawel Jakub Dawidek static int
1541461167c2SPawel Jakub Dawidek sysctl_jail_jailed(SYSCTL_HANDLER_ARGS)
1542461167c2SPawel Jakub Dawidek {
1543461167c2SPawel Jakub Dawidek 	int error, injail;
1544461167c2SPawel Jakub Dawidek 
1545461167c2SPawel Jakub Dawidek 	injail = jailed(req->td->td_ucred);
1546461167c2SPawel Jakub Dawidek 	error = SYSCTL_OUT(req, &injail, sizeof(injail));
1547461167c2SPawel Jakub Dawidek 
1548461167c2SPawel Jakub Dawidek 	return (error);
1549461167c2SPawel Jakub Dawidek }
1550f3b86a5fSEd Schouten SYSCTL_PROC(_security_jail, OID_AUTO, jailed,
1551f3b86a5fSEd Schouten     CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 0,
1552f3b86a5fSEd Schouten     sysctl_jail_jailed, "I", "Process in jail?");
1553413628a7SBjoern A. Zeeb 
1554413628a7SBjoern A. Zeeb #ifdef DDB
1555413628a7SBjoern A. Zeeb DB_SHOW_COMMAND(jails, db_show_jails)
1556413628a7SBjoern A. Zeeb {
1557413628a7SBjoern A. Zeeb 	struct prison *pr;
1558413628a7SBjoern A. Zeeb #ifdef INET
1559413628a7SBjoern A. Zeeb 	struct in_addr ia;
1560413628a7SBjoern A. Zeeb #endif
1561413628a7SBjoern A. Zeeb #ifdef INET6
1562413628a7SBjoern A. Zeeb 	char ip6buf[INET6_ADDRSTRLEN];
1563413628a7SBjoern A. Zeeb #endif
1564413628a7SBjoern A. Zeeb 	const char *state;
1565413628a7SBjoern A. Zeeb #if defined(INET) || defined(INET6)
1566413628a7SBjoern A. Zeeb 	int i;
1567413628a7SBjoern A. Zeeb #endif
1568413628a7SBjoern A. Zeeb 
1569413628a7SBjoern A. Zeeb 	db_printf(
1570413628a7SBjoern A. Zeeb 	    "   JID  pr_ref  pr_nprocs  pr_ip4s  pr_ip6s\n");
1571413628a7SBjoern A. Zeeb 	db_printf(
1572413628a7SBjoern A. Zeeb 	    "        Hostname                      Path\n");
1573413628a7SBjoern A. Zeeb 	db_printf(
1574413628a7SBjoern A. Zeeb 	    "        Name                          State\n");
1575413628a7SBjoern A. Zeeb 	db_printf(
1576413628a7SBjoern A. Zeeb 	    "        Cpusetid\n");
1577413628a7SBjoern A. Zeeb 	db_printf(
1578413628a7SBjoern A. Zeeb 	    "        IP Address(es)\n");
1579413628a7SBjoern A. Zeeb 	LIST_FOREACH(pr, &allprison, pr_list) {
1580413628a7SBjoern A. Zeeb 		db_printf("%6d  %6d  %9d  %7d  %7d\n",
1581413628a7SBjoern A. Zeeb 		    pr->pr_id, pr->pr_ref, pr->pr_nprocs,
1582413628a7SBjoern A. Zeeb 		    pr->pr_ip4s, pr->pr_ip6s);
1583413628a7SBjoern A. Zeeb 		db_printf("%6s  %-29.29s %.74s\n",
1584413628a7SBjoern A. Zeeb 		    "", pr->pr_host, pr->pr_path);
15850f1fe22dSBjoern A. Zeeb 		if (pr->pr_state < 0 || pr->pr_state >= (int)((sizeof(
1586413628a7SBjoern A. Zeeb 		    prison_states) / sizeof(struct prison_state))))
1587413628a7SBjoern A. Zeeb 			state = "(bogus)";
1588413628a7SBjoern A. Zeeb 		else
1589413628a7SBjoern A. Zeeb 			state = prison_states[pr->pr_state].state_name;
1590413628a7SBjoern A. Zeeb 		db_printf("%6s  %-29.29s %.74s\n",
15910f1fe22dSBjoern A. Zeeb 		    "", (pr->pr_name[0] != '\0') ? pr->pr_name : "", state);
1592413628a7SBjoern A. Zeeb 		db_printf("%6s  %-6d\n",
1593413628a7SBjoern A. Zeeb 		    "", pr->pr_cpuset->cs_id);
1594413628a7SBjoern A. Zeeb #ifdef INET
1595413628a7SBjoern A. Zeeb 		for (i=0; i < pr->pr_ip4s; i++) {
1596413628a7SBjoern A. Zeeb 			ia.s_addr = pr->pr_ip4[i].s_addr;
1597413628a7SBjoern A. Zeeb 			db_printf("%6s  %s\n", "", inet_ntoa(ia));
1598413628a7SBjoern A. Zeeb 		}
1599413628a7SBjoern A. Zeeb #endif
1600413628a7SBjoern A. Zeeb #ifdef INET6
1601413628a7SBjoern A. Zeeb 		for (i=0; i < pr->pr_ip6s; i++)
1602413628a7SBjoern A. Zeeb 			db_printf("%6s  %s\n",
1603413628a7SBjoern A. Zeeb 			    "", ip6_sprintf(ip6buf, &pr->pr_ip6[i]));
1604413628a7SBjoern A. Zeeb #endif /* INET6 */
1605413628a7SBjoern A. Zeeb 		if (db_pager_quit)
1606413628a7SBjoern A. Zeeb 			break;
1607413628a7SBjoern A. Zeeb 	}
1608413628a7SBjoern A. Zeeb }
1609413628a7SBjoern A. Zeeb #endif /* DDB */
1610