xref: /freebsd/sys/kern/kern_jail.c (revision 413628a7e3d23a897cd959638d325395e4c9691b)
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++) {
220413628a7SBjoern A. Zeeb 				if (_prison_check_ip4(pr, &p->pr_ip4[i]))
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++) {
229413628a7SBjoern A. Zeeb 				if (_prison_check_ip6(pr, &p->pr_ip6[i]))
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;
296413628a7SBjoern A. Zeeb 	}
297413628a7SBjoern A. Zeeb #endif
298413628a7SBjoern A. Zeeb #ifdef INET6
299413628a7SBjoern A. Zeeb 	if (j->ip6s > 0) {
300413628a7SBjoern A. Zeeb 		ip6 = (struct in6_addr *)malloc(j->ip6s * sizeof(struct in6_addr),
301413628a7SBjoern A. Zeeb 		    M_PRISON, M_WAITOK | M_ZERO);
302413628a7SBjoern A. Zeeb 		error = copyin(j->ip6, ip6, j->ip6s * sizeof(struct in6_addr));
303413628a7SBjoern A. Zeeb 		if (error)
304413628a7SBjoern A. Zeeb 			goto e_free_ip;
305413628a7SBjoern A. Zeeb 		/* Sort all but the first IPv6 address. */
306413628a7SBjoern A. Zeeb 		if (j->ip6s > 1)
307413628a7SBjoern A. Zeeb 			qsort((ip6 + 1), j->ip6s - 1,
308413628a7SBjoern A. Zeeb 			    sizeof(struct in6_addr), qcmp_v6);
309413628a7SBjoern A. Zeeb 		for (i=0; i<j->ip6s; i++) {
310413628a7SBjoern A. Zeeb 			if (IN6_IS_ADDR_UNSPECIFIED(&ip6[i])) {
311413628a7SBjoern A. Zeeb 				error = EINVAL;
312413628a7SBjoern A. Zeeb 				goto e_free_ip;
313413628a7SBjoern A. Zeeb 			}
314413628a7SBjoern A. Zeeb 			if ((i+1) < j->ip6s &&
315413628a7SBjoern A. Zeeb 			    (IN6_ARE_ADDR_EQUAL(&ip6[0], &ip6[i+1]) ||
316413628a7SBjoern A. Zeeb 			    IN6_ARE_ADDR_EQUAL(&ip6[i], &ip6[i+1]))) {
317413628a7SBjoern A. Zeeb 				error = EINVAL;
318413628a7SBjoern A. Zeeb 				goto e_free_ip;
319413628a7SBjoern A. Zeeb 			}
320413628a7SBjoern A. Zeeb 		}
321413628a7SBjoern A. Zeeb 
322413628a7SBjoern A. Zeeb 		j->ip6 = ip6;
323413628a7SBjoern A. Zeeb 	}
324413628a7SBjoern A. Zeeb #endif
325413628a7SBjoern A. Zeeb 	return (0);
326413628a7SBjoern A. Zeeb 
327413628a7SBjoern A. Zeeb e_free_ip:
328413628a7SBjoern A. Zeeb #ifdef INET6
329413628a7SBjoern A. Zeeb 	free(ip6, M_PRISON);
330413628a7SBjoern A. Zeeb #endif
331413628a7SBjoern A. Zeeb #ifdef INET
332413628a7SBjoern A. Zeeb 	free(ip4, M_PRISON);
333413628a7SBjoern A. Zeeb #endif
334413628a7SBjoern A. Zeeb 	return (error);
335413628a7SBjoern A. Zeeb }
336413628a7SBjoern A. Zeeb #endif /* INET || INET6 */
337413628a7SBjoern A. Zeeb 
338413628a7SBjoern A. Zeeb static int
339413628a7SBjoern A. Zeeb jail_handle_ips(struct jail *j)
340413628a7SBjoern A. Zeeb {
341413628a7SBjoern A. Zeeb #if defined(INET) || defined(INET6)
342413628a7SBjoern A. Zeeb 	int error;
343413628a7SBjoern A. Zeeb #endif
344413628a7SBjoern A. Zeeb 
345413628a7SBjoern A. Zeeb 	/*
346413628a7SBjoern A. Zeeb 	 * Finish conversion for older versions, copyin and setup IPs.
347413628a7SBjoern A. Zeeb 	 */
348413628a7SBjoern A. Zeeb 	switch (j->version) {
349413628a7SBjoern A. Zeeb 	case 0:
350413628a7SBjoern A. Zeeb 	{
351413628a7SBjoern A. Zeeb #ifdef INET
352413628a7SBjoern A. Zeeb 		/* FreeBSD single IPv4 jails. */
353413628a7SBjoern A. Zeeb 		struct in_addr *ip4;
354413628a7SBjoern A. Zeeb 
355413628a7SBjoern A. Zeeb 		if (j->ip4s == INADDR_ANY || j->ip4s == INADDR_BROADCAST)
356413628a7SBjoern A. Zeeb 			return (EINVAL);
357413628a7SBjoern A. Zeeb 		ip4 = (struct in_addr *)malloc(sizeof(struct in_addr),
358413628a7SBjoern A. Zeeb 		    M_PRISON, M_WAITOK | M_ZERO);
359413628a7SBjoern A. Zeeb 
360413628a7SBjoern A. Zeeb 		/*
361413628a7SBjoern A. Zeeb 		 * Jail version 0 still used HBO for the IPv4 address.
362413628a7SBjoern A. Zeeb 		 */
363413628a7SBjoern A. Zeeb 		ip4->s_addr = htonl(j->ip4s);
364413628a7SBjoern A. Zeeb 		j->ip4s = 1;
365413628a7SBjoern A. Zeeb 		j->ip4 = ip4;
366413628a7SBjoern A. Zeeb 		break;
367413628a7SBjoern A. Zeeb #else
368413628a7SBjoern A. Zeeb 		return (EINVAL);
369413628a7SBjoern A. Zeeb #endif
370413628a7SBjoern A. Zeeb 	}
371413628a7SBjoern A. Zeeb 
372413628a7SBjoern A. Zeeb 	case 1:
373413628a7SBjoern A. Zeeb 		/*
374413628a7SBjoern A. Zeeb 		 * Version 1 was used by multi-IPv4 jail implementations
375413628a7SBjoern A. Zeeb 		 * that never made it into the official kernel.
376413628a7SBjoern A. Zeeb 		 * We should never hit this here; jail() should catch it.
377413628a7SBjoern A. Zeeb 		 */
378413628a7SBjoern A. Zeeb 		return (EINVAL);
379413628a7SBjoern A. Zeeb 
380413628a7SBjoern A. Zeeb 	case 2:	/* JAIL_API_VERSION */
381413628a7SBjoern A. Zeeb 		/* FreeBSD multi-IPv4/IPv6,noIP jails. */
382413628a7SBjoern A. Zeeb #if defined(INET) || defined(INET6)
383413628a7SBjoern A. Zeeb #ifdef INET
384413628a7SBjoern A. Zeeb 		if (j->ip4s > jail_max_af_ips)
385413628a7SBjoern A. Zeeb 			return (EINVAL);
386413628a7SBjoern A. Zeeb #else
387413628a7SBjoern A. Zeeb 		if (j->ip4s != 0)
388413628a7SBjoern A. Zeeb 			return (EINVAL);
389413628a7SBjoern A. Zeeb #endif
390413628a7SBjoern A. Zeeb #ifdef INET6
391413628a7SBjoern A. Zeeb 		if (j->ip6s > jail_max_af_ips)
392413628a7SBjoern A. Zeeb 			return (EINVAL);
393413628a7SBjoern A. Zeeb #else
394413628a7SBjoern A. Zeeb 		if (j->ip6s != 0)
395413628a7SBjoern A. Zeeb 			return (EINVAL);
396413628a7SBjoern A. Zeeb #endif
397413628a7SBjoern A. Zeeb 		error = jail_copyin_ips(j);
398413628a7SBjoern A. Zeeb 		if (error)
399413628a7SBjoern A. Zeeb 			return (error);
400413628a7SBjoern A. Zeeb #endif
401413628a7SBjoern A. Zeeb 		break;
402413628a7SBjoern A. Zeeb 
403413628a7SBjoern A. Zeeb 	default:
404413628a7SBjoern A. Zeeb 		/* Sci-Fi jails are not supported, sorry. */
405413628a7SBjoern A. Zeeb 		return (EINVAL);
406413628a7SBjoern A. Zeeb 	}
407413628a7SBjoern A. Zeeb 
408413628a7SBjoern A. Zeeb 	return (0);
409413628a7SBjoern A. Zeeb }
410413628a7SBjoern A. Zeeb 
411413628a7SBjoern A. Zeeb 
412116734c4SMatthew Dillon /*
4139ddb7954SMike Barcroft  * struct jail_args {
4149ddb7954SMike Barcroft  *	struct jail *jail;
4159ddb7954SMike Barcroft  * };
416116734c4SMatthew Dillon  */
41775c13541SPoul-Henning Kamp int
4189ddb7954SMike Barcroft jail(struct thread *td, struct jail_args *uap)
41975c13541SPoul-Henning Kamp {
420413628a7SBjoern A. Zeeb 	uint32_t version;
421413628a7SBjoern A. Zeeb 	int error;
422413628a7SBjoern A. Zeeb 	struct jail j;
423413628a7SBjoern A. Zeeb 
424413628a7SBjoern A. Zeeb 	error = copyin(uap->jail, &version, sizeof(uint32_t));
425413628a7SBjoern A. Zeeb 	if (error)
426413628a7SBjoern A. Zeeb 		return (error);
427413628a7SBjoern A. Zeeb 
428413628a7SBjoern A. Zeeb 	switch (version) {
429413628a7SBjoern A. Zeeb 	case 0:
430413628a7SBjoern A. Zeeb 		/* FreeBSD single IPv4 jails. */
431413628a7SBjoern A. Zeeb 	{
432413628a7SBjoern A. Zeeb 		struct jail_v0 j0;
433413628a7SBjoern A. Zeeb 
434413628a7SBjoern A. Zeeb 		bzero(&j, sizeof(struct jail));
435413628a7SBjoern A. Zeeb 		error = copyin(uap->jail, &j0, sizeof(struct jail_v0));
436413628a7SBjoern A. Zeeb 		if (error)
437413628a7SBjoern A. Zeeb 			return (error);
438413628a7SBjoern A. Zeeb 		j.version = j0.version;
439413628a7SBjoern A. Zeeb 		j.path = j0.path;
440413628a7SBjoern A. Zeeb 		j.hostname = j0.hostname;
441413628a7SBjoern A. Zeeb 		j.ip4s = j0.ip_number;
442413628a7SBjoern A. Zeeb 		break;
443413628a7SBjoern A. Zeeb 	}
444413628a7SBjoern A. Zeeb 
445413628a7SBjoern A. Zeeb 	case 1:
446413628a7SBjoern A. Zeeb 		/*
447413628a7SBjoern A. Zeeb 		 * Version 1 was used by multi-IPv4 jail implementations
448413628a7SBjoern A. Zeeb 		 * that never made it into the official kernel.
449413628a7SBjoern A. Zeeb 		 */
450413628a7SBjoern A. Zeeb 		return (EINVAL);
451413628a7SBjoern A. Zeeb 
452413628a7SBjoern A. Zeeb 	case 2:	/* JAIL_API_VERSION */
453413628a7SBjoern A. Zeeb 		/* FreeBSD multi-IPv4/IPv6,noIP jails. */
454413628a7SBjoern A. Zeeb 		error = copyin(uap->jail, &j, sizeof(struct jail));
455413628a7SBjoern A. Zeeb 		if (error)
456413628a7SBjoern A. Zeeb 			return (error);
457413628a7SBjoern A. Zeeb 		break;
458413628a7SBjoern A. Zeeb 
459413628a7SBjoern A. Zeeb 	default:
460413628a7SBjoern A. Zeeb 		/* Sci-Fi jails are not supported, sorry. */
461413628a7SBjoern A. Zeeb 		return (EINVAL);
462413628a7SBjoern A. Zeeb 	}
463413628a7SBjoern A. Zeeb 	return (kern_jail(td, &j));
464413628a7SBjoern A. Zeeb }
465413628a7SBjoern A. Zeeb 
466413628a7SBjoern A. Zeeb int
467413628a7SBjoern A. Zeeb kern_jail(struct thread *td, struct jail *j)
468413628a7SBjoern A. Zeeb {
469fd7a8150SMike Barcroft 	struct nameidata nd;
4702110d913SXin LI 	struct prison *pr, *tpr;
471fd7a8150SMike Barcroft 	struct jail_attach_args jaa;
4722110d913SXin LI 	int vfslocked, error, tryprid;
47375c13541SPoul-Henning Kamp 
474413628a7SBjoern A. Zeeb 	KASSERT(j != NULL, ("%s: j is NULL", __func__));
475413628a7SBjoern A. Zeeb 
476413628a7SBjoern A. Zeeb 	/* Handle addresses - convert old structs, copyin, check IPs. */
477413628a7SBjoern A. Zeeb 	error = jail_handle_ips(j);
47875c13541SPoul-Henning Kamp 	if (error)
479a2f2b3afSJohn Baldwin 		return (error);
480a2f2b3afSJohn Baldwin 
481413628a7SBjoern A. Zeeb 	/* Allocate struct prison and fill it with life. */
4821ede983cSDag-Erling Smørgrav 	pr = malloc(sizeof(*pr), M_PRISON, M_WAITOK | M_ZERO);
4836008862bSJohn Baldwin 	mtx_init(&pr->pr_mtx, "jail mutex", NULL, MTX_DEF);
484fd7a8150SMike Barcroft 	pr->pr_ref = 1;
485413628a7SBjoern A. Zeeb 	error = copyinstr(j->path, &pr->pr_path, sizeof(pr->pr_path), NULL);
486fd7a8150SMike Barcroft 	if (error)
487fd7a8150SMike Barcroft 		goto e_killmtx;
488453f7d53SChristian S.J. Peron 	NDINIT(&nd, LOOKUP, MPSAFE | FOLLOW | LOCKLEAF, UIO_SYSSPACE,
489453f7d53SChristian S.J. Peron 	    pr->pr_path, td);
490fd7a8150SMike Barcroft 	error = namei(&nd);
491453f7d53SChristian S.J. Peron 	if (error)
492fd7a8150SMike Barcroft 		goto e_killmtx;
493453f7d53SChristian S.J. Peron 	vfslocked = NDHASGIANT(&nd);
494fd7a8150SMike Barcroft 	pr->pr_root = nd.ni_vp;
49522db15c0SAttilio Rao 	VOP_UNLOCK(nd.ni_vp, 0);
496fd7a8150SMike Barcroft 	NDFREE(&nd, NDF_ONLY_PNBUF);
497453f7d53SChristian S.J. Peron 	VFS_UNLOCK_GIANT(vfslocked);
498413628a7SBjoern A. Zeeb 	error = copyinstr(j->hostname, &pr->pr_host, sizeof(pr->pr_host), NULL);
49975c13541SPoul-Henning Kamp 	if (error)
500fd7a8150SMike Barcroft 		goto e_dropvnref;
501413628a7SBjoern A. Zeeb 	if (j->jailname != NULL) {
502413628a7SBjoern A. Zeeb 		error = copyinstr(j->jailname, &pr->pr_name,
503413628a7SBjoern A. Zeeb 		    sizeof(pr->pr_name), NULL);
504413628a7SBjoern A. Zeeb 		if (error)
505413628a7SBjoern A. Zeeb 			goto e_dropvnref;
506413628a7SBjoern A. Zeeb 	}
507413628a7SBjoern A. Zeeb 	if (j->ip4s > 0) {
508413628a7SBjoern A. Zeeb 		pr->pr_ip4 = j->ip4;
509413628a7SBjoern A. Zeeb 		pr->pr_ip4s = j->ip4s;
510413628a7SBjoern A. Zeeb 	}
511413628a7SBjoern A. Zeeb #ifdef INET6
512413628a7SBjoern A. Zeeb 	if (j->ip6s > 0) {
513413628a7SBjoern A. Zeeb 		pr->pr_ip6 = j->ip6;
514413628a7SBjoern A. Zeeb 		pr->pr_ip6s = j->ip6s;
515413628a7SBjoern A. Zeeb 	}
516413628a7SBjoern A. Zeeb #endif
517fd7a8150SMike Barcroft 	pr->pr_linux = NULL;
518fd7a8150SMike Barcroft 	pr->pr_securelevel = securelevel;
5191ba4a712SPawel Jakub Dawidek 	bzero(&pr->pr_osd, sizeof(pr->pr_osd));
520fd7a8150SMike Barcroft 
521413628a7SBjoern A. Zeeb 	/*
522413628a7SBjoern A. Zeeb 	 * Pre-set prison state to ALIVE upon cration.  This is needed so we
523413628a7SBjoern A. Zeeb 	 * can later attach the process to it, etc (avoiding another extra
524413628a7SBjoern A. Zeeb 	 * state for ther process of creation, complicating things).
525413628a7SBjoern A. Zeeb 	 */
526413628a7SBjoern A. Zeeb 	pr->pr_state = PRISON_STATE_ALIVE;
527413628a7SBjoern A. Zeeb 
528413628a7SBjoern A. Zeeb 	/* Allocate a dedicated cpuset for each jail. */
529413628a7SBjoern A. Zeeb 	error = cpuset_create_root(td, &pr->pr_cpuset);
530413628a7SBjoern A. Zeeb 	if (error)
531413628a7SBjoern A. Zeeb 		goto e_dropvnref;
532413628a7SBjoern A. Zeeb 
533dc68a633SPawel Jakub Dawidek 	sx_xlock(&allprison_lock);
534413628a7SBjoern A. Zeeb 	/* Make sure we cannot run into problems with ambiguous bind()ings. */
535413628a7SBjoern A. Zeeb 	error = prison_check_conflicting_ips(pr);
536413628a7SBjoern A. Zeeb 	if (error) {
537413628a7SBjoern A. Zeeb 		sx_xunlock(&allprison_lock);
538413628a7SBjoern A. Zeeb 		goto e_dropcpuset;
539413628a7SBjoern A. Zeeb 	}
540413628a7SBjoern A. Zeeb 
541413628a7SBjoern A. Zeeb 	/* Determine next pr_id and add prison to allprison list. */
5422110d913SXin LI 	tryprid = lastprid + 1;
5432110d913SXin LI 	if (tryprid == JAIL_MAX)
5442110d913SXin LI 		tryprid = 1;
5452110d913SXin LI next:
5462110d913SXin LI 	LIST_FOREACH(tpr, &allprison, pr_list) {
5472110d913SXin LI 		if (tpr->pr_id == tryprid) {
5482110d913SXin LI 			tryprid++;
5492110d913SXin LI 			if (tryprid == JAIL_MAX) {
5502110d913SXin LI 				sx_xunlock(&allprison_lock);
5512110d913SXin LI 				error = EAGAIN;
552413628a7SBjoern A. Zeeb 				goto e_dropcpuset;
5532110d913SXin LI 			}
5542110d913SXin LI 			goto next;
5552110d913SXin LI 		}
5562110d913SXin LI 	}
5572110d913SXin LI 	pr->pr_id = jaa.jid = lastprid = tryprid;
558fd7a8150SMike Barcroft 	LIST_INSERT_HEAD(&allprison, pr, pr_list);
559fd7a8150SMike Barcroft 	prisoncount++;
5601ba4a712SPawel Jakub Dawidek 	sx_xunlock(&allprison_lock);
561fd7a8150SMike Barcroft 
562fd7a8150SMike Barcroft 	error = jail_attach(td, &jaa);
563a2f2b3afSJohn Baldwin 	if (error)
564fd7a8150SMike Barcroft 		goto e_dropprref;
565fd7a8150SMike Barcroft 	mtx_lock(&pr->pr_mtx);
566fd7a8150SMike Barcroft 	pr->pr_ref--;
567fd7a8150SMike Barcroft 	mtx_unlock(&pr->pr_mtx);
568fd7a8150SMike Barcroft 	td->td_retval[0] = jaa.jid;
56975c13541SPoul-Henning Kamp 	return (0);
570fd7a8150SMike Barcroft e_dropprref:
571dc68a633SPawel Jakub Dawidek 	sx_xlock(&allprison_lock);
572fd7a8150SMike Barcroft 	LIST_REMOVE(pr, pr_list);
573fd7a8150SMike Barcroft 	prisoncount--;
5741ba4a712SPawel Jakub Dawidek 	sx_xunlock(&allprison_lock);
575413628a7SBjoern A. Zeeb e_dropcpuset:
576413628a7SBjoern A. Zeeb 	cpuset_rel(pr->pr_cpuset);
577fd7a8150SMike Barcroft e_dropvnref:
578453f7d53SChristian S.J. Peron 	vfslocked = VFS_LOCK_GIANT(pr->pr_root->v_mount);
579fd7a8150SMike Barcroft 	vrele(pr->pr_root);
580453f7d53SChristian S.J. Peron 	VFS_UNLOCK_GIANT(vfslocked);
581fd7a8150SMike Barcroft e_killmtx:
582894db7b0SMaxime Henrion 	mtx_destroy(&pr->pr_mtx);
5831ede983cSDag-Erling Smørgrav 	free(pr, M_PRISON);
584413628a7SBjoern A. Zeeb #ifdef INET6
585413628a7SBjoern A. Zeeb 	free(j->ip6, M_PRISON);
586413628a7SBjoern A. Zeeb #endif
587413628a7SBjoern A. Zeeb #ifdef INET
588413628a7SBjoern A. Zeeb 	free(j->ip4, M_PRISON);
589413628a7SBjoern A. Zeeb #endif
59075c13541SPoul-Henning Kamp 	return (error);
59175c13541SPoul-Henning Kamp }
59275c13541SPoul-Henning Kamp 
593fd7a8150SMike Barcroft /*
5949ddb7954SMike Barcroft  * struct jail_attach_args {
5959ddb7954SMike Barcroft  *	int jid;
5969ddb7954SMike Barcroft  * };
597fd7a8150SMike Barcroft  */
598fd7a8150SMike Barcroft int
5999ddb7954SMike Barcroft jail_attach(struct thread *td, struct jail_attach_args *uap)
600fd7a8150SMike Barcroft {
601fd7a8150SMike Barcroft 	struct proc *p;
602fd7a8150SMike Barcroft 	struct ucred *newcred, *oldcred;
603fd7a8150SMike Barcroft 	struct prison *pr;
604453f7d53SChristian S.J. Peron 	int vfslocked, error;
605fd7a8150SMike Barcroft 
60657f22bd4SJacques Vidrine 	/*
60757f22bd4SJacques Vidrine 	 * XXX: Note that there is a slight race here if two threads
60857f22bd4SJacques Vidrine 	 * in the same privileged process attempt to attach to two
60957f22bd4SJacques Vidrine 	 * different jails at the same time.  It is important for
61057f22bd4SJacques Vidrine 	 * user processes not to do this, or they might end up with
61157f22bd4SJacques Vidrine 	 * a process root from one prison, but attached to the jail
61257f22bd4SJacques Vidrine 	 * of another.
61357f22bd4SJacques Vidrine 	 */
614800c9408SRobert Watson 	error = priv_check(td, PRIV_JAIL_ATTACH);
61557f22bd4SJacques Vidrine 	if (error)
61657f22bd4SJacques Vidrine 		return (error);
617fd7a8150SMike Barcroft 
61857f22bd4SJacques Vidrine 	p = td->td_proc;
619dc68a633SPawel Jakub Dawidek 	sx_slock(&allprison_lock);
620fd7a8150SMike Barcroft 	pr = prison_find(uap->jid);
621fd7a8150SMike Barcroft 	if (pr == NULL) {
622dc68a633SPawel Jakub Dawidek 		sx_sunlock(&allprison_lock);
623fd7a8150SMike Barcroft 		return (EINVAL);
624fd7a8150SMike Barcroft 	}
625413628a7SBjoern A. Zeeb 
626413628a7SBjoern A. Zeeb 	/*
627413628a7SBjoern A. Zeeb 	 * Do not allow a process to attach to a prison that is not
628413628a7SBjoern A. Zeeb 	 * considered to be "ALIVE".
629413628a7SBjoern A. Zeeb 	 */
630413628a7SBjoern A. Zeeb 	if (pr->pr_state != PRISON_STATE_ALIVE) {
631413628a7SBjoern A. Zeeb 		mtx_unlock(&pr->pr_mtx);
632413628a7SBjoern A. Zeeb 		sx_sunlock(&allprison_lock);
633413628a7SBjoern A. Zeeb 		return (EINVAL);
634413628a7SBjoern A. Zeeb 	}
635fd7a8150SMike Barcroft 	pr->pr_ref++;
636fd7a8150SMike Barcroft 	mtx_unlock(&pr->pr_mtx);
637dc68a633SPawel Jakub Dawidek 	sx_sunlock(&allprison_lock);
638fd7a8150SMike Barcroft 
639413628a7SBjoern A. Zeeb 	/*
640413628a7SBjoern A. Zeeb 	 * Reparent the newly attached process to this jail.
641413628a7SBjoern A. Zeeb 	 */
642413628a7SBjoern A. Zeeb 	error = cpuset_setproc_update_set(p, pr->pr_cpuset);
643413628a7SBjoern A. Zeeb 	if (error)
644413628a7SBjoern A. Zeeb 		goto e_unref;
645413628a7SBjoern A. Zeeb 
646453f7d53SChristian S.J. Peron 	vfslocked = VFS_LOCK_GIANT(pr->pr_root->v_mount);
647cb05b60aSAttilio Rao 	vn_lock(pr->pr_root, LK_EXCLUSIVE | LK_RETRY);
648fd7a8150SMike Barcroft 	if ((error = change_dir(pr->pr_root, td)) != 0)
649fd7a8150SMike Barcroft 		goto e_unlock;
650fd7a8150SMike Barcroft #ifdef MAC
65130d239bcSRobert Watson 	if ((error = mac_vnode_check_chroot(td->td_ucred, pr->pr_root)))
652fd7a8150SMike Barcroft 		goto e_unlock;
653fd7a8150SMike Barcroft #endif
65422db15c0SAttilio Rao 	VOP_UNLOCK(pr->pr_root, 0);
655fd7a8150SMike Barcroft 	change_root(pr->pr_root, td);
656453f7d53SChristian S.J. Peron 	VFS_UNLOCK_GIANT(vfslocked);
657fd7a8150SMike Barcroft 
658fd7a8150SMike Barcroft 	newcred = crget();
659fd7a8150SMike Barcroft 	PROC_LOCK(p);
660fd7a8150SMike Barcroft 	oldcred = p->p_ucred;
661fd7a8150SMike Barcroft 	setsugid(p);
662fd7a8150SMike Barcroft 	crcopy(newcred, oldcred);
66369c4ee54SJohn Baldwin 	newcred->cr_prison = pr;
664fd7a8150SMike Barcroft 	p->p_ucred = newcred;
665413628a7SBjoern A. Zeeb 	prison_proc_hold(pr);
666fd7a8150SMike Barcroft 	PROC_UNLOCK(p);
667fd7a8150SMike Barcroft 	crfree(oldcred);
668fd7a8150SMike Barcroft 	return (0);
669fd7a8150SMike Barcroft e_unlock:
67022db15c0SAttilio Rao 	VOP_UNLOCK(pr->pr_root, 0);
671453f7d53SChristian S.J. Peron 	VFS_UNLOCK_GIANT(vfslocked);
672413628a7SBjoern A. Zeeb e_unref:
673fd7a8150SMike Barcroft 	mtx_lock(&pr->pr_mtx);
674fd7a8150SMike Barcroft 	pr->pr_ref--;
675fd7a8150SMike Barcroft 	mtx_unlock(&pr->pr_mtx);
676fd7a8150SMike Barcroft 	return (error);
677fd7a8150SMike Barcroft }
678fd7a8150SMike Barcroft 
679fd7a8150SMike Barcroft /*
680fd7a8150SMike Barcroft  * Returns a locked prison instance, or NULL on failure.
681fd7a8150SMike Barcroft  */
68254b369c1SPawel Jakub Dawidek struct prison *
683fd7a8150SMike Barcroft prison_find(int prid)
684fd7a8150SMike Barcroft {
685fd7a8150SMike Barcroft 	struct prison *pr;
686fd7a8150SMike Barcroft 
687dc68a633SPawel Jakub Dawidek 	sx_assert(&allprison_lock, SX_LOCKED);
688fd7a8150SMike Barcroft 	LIST_FOREACH(pr, &allprison, pr_list) {
689fd7a8150SMike Barcroft 		if (pr->pr_id == prid) {
690fd7a8150SMike Barcroft 			mtx_lock(&pr->pr_mtx);
691c2cda609SPawel Jakub Dawidek 			if (pr->pr_ref == 0) {
692c2cda609SPawel Jakub Dawidek 				mtx_unlock(&pr->pr_mtx);
693c2cda609SPawel Jakub Dawidek 				break;
694c2cda609SPawel Jakub Dawidek 			}
695fd7a8150SMike Barcroft 			return (pr);
696fd7a8150SMike Barcroft 		}
697fd7a8150SMike Barcroft 	}
698fd7a8150SMike Barcroft 	return (NULL);
699fd7a8150SMike Barcroft }
700fd7a8150SMike Barcroft 
70191421ba2SRobert Watson void
7021ba4a712SPawel Jakub Dawidek prison_free_locked(struct prison *pr)
70391421ba2SRobert Watson {
70491421ba2SRobert Watson 
7051ba4a712SPawel Jakub Dawidek 	mtx_assert(&pr->pr_mtx, MA_OWNED);
70691421ba2SRobert Watson 	pr->pr_ref--;
70791421ba2SRobert Watson 	if (pr->pr_ref == 0) {
70801137630SRobert Watson 		mtx_unlock(&pr->pr_mtx);
709c2cda609SPawel Jakub Dawidek 		TASK_INIT(&pr->pr_task, 0, prison_complete, pr);
710c2cda609SPawel Jakub Dawidek 		taskqueue_enqueue(taskqueue_thread, &pr->pr_task);
711c2cda609SPawel Jakub Dawidek 		return;
712c2cda609SPawel Jakub Dawidek 	}
713c2cda609SPawel Jakub Dawidek 	mtx_unlock(&pr->pr_mtx);
714c2cda609SPawel Jakub Dawidek }
715c2cda609SPawel Jakub Dawidek 
7161ba4a712SPawel Jakub Dawidek void
7171ba4a712SPawel Jakub Dawidek prison_free(struct prison *pr)
7181ba4a712SPawel Jakub Dawidek {
7191ba4a712SPawel Jakub Dawidek 
7201ba4a712SPawel Jakub Dawidek 	mtx_lock(&pr->pr_mtx);
7211ba4a712SPawel Jakub Dawidek 	prison_free_locked(pr);
7221ba4a712SPawel Jakub Dawidek }
7231ba4a712SPawel Jakub Dawidek 
724c2cda609SPawel Jakub Dawidek static void
725c2cda609SPawel Jakub Dawidek prison_complete(void *context, int pending)
726c2cda609SPawel Jakub Dawidek {
727c2cda609SPawel Jakub Dawidek 	struct prison *pr;
728c2cda609SPawel Jakub Dawidek 	int vfslocked;
729c2cda609SPawel Jakub Dawidek 
730c2cda609SPawel Jakub Dawidek 	pr = (struct prison *)context;
731c2cda609SPawel Jakub Dawidek 
732c2cda609SPawel Jakub Dawidek 	sx_xlock(&allprison_lock);
733264de85eSPawel Jakub Dawidek 	LIST_REMOVE(pr, pr_list);
734fd7a8150SMike Barcroft 	prisoncount--;
7351ba4a712SPawel Jakub Dawidek 	sx_xunlock(&allprison_lock);
7361ba4a712SPawel Jakub Dawidek 
737413628a7SBjoern A. Zeeb 	cpuset_rel(pr->pr_cpuset);
738413628a7SBjoern A. Zeeb 
7391ba4a712SPawel Jakub Dawidek 	/* Free all OSD associated to this jail. */
7401ba4a712SPawel Jakub Dawidek 	osd_jail_exit(pr);
741b3059e09SRobert Watson 
742453f7d53SChristian S.J. Peron 	vfslocked = VFS_LOCK_GIANT(pr->pr_root->v_mount);
743b3059e09SRobert Watson 	vrele(pr->pr_root);
744453f7d53SChristian S.J. Peron 	VFS_UNLOCK_GIANT(vfslocked);
745b3059e09SRobert Watson 
746b3059e09SRobert Watson 	mtx_destroy(&pr->pr_mtx);
7471ede983cSDag-Erling Smørgrav 	free(pr->pr_linux, M_PRISON);
748413628a7SBjoern A. Zeeb #ifdef INET6
749413628a7SBjoern A. Zeeb 	free(pr->pr_ip6, M_PRISON);
750413628a7SBjoern A. Zeeb #endif
751413628a7SBjoern A. Zeeb #ifdef INET
752413628a7SBjoern A. Zeeb 	free(pr->pr_ip4, M_PRISON);
753413628a7SBjoern A. Zeeb #endif
7541ede983cSDag-Erling Smørgrav 	free(pr, M_PRISON);
755b3059e09SRobert Watson }
756b3059e09SRobert Watson 
75791421ba2SRobert Watson void
7581ba4a712SPawel Jakub Dawidek prison_hold_locked(struct prison *pr)
7591ba4a712SPawel Jakub Dawidek {
7601ba4a712SPawel Jakub Dawidek 
7611ba4a712SPawel Jakub Dawidek 	mtx_assert(&pr->pr_mtx, MA_OWNED);
7621ba4a712SPawel Jakub Dawidek 	KASSERT(pr->pr_ref > 0,
7631ba4a712SPawel Jakub Dawidek 	    ("Trying to hold dead prison (id=%d).", pr->pr_id));
7641ba4a712SPawel Jakub Dawidek 	pr->pr_ref++;
7651ba4a712SPawel Jakub Dawidek }
7661ba4a712SPawel Jakub Dawidek 
7671ba4a712SPawel Jakub Dawidek void
76891421ba2SRobert Watson prison_hold(struct prison *pr)
76991421ba2SRobert Watson {
77091421ba2SRobert Watson 
77101137630SRobert Watson 	mtx_lock(&pr->pr_mtx);
7721ba4a712SPawel Jakub Dawidek 	prison_hold_locked(pr);
77301137630SRobert Watson 	mtx_unlock(&pr->pr_mtx);
77401137630SRobert Watson }
77501137630SRobert Watson 
776413628a7SBjoern A. Zeeb void
777413628a7SBjoern A. Zeeb prison_proc_hold(struct prison *pr)
77801137630SRobert Watson {
77901137630SRobert Watson 
780413628a7SBjoern A. Zeeb 	mtx_lock(&pr->pr_mtx);
781413628a7SBjoern A. Zeeb 	KASSERT(pr->pr_state == PRISON_STATE_ALIVE,
782413628a7SBjoern A. Zeeb 	    ("Cannot add a process to a non-alive prison (id=%d).", pr->pr_id));
783413628a7SBjoern A. Zeeb 	pr->pr_nprocs++;
784413628a7SBjoern A. Zeeb 	mtx_unlock(&pr->pr_mtx);
78575c13541SPoul-Henning Kamp }
78675c13541SPoul-Henning Kamp 
78775c13541SPoul-Henning Kamp void
788413628a7SBjoern A. Zeeb prison_proc_free(struct prison *pr)
78975c13541SPoul-Henning Kamp {
790413628a7SBjoern A. Zeeb 
791413628a7SBjoern A. Zeeb 	mtx_lock(&pr->pr_mtx);
792413628a7SBjoern A. Zeeb 	KASSERT(pr->pr_state == PRISON_STATE_ALIVE && pr->pr_nprocs > 0,
793413628a7SBjoern A. Zeeb 	    ("Trying to kill a process in a dead prison (id=%d).", pr->pr_id));
794413628a7SBjoern A. Zeeb 	pr->pr_nprocs--;
795413628a7SBjoern A. Zeeb 	if (pr->pr_nprocs == 0)
796413628a7SBjoern A. Zeeb 		pr->pr_state = PRISON_STATE_DYING;
797413628a7SBjoern A. Zeeb 	mtx_unlock(&pr->pr_mtx);
798413628a7SBjoern A. Zeeb }
799413628a7SBjoern A. Zeeb 
800413628a7SBjoern A. Zeeb 
801413628a7SBjoern A. Zeeb #ifdef INET
802413628a7SBjoern A. Zeeb /*
803413628a7SBjoern A. Zeeb  * Pass back primary IPv4 address of this jail.
804413628a7SBjoern A. Zeeb  *
805413628a7SBjoern A. Zeeb  * If not jailed return success but do not alter the address.  Caller has to
806413628a7SBjoern A. Zeeb  * make sure to intialize it correctly (INADDR_ANY).
807413628a7SBjoern A. Zeeb  *
808413628a7SBjoern A. Zeeb  * Returns 0 on success, 1 on error.  Address returned in NBO.
809413628a7SBjoern A. Zeeb  */
810413628a7SBjoern A. Zeeb int
811413628a7SBjoern A. Zeeb prison_getip4(struct ucred *cred, struct in_addr *ia)
812413628a7SBjoern A. Zeeb {
813413628a7SBjoern A. Zeeb 
814413628a7SBjoern A. Zeeb 	KASSERT(cred != NULL, ("%s: cred is NULL", __func__));
815413628a7SBjoern A. Zeeb 	KASSERT(ia != NULL, ("%s: ia is NULL", __func__));
81675c13541SPoul-Henning Kamp 
81791421ba2SRobert Watson 	if (!jailed(cred))
818413628a7SBjoern A. Zeeb 		/* Do not change address passed in. */
819413628a7SBjoern A. Zeeb 		return (0);
820413628a7SBjoern A. Zeeb 
821413628a7SBjoern A. Zeeb 	if (cred->cr_prison->pr_ip4 == NULL)
822413628a7SBjoern A. Zeeb 		return (1);
823413628a7SBjoern A. Zeeb 
824413628a7SBjoern A. Zeeb 	ia->s_addr = cred->cr_prison->pr_ip4[0].s_addr;
825413628a7SBjoern A. Zeeb 	return (0);
82675c13541SPoul-Henning Kamp }
827413628a7SBjoern A. Zeeb 
828413628a7SBjoern A. Zeeb /*
829413628a7SBjoern A. Zeeb  * Make sure our (source) address is set to something meaningful to this
830413628a7SBjoern A. Zeeb  * jail.
831413628a7SBjoern A. Zeeb  *
832413628a7SBjoern A. Zeeb  * Returns 0 on success, 1 on error.  Address passed in in NBO and returned
833413628a7SBjoern A. Zeeb  * in NBO.
834413628a7SBjoern A. Zeeb  */
835413628a7SBjoern A. Zeeb int
836413628a7SBjoern A. Zeeb prison_local_ip4(struct ucred *cred, struct in_addr *ia)
837413628a7SBjoern A. Zeeb {
838413628a7SBjoern A. Zeeb 	struct in_addr ia0;
839413628a7SBjoern A. Zeeb 
840413628a7SBjoern A. Zeeb 	KASSERT(cred != NULL, ("%s: cred is NULL", __func__));
841413628a7SBjoern A. Zeeb 	KASSERT(ia != NULL, ("%s: ia is NULL", __func__));
842413628a7SBjoern A. Zeeb 
843413628a7SBjoern A. Zeeb 	if (!jailed(cred))
844413628a7SBjoern A. Zeeb 		return (0);
845413628a7SBjoern A. Zeeb 	if (cred->cr_prison->pr_ip4 == NULL)
846413628a7SBjoern A. Zeeb 		return (1);
847413628a7SBjoern A. Zeeb 
848413628a7SBjoern A. Zeeb 	ia0.s_addr = ntohl(ia->s_addr);
849413628a7SBjoern A. Zeeb 	if (ia0.s_addr == INADDR_LOOPBACK) {
850413628a7SBjoern A. Zeeb 		ia->s_addr = cred->cr_prison->pr_ip4[0].s_addr;
851413628a7SBjoern A. Zeeb 		return (0);
852413628a7SBjoern A. Zeeb 	}
853413628a7SBjoern A. Zeeb 
854413628a7SBjoern A. Zeeb 	/*
855413628a7SBjoern A. Zeeb 	 * In case there is only 1 IPv4 address, bind directly.
856413628a7SBjoern A. Zeeb 	 */
857413628a7SBjoern A. Zeeb 	if (ia0.s_addr == INADDR_ANY && cred->cr_prison->pr_ip4s == 1) {
858413628a7SBjoern A. Zeeb 		ia->s_addr = cred->cr_prison->pr_ip4[0].s_addr;
859413628a7SBjoern A. Zeeb 		return (0);
860413628a7SBjoern A. Zeeb 	}
861413628a7SBjoern A. Zeeb 
862413628a7SBjoern A. Zeeb 	if (ia0.s_addr == INADDR_ANY || prison_check_ip4(cred, ia))
863413628a7SBjoern A. Zeeb 		return (0);
864413628a7SBjoern A. Zeeb 
865413628a7SBjoern A. Zeeb 	return (1);
866413628a7SBjoern A. Zeeb }
867413628a7SBjoern A. Zeeb 
868413628a7SBjoern A. Zeeb /*
869413628a7SBjoern A. Zeeb  * Rewrite destination address in case we will connect to loopback address.
870413628a7SBjoern A. Zeeb  *
871413628a7SBjoern A. Zeeb  * Returns 0 on success, 1 on error.  Address passed in in NBO and returned
872413628a7SBjoern A. Zeeb  * in NBO.
873413628a7SBjoern A. Zeeb  */
874413628a7SBjoern A. Zeeb int
875413628a7SBjoern A. Zeeb prison_remote_ip4(struct ucred *cred, struct in_addr *ia)
876413628a7SBjoern A. Zeeb {
877413628a7SBjoern A. Zeeb 
878413628a7SBjoern A. Zeeb 	KASSERT(cred != NULL, ("%s: cred is NULL", __func__));
879413628a7SBjoern A. Zeeb 	KASSERT(ia != NULL, ("%s: ia is NULL", __func__));
880413628a7SBjoern A. Zeeb 
881413628a7SBjoern A. Zeeb 	if (!jailed(cred))
882413628a7SBjoern A. Zeeb 		return (0);
883413628a7SBjoern A. Zeeb 	if (cred->cr_prison->pr_ip4 == NULL)
884413628a7SBjoern A. Zeeb 		return (1);
885413628a7SBjoern A. Zeeb 	if (ntohl(ia->s_addr) == INADDR_LOOPBACK) {
886413628a7SBjoern A. Zeeb 		ia->s_addr = cred->cr_prison->pr_ip4[0].s_addr;
887413628a7SBjoern A. Zeeb 		return (0);
888413628a7SBjoern A. Zeeb 	}
889413628a7SBjoern A. Zeeb 
890413628a7SBjoern A. Zeeb 	/*
891413628a7SBjoern A. Zeeb 	 * Return success because nothing had to be changed.
892413628a7SBjoern A. Zeeb 	 */
893413628a7SBjoern A. Zeeb 	return (0);
894413628a7SBjoern A. Zeeb }
895413628a7SBjoern A. Zeeb 
896413628a7SBjoern A. Zeeb /*
897413628a7SBjoern A. Zeeb  * Check if given address belongs to the jail referenced by cred.
898413628a7SBjoern A. Zeeb  *
899413628a7SBjoern A. Zeeb  * Returns 1 if address belongs to jail, 0 if not.  Address passed in in NBO.
900413628a7SBjoern A. Zeeb  */
901413628a7SBjoern A. Zeeb static int
902413628a7SBjoern A. Zeeb _prison_check_ip4(struct prison *pr, struct in_addr *ia)
903413628a7SBjoern A. Zeeb {
904413628a7SBjoern A. Zeeb 	int i, a, z, d;
905413628a7SBjoern A. Zeeb 
906413628a7SBjoern A. Zeeb 	if (pr->pr_ip4 == NULL)
907413628a7SBjoern A. Zeeb 		return (0);
908413628a7SBjoern A. Zeeb 
909413628a7SBjoern A. Zeeb 	/*
910413628a7SBjoern A. Zeeb 	 * Check the primary IP.
911413628a7SBjoern A. Zeeb 	 */
912413628a7SBjoern A. Zeeb 	if (pr->pr_ip4[0].s_addr == ia->s_addr)
913413628a7SBjoern A. Zeeb 		return (1);
914413628a7SBjoern A. Zeeb 
915413628a7SBjoern A. Zeeb 	/*
916413628a7SBjoern A. Zeeb 	 * All the other IPs are sorted so we can do a binary search.
917413628a7SBjoern A. Zeeb 	 */
918413628a7SBjoern A. Zeeb 	a = 0;
919413628a7SBjoern A. Zeeb 	z = pr->pr_ip4s - 2;
920413628a7SBjoern A. Zeeb 	while (a <= z) {
921413628a7SBjoern A. Zeeb 		i = (a + z) / 2;
922413628a7SBjoern A. Zeeb 		d = qcmp_v4(&pr->pr_ip4[i+1], ia);
923413628a7SBjoern A. Zeeb 		if (d > 0)
924413628a7SBjoern A. Zeeb 			z = i - 1;
925413628a7SBjoern A. Zeeb 		else if (d < 0)
926413628a7SBjoern A. Zeeb 			a = i + 1;
927413628a7SBjoern A. Zeeb 		else
928413628a7SBjoern A. Zeeb 			return (1);
929413628a7SBjoern A. Zeeb 	}
930413628a7SBjoern A. Zeeb 	return (0);
93175c13541SPoul-Henning Kamp }
93275c13541SPoul-Henning Kamp 
93375c13541SPoul-Henning Kamp int
934413628a7SBjoern A. Zeeb prison_check_ip4(struct ucred *cred, struct in_addr *ia)
935413628a7SBjoern A. Zeeb {
936413628a7SBjoern A. Zeeb 
937413628a7SBjoern A. Zeeb 	KASSERT(cred != NULL, ("%s: cred is NULL", __func__));
938413628a7SBjoern A. Zeeb 	KASSERT(ia != NULL, ("%s: ia is NULL", __func__));
939413628a7SBjoern A. Zeeb 
940413628a7SBjoern A. Zeeb 	if (!jailed(cred))
941413628a7SBjoern A. Zeeb 		return (1);
942413628a7SBjoern A. Zeeb 
943413628a7SBjoern A. Zeeb 	return (_prison_check_ip4(cred->cr_prison, ia));
944413628a7SBjoern A. Zeeb }
945413628a7SBjoern A. Zeeb #endif
946413628a7SBjoern A. Zeeb 
947413628a7SBjoern A. Zeeb #ifdef INET6
948413628a7SBjoern A. Zeeb /*
949413628a7SBjoern A. Zeeb  * Pass back primary IPv6 address for this jail.
950413628a7SBjoern A. Zeeb  *
951413628a7SBjoern A. Zeeb  * If not jailed return success but do not alter the address.  Caller has to
952413628a7SBjoern A. Zeeb  * make sure to intialize it correctly (IN6ADDR_ANY_INIT).
953413628a7SBjoern A. Zeeb  *
954413628a7SBjoern A. Zeeb  * Returns 0 on success, 1 on error.
955413628a7SBjoern A. Zeeb  */
956413628a7SBjoern A. Zeeb int
957413628a7SBjoern A. Zeeb prison_getip6(struct ucred *cred, struct in6_addr *ia6)
958413628a7SBjoern A. Zeeb {
959413628a7SBjoern A. Zeeb 
960413628a7SBjoern A. Zeeb 	KASSERT(cred != NULL, ("%s: cred is NULL", __func__));
961413628a7SBjoern A. Zeeb 	KASSERT(ia6 != NULL, ("%s: ia6 is NULL", __func__));
962413628a7SBjoern A. Zeeb 
963413628a7SBjoern A. Zeeb 	if (!jailed(cred))
964413628a7SBjoern A. Zeeb 		return (0);
965413628a7SBjoern A. Zeeb 	if (cred->cr_prison->pr_ip6 == NULL)
966413628a7SBjoern A. Zeeb 		return (1);
967413628a7SBjoern A. Zeeb 	bcopy(&cred->cr_prison->pr_ip6[0], ia6, sizeof(struct in6_addr));
968413628a7SBjoern A. Zeeb 	return (0);
969413628a7SBjoern A. Zeeb }
970413628a7SBjoern A. Zeeb 
971413628a7SBjoern A. Zeeb /*
972413628a7SBjoern A. Zeeb  * Make sure our (source) address is set to something meaningful to this jail.
973413628a7SBjoern A. Zeeb  *
974413628a7SBjoern A. Zeeb  * v6only should be set based on (inp->inp_flags & IN6P_IPV6_V6ONLY != 0)
975413628a7SBjoern A. Zeeb  * when needed while binding.
976413628a7SBjoern A. Zeeb  *
977413628a7SBjoern A. Zeeb  * Returns 0 on success, 1 on error.
978413628a7SBjoern A. Zeeb  */
979413628a7SBjoern A. Zeeb int
980413628a7SBjoern A. Zeeb prison_local_ip6(struct ucred *cred, struct in6_addr *ia6, int v6only)
981413628a7SBjoern A. Zeeb {
982413628a7SBjoern A. Zeeb 
983413628a7SBjoern A. Zeeb 	KASSERT(cred != NULL, ("%s: cred is NULL", __func__));
984413628a7SBjoern A. Zeeb 	KASSERT(ia6 != NULL, ("%s: ia6 is NULL", __func__));
985413628a7SBjoern A. Zeeb 
986413628a7SBjoern A. Zeeb 	if (!jailed(cred))
987413628a7SBjoern A. Zeeb 		return (0);
988413628a7SBjoern A. Zeeb 	if (cred->cr_prison->pr_ip6 == NULL)
989413628a7SBjoern A. Zeeb 		return (1);
990413628a7SBjoern A. Zeeb 	if (IN6_IS_ADDR_LOOPBACK(ia6)) {
991413628a7SBjoern A. Zeeb 		bcopy(&cred->cr_prison->pr_ip6[0], ia6,
992413628a7SBjoern A. Zeeb 		    sizeof(struct in6_addr));
993413628a7SBjoern A. Zeeb 		return (0);
994413628a7SBjoern A. Zeeb 	}
995413628a7SBjoern A. Zeeb 
996413628a7SBjoern A. Zeeb 	/*
997413628a7SBjoern A. Zeeb 	 * In case there is only 1 IPv6 address, and v6only is true, then
998413628a7SBjoern A. Zeeb 	 * bind directly.
999413628a7SBjoern A. Zeeb 	 */
1000413628a7SBjoern A. Zeeb 	if (v6only != 0 && IN6_IS_ADDR_UNSPECIFIED(ia6) &&
1001413628a7SBjoern A. Zeeb 	    cred->cr_prison->pr_ip6s == 1) {
1002413628a7SBjoern A. Zeeb 		bcopy(&cred->cr_prison->pr_ip6[0], ia6,
1003413628a7SBjoern A. Zeeb 		    sizeof(struct in6_addr));
1004413628a7SBjoern A. Zeeb 		return (0);
1005413628a7SBjoern A. Zeeb 	}
1006413628a7SBjoern A. Zeeb 	if (IN6_IS_ADDR_UNSPECIFIED(ia6) || prison_check_ip6(cred, ia6))
1007413628a7SBjoern A. Zeeb 		return (0);
1008413628a7SBjoern A. Zeeb 	return (1);
1009413628a7SBjoern A. Zeeb }
1010413628a7SBjoern A. Zeeb 
1011413628a7SBjoern A. Zeeb /*
1012413628a7SBjoern A. Zeeb  * Rewrite destination address in case we will connect to loopback address.
1013413628a7SBjoern A. Zeeb  *
1014413628a7SBjoern A. Zeeb  * Returns 0 on success, 1 on error.
1015413628a7SBjoern A. Zeeb  */
1016413628a7SBjoern A. Zeeb int
1017413628a7SBjoern A. Zeeb prison_remote_ip6(struct ucred *cred, struct in6_addr *ia6)
1018413628a7SBjoern A. Zeeb {
1019413628a7SBjoern A. Zeeb 
1020413628a7SBjoern A. Zeeb 	KASSERT(cred != NULL, ("%s: cred is NULL", __func__));
1021413628a7SBjoern A. Zeeb 	KASSERT(ia6 != NULL, ("%s: ia6 is NULL", __func__));
1022413628a7SBjoern A. Zeeb 
1023413628a7SBjoern A. Zeeb 	if (!jailed(cred))
1024413628a7SBjoern A. Zeeb 		return (0);
1025413628a7SBjoern A. Zeeb 	if (cred->cr_prison->pr_ip6 == NULL)
1026413628a7SBjoern A. Zeeb 		return (1);
1027413628a7SBjoern A. Zeeb 	if (IN6_IS_ADDR_LOOPBACK(ia6)) {
1028413628a7SBjoern A. Zeeb 		bcopy(&cred->cr_prison->pr_ip6[0], ia6,
1029413628a7SBjoern A. Zeeb 		    sizeof(struct in6_addr));
1030413628a7SBjoern A. Zeeb 		return (0);
1031413628a7SBjoern A. Zeeb 	}
1032413628a7SBjoern A. Zeeb 
1033413628a7SBjoern A. Zeeb 	/*
1034413628a7SBjoern A. Zeeb 	 * Return success because nothing had to be changed.
1035413628a7SBjoern A. Zeeb 	 */
1036413628a7SBjoern A. Zeeb 	return (0);
1037413628a7SBjoern A. Zeeb }
1038413628a7SBjoern A. Zeeb 
1039413628a7SBjoern A. Zeeb /*
1040413628a7SBjoern A. Zeeb  * Check if given address belongs to the jail referenced by cred.
1041413628a7SBjoern A. Zeeb  *
1042413628a7SBjoern A. Zeeb  * Returns 1 if address belongs to jail, 0 if not.
1043413628a7SBjoern A. Zeeb  */
1044413628a7SBjoern A. Zeeb static int
1045413628a7SBjoern A. Zeeb _prison_check_ip6(struct prison *pr, struct in6_addr *ia6)
1046413628a7SBjoern A. Zeeb {
1047413628a7SBjoern A. Zeeb 	int i, a, z, d;
1048413628a7SBjoern A. Zeeb 
1049413628a7SBjoern A. Zeeb 	if (pr->pr_ip6 == NULL)
1050413628a7SBjoern A. Zeeb 		return (0);
1051413628a7SBjoern A. Zeeb 
1052413628a7SBjoern A. Zeeb 	/*
1053413628a7SBjoern A. Zeeb 	 * Check the primary IP.
1054413628a7SBjoern A. Zeeb 	 */
1055413628a7SBjoern A. Zeeb 	if (IN6_ARE_ADDR_EQUAL(&pr->pr_ip6[0], ia6))
1056413628a7SBjoern A. Zeeb 		return (1);
1057413628a7SBjoern A. Zeeb 
1058413628a7SBjoern A. Zeeb 	/*
1059413628a7SBjoern A. Zeeb 	 * All the other IPs are sorted so we can do a binary search.
1060413628a7SBjoern A. Zeeb 	 */
1061413628a7SBjoern A. Zeeb 	a = 0;
1062413628a7SBjoern A. Zeeb 	z = pr->pr_ip6s - 2;
1063413628a7SBjoern A. Zeeb 	while (a <= z) {
1064413628a7SBjoern A. Zeeb 		i = (a + z) / 2;
1065413628a7SBjoern A. Zeeb 		d = qcmp_v6(&pr->pr_ip6[i+1], ia6);
1066413628a7SBjoern A. Zeeb 		if (d > 0)
1067413628a7SBjoern A. Zeeb 			z = i - 1;
1068413628a7SBjoern A. Zeeb 		else if (d < 0)
1069413628a7SBjoern A. Zeeb 			a = i + 1;
1070413628a7SBjoern A. Zeeb 		else
1071413628a7SBjoern A. Zeeb 			return (1);
1072413628a7SBjoern A. Zeeb 	}
1073413628a7SBjoern A. Zeeb 	return (0);
1074413628a7SBjoern A. Zeeb }
1075413628a7SBjoern A. Zeeb 
1076413628a7SBjoern A. Zeeb int
1077413628a7SBjoern A. Zeeb prison_check_ip6(struct ucred *cred, struct in6_addr *ia6)
1078413628a7SBjoern A. Zeeb {
1079413628a7SBjoern A. Zeeb 
1080413628a7SBjoern A. Zeeb 	KASSERT(cred != NULL, ("%s: cred is NULL", __func__));
1081413628a7SBjoern A. Zeeb 	KASSERT(ia6 != NULL, ("%s: ia6 is NULL", __func__));
1082413628a7SBjoern A. Zeeb 
1083413628a7SBjoern A. Zeeb 	if (!jailed(cred))
1084413628a7SBjoern A. Zeeb 		return (1);
1085413628a7SBjoern A. Zeeb 
1086413628a7SBjoern A. Zeeb 	return (_prison_check_ip6(cred->cr_prison, ia6));
1087413628a7SBjoern A. Zeeb }
1088413628a7SBjoern A. Zeeb #endif
1089413628a7SBjoern A. Zeeb 
1090413628a7SBjoern A. Zeeb /*
1091413628a7SBjoern A. Zeeb  * Check if given address belongs to the jail referenced by cred (wrapper to
1092413628a7SBjoern A. Zeeb  * prison_check_ip[46]).
1093413628a7SBjoern A. Zeeb  *
1094413628a7SBjoern A. Zeeb  * Returns 1 if address belongs to jail, 0 if not.  IPv4 Address passed in in
1095413628a7SBjoern A. Zeeb  * NBO.
1096413628a7SBjoern A. Zeeb  */
1097413628a7SBjoern A. Zeeb int
109891421ba2SRobert Watson prison_if(struct ucred *cred, struct sockaddr *sa)
109975c13541SPoul-Henning Kamp {
1100413628a7SBjoern A. Zeeb #ifdef INET
11019ddb7954SMike Barcroft 	struct sockaddr_in *sai;
1102413628a7SBjoern A. Zeeb #endif
1103413628a7SBjoern A. Zeeb #ifdef INET6
1104413628a7SBjoern A. Zeeb 	struct sockaddr_in6 *sai6;
1105413628a7SBjoern A. Zeeb #endif
110675c13541SPoul-Henning Kamp 	int ok;
110775c13541SPoul-Henning Kamp 
1108413628a7SBjoern A. Zeeb 	KASSERT(cred != NULL, ("%s: cred is NULL", __func__));
1109413628a7SBjoern A. Zeeb 	KASSERT(sa != NULL, ("%s: sa is NULL", __func__));
1110413628a7SBjoern A. Zeeb 
1111413628a7SBjoern A. Zeeb 	ok = 0;
1112413628a7SBjoern A. Zeeb 	switch(sa->sa_family)
1113413628a7SBjoern A. Zeeb 	{
1114413628a7SBjoern A. Zeeb #ifdef INET
1115413628a7SBjoern A. Zeeb 	case AF_INET:
11169ddb7954SMike Barcroft 		sai = (struct sockaddr_in *)sa;
1117413628a7SBjoern A. Zeeb 		if (prison_check_ip4(cred, &sai->sin_addr))
11187cadc266SRobert Watson 			ok = 1;
1119413628a7SBjoern A. Zeeb 		break;
1120413628a7SBjoern A. Zeeb 
1121413628a7SBjoern A. Zeeb #endif
1122413628a7SBjoern A. Zeeb #ifdef INET6
1123413628a7SBjoern A. Zeeb 	case AF_INET6:
1124413628a7SBjoern A. Zeeb 		sai6 = (struct sockaddr_in6 *)sa;
1125413628a7SBjoern A. Zeeb 		if (prison_check_ip6(cred, (struct in6_addr *)&sai6->sin6_addr))
112675c13541SPoul-Henning Kamp 			ok = 1;
1127413628a7SBjoern A. Zeeb 		break;
1128413628a7SBjoern A. Zeeb 
1129413628a7SBjoern A. Zeeb #endif
1130413628a7SBjoern A. Zeeb 	default:
1131413628a7SBjoern A. Zeeb 		if (!jail_socket_unixiproute_only)
1132413628a7SBjoern A. Zeeb 			ok = 1;
1133413628a7SBjoern A. Zeeb 	}
113475c13541SPoul-Henning Kamp 	return (ok);
113575c13541SPoul-Henning Kamp }
113691421ba2SRobert Watson 
113791421ba2SRobert Watson /*
113891421ba2SRobert Watson  * Return 0 if jails permit p1 to frob p2, otherwise ESRCH.
113991421ba2SRobert Watson  */
114091421ba2SRobert Watson int
11419ddb7954SMike Barcroft prison_check(struct ucred *cred1, struct ucred *cred2)
114291421ba2SRobert Watson {
114391421ba2SRobert Watson 
114491421ba2SRobert Watson 	if (jailed(cred1)) {
114591421ba2SRobert Watson 		if (!jailed(cred2))
114691421ba2SRobert Watson 			return (ESRCH);
114791421ba2SRobert Watson 		if (cred2->cr_prison != cred1->cr_prison)
114891421ba2SRobert Watson 			return (ESRCH);
114991421ba2SRobert Watson 	}
115091421ba2SRobert Watson 
115191421ba2SRobert Watson 	return (0);
115291421ba2SRobert Watson }
115391421ba2SRobert Watson 
115491421ba2SRobert Watson /*
115591421ba2SRobert Watson  * Return 1 if the passed credential is in a jail, otherwise 0.
115691421ba2SRobert Watson  */
115791421ba2SRobert Watson int
11589ddb7954SMike Barcroft jailed(struct ucred *cred)
115991421ba2SRobert Watson {
116091421ba2SRobert Watson 
116191421ba2SRobert Watson 	return (cred->cr_prison != NULL);
116291421ba2SRobert Watson }
11639484d0c0SRobert Drehmel 
11649484d0c0SRobert Drehmel /*
11659484d0c0SRobert Drehmel  * Return the correct hostname for the passed credential.
11669484d0c0SRobert Drehmel  */
1167ad1ff099SRobert Drehmel void
11689ddb7954SMike Barcroft getcredhostname(struct ucred *cred, char *buf, size_t size)
11699484d0c0SRobert Drehmel {
11708b615593SMarko Zec 	INIT_VPROCG(cred->cr_vimage->v_procg);
11719484d0c0SRobert Drehmel 
1172ad1ff099SRobert Drehmel 	if (jailed(cred)) {
1173ad1ff099SRobert Drehmel 		mtx_lock(&cred->cr_prison->pr_mtx);
1174e80fb434SRobert Drehmel 		strlcpy(buf, cred->cr_prison->pr_host, size);
1175ad1ff099SRobert Drehmel 		mtx_unlock(&cred->cr_prison->pr_mtx);
11764f7d1876SRobert Watson 	} else {
11774f7d1876SRobert Watson 		mtx_lock(&hostname_mtx);
1178603724d3SBjoern A. Zeeb 		strlcpy(buf, V_hostname, size);
11794f7d1876SRobert Watson 		mtx_unlock(&hostname_mtx);
11804f7d1876SRobert Watson 	}
11819484d0c0SRobert Drehmel }
1182fd7a8150SMike Barcroft 
1183f08df373SRobert Watson /*
1184820a0de9SPawel Jakub Dawidek  * Determine whether the subject represented by cred can "see"
1185820a0de9SPawel Jakub Dawidek  * status of a mount point.
1186820a0de9SPawel Jakub Dawidek  * Returns: 0 for permitted, ENOENT otherwise.
1187820a0de9SPawel Jakub Dawidek  * XXX: This function should be called cr_canseemount() and should be
1188820a0de9SPawel Jakub Dawidek  *      placed in kern_prot.c.
1189f08df373SRobert Watson  */
1190f08df373SRobert Watson int
1191820a0de9SPawel Jakub Dawidek prison_canseemount(struct ucred *cred, struct mount *mp)
1192f08df373SRobert Watson {
1193820a0de9SPawel Jakub Dawidek 	struct prison *pr;
1194820a0de9SPawel Jakub Dawidek 	struct statfs *sp;
1195820a0de9SPawel Jakub Dawidek 	size_t len;
1196f08df373SRobert Watson 
1197820a0de9SPawel Jakub Dawidek 	if (!jailed(cred) || jail_enforce_statfs == 0)
1198820a0de9SPawel Jakub Dawidek 		return (0);
1199820a0de9SPawel Jakub Dawidek 	pr = cred->cr_prison;
1200820a0de9SPawel Jakub Dawidek 	if (pr->pr_root->v_mount == mp)
1201820a0de9SPawel Jakub Dawidek 		return (0);
1202820a0de9SPawel Jakub Dawidek 	if (jail_enforce_statfs == 2)
1203820a0de9SPawel Jakub Dawidek 		return (ENOENT);
1204820a0de9SPawel Jakub Dawidek 	/*
1205820a0de9SPawel Jakub Dawidek 	 * If jail's chroot directory is set to "/" we should be able to see
1206820a0de9SPawel Jakub Dawidek 	 * all mount-points from inside a jail.
1207820a0de9SPawel Jakub Dawidek 	 * This is ugly check, but this is the only situation when jail's
1208820a0de9SPawel Jakub Dawidek 	 * directory ends with '/'.
1209820a0de9SPawel Jakub Dawidek 	 */
1210820a0de9SPawel Jakub Dawidek 	if (strcmp(pr->pr_path, "/") == 0)
1211820a0de9SPawel Jakub Dawidek 		return (0);
1212820a0de9SPawel Jakub Dawidek 	len = strlen(pr->pr_path);
1213820a0de9SPawel Jakub Dawidek 	sp = &mp->mnt_stat;
1214820a0de9SPawel Jakub Dawidek 	if (strncmp(pr->pr_path, sp->f_mntonname, len) != 0)
1215820a0de9SPawel Jakub Dawidek 		return (ENOENT);
1216820a0de9SPawel Jakub Dawidek 	/*
1217820a0de9SPawel Jakub Dawidek 	 * Be sure that we don't have situation where jail's root directory
1218820a0de9SPawel Jakub Dawidek 	 * is "/some/path" and mount point is "/some/pathpath".
1219820a0de9SPawel Jakub Dawidek 	 */
1220820a0de9SPawel Jakub Dawidek 	if (sp->f_mntonname[len] != '\0' && sp->f_mntonname[len] != '/')
1221820a0de9SPawel Jakub Dawidek 		return (ENOENT);
1222f08df373SRobert Watson 	return (0);
1223f08df373SRobert Watson }
1224820a0de9SPawel Jakub Dawidek 
1225820a0de9SPawel Jakub Dawidek void
1226820a0de9SPawel Jakub Dawidek prison_enforce_statfs(struct ucred *cred, struct mount *mp, struct statfs *sp)
1227820a0de9SPawel Jakub Dawidek {
1228820a0de9SPawel Jakub Dawidek 	char jpath[MAXPATHLEN];
1229820a0de9SPawel Jakub Dawidek 	struct prison *pr;
1230820a0de9SPawel Jakub Dawidek 	size_t len;
1231820a0de9SPawel Jakub Dawidek 
1232820a0de9SPawel Jakub Dawidek 	if (!jailed(cred) || jail_enforce_statfs == 0)
1233820a0de9SPawel Jakub Dawidek 		return;
1234820a0de9SPawel Jakub Dawidek 	pr = cred->cr_prison;
1235820a0de9SPawel Jakub Dawidek 	if (prison_canseemount(cred, mp) != 0) {
1236820a0de9SPawel Jakub Dawidek 		bzero(sp->f_mntonname, sizeof(sp->f_mntonname));
1237820a0de9SPawel Jakub Dawidek 		strlcpy(sp->f_mntonname, "[restricted]",
1238820a0de9SPawel Jakub Dawidek 		    sizeof(sp->f_mntonname));
1239820a0de9SPawel Jakub Dawidek 		return;
1240820a0de9SPawel Jakub Dawidek 	}
1241820a0de9SPawel Jakub Dawidek 	if (pr->pr_root->v_mount == mp) {
1242820a0de9SPawel Jakub Dawidek 		/*
1243820a0de9SPawel Jakub Dawidek 		 * Clear current buffer data, so we are sure nothing from
1244820a0de9SPawel Jakub Dawidek 		 * the valid path left there.
1245820a0de9SPawel Jakub Dawidek 		 */
1246820a0de9SPawel Jakub Dawidek 		bzero(sp->f_mntonname, sizeof(sp->f_mntonname));
1247820a0de9SPawel Jakub Dawidek 		*sp->f_mntonname = '/';
1248820a0de9SPawel Jakub Dawidek 		return;
1249820a0de9SPawel Jakub Dawidek 	}
1250820a0de9SPawel Jakub Dawidek 	/*
1251820a0de9SPawel Jakub Dawidek 	 * If jail's chroot directory is set to "/" we should be able to see
1252820a0de9SPawel Jakub Dawidek 	 * all mount-points from inside a jail.
1253820a0de9SPawel Jakub Dawidek 	 */
1254820a0de9SPawel Jakub Dawidek 	if (strcmp(pr->pr_path, "/") == 0)
1255820a0de9SPawel Jakub Dawidek 		return;
1256820a0de9SPawel Jakub Dawidek 	len = strlen(pr->pr_path);
1257820a0de9SPawel Jakub Dawidek 	strlcpy(jpath, sp->f_mntonname + len, sizeof(jpath));
1258820a0de9SPawel Jakub Dawidek 	/*
1259820a0de9SPawel Jakub Dawidek 	 * Clear current buffer data, so we are sure nothing from
1260820a0de9SPawel Jakub Dawidek 	 * the valid path left there.
1261820a0de9SPawel Jakub Dawidek 	 */
1262820a0de9SPawel Jakub Dawidek 	bzero(sp->f_mntonname, sizeof(sp->f_mntonname));
1263820a0de9SPawel Jakub Dawidek 	if (*jpath == '\0') {
1264820a0de9SPawel Jakub Dawidek 		/* Should never happen. */
1265820a0de9SPawel Jakub Dawidek 		*sp->f_mntonname = '/';
1266820a0de9SPawel Jakub Dawidek 	} else {
1267820a0de9SPawel Jakub Dawidek 		strlcpy(sp->f_mntonname, jpath, sizeof(sp->f_mntonname));
1268820a0de9SPawel Jakub Dawidek 	}
1269f08df373SRobert Watson }
1270f08df373SRobert Watson 
1271800c9408SRobert Watson /*
1272800c9408SRobert Watson  * Check with permission for a specific privilege is granted within jail.  We
1273800c9408SRobert Watson  * have a specific list of accepted privileges; the rest are denied.
1274800c9408SRobert Watson  */
1275800c9408SRobert Watson int
1276800c9408SRobert Watson prison_priv_check(struct ucred *cred, int priv)
1277800c9408SRobert Watson {
1278800c9408SRobert Watson 
1279800c9408SRobert Watson 	if (!jailed(cred))
1280800c9408SRobert Watson 		return (0);
1281800c9408SRobert Watson 
1282800c9408SRobert Watson 	switch (priv) {
1283800c9408SRobert Watson 
1284800c9408SRobert Watson 		/*
1285800c9408SRobert Watson 		 * Allow ktrace privileges for root in jail.
1286800c9408SRobert Watson 		 */
1287800c9408SRobert Watson 	case PRIV_KTRACE:
1288800c9408SRobert Watson 
1289c3c1b5e6SRobert Watson #if 0
1290800c9408SRobert Watson 		/*
1291800c9408SRobert Watson 		 * Allow jailed processes to configure audit identity and
1292800c9408SRobert Watson 		 * submit audit records (login, etc).  In the future we may
1293800c9408SRobert Watson 		 * want to further refine the relationship between audit and
1294800c9408SRobert Watson 		 * jail.
1295800c9408SRobert Watson 		 */
1296800c9408SRobert Watson 	case PRIV_AUDIT_GETAUDIT:
1297800c9408SRobert Watson 	case PRIV_AUDIT_SETAUDIT:
1298800c9408SRobert Watson 	case PRIV_AUDIT_SUBMIT:
1299c3c1b5e6SRobert Watson #endif
1300800c9408SRobert Watson 
1301800c9408SRobert Watson 		/*
1302800c9408SRobert Watson 		 * Allow jailed processes to manipulate process UNIX
1303800c9408SRobert Watson 		 * credentials in any way they see fit.
1304800c9408SRobert Watson 		 */
1305800c9408SRobert Watson 	case PRIV_CRED_SETUID:
1306800c9408SRobert Watson 	case PRIV_CRED_SETEUID:
1307800c9408SRobert Watson 	case PRIV_CRED_SETGID:
1308800c9408SRobert Watson 	case PRIV_CRED_SETEGID:
1309800c9408SRobert Watson 	case PRIV_CRED_SETGROUPS:
1310800c9408SRobert Watson 	case PRIV_CRED_SETREUID:
1311800c9408SRobert Watson 	case PRIV_CRED_SETREGID:
1312800c9408SRobert Watson 	case PRIV_CRED_SETRESUID:
1313800c9408SRobert Watson 	case PRIV_CRED_SETRESGID:
1314800c9408SRobert Watson 
1315800c9408SRobert Watson 		/*
1316800c9408SRobert Watson 		 * Jail implements visibility constraints already, so allow
1317800c9408SRobert Watson 		 * jailed root to override uid/gid-based constraints.
1318800c9408SRobert Watson 		 */
1319800c9408SRobert Watson 	case PRIV_SEEOTHERGIDS:
1320800c9408SRobert Watson 	case PRIV_SEEOTHERUIDS:
1321800c9408SRobert Watson 
1322800c9408SRobert Watson 		/*
1323800c9408SRobert Watson 		 * Jail implements inter-process debugging limits already, so
1324800c9408SRobert Watson 		 * allow jailed root various debugging privileges.
1325800c9408SRobert Watson 		 */
1326800c9408SRobert Watson 	case PRIV_DEBUG_DIFFCRED:
1327800c9408SRobert Watson 	case PRIV_DEBUG_SUGID:
1328800c9408SRobert Watson 	case PRIV_DEBUG_UNPRIV:
1329800c9408SRobert Watson 
1330800c9408SRobert Watson 		/*
1331800c9408SRobert Watson 		 * Allow jail to set various resource limits and login
1332800c9408SRobert Watson 		 * properties, and for now, exceed process resource limits.
1333800c9408SRobert Watson 		 */
1334800c9408SRobert Watson 	case PRIV_PROC_LIMIT:
1335800c9408SRobert Watson 	case PRIV_PROC_SETLOGIN:
1336800c9408SRobert Watson 	case PRIV_PROC_SETRLIMIT:
1337800c9408SRobert Watson 
1338800c9408SRobert Watson 		/*
1339800c9408SRobert Watson 		 * System V and POSIX IPC privileges are granted in jail.
1340800c9408SRobert Watson 		 */
1341800c9408SRobert Watson 	case PRIV_IPC_READ:
1342800c9408SRobert Watson 	case PRIV_IPC_WRITE:
1343800c9408SRobert Watson 	case PRIV_IPC_ADMIN:
1344800c9408SRobert Watson 	case PRIV_IPC_MSGSIZE:
1345800c9408SRobert Watson 	case PRIV_MQ_ADMIN:
1346800c9408SRobert Watson 
1347800c9408SRobert Watson 		/*
1348800c9408SRobert Watson 		 * Jail implements its own inter-process limits, so allow
1349800c9408SRobert Watson 		 * root processes in jail to change scheduling on other
1350800c9408SRobert Watson 		 * processes in the same jail.  Likewise for signalling.
1351800c9408SRobert Watson 		 */
1352800c9408SRobert Watson 	case PRIV_SCHED_DIFFCRED:
1353413628a7SBjoern A. Zeeb 	case PRIV_SCHED_CPUSET:
1354800c9408SRobert Watson 	case PRIV_SIGNAL_DIFFCRED:
1355800c9408SRobert Watson 	case PRIV_SIGNAL_SUGID:
1356800c9408SRobert Watson 
1357800c9408SRobert Watson 		/*
1358800c9408SRobert Watson 		 * Allow jailed processes to write to sysctls marked as jail
1359800c9408SRobert Watson 		 * writable.
1360800c9408SRobert Watson 		 */
1361800c9408SRobert Watson 	case PRIV_SYSCTL_WRITEJAIL:
1362800c9408SRobert Watson 
1363800c9408SRobert Watson 		/*
1364800c9408SRobert Watson 		 * Allow root in jail to manage a variety of quota
1365e82d0201SRobert Watson 		 * properties.  These should likely be conditional on a
1366e82d0201SRobert Watson 		 * configuration option.
1367800c9408SRobert Watson 		 */
136895b091d2SRobert Watson 	case PRIV_VFS_GETQUOTA:
136995b091d2SRobert Watson 	case PRIV_VFS_SETQUOTA:
1370800c9408SRobert Watson 
1371800c9408SRobert Watson 		/*
1372800c9408SRobert Watson 		 * Since Jail relies on chroot() to implement file system
1373800c9408SRobert Watson 		 * protections, grant many VFS privileges to root in jail.
1374800c9408SRobert Watson 		 * Be careful to exclude mount-related and NFS-related
1375800c9408SRobert Watson 		 * privileges.
1376800c9408SRobert Watson 		 */
1377800c9408SRobert Watson 	case PRIV_VFS_READ:
1378800c9408SRobert Watson 	case PRIV_VFS_WRITE:
1379800c9408SRobert Watson 	case PRIV_VFS_ADMIN:
1380800c9408SRobert Watson 	case PRIV_VFS_EXEC:
1381800c9408SRobert Watson 	case PRIV_VFS_LOOKUP:
1382800c9408SRobert Watson 	case PRIV_VFS_BLOCKRESERVE:	/* XXXRW: Slightly surprising. */
1383800c9408SRobert Watson 	case PRIV_VFS_CHFLAGS_DEV:
1384800c9408SRobert Watson 	case PRIV_VFS_CHOWN:
1385800c9408SRobert Watson 	case PRIV_VFS_CHROOT:
1386bb531912SPawel Jakub Dawidek 	case PRIV_VFS_RETAINSUGID:
1387800c9408SRobert Watson 	case PRIV_VFS_FCHROOT:
1388800c9408SRobert Watson 	case PRIV_VFS_LINK:
1389800c9408SRobert Watson 	case PRIV_VFS_SETGID:
1390e41966dcSRobert Watson 	case PRIV_VFS_STAT:
1391800c9408SRobert Watson 	case PRIV_VFS_STICKYFILE:
1392800c9408SRobert Watson 		return (0);
1393800c9408SRobert Watson 
1394800c9408SRobert Watson 		/*
1395800c9408SRobert Watson 		 * Depending on the global setting, allow privilege of
1396800c9408SRobert Watson 		 * setting system flags.
1397800c9408SRobert Watson 		 */
1398800c9408SRobert Watson 	case PRIV_VFS_SYSFLAGS:
1399800c9408SRobert Watson 		if (jail_chflags_allowed)
1400800c9408SRobert Watson 			return (0);
1401800c9408SRobert Watson 		else
1402800c9408SRobert Watson 			return (EPERM);
1403800c9408SRobert Watson 
1404800c9408SRobert Watson 		/*
1405f3a8d2f9SPawel Jakub Dawidek 		 * Depending on the global setting, allow privilege of
1406f3a8d2f9SPawel Jakub Dawidek 		 * mounting/unmounting file systems.
1407f3a8d2f9SPawel Jakub Dawidek 		 */
1408f3a8d2f9SPawel Jakub Dawidek 	case PRIV_VFS_MOUNT:
1409f3a8d2f9SPawel Jakub Dawidek 	case PRIV_VFS_UNMOUNT:
1410f3a8d2f9SPawel Jakub Dawidek 	case PRIV_VFS_MOUNT_NONUSER:
141124b0502eSPawel Jakub Dawidek 	case PRIV_VFS_MOUNT_OWNER:
1412f3a8d2f9SPawel Jakub Dawidek 		if (jail_mount_allowed)
1413f3a8d2f9SPawel Jakub Dawidek 			return (0);
1414f3a8d2f9SPawel Jakub Dawidek 		else
1415f3a8d2f9SPawel Jakub Dawidek 			return (EPERM);
1416f3a8d2f9SPawel Jakub Dawidek 
1417f3a8d2f9SPawel Jakub Dawidek 		/*
14184b084056SRobert Watson 		 * Allow jailed root to bind reserved ports and reuse in-use
14194b084056SRobert Watson 		 * ports.
1420800c9408SRobert Watson 		 */
1421800c9408SRobert Watson 	case PRIV_NETINET_RESERVEDPORT:
14224b084056SRobert Watson 	case PRIV_NETINET_REUSEPORT:
1423800c9408SRobert Watson 		return (0);
1424800c9408SRobert Watson 
1425800c9408SRobert Watson 		/*
142679ba3952SBjoern A. Zeeb 		 * Allow jailed root to set certian IPv4/6 (option) headers.
142779ba3952SBjoern A. Zeeb 		 */
142879ba3952SBjoern A. Zeeb 	case PRIV_NETINET_SETHDROPTS:
142979ba3952SBjoern A. Zeeb 		return (0);
143079ba3952SBjoern A. Zeeb 
143179ba3952SBjoern A. Zeeb 		/*
1432800c9408SRobert Watson 		 * Conditionally allow creating raw sockets in jail.
1433800c9408SRobert Watson 		 */
1434800c9408SRobert Watson 	case PRIV_NETINET_RAW:
1435800c9408SRobert Watson 		if (jail_allow_raw_sockets)
1436800c9408SRobert Watson 			return (0);
1437800c9408SRobert Watson 		else
1438800c9408SRobert Watson 			return (EPERM);
1439800c9408SRobert Watson 
1440800c9408SRobert Watson 		/*
1441800c9408SRobert Watson 		 * Since jail implements its own visibility limits on netstat
1442800c9408SRobert Watson 		 * sysctls, allow getcred.  This allows identd to work in
1443800c9408SRobert Watson 		 * jail.
1444800c9408SRobert Watson 		 */
1445800c9408SRobert Watson 	case PRIV_NETINET_GETCRED:
1446800c9408SRobert Watson 		return (0);
1447800c9408SRobert Watson 
1448800c9408SRobert Watson 	default:
1449800c9408SRobert Watson 		/*
1450800c9408SRobert Watson 		 * In all remaining cases, deny the privilege request.  This
1451800c9408SRobert Watson 		 * includes almost all network privileges, many system
1452800c9408SRobert Watson 		 * configuration privileges.
1453800c9408SRobert Watson 		 */
1454800c9408SRobert Watson 		return (EPERM);
1455800c9408SRobert Watson 	}
1456800c9408SRobert Watson }
1457800c9408SRobert Watson 
1458fd7a8150SMike Barcroft static int
1459fd7a8150SMike Barcroft sysctl_jail_list(SYSCTL_HANDLER_ARGS)
1460fd7a8150SMike Barcroft {
1461fd7a8150SMike Barcroft 	struct xprison *xp, *sxp;
1462fd7a8150SMike Barcroft 	struct prison *pr;
1463413628a7SBjoern A. Zeeb 	char *p;
1464413628a7SBjoern A. Zeeb 	size_t len;
1465fd7a8150SMike Barcroft 	int count, error;
1466fd7a8150SMike Barcroft 
14677f4704c0SPawel Jakub Dawidek 	if (jailed(req->td->td_ucred))
1468679a1060SRobert Watson 		return (0);
1469fd7a8150SMike Barcroft 
1470dc68a633SPawel Jakub Dawidek 	sx_slock(&allprison_lock);
1471dc68a633SPawel Jakub Dawidek 	if ((count = prisoncount) == 0) {
1472dc68a633SPawel Jakub Dawidek 		sx_sunlock(&allprison_lock);
1473fd7a8150SMike Barcroft 		return (0);
1474dc68a633SPawel Jakub Dawidek 	}
1475fd7a8150SMike Barcroft 
1476413628a7SBjoern A. Zeeb 	len = sizeof(*xp) * count;
1477413628a7SBjoern A. Zeeb 	LIST_FOREACH(pr, &allprison, pr_list) {
1478413628a7SBjoern A. Zeeb #ifdef INET
1479413628a7SBjoern A. Zeeb 		len += pr->pr_ip4s * sizeof(struct in_addr);
1480413628a7SBjoern A. Zeeb #endif
1481413628a7SBjoern A. Zeeb #ifdef INET6
1482413628a7SBjoern A. Zeeb 		len += pr->pr_ip6s * sizeof(struct in6_addr);
1483413628a7SBjoern A. Zeeb #endif
1484413628a7SBjoern A. Zeeb 	}
1485413628a7SBjoern A. Zeeb 
1486413628a7SBjoern A. Zeeb 	sxp = xp = malloc(len, M_TEMP, M_WAITOK | M_ZERO);
1487fd7a8150SMike Barcroft 
1488fd7a8150SMike Barcroft 	LIST_FOREACH(pr, &allprison, pr_list) {
1489fd7a8150SMike Barcroft 		xp->pr_version = XPRISON_VERSION;
1490fd7a8150SMike Barcroft 		xp->pr_id = pr->pr_id;
1491413628a7SBjoern A. Zeeb 		xp->pr_state = pr->pr_state;
1492413628a7SBjoern A. Zeeb 		xp->pr_cpusetid = pr->pr_cpuset->cs_id;
1493b63b0c65SPawel Jakub Dawidek 		strlcpy(xp->pr_path, pr->pr_path, sizeof(xp->pr_path));
1494b63b0c65SPawel Jakub Dawidek 		mtx_lock(&pr->pr_mtx);
1495b63b0c65SPawel Jakub Dawidek 		strlcpy(xp->pr_host, pr->pr_host, sizeof(xp->pr_host));
1496413628a7SBjoern A. Zeeb 		strlcpy(xp->pr_name, pr->pr_name, sizeof(xp->pr_name));
1497fd7a8150SMike Barcroft 		mtx_unlock(&pr->pr_mtx);
1498413628a7SBjoern A. Zeeb #ifdef INET
1499413628a7SBjoern A. Zeeb 		xp->pr_ip4s = pr->pr_ip4s;
1500413628a7SBjoern A. Zeeb #endif
1501413628a7SBjoern A. Zeeb #ifdef INET6
1502413628a7SBjoern A. Zeeb 		xp->pr_ip6s = pr->pr_ip6s;
1503413628a7SBjoern A. Zeeb #endif
1504413628a7SBjoern A. Zeeb 		p = (char *)(xp + 1);
1505413628a7SBjoern A. Zeeb #ifdef INET
1506413628a7SBjoern A. Zeeb 		if (pr->pr_ip4s > 0) {
1507413628a7SBjoern A. Zeeb 			bcopy(pr->pr_ip4, (struct in_addr *)p,
1508413628a7SBjoern A. Zeeb 			    pr->pr_ip4s * sizeof(struct in_addr));
1509413628a7SBjoern A. Zeeb 			p += (pr->pr_ip4s * sizeof(struct in_addr));
1510413628a7SBjoern A. Zeeb 		}
1511413628a7SBjoern A. Zeeb #endif
1512413628a7SBjoern A. Zeeb #ifdef INET6
1513413628a7SBjoern A. Zeeb 		if (pr->pr_ip6s > 0) {
1514413628a7SBjoern A. Zeeb 			bcopy(pr->pr_ip6, (struct in6_addr *)p,
1515413628a7SBjoern A. Zeeb 			    pr->pr_ip6s * sizeof(struct in6_addr));
1516413628a7SBjoern A. Zeeb 			p += (pr->pr_ip6s * sizeof(struct in6_addr));
1517413628a7SBjoern A. Zeeb 		}
1518413628a7SBjoern A. Zeeb #endif
1519413628a7SBjoern A. Zeeb 		xp = (struct xprison *)p;
1520fd7a8150SMike Barcroft 	}
1521dc68a633SPawel Jakub Dawidek 	sx_sunlock(&allprison_lock);
1522fd7a8150SMike Barcroft 
1523413628a7SBjoern A. Zeeb 	error = SYSCTL_OUT(req, sxp, len);
1524fd7a8150SMike Barcroft 	free(sxp, M_TEMP);
1525fd7a8150SMike Barcroft 	return (error);
1526fd7a8150SMike Barcroft }
1527fd7a8150SMike Barcroft 
1528fd7a8150SMike Barcroft SYSCTL_OID(_security_jail, OID_AUTO, list, CTLTYPE_STRUCT | CTLFLAG_RD,
1529fd7a8150SMike Barcroft     NULL, 0, sysctl_jail_list, "S", "List of active jails");
1530461167c2SPawel Jakub Dawidek 
1531461167c2SPawel Jakub Dawidek static int
1532461167c2SPawel Jakub Dawidek sysctl_jail_jailed(SYSCTL_HANDLER_ARGS)
1533461167c2SPawel Jakub Dawidek {
1534461167c2SPawel Jakub Dawidek 	int error, injail;
1535461167c2SPawel Jakub Dawidek 
1536461167c2SPawel Jakub Dawidek 	injail = jailed(req->td->td_ucred);
1537461167c2SPawel Jakub Dawidek 	error = SYSCTL_OUT(req, &injail, sizeof(injail));
1538461167c2SPawel Jakub Dawidek 
1539461167c2SPawel Jakub Dawidek 	return (error);
1540461167c2SPawel Jakub Dawidek }
1541461167c2SPawel Jakub Dawidek SYSCTL_PROC(_security_jail, OID_AUTO, jailed, CTLTYPE_INT | CTLFLAG_RD,
1542461167c2SPawel Jakub Dawidek     NULL, 0, sysctl_jail_jailed, "I", "Process in jail?");
1543413628a7SBjoern A. Zeeb 
1544413628a7SBjoern A. Zeeb #ifdef DDB
1545413628a7SBjoern A. Zeeb DB_SHOW_COMMAND(jails, db_show_jails)
1546413628a7SBjoern A. Zeeb {
1547413628a7SBjoern A. Zeeb 	struct prison *pr;
1548413628a7SBjoern A. Zeeb #ifdef INET
1549413628a7SBjoern A. Zeeb 	struct in_addr ia;
1550413628a7SBjoern A. Zeeb #endif
1551413628a7SBjoern A. Zeeb #ifdef INET6
1552413628a7SBjoern A. Zeeb 	char ip6buf[INET6_ADDRSTRLEN];
1553413628a7SBjoern A. Zeeb #endif
1554413628a7SBjoern A. Zeeb 	const char *state;
1555413628a7SBjoern A. Zeeb #if defined(INET) || defined(INET6)
1556413628a7SBjoern A. Zeeb 	int i;
1557413628a7SBjoern A. Zeeb #endif
1558413628a7SBjoern A. Zeeb 
1559413628a7SBjoern A. Zeeb 	db_printf(
1560413628a7SBjoern A. Zeeb 	    "   JID  pr_ref  pr_nprocs  pr_ip4s  pr_ip6s\n");
1561413628a7SBjoern A. Zeeb 	db_printf(
1562413628a7SBjoern A. Zeeb 	    "        Hostname                      Path\n");
1563413628a7SBjoern A. Zeeb 	db_printf(
1564413628a7SBjoern A. Zeeb 	    "        Name                          State\n");
1565413628a7SBjoern A. Zeeb 	db_printf(
1566413628a7SBjoern A. Zeeb 	    "        Cpusetid\n");
1567413628a7SBjoern A. Zeeb 	db_printf(
1568413628a7SBjoern A. Zeeb 	    "        IP Address(es)\n");
1569413628a7SBjoern A. Zeeb 	LIST_FOREACH(pr, &allprison, pr_list) {
1570413628a7SBjoern A. Zeeb 		db_printf("%6d  %6d  %9d  %7d  %7d\n",
1571413628a7SBjoern A. Zeeb 		    pr->pr_id, pr->pr_ref, pr->pr_nprocs,
1572413628a7SBjoern A. Zeeb 		    pr->pr_ip4s, pr->pr_ip6s);
1573413628a7SBjoern A. Zeeb 		db_printf("%6s  %-29.29s %.74s\n",
1574413628a7SBjoern A. Zeeb 		    "", pr->pr_host, pr->pr_path);
1575413628a7SBjoern A. Zeeb 		if (pr->pr_state < 0 || pr->pr_state > (int)((sizeof(
1576413628a7SBjoern A. Zeeb 		    prison_states) / sizeof(struct prison_state))))
1577413628a7SBjoern A. Zeeb 			state = "(bogus)";
1578413628a7SBjoern A. Zeeb 		else
1579413628a7SBjoern A. Zeeb 			state = prison_states[pr->pr_state].state_name;
1580413628a7SBjoern A. Zeeb 		db_printf("%6s  %-29.29s %.74s\n",
1581413628a7SBjoern A. Zeeb 		    "", (pr->pr_name != NULL) ? pr->pr_name : "", state);
1582413628a7SBjoern A. Zeeb 		db_printf("%6s  %-6d\n",
1583413628a7SBjoern A. Zeeb 		    "", pr->pr_cpuset->cs_id);
1584413628a7SBjoern A. Zeeb #ifdef INET
1585413628a7SBjoern A. Zeeb 		for (i=0; i < pr->pr_ip4s; i++) {
1586413628a7SBjoern A. Zeeb 			ia.s_addr = pr->pr_ip4[i].s_addr;
1587413628a7SBjoern A. Zeeb 			db_printf("%6s  %s\n", "", inet_ntoa(ia));
1588413628a7SBjoern A. Zeeb 		}
1589413628a7SBjoern A. Zeeb #endif
1590413628a7SBjoern A. Zeeb #ifdef INET6
1591413628a7SBjoern A. Zeeb 		for (i=0; i < pr->pr_ip6s; i++)
1592413628a7SBjoern A. Zeeb 			db_printf("%6s  %s\n",
1593413628a7SBjoern A. Zeeb 			    "", ip6_sprintf(ip6buf, &pr->pr_ip6[i]));
1594413628a7SBjoern A. Zeeb #endif /* INET6 */
1595413628a7SBjoern A. Zeeb 		if (db_pager_quit)
1596413628a7SBjoern A. Zeeb 			break;
1597413628a7SBjoern A. Zeeb 	}
1598413628a7SBjoern A. Zeeb }
1599413628a7SBjoern A. Zeeb #endif /* DDB */
1600