19454b2d8SWarner Losh /*- 2413628a7SBjoern A. Zeeb * Copyright (c) 1999 Poul-Henning Kamp. 3413628a7SBjoern A. Zeeb * Copyright (c) 2008 Bjoern A. Zeeb. 4b38ff370SJamie Gritton * Copyright (c) 2009 James Gritton. 5413628a7SBjoern A. Zeeb * All rights reserved. 6b9f0b66cSBjoern A. Zeeb * 7b9f0b66cSBjoern A. Zeeb * Redistribution and use in source and binary forms, with or without 8b9f0b66cSBjoern A. Zeeb * modification, are permitted provided that the following conditions 9b9f0b66cSBjoern A. Zeeb * are met: 10b9f0b66cSBjoern A. Zeeb * 1. Redistributions of source code must retain the above copyright 11b9f0b66cSBjoern A. Zeeb * notice, this list of conditions and the following disclaimer. 12b9f0b66cSBjoern A. Zeeb * 2. Redistributions in binary form must reproduce the above copyright 13b9f0b66cSBjoern A. Zeeb * notice, this list of conditions and the following disclaimer in the 14b9f0b66cSBjoern A. Zeeb * documentation and/or other materials provided with the distribution. 15b9f0b66cSBjoern A. Zeeb * 16b9f0b66cSBjoern A. Zeeb * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17b9f0b66cSBjoern A. Zeeb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18b9f0b66cSBjoern A. Zeeb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19b9f0b66cSBjoern A. Zeeb * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20b9f0b66cSBjoern A. Zeeb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21b9f0b66cSBjoern A. Zeeb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22b9f0b66cSBjoern A. Zeeb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23b9f0b66cSBjoern A. Zeeb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24b9f0b66cSBjoern A. Zeeb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25b9f0b66cSBjoern A. Zeeb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26b9f0b66cSBjoern A. Zeeb * SUCH DAMAGE. 2707901f22SPoul-Henning Kamp */ 2875c13541SPoul-Henning Kamp 29677b542eSDavid E. O'Brien #include <sys/cdefs.h> 30677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$"); 31677b542eSDavid E. O'Brien 3276ca6f88SJamie Gritton #include "opt_compat.h" 33413628a7SBjoern A. Zeeb #include "opt_ddb.h" 34413628a7SBjoern A. Zeeb #include "opt_inet.h" 35413628a7SBjoern A. Zeeb #include "opt_inet6.h" 3646e3b1cbSPawel Jakub Dawidek 3775c13541SPoul-Henning Kamp #include <sys/param.h> 3875c13541SPoul-Henning Kamp #include <sys/types.h> 3975c13541SPoul-Henning Kamp #include <sys/kernel.h> 4075c13541SPoul-Henning Kamp #include <sys/systm.h> 4175c13541SPoul-Henning Kamp #include <sys/errno.h> 4275c13541SPoul-Henning Kamp #include <sys/sysproto.h> 4375c13541SPoul-Henning Kamp #include <sys/malloc.h> 440304c731SJamie Gritton #include <sys/osd.h> 45800c9408SRobert Watson #include <sys/priv.h> 4675c13541SPoul-Henning Kamp #include <sys/proc.h> 47b3059e09SRobert Watson #include <sys/taskqueue.h> 4857b4252eSKonstantin Belousov #include <sys/fcntl.h> 4975c13541SPoul-Henning Kamp #include <sys/jail.h> 5001137630SRobert Watson #include <sys/lock.h> 5101137630SRobert Watson #include <sys/mutex.h> 52dc68a633SPawel Jakub Dawidek #include <sys/sx.h> 5376ca6f88SJamie Gritton #include <sys/sysent.h> 54fd7a8150SMike Barcroft #include <sys/namei.h> 55820a0de9SPawel Jakub Dawidek #include <sys/mount.h> 56fd7a8150SMike Barcroft #include <sys/queue.h> 5775c13541SPoul-Henning Kamp #include <sys/socket.h> 58fd7a8150SMike Barcroft #include <sys/syscallsubr.h> 5983f1e257SRobert Watson #include <sys/sysctl.h> 60fd7a8150SMike Barcroft #include <sys/vnode.h> 61603724d3SBjoern A. Zeeb #include <sys/vimage.h> 6275c13541SPoul-Henning Kamp #include <net/if.h> 6375c13541SPoul-Henning Kamp #include <netinet/in.h> 64413628a7SBjoern A. Zeeb #ifdef DDB 65413628a7SBjoern A. Zeeb #include <ddb/ddb.h> 66413628a7SBjoern A. Zeeb #ifdef INET6 67413628a7SBjoern A. Zeeb #include <netinet6/in6_var.h> 68413628a7SBjoern A. Zeeb #endif /* INET6 */ 69413628a7SBjoern A. Zeeb #endif /* DDB */ 7075c13541SPoul-Henning Kamp 71aed55708SRobert Watson #include <security/mac/mac_framework.h> 72aed55708SRobert Watson 7375c13541SPoul-Henning Kamp MALLOC_DEFINE(M_PRISON, "prison", "Prison structures"); 7475c13541SPoul-Henning Kamp 750304c731SJamie Gritton /* prison0 describes what is "real" about the system. */ 760304c731SJamie Gritton struct prison prison0 = { 770304c731SJamie Gritton .pr_id = 0, 780304c731SJamie Gritton .pr_name = "0", 790304c731SJamie Gritton .pr_ref = 1, 800304c731SJamie Gritton .pr_uref = 1, 810304c731SJamie Gritton .pr_path = "/", 820304c731SJamie Gritton .pr_securelevel = -1, 8376ca6f88SJamie Gritton .pr_uuid = "00000000-0000-0000-0000-000000000000", 840304c731SJamie Gritton .pr_children = LIST_HEAD_INITIALIZER(&prison0.pr_children), 8576ca6f88SJamie Gritton .pr_flags = PR_HOST, 860304c731SJamie Gritton .pr_allow = PR_ALLOW_ALL, 870304c731SJamie Gritton }; 880304c731SJamie Gritton MTX_SYSINIT(prison0, &prison0.pr_mtx, "jail mutex", MTX_DEF); 8983f1e257SRobert Watson 900304c731SJamie Gritton /* allprison and lastprid are protected by allprison_lock. */ 91dc68a633SPawel Jakub Dawidek struct sx allprison_lock; 92b38ff370SJamie Gritton SX_SYSINIT(allprison_lock, &allprison_lock, "allprison"); 93b38ff370SJamie Gritton struct prisonlist allprison = TAILQ_HEAD_INITIALIZER(allprison); 942110d913SXin LI int lastprid = 0; 95fd7a8150SMike Barcroft 96b38ff370SJamie Gritton static int do_jail_attach(struct thread *td, struct prison *pr); 97b3059e09SRobert Watson static void prison_complete(void *context, int pending); 98b38ff370SJamie Gritton static void prison_deref(struct prison *pr, int flags); 990304c731SJamie Gritton static char *prison_path(struct prison *pr1, struct prison *pr2); 1000304c731SJamie Gritton static void prison_remove_one(struct prison *pr); 101413628a7SBjoern A. Zeeb #ifdef INET 1028571af59SJamie Gritton static int _prison_check_ip4(struct prison *pr, struct in_addr *ia); 1030304c731SJamie Gritton static int prison_restrict_ip4(struct prison *pr, struct in_addr *newip4); 104413628a7SBjoern A. Zeeb #endif 105413628a7SBjoern A. Zeeb #ifdef INET6 1068571af59SJamie Gritton static int _prison_check_ip6(struct prison *pr, struct in6_addr *ia6); 1070304c731SJamie Gritton static int prison_restrict_ip6(struct prison *pr, struct in6_addr *newip6); 108413628a7SBjoern A. Zeeb #endif 109fd7a8150SMike Barcroft 110b38ff370SJamie Gritton /* Flags for prison_deref */ 111b38ff370SJamie Gritton #define PD_DEREF 0x01 112b38ff370SJamie Gritton #define PD_DEUREF 0x02 113b38ff370SJamie Gritton #define PD_LOCKED 0x04 114b38ff370SJamie Gritton #define PD_LIST_SLOCKED 0x08 115b38ff370SJamie Gritton #define PD_LIST_XLOCKED 0x10 116fd7a8150SMike Barcroft 1170304c731SJamie Gritton /* 1180304c731SJamie Gritton * Parameter names corresponding to PR_* flag values 1190304c731SJamie Gritton */ 1200304c731SJamie Gritton static char *pr_flag_names[] = { 1210304c731SJamie Gritton [0] = "persist", 12276ca6f88SJamie Gritton "host", 1230304c731SJamie Gritton #ifdef INET 12476ca6f88SJamie Gritton "ip4", 1250304c731SJamie Gritton #endif 1260304c731SJamie Gritton #ifdef INET6 1270304c731SJamie Gritton [3] = "ip6", 1280304c731SJamie Gritton #endif 1290304c731SJamie Gritton }; 1300304c731SJamie Gritton 1310304c731SJamie Gritton static char *pr_flag_nonames[] = { 1320304c731SJamie Gritton [0] = "nopersist", 13376ca6f88SJamie Gritton "nohost", 1340304c731SJamie Gritton #ifdef INET 13576ca6f88SJamie Gritton "noip4", 1360304c731SJamie Gritton #endif 1370304c731SJamie Gritton #ifdef INET6 1380304c731SJamie Gritton [3] = "noip6", 1390304c731SJamie Gritton #endif 1400304c731SJamie Gritton }; 1410304c731SJamie Gritton 1420304c731SJamie Gritton static char *pr_allow_names[] = { 1430304c731SJamie Gritton "allow.set_hostname", 1440304c731SJamie Gritton "allow.sysvipc", 1450304c731SJamie Gritton "allow.raw_sockets", 1460304c731SJamie Gritton "allow.chflags", 1470304c731SJamie Gritton "allow.mount", 1480304c731SJamie Gritton "allow.quotas", 1490304c731SJamie Gritton "allow.jails", 1500304c731SJamie Gritton "allow.socket_af", 1510304c731SJamie Gritton }; 1520304c731SJamie Gritton 1530304c731SJamie Gritton static char *pr_allow_nonames[] = { 1540304c731SJamie Gritton "allow.noset_hostname", 1550304c731SJamie Gritton "allow.nosysvipc", 1560304c731SJamie Gritton "allow.noraw_sockets", 1570304c731SJamie Gritton "allow.nochflags", 1580304c731SJamie Gritton "allow.nomount", 1590304c731SJamie Gritton "allow.noquotas", 1600304c731SJamie Gritton "allow.nojails", 1610304c731SJamie Gritton "allow.nosocket_af", 1620304c731SJamie Gritton }; 1630304c731SJamie Gritton 1640304c731SJamie Gritton #define JAIL_DEFAULT_ALLOW PR_ALLOW_SET_HOSTNAME 1650304c731SJamie Gritton static unsigned jail_default_allow = JAIL_DEFAULT_ALLOW; 1660304c731SJamie Gritton static int jail_default_enforce_statfs = 2; 1670304c731SJamie Gritton #if defined(INET) || defined(INET6) 168e92e0574SJamie Gritton static unsigned jail_max_af_ips = 255; 1690304c731SJamie Gritton #endif 1700304c731SJamie Gritton 171413628a7SBjoern A. Zeeb #ifdef INET 172413628a7SBjoern A. Zeeb static int 173413628a7SBjoern A. Zeeb qcmp_v4(const void *ip1, const void *ip2) 174413628a7SBjoern A. Zeeb { 175413628a7SBjoern A. Zeeb in_addr_t iaa, iab; 176413628a7SBjoern A. Zeeb 177413628a7SBjoern A. Zeeb /* 178413628a7SBjoern A. Zeeb * We need to compare in HBO here to get the list sorted as expected 179413628a7SBjoern A. Zeeb * by the result of the code. Sorting NBO addresses gives you 180413628a7SBjoern A. Zeeb * interesting results. If you do not understand, do not try. 181413628a7SBjoern A. Zeeb */ 182413628a7SBjoern A. Zeeb iaa = ntohl(((const struct in_addr *)ip1)->s_addr); 183413628a7SBjoern A. Zeeb iab = ntohl(((const struct in_addr *)ip2)->s_addr); 184413628a7SBjoern A. Zeeb 185413628a7SBjoern A. Zeeb /* 186413628a7SBjoern A. Zeeb * Do not simply return the difference of the two numbers, the int is 187413628a7SBjoern A. Zeeb * not wide enough. 188413628a7SBjoern A. Zeeb */ 189413628a7SBjoern A. Zeeb if (iaa > iab) 190413628a7SBjoern A. Zeeb return (1); 191413628a7SBjoern A. Zeeb else if (iaa < iab) 192413628a7SBjoern A. Zeeb return (-1); 193413628a7SBjoern A. Zeeb else 194413628a7SBjoern A. Zeeb return (0); 195413628a7SBjoern A. Zeeb } 196413628a7SBjoern A. Zeeb #endif 197413628a7SBjoern A. Zeeb 198413628a7SBjoern A. Zeeb #ifdef INET6 199413628a7SBjoern A. Zeeb static int 200413628a7SBjoern A. Zeeb qcmp_v6(const void *ip1, const void *ip2) 201413628a7SBjoern A. Zeeb { 202413628a7SBjoern A. Zeeb const struct in6_addr *ia6a, *ia6b; 203413628a7SBjoern A. Zeeb int i, rc; 204413628a7SBjoern A. Zeeb 205413628a7SBjoern A. Zeeb ia6a = (const struct in6_addr *)ip1; 206413628a7SBjoern A. Zeeb ia6b = (const struct in6_addr *)ip2; 207413628a7SBjoern A. Zeeb 208413628a7SBjoern A. Zeeb rc = 0; 209413628a7SBjoern A. Zeeb for (i = 0; rc == 0 && i < sizeof(struct in6_addr); i++) { 210413628a7SBjoern A. Zeeb if (ia6a->s6_addr[i] > ia6b->s6_addr[i]) 211413628a7SBjoern A. Zeeb rc = 1; 212413628a7SBjoern A. Zeeb else if (ia6a->s6_addr[i] < ia6b->s6_addr[i]) 213413628a7SBjoern A. Zeeb rc = -1; 214413628a7SBjoern A. Zeeb } 215413628a7SBjoern A. Zeeb return (rc); 216413628a7SBjoern A. Zeeb } 217413628a7SBjoern A. Zeeb #endif 218413628a7SBjoern A. Zeeb 219116734c4SMatthew Dillon /* 2209ddb7954SMike Barcroft * struct jail_args { 2219ddb7954SMike Barcroft * struct jail *jail; 2229ddb7954SMike Barcroft * }; 223116734c4SMatthew Dillon */ 22475c13541SPoul-Henning Kamp int 2259ddb7954SMike Barcroft jail(struct thread *td, struct jail_args *uap) 22675c13541SPoul-Henning Kamp { 227413628a7SBjoern A. Zeeb uint32_t version; 228413628a7SBjoern A. Zeeb int error; 2290304c731SJamie Gritton struct jail j; 230413628a7SBjoern A. Zeeb 231413628a7SBjoern A. Zeeb error = copyin(uap->jail, &version, sizeof(uint32_t)); 232413628a7SBjoern A. Zeeb if (error) 233413628a7SBjoern A. Zeeb return (error); 234413628a7SBjoern A. Zeeb 235413628a7SBjoern A. Zeeb switch (version) { 236413628a7SBjoern A. Zeeb case 0: 237413628a7SBjoern A. Zeeb { 238413628a7SBjoern A. Zeeb struct jail_v0 j0; 239413628a7SBjoern A. Zeeb 2400304c731SJamie Gritton /* FreeBSD single IPv4 jails. */ 2410304c731SJamie Gritton bzero(&j, sizeof(struct jail)); 242413628a7SBjoern A. Zeeb error = copyin(uap->jail, &j0, sizeof(struct jail_v0)); 243413628a7SBjoern A. Zeeb if (error) 244413628a7SBjoern A. Zeeb return (error); 2450304c731SJamie Gritton j.version = j0.version; 2460304c731SJamie Gritton j.path = j0.path; 2470304c731SJamie Gritton j.hostname = j0.hostname; 2480304c731SJamie Gritton j.ip4s = j0.ip_number; 249413628a7SBjoern A. Zeeb break; 250413628a7SBjoern A. Zeeb } 251413628a7SBjoern A. Zeeb 252413628a7SBjoern A. Zeeb case 1: 253413628a7SBjoern A. Zeeb /* 254413628a7SBjoern A. Zeeb * Version 1 was used by multi-IPv4 jail implementations 255413628a7SBjoern A. Zeeb * that never made it into the official kernel. 256413628a7SBjoern A. Zeeb */ 257413628a7SBjoern A. Zeeb return (EINVAL); 258413628a7SBjoern A. Zeeb 259413628a7SBjoern A. Zeeb case 2: /* JAIL_API_VERSION */ 260413628a7SBjoern A. Zeeb /* FreeBSD multi-IPv4/IPv6,noIP jails. */ 261413628a7SBjoern A. Zeeb error = copyin(uap->jail, &j, sizeof(struct jail)); 262413628a7SBjoern A. Zeeb if (error) 263413628a7SBjoern A. Zeeb return (error); 2640304c731SJamie Gritton break; 2650304c731SJamie Gritton 2660304c731SJamie Gritton default: 2670304c731SJamie Gritton /* Sci-Fi jails are not supported, sorry. */ 2680304c731SJamie Gritton return (EINVAL); 2690304c731SJamie Gritton } 2700304c731SJamie Gritton return (kern_jail(td, &j)); 2710304c731SJamie Gritton } 2720304c731SJamie Gritton 2730304c731SJamie Gritton int 2740304c731SJamie Gritton kern_jail(struct thread *td, struct jail *j) 2750304c731SJamie Gritton { 276e92e0574SJamie Gritton struct iovec optiov[2 * (4 277e92e0574SJamie Gritton + sizeof(pr_allow_names) / sizeof(pr_allow_names[0]) 278e92e0574SJamie Gritton #ifdef INET 279e92e0574SJamie Gritton + 1 280e92e0574SJamie Gritton #endif 281e92e0574SJamie Gritton #ifdef INET6 282e92e0574SJamie Gritton + 1 283e92e0574SJamie Gritton #endif 284e92e0574SJamie Gritton )]; 2850304c731SJamie Gritton struct uio opt; 2860304c731SJamie Gritton char *u_path, *u_hostname, *u_name; 2870304c731SJamie Gritton #ifdef INET 288e92e0574SJamie Gritton uint32_t ip4s; 2890304c731SJamie Gritton struct in_addr *u_ip4; 2900304c731SJamie Gritton #endif 2910304c731SJamie Gritton #ifdef INET6 2920304c731SJamie Gritton struct in6_addr *u_ip6; 2930304c731SJamie Gritton #endif 2940304c731SJamie Gritton size_t tmplen; 2950304c731SJamie Gritton int error, enforce_statfs, fi; 2960304c731SJamie Gritton 2970304c731SJamie Gritton bzero(&optiov, sizeof(optiov)); 2980304c731SJamie Gritton opt.uio_iov = optiov; 2990304c731SJamie Gritton opt.uio_iovcnt = 0; 3000304c731SJamie Gritton opt.uio_offset = -1; 3010304c731SJamie Gritton opt.uio_resid = -1; 3020304c731SJamie Gritton opt.uio_segflg = UIO_SYSSPACE; 3030304c731SJamie Gritton opt.uio_rw = UIO_READ; 3040304c731SJamie Gritton opt.uio_td = td; 3050304c731SJamie Gritton 3060304c731SJamie Gritton /* Set permissions for top-level jails from sysctls. */ 3070304c731SJamie Gritton if (!jailed(td->td_ucred)) { 3080304c731SJamie Gritton for (fi = 0; fi < sizeof(pr_allow_names) / 3090304c731SJamie Gritton sizeof(pr_allow_names[0]); fi++) { 3100304c731SJamie Gritton optiov[opt.uio_iovcnt].iov_base = 3110304c731SJamie Gritton (jail_default_allow & (1 << fi)) 3120304c731SJamie Gritton ? pr_allow_names[fi] : pr_allow_nonames[fi]; 3130304c731SJamie Gritton optiov[opt.uio_iovcnt].iov_len = 3140304c731SJamie Gritton strlen(optiov[opt.uio_iovcnt].iov_base) + 1; 3150304c731SJamie Gritton opt.uio_iovcnt += 2; 3160304c731SJamie Gritton } 3170304c731SJamie Gritton optiov[opt.uio_iovcnt].iov_base = "enforce_statfs"; 3180304c731SJamie Gritton optiov[opt.uio_iovcnt].iov_len = sizeof("enforce_statfs"); 3190304c731SJamie Gritton opt.uio_iovcnt++; 3200304c731SJamie Gritton enforce_statfs = jail_default_enforce_statfs; 3210304c731SJamie Gritton optiov[opt.uio_iovcnt].iov_base = &enforce_statfs; 3220304c731SJamie Gritton optiov[opt.uio_iovcnt].iov_len = sizeof(enforce_statfs); 3230304c731SJamie Gritton opt.uio_iovcnt++; 3240304c731SJamie Gritton } 3250304c731SJamie Gritton 326b38ff370SJamie Gritton tmplen = MAXPATHLEN + MAXHOSTNAMELEN + MAXHOSTNAMELEN; 327b38ff370SJamie Gritton #ifdef INET 3280304c731SJamie Gritton ip4s = (j->version == 0) ? 1 : j->ip4s; 3290304c731SJamie Gritton if (ip4s > jail_max_af_ips) 330b38ff370SJamie Gritton return (EINVAL); 3310304c731SJamie Gritton tmplen += ip4s * sizeof(struct in_addr); 332b38ff370SJamie Gritton #else 3330304c731SJamie Gritton if (j->ip4s > 0) 334b38ff370SJamie Gritton return (EINVAL); 335b38ff370SJamie Gritton #endif 336b38ff370SJamie Gritton #ifdef INET6 3370304c731SJamie Gritton if (j->ip6s > jail_max_af_ips) 338b38ff370SJamie Gritton return (EINVAL); 3390304c731SJamie Gritton tmplen += j->ip6s * sizeof(struct in6_addr); 340b38ff370SJamie Gritton #else 3410304c731SJamie Gritton if (j->ip6s > 0) 342b38ff370SJamie Gritton return (EINVAL); 343b38ff370SJamie Gritton #endif 344b38ff370SJamie Gritton u_path = malloc(tmplen, M_TEMP, M_WAITOK); 345b38ff370SJamie Gritton u_hostname = u_path + MAXPATHLEN; 346b38ff370SJamie Gritton u_name = u_hostname + MAXHOSTNAMELEN; 347b38ff370SJamie Gritton #ifdef INET 348b38ff370SJamie Gritton u_ip4 = (struct in_addr *)(u_name + MAXHOSTNAMELEN); 349b38ff370SJamie Gritton #endif 350b38ff370SJamie Gritton #ifdef INET6 351b38ff370SJamie Gritton #ifdef INET 3520304c731SJamie Gritton u_ip6 = (struct in6_addr *)(u_ip4 + ip4s); 353b38ff370SJamie Gritton #else 354b38ff370SJamie Gritton u_ip6 = (struct in6_addr *)(u_name + MAXHOSTNAMELEN); 355b38ff370SJamie Gritton #endif 356b38ff370SJamie Gritton #endif 3570304c731SJamie Gritton optiov[opt.uio_iovcnt].iov_base = "path"; 3580304c731SJamie Gritton optiov[opt.uio_iovcnt].iov_len = sizeof("path"); 3590304c731SJamie Gritton opt.uio_iovcnt++; 3600304c731SJamie Gritton optiov[opt.uio_iovcnt].iov_base = u_path; 3610304c731SJamie Gritton error = copyinstr(j->path, u_path, MAXPATHLEN, 3620304c731SJamie Gritton &optiov[opt.uio_iovcnt].iov_len); 363b38ff370SJamie Gritton if (error) { 364b38ff370SJamie Gritton free(u_path, M_TEMP); 365b38ff370SJamie Gritton return (error); 366b38ff370SJamie Gritton } 3670304c731SJamie Gritton opt.uio_iovcnt++; 3680304c731SJamie Gritton optiov[opt.uio_iovcnt].iov_base = "host.hostname"; 3690304c731SJamie Gritton optiov[opt.uio_iovcnt].iov_len = sizeof("host.hostname"); 3700304c731SJamie Gritton opt.uio_iovcnt++; 3710304c731SJamie Gritton optiov[opt.uio_iovcnt].iov_base = u_hostname; 3720304c731SJamie Gritton error = copyinstr(j->hostname, u_hostname, MAXHOSTNAMELEN, 3730304c731SJamie Gritton &optiov[opt.uio_iovcnt].iov_len); 374b38ff370SJamie Gritton if (error) { 375b38ff370SJamie Gritton free(u_path, M_TEMP); 376b38ff370SJamie Gritton return (error); 377b38ff370SJamie Gritton } 3780304c731SJamie Gritton opt.uio_iovcnt++; 3790304c731SJamie Gritton if (j->jailname != NULL) { 380b38ff370SJamie Gritton optiov[opt.uio_iovcnt].iov_base = "name"; 381b38ff370SJamie Gritton optiov[opt.uio_iovcnt].iov_len = sizeof("name"); 382b38ff370SJamie Gritton opt.uio_iovcnt++; 383b38ff370SJamie Gritton optiov[opt.uio_iovcnt].iov_base = u_name; 3840304c731SJamie Gritton error = copyinstr(j->jailname, u_name, MAXHOSTNAMELEN, 385b38ff370SJamie Gritton &optiov[opt.uio_iovcnt].iov_len); 386b38ff370SJamie Gritton if (error) { 387b38ff370SJamie Gritton free(u_path, M_TEMP); 388b38ff370SJamie Gritton return (error); 389b38ff370SJamie Gritton } 390b38ff370SJamie Gritton opt.uio_iovcnt++; 391b38ff370SJamie Gritton } 392b38ff370SJamie Gritton #ifdef INET 393b38ff370SJamie Gritton optiov[opt.uio_iovcnt].iov_base = "ip4.addr"; 394b38ff370SJamie Gritton optiov[opt.uio_iovcnt].iov_len = sizeof("ip4.addr"); 395b38ff370SJamie Gritton opt.uio_iovcnt++; 396b38ff370SJamie Gritton optiov[opt.uio_iovcnt].iov_base = u_ip4; 3970304c731SJamie Gritton optiov[opt.uio_iovcnt].iov_len = ip4s * sizeof(struct in_addr); 3980304c731SJamie Gritton if (j->version == 0) 3990304c731SJamie Gritton u_ip4->s_addr = j->ip4s; 4000304c731SJamie Gritton else { 4010304c731SJamie Gritton error = copyin(j->ip4, u_ip4, optiov[opt.uio_iovcnt].iov_len); 402b38ff370SJamie Gritton if (error) { 403b38ff370SJamie Gritton free(u_path, M_TEMP); 404b38ff370SJamie Gritton return (error); 405b38ff370SJamie Gritton } 4060304c731SJamie Gritton } 407b38ff370SJamie Gritton opt.uio_iovcnt++; 408b38ff370SJamie Gritton #endif 409b38ff370SJamie Gritton #ifdef INET6 410b38ff370SJamie Gritton optiov[opt.uio_iovcnt].iov_base = "ip6.addr"; 411b38ff370SJamie Gritton optiov[opt.uio_iovcnt].iov_len = sizeof("ip6.addr"); 412b38ff370SJamie Gritton opt.uio_iovcnt++; 413b38ff370SJamie Gritton optiov[opt.uio_iovcnt].iov_base = u_ip6; 4140304c731SJamie Gritton optiov[opt.uio_iovcnt].iov_len = j->ip6s * sizeof(struct in6_addr); 4150304c731SJamie Gritton error = copyin(j->ip6, u_ip6, optiov[opt.uio_iovcnt].iov_len); 416b38ff370SJamie Gritton if (error) { 417b38ff370SJamie Gritton free(u_path, M_TEMP); 418b38ff370SJamie Gritton return (error); 419b38ff370SJamie Gritton } 420b38ff370SJamie Gritton opt.uio_iovcnt++; 421b38ff370SJamie Gritton #endif 4220304c731SJamie Gritton KASSERT(opt.uio_iovcnt <= sizeof(optiov) / sizeof(optiov[0]), 4230304c731SJamie Gritton ("kern_jail: too many iovecs (%d)", opt.uio_iovcnt)); 424b38ff370SJamie Gritton error = kern_jail_set(td, &opt, JAIL_CREATE | JAIL_ATTACH); 425b38ff370SJamie Gritton free(u_path, M_TEMP); 426b38ff370SJamie Gritton return (error); 427b38ff370SJamie Gritton } 428b38ff370SJamie Gritton 4290304c731SJamie Gritton 430b38ff370SJamie Gritton /* 431b38ff370SJamie Gritton * struct jail_set_args { 432b38ff370SJamie Gritton * struct iovec *iovp; 433b38ff370SJamie Gritton * unsigned int iovcnt; 434b38ff370SJamie Gritton * int flags; 435b38ff370SJamie Gritton * }; 436b38ff370SJamie Gritton */ 437b38ff370SJamie Gritton int 438b38ff370SJamie Gritton jail_set(struct thread *td, struct jail_set_args *uap) 439b38ff370SJamie Gritton { 440b38ff370SJamie Gritton struct uio *auio; 441b38ff370SJamie Gritton int error; 442b38ff370SJamie Gritton 443b38ff370SJamie Gritton /* Check that we have an even number of iovecs. */ 444b38ff370SJamie Gritton if (uap->iovcnt & 1) 445b38ff370SJamie Gritton return (EINVAL); 446b38ff370SJamie Gritton 447b38ff370SJamie Gritton error = copyinuio(uap->iovp, uap->iovcnt, &auio); 448b38ff370SJamie Gritton if (error) 449b38ff370SJamie Gritton return (error); 450b38ff370SJamie Gritton error = kern_jail_set(td, auio, uap->flags); 451b38ff370SJamie Gritton free(auio, M_IOV); 452b38ff370SJamie Gritton return (error); 453413628a7SBjoern A. Zeeb } 454413628a7SBjoern A. Zeeb 455413628a7SBjoern A. Zeeb int 456b38ff370SJamie Gritton kern_jail_set(struct thread *td, struct uio *optuio, int flags) 457413628a7SBjoern A. Zeeb { 458fd7a8150SMike Barcroft struct nameidata nd; 459b38ff370SJamie Gritton #ifdef INET 460b38ff370SJamie Gritton struct in_addr *ip4; 461413628a7SBjoern A. Zeeb #endif 462b38ff370SJamie Gritton #ifdef INET6 463b38ff370SJamie Gritton struct in6_addr *ip6; 464b38ff370SJamie Gritton #endif 465b38ff370SJamie Gritton struct vfsopt *opt; 466b38ff370SJamie Gritton struct vfsoptlist *opts; 4670304c731SJamie Gritton struct prison *pr, *deadpr, *mypr, *ppr, *tpr; 468b38ff370SJamie Gritton struct vnode *root; 46976ca6f88SJamie Gritton char *domain, *errmsg, *host, *name, *p, *path, *uuid; 4700304c731SJamie Gritton #if defined(INET) || defined(INET6) 471b38ff370SJamie Gritton void *op; 4720304c731SJamie Gritton #endif 47376ca6f88SJamie Gritton unsigned long hid; 4740304c731SJamie Gritton size_t namelen, onamelen; 4750304c731SJamie Gritton int created, cuflags, descend, enforce, error, errmsg_len, errmsg_pos; 47676ca6f88SJamie Gritton int gotenforce, gothid, gotslevel, fi, jid, len; 477b38ff370SJamie Gritton int slevel, vfslocked; 478d465a41dSBjoern A. Zeeb #if defined(INET) || defined(INET6) 4790304c731SJamie Gritton int ii, ij; 480413628a7SBjoern A. Zeeb #endif 481413628a7SBjoern A. Zeeb #ifdef INET 4820304c731SJamie Gritton int ip4s, ip4a, redo_ip4; 483413628a7SBjoern A. Zeeb #endif 484b38ff370SJamie Gritton #ifdef INET6 4850304c731SJamie Gritton int ip6s, ip6a, redo_ip6; 486b38ff370SJamie Gritton #endif 487b38ff370SJamie Gritton unsigned pr_flags, ch_flags; 4880304c731SJamie Gritton unsigned pr_allow, ch_allow, tallow; 489b38ff370SJamie Gritton char numbuf[12]; 490b38ff370SJamie Gritton 491b38ff370SJamie Gritton error = priv_check(td, PRIV_JAIL_SET); 492b38ff370SJamie Gritton if (!error && (flags & JAIL_ATTACH)) 493b38ff370SJamie Gritton error = priv_check(td, PRIV_JAIL_ATTACH); 494b38ff370SJamie Gritton if (error) 49575c13541SPoul-Henning Kamp return (error); 4960304c731SJamie Gritton mypr = ppr = td->td_ucred->cr_prison; 4970304c731SJamie Gritton if ((flags & JAIL_CREATE) && !(mypr->pr_allow & PR_ALLOW_JAILS)) 4980304c731SJamie Gritton return (EPERM); 499b38ff370SJamie Gritton if (flags & ~JAIL_SET_MASK) 500b38ff370SJamie Gritton return (EINVAL); 501b38ff370SJamie Gritton 502b38ff370SJamie Gritton /* 503b38ff370SJamie Gritton * Check all the parameters before committing to anything. Not all 504b38ff370SJamie Gritton * errors can be caught early, but we may as well try. Also, this 505b38ff370SJamie Gritton * takes care of some expensive stuff (path lookup) before getting 506b38ff370SJamie Gritton * the allprison lock. 507b38ff370SJamie Gritton * 508b38ff370SJamie Gritton * XXX Jails are not filesystems, and jail parameters are not mount 509b38ff370SJamie Gritton * options. But it makes more sense to re-use the vfsopt code 510b38ff370SJamie Gritton * than duplicate it under a different name. 511b38ff370SJamie Gritton */ 512b38ff370SJamie Gritton error = vfs_buildopts(optuio, &opts); 513b38ff370SJamie Gritton if (error) 514b38ff370SJamie Gritton return (error); 515b38ff370SJamie Gritton #ifdef INET 5160304c731SJamie Gritton ip4a = 0; 517b38ff370SJamie Gritton ip4 = NULL; 518b38ff370SJamie Gritton #endif 519b38ff370SJamie Gritton #ifdef INET6 5200304c731SJamie Gritton ip6a = 0; 521b38ff370SJamie Gritton ip6 = NULL; 522b38ff370SJamie Gritton #endif 523b38ff370SJamie Gritton 5240304c731SJamie Gritton #if defined(INET) || defined(INET6) 5250304c731SJamie Gritton again: 5260304c731SJamie Gritton #endif 527b38ff370SJamie Gritton error = vfs_copyopt(opts, "jid", &jid, sizeof(jid)); 528b38ff370SJamie Gritton if (error == ENOENT) 529b38ff370SJamie Gritton jid = 0; 530b38ff370SJamie Gritton else if (error != 0) 531b38ff370SJamie Gritton goto done_free; 532b38ff370SJamie Gritton 533b38ff370SJamie Gritton error = vfs_copyopt(opts, "securelevel", &slevel, sizeof(slevel)); 534b38ff370SJamie Gritton if (error == ENOENT) 535b38ff370SJamie Gritton gotslevel = 0; 536b38ff370SJamie Gritton else if (error != 0) 537b38ff370SJamie Gritton goto done_free; 538b38ff370SJamie Gritton else 539b38ff370SJamie Gritton gotslevel = 1; 540b38ff370SJamie Gritton 5410304c731SJamie Gritton error = vfs_copyopt(opts, "enforce_statfs", &enforce, sizeof(enforce)); 5420304c731SJamie Gritton gotenforce = (error == 0); 5430304c731SJamie Gritton if (gotenforce) { 5440304c731SJamie Gritton if (enforce < 0 || enforce > 2) 5450304c731SJamie Gritton return (EINVAL); 5460304c731SJamie Gritton } else if (error != ENOENT) 5470304c731SJamie Gritton goto done_free; 5480304c731SJamie Gritton 549b38ff370SJamie Gritton pr_flags = ch_flags = 0; 5500304c731SJamie Gritton for (fi = 0; fi < sizeof(pr_flag_names) / sizeof(pr_flag_names[0]); 5510304c731SJamie Gritton fi++) { 5520304c731SJamie Gritton if (pr_flag_names[fi] == NULL) 5530304c731SJamie Gritton continue; 5540304c731SJamie Gritton vfs_flagopt(opts, pr_flag_names[fi], &pr_flags, 1 << fi); 5550304c731SJamie Gritton vfs_flagopt(opts, pr_flag_nonames[fi], &ch_flags, 1 << fi); 5560304c731SJamie Gritton } 557b38ff370SJamie Gritton ch_flags |= pr_flags; 558b38ff370SJamie Gritton if ((flags & (JAIL_CREATE | JAIL_UPDATE | JAIL_ATTACH)) == JAIL_CREATE 559b38ff370SJamie Gritton && !(pr_flags & PR_PERSIST)) { 560b38ff370SJamie Gritton error = EINVAL; 561b38ff370SJamie Gritton vfs_opterror(opts, "new jail must persist or attach"); 562b38ff370SJamie Gritton goto done_errmsg; 563b38ff370SJamie Gritton } 564b38ff370SJamie Gritton 5650304c731SJamie Gritton pr_allow = ch_allow = 0; 5660304c731SJamie Gritton for (fi = 0; fi < sizeof(pr_allow_names) / sizeof(pr_allow_names[0]); 5670304c731SJamie Gritton fi++) { 5680304c731SJamie Gritton vfs_flagopt(opts, pr_allow_names[fi], &pr_allow, 1 << fi); 5690304c731SJamie Gritton vfs_flagopt(opts, pr_allow_nonames[fi], &ch_allow, 1 << fi); 5700304c731SJamie Gritton } 5710304c731SJamie Gritton ch_allow |= pr_allow; 5720304c731SJamie Gritton 573b38ff370SJamie Gritton error = vfs_getopt(opts, "name", (void **)&name, &len); 574b38ff370SJamie Gritton if (error == ENOENT) 575b38ff370SJamie Gritton name = NULL; 576b38ff370SJamie Gritton else if (error != 0) 577b38ff370SJamie Gritton goto done_free; 578b38ff370SJamie Gritton else { 579b38ff370SJamie Gritton if (len == 0 || name[len - 1] != '\0') { 580b38ff370SJamie Gritton error = EINVAL; 581b38ff370SJamie Gritton goto done_free; 582b38ff370SJamie Gritton } 583b38ff370SJamie Gritton if (len > MAXHOSTNAMELEN) { 584b38ff370SJamie Gritton error = ENAMETOOLONG; 585b38ff370SJamie Gritton goto done_free; 586b38ff370SJamie Gritton } 587b38ff370SJamie Gritton } 588b38ff370SJamie Gritton 589b38ff370SJamie Gritton error = vfs_getopt(opts, "host.hostname", (void **)&host, &len); 590b38ff370SJamie Gritton if (error == ENOENT) 591b38ff370SJamie Gritton host = NULL; 592b38ff370SJamie Gritton else if (error != 0) 593b38ff370SJamie Gritton goto done_free; 594b38ff370SJamie Gritton else { 59576ca6f88SJamie Gritton ch_flags |= PR_HOST; 59676ca6f88SJamie Gritton pr_flags |= PR_HOST; 597b38ff370SJamie Gritton if (len == 0 || host[len - 1] != '\0') { 598b38ff370SJamie Gritton error = EINVAL; 599b38ff370SJamie Gritton goto done_free; 600b38ff370SJamie Gritton } 601b38ff370SJamie Gritton if (len > MAXHOSTNAMELEN) { 602b38ff370SJamie Gritton error = ENAMETOOLONG; 603b38ff370SJamie Gritton goto done_free; 604b38ff370SJamie Gritton } 605b38ff370SJamie Gritton } 606b38ff370SJamie Gritton 60776ca6f88SJamie Gritton error = vfs_getopt(opts, "host.domainname", (void **)&domain, &len); 60876ca6f88SJamie Gritton if (error == ENOENT) 60976ca6f88SJamie Gritton domain = NULL; 61076ca6f88SJamie Gritton else if (error != 0) 61176ca6f88SJamie Gritton goto done_free; 61276ca6f88SJamie Gritton else { 61376ca6f88SJamie Gritton ch_flags |= PR_HOST; 61476ca6f88SJamie Gritton pr_flags |= PR_HOST; 61576ca6f88SJamie Gritton if (len == 0 || domain[len - 1] != '\0') { 61676ca6f88SJamie Gritton error = EINVAL; 61776ca6f88SJamie Gritton goto done_free; 61876ca6f88SJamie Gritton } 61976ca6f88SJamie Gritton if (len > MAXHOSTNAMELEN) { 62076ca6f88SJamie Gritton error = ENAMETOOLONG; 62176ca6f88SJamie Gritton goto done_free; 62276ca6f88SJamie Gritton } 62376ca6f88SJamie Gritton } 62476ca6f88SJamie Gritton 62576ca6f88SJamie Gritton error = vfs_getopt(opts, "host.hostuuid", (void **)&uuid, &len); 62676ca6f88SJamie Gritton if (error == ENOENT) 62776ca6f88SJamie Gritton uuid = NULL; 62876ca6f88SJamie Gritton else if (error != 0) 62976ca6f88SJamie Gritton goto done_free; 63076ca6f88SJamie Gritton else { 63176ca6f88SJamie Gritton ch_flags |= PR_HOST; 63276ca6f88SJamie Gritton pr_flags |= PR_HOST; 63376ca6f88SJamie Gritton if (len == 0 || uuid[len - 1] != '\0') { 63476ca6f88SJamie Gritton error = EINVAL; 63576ca6f88SJamie Gritton goto done_free; 63676ca6f88SJamie Gritton } 63776ca6f88SJamie Gritton if (len > HOSTUUIDLEN) { 63876ca6f88SJamie Gritton error = ENAMETOOLONG; 63976ca6f88SJamie Gritton goto done_free; 64076ca6f88SJamie Gritton } 64176ca6f88SJamie Gritton } 64276ca6f88SJamie Gritton 64376ca6f88SJamie Gritton #ifdef COMPAT_IA32 64476ca6f88SJamie Gritton if (td->td_proc->p_sysent->sv_flags & SV_IA32) { 64576ca6f88SJamie Gritton uint32_t hid32; 64676ca6f88SJamie Gritton 64776ca6f88SJamie Gritton error = vfs_copyopt(opts, "host.hostid", &hid32, sizeof(hid32)); 64876ca6f88SJamie Gritton hid = hid32; 64976ca6f88SJamie Gritton } else 65076ca6f88SJamie Gritton #endif 65176ca6f88SJamie Gritton error = vfs_copyopt(opts, "host.hostid", &hid, sizeof(hid)); 65276ca6f88SJamie Gritton if (error == ENOENT) 65376ca6f88SJamie Gritton gothid = 0; 65476ca6f88SJamie Gritton else if (error != 0) 65576ca6f88SJamie Gritton goto done_free; 65676ca6f88SJamie Gritton else { 65776ca6f88SJamie Gritton gothid = 1; 65876ca6f88SJamie Gritton ch_flags |= PR_HOST; 65976ca6f88SJamie Gritton pr_flags |= PR_HOST; 66076ca6f88SJamie Gritton } 66176ca6f88SJamie Gritton 6620304c731SJamie Gritton /* This might be the second time around for this option. */ 663b38ff370SJamie Gritton #ifdef INET 664b38ff370SJamie Gritton error = vfs_getopt(opts, "ip4.addr", &op, &ip4s); 665b38ff370SJamie Gritton if (error == ENOENT) 666b38ff370SJamie Gritton ip4s = -1; 667b38ff370SJamie Gritton else if (error != 0) 668b38ff370SJamie Gritton goto done_free; 669b38ff370SJamie Gritton else if (ip4s & (sizeof(*ip4) - 1)) { 670b38ff370SJamie Gritton error = EINVAL; 671b38ff370SJamie Gritton goto done_free; 6720304c731SJamie Gritton } else { 6730304c731SJamie Gritton ch_flags |= PR_IP4_USER; 6740304c731SJamie Gritton pr_flags |= PR_IP4_USER; 6750304c731SJamie Gritton if (ip4s > 0) { 676b38ff370SJamie Gritton ip4s /= sizeof(*ip4); 677b38ff370SJamie Gritton if (ip4s > jail_max_af_ips) { 678b38ff370SJamie Gritton error = EINVAL; 679b38ff370SJamie Gritton vfs_opterror(opts, "too many IPv4 addresses"); 680b38ff370SJamie Gritton goto done_errmsg; 681b38ff370SJamie Gritton } 6820304c731SJamie Gritton if (ip4a < ip4s) { 6830304c731SJamie Gritton ip4a = ip4s; 6840304c731SJamie Gritton free(ip4, M_PRISON); 6850304c731SJamie Gritton ip4 = NULL; 6860304c731SJamie Gritton } 6870304c731SJamie Gritton if (ip4 == NULL) 6880304c731SJamie Gritton ip4 = malloc(ip4a * sizeof(*ip4), M_PRISON, 6890304c731SJamie Gritton M_WAITOK); 690b38ff370SJamie Gritton bcopy(op, ip4, ip4s * sizeof(*ip4)); 691b38ff370SJamie Gritton /* 6920304c731SJamie Gritton * IP addresses are all sorted but ip[0] to preserve 6930304c731SJamie Gritton * the primary IP address as given from userland. 6940304c731SJamie Gritton * This special IP is used for unbound outgoing 6950304c731SJamie Gritton * connections as well for "loopback" traffic. 696b38ff370SJamie Gritton */ 697b38ff370SJamie Gritton if (ip4s > 1) 698b38ff370SJamie Gritton qsort(ip4 + 1, ip4s - 1, sizeof(*ip4), qcmp_v4); 699b38ff370SJamie Gritton /* 7000304c731SJamie Gritton * Check for duplicate addresses and do some simple 7010304c731SJamie Gritton * zero and broadcast checks. If users give other bogus 7020304c731SJamie Gritton * addresses it is their problem. 703b38ff370SJamie Gritton * 7040304c731SJamie Gritton * We do not have to care about byte order for these 7050304c731SJamie Gritton * checks so we will do them in NBO. 706b38ff370SJamie Gritton */ 707b38ff370SJamie Gritton for (ii = 0; ii < ip4s; ii++) { 708b38ff370SJamie Gritton if (ip4[ii].s_addr == INADDR_ANY || 709b38ff370SJamie Gritton ip4[ii].s_addr == INADDR_BROADCAST) { 710b38ff370SJamie Gritton error = EINVAL; 711b38ff370SJamie Gritton goto done_free; 712b38ff370SJamie Gritton } 713b38ff370SJamie Gritton if ((ii+1) < ip4s && 714b38ff370SJamie Gritton (ip4[0].s_addr == ip4[ii+1].s_addr || 715b38ff370SJamie Gritton ip4[ii].s_addr == ip4[ii+1].s_addr)) { 716b38ff370SJamie Gritton error = EINVAL; 717b38ff370SJamie Gritton goto done_free; 718b38ff370SJamie Gritton } 719b38ff370SJamie Gritton } 720b38ff370SJamie Gritton } 7210304c731SJamie Gritton } 722b38ff370SJamie Gritton #endif 723b38ff370SJamie Gritton 724b38ff370SJamie Gritton #ifdef INET6 725b38ff370SJamie Gritton error = vfs_getopt(opts, "ip6.addr", &op, &ip6s); 726b38ff370SJamie Gritton if (error == ENOENT) 727b38ff370SJamie Gritton ip6s = -1; 728b38ff370SJamie Gritton else if (error != 0) 729b38ff370SJamie Gritton goto done_free; 730b38ff370SJamie Gritton else if (ip6s & (sizeof(*ip6) - 1)) { 731b38ff370SJamie Gritton error = EINVAL; 732b38ff370SJamie Gritton goto done_free; 7330304c731SJamie Gritton } else { 7340304c731SJamie Gritton ch_flags |= PR_IP6_USER; 7350304c731SJamie Gritton pr_flags |= PR_IP6_USER; 7360304c731SJamie Gritton if (ip6s > 0) { 737b38ff370SJamie Gritton ip6s /= sizeof(*ip6); 738b38ff370SJamie Gritton if (ip6s > jail_max_af_ips) { 739b38ff370SJamie Gritton error = EINVAL; 740b38ff370SJamie Gritton vfs_opterror(opts, "too many IPv6 addresses"); 741b38ff370SJamie Gritton goto done_errmsg; 742b38ff370SJamie Gritton } 7430304c731SJamie Gritton if (ip6a < ip6s) { 7440304c731SJamie Gritton ip6a = ip6s; 7450304c731SJamie Gritton free(ip6, M_PRISON); 7460304c731SJamie Gritton ip6 = NULL; 7470304c731SJamie Gritton } 7480304c731SJamie Gritton if (ip6 == NULL) 7490304c731SJamie Gritton ip6 = malloc(ip6a * sizeof(*ip6), M_PRISON, 7500304c731SJamie Gritton M_WAITOK); 751b38ff370SJamie Gritton bcopy(op, ip6, ip6s * sizeof(*ip6)); 752b38ff370SJamie Gritton if (ip6s > 1) 753b38ff370SJamie Gritton qsort(ip6 + 1, ip6s - 1, sizeof(*ip6), qcmp_v6); 754b38ff370SJamie Gritton for (ii = 0; ii < ip6s; ii++) { 7550304c731SJamie Gritton if (IN6_IS_ADDR_UNSPECIFIED(&ip6[ii])) { 756b38ff370SJamie Gritton error = EINVAL; 757b38ff370SJamie Gritton goto done_free; 758b38ff370SJamie Gritton } 759b38ff370SJamie Gritton if ((ii+1) < ip6s && 760b38ff370SJamie Gritton (IN6_ARE_ADDR_EQUAL(&ip6[0], &ip6[ii+1]) || 761b38ff370SJamie Gritton IN6_ARE_ADDR_EQUAL(&ip6[ii], &ip6[ii+1]))) 762b38ff370SJamie Gritton { 763b38ff370SJamie Gritton error = EINVAL; 764b38ff370SJamie Gritton goto done_free; 765b38ff370SJamie Gritton } 766b38ff370SJamie Gritton } 767b38ff370SJamie Gritton } 7680304c731SJamie Gritton } 769b38ff370SJamie Gritton #endif 770b38ff370SJamie Gritton 771b38ff370SJamie Gritton root = NULL; 772b38ff370SJamie Gritton error = vfs_getopt(opts, "path", (void **)&path, &len); 773b38ff370SJamie Gritton if (error == ENOENT) 774b38ff370SJamie Gritton path = NULL; 775b38ff370SJamie Gritton else if (error != 0) 776b38ff370SJamie Gritton goto done_free; 777b38ff370SJamie Gritton else { 778b38ff370SJamie Gritton if (flags & JAIL_UPDATE) { 779b38ff370SJamie Gritton error = EINVAL; 780b38ff370SJamie Gritton vfs_opterror(opts, 781b38ff370SJamie Gritton "path cannot be changed after creation"); 782b38ff370SJamie Gritton goto done_errmsg; 783b38ff370SJamie Gritton } 784b38ff370SJamie Gritton if (len == 0 || path[len - 1] != '\0') { 785b38ff370SJamie Gritton error = EINVAL; 786b38ff370SJamie Gritton goto done_free; 787b38ff370SJamie Gritton } 788b38ff370SJamie Gritton if (len < 2 || (len == 2 && path[0] == '/')) 789b38ff370SJamie Gritton path = NULL; 790b38ff370SJamie Gritton else { 7910304c731SJamie Gritton /* Leave room for a real-root full pathname. */ 7920304c731SJamie Gritton if (len + (path[0] == '/' && strcmp(mypr->pr_path, "/") 7930304c731SJamie Gritton ? strlen(mypr->pr_path) : 0) > MAXPATHLEN) { 7940304c731SJamie Gritton error = ENAMETOOLONG; 7950304c731SJamie Gritton goto done_free; 7960304c731SJamie Gritton } 797b38ff370SJamie Gritton NDINIT(&nd, LOOKUP, MPSAFE | FOLLOW, UIO_SYSSPACE, 798b38ff370SJamie Gritton path, td); 799b38ff370SJamie Gritton error = namei(&nd); 800b38ff370SJamie Gritton if (error) 801b38ff370SJamie Gritton goto done_free; 802b38ff370SJamie Gritton vfslocked = NDHASGIANT(&nd); 803b38ff370SJamie Gritton root = nd.ni_vp; 804b38ff370SJamie Gritton NDFREE(&nd, NDF_ONLY_PNBUF); 805b38ff370SJamie Gritton if (root->v_type != VDIR) { 806b38ff370SJamie Gritton error = ENOTDIR; 807b38ff370SJamie Gritton vrele(root); 808b38ff370SJamie Gritton VFS_UNLOCK_GIANT(vfslocked); 809b38ff370SJamie Gritton goto done_free; 810b38ff370SJamie Gritton } 811b38ff370SJamie Gritton VFS_UNLOCK_GIANT(vfslocked); 812b38ff370SJamie Gritton } 813b38ff370SJamie Gritton } 814b38ff370SJamie Gritton 815b38ff370SJamie Gritton /* 816b38ff370SJamie Gritton * Grab the allprison lock before letting modules check their 817b38ff370SJamie Gritton * parameters. Once we have it, do not let go so we'll have a 818b38ff370SJamie Gritton * consistent view of the OSD list. 819b38ff370SJamie Gritton */ 820b38ff370SJamie Gritton sx_xlock(&allprison_lock); 821b38ff370SJamie Gritton error = osd_jail_call(NULL, PR_METHOD_CHECK, opts); 822b38ff370SJamie Gritton if (error) 823b38ff370SJamie Gritton goto done_unlock_list; 824b38ff370SJamie Gritton 825b38ff370SJamie Gritton /* By now, all parameters should have been noted. */ 826b38ff370SJamie Gritton TAILQ_FOREACH(opt, opts, link) { 827b38ff370SJamie Gritton if (!opt->seen && strcmp(opt->name, "errmsg")) { 828b38ff370SJamie Gritton error = EINVAL; 829b38ff370SJamie Gritton vfs_opterror(opts, "unknown parameter: %s", opt->name); 830b38ff370SJamie Gritton goto done_unlock_list; 831b38ff370SJamie Gritton } 832b38ff370SJamie Gritton } 833b38ff370SJamie Gritton 834b38ff370SJamie Gritton /* 835b38ff370SJamie Gritton * See if we are creating a new record or updating an existing one. 836b38ff370SJamie Gritton * This abuses the file error codes ENOENT and EEXIST. 837b38ff370SJamie Gritton */ 838b38ff370SJamie Gritton cuflags = flags & (JAIL_CREATE | JAIL_UPDATE); 839b38ff370SJamie Gritton if (!cuflags) { 840b38ff370SJamie Gritton error = EINVAL; 841b38ff370SJamie Gritton vfs_opterror(opts, "no valid operation (create or update)"); 842b38ff370SJamie Gritton goto done_unlock_list; 843b38ff370SJamie Gritton } 844b38ff370SJamie Gritton pr = NULL; 845b38ff370SJamie Gritton if (jid != 0) { 8460304c731SJamie Gritton /* 8470304c731SJamie Gritton * See if a requested jid already exists. There is an 8480304c731SJamie Gritton * information leak here if the jid exists but is not within 8490304c731SJamie Gritton * the caller's jail hierarchy. Jail creators will get EEXIST 8500304c731SJamie Gritton * even though they cannot see the jail, and CREATE | UPDATE 8510304c731SJamie Gritton * will return ENOENT which is not normally a valid error. 8520304c731SJamie Gritton */ 853b38ff370SJamie Gritton if (jid < 0) { 854b38ff370SJamie Gritton error = EINVAL; 855b38ff370SJamie Gritton vfs_opterror(opts, "negative jid"); 856b38ff370SJamie Gritton goto done_unlock_list; 857b38ff370SJamie Gritton } 858b38ff370SJamie Gritton pr = prison_find(jid); 859b38ff370SJamie Gritton if (pr != NULL) { 8600304c731SJamie Gritton ppr = pr->pr_parent; 861b38ff370SJamie Gritton /* Create: jid must not exist. */ 862b38ff370SJamie Gritton if (cuflags == JAIL_CREATE) { 863b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 864b38ff370SJamie Gritton error = EEXIST; 865b38ff370SJamie Gritton vfs_opterror(opts, "jail %d already exists", 866b38ff370SJamie Gritton jid); 867b38ff370SJamie Gritton goto done_unlock_list; 868b38ff370SJamie Gritton } 8690304c731SJamie Gritton if (!prison_ischild(mypr, pr)) { 8700304c731SJamie Gritton mtx_unlock(&pr->pr_mtx); 8710304c731SJamie Gritton pr = NULL; 8720304c731SJamie Gritton } else if (pr->pr_uref == 0) { 873b38ff370SJamie Gritton if (!(flags & JAIL_DYING)) { 874b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 875b38ff370SJamie Gritton error = ENOENT; 876b38ff370SJamie Gritton vfs_opterror(opts, "jail %d is dying", 877b38ff370SJamie Gritton jid); 878b38ff370SJamie Gritton goto done_unlock_list; 879b38ff370SJamie Gritton } else if ((flags & JAIL_ATTACH) || 880b38ff370SJamie Gritton (pr_flags & PR_PERSIST)) { 881b38ff370SJamie Gritton /* 882b38ff370SJamie Gritton * A dying jail might be resurrected 883b38ff370SJamie Gritton * (via attach or persist), but first 884b38ff370SJamie Gritton * it must determine if another jail 885b38ff370SJamie Gritton * has claimed its name. Accomplish 886b38ff370SJamie Gritton * this by implicitly re-setting the 887b38ff370SJamie Gritton * name. 888b38ff370SJamie Gritton */ 889b38ff370SJamie Gritton if (name == NULL) 8900304c731SJamie Gritton name = prison_name(mypr, pr); 891b38ff370SJamie Gritton } 892b38ff370SJamie Gritton } 893b38ff370SJamie Gritton } 894b38ff370SJamie Gritton if (pr == NULL) { 895b38ff370SJamie Gritton /* Update: jid must exist. */ 896b38ff370SJamie Gritton if (cuflags == JAIL_UPDATE) { 897b38ff370SJamie Gritton error = ENOENT; 898b38ff370SJamie Gritton vfs_opterror(opts, "jail %d not found", jid); 899b38ff370SJamie Gritton goto done_unlock_list; 900b38ff370SJamie Gritton } 901b38ff370SJamie Gritton } 902b38ff370SJamie Gritton } 903b38ff370SJamie Gritton /* 904b38ff370SJamie Gritton * If the caller provided a name, look for a jail by that name. 905b38ff370SJamie Gritton * This has different semantics for creates and updates keyed by jid 906b38ff370SJamie Gritton * (where the name must not already exist in a different jail), 907b38ff370SJamie Gritton * and updates keyed by the name itself (where the name must exist 908b38ff370SJamie Gritton * because that is the jail being updated). 909b38ff370SJamie Gritton */ 910b38ff370SJamie Gritton if (name != NULL) { 9110304c731SJamie Gritton p = strrchr(name, '.'); 9120304c731SJamie Gritton if (p != NULL) { 9130304c731SJamie Gritton /* 9140304c731SJamie Gritton * This is a hierarchical name. Split it into the 9150304c731SJamie Gritton * parent and child names, and make sure the parent 9160304c731SJamie Gritton * exists or matches an already found jail. 9170304c731SJamie Gritton */ 9180304c731SJamie Gritton *p = '\0'; 9190304c731SJamie Gritton if (pr != NULL) { 9200304c731SJamie Gritton if (strncmp(name, ppr->pr_name, p - name) || 9210304c731SJamie Gritton ppr->pr_name[p - name] != '\0') { 9220304c731SJamie Gritton mtx_unlock(&pr->pr_mtx); 9230304c731SJamie Gritton error = EINVAL; 9240304c731SJamie Gritton vfs_opterror(opts, 9250304c731SJamie Gritton "cannot change jail's parent"); 9260304c731SJamie Gritton goto done_unlock_list; 9270304c731SJamie Gritton } 9280304c731SJamie Gritton } else { 9290304c731SJamie Gritton ppr = prison_find_name(mypr, name); 9300304c731SJamie Gritton if (ppr == NULL) { 9310304c731SJamie Gritton error = ENOENT; 9320304c731SJamie Gritton vfs_opterror(opts, 9330304c731SJamie Gritton "jail \"%s\" not found", name); 9340304c731SJamie Gritton goto done_unlock_list; 9350304c731SJamie Gritton } 9360304c731SJamie Gritton mtx_unlock(&ppr->pr_mtx); 9370304c731SJamie Gritton } 9380304c731SJamie Gritton name = p + 1; 9390304c731SJamie Gritton } 940b38ff370SJamie Gritton if (name[0] != '\0') { 9410304c731SJamie Gritton namelen = 9420304c731SJamie Gritton (ppr == &prison0) ? 0 : strlen(ppr->pr_name) + 1; 943b38ff370SJamie Gritton name_again: 9440304c731SJamie Gritton deadpr = NULL; 9450304c731SJamie Gritton FOREACH_PRISON_CHILD(ppr, tpr) { 946b38ff370SJamie Gritton if (tpr != pr && tpr->pr_ref > 0 && 9470304c731SJamie Gritton !strcmp(tpr->pr_name + namelen, name)) { 948b38ff370SJamie Gritton if (pr == NULL && 949b38ff370SJamie Gritton cuflags != JAIL_CREATE) { 950b38ff370SJamie Gritton mtx_lock(&tpr->pr_mtx); 951b38ff370SJamie Gritton if (tpr->pr_ref > 0) { 952b38ff370SJamie Gritton /* 953b38ff370SJamie Gritton * Use this jail 954b38ff370SJamie Gritton * for updates. 955b38ff370SJamie Gritton */ 956b38ff370SJamie Gritton if (tpr->pr_uref > 0) { 957b38ff370SJamie Gritton pr = tpr; 958b38ff370SJamie Gritton break; 959b38ff370SJamie Gritton } 960b38ff370SJamie Gritton deadpr = tpr; 961b38ff370SJamie Gritton } 962b38ff370SJamie Gritton mtx_unlock(&tpr->pr_mtx); 963b38ff370SJamie Gritton } else if (tpr->pr_uref > 0) { 964b38ff370SJamie Gritton /* 965b38ff370SJamie Gritton * Create, or update(jid): 966b38ff370SJamie Gritton * name must not exist in an 9670304c731SJamie Gritton * active sibling jail. 968b38ff370SJamie Gritton */ 969b38ff370SJamie Gritton error = EEXIST; 970b38ff370SJamie Gritton if (pr != NULL) 971b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 972b38ff370SJamie Gritton vfs_opterror(opts, 973b38ff370SJamie Gritton "jail \"%s\" already exists", 974b38ff370SJamie Gritton name); 975b38ff370SJamie Gritton goto done_unlock_list; 976b38ff370SJamie Gritton } 977b38ff370SJamie Gritton } 978b38ff370SJamie Gritton } 979b38ff370SJamie Gritton /* If no active jail is found, use a dying one. */ 980b38ff370SJamie Gritton if (deadpr != NULL && pr == NULL) { 981b38ff370SJamie Gritton if (flags & JAIL_DYING) { 982b38ff370SJamie Gritton mtx_lock(&deadpr->pr_mtx); 983b38ff370SJamie Gritton if (deadpr->pr_ref == 0) { 984b38ff370SJamie Gritton mtx_unlock(&deadpr->pr_mtx); 985b38ff370SJamie Gritton goto name_again; 986b38ff370SJamie Gritton } 987b38ff370SJamie Gritton pr = deadpr; 988b38ff370SJamie Gritton } else if (cuflags == JAIL_UPDATE) { 989b38ff370SJamie Gritton error = ENOENT; 990b38ff370SJamie Gritton vfs_opterror(opts, 991b38ff370SJamie Gritton "jail \"%s\" is dying", name); 992b38ff370SJamie Gritton goto done_unlock_list; 993b38ff370SJamie Gritton } 994b38ff370SJamie Gritton } 995b38ff370SJamie Gritton /* Update: name must exist if no jid. */ 996b38ff370SJamie Gritton else if (cuflags == JAIL_UPDATE && pr == NULL) { 997b38ff370SJamie Gritton error = ENOENT; 998b38ff370SJamie Gritton vfs_opterror(opts, "jail \"%s\" not found", 999b38ff370SJamie Gritton name); 1000b38ff370SJamie Gritton goto done_unlock_list; 1001b38ff370SJamie Gritton } 1002b38ff370SJamie Gritton } 1003b38ff370SJamie Gritton } 1004b38ff370SJamie Gritton /* Update: must provide a jid or name. */ 1005b38ff370SJamie Gritton else if (cuflags == JAIL_UPDATE && pr == NULL) { 1006b38ff370SJamie Gritton error = ENOENT; 1007b38ff370SJamie Gritton vfs_opterror(opts, "update specified no jail"); 1008b38ff370SJamie Gritton goto done_unlock_list; 1009b38ff370SJamie Gritton } 1010b38ff370SJamie Gritton 1011b38ff370SJamie Gritton /* If there's no prison to update, create a new one and link it in. */ 1012b38ff370SJamie Gritton if (pr == NULL) { 1013b38ff370SJamie Gritton created = 1; 10140304c731SJamie Gritton mtx_lock(&ppr->pr_mtx); 10150304c731SJamie Gritton if (ppr->pr_ref == 0 || (ppr->pr_flags & PR_REMOVE)) { 10160304c731SJamie Gritton mtx_unlock(&ppr->pr_mtx); 10170304c731SJamie Gritton error = ENOENT; 10180304c731SJamie Gritton vfs_opterror(opts, "parent jail went away!"); 10190304c731SJamie Gritton goto done_unlock_list; 10200304c731SJamie Gritton } 10210304c731SJamie Gritton ppr->pr_ref++; 10220304c731SJamie Gritton ppr->pr_uref++; 10230304c731SJamie Gritton mtx_unlock(&ppr->pr_mtx); 1024b38ff370SJamie Gritton pr = malloc(sizeof(*pr), M_PRISON, M_WAITOK | M_ZERO); 1025b38ff370SJamie Gritton if (jid == 0) { 1026b38ff370SJamie Gritton /* Find the next free jid. */ 1027b38ff370SJamie Gritton jid = lastprid + 1; 1028b38ff370SJamie Gritton findnext: 1029b38ff370SJamie Gritton if (jid == JAIL_MAX) 1030b38ff370SJamie Gritton jid = 1; 1031b38ff370SJamie Gritton TAILQ_FOREACH(tpr, &allprison, pr_list) { 1032b38ff370SJamie Gritton if (tpr->pr_id < jid) 1033b38ff370SJamie Gritton continue; 1034b38ff370SJamie Gritton if (tpr->pr_id > jid || tpr->pr_ref == 0) { 1035b38ff370SJamie Gritton TAILQ_INSERT_BEFORE(tpr, pr, pr_list); 1036b38ff370SJamie Gritton break; 1037b38ff370SJamie Gritton } 1038b38ff370SJamie Gritton if (jid == lastprid) { 1039b38ff370SJamie Gritton error = EAGAIN; 1040b38ff370SJamie Gritton vfs_opterror(opts, 1041b38ff370SJamie Gritton "no available jail IDs"); 1042b38ff370SJamie Gritton free(pr, M_PRISON); 10430304c731SJamie Gritton prison_deref(ppr, PD_DEREF | 10440304c731SJamie Gritton PD_DEUREF | PD_LIST_XLOCKED); 10450304c731SJamie Gritton goto done_releroot; 1046b38ff370SJamie Gritton } 1047b38ff370SJamie Gritton jid++; 1048b38ff370SJamie Gritton goto findnext; 1049b38ff370SJamie Gritton } 1050b38ff370SJamie Gritton lastprid = jid; 1051b38ff370SJamie Gritton } else { 1052b38ff370SJamie Gritton /* 1053b38ff370SJamie Gritton * The jail already has a jid (that did not yet exist), 1054b38ff370SJamie Gritton * so just find where to insert it. 1055b38ff370SJamie Gritton */ 1056b38ff370SJamie Gritton TAILQ_FOREACH(tpr, &allprison, pr_list) 1057b38ff370SJamie Gritton if (tpr->pr_id >= jid) { 1058b38ff370SJamie Gritton TAILQ_INSERT_BEFORE(tpr, pr, pr_list); 1059b38ff370SJamie Gritton break; 1060b38ff370SJamie Gritton } 1061b38ff370SJamie Gritton } 1062b38ff370SJamie Gritton if (tpr == NULL) 1063b38ff370SJamie Gritton TAILQ_INSERT_TAIL(&allprison, pr, pr_list); 10640304c731SJamie Gritton LIST_INSERT_HEAD(&ppr->pr_children, pr, pr_sibling); 10650304c731SJamie Gritton for (tpr = ppr; tpr != NULL; tpr = tpr->pr_parent) 10660304c731SJamie Gritton tpr->pr_prisoncount++; 1067b38ff370SJamie Gritton 10680304c731SJamie Gritton pr->pr_parent = ppr; 1069b38ff370SJamie Gritton pr->pr_id = jid; 10700304c731SJamie Gritton 10710304c731SJamie Gritton /* Set some default values, and inherit some from the parent. */ 1072b38ff370SJamie Gritton if (name == NULL) 1073b38ff370SJamie Gritton name = ""; 107476ca6f88SJamie Gritton if (host != NULL || domain != NULL || uuid != NULL || gothid) { 107576ca6f88SJamie Gritton if (host == NULL) 107676ca6f88SJamie Gritton host = ppr->pr_host; 107776ca6f88SJamie Gritton if (domain == NULL) 107876ca6f88SJamie Gritton domain = ppr->pr_domain; 107976ca6f88SJamie Gritton if (uuid == NULL) 108076ca6f88SJamie Gritton uuid = ppr->pr_uuid; 108176ca6f88SJamie Gritton if (!gothid) 108276ca6f88SJamie Gritton hid = ppr->pr_hostid; 108376ca6f88SJamie Gritton } 1084b38ff370SJamie Gritton if (path == NULL) { 1085b38ff370SJamie Gritton path = "/"; 10860304c731SJamie Gritton root = mypr->pr_root; 1087b38ff370SJamie Gritton vref(root); 1088b38ff370SJamie Gritton } 10890304c731SJamie Gritton #ifdef INET 10900304c731SJamie Gritton pr->pr_flags |= ppr->pr_flags & PR_IP4; 10910304c731SJamie Gritton pr->pr_ip4s = ppr->pr_ip4s; 10920304c731SJamie Gritton if (ppr->pr_ip4 != NULL) { 10930304c731SJamie Gritton pr->pr_ip4 = malloc(pr->pr_ip4s * 10940304c731SJamie Gritton sizeof(struct in_addr), M_PRISON, M_WAITOK); 10950304c731SJamie Gritton bcopy(ppr->pr_ip4, pr->pr_ip4, 10960304c731SJamie Gritton pr->pr_ip4s * sizeof(*pr->pr_ip4)); 10970304c731SJamie Gritton } 10980304c731SJamie Gritton #endif 10990304c731SJamie Gritton #ifdef INET6 11000304c731SJamie Gritton pr->pr_flags |= ppr->pr_flags & PR_IP6; 11010304c731SJamie Gritton pr->pr_ip6s = ppr->pr_ip6s; 11020304c731SJamie Gritton if (ppr->pr_ip6 != NULL) { 11030304c731SJamie Gritton pr->pr_ip6 = malloc(pr->pr_ip6s * 11040304c731SJamie Gritton sizeof(struct in6_addr), M_PRISON, M_WAITOK); 11050304c731SJamie Gritton bcopy(ppr->pr_ip6, pr->pr_ip6, 11060304c731SJamie Gritton pr->pr_ip6s * sizeof(*pr->pr_ip6)); 11070304c731SJamie Gritton } 11080304c731SJamie Gritton #endif 11090304c731SJamie Gritton pr->pr_securelevel = ppr->pr_securelevel; 11100304c731SJamie Gritton pr->pr_allow = JAIL_DEFAULT_ALLOW & ppr->pr_allow; 11110304c731SJamie Gritton pr->pr_enforce_statfs = ppr->pr_enforce_statfs; 1112b38ff370SJamie Gritton 11130304c731SJamie Gritton LIST_INIT(&pr->pr_children); 11140304c731SJamie Gritton mtx_init(&pr->pr_mtx, "jail mutex", NULL, MTX_DEF | MTX_DUPOK); 1115b38ff370SJamie Gritton 1116b38ff370SJamie Gritton /* 1117b38ff370SJamie Gritton * Allocate a dedicated cpuset for each jail. 1118b38ff370SJamie Gritton * Unlike other initial settings, this may return an erorr. 1119b38ff370SJamie Gritton */ 11200304c731SJamie Gritton error = cpuset_create_root(ppr, &pr->pr_cpuset); 1121b38ff370SJamie Gritton if (error) { 1122b38ff370SJamie Gritton prison_deref(pr, PD_LIST_XLOCKED); 1123b38ff370SJamie Gritton goto done_releroot; 1124b38ff370SJamie Gritton } 1125b38ff370SJamie Gritton 1126b38ff370SJamie Gritton mtx_lock(&pr->pr_mtx); 1127b38ff370SJamie Gritton /* 1128b38ff370SJamie Gritton * New prisons do not yet have a reference, because we do not 1129b38ff370SJamie Gritton * want other to see the incomplete prison once the 1130b38ff370SJamie Gritton * allprison_lock is downgraded. 1131b38ff370SJamie Gritton */ 1132b38ff370SJamie Gritton } else { 1133b38ff370SJamie Gritton created = 0; 1134b38ff370SJamie Gritton /* 1135b38ff370SJamie Gritton * Grab a reference for existing prisons, to ensure they 1136b38ff370SJamie Gritton * continue to exist for the duration of the call. 1137b38ff370SJamie Gritton */ 1138b38ff370SJamie Gritton pr->pr_ref++; 1139b38ff370SJamie Gritton } 1140b38ff370SJamie Gritton 1141b38ff370SJamie Gritton /* Do final error checking before setting anything. */ 11420304c731SJamie Gritton if (gotslevel) { 11430304c731SJamie Gritton if (slevel < ppr->pr_securelevel) { 11440304c731SJamie Gritton error = EPERM; 11450304c731SJamie Gritton goto done_deref_locked; 11460304c731SJamie Gritton } 11470304c731SJamie Gritton } 11480304c731SJamie Gritton if (gotenforce) { 11490304c731SJamie Gritton if (enforce < ppr->pr_enforce_statfs) { 11500304c731SJamie Gritton error = EPERM; 11510304c731SJamie Gritton goto done_deref_locked; 11520304c731SJamie Gritton } 11530304c731SJamie Gritton } 1154b38ff370SJamie Gritton #ifdef INET 11550304c731SJamie Gritton if (ch_flags & PR_IP4_USER) { 11560304c731SJamie Gritton if (ppr->pr_flags & PR_IP4) { 11570304c731SJamie Gritton if (!(pr_flags & PR_IP4_USER)) { 1158b38ff370SJamie Gritton /* 11590304c731SJamie Gritton * Silently ignore attempts to make the IP 11600304c731SJamie Gritton * addresses unrestricted when the parent is 11610304c731SJamie Gritton * restricted; in other words, interpret 11620304c731SJamie Gritton * "unrestricted" as "as unrestricted as 11630304c731SJamie Gritton * possible". 1164b38ff370SJamie Gritton */ 11650304c731SJamie Gritton ip4s = ppr->pr_ip4s; 11660304c731SJamie Gritton if (ip4s == 0) { 11670304c731SJamie Gritton free(ip4, M_PRISON); 11680304c731SJamie Gritton ip4 = NULL; 11690304c731SJamie Gritton } else if (ip4s <= ip4a) { 11700304c731SJamie Gritton /* Inherit the parent's address(es). */ 11710304c731SJamie Gritton bcopy(ppr->pr_ip4, ip4, 11720304c731SJamie Gritton ip4s * sizeof(*ip4)); 11730304c731SJamie Gritton } else { 11740304c731SJamie Gritton /* 11750304c731SJamie Gritton * There's no room for the parent's 11760304c731SJamie Gritton * address list. Allocate some more. 11770304c731SJamie Gritton */ 11780304c731SJamie Gritton ip4a = ip4s; 11790304c731SJamie Gritton free(ip4, M_PRISON); 11800304c731SJamie Gritton ip4 = malloc(ip4a * sizeof(*ip4), 11810304c731SJamie Gritton M_PRISON, M_NOWAIT); 11820304c731SJamie Gritton if (ip4 != NULL) 11830304c731SJamie Gritton bcopy(ppr->pr_ip4, ip4, 11840304c731SJamie Gritton ip4s * sizeof(*ip4)); 11850304c731SJamie Gritton else { 11860304c731SJamie Gritton /* Allocation failed without 11870304c731SJamie Gritton * sleeping. Unlocking the 11880304c731SJamie Gritton * prison now will invalidate 11890304c731SJamie Gritton * some checks and prematurely 11900304c731SJamie Gritton * show an unfinished new jail. 11910304c731SJamie Gritton * So let go of everything and 11920304c731SJamie Gritton * start over. 11930304c731SJamie Gritton */ 11940304c731SJamie Gritton prison_deref(pr, created 11950304c731SJamie Gritton ? PD_LOCKED | 11960304c731SJamie Gritton PD_LIST_XLOCKED 11970304c731SJamie Gritton : PD_DEREF | PD_LOCKED | 11980304c731SJamie Gritton PD_LIST_XLOCKED); 11990304c731SJamie Gritton if (root != NULL) { 12000304c731SJamie Gritton vfslocked = 12010304c731SJamie Gritton VFS_LOCK_GIANT( 12020304c731SJamie Gritton root->v_mount); 12030304c731SJamie Gritton vrele(root); 12040304c731SJamie Gritton VFS_UNLOCK_GIANT( 12050304c731SJamie Gritton vfslocked); 12060304c731SJamie Gritton } 12070304c731SJamie Gritton ip4 = malloc(ip4a * 12080304c731SJamie Gritton sizeof(*ip4), M_PRISON, 12090304c731SJamie Gritton M_WAITOK); 12100304c731SJamie Gritton goto again; 12110304c731SJamie Gritton } 12120304c731SJamie Gritton } 12130304c731SJamie Gritton } else if (ip4s > 0) { 12140304c731SJamie Gritton /* 12150304c731SJamie Gritton * Make sure the new set of IP addresses is a 12160304c731SJamie Gritton * subset of the parent's list. Don't worry 12170304c731SJamie Gritton * about the parent being unlocked, as any 12180304c731SJamie Gritton * setting is done with allprison_lock held. 12190304c731SJamie Gritton */ 12200304c731SJamie Gritton for (ij = 0; ij < ppr->pr_ip4s; ij++) 12210304c731SJamie Gritton if (ip4[0].s_addr == 12220304c731SJamie Gritton ppr->pr_ip4[ij].s_addr) 12230304c731SJamie Gritton break; 12240304c731SJamie Gritton if (ij == ppr->pr_ip4s) { 12250304c731SJamie Gritton error = EPERM; 12260304c731SJamie Gritton goto done_deref_locked; 12270304c731SJamie Gritton } 12280304c731SJamie Gritton if (ip4s > 1) { 12290304c731SJamie Gritton for (ii = ij = 1; ii < ip4s; ii++) { 12300304c731SJamie Gritton if (ip4[ii].s_addr == 12310304c731SJamie Gritton ppr->pr_ip4[0].s_addr) 1232b38ff370SJamie Gritton continue; 12330304c731SJamie Gritton for (; ij < ppr->pr_ip4s; ij++) 12340304c731SJamie Gritton if (ip4[ii].s_addr == 12350304c731SJamie Gritton ppr->pr_ip4[ij].s_addr) 12360304c731SJamie Gritton break; 12370304c731SJamie Gritton if (ij == ppr->pr_ip4s) 12380304c731SJamie Gritton break; 12390304c731SJamie Gritton } 12400304c731SJamie Gritton if (ij == ppr->pr_ip4s) { 12410304c731SJamie Gritton error = EPERM; 12420304c731SJamie Gritton goto done_deref_locked; 12430304c731SJamie Gritton } 12440304c731SJamie Gritton } 12450304c731SJamie Gritton } 12460304c731SJamie Gritton } 12470304c731SJamie Gritton if (ip4s > 0) { 12480304c731SJamie Gritton /* 12490304c731SJamie Gritton * Check for conflicting IP addresses. We permit them 12500304c731SJamie Gritton * if there is no more than one IP on each jail. If 12510304c731SJamie Gritton * there is a duplicate on a jail with more than one 12520304c731SJamie Gritton * IP stop checking and return error. 12530304c731SJamie Gritton */ 12540304c731SJamie Gritton FOREACH_PRISON_DESCENDANT(&prison0, tpr, descend) { 12550304c731SJamie Gritton if (tpr == pr || tpr->pr_uref == 0) { 12560304c731SJamie Gritton descend = 0; 12570304c731SJamie Gritton continue; 12580304c731SJamie Gritton } 12590304c731SJamie Gritton if (!(tpr->pr_flags & PR_IP4_USER)) 12600304c731SJamie Gritton continue; 12610304c731SJamie Gritton descend = 0; 12620304c731SJamie Gritton if (tpr->pr_ip4 == NULL || 12630304c731SJamie Gritton (ip4s == 1 && tpr->pr_ip4s == 1)) 12640304c731SJamie Gritton continue; 12650304c731SJamie Gritton for (ii = 0; ii < ip4s; ii++) { 1266b38ff370SJamie Gritton if (_prison_check_ip4(tpr, 1267b38ff370SJamie Gritton &ip4[ii]) == 0) { 12680304c731SJamie Gritton error = EADDRINUSE; 1269b38ff370SJamie Gritton vfs_opterror(opts, 1270b38ff370SJamie Gritton "IPv4 addresses clash"); 1271b38ff370SJamie Gritton goto done_deref_locked; 1272b38ff370SJamie Gritton } 12730304c731SJamie Gritton } 12740304c731SJamie Gritton } 12750304c731SJamie Gritton } 12760304c731SJamie Gritton } 1277b38ff370SJamie Gritton #endif 1278b38ff370SJamie Gritton #ifdef INET6 12790304c731SJamie Gritton if (ch_flags & PR_IP6_USER) { 12800304c731SJamie Gritton if (ppr->pr_flags & PR_IP6) { 12810304c731SJamie Gritton if (!(pr_flags & PR_IP6_USER)) { 12820304c731SJamie Gritton /* 12830304c731SJamie Gritton * Silently ignore attempts to make the IP 12840304c731SJamie Gritton * addresses unrestricted when the parent is 12850304c731SJamie Gritton * restricted. 12860304c731SJamie Gritton */ 12870304c731SJamie Gritton ip6s = ppr->pr_ip6s; 12880304c731SJamie Gritton if (ip6s == 0) { 12890304c731SJamie Gritton free(ip6, M_PRISON); 12900304c731SJamie Gritton ip6 = NULL; 12910304c731SJamie Gritton } else if (ip6s <= ip6a) { 12920304c731SJamie Gritton /* Inherit the parent's address(es). */ 12930304c731SJamie Gritton bcopy(ppr->pr_ip6, ip6, 12940304c731SJamie Gritton ip6s * sizeof(*ip6)); 12950304c731SJamie Gritton } else { 12960304c731SJamie Gritton /* 12970304c731SJamie Gritton * There's no room for the parent's 12980304c731SJamie Gritton * address list. 12990304c731SJamie Gritton */ 13000304c731SJamie Gritton ip6a = ip6s; 13010304c731SJamie Gritton free(ip6, M_PRISON); 13020304c731SJamie Gritton ip6 = malloc(ip6a * sizeof(*ip6), 13030304c731SJamie Gritton M_PRISON, M_NOWAIT); 13040304c731SJamie Gritton if (ip6 != NULL) 13050304c731SJamie Gritton bcopy(ppr->pr_ip6, ip6, 13060304c731SJamie Gritton ip6s * sizeof(*ip6)); 13070304c731SJamie Gritton else { 13080304c731SJamie Gritton prison_deref(pr, created 13090304c731SJamie Gritton ? PD_LOCKED | 13100304c731SJamie Gritton PD_LIST_XLOCKED 13110304c731SJamie Gritton : PD_DEREF | PD_LOCKED | 13120304c731SJamie Gritton PD_LIST_XLOCKED); 13130304c731SJamie Gritton if (root != NULL) { 13140304c731SJamie Gritton vfslocked = 13150304c731SJamie Gritton VFS_LOCK_GIANT( 13160304c731SJamie Gritton root->v_mount); 13170304c731SJamie Gritton vrele(root); 13180304c731SJamie Gritton VFS_UNLOCK_GIANT( 13190304c731SJamie Gritton vfslocked); 13200304c731SJamie Gritton } 13210304c731SJamie Gritton ip6 = malloc(ip6a * 13220304c731SJamie Gritton sizeof(*ip6), M_PRISON, 13230304c731SJamie Gritton M_WAITOK); 13240304c731SJamie Gritton goto again; 13250304c731SJamie Gritton } 13260304c731SJamie Gritton } 13270304c731SJamie Gritton } else if (ip6s > 0) { 13280304c731SJamie Gritton /* 13290304c731SJamie Gritton * Make sure the new set of IP addresses is a 13300304c731SJamie Gritton * subset of the parent's list. 13310304c731SJamie Gritton */ 13320304c731SJamie Gritton for (ij = 0; ij < ppr->pr_ip6s; ij++) 13330304c731SJamie Gritton if (IN6_ARE_ADDR_EQUAL(&ip6[0], 13340304c731SJamie Gritton &ppr->pr_ip6[ij])) 13350304c731SJamie Gritton break; 13360304c731SJamie Gritton if (ij == ppr->pr_ip6s) { 13370304c731SJamie Gritton error = EPERM; 13380304c731SJamie Gritton goto done_deref_locked; 13390304c731SJamie Gritton } 13400304c731SJamie Gritton if (ip6s > 1) { 13410304c731SJamie Gritton for (ii = ij = 1; ii < ip6s; ii++) { 13420304c731SJamie Gritton if (IN6_ARE_ADDR_EQUAL(&ip6[ii], 13430304c731SJamie Gritton &ppr->pr_ip6[0])) 13440304c731SJamie Gritton continue; 13450304c731SJamie Gritton for (; ij < ppr->pr_ip6s; ij++) 13460304c731SJamie Gritton if (IN6_ARE_ADDR_EQUAL( 13470304c731SJamie Gritton &ip6[ii], 13480304c731SJamie Gritton &ppr->pr_ip6[ij])) 13490304c731SJamie Gritton break; 13500304c731SJamie Gritton if (ij == ppr->pr_ip6s) 13510304c731SJamie Gritton break; 13520304c731SJamie Gritton } 13530304c731SJamie Gritton if (ij == ppr->pr_ip6s) { 13540304c731SJamie Gritton error = EPERM; 13550304c731SJamie Gritton goto done_deref_locked; 13560304c731SJamie Gritton } 13570304c731SJamie Gritton } 13580304c731SJamie Gritton } 13590304c731SJamie Gritton } 13600304c731SJamie Gritton if (ip6s > 0) { 13610304c731SJamie Gritton /* Check for conflicting IP addresses. */ 13620304c731SJamie Gritton FOREACH_PRISON_DESCENDANT(&prison0, tpr, descend) { 13630304c731SJamie Gritton if (tpr == pr || tpr->pr_uref == 0) { 13640304c731SJamie Gritton descend = 0; 13650304c731SJamie Gritton continue; 13660304c731SJamie Gritton } 13670304c731SJamie Gritton if (!(tpr->pr_flags & PR_IP6_USER)) 13680304c731SJamie Gritton continue; 13690304c731SJamie Gritton descend = 0; 13700304c731SJamie Gritton if (tpr->pr_ip6 == NULL || 13710304c731SJamie Gritton (ip6s == 1 && tpr->pr_ip6s == 1)) 13720304c731SJamie Gritton continue; 13730304c731SJamie Gritton for (ii = 0; ii < ip6s; ii++) { 1374b38ff370SJamie Gritton if (_prison_check_ip6(tpr, 1375b38ff370SJamie Gritton &ip6[ii]) == 0) { 13760304c731SJamie Gritton error = EADDRINUSE; 1377b38ff370SJamie Gritton vfs_opterror(opts, 1378b38ff370SJamie Gritton "IPv6 addresses clash"); 1379b38ff370SJamie Gritton goto done_deref_locked; 1380b38ff370SJamie Gritton } 13810304c731SJamie Gritton } 13820304c731SJamie Gritton } 13830304c731SJamie Gritton } 1384b38ff370SJamie Gritton } 1385b38ff370SJamie Gritton #endif 13860304c731SJamie Gritton onamelen = namelen = 0; 13870304c731SJamie Gritton if (name != NULL) { 1388b38ff370SJamie Gritton /* Give a default name of the jid. */ 1389b38ff370SJamie Gritton if (name[0] == '\0') 1390b38ff370SJamie Gritton snprintf(name = numbuf, sizeof(numbuf), "%d", jid); 1391b38ff370SJamie Gritton else if (strtoul(name, &p, 10) != jid && *p == '\0') { 1392b38ff370SJamie Gritton error = EINVAL; 1393b38ff370SJamie Gritton vfs_opterror(opts, "name cannot be numeric"); 13940304c731SJamie Gritton goto done_deref_locked; 1395b38ff370SJamie Gritton } 1396b38ff370SJamie Gritton /* 13970304c731SJamie Gritton * Make sure the name isn't too long for the prison or its 13980304c731SJamie Gritton * children. 1399b38ff370SJamie Gritton */ 14000304c731SJamie Gritton onamelen = strlen(pr->pr_name); 14010304c731SJamie Gritton namelen = strlen(name); 14020304c731SJamie Gritton if (strlen(ppr->pr_name) + namelen + 2 > sizeof(pr->pr_name)) { 14030304c731SJamie Gritton error = ENAMETOOLONG; 14040304c731SJamie Gritton goto done_deref_locked; 14050304c731SJamie Gritton } 14060304c731SJamie Gritton FOREACH_PRISON_DESCENDANT(pr, tpr, descend) { 14070304c731SJamie Gritton if (strlen(tpr->pr_name) + (namelen - onamelen) >= 14080304c731SJamie Gritton sizeof(pr->pr_name)) { 14090304c731SJamie Gritton error = ENAMETOOLONG; 14100304c731SJamie Gritton goto done_deref_locked; 14110304c731SJamie Gritton } 14120304c731SJamie Gritton } 14130304c731SJamie Gritton } 14140304c731SJamie Gritton if (pr_allow & ~ppr->pr_allow) { 14150304c731SJamie Gritton error = EPERM; 14160304c731SJamie Gritton goto done_deref_locked; 1417b38ff370SJamie Gritton } 1418b38ff370SJamie Gritton 1419b38ff370SJamie Gritton /* Set the parameters of the prison. */ 1420b38ff370SJamie Gritton #ifdef INET 14210304c731SJamie Gritton redo_ip4 = 0; 14220304c731SJamie Gritton if (ch_flags & PR_IP4_USER) { 14230304c731SJamie Gritton if (pr_flags & PR_IP4_USER) { 14240304c731SJamie Gritton /* Some restriction set. */ 14250304c731SJamie Gritton pr->pr_flags |= PR_IP4; 1426b38ff370SJamie Gritton if (ip4s >= 0) { 1427b38ff370SJamie Gritton free(pr->pr_ip4, M_PRISON); 14280304c731SJamie Gritton pr->pr_ip4s = ip4s; 1429b38ff370SJamie Gritton pr->pr_ip4 = ip4; 1430b38ff370SJamie Gritton ip4 = NULL; 1431b38ff370SJamie Gritton } 14320304c731SJamie Gritton } else if (ppr->pr_flags & PR_IP4) { 14330304c731SJamie Gritton /* This restriction cleared, but keep inherited. */ 14340304c731SJamie Gritton free(pr->pr_ip4, M_PRISON); 14350304c731SJamie Gritton pr->pr_ip4s = ip4s; 14360304c731SJamie Gritton pr->pr_ip4 = ip4; 14370304c731SJamie Gritton ip4 = NULL; 14380304c731SJamie Gritton } else { 14390304c731SJamie Gritton /* Restriction cleared, now unrestricted. */ 14400304c731SJamie Gritton pr->pr_flags &= ~PR_IP4; 14410304c731SJamie Gritton free(pr->pr_ip4, M_PRISON); 14420304c731SJamie Gritton pr->pr_ip4s = 0; 14430304c731SJamie Gritton } 14440304c731SJamie Gritton FOREACH_PRISON_DESCENDANT_LOCKED(pr, tpr, descend) { 14450304c731SJamie Gritton if (prison_restrict_ip4(tpr, NULL)) { 14460304c731SJamie Gritton redo_ip4 = 1; 14470304c731SJamie Gritton descend = 0; 14480304c731SJamie Gritton } 14490304c731SJamie Gritton } 14500304c731SJamie Gritton } 1451b38ff370SJamie Gritton #endif 1452b38ff370SJamie Gritton #ifdef INET6 14530304c731SJamie Gritton redo_ip6 = 0; 14540304c731SJamie Gritton if (ch_flags & PR_IP6_USER) { 14550304c731SJamie Gritton if (pr_flags & PR_IP6_USER) { 14560304c731SJamie Gritton /* Some restriction set. */ 14570304c731SJamie Gritton pr->pr_flags |= PR_IP6; 1458b38ff370SJamie Gritton if (ip6s >= 0) { 1459b38ff370SJamie Gritton free(pr->pr_ip6, M_PRISON); 14600304c731SJamie Gritton pr->pr_ip6s = ip6s; 1461b38ff370SJamie Gritton pr->pr_ip6 = ip6; 1462b38ff370SJamie Gritton ip6 = NULL; 1463b38ff370SJamie Gritton } 14640304c731SJamie Gritton } else if (ppr->pr_flags & PR_IP6) { 14650304c731SJamie Gritton /* This restriction cleared, but keep inherited. */ 14660304c731SJamie Gritton free(pr->pr_ip6, M_PRISON); 14670304c731SJamie Gritton pr->pr_ip6s = ip6s; 14680304c731SJamie Gritton pr->pr_ip6 = ip6; 14690304c731SJamie Gritton ip6 = NULL; 14700304c731SJamie Gritton } else { 14710304c731SJamie Gritton /* Restriction cleared, now unrestricted. */ 14720304c731SJamie Gritton pr->pr_flags &= ~PR_IP6; 14730304c731SJamie Gritton free(pr->pr_ip6, M_PRISON); 14740304c731SJamie Gritton pr->pr_ip6s = 0; 14750304c731SJamie Gritton } 14760304c731SJamie Gritton FOREACH_PRISON_DESCENDANT_LOCKED(pr, tpr, descend) { 14770304c731SJamie Gritton if (prison_restrict_ip6(tpr, NULL)) { 14780304c731SJamie Gritton redo_ip6 = 1; 14790304c731SJamie Gritton descend = 0; 14800304c731SJamie Gritton } 14810304c731SJamie Gritton } 14820304c731SJamie Gritton } 1483b38ff370SJamie Gritton #endif 14840304c731SJamie Gritton if (gotslevel) { 1485b38ff370SJamie Gritton pr->pr_securelevel = slevel; 14860304c731SJamie Gritton /* Set all child jails to be at least this level. */ 14870304c731SJamie Gritton FOREACH_PRISON_DESCENDANT_LOCKED(pr, tpr, descend) 14880304c731SJamie Gritton if (tpr->pr_securelevel < slevel) 14890304c731SJamie Gritton tpr->pr_securelevel = slevel; 14900304c731SJamie Gritton } 14910304c731SJamie Gritton if (gotenforce) { 14920304c731SJamie Gritton pr->pr_enforce_statfs = enforce; 14930304c731SJamie Gritton /* Pass this restriction on to the children. */ 14940304c731SJamie Gritton FOREACH_PRISON_DESCENDANT_LOCKED(pr, tpr, descend) 14950304c731SJamie Gritton if (tpr->pr_enforce_statfs < enforce) 14960304c731SJamie Gritton tpr->pr_enforce_statfs = enforce; 14970304c731SJamie Gritton } 14980304c731SJamie Gritton if (name != NULL) { 14990304c731SJamie Gritton if (ppr == &prison0) 1500b38ff370SJamie Gritton strlcpy(pr->pr_name, name, sizeof(pr->pr_name)); 15010304c731SJamie Gritton else 15020304c731SJamie Gritton snprintf(pr->pr_name, sizeof(pr->pr_name), "%s.%s", 15030304c731SJamie Gritton ppr->pr_name, name); 15040304c731SJamie Gritton /* Change this component of child names. */ 15050304c731SJamie Gritton FOREACH_PRISON_DESCENDANT_LOCKED(pr, tpr, descend) { 15060304c731SJamie Gritton bcopy(tpr->pr_name + onamelen, tpr->pr_name + namelen, 15070304c731SJamie Gritton strlen(tpr->pr_name + onamelen) + 1); 15080304c731SJamie Gritton bcopy(pr->pr_name, tpr->pr_name, namelen); 15090304c731SJamie Gritton } 15100304c731SJamie Gritton } 1511b38ff370SJamie Gritton if (path != NULL) { 15120304c731SJamie Gritton /* Try to keep a real-rooted full pathname. */ 15130304c731SJamie Gritton if (path[0] == '/' && strcmp(mypr->pr_path, "/")) 15140304c731SJamie Gritton snprintf(pr->pr_path, sizeof(pr->pr_path), "%s%s", 15150304c731SJamie Gritton mypr->pr_path, path); 15160304c731SJamie Gritton else 1517b38ff370SJamie Gritton strlcpy(pr->pr_path, path, sizeof(pr->pr_path)); 1518b38ff370SJamie Gritton pr->pr_root = root; 1519b38ff370SJamie Gritton } 152076ca6f88SJamie Gritton if (PR_HOST & ch_flags & ~pr_flags) { 152176ca6f88SJamie Gritton if (pr->pr_flags & PR_HOST) { 152276ca6f88SJamie Gritton /* 152376ca6f88SJamie Gritton * Copy the parent's host info. As with pr_ip4 above, 152476ca6f88SJamie Gritton * the lack of a lock on the parent is not a problem; 152576ca6f88SJamie Gritton * it is always set with allprison_lock at least 152676ca6f88SJamie Gritton * shared, and is held exclusively here. 152776ca6f88SJamie Gritton */ 152876ca6f88SJamie Gritton strlcpy(pr->pr_host, pr->pr_parent->pr_host, 152976ca6f88SJamie Gritton sizeof(pr->pr_host)); 153076ca6f88SJamie Gritton strlcpy(pr->pr_domain, pr->pr_parent->pr_domain, 153176ca6f88SJamie Gritton sizeof(pr->pr_domain)); 153276ca6f88SJamie Gritton strlcpy(pr->pr_uuid, pr->pr_parent->pr_uuid, 153376ca6f88SJamie Gritton sizeof(pr->pr_uuid)); 153476ca6f88SJamie Gritton pr->pr_hostid = pr->pr_parent->pr_hostid; 153576ca6f88SJamie Gritton } 153676ca6f88SJamie Gritton } else if (host != NULL || domain != NULL || uuid != NULL || gothid) { 153776ca6f88SJamie Gritton /* Set this prison, and any descendants without PR_HOST. */ 1538b38ff370SJamie Gritton if (host != NULL) 1539b38ff370SJamie Gritton strlcpy(pr->pr_host, host, sizeof(pr->pr_host)); 154076ca6f88SJamie Gritton if (domain != NULL) 154176ca6f88SJamie Gritton strlcpy(pr->pr_domain, domain, sizeof(pr->pr_domain)); 154276ca6f88SJamie Gritton if (uuid != NULL) 154376ca6f88SJamie Gritton strlcpy(pr->pr_uuid, uuid, sizeof(pr->pr_uuid)); 154476ca6f88SJamie Gritton if (gothid) 154576ca6f88SJamie Gritton pr->pr_hostid = hid; 154676ca6f88SJamie Gritton FOREACH_PRISON_DESCENDANT_LOCKED(pr, tpr, descend) { 154776ca6f88SJamie Gritton if (tpr->pr_flags & PR_HOST) 154876ca6f88SJamie Gritton descend = 0; 154976ca6f88SJamie Gritton else { 155076ca6f88SJamie Gritton if (host != NULL) 155176ca6f88SJamie Gritton strlcpy(tpr->pr_host, pr->pr_host, 155276ca6f88SJamie Gritton sizeof(tpr->pr_host)); 155376ca6f88SJamie Gritton if (domain != NULL) 155476ca6f88SJamie Gritton strlcpy(tpr->pr_domain, pr->pr_domain, 155576ca6f88SJamie Gritton sizeof(tpr->pr_domain)); 155676ca6f88SJamie Gritton if (uuid != NULL) 155776ca6f88SJamie Gritton strlcpy(tpr->pr_uuid, pr->pr_uuid, 155876ca6f88SJamie Gritton sizeof(tpr->pr_uuid)); 155976ca6f88SJamie Gritton if (gothid) 156076ca6f88SJamie Gritton tpr->pr_hostid = hid; 156176ca6f88SJamie Gritton } 156276ca6f88SJamie Gritton } 156376ca6f88SJamie Gritton } 15640304c731SJamie Gritton if ((tallow = ch_allow & ~pr_allow)) { 15650304c731SJamie Gritton /* Clear allow bits in all children. */ 15660304c731SJamie Gritton FOREACH_PRISON_DESCENDANT_LOCKED(pr, tpr, descend) 15670304c731SJamie Gritton tpr->pr_allow &= ~tallow; 15680304c731SJamie Gritton } 15690304c731SJamie Gritton pr->pr_allow = (pr->pr_allow & ~ch_allow) | pr_allow; 1570b38ff370SJamie Gritton /* 1571b38ff370SJamie Gritton * Persistent prisons get an extra reference, and prisons losing their 1572b38ff370SJamie Gritton * persist flag lose that reference. Only do this for existing prisons 1573b38ff370SJamie Gritton * for now, so new ones will remain unseen until after the module 1574b38ff370SJamie Gritton * handlers have completed. 1575b38ff370SJamie Gritton */ 1576b38ff370SJamie Gritton if (!created && (ch_flags & PR_PERSIST & (pr_flags ^ pr->pr_flags))) { 1577b38ff370SJamie Gritton if (pr_flags & PR_PERSIST) { 1578b38ff370SJamie Gritton pr->pr_ref++; 1579b38ff370SJamie Gritton pr->pr_uref++; 1580b38ff370SJamie Gritton } else { 1581b38ff370SJamie Gritton pr->pr_ref--; 1582b38ff370SJamie Gritton pr->pr_uref--; 1583b38ff370SJamie Gritton } 1584b38ff370SJamie Gritton } 1585b38ff370SJamie Gritton pr->pr_flags = (pr->pr_flags & ~ch_flags) | pr_flags; 1586b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 1587b38ff370SJamie Gritton 15880304c731SJamie Gritton /* Locks may have prevented a complete restriction of child IP 15890304c731SJamie Gritton * addresses. If so, allocate some more memory and try again. 15900304c731SJamie Gritton */ 15910304c731SJamie Gritton #ifdef INET 15920304c731SJamie Gritton while (redo_ip4) { 15930304c731SJamie Gritton ip4s = pr->pr_ip4s; 15940304c731SJamie Gritton ip4 = malloc(ip4s * sizeof(*ip4), M_PRISON, M_WAITOK); 15950304c731SJamie Gritton mtx_lock(&pr->pr_mtx); 15960304c731SJamie Gritton redo_ip4 = 0; 15970304c731SJamie Gritton FOREACH_PRISON_DESCENDANT_LOCKED(pr, tpr, descend) { 15980304c731SJamie Gritton if (prison_restrict_ip4(tpr, ip4)) { 15990304c731SJamie Gritton if (ip4 != NULL) 16000304c731SJamie Gritton ip4 = NULL; 16010304c731SJamie Gritton else 16020304c731SJamie Gritton redo_ip4 = 1; 16030304c731SJamie Gritton } 16040304c731SJamie Gritton } 16050304c731SJamie Gritton mtx_unlock(&pr->pr_mtx); 16060304c731SJamie Gritton } 16070304c731SJamie Gritton #endif 16080304c731SJamie Gritton #ifdef INET6 16090304c731SJamie Gritton while (redo_ip6) { 16100304c731SJamie Gritton ip6s = pr->pr_ip6s; 16110304c731SJamie Gritton ip6 = malloc(ip6s * sizeof(*ip6), M_PRISON, M_WAITOK); 16120304c731SJamie Gritton mtx_lock(&pr->pr_mtx); 16130304c731SJamie Gritton redo_ip6 = 0; 16140304c731SJamie Gritton FOREACH_PRISON_DESCENDANT_LOCKED(pr, tpr, descend) { 16150304c731SJamie Gritton if (prison_restrict_ip6(tpr, ip6)) { 16160304c731SJamie Gritton if (ip6 != NULL) 16170304c731SJamie Gritton ip6 = NULL; 16180304c731SJamie Gritton else 16190304c731SJamie Gritton redo_ip6 = 1; 16200304c731SJamie Gritton } 16210304c731SJamie Gritton } 16220304c731SJamie Gritton mtx_unlock(&pr->pr_mtx); 16230304c731SJamie Gritton } 16240304c731SJamie Gritton #endif 16250304c731SJamie Gritton 1626b38ff370SJamie Gritton /* Let the modules do their work. */ 1627b38ff370SJamie Gritton sx_downgrade(&allprison_lock); 1628b38ff370SJamie Gritton if (created) { 1629b38ff370SJamie Gritton error = osd_jail_call(pr, PR_METHOD_CREATE, opts); 1630b38ff370SJamie Gritton if (error) { 1631b38ff370SJamie Gritton prison_deref(pr, PD_LIST_SLOCKED); 1632b38ff370SJamie Gritton goto done_errmsg; 1633b38ff370SJamie Gritton } 1634b38ff370SJamie Gritton } 1635b38ff370SJamie Gritton error = osd_jail_call(pr, PR_METHOD_SET, opts); 1636b38ff370SJamie Gritton if (error) { 1637b38ff370SJamie Gritton prison_deref(pr, created 1638b38ff370SJamie Gritton ? PD_LIST_SLOCKED 1639b38ff370SJamie Gritton : PD_DEREF | PD_LIST_SLOCKED); 1640b38ff370SJamie Gritton goto done_errmsg; 1641b38ff370SJamie Gritton } 1642b38ff370SJamie Gritton 1643b38ff370SJamie Gritton /* Attach this process to the prison if requested. */ 1644b38ff370SJamie Gritton if (flags & JAIL_ATTACH) { 1645b38ff370SJamie Gritton mtx_lock(&pr->pr_mtx); 1646b38ff370SJamie Gritton error = do_jail_attach(td, pr); 1647b38ff370SJamie Gritton if (error) { 1648b38ff370SJamie Gritton vfs_opterror(opts, "attach failed"); 1649b38ff370SJamie Gritton if (!created) 1650b38ff370SJamie Gritton prison_deref(pr, PD_DEREF); 1651b38ff370SJamie Gritton goto done_errmsg; 1652b38ff370SJamie Gritton } 1653b38ff370SJamie Gritton } 1654b38ff370SJamie Gritton 1655b38ff370SJamie Gritton /* 1656b38ff370SJamie Gritton * Now that it is all there, drop the temporary reference from existing 1657b38ff370SJamie Gritton * prisons. Or add a reference to newly created persistent prisons 1658b38ff370SJamie Gritton * (which was not done earlier so that the prison would not be publicly 1659b38ff370SJamie Gritton * visible). 1660b38ff370SJamie Gritton */ 1661b38ff370SJamie Gritton if (!created) { 1662b38ff370SJamie Gritton prison_deref(pr, (flags & JAIL_ATTACH) 1663b38ff370SJamie Gritton ? PD_DEREF 1664b38ff370SJamie Gritton : PD_DEREF | PD_LIST_SLOCKED); 1665b38ff370SJamie Gritton } else { 1666b38ff370SJamie Gritton if (pr_flags & PR_PERSIST) { 1667b38ff370SJamie Gritton mtx_lock(&pr->pr_mtx); 1668b38ff370SJamie Gritton pr->pr_ref++; 1669b38ff370SJamie Gritton pr->pr_uref++; 1670b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 1671b38ff370SJamie Gritton } 1672b38ff370SJamie Gritton if (!(flags & JAIL_ATTACH)) 1673b38ff370SJamie Gritton sx_sunlock(&allprison_lock); 1674b38ff370SJamie Gritton } 1675b38ff370SJamie Gritton td->td_retval[0] = pr->pr_id; 1676b38ff370SJamie Gritton goto done_errmsg; 1677b38ff370SJamie Gritton 16780304c731SJamie Gritton done_deref_locked: 16790304c731SJamie Gritton prison_deref(pr, created 16800304c731SJamie Gritton ? PD_LOCKED | PD_LIST_XLOCKED 16810304c731SJamie Gritton : PD_DEREF | PD_LOCKED | PD_LIST_XLOCKED); 16820304c731SJamie Gritton goto done_releroot; 1683b38ff370SJamie Gritton done_unlock_list: 1684b38ff370SJamie Gritton sx_xunlock(&allprison_lock); 1685b38ff370SJamie Gritton done_releroot: 1686b38ff370SJamie Gritton if (root != NULL) { 1687b38ff370SJamie Gritton vfslocked = VFS_LOCK_GIANT(root->v_mount); 1688b38ff370SJamie Gritton vrele(root); 1689b38ff370SJamie Gritton VFS_UNLOCK_GIANT(vfslocked); 1690b38ff370SJamie Gritton } 1691b38ff370SJamie Gritton done_errmsg: 1692b38ff370SJamie Gritton if (error) { 1693b38ff370SJamie Gritton vfs_getopt(opts, "errmsg", (void **)&errmsg, &errmsg_len); 1694b38ff370SJamie Gritton if (errmsg_len > 0) { 1695b38ff370SJamie Gritton errmsg_pos = 2 * vfs_getopt_pos(opts, "errmsg") + 1; 1696b38ff370SJamie Gritton if (errmsg_pos > 0) { 1697b38ff370SJamie Gritton if (optuio->uio_segflg == UIO_SYSSPACE) 1698b38ff370SJamie Gritton bcopy(errmsg, 1699b38ff370SJamie Gritton optuio->uio_iov[errmsg_pos].iov_base, 1700b38ff370SJamie Gritton errmsg_len); 1701b38ff370SJamie Gritton else 1702b38ff370SJamie Gritton copyout(errmsg, 1703b38ff370SJamie Gritton optuio->uio_iov[errmsg_pos].iov_base, 1704b38ff370SJamie Gritton errmsg_len); 1705b38ff370SJamie Gritton } 1706b38ff370SJamie Gritton } 1707b38ff370SJamie Gritton } 1708b38ff370SJamie Gritton done_free: 1709b38ff370SJamie Gritton #ifdef INET 1710b38ff370SJamie Gritton free(ip4, M_PRISON); 1711b38ff370SJamie Gritton #endif 1712b38ff370SJamie Gritton #ifdef INET6 1713b38ff370SJamie Gritton free(ip6, M_PRISON); 1714b38ff370SJamie Gritton #endif 1715b38ff370SJamie Gritton vfs_freeopts(opts); 1716b38ff370SJamie Gritton return (error); 1717b38ff370SJamie Gritton } 1718b38ff370SJamie Gritton 1719b38ff370SJamie Gritton 1720b38ff370SJamie Gritton /* 1721b38ff370SJamie Gritton * struct jail_get_args { 1722b38ff370SJamie Gritton * struct iovec *iovp; 1723b38ff370SJamie Gritton * unsigned int iovcnt; 1724b38ff370SJamie Gritton * int flags; 1725b38ff370SJamie Gritton * }; 1726b38ff370SJamie Gritton */ 1727b38ff370SJamie Gritton int 1728b38ff370SJamie Gritton jail_get(struct thread *td, struct jail_get_args *uap) 1729b38ff370SJamie Gritton { 1730b38ff370SJamie Gritton struct uio *auio; 1731b38ff370SJamie Gritton int error; 1732b38ff370SJamie Gritton 1733b38ff370SJamie Gritton /* Check that we have an even number of iovecs. */ 1734b38ff370SJamie Gritton if (uap->iovcnt & 1) 1735b38ff370SJamie Gritton return (EINVAL); 1736b38ff370SJamie Gritton 1737b38ff370SJamie Gritton error = copyinuio(uap->iovp, uap->iovcnt, &auio); 1738b38ff370SJamie Gritton if (error) 1739b38ff370SJamie Gritton return (error); 1740b38ff370SJamie Gritton error = kern_jail_get(td, auio, uap->flags); 1741b38ff370SJamie Gritton if (error == 0) 1742b38ff370SJamie Gritton error = copyout(auio->uio_iov, uap->iovp, 1743b38ff370SJamie Gritton uap->iovcnt * sizeof (struct iovec)); 1744b38ff370SJamie Gritton free(auio, M_IOV); 1745b38ff370SJamie Gritton return (error); 1746b38ff370SJamie Gritton } 1747b38ff370SJamie Gritton 1748b38ff370SJamie Gritton int 1749b38ff370SJamie Gritton kern_jail_get(struct thread *td, struct uio *optuio, int flags) 1750b38ff370SJamie Gritton { 17510304c731SJamie Gritton struct prison *pr, *mypr; 1752b38ff370SJamie Gritton struct vfsopt *opt; 1753b38ff370SJamie Gritton struct vfsoptlist *opts; 1754b38ff370SJamie Gritton char *errmsg, *name; 17550304c731SJamie Gritton int error, errmsg_len, errmsg_pos, fi, i, jid, len, locked, pos; 1756b38ff370SJamie Gritton 1757b38ff370SJamie Gritton if (flags & ~JAIL_GET_MASK) 1758b38ff370SJamie Gritton return (EINVAL); 1759b38ff370SJamie Gritton 1760b38ff370SJamie Gritton /* Get the parameter list. */ 1761b38ff370SJamie Gritton error = vfs_buildopts(optuio, &opts); 1762b38ff370SJamie Gritton if (error) 1763b38ff370SJamie Gritton return (error); 1764b38ff370SJamie Gritton errmsg_pos = vfs_getopt_pos(opts, "errmsg"); 17650304c731SJamie Gritton mypr = td->td_ucred->cr_prison; 17661e2a13e6SJamie Gritton 1767b38ff370SJamie Gritton /* 1768b38ff370SJamie Gritton * Find the prison specified by one of: lastjid, jid, name. 1769b38ff370SJamie Gritton */ 1770b38ff370SJamie Gritton sx_slock(&allprison_lock); 1771b38ff370SJamie Gritton error = vfs_copyopt(opts, "lastjid", &jid, sizeof(jid)); 1772b38ff370SJamie Gritton if (error == 0) { 1773b38ff370SJamie Gritton TAILQ_FOREACH(pr, &allprison, pr_list) { 17740304c731SJamie Gritton if (pr->pr_id > jid && prison_ischild(mypr, pr)) { 1775b38ff370SJamie Gritton mtx_lock(&pr->pr_mtx); 1776b38ff370SJamie Gritton if (pr->pr_ref > 0 && 1777b38ff370SJamie Gritton (pr->pr_uref > 0 || (flags & JAIL_DYING))) 1778b38ff370SJamie Gritton break; 1779b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 1780b38ff370SJamie Gritton } 1781b38ff370SJamie Gritton } 1782b38ff370SJamie Gritton if (pr != NULL) 1783b38ff370SJamie Gritton goto found_prison; 1784b38ff370SJamie Gritton error = ENOENT; 1785b38ff370SJamie Gritton vfs_opterror(opts, "no jail after %d", jid); 1786b38ff370SJamie Gritton goto done_unlock_list; 1787b38ff370SJamie Gritton } else if (error != ENOENT) 1788b38ff370SJamie Gritton goto done_unlock_list; 1789b38ff370SJamie Gritton 1790b38ff370SJamie Gritton error = vfs_copyopt(opts, "jid", &jid, sizeof(jid)); 1791b38ff370SJamie Gritton if (error == 0) { 1792b38ff370SJamie Gritton if (jid != 0) { 17930304c731SJamie Gritton pr = prison_find_child(mypr, jid); 1794b38ff370SJamie Gritton if (pr != NULL) { 1795b38ff370SJamie Gritton if (pr->pr_uref == 0 && !(flags & JAIL_DYING)) { 1796b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 1797b38ff370SJamie Gritton error = ENOENT; 1798b38ff370SJamie Gritton vfs_opterror(opts, "jail %d is dying", 1799b38ff370SJamie Gritton jid); 1800b38ff370SJamie Gritton goto done_unlock_list; 1801b38ff370SJamie Gritton } 1802b38ff370SJamie Gritton goto found_prison; 1803b38ff370SJamie Gritton } 1804b38ff370SJamie Gritton error = ENOENT; 1805b38ff370SJamie Gritton vfs_opterror(opts, "jail %d not found", jid); 1806b38ff370SJamie Gritton goto done_unlock_list; 1807b38ff370SJamie Gritton } 1808b38ff370SJamie Gritton } else if (error != ENOENT) 1809b38ff370SJamie Gritton goto done_unlock_list; 1810b38ff370SJamie Gritton 1811b38ff370SJamie Gritton error = vfs_getopt(opts, "name", (void **)&name, &len); 1812b38ff370SJamie Gritton if (error == 0) { 1813b38ff370SJamie Gritton if (len == 0 || name[len - 1] != '\0') { 1814b38ff370SJamie Gritton error = EINVAL; 1815b38ff370SJamie Gritton goto done_unlock_list; 1816b38ff370SJamie Gritton } 18170304c731SJamie Gritton pr = prison_find_name(mypr, name); 1818b38ff370SJamie Gritton if (pr != NULL) { 1819b38ff370SJamie Gritton if (pr->pr_uref == 0 && !(flags & JAIL_DYING)) { 1820b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 1821b38ff370SJamie Gritton error = ENOENT; 1822b38ff370SJamie Gritton vfs_opterror(opts, "jail \"%s\" is dying", 1823b38ff370SJamie Gritton name); 1824b38ff370SJamie Gritton goto done_unlock_list; 1825b38ff370SJamie Gritton } 1826b38ff370SJamie Gritton goto found_prison; 1827b38ff370SJamie Gritton } 1828b38ff370SJamie Gritton error = ENOENT; 1829b38ff370SJamie Gritton vfs_opterror(opts, "jail \"%s\" not found", name); 1830b38ff370SJamie Gritton goto done_unlock_list; 1831b38ff370SJamie Gritton } else if (error != ENOENT) 1832b38ff370SJamie Gritton goto done_unlock_list; 1833b38ff370SJamie Gritton 1834b38ff370SJamie Gritton vfs_opterror(opts, "no jail specified"); 1835b38ff370SJamie Gritton error = ENOENT; 1836b38ff370SJamie Gritton goto done_unlock_list; 1837b38ff370SJamie Gritton 1838b38ff370SJamie Gritton found_prison: 1839b38ff370SJamie Gritton /* Get the parameters of the prison. */ 1840b38ff370SJamie Gritton pr->pr_ref++; 1841b38ff370SJamie Gritton locked = PD_LOCKED; 1842b38ff370SJamie Gritton td->td_retval[0] = pr->pr_id; 1843b38ff370SJamie Gritton error = vfs_setopt(opts, "jid", &pr->pr_id, sizeof(pr->pr_id)); 1844b38ff370SJamie Gritton if (error != 0 && error != ENOENT) 1845b38ff370SJamie Gritton goto done_deref; 18460304c731SJamie Gritton i = (pr->pr_parent == mypr) ? 0 : pr->pr_parent->pr_id; 18470304c731SJamie Gritton error = vfs_setopt(opts, "parent", &i, sizeof(i)); 1848b38ff370SJamie Gritton if (error != 0 && error != ENOENT) 1849b38ff370SJamie Gritton goto done_deref; 18500304c731SJamie Gritton error = vfs_setopts(opts, "name", prison_name(mypr, pr)); 18510304c731SJamie Gritton if (error != 0 && error != ENOENT) 18520304c731SJamie Gritton goto done_deref; 18530304c731SJamie Gritton error = vfs_setopt(opts, "cpuset.id", &pr->pr_cpuset->cs_id, 1854b38ff370SJamie Gritton sizeof(pr->pr_cpuset->cs_id)); 1855b38ff370SJamie Gritton if (error != 0 && error != ENOENT) 1856b38ff370SJamie Gritton goto done_deref; 18570304c731SJamie Gritton error = vfs_setopts(opts, "path", prison_path(mypr, pr)); 1858b38ff370SJamie Gritton if (error != 0 && error != ENOENT) 1859b38ff370SJamie Gritton goto done_deref; 1860b38ff370SJamie Gritton #ifdef INET 1861b38ff370SJamie Gritton error = vfs_setopt_part(opts, "ip4.addr", pr->pr_ip4, 1862b38ff370SJamie Gritton pr->pr_ip4s * sizeof(*pr->pr_ip4)); 1863b38ff370SJamie Gritton if (error != 0 && error != ENOENT) 1864b38ff370SJamie Gritton goto done_deref; 1865b38ff370SJamie Gritton #endif 1866b38ff370SJamie Gritton #ifdef INET6 1867b38ff370SJamie Gritton error = vfs_setopt_part(opts, "ip6.addr", pr->pr_ip6, 1868b38ff370SJamie Gritton pr->pr_ip6s * sizeof(*pr->pr_ip6)); 1869b38ff370SJamie Gritton if (error != 0 && error != ENOENT) 1870b38ff370SJamie Gritton goto done_deref; 1871b38ff370SJamie Gritton #endif 1872b38ff370SJamie Gritton error = vfs_setopt(opts, "securelevel", &pr->pr_securelevel, 1873b38ff370SJamie Gritton sizeof(pr->pr_securelevel)); 1874b38ff370SJamie Gritton if (error != 0 && error != ENOENT) 1875b38ff370SJamie Gritton goto done_deref; 1876b38ff370SJamie Gritton error = vfs_setopts(opts, "host.hostname", pr->pr_host); 1877b38ff370SJamie Gritton if (error != 0 && error != ENOENT) 1878b38ff370SJamie Gritton goto done_deref; 187976ca6f88SJamie Gritton error = vfs_setopts(opts, "host.domainname", pr->pr_domain); 188076ca6f88SJamie Gritton if (error != 0 && error != ENOENT) 188176ca6f88SJamie Gritton goto done_deref; 188276ca6f88SJamie Gritton error = vfs_setopts(opts, "host.hostuuid", pr->pr_uuid); 188376ca6f88SJamie Gritton if (error != 0 && error != ENOENT) 188476ca6f88SJamie Gritton goto done_deref; 188576ca6f88SJamie Gritton #ifdef COMPAT_IA32 188676ca6f88SJamie Gritton if (td->td_proc->p_sysent->sv_flags & SV_IA32) { 188776ca6f88SJamie Gritton uint32_t hid32 = pr->pr_hostid; 188876ca6f88SJamie Gritton 188976ca6f88SJamie Gritton error = vfs_setopt(opts, "host.hostid", &hid32, sizeof(hid32)); 189076ca6f88SJamie Gritton } else 189176ca6f88SJamie Gritton #endif 189276ca6f88SJamie Gritton error = vfs_setopt(opts, "host.hostid", &pr->pr_hostid, 189376ca6f88SJamie Gritton sizeof(pr->pr_hostid)); 189476ca6f88SJamie Gritton if (error != 0 && error != ENOENT) 189576ca6f88SJamie Gritton goto done_deref; 18960304c731SJamie Gritton error = vfs_setopt(opts, "enforce_statfs", &pr->pr_enforce_statfs, 18970304c731SJamie Gritton sizeof(pr->pr_enforce_statfs)); 18980304c731SJamie Gritton if (error != 0 && error != ENOENT) 18990304c731SJamie Gritton goto done_deref; 19000304c731SJamie Gritton for (fi = 0; fi < sizeof(pr_flag_names) / sizeof(pr_flag_names[0]); 19010304c731SJamie Gritton fi++) { 19020304c731SJamie Gritton if (pr_flag_names[fi] == NULL) 19030304c731SJamie Gritton continue; 19040304c731SJamie Gritton i = (pr->pr_flags & (1 << fi)) ? 1 : 0; 19050304c731SJamie Gritton error = vfs_setopt(opts, pr_flag_names[fi], &i, sizeof(i)); 1906b38ff370SJamie Gritton if (error != 0 && error != ENOENT) 1907b38ff370SJamie Gritton goto done_deref; 1908b38ff370SJamie Gritton i = !i; 19090304c731SJamie Gritton error = vfs_setopt(opts, pr_flag_nonames[fi], &i, sizeof(i)); 1910b38ff370SJamie Gritton if (error != 0 && error != ENOENT) 1911b38ff370SJamie Gritton goto done_deref; 19120304c731SJamie Gritton } 19130304c731SJamie Gritton for (fi = 0; fi < sizeof(pr_allow_names) / sizeof(pr_allow_names[0]); 19140304c731SJamie Gritton fi++) { 19150304c731SJamie Gritton if (pr_allow_names[fi] == NULL) 19160304c731SJamie Gritton continue; 19170304c731SJamie Gritton i = (pr->pr_allow & (1 << fi)) ? 1 : 0; 19180304c731SJamie Gritton error = vfs_setopt(opts, pr_allow_names[fi], &i, sizeof(i)); 19190304c731SJamie Gritton if (error != 0 && error != ENOENT) 19200304c731SJamie Gritton goto done_deref; 19210304c731SJamie Gritton i = !i; 19220304c731SJamie Gritton error = vfs_setopt(opts, pr_allow_nonames[fi], &i, sizeof(i)); 19230304c731SJamie Gritton if (error != 0 && error != ENOENT) 19240304c731SJamie Gritton goto done_deref; 19250304c731SJamie Gritton } 1926b38ff370SJamie Gritton i = (pr->pr_uref == 0); 1927b38ff370SJamie Gritton error = vfs_setopt(opts, "dying", &i, sizeof(i)); 1928b38ff370SJamie Gritton if (error != 0 && error != ENOENT) 1929b38ff370SJamie Gritton goto done_deref; 1930b38ff370SJamie Gritton i = !i; 1931b38ff370SJamie Gritton error = vfs_setopt(opts, "nodying", &i, sizeof(i)); 1932b38ff370SJamie Gritton if (error != 0 && error != ENOENT) 1933b38ff370SJamie Gritton goto done_deref; 1934b38ff370SJamie Gritton 1935b38ff370SJamie Gritton /* Get the module parameters. */ 1936b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 1937b38ff370SJamie Gritton locked = 0; 1938b38ff370SJamie Gritton error = osd_jail_call(pr, PR_METHOD_GET, opts); 1939b38ff370SJamie Gritton if (error) 1940b38ff370SJamie Gritton goto done_deref; 1941b38ff370SJamie Gritton prison_deref(pr, PD_DEREF | PD_LIST_SLOCKED); 1942b38ff370SJamie Gritton 1943b38ff370SJamie Gritton /* By now, all parameters should have been noted. */ 1944b38ff370SJamie Gritton TAILQ_FOREACH(opt, opts, link) { 1945b38ff370SJamie Gritton if (!opt->seen && strcmp(opt->name, "errmsg")) { 1946b38ff370SJamie Gritton error = EINVAL; 1947b38ff370SJamie Gritton vfs_opterror(opts, "unknown parameter: %s", opt->name); 1948b38ff370SJamie Gritton goto done_errmsg; 1949b38ff370SJamie Gritton } 1950b38ff370SJamie Gritton } 1951b38ff370SJamie Gritton 1952b38ff370SJamie Gritton /* Write the fetched parameters back to userspace. */ 1953b38ff370SJamie Gritton error = 0; 1954b38ff370SJamie Gritton TAILQ_FOREACH(opt, opts, link) { 1955b38ff370SJamie Gritton if (opt->pos >= 0 && opt->pos != errmsg_pos) { 1956b38ff370SJamie Gritton pos = 2 * opt->pos + 1; 1957b38ff370SJamie Gritton optuio->uio_iov[pos].iov_len = opt->len; 1958b38ff370SJamie Gritton if (opt->value != NULL) { 1959b38ff370SJamie Gritton if (optuio->uio_segflg == UIO_SYSSPACE) { 1960b38ff370SJamie Gritton bcopy(opt->value, 1961b38ff370SJamie Gritton optuio->uio_iov[pos].iov_base, 1962b38ff370SJamie Gritton opt->len); 1963b38ff370SJamie Gritton } else { 1964b38ff370SJamie Gritton error = copyout(opt->value, 1965b38ff370SJamie Gritton optuio->uio_iov[pos].iov_base, 1966b38ff370SJamie Gritton opt->len); 1967b38ff370SJamie Gritton if (error) 1968b38ff370SJamie Gritton break; 1969b38ff370SJamie Gritton } 1970b38ff370SJamie Gritton } 1971b38ff370SJamie Gritton } 1972b38ff370SJamie Gritton } 1973b38ff370SJamie Gritton goto done_errmsg; 1974b38ff370SJamie Gritton 1975b38ff370SJamie Gritton done_deref: 1976b38ff370SJamie Gritton prison_deref(pr, locked | PD_DEREF | PD_LIST_SLOCKED); 1977b38ff370SJamie Gritton goto done_errmsg; 1978b38ff370SJamie Gritton 1979b38ff370SJamie Gritton done_unlock_list: 1980b38ff370SJamie Gritton sx_sunlock(&allprison_lock); 1981b38ff370SJamie Gritton done_errmsg: 1982b38ff370SJamie Gritton if (error && errmsg_pos >= 0) { 1983b38ff370SJamie Gritton vfs_getopt(opts, "errmsg", (void **)&errmsg, &errmsg_len); 1984b38ff370SJamie Gritton errmsg_pos = 2 * errmsg_pos + 1; 1985b38ff370SJamie Gritton if (errmsg_len > 0) { 1986b38ff370SJamie Gritton if (optuio->uio_segflg == UIO_SYSSPACE) 1987b38ff370SJamie Gritton bcopy(errmsg, 1988b38ff370SJamie Gritton optuio->uio_iov[errmsg_pos].iov_base, 1989b38ff370SJamie Gritton errmsg_len); 1990b38ff370SJamie Gritton else 1991b38ff370SJamie Gritton copyout(errmsg, 1992b38ff370SJamie Gritton optuio->uio_iov[errmsg_pos].iov_base, 1993b38ff370SJamie Gritton errmsg_len); 1994b38ff370SJamie Gritton } 1995b38ff370SJamie Gritton } 1996b38ff370SJamie Gritton vfs_freeopts(opts); 1997b38ff370SJamie Gritton return (error); 1998b38ff370SJamie Gritton } 1999b38ff370SJamie Gritton 20000304c731SJamie Gritton 2001b38ff370SJamie Gritton /* 2002b38ff370SJamie Gritton * struct jail_remove_args { 2003b38ff370SJamie Gritton * int jid; 2004b38ff370SJamie Gritton * }; 2005b38ff370SJamie Gritton */ 2006b38ff370SJamie Gritton int 2007b38ff370SJamie Gritton jail_remove(struct thread *td, struct jail_remove_args *uap) 2008b38ff370SJamie Gritton { 20090304c731SJamie Gritton struct prison *pr, *cpr, *lpr, *tpr; 20100304c731SJamie Gritton int descend, error; 2011b38ff370SJamie Gritton 2012b38ff370SJamie Gritton error = priv_check(td, PRIV_JAIL_REMOVE); 2013b38ff370SJamie Gritton if (error) 2014b38ff370SJamie Gritton return (error); 2015b38ff370SJamie Gritton 2016b38ff370SJamie Gritton sx_xlock(&allprison_lock); 20170304c731SJamie Gritton pr = prison_find_child(td->td_ucred->cr_prison, uap->jid); 2018b38ff370SJamie Gritton if (pr == NULL) { 2019b38ff370SJamie Gritton sx_xunlock(&allprison_lock); 2020b38ff370SJamie Gritton return (EINVAL); 2021b38ff370SJamie Gritton } 2022b38ff370SJamie Gritton 20230304c731SJamie Gritton /* Remove all descendants of this prison, then remove this prison. */ 20240304c731SJamie Gritton pr->pr_ref++; 20250304c731SJamie Gritton pr->pr_flags |= PR_REMOVE; 20260304c731SJamie Gritton if (!LIST_EMPTY(&pr->pr_children)) { 20270304c731SJamie Gritton mtx_unlock(&pr->pr_mtx); 20280304c731SJamie Gritton lpr = NULL; 20290304c731SJamie Gritton FOREACH_PRISON_DESCENDANT(pr, cpr, descend) { 20300304c731SJamie Gritton mtx_lock(&cpr->pr_mtx); 20310304c731SJamie Gritton if (cpr->pr_ref > 0) { 20320304c731SJamie Gritton tpr = cpr; 20330304c731SJamie Gritton cpr->pr_ref++; 20340304c731SJamie Gritton cpr->pr_flags |= PR_REMOVE; 20350304c731SJamie Gritton } else { 20360304c731SJamie Gritton /* Already removed - do not do it again. */ 20370304c731SJamie Gritton tpr = NULL; 20380304c731SJamie Gritton } 20390304c731SJamie Gritton mtx_unlock(&cpr->pr_mtx); 20400304c731SJamie Gritton if (lpr != NULL) { 20410304c731SJamie Gritton mtx_lock(&lpr->pr_mtx); 20420304c731SJamie Gritton prison_remove_one(lpr); 20430304c731SJamie Gritton sx_xlock(&allprison_lock); 20440304c731SJamie Gritton } 20450304c731SJamie Gritton lpr = tpr; 20460304c731SJamie Gritton } 20470304c731SJamie Gritton if (lpr != NULL) { 20480304c731SJamie Gritton mtx_lock(&lpr->pr_mtx); 20490304c731SJamie Gritton prison_remove_one(lpr); 20500304c731SJamie Gritton sx_xlock(&allprison_lock); 20510304c731SJamie Gritton } 20520304c731SJamie Gritton mtx_lock(&pr->pr_mtx); 20530304c731SJamie Gritton } 20540304c731SJamie Gritton prison_remove_one(pr); 20550304c731SJamie Gritton return (0); 20560304c731SJamie Gritton } 20570304c731SJamie Gritton 20580304c731SJamie Gritton static void 20590304c731SJamie Gritton prison_remove_one(struct prison *pr) 20600304c731SJamie Gritton { 20610304c731SJamie Gritton struct proc *p; 20620304c731SJamie Gritton int deuref; 20630304c731SJamie Gritton 2064b38ff370SJamie Gritton /* If the prison was persistent, it is not anymore. */ 2065b38ff370SJamie Gritton deuref = 0; 2066b38ff370SJamie Gritton if (pr->pr_flags & PR_PERSIST) { 2067b38ff370SJamie Gritton pr->pr_ref--; 2068b38ff370SJamie Gritton deuref = PD_DEUREF; 2069b38ff370SJamie Gritton pr->pr_flags &= ~PR_PERSIST; 2070b38ff370SJamie Gritton } 2071b38ff370SJamie Gritton 20720304c731SJamie Gritton /* 20730304c731SJamie Gritton * jail_remove added a reference. If that's the only one, remove 20740304c731SJamie Gritton * the prison now. 20750304c731SJamie Gritton */ 20760304c731SJamie Gritton KASSERT(pr->pr_ref > 0, 20770304c731SJamie Gritton ("prison_remove_one removing a dead prison (jid=%d)", pr->pr_id)); 20780304c731SJamie Gritton if (pr->pr_ref == 1) { 2079b38ff370SJamie Gritton prison_deref(pr, 2080b38ff370SJamie Gritton deuref | PD_DEREF | PD_LOCKED | PD_LIST_XLOCKED); 20810304c731SJamie Gritton return; 2082b38ff370SJamie Gritton } 2083b38ff370SJamie Gritton 2084b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 2085b38ff370SJamie Gritton sx_xunlock(&allprison_lock); 2086b38ff370SJamie Gritton /* 2087b38ff370SJamie Gritton * Kill all processes unfortunate enough to be attached to this prison. 2088b38ff370SJamie Gritton */ 2089b38ff370SJamie Gritton sx_slock(&allproc_lock); 2090b38ff370SJamie Gritton LIST_FOREACH(p, &allproc, p_list) { 2091b38ff370SJamie Gritton PROC_LOCK(p); 2092b38ff370SJamie Gritton if (p->p_state != PRS_NEW && p->p_ucred && 2093b38ff370SJamie Gritton p->p_ucred->cr_prison == pr) 2094b38ff370SJamie Gritton psignal(p, SIGKILL); 2095b38ff370SJamie Gritton PROC_UNLOCK(p); 2096b38ff370SJamie Gritton } 2097b38ff370SJamie Gritton sx_sunlock(&allproc_lock); 20980304c731SJamie Gritton /* Remove the temporary reference added by jail_remove. */ 2099b38ff370SJamie Gritton prison_deref(pr, deuref | PD_DEREF); 210075c13541SPoul-Henning Kamp } 210175c13541SPoul-Henning Kamp 21028571af59SJamie Gritton 2103fd7a8150SMike Barcroft /* 21049ddb7954SMike Barcroft * struct jail_attach_args { 21059ddb7954SMike Barcroft * int jid; 21069ddb7954SMike Barcroft * }; 2107fd7a8150SMike Barcroft */ 2108fd7a8150SMike Barcroft int 21099ddb7954SMike Barcroft jail_attach(struct thread *td, struct jail_attach_args *uap) 2110fd7a8150SMike Barcroft { 2111b38ff370SJamie Gritton struct prison *pr; 2112b38ff370SJamie Gritton int error; 2113b38ff370SJamie Gritton 2114b38ff370SJamie Gritton error = priv_check(td, PRIV_JAIL_ATTACH); 2115b38ff370SJamie Gritton if (error) 2116b38ff370SJamie Gritton return (error); 2117b38ff370SJamie Gritton 2118b38ff370SJamie Gritton sx_slock(&allprison_lock); 21190304c731SJamie Gritton pr = prison_find_child(td->td_ucred->cr_prison, uap->jid); 2120b38ff370SJamie Gritton if (pr == NULL) { 2121b38ff370SJamie Gritton sx_sunlock(&allprison_lock); 2122b38ff370SJamie Gritton return (EINVAL); 2123b38ff370SJamie Gritton } 2124b38ff370SJamie Gritton 2125b38ff370SJamie Gritton /* 2126b38ff370SJamie Gritton * Do not allow a process to attach to a prison that is not 2127b38ff370SJamie Gritton * considered to be "alive". 2128b38ff370SJamie Gritton */ 2129b38ff370SJamie Gritton if (pr->pr_uref == 0) { 2130b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 2131b38ff370SJamie Gritton sx_sunlock(&allprison_lock); 2132b38ff370SJamie Gritton return (EINVAL); 2133b38ff370SJamie Gritton } 2134b38ff370SJamie Gritton 2135b38ff370SJamie Gritton return (do_jail_attach(td, pr)); 2136b38ff370SJamie Gritton } 2137b38ff370SJamie Gritton 2138b38ff370SJamie Gritton static int 2139b38ff370SJamie Gritton do_jail_attach(struct thread *td, struct prison *pr) 2140b38ff370SJamie Gritton { 21410304c731SJamie Gritton struct prison *ppr; 2142fd7a8150SMike Barcroft struct proc *p; 2143fd7a8150SMike Barcroft struct ucred *newcred, *oldcred; 2144453f7d53SChristian S.J. Peron int vfslocked, error; 2145fd7a8150SMike Barcroft 214657f22bd4SJacques Vidrine /* 214757f22bd4SJacques Vidrine * XXX: Note that there is a slight race here if two threads 214857f22bd4SJacques Vidrine * in the same privileged process attempt to attach to two 214957f22bd4SJacques Vidrine * different jails at the same time. It is important for 215057f22bd4SJacques Vidrine * user processes not to do this, or they might end up with 215157f22bd4SJacques Vidrine * a process root from one prison, but attached to the jail 215257f22bd4SJacques Vidrine * of another. 215357f22bd4SJacques Vidrine */ 2154fd7a8150SMike Barcroft pr->pr_ref++; 2155b38ff370SJamie Gritton pr->pr_uref++; 2156fd7a8150SMike Barcroft mtx_unlock(&pr->pr_mtx); 2157b38ff370SJamie Gritton 2158b38ff370SJamie Gritton /* Let modules do whatever they need to prepare for attaching. */ 2159b38ff370SJamie Gritton error = osd_jail_call(pr, PR_METHOD_ATTACH, td); 2160b38ff370SJamie Gritton if (error) { 2161b38ff370SJamie Gritton prison_deref(pr, PD_DEREF | PD_DEUREF | PD_LIST_SLOCKED); 2162b38ff370SJamie Gritton return (error); 2163b38ff370SJamie Gritton } 2164dc68a633SPawel Jakub Dawidek sx_sunlock(&allprison_lock); 2165fd7a8150SMike Barcroft 2166413628a7SBjoern A. Zeeb /* 2167413628a7SBjoern A. Zeeb * Reparent the newly attached process to this jail. 2168413628a7SBjoern A. Zeeb */ 21690304c731SJamie Gritton ppr = td->td_ucred->cr_prison; 2170b38ff370SJamie Gritton p = td->td_proc; 2171413628a7SBjoern A. Zeeb error = cpuset_setproc_update_set(p, pr->pr_cpuset); 2172413628a7SBjoern A. Zeeb if (error) 2173b38ff370SJamie Gritton goto e_revert_osd; 2174413628a7SBjoern A. Zeeb 2175453f7d53SChristian S.J. Peron vfslocked = VFS_LOCK_GIANT(pr->pr_root->v_mount); 2176cb05b60aSAttilio Rao vn_lock(pr->pr_root, LK_EXCLUSIVE | LK_RETRY); 2177fd7a8150SMike Barcroft if ((error = change_dir(pr->pr_root, td)) != 0) 2178fd7a8150SMike Barcroft goto e_unlock; 2179fd7a8150SMike Barcroft #ifdef MAC 218030d239bcSRobert Watson if ((error = mac_vnode_check_chroot(td->td_ucred, pr->pr_root))) 2181fd7a8150SMike Barcroft goto e_unlock; 2182fd7a8150SMike Barcroft #endif 218322db15c0SAttilio Rao VOP_UNLOCK(pr->pr_root, 0); 2184b38ff370SJamie Gritton if ((error = change_root(pr->pr_root, td))) 2185b38ff370SJamie Gritton goto e_unlock_giant; 2186453f7d53SChristian S.J. Peron VFS_UNLOCK_GIANT(vfslocked); 2187fd7a8150SMike Barcroft 2188fd7a8150SMike Barcroft newcred = crget(); 2189fd7a8150SMike Barcroft PROC_LOCK(p); 2190fd7a8150SMike Barcroft oldcred = p->p_ucred; 2191fd7a8150SMike Barcroft setsugid(p); 2192fd7a8150SMike Barcroft crcopy(newcred, oldcred); 219369c4ee54SJohn Baldwin newcred->cr_prison = pr; 2194fd7a8150SMike Barcroft p->p_ucred = newcred; 2195fd7a8150SMike Barcroft PROC_UNLOCK(p); 2196fd7a8150SMike Barcroft crfree(oldcred); 21970304c731SJamie Gritton prison_deref(ppr, PD_DEREF | PD_DEUREF); 2198fd7a8150SMike Barcroft return (0); 2199fd7a8150SMike Barcroft e_unlock: 220022db15c0SAttilio Rao VOP_UNLOCK(pr->pr_root, 0); 2201b38ff370SJamie Gritton e_unlock_giant: 2202453f7d53SChristian S.J. Peron VFS_UNLOCK_GIANT(vfslocked); 2203b38ff370SJamie Gritton e_revert_osd: 2204b38ff370SJamie Gritton /* Tell modules this thread is still in its old jail after all. */ 22050304c731SJamie Gritton (void)osd_jail_call(ppr, PR_METHOD_ATTACH, td); 2206b38ff370SJamie Gritton prison_deref(pr, PD_DEREF | PD_DEUREF); 2207fd7a8150SMike Barcroft return (error); 2208fd7a8150SMike Barcroft } 2209fd7a8150SMike Barcroft 22100304c731SJamie Gritton 2211fd7a8150SMike Barcroft /* 2212fd7a8150SMike Barcroft * Returns a locked prison instance, or NULL on failure. 2213fd7a8150SMike Barcroft */ 221454b369c1SPawel Jakub Dawidek struct prison * 2215fd7a8150SMike Barcroft prison_find(int prid) 2216fd7a8150SMike Barcroft { 2217fd7a8150SMike Barcroft struct prison *pr; 2218fd7a8150SMike Barcroft 2219dc68a633SPawel Jakub Dawidek sx_assert(&allprison_lock, SX_LOCKED); 2220b38ff370SJamie Gritton TAILQ_FOREACH(pr, &allprison, pr_list) { 2221fd7a8150SMike Barcroft if (pr->pr_id == prid) { 2222fd7a8150SMike Barcroft mtx_lock(&pr->pr_mtx); 2223b38ff370SJamie Gritton if (pr->pr_ref > 0) 2224fd7a8150SMike Barcroft return (pr); 2225b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 2226fd7a8150SMike Barcroft } 2227fd7a8150SMike Barcroft } 2228fd7a8150SMike Barcroft return (NULL); 2229fd7a8150SMike Barcroft } 2230fd7a8150SMike Barcroft 2231b38ff370SJamie Gritton /* 22320304c731SJamie Gritton * Find a prison that is a descendant of mypr. Returns a locked prison or NULL. 2233b38ff370SJamie Gritton */ 2234b38ff370SJamie Gritton struct prison * 22350304c731SJamie Gritton prison_find_child(struct prison *mypr, int prid) 2236b38ff370SJamie Gritton { 22370304c731SJamie Gritton struct prison *pr; 22380304c731SJamie Gritton int descend; 2239b38ff370SJamie Gritton 2240b38ff370SJamie Gritton sx_assert(&allprison_lock, SX_LOCKED); 22410304c731SJamie Gritton FOREACH_PRISON_DESCENDANT(mypr, pr, descend) { 22420304c731SJamie Gritton if (pr->pr_id == prid) { 22430304c731SJamie Gritton mtx_lock(&pr->pr_mtx); 22440304c731SJamie Gritton if (pr->pr_ref > 0) 22450304c731SJamie Gritton return (pr); 22460304c731SJamie Gritton mtx_unlock(&pr->pr_mtx); 22470304c731SJamie Gritton } 22480304c731SJamie Gritton } 22490304c731SJamie Gritton return (NULL); 22500304c731SJamie Gritton } 22510304c731SJamie Gritton 22520304c731SJamie Gritton /* 22530304c731SJamie Gritton * Look for the name relative to mypr. Returns a locked prison or NULL. 22540304c731SJamie Gritton */ 22550304c731SJamie Gritton struct prison * 22560304c731SJamie Gritton prison_find_name(struct prison *mypr, const char *name) 22570304c731SJamie Gritton { 22580304c731SJamie Gritton struct prison *pr, *deadpr; 22590304c731SJamie Gritton size_t mylen; 22600304c731SJamie Gritton int descend; 22610304c731SJamie Gritton 22620304c731SJamie Gritton sx_assert(&allprison_lock, SX_LOCKED); 22630304c731SJamie Gritton mylen = (mypr == &prison0) ? 0 : strlen(mypr->pr_name) + 1; 2264b38ff370SJamie Gritton again: 2265b38ff370SJamie Gritton deadpr = NULL; 22660304c731SJamie Gritton FOREACH_PRISON_DESCENDANT(mypr, pr, descend) { 22670304c731SJamie Gritton if (!strcmp(pr->pr_name + mylen, name)) { 2268b38ff370SJamie Gritton mtx_lock(&pr->pr_mtx); 2269b38ff370SJamie Gritton if (pr->pr_ref > 0) { 2270b38ff370SJamie Gritton if (pr->pr_uref > 0) 2271b38ff370SJamie Gritton return (pr); 2272b38ff370SJamie Gritton deadpr = pr; 2273b38ff370SJamie Gritton } 2274b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 2275b38ff370SJamie Gritton } 2276b38ff370SJamie Gritton } 22770304c731SJamie Gritton /* There was no valid prison - perhaps there was a dying one. */ 2278b38ff370SJamie Gritton if (deadpr != NULL) { 2279b38ff370SJamie Gritton mtx_lock(&deadpr->pr_mtx); 2280b38ff370SJamie Gritton if (deadpr->pr_ref == 0) { 2281b38ff370SJamie Gritton mtx_unlock(&deadpr->pr_mtx); 2282b38ff370SJamie Gritton goto again; 2283b38ff370SJamie Gritton } 2284b38ff370SJamie Gritton } 2285b38ff370SJamie Gritton return (deadpr); 2286b38ff370SJamie Gritton } 2287b38ff370SJamie Gritton 2288b38ff370SJamie Gritton /* 22890304c731SJamie Gritton * See if a prison has the specific flag set. 22900304c731SJamie Gritton */ 22910304c731SJamie Gritton int 22920304c731SJamie Gritton prison_flag(struct ucred *cred, unsigned flag) 22930304c731SJamie Gritton { 22940304c731SJamie Gritton 22950304c731SJamie Gritton /* This is an atomic read, so no locking is necessary. */ 22960304c731SJamie Gritton return (cred->cr_prison->pr_flags & flag); 22970304c731SJamie Gritton } 22980304c731SJamie Gritton 22990304c731SJamie Gritton int 23000304c731SJamie Gritton prison_allow(struct ucred *cred, unsigned flag) 23010304c731SJamie Gritton { 23020304c731SJamie Gritton 23030304c731SJamie Gritton /* This is an atomic read, so no locking is necessary. */ 23040304c731SJamie Gritton return (cred->cr_prison->pr_allow & flag); 23050304c731SJamie Gritton } 23060304c731SJamie Gritton 23070304c731SJamie Gritton /* 2308b38ff370SJamie Gritton * Remove a prison reference. If that was the last reference, remove the 2309b38ff370SJamie Gritton * prison itself - but not in this context in case there are locks held. 2310b38ff370SJamie Gritton */ 231191421ba2SRobert Watson void 23121ba4a712SPawel Jakub Dawidek prison_free_locked(struct prison *pr) 231391421ba2SRobert Watson { 231491421ba2SRobert Watson 23151ba4a712SPawel Jakub Dawidek mtx_assert(&pr->pr_mtx, MA_OWNED); 231691421ba2SRobert Watson pr->pr_ref--; 231791421ba2SRobert Watson if (pr->pr_ref == 0) { 231801137630SRobert Watson mtx_unlock(&pr->pr_mtx); 2319c2cda609SPawel Jakub Dawidek TASK_INIT(&pr->pr_task, 0, prison_complete, pr); 2320c2cda609SPawel Jakub Dawidek taskqueue_enqueue(taskqueue_thread, &pr->pr_task); 2321c2cda609SPawel Jakub Dawidek return; 2322c2cda609SPawel Jakub Dawidek } 2323c2cda609SPawel Jakub Dawidek mtx_unlock(&pr->pr_mtx); 2324c2cda609SPawel Jakub Dawidek } 2325c2cda609SPawel Jakub Dawidek 23261ba4a712SPawel Jakub Dawidek void 23271ba4a712SPawel Jakub Dawidek prison_free(struct prison *pr) 23281ba4a712SPawel Jakub Dawidek { 23291ba4a712SPawel Jakub Dawidek 23301ba4a712SPawel Jakub Dawidek mtx_lock(&pr->pr_mtx); 23311ba4a712SPawel Jakub Dawidek prison_free_locked(pr); 23321ba4a712SPawel Jakub Dawidek } 23331ba4a712SPawel Jakub Dawidek 2334c2cda609SPawel Jakub Dawidek static void 2335c2cda609SPawel Jakub Dawidek prison_complete(void *context, int pending) 2336c2cda609SPawel Jakub Dawidek { 2337b38ff370SJamie Gritton 2338b38ff370SJamie Gritton prison_deref((struct prison *)context, 0); 2339b38ff370SJamie Gritton } 2340b38ff370SJamie Gritton 2341b38ff370SJamie Gritton /* 2342b38ff370SJamie Gritton * Remove a prison reference (usually). This internal version assumes no 2343b38ff370SJamie Gritton * mutexes are held, except perhaps the prison itself. If there are no more 2344b38ff370SJamie Gritton * references, release and delist the prison. On completion, the prison lock 2345b38ff370SJamie Gritton * and the allprison lock are both unlocked. 2346b38ff370SJamie Gritton */ 2347b38ff370SJamie Gritton static void 2348b38ff370SJamie Gritton prison_deref(struct prison *pr, int flags) 2349b38ff370SJamie Gritton { 23500304c731SJamie Gritton struct prison *ppr, *tpr; 2351c2cda609SPawel Jakub Dawidek int vfslocked; 2352c2cda609SPawel Jakub Dawidek 2353b38ff370SJamie Gritton if (!(flags & PD_LOCKED)) 2354b38ff370SJamie Gritton mtx_lock(&pr->pr_mtx); 23550304c731SJamie Gritton /* Decrement the user references in a separate loop. */ 2356b38ff370SJamie Gritton if (flags & PD_DEUREF) { 23570304c731SJamie Gritton for (tpr = pr;; tpr = tpr->pr_parent) { 23580304c731SJamie Gritton if (tpr != pr) 23590304c731SJamie Gritton mtx_lock(&tpr->pr_mtx); 23600304c731SJamie Gritton if (--tpr->pr_uref > 0) 23610304c731SJamie Gritton break; 23620304c731SJamie Gritton KASSERT(tpr != &prison0, ("prison0 pr_uref=0")); 23630304c731SJamie Gritton mtx_unlock(&tpr->pr_mtx); 23640304c731SJamie Gritton } 2365b38ff370SJamie Gritton /* Done if there were only user references to remove. */ 2366b38ff370SJamie Gritton if (!(flags & PD_DEREF)) { 23670304c731SJamie Gritton mtx_unlock(&tpr->pr_mtx); 2368b38ff370SJamie Gritton if (flags & PD_LIST_SLOCKED) 2369b38ff370SJamie Gritton sx_sunlock(&allprison_lock); 2370b38ff370SJamie Gritton else if (flags & PD_LIST_XLOCKED) 2371b38ff370SJamie Gritton sx_xunlock(&allprison_lock); 2372b38ff370SJamie Gritton return; 2373b38ff370SJamie Gritton } 23740304c731SJamie Gritton if (tpr != pr) { 23750304c731SJamie Gritton mtx_unlock(&tpr->pr_mtx); 23760304c731SJamie Gritton mtx_lock(&pr->pr_mtx); 2377b38ff370SJamie Gritton } 23780304c731SJamie Gritton } 23790304c731SJamie Gritton 23800304c731SJamie Gritton for (;;) { 2381b38ff370SJamie Gritton if (flags & PD_DEREF) 2382b38ff370SJamie Gritton pr->pr_ref--; 2383b38ff370SJamie Gritton /* If the prison still has references, nothing else to do. */ 2384b38ff370SJamie Gritton if (pr->pr_ref > 0) { 2385b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 2386b38ff370SJamie Gritton if (flags & PD_LIST_SLOCKED) 2387b38ff370SJamie Gritton sx_sunlock(&allprison_lock); 2388b38ff370SJamie Gritton else if (flags & PD_LIST_XLOCKED) 2389b38ff370SJamie Gritton sx_xunlock(&allprison_lock); 2390b38ff370SJamie Gritton return; 2391b38ff370SJamie Gritton } 2392c2cda609SPawel Jakub Dawidek 2393b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 2394b38ff370SJamie Gritton if (flags & PD_LIST_SLOCKED) { 2395b38ff370SJamie Gritton if (!sx_try_upgrade(&allprison_lock)) { 2396b38ff370SJamie Gritton sx_sunlock(&allprison_lock); 2397c2cda609SPawel Jakub Dawidek sx_xlock(&allprison_lock); 2398b38ff370SJamie Gritton } 2399b38ff370SJamie Gritton } else if (!(flags & PD_LIST_XLOCKED)) 2400b38ff370SJamie Gritton sx_xlock(&allprison_lock); 2401b38ff370SJamie Gritton 2402b38ff370SJamie Gritton TAILQ_REMOVE(&allprison, pr, pr_list); 24030304c731SJamie Gritton LIST_REMOVE(pr, pr_sibling); 24040304c731SJamie Gritton ppr = pr->pr_parent; 24050304c731SJamie Gritton for (tpr = ppr; tpr != NULL; tpr = tpr->pr_parent) 24060304c731SJamie Gritton tpr->pr_prisoncount--; 24070304c731SJamie Gritton sx_downgrade(&allprison_lock); 24081ba4a712SPawel Jakub Dawidek 2409b38ff370SJamie Gritton if (pr->pr_root != NULL) { 2410453f7d53SChristian S.J. Peron vfslocked = VFS_LOCK_GIANT(pr->pr_root->v_mount); 2411b3059e09SRobert Watson vrele(pr->pr_root); 2412453f7d53SChristian S.J. Peron VFS_UNLOCK_GIANT(vfslocked); 2413b38ff370SJamie Gritton } 2414b3059e09SRobert Watson mtx_destroy(&pr->pr_mtx); 2415413628a7SBjoern A. Zeeb #ifdef INET 2416413628a7SBjoern A. Zeeb free(pr->pr_ip4, M_PRISON); 2417413628a7SBjoern A. Zeeb #endif 2418b38ff370SJamie Gritton #ifdef INET6 2419b38ff370SJamie Gritton free(pr->pr_ip6, M_PRISON); 2420b38ff370SJamie Gritton #endif 2421b38ff370SJamie Gritton if (pr->pr_cpuset != NULL) 2422b38ff370SJamie Gritton cpuset_rel(pr->pr_cpuset); 2423b38ff370SJamie Gritton osd_jail_exit(pr); 24241ede983cSDag-Erling Smørgrav free(pr, M_PRISON); 24250304c731SJamie Gritton 24260304c731SJamie Gritton /* Removing a prison frees a reference on its parent. */ 24270304c731SJamie Gritton pr = ppr; 24280304c731SJamie Gritton mtx_lock(&pr->pr_mtx); 24290304c731SJamie Gritton flags = PD_DEREF | PD_LIST_SLOCKED; 24300304c731SJamie Gritton } 2431b3059e09SRobert Watson } 2432b3059e09SRobert Watson 243391421ba2SRobert Watson void 24341ba4a712SPawel Jakub Dawidek prison_hold_locked(struct prison *pr) 24351ba4a712SPawel Jakub Dawidek { 24361ba4a712SPawel Jakub Dawidek 24371ba4a712SPawel Jakub Dawidek mtx_assert(&pr->pr_mtx, MA_OWNED); 24381ba4a712SPawel Jakub Dawidek KASSERT(pr->pr_ref > 0, 2439af7bd9a4SJamie Gritton ("Trying to hold dead prison (jid=%d).", pr->pr_id)); 24401ba4a712SPawel Jakub Dawidek pr->pr_ref++; 24411ba4a712SPawel Jakub Dawidek } 24421ba4a712SPawel Jakub Dawidek 24431ba4a712SPawel Jakub Dawidek void 244491421ba2SRobert Watson prison_hold(struct prison *pr) 244591421ba2SRobert Watson { 244691421ba2SRobert Watson 244701137630SRobert Watson mtx_lock(&pr->pr_mtx); 24481ba4a712SPawel Jakub Dawidek prison_hold_locked(pr); 244901137630SRobert Watson mtx_unlock(&pr->pr_mtx); 245001137630SRobert Watson } 245101137630SRobert Watson 2452413628a7SBjoern A. Zeeb void 2453413628a7SBjoern A. Zeeb prison_proc_hold(struct prison *pr) 245401137630SRobert Watson { 245501137630SRobert Watson 2456413628a7SBjoern A. Zeeb mtx_lock(&pr->pr_mtx); 2457b38ff370SJamie Gritton KASSERT(pr->pr_uref > 0, 2458b38ff370SJamie Gritton ("Cannot add a process to a non-alive prison (jid=%d)", pr->pr_id)); 2459b38ff370SJamie Gritton pr->pr_uref++; 2460413628a7SBjoern A. Zeeb mtx_unlock(&pr->pr_mtx); 246175c13541SPoul-Henning Kamp } 246275c13541SPoul-Henning Kamp 246375c13541SPoul-Henning Kamp void 2464413628a7SBjoern A. Zeeb prison_proc_free(struct prison *pr) 246575c13541SPoul-Henning Kamp { 2466413628a7SBjoern A. Zeeb 2467413628a7SBjoern A. Zeeb mtx_lock(&pr->pr_mtx); 2468b38ff370SJamie Gritton KASSERT(pr->pr_uref > 0, 2469b38ff370SJamie Gritton ("Trying to kill a process in a dead prison (jid=%d)", pr->pr_id)); 2470b38ff370SJamie Gritton prison_deref(pr, PD_DEUREF | PD_LOCKED); 2471413628a7SBjoern A. Zeeb } 2472413628a7SBjoern A. Zeeb 2473413628a7SBjoern A. Zeeb 2474413628a7SBjoern A. Zeeb #ifdef INET 2475413628a7SBjoern A. Zeeb /* 24760304c731SJamie Gritton * Restrict a prison's IP address list with its parent's, possibly replacing 24770304c731SJamie Gritton * it. Return true if the replacement buffer was used (or would have been). 24780304c731SJamie Gritton */ 24790304c731SJamie Gritton static int 24800304c731SJamie Gritton prison_restrict_ip4(struct prison *pr, struct in_addr *newip4) 24810304c731SJamie Gritton { 24820304c731SJamie Gritton int ii, ij, used; 24830304c731SJamie Gritton struct prison *ppr; 24840304c731SJamie Gritton 24850304c731SJamie Gritton ppr = pr->pr_parent; 24860304c731SJamie Gritton if (!(pr->pr_flags & PR_IP4_USER)) { 24870304c731SJamie Gritton /* This has no user settings, so just copy the parent's list. */ 24880304c731SJamie Gritton if (pr->pr_ip4s < ppr->pr_ip4s) { 24890304c731SJamie Gritton /* 24900304c731SJamie Gritton * There's no room for the parent's list. Use the 24910304c731SJamie Gritton * new list buffer, which is assumed to be big enough 24920304c731SJamie Gritton * (if it was passed). If there's no buffer, try to 24930304c731SJamie Gritton * allocate one. 24940304c731SJamie Gritton */ 24950304c731SJamie Gritton used = 1; 24960304c731SJamie Gritton if (newip4 == NULL) { 24970304c731SJamie Gritton newip4 = malloc(ppr->pr_ip4s * sizeof(*newip4), 24980304c731SJamie Gritton M_PRISON, M_NOWAIT); 24990304c731SJamie Gritton if (newip4 != NULL) 25000304c731SJamie Gritton used = 0; 25010304c731SJamie Gritton } 25020304c731SJamie Gritton if (newip4 != NULL) { 25030304c731SJamie Gritton bcopy(ppr->pr_ip4, newip4, 25040304c731SJamie Gritton ppr->pr_ip4s * sizeof(*newip4)); 25050304c731SJamie Gritton free(pr->pr_ip4, M_PRISON); 25060304c731SJamie Gritton pr->pr_ip4 = newip4; 25070304c731SJamie Gritton pr->pr_ip4s = ppr->pr_ip4s; 25080304c731SJamie Gritton pr->pr_flags |= PR_IP4; 25090304c731SJamie Gritton } 25100304c731SJamie Gritton return (used); 25110304c731SJamie Gritton } 25120304c731SJamie Gritton pr->pr_ip4s = ppr->pr_ip4s; 25130304c731SJamie Gritton if (pr->pr_ip4s > 0) 25140304c731SJamie Gritton bcopy(ppr->pr_ip4, pr->pr_ip4, 25150304c731SJamie Gritton pr->pr_ip4s * sizeof(*newip4)); 25160304c731SJamie Gritton else if (pr->pr_ip4 != NULL) { 25170304c731SJamie Gritton free(pr->pr_ip4, M_PRISON); 25180304c731SJamie Gritton pr->pr_ip4 = NULL; 25190304c731SJamie Gritton } 25200304c731SJamie Gritton pr->pr_flags = 25210304c731SJamie Gritton (pr->pr_flags & ~PR_IP4) | (ppr->pr_flags & PR_IP4); 25220304c731SJamie Gritton } else if (pr->pr_ip4s > 0 && (ppr->pr_flags & PR_IP4)) { 25230304c731SJamie Gritton /* Remove addresses that aren't in the parent. */ 25240304c731SJamie Gritton for (ij = 0; ij < ppr->pr_ip4s; ij++) 25250304c731SJamie Gritton if (pr->pr_ip4[0].s_addr == ppr->pr_ip4[ij].s_addr) 25260304c731SJamie Gritton break; 25270304c731SJamie Gritton if (ij < ppr->pr_ip4s) 25280304c731SJamie Gritton ii = 1; 25290304c731SJamie Gritton else { 25300304c731SJamie Gritton bcopy(pr->pr_ip4 + 1, pr->pr_ip4, 25310304c731SJamie Gritton --pr->pr_ip4s * sizeof(*pr->pr_ip4)); 25320304c731SJamie Gritton ii = 0; 25330304c731SJamie Gritton } 25340304c731SJamie Gritton for (ij = 1; ii < pr->pr_ip4s; ) { 25350304c731SJamie Gritton if (pr->pr_ip4[ii].s_addr == ppr->pr_ip4[0].s_addr) { 25360304c731SJamie Gritton ii++; 25370304c731SJamie Gritton continue; 25380304c731SJamie Gritton } 25390304c731SJamie Gritton switch (ij >= ppr->pr_ip4s ? -1 : 25400304c731SJamie Gritton qcmp_v4(&pr->pr_ip4[ii], &ppr->pr_ip4[ij])) { 25410304c731SJamie Gritton case -1: 25420304c731SJamie Gritton bcopy(pr->pr_ip4 + ii + 1, pr->pr_ip4 + ii, 25430304c731SJamie Gritton (--pr->pr_ip4s - ii) * sizeof(*pr->pr_ip4)); 25440304c731SJamie Gritton break; 25450304c731SJamie Gritton case 0: 25460304c731SJamie Gritton ii++; 25470304c731SJamie Gritton ij++; 25480304c731SJamie Gritton break; 25490304c731SJamie Gritton case 1: 25500304c731SJamie Gritton ij++; 25510304c731SJamie Gritton break; 25520304c731SJamie Gritton } 25530304c731SJamie Gritton } 25540304c731SJamie Gritton if (pr->pr_ip4s == 0) { 25550304c731SJamie Gritton free(pr->pr_ip4, M_PRISON); 25560304c731SJamie Gritton pr->pr_ip4 = NULL; 25570304c731SJamie Gritton } 25580304c731SJamie Gritton } 25590304c731SJamie Gritton return (0); 25600304c731SJamie Gritton } 25610304c731SJamie Gritton 25620304c731SJamie Gritton /* 2563413628a7SBjoern A. Zeeb * Pass back primary IPv4 address of this jail. 2564413628a7SBjoern A. Zeeb * 25650304c731SJamie Gritton * If not restricted return success but do not alter the address. Caller has 25660304c731SJamie Gritton * to make sure to initialize it correctly (e.g. INADDR_ANY). 2567413628a7SBjoern A. Zeeb * 2568b89e82ddSJamie Gritton * Returns 0 on success, EAFNOSUPPORT if the jail doesn't allow IPv4. 2569b89e82ddSJamie Gritton * Address returned in NBO. 2570413628a7SBjoern A. Zeeb */ 2571413628a7SBjoern A. Zeeb int 25721cecba0fSBjoern A. Zeeb prison_get_ip4(struct ucred *cred, struct in_addr *ia) 2573413628a7SBjoern A. Zeeb { 2574b38ff370SJamie Gritton struct prison *pr; 2575413628a7SBjoern A. Zeeb 2576413628a7SBjoern A. Zeeb KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 2577413628a7SBjoern A. Zeeb KASSERT(ia != NULL, ("%s: ia is NULL", __func__)); 257875c13541SPoul-Henning Kamp 2579b38ff370SJamie Gritton pr = cred->cr_prison; 25800304c731SJamie Gritton if (!(pr->pr_flags & PR_IP4)) 25810304c731SJamie Gritton return (0); 2582b38ff370SJamie Gritton mtx_lock(&pr->pr_mtx); 25830304c731SJamie Gritton if (!(pr->pr_flags & PR_IP4)) { 25840304c731SJamie Gritton mtx_unlock(&pr->pr_mtx); 25850304c731SJamie Gritton return (0); 25860304c731SJamie Gritton } 2587b38ff370SJamie Gritton if (pr->pr_ip4 == NULL) { 2588b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 2589b89e82ddSJamie Gritton return (EAFNOSUPPORT); 2590b38ff370SJamie Gritton } 2591413628a7SBjoern A. Zeeb 2592b38ff370SJamie Gritton ia->s_addr = pr->pr_ip4[0].s_addr; 2593b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 2594413628a7SBjoern A. Zeeb return (0); 259575c13541SPoul-Henning Kamp } 2596413628a7SBjoern A. Zeeb 2597413628a7SBjoern A. Zeeb /* 25980304c731SJamie Gritton * Return true if pr1 and pr2 have the same IPv4 address restrictions. 25990304c731SJamie Gritton */ 26000304c731SJamie Gritton int 26010304c731SJamie Gritton prison_equal_ip4(struct prison *pr1, struct prison *pr2) 26020304c731SJamie Gritton { 26030304c731SJamie Gritton 26040304c731SJamie Gritton if (pr1 == pr2) 26050304c731SJamie Gritton return (1); 26060304c731SJamie Gritton 26070304c731SJamie Gritton /* 26080304c731SJamie Gritton * jail_set maintains an exclusive hold on allprison_lock while it 26090304c731SJamie Gritton * changes the IP addresses, so only a shared hold is needed. This is 26100304c731SJamie Gritton * easier than locking the two prisons which would require finding the 26110304c731SJamie Gritton * proper locking order and end up needing allprison_lock anyway. 26120304c731SJamie Gritton */ 26130304c731SJamie Gritton sx_slock(&allprison_lock); 26140304c731SJamie Gritton while (pr1 != &prison0 && !(pr1->pr_flags & PR_IP4_USER)) 26150304c731SJamie Gritton pr1 = pr1->pr_parent; 26160304c731SJamie Gritton while (pr2 != &prison0 && !(pr2->pr_flags & PR_IP4_USER)) 26170304c731SJamie Gritton pr2 = pr2->pr_parent; 26180304c731SJamie Gritton sx_sunlock(&allprison_lock); 26190304c731SJamie Gritton return (pr1 == pr2); 26200304c731SJamie Gritton } 26210304c731SJamie Gritton 26220304c731SJamie Gritton /* 2623413628a7SBjoern A. Zeeb * Make sure our (source) address is set to something meaningful to this 2624413628a7SBjoern A. Zeeb * jail. 2625413628a7SBjoern A. Zeeb * 26260304c731SJamie Gritton * Returns 0 if jail doesn't restrict IPv4 or if address belongs to jail, 26270304c731SJamie Gritton * EADDRNOTAVAIL if the address doesn't belong, or EAFNOSUPPORT if the jail 26280304c731SJamie Gritton * doesn't allow IPv4. Address passed in in NBO and returned in NBO. 2629413628a7SBjoern A. Zeeb */ 2630413628a7SBjoern A. Zeeb int 2631413628a7SBjoern A. Zeeb prison_local_ip4(struct ucred *cred, struct in_addr *ia) 2632413628a7SBjoern A. Zeeb { 2633b38ff370SJamie Gritton struct prison *pr; 2634413628a7SBjoern A. Zeeb struct in_addr ia0; 2635b38ff370SJamie Gritton int error; 2636413628a7SBjoern A. Zeeb 2637413628a7SBjoern A. Zeeb KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 2638413628a7SBjoern A. Zeeb KASSERT(ia != NULL, ("%s: ia is NULL", __func__)); 2639413628a7SBjoern A. Zeeb 2640b38ff370SJamie Gritton pr = cred->cr_prison; 26410304c731SJamie Gritton if (!(pr->pr_flags & PR_IP4)) 26420304c731SJamie Gritton return (0); 2643b38ff370SJamie Gritton mtx_lock(&pr->pr_mtx); 26440304c731SJamie Gritton if (!(pr->pr_flags & PR_IP4)) { 26450304c731SJamie Gritton mtx_unlock(&pr->pr_mtx); 26460304c731SJamie Gritton return (0); 26470304c731SJamie Gritton } 2648b38ff370SJamie Gritton if (pr->pr_ip4 == NULL) { 2649b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 2650b89e82ddSJamie Gritton return (EAFNOSUPPORT); 2651b38ff370SJamie Gritton } 2652413628a7SBjoern A. Zeeb 2653413628a7SBjoern A. Zeeb ia0.s_addr = ntohl(ia->s_addr); 2654413628a7SBjoern A. Zeeb if (ia0.s_addr == INADDR_LOOPBACK) { 2655b38ff370SJamie Gritton ia->s_addr = pr->pr_ip4[0].s_addr; 2656b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 2657413628a7SBjoern A. Zeeb return (0); 2658413628a7SBjoern A. Zeeb } 2659413628a7SBjoern A. Zeeb 2660b89e82ddSJamie Gritton if (ia0.s_addr == INADDR_ANY) { 2661413628a7SBjoern A. Zeeb /* 2662413628a7SBjoern A. Zeeb * In case there is only 1 IPv4 address, bind directly. 2663413628a7SBjoern A. Zeeb */ 2664b38ff370SJamie Gritton if (pr->pr_ip4s == 1) 2665b38ff370SJamie Gritton ia->s_addr = pr->pr_ip4[0].s_addr; 2666b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 2667413628a7SBjoern A. Zeeb return (0); 2668413628a7SBjoern A. Zeeb } 2669413628a7SBjoern A. Zeeb 2670b38ff370SJamie Gritton error = _prison_check_ip4(pr, ia); 2671b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 2672b38ff370SJamie Gritton return (error); 2673413628a7SBjoern A. Zeeb } 2674413628a7SBjoern A. Zeeb 2675413628a7SBjoern A. Zeeb /* 2676413628a7SBjoern A. Zeeb * Rewrite destination address in case we will connect to loopback address. 2677413628a7SBjoern A. Zeeb * 2678b89e82ddSJamie Gritton * Returns 0 on success, EAFNOSUPPORT if the jail doesn't allow IPv4. 2679b89e82ddSJamie Gritton * Address passed in in NBO and returned in NBO. 2680413628a7SBjoern A. Zeeb */ 2681413628a7SBjoern A. Zeeb int 2682413628a7SBjoern A. Zeeb prison_remote_ip4(struct ucred *cred, struct in_addr *ia) 2683413628a7SBjoern A. Zeeb { 2684b38ff370SJamie Gritton struct prison *pr; 2685413628a7SBjoern A. Zeeb 2686413628a7SBjoern A. Zeeb KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 2687413628a7SBjoern A. Zeeb KASSERT(ia != NULL, ("%s: ia is NULL", __func__)); 2688413628a7SBjoern A. Zeeb 2689b38ff370SJamie Gritton pr = cred->cr_prison; 26900304c731SJamie Gritton if (!(pr->pr_flags & PR_IP4)) 26910304c731SJamie Gritton return (0); 2692b38ff370SJamie Gritton mtx_lock(&pr->pr_mtx); 26930304c731SJamie Gritton if (!(pr->pr_flags & PR_IP4)) { 26940304c731SJamie Gritton mtx_unlock(&pr->pr_mtx); 26950304c731SJamie Gritton return (0); 26960304c731SJamie Gritton } 2697b38ff370SJamie Gritton if (pr->pr_ip4 == NULL) { 2698b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 2699b89e82ddSJamie Gritton return (EAFNOSUPPORT); 2700b38ff370SJamie Gritton } 2701b89e82ddSJamie Gritton 2702413628a7SBjoern A. Zeeb if (ntohl(ia->s_addr) == INADDR_LOOPBACK) { 2703b38ff370SJamie Gritton ia->s_addr = pr->pr_ip4[0].s_addr; 2704b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 2705413628a7SBjoern A. Zeeb return (0); 2706413628a7SBjoern A. Zeeb } 2707413628a7SBjoern A. Zeeb 2708413628a7SBjoern A. Zeeb /* 2709413628a7SBjoern A. Zeeb * Return success because nothing had to be changed. 2710413628a7SBjoern A. Zeeb */ 2711b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 2712413628a7SBjoern A. Zeeb return (0); 2713413628a7SBjoern A. Zeeb } 2714413628a7SBjoern A. Zeeb 2715413628a7SBjoern A. Zeeb /* 2716b89e82ddSJamie Gritton * Check if given address belongs to the jail referenced by cred/prison. 2717413628a7SBjoern A. Zeeb * 27180304c731SJamie Gritton * Returns 0 if jail doesn't restrict IPv4 or if address belongs to jail, 27190304c731SJamie Gritton * EADDRNOTAVAIL if the address doesn't belong, or EAFNOSUPPORT if the jail 27200304c731SJamie Gritton * doesn't allow IPv4. Address passed in in NBO. 2721413628a7SBjoern A. Zeeb */ 2722413628a7SBjoern A. Zeeb static int 2723413628a7SBjoern A. Zeeb _prison_check_ip4(struct prison *pr, struct in_addr *ia) 2724413628a7SBjoern A. Zeeb { 2725413628a7SBjoern A. Zeeb int i, a, z, d; 2726413628a7SBjoern A. Zeeb 2727413628a7SBjoern A. Zeeb /* 2728413628a7SBjoern A. Zeeb * Check the primary IP. 2729413628a7SBjoern A. Zeeb */ 2730413628a7SBjoern A. Zeeb if (pr->pr_ip4[0].s_addr == ia->s_addr) 2731b89e82ddSJamie Gritton return (0); 2732413628a7SBjoern A. Zeeb 2733413628a7SBjoern A. Zeeb /* 2734413628a7SBjoern A. Zeeb * All the other IPs are sorted so we can do a binary search. 2735413628a7SBjoern A. Zeeb */ 2736413628a7SBjoern A. Zeeb a = 0; 2737413628a7SBjoern A. Zeeb z = pr->pr_ip4s - 2; 2738413628a7SBjoern A. Zeeb while (a <= z) { 2739413628a7SBjoern A. Zeeb i = (a + z) / 2; 2740413628a7SBjoern A. Zeeb d = qcmp_v4(&pr->pr_ip4[i+1], ia); 2741413628a7SBjoern A. Zeeb if (d > 0) 2742413628a7SBjoern A. Zeeb z = i - 1; 2743413628a7SBjoern A. Zeeb else if (d < 0) 2744413628a7SBjoern A. Zeeb a = i + 1; 2745413628a7SBjoern A. Zeeb else 2746413628a7SBjoern A. Zeeb return (0); 274775c13541SPoul-Henning Kamp } 274875c13541SPoul-Henning Kamp 2749b89e82ddSJamie Gritton return (EADDRNOTAVAIL); 2750b89e82ddSJamie Gritton } 2751b89e82ddSJamie Gritton 275275c13541SPoul-Henning Kamp int 2753413628a7SBjoern A. Zeeb prison_check_ip4(struct ucred *cred, struct in_addr *ia) 2754413628a7SBjoern A. Zeeb { 2755b38ff370SJamie Gritton struct prison *pr; 2756b38ff370SJamie Gritton int error; 2757413628a7SBjoern A. Zeeb 2758413628a7SBjoern A. Zeeb KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 2759413628a7SBjoern A. Zeeb KASSERT(ia != NULL, ("%s: ia is NULL", __func__)); 2760413628a7SBjoern A. Zeeb 2761b38ff370SJamie Gritton pr = cred->cr_prison; 27620304c731SJamie Gritton if (!(pr->pr_flags & PR_IP4)) 27630304c731SJamie Gritton return (0); 2764b38ff370SJamie Gritton mtx_lock(&pr->pr_mtx); 27650304c731SJamie Gritton if (!(pr->pr_flags & PR_IP4)) { 27660304c731SJamie Gritton mtx_unlock(&pr->pr_mtx); 27670304c731SJamie Gritton return (0); 27680304c731SJamie Gritton } 2769b38ff370SJamie Gritton if (pr->pr_ip4 == NULL) { 2770b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 2771b89e82ddSJamie Gritton return (EAFNOSUPPORT); 2772b38ff370SJamie Gritton } 2773413628a7SBjoern A. Zeeb 2774b38ff370SJamie Gritton error = _prison_check_ip4(pr, ia); 2775b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 2776b38ff370SJamie Gritton return (error); 2777413628a7SBjoern A. Zeeb } 2778413628a7SBjoern A. Zeeb #endif 2779413628a7SBjoern A. Zeeb 2780413628a7SBjoern A. Zeeb #ifdef INET6 27810304c731SJamie Gritton static int 27820304c731SJamie Gritton prison_restrict_ip6(struct prison *pr, struct in6_addr *newip6) 27830304c731SJamie Gritton { 27840304c731SJamie Gritton int ii, ij, used; 27850304c731SJamie Gritton struct prison *ppr; 27860304c731SJamie Gritton 27870304c731SJamie Gritton ppr = pr->pr_parent; 27880304c731SJamie Gritton if (!(pr->pr_flags & PR_IP6_USER)) { 27890304c731SJamie Gritton /* This has no user settings, so just copy the parent's list. */ 27900304c731SJamie Gritton if (pr->pr_ip6s < ppr->pr_ip6s) { 27910304c731SJamie Gritton /* 27920304c731SJamie Gritton * There's no room for the parent's list. Use the 27930304c731SJamie Gritton * new list buffer, which is assumed to be big enough 27940304c731SJamie Gritton * (if it was passed). If there's no buffer, try to 27950304c731SJamie Gritton * allocate one. 27960304c731SJamie Gritton */ 27970304c731SJamie Gritton used = 1; 27980304c731SJamie Gritton if (newip6 == NULL) { 27990304c731SJamie Gritton newip6 = malloc(ppr->pr_ip6s * sizeof(*newip6), 28000304c731SJamie Gritton M_PRISON, M_NOWAIT); 28010304c731SJamie Gritton if (newip6 != NULL) 28020304c731SJamie Gritton used = 0; 28030304c731SJamie Gritton } 28040304c731SJamie Gritton if (newip6 != NULL) { 28050304c731SJamie Gritton bcopy(ppr->pr_ip6, newip6, 28060304c731SJamie Gritton ppr->pr_ip6s * sizeof(*newip6)); 28070304c731SJamie Gritton free(pr->pr_ip6, M_PRISON); 28080304c731SJamie Gritton pr->pr_ip6 = newip6; 28090304c731SJamie Gritton pr->pr_ip6s = ppr->pr_ip6s; 28100304c731SJamie Gritton pr->pr_flags |= PR_IP6; 28110304c731SJamie Gritton } 28120304c731SJamie Gritton return (used); 28130304c731SJamie Gritton } 28140304c731SJamie Gritton pr->pr_ip6s = ppr->pr_ip6s; 28150304c731SJamie Gritton if (pr->pr_ip6s > 0) 28160304c731SJamie Gritton bcopy(ppr->pr_ip6, pr->pr_ip6, 28170304c731SJamie Gritton pr->pr_ip6s * sizeof(*newip6)); 28180304c731SJamie Gritton else if (pr->pr_ip6 != NULL) { 28190304c731SJamie Gritton free(pr->pr_ip6, M_PRISON); 28200304c731SJamie Gritton pr->pr_ip6 = NULL; 28210304c731SJamie Gritton } 28220304c731SJamie Gritton pr->pr_flags = 28230304c731SJamie Gritton (pr->pr_flags & ~PR_IP6) | (ppr->pr_flags & PR_IP6); 28240304c731SJamie Gritton } else if (pr->pr_ip6s > 0 && (ppr->pr_flags & PR_IP6)) { 28250304c731SJamie Gritton /* Remove addresses that aren't in the parent. */ 28260304c731SJamie Gritton for (ij = 0; ij < ppr->pr_ip6s; ij++) 28270304c731SJamie Gritton if (IN6_ARE_ADDR_EQUAL(&pr->pr_ip6[0], 28280304c731SJamie Gritton &ppr->pr_ip6[ij])) 28290304c731SJamie Gritton break; 28300304c731SJamie Gritton if (ij < ppr->pr_ip6s) 28310304c731SJamie Gritton ii = 1; 28320304c731SJamie Gritton else { 28330304c731SJamie Gritton bcopy(pr->pr_ip6 + 1, pr->pr_ip6, 28340304c731SJamie Gritton --pr->pr_ip6s * sizeof(*pr->pr_ip6)); 28350304c731SJamie Gritton ii = 0; 28360304c731SJamie Gritton } 28370304c731SJamie Gritton for (ij = 1; ii < pr->pr_ip6s; ) { 28380304c731SJamie Gritton if (IN6_ARE_ADDR_EQUAL(&pr->pr_ip6[ii], 28390304c731SJamie Gritton &ppr->pr_ip6[0])) { 28400304c731SJamie Gritton ii++; 28410304c731SJamie Gritton continue; 28420304c731SJamie Gritton } 28430304c731SJamie Gritton switch (ij >= ppr->pr_ip4s ? -1 : 28440304c731SJamie Gritton qcmp_v6(&pr->pr_ip6[ii], &ppr->pr_ip6[ij])) { 28450304c731SJamie Gritton case -1: 28460304c731SJamie Gritton bcopy(pr->pr_ip6 + ii + 1, pr->pr_ip6 + ii, 28470304c731SJamie Gritton (--pr->pr_ip6s - ii) * sizeof(*pr->pr_ip6)); 28480304c731SJamie Gritton break; 28490304c731SJamie Gritton case 0: 28500304c731SJamie Gritton ii++; 28510304c731SJamie Gritton ij++; 28520304c731SJamie Gritton break; 28530304c731SJamie Gritton case 1: 28540304c731SJamie Gritton ij++; 28550304c731SJamie Gritton break; 28560304c731SJamie Gritton } 28570304c731SJamie Gritton } 28580304c731SJamie Gritton if (pr->pr_ip6s == 0) { 28590304c731SJamie Gritton free(pr->pr_ip6, M_PRISON); 28600304c731SJamie Gritton pr->pr_ip6 = NULL; 28610304c731SJamie Gritton } 28620304c731SJamie Gritton } 28630304c731SJamie Gritton return 0; 28640304c731SJamie Gritton } 28650304c731SJamie Gritton 2866413628a7SBjoern A. Zeeb /* 2867413628a7SBjoern A. Zeeb * Pass back primary IPv6 address for this jail. 2868413628a7SBjoern A. Zeeb * 28690304c731SJamie Gritton * If not restricted return success but do not alter the address. Caller has 28700304c731SJamie Gritton * to make sure to initialize it correctly (e.g. IN6ADDR_ANY_INIT). 2871413628a7SBjoern A. Zeeb * 2872b89e82ddSJamie Gritton * Returns 0 on success, EAFNOSUPPORT if the jail doesn't allow IPv6. 2873413628a7SBjoern A. Zeeb */ 2874413628a7SBjoern A. Zeeb int 28751cecba0fSBjoern A. Zeeb prison_get_ip6(struct ucred *cred, struct in6_addr *ia6) 2876413628a7SBjoern A. Zeeb { 2877b38ff370SJamie Gritton struct prison *pr; 2878413628a7SBjoern A. Zeeb 2879413628a7SBjoern A. Zeeb KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 2880413628a7SBjoern A. Zeeb KASSERT(ia6 != NULL, ("%s: ia6 is NULL", __func__)); 2881413628a7SBjoern A. Zeeb 2882b38ff370SJamie Gritton pr = cred->cr_prison; 28830304c731SJamie Gritton if (!(pr->pr_flags & PR_IP6)) 28840304c731SJamie Gritton return (0); 2885b38ff370SJamie Gritton mtx_lock(&pr->pr_mtx); 28860304c731SJamie Gritton if (!(pr->pr_flags & PR_IP6)) { 28870304c731SJamie Gritton mtx_unlock(&pr->pr_mtx); 28880304c731SJamie Gritton return (0); 28890304c731SJamie Gritton } 2890b38ff370SJamie Gritton if (pr->pr_ip6 == NULL) { 2891b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 2892b89e82ddSJamie Gritton return (EAFNOSUPPORT); 2893b38ff370SJamie Gritton } 2894b89e82ddSJamie Gritton 2895b38ff370SJamie Gritton bcopy(&pr->pr_ip6[0], ia6, sizeof(struct in6_addr)); 2896b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 2897413628a7SBjoern A. Zeeb return (0); 2898413628a7SBjoern A. Zeeb } 2899413628a7SBjoern A. Zeeb 2900413628a7SBjoern A. Zeeb /* 29010304c731SJamie Gritton * Return true if pr1 and pr2 have the same IPv6 address restrictions. 29020304c731SJamie Gritton */ 29030304c731SJamie Gritton int 29040304c731SJamie Gritton prison_equal_ip6(struct prison *pr1, struct prison *pr2) 29050304c731SJamie Gritton { 29060304c731SJamie Gritton 29070304c731SJamie Gritton if (pr1 == pr2) 29080304c731SJamie Gritton return (1); 29090304c731SJamie Gritton 29100304c731SJamie Gritton sx_slock(&allprison_lock); 29110304c731SJamie Gritton while (pr1 != &prison0 && !(pr1->pr_flags & PR_IP6_USER)) 29120304c731SJamie Gritton pr1 = pr1->pr_parent; 29130304c731SJamie Gritton while (pr2 != &prison0 && !(pr2->pr_flags & PR_IP6_USER)) 29140304c731SJamie Gritton pr2 = pr2->pr_parent; 29150304c731SJamie Gritton sx_sunlock(&allprison_lock); 29160304c731SJamie Gritton return (pr1 == pr2); 29170304c731SJamie Gritton } 29180304c731SJamie Gritton 29190304c731SJamie Gritton /* 2920413628a7SBjoern A. Zeeb * Make sure our (source) address is set to something meaningful to this jail. 2921413628a7SBjoern A. Zeeb * 2922413628a7SBjoern A. Zeeb * v6only should be set based on (inp->inp_flags & IN6P_IPV6_V6ONLY != 0) 2923413628a7SBjoern A. Zeeb * when needed while binding. 2924413628a7SBjoern A. Zeeb * 29250304c731SJamie Gritton * Returns 0 if jail doesn't restrict IPv6 or if address belongs to jail, 29260304c731SJamie Gritton * EADDRNOTAVAIL if the address doesn't belong, or EAFNOSUPPORT if the jail 29270304c731SJamie Gritton * doesn't allow IPv6. 2928413628a7SBjoern A. Zeeb */ 2929413628a7SBjoern A. Zeeb int 2930413628a7SBjoern A. Zeeb prison_local_ip6(struct ucred *cred, struct in6_addr *ia6, int v6only) 2931413628a7SBjoern A. Zeeb { 2932b38ff370SJamie Gritton struct prison *pr; 2933b38ff370SJamie Gritton int error; 2934413628a7SBjoern A. Zeeb 2935413628a7SBjoern A. Zeeb KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 2936413628a7SBjoern A. Zeeb KASSERT(ia6 != NULL, ("%s: ia6 is NULL", __func__)); 2937413628a7SBjoern A. Zeeb 2938b38ff370SJamie Gritton pr = cred->cr_prison; 29390304c731SJamie Gritton if (!(pr->pr_flags & PR_IP6)) 29400304c731SJamie Gritton return (0); 2941b38ff370SJamie Gritton mtx_lock(&pr->pr_mtx); 29420304c731SJamie Gritton if (!(pr->pr_flags & PR_IP6)) { 29430304c731SJamie Gritton mtx_unlock(&pr->pr_mtx); 29440304c731SJamie Gritton return (0); 29450304c731SJamie Gritton } 2946b38ff370SJamie Gritton if (pr->pr_ip6 == NULL) { 2947b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 2948b89e82ddSJamie Gritton return (EAFNOSUPPORT); 2949b38ff370SJamie Gritton } 2950b89e82ddSJamie Gritton 2951413628a7SBjoern A. Zeeb if (IN6_IS_ADDR_LOOPBACK(ia6)) { 2952b38ff370SJamie Gritton bcopy(&pr->pr_ip6[0], ia6, sizeof(struct in6_addr)); 2953b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 2954413628a7SBjoern A. Zeeb return (0); 2955413628a7SBjoern A. Zeeb } 2956413628a7SBjoern A. Zeeb 2957b89e82ddSJamie Gritton if (IN6_IS_ADDR_UNSPECIFIED(ia6)) { 2958413628a7SBjoern A. Zeeb /* 2959b89e82ddSJamie Gritton * In case there is only 1 IPv6 address, and v6only is true, 2960b89e82ddSJamie Gritton * then bind directly. 2961413628a7SBjoern A. Zeeb */ 2962b38ff370SJamie Gritton if (v6only != 0 && pr->pr_ip6s == 1) 2963b38ff370SJamie Gritton bcopy(&pr->pr_ip6[0], ia6, sizeof(struct in6_addr)); 2964b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 2965413628a7SBjoern A. Zeeb return (0); 2966413628a7SBjoern A. Zeeb } 2967b89e82ddSJamie Gritton 2968b38ff370SJamie Gritton error = _prison_check_ip6(pr, ia6); 2969b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 2970b38ff370SJamie Gritton return (error); 2971413628a7SBjoern A. Zeeb } 2972413628a7SBjoern A. Zeeb 2973413628a7SBjoern A. Zeeb /* 2974413628a7SBjoern A. Zeeb * Rewrite destination address in case we will connect to loopback address. 2975413628a7SBjoern A. Zeeb * 2976b89e82ddSJamie Gritton * Returns 0 on success, EAFNOSUPPORT if the jail doesn't allow IPv6. 2977413628a7SBjoern A. Zeeb */ 2978413628a7SBjoern A. Zeeb int 2979413628a7SBjoern A. Zeeb prison_remote_ip6(struct ucred *cred, struct in6_addr *ia6) 2980413628a7SBjoern A. Zeeb { 2981b38ff370SJamie Gritton struct prison *pr; 2982413628a7SBjoern A. Zeeb 2983413628a7SBjoern A. Zeeb KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 2984413628a7SBjoern A. Zeeb KASSERT(ia6 != NULL, ("%s: ia6 is NULL", __func__)); 2985413628a7SBjoern A. Zeeb 2986b38ff370SJamie Gritton pr = cred->cr_prison; 29870304c731SJamie Gritton if (!(pr->pr_flags & PR_IP6)) 29880304c731SJamie Gritton return (0); 2989b38ff370SJamie Gritton mtx_lock(&pr->pr_mtx); 29900304c731SJamie Gritton if (!(pr->pr_flags & PR_IP6)) { 29910304c731SJamie Gritton mtx_unlock(&pr->pr_mtx); 29920304c731SJamie Gritton return (0); 29930304c731SJamie Gritton } 2994b38ff370SJamie Gritton if (pr->pr_ip6 == NULL) { 2995b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 2996b89e82ddSJamie Gritton return (EAFNOSUPPORT); 2997b38ff370SJamie Gritton } 2998b89e82ddSJamie Gritton 2999413628a7SBjoern A. Zeeb if (IN6_IS_ADDR_LOOPBACK(ia6)) { 3000b38ff370SJamie Gritton bcopy(&pr->pr_ip6[0], ia6, sizeof(struct in6_addr)); 3001b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 3002413628a7SBjoern A. Zeeb return (0); 3003413628a7SBjoern A. Zeeb } 3004413628a7SBjoern A. Zeeb 3005413628a7SBjoern A. Zeeb /* 3006413628a7SBjoern A. Zeeb * Return success because nothing had to be changed. 3007413628a7SBjoern A. Zeeb */ 3008b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 3009413628a7SBjoern A. Zeeb return (0); 3010413628a7SBjoern A. Zeeb } 3011413628a7SBjoern A. Zeeb 3012413628a7SBjoern A. Zeeb /* 3013b89e82ddSJamie Gritton * Check if given address belongs to the jail referenced by cred/prison. 3014413628a7SBjoern A. Zeeb * 30150304c731SJamie Gritton * Returns 0 if jail doesn't restrict IPv6 or if address belongs to jail, 30160304c731SJamie Gritton * EADDRNOTAVAIL if the address doesn't belong, or EAFNOSUPPORT if the jail 30170304c731SJamie Gritton * doesn't allow IPv6. 3018413628a7SBjoern A. Zeeb */ 3019413628a7SBjoern A. Zeeb static int 3020413628a7SBjoern A. Zeeb _prison_check_ip6(struct prison *pr, struct in6_addr *ia6) 3021413628a7SBjoern A. Zeeb { 3022413628a7SBjoern A. Zeeb int i, a, z, d; 3023413628a7SBjoern A. Zeeb 3024413628a7SBjoern A. Zeeb /* 3025413628a7SBjoern A. Zeeb * Check the primary IP. 3026413628a7SBjoern A. Zeeb */ 3027413628a7SBjoern A. Zeeb if (IN6_ARE_ADDR_EQUAL(&pr->pr_ip6[0], ia6)) 3028b89e82ddSJamie Gritton return (0); 3029413628a7SBjoern A. Zeeb 3030413628a7SBjoern A. Zeeb /* 3031413628a7SBjoern A. Zeeb * All the other IPs are sorted so we can do a binary search. 3032413628a7SBjoern A. Zeeb */ 3033413628a7SBjoern A. Zeeb a = 0; 3034413628a7SBjoern A. Zeeb z = pr->pr_ip6s - 2; 3035413628a7SBjoern A. Zeeb while (a <= z) { 3036413628a7SBjoern A. Zeeb i = (a + z) / 2; 3037413628a7SBjoern A. Zeeb d = qcmp_v6(&pr->pr_ip6[i+1], ia6); 3038413628a7SBjoern A. Zeeb if (d > 0) 3039413628a7SBjoern A. Zeeb z = i - 1; 3040413628a7SBjoern A. Zeeb else if (d < 0) 3041413628a7SBjoern A. Zeeb a = i + 1; 3042413628a7SBjoern A. Zeeb else 3043413628a7SBjoern A. Zeeb return (0); 3044413628a7SBjoern A. Zeeb } 3045413628a7SBjoern A. Zeeb 3046b89e82ddSJamie Gritton return (EADDRNOTAVAIL); 3047b89e82ddSJamie Gritton } 3048b89e82ddSJamie Gritton 3049413628a7SBjoern A. Zeeb int 3050413628a7SBjoern A. Zeeb prison_check_ip6(struct ucred *cred, struct in6_addr *ia6) 3051413628a7SBjoern A. Zeeb { 3052b38ff370SJamie Gritton struct prison *pr; 3053b38ff370SJamie Gritton int error; 3054413628a7SBjoern A. Zeeb 3055413628a7SBjoern A. Zeeb KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 3056413628a7SBjoern A. Zeeb KASSERT(ia6 != NULL, ("%s: ia6 is NULL", __func__)); 3057413628a7SBjoern A. Zeeb 3058b38ff370SJamie Gritton pr = cred->cr_prison; 30590304c731SJamie Gritton if (!(pr->pr_flags & PR_IP6)) 30600304c731SJamie Gritton return (0); 3061b38ff370SJamie Gritton mtx_lock(&pr->pr_mtx); 30620304c731SJamie Gritton if (!(pr->pr_flags & PR_IP6)) { 30630304c731SJamie Gritton mtx_unlock(&pr->pr_mtx); 30640304c731SJamie Gritton return (0); 30650304c731SJamie Gritton } 3066b38ff370SJamie Gritton if (pr->pr_ip6 == NULL) { 3067b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 3068b89e82ddSJamie Gritton return (EAFNOSUPPORT); 3069b38ff370SJamie Gritton } 3070413628a7SBjoern A. Zeeb 3071b38ff370SJamie Gritton error = _prison_check_ip6(pr, ia6); 3072b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 3073b38ff370SJamie Gritton return (error); 3074413628a7SBjoern A. Zeeb } 3075413628a7SBjoern A. Zeeb #endif 3076413628a7SBjoern A. Zeeb 3077413628a7SBjoern A. Zeeb /* 3078ca04ba64SJamie Gritton * Check if a jail supports the given address family. 3079ca04ba64SJamie Gritton * 3080ca04ba64SJamie Gritton * Returns 0 if not jailed or the address family is supported, EAFNOSUPPORT 3081ca04ba64SJamie Gritton * if not. 3082ca04ba64SJamie Gritton */ 3083ca04ba64SJamie Gritton int 3084ca04ba64SJamie Gritton prison_check_af(struct ucred *cred, int af) 3085ca04ba64SJamie Gritton { 30860304c731SJamie Gritton struct prison *pr; 3087ca04ba64SJamie Gritton int error; 3088ca04ba64SJamie Gritton 3089ca04ba64SJamie Gritton KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 3090ca04ba64SJamie Gritton 30910304c731SJamie Gritton pr = cred->cr_prison; 3092ca04ba64SJamie Gritton error = 0; 3093ca04ba64SJamie Gritton switch (af) 3094ca04ba64SJamie Gritton { 3095ca04ba64SJamie Gritton #ifdef INET 3096ca04ba64SJamie Gritton case AF_INET: 30970304c731SJamie Gritton if (pr->pr_flags & PR_IP4) 30980304c731SJamie Gritton { 30990304c731SJamie Gritton mtx_lock(&pr->pr_mtx); 31000304c731SJamie Gritton if ((pr->pr_flags & PR_IP4) && pr->pr_ip4 == NULL) 3101ca04ba64SJamie Gritton error = EAFNOSUPPORT; 31020304c731SJamie Gritton mtx_unlock(&pr->pr_mtx); 31030304c731SJamie Gritton } 3104ca04ba64SJamie Gritton break; 3105ca04ba64SJamie Gritton #endif 3106ca04ba64SJamie Gritton #ifdef INET6 3107ca04ba64SJamie Gritton case AF_INET6: 31080304c731SJamie Gritton if (pr->pr_flags & PR_IP6) 31090304c731SJamie Gritton { 31100304c731SJamie Gritton mtx_lock(&pr->pr_mtx); 31110304c731SJamie Gritton if ((pr->pr_flags & PR_IP6) && pr->pr_ip6 == NULL) 3112ca04ba64SJamie Gritton error = EAFNOSUPPORT; 31130304c731SJamie Gritton mtx_unlock(&pr->pr_mtx); 31140304c731SJamie Gritton } 3115ca04ba64SJamie Gritton break; 3116ca04ba64SJamie Gritton #endif 3117ca04ba64SJamie Gritton case AF_LOCAL: 3118ca04ba64SJamie Gritton case AF_ROUTE: 3119ca04ba64SJamie Gritton break; 3120ca04ba64SJamie Gritton default: 31210304c731SJamie Gritton if (!(pr->pr_allow & PR_ALLOW_SOCKET_AF)) 3122ca04ba64SJamie Gritton error = EAFNOSUPPORT; 3123ca04ba64SJamie Gritton } 3124ca04ba64SJamie Gritton return (error); 3125ca04ba64SJamie Gritton } 3126ca04ba64SJamie Gritton 3127ca04ba64SJamie Gritton /* 3128413628a7SBjoern A. Zeeb * Check if given address belongs to the jail referenced by cred (wrapper to 3129413628a7SBjoern A. Zeeb * prison_check_ip[46]). 3130413628a7SBjoern A. Zeeb * 31310304c731SJamie Gritton * Returns 0 if jail doesn't restrict the address family or if address belongs 31320304c731SJamie Gritton * to jail, EADDRNOTAVAIL if the address doesn't belong, or EAFNOSUPPORT if 31330304c731SJamie Gritton * the jail doesn't allow the address family. IPv4 Address passed in in NBO. 3134413628a7SBjoern A. Zeeb */ 3135413628a7SBjoern A. Zeeb int 313691421ba2SRobert Watson prison_if(struct ucred *cred, struct sockaddr *sa) 313775c13541SPoul-Henning Kamp { 3138413628a7SBjoern A. Zeeb #ifdef INET 31399ddb7954SMike Barcroft struct sockaddr_in *sai; 3140413628a7SBjoern A. Zeeb #endif 3141413628a7SBjoern A. Zeeb #ifdef INET6 3142413628a7SBjoern A. Zeeb struct sockaddr_in6 *sai6; 3143413628a7SBjoern A. Zeeb #endif 3144b89e82ddSJamie Gritton int error; 314575c13541SPoul-Henning Kamp 3146413628a7SBjoern A. Zeeb KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 3147413628a7SBjoern A. Zeeb KASSERT(sa != NULL, ("%s: sa is NULL", __func__)); 3148413628a7SBjoern A. Zeeb 3149b89e82ddSJamie Gritton error = 0; 3150413628a7SBjoern A. Zeeb switch (sa->sa_family) 3151413628a7SBjoern A. Zeeb { 3152413628a7SBjoern A. Zeeb #ifdef INET 3153413628a7SBjoern A. Zeeb case AF_INET: 31549ddb7954SMike Barcroft sai = (struct sockaddr_in *)sa; 3155b89e82ddSJamie Gritton error = prison_check_ip4(cred, &sai->sin_addr); 3156413628a7SBjoern A. Zeeb break; 3157413628a7SBjoern A. Zeeb #endif 3158413628a7SBjoern A. Zeeb #ifdef INET6 3159413628a7SBjoern A. Zeeb case AF_INET6: 3160413628a7SBjoern A. Zeeb sai6 = (struct sockaddr_in6 *)sa; 3161b89e82ddSJamie Gritton error = prison_check_ip6(cred, &sai6->sin6_addr); 3162413628a7SBjoern A. Zeeb break; 3163413628a7SBjoern A. Zeeb #endif 3164413628a7SBjoern A. Zeeb default: 31650304c731SJamie Gritton if (!(cred->cr_prison->pr_allow & PR_ALLOW_SOCKET_AF)) 3166b89e82ddSJamie Gritton error = EAFNOSUPPORT; 3167413628a7SBjoern A. Zeeb } 3168b89e82ddSJamie Gritton return (error); 316975c13541SPoul-Henning Kamp } 317091421ba2SRobert Watson 317191421ba2SRobert Watson /* 317291421ba2SRobert Watson * Return 0 if jails permit p1 to frob p2, otherwise ESRCH. 317391421ba2SRobert Watson */ 317491421ba2SRobert Watson int 31759ddb7954SMike Barcroft prison_check(struct ucred *cred1, struct ucred *cred2) 317691421ba2SRobert Watson { 317791421ba2SRobert Watson 317829b02909SMarko Zec #ifdef VIMAGE 317929b02909SMarko Zec if (cred2->cr_vimage->v_procg != cred1->cr_vimage->v_procg) 318029b02909SMarko Zec return (ESRCH); 318129b02909SMarko Zec #endif 31820304c731SJamie Gritton return ((cred1->cr_prison == cred2->cr_prison || 31830304c731SJamie Gritton prison_ischild(cred1->cr_prison, cred2->cr_prison)) ? 0 : ESRCH); 31840304c731SJamie Gritton } 318591421ba2SRobert Watson 31860304c731SJamie Gritton /* 31870304c731SJamie Gritton * Return 1 if p2 is a child of p1, otherwise 0. 31880304c731SJamie Gritton */ 31890304c731SJamie Gritton int 31900304c731SJamie Gritton prison_ischild(struct prison *pr1, struct prison *pr2) 31910304c731SJamie Gritton { 31920304c731SJamie Gritton 31930304c731SJamie Gritton for (pr2 = pr2->pr_parent; pr2 != NULL; pr2 = pr2->pr_parent) 31940304c731SJamie Gritton if (pr1 == pr2) 31950304c731SJamie Gritton return (1); 319691421ba2SRobert Watson return (0); 319791421ba2SRobert Watson } 319891421ba2SRobert Watson 319991421ba2SRobert Watson /* 320091421ba2SRobert Watson * Return 1 if the passed credential is in a jail, otherwise 0. 320191421ba2SRobert Watson */ 320291421ba2SRobert Watson int 32039ddb7954SMike Barcroft jailed(struct ucred *cred) 320491421ba2SRobert Watson { 320591421ba2SRobert Watson 32060304c731SJamie Gritton return (cred->cr_prison != &prison0); 320791421ba2SRobert Watson } 32089484d0c0SRobert Drehmel 32099484d0c0SRobert Drehmel /* 32107455b100SJamie Gritton * Return the correct hostname (domainname, et al) for the passed credential. 32119484d0c0SRobert Drehmel */ 3212ad1ff099SRobert Drehmel void 32139ddb7954SMike Barcroft getcredhostname(struct ucred *cred, char *buf, size_t size) 32149484d0c0SRobert Drehmel { 321576ca6f88SJamie Gritton struct prison *pr; 32169484d0c0SRobert Drehmel 32177455b100SJamie Gritton /* 32187455b100SJamie Gritton * A NULL credential can be used to shortcut to the physical 32197455b100SJamie Gritton * system's hostname. 32207455b100SJamie Gritton */ 322176ca6f88SJamie Gritton pr = (cred != NULL) ? cred->cr_prison : &prison0; 322276ca6f88SJamie Gritton mtx_lock(&pr->pr_mtx); 322376ca6f88SJamie Gritton strlcpy(buf, pr->pr_host, size); 322476ca6f88SJamie Gritton mtx_unlock(&pr->pr_mtx); 32259484d0c0SRobert Drehmel } 3226fd7a8150SMike Barcroft 32277455b100SJamie Gritton void 32287455b100SJamie Gritton getcreddomainname(struct ucred *cred, char *buf, size_t size) 32297455b100SJamie Gritton { 32307455b100SJamie Gritton 32317455b100SJamie Gritton mtx_lock(&cred->cr_prison->pr_mtx); 32327455b100SJamie Gritton strlcpy(buf, cred->cr_prison->pr_domain, size); 32337455b100SJamie Gritton mtx_unlock(&cred->cr_prison->pr_mtx); 32347455b100SJamie Gritton } 32357455b100SJamie Gritton 32367455b100SJamie Gritton void 32377455b100SJamie Gritton getcredhostuuid(struct ucred *cred, char *buf, size_t size) 32387455b100SJamie Gritton { 32397455b100SJamie Gritton 32407455b100SJamie Gritton mtx_lock(&cred->cr_prison->pr_mtx); 32417455b100SJamie Gritton strlcpy(buf, cred->cr_prison->pr_uuid, size); 32427455b100SJamie Gritton mtx_unlock(&cred->cr_prison->pr_mtx); 32437455b100SJamie Gritton } 32447455b100SJamie Gritton 32457455b100SJamie Gritton void 32467455b100SJamie Gritton getcredhostid(struct ucred *cred, unsigned long *hostid) 32477455b100SJamie Gritton { 32487455b100SJamie Gritton 32497455b100SJamie Gritton mtx_lock(&cred->cr_prison->pr_mtx); 32507455b100SJamie Gritton *hostid = cred->cr_prison->pr_hostid; 32517455b100SJamie Gritton mtx_unlock(&cred->cr_prison->pr_mtx); 32527455b100SJamie Gritton } 32537455b100SJamie Gritton 3254f08df373SRobert Watson /* 3255820a0de9SPawel Jakub Dawidek * Determine whether the subject represented by cred can "see" 3256820a0de9SPawel Jakub Dawidek * status of a mount point. 3257820a0de9SPawel Jakub Dawidek * Returns: 0 for permitted, ENOENT otherwise. 3258820a0de9SPawel Jakub Dawidek * XXX: This function should be called cr_canseemount() and should be 3259820a0de9SPawel Jakub Dawidek * placed in kern_prot.c. 3260f08df373SRobert Watson */ 3261f08df373SRobert Watson int 3262820a0de9SPawel Jakub Dawidek prison_canseemount(struct ucred *cred, struct mount *mp) 3263f08df373SRobert Watson { 3264820a0de9SPawel Jakub Dawidek struct prison *pr; 3265820a0de9SPawel Jakub Dawidek struct statfs *sp; 3266820a0de9SPawel Jakub Dawidek size_t len; 3267f08df373SRobert Watson 3268820a0de9SPawel Jakub Dawidek pr = cred->cr_prison; 32690304c731SJamie Gritton if (pr->pr_enforce_statfs == 0) 32700304c731SJamie Gritton return (0); 3271820a0de9SPawel Jakub Dawidek if (pr->pr_root->v_mount == mp) 3272820a0de9SPawel Jakub Dawidek return (0); 32730304c731SJamie Gritton if (pr->pr_enforce_statfs == 2) 3274820a0de9SPawel Jakub Dawidek return (ENOENT); 3275820a0de9SPawel Jakub Dawidek /* 3276820a0de9SPawel Jakub Dawidek * If jail's chroot directory is set to "/" we should be able to see 3277820a0de9SPawel Jakub Dawidek * all mount-points from inside a jail. 3278820a0de9SPawel Jakub Dawidek * This is ugly check, but this is the only situation when jail's 3279820a0de9SPawel Jakub Dawidek * directory ends with '/'. 3280820a0de9SPawel Jakub Dawidek */ 3281820a0de9SPawel Jakub Dawidek if (strcmp(pr->pr_path, "/") == 0) 3282820a0de9SPawel Jakub Dawidek return (0); 3283820a0de9SPawel Jakub Dawidek len = strlen(pr->pr_path); 3284820a0de9SPawel Jakub Dawidek sp = &mp->mnt_stat; 3285820a0de9SPawel Jakub Dawidek if (strncmp(pr->pr_path, sp->f_mntonname, len) != 0) 3286820a0de9SPawel Jakub Dawidek return (ENOENT); 3287820a0de9SPawel Jakub Dawidek /* 3288820a0de9SPawel Jakub Dawidek * Be sure that we don't have situation where jail's root directory 3289820a0de9SPawel Jakub Dawidek * is "/some/path" and mount point is "/some/pathpath". 3290820a0de9SPawel Jakub Dawidek */ 3291820a0de9SPawel Jakub Dawidek if (sp->f_mntonname[len] != '\0' && sp->f_mntonname[len] != '/') 3292820a0de9SPawel Jakub Dawidek return (ENOENT); 3293f08df373SRobert Watson return (0); 3294f08df373SRobert Watson } 3295820a0de9SPawel Jakub Dawidek 3296820a0de9SPawel Jakub Dawidek void 3297820a0de9SPawel Jakub Dawidek prison_enforce_statfs(struct ucred *cred, struct mount *mp, struct statfs *sp) 3298820a0de9SPawel Jakub Dawidek { 3299820a0de9SPawel Jakub Dawidek char jpath[MAXPATHLEN]; 3300820a0de9SPawel Jakub Dawidek struct prison *pr; 3301820a0de9SPawel Jakub Dawidek size_t len; 3302820a0de9SPawel Jakub Dawidek 3303820a0de9SPawel Jakub Dawidek pr = cred->cr_prison; 33040304c731SJamie Gritton if (pr->pr_enforce_statfs == 0) 33050304c731SJamie Gritton return; 3306820a0de9SPawel Jakub Dawidek if (prison_canseemount(cred, mp) != 0) { 3307820a0de9SPawel Jakub Dawidek bzero(sp->f_mntonname, sizeof(sp->f_mntonname)); 3308820a0de9SPawel Jakub Dawidek strlcpy(sp->f_mntonname, "[restricted]", 3309820a0de9SPawel Jakub Dawidek sizeof(sp->f_mntonname)); 3310820a0de9SPawel Jakub Dawidek return; 3311820a0de9SPawel Jakub Dawidek } 3312820a0de9SPawel Jakub Dawidek if (pr->pr_root->v_mount == mp) { 3313820a0de9SPawel Jakub Dawidek /* 3314820a0de9SPawel Jakub Dawidek * Clear current buffer data, so we are sure nothing from 3315820a0de9SPawel Jakub Dawidek * the valid path left there. 3316820a0de9SPawel Jakub Dawidek */ 3317820a0de9SPawel Jakub Dawidek bzero(sp->f_mntonname, sizeof(sp->f_mntonname)); 3318820a0de9SPawel Jakub Dawidek *sp->f_mntonname = '/'; 3319820a0de9SPawel Jakub Dawidek return; 3320820a0de9SPawel Jakub Dawidek } 3321820a0de9SPawel Jakub Dawidek /* 3322820a0de9SPawel Jakub Dawidek * If jail's chroot directory is set to "/" we should be able to see 3323820a0de9SPawel Jakub Dawidek * all mount-points from inside a jail. 3324820a0de9SPawel Jakub Dawidek */ 3325820a0de9SPawel Jakub Dawidek if (strcmp(pr->pr_path, "/") == 0) 3326820a0de9SPawel Jakub Dawidek return; 3327820a0de9SPawel Jakub Dawidek len = strlen(pr->pr_path); 3328820a0de9SPawel Jakub Dawidek strlcpy(jpath, sp->f_mntonname + len, sizeof(jpath)); 3329820a0de9SPawel Jakub Dawidek /* 3330820a0de9SPawel Jakub Dawidek * Clear current buffer data, so we are sure nothing from 3331820a0de9SPawel Jakub Dawidek * the valid path left there. 3332820a0de9SPawel Jakub Dawidek */ 3333820a0de9SPawel Jakub Dawidek bzero(sp->f_mntonname, sizeof(sp->f_mntonname)); 3334820a0de9SPawel Jakub Dawidek if (*jpath == '\0') { 3335820a0de9SPawel Jakub Dawidek /* Should never happen. */ 3336820a0de9SPawel Jakub Dawidek *sp->f_mntonname = '/'; 3337820a0de9SPawel Jakub Dawidek } else { 3338820a0de9SPawel Jakub Dawidek strlcpy(sp->f_mntonname, jpath, sizeof(sp->f_mntonname)); 3339820a0de9SPawel Jakub Dawidek } 3340f08df373SRobert Watson } 3341f08df373SRobert Watson 3342800c9408SRobert Watson /* 3343800c9408SRobert Watson * Check with permission for a specific privilege is granted within jail. We 3344800c9408SRobert Watson * have a specific list of accepted privileges; the rest are denied. 3345800c9408SRobert Watson */ 3346800c9408SRobert Watson int 3347800c9408SRobert Watson prison_priv_check(struct ucred *cred, int priv) 3348800c9408SRobert Watson { 3349800c9408SRobert Watson 3350800c9408SRobert Watson if (!jailed(cred)) 3351800c9408SRobert Watson return (0); 3352800c9408SRobert Watson 3353800c9408SRobert Watson switch (priv) { 3354800c9408SRobert Watson 3355800c9408SRobert Watson /* 3356800c9408SRobert Watson * Allow ktrace privileges for root in jail. 3357800c9408SRobert Watson */ 3358800c9408SRobert Watson case PRIV_KTRACE: 3359800c9408SRobert Watson 3360c3c1b5e6SRobert Watson #if 0 3361800c9408SRobert Watson /* 3362800c9408SRobert Watson * Allow jailed processes to configure audit identity and 3363800c9408SRobert Watson * submit audit records (login, etc). In the future we may 3364800c9408SRobert Watson * want to further refine the relationship between audit and 3365800c9408SRobert Watson * jail. 3366800c9408SRobert Watson */ 3367800c9408SRobert Watson case PRIV_AUDIT_GETAUDIT: 3368800c9408SRobert Watson case PRIV_AUDIT_SETAUDIT: 3369800c9408SRobert Watson case PRIV_AUDIT_SUBMIT: 3370c3c1b5e6SRobert Watson #endif 3371800c9408SRobert Watson 3372800c9408SRobert Watson /* 3373800c9408SRobert Watson * Allow jailed processes to manipulate process UNIX 3374800c9408SRobert Watson * credentials in any way they see fit. 3375800c9408SRobert Watson */ 3376800c9408SRobert Watson case PRIV_CRED_SETUID: 3377800c9408SRobert Watson case PRIV_CRED_SETEUID: 3378800c9408SRobert Watson case PRIV_CRED_SETGID: 3379800c9408SRobert Watson case PRIV_CRED_SETEGID: 3380800c9408SRobert Watson case PRIV_CRED_SETGROUPS: 3381800c9408SRobert Watson case PRIV_CRED_SETREUID: 3382800c9408SRobert Watson case PRIV_CRED_SETREGID: 3383800c9408SRobert Watson case PRIV_CRED_SETRESUID: 3384800c9408SRobert Watson case PRIV_CRED_SETRESGID: 3385800c9408SRobert Watson 3386800c9408SRobert Watson /* 3387800c9408SRobert Watson * Jail implements visibility constraints already, so allow 3388800c9408SRobert Watson * jailed root to override uid/gid-based constraints. 3389800c9408SRobert Watson */ 3390800c9408SRobert Watson case PRIV_SEEOTHERGIDS: 3391800c9408SRobert Watson case PRIV_SEEOTHERUIDS: 3392800c9408SRobert Watson 3393800c9408SRobert Watson /* 3394800c9408SRobert Watson * Jail implements inter-process debugging limits already, so 3395800c9408SRobert Watson * allow jailed root various debugging privileges. 3396800c9408SRobert Watson */ 3397800c9408SRobert Watson case PRIV_DEBUG_DIFFCRED: 3398800c9408SRobert Watson case PRIV_DEBUG_SUGID: 3399800c9408SRobert Watson case PRIV_DEBUG_UNPRIV: 3400800c9408SRobert Watson 3401800c9408SRobert Watson /* 3402800c9408SRobert Watson * Allow jail to set various resource limits and login 3403800c9408SRobert Watson * properties, and for now, exceed process resource limits. 3404800c9408SRobert Watson */ 3405800c9408SRobert Watson case PRIV_PROC_LIMIT: 3406800c9408SRobert Watson case PRIV_PROC_SETLOGIN: 3407800c9408SRobert Watson case PRIV_PROC_SETRLIMIT: 3408800c9408SRobert Watson 3409800c9408SRobert Watson /* 3410800c9408SRobert Watson * System V and POSIX IPC privileges are granted in jail. 3411800c9408SRobert Watson */ 3412800c9408SRobert Watson case PRIV_IPC_READ: 3413800c9408SRobert Watson case PRIV_IPC_WRITE: 3414800c9408SRobert Watson case PRIV_IPC_ADMIN: 3415800c9408SRobert Watson case PRIV_IPC_MSGSIZE: 3416800c9408SRobert Watson case PRIV_MQ_ADMIN: 3417800c9408SRobert Watson 3418800c9408SRobert Watson /* 34190304c731SJamie Gritton * Jail operations within a jail work on child jails. 34200304c731SJamie Gritton */ 34210304c731SJamie Gritton case PRIV_JAIL_ATTACH: 34220304c731SJamie Gritton case PRIV_JAIL_SET: 34230304c731SJamie Gritton case PRIV_JAIL_REMOVE: 34240304c731SJamie Gritton 34250304c731SJamie Gritton /* 3426800c9408SRobert Watson * Jail implements its own inter-process limits, so allow 3427800c9408SRobert Watson * root processes in jail to change scheduling on other 3428800c9408SRobert Watson * processes in the same jail. Likewise for signalling. 3429800c9408SRobert Watson */ 3430800c9408SRobert Watson case PRIV_SCHED_DIFFCRED: 3431413628a7SBjoern A. Zeeb case PRIV_SCHED_CPUSET: 3432800c9408SRobert Watson case PRIV_SIGNAL_DIFFCRED: 3433800c9408SRobert Watson case PRIV_SIGNAL_SUGID: 3434800c9408SRobert Watson 3435800c9408SRobert Watson /* 3436800c9408SRobert Watson * Allow jailed processes to write to sysctls marked as jail 3437800c9408SRobert Watson * writable. 3438800c9408SRobert Watson */ 3439800c9408SRobert Watson case PRIV_SYSCTL_WRITEJAIL: 3440800c9408SRobert Watson 3441800c9408SRobert Watson /* 3442800c9408SRobert Watson * Allow root in jail to manage a variety of quota 3443e82d0201SRobert Watson * properties. These should likely be conditional on a 3444e82d0201SRobert Watson * configuration option. 3445800c9408SRobert Watson */ 344695b091d2SRobert Watson case PRIV_VFS_GETQUOTA: 344795b091d2SRobert Watson case PRIV_VFS_SETQUOTA: 3448800c9408SRobert Watson 3449800c9408SRobert Watson /* 3450800c9408SRobert Watson * Since Jail relies on chroot() to implement file system 3451800c9408SRobert Watson * protections, grant many VFS privileges to root in jail. 3452800c9408SRobert Watson * Be careful to exclude mount-related and NFS-related 3453800c9408SRobert Watson * privileges. 3454800c9408SRobert Watson */ 3455800c9408SRobert Watson case PRIV_VFS_READ: 3456800c9408SRobert Watson case PRIV_VFS_WRITE: 3457800c9408SRobert Watson case PRIV_VFS_ADMIN: 3458800c9408SRobert Watson case PRIV_VFS_EXEC: 3459800c9408SRobert Watson case PRIV_VFS_LOOKUP: 3460800c9408SRobert Watson case PRIV_VFS_BLOCKRESERVE: /* XXXRW: Slightly surprising. */ 3461800c9408SRobert Watson case PRIV_VFS_CHFLAGS_DEV: 3462800c9408SRobert Watson case PRIV_VFS_CHOWN: 3463800c9408SRobert Watson case PRIV_VFS_CHROOT: 3464bb531912SPawel Jakub Dawidek case PRIV_VFS_RETAINSUGID: 3465800c9408SRobert Watson case PRIV_VFS_FCHROOT: 3466800c9408SRobert Watson case PRIV_VFS_LINK: 3467800c9408SRobert Watson case PRIV_VFS_SETGID: 3468e41966dcSRobert Watson case PRIV_VFS_STAT: 3469800c9408SRobert Watson case PRIV_VFS_STICKYFILE: 3470800c9408SRobert Watson return (0); 3471800c9408SRobert Watson 3472800c9408SRobert Watson /* 3473800c9408SRobert Watson * Depending on the global setting, allow privilege of 3474800c9408SRobert Watson * setting system flags. 3475800c9408SRobert Watson */ 3476800c9408SRobert Watson case PRIV_VFS_SYSFLAGS: 34770304c731SJamie Gritton if (cred->cr_prison->pr_allow & PR_ALLOW_CHFLAGS) 3478800c9408SRobert Watson return (0); 3479800c9408SRobert Watson else 3480800c9408SRobert Watson return (EPERM); 3481800c9408SRobert Watson 3482800c9408SRobert Watson /* 3483f3a8d2f9SPawel Jakub Dawidek * Depending on the global setting, allow privilege of 3484f3a8d2f9SPawel Jakub Dawidek * mounting/unmounting file systems. 3485f3a8d2f9SPawel Jakub Dawidek */ 3486f3a8d2f9SPawel Jakub Dawidek case PRIV_VFS_MOUNT: 3487f3a8d2f9SPawel Jakub Dawidek case PRIV_VFS_UNMOUNT: 3488f3a8d2f9SPawel Jakub Dawidek case PRIV_VFS_MOUNT_NONUSER: 348924b0502eSPawel Jakub Dawidek case PRIV_VFS_MOUNT_OWNER: 34900304c731SJamie Gritton if (cred->cr_prison->pr_allow & PR_ALLOW_MOUNT) 3491f3a8d2f9SPawel Jakub Dawidek return (0); 3492f3a8d2f9SPawel Jakub Dawidek else 3493f3a8d2f9SPawel Jakub Dawidek return (EPERM); 3494f3a8d2f9SPawel Jakub Dawidek 3495f3a8d2f9SPawel Jakub Dawidek /* 34964b084056SRobert Watson * Allow jailed root to bind reserved ports and reuse in-use 34974b084056SRobert Watson * ports. 3498800c9408SRobert Watson */ 3499800c9408SRobert Watson case PRIV_NETINET_RESERVEDPORT: 35004b084056SRobert Watson case PRIV_NETINET_REUSEPORT: 3501800c9408SRobert Watson return (0); 3502800c9408SRobert Watson 3503800c9408SRobert Watson /* 350479ba3952SBjoern A. Zeeb * Allow jailed root to set certian IPv4/6 (option) headers. 350579ba3952SBjoern A. Zeeb */ 350679ba3952SBjoern A. Zeeb case PRIV_NETINET_SETHDROPTS: 350779ba3952SBjoern A. Zeeb return (0); 350879ba3952SBjoern A. Zeeb 350979ba3952SBjoern A. Zeeb /* 3510800c9408SRobert Watson * Conditionally allow creating raw sockets in jail. 3511800c9408SRobert Watson */ 3512800c9408SRobert Watson case PRIV_NETINET_RAW: 35130304c731SJamie Gritton if (cred->cr_prison->pr_allow & PR_ALLOW_RAW_SOCKETS) 3514800c9408SRobert Watson return (0); 3515800c9408SRobert Watson else 3516800c9408SRobert Watson return (EPERM); 3517800c9408SRobert Watson 3518800c9408SRobert Watson /* 3519800c9408SRobert Watson * Since jail implements its own visibility limits on netstat 3520800c9408SRobert Watson * sysctls, allow getcred. This allows identd to work in 3521800c9408SRobert Watson * jail. 3522800c9408SRobert Watson */ 3523800c9408SRobert Watson case PRIV_NETINET_GETCRED: 3524800c9408SRobert Watson return (0); 3525800c9408SRobert Watson 3526800c9408SRobert Watson default: 3527800c9408SRobert Watson /* 3528800c9408SRobert Watson * In all remaining cases, deny the privilege request. This 3529800c9408SRobert Watson * includes almost all network privileges, many system 3530800c9408SRobert Watson * configuration privileges. 3531800c9408SRobert Watson */ 3532800c9408SRobert Watson return (EPERM); 3533800c9408SRobert Watson } 3534800c9408SRobert Watson } 3535800c9408SRobert Watson 35360304c731SJamie Gritton /* 35370304c731SJamie Gritton * Return the part of pr2's name that is relative to pr1, or the whole name 35380304c731SJamie Gritton * if it does not directly follow. 35390304c731SJamie Gritton */ 35400304c731SJamie Gritton 35410304c731SJamie Gritton char * 35420304c731SJamie Gritton prison_name(struct prison *pr1, struct prison *pr2) 35430304c731SJamie Gritton { 35440304c731SJamie Gritton char *name; 35450304c731SJamie Gritton 35460304c731SJamie Gritton /* Jails see themselves as "0" (if they see themselves at all). */ 35470304c731SJamie Gritton if (pr1 == pr2) 35480304c731SJamie Gritton return "0"; 35490304c731SJamie Gritton name = pr2->pr_name; 35500304c731SJamie Gritton if (prison_ischild(pr1, pr2)) { 35510304c731SJamie Gritton /* 35520304c731SJamie Gritton * pr1 isn't locked (and allprison_lock may not be either) 35530304c731SJamie Gritton * so its length can't be counted on. But the number of dots 35540304c731SJamie Gritton * can be counted on - and counted. 35550304c731SJamie Gritton */ 35560304c731SJamie Gritton for (; pr1 != &prison0; pr1 = pr1->pr_parent) 35570304c731SJamie Gritton name = strchr(name, '.') + 1; 35580304c731SJamie Gritton } 35590304c731SJamie Gritton return (name); 35600304c731SJamie Gritton } 35610304c731SJamie Gritton 35620304c731SJamie Gritton /* 35630304c731SJamie Gritton * Return the part of pr2's path that is relative to pr1, or the whole path 35640304c731SJamie Gritton * if it does not directly follow. 35650304c731SJamie Gritton */ 35660304c731SJamie Gritton static char * 35670304c731SJamie Gritton prison_path(struct prison *pr1, struct prison *pr2) 35680304c731SJamie Gritton { 35690304c731SJamie Gritton char *path1, *path2; 35700304c731SJamie Gritton int len1; 35710304c731SJamie Gritton 35720304c731SJamie Gritton path1 = pr1->pr_path; 35730304c731SJamie Gritton path2 = pr2->pr_path; 35740304c731SJamie Gritton if (!strcmp(path1, "/")) 35750304c731SJamie Gritton return (path2); 35760304c731SJamie Gritton len1 = strlen(path1); 35770304c731SJamie Gritton if (strncmp(path1, path2, len1)) 35780304c731SJamie Gritton return (path2); 35790304c731SJamie Gritton if (path2[len1] == '\0') 35800304c731SJamie Gritton return "/"; 35810304c731SJamie Gritton if (path2[len1] == '/') 35820304c731SJamie Gritton return (path2 + len1); 35830304c731SJamie Gritton return (path2); 35840304c731SJamie Gritton } 35850304c731SJamie Gritton 35860304c731SJamie Gritton 35870304c731SJamie Gritton /* 35880304c731SJamie Gritton * Jail-related sysctls. 35890304c731SJamie Gritton */ 35900304c731SJamie Gritton SYSCTL_NODE(_security, OID_AUTO, jail, CTLFLAG_RW, 0, 35910304c731SJamie Gritton "Jails"); 35920304c731SJamie Gritton 3593fd7a8150SMike Barcroft static int 3594fd7a8150SMike Barcroft sysctl_jail_list(SYSCTL_HANDLER_ARGS) 3595fd7a8150SMike Barcroft { 3596b38ff370SJamie Gritton struct xprison *xp; 35970304c731SJamie Gritton struct prison *pr, *cpr; 3598b38ff370SJamie Gritton #ifdef INET 3599b38ff370SJamie Gritton struct in_addr *ip4 = NULL; 3600b38ff370SJamie Gritton int ip4s = 0; 3601b38ff370SJamie Gritton #endif 3602b38ff370SJamie Gritton #ifdef INET6 3603b38ff370SJamie Gritton struct in_addr *ip6 = NULL; 3604b38ff370SJamie Gritton int ip6s = 0; 3605b38ff370SJamie Gritton #endif 36060304c731SJamie Gritton int descend, error; 3607fd7a8150SMike Barcroft 3608b38ff370SJamie Gritton xp = malloc(sizeof(*xp), M_TEMP, M_WAITOK); 36090304c731SJamie Gritton pr = req->td->td_ucred->cr_prison; 3610b38ff370SJamie Gritton error = 0; 3611dc68a633SPawel Jakub Dawidek sx_slock(&allprison_lock); 36120304c731SJamie Gritton FOREACH_PRISON_DESCENDANT(pr, cpr, descend) { 36130304c731SJamie Gritton #if defined(INET) || defined(INET6) 3614b38ff370SJamie Gritton again: 36150304c731SJamie Gritton #endif 36160304c731SJamie Gritton mtx_lock(&cpr->pr_mtx); 3617413628a7SBjoern A. Zeeb #ifdef INET 36180304c731SJamie Gritton if (cpr->pr_ip4s > 0) { 36190304c731SJamie Gritton if (ip4s < cpr->pr_ip4s) { 36200304c731SJamie Gritton ip4s = cpr->pr_ip4s; 36210304c731SJamie Gritton mtx_unlock(&cpr->pr_mtx); 3622b38ff370SJamie Gritton ip4 = realloc(ip4, ip4s * 3623b38ff370SJamie Gritton sizeof(struct in_addr), M_TEMP, M_WAITOK); 3624b38ff370SJamie Gritton goto again; 3625b38ff370SJamie Gritton } 36260304c731SJamie Gritton bcopy(cpr->pr_ip4, ip4, 36270304c731SJamie Gritton cpr->pr_ip4s * sizeof(struct in_addr)); 3628b38ff370SJamie Gritton } 3629413628a7SBjoern A. Zeeb #endif 3630413628a7SBjoern A. Zeeb #ifdef INET6 36310304c731SJamie Gritton if (cpr->pr_ip6s > 0) { 36320304c731SJamie Gritton if (ip6s < cpr->pr_ip6s) { 36330304c731SJamie Gritton ip6s = cpr->pr_ip6s; 36340304c731SJamie Gritton mtx_unlock(&cpr->pr_mtx); 3635b38ff370SJamie Gritton ip6 = realloc(ip6, ip6s * 3636b38ff370SJamie Gritton sizeof(struct in6_addr), M_TEMP, M_WAITOK); 3637b38ff370SJamie Gritton goto again; 3638413628a7SBjoern A. Zeeb } 36390304c731SJamie Gritton bcopy(cpr->pr_ip6, ip6, 36400304c731SJamie Gritton cpr->pr_ip6s * sizeof(struct in6_addr)); 3641b38ff370SJamie Gritton } 3642b38ff370SJamie Gritton #endif 36430304c731SJamie Gritton if (cpr->pr_ref == 0) { 36440304c731SJamie Gritton mtx_unlock(&cpr->pr_mtx); 3645b38ff370SJamie Gritton continue; 3646b38ff370SJamie Gritton } 3647b38ff370SJamie Gritton bzero(xp, sizeof(*xp)); 3648fd7a8150SMike Barcroft xp->pr_version = XPRISON_VERSION; 36490304c731SJamie Gritton xp->pr_id = cpr->pr_id; 36500304c731SJamie Gritton xp->pr_state = cpr->pr_uref > 0 3651b38ff370SJamie Gritton ? PRISON_STATE_ALIVE : PRISON_STATE_DYING; 36520304c731SJamie Gritton strlcpy(xp->pr_path, prison_path(pr, cpr), sizeof(xp->pr_path)); 36530304c731SJamie Gritton strlcpy(xp->pr_host, cpr->pr_host, sizeof(xp->pr_host)); 36540304c731SJamie Gritton strlcpy(xp->pr_name, prison_name(pr, cpr), sizeof(xp->pr_name)); 3655413628a7SBjoern A. Zeeb #ifdef INET 36560304c731SJamie Gritton xp->pr_ip4s = cpr->pr_ip4s; 3657413628a7SBjoern A. Zeeb #endif 3658413628a7SBjoern A. Zeeb #ifdef INET6 36590304c731SJamie Gritton xp->pr_ip6s = cpr->pr_ip6s; 3660413628a7SBjoern A. Zeeb #endif 36610304c731SJamie Gritton mtx_unlock(&cpr->pr_mtx); 3662b38ff370SJamie Gritton error = SYSCTL_OUT(req, xp, sizeof(*xp)); 3663b38ff370SJamie Gritton if (error) 3664b38ff370SJamie Gritton break; 3665413628a7SBjoern A. Zeeb #ifdef INET 3666b38ff370SJamie Gritton if (xp->pr_ip4s > 0) { 3667b38ff370SJamie Gritton error = SYSCTL_OUT(req, ip4, 3668b38ff370SJamie Gritton xp->pr_ip4s * sizeof(struct in_addr)); 3669b38ff370SJamie Gritton if (error) 3670b38ff370SJamie Gritton break; 3671413628a7SBjoern A. Zeeb } 3672413628a7SBjoern A. Zeeb #endif 3673413628a7SBjoern A. Zeeb #ifdef INET6 3674b38ff370SJamie Gritton if (xp->pr_ip6s > 0) { 3675b38ff370SJamie Gritton error = SYSCTL_OUT(req, ip6, 3676b38ff370SJamie Gritton xp->pr_ip6s * sizeof(struct in6_addr)); 3677b38ff370SJamie Gritton if (error) 3678b38ff370SJamie Gritton break; 3679413628a7SBjoern A. Zeeb } 3680413628a7SBjoern A. Zeeb #endif 3681fd7a8150SMike Barcroft } 3682dc68a633SPawel Jakub Dawidek sx_sunlock(&allprison_lock); 3683b38ff370SJamie Gritton free(xp, M_TEMP); 3684b38ff370SJamie Gritton #ifdef INET 3685b38ff370SJamie Gritton free(ip4, M_TEMP); 3686b38ff370SJamie Gritton #endif 3687b38ff370SJamie Gritton #ifdef INET6 3688b38ff370SJamie Gritton free(ip6, M_TEMP); 3689b38ff370SJamie Gritton #endif 3690fd7a8150SMike Barcroft return (error); 3691fd7a8150SMike Barcroft } 3692fd7a8150SMike Barcroft 3693f3b86a5fSEd Schouten SYSCTL_OID(_security_jail, OID_AUTO, list, 3694f3b86a5fSEd Schouten CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 0, 3695f3b86a5fSEd Schouten sysctl_jail_list, "S", "List of active jails"); 3696461167c2SPawel Jakub Dawidek 3697461167c2SPawel Jakub Dawidek static int 3698461167c2SPawel Jakub Dawidek sysctl_jail_jailed(SYSCTL_HANDLER_ARGS) 3699461167c2SPawel Jakub Dawidek { 3700461167c2SPawel Jakub Dawidek int error, injail; 3701461167c2SPawel Jakub Dawidek 3702461167c2SPawel Jakub Dawidek injail = jailed(req->td->td_ucred); 3703461167c2SPawel Jakub Dawidek error = SYSCTL_OUT(req, &injail, sizeof(injail)); 3704461167c2SPawel Jakub Dawidek 3705461167c2SPawel Jakub Dawidek return (error); 3706461167c2SPawel Jakub Dawidek } 37070304c731SJamie Gritton 3708f3b86a5fSEd Schouten SYSCTL_PROC(_security_jail, OID_AUTO, jailed, 3709f3b86a5fSEd Schouten CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 0, 3710f3b86a5fSEd Schouten sysctl_jail_jailed, "I", "Process in jail?"); 3711413628a7SBjoern A. Zeeb 37120304c731SJamie Gritton #if defined(INET) || defined(INET6) 3713e92e0574SJamie Gritton SYSCTL_UINT(_security_jail, OID_AUTO, jail_max_af_ips, CTLFLAG_RW, 37140304c731SJamie Gritton &jail_max_af_ips, 0, 37150304c731SJamie Gritton "Number of IP addresses a jail may have at most per address family"); 37160304c731SJamie Gritton #endif 37170304c731SJamie Gritton 37180304c731SJamie Gritton /* 37190304c731SJamie Gritton * Default parameters for jail(2) compatability. For historical reasons, 37200304c731SJamie Gritton * the sysctl names have varying similarity to the parameter names. Prisons 37210304c731SJamie Gritton * just see their own parameters, and can't change them. 37220304c731SJamie Gritton */ 37230304c731SJamie Gritton static int 37240304c731SJamie Gritton sysctl_jail_default_allow(SYSCTL_HANDLER_ARGS) 37250304c731SJamie Gritton { 37260304c731SJamie Gritton struct prison *pr; 37270304c731SJamie Gritton int allow, error, i; 37280304c731SJamie Gritton 37290304c731SJamie Gritton pr = req->td->td_ucred->cr_prison; 37300304c731SJamie Gritton allow = (pr == &prison0) ? jail_default_allow : pr->pr_allow; 37310304c731SJamie Gritton 37320304c731SJamie Gritton /* Get the current flag value, and convert it to a boolean. */ 37330304c731SJamie Gritton i = (allow & arg2) ? 1 : 0; 37340304c731SJamie Gritton if (arg1 != NULL) 37350304c731SJamie Gritton i = !i; 37360304c731SJamie Gritton error = sysctl_handle_int(oidp, &i, 0, req); 37370304c731SJamie Gritton if (error || !req->newptr) 37380304c731SJamie Gritton return (error); 37390304c731SJamie Gritton i = i ? arg2 : 0; 37400304c731SJamie Gritton if (arg1 != NULL) 37410304c731SJamie Gritton i ^= arg2; 37420304c731SJamie Gritton /* 37430304c731SJamie Gritton * The sysctls don't have CTLFLAGS_PRISON, so assume prison0 37440304c731SJamie Gritton * for writing. 37450304c731SJamie Gritton */ 37460304c731SJamie Gritton mtx_lock(&prison0.pr_mtx); 37470304c731SJamie Gritton jail_default_allow = (jail_default_allow & ~arg2) | i; 37480304c731SJamie Gritton mtx_unlock(&prison0.pr_mtx); 37490304c731SJamie Gritton return (0); 37500304c731SJamie Gritton } 37510304c731SJamie Gritton 37520304c731SJamie Gritton SYSCTL_PROC(_security_jail, OID_AUTO, set_hostname_allowed, 37530304c731SJamie Gritton CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, 37540304c731SJamie Gritton NULL, PR_ALLOW_SET_HOSTNAME, sysctl_jail_default_allow, "I", 37550304c731SJamie Gritton "Processes in jail can set their hostnames"); 37560304c731SJamie Gritton SYSCTL_PROC(_security_jail, OID_AUTO, socket_unixiproute_only, 37570304c731SJamie Gritton CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, 37580304c731SJamie Gritton (void *)1, PR_ALLOW_SOCKET_AF, sysctl_jail_default_allow, "I", 37590304c731SJamie Gritton "Processes in jail are limited to creating UNIX/IP/route sockets only"); 37600304c731SJamie Gritton SYSCTL_PROC(_security_jail, OID_AUTO, sysvipc_allowed, 37610304c731SJamie Gritton CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, 37620304c731SJamie Gritton NULL, PR_ALLOW_SYSVIPC, sysctl_jail_default_allow, "I", 37630304c731SJamie Gritton "Processes in jail can use System V IPC primitives"); 37640304c731SJamie Gritton SYSCTL_PROC(_security_jail, OID_AUTO, allow_raw_sockets, 37650304c731SJamie Gritton CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, 37660304c731SJamie Gritton NULL, PR_ALLOW_RAW_SOCKETS, sysctl_jail_default_allow, "I", 37670304c731SJamie Gritton "Prison root can create raw sockets"); 37680304c731SJamie Gritton SYSCTL_PROC(_security_jail, OID_AUTO, chflags_allowed, 37690304c731SJamie Gritton CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, 37700304c731SJamie Gritton NULL, PR_ALLOW_CHFLAGS, sysctl_jail_default_allow, "I", 37710304c731SJamie Gritton "Processes in jail can alter system file flags"); 37720304c731SJamie Gritton SYSCTL_PROC(_security_jail, OID_AUTO, mount_allowed, 37730304c731SJamie Gritton CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, 37740304c731SJamie Gritton NULL, PR_ALLOW_MOUNT, sysctl_jail_default_allow, "I", 37750304c731SJamie Gritton "Processes in jail can mount/unmount jail-friendly file systems"); 37760304c731SJamie Gritton 37770304c731SJamie Gritton static int 37780304c731SJamie Gritton sysctl_jail_default_level(SYSCTL_HANDLER_ARGS) 37790304c731SJamie Gritton { 37800304c731SJamie Gritton struct prison *pr; 37810304c731SJamie Gritton int level, error; 37820304c731SJamie Gritton 37830304c731SJamie Gritton pr = req->td->td_ucred->cr_prison; 37840304c731SJamie Gritton level = (pr == &prison0) ? *(int *)arg1 : *(int *)((char *)pr + arg2); 37850304c731SJamie Gritton error = sysctl_handle_int(oidp, &level, 0, req); 37860304c731SJamie Gritton if (error || !req->newptr) 37870304c731SJamie Gritton return (error); 37880304c731SJamie Gritton *(int *)arg1 = level; 37890304c731SJamie Gritton return (0); 37900304c731SJamie Gritton } 37910304c731SJamie Gritton 37920304c731SJamie Gritton SYSCTL_PROC(_security_jail, OID_AUTO, enforce_statfs, 37930304c731SJamie Gritton CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, 37940304c731SJamie Gritton &jail_default_enforce_statfs, offsetof(struct prison, pr_enforce_statfs), 37950304c731SJamie Gritton sysctl_jail_default_level, "I", 37960304c731SJamie Gritton "Processes in jail cannot see all mounted file systems"); 37970304c731SJamie Gritton 37980304c731SJamie Gritton /* 37990304c731SJamie Gritton * Nodes to describe jail parameters. Maximum length of string parameters 38000304c731SJamie Gritton * is returned in the string itself, and the other parameters exist merely 38010304c731SJamie Gritton * to make themselves and their types known. 38020304c731SJamie Gritton */ 38030304c731SJamie Gritton SYSCTL_NODE(_security_jail, OID_AUTO, param, CTLFLAG_RW, 0, 38040304c731SJamie Gritton "Jail parameters"); 38050304c731SJamie Gritton 38060304c731SJamie Gritton int 38070304c731SJamie Gritton sysctl_jail_param(SYSCTL_HANDLER_ARGS) 38080304c731SJamie Gritton { 38090304c731SJamie Gritton int i; 38100304c731SJamie Gritton long l; 38110304c731SJamie Gritton size_t s; 38120304c731SJamie Gritton char numbuf[12]; 38130304c731SJamie Gritton 38140304c731SJamie Gritton switch (oidp->oid_kind & CTLTYPE) 38150304c731SJamie Gritton { 38160304c731SJamie Gritton case CTLTYPE_LONG: 38170304c731SJamie Gritton case CTLTYPE_ULONG: 38180304c731SJamie Gritton l = 0; 38190304c731SJamie Gritton #ifdef SCTL_MASK32 38200304c731SJamie Gritton if (!(req->flags & SCTL_MASK32)) 38210304c731SJamie Gritton #endif 38220304c731SJamie Gritton return (SYSCTL_OUT(req, &l, sizeof(l))); 38230304c731SJamie Gritton case CTLTYPE_INT: 38240304c731SJamie Gritton case CTLTYPE_UINT: 38250304c731SJamie Gritton i = 0; 38260304c731SJamie Gritton return (SYSCTL_OUT(req, &i, sizeof(i))); 38270304c731SJamie Gritton case CTLTYPE_STRING: 38280304c731SJamie Gritton snprintf(numbuf, sizeof(numbuf), "%d", arg2); 38290304c731SJamie Gritton return 38300304c731SJamie Gritton (sysctl_handle_string(oidp, numbuf, sizeof(numbuf), req)); 38310304c731SJamie Gritton case CTLTYPE_STRUCT: 38320304c731SJamie Gritton s = (size_t)arg2; 38330304c731SJamie Gritton return (SYSCTL_OUT(req, &s, sizeof(s))); 38340304c731SJamie Gritton } 38350304c731SJamie Gritton return (0); 38360304c731SJamie Gritton } 38370304c731SJamie Gritton 38380304c731SJamie Gritton SYSCTL_JAIL_PARAM(, jid, CTLTYPE_INT | CTLFLAG_RDTUN, "I", "Jail ID"); 38390304c731SJamie Gritton SYSCTL_JAIL_PARAM(, parent, CTLTYPE_INT | CTLFLAG_RD, "I", "Jail parent ID"); 38400304c731SJamie Gritton SYSCTL_JAIL_PARAM_STRING(, name, CTLFLAG_RW, MAXHOSTNAMELEN, "Jail name"); 38410304c731SJamie Gritton SYSCTL_JAIL_PARAM_STRING(, path, CTLFLAG_RDTUN, MAXPATHLEN, "Jail root path"); 38420304c731SJamie Gritton SYSCTL_JAIL_PARAM(, securelevel, CTLTYPE_INT | CTLFLAG_RW, 38430304c731SJamie Gritton "I", "Jail secure level"); 38440304c731SJamie Gritton SYSCTL_JAIL_PARAM(, enforce_statfs, CTLTYPE_INT | CTLFLAG_RW, 38450304c731SJamie Gritton "I", "Jail cannot see all mounted file systems"); 38460304c731SJamie Gritton SYSCTL_JAIL_PARAM(, persist, CTLTYPE_INT | CTLFLAG_RW, 38470304c731SJamie Gritton "B", "Jail persistence"); 38480304c731SJamie Gritton SYSCTL_JAIL_PARAM(, dying, CTLTYPE_INT | CTLFLAG_RD, 38490304c731SJamie Gritton "B", "Jail is in the process of shutting down"); 38500304c731SJamie Gritton 38510304c731SJamie Gritton SYSCTL_JAIL_PARAM_NODE(host, "Jail host info"); 385276ca6f88SJamie Gritton SYSCTL_JAIL_PARAM(, nohost, CTLTYPE_INT | CTLFLAG_RW, 385376ca6f88SJamie Gritton "BN", "Jail w/ no host info"); 38540304c731SJamie Gritton SYSCTL_JAIL_PARAM_STRING(_host, hostname, CTLFLAG_RW, MAXHOSTNAMELEN, 38550304c731SJamie Gritton "Jail hostname"); 385676ca6f88SJamie Gritton SYSCTL_JAIL_PARAM_STRING(_host, domainname, CTLFLAG_RW, MAXHOSTNAMELEN, 385776ca6f88SJamie Gritton "Jail NIS domainname"); 385876ca6f88SJamie Gritton SYSCTL_JAIL_PARAM_STRING(_host, hostuuid, CTLFLAG_RW, HOSTUUIDLEN, 385976ca6f88SJamie Gritton "Jail host UUID"); 386076ca6f88SJamie Gritton SYSCTL_JAIL_PARAM(_host, hostid, CTLTYPE_ULONG | CTLFLAG_RW, 386176ca6f88SJamie Gritton "LU", "Jail host ID"); 38620304c731SJamie Gritton 38630304c731SJamie Gritton SYSCTL_JAIL_PARAM_NODE(cpuset, "Jail cpuset"); 38640304c731SJamie Gritton SYSCTL_JAIL_PARAM(_cpuset, id, CTLTYPE_INT | CTLFLAG_RD, "I", "Jail cpuset ID"); 38650304c731SJamie Gritton 38660304c731SJamie Gritton #ifdef INET 38670304c731SJamie Gritton SYSCTL_JAIL_PARAM_NODE(ip4, "Jail IPv4 address virtualization"); 38680304c731SJamie Gritton SYSCTL_JAIL_PARAM(, noip4, CTLTYPE_INT | CTLFLAG_RW, 38690304c731SJamie Gritton "BN", "Jail w/ no IP address virtualization"); 38700304c731SJamie Gritton SYSCTL_JAIL_PARAM_STRUCT(_ip4, addr, CTLFLAG_RW, sizeof(struct in_addr), 38710304c731SJamie Gritton "S,in_addr,a", "Jail IPv4 addresses"); 38720304c731SJamie Gritton #endif 38730304c731SJamie Gritton #ifdef INET6 38740304c731SJamie Gritton SYSCTL_JAIL_PARAM_NODE(ip6, "Jail IPv6 address virtualization"); 38750304c731SJamie Gritton SYSCTL_JAIL_PARAM(, noip6, CTLTYPE_INT | CTLFLAG_RW, 38760304c731SJamie Gritton "BN", "Jail w/ no IP address virtualization"); 38770304c731SJamie Gritton SYSCTL_JAIL_PARAM_STRUCT(_ip6, addr, CTLFLAG_RW, sizeof(struct in6_addr), 38780304c731SJamie Gritton "S,in6_addr,a", "Jail IPv6 addresses"); 38790304c731SJamie Gritton #endif 38800304c731SJamie Gritton 38810304c731SJamie Gritton SYSCTL_JAIL_PARAM_NODE(allow, "Jail permission flags"); 38820304c731SJamie Gritton SYSCTL_JAIL_PARAM(_allow, set_hostname, CTLTYPE_INT | CTLFLAG_RW, 38830304c731SJamie Gritton "B", "Jail may set hostname"); 38840304c731SJamie Gritton SYSCTL_JAIL_PARAM(_allow, sysvipc, CTLTYPE_INT | CTLFLAG_RW, 38850304c731SJamie Gritton "B", "Jail may use SYSV IPC"); 38860304c731SJamie Gritton SYSCTL_JAIL_PARAM(_allow, raw_sockets, CTLTYPE_INT | CTLFLAG_RW, 38870304c731SJamie Gritton "B", "Jail may create raw sockets"); 38880304c731SJamie Gritton SYSCTL_JAIL_PARAM(_allow, chflags, CTLTYPE_INT | CTLFLAG_RW, 38890304c731SJamie Gritton "B", "Jail may alter system file flags"); 38900304c731SJamie Gritton SYSCTL_JAIL_PARAM(_allow, mount, CTLTYPE_INT | CTLFLAG_RW, 38910304c731SJamie Gritton "B", "Jail may mount/unmount jail-friendly file systems"); 38920304c731SJamie Gritton SYSCTL_JAIL_PARAM(_allow, quotas, CTLTYPE_INT | CTLFLAG_RW, 38930304c731SJamie Gritton "B", "Jail may set file quotas"); 38940304c731SJamie Gritton SYSCTL_JAIL_PARAM(_allow, jails, CTLTYPE_INT | CTLFLAG_RW, 38950304c731SJamie Gritton "B", "Jail may create child jails"); 38960304c731SJamie Gritton SYSCTL_JAIL_PARAM(_allow, socket_af, CTLTYPE_INT | CTLFLAG_RW, 38970304c731SJamie Gritton "B", "Jail may create sockets other than just UNIX/IPv4/IPv6/route"); 38980304c731SJamie Gritton 38990304c731SJamie Gritton 3900413628a7SBjoern A. Zeeb #ifdef DDB 3901b38ff370SJamie Gritton 3902b38ff370SJamie Gritton static void 3903b38ff370SJamie Gritton db_show_prison(struct prison *pr) 3904413628a7SBjoern A. Zeeb { 39050304c731SJamie Gritton int fi; 3906b38ff370SJamie Gritton #if defined(INET) || defined(INET6) 3907b38ff370SJamie Gritton int ii; 3908413628a7SBjoern A. Zeeb #endif 3909413628a7SBjoern A. Zeeb #ifdef INET6 3910413628a7SBjoern A. Zeeb char ip6buf[INET6_ADDRSTRLEN]; 3911413628a7SBjoern A. Zeeb #endif 3912413628a7SBjoern A. Zeeb 3913b38ff370SJamie Gritton db_printf("prison %p:\n", pr); 3914b38ff370SJamie Gritton db_printf(" jid = %d\n", pr->pr_id); 3915b38ff370SJamie Gritton db_printf(" name = %s\n", pr->pr_name); 39160304c731SJamie Gritton db_printf(" parent = %p\n", pr->pr_parent); 3917b38ff370SJamie Gritton db_printf(" ref = %d\n", pr->pr_ref); 3918b38ff370SJamie Gritton db_printf(" uref = %d\n", pr->pr_uref); 3919b38ff370SJamie Gritton db_printf(" path = %s\n", pr->pr_path); 3920b38ff370SJamie Gritton db_printf(" cpuset = %d\n", pr->pr_cpuset 3921b38ff370SJamie Gritton ? pr->pr_cpuset->cs_id : -1); 3922b38ff370SJamie Gritton db_printf(" root = %p\n", pr->pr_root); 3923b38ff370SJamie Gritton db_printf(" securelevel = %d\n", pr->pr_securelevel); 39240304c731SJamie Gritton db_printf(" child = %p\n", LIST_FIRST(&pr->pr_children)); 39250304c731SJamie Gritton db_printf(" sibling = %p\n", LIST_NEXT(pr, pr_sibling)); 3926b38ff370SJamie Gritton db_printf(" flags = %x", pr->pr_flags); 39270304c731SJamie Gritton for (fi = 0; fi < sizeof(pr_flag_names) / sizeof(pr_flag_names[0]); 39280304c731SJamie Gritton fi++) 39290304c731SJamie Gritton if (pr_flag_names[fi] != NULL && (pr->pr_flags & (1 << fi))) 39300304c731SJamie Gritton db_printf(" %s", pr_flag_names[fi]); 39310304c731SJamie Gritton db_printf(" allow = %x", pr->pr_allow); 39320304c731SJamie Gritton for (fi = 0; fi < sizeof(pr_allow_names) / sizeof(pr_allow_names[0]); 39330304c731SJamie Gritton fi++) 39340304c731SJamie Gritton if (pr_allow_names[fi] != NULL && (pr->pr_allow & (1 << fi))) 39350304c731SJamie Gritton db_printf(" %s", pr_allow_names[fi]); 3936b38ff370SJamie Gritton db_printf("\n"); 39370304c731SJamie Gritton db_printf(" enforce_statfs = %d\n", pr->pr_enforce_statfs); 3938b38ff370SJamie Gritton db_printf(" host.hostname = %s\n", pr->pr_host); 393976ca6f88SJamie Gritton db_printf(" host.domainname = %s\n", pr->pr_domain); 394076ca6f88SJamie Gritton db_printf(" host.hostuuid = %s\n", pr->pr_uuid); 394176ca6f88SJamie Gritton db_printf(" host.hostid = %lu\n", pr->pr_hostid); 3942413628a7SBjoern A. Zeeb #ifdef INET 3943b38ff370SJamie Gritton db_printf(" ip4s = %d\n", pr->pr_ip4s); 3944b38ff370SJamie Gritton for (ii = 0; ii < pr->pr_ip4s; ii++) 3945b38ff370SJamie Gritton db_printf(" %s %s\n", 3946b38ff370SJamie Gritton ii == 0 ? "ip4 =" : " ", 3947b38ff370SJamie Gritton inet_ntoa(pr->pr_ip4[ii])); 3948413628a7SBjoern A. Zeeb #endif 3949413628a7SBjoern A. Zeeb #ifdef INET6 3950b38ff370SJamie Gritton db_printf(" ip6s = %d\n", pr->pr_ip6s); 3951b38ff370SJamie Gritton for (ii = 0; ii < pr->pr_ip6s; ii++) 3952b38ff370SJamie Gritton db_printf(" %s %s\n", 3953b38ff370SJamie Gritton ii == 0 ? "ip6 =" : " ", 3954b38ff370SJamie Gritton ip6_sprintf(ip6buf, &pr->pr_ip6[ii])); 3955b38ff370SJamie Gritton #endif 3956b38ff370SJamie Gritton } 3957b38ff370SJamie Gritton 3958b38ff370SJamie Gritton DB_SHOW_COMMAND(prison, db_show_prison_command) 3959b38ff370SJamie Gritton { 3960b38ff370SJamie Gritton struct prison *pr; 3961b38ff370SJamie Gritton 3962b38ff370SJamie Gritton if (!have_addr) { 39630304c731SJamie Gritton /* 39640304c731SJamie Gritton * Show all prisons in the list, and prison0 which is not 39650304c731SJamie Gritton * listed. 39660304c731SJamie Gritton */ 39670304c731SJamie Gritton db_show_prison(&prison0); 39680304c731SJamie Gritton if (!db_pager_quit) { 3969b38ff370SJamie Gritton TAILQ_FOREACH(pr, &allprison, pr_list) { 3970b38ff370SJamie Gritton db_show_prison(pr); 3971413628a7SBjoern A. Zeeb if (db_pager_quit) 3972413628a7SBjoern A. Zeeb break; 3973413628a7SBjoern A. Zeeb } 39740304c731SJamie Gritton } 3975b38ff370SJamie Gritton return; 3976413628a7SBjoern A. Zeeb } 3977b38ff370SJamie Gritton 39780304c731SJamie Gritton if (addr == 0) 39790304c731SJamie Gritton pr = &prison0; 39800304c731SJamie Gritton else { 3981b38ff370SJamie Gritton /* Look for a prison with the ID and with references. */ 3982b38ff370SJamie Gritton TAILQ_FOREACH(pr, &allprison, pr_list) 3983b38ff370SJamie Gritton if (pr->pr_id == addr && pr->pr_ref > 0) 3984b38ff370SJamie Gritton break; 3985b38ff370SJamie Gritton if (pr == NULL) 3986b38ff370SJamie Gritton /* Look again, without requiring a reference. */ 3987b38ff370SJamie Gritton TAILQ_FOREACH(pr, &allprison, pr_list) 3988b38ff370SJamie Gritton if (pr->pr_id == addr) 3989b38ff370SJamie Gritton break; 3990b38ff370SJamie Gritton if (pr == NULL) 3991b38ff370SJamie Gritton /* Assume address points to a valid prison. */ 3992b38ff370SJamie Gritton pr = (struct prison *)addr; 39930304c731SJamie Gritton } 3994b38ff370SJamie Gritton db_show_prison(pr); 3995b38ff370SJamie Gritton } 3996b38ff370SJamie Gritton 3997413628a7SBjoern A. Zeeb #endif /* DDB */ 3998