xref: /freebsd/sys/kern/kern_jail.c (revision f3a8d2f93ce69707ed05a48e89d884046f2d8a6a)
19454b2d8SWarner Losh /*-
207901f22SPoul-Henning Kamp  * ----------------------------------------------------------------------------
307901f22SPoul-Henning Kamp  * "THE BEER-WARE LICENSE" (Revision 42):
407901f22SPoul-Henning Kamp  * <phk@FreeBSD.ORG> wrote this file.  As long as you retain this notice you
507901f22SPoul-Henning Kamp  * can do whatever you want with this stuff. If we meet some day, and you think
607901f22SPoul-Henning Kamp  * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
707901f22SPoul-Henning Kamp  * ----------------------------------------------------------------------------
807901f22SPoul-Henning Kamp  */
975c13541SPoul-Henning Kamp 
10677b542eSDavid E. O'Brien #include <sys/cdefs.h>
11677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$");
12677b542eSDavid E. O'Brien 
1346e3b1cbSPawel Jakub Dawidek #include "opt_mac.h"
1446e3b1cbSPawel Jakub Dawidek 
1575c13541SPoul-Henning Kamp #include <sys/param.h>
1675c13541SPoul-Henning Kamp #include <sys/types.h>
1775c13541SPoul-Henning Kamp #include <sys/kernel.h>
1875c13541SPoul-Henning Kamp #include <sys/systm.h>
1975c13541SPoul-Henning Kamp #include <sys/errno.h>
2075c13541SPoul-Henning Kamp #include <sys/sysproto.h>
2175c13541SPoul-Henning Kamp #include <sys/malloc.h>
22800c9408SRobert Watson #include <sys/priv.h>
2375c13541SPoul-Henning Kamp #include <sys/proc.h>
24b3059e09SRobert Watson #include <sys/taskqueue.h>
2575c13541SPoul-Henning Kamp #include <sys/jail.h>
2601137630SRobert Watson #include <sys/lock.h>
2701137630SRobert Watson #include <sys/mutex.h>
28fd7a8150SMike Barcroft #include <sys/namei.h>
29820a0de9SPawel Jakub Dawidek #include <sys/mount.h>
30fd7a8150SMike Barcroft #include <sys/queue.h>
3175c13541SPoul-Henning Kamp #include <sys/socket.h>
32fd7a8150SMike Barcroft #include <sys/syscallsubr.h>
3383f1e257SRobert Watson #include <sys/sysctl.h>
34fd7a8150SMike Barcroft #include <sys/vnode.h>
3575c13541SPoul-Henning Kamp #include <net/if.h>
3675c13541SPoul-Henning Kamp #include <netinet/in.h>
3775c13541SPoul-Henning Kamp 
38aed55708SRobert Watson #include <security/mac/mac_framework.h>
39aed55708SRobert Watson 
4075c13541SPoul-Henning Kamp MALLOC_DEFINE(M_PRISON, "prison", "Prison structures");
4175c13541SPoul-Henning Kamp 
42d0615c64SAndrew R. Reiter SYSCTL_NODE(_security, OID_AUTO, jail, CTLFLAG_RW, 0,
4383f1e257SRobert Watson     "Jail rules");
4483f1e257SRobert Watson 
4583f1e257SRobert Watson int	jail_set_hostname_allowed = 1;
46d0615c64SAndrew R. Reiter SYSCTL_INT(_security_jail, OID_AUTO, set_hostname_allowed, CTLFLAG_RW,
4783f1e257SRobert Watson     &jail_set_hostname_allowed, 0,
4883f1e257SRobert Watson     "Processes in jail can set their hostnames");
4983f1e257SRobert Watson 
507cadc266SRobert Watson int	jail_socket_unixiproute_only = 1;
51d0615c64SAndrew R. Reiter SYSCTL_INT(_security_jail, OID_AUTO, socket_unixiproute_only, CTLFLAG_RW,
527cadc266SRobert Watson     &jail_socket_unixiproute_only, 0,
537cadc266SRobert Watson     "Processes in jail are limited to creating UNIX/IPv4/route sockets only");
547cadc266SRobert Watson 
55cb1f0db9SRobert Watson int	jail_sysvipc_allowed = 0;
56d0615c64SAndrew R. Reiter SYSCTL_INT(_security_jail, OID_AUTO, sysvipc_allowed, CTLFLAG_RW,
57cb1f0db9SRobert Watson     &jail_sysvipc_allowed, 0,
58cb1f0db9SRobert Watson     "Processes in jail can use System V IPC primitives");
59cb1f0db9SRobert Watson 
60820a0de9SPawel Jakub Dawidek static int jail_enforce_statfs = 2;
61820a0de9SPawel Jakub Dawidek SYSCTL_INT(_security_jail, OID_AUTO, enforce_statfs, CTLFLAG_RW,
62820a0de9SPawel Jakub Dawidek     &jail_enforce_statfs, 0,
63820a0de9SPawel Jakub Dawidek     "Processes in jail cannot see all mounted file systems");
64f08df373SRobert Watson 
655a59cefcSBosko Milekic int	jail_allow_raw_sockets = 0;
665a59cefcSBosko Milekic SYSCTL_INT(_security_jail, OID_AUTO, allow_raw_sockets, CTLFLAG_RW,
675a59cefcSBosko Milekic     &jail_allow_raw_sockets, 0,
685a59cefcSBosko Milekic     "Prison root can create raw sockets");
695a59cefcSBosko Milekic 
7079653046SColin Percival int	jail_chflags_allowed = 0;
7179653046SColin Percival SYSCTL_INT(_security_jail, OID_AUTO, chflags_allowed, CTLFLAG_RW,
7279653046SColin Percival     &jail_chflags_allowed, 0,
7379653046SColin Percival     "Processes in jail can alter system file flags");
7479653046SColin Percival 
75f3a8d2f9SPawel Jakub Dawidek int	jail_mount_allowed = 0;
76f3a8d2f9SPawel Jakub Dawidek SYSCTL_INT(_security_jail, OID_AUTO, mount_allowed, CTLFLAG_RW,
77f3a8d2f9SPawel Jakub Dawidek     &jail_mount_allowed, 0,
78f3a8d2f9SPawel Jakub Dawidek     "Processes in jail can mount/unmount jail-friendly file systems");
79f3a8d2f9SPawel Jakub Dawidek 
80fd7a8150SMike Barcroft /* allprison, lastprid, and prisoncount are protected by allprison_mtx. */
81fd7a8150SMike Barcroft struct	prisonlist allprison;
82fd7a8150SMike Barcroft struct	mtx allprison_mtx;
83fd7a8150SMike Barcroft int	lastprid = 0;
84fd7a8150SMike Barcroft int	prisoncount = 0;
85fd7a8150SMike Barcroft 
86fd7a8150SMike Barcroft static void		 init_prison(void *);
87b3059e09SRobert Watson static void		 prison_complete(void *context, int pending);
88fd7a8150SMike Barcroft static struct prison	*prison_find(int);
89fd7a8150SMike Barcroft static int		 sysctl_jail_list(SYSCTL_HANDLER_ARGS);
90fd7a8150SMike Barcroft 
91fd7a8150SMike Barcroft static void
92fd7a8150SMike Barcroft init_prison(void *data __unused)
93fd7a8150SMike Barcroft {
94fd7a8150SMike Barcroft 
95fd7a8150SMike Barcroft 	mtx_init(&allprison_mtx, "allprison", NULL, MTX_DEF);
96fd7a8150SMike Barcroft 	LIST_INIT(&allprison);
97fd7a8150SMike Barcroft }
98fd7a8150SMike Barcroft 
99fd7a8150SMike Barcroft SYSINIT(prison, SI_SUB_INTRINSIC, SI_ORDER_ANY, init_prison, NULL);
100fd7a8150SMike Barcroft 
101116734c4SMatthew Dillon /*
1029ddb7954SMike Barcroft  * struct jail_args {
1039ddb7954SMike Barcroft  *	struct jail *jail;
1049ddb7954SMike Barcroft  * };
105116734c4SMatthew Dillon  */
10675c13541SPoul-Henning Kamp int
1079ddb7954SMike Barcroft jail(struct thread *td, struct jail_args *uap)
10875c13541SPoul-Henning Kamp {
109fd7a8150SMike Barcroft 	struct nameidata nd;
110fd7a8150SMike Barcroft 	struct prison *pr, *tpr;
11175c13541SPoul-Henning Kamp 	struct jail j;
112fd7a8150SMike Barcroft 	struct jail_attach_args jaa;
113453f7d53SChristian S.J. Peron 	int vfslocked, error, tryprid;
11475c13541SPoul-Henning Kamp 
1159ddb7954SMike Barcroft 	error = copyin(uap->jail, &j, sizeof(j));
11675c13541SPoul-Henning Kamp 	if (error)
117a2f2b3afSJohn Baldwin 		return (error);
118a2f2b3afSJohn Baldwin 	if (j.version != 0)
119a2f2b3afSJohn Baldwin 		return (EINVAL);
120a2f2b3afSJohn Baldwin 
1219ddb7954SMike Barcroft 	MALLOC(pr, struct prison *, sizeof(*pr), M_PRISON, M_WAITOK | M_ZERO);
1226008862bSJohn Baldwin 	mtx_init(&pr->pr_mtx, "jail mutex", NULL, MTX_DEF);
123fd7a8150SMike Barcroft 	pr->pr_ref = 1;
1249ddb7954SMike Barcroft 	error = copyinstr(j.path, &pr->pr_path, sizeof(pr->pr_path), 0);
125fd7a8150SMike Barcroft 	if (error)
126fd7a8150SMike Barcroft 		goto e_killmtx;
127453f7d53SChristian S.J. Peron 	NDINIT(&nd, LOOKUP, MPSAFE | FOLLOW | LOCKLEAF, UIO_SYSSPACE,
128453f7d53SChristian S.J. Peron 	    pr->pr_path, td);
129fd7a8150SMike Barcroft 	error = namei(&nd);
130453f7d53SChristian S.J. Peron 	if (error)
131fd7a8150SMike Barcroft 		goto e_killmtx;
132453f7d53SChristian S.J. Peron 	vfslocked = NDHASGIANT(&nd);
133fd7a8150SMike Barcroft 	pr->pr_root = nd.ni_vp;
134fd7a8150SMike Barcroft 	VOP_UNLOCK(nd.ni_vp, 0, td);
135fd7a8150SMike Barcroft 	NDFREE(&nd, NDF_ONLY_PNBUF);
136453f7d53SChristian S.J. Peron 	VFS_UNLOCK_GIANT(vfslocked);
1379ddb7954SMike Barcroft 	error = copyinstr(j.hostname, &pr->pr_host, sizeof(pr->pr_host), 0);
13875c13541SPoul-Henning Kamp 	if (error)
139fd7a8150SMike Barcroft 		goto e_dropvnref;
140a2f2b3afSJohn Baldwin 	pr->pr_ip = j.ip_number;
141fd7a8150SMike Barcroft 	pr->pr_linux = NULL;
142fd7a8150SMike Barcroft 	pr->pr_securelevel = securelevel;
143fd7a8150SMike Barcroft 
144fd7a8150SMike Barcroft 	/* Determine next pr_id and add prison to allprison list. */
145fd7a8150SMike Barcroft 	mtx_lock(&allprison_mtx);
146fd7a8150SMike Barcroft 	tryprid = lastprid + 1;
147fd7a8150SMike Barcroft 	if (tryprid == JAIL_MAX)
148fd7a8150SMike Barcroft 		tryprid = 1;
149fd7a8150SMike Barcroft next:
150fd7a8150SMike Barcroft 	LIST_FOREACH(tpr, &allprison, pr_list) {
151fd7a8150SMike Barcroft 		if (tpr->pr_id == tryprid) {
152fd7a8150SMike Barcroft 			tryprid++;
153fd7a8150SMike Barcroft 			if (tryprid == JAIL_MAX) {
154fd7a8150SMike Barcroft 				mtx_unlock(&allprison_mtx);
155fd7a8150SMike Barcroft 				error = EAGAIN;
156fd7a8150SMike Barcroft 				goto e_dropvnref;
157fd7a8150SMike Barcroft 			}
158fd7a8150SMike Barcroft 			goto next;
159fd7a8150SMike Barcroft 		}
160fd7a8150SMike Barcroft 	}
161fd7a8150SMike Barcroft 	pr->pr_id = jaa.jid = lastprid = tryprid;
162fd7a8150SMike Barcroft 	LIST_INSERT_HEAD(&allprison, pr, pr_list);
163fd7a8150SMike Barcroft 	prisoncount++;
164fd7a8150SMike Barcroft 	mtx_unlock(&allprison_mtx);
165fd7a8150SMike Barcroft 
166fd7a8150SMike Barcroft 	error = jail_attach(td, &jaa);
167a2f2b3afSJohn Baldwin 	if (error)
168fd7a8150SMike Barcroft 		goto e_dropprref;
169fd7a8150SMike Barcroft 	mtx_lock(&pr->pr_mtx);
170fd7a8150SMike Barcroft 	pr->pr_ref--;
171fd7a8150SMike Barcroft 	mtx_unlock(&pr->pr_mtx);
172fd7a8150SMike Barcroft 	td->td_retval[0] = jaa.jid;
17375c13541SPoul-Henning Kamp 	return (0);
174fd7a8150SMike Barcroft e_dropprref:
175fd7a8150SMike Barcroft 	mtx_lock(&allprison_mtx);
176fd7a8150SMike Barcroft 	LIST_REMOVE(pr, pr_list);
177fd7a8150SMike Barcroft 	prisoncount--;
178fd7a8150SMike Barcroft 	mtx_unlock(&allprison_mtx);
179fd7a8150SMike Barcroft e_dropvnref:
180453f7d53SChristian S.J. Peron 	vfslocked = VFS_LOCK_GIANT(pr->pr_root->v_mount);
181fd7a8150SMike Barcroft 	vrele(pr->pr_root);
182453f7d53SChristian S.J. Peron 	VFS_UNLOCK_GIANT(vfslocked);
183fd7a8150SMike Barcroft e_killmtx:
184894db7b0SMaxime Henrion 	mtx_destroy(&pr->pr_mtx);
18575c13541SPoul-Henning Kamp 	FREE(pr, M_PRISON);
18675c13541SPoul-Henning Kamp 	return (error);
18775c13541SPoul-Henning Kamp }
18875c13541SPoul-Henning Kamp 
189fd7a8150SMike Barcroft /*
1909ddb7954SMike Barcroft  * struct jail_attach_args {
1919ddb7954SMike Barcroft  *	int jid;
1929ddb7954SMike Barcroft  * };
193fd7a8150SMike Barcroft  */
194fd7a8150SMike Barcroft int
1959ddb7954SMike Barcroft jail_attach(struct thread *td, struct jail_attach_args *uap)
196fd7a8150SMike Barcroft {
197fd7a8150SMike Barcroft 	struct proc *p;
198fd7a8150SMike Barcroft 	struct ucred *newcred, *oldcred;
199fd7a8150SMike Barcroft 	struct prison *pr;
200453f7d53SChristian S.J. Peron 	int vfslocked, error;
201fd7a8150SMike Barcroft 
20257f22bd4SJacques Vidrine 	/*
20357f22bd4SJacques Vidrine 	 * XXX: Note that there is a slight race here if two threads
20457f22bd4SJacques Vidrine 	 * in the same privileged process attempt to attach to two
20557f22bd4SJacques Vidrine 	 * different jails at the same time.  It is important for
20657f22bd4SJacques Vidrine 	 * user processes not to do this, or they might end up with
20757f22bd4SJacques Vidrine 	 * a process root from one prison, but attached to the jail
20857f22bd4SJacques Vidrine 	 * of another.
20957f22bd4SJacques Vidrine 	 */
210800c9408SRobert Watson 	error = priv_check(td, PRIV_JAIL_ATTACH);
21157f22bd4SJacques Vidrine 	if (error)
21257f22bd4SJacques Vidrine 		return (error);
213fd7a8150SMike Barcroft 
21457f22bd4SJacques Vidrine 	p = td->td_proc;
215fd7a8150SMike Barcroft 	mtx_lock(&allprison_mtx);
216fd7a8150SMike Barcroft 	pr = prison_find(uap->jid);
217fd7a8150SMike Barcroft 	if (pr == NULL) {
218fd7a8150SMike Barcroft 		mtx_unlock(&allprison_mtx);
219fd7a8150SMike Barcroft 		return (EINVAL);
220fd7a8150SMike Barcroft 	}
221fd7a8150SMike Barcroft 	pr->pr_ref++;
222fd7a8150SMike Barcroft 	mtx_unlock(&pr->pr_mtx);
223fd7a8150SMike Barcroft 	mtx_unlock(&allprison_mtx);
224fd7a8150SMike Barcroft 
225453f7d53SChristian S.J. Peron 	vfslocked = VFS_LOCK_GIANT(pr->pr_root->v_mount);
226fd7a8150SMike Barcroft 	vn_lock(pr->pr_root, LK_EXCLUSIVE | LK_RETRY, td);
227fd7a8150SMike Barcroft 	if ((error = change_dir(pr->pr_root, td)) != 0)
228fd7a8150SMike Barcroft 		goto e_unlock;
229fd7a8150SMike Barcroft #ifdef MAC
230fd7a8150SMike Barcroft 	if ((error = mac_check_vnode_chroot(td->td_ucred, pr->pr_root)))
231fd7a8150SMike Barcroft 		goto e_unlock;
232fd7a8150SMike Barcroft #endif
233fd7a8150SMike Barcroft 	VOP_UNLOCK(pr->pr_root, 0, td);
234fd7a8150SMike Barcroft 	change_root(pr->pr_root, td);
235453f7d53SChristian S.J. Peron 	VFS_UNLOCK_GIANT(vfslocked);
236fd7a8150SMike Barcroft 
237fd7a8150SMike Barcroft 	newcred = crget();
238fd7a8150SMike Barcroft 	PROC_LOCK(p);
239fd7a8150SMike Barcroft 	oldcred = p->p_ucred;
240fd7a8150SMike Barcroft 	setsugid(p);
241fd7a8150SMike Barcroft 	crcopy(newcred, oldcred);
24269c4ee54SJohn Baldwin 	newcred->cr_prison = pr;
243fd7a8150SMike Barcroft 	p->p_ucred = newcred;
244fd7a8150SMike Barcroft 	PROC_UNLOCK(p);
245fd7a8150SMike Barcroft 	crfree(oldcred);
246fd7a8150SMike Barcroft 	return (0);
247fd7a8150SMike Barcroft e_unlock:
248fd7a8150SMike Barcroft 	VOP_UNLOCK(pr->pr_root, 0, td);
249453f7d53SChristian S.J. Peron 	VFS_UNLOCK_GIANT(vfslocked);
250fd7a8150SMike Barcroft 	mtx_lock(&pr->pr_mtx);
251fd7a8150SMike Barcroft 	pr->pr_ref--;
252fd7a8150SMike Barcroft 	mtx_unlock(&pr->pr_mtx);
253fd7a8150SMike Barcroft 	return (error);
254fd7a8150SMike Barcroft }
255fd7a8150SMike Barcroft 
256fd7a8150SMike Barcroft /*
257fd7a8150SMike Barcroft  * Returns a locked prison instance, or NULL on failure.
258fd7a8150SMike Barcroft  */
259fd7a8150SMike Barcroft static struct prison *
260fd7a8150SMike Barcroft prison_find(int prid)
261fd7a8150SMike Barcroft {
262fd7a8150SMike Barcroft 	struct prison *pr;
263fd7a8150SMike Barcroft 
264fd7a8150SMike Barcroft 	mtx_assert(&allprison_mtx, MA_OWNED);
265fd7a8150SMike Barcroft 	LIST_FOREACH(pr, &allprison, pr_list) {
266fd7a8150SMike Barcroft 		if (pr->pr_id == prid) {
267fd7a8150SMike Barcroft 			mtx_lock(&pr->pr_mtx);
268fd7a8150SMike Barcroft 			return (pr);
269fd7a8150SMike Barcroft 		}
270fd7a8150SMike Barcroft 	}
271fd7a8150SMike Barcroft 	return (NULL);
272fd7a8150SMike Barcroft }
273fd7a8150SMike Barcroft 
27491421ba2SRobert Watson void
27591421ba2SRobert Watson prison_free(struct prison *pr)
27691421ba2SRobert Watson {
27791421ba2SRobert Watson 
278fd7a8150SMike Barcroft 	mtx_lock(&allprison_mtx);
27901137630SRobert Watson 	mtx_lock(&pr->pr_mtx);
28091421ba2SRobert Watson 	pr->pr_ref--;
28191421ba2SRobert Watson 	if (pr->pr_ref == 0) {
282fd7a8150SMike Barcroft 		LIST_REMOVE(pr, pr_list);
28301137630SRobert Watson 		mtx_unlock(&pr->pr_mtx);
284fd7a8150SMike Barcroft 		prisoncount--;
285fd7a8150SMike Barcroft 		mtx_unlock(&allprison_mtx);
286b3059e09SRobert Watson 
287b3059e09SRobert Watson 		TASK_INIT(&pr->pr_task, 0, prison_complete, pr);
28822fdc83fSJeff Roberson 		taskqueue_enqueue(taskqueue_thread, &pr->pr_task);
28901137630SRobert Watson 		return;
29091421ba2SRobert Watson 	}
29101137630SRobert Watson 	mtx_unlock(&pr->pr_mtx);
292fd7a8150SMike Barcroft 	mtx_unlock(&allprison_mtx);
29391421ba2SRobert Watson }
29491421ba2SRobert Watson 
295b3059e09SRobert Watson static void
296b3059e09SRobert Watson prison_complete(void *context, int pending)
297b3059e09SRobert Watson {
298b3059e09SRobert Watson 	struct prison *pr;
299453f7d53SChristian S.J. Peron 	int vfslocked;
300b3059e09SRobert Watson 
301b3059e09SRobert Watson 	pr = (struct prison *)context;
302b3059e09SRobert Watson 
303453f7d53SChristian S.J. Peron 	vfslocked = VFS_LOCK_GIANT(pr->pr_root->v_mount);
304b3059e09SRobert Watson 	vrele(pr->pr_root);
305453f7d53SChristian S.J. Peron 	VFS_UNLOCK_GIANT(vfslocked);
306b3059e09SRobert Watson 
307b3059e09SRobert Watson 	mtx_destroy(&pr->pr_mtx);
308b3059e09SRobert Watson 	if (pr->pr_linux != NULL)
309b3059e09SRobert Watson 		FREE(pr->pr_linux, M_PRISON);
310b3059e09SRobert Watson 	FREE(pr, M_PRISON);
311b3059e09SRobert Watson }
312b3059e09SRobert Watson 
31391421ba2SRobert Watson void
31491421ba2SRobert Watson prison_hold(struct prison *pr)
31591421ba2SRobert Watson {
31691421ba2SRobert Watson 
31701137630SRobert Watson 	mtx_lock(&pr->pr_mtx);
31891421ba2SRobert Watson 	pr->pr_ref++;
31901137630SRobert Watson 	mtx_unlock(&pr->pr_mtx);
32001137630SRobert Watson }
32101137630SRobert Watson 
32201137630SRobert Watson u_int32_t
32301137630SRobert Watson prison_getip(struct ucred *cred)
32401137630SRobert Watson {
32501137630SRobert Watson 
32601137630SRobert Watson 	return (cred->cr_prison->pr_ip);
32791421ba2SRobert Watson }
32891421ba2SRobert Watson 
32975c13541SPoul-Henning Kamp int
33091421ba2SRobert Watson prison_ip(struct ucred *cred, int flag, u_int32_t *ip)
33175c13541SPoul-Henning Kamp {
33275c13541SPoul-Henning Kamp 	u_int32_t tmp;
33375c13541SPoul-Henning Kamp 
33491421ba2SRobert Watson 	if (!jailed(cred))
33575c13541SPoul-Henning Kamp 		return (0);
33675c13541SPoul-Henning Kamp 	if (flag)
33775c13541SPoul-Henning Kamp 		tmp = *ip;
33875c13541SPoul-Henning Kamp 	else
33975c13541SPoul-Henning Kamp 		tmp = ntohl(*ip);
34075c13541SPoul-Henning Kamp 	if (tmp == INADDR_ANY) {
34175c13541SPoul-Henning Kamp 		if (flag)
34291421ba2SRobert Watson 			*ip = cred->cr_prison->pr_ip;
34375c13541SPoul-Henning Kamp 		else
34491421ba2SRobert Watson 			*ip = htonl(cred->cr_prison->pr_ip);
34575c13541SPoul-Henning Kamp 		return (0);
34675c13541SPoul-Henning Kamp 	}
347fd6aaf7fSRobert Watson 	if (tmp == INADDR_LOOPBACK) {
348fd6aaf7fSRobert Watson 		if (flag)
349fd6aaf7fSRobert Watson 			*ip = cred->cr_prison->pr_ip;
350fd6aaf7fSRobert Watson 		else
351fd6aaf7fSRobert Watson 			*ip = htonl(cred->cr_prison->pr_ip);
352fd6aaf7fSRobert Watson 		return (0);
353fd6aaf7fSRobert Watson 	}
35491421ba2SRobert Watson 	if (cred->cr_prison->pr_ip != tmp)
35575c13541SPoul-Henning Kamp 		return (1);
35675c13541SPoul-Henning Kamp 	return (0);
35775c13541SPoul-Henning Kamp }
35875c13541SPoul-Henning Kamp 
35975c13541SPoul-Henning Kamp void
36091421ba2SRobert Watson prison_remote_ip(struct ucred *cred, int flag, u_int32_t *ip)
36175c13541SPoul-Henning Kamp {
36275c13541SPoul-Henning Kamp 	u_int32_t tmp;
36375c13541SPoul-Henning Kamp 
36491421ba2SRobert Watson 	if (!jailed(cred))
36575c13541SPoul-Henning Kamp 		return;
36675c13541SPoul-Henning Kamp 	if (flag)
36775c13541SPoul-Henning Kamp 		tmp = *ip;
36875c13541SPoul-Henning Kamp 	else
36975c13541SPoul-Henning Kamp 		tmp = ntohl(*ip);
370fd6aaf7fSRobert Watson 	if (tmp == INADDR_LOOPBACK) {
37175c13541SPoul-Henning Kamp 		if (flag)
37291421ba2SRobert Watson 			*ip = cred->cr_prison->pr_ip;
37375c13541SPoul-Henning Kamp 		else
37491421ba2SRobert Watson 			*ip = htonl(cred->cr_prison->pr_ip);
37575c13541SPoul-Henning Kamp 		return;
37675c13541SPoul-Henning Kamp 	}
37775c13541SPoul-Henning Kamp 	return;
37875c13541SPoul-Henning Kamp }
37975c13541SPoul-Henning Kamp 
38075c13541SPoul-Henning Kamp int
38191421ba2SRobert Watson prison_if(struct ucred *cred, struct sockaddr *sa)
38275c13541SPoul-Henning Kamp {
3839ddb7954SMike Barcroft 	struct sockaddr_in *sai;
38475c13541SPoul-Henning Kamp 	int ok;
38575c13541SPoul-Henning Kamp 
3869ddb7954SMike Barcroft 	sai = (struct sockaddr_in *)sa;
3877cadc266SRobert Watson 	if ((sai->sin_family != AF_INET) && jail_socket_unixiproute_only)
3887cadc266SRobert Watson 		ok = 1;
3897cadc266SRobert Watson 	else if (sai->sin_family != AF_INET)
39075c13541SPoul-Henning Kamp 		ok = 0;
39191421ba2SRobert Watson 	else if (cred->cr_prison->pr_ip != ntohl(sai->sin_addr.s_addr))
39275c13541SPoul-Henning Kamp 		ok = 1;
39375c13541SPoul-Henning Kamp 	else
39475c13541SPoul-Henning Kamp 		ok = 0;
39575c13541SPoul-Henning Kamp 	return (ok);
39675c13541SPoul-Henning Kamp }
39791421ba2SRobert Watson 
39891421ba2SRobert Watson /*
39991421ba2SRobert Watson  * Return 0 if jails permit p1 to frob p2, otherwise ESRCH.
40091421ba2SRobert Watson  */
40191421ba2SRobert Watson int
4029ddb7954SMike Barcroft prison_check(struct ucred *cred1, struct ucred *cred2)
40391421ba2SRobert Watson {
40491421ba2SRobert Watson 
40591421ba2SRobert Watson 	if (jailed(cred1)) {
40691421ba2SRobert Watson 		if (!jailed(cred2))
40791421ba2SRobert Watson 			return (ESRCH);
40891421ba2SRobert Watson 		if (cred2->cr_prison != cred1->cr_prison)
40991421ba2SRobert Watson 			return (ESRCH);
41091421ba2SRobert Watson 	}
41191421ba2SRobert Watson 
41291421ba2SRobert Watson 	return (0);
41391421ba2SRobert Watson }
41491421ba2SRobert Watson 
41591421ba2SRobert Watson /*
41691421ba2SRobert Watson  * Return 1 if the passed credential is in a jail, otherwise 0.
41791421ba2SRobert Watson  */
41891421ba2SRobert Watson int
4199ddb7954SMike Barcroft jailed(struct ucred *cred)
42091421ba2SRobert Watson {
42191421ba2SRobert Watson 
42291421ba2SRobert Watson 	return (cred->cr_prison != NULL);
42391421ba2SRobert Watson }
4249484d0c0SRobert Drehmel 
4259484d0c0SRobert Drehmel /*
4269484d0c0SRobert Drehmel  * Return the correct hostname for the passed credential.
4279484d0c0SRobert Drehmel  */
428ad1ff099SRobert Drehmel void
4299ddb7954SMike Barcroft getcredhostname(struct ucred *cred, char *buf, size_t size)
4309484d0c0SRobert Drehmel {
4319484d0c0SRobert Drehmel 
432ad1ff099SRobert Drehmel 	if (jailed(cred)) {
433ad1ff099SRobert Drehmel 		mtx_lock(&cred->cr_prison->pr_mtx);
434e80fb434SRobert Drehmel 		strlcpy(buf, cred->cr_prison->pr_host, size);
435ad1ff099SRobert Drehmel 		mtx_unlock(&cred->cr_prison->pr_mtx);
4369ddb7954SMike Barcroft 	} else
437e80fb434SRobert Drehmel 		strlcpy(buf, hostname, size);
4389484d0c0SRobert Drehmel }
439fd7a8150SMike Barcroft 
440f08df373SRobert Watson /*
441820a0de9SPawel Jakub Dawidek  * Determine whether the subject represented by cred can "see"
442820a0de9SPawel Jakub Dawidek  * status of a mount point.
443820a0de9SPawel Jakub Dawidek  * Returns: 0 for permitted, ENOENT otherwise.
444820a0de9SPawel Jakub Dawidek  * XXX: This function should be called cr_canseemount() and should be
445820a0de9SPawel Jakub Dawidek  *      placed in kern_prot.c.
446f08df373SRobert Watson  */
447f08df373SRobert Watson int
448820a0de9SPawel Jakub Dawidek prison_canseemount(struct ucred *cred, struct mount *mp)
449f08df373SRobert Watson {
450820a0de9SPawel Jakub Dawidek 	struct prison *pr;
451820a0de9SPawel Jakub Dawidek 	struct statfs *sp;
452820a0de9SPawel Jakub Dawidek 	size_t len;
453f08df373SRobert Watson 
454820a0de9SPawel Jakub Dawidek 	if (!jailed(cred) || jail_enforce_statfs == 0)
455820a0de9SPawel Jakub Dawidek 		return (0);
456820a0de9SPawel Jakub Dawidek 	pr = cred->cr_prison;
457820a0de9SPawel Jakub Dawidek 	if (pr->pr_root->v_mount == mp)
458820a0de9SPawel Jakub Dawidek 		return (0);
459820a0de9SPawel Jakub Dawidek 	if (jail_enforce_statfs == 2)
460820a0de9SPawel Jakub Dawidek 		return (ENOENT);
461820a0de9SPawel Jakub Dawidek 	/*
462820a0de9SPawel Jakub Dawidek 	 * If jail's chroot directory is set to "/" we should be able to see
463820a0de9SPawel Jakub Dawidek 	 * all mount-points from inside a jail.
464820a0de9SPawel Jakub Dawidek 	 * This is ugly check, but this is the only situation when jail's
465820a0de9SPawel Jakub Dawidek 	 * directory ends with '/'.
466820a0de9SPawel Jakub Dawidek 	 */
467820a0de9SPawel Jakub Dawidek 	if (strcmp(pr->pr_path, "/") == 0)
468820a0de9SPawel Jakub Dawidek 		return (0);
469820a0de9SPawel Jakub Dawidek 	len = strlen(pr->pr_path);
470820a0de9SPawel Jakub Dawidek 	sp = &mp->mnt_stat;
471820a0de9SPawel Jakub Dawidek 	if (strncmp(pr->pr_path, sp->f_mntonname, len) != 0)
472820a0de9SPawel Jakub Dawidek 		return (ENOENT);
473820a0de9SPawel Jakub Dawidek 	/*
474820a0de9SPawel Jakub Dawidek 	 * Be sure that we don't have situation where jail's root directory
475820a0de9SPawel Jakub Dawidek 	 * is "/some/path" and mount point is "/some/pathpath".
476820a0de9SPawel Jakub Dawidek 	 */
477820a0de9SPawel Jakub Dawidek 	if (sp->f_mntonname[len] != '\0' && sp->f_mntonname[len] != '/')
478820a0de9SPawel Jakub Dawidek 		return (ENOENT);
479f08df373SRobert Watson 	return (0);
480f08df373SRobert Watson }
481820a0de9SPawel Jakub Dawidek 
482820a0de9SPawel Jakub Dawidek void
483820a0de9SPawel Jakub Dawidek prison_enforce_statfs(struct ucred *cred, struct mount *mp, struct statfs *sp)
484820a0de9SPawel Jakub Dawidek {
485820a0de9SPawel Jakub Dawidek 	char jpath[MAXPATHLEN];
486820a0de9SPawel Jakub Dawidek 	struct prison *pr;
487820a0de9SPawel Jakub Dawidek 	size_t len;
488820a0de9SPawel Jakub Dawidek 
489820a0de9SPawel Jakub Dawidek 	if (!jailed(cred) || jail_enforce_statfs == 0)
490820a0de9SPawel Jakub Dawidek 		return;
491820a0de9SPawel Jakub Dawidek 	pr = cred->cr_prison;
492820a0de9SPawel Jakub Dawidek 	if (prison_canseemount(cred, mp) != 0) {
493820a0de9SPawel Jakub Dawidek 		bzero(sp->f_mntonname, sizeof(sp->f_mntonname));
494820a0de9SPawel Jakub Dawidek 		strlcpy(sp->f_mntonname, "[restricted]",
495820a0de9SPawel Jakub Dawidek 		    sizeof(sp->f_mntonname));
496820a0de9SPawel Jakub Dawidek 		return;
497820a0de9SPawel Jakub Dawidek 	}
498820a0de9SPawel Jakub Dawidek 	if (pr->pr_root->v_mount == mp) {
499820a0de9SPawel Jakub Dawidek 		/*
500820a0de9SPawel Jakub Dawidek 		 * Clear current buffer data, so we are sure nothing from
501820a0de9SPawel Jakub Dawidek 		 * the valid path left there.
502820a0de9SPawel Jakub Dawidek 		 */
503820a0de9SPawel Jakub Dawidek 		bzero(sp->f_mntonname, sizeof(sp->f_mntonname));
504820a0de9SPawel Jakub Dawidek 		*sp->f_mntonname = '/';
505820a0de9SPawel Jakub Dawidek 		return;
506820a0de9SPawel Jakub Dawidek 	}
507820a0de9SPawel Jakub Dawidek 	/*
508820a0de9SPawel Jakub Dawidek 	 * If jail's chroot directory is set to "/" we should be able to see
509820a0de9SPawel Jakub Dawidek 	 * all mount-points from inside a jail.
510820a0de9SPawel Jakub Dawidek 	 */
511820a0de9SPawel Jakub Dawidek 	if (strcmp(pr->pr_path, "/") == 0)
512820a0de9SPawel Jakub Dawidek 		return;
513820a0de9SPawel Jakub Dawidek 	len = strlen(pr->pr_path);
514820a0de9SPawel Jakub Dawidek 	strlcpy(jpath, sp->f_mntonname + len, sizeof(jpath));
515820a0de9SPawel Jakub Dawidek 	/*
516820a0de9SPawel Jakub Dawidek 	 * Clear current buffer data, so we are sure nothing from
517820a0de9SPawel Jakub Dawidek 	 * the valid path left there.
518820a0de9SPawel Jakub Dawidek 	 */
519820a0de9SPawel Jakub Dawidek 	bzero(sp->f_mntonname, sizeof(sp->f_mntonname));
520820a0de9SPawel Jakub Dawidek 	if (*jpath == '\0') {
521820a0de9SPawel Jakub Dawidek 		/* Should never happen. */
522820a0de9SPawel Jakub Dawidek 		*sp->f_mntonname = '/';
523820a0de9SPawel Jakub Dawidek 	} else {
524820a0de9SPawel Jakub Dawidek 		strlcpy(sp->f_mntonname, jpath, sizeof(sp->f_mntonname));
525820a0de9SPawel Jakub Dawidek 	}
526f08df373SRobert Watson }
527f08df373SRobert Watson 
528800c9408SRobert Watson /*
529800c9408SRobert Watson  * Check with permission for a specific privilege is granted within jail.  We
530800c9408SRobert Watson  * have a specific list of accepted privileges; the rest are denied.
531800c9408SRobert Watson  */
532800c9408SRobert Watson int
533800c9408SRobert Watson prison_priv_check(struct ucred *cred, int priv)
534800c9408SRobert Watson {
535800c9408SRobert Watson 
536800c9408SRobert Watson 	if (!jailed(cred))
537800c9408SRobert Watson 		return (0);
538800c9408SRobert Watson 
539800c9408SRobert Watson 	switch (priv) {
540800c9408SRobert Watson 
541800c9408SRobert Watson 		/*
542800c9408SRobert Watson 		 * Allow ktrace privileges for root in jail.
543800c9408SRobert Watson 		 */
544800c9408SRobert Watson 	case PRIV_KTRACE:
545800c9408SRobert Watson 
546c3c1b5e6SRobert Watson #if 0
547800c9408SRobert Watson 		/*
548800c9408SRobert Watson 		 * Allow jailed processes to configure audit identity and
549800c9408SRobert Watson 		 * submit audit records (login, etc).  In the future we may
550800c9408SRobert Watson 		 * want to further refine the relationship between audit and
551800c9408SRobert Watson 		 * jail.
552800c9408SRobert Watson 		 */
553800c9408SRobert Watson 	case PRIV_AUDIT_GETAUDIT:
554800c9408SRobert Watson 	case PRIV_AUDIT_SETAUDIT:
555800c9408SRobert Watson 	case PRIV_AUDIT_SUBMIT:
556c3c1b5e6SRobert Watson #endif
557800c9408SRobert Watson 
558800c9408SRobert Watson 		/*
559800c9408SRobert Watson 		 * Allow jailed processes to manipulate process UNIX
560800c9408SRobert Watson 		 * credentials in any way they see fit.
561800c9408SRobert Watson 		 */
562800c9408SRobert Watson 	case PRIV_CRED_SETUID:
563800c9408SRobert Watson 	case PRIV_CRED_SETEUID:
564800c9408SRobert Watson 	case PRIV_CRED_SETGID:
565800c9408SRobert Watson 	case PRIV_CRED_SETEGID:
566800c9408SRobert Watson 	case PRIV_CRED_SETGROUPS:
567800c9408SRobert Watson 	case PRIV_CRED_SETREUID:
568800c9408SRobert Watson 	case PRIV_CRED_SETREGID:
569800c9408SRobert Watson 	case PRIV_CRED_SETRESUID:
570800c9408SRobert Watson 	case PRIV_CRED_SETRESGID:
571800c9408SRobert Watson 
572800c9408SRobert Watson 		/*
573800c9408SRobert Watson 		 * Jail implements visibility constraints already, so allow
574800c9408SRobert Watson 		 * jailed root to override uid/gid-based constraints.
575800c9408SRobert Watson 		 */
576800c9408SRobert Watson 	case PRIV_SEEOTHERGIDS:
577800c9408SRobert Watson 	case PRIV_SEEOTHERUIDS:
578800c9408SRobert Watson 
579800c9408SRobert Watson 		/*
580800c9408SRobert Watson 		 * Jail implements inter-process debugging limits already, so
581800c9408SRobert Watson 		 * allow jailed root various debugging privileges.
582800c9408SRobert Watson 		 */
583800c9408SRobert Watson 	case PRIV_DEBUG_DIFFCRED:
584800c9408SRobert Watson 	case PRIV_DEBUG_SUGID:
585800c9408SRobert Watson 	case PRIV_DEBUG_UNPRIV:
586800c9408SRobert Watson 
587800c9408SRobert Watson 		/*
588800c9408SRobert Watson 		 * Allow jail to set various resource limits and login
589800c9408SRobert Watson 		 * properties, and for now, exceed process resource limits.
590800c9408SRobert Watson 		 */
591800c9408SRobert Watson 	case PRIV_PROC_LIMIT:
592800c9408SRobert Watson 	case PRIV_PROC_SETLOGIN:
593800c9408SRobert Watson 	case PRIV_PROC_SETRLIMIT:
594800c9408SRobert Watson 
595800c9408SRobert Watson 		/*
596800c9408SRobert Watson 		 * System V and POSIX IPC privileges are granted in jail.
597800c9408SRobert Watson 		 */
598800c9408SRobert Watson 	case PRIV_IPC_READ:
599800c9408SRobert Watson 	case PRIV_IPC_WRITE:
600800c9408SRobert Watson 	case PRIV_IPC_ADMIN:
601800c9408SRobert Watson 	case PRIV_IPC_MSGSIZE:
602800c9408SRobert Watson 	case PRIV_MQ_ADMIN:
603800c9408SRobert Watson 
604800c9408SRobert Watson 		/*
605800c9408SRobert Watson 		 * Jail implements its own inter-process limits, so allow
606800c9408SRobert Watson 		 * root processes in jail to change scheduling on other
607800c9408SRobert Watson 		 * processes in the same jail.  Likewise for signalling.
608800c9408SRobert Watson 		 */
609800c9408SRobert Watson 	case PRIV_SCHED_DIFFCRED:
610800c9408SRobert Watson 	case PRIV_SIGNAL_DIFFCRED:
611800c9408SRobert Watson 	case PRIV_SIGNAL_SUGID:
612800c9408SRobert Watson 
613800c9408SRobert Watson 		/*
614800c9408SRobert Watson 		 * Allow jailed processes to write to sysctls marked as jail
615800c9408SRobert Watson 		 * writable.
616800c9408SRobert Watson 		 */
617800c9408SRobert Watson 	case PRIV_SYSCTL_WRITEJAIL:
618800c9408SRobert Watson 
619800c9408SRobert Watson 		/*
620800c9408SRobert Watson 		 * Allow root in jail to manage a variety of quota
621e82d0201SRobert Watson 		 * properties.  These should likely be conditional on a
622e82d0201SRobert Watson 		 * configuration option.
623800c9408SRobert Watson 		 */
62495b091d2SRobert Watson 	case PRIV_VFS_GETQUOTA:
62595b091d2SRobert Watson 	case PRIV_VFS_SETQUOTA:
626800c9408SRobert Watson 
627800c9408SRobert Watson 		/*
628800c9408SRobert Watson 		 * Since Jail relies on chroot() to implement file system
629800c9408SRobert Watson 		 * protections, grant many VFS privileges to root in jail.
630800c9408SRobert Watson 		 * Be careful to exclude mount-related and NFS-related
631800c9408SRobert Watson 		 * privileges.
632800c9408SRobert Watson 		 */
633800c9408SRobert Watson 	case PRIV_VFS_READ:
634800c9408SRobert Watson 	case PRIV_VFS_WRITE:
635800c9408SRobert Watson 	case PRIV_VFS_ADMIN:
636800c9408SRobert Watson 	case PRIV_VFS_EXEC:
637800c9408SRobert Watson 	case PRIV_VFS_LOOKUP:
638800c9408SRobert Watson 	case PRIV_VFS_BLOCKRESERVE:	/* XXXRW: Slightly surprising. */
639800c9408SRobert Watson 	case PRIV_VFS_CHFLAGS_DEV:
640800c9408SRobert Watson 	case PRIV_VFS_CHOWN:
641800c9408SRobert Watson 	case PRIV_VFS_CHROOT:
642bb531912SPawel Jakub Dawidek 	case PRIV_VFS_RETAINSUGID:
643800c9408SRobert Watson 	case PRIV_VFS_FCHROOT:
644800c9408SRobert Watson 	case PRIV_VFS_LINK:
645800c9408SRobert Watson 	case PRIV_VFS_SETGID:
646800c9408SRobert Watson 	case PRIV_VFS_STICKYFILE:
647800c9408SRobert Watson 		return (0);
648800c9408SRobert Watson 
649800c9408SRobert Watson 		/*
650800c9408SRobert Watson 		 * Depending on the global setting, allow privilege of
651800c9408SRobert Watson 		 * setting system flags.
652800c9408SRobert Watson 		 */
653800c9408SRobert Watson 	case PRIV_VFS_SYSFLAGS:
654800c9408SRobert Watson 		if (jail_chflags_allowed)
655800c9408SRobert Watson 			return (0);
656800c9408SRobert Watson 		else
657800c9408SRobert Watson 			return (EPERM);
658800c9408SRobert Watson 
659800c9408SRobert Watson 		/*
660f3a8d2f9SPawel Jakub Dawidek 		 * Depending on the global setting, allow privilege of
661f3a8d2f9SPawel Jakub Dawidek 		 * mounting/unmounting file systems.
662f3a8d2f9SPawel Jakub Dawidek 		 */
663f3a8d2f9SPawel Jakub Dawidek 	case PRIV_VFS_MOUNT:
664f3a8d2f9SPawel Jakub Dawidek 	case PRIV_VFS_UNMOUNT:
665f3a8d2f9SPawel Jakub Dawidek 	case PRIV_VFS_MOUNT_NONUSER:
666f3a8d2f9SPawel Jakub Dawidek 		if (jail_mount_allowed)
667f3a8d2f9SPawel Jakub Dawidek 			return (0);
668f3a8d2f9SPawel Jakub Dawidek 		else
669f3a8d2f9SPawel Jakub Dawidek 			return (EPERM);
670f3a8d2f9SPawel Jakub Dawidek 
671f3a8d2f9SPawel Jakub Dawidek 		/*
672800c9408SRobert Watson 		 * Allow jailed root to bind reserved ports.
673800c9408SRobert Watson 		 */
674800c9408SRobert Watson 	case PRIV_NETINET_RESERVEDPORT:
675800c9408SRobert Watson 		return (0);
676800c9408SRobert Watson 
677800c9408SRobert Watson 		/*
678800c9408SRobert Watson 		 * Conditionally allow creating raw sockets in jail.
679800c9408SRobert Watson 		 */
680800c9408SRobert Watson 	case PRIV_NETINET_RAW:
681800c9408SRobert Watson 		if (jail_allow_raw_sockets)
682800c9408SRobert Watson 			return (0);
683800c9408SRobert Watson 		else
684800c9408SRobert Watson 			return (EPERM);
685800c9408SRobert Watson 
686800c9408SRobert Watson 		/*
687800c9408SRobert Watson 		 * Since jail implements its own visibility limits on netstat
688800c9408SRobert Watson 		 * sysctls, allow getcred.  This allows identd to work in
689800c9408SRobert Watson 		 * jail.
690800c9408SRobert Watson 		 */
691800c9408SRobert Watson 	case PRIV_NETINET_GETCRED:
692800c9408SRobert Watson 		return (0);
693800c9408SRobert Watson 
694800c9408SRobert Watson 	default:
695800c9408SRobert Watson 		/*
696800c9408SRobert Watson 		 * In all remaining cases, deny the privilege request.  This
697800c9408SRobert Watson 		 * includes almost all network privileges, many system
698800c9408SRobert Watson 		 * configuration privileges.
699800c9408SRobert Watson 		 */
700800c9408SRobert Watson 		return (EPERM);
701800c9408SRobert Watson 	}
702800c9408SRobert Watson }
703800c9408SRobert Watson 
704fd7a8150SMike Barcroft static int
705fd7a8150SMike Barcroft sysctl_jail_list(SYSCTL_HANDLER_ARGS)
706fd7a8150SMike Barcroft {
707fd7a8150SMike Barcroft 	struct xprison *xp, *sxp;
708fd7a8150SMike Barcroft 	struct prison *pr;
709fd7a8150SMike Barcroft 	int count, error;
710fd7a8150SMike Barcroft 
7117f4704c0SPawel Jakub Dawidek 	if (jailed(req->td->td_ucred))
712679a1060SRobert Watson 		return (0);
713fd7a8150SMike Barcroft retry:
714fd7a8150SMike Barcroft 	mtx_lock(&allprison_mtx);
715fd7a8150SMike Barcroft 	count = prisoncount;
716fd7a8150SMike Barcroft 	mtx_unlock(&allprison_mtx);
717fd7a8150SMike Barcroft 
718fd7a8150SMike Barcroft 	if (count == 0)
719fd7a8150SMike Barcroft 		return (0);
720fd7a8150SMike Barcroft 
721fd7a8150SMike Barcroft 	sxp = xp = malloc(sizeof(*xp) * count, M_TEMP, M_WAITOK | M_ZERO);
722fd7a8150SMike Barcroft 	mtx_lock(&allprison_mtx);
723fd7a8150SMike Barcroft 	if (count != prisoncount) {
724fd7a8150SMike Barcroft 		mtx_unlock(&allprison_mtx);
725fd7a8150SMike Barcroft 		free(sxp, M_TEMP);
726fd7a8150SMike Barcroft 		goto retry;
727fd7a8150SMike Barcroft 	}
728fd7a8150SMike Barcroft 
729fd7a8150SMike Barcroft 	LIST_FOREACH(pr, &allprison, pr_list) {
730fd7a8150SMike Barcroft 		mtx_lock(&pr->pr_mtx);
731fd7a8150SMike Barcroft 		xp->pr_version = XPRISON_VERSION;
732fd7a8150SMike Barcroft 		xp->pr_id = pr->pr_id;
733fd7a8150SMike Barcroft 		strlcpy(xp->pr_path, pr->pr_path, sizeof(xp->pr_path));
734fd7a8150SMike Barcroft 		strlcpy(xp->pr_host, pr->pr_host, sizeof(xp->pr_host));
735fd7a8150SMike Barcroft 		xp->pr_ip = pr->pr_ip;
736fd7a8150SMike Barcroft 		mtx_unlock(&pr->pr_mtx);
737fd7a8150SMike Barcroft 		xp++;
738fd7a8150SMike Barcroft 	}
739fd7a8150SMike Barcroft 	mtx_unlock(&allprison_mtx);
740fd7a8150SMike Barcroft 
741fd7a8150SMike Barcroft 	error = SYSCTL_OUT(req, sxp, sizeof(*sxp) * count);
742fd7a8150SMike Barcroft 	free(sxp, M_TEMP);
743fd7a8150SMike Barcroft 	return (error);
744fd7a8150SMike Barcroft }
745fd7a8150SMike Barcroft 
746fd7a8150SMike Barcroft SYSCTL_OID(_security_jail, OID_AUTO, list, CTLTYPE_STRUCT | CTLFLAG_RD,
747fd7a8150SMike Barcroft     NULL, 0, sysctl_jail_list, "S", "List of active jails");
748461167c2SPawel Jakub Dawidek 
749461167c2SPawel Jakub Dawidek static int
750461167c2SPawel Jakub Dawidek sysctl_jail_jailed(SYSCTL_HANDLER_ARGS)
751461167c2SPawel Jakub Dawidek {
752461167c2SPawel Jakub Dawidek 	int error, injail;
753461167c2SPawel Jakub Dawidek 
754461167c2SPawel Jakub Dawidek 	injail = jailed(req->td->td_ucred);
755461167c2SPawel Jakub Dawidek 	error = SYSCTL_OUT(req, &injail, sizeof(injail));
756461167c2SPawel Jakub Dawidek 
757461167c2SPawel Jakub Dawidek 	return (error);
758461167c2SPawel Jakub Dawidek }
759461167c2SPawel Jakub Dawidek SYSCTL_PROC(_security_jail, OID_AUTO, jailed, CTLTYPE_INT | CTLFLAG_RD,
760461167c2SPawel Jakub Dawidek     NULL, 0, sysctl_jail_jailed, "I", "Process in jail?");
761