xref: /dflybsd-src/sys/kern/kern_jail.c (revision 90ea502b8c5d21f908cedff6680ee2bc9e74ce74)
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 /*-
11  * Copyright (c) 2006 Victor Balada Diaz <victor@bsdes.net>
12  * All rights reserved.
13  *
14  * Redistribution and use in source and binary forms, with or without
15  * modification, are permitted provided that the following conditions
16  * are met:
17  * 1. Redistributions of source code must retain the above copyright
18  *    notice, this list of conditions and the following disclaimer.
19  * 2. Redistributions in binary form must reproduce the above copyright
20  *    notice, this list of conditions and the following disclaimer in the
21  *    documentation and/or other materials provided with the distribution.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  */
35 
36 
37 /*
38  * $FreeBSD: src/sys/kern/kern_jail.c,v 1.6.2.3 2001/08/17 01:00:26 rwatson Exp $
39  * $DragonFly: src/sys/kern/kern_jail.c,v 1.19 2008/05/17 18:20:33 dillon Exp $
40  */
41 
42 #include "opt_inet6.h"
43 
44 #include <sys/param.h>
45 #include <sys/types.h>
46 #include <sys/kernel.h>
47 #include <sys/systm.h>
48 #include <sys/errno.h>
49 #include <sys/sysproto.h>
50 #include <sys/malloc.h>
51 #include <sys/nlookup.h>
52 #include <sys/namecache.h>
53 #include <sys/proc.h>
54 #include <sys/priv.h>
55 #include <sys/jail.h>
56 #include <sys/socket.h>
57 #include <sys/sysctl.h>
58 #include <sys/kern_syscall.h>
59 #include <net/if.h>
60 #include <netinet/in.h>
61 #include <netinet6/in6_var.h>
62 
63 static struct prison	*prison_find(int);
64 static void		prison_ipcache_init(struct prison *);
65 
66 MALLOC_DEFINE(M_PRISON, "prison", "Prison structures");
67 
68 SYSCTL_NODE(, OID_AUTO, jail, CTLFLAG_RW, 0,
69     "Jail rules");
70 
71 int	jail_set_hostname_allowed = 1;
72 SYSCTL_INT(_jail, OID_AUTO, set_hostname_allowed, CTLFLAG_RW,
73     &jail_set_hostname_allowed, 0,
74     "Processes in jail can set their hostnames");
75 
76 int	jail_socket_unixiproute_only = 1;
77 SYSCTL_INT(_jail, OID_AUTO, socket_unixiproute_only, CTLFLAG_RW,
78     &jail_socket_unixiproute_only, 0,
79     "Processes in jail are limited to creating UNIX/IPv[46]/route sockets only");
80 
81 int	jail_sysvipc_allowed = 0;
82 SYSCTL_INT(_jail, OID_AUTO, sysvipc_allowed, CTLFLAG_RW,
83     &jail_sysvipc_allowed, 0,
84     "Processes in jail can use System V IPC primitives");
85 
86 int    jail_chflags_allowed = 0;
87 SYSCTL_INT(_jail, OID_AUTO, chflags_allowed, CTLFLAG_RW,
88     &jail_chflags_allowed, 0,
89     "Process in jail can set chflags(1)");
90 
91 int    jail_allow_raw_sockets = 0;
92 SYSCTL_INT(_jail, OID_AUTO, allow_raw_sockets, CTLFLAG_RW,
93     &jail_allow_raw_sockets, 0,
94     "Process in jail can create raw sockets");
95 
96 int	lastprid = 0;
97 int	prisoncount = 0;
98 
99 LIST_HEAD(prisonlist, prison);
100 struct	prisonlist allprison = LIST_HEAD_INITIALIZER(&allprison);
101 
102 static int
103 kern_jail_attach(int jid)
104 {
105 	struct proc *p = curthread->td_proc;
106 	struct prison *pr;
107 	int error;
108 
109 	pr = prison_find(jid);
110 	if (pr == NULL)
111 		return(EINVAL);
112 
113 	error = kern_chroot(&pr->pr_root);
114 	if (error)
115 		return(error);
116 
117 	prison_hold(pr);
118 	cratom(&p->p_ucred);
119 	p->p_ucred->cr_prison = pr;
120 	p->p_flag |= P_JAILED;
121 
122 	return(0);
123 }
124 
125 static int
126 assign_prison_id(struct prison *pr)
127 {
128 	int tryprid;
129 	struct prison *tpr;
130 
131 	tryprid = lastprid + 1;
132 	if (tryprid == JAIL_MAX)
133 		tryprid = 1;
134 next:
135 	LIST_FOREACH(tpr, &allprison, pr_list) {
136 		if (tpr->pr_id != tryprid)
137 			continue;
138 		tryprid++;
139 		if (tryprid == JAIL_MAX) {
140 			return (ERANGE);
141 		}
142 		goto next;
143 	}
144 	pr->pr_id = lastprid = tryprid;
145 
146 	return (0);
147 }
148 
149 static int
150 kern_jail(struct prison *pr, struct jail *j)
151 {
152 	int error;
153 	struct nlookupdata nd;
154 
155 	error = nlookup_init(&nd, j->path, UIO_USERSPACE, NLC_FOLLOW);
156 	if (error) {
157 		nlookup_done(&nd);
158 		return (error);
159 	}
160 	error = nlookup(&nd);
161 	if (error) {
162 		nlookup_done(&nd);
163 		return (error);
164 	}
165 	cache_copy(&nd.nl_nch, &pr->pr_root);
166 
167 	varsymset_init(&pr->pr_varsymset, NULL);
168 	prison_ipcache_init(pr);
169 
170 	error = assign_prison_id(pr);
171 	if (error) {
172 		varsymset_clean(&pr->pr_varsymset);
173 		nlookup_done(&nd);
174 		return (error);
175 	}
176 
177 	LIST_INSERT_HEAD(&allprison, pr, pr_list);
178 	prisoncount++;
179 
180 	error = kern_jail_attach(pr->pr_id);
181 	if (error) {
182 		LIST_REMOVE(pr, pr_list);
183 		varsymset_clean(&pr->pr_varsymset);
184 	}
185 	nlookup_done(&nd);
186 	return (error);
187 }
188 
189 /*
190  * jail()
191  *
192  * jail_args(syscallarg(struct jail *) jail)
193  *
194  * MPALMOSTSAFE
195  */
196 int
197 sys_jail(struct jail_args *uap)
198 {
199 	struct thread *td = curthread;
200 	struct prison *pr;
201 	struct jail_ip_storage *jip;
202 	struct jail j;
203 	int error;
204 	uint32_t jversion;
205 
206 	uap->sysmsg_result = -1;
207 
208 	error = priv_check(td, PRIV_JAIL_CREATE);
209 	if (error)
210 		return (error);
211 
212 	error = copyin(uap->jail, &jversion, sizeof(jversion));
213 	if (error)
214 		return (error);
215 
216 	pr = kmalloc(sizeof(*pr), M_PRISON, M_WAITOK | M_ZERO);
217 	SLIST_INIT(&pr->pr_ips);
218 	get_mplock();
219 
220 	switch (jversion) {
221 	case 0:
222 		/* Single IPv4 jails. */
223 		{
224 		struct jail_v0 jv0;
225 		struct sockaddr_in ip4addr;
226 
227 		error = copyin(uap->jail, &jv0, sizeof(jv0));
228 		if (error)
229 			goto out;
230 
231 		j.path = jv0.path;
232 		j.hostname = jv0.hostname;
233 
234 		jip = kmalloc(sizeof(*jip),  M_PRISON, M_WAITOK | M_ZERO);
235 		ip4addr.sin_family = AF_INET;
236 		ip4addr.sin_addr.s_addr = htonl(jv0.ip_number);
237 		memcpy(&jip->ip, &ip4addr, sizeof(ip4addr));
238 		SLIST_INSERT_HEAD(&pr->pr_ips, jip, entries);
239 		break;
240 		}
241 
242 	case 1:
243 		/*
244 		 * DragonFly multi noIP/IPv4/IPv6 jails
245 		 *
246 		 * NOTE: This version is unsupported by FreeBSD
247 		 * (which uses version 2 instead).
248 		 */
249 
250 		error = copyin(uap->jail, &j, sizeof(j));
251 		if (error)
252 			goto out;
253 
254 		for (int i = 0; i < j.n_ips; i++) {
255 			jip = kmalloc(sizeof(*jip), M_PRISON,
256 				      M_WAITOK | M_ZERO);
257 			SLIST_INSERT_HEAD(&pr->pr_ips, jip, entries);
258 			error = copyin(&j.ips[i], &jip->ip,
259 					sizeof(struct sockaddr_storage));
260 			if (error)
261 				goto out;
262 		}
263 		break;
264 	default:
265 		error = EINVAL;
266 		goto out;
267 	}
268 
269 	error = copyinstr(j.hostname, &pr->pr_host, sizeof(pr->pr_host), 0);
270 	if (error)
271 		goto out;
272 
273 	error = kern_jail(pr, &j);
274 	if (error)
275 		goto out;
276 
277 	uap->sysmsg_result = pr->pr_id;
278 	rel_mplock();
279 	return (0);
280 
281 out:
282 	/* Delete all ips */
283 	while (!SLIST_EMPTY(&pr->pr_ips)) {
284 		jip = SLIST_FIRST(&pr->pr_ips);
285 		SLIST_REMOVE_HEAD(&pr->pr_ips, entries);
286 		kfree(jip, M_PRISON);
287 	}
288 	rel_mplock();
289 	kfree(pr, M_PRISON);
290 	return (error);
291 }
292 
293 /*
294  * int jail_attach(int jid);
295  *
296  * MPALMOSTSAFE
297  */
298 int
299 sys_jail_attach(struct jail_attach_args *uap)
300 {
301 	struct thread *td = curthread;
302 	int error;
303 
304 	error = priv_check(td, PRIV_JAIL_ATTACH);
305 	if (error)
306 		return(error);
307 	get_mplock();
308 	error = kern_jail_attach(uap->jid);
309 	rel_mplock();
310 	return (error);
311 }
312 
313 static void
314 prison_ipcache_init(struct prison *pr)
315 {
316 	struct jail_ip_storage *jis;
317 	struct sockaddr_in *ip4;
318 	struct sockaddr_in6 *ip6;
319 
320 	SLIST_FOREACH(jis, &pr->pr_ips, entries) {
321 		switch (jis->ip.ss_family) {
322 		case AF_INET:
323 			ip4 = (struct sockaddr_in *)&jis->ip;
324 			if ((ntohl(ip4->sin_addr.s_addr) >> IN_CLASSA_NSHIFT) ==
325 			    IN_LOOPBACKNET) {
326 				/* loopback address */
327 				if (pr->local_ip4 == NULL)
328 					pr->local_ip4 = ip4;
329 			} else {
330 				/* public address */
331 				if (pr->nonlocal_ip4 == NULL)
332 					pr->nonlocal_ip4 = ip4;
333 			}
334 			break;
335 
336 		case AF_INET6:
337 			ip6 = (struct sockaddr_in6 *)&jis->ip;
338 			if (IN6_IS_ADDR_LOOPBACK(&ip6->sin6_addr)) {
339 				/* loopback address */
340 				if (pr->local_ip6 == NULL)
341 					pr->local_ip6 = ip6;
342 			} else {
343 				/* public address */
344 				if (pr->nonlocal_ip6 == NULL)
345 					pr->nonlocal_ip6 = ip6;
346 			}
347 			break;
348 		}
349 	}
350 }
351 
352 /*
353  * Changes INADDR_LOOPBACK for a valid jail address.
354  * ip is in network byte order.
355  * Returns 1 if the ip is among jail valid ips.
356  * Returns 0 if is not among jail valid ips or
357  * if couldn't replace INADDR_LOOPBACK for a valid
358  * IP.
359  */
360 int
361 prison_replace_wildcards(struct thread *td, struct sockaddr *ip)
362 {
363 	struct sockaddr_in *ip4 = (struct sockaddr_in *)ip;
364 	struct sockaddr_in6 *ip6 = (struct sockaddr_in6 *)ip;
365 	struct prison *pr;
366 
367 	if (td->td_proc == NULL)
368 		return (1);
369 	if ((pr = td->td_ucred->cr_prison) == NULL)
370 		return (1);
371 
372 	if ((ip->sa_family == AF_INET &&
373 	    ip4->sin_addr.s_addr == htonl(INADDR_ANY)) ||
374 	    (ip->sa_family == AF_INET6 &&
375 	    IN6_IS_ADDR_UNSPECIFIED(&ip6->sin6_addr)))
376 		return (1);
377 	if ((ip->sa_family == AF_INET &&
378 	    ip4->sin_addr.s_addr == htonl(INADDR_LOOPBACK)) ||
379 	    (ip->sa_family == AF_INET6 &&
380 	    IN6_IS_ADDR_LOOPBACK(&ip6->sin6_addr))) {
381 		if (!prison_get_local(pr, ip->sa_family, ip) &&
382 		    !prison_get_nonlocal(pr, ip->sa_family, ip))
383 			return(0);
384 		else
385 			return(1);
386 	}
387 	if (jailed_ip(pr, ip))
388 		return(1);
389 	return(0);
390 }
391 
392 int
393 prison_remote_ip(struct thread *td, struct sockaddr *ip)
394 {
395 	struct sockaddr_in *ip4 = (struct sockaddr_in *)ip;
396 	struct sockaddr_in6 *ip6 = (struct sockaddr_in6 *)ip;
397 	struct prison *pr;
398 
399 	if (td == NULL || td->td_proc == NULL)
400 		return(1);
401 	if ((pr = td->td_ucred->cr_prison) == NULL)
402 		return(1);
403 	if ((ip->sa_family == AF_INET &&
404 	    ip4->sin_addr.s_addr == htonl(INADDR_LOOPBACK)) ||
405 	    (ip->sa_family == AF_INET6 &&
406 	    IN6_IS_ADDR_LOOPBACK(&ip6->sin6_addr))) {
407 		if (!prison_get_local(pr, ip->sa_family, ip) &&
408 		    !prison_get_nonlocal(pr, ip->sa_family, ip))
409 			return(0);
410 		else
411 			return(1);
412 	}
413 	return(1);
414 }
415 
416 /*
417  * Prison get non loopback ip:
418  * - af is the address family of the ip we want (AF_INET|AF_INET6).
419  * - If ip != NULL, put the first IP address that is not a loopback address
420  *   into *ip.
421  *
422  * ip is in network by order and we don't touch it unless we find a valid ip.
423  * No matter if ip == NULL or not, we return either a valid struct sockaddr *,
424  * or NULL.  This struct may not be modified.
425  */
426 struct sockaddr *
427 prison_get_nonlocal(struct prison *pr, sa_family_t af, struct sockaddr *ip)
428 {
429 	struct sockaddr_in *ip4 = (struct sockaddr_in *)ip;
430 	struct sockaddr_in6 *ip6 = (struct sockaddr_in6 *)ip;
431 
432 	/* Check if it is cached */
433 	switch(af) {
434 	case AF_INET:
435 		if (ip4 != NULL && pr->nonlocal_ip4 != NULL)
436 			ip4->sin_addr.s_addr = pr->nonlocal_ip4->sin_addr.s_addr;
437 		return (struct sockaddr *)pr->nonlocal_ip4;
438 
439 	case AF_INET6:
440 		if (ip6 != NULL && pr->nonlocal_ip6 != NULL)
441 			ip6->sin6_addr = pr->nonlocal_ip6->sin6_addr;
442 		return (struct sockaddr *)pr->nonlocal_ip6;
443 	}
444 
445 	/* NOTREACHED */
446 	return NULL;
447 }
448 
449 /*
450  * Prison get loopback ip.
451  * - af is the address family of the ip we want (AF_INET|AF_INET6).
452  * - If ip != NULL, put the first IP address that is not a loopback address
453  *   into *ip.
454  *
455  * ip is in network by order and we don't touch it unless we find a valid ip.
456  * No matter if ip == NULL or not, we return either a valid struct sockaddr *,
457  * or NULL.  This struct may not be modified.
458  */
459 struct sockaddr *
460 prison_get_local(struct prison *pr, sa_family_t af, struct sockaddr *ip)
461 {
462 	struct sockaddr_in *ip4 = (struct sockaddr_in *)ip;
463 	struct sockaddr_in6 *ip6 = (struct sockaddr_in6 *)ip;
464 
465 	/* Check if it is cached */
466 	switch(af) {
467 	case AF_INET:
468 		if (ip4 != NULL && pr->local_ip4 != NULL)
469 			ip4->sin_addr.s_addr = pr->local_ip4->sin_addr.s_addr;
470 		return (struct sockaddr *)pr->local_ip4;
471 
472 	case AF_INET6:
473 		if (ip6 != NULL && pr->local_ip6 != NULL)
474 			ip6->sin6_addr = pr->local_ip6->sin6_addr;
475 		return (struct sockaddr *)pr->local_ip6;
476 	}
477 
478 	/* NOTREACHED */
479 	return NULL;
480 }
481 
482 /* Check if the IP is among ours, if it is return 1, else 0 */
483 int
484 jailed_ip(struct prison *pr, struct sockaddr *ip)
485 {
486 	struct jail_ip_storage *jis;
487 	struct sockaddr_in *jip4, *ip4;
488 	struct sockaddr_in6 *jip6, *ip6;
489 
490 	if (pr == NULL)
491 		return(0);
492 	ip4 = (struct sockaddr_in *)ip;
493 	ip6 = (struct sockaddr_in6 *)ip;
494 	SLIST_FOREACH(jis, &pr->pr_ips, entries) {
495 		switch (ip->sa_family) {
496 		case AF_INET:
497 			jip4 = (struct sockaddr_in *) &jis->ip;
498 			if (jip4->sin_family == AF_INET &&
499 			    ip4->sin_addr.s_addr == jip4->sin_addr.s_addr)
500 				return(1);
501 			break;
502 		case AF_INET6:
503 			jip6 = (struct sockaddr_in6 *) &jis->ip;
504 			if (jip6->sin6_family == AF_INET6 &&
505 			    IN6_ARE_ADDR_EQUAL(&ip6->sin6_addr,
506 					       &jip6->sin6_addr))
507 				return(1);
508 			break;
509 		}
510 	}
511 	/* Ip not in list */
512 	return(0);
513 }
514 
515 int
516 prison_if(struct ucred *cred, struct sockaddr *sa)
517 {
518 	struct prison *pr;
519 	struct sockaddr_in *sai = (struct sockaddr_in*) sa;
520 
521 	pr = cred->cr_prison;
522 
523 	if (((sai->sin_family != AF_INET) && (sai->sin_family != AF_INET6))
524 	    && jail_socket_unixiproute_only)
525 		return(1);
526 	else if ((sai->sin_family != AF_INET) && (sai->sin_family != AF_INET6))
527 		return(0);
528 	else if (jailed_ip(pr, sa))
529 		return(0);
530 	return(1);
531 }
532 
533 /*
534  * Returns a prison instance, or NULL on failure.
535  */
536 static struct prison *
537 prison_find(int prid)
538 {
539 	struct prison *pr;
540 
541 	LIST_FOREACH(pr, &allprison, pr_list) {
542 		if (pr->pr_id == prid)
543 			break;
544 	}
545 	return(pr);
546 }
547 
548 static int
549 sysctl_jail_list(SYSCTL_HANDLER_ARGS)
550 {
551 	struct thread *td = curthread;
552 	struct jail_ip_storage *jip;
553 #ifdef INET6
554 	struct sockaddr_in6 *jsin6;
555 #endif
556 	struct sockaddr_in *jsin;
557 	struct lwp *lp;
558 	struct prison *pr;
559 	unsigned int jlssize, jlsused;
560 	int count, error;
561 	char *jls; /* Jail list */
562 	char *oip; /* Output ip */
563 	char *fullpath, *freepath;
564 
565 	jlsused = 0;
566 
567 	if (jailed(td->td_ucred))
568 		return (0);
569 	lp = td->td_lwp;
570 retry:
571 	count = prisoncount;
572 
573 	if (count == 0)
574 		return(0);
575 
576 	jlssize = (count * 1024);
577 	jls = kmalloc(jlssize + 1, M_TEMP, M_WAITOK | M_ZERO);
578 	if (count < prisoncount) {
579 		kfree(jls, M_TEMP);
580 		goto retry;
581 	}
582 	count = prisoncount;
583 
584 	LIST_FOREACH(pr, &allprison, pr_list) {
585 		error = cache_fullpath(lp->lwp_proc, &pr->pr_root,
586 					&fullpath, &freepath);
587 		if (error)
588 			continue;
589 		if (jlsused && jlsused < jlssize)
590 			jls[jlsused++] = '\n';
591 		count = ksnprintf(jls + jlsused, (jlssize - jlsused),
592 				 "%d %s %s",
593 				 pr->pr_id, pr->pr_host, fullpath);
594 		kfree(freepath, M_TEMP);
595 		if (count < 0)
596 			goto end;
597 		jlsused += count;
598 
599 		/* Copy the IPS */
600 		SLIST_FOREACH(jip, &pr->pr_ips, entries) {
601 			jsin = (struct sockaddr_in *)&jip->ip;
602 
603 			switch(jsin->sin_family) {
604 			case AF_INET:
605 				oip = inet_ntoa(jsin->sin_addr);
606 				break;
607 #ifdef INET6
608 			case AF_INET6:
609 				jsin6 = (struct sockaddr_in6 *)&jip->ip;
610 				oip = ip6_sprintf(&jsin6->sin6_addr);
611 				break;
612 #endif
613 			default:
614 				oip = "?family?";
615 				break;
616 			}
617 
618 			if ((jlssize - jlsused) < (strlen(oip) + 1)) {
619 				error = ERANGE;
620 				goto end;
621 			}
622 			count = ksnprintf(jls + jlsused, (jlssize - jlsused),
623 					  " %s", oip);
624 			if (count < 0)
625 				goto end;
626 			jlsused += count;
627 		}
628 	}
629 
630 	/*
631 	 * The format is:
632 	 * pr_id <SPC> hostname1 <SPC> PATH1 <SPC> IP1 <SPC> IP2\npr_id...
633 	 */
634 	error = SYSCTL_OUT(req, jls, jlsused);
635 end:
636 	kfree(jls, M_TEMP);
637 	return(error);
638 }
639 
640 SYSCTL_OID(_jail, OID_AUTO, list, CTLTYPE_STRING | CTLFLAG_RD, NULL, 0,
641 	   sysctl_jail_list, "A", "List of active jails");
642 
643 void
644 prison_hold(struct prison *pr)
645 {
646 	pr->pr_ref++;
647 }
648 
649 void
650 prison_free(struct prison *pr)
651 {
652 	struct jail_ip_storage *jls;
653 	KKASSERT(pr->pr_ref >= 1);
654 
655 	if (--pr->pr_ref > 0)
656 		return;
657 
658 	/* Delete all ips */
659 	while (!SLIST_EMPTY(&pr->pr_ips)) {
660 		jls = SLIST_FIRST(&pr->pr_ips);
661 		SLIST_REMOVE_HEAD(&pr->pr_ips, entries);
662 		kfree(jls, M_PRISON);
663 	}
664 	LIST_REMOVE(pr, pr_list);
665 	prisoncount--;
666 
667 	if (pr->pr_linux != NULL)
668 		kfree(pr->pr_linux, M_PRISON);
669 	varsymset_clean(&pr->pr_varsymset);
670 	cache_drop(&pr->pr_root);
671 	kfree(pr, M_PRISON);
672 }
673 
674 /*
675  * Check if permisson for a specific privilege is granted within jail.
676  *
677  * MPSAFE
678  */
679 int
680 prison_priv_check(struct ucred *cred, int priv)
681 {
682 	if (!jailed(cred))
683 		return (0);
684 
685 	switch (priv) {
686 	case PRIV_CRED_SETUID:
687 	case PRIV_CRED_SETEUID:
688 	case PRIV_CRED_SETGID:
689 	case PRIV_CRED_SETEGID:
690 	case PRIV_CRED_SETGROUPS:
691 	case PRIV_CRED_SETREUID:
692 	case PRIV_CRED_SETREGID:
693 	case PRIV_CRED_SETRESUID:
694 	case PRIV_CRED_SETRESGID:
695 
696 	case PRIV_VFS_SYSFLAGS:
697 	case PRIV_VFS_CHOWN:
698 	case PRIV_VFS_CHMOD:
699 	case PRIV_VFS_CHROOT:
700 	case PRIV_VFS_LINK:
701 	case PRIV_VFS_CHFLAGS_DEV:
702 	case PRIV_VFS_REVOKE:
703 	case PRIV_VFS_MKNOD_BAD:
704 	case PRIV_VFS_MKNOD_WHT:
705 	case PRIV_VFS_MKNOD_DIR:
706 	case PRIV_VFS_SETATTR:
707 	case PRIV_VFS_SETGID:
708 
709 	case PRIV_PROC_SETRLIMIT:
710 	case PRIV_PROC_SETLOGIN:
711 
712 	case PRIV_SYSCTL_WRITEJAIL:
713 
714 	case PRIV_VARSYM_SYS:
715 
716 	case PRIV_SETHOSTNAME:
717 
718 	case PRIV_PROC_TRESPASS:
719 
720 		return (0);
721 
722 	case PRIV_UFS_QUOTAON:
723 	case PRIV_UFS_QUOTAOFF:
724 	case PRIV_VFS_SETQUOTA:
725 	case PRIV_UFS_SETUSE:
726 	case PRIV_VFS_GETQUOTA:
727 		return (0);
728 
729 
730 	case PRIV_DEBUG_UNPRIV:
731 		return (0);
732 
733 
734 		/*
735 		 * Allow jailed root to bind reserved ports.
736 		 */
737 	case PRIV_NETINET_RESERVEDPORT:
738 		return (0);
739 
740 
741 		/*
742 		 * Conditionally allow creating raw sockets in jail.
743 		 */
744 	case PRIV_NETINET_RAW:
745 		if (jail_allow_raw_sockets)
746 			return (0);
747 		else
748 			return (EPERM);
749 
750 	case PRIV_HAMMER_IOCTL:
751 		return (0);
752 
753 	default:
754 
755 		return (EPERM);
756 	}
757 }
758