suser_* to priv_* conversion
[dragonfly.git] / sys / kern / kern_jail.c
blobacd7022145eea23a2be57b55037573e6ab937de5
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 * ----------------------------------------------------------------------------
9 */
10 /*-
11 * Copyright (c) 2006 Victor Balada Diaz <victor@bsdes.net>
12 * All rights reserved.
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.
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.
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 $
42 #include "opt_inet6.h"
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>
63 static struct prison *prison_find(int);
64 static void prison_ipcache_init(struct prison *);
66 MALLOC_DEFINE(M_PRISON, "prison", "Prison structures");
68 SYSCTL_NODE(, OID_AUTO, jail, CTLFLAG_RW, 0,
69 "Jail rules");
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");
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");
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");
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)");
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");
96 int lastprid = 0;
97 int prisoncount = 0;
99 LIST_HEAD(prisonlist, prison);
100 struct prisonlist allprison = LIST_HEAD_INITIALIZER(&allprison);
102 static int
103 kern_jail_attach(int jid)
105 struct proc *p = curthread->td_proc;
106 struct prison *pr;
107 int error;
109 pr = prison_find(jid);
110 if (pr == NULL)
111 return(EINVAL);
113 error = kern_chroot(&pr->pr_root);
114 if (error)
115 return(error);
117 prison_hold(pr);
118 cratom(&p->p_ucred);
119 p->p_ucred->cr_prison = pr;
120 p->p_flag |= P_JAILED;
122 return(0);
126 * jail()
128 * jail_args(syscallarg(struct jail *) jail)
131 sys_jail(struct jail_args *uap)
133 struct prison *pr, *tpr;
134 struct jail j;
135 struct jail_v0 jv0;
136 struct thread *td = curthread;
137 int error, tryprid, i;
138 uint32_t jversion;
139 struct nlookupdata nd;
140 /* Multiip */
141 struct sockaddr_storage *uips; /* Userland ips */
142 struct sockaddr_in ip4addr;
143 struct jail_ip_storage *jip;
144 /* Multiip */
146 error = priv_check(td, PRIV_ROOT);
147 if (error) {
148 uap->sysmsg_result = -1;
149 return(error);
151 error = copyin(uap->jail, &jversion, sizeof jversion);
152 if (error) {
153 uap->sysmsg_result = -1;
154 return(error);
156 pr = kmalloc(sizeof *pr , M_PRISON, M_WAITOK | M_ZERO);
157 SLIST_INIT(&pr->pr_ips);
159 switch (jversion) {
160 case 0:
161 error = copyin(uap->jail, &jv0, sizeof(struct jail_v0));
162 if (error)
163 goto bail;
164 jip = kmalloc(sizeof(*jip), M_PRISON, M_WAITOK | M_ZERO);
165 ip4addr.sin_family = AF_INET;
166 ip4addr.sin_addr.s_addr = htonl(jv0.ip_number);
167 memcpy(&jip->ip, &ip4addr, sizeof(ip4addr));
168 SLIST_INSERT_HEAD(&pr->pr_ips, jip, entries);
169 break;
170 case 1:
171 error = copyin(uap->jail, &j, sizeof(j));
172 if (error)
173 goto bail;
174 uips = kmalloc((sizeof(*uips) * j.n_ips), M_PRISON,
175 M_WAITOK | M_ZERO);
176 error = copyin(j.ips, uips, (sizeof(*uips) * j.n_ips));
177 if (error) {
178 kfree(uips, M_PRISON);
179 goto bail;
181 for (i = 0; i < j.n_ips; i++) {
182 jip = kmalloc(sizeof(*jip), M_PRISON,
183 M_WAITOK | M_ZERO);
184 memcpy(&jip->ip, &uips[i], sizeof(*uips));
185 SLIST_INSERT_HEAD(&pr->pr_ips, jip, entries);
187 kfree(uips, M_PRISON);
188 break;
189 default:
190 error = EINVAL;
191 goto bail;
194 error = copyinstr(j.hostname, &pr->pr_host, sizeof pr->pr_host, 0);
195 if (error)
196 goto bail;
197 error = nlookup_init(&nd, j.path, UIO_USERSPACE, NLC_FOLLOW);
198 if (error)
199 goto nlookup_init_clean;
200 error = nlookup(&nd);
201 if (error)
202 goto nlookup_init_clean;
203 cache_copy(&nd.nl_nch, &pr->pr_root);
205 varsymset_init(&pr->pr_varsymset, NULL);
206 prison_ipcache_init(pr);
208 tryprid = lastprid + 1;
209 if (tryprid == JAIL_MAX)
210 tryprid = 1;
211 next:
212 LIST_FOREACH(tpr, &allprison, pr_list) {
213 if (tpr->pr_id != tryprid)
214 continue;
215 tryprid++;
216 if (tryprid == JAIL_MAX) {
217 error = ERANGE;
218 goto varsym_clean;
220 goto next;
222 pr->pr_id = lastprid = tryprid;
223 LIST_INSERT_HEAD(&allprison, pr, pr_list);
224 prisoncount++;
226 error = kern_jail_attach(pr->pr_id);
227 if (error)
228 goto jail_attach_clean;
230 nlookup_done(&nd);
231 uap->sysmsg_result = pr->pr_id;
232 return (0);
234 jail_attach_clean:
235 LIST_REMOVE(pr, pr_list);
236 varsym_clean:
237 varsymset_clean(&pr->pr_varsymset);
238 nlookup_init_clean:
239 nlookup_done(&nd);
240 bail:
241 /* Delete all ips */
242 while (!SLIST_EMPTY(&pr->pr_ips)) {
243 jip = SLIST_FIRST(&pr->pr_ips);
244 SLIST_REMOVE_HEAD(&pr->pr_ips, entries);
245 FREE(jip, M_PRISON);
247 FREE(pr, M_PRISON);
248 return(error);
252 * int jail_attach(int jid);
255 sys_jail_attach(struct jail_attach_args *uap)
257 struct thread *td = curthread;
258 int error;
260 error = priv_check(td, PRIV_ROOT);
261 if (error)
262 return(error);
264 return(kern_jail_attach(uap->jid));
267 static void
268 prison_ipcache_init(struct prison *pr)
270 struct jail_ip_storage *jis;
271 struct sockaddr_in *ip4;
272 struct sockaddr_in6 *ip6;
274 SLIST_FOREACH(jis, &pr->pr_ips, entries) {
275 switch (jis->ip.ss_family) {
276 case AF_INET:
277 ip4 = (struct sockaddr_in *)&jis->ip;
278 if ((ntohl(ip4->sin_addr.s_addr) >> IN_CLASSA_NSHIFT) ==
279 IN_LOOPBACKNET) {
280 /* loopback address */
281 if (pr->local_ip4 == NULL)
282 pr->local_ip4 = ip4;
283 } else {
284 /* public address */
285 if (pr->nonlocal_ip4 == NULL)
286 pr->nonlocal_ip4 = ip4;
288 break;
290 case AF_INET6:
291 ip6 = (struct sockaddr_in6 *)&jis->ip;
292 if (IN6_IS_ADDR_LOOPBACK(&ip6->sin6_addr)) {
293 /* loopback address */
294 if (pr->local_ip6 == NULL)
295 pr->local_ip6 = ip6;
296 } else {
297 /* public address */
298 if (pr->nonlocal_ip6 == NULL)
299 pr->nonlocal_ip6 = ip6;
301 break;
307 * Changes INADDR_LOOPBACK for a valid jail address.
308 * ip is in network byte order.
309 * Returns 1 if the ip is among jail valid ips.
310 * Returns 0 if is not among jail valid ips or
311 * if couldn't replace INADDR_LOOPBACK for a valid
312 * IP.
315 prison_replace_wildcards(struct thread *td, struct sockaddr *ip)
317 struct sockaddr_in *ip4 = (struct sockaddr_in *)ip;
318 struct sockaddr_in6 *ip6 = (struct sockaddr_in6 *)ip;
319 struct prison *pr;
321 if (td->td_proc == NULL)
322 return (1);
323 if ((pr = td->td_proc->p_ucred->cr_prison) == NULL)
324 return (1);
326 if ((ip->sa_family == AF_INET &&
327 ip4->sin_addr.s_addr == htonl(INADDR_ANY)) ||
328 (ip->sa_family == AF_INET6 &&
329 IN6_IS_ADDR_UNSPECIFIED(&ip6->sin6_addr)))
330 return (1);
331 if ((ip->sa_family == AF_INET &&
332 ip4->sin_addr.s_addr == htonl(INADDR_LOOPBACK)) ||
333 (ip->sa_family == AF_INET6 &&
334 IN6_IS_ADDR_LOOPBACK(&ip6->sin6_addr))) {
335 if (!prison_get_local(pr, ip->sa_family, ip) &&
336 !prison_get_nonlocal(pr, ip->sa_family, ip))
337 return(0);
338 else
339 return(1);
341 if (jailed_ip(pr, ip))
342 return(1);
343 return(0);
347 prison_remote_ip(struct thread *td, struct sockaddr *ip)
349 struct sockaddr_in *ip4 = (struct sockaddr_in *)ip;
350 struct sockaddr_in6 *ip6 = (struct sockaddr_in6 *)ip;
351 struct prison *pr;
353 if (td == NULL || td->td_proc == NULL)
354 return(1);
355 if ((pr = td->td_proc->p_ucred->cr_prison) == NULL)
356 return(1);
357 if ((ip->sa_family == AF_INET &&
358 ip4->sin_addr.s_addr == htonl(INADDR_LOOPBACK)) ||
359 (ip->sa_family == AF_INET6 &&
360 IN6_IS_ADDR_LOOPBACK(&ip6->sin6_addr))) {
361 if (!prison_get_local(pr, ip->sa_family, ip) &&
362 !prison_get_nonlocal(pr, ip->sa_family, ip))
363 return(0);
364 else
365 return(1);
367 return(1);
371 * Prison get non loopback ip:
372 * - af is the address family of the ip we want (AF_INET|AF_INET6).
373 * - If ip != NULL, put the first IP address that is not a loopback address
374 * into *ip.
376 * ip is in network by order and we don't touch it unless we find a valid ip.
377 * No matter if ip == NULL or not, we return either a valid struct sockaddr *,
378 * or NULL. This struct may not be modified.
380 struct sockaddr *
381 prison_get_nonlocal(struct prison *pr, sa_family_t af, struct sockaddr *ip)
383 struct sockaddr_in *ip4 = (struct sockaddr_in *)ip;
384 struct sockaddr_in6 *ip6 = (struct sockaddr_in6 *)ip;
386 /* Check if it is cached */
387 switch(af) {
388 case AF_INET:
389 if (ip4 != NULL && pr->nonlocal_ip4 != NULL)
390 ip4->sin_addr.s_addr = pr->nonlocal_ip4->sin_addr.s_addr;
391 return (struct sockaddr *)pr->nonlocal_ip4;
393 case AF_INET6:
394 if (ip6 != NULL && pr->nonlocal_ip6 != NULL)
395 ip6->sin6_addr = pr->nonlocal_ip6->sin6_addr;
396 return (struct sockaddr *)pr->nonlocal_ip6;
399 /* NOTREACHED */
400 return NULL;
404 * Prison get loopback ip.
405 * - af is the address family of the ip we want (AF_INET|AF_INET6).
406 * - If ip != NULL, put the first IP address that is not a loopback address
407 * into *ip.
409 * ip is in network by order and we don't touch it unless we find a valid ip.
410 * No matter if ip == NULL or not, we return either a valid struct sockaddr *,
411 * or NULL. This struct may not be modified.
413 struct sockaddr *
414 prison_get_local(struct prison *pr, sa_family_t af, struct sockaddr *ip)
416 struct sockaddr_in *ip4 = (struct sockaddr_in *)ip;
417 struct sockaddr_in6 *ip6 = (struct sockaddr_in6 *)ip;
419 /* Check if it is cached */
420 switch(af) {
421 case AF_INET:
422 if (ip4 != NULL && pr->local_ip4 != NULL)
423 ip4->sin_addr.s_addr = pr->local_ip4->sin_addr.s_addr;
424 return (struct sockaddr *)pr->local_ip4;
426 case AF_INET6:
427 if (ip6 != NULL && pr->local_ip6 != NULL)
428 ip6->sin6_addr = pr->local_ip6->sin6_addr;
429 return (struct sockaddr *)pr->local_ip6;
432 /* NOTREACHED */
433 return NULL;
436 /* Check if the IP is among ours, if it is return 1, else 0 */
438 jailed_ip(struct prison *pr, struct sockaddr *ip)
440 struct jail_ip_storage *jis;
441 struct sockaddr_in *jip4, *ip4;
442 struct sockaddr_in6 *jip6, *ip6;
444 if (pr == NULL)
445 return(0);
446 ip4 = (struct sockaddr_in *)ip;
447 ip6 = (struct sockaddr_in6 *)ip;
448 SLIST_FOREACH(jis, &pr->pr_ips, entries) {
449 switch (ip->sa_family) {
450 case AF_INET:
451 jip4 = (struct sockaddr_in *) &jis->ip;
452 if (jip4->sin_family == AF_INET &&
453 ip4->sin_addr.s_addr == jip4->sin_addr.s_addr)
454 return(1);
455 break;
456 case AF_INET6:
457 jip6 = (struct sockaddr_in6 *) &jis->ip;
458 if (jip6->sin6_family == AF_INET6 &&
459 IN6_ARE_ADDR_EQUAL(&ip6->sin6_addr,
460 &jip6->sin6_addr))
461 return(1);
462 break;
465 /* Ip not in list */
466 return(0);
470 prison_if(struct ucred *cred, struct sockaddr *sa)
472 struct prison *pr;
473 struct sockaddr_in *sai = (struct sockaddr_in*) sa;
475 pr = cred->cr_prison;
477 if (((sai->sin_family != AF_INET) && (sai->sin_family != AF_INET6))
478 && jail_socket_unixiproute_only)
479 return(1);
480 else if ((sai->sin_family != AF_INET) && (sai->sin_family != AF_INET6))
481 return(0);
482 else if (jailed_ip(pr, sa))
483 return(0);
484 return(1);
488 * Returns a prison instance, or NULL on failure.
490 static struct prison *
491 prison_find(int prid)
493 struct prison *pr;
495 LIST_FOREACH(pr, &allprison, pr_list) {
496 if (pr->pr_id == prid)
497 break;
499 return(pr);
502 static int
503 sysctl_jail_list(SYSCTL_HANDLER_ARGS)
505 struct jail_ip_storage *jip;
506 #ifdef INET6
507 struct sockaddr_in6 *jsin6;
508 #endif
509 struct sockaddr_in *jsin;
510 struct proc *p;
511 struct prison *pr;
512 unsigned int jlssize, jlsused;
513 int count, error;
514 char *jls; /* Jail list */
515 char *oip; /* Output ip */
516 char *fullpath, *freepath;
518 jlsused = 0;
519 p = curthread->td_proc;
521 if (jailed(p->p_ucred))
522 return (0);
523 retry:
524 count = prisoncount;
526 if (count == 0)
527 return(0);
529 jlssize = (count * 1024);
530 jls = kmalloc(jlssize + 1, M_TEMP, M_WAITOK | M_ZERO);
531 if (count < prisoncount) {
532 kfree(jls, M_TEMP);
533 goto retry;
535 count = prisoncount;
537 LIST_FOREACH(pr, &allprison, pr_list) {
538 error = cache_fullpath(p, &pr->pr_root, &fullpath, &freepath);
539 if (error)
540 continue;
541 if (jlsused && jlsused < jlssize)
542 jls[jlsused++] = '\n';
543 count = ksnprintf(jls + jlsused, (jlssize - jlsused),
544 "%d %s %s",
545 pr->pr_id, pr->pr_host, fullpath);
546 kfree(freepath, M_TEMP);
547 if (count < 0)
548 goto end;
549 jlsused += count;
551 /* Copy the IPS */
552 SLIST_FOREACH(jip, &pr->pr_ips, entries) {
553 jsin = (struct sockaddr_in *)&jip->ip;
555 switch(jsin->sin_family) {
556 case AF_INET:
557 oip = inet_ntoa(jsin->sin_addr);
558 break;
559 #ifdef INET6
560 case AF_INET6:
561 jsin6 = (struct sockaddr_in6 *)&jip->ip;
562 oip = ip6_sprintf(&jsin6->sin6_addr);
563 break;
564 #endif
565 default:
566 oip = "?family?";
567 break;
570 if ((jlssize - jlsused) < (strlen(oip) + 1)) {
571 error = ERANGE;
572 goto end;
574 count = ksnprintf(jls + jlsused, (jlssize - jlsused),
575 " %s", oip);
576 if (count < 0)
577 goto end;
578 jlsused += count;
583 * The format is:
584 * pr_id <SPC> hostname1 <SPC> PATH1 <SPC> IP1 <SPC> IP2\npr_id...
586 error = SYSCTL_OUT(req, jls, jlsused);
587 end:
588 kfree(jls, M_TEMP);
589 return(error);
592 SYSCTL_OID(_jail, OID_AUTO, list, CTLTYPE_STRING | CTLFLAG_RD, NULL, 0,
593 sysctl_jail_list, "A", "List of active jails");
595 void
596 prison_hold(struct prison *pr)
598 pr->pr_ref++;
601 void
602 prison_free(struct prison *pr)
604 struct jail_ip_storage *jls;
605 KKASSERT(pr->pr_ref >= 1);
607 if (--pr->pr_ref > 0)
608 return;
610 /* Delete all ips */
611 while (!SLIST_EMPTY(&pr->pr_ips)) {
612 jls = SLIST_FIRST(&pr->pr_ips);
613 SLIST_REMOVE_HEAD(&pr->pr_ips, entries);
614 FREE(jls, M_PRISON);
616 LIST_REMOVE(pr, pr_list);
617 prisoncount--;
619 if (pr->pr_linux != NULL)
620 kfree(pr->pr_linux, M_PRISON);
621 varsymset_clean(&pr->pr_varsymset);
622 cache_drop(&pr->pr_root);
623 kfree(pr, M_PRISON);