kern_jail.c revision 185029
1/*-
2 * ----------------------------------------------------------------------------
3 * "THE BEER-WARE LICENSE" (Revision 42):
4 * <phk@FreeBSD.ORG> wrote this file.  As long as you retain this notice you
5 * can do whatever you want with this stuff. If we meet some day, and you think
6 * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
7 * ----------------------------------------------------------------------------
8 */
9
10#include <sys/cdefs.h>
11__FBSDID("$FreeBSD: head/sys/kern/kern_jail.c 185029 2008-11-17 20:49:29Z pjd $");
12
13#include "opt_mac.h"
14
15#include <sys/param.h>
16#include <sys/types.h>
17#include <sys/kernel.h>
18#include <sys/systm.h>
19#include <sys/errno.h>
20#include <sys/sysproto.h>
21#include <sys/malloc.h>
22#include <sys/priv.h>
23#include <sys/proc.h>
24#include <sys/taskqueue.h>
25#include <sys/fcntl.h>
26#include <sys/jail.h>
27#include <sys/lock.h>
28#include <sys/mutex.h>
29#include <sys/sx.h>
30#include <sys/namei.h>
31#include <sys/mount.h>
32#include <sys/queue.h>
33#include <sys/socket.h>
34#include <sys/syscallsubr.h>
35#include <sys/sysctl.h>
36#include <sys/vnode.h>
37#include <sys/vimage.h>
38#include <sys/osd.h>
39#include <net/if.h>
40#include <netinet/in.h>
41
42#include <security/mac/mac_framework.h>
43
44MALLOC_DEFINE(M_PRISON, "prison", "Prison structures");
45
46SYSCTL_NODE(_security, OID_AUTO, jail, CTLFLAG_RW, 0,
47    "Jail rules");
48
49int	jail_set_hostname_allowed = 1;
50SYSCTL_INT(_security_jail, OID_AUTO, set_hostname_allowed, CTLFLAG_RW,
51    &jail_set_hostname_allowed, 0,
52    "Processes in jail can set their hostnames");
53
54int	jail_socket_unixiproute_only = 1;
55SYSCTL_INT(_security_jail, OID_AUTO, socket_unixiproute_only, CTLFLAG_RW,
56    &jail_socket_unixiproute_only, 0,
57    "Processes in jail are limited to creating UNIX/IPv4/route sockets only");
58
59int	jail_sysvipc_allowed = 0;
60SYSCTL_INT(_security_jail, OID_AUTO, sysvipc_allowed, CTLFLAG_RW,
61    &jail_sysvipc_allowed, 0,
62    "Processes in jail can use System V IPC primitives");
63
64static int jail_enforce_statfs = 2;
65SYSCTL_INT(_security_jail, OID_AUTO, enforce_statfs, CTLFLAG_RW,
66    &jail_enforce_statfs, 0,
67    "Processes in jail cannot see all mounted file systems");
68
69int	jail_allow_raw_sockets = 0;
70SYSCTL_INT(_security_jail, OID_AUTO, allow_raw_sockets, CTLFLAG_RW,
71    &jail_allow_raw_sockets, 0,
72    "Prison root can create raw sockets");
73
74int	jail_chflags_allowed = 0;
75SYSCTL_INT(_security_jail, OID_AUTO, chflags_allowed, CTLFLAG_RW,
76    &jail_chflags_allowed, 0,
77    "Processes in jail can alter system file flags");
78
79int	jail_mount_allowed = 0;
80SYSCTL_INT(_security_jail, OID_AUTO, mount_allowed, CTLFLAG_RW,
81    &jail_mount_allowed, 0,
82    "Processes in jail can mount/unmount jail-friendly file systems");
83
84/* allprison, lastprid, and prisoncount are protected by allprison_lock. */
85struct	prisonlist allprison;
86struct	sx allprison_lock;
87int	lastprid = 0;
88int	prisoncount = 0;
89
90static void		 init_prison(void *);
91static void		 prison_complete(void *context, int pending);
92static int		 sysctl_jail_list(SYSCTL_HANDLER_ARGS);
93
94static void
95init_prison(void *data __unused)
96{
97
98	sx_init(&allprison_lock, "allprison");
99	LIST_INIT(&allprison);
100}
101
102SYSINIT(prison, SI_SUB_INTRINSIC, SI_ORDER_ANY, init_prison, NULL);
103
104/*
105 * struct jail_args {
106 *	struct jail *jail;
107 * };
108 */
109int
110jail(struct thread *td, struct jail_args *uap)
111{
112	struct nameidata nd;
113	struct prison *pr, *tpr;
114	struct jail j;
115	struct jail_attach_args jaa;
116	int vfslocked, error, tryprid;
117
118	error = copyin(uap->jail, &j, sizeof(j));
119	if (error)
120		return (error);
121	if (j.version != 0)
122		return (EINVAL);
123
124	pr = malloc(sizeof(*pr), M_PRISON, M_WAITOK | M_ZERO);
125	mtx_init(&pr->pr_mtx, "jail mutex", NULL, MTX_DEF);
126	pr->pr_ref = 1;
127	error = copyinstr(j.path, &pr->pr_path, sizeof(pr->pr_path), 0);
128	if (error)
129		goto e_killmtx;
130	NDINIT(&nd, LOOKUP, MPSAFE | FOLLOW | LOCKLEAF, UIO_SYSSPACE,
131	    pr->pr_path, td);
132	error = namei(&nd);
133	if (error)
134		goto e_killmtx;
135	vfslocked = NDHASGIANT(&nd);
136	pr->pr_root = nd.ni_vp;
137	VOP_UNLOCK(nd.ni_vp, 0);
138	NDFREE(&nd, NDF_ONLY_PNBUF);
139	VFS_UNLOCK_GIANT(vfslocked);
140	error = copyinstr(j.hostname, &pr->pr_host, sizeof(pr->pr_host), 0);
141	if (error)
142		goto e_dropvnref;
143	pr->pr_ip = j.ip_number;
144	pr->pr_linux = NULL;
145	pr->pr_securelevel = securelevel;
146	bzero(&pr->pr_osd, sizeof(pr->pr_osd));
147
148	/* Determine next pr_id and add prison to allprison list. */
149	sx_xlock(&allprison_lock);
150	tryprid = lastprid + 1;
151	if (tryprid == JAIL_MAX)
152		tryprid = 1;
153next:
154	LIST_FOREACH(tpr, &allprison, pr_list) {
155		if (tpr->pr_id == tryprid) {
156			tryprid++;
157			if (tryprid == JAIL_MAX) {
158				sx_xunlock(&allprison_lock);
159				error = EAGAIN;
160				goto e_dropvnref;
161			}
162			goto next;
163		}
164	}
165	pr->pr_id = jaa.jid = lastprid = tryprid;
166	LIST_INSERT_HEAD(&allprison, pr, pr_list);
167	prisoncount++;
168	sx_xunlock(&allprison_lock);
169
170	error = jail_attach(td, &jaa);
171	if (error)
172		goto e_dropprref;
173	mtx_lock(&pr->pr_mtx);
174	pr->pr_ref--;
175	mtx_unlock(&pr->pr_mtx);
176	td->td_retval[0] = jaa.jid;
177	return (0);
178e_dropprref:
179	sx_xlock(&allprison_lock);
180	LIST_REMOVE(pr, pr_list);
181	prisoncount--;
182	sx_xunlock(&allprison_lock);
183e_dropvnref:
184	vfslocked = VFS_LOCK_GIANT(pr->pr_root->v_mount);
185	vrele(pr->pr_root);
186	VFS_UNLOCK_GIANT(vfslocked);
187e_killmtx:
188	mtx_destroy(&pr->pr_mtx);
189	free(pr, M_PRISON);
190	return (error);
191}
192
193/*
194 * struct jail_attach_args {
195 *	int jid;
196 * };
197 */
198int
199jail_attach(struct thread *td, struct jail_attach_args *uap)
200{
201	struct proc *p;
202	struct ucred *newcred, *oldcred;
203	struct prison *pr;
204	int vfslocked, error;
205
206	/*
207	 * XXX: Note that there is a slight race here if two threads
208	 * in the same privileged process attempt to attach to two
209	 * different jails at the same time.  It is important for
210	 * user processes not to do this, or they might end up with
211	 * a process root from one prison, but attached to the jail
212	 * of another.
213	 */
214	error = priv_check(td, PRIV_JAIL_ATTACH);
215	if (error)
216		return (error);
217
218	p = td->td_proc;
219	sx_slock(&allprison_lock);
220	pr = prison_find(uap->jid);
221	if (pr == NULL) {
222		sx_sunlock(&allprison_lock);
223		return (EINVAL);
224	}
225	pr->pr_ref++;
226	mtx_unlock(&pr->pr_mtx);
227	sx_sunlock(&allprison_lock);
228
229	vfslocked = VFS_LOCK_GIANT(pr->pr_root->v_mount);
230	vn_lock(pr->pr_root, LK_EXCLUSIVE | LK_RETRY);
231	if ((error = change_dir(pr->pr_root, td)) != 0)
232		goto e_unlock;
233#ifdef MAC
234	if ((error = mac_vnode_check_chroot(td->td_ucred, pr->pr_root)))
235		goto e_unlock;
236#endif
237	VOP_UNLOCK(pr->pr_root, 0);
238	change_root(pr->pr_root, td);
239	VFS_UNLOCK_GIANT(vfslocked);
240
241	newcred = crget();
242	PROC_LOCK(p);
243	oldcred = p->p_ucred;
244	setsugid(p);
245	crcopy(newcred, oldcred);
246	newcred->cr_prison = pr;
247	p->p_ucred = newcred;
248	PROC_UNLOCK(p);
249	crfree(oldcred);
250	return (0);
251e_unlock:
252	VOP_UNLOCK(pr->pr_root, 0);
253	VFS_UNLOCK_GIANT(vfslocked);
254	mtx_lock(&pr->pr_mtx);
255	pr->pr_ref--;
256	mtx_unlock(&pr->pr_mtx);
257	return (error);
258}
259
260/*
261 * Returns a locked prison instance, or NULL on failure.
262 */
263struct prison *
264prison_find(int prid)
265{
266	struct prison *pr;
267
268	sx_assert(&allprison_lock, SX_LOCKED);
269	LIST_FOREACH(pr, &allprison, pr_list) {
270		if (pr->pr_id == prid) {
271			mtx_lock(&pr->pr_mtx);
272			if (pr->pr_ref == 0) {
273				mtx_unlock(&pr->pr_mtx);
274				break;
275			}
276			return (pr);
277		}
278	}
279	return (NULL);
280}
281
282void
283prison_free_locked(struct prison *pr)
284{
285
286	mtx_assert(&pr->pr_mtx, MA_OWNED);
287	pr->pr_ref--;
288	if (pr->pr_ref == 0) {
289		mtx_unlock(&pr->pr_mtx);
290		TASK_INIT(&pr->pr_task, 0, prison_complete, pr);
291		taskqueue_enqueue(taskqueue_thread, &pr->pr_task);
292		return;
293	}
294	mtx_unlock(&pr->pr_mtx);
295}
296
297void
298prison_free(struct prison *pr)
299{
300
301	mtx_lock(&pr->pr_mtx);
302	prison_free_locked(pr);
303}
304
305static void
306prison_complete(void *context, int pending)
307{
308	struct prison *pr;
309	int vfslocked;
310
311	pr = (struct prison *)context;
312
313	sx_xlock(&allprison_lock);
314	LIST_REMOVE(pr, pr_list);
315	prisoncount--;
316	sx_xunlock(&allprison_lock);
317
318	/* Free all OSD associated to this jail. */
319	osd_jail_exit(pr);
320
321	vfslocked = VFS_LOCK_GIANT(pr->pr_root->v_mount);
322	vrele(pr->pr_root);
323	VFS_UNLOCK_GIANT(vfslocked);
324
325	mtx_destroy(&pr->pr_mtx);
326	if (pr->pr_linux != NULL)
327		free(pr->pr_linux, M_PRISON);
328	free(pr, M_PRISON);
329}
330
331void
332prison_hold_locked(struct prison *pr)
333{
334
335	mtx_assert(&pr->pr_mtx, MA_OWNED);
336	KASSERT(pr->pr_ref > 0,
337	    ("Trying to hold dead prison (id=%d).", pr->pr_id));
338	pr->pr_ref++;
339}
340
341void
342prison_hold(struct prison *pr)
343{
344
345	mtx_lock(&pr->pr_mtx);
346	prison_hold_locked(pr);
347	mtx_unlock(&pr->pr_mtx);
348}
349
350u_int32_t
351prison_getip(struct ucred *cred)
352{
353
354	return (cred->cr_prison->pr_ip);
355}
356
357int
358prison_ip(struct ucred *cred, int flag, u_int32_t *ip)
359{
360	u_int32_t tmp;
361
362	if (!jailed(cred))
363		return (0);
364	if (flag)
365		tmp = *ip;
366	else
367		tmp = ntohl(*ip);
368	if (tmp == INADDR_ANY) {
369		if (flag)
370			*ip = cred->cr_prison->pr_ip;
371		else
372			*ip = htonl(cred->cr_prison->pr_ip);
373		return (0);
374	}
375	if (tmp == INADDR_LOOPBACK) {
376		if (flag)
377			*ip = cred->cr_prison->pr_ip;
378		else
379			*ip = htonl(cred->cr_prison->pr_ip);
380		return (0);
381	}
382	if (cred->cr_prison->pr_ip != tmp)
383		return (1);
384	return (0);
385}
386
387void
388prison_remote_ip(struct ucred *cred, int flag, u_int32_t *ip)
389{
390	u_int32_t tmp;
391
392	if (!jailed(cred))
393		return;
394	if (flag)
395		tmp = *ip;
396	else
397		tmp = ntohl(*ip);
398	if (tmp == INADDR_LOOPBACK) {
399		if (flag)
400			*ip = cred->cr_prison->pr_ip;
401		else
402			*ip = htonl(cred->cr_prison->pr_ip);
403		return;
404	}
405	return;
406}
407
408int
409prison_if(struct ucred *cred, struct sockaddr *sa)
410{
411	struct sockaddr_in *sai;
412	int ok;
413
414	sai = (struct sockaddr_in *)sa;
415	if ((sai->sin_family != AF_INET) && jail_socket_unixiproute_only)
416		ok = 1;
417	else if (sai->sin_family != AF_INET)
418		ok = 0;
419	else if (cred->cr_prison->pr_ip != ntohl(sai->sin_addr.s_addr))
420		ok = 1;
421	else
422		ok = 0;
423	return (ok);
424}
425
426/*
427 * Return 0 if jails permit p1 to frob p2, otherwise ESRCH.
428 */
429int
430prison_check(struct ucred *cred1, struct ucred *cred2)
431{
432
433	if (jailed(cred1)) {
434		if (!jailed(cred2))
435			return (ESRCH);
436		if (cred2->cr_prison != cred1->cr_prison)
437			return (ESRCH);
438	}
439
440	return (0);
441}
442
443/*
444 * Return 1 if the passed credential is in a jail, otherwise 0.
445 */
446int
447jailed(struct ucred *cred)
448{
449
450	return (cred->cr_prison != NULL);
451}
452
453/*
454 * Return the correct hostname for the passed credential.
455 */
456void
457getcredhostname(struct ucred *cred, char *buf, size_t size)
458{
459	INIT_VPROCG(cred->cr_vimage->v_procg);
460
461	if (jailed(cred)) {
462		mtx_lock(&cred->cr_prison->pr_mtx);
463		strlcpy(buf, cred->cr_prison->pr_host, size);
464		mtx_unlock(&cred->cr_prison->pr_mtx);
465	} else {
466		mtx_lock(&hostname_mtx);
467		strlcpy(buf, V_hostname, size);
468		mtx_unlock(&hostname_mtx);
469	}
470}
471
472/*
473 * Determine whether the subject represented by cred can "see"
474 * status of a mount point.
475 * Returns: 0 for permitted, ENOENT otherwise.
476 * XXX: This function should be called cr_canseemount() and should be
477 *      placed in kern_prot.c.
478 */
479int
480prison_canseemount(struct ucred *cred, struct mount *mp)
481{
482	struct prison *pr;
483	struct statfs *sp;
484	size_t len;
485
486	if (!jailed(cred) || jail_enforce_statfs == 0)
487		return (0);
488	pr = cred->cr_prison;
489	if (pr->pr_root->v_mount == mp)
490		return (0);
491	if (jail_enforce_statfs == 2)
492		return (ENOENT);
493	/*
494	 * If jail's chroot directory is set to "/" we should be able to see
495	 * all mount-points from inside a jail.
496	 * This is ugly check, but this is the only situation when jail's
497	 * directory ends with '/'.
498	 */
499	if (strcmp(pr->pr_path, "/") == 0)
500		return (0);
501	len = strlen(pr->pr_path);
502	sp = &mp->mnt_stat;
503	if (strncmp(pr->pr_path, sp->f_mntonname, len) != 0)
504		return (ENOENT);
505	/*
506	 * Be sure that we don't have situation where jail's root directory
507	 * is "/some/path" and mount point is "/some/pathpath".
508	 */
509	if (sp->f_mntonname[len] != '\0' && sp->f_mntonname[len] != '/')
510		return (ENOENT);
511	return (0);
512}
513
514void
515prison_enforce_statfs(struct ucred *cred, struct mount *mp, struct statfs *sp)
516{
517	char jpath[MAXPATHLEN];
518	struct prison *pr;
519	size_t len;
520
521	if (!jailed(cred) || jail_enforce_statfs == 0)
522		return;
523	pr = cred->cr_prison;
524	if (prison_canseemount(cred, mp) != 0) {
525		bzero(sp->f_mntonname, sizeof(sp->f_mntonname));
526		strlcpy(sp->f_mntonname, "[restricted]",
527		    sizeof(sp->f_mntonname));
528		return;
529	}
530	if (pr->pr_root->v_mount == mp) {
531		/*
532		 * Clear current buffer data, so we are sure nothing from
533		 * the valid path left there.
534		 */
535		bzero(sp->f_mntonname, sizeof(sp->f_mntonname));
536		*sp->f_mntonname = '/';
537		return;
538	}
539	/*
540	 * If jail's chroot directory is set to "/" we should be able to see
541	 * all mount-points from inside a jail.
542	 */
543	if (strcmp(pr->pr_path, "/") == 0)
544		return;
545	len = strlen(pr->pr_path);
546	strlcpy(jpath, sp->f_mntonname + len, sizeof(jpath));
547	/*
548	 * Clear current buffer data, so we are sure nothing from
549	 * the valid path left there.
550	 */
551	bzero(sp->f_mntonname, sizeof(sp->f_mntonname));
552	if (*jpath == '\0') {
553		/* Should never happen. */
554		*sp->f_mntonname = '/';
555	} else {
556		strlcpy(sp->f_mntonname, jpath, sizeof(sp->f_mntonname));
557	}
558}
559
560/*
561 * Check with permission for a specific privilege is granted within jail.  We
562 * have a specific list of accepted privileges; the rest are denied.
563 */
564int
565prison_priv_check(struct ucred *cred, int priv)
566{
567
568	if (!jailed(cred))
569		return (0);
570
571	switch (priv) {
572
573		/*
574		 * Allow ktrace privileges for root in jail.
575		 */
576	case PRIV_KTRACE:
577
578#if 0
579		/*
580		 * Allow jailed processes to configure audit identity and
581		 * submit audit records (login, etc).  In the future we may
582		 * want to further refine the relationship between audit and
583		 * jail.
584		 */
585	case PRIV_AUDIT_GETAUDIT:
586	case PRIV_AUDIT_SETAUDIT:
587	case PRIV_AUDIT_SUBMIT:
588#endif
589
590		/*
591		 * Allow jailed processes to manipulate process UNIX
592		 * credentials in any way they see fit.
593		 */
594	case PRIV_CRED_SETUID:
595	case PRIV_CRED_SETEUID:
596	case PRIV_CRED_SETGID:
597	case PRIV_CRED_SETEGID:
598	case PRIV_CRED_SETGROUPS:
599	case PRIV_CRED_SETREUID:
600	case PRIV_CRED_SETREGID:
601	case PRIV_CRED_SETRESUID:
602	case PRIV_CRED_SETRESGID:
603
604		/*
605		 * Jail implements visibility constraints already, so allow
606		 * jailed root to override uid/gid-based constraints.
607		 */
608	case PRIV_SEEOTHERGIDS:
609	case PRIV_SEEOTHERUIDS:
610
611		/*
612		 * Jail implements inter-process debugging limits already, so
613		 * allow jailed root various debugging privileges.
614		 */
615	case PRIV_DEBUG_DIFFCRED:
616	case PRIV_DEBUG_SUGID:
617	case PRIV_DEBUG_UNPRIV:
618
619		/*
620		 * Allow jail to set various resource limits and login
621		 * properties, and for now, exceed process resource limits.
622		 */
623	case PRIV_PROC_LIMIT:
624	case PRIV_PROC_SETLOGIN:
625	case PRIV_PROC_SETRLIMIT:
626
627		/*
628		 * System V and POSIX IPC privileges are granted in jail.
629		 */
630	case PRIV_IPC_READ:
631	case PRIV_IPC_WRITE:
632	case PRIV_IPC_ADMIN:
633	case PRIV_IPC_MSGSIZE:
634	case PRIV_MQ_ADMIN:
635
636		/*
637		 * Jail implements its own inter-process limits, so allow
638		 * root processes in jail to change scheduling on other
639		 * processes in the same jail.  Likewise for signalling.
640		 */
641	case PRIV_SCHED_DIFFCRED:
642	case PRIV_SIGNAL_DIFFCRED:
643	case PRIV_SIGNAL_SUGID:
644
645		/*
646		 * Allow jailed processes to write to sysctls marked as jail
647		 * writable.
648		 */
649	case PRIV_SYSCTL_WRITEJAIL:
650
651		/*
652		 * Allow root in jail to manage a variety of quota
653		 * properties.  These should likely be conditional on a
654		 * configuration option.
655		 */
656	case PRIV_VFS_GETQUOTA:
657	case PRIV_VFS_SETQUOTA:
658
659		/*
660		 * Since Jail relies on chroot() to implement file system
661		 * protections, grant many VFS privileges to root in jail.
662		 * Be careful to exclude mount-related and NFS-related
663		 * privileges.
664		 */
665	case PRIV_VFS_READ:
666	case PRIV_VFS_WRITE:
667	case PRIV_VFS_ADMIN:
668	case PRIV_VFS_EXEC:
669	case PRIV_VFS_LOOKUP:
670	case PRIV_VFS_BLOCKRESERVE:	/* XXXRW: Slightly surprising. */
671	case PRIV_VFS_CHFLAGS_DEV:
672	case PRIV_VFS_CHOWN:
673	case PRIV_VFS_CHROOT:
674	case PRIV_VFS_RETAINSUGID:
675	case PRIV_VFS_FCHROOT:
676	case PRIV_VFS_LINK:
677	case PRIV_VFS_SETGID:
678	case PRIV_VFS_STAT:
679	case PRIV_VFS_STICKYFILE:
680		return (0);
681
682		/*
683		 * Depending on the global setting, allow privilege of
684		 * setting system flags.
685		 */
686	case PRIV_VFS_SYSFLAGS:
687		if (jail_chflags_allowed)
688			return (0);
689		else
690			return (EPERM);
691
692		/*
693		 * Depending on the global setting, allow privilege of
694		 * mounting/unmounting file systems.
695		 */
696	case PRIV_VFS_MOUNT:
697	case PRIV_VFS_UNMOUNT:
698	case PRIV_VFS_MOUNT_NONUSER:
699	case PRIV_VFS_MOUNT_OWNER:
700		if (jail_mount_allowed)
701			return (0);
702		else
703			return (EPERM);
704
705		/*
706		 * Allow jailed root to bind reserved ports and reuse in-use
707		 * ports.
708		 */
709	case PRIV_NETINET_RESERVEDPORT:
710	case PRIV_NETINET_REUSEPORT:
711		return (0);
712
713		/*
714		 * Allow jailed root to set certian IPv4/6 (option) headers.
715		 */
716	case PRIV_NETINET_SETHDROPTS:
717		return (0);
718
719		/*
720		 * Conditionally allow creating raw sockets in jail.
721		 */
722	case PRIV_NETINET_RAW:
723		if (jail_allow_raw_sockets)
724			return (0);
725		else
726			return (EPERM);
727
728		/*
729		 * Since jail implements its own visibility limits on netstat
730		 * sysctls, allow getcred.  This allows identd to work in
731		 * jail.
732		 */
733	case PRIV_NETINET_GETCRED:
734		return (0);
735
736	default:
737		/*
738		 * In all remaining cases, deny the privilege request.  This
739		 * includes almost all network privileges, many system
740		 * configuration privileges.
741		 */
742		return (EPERM);
743	}
744}
745
746static int
747sysctl_jail_list(SYSCTL_HANDLER_ARGS)
748{
749	struct xprison *xp, *sxp;
750	struct prison *pr;
751	int count, error;
752
753	if (jailed(req->td->td_ucred))
754		return (0);
755
756	sx_slock(&allprison_lock);
757	if ((count = prisoncount) == 0) {
758		sx_sunlock(&allprison_lock);
759		return (0);
760	}
761
762	sxp = xp = malloc(sizeof(*xp) * count, M_TEMP, M_WAITOK | M_ZERO);
763
764	LIST_FOREACH(pr, &allprison, pr_list) {
765		xp->pr_version = XPRISON_VERSION;
766		xp->pr_id = pr->pr_id;
767		xp->pr_ip = pr->pr_ip;
768		strlcpy(xp->pr_path, pr->pr_path, sizeof(xp->pr_path));
769		mtx_lock(&pr->pr_mtx);
770		strlcpy(xp->pr_host, pr->pr_host, sizeof(xp->pr_host));
771		mtx_unlock(&pr->pr_mtx);
772		xp++;
773	}
774	sx_sunlock(&allprison_lock);
775
776	error = SYSCTL_OUT(req, sxp, sizeof(*sxp) * count);
777	free(sxp, M_TEMP);
778	return (error);
779}
780
781SYSCTL_OID(_security_jail, OID_AUTO, list, CTLTYPE_STRUCT | CTLFLAG_RD,
782    NULL, 0, sysctl_jail_list, "S", "List of active jails");
783
784static int
785sysctl_jail_jailed(SYSCTL_HANDLER_ARGS)
786{
787	int error, injail;
788
789	injail = jailed(req->td->td_ucred);
790	error = SYSCTL_OUT(req, &injail, sizeof(injail));
791
792	return (error);
793}
794SYSCTL_PROC(_security_jail, OID_AUTO, jailed, CTLTYPE_INT | CTLFLAG_RD,
795    NULL, 0, sysctl_jail_jailed, "I", "Process in jail?");
796