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