xref: /freebsd/sys/kern/kern_jail.c (revision b9f0b66c7530723c284d97f83494582f9bc47b62)
19454b2d8SWarner Losh /*-
2b9f0b66cSBjoern A. Zeeb  * Copyright (c) 1999 Poul-Henning Kamp. All rights reserved.
3b9f0b66cSBjoern A. Zeeb  *
4b9f0b66cSBjoern A. Zeeb  * Redistribution and use in source and binary forms, with or without
5b9f0b66cSBjoern A. Zeeb  * modification, are permitted provided that the following conditions
6b9f0b66cSBjoern A. Zeeb  * are met:
7b9f0b66cSBjoern A. Zeeb  * 1. Redistributions of source code must retain the above copyright
8b9f0b66cSBjoern A. Zeeb  *    notice, this list of conditions and the following disclaimer.
9b9f0b66cSBjoern A. Zeeb  * 2. Redistributions in binary form must reproduce the above copyright
10b9f0b66cSBjoern A. Zeeb  *    notice, this list of conditions and the following disclaimer in the
11b9f0b66cSBjoern A. Zeeb  *    documentation and/or other materials provided with the distribution.
12b9f0b66cSBjoern A. Zeeb  *
13b9f0b66cSBjoern A. Zeeb  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14b9f0b66cSBjoern A. Zeeb  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15b9f0b66cSBjoern A. Zeeb  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16b9f0b66cSBjoern A. Zeeb  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17b9f0b66cSBjoern A. Zeeb  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18b9f0b66cSBjoern A. Zeeb  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19b9f0b66cSBjoern A. Zeeb  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20b9f0b66cSBjoern A. Zeeb  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21b9f0b66cSBjoern A. Zeeb  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22b9f0b66cSBjoern A. Zeeb  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23b9f0b66cSBjoern A. Zeeb  * SUCH DAMAGE.
2407901f22SPoul-Henning Kamp  */
2575c13541SPoul-Henning Kamp 
26677b542eSDavid E. O'Brien #include <sys/cdefs.h>
27677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$");
28677b542eSDavid E. O'Brien 
2946e3b1cbSPawel Jakub Dawidek #include "opt_mac.h"
3046e3b1cbSPawel Jakub Dawidek 
3175c13541SPoul-Henning Kamp #include <sys/param.h>
3275c13541SPoul-Henning Kamp #include <sys/types.h>
3375c13541SPoul-Henning Kamp #include <sys/kernel.h>
3475c13541SPoul-Henning Kamp #include <sys/systm.h>
3575c13541SPoul-Henning Kamp #include <sys/errno.h>
3675c13541SPoul-Henning Kamp #include <sys/sysproto.h>
3775c13541SPoul-Henning Kamp #include <sys/malloc.h>
38800c9408SRobert Watson #include <sys/priv.h>
3975c13541SPoul-Henning Kamp #include <sys/proc.h>
40b3059e09SRobert Watson #include <sys/taskqueue.h>
4157b4252eSKonstantin Belousov #include <sys/fcntl.h>
4275c13541SPoul-Henning Kamp #include <sys/jail.h>
4301137630SRobert Watson #include <sys/lock.h>
4401137630SRobert Watson #include <sys/mutex.h>
45dc68a633SPawel Jakub Dawidek #include <sys/sx.h>
46fd7a8150SMike Barcroft #include <sys/namei.h>
47820a0de9SPawel Jakub Dawidek #include <sys/mount.h>
48fd7a8150SMike Barcroft #include <sys/queue.h>
4975c13541SPoul-Henning Kamp #include <sys/socket.h>
50fd7a8150SMike Barcroft #include <sys/syscallsubr.h>
5183f1e257SRobert Watson #include <sys/sysctl.h>
52fd7a8150SMike Barcroft #include <sys/vnode.h>
53603724d3SBjoern A. Zeeb #include <sys/vimage.h>
541ba4a712SPawel Jakub Dawidek #include <sys/osd.h>
5575c13541SPoul-Henning Kamp #include <net/if.h>
5675c13541SPoul-Henning Kamp #include <netinet/in.h>
5775c13541SPoul-Henning Kamp 
58aed55708SRobert Watson #include <security/mac/mac_framework.h>
59aed55708SRobert Watson 
6075c13541SPoul-Henning Kamp MALLOC_DEFINE(M_PRISON, "prison", "Prison structures");
6175c13541SPoul-Henning Kamp 
62d0615c64SAndrew R. Reiter SYSCTL_NODE(_security, OID_AUTO, jail, CTLFLAG_RW, 0,
6383f1e257SRobert Watson     "Jail rules");
6483f1e257SRobert Watson 
6583f1e257SRobert Watson int	jail_set_hostname_allowed = 1;
66d0615c64SAndrew R. Reiter SYSCTL_INT(_security_jail, OID_AUTO, set_hostname_allowed, CTLFLAG_RW,
6783f1e257SRobert Watson     &jail_set_hostname_allowed, 0,
6883f1e257SRobert Watson     "Processes in jail can set their hostnames");
6983f1e257SRobert Watson 
707cadc266SRobert Watson int	jail_socket_unixiproute_only = 1;
71d0615c64SAndrew R. Reiter SYSCTL_INT(_security_jail, OID_AUTO, socket_unixiproute_only, CTLFLAG_RW,
727cadc266SRobert Watson     &jail_socket_unixiproute_only, 0,
737cadc266SRobert Watson     "Processes in jail are limited to creating UNIX/IPv4/route sockets only");
747cadc266SRobert Watson 
75cb1f0db9SRobert Watson int	jail_sysvipc_allowed = 0;
76d0615c64SAndrew R. Reiter SYSCTL_INT(_security_jail, OID_AUTO, sysvipc_allowed, CTLFLAG_RW,
77cb1f0db9SRobert Watson     &jail_sysvipc_allowed, 0,
78cb1f0db9SRobert Watson     "Processes in jail can use System V IPC primitives");
79cb1f0db9SRobert Watson 
80820a0de9SPawel Jakub Dawidek static int jail_enforce_statfs = 2;
81820a0de9SPawel Jakub Dawidek SYSCTL_INT(_security_jail, OID_AUTO, enforce_statfs, CTLFLAG_RW,
82820a0de9SPawel Jakub Dawidek     &jail_enforce_statfs, 0,
83820a0de9SPawel Jakub Dawidek     "Processes in jail cannot see all mounted file systems");
84f08df373SRobert Watson 
855a59cefcSBosko Milekic int	jail_allow_raw_sockets = 0;
865a59cefcSBosko Milekic SYSCTL_INT(_security_jail, OID_AUTO, allow_raw_sockets, CTLFLAG_RW,
875a59cefcSBosko Milekic     &jail_allow_raw_sockets, 0,
885a59cefcSBosko Milekic     "Prison root can create raw sockets");
895a59cefcSBosko Milekic 
9079653046SColin Percival int	jail_chflags_allowed = 0;
9179653046SColin Percival SYSCTL_INT(_security_jail, OID_AUTO, chflags_allowed, CTLFLAG_RW,
9279653046SColin Percival     &jail_chflags_allowed, 0,
9379653046SColin Percival     "Processes in jail can alter system file flags");
9479653046SColin Percival 
95f3a8d2f9SPawel Jakub Dawidek int	jail_mount_allowed = 0;
96f3a8d2f9SPawel Jakub Dawidek SYSCTL_INT(_security_jail, OID_AUTO, mount_allowed, CTLFLAG_RW,
97f3a8d2f9SPawel Jakub Dawidek     &jail_mount_allowed, 0,
98f3a8d2f9SPawel Jakub Dawidek     "Processes in jail can mount/unmount jail-friendly file systems");
99f3a8d2f9SPawel Jakub Dawidek 
1002110d913SXin LI /* allprison, lastprid, and prisoncount are protected by allprison_lock. */
1012110d913SXin LI struct	prisonlist allprison;
102dc68a633SPawel Jakub Dawidek struct	sx allprison_lock;
1032110d913SXin LI int	lastprid = 0;
104fd7a8150SMike Barcroft int	prisoncount = 0;
105fd7a8150SMike Barcroft 
106fd7a8150SMike Barcroft static void		 init_prison(void *);
107b3059e09SRobert Watson static void		 prison_complete(void *context, int pending);
108fd7a8150SMike Barcroft static int		 sysctl_jail_list(SYSCTL_HANDLER_ARGS);
109fd7a8150SMike Barcroft 
110fd7a8150SMike Barcroft static void
111fd7a8150SMike Barcroft init_prison(void *data __unused)
112fd7a8150SMike Barcroft {
113fd7a8150SMike Barcroft 
1142110d913SXin LI 	sx_init(&allprison_lock, "allprison");
1152110d913SXin LI 	LIST_INIT(&allprison);
116fd7a8150SMike Barcroft }
117fd7a8150SMike Barcroft 
118fd7a8150SMike Barcroft SYSINIT(prison, SI_SUB_INTRINSIC, SI_ORDER_ANY, init_prison, NULL);
119fd7a8150SMike Barcroft 
120116734c4SMatthew Dillon /*
1219ddb7954SMike Barcroft  * struct jail_args {
1229ddb7954SMike Barcroft  *	struct jail *jail;
1239ddb7954SMike Barcroft  * };
124116734c4SMatthew Dillon  */
12575c13541SPoul-Henning Kamp int
1269ddb7954SMike Barcroft jail(struct thread *td, struct jail_args *uap)
12775c13541SPoul-Henning Kamp {
128fd7a8150SMike Barcroft 	struct nameidata nd;
1292110d913SXin LI 	struct prison *pr, *tpr;
13075c13541SPoul-Henning Kamp 	struct jail j;
131fd7a8150SMike Barcroft 	struct jail_attach_args jaa;
1322110d913SXin LI 	int vfslocked, error, tryprid;
13375c13541SPoul-Henning Kamp 
1349ddb7954SMike Barcroft 	error = copyin(uap->jail, &j, sizeof(j));
13575c13541SPoul-Henning Kamp 	if (error)
136a2f2b3afSJohn Baldwin 		return (error);
137a2f2b3afSJohn Baldwin 	if (j.version != 0)
138a2f2b3afSJohn Baldwin 		return (EINVAL);
139a2f2b3afSJohn Baldwin 
1401ede983cSDag-Erling Smørgrav 	pr = malloc(sizeof(*pr), M_PRISON, M_WAITOK | M_ZERO);
1416008862bSJohn Baldwin 	mtx_init(&pr->pr_mtx, "jail mutex", NULL, MTX_DEF);
142fd7a8150SMike Barcroft 	pr->pr_ref = 1;
1439ddb7954SMike Barcroft 	error = copyinstr(j.path, &pr->pr_path, sizeof(pr->pr_path), 0);
144fd7a8150SMike Barcroft 	if (error)
145fd7a8150SMike Barcroft 		goto e_killmtx;
146453f7d53SChristian S.J. Peron 	NDINIT(&nd, LOOKUP, MPSAFE | FOLLOW | LOCKLEAF, UIO_SYSSPACE,
147453f7d53SChristian S.J. Peron 	    pr->pr_path, td);
148fd7a8150SMike Barcroft 	error = namei(&nd);
149453f7d53SChristian S.J. Peron 	if (error)
150fd7a8150SMike Barcroft 		goto e_killmtx;
151453f7d53SChristian S.J. Peron 	vfslocked = NDHASGIANT(&nd);
152fd7a8150SMike Barcroft 	pr->pr_root = nd.ni_vp;
15322db15c0SAttilio Rao 	VOP_UNLOCK(nd.ni_vp, 0);
154fd7a8150SMike Barcroft 	NDFREE(&nd, NDF_ONLY_PNBUF);
155453f7d53SChristian S.J. Peron 	VFS_UNLOCK_GIANT(vfslocked);
1569ddb7954SMike Barcroft 	error = copyinstr(j.hostname, &pr->pr_host, sizeof(pr->pr_host), 0);
15775c13541SPoul-Henning Kamp 	if (error)
158fd7a8150SMike Barcroft 		goto e_dropvnref;
159a2f2b3afSJohn Baldwin 	pr->pr_ip = j.ip_number;
160fd7a8150SMike Barcroft 	pr->pr_linux = NULL;
161fd7a8150SMike Barcroft 	pr->pr_securelevel = securelevel;
1621ba4a712SPawel Jakub Dawidek 	bzero(&pr->pr_osd, sizeof(pr->pr_osd));
163fd7a8150SMike Barcroft 
1642110d913SXin LI 	/* Determine next pr_id and add prison to allprison list. */
165dc68a633SPawel Jakub Dawidek 	sx_xlock(&allprison_lock);
1662110d913SXin LI 	tryprid = lastprid + 1;
1672110d913SXin LI 	if (tryprid == JAIL_MAX)
1682110d913SXin LI 		tryprid = 1;
1692110d913SXin LI next:
1702110d913SXin LI 	LIST_FOREACH(tpr, &allprison, pr_list) {
1712110d913SXin LI 		if (tpr->pr_id == tryprid) {
1722110d913SXin LI 			tryprid++;
1732110d913SXin LI 			if (tryprid == JAIL_MAX) {
1742110d913SXin LI 				sx_xunlock(&allprison_lock);
1752110d913SXin LI 				error = EAGAIN;
1762110d913SXin LI 				goto e_dropvnref;
1772110d913SXin LI 			}
1782110d913SXin LI 			goto next;
1792110d913SXin LI 		}
1802110d913SXin LI 	}
1812110d913SXin LI 	pr->pr_id = jaa.jid = lastprid = tryprid;
182fd7a8150SMike Barcroft 	LIST_INSERT_HEAD(&allprison, pr, pr_list);
183fd7a8150SMike Barcroft 	prisoncount++;
1841ba4a712SPawel Jakub Dawidek 	sx_xunlock(&allprison_lock);
185fd7a8150SMike Barcroft 
186fd7a8150SMike Barcroft 	error = jail_attach(td, &jaa);
187a2f2b3afSJohn Baldwin 	if (error)
188fd7a8150SMike Barcroft 		goto e_dropprref;
189fd7a8150SMike Barcroft 	mtx_lock(&pr->pr_mtx);
190fd7a8150SMike Barcroft 	pr->pr_ref--;
191fd7a8150SMike Barcroft 	mtx_unlock(&pr->pr_mtx);
192fd7a8150SMike Barcroft 	td->td_retval[0] = jaa.jid;
19375c13541SPoul-Henning Kamp 	return (0);
194fd7a8150SMike Barcroft e_dropprref:
195dc68a633SPawel Jakub Dawidek 	sx_xlock(&allprison_lock);
196fd7a8150SMike Barcroft 	LIST_REMOVE(pr, pr_list);
197fd7a8150SMike Barcroft 	prisoncount--;
1981ba4a712SPawel Jakub Dawidek 	sx_xunlock(&allprison_lock);
199fd7a8150SMike Barcroft e_dropvnref:
200453f7d53SChristian S.J. Peron 	vfslocked = VFS_LOCK_GIANT(pr->pr_root->v_mount);
201fd7a8150SMike Barcroft 	vrele(pr->pr_root);
202453f7d53SChristian S.J. Peron 	VFS_UNLOCK_GIANT(vfslocked);
203fd7a8150SMike Barcroft e_killmtx:
204894db7b0SMaxime Henrion 	mtx_destroy(&pr->pr_mtx);
2051ede983cSDag-Erling Smørgrav 	free(pr, M_PRISON);
20675c13541SPoul-Henning Kamp 	return (error);
20775c13541SPoul-Henning Kamp }
20875c13541SPoul-Henning Kamp 
209fd7a8150SMike Barcroft /*
2109ddb7954SMike Barcroft  * struct jail_attach_args {
2119ddb7954SMike Barcroft  *	int jid;
2129ddb7954SMike Barcroft  * };
213fd7a8150SMike Barcroft  */
214fd7a8150SMike Barcroft int
2159ddb7954SMike Barcroft jail_attach(struct thread *td, struct jail_attach_args *uap)
216fd7a8150SMike Barcroft {
217fd7a8150SMike Barcroft 	struct proc *p;
218fd7a8150SMike Barcroft 	struct ucred *newcred, *oldcred;
219fd7a8150SMike Barcroft 	struct prison *pr;
220453f7d53SChristian S.J. Peron 	int vfslocked, error;
221fd7a8150SMike Barcroft 
22257f22bd4SJacques Vidrine 	/*
22357f22bd4SJacques Vidrine 	 * XXX: Note that there is a slight race here if two threads
22457f22bd4SJacques Vidrine 	 * in the same privileged process attempt to attach to two
22557f22bd4SJacques Vidrine 	 * different jails at the same time.  It is important for
22657f22bd4SJacques Vidrine 	 * user processes not to do this, or they might end up with
22757f22bd4SJacques Vidrine 	 * a process root from one prison, but attached to the jail
22857f22bd4SJacques Vidrine 	 * of another.
22957f22bd4SJacques Vidrine 	 */
230800c9408SRobert Watson 	error = priv_check(td, PRIV_JAIL_ATTACH);
23157f22bd4SJacques Vidrine 	if (error)
23257f22bd4SJacques Vidrine 		return (error);
233fd7a8150SMike Barcroft 
23457f22bd4SJacques Vidrine 	p = td->td_proc;
235dc68a633SPawel Jakub Dawidek 	sx_slock(&allprison_lock);
236fd7a8150SMike Barcroft 	pr = prison_find(uap->jid);
237fd7a8150SMike Barcroft 	if (pr == NULL) {
238dc68a633SPawel Jakub Dawidek 		sx_sunlock(&allprison_lock);
239fd7a8150SMike Barcroft 		return (EINVAL);
240fd7a8150SMike Barcroft 	}
241fd7a8150SMike Barcroft 	pr->pr_ref++;
242fd7a8150SMike Barcroft 	mtx_unlock(&pr->pr_mtx);
243dc68a633SPawel Jakub Dawidek 	sx_sunlock(&allprison_lock);
244fd7a8150SMike Barcroft 
245453f7d53SChristian S.J. Peron 	vfslocked = VFS_LOCK_GIANT(pr->pr_root->v_mount);
246cb05b60aSAttilio Rao 	vn_lock(pr->pr_root, LK_EXCLUSIVE | LK_RETRY);
247fd7a8150SMike Barcroft 	if ((error = change_dir(pr->pr_root, td)) != 0)
248fd7a8150SMike Barcroft 		goto e_unlock;
249fd7a8150SMike Barcroft #ifdef MAC
25030d239bcSRobert Watson 	if ((error = mac_vnode_check_chroot(td->td_ucred, pr->pr_root)))
251fd7a8150SMike Barcroft 		goto e_unlock;
252fd7a8150SMike Barcroft #endif
25322db15c0SAttilio Rao 	VOP_UNLOCK(pr->pr_root, 0);
254fd7a8150SMike Barcroft 	change_root(pr->pr_root, td);
255453f7d53SChristian S.J. Peron 	VFS_UNLOCK_GIANT(vfslocked);
256fd7a8150SMike Barcroft 
257fd7a8150SMike Barcroft 	newcred = crget();
258fd7a8150SMike Barcroft 	PROC_LOCK(p);
259fd7a8150SMike Barcroft 	oldcred = p->p_ucred;
260fd7a8150SMike Barcroft 	setsugid(p);
261fd7a8150SMike Barcroft 	crcopy(newcred, oldcred);
26269c4ee54SJohn Baldwin 	newcred->cr_prison = pr;
263fd7a8150SMike Barcroft 	p->p_ucred = newcred;
264fd7a8150SMike Barcroft 	PROC_UNLOCK(p);
265fd7a8150SMike Barcroft 	crfree(oldcred);
266fd7a8150SMike Barcroft 	return (0);
267fd7a8150SMike Barcroft e_unlock:
26822db15c0SAttilio Rao 	VOP_UNLOCK(pr->pr_root, 0);
269453f7d53SChristian S.J. Peron 	VFS_UNLOCK_GIANT(vfslocked);
270fd7a8150SMike Barcroft 	mtx_lock(&pr->pr_mtx);
271fd7a8150SMike Barcroft 	pr->pr_ref--;
272fd7a8150SMike Barcroft 	mtx_unlock(&pr->pr_mtx);
273fd7a8150SMike Barcroft 	return (error);
274fd7a8150SMike Barcroft }
275fd7a8150SMike Barcroft 
276fd7a8150SMike Barcroft /*
277fd7a8150SMike Barcroft  * Returns a locked prison instance, or NULL on failure.
278fd7a8150SMike Barcroft  */
27954b369c1SPawel Jakub Dawidek struct prison *
280fd7a8150SMike Barcroft prison_find(int prid)
281fd7a8150SMike Barcroft {
282fd7a8150SMike Barcroft 	struct prison *pr;
283fd7a8150SMike Barcroft 
284dc68a633SPawel Jakub Dawidek 	sx_assert(&allprison_lock, SX_LOCKED);
285fd7a8150SMike Barcroft 	LIST_FOREACH(pr, &allprison, pr_list) {
286fd7a8150SMike Barcroft 		if (pr->pr_id == prid) {
287fd7a8150SMike Barcroft 			mtx_lock(&pr->pr_mtx);
288c2cda609SPawel Jakub Dawidek 			if (pr->pr_ref == 0) {
289c2cda609SPawel Jakub Dawidek 				mtx_unlock(&pr->pr_mtx);
290c2cda609SPawel Jakub Dawidek 				break;
291c2cda609SPawel Jakub Dawidek 			}
292fd7a8150SMike Barcroft 			return (pr);
293fd7a8150SMike Barcroft 		}
294fd7a8150SMike Barcroft 	}
295fd7a8150SMike Barcroft 	return (NULL);
296fd7a8150SMike Barcroft }
297fd7a8150SMike Barcroft 
29891421ba2SRobert Watson void
2991ba4a712SPawel Jakub Dawidek prison_free_locked(struct prison *pr)
30091421ba2SRobert Watson {
30191421ba2SRobert Watson 
3021ba4a712SPawel Jakub Dawidek 	mtx_assert(&pr->pr_mtx, MA_OWNED);
30391421ba2SRobert Watson 	pr->pr_ref--;
30491421ba2SRobert Watson 	if (pr->pr_ref == 0) {
30501137630SRobert Watson 		mtx_unlock(&pr->pr_mtx);
306c2cda609SPawel Jakub Dawidek 		TASK_INIT(&pr->pr_task, 0, prison_complete, pr);
307c2cda609SPawel Jakub Dawidek 		taskqueue_enqueue(taskqueue_thread, &pr->pr_task);
308c2cda609SPawel Jakub Dawidek 		return;
309c2cda609SPawel Jakub Dawidek 	}
310c2cda609SPawel Jakub Dawidek 	mtx_unlock(&pr->pr_mtx);
311c2cda609SPawel Jakub Dawidek }
312c2cda609SPawel Jakub Dawidek 
3131ba4a712SPawel Jakub Dawidek void
3141ba4a712SPawel Jakub Dawidek prison_free(struct prison *pr)
3151ba4a712SPawel Jakub Dawidek {
3161ba4a712SPawel Jakub Dawidek 
3171ba4a712SPawel Jakub Dawidek 	mtx_lock(&pr->pr_mtx);
3181ba4a712SPawel Jakub Dawidek 	prison_free_locked(pr);
3191ba4a712SPawel Jakub Dawidek }
3201ba4a712SPawel Jakub Dawidek 
321c2cda609SPawel Jakub Dawidek static void
322c2cda609SPawel Jakub Dawidek prison_complete(void *context, int pending)
323c2cda609SPawel Jakub Dawidek {
324c2cda609SPawel Jakub Dawidek 	struct prison *pr;
325c2cda609SPawel Jakub Dawidek 	int vfslocked;
326c2cda609SPawel Jakub Dawidek 
327c2cda609SPawel Jakub Dawidek 	pr = (struct prison *)context;
328c2cda609SPawel Jakub Dawidek 
329c2cda609SPawel Jakub Dawidek 	sx_xlock(&allprison_lock);
330264de85eSPawel Jakub Dawidek 	LIST_REMOVE(pr, pr_list);
331fd7a8150SMike Barcroft 	prisoncount--;
3321ba4a712SPawel Jakub Dawidek 	sx_xunlock(&allprison_lock);
3331ba4a712SPawel Jakub Dawidek 
3341ba4a712SPawel Jakub Dawidek 	/* Free all OSD associated to this jail. */
3351ba4a712SPawel Jakub Dawidek 	osd_jail_exit(pr);
336b3059e09SRobert Watson 
337453f7d53SChristian S.J. Peron 	vfslocked = VFS_LOCK_GIANT(pr->pr_root->v_mount);
338b3059e09SRobert Watson 	vrele(pr->pr_root);
339453f7d53SChristian S.J. Peron 	VFS_UNLOCK_GIANT(vfslocked);
340b3059e09SRobert Watson 
341b3059e09SRobert Watson 	mtx_destroy(&pr->pr_mtx);
342b3059e09SRobert Watson 	if (pr->pr_linux != NULL)
3431ede983cSDag-Erling Smørgrav 		free(pr->pr_linux, M_PRISON);
3441ede983cSDag-Erling Smørgrav 	free(pr, M_PRISON);
345b3059e09SRobert Watson }
346b3059e09SRobert Watson 
34791421ba2SRobert Watson void
3481ba4a712SPawel Jakub Dawidek prison_hold_locked(struct prison *pr)
3491ba4a712SPawel Jakub Dawidek {
3501ba4a712SPawel Jakub Dawidek 
3511ba4a712SPawel Jakub Dawidek 	mtx_assert(&pr->pr_mtx, MA_OWNED);
3521ba4a712SPawel Jakub Dawidek 	KASSERT(pr->pr_ref > 0,
3531ba4a712SPawel Jakub Dawidek 	    ("Trying to hold dead prison (id=%d).", pr->pr_id));
3541ba4a712SPawel Jakub Dawidek 	pr->pr_ref++;
3551ba4a712SPawel Jakub Dawidek }
3561ba4a712SPawel Jakub Dawidek 
3571ba4a712SPawel Jakub Dawidek void
35891421ba2SRobert Watson prison_hold(struct prison *pr)
35991421ba2SRobert Watson {
36091421ba2SRobert Watson 
36101137630SRobert Watson 	mtx_lock(&pr->pr_mtx);
3621ba4a712SPawel Jakub Dawidek 	prison_hold_locked(pr);
36301137630SRobert Watson 	mtx_unlock(&pr->pr_mtx);
36401137630SRobert Watson }
36501137630SRobert Watson 
36601137630SRobert Watson u_int32_t
36701137630SRobert Watson prison_getip(struct ucred *cred)
36801137630SRobert Watson {
36901137630SRobert Watson 
37001137630SRobert Watson 	return (cred->cr_prison->pr_ip);
37191421ba2SRobert Watson }
37291421ba2SRobert Watson 
37375c13541SPoul-Henning Kamp int
37491421ba2SRobert Watson prison_ip(struct ucred *cred, int flag, u_int32_t *ip)
37575c13541SPoul-Henning Kamp {
37675c13541SPoul-Henning Kamp 	u_int32_t tmp;
37775c13541SPoul-Henning Kamp 
37891421ba2SRobert Watson 	if (!jailed(cred))
37975c13541SPoul-Henning Kamp 		return (0);
38075c13541SPoul-Henning Kamp 	if (flag)
38175c13541SPoul-Henning Kamp 		tmp = *ip;
38275c13541SPoul-Henning Kamp 	else
38375c13541SPoul-Henning Kamp 		tmp = ntohl(*ip);
38475c13541SPoul-Henning Kamp 	if (tmp == INADDR_ANY) {
38575c13541SPoul-Henning Kamp 		if (flag)
38691421ba2SRobert Watson 			*ip = cred->cr_prison->pr_ip;
38775c13541SPoul-Henning Kamp 		else
38891421ba2SRobert Watson 			*ip = htonl(cred->cr_prison->pr_ip);
38975c13541SPoul-Henning Kamp 		return (0);
39075c13541SPoul-Henning Kamp 	}
391fd6aaf7fSRobert Watson 	if (tmp == INADDR_LOOPBACK) {
392fd6aaf7fSRobert Watson 		if (flag)
393fd6aaf7fSRobert Watson 			*ip = cred->cr_prison->pr_ip;
394fd6aaf7fSRobert Watson 		else
395fd6aaf7fSRobert Watson 			*ip = htonl(cred->cr_prison->pr_ip);
396fd6aaf7fSRobert Watson 		return (0);
397fd6aaf7fSRobert Watson 	}
39891421ba2SRobert Watson 	if (cred->cr_prison->pr_ip != tmp)
39975c13541SPoul-Henning Kamp 		return (1);
40075c13541SPoul-Henning Kamp 	return (0);
40175c13541SPoul-Henning Kamp }
40275c13541SPoul-Henning Kamp 
40375c13541SPoul-Henning Kamp void
40491421ba2SRobert Watson prison_remote_ip(struct ucred *cred, int flag, u_int32_t *ip)
40575c13541SPoul-Henning Kamp {
40675c13541SPoul-Henning Kamp 	u_int32_t tmp;
40775c13541SPoul-Henning Kamp 
40891421ba2SRobert Watson 	if (!jailed(cred))
40975c13541SPoul-Henning Kamp 		return;
41075c13541SPoul-Henning Kamp 	if (flag)
41175c13541SPoul-Henning Kamp 		tmp = *ip;
41275c13541SPoul-Henning Kamp 	else
41375c13541SPoul-Henning Kamp 		tmp = ntohl(*ip);
414fd6aaf7fSRobert Watson 	if (tmp == INADDR_LOOPBACK) {
41575c13541SPoul-Henning Kamp 		if (flag)
41691421ba2SRobert Watson 			*ip = cred->cr_prison->pr_ip;
41775c13541SPoul-Henning Kamp 		else
41891421ba2SRobert Watson 			*ip = htonl(cred->cr_prison->pr_ip);
41975c13541SPoul-Henning Kamp 		return;
42075c13541SPoul-Henning Kamp 	}
42175c13541SPoul-Henning Kamp 	return;
42275c13541SPoul-Henning Kamp }
42375c13541SPoul-Henning Kamp 
42475c13541SPoul-Henning Kamp int
42591421ba2SRobert Watson prison_if(struct ucred *cred, struct sockaddr *sa)
42675c13541SPoul-Henning Kamp {
4279ddb7954SMike Barcroft 	struct sockaddr_in *sai;
42875c13541SPoul-Henning Kamp 	int ok;
42975c13541SPoul-Henning Kamp 
4309ddb7954SMike Barcroft 	sai = (struct sockaddr_in *)sa;
4317cadc266SRobert Watson 	if ((sai->sin_family != AF_INET) && jail_socket_unixiproute_only)
4327cadc266SRobert Watson 		ok = 1;
4337cadc266SRobert Watson 	else if (sai->sin_family != AF_INET)
43475c13541SPoul-Henning Kamp 		ok = 0;
43591421ba2SRobert Watson 	else if (cred->cr_prison->pr_ip != ntohl(sai->sin_addr.s_addr))
43675c13541SPoul-Henning Kamp 		ok = 1;
43775c13541SPoul-Henning Kamp 	else
43875c13541SPoul-Henning Kamp 		ok = 0;
43975c13541SPoul-Henning Kamp 	return (ok);
44075c13541SPoul-Henning Kamp }
44191421ba2SRobert Watson 
44291421ba2SRobert Watson /*
44391421ba2SRobert Watson  * Return 0 if jails permit p1 to frob p2, otherwise ESRCH.
44491421ba2SRobert Watson  */
44591421ba2SRobert Watson int
4469ddb7954SMike Barcroft prison_check(struct ucred *cred1, struct ucred *cred2)
44791421ba2SRobert Watson {
44891421ba2SRobert Watson 
44991421ba2SRobert Watson 	if (jailed(cred1)) {
45091421ba2SRobert Watson 		if (!jailed(cred2))
45191421ba2SRobert Watson 			return (ESRCH);
45291421ba2SRobert Watson 		if (cred2->cr_prison != cred1->cr_prison)
45391421ba2SRobert Watson 			return (ESRCH);
45491421ba2SRobert Watson 	}
45591421ba2SRobert Watson 
45691421ba2SRobert Watson 	return (0);
45791421ba2SRobert Watson }
45891421ba2SRobert Watson 
45991421ba2SRobert Watson /*
46091421ba2SRobert Watson  * Return 1 if the passed credential is in a jail, otherwise 0.
46191421ba2SRobert Watson  */
46291421ba2SRobert Watson int
4639ddb7954SMike Barcroft jailed(struct ucred *cred)
46491421ba2SRobert Watson {
46591421ba2SRobert Watson 
46691421ba2SRobert Watson 	return (cred->cr_prison != NULL);
46791421ba2SRobert Watson }
4689484d0c0SRobert Drehmel 
4699484d0c0SRobert Drehmel /*
4709484d0c0SRobert Drehmel  * Return the correct hostname for the passed credential.
4719484d0c0SRobert Drehmel  */
472ad1ff099SRobert Drehmel void
4739ddb7954SMike Barcroft getcredhostname(struct ucred *cred, char *buf, size_t size)
4749484d0c0SRobert Drehmel {
4758b615593SMarko Zec 	INIT_VPROCG(cred->cr_vimage->v_procg);
4769484d0c0SRobert Drehmel 
477ad1ff099SRobert Drehmel 	if (jailed(cred)) {
478ad1ff099SRobert Drehmel 		mtx_lock(&cred->cr_prison->pr_mtx);
479e80fb434SRobert Drehmel 		strlcpy(buf, cred->cr_prison->pr_host, size);
480ad1ff099SRobert Drehmel 		mtx_unlock(&cred->cr_prison->pr_mtx);
4814f7d1876SRobert Watson 	} else {
4824f7d1876SRobert Watson 		mtx_lock(&hostname_mtx);
483603724d3SBjoern A. Zeeb 		strlcpy(buf, V_hostname, size);
4844f7d1876SRobert Watson 		mtx_unlock(&hostname_mtx);
4854f7d1876SRobert Watson 	}
4869484d0c0SRobert Drehmel }
487fd7a8150SMike Barcroft 
488f08df373SRobert Watson /*
489820a0de9SPawel Jakub Dawidek  * Determine whether the subject represented by cred can "see"
490820a0de9SPawel Jakub Dawidek  * status of a mount point.
491820a0de9SPawel Jakub Dawidek  * Returns: 0 for permitted, ENOENT otherwise.
492820a0de9SPawel Jakub Dawidek  * XXX: This function should be called cr_canseemount() and should be
493820a0de9SPawel Jakub Dawidek  *      placed in kern_prot.c.
494f08df373SRobert Watson  */
495f08df373SRobert Watson int
496820a0de9SPawel Jakub Dawidek prison_canseemount(struct ucred *cred, struct mount *mp)
497f08df373SRobert Watson {
498820a0de9SPawel Jakub Dawidek 	struct prison *pr;
499820a0de9SPawel Jakub Dawidek 	struct statfs *sp;
500820a0de9SPawel Jakub Dawidek 	size_t len;
501f08df373SRobert Watson 
502820a0de9SPawel Jakub Dawidek 	if (!jailed(cred) || jail_enforce_statfs == 0)
503820a0de9SPawel Jakub Dawidek 		return (0);
504820a0de9SPawel Jakub Dawidek 	pr = cred->cr_prison;
505820a0de9SPawel Jakub Dawidek 	if (pr->pr_root->v_mount == mp)
506820a0de9SPawel Jakub Dawidek 		return (0);
507820a0de9SPawel Jakub Dawidek 	if (jail_enforce_statfs == 2)
508820a0de9SPawel Jakub Dawidek 		return (ENOENT);
509820a0de9SPawel Jakub Dawidek 	/*
510820a0de9SPawel Jakub Dawidek 	 * If jail's chroot directory is set to "/" we should be able to see
511820a0de9SPawel Jakub Dawidek 	 * all mount-points from inside a jail.
512820a0de9SPawel Jakub Dawidek 	 * This is ugly check, but this is the only situation when jail's
513820a0de9SPawel Jakub Dawidek 	 * directory ends with '/'.
514820a0de9SPawel Jakub Dawidek 	 */
515820a0de9SPawel Jakub Dawidek 	if (strcmp(pr->pr_path, "/") == 0)
516820a0de9SPawel Jakub Dawidek 		return (0);
517820a0de9SPawel Jakub Dawidek 	len = strlen(pr->pr_path);
518820a0de9SPawel Jakub Dawidek 	sp = &mp->mnt_stat;
519820a0de9SPawel Jakub Dawidek 	if (strncmp(pr->pr_path, sp->f_mntonname, len) != 0)
520820a0de9SPawel Jakub Dawidek 		return (ENOENT);
521820a0de9SPawel Jakub Dawidek 	/*
522820a0de9SPawel Jakub Dawidek 	 * Be sure that we don't have situation where jail's root directory
523820a0de9SPawel Jakub Dawidek 	 * is "/some/path" and mount point is "/some/pathpath".
524820a0de9SPawel Jakub Dawidek 	 */
525820a0de9SPawel Jakub Dawidek 	if (sp->f_mntonname[len] != '\0' && sp->f_mntonname[len] != '/')
526820a0de9SPawel Jakub Dawidek 		return (ENOENT);
527f08df373SRobert Watson 	return (0);
528f08df373SRobert Watson }
529820a0de9SPawel Jakub Dawidek 
530820a0de9SPawel Jakub Dawidek void
531820a0de9SPawel Jakub Dawidek prison_enforce_statfs(struct ucred *cred, struct mount *mp, struct statfs *sp)
532820a0de9SPawel Jakub Dawidek {
533820a0de9SPawel Jakub Dawidek 	char jpath[MAXPATHLEN];
534820a0de9SPawel Jakub Dawidek 	struct prison *pr;
535820a0de9SPawel Jakub Dawidek 	size_t len;
536820a0de9SPawel Jakub Dawidek 
537820a0de9SPawel Jakub Dawidek 	if (!jailed(cred) || jail_enforce_statfs == 0)
538820a0de9SPawel Jakub Dawidek 		return;
539820a0de9SPawel Jakub Dawidek 	pr = cred->cr_prison;
540820a0de9SPawel Jakub Dawidek 	if (prison_canseemount(cred, mp) != 0) {
541820a0de9SPawel Jakub Dawidek 		bzero(sp->f_mntonname, sizeof(sp->f_mntonname));
542820a0de9SPawel Jakub Dawidek 		strlcpy(sp->f_mntonname, "[restricted]",
543820a0de9SPawel Jakub Dawidek 		    sizeof(sp->f_mntonname));
544820a0de9SPawel Jakub Dawidek 		return;
545820a0de9SPawel Jakub Dawidek 	}
546820a0de9SPawel Jakub Dawidek 	if (pr->pr_root->v_mount == mp) {
547820a0de9SPawel Jakub Dawidek 		/*
548820a0de9SPawel Jakub Dawidek 		 * Clear current buffer data, so we are sure nothing from
549820a0de9SPawel Jakub Dawidek 		 * the valid path left there.
550820a0de9SPawel Jakub Dawidek 		 */
551820a0de9SPawel Jakub Dawidek 		bzero(sp->f_mntonname, sizeof(sp->f_mntonname));
552820a0de9SPawel Jakub Dawidek 		*sp->f_mntonname = '/';
553820a0de9SPawel Jakub Dawidek 		return;
554820a0de9SPawel Jakub Dawidek 	}
555820a0de9SPawel Jakub Dawidek 	/*
556820a0de9SPawel Jakub Dawidek 	 * If jail's chroot directory is set to "/" we should be able to see
557820a0de9SPawel Jakub Dawidek 	 * all mount-points from inside a jail.
558820a0de9SPawel Jakub Dawidek 	 */
559820a0de9SPawel Jakub Dawidek 	if (strcmp(pr->pr_path, "/") == 0)
560820a0de9SPawel Jakub Dawidek 		return;
561820a0de9SPawel Jakub Dawidek 	len = strlen(pr->pr_path);
562820a0de9SPawel Jakub Dawidek 	strlcpy(jpath, sp->f_mntonname + len, sizeof(jpath));
563820a0de9SPawel Jakub Dawidek 	/*
564820a0de9SPawel Jakub Dawidek 	 * Clear current buffer data, so we are sure nothing from
565820a0de9SPawel Jakub Dawidek 	 * the valid path left there.
566820a0de9SPawel Jakub Dawidek 	 */
567820a0de9SPawel Jakub Dawidek 	bzero(sp->f_mntonname, sizeof(sp->f_mntonname));
568820a0de9SPawel Jakub Dawidek 	if (*jpath == '\0') {
569820a0de9SPawel Jakub Dawidek 		/* Should never happen. */
570820a0de9SPawel Jakub Dawidek 		*sp->f_mntonname = '/';
571820a0de9SPawel Jakub Dawidek 	} else {
572820a0de9SPawel Jakub Dawidek 		strlcpy(sp->f_mntonname, jpath, sizeof(sp->f_mntonname));
573820a0de9SPawel Jakub Dawidek 	}
574f08df373SRobert Watson }
575f08df373SRobert Watson 
576800c9408SRobert Watson /*
577800c9408SRobert Watson  * Check with permission for a specific privilege is granted within jail.  We
578800c9408SRobert Watson  * have a specific list of accepted privileges; the rest are denied.
579800c9408SRobert Watson  */
580800c9408SRobert Watson int
581800c9408SRobert Watson prison_priv_check(struct ucred *cred, int priv)
582800c9408SRobert Watson {
583800c9408SRobert Watson 
584800c9408SRobert Watson 	if (!jailed(cred))
585800c9408SRobert Watson 		return (0);
586800c9408SRobert Watson 
587800c9408SRobert Watson 	switch (priv) {
588800c9408SRobert Watson 
589800c9408SRobert Watson 		/*
590800c9408SRobert Watson 		 * Allow ktrace privileges for root in jail.
591800c9408SRobert Watson 		 */
592800c9408SRobert Watson 	case PRIV_KTRACE:
593800c9408SRobert Watson 
594c3c1b5e6SRobert Watson #if 0
595800c9408SRobert Watson 		/*
596800c9408SRobert Watson 		 * Allow jailed processes to configure audit identity and
597800c9408SRobert Watson 		 * submit audit records (login, etc).  In the future we may
598800c9408SRobert Watson 		 * want to further refine the relationship between audit and
599800c9408SRobert Watson 		 * jail.
600800c9408SRobert Watson 		 */
601800c9408SRobert Watson 	case PRIV_AUDIT_GETAUDIT:
602800c9408SRobert Watson 	case PRIV_AUDIT_SETAUDIT:
603800c9408SRobert Watson 	case PRIV_AUDIT_SUBMIT:
604c3c1b5e6SRobert Watson #endif
605800c9408SRobert Watson 
606800c9408SRobert Watson 		/*
607800c9408SRobert Watson 		 * Allow jailed processes to manipulate process UNIX
608800c9408SRobert Watson 		 * credentials in any way they see fit.
609800c9408SRobert Watson 		 */
610800c9408SRobert Watson 	case PRIV_CRED_SETUID:
611800c9408SRobert Watson 	case PRIV_CRED_SETEUID:
612800c9408SRobert Watson 	case PRIV_CRED_SETGID:
613800c9408SRobert Watson 	case PRIV_CRED_SETEGID:
614800c9408SRobert Watson 	case PRIV_CRED_SETGROUPS:
615800c9408SRobert Watson 	case PRIV_CRED_SETREUID:
616800c9408SRobert Watson 	case PRIV_CRED_SETREGID:
617800c9408SRobert Watson 	case PRIV_CRED_SETRESUID:
618800c9408SRobert Watson 	case PRIV_CRED_SETRESGID:
619800c9408SRobert Watson 
620800c9408SRobert Watson 		/*
621800c9408SRobert Watson 		 * Jail implements visibility constraints already, so allow
622800c9408SRobert Watson 		 * jailed root to override uid/gid-based constraints.
623800c9408SRobert Watson 		 */
624800c9408SRobert Watson 	case PRIV_SEEOTHERGIDS:
625800c9408SRobert Watson 	case PRIV_SEEOTHERUIDS:
626800c9408SRobert Watson 
627800c9408SRobert Watson 		/*
628800c9408SRobert Watson 		 * Jail implements inter-process debugging limits already, so
629800c9408SRobert Watson 		 * allow jailed root various debugging privileges.
630800c9408SRobert Watson 		 */
631800c9408SRobert Watson 	case PRIV_DEBUG_DIFFCRED:
632800c9408SRobert Watson 	case PRIV_DEBUG_SUGID:
633800c9408SRobert Watson 	case PRIV_DEBUG_UNPRIV:
634800c9408SRobert Watson 
635800c9408SRobert Watson 		/*
636800c9408SRobert Watson 		 * Allow jail to set various resource limits and login
637800c9408SRobert Watson 		 * properties, and for now, exceed process resource limits.
638800c9408SRobert Watson 		 */
639800c9408SRobert Watson 	case PRIV_PROC_LIMIT:
640800c9408SRobert Watson 	case PRIV_PROC_SETLOGIN:
641800c9408SRobert Watson 	case PRIV_PROC_SETRLIMIT:
642800c9408SRobert Watson 
643800c9408SRobert Watson 		/*
644800c9408SRobert Watson 		 * System V and POSIX IPC privileges are granted in jail.
645800c9408SRobert Watson 		 */
646800c9408SRobert Watson 	case PRIV_IPC_READ:
647800c9408SRobert Watson 	case PRIV_IPC_WRITE:
648800c9408SRobert Watson 	case PRIV_IPC_ADMIN:
649800c9408SRobert Watson 	case PRIV_IPC_MSGSIZE:
650800c9408SRobert Watson 	case PRIV_MQ_ADMIN:
651800c9408SRobert Watson 
652800c9408SRobert Watson 		/*
653800c9408SRobert Watson 		 * Jail implements its own inter-process limits, so allow
654800c9408SRobert Watson 		 * root processes in jail to change scheduling on other
655800c9408SRobert Watson 		 * processes in the same jail.  Likewise for signalling.
656800c9408SRobert Watson 		 */
657800c9408SRobert Watson 	case PRIV_SCHED_DIFFCRED:
658800c9408SRobert Watson 	case PRIV_SIGNAL_DIFFCRED:
659800c9408SRobert Watson 	case PRIV_SIGNAL_SUGID:
660800c9408SRobert Watson 
661800c9408SRobert Watson 		/*
662800c9408SRobert Watson 		 * Allow jailed processes to write to sysctls marked as jail
663800c9408SRobert Watson 		 * writable.
664800c9408SRobert Watson 		 */
665800c9408SRobert Watson 	case PRIV_SYSCTL_WRITEJAIL:
666800c9408SRobert Watson 
667800c9408SRobert Watson 		/*
668800c9408SRobert Watson 		 * Allow root in jail to manage a variety of quota
669e82d0201SRobert Watson 		 * properties.  These should likely be conditional on a
670e82d0201SRobert Watson 		 * configuration option.
671800c9408SRobert Watson 		 */
67295b091d2SRobert Watson 	case PRIV_VFS_GETQUOTA:
67395b091d2SRobert Watson 	case PRIV_VFS_SETQUOTA:
674800c9408SRobert Watson 
675800c9408SRobert Watson 		/*
676800c9408SRobert Watson 		 * Since Jail relies on chroot() to implement file system
677800c9408SRobert Watson 		 * protections, grant many VFS privileges to root in jail.
678800c9408SRobert Watson 		 * Be careful to exclude mount-related and NFS-related
679800c9408SRobert Watson 		 * privileges.
680800c9408SRobert Watson 		 */
681800c9408SRobert Watson 	case PRIV_VFS_READ:
682800c9408SRobert Watson 	case PRIV_VFS_WRITE:
683800c9408SRobert Watson 	case PRIV_VFS_ADMIN:
684800c9408SRobert Watson 	case PRIV_VFS_EXEC:
685800c9408SRobert Watson 	case PRIV_VFS_LOOKUP:
686800c9408SRobert Watson 	case PRIV_VFS_BLOCKRESERVE:	/* XXXRW: Slightly surprising. */
687800c9408SRobert Watson 	case PRIV_VFS_CHFLAGS_DEV:
688800c9408SRobert Watson 	case PRIV_VFS_CHOWN:
689800c9408SRobert Watson 	case PRIV_VFS_CHROOT:
690bb531912SPawel Jakub Dawidek 	case PRIV_VFS_RETAINSUGID:
691800c9408SRobert Watson 	case PRIV_VFS_FCHROOT:
692800c9408SRobert Watson 	case PRIV_VFS_LINK:
693800c9408SRobert Watson 	case PRIV_VFS_SETGID:
694e41966dcSRobert Watson 	case PRIV_VFS_STAT:
695800c9408SRobert Watson 	case PRIV_VFS_STICKYFILE:
696800c9408SRobert Watson 		return (0);
697800c9408SRobert Watson 
698800c9408SRobert Watson 		/*
699800c9408SRobert Watson 		 * Depending on the global setting, allow privilege of
700800c9408SRobert Watson 		 * setting system flags.
701800c9408SRobert Watson 		 */
702800c9408SRobert Watson 	case PRIV_VFS_SYSFLAGS:
703800c9408SRobert Watson 		if (jail_chflags_allowed)
704800c9408SRobert Watson 			return (0);
705800c9408SRobert Watson 		else
706800c9408SRobert Watson 			return (EPERM);
707800c9408SRobert Watson 
708800c9408SRobert Watson 		/*
709f3a8d2f9SPawel Jakub Dawidek 		 * Depending on the global setting, allow privilege of
710f3a8d2f9SPawel Jakub Dawidek 		 * mounting/unmounting file systems.
711f3a8d2f9SPawel Jakub Dawidek 		 */
712f3a8d2f9SPawel Jakub Dawidek 	case PRIV_VFS_MOUNT:
713f3a8d2f9SPawel Jakub Dawidek 	case PRIV_VFS_UNMOUNT:
714f3a8d2f9SPawel Jakub Dawidek 	case PRIV_VFS_MOUNT_NONUSER:
71524b0502eSPawel Jakub Dawidek 	case PRIV_VFS_MOUNT_OWNER:
716f3a8d2f9SPawel Jakub Dawidek 		if (jail_mount_allowed)
717f3a8d2f9SPawel Jakub Dawidek 			return (0);
718f3a8d2f9SPawel Jakub Dawidek 		else
719f3a8d2f9SPawel Jakub Dawidek 			return (EPERM);
720f3a8d2f9SPawel Jakub Dawidek 
721f3a8d2f9SPawel Jakub Dawidek 		/*
7224b084056SRobert Watson 		 * Allow jailed root to bind reserved ports and reuse in-use
7234b084056SRobert Watson 		 * ports.
724800c9408SRobert Watson 		 */
725800c9408SRobert Watson 	case PRIV_NETINET_RESERVEDPORT:
7264b084056SRobert Watson 	case PRIV_NETINET_REUSEPORT:
727800c9408SRobert Watson 		return (0);
728800c9408SRobert Watson 
729800c9408SRobert Watson 		/*
73079ba3952SBjoern A. Zeeb 		 * Allow jailed root to set certian IPv4/6 (option) headers.
73179ba3952SBjoern A. Zeeb 		 */
73279ba3952SBjoern A. Zeeb 	case PRIV_NETINET_SETHDROPTS:
73379ba3952SBjoern A. Zeeb 		return (0);
73479ba3952SBjoern A. Zeeb 
73579ba3952SBjoern A. Zeeb 		/*
736800c9408SRobert Watson 		 * Conditionally allow creating raw sockets in jail.
737800c9408SRobert Watson 		 */
738800c9408SRobert Watson 	case PRIV_NETINET_RAW:
739800c9408SRobert Watson 		if (jail_allow_raw_sockets)
740800c9408SRobert Watson 			return (0);
741800c9408SRobert Watson 		else
742800c9408SRobert Watson 			return (EPERM);
743800c9408SRobert Watson 
744800c9408SRobert Watson 		/*
745800c9408SRobert Watson 		 * Since jail implements its own visibility limits on netstat
746800c9408SRobert Watson 		 * sysctls, allow getcred.  This allows identd to work in
747800c9408SRobert Watson 		 * jail.
748800c9408SRobert Watson 		 */
749800c9408SRobert Watson 	case PRIV_NETINET_GETCRED:
750800c9408SRobert Watson 		return (0);
751800c9408SRobert Watson 
752800c9408SRobert Watson 	default:
753800c9408SRobert Watson 		/*
754800c9408SRobert Watson 		 * In all remaining cases, deny the privilege request.  This
755800c9408SRobert Watson 		 * includes almost all network privileges, many system
756800c9408SRobert Watson 		 * configuration privileges.
757800c9408SRobert Watson 		 */
758800c9408SRobert Watson 		return (EPERM);
759800c9408SRobert Watson 	}
760800c9408SRobert Watson }
761800c9408SRobert Watson 
762fd7a8150SMike Barcroft static int
763fd7a8150SMike Barcroft sysctl_jail_list(SYSCTL_HANDLER_ARGS)
764fd7a8150SMike Barcroft {
765fd7a8150SMike Barcroft 	struct xprison *xp, *sxp;
766fd7a8150SMike Barcroft 	struct prison *pr;
767fd7a8150SMike Barcroft 	int count, error;
768fd7a8150SMike Barcroft 
7697f4704c0SPawel Jakub Dawidek 	if (jailed(req->td->td_ucred))
770679a1060SRobert Watson 		return (0);
771fd7a8150SMike Barcroft 
772dc68a633SPawel Jakub Dawidek 	sx_slock(&allprison_lock);
773dc68a633SPawel Jakub Dawidek 	if ((count = prisoncount) == 0) {
774dc68a633SPawel Jakub Dawidek 		sx_sunlock(&allprison_lock);
775fd7a8150SMike Barcroft 		return (0);
776dc68a633SPawel Jakub Dawidek 	}
777fd7a8150SMike Barcroft 
778fd7a8150SMike Barcroft 	sxp = xp = malloc(sizeof(*xp) * count, M_TEMP, M_WAITOK | M_ZERO);
779fd7a8150SMike Barcroft 
780fd7a8150SMike Barcroft 	LIST_FOREACH(pr, &allprison, pr_list) {
781fd7a8150SMike Barcroft 		xp->pr_version = XPRISON_VERSION;
782fd7a8150SMike Barcroft 		xp->pr_id = pr->pr_id;
783fd7a8150SMike Barcroft 		xp->pr_ip = pr->pr_ip;
784b63b0c65SPawel Jakub Dawidek 		strlcpy(xp->pr_path, pr->pr_path, sizeof(xp->pr_path));
785b63b0c65SPawel Jakub Dawidek 		mtx_lock(&pr->pr_mtx);
786b63b0c65SPawel Jakub Dawidek 		strlcpy(xp->pr_host, pr->pr_host, sizeof(xp->pr_host));
787fd7a8150SMike Barcroft 		mtx_unlock(&pr->pr_mtx);
788fd7a8150SMike Barcroft 		xp++;
789fd7a8150SMike Barcroft 	}
790dc68a633SPawel Jakub Dawidek 	sx_sunlock(&allprison_lock);
791fd7a8150SMike Barcroft 
792fd7a8150SMike Barcroft 	error = SYSCTL_OUT(req, sxp, sizeof(*sxp) * count);
793fd7a8150SMike Barcroft 	free(sxp, M_TEMP);
794fd7a8150SMike Barcroft 	return (error);
795fd7a8150SMike Barcroft }
796fd7a8150SMike Barcroft 
797fd7a8150SMike Barcroft SYSCTL_OID(_security_jail, OID_AUTO, list, CTLTYPE_STRUCT | CTLFLAG_RD,
798fd7a8150SMike Barcroft     NULL, 0, sysctl_jail_list, "S", "List of active jails");
799461167c2SPawel Jakub Dawidek 
800461167c2SPawel Jakub Dawidek static int
801461167c2SPawel Jakub Dawidek sysctl_jail_jailed(SYSCTL_HANDLER_ARGS)
802461167c2SPawel Jakub Dawidek {
803461167c2SPawel Jakub Dawidek 	int error, injail;
804461167c2SPawel Jakub Dawidek 
805461167c2SPawel Jakub Dawidek 	injail = jailed(req->td->td_ucred);
806461167c2SPawel Jakub Dawidek 	error = SYSCTL_OUT(req, &injail, sizeof(injail));
807461167c2SPawel Jakub Dawidek 
808461167c2SPawel Jakub Dawidek 	return (error);
809461167c2SPawel Jakub Dawidek }
810461167c2SPawel Jakub Dawidek SYSCTL_PROC(_security_jail, OID_AUTO, jailed, CTLTYPE_INT | CTLFLAG_RD,
811461167c2SPawel Jakub Dawidek     NULL, 0, sysctl_jail_jailed, "I", "Process in jail?");
812