suser_* to priv_* conversion
[dragonfly.git] / sys / kern / kern_jail.c
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 /*
126  * jail()
127  *
128  * jail_args(syscallarg(struct jail *) jail)
129  */
130 int
131 sys_jail(struct jail_args *uap)
132 {
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 */
145
146         error = priv_check(td, PRIV_ROOT);
147         if (error) {
148                 uap->sysmsg_result = -1;
149                 return(error);
150         }
151         error = copyin(uap->jail, &jversion, sizeof jversion);
152         if (error) {
153                 uap->sysmsg_result = -1;
154                 return(error);
155         }
156         pr = kmalloc(sizeof *pr , M_PRISON, M_WAITOK | M_ZERO);
157         SLIST_INIT(&pr->pr_ips);
158
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;
180                 }
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);
186                 }
187                 kfree(uips, M_PRISON);
188                 break;
189         default:
190                 error = EINVAL;
191                 goto bail;
192         }
193
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);
204
205         varsymset_init(&pr->pr_varsymset, NULL);
206         prison_ipcache_init(pr);
207
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;
219                 }
220                 goto next;
221         }
222         pr->pr_id = lastprid = tryprid;
223         LIST_INSERT_HEAD(&allprison, pr, pr_list);
224         prisoncount++;
225
226         error = kern_jail_attach(pr->pr_id);
227         if (error)
228                 goto jail_attach_clean;
229
230         nlookup_done(&nd);
231         uap->sysmsg_result = pr->pr_id;
232         return (0);
233
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);
246         }
247         FREE(pr, M_PRISON);
248         return(error);
249 }
250
251 /*
252  * int jail_attach(int jid);
253  */
254 int
255 sys_jail_attach(struct jail_attach_args *uap)
256 {
257         struct thread *td = curthread;
258         int error;
259
260         error = priv_check(td, PRIV_ROOT);
261         if (error)
262                 return(error);
263
264         return(kern_jail_attach(uap->jid));
265 }
266
267 static void
268 prison_ipcache_init(struct prison *pr)
269 {
270         struct jail_ip_storage *jis;
271         struct sockaddr_in *ip4;
272         struct sockaddr_in6 *ip6;
273
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;
287                         }
288                         break;
289
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;
300                         }
301                         break;
302                 }
303         }
304 }
305
306 /* 
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.
313  */
314 int
315 prison_replace_wildcards(struct thread *td, struct sockaddr *ip)
316 {
317         struct sockaddr_in *ip4 = (struct sockaddr_in *)ip;
318         struct sockaddr_in6 *ip6 = (struct sockaddr_in6 *)ip;
319         struct prison *pr;
320
321         if (td->td_proc == NULL)
322                 return (1);
323         if ((pr = td->td_proc->p_ucred->cr_prison) == NULL)
324                 return (1);
325
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);
340         }
341         if (jailed_ip(pr, ip))
342                 return(1);
343         return(0);
344 }
345
346 int
347 prison_remote_ip(struct thread *td, struct sockaddr *ip)
348 {
349         struct sockaddr_in *ip4 = (struct sockaddr_in *)ip;
350         struct sockaddr_in6 *ip6 = (struct sockaddr_in6 *)ip;
351         struct prison *pr;
352
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);
366         }
367         return(1);
368 }
369
370 /*
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.
375  *
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.
379  */
380 struct sockaddr *
381 prison_get_nonlocal(struct prison *pr, sa_family_t af, struct sockaddr *ip)
382 {
383         struct sockaddr_in *ip4 = (struct sockaddr_in *)ip;
384         struct sockaddr_in6 *ip6 = (struct sockaddr_in6 *)ip;
385
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;
392
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;
397         }
398
399         /* NOTREACHED */
400         return NULL;
401 }
402
403 /*
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.
408  *
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.
412  */
413 struct sockaddr *
414 prison_get_local(struct prison *pr, sa_family_t af, struct sockaddr *ip)
415 {
416         struct sockaddr_in *ip4 = (struct sockaddr_in *)ip;
417         struct sockaddr_in6 *ip6 = (struct sockaddr_in6 *)ip;
418
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;
425
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;
430         }
431
432         /* NOTREACHED */
433         return NULL;
434 }
435
436 /* Check if the IP is among ours, if it is return 1, else 0 */
437 int
438 jailed_ip(struct prison *pr, struct sockaddr *ip)
439 {
440         struct jail_ip_storage *jis;
441         struct sockaddr_in *jip4, *ip4;
442         struct sockaddr_in6 *jip6, *ip6;
443
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;
463                 }
464         }
465         /* Ip not in list */
466         return(0);
467 }
468
469 int
470 prison_if(struct ucred *cred, struct sockaddr *sa)
471 {
472         struct prison *pr;
473         struct sockaddr_in *sai = (struct sockaddr_in*) sa;
474
475         pr = cred->cr_prison;
476
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);
485 }
486
487 /*
488  * Returns a prison instance, or NULL on failure.
489  */
490 static struct prison *
491 prison_find(int prid)
492 {
493         struct prison *pr;
494
495         LIST_FOREACH(pr, &allprison, pr_list) {
496                 if (pr->pr_id == prid)
497                         break;
498         }
499         return(pr);
500 }
501
502 static int
503 sysctl_jail_list(SYSCTL_HANDLER_ARGS)
504 {
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;
517
518         jlsused = 0;
519         p = curthread->td_proc;
520
521         if (jailed(p->p_ucred))
522                 return (0);
523 retry:
524         count = prisoncount;
525
526         if (count == 0)
527                 return(0);
528
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;
534         }
535         count = prisoncount;
536
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;
550
551                 /* Copy the IPS */
552                 SLIST_FOREACH(jip, &pr->pr_ips, entries) {
553                         jsin = (struct sockaddr_in *)&jip->ip;
554
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;
568                         }
569
570                         if ((jlssize - jlsused) < (strlen(oip) + 1)) {
571                                 error = ERANGE;
572                                 goto end;
573                         }
574                         count = ksnprintf(jls + jlsused, (jlssize - jlsused),
575                                           " %s", oip);
576                         if (count < 0)
577                                 goto end;
578                         jlsused += count;
579                 }
580         }
581
582         /* 
583          * The format is:
584          * pr_id <SPC> hostname1 <SPC> PATH1 <SPC> IP1 <SPC> IP2\npr_id...
585          */
586         error = SYSCTL_OUT(req, jls, jlsused);
587 end:
588         kfree(jls, M_TEMP);
589         return(error);
590 }
591
592 SYSCTL_OID(_jail, OID_AUTO, list, CTLTYPE_STRING | CTLFLAG_RD, NULL, 0,
593            sysctl_jail_list, "A", "List of active jails");
594
595 void
596 prison_hold(struct prison *pr)
597 {
598         pr->pr_ref++;
599 }
600
601 void
602 prison_free(struct prison *pr)
603 {
604         struct jail_ip_storage *jls;
605         KKASSERT(pr->pr_ref >= 1);
606
607         if (--pr->pr_ref > 0)
608                 return;
609
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);
615         }
616         LIST_REMOVE(pr, pr_list);
617         prisoncount--;
618
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);
624 }