19454b2d8SWarner Losh /*- 2413628a7SBjoern A. Zeeb * Copyright (c) 1999 Poul-Henning Kamp. 3413628a7SBjoern A. Zeeb * Copyright (c) 2008 Bjoern A. Zeeb. 4413628a7SBjoern A. Zeeb * All rights reserved. 5b9f0b66cSBjoern A. Zeeb * 6b9f0b66cSBjoern A. Zeeb * Redistribution and use in source and binary forms, with or without 7b9f0b66cSBjoern A. Zeeb * modification, are permitted provided that the following conditions 8b9f0b66cSBjoern A. Zeeb * are met: 9b9f0b66cSBjoern A. Zeeb * 1. Redistributions of source code must retain the above copyright 10b9f0b66cSBjoern A. Zeeb * notice, this list of conditions and the following disclaimer. 11b9f0b66cSBjoern A. Zeeb * 2. Redistributions in binary form must reproduce the above copyright 12b9f0b66cSBjoern A. Zeeb * notice, this list of conditions and the following disclaimer in the 13b9f0b66cSBjoern A. Zeeb * documentation and/or other materials provided with the distribution. 14b9f0b66cSBjoern A. Zeeb * 15b9f0b66cSBjoern A. Zeeb * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16b9f0b66cSBjoern A. Zeeb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17b9f0b66cSBjoern A. Zeeb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18b9f0b66cSBjoern A. Zeeb * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19b9f0b66cSBjoern A. Zeeb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20b9f0b66cSBjoern A. Zeeb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21b9f0b66cSBjoern A. Zeeb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22b9f0b66cSBjoern A. Zeeb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23b9f0b66cSBjoern A. Zeeb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24b9f0b66cSBjoern A. Zeeb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25b9f0b66cSBjoern A. Zeeb * SUCH DAMAGE. 2607901f22SPoul-Henning Kamp */ 2775c13541SPoul-Henning Kamp 28677b542eSDavid E. O'Brien #include <sys/cdefs.h> 29677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$"); 30677b542eSDavid E. O'Brien 31413628a7SBjoern A. Zeeb #include "opt_ddb.h" 32413628a7SBjoern A. Zeeb #include "opt_inet.h" 33413628a7SBjoern A. Zeeb #include "opt_inet6.h" 3446e3b1cbSPawel Jakub Dawidek #include "opt_mac.h" 3546e3b1cbSPawel Jakub Dawidek 3675c13541SPoul-Henning Kamp #include <sys/param.h> 3775c13541SPoul-Henning Kamp #include <sys/types.h> 3875c13541SPoul-Henning Kamp #include <sys/kernel.h> 3975c13541SPoul-Henning Kamp #include <sys/systm.h> 4075c13541SPoul-Henning Kamp #include <sys/errno.h> 4175c13541SPoul-Henning Kamp #include <sys/sysproto.h> 4275c13541SPoul-Henning Kamp #include <sys/malloc.h> 43800c9408SRobert Watson #include <sys/priv.h> 4475c13541SPoul-Henning Kamp #include <sys/proc.h> 45b3059e09SRobert Watson #include <sys/taskqueue.h> 4657b4252eSKonstantin Belousov #include <sys/fcntl.h> 4775c13541SPoul-Henning Kamp #include <sys/jail.h> 4801137630SRobert Watson #include <sys/lock.h> 4901137630SRobert Watson #include <sys/mutex.h> 50dc68a633SPawel Jakub Dawidek #include <sys/sx.h> 51fd7a8150SMike Barcroft #include <sys/namei.h> 52820a0de9SPawel Jakub Dawidek #include <sys/mount.h> 53fd7a8150SMike Barcroft #include <sys/queue.h> 5475c13541SPoul-Henning Kamp #include <sys/socket.h> 55fd7a8150SMike Barcroft #include <sys/syscallsubr.h> 5683f1e257SRobert Watson #include <sys/sysctl.h> 57fd7a8150SMike Barcroft #include <sys/vnode.h> 58603724d3SBjoern A. Zeeb #include <sys/vimage.h> 591ba4a712SPawel Jakub Dawidek #include <sys/osd.h> 6075c13541SPoul-Henning Kamp #include <net/if.h> 6175c13541SPoul-Henning Kamp #include <netinet/in.h> 62413628a7SBjoern A. Zeeb #ifdef DDB 63413628a7SBjoern A. Zeeb #include <ddb/ddb.h> 64413628a7SBjoern A. Zeeb #ifdef INET6 65413628a7SBjoern A. Zeeb #include <netinet6/in6_var.h> 66413628a7SBjoern A. Zeeb #endif /* INET6 */ 67413628a7SBjoern A. Zeeb #endif /* DDB */ 6875c13541SPoul-Henning Kamp 69aed55708SRobert Watson #include <security/mac/mac_framework.h> 70aed55708SRobert Watson 7175c13541SPoul-Henning Kamp MALLOC_DEFINE(M_PRISON, "prison", "Prison structures"); 7275c13541SPoul-Henning Kamp 73d0615c64SAndrew R. Reiter SYSCTL_NODE(_security, OID_AUTO, jail, CTLFLAG_RW, 0, 7483f1e257SRobert Watson "Jail rules"); 7583f1e257SRobert Watson 7683f1e257SRobert Watson int jail_set_hostname_allowed = 1; 77d0615c64SAndrew R. Reiter SYSCTL_INT(_security_jail, OID_AUTO, set_hostname_allowed, CTLFLAG_RW, 7883f1e257SRobert Watson &jail_set_hostname_allowed, 0, 7983f1e257SRobert Watson "Processes in jail can set their hostnames"); 8083f1e257SRobert Watson 817cadc266SRobert Watson int jail_socket_unixiproute_only = 1; 82d0615c64SAndrew R. Reiter SYSCTL_INT(_security_jail, OID_AUTO, socket_unixiproute_only, CTLFLAG_RW, 837cadc266SRobert Watson &jail_socket_unixiproute_only, 0, 84413628a7SBjoern A. Zeeb "Processes in jail are limited to creating UNIX/IP/route sockets only"); 857cadc266SRobert Watson 86cb1f0db9SRobert Watson int jail_sysvipc_allowed = 0; 87d0615c64SAndrew R. Reiter SYSCTL_INT(_security_jail, OID_AUTO, sysvipc_allowed, CTLFLAG_RW, 88cb1f0db9SRobert Watson &jail_sysvipc_allowed, 0, 89cb1f0db9SRobert Watson "Processes in jail can use System V IPC primitives"); 90cb1f0db9SRobert Watson 91820a0de9SPawel Jakub Dawidek static int jail_enforce_statfs = 2; 92820a0de9SPawel Jakub Dawidek SYSCTL_INT(_security_jail, OID_AUTO, enforce_statfs, CTLFLAG_RW, 93820a0de9SPawel Jakub Dawidek &jail_enforce_statfs, 0, 94820a0de9SPawel Jakub Dawidek "Processes in jail cannot see all mounted file systems"); 95f08df373SRobert Watson 965a59cefcSBosko Milekic int jail_allow_raw_sockets = 0; 975a59cefcSBosko Milekic SYSCTL_INT(_security_jail, OID_AUTO, allow_raw_sockets, CTLFLAG_RW, 985a59cefcSBosko Milekic &jail_allow_raw_sockets, 0, 995a59cefcSBosko Milekic "Prison root can create raw sockets"); 1005a59cefcSBosko Milekic 10179653046SColin Percival int jail_chflags_allowed = 0; 10279653046SColin Percival SYSCTL_INT(_security_jail, OID_AUTO, chflags_allowed, CTLFLAG_RW, 10379653046SColin Percival &jail_chflags_allowed, 0, 10479653046SColin Percival "Processes in jail can alter system file flags"); 10579653046SColin Percival 106f3a8d2f9SPawel Jakub Dawidek int jail_mount_allowed = 0; 107f3a8d2f9SPawel Jakub Dawidek SYSCTL_INT(_security_jail, OID_AUTO, mount_allowed, CTLFLAG_RW, 108f3a8d2f9SPawel Jakub Dawidek &jail_mount_allowed, 0, 109f3a8d2f9SPawel Jakub Dawidek "Processes in jail can mount/unmount jail-friendly file systems"); 110f3a8d2f9SPawel Jakub Dawidek 111413628a7SBjoern A. Zeeb int jail_max_af_ips = 255; 112413628a7SBjoern A. Zeeb SYSCTL_INT(_security_jail, OID_AUTO, jail_max_af_ips, CTLFLAG_RW, 113413628a7SBjoern A. Zeeb &jail_max_af_ips, 0, 114413628a7SBjoern A. Zeeb "Number of IP addresses a jail may have at most per address family"); 115413628a7SBjoern A. Zeeb 1162110d913SXin LI /* allprison, lastprid, and prisoncount are protected by allprison_lock. */ 1172110d913SXin LI struct prisonlist allprison; 118dc68a633SPawel Jakub Dawidek struct sx allprison_lock; 1192110d913SXin LI int lastprid = 0; 120fd7a8150SMike Barcroft int prisoncount = 0; 121fd7a8150SMike Barcroft 122fd7a8150SMike Barcroft static void init_prison(void *); 123b3059e09SRobert Watson static void prison_complete(void *context, int pending); 124fd7a8150SMike Barcroft static int sysctl_jail_list(SYSCTL_HANDLER_ARGS); 125413628a7SBjoern A. Zeeb #ifdef INET 126413628a7SBjoern A. Zeeb static int _prison_check_ip4(struct prison *, struct in_addr *); 127413628a7SBjoern A. Zeeb #endif 128413628a7SBjoern A. Zeeb #ifdef INET6 129413628a7SBjoern A. Zeeb static int _prison_check_ip6(struct prison *, struct in6_addr *); 130413628a7SBjoern A. Zeeb #endif 131fd7a8150SMike Barcroft 132fd7a8150SMike Barcroft static void 133fd7a8150SMike Barcroft init_prison(void *data __unused) 134fd7a8150SMike Barcroft { 135fd7a8150SMike Barcroft 1362110d913SXin LI sx_init(&allprison_lock, "allprison"); 1372110d913SXin LI LIST_INIT(&allprison); 138fd7a8150SMike Barcroft } 139fd7a8150SMike Barcroft 140fd7a8150SMike Barcroft SYSINIT(prison, SI_SUB_INTRINSIC, SI_ORDER_ANY, init_prison, NULL); 141fd7a8150SMike Barcroft 142413628a7SBjoern A. Zeeb #ifdef INET 143413628a7SBjoern A. Zeeb static int 144413628a7SBjoern A. Zeeb qcmp_v4(const void *ip1, const void *ip2) 145413628a7SBjoern A. Zeeb { 146413628a7SBjoern A. Zeeb in_addr_t iaa, iab; 147413628a7SBjoern A. Zeeb 148413628a7SBjoern A. Zeeb /* 149413628a7SBjoern A. Zeeb * We need to compare in HBO here to get the list sorted as expected 150413628a7SBjoern A. Zeeb * by the result of the code. Sorting NBO addresses gives you 151413628a7SBjoern A. Zeeb * interesting results. If you do not understand, do not try. 152413628a7SBjoern A. Zeeb */ 153413628a7SBjoern A. Zeeb iaa = ntohl(((const struct in_addr *)ip1)->s_addr); 154413628a7SBjoern A. Zeeb iab = ntohl(((const struct in_addr *)ip2)->s_addr); 155413628a7SBjoern A. Zeeb 156413628a7SBjoern A. Zeeb /* 157413628a7SBjoern A. Zeeb * Do not simply return the difference of the two numbers, the int is 158413628a7SBjoern A. Zeeb * not wide enough. 159413628a7SBjoern A. Zeeb */ 160413628a7SBjoern A. Zeeb if (iaa > iab) 161413628a7SBjoern A. Zeeb return (1); 162413628a7SBjoern A. Zeeb else if (iaa < iab) 163413628a7SBjoern A. Zeeb return (-1); 164413628a7SBjoern A. Zeeb else 165413628a7SBjoern A. Zeeb return (0); 166413628a7SBjoern A. Zeeb } 167413628a7SBjoern A. Zeeb #endif 168413628a7SBjoern A. Zeeb 169413628a7SBjoern A. Zeeb #ifdef INET6 170413628a7SBjoern A. Zeeb static int 171413628a7SBjoern A. Zeeb qcmp_v6(const void *ip1, const void *ip2) 172413628a7SBjoern A. Zeeb { 173413628a7SBjoern A. Zeeb const struct in6_addr *ia6a, *ia6b; 174413628a7SBjoern A. Zeeb int i, rc; 175413628a7SBjoern A. Zeeb 176413628a7SBjoern A. Zeeb ia6a = (const struct in6_addr *)ip1; 177413628a7SBjoern A. Zeeb ia6b = (const struct in6_addr *)ip2; 178413628a7SBjoern A. Zeeb 179413628a7SBjoern A. Zeeb rc = 0; 180413628a7SBjoern A. Zeeb for (i=0; rc == 0 && i < sizeof(struct in6_addr); i++) { 181413628a7SBjoern A. Zeeb if (ia6a->s6_addr[i] > ia6b->s6_addr[i]) 182413628a7SBjoern A. Zeeb rc = 1; 183413628a7SBjoern A. Zeeb else if (ia6a->s6_addr[i] < ia6b->s6_addr[i]) 184413628a7SBjoern A. Zeeb rc = -1; 185413628a7SBjoern A. Zeeb } 186413628a7SBjoern A. Zeeb return (rc); 187413628a7SBjoern A. Zeeb } 188413628a7SBjoern A. Zeeb #endif 189413628a7SBjoern A. Zeeb 190413628a7SBjoern A. Zeeb #if defined(INET) || defined(INET6) 191413628a7SBjoern A. Zeeb static int 192413628a7SBjoern A. Zeeb prison_check_conflicting_ips(struct prison *p) 193413628a7SBjoern A. Zeeb { 194413628a7SBjoern A. Zeeb struct prison *pr; 195413628a7SBjoern A. Zeeb int i; 196413628a7SBjoern A. Zeeb 197413628a7SBjoern A. Zeeb sx_assert(&allprison_lock, SX_LOCKED); 198413628a7SBjoern A. Zeeb 199413628a7SBjoern A. Zeeb if (p->pr_ip4s == 0 && p->pr_ip6s == 0) 200413628a7SBjoern A. Zeeb return (0); 201413628a7SBjoern A. Zeeb 202413628a7SBjoern A. Zeeb LIST_FOREACH(pr, &allprison, pr_list) { 203413628a7SBjoern A. Zeeb /* 204413628a7SBjoern A. Zeeb * Skip 'dying' prisons to avoid problems when 205413628a7SBjoern A. Zeeb * restarting multi-IP jails. 206413628a7SBjoern A. Zeeb */ 207413628a7SBjoern A. Zeeb if (pr->pr_state == PRISON_STATE_DYING) 208413628a7SBjoern A. Zeeb continue; 209413628a7SBjoern A. Zeeb 210413628a7SBjoern A. Zeeb /* 211413628a7SBjoern A. Zeeb * We permit conflicting IPs if there is no 212413628a7SBjoern A. Zeeb * more than 1 IP on eeach jail. 213413628a7SBjoern A. Zeeb * In case there is one duplicate on a jail with 214413628a7SBjoern A. Zeeb * more than one IP stop checking and return error. 215413628a7SBjoern A. Zeeb */ 216413628a7SBjoern A. Zeeb #ifdef INET 217413628a7SBjoern A. Zeeb if ((p->pr_ip4s >= 1 && pr->pr_ip4s > 1) || 218413628a7SBjoern A. Zeeb (p->pr_ip4s > 1 && pr->pr_ip4s >= 1)) { 219413628a7SBjoern A. Zeeb for (i = 0; i < p->pr_ip4s; i++) { 220b89e82ddSJamie Gritton if (_prison_check_ip4(pr, &p->pr_ip4[i]) == 0) 221413628a7SBjoern A. Zeeb return (EINVAL); 222413628a7SBjoern A. Zeeb } 223413628a7SBjoern A. Zeeb } 224413628a7SBjoern A. Zeeb #endif 225413628a7SBjoern A. Zeeb #ifdef INET6 226413628a7SBjoern A. Zeeb if ((p->pr_ip6s >= 1 && pr->pr_ip6s > 1) || 227413628a7SBjoern A. Zeeb (p->pr_ip6s > 1 && pr->pr_ip6s >= 1)) { 228413628a7SBjoern A. Zeeb for (i = 0; i < p->pr_ip6s; i++) { 229b89e82ddSJamie Gritton if (_prison_check_ip6(pr, &p->pr_ip6[i]) == 0) 230413628a7SBjoern A. Zeeb return (EINVAL); 231413628a7SBjoern A. Zeeb } 232413628a7SBjoern A. Zeeb } 233413628a7SBjoern A. Zeeb #endif 234413628a7SBjoern A. Zeeb } 235413628a7SBjoern A. Zeeb 236413628a7SBjoern A. Zeeb return (0); 237413628a7SBjoern A. Zeeb } 238413628a7SBjoern A. Zeeb 239413628a7SBjoern A. Zeeb static int 240413628a7SBjoern A. Zeeb jail_copyin_ips(struct jail *j) 241413628a7SBjoern A. Zeeb { 242413628a7SBjoern A. Zeeb #ifdef INET 243413628a7SBjoern A. Zeeb struct in_addr *ip4; 244413628a7SBjoern A. Zeeb #endif 245413628a7SBjoern A. Zeeb #ifdef INET6 246413628a7SBjoern A. Zeeb struct in6_addr *ip6; 247413628a7SBjoern A. Zeeb #endif 248413628a7SBjoern A. Zeeb int error, i; 249413628a7SBjoern A. Zeeb 250413628a7SBjoern A. Zeeb /* 251413628a7SBjoern A. Zeeb * Copy in addresses, check for duplicate addresses and do some 252413628a7SBjoern A. Zeeb * simple 0 and broadcast checks. If users give other bogus addresses 253413628a7SBjoern A. Zeeb * it is their problem. 254413628a7SBjoern A. Zeeb * 255413628a7SBjoern A. Zeeb * IP addresses are all sorted but ip[0] to preserve the primary IP 256413628a7SBjoern A. Zeeb * address as given from userland. This special IP is used for 257413628a7SBjoern A. Zeeb * unbound outgoing connections as well for "loopback" traffic. 258413628a7SBjoern A. Zeeb */ 259413628a7SBjoern A. Zeeb #ifdef INET 260413628a7SBjoern A. Zeeb ip4 = NULL; 261413628a7SBjoern A. Zeeb #endif 262413628a7SBjoern A. Zeeb #ifdef INET6 263413628a7SBjoern A. Zeeb ip6 = NULL; 264413628a7SBjoern A. Zeeb #endif 265413628a7SBjoern A. Zeeb #ifdef INET 266413628a7SBjoern A. Zeeb if (j->ip4s > 0) { 267413628a7SBjoern A. Zeeb ip4 = (struct in_addr *)malloc(j->ip4s * sizeof(struct in_addr), 268413628a7SBjoern A. Zeeb M_PRISON, M_WAITOK | M_ZERO); 269413628a7SBjoern A. Zeeb error = copyin(j->ip4, ip4, j->ip4s * sizeof(struct in_addr)); 270413628a7SBjoern A. Zeeb if (error) 271413628a7SBjoern A. Zeeb goto e_free_ip; 272413628a7SBjoern A. Zeeb /* Sort all but the first IPv4 address. */ 273413628a7SBjoern A. Zeeb if (j->ip4s > 1) 274413628a7SBjoern A. Zeeb qsort((ip4 + 1), j->ip4s - 1, 275413628a7SBjoern A. Zeeb sizeof(struct in_addr), qcmp_v4); 276413628a7SBjoern A. Zeeb 277413628a7SBjoern A. Zeeb /* 278413628a7SBjoern A. Zeeb * We do not have to care about byte order for these checks 279413628a7SBjoern A. Zeeb * so we will do them in NBO. 280413628a7SBjoern A. Zeeb */ 281413628a7SBjoern A. Zeeb for (i=0; i<j->ip4s; i++) { 282413628a7SBjoern A. Zeeb if (ip4[i].s_addr == htonl(INADDR_ANY) || 283413628a7SBjoern A. Zeeb ip4[i].s_addr == htonl(INADDR_BROADCAST)) { 284413628a7SBjoern A. Zeeb error = EINVAL; 285413628a7SBjoern A. Zeeb goto e_free_ip; 286413628a7SBjoern A. Zeeb } 287413628a7SBjoern A. Zeeb if ((i+1) < j->ip4s && 288413628a7SBjoern A. Zeeb (ip4[0].s_addr == ip4[i+1].s_addr || 289413628a7SBjoern A. Zeeb ip4[i].s_addr == ip4[i+1].s_addr)) { 290413628a7SBjoern A. Zeeb error = EINVAL; 291413628a7SBjoern A. Zeeb goto e_free_ip; 292413628a7SBjoern A. Zeeb } 293413628a7SBjoern A. Zeeb } 294413628a7SBjoern A. Zeeb 295413628a7SBjoern A. Zeeb j->ip4 = ip4; 296bc971b2cSPeter Holm } else 297bc971b2cSPeter Holm j->ip4 = NULL; 298413628a7SBjoern A. Zeeb #endif 299413628a7SBjoern A. Zeeb #ifdef INET6 300413628a7SBjoern A. Zeeb if (j->ip6s > 0) { 301413628a7SBjoern A. Zeeb ip6 = (struct in6_addr *)malloc(j->ip6s * sizeof(struct in6_addr), 302413628a7SBjoern A. Zeeb M_PRISON, M_WAITOK | M_ZERO); 303413628a7SBjoern A. Zeeb error = copyin(j->ip6, ip6, j->ip6s * sizeof(struct in6_addr)); 304413628a7SBjoern A. Zeeb if (error) 305413628a7SBjoern A. Zeeb goto e_free_ip; 306413628a7SBjoern A. Zeeb /* Sort all but the first IPv6 address. */ 307413628a7SBjoern A. Zeeb if (j->ip6s > 1) 308413628a7SBjoern A. Zeeb qsort((ip6 + 1), j->ip6s - 1, 309413628a7SBjoern A. Zeeb sizeof(struct in6_addr), qcmp_v6); 310413628a7SBjoern A. Zeeb for (i=0; i<j->ip6s; i++) { 311413628a7SBjoern A. Zeeb if (IN6_IS_ADDR_UNSPECIFIED(&ip6[i])) { 312413628a7SBjoern A. Zeeb error = EINVAL; 313413628a7SBjoern A. Zeeb goto e_free_ip; 314413628a7SBjoern A. Zeeb } 315413628a7SBjoern A. Zeeb if ((i+1) < j->ip6s && 316413628a7SBjoern A. Zeeb (IN6_ARE_ADDR_EQUAL(&ip6[0], &ip6[i+1]) || 317413628a7SBjoern A. Zeeb IN6_ARE_ADDR_EQUAL(&ip6[i], &ip6[i+1]))) { 318413628a7SBjoern A. Zeeb error = EINVAL; 319413628a7SBjoern A. Zeeb goto e_free_ip; 320413628a7SBjoern A. Zeeb } 321413628a7SBjoern A. Zeeb } 322413628a7SBjoern A. Zeeb 323413628a7SBjoern A. Zeeb j->ip6 = ip6; 324bc971b2cSPeter Holm } else 325bc971b2cSPeter Holm j->ip6 = NULL; 326413628a7SBjoern A. Zeeb #endif 327413628a7SBjoern A. Zeeb return (0); 328413628a7SBjoern A. Zeeb 329413628a7SBjoern A. Zeeb e_free_ip: 330413628a7SBjoern A. Zeeb #ifdef INET6 331413628a7SBjoern A. Zeeb free(ip6, M_PRISON); 332413628a7SBjoern A. Zeeb #endif 333413628a7SBjoern A. Zeeb #ifdef INET 334413628a7SBjoern A. Zeeb free(ip4, M_PRISON); 335413628a7SBjoern A. Zeeb #endif 336413628a7SBjoern A. Zeeb return (error); 337413628a7SBjoern A. Zeeb } 338413628a7SBjoern A. Zeeb #endif /* INET || INET6 */ 339413628a7SBjoern A. Zeeb 340413628a7SBjoern A. Zeeb static int 341413628a7SBjoern A. Zeeb jail_handle_ips(struct jail *j) 342413628a7SBjoern A. Zeeb { 343413628a7SBjoern A. Zeeb #if defined(INET) || defined(INET6) 344413628a7SBjoern A. Zeeb int error; 345413628a7SBjoern A. Zeeb #endif 346413628a7SBjoern A. Zeeb 347413628a7SBjoern A. Zeeb /* 348413628a7SBjoern A. Zeeb * Finish conversion for older versions, copyin and setup IPs. 349413628a7SBjoern A. Zeeb */ 350413628a7SBjoern A. Zeeb switch (j->version) { 351413628a7SBjoern A. Zeeb case 0: 352413628a7SBjoern A. Zeeb { 353413628a7SBjoern A. Zeeb #ifdef INET 354413628a7SBjoern A. Zeeb /* FreeBSD single IPv4 jails. */ 355413628a7SBjoern A. Zeeb struct in_addr *ip4; 356413628a7SBjoern A. Zeeb 357413628a7SBjoern A. Zeeb if (j->ip4s == INADDR_ANY || j->ip4s == INADDR_BROADCAST) 358413628a7SBjoern A. Zeeb return (EINVAL); 359413628a7SBjoern A. Zeeb ip4 = (struct in_addr *)malloc(sizeof(struct in_addr), 360413628a7SBjoern A. Zeeb M_PRISON, M_WAITOK | M_ZERO); 361413628a7SBjoern A. Zeeb 362413628a7SBjoern A. Zeeb /* 363413628a7SBjoern A. Zeeb * Jail version 0 still used HBO for the IPv4 address. 364413628a7SBjoern A. Zeeb */ 365413628a7SBjoern A. Zeeb ip4->s_addr = htonl(j->ip4s); 366413628a7SBjoern A. Zeeb j->ip4s = 1; 367413628a7SBjoern A. Zeeb j->ip4 = ip4; 368413628a7SBjoern A. Zeeb break; 369413628a7SBjoern A. Zeeb #else 370413628a7SBjoern A. Zeeb return (EINVAL); 371413628a7SBjoern A. Zeeb #endif 372413628a7SBjoern A. Zeeb } 373413628a7SBjoern A. Zeeb 374413628a7SBjoern A. Zeeb case 1: 375413628a7SBjoern A. Zeeb /* 376413628a7SBjoern A. Zeeb * Version 1 was used by multi-IPv4 jail implementations 377413628a7SBjoern A. Zeeb * that never made it into the official kernel. 378413628a7SBjoern A. Zeeb * We should never hit this here; jail() should catch it. 379413628a7SBjoern A. Zeeb */ 380413628a7SBjoern A. Zeeb return (EINVAL); 381413628a7SBjoern A. Zeeb 382413628a7SBjoern A. Zeeb case 2: /* JAIL_API_VERSION */ 383413628a7SBjoern A. Zeeb /* FreeBSD multi-IPv4/IPv6,noIP jails. */ 384413628a7SBjoern A. Zeeb #if defined(INET) || defined(INET6) 385413628a7SBjoern A. Zeeb #ifdef INET 386413628a7SBjoern A. Zeeb if (j->ip4s > jail_max_af_ips) 387413628a7SBjoern A. Zeeb return (EINVAL); 388413628a7SBjoern A. Zeeb #else 389413628a7SBjoern A. Zeeb if (j->ip4s != 0) 390413628a7SBjoern A. Zeeb return (EINVAL); 391413628a7SBjoern A. Zeeb #endif 392413628a7SBjoern A. Zeeb #ifdef INET6 393413628a7SBjoern A. Zeeb if (j->ip6s > jail_max_af_ips) 394413628a7SBjoern A. Zeeb return (EINVAL); 395413628a7SBjoern A. Zeeb #else 396413628a7SBjoern A. Zeeb if (j->ip6s != 0) 397413628a7SBjoern A. Zeeb return (EINVAL); 398413628a7SBjoern A. Zeeb #endif 399413628a7SBjoern A. Zeeb error = jail_copyin_ips(j); 400413628a7SBjoern A. Zeeb if (error) 401413628a7SBjoern A. Zeeb return (error); 402413628a7SBjoern A. Zeeb #endif 403413628a7SBjoern A. Zeeb break; 404413628a7SBjoern A. Zeeb 405413628a7SBjoern A. Zeeb default: 406413628a7SBjoern A. Zeeb /* Sci-Fi jails are not supported, sorry. */ 407413628a7SBjoern A. Zeeb return (EINVAL); 408413628a7SBjoern A. Zeeb } 409413628a7SBjoern A. Zeeb 410413628a7SBjoern A. Zeeb return (0); 411413628a7SBjoern A. Zeeb } 412413628a7SBjoern A. Zeeb 413413628a7SBjoern A. Zeeb 414116734c4SMatthew Dillon /* 4159ddb7954SMike Barcroft * struct jail_args { 4169ddb7954SMike Barcroft * struct jail *jail; 4179ddb7954SMike Barcroft * }; 418116734c4SMatthew Dillon */ 41975c13541SPoul-Henning Kamp int 4209ddb7954SMike Barcroft jail(struct thread *td, struct jail_args *uap) 42175c13541SPoul-Henning Kamp { 422413628a7SBjoern A. Zeeb uint32_t version; 423413628a7SBjoern A. Zeeb int error; 424413628a7SBjoern A. Zeeb struct jail j; 425413628a7SBjoern A. Zeeb 426413628a7SBjoern A. Zeeb error = copyin(uap->jail, &version, sizeof(uint32_t)); 427413628a7SBjoern A. Zeeb if (error) 428413628a7SBjoern A. Zeeb return (error); 429413628a7SBjoern A. Zeeb 430413628a7SBjoern A. Zeeb switch (version) { 431413628a7SBjoern A. Zeeb case 0: 432413628a7SBjoern A. Zeeb /* FreeBSD single IPv4 jails. */ 433413628a7SBjoern A. Zeeb { 434413628a7SBjoern A. Zeeb struct jail_v0 j0; 435413628a7SBjoern A. Zeeb 436413628a7SBjoern A. Zeeb bzero(&j, sizeof(struct jail)); 437413628a7SBjoern A. Zeeb error = copyin(uap->jail, &j0, sizeof(struct jail_v0)); 438413628a7SBjoern A. Zeeb if (error) 439413628a7SBjoern A. Zeeb return (error); 440413628a7SBjoern A. Zeeb j.version = j0.version; 441413628a7SBjoern A. Zeeb j.path = j0.path; 442413628a7SBjoern A. Zeeb j.hostname = j0.hostname; 443413628a7SBjoern A. Zeeb j.ip4s = j0.ip_number; 444413628a7SBjoern A. Zeeb break; 445413628a7SBjoern A. Zeeb } 446413628a7SBjoern A. Zeeb 447413628a7SBjoern A. Zeeb case 1: 448413628a7SBjoern A. Zeeb /* 449413628a7SBjoern A. Zeeb * Version 1 was used by multi-IPv4 jail implementations 450413628a7SBjoern A. Zeeb * that never made it into the official kernel. 451413628a7SBjoern A. Zeeb */ 452413628a7SBjoern A. Zeeb return (EINVAL); 453413628a7SBjoern A. Zeeb 454413628a7SBjoern A. Zeeb case 2: /* JAIL_API_VERSION */ 455413628a7SBjoern A. Zeeb /* FreeBSD multi-IPv4/IPv6,noIP jails. */ 456413628a7SBjoern A. Zeeb error = copyin(uap->jail, &j, sizeof(struct jail)); 457413628a7SBjoern A. Zeeb if (error) 458413628a7SBjoern A. Zeeb return (error); 459413628a7SBjoern A. Zeeb break; 460413628a7SBjoern A. Zeeb 461413628a7SBjoern A. Zeeb default: 462413628a7SBjoern A. Zeeb /* Sci-Fi jails are not supported, sorry. */ 463413628a7SBjoern A. Zeeb return (EINVAL); 464413628a7SBjoern A. Zeeb } 465413628a7SBjoern A. Zeeb return (kern_jail(td, &j)); 466413628a7SBjoern A. Zeeb } 467413628a7SBjoern A. Zeeb 468413628a7SBjoern A. Zeeb int 469413628a7SBjoern A. Zeeb kern_jail(struct thread *td, struct jail *j) 470413628a7SBjoern A. Zeeb { 471fd7a8150SMike Barcroft struct nameidata nd; 4722110d913SXin LI struct prison *pr, *tpr; 473fd7a8150SMike Barcroft struct jail_attach_args jaa; 4742110d913SXin LI int vfslocked, error, tryprid; 47575c13541SPoul-Henning Kamp 476413628a7SBjoern A. Zeeb KASSERT(j != NULL, ("%s: j is NULL", __func__)); 477413628a7SBjoern A. Zeeb 478413628a7SBjoern A. Zeeb /* Handle addresses - convert old structs, copyin, check IPs. */ 479413628a7SBjoern A. Zeeb error = jail_handle_ips(j); 48075c13541SPoul-Henning Kamp if (error) 481a2f2b3afSJohn Baldwin return (error); 482a2f2b3afSJohn Baldwin 483413628a7SBjoern A. Zeeb /* Allocate struct prison and fill it with life. */ 4841ede983cSDag-Erling Smørgrav pr = malloc(sizeof(*pr), M_PRISON, M_WAITOK | M_ZERO); 4856008862bSJohn Baldwin mtx_init(&pr->pr_mtx, "jail mutex", NULL, MTX_DEF); 486fd7a8150SMike Barcroft pr->pr_ref = 1; 487413628a7SBjoern A. Zeeb error = copyinstr(j->path, &pr->pr_path, sizeof(pr->pr_path), NULL); 488fd7a8150SMike Barcroft if (error) 489fd7a8150SMike Barcroft goto e_killmtx; 490453f7d53SChristian S.J. Peron NDINIT(&nd, LOOKUP, MPSAFE | FOLLOW | LOCKLEAF, UIO_SYSSPACE, 491453f7d53SChristian S.J. Peron pr->pr_path, td); 492fd7a8150SMike Barcroft error = namei(&nd); 493453f7d53SChristian S.J. Peron if (error) 494fd7a8150SMike Barcroft goto e_killmtx; 495453f7d53SChristian S.J. Peron vfslocked = NDHASGIANT(&nd); 496fd7a8150SMike Barcroft pr->pr_root = nd.ni_vp; 49722db15c0SAttilio Rao VOP_UNLOCK(nd.ni_vp, 0); 498fd7a8150SMike Barcroft NDFREE(&nd, NDF_ONLY_PNBUF); 499453f7d53SChristian S.J. Peron VFS_UNLOCK_GIANT(vfslocked); 500413628a7SBjoern A. Zeeb error = copyinstr(j->hostname, &pr->pr_host, sizeof(pr->pr_host), NULL); 50175c13541SPoul-Henning Kamp if (error) 502fd7a8150SMike Barcroft goto e_dropvnref; 503413628a7SBjoern A. Zeeb if (j->jailname != NULL) { 504413628a7SBjoern A. Zeeb error = copyinstr(j->jailname, &pr->pr_name, 505413628a7SBjoern A. Zeeb sizeof(pr->pr_name), NULL); 506413628a7SBjoern A. Zeeb if (error) 507413628a7SBjoern A. Zeeb goto e_dropvnref; 508413628a7SBjoern A. Zeeb } 509413628a7SBjoern A. Zeeb if (j->ip4s > 0) { 510413628a7SBjoern A. Zeeb pr->pr_ip4 = j->ip4; 511413628a7SBjoern A. Zeeb pr->pr_ip4s = j->ip4s; 512413628a7SBjoern A. Zeeb } 513413628a7SBjoern A. Zeeb #ifdef INET6 514413628a7SBjoern A. Zeeb if (j->ip6s > 0) { 515413628a7SBjoern A. Zeeb pr->pr_ip6 = j->ip6; 516413628a7SBjoern A. Zeeb pr->pr_ip6s = j->ip6s; 517413628a7SBjoern A. Zeeb } 518413628a7SBjoern A. Zeeb #endif 519fd7a8150SMike Barcroft pr->pr_linux = NULL; 520fd7a8150SMike Barcroft pr->pr_securelevel = securelevel; 5211ba4a712SPawel Jakub Dawidek bzero(&pr->pr_osd, sizeof(pr->pr_osd)); 522fd7a8150SMike Barcroft 523413628a7SBjoern A. Zeeb /* 524413628a7SBjoern A. Zeeb * Pre-set prison state to ALIVE upon cration. This is needed so we 525413628a7SBjoern A. Zeeb * can later attach the process to it, etc (avoiding another extra 526413628a7SBjoern A. Zeeb * state for ther process of creation, complicating things). 527413628a7SBjoern A. Zeeb */ 528413628a7SBjoern A. Zeeb pr->pr_state = PRISON_STATE_ALIVE; 529413628a7SBjoern A. Zeeb 530413628a7SBjoern A. Zeeb /* Allocate a dedicated cpuset for each jail. */ 531413628a7SBjoern A. Zeeb error = cpuset_create_root(td, &pr->pr_cpuset); 532413628a7SBjoern A. Zeeb if (error) 533413628a7SBjoern A. Zeeb goto e_dropvnref; 534413628a7SBjoern A. Zeeb 535dc68a633SPawel Jakub Dawidek sx_xlock(&allprison_lock); 536413628a7SBjoern A. Zeeb /* Make sure we cannot run into problems with ambiguous bind()ings. */ 537d465a41dSBjoern A. Zeeb #if defined(INET) || defined(INET6) 538413628a7SBjoern A. Zeeb error = prison_check_conflicting_ips(pr); 539413628a7SBjoern A. Zeeb if (error) { 540413628a7SBjoern A. Zeeb sx_xunlock(&allprison_lock); 541413628a7SBjoern A. Zeeb goto e_dropcpuset; 542413628a7SBjoern A. Zeeb } 543d465a41dSBjoern A. Zeeb #endif 544413628a7SBjoern A. Zeeb 545413628a7SBjoern A. Zeeb /* Determine next pr_id and add prison to allprison list. */ 5462110d913SXin LI tryprid = lastprid + 1; 5472110d913SXin LI if (tryprid == JAIL_MAX) 5482110d913SXin LI tryprid = 1; 5492110d913SXin LI next: 5502110d913SXin LI LIST_FOREACH(tpr, &allprison, pr_list) { 5512110d913SXin LI if (tpr->pr_id == tryprid) { 5522110d913SXin LI tryprid++; 5532110d913SXin LI if (tryprid == JAIL_MAX) { 5542110d913SXin LI sx_xunlock(&allprison_lock); 5552110d913SXin LI error = EAGAIN; 556413628a7SBjoern A. Zeeb goto e_dropcpuset; 5572110d913SXin LI } 5582110d913SXin LI goto next; 5592110d913SXin LI } 5602110d913SXin LI } 5612110d913SXin LI pr->pr_id = jaa.jid = lastprid = tryprid; 562fd7a8150SMike Barcroft LIST_INSERT_HEAD(&allprison, pr, pr_list); 563fd7a8150SMike Barcroft prisoncount++; 5641ba4a712SPawel Jakub Dawidek sx_xunlock(&allprison_lock); 565fd7a8150SMike Barcroft 566fd7a8150SMike Barcroft error = jail_attach(td, &jaa); 567a2f2b3afSJohn Baldwin if (error) 568fd7a8150SMike Barcroft goto e_dropprref; 569fd7a8150SMike Barcroft mtx_lock(&pr->pr_mtx); 570fd7a8150SMike Barcroft pr->pr_ref--; 571fd7a8150SMike Barcroft mtx_unlock(&pr->pr_mtx); 572fd7a8150SMike Barcroft td->td_retval[0] = jaa.jid; 57375c13541SPoul-Henning Kamp return (0); 574fd7a8150SMike Barcroft e_dropprref: 575dc68a633SPawel Jakub Dawidek sx_xlock(&allprison_lock); 576fd7a8150SMike Barcroft LIST_REMOVE(pr, pr_list); 577fd7a8150SMike Barcroft prisoncount--; 5781ba4a712SPawel Jakub Dawidek sx_xunlock(&allprison_lock); 579413628a7SBjoern A. Zeeb e_dropcpuset: 580413628a7SBjoern A. Zeeb cpuset_rel(pr->pr_cpuset); 581fd7a8150SMike Barcroft e_dropvnref: 582453f7d53SChristian S.J. Peron vfslocked = VFS_LOCK_GIANT(pr->pr_root->v_mount); 583fd7a8150SMike Barcroft vrele(pr->pr_root); 584453f7d53SChristian S.J. Peron VFS_UNLOCK_GIANT(vfslocked); 585fd7a8150SMike Barcroft e_killmtx: 586894db7b0SMaxime Henrion mtx_destroy(&pr->pr_mtx); 5871ede983cSDag-Erling Smørgrav free(pr, M_PRISON); 588413628a7SBjoern A. Zeeb #ifdef INET6 589413628a7SBjoern A. Zeeb free(j->ip6, M_PRISON); 590413628a7SBjoern A. Zeeb #endif 591413628a7SBjoern A. Zeeb #ifdef INET 592413628a7SBjoern A. Zeeb free(j->ip4, M_PRISON); 593413628a7SBjoern A. Zeeb #endif 59475c13541SPoul-Henning Kamp return (error); 59575c13541SPoul-Henning Kamp } 59675c13541SPoul-Henning Kamp 597fd7a8150SMike Barcroft /* 5989ddb7954SMike Barcroft * struct jail_attach_args { 5999ddb7954SMike Barcroft * int jid; 6009ddb7954SMike Barcroft * }; 601fd7a8150SMike Barcroft */ 602fd7a8150SMike Barcroft int 6039ddb7954SMike Barcroft jail_attach(struct thread *td, struct jail_attach_args *uap) 604fd7a8150SMike Barcroft { 605fd7a8150SMike Barcroft struct proc *p; 606fd7a8150SMike Barcroft struct ucred *newcred, *oldcred; 607fd7a8150SMike Barcroft struct prison *pr; 608453f7d53SChristian S.J. Peron int vfslocked, error; 609fd7a8150SMike Barcroft 61057f22bd4SJacques Vidrine /* 61157f22bd4SJacques Vidrine * XXX: Note that there is a slight race here if two threads 61257f22bd4SJacques Vidrine * in the same privileged process attempt to attach to two 61357f22bd4SJacques Vidrine * different jails at the same time. It is important for 61457f22bd4SJacques Vidrine * user processes not to do this, or they might end up with 61557f22bd4SJacques Vidrine * a process root from one prison, but attached to the jail 61657f22bd4SJacques Vidrine * of another. 61757f22bd4SJacques Vidrine */ 618800c9408SRobert Watson error = priv_check(td, PRIV_JAIL_ATTACH); 61957f22bd4SJacques Vidrine if (error) 62057f22bd4SJacques Vidrine return (error); 621fd7a8150SMike Barcroft 62257f22bd4SJacques Vidrine p = td->td_proc; 623dc68a633SPawel Jakub Dawidek sx_slock(&allprison_lock); 624fd7a8150SMike Barcroft pr = prison_find(uap->jid); 625fd7a8150SMike Barcroft if (pr == NULL) { 626dc68a633SPawel Jakub Dawidek sx_sunlock(&allprison_lock); 627fd7a8150SMike Barcroft return (EINVAL); 628fd7a8150SMike Barcroft } 629413628a7SBjoern A. Zeeb 630413628a7SBjoern A. Zeeb /* 631413628a7SBjoern A. Zeeb * Do not allow a process to attach to a prison that is not 632413628a7SBjoern A. Zeeb * considered to be "ALIVE". 633413628a7SBjoern A. Zeeb */ 634413628a7SBjoern A. Zeeb if (pr->pr_state != PRISON_STATE_ALIVE) { 635413628a7SBjoern A. Zeeb mtx_unlock(&pr->pr_mtx); 636413628a7SBjoern A. Zeeb sx_sunlock(&allprison_lock); 637413628a7SBjoern A. Zeeb return (EINVAL); 638413628a7SBjoern A. Zeeb } 639fd7a8150SMike Barcroft pr->pr_ref++; 640fd7a8150SMike Barcroft mtx_unlock(&pr->pr_mtx); 641dc68a633SPawel Jakub Dawidek sx_sunlock(&allprison_lock); 642fd7a8150SMike Barcroft 643413628a7SBjoern A. Zeeb /* 644413628a7SBjoern A. Zeeb * Reparent the newly attached process to this jail. 645413628a7SBjoern A. Zeeb */ 646413628a7SBjoern A. Zeeb error = cpuset_setproc_update_set(p, pr->pr_cpuset); 647413628a7SBjoern A. Zeeb if (error) 648413628a7SBjoern A. Zeeb goto e_unref; 649413628a7SBjoern A. Zeeb 650453f7d53SChristian S.J. Peron vfslocked = VFS_LOCK_GIANT(pr->pr_root->v_mount); 651cb05b60aSAttilio Rao vn_lock(pr->pr_root, LK_EXCLUSIVE | LK_RETRY); 652fd7a8150SMike Barcroft if ((error = change_dir(pr->pr_root, td)) != 0) 653fd7a8150SMike Barcroft goto e_unlock; 654fd7a8150SMike Barcroft #ifdef MAC 65530d239bcSRobert Watson if ((error = mac_vnode_check_chroot(td->td_ucred, pr->pr_root))) 656fd7a8150SMike Barcroft goto e_unlock; 657fd7a8150SMike Barcroft #endif 65822db15c0SAttilio Rao VOP_UNLOCK(pr->pr_root, 0); 659fd7a8150SMike Barcroft change_root(pr->pr_root, td); 660453f7d53SChristian S.J. Peron VFS_UNLOCK_GIANT(vfslocked); 661fd7a8150SMike Barcroft 662fd7a8150SMike Barcroft newcred = crget(); 663fd7a8150SMike Barcroft PROC_LOCK(p); 664fd7a8150SMike Barcroft oldcred = p->p_ucred; 665fd7a8150SMike Barcroft setsugid(p); 666fd7a8150SMike Barcroft crcopy(newcred, oldcred); 66769c4ee54SJohn Baldwin newcred->cr_prison = pr; 668fd7a8150SMike Barcroft p->p_ucred = newcred; 669413628a7SBjoern A. Zeeb prison_proc_hold(pr); 670fd7a8150SMike Barcroft PROC_UNLOCK(p); 671fd7a8150SMike Barcroft crfree(oldcred); 672fd7a8150SMike Barcroft return (0); 673fd7a8150SMike Barcroft e_unlock: 67422db15c0SAttilio Rao VOP_UNLOCK(pr->pr_root, 0); 675453f7d53SChristian S.J. Peron VFS_UNLOCK_GIANT(vfslocked); 676413628a7SBjoern A. Zeeb e_unref: 677fd7a8150SMike Barcroft mtx_lock(&pr->pr_mtx); 678fd7a8150SMike Barcroft pr->pr_ref--; 679fd7a8150SMike Barcroft mtx_unlock(&pr->pr_mtx); 680fd7a8150SMike Barcroft return (error); 681fd7a8150SMike Barcroft } 682fd7a8150SMike Barcroft 683fd7a8150SMike Barcroft /* 684fd7a8150SMike Barcroft * Returns a locked prison instance, or NULL on failure. 685fd7a8150SMike Barcroft */ 68654b369c1SPawel Jakub Dawidek struct prison * 687fd7a8150SMike Barcroft prison_find(int prid) 688fd7a8150SMike Barcroft { 689fd7a8150SMike Barcroft struct prison *pr; 690fd7a8150SMike Barcroft 691dc68a633SPawel Jakub Dawidek sx_assert(&allprison_lock, SX_LOCKED); 692fd7a8150SMike Barcroft LIST_FOREACH(pr, &allprison, pr_list) { 693fd7a8150SMike Barcroft if (pr->pr_id == prid) { 694fd7a8150SMike Barcroft mtx_lock(&pr->pr_mtx); 695c2cda609SPawel Jakub Dawidek if (pr->pr_ref == 0) { 696c2cda609SPawel Jakub Dawidek mtx_unlock(&pr->pr_mtx); 697c2cda609SPawel Jakub Dawidek break; 698c2cda609SPawel Jakub Dawidek } 699fd7a8150SMike Barcroft return (pr); 700fd7a8150SMike Barcroft } 701fd7a8150SMike Barcroft } 702fd7a8150SMike Barcroft return (NULL); 703fd7a8150SMike Barcroft } 704fd7a8150SMike Barcroft 70591421ba2SRobert Watson void 7061ba4a712SPawel Jakub Dawidek prison_free_locked(struct prison *pr) 70791421ba2SRobert Watson { 70891421ba2SRobert Watson 7091ba4a712SPawel Jakub Dawidek mtx_assert(&pr->pr_mtx, MA_OWNED); 71091421ba2SRobert Watson pr->pr_ref--; 71191421ba2SRobert Watson if (pr->pr_ref == 0) { 71201137630SRobert Watson mtx_unlock(&pr->pr_mtx); 713c2cda609SPawel Jakub Dawidek TASK_INIT(&pr->pr_task, 0, prison_complete, pr); 714c2cda609SPawel Jakub Dawidek taskqueue_enqueue(taskqueue_thread, &pr->pr_task); 715c2cda609SPawel Jakub Dawidek return; 716c2cda609SPawel Jakub Dawidek } 717c2cda609SPawel Jakub Dawidek mtx_unlock(&pr->pr_mtx); 718c2cda609SPawel Jakub Dawidek } 719c2cda609SPawel Jakub Dawidek 7201ba4a712SPawel Jakub Dawidek void 7211ba4a712SPawel Jakub Dawidek prison_free(struct prison *pr) 7221ba4a712SPawel Jakub Dawidek { 7231ba4a712SPawel Jakub Dawidek 7241ba4a712SPawel Jakub Dawidek mtx_lock(&pr->pr_mtx); 7251ba4a712SPawel Jakub Dawidek prison_free_locked(pr); 7261ba4a712SPawel Jakub Dawidek } 7271ba4a712SPawel Jakub Dawidek 728c2cda609SPawel Jakub Dawidek static void 729c2cda609SPawel Jakub Dawidek prison_complete(void *context, int pending) 730c2cda609SPawel Jakub Dawidek { 731c2cda609SPawel Jakub Dawidek struct prison *pr; 732c2cda609SPawel Jakub Dawidek int vfslocked; 733c2cda609SPawel Jakub Dawidek 734c2cda609SPawel Jakub Dawidek pr = (struct prison *)context; 735c2cda609SPawel Jakub Dawidek 736c2cda609SPawel Jakub Dawidek sx_xlock(&allprison_lock); 737264de85eSPawel Jakub Dawidek LIST_REMOVE(pr, pr_list); 738fd7a8150SMike Barcroft prisoncount--; 7391ba4a712SPawel Jakub Dawidek sx_xunlock(&allprison_lock); 7401ba4a712SPawel Jakub Dawidek 741413628a7SBjoern A. Zeeb cpuset_rel(pr->pr_cpuset); 742413628a7SBjoern A. Zeeb 7431ba4a712SPawel Jakub Dawidek /* Free all OSD associated to this jail. */ 7441ba4a712SPawel Jakub Dawidek osd_jail_exit(pr); 745b3059e09SRobert Watson 746453f7d53SChristian S.J. Peron vfslocked = VFS_LOCK_GIANT(pr->pr_root->v_mount); 747b3059e09SRobert Watson vrele(pr->pr_root); 748453f7d53SChristian S.J. Peron VFS_UNLOCK_GIANT(vfslocked); 749b3059e09SRobert Watson 750b3059e09SRobert Watson mtx_destroy(&pr->pr_mtx); 7511ede983cSDag-Erling Smørgrav free(pr->pr_linux, M_PRISON); 752413628a7SBjoern A. Zeeb #ifdef INET6 753413628a7SBjoern A. Zeeb free(pr->pr_ip6, M_PRISON); 754413628a7SBjoern A. Zeeb #endif 755413628a7SBjoern A. Zeeb #ifdef INET 756413628a7SBjoern A. Zeeb free(pr->pr_ip4, M_PRISON); 757413628a7SBjoern A. Zeeb #endif 7581ede983cSDag-Erling Smørgrav free(pr, M_PRISON); 759b3059e09SRobert Watson } 760b3059e09SRobert Watson 76191421ba2SRobert Watson void 7621ba4a712SPawel Jakub Dawidek prison_hold_locked(struct prison *pr) 7631ba4a712SPawel Jakub Dawidek { 7641ba4a712SPawel Jakub Dawidek 7651ba4a712SPawel Jakub Dawidek mtx_assert(&pr->pr_mtx, MA_OWNED); 7661ba4a712SPawel Jakub Dawidek KASSERT(pr->pr_ref > 0, 7671ba4a712SPawel Jakub Dawidek ("Trying to hold dead prison (id=%d).", pr->pr_id)); 7681ba4a712SPawel Jakub Dawidek pr->pr_ref++; 7691ba4a712SPawel Jakub Dawidek } 7701ba4a712SPawel Jakub Dawidek 7711ba4a712SPawel Jakub Dawidek void 77291421ba2SRobert Watson prison_hold(struct prison *pr) 77391421ba2SRobert Watson { 77491421ba2SRobert Watson 77501137630SRobert Watson mtx_lock(&pr->pr_mtx); 7761ba4a712SPawel Jakub Dawidek prison_hold_locked(pr); 77701137630SRobert Watson mtx_unlock(&pr->pr_mtx); 77801137630SRobert Watson } 77901137630SRobert Watson 780413628a7SBjoern A. Zeeb void 781413628a7SBjoern A. Zeeb prison_proc_hold(struct prison *pr) 78201137630SRobert Watson { 78301137630SRobert Watson 784413628a7SBjoern A. Zeeb mtx_lock(&pr->pr_mtx); 785413628a7SBjoern A. Zeeb KASSERT(pr->pr_state == PRISON_STATE_ALIVE, 786413628a7SBjoern A. Zeeb ("Cannot add a process to a non-alive prison (id=%d).", pr->pr_id)); 787413628a7SBjoern A. Zeeb pr->pr_nprocs++; 788413628a7SBjoern A. Zeeb mtx_unlock(&pr->pr_mtx); 78975c13541SPoul-Henning Kamp } 79075c13541SPoul-Henning Kamp 79175c13541SPoul-Henning Kamp void 792413628a7SBjoern A. Zeeb prison_proc_free(struct prison *pr) 79375c13541SPoul-Henning Kamp { 794413628a7SBjoern A. Zeeb 795413628a7SBjoern A. Zeeb mtx_lock(&pr->pr_mtx); 796413628a7SBjoern A. Zeeb KASSERT(pr->pr_state == PRISON_STATE_ALIVE && pr->pr_nprocs > 0, 797413628a7SBjoern A. Zeeb ("Trying to kill a process in a dead prison (id=%d).", pr->pr_id)); 798413628a7SBjoern A. Zeeb pr->pr_nprocs--; 799413628a7SBjoern A. Zeeb if (pr->pr_nprocs == 0) 800413628a7SBjoern A. Zeeb pr->pr_state = PRISON_STATE_DYING; 801413628a7SBjoern A. Zeeb mtx_unlock(&pr->pr_mtx); 802413628a7SBjoern A. Zeeb } 803413628a7SBjoern A. Zeeb 804413628a7SBjoern A. Zeeb 805413628a7SBjoern A. Zeeb #ifdef INET 806413628a7SBjoern A. Zeeb /* 807413628a7SBjoern A. Zeeb * Pass back primary IPv4 address of this jail. 808413628a7SBjoern A. Zeeb * 809413628a7SBjoern A. Zeeb * If not jailed return success but do not alter the address. Caller has to 810b89e82ddSJamie Gritton * make sure to intialize it correctly (e.g. INADDR_ANY). 811413628a7SBjoern A. Zeeb * 812b89e82ddSJamie Gritton * Returns 0 on success, EAFNOSUPPORT if the jail doesn't allow IPv4. 813b89e82ddSJamie Gritton * Address returned in NBO. 814413628a7SBjoern A. Zeeb */ 815413628a7SBjoern A. Zeeb int 8161cecba0fSBjoern A. Zeeb prison_get_ip4(struct ucred *cred, struct in_addr *ia) 817413628a7SBjoern A. Zeeb { 818413628a7SBjoern A. Zeeb 819413628a7SBjoern A. Zeeb KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 820413628a7SBjoern A. Zeeb KASSERT(ia != NULL, ("%s: ia is NULL", __func__)); 82175c13541SPoul-Henning Kamp 82291421ba2SRobert Watson if (!jailed(cred)) 823413628a7SBjoern A. Zeeb /* Do not change address passed in. */ 824413628a7SBjoern A. Zeeb return (0); 825413628a7SBjoern A. Zeeb 826413628a7SBjoern A. Zeeb if (cred->cr_prison->pr_ip4 == NULL) 827b89e82ddSJamie Gritton return (EAFNOSUPPORT); 828413628a7SBjoern A. Zeeb 829413628a7SBjoern A. Zeeb ia->s_addr = cred->cr_prison->pr_ip4[0].s_addr; 830413628a7SBjoern A. Zeeb return (0); 83175c13541SPoul-Henning Kamp } 832413628a7SBjoern A. Zeeb 833413628a7SBjoern A. Zeeb /* 834413628a7SBjoern A. Zeeb * Make sure our (source) address is set to something meaningful to this 835413628a7SBjoern A. Zeeb * jail. 836413628a7SBjoern A. Zeeb * 837b89e82ddSJamie Gritton * Returns 0 if not jailed or if address belongs to jail, EADDRNOTAVAIL if 838b89e82ddSJamie Gritton * the address doesn't belong, or EAFNOSUPPORT if the jail doesn't allow IPv4. 839b89e82ddSJamie Gritton * Address passed in in NBO and returned in NBO. 840413628a7SBjoern A. Zeeb */ 841413628a7SBjoern A. Zeeb int 842413628a7SBjoern A. Zeeb prison_local_ip4(struct ucred *cred, struct in_addr *ia) 843413628a7SBjoern A. Zeeb { 844413628a7SBjoern A. Zeeb struct in_addr ia0; 845413628a7SBjoern A. Zeeb 846413628a7SBjoern A. Zeeb KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 847413628a7SBjoern A. Zeeb KASSERT(ia != NULL, ("%s: ia is NULL", __func__)); 848413628a7SBjoern A. Zeeb 849413628a7SBjoern A. Zeeb if (!jailed(cred)) 850413628a7SBjoern A. Zeeb return (0); 851413628a7SBjoern A. Zeeb if (cred->cr_prison->pr_ip4 == NULL) 852b89e82ddSJamie Gritton return (EAFNOSUPPORT); 853413628a7SBjoern A. Zeeb 854413628a7SBjoern A. Zeeb ia0.s_addr = ntohl(ia->s_addr); 855413628a7SBjoern A. Zeeb if (ia0.s_addr == INADDR_LOOPBACK) { 856413628a7SBjoern A. Zeeb ia->s_addr = cred->cr_prison->pr_ip4[0].s_addr; 857413628a7SBjoern A. Zeeb return (0); 858413628a7SBjoern A. Zeeb } 859413628a7SBjoern A. Zeeb 860b89e82ddSJamie Gritton if (ia0.s_addr == INADDR_ANY) { 861413628a7SBjoern A. Zeeb /* 862413628a7SBjoern A. Zeeb * In case there is only 1 IPv4 address, bind directly. 863413628a7SBjoern A. Zeeb */ 864b89e82ddSJamie Gritton if (cred->cr_prison->pr_ip4s == 1) 865413628a7SBjoern A. Zeeb ia->s_addr = cred->cr_prison->pr_ip4[0].s_addr; 866413628a7SBjoern A. Zeeb return (0); 867413628a7SBjoern A. Zeeb } 868413628a7SBjoern A. Zeeb 869b89e82ddSJamie Gritton return (_prison_check_ip4(cred->cr_prison, ia)); 870413628a7SBjoern A. Zeeb } 871413628a7SBjoern A. Zeeb 872413628a7SBjoern A. Zeeb /* 873413628a7SBjoern A. Zeeb * Rewrite destination address in case we will connect to loopback address. 874413628a7SBjoern A. Zeeb * 875b89e82ddSJamie Gritton * Returns 0 on success, EAFNOSUPPORT if the jail doesn't allow IPv4. 876b89e82ddSJamie Gritton * Address passed in in NBO and returned in NBO. 877413628a7SBjoern A. Zeeb */ 878413628a7SBjoern A. Zeeb int 879413628a7SBjoern A. Zeeb prison_remote_ip4(struct ucred *cred, struct in_addr *ia) 880413628a7SBjoern A. Zeeb { 881413628a7SBjoern A. Zeeb 882413628a7SBjoern A. Zeeb KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 883413628a7SBjoern A. Zeeb KASSERT(ia != NULL, ("%s: ia is NULL", __func__)); 884413628a7SBjoern A. Zeeb 885413628a7SBjoern A. Zeeb if (!jailed(cred)) 886413628a7SBjoern A. Zeeb return (0); 887413628a7SBjoern A. Zeeb if (cred->cr_prison->pr_ip4 == NULL) 888b89e82ddSJamie Gritton return (EAFNOSUPPORT); 889b89e82ddSJamie Gritton 890413628a7SBjoern A. Zeeb if (ntohl(ia->s_addr) == INADDR_LOOPBACK) { 891413628a7SBjoern A. Zeeb ia->s_addr = cred->cr_prison->pr_ip4[0].s_addr; 892413628a7SBjoern A. Zeeb return (0); 893413628a7SBjoern A. Zeeb } 894413628a7SBjoern A. Zeeb 895413628a7SBjoern A. Zeeb /* 896413628a7SBjoern A. Zeeb * Return success because nothing had to be changed. 897413628a7SBjoern A. Zeeb */ 898413628a7SBjoern A. Zeeb return (0); 899413628a7SBjoern A. Zeeb } 900413628a7SBjoern A. Zeeb 901413628a7SBjoern A. Zeeb /* 902b89e82ddSJamie Gritton * Check if given address belongs to the jail referenced by cred/prison. 903413628a7SBjoern A. Zeeb * 904b89e82ddSJamie Gritton * Returns 0 if not jailed or if address belongs to jail, EADDRNOTAVAIL if 905b89e82ddSJamie Gritton * the address doesn't belong, or EAFNOSUPPORT if the jail doesn't allow IPv4. 906b89e82ddSJamie Gritton * Address passed in in NBO. 907413628a7SBjoern A. Zeeb */ 908413628a7SBjoern A. Zeeb static int 909413628a7SBjoern A. Zeeb _prison_check_ip4(struct prison *pr, struct in_addr *ia) 910413628a7SBjoern A. Zeeb { 911413628a7SBjoern A. Zeeb int i, a, z, d; 912413628a7SBjoern A. Zeeb 913413628a7SBjoern A. Zeeb /* 914413628a7SBjoern A. Zeeb * Check the primary IP. 915413628a7SBjoern A. Zeeb */ 916413628a7SBjoern A. Zeeb if (pr->pr_ip4[0].s_addr == ia->s_addr) 917b89e82ddSJamie Gritton return (0); 918413628a7SBjoern A. Zeeb 919413628a7SBjoern A. Zeeb /* 920413628a7SBjoern A. Zeeb * All the other IPs are sorted so we can do a binary search. 921413628a7SBjoern A. Zeeb */ 922413628a7SBjoern A. Zeeb a = 0; 923413628a7SBjoern A. Zeeb z = pr->pr_ip4s - 2; 924413628a7SBjoern A. Zeeb while (a <= z) { 925413628a7SBjoern A. Zeeb i = (a + z) / 2; 926413628a7SBjoern A. Zeeb d = qcmp_v4(&pr->pr_ip4[i+1], ia); 927413628a7SBjoern A. Zeeb if (d > 0) 928413628a7SBjoern A. Zeeb z = i - 1; 929413628a7SBjoern A. Zeeb else if (d < 0) 930413628a7SBjoern A. Zeeb a = i + 1; 931413628a7SBjoern A. Zeeb else 932413628a7SBjoern A. Zeeb return (0); 93375c13541SPoul-Henning Kamp } 93475c13541SPoul-Henning Kamp 935b89e82ddSJamie Gritton return (EADDRNOTAVAIL); 936b89e82ddSJamie Gritton } 937b89e82ddSJamie Gritton 93875c13541SPoul-Henning Kamp int 939413628a7SBjoern A. Zeeb prison_check_ip4(struct ucred *cred, struct in_addr *ia) 940413628a7SBjoern A. Zeeb { 941413628a7SBjoern A. Zeeb 942413628a7SBjoern A. Zeeb KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 943413628a7SBjoern A. Zeeb KASSERT(ia != NULL, ("%s: ia is NULL", __func__)); 944413628a7SBjoern A. Zeeb 945413628a7SBjoern A. Zeeb if (!jailed(cred)) 946b89e82ddSJamie Gritton return (0); 947b89e82ddSJamie Gritton if (cred->cr_prison->pr_ip4 == NULL) 948b89e82ddSJamie Gritton return (EAFNOSUPPORT); 949413628a7SBjoern A. Zeeb 950413628a7SBjoern A. Zeeb return (_prison_check_ip4(cred->cr_prison, ia)); 951413628a7SBjoern A. Zeeb } 952413628a7SBjoern A. Zeeb #endif 953413628a7SBjoern A. Zeeb 954413628a7SBjoern A. Zeeb #ifdef INET6 955413628a7SBjoern A. Zeeb /* 956413628a7SBjoern A. Zeeb * Pass back primary IPv6 address for this jail. 957413628a7SBjoern A. Zeeb * 958413628a7SBjoern A. Zeeb * If not jailed return success but do not alter the address. Caller has to 959b89e82ddSJamie Gritton * make sure to intialize it correctly (e.g. IN6ADDR_ANY_INIT). 960413628a7SBjoern A. Zeeb * 961b89e82ddSJamie Gritton * Returns 0 on success, EAFNOSUPPORT if the jail doesn't allow IPv6. 962413628a7SBjoern A. Zeeb */ 963413628a7SBjoern A. Zeeb int 9641cecba0fSBjoern A. Zeeb prison_get_ip6(struct ucred *cred, struct in6_addr *ia6) 965413628a7SBjoern A. Zeeb { 966413628a7SBjoern A. Zeeb 967413628a7SBjoern A. Zeeb KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 968413628a7SBjoern A. Zeeb KASSERT(ia6 != NULL, ("%s: ia6 is NULL", __func__)); 969413628a7SBjoern A. Zeeb 970413628a7SBjoern A. Zeeb if (!jailed(cred)) 971413628a7SBjoern A. Zeeb return (0); 972413628a7SBjoern A. Zeeb if (cred->cr_prison->pr_ip6 == NULL) 973b89e82ddSJamie Gritton return (EAFNOSUPPORT); 974b89e82ddSJamie Gritton 975413628a7SBjoern A. Zeeb bcopy(&cred->cr_prison->pr_ip6[0], ia6, sizeof(struct in6_addr)); 976413628a7SBjoern A. Zeeb return (0); 977413628a7SBjoern A. Zeeb } 978413628a7SBjoern A. Zeeb 979413628a7SBjoern A. Zeeb /* 980413628a7SBjoern A. Zeeb * Make sure our (source) address is set to something meaningful to this jail. 981413628a7SBjoern A. Zeeb * 982413628a7SBjoern A. Zeeb * v6only should be set based on (inp->inp_flags & IN6P_IPV6_V6ONLY != 0) 983413628a7SBjoern A. Zeeb * when needed while binding. 984413628a7SBjoern A. Zeeb * 985b89e82ddSJamie Gritton * Returns 0 if not jailed or if address belongs to jail, EADDRNOTAVAIL if 986b89e82ddSJamie Gritton * the address doesn't belong, or EAFNOSUPPORT if the jail doesn't allow IPv6. 987413628a7SBjoern A. Zeeb */ 988413628a7SBjoern A. Zeeb int 989413628a7SBjoern A. Zeeb prison_local_ip6(struct ucred *cred, struct in6_addr *ia6, int v6only) 990413628a7SBjoern A. Zeeb { 991413628a7SBjoern A. Zeeb 992413628a7SBjoern A. Zeeb KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 993413628a7SBjoern A. Zeeb KASSERT(ia6 != NULL, ("%s: ia6 is NULL", __func__)); 994413628a7SBjoern A. Zeeb 995413628a7SBjoern A. Zeeb if (!jailed(cred)) 996413628a7SBjoern A. Zeeb return (0); 997413628a7SBjoern A. Zeeb if (cred->cr_prison->pr_ip6 == NULL) 998b89e82ddSJamie Gritton return (EAFNOSUPPORT); 999b89e82ddSJamie Gritton 1000413628a7SBjoern A. Zeeb if (IN6_IS_ADDR_LOOPBACK(ia6)) { 1001413628a7SBjoern A. Zeeb bcopy(&cred->cr_prison->pr_ip6[0], ia6, 1002413628a7SBjoern A. Zeeb sizeof(struct in6_addr)); 1003413628a7SBjoern A. Zeeb return (0); 1004413628a7SBjoern A. Zeeb } 1005413628a7SBjoern A. Zeeb 1006b89e82ddSJamie Gritton if (IN6_IS_ADDR_UNSPECIFIED(ia6)) { 1007413628a7SBjoern A. Zeeb /* 1008b89e82ddSJamie Gritton * In case there is only 1 IPv6 address, and v6only is true, 1009b89e82ddSJamie Gritton * then bind directly. 1010413628a7SBjoern A. Zeeb */ 1011b89e82ddSJamie Gritton if (v6only != 0 && cred->cr_prison->pr_ip6s == 1) 1012413628a7SBjoern A. Zeeb bcopy(&cred->cr_prison->pr_ip6[0], ia6, 1013413628a7SBjoern A. Zeeb sizeof(struct in6_addr)); 1014413628a7SBjoern A. Zeeb return (0); 1015413628a7SBjoern A. Zeeb } 1016b89e82ddSJamie Gritton 1017b89e82ddSJamie Gritton return (_prison_check_ip6(cred->cr_prison, ia6)); 1018413628a7SBjoern A. Zeeb } 1019413628a7SBjoern A. Zeeb 1020413628a7SBjoern A. Zeeb /* 1021413628a7SBjoern A. Zeeb * Rewrite destination address in case we will connect to loopback address. 1022413628a7SBjoern A. Zeeb * 1023b89e82ddSJamie Gritton * Returns 0 on success, EAFNOSUPPORT if the jail doesn't allow IPv6. 1024413628a7SBjoern A. Zeeb */ 1025413628a7SBjoern A. Zeeb int 1026413628a7SBjoern A. Zeeb prison_remote_ip6(struct ucred *cred, struct in6_addr *ia6) 1027413628a7SBjoern A. Zeeb { 1028413628a7SBjoern A. Zeeb 1029413628a7SBjoern A. Zeeb KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 1030413628a7SBjoern A. Zeeb KASSERT(ia6 != NULL, ("%s: ia6 is NULL", __func__)); 1031413628a7SBjoern A. Zeeb 1032413628a7SBjoern A. Zeeb if (!jailed(cred)) 1033413628a7SBjoern A. Zeeb return (0); 1034413628a7SBjoern A. Zeeb if (cred->cr_prison->pr_ip6 == NULL) 1035b89e82ddSJamie Gritton return (EAFNOSUPPORT); 1036b89e82ddSJamie Gritton 1037413628a7SBjoern A. Zeeb if (IN6_IS_ADDR_LOOPBACK(ia6)) { 1038413628a7SBjoern A. Zeeb bcopy(&cred->cr_prison->pr_ip6[0], ia6, 1039413628a7SBjoern A. Zeeb sizeof(struct in6_addr)); 1040413628a7SBjoern A. Zeeb return (0); 1041413628a7SBjoern A. Zeeb } 1042413628a7SBjoern A. Zeeb 1043413628a7SBjoern A. Zeeb /* 1044413628a7SBjoern A. Zeeb * Return success because nothing had to be changed. 1045413628a7SBjoern A. Zeeb */ 1046413628a7SBjoern A. Zeeb return (0); 1047413628a7SBjoern A. Zeeb } 1048413628a7SBjoern A. Zeeb 1049413628a7SBjoern A. Zeeb /* 1050b89e82ddSJamie Gritton * Check if given address belongs to the jail referenced by cred/prison. 1051413628a7SBjoern A. Zeeb * 1052b89e82ddSJamie Gritton * Returns 0 if not jailed or if address belongs to jail, EADDRNOTAVAIL if 1053b89e82ddSJamie Gritton * the address doesn't belong, or EAFNOSUPPORT if the jail doesn't allow IPv6. 1054413628a7SBjoern A. Zeeb */ 1055413628a7SBjoern A. Zeeb static int 1056413628a7SBjoern A. Zeeb _prison_check_ip6(struct prison *pr, struct in6_addr *ia6) 1057413628a7SBjoern A. Zeeb { 1058413628a7SBjoern A. Zeeb int i, a, z, d; 1059413628a7SBjoern A. Zeeb 1060413628a7SBjoern A. Zeeb /* 1061413628a7SBjoern A. Zeeb * Check the primary IP. 1062413628a7SBjoern A. Zeeb */ 1063413628a7SBjoern A. Zeeb if (IN6_ARE_ADDR_EQUAL(&pr->pr_ip6[0], ia6)) 1064b89e82ddSJamie Gritton return (0); 1065413628a7SBjoern A. Zeeb 1066413628a7SBjoern A. Zeeb /* 1067413628a7SBjoern A. Zeeb * All the other IPs are sorted so we can do a binary search. 1068413628a7SBjoern A. Zeeb */ 1069413628a7SBjoern A. Zeeb a = 0; 1070413628a7SBjoern A. Zeeb z = pr->pr_ip6s - 2; 1071413628a7SBjoern A. Zeeb while (a <= z) { 1072413628a7SBjoern A. Zeeb i = (a + z) / 2; 1073413628a7SBjoern A. Zeeb d = qcmp_v6(&pr->pr_ip6[i+1], ia6); 1074413628a7SBjoern A. Zeeb if (d > 0) 1075413628a7SBjoern A. Zeeb z = i - 1; 1076413628a7SBjoern A. Zeeb else if (d < 0) 1077413628a7SBjoern A. Zeeb a = i + 1; 1078413628a7SBjoern A. Zeeb else 1079413628a7SBjoern A. Zeeb return (0); 1080413628a7SBjoern A. Zeeb } 1081413628a7SBjoern A. Zeeb 1082b89e82ddSJamie Gritton return (EADDRNOTAVAIL); 1083b89e82ddSJamie Gritton } 1084b89e82ddSJamie Gritton 1085413628a7SBjoern A. Zeeb int 1086413628a7SBjoern A. Zeeb prison_check_ip6(struct ucred *cred, struct in6_addr *ia6) 1087413628a7SBjoern A. Zeeb { 1088413628a7SBjoern A. Zeeb 1089413628a7SBjoern A. Zeeb KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 1090413628a7SBjoern A. Zeeb KASSERT(ia6 != NULL, ("%s: ia6 is NULL", __func__)); 1091413628a7SBjoern A. Zeeb 1092413628a7SBjoern A. Zeeb if (!jailed(cred)) 1093b89e82ddSJamie Gritton return (0); 1094b89e82ddSJamie Gritton if (cred->cr_prison->pr_ip6 == NULL) 1095b89e82ddSJamie Gritton return (EAFNOSUPPORT); 1096413628a7SBjoern A. Zeeb 1097413628a7SBjoern A. Zeeb return (_prison_check_ip6(cred->cr_prison, ia6)); 1098413628a7SBjoern A. Zeeb } 1099413628a7SBjoern A. Zeeb #endif 1100413628a7SBjoern A. Zeeb 1101413628a7SBjoern A. Zeeb /* 1102ca04ba64SJamie Gritton * Check if a jail supports the given address family. 1103ca04ba64SJamie Gritton * 1104ca04ba64SJamie Gritton * Returns 0 if not jailed or the address family is supported, EAFNOSUPPORT 1105ca04ba64SJamie Gritton * if not. 1106ca04ba64SJamie Gritton */ 1107ca04ba64SJamie Gritton int 1108ca04ba64SJamie Gritton prison_check_af(struct ucred *cred, int af) 1109ca04ba64SJamie Gritton { 1110ca04ba64SJamie Gritton int error; 1111ca04ba64SJamie Gritton 1112ca04ba64SJamie Gritton KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 1113ca04ba64SJamie Gritton 1114ca04ba64SJamie Gritton 1115ca04ba64SJamie Gritton if (!jailed(cred)) 1116ca04ba64SJamie Gritton return (0); 1117ca04ba64SJamie Gritton 1118ca04ba64SJamie Gritton error = 0; 1119ca04ba64SJamie Gritton switch (af) 1120ca04ba64SJamie Gritton { 1121ca04ba64SJamie Gritton #ifdef INET 1122ca04ba64SJamie Gritton case AF_INET: 1123ca04ba64SJamie Gritton if (cred->cr_prison->pr_ip4 == NULL) 1124ca04ba64SJamie Gritton error = EAFNOSUPPORT; 1125ca04ba64SJamie Gritton break; 1126ca04ba64SJamie Gritton #endif 1127ca04ba64SJamie Gritton #ifdef INET6 1128ca04ba64SJamie Gritton case AF_INET6: 1129ca04ba64SJamie Gritton if (cred->cr_prison->pr_ip6 == NULL) 1130ca04ba64SJamie Gritton error = EAFNOSUPPORT; 1131ca04ba64SJamie Gritton break; 1132ca04ba64SJamie Gritton #endif 1133ca04ba64SJamie Gritton case AF_LOCAL: 1134ca04ba64SJamie Gritton case AF_ROUTE: 1135ca04ba64SJamie Gritton break; 1136ca04ba64SJamie Gritton default: 1137ca04ba64SJamie Gritton if (jail_socket_unixiproute_only) 1138ca04ba64SJamie Gritton error = EAFNOSUPPORT; 1139ca04ba64SJamie Gritton } 1140ca04ba64SJamie Gritton return (error); 1141ca04ba64SJamie Gritton } 1142ca04ba64SJamie Gritton 1143ca04ba64SJamie Gritton /* 1144413628a7SBjoern A. Zeeb * Check if given address belongs to the jail referenced by cred (wrapper to 1145413628a7SBjoern A. Zeeb * prison_check_ip[46]). 1146413628a7SBjoern A. Zeeb * 1147b89e82ddSJamie Gritton * Returns 0 if not jailed or if address belongs to jail, EADDRNOTAVAIL if 1148b89e82ddSJamie Gritton * the address doesn't belong, or EAFNOSUPPORT if the jail doesn't allow 1149b89e82ddSJamie Gritton * the address family. IPv4 Address passed in in NBO. 1150413628a7SBjoern A. Zeeb */ 1151413628a7SBjoern A. Zeeb int 115291421ba2SRobert Watson prison_if(struct ucred *cred, struct sockaddr *sa) 115375c13541SPoul-Henning Kamp { 1154413628a7SBjoern A. Zeeb #ifdef INET 11559ddb7954SMike Barcroft struct sockaddr_in *sai; 1156413628a7SBjoern A. Zeeb #endif 1157413628a7SBjoern A. Zeeb #ifdef INET6 1158413628a7SBjoern A. Zeeb struct sockaddr_in6 *sai6; 1159413628a7SBjoern A. Zeeb #endif 1160b89e82ddSJamie Gritton int error; 116175c13541SPoul-Henning Kamp 1162413628a7SBjoern A. Zeeb KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 1163413628a7SBjoern A. Zeeb KASSERT(sa != NULL, ("%s: sa is NULL", __func__)); 1164413628a7SBjoern A. Zeeb 1165b89e82ddSJamie Gritton error = 0; 1166413628a7SBjoern A. Zeeb switch (sa->sa_family) 1167413628a7SBjoern A. Zeeb { 1168413628a7SBjoern A. Zeeb #ifdef INET 1169413628a7SBjoern A. Zeeb case AF_INET: 11709ddb7954SMike Barcroft sai = (struct sockaddr_in *)sa; 1171b89e82ddSJamie Gritton error = prison_check_ip4(cred, &sai->sin_addr); 1172413628a7SBjoern A. Zeeb break; 1173413628a7SBjoern A. Zeeb #endif 1174413628a7SBjoern A. Zeeb #ifdef INET6 1175413628a7SBjoern A. Zeeb case AF_INET6: 1176413628a7SBjoern A. Zeeb sai6 = (struct sockaddr_in6 *)sa; 1177b89e82ddSJamie Gritton error = prison_check_ip6(cred, &sai6->sin6_addr); 1178413628a7SBjoern A. Zeeb break; 1179413628a7SBjoern A. Zeeb #endif 1180413628a7SBjoern A. Zeeb default: 1181b89e82ddSJamie Gritton if (jailed(cred) && jail_socket_unixiproute_only) 1182b89e82ddSJamie Gritton error = EAFNOSUPPORT; 1183413628a7SBjoern A. Zeeb } 1184b89e82ddSJamie Gritton return (error); 118575c13541SPoul-Henning Kamp } 118691421ba2SRobert Watson 118791421ba2SRobert Watson /* 118891421ba2SRobert Watson * Return 0 if jails permit p1 to frob p2, otherwise ESRCH. 118991421ba2SRobert Watson */ 119091421ba2SRobert Watson int 11919ddb7954SMike Barcroft prison_check(struct ucred *cred1, struct ucred *cred2) 119291421ba2SRobert Watson { 119391421ba2SRobert Watson 119491421ba2SRobert Watson if (jailed(cred1)) { 119591421ba2SRobert Watson if (!jailed(cred2)) 119691421ba2SRobert Watson return (ESRCH); 119791421ba2SRobert Watson if (cred2->cr_prison != cred1->cr_prison) 119891421ba2SRobert Watson return (ESRCH); 119991421ba2SRobert Watson } 120091421ba2SRobert Watson 120191421ba2SRobert Watson return (0); 120291421ba2SRobert Watson } 120391421ba2SRobert Watson 120491421ba2SRobert Watson /* 120591421ba2SRobert Watson * Return 1 if the passed credential is in a jail, otherwise 0. 120691421ba2SRobert Watson */ 120791421ba2SRobert Watson int 12089ddb7954SMike Barcroft jailed(struct ucred *cred) 120991421ba2SRobert Watson { 121091421ba2SRobert Watson 121191421ba2SRobert Watson return (cred->cr_prison != NULL); 121291421ba2SRobert Watson } 12139484d0c0SRobert Drehmel 12149484d0c0SRobert Drehmel /* 12159484d0c0SRobert Drehmel * Return the correct hostname for the passed credential. 12169484d0c0SRobert Drehmel */ 1217ad1ff099SRobert Drehmel void 12189ddb7954SMike Barcroft getcredhostname(struct ucred *cred, char *buf, size_t size) 12199484d0c0SRobert Drehmel { 12208b615593SMarko Zec INIT_VPROCG(cred->cr_vimage->v_procg); 12219484d0c0SRobert Drehmel 1222ad1ff099SRobert Drehmel if (jailed(cred)) { 1223ad1ff099SRobert Drehmel mtx_lock(&cred->cr_prison->pr_mtx); 1224e80fb434SRobert Drehmel strlcpy(buf, cred->cr_prison->pr_host, size); 1225ad1ff099SRobert Drehmel mtx_unlock(&cred->cr_prison->pr_mtx); 12264f7d1876SRobert Watson } else { 12274f7d1876SRobert Watson mtx_lock(&hostname_mtx); 1228603724d3SBjoern A. Zeeb strlcpy(buf, V_hostname, size); 12294f7d1876SRobert Watson mtx_unlock(&hostname_mtx); 12304f7d1876SRobert Watson } 12319484d0c0SRobert Drehmel } 1232fd7a8150SMike Barcroft 1233f08df373SRobert Watson /* 1234820a0de9SPawel Jakub Dawidek * Determine whether the subject represented by cred can "see" 1235820a0de9SPawel Jakub Dawidek * status of a mount point. 1236820a0de9SPawel Jakub Dawidek * Returns: 0 for permitted, ENOENT otherwise. 1237820a0de9SPawel Jakub Dawidek * XXX: This function should be called cr_canseemount() and should be 1238820a0de9SPawel Jakub Dawidek * placed in kern_prot.c. 1239f08df373SRobert Watson */ 1240f08df373SRobert Watson int 1241820a0de9SPawel Jakub Dawidek prison_canseemount(struct ucred *cred, struct mount *mp) 1242f08df373SRobert Watson { 1243820a0de9SPawel Jakub Dawidek struct prison *pr; 1244820a0de9SPawel Jakub Dawidek struct statfs *sp; 1245820a0de9SPawel Jakub Dawidek size_t len; 1246f08df373SRobert Watson 1247820a0de9SPawel Jakub Dawidek if (!jailed(cred) || jail_enforce_statfs == 0) 1248820a0de9SPawel Jakub Dawidek return (0); 1249820a0de9SPawel Jakub Dawidek pr = cred->cr_prison; 1250820a0de9SPawel Jakub Dawidek if (pr->pr_root->v_mount == mp) 1251820a0de9SPawel Jakub Dawidek return (0); 1252820a0de9SPawel Jakub Dawidek if (jail_enforce_statfs == 2) 1253820a0de9SPawel Jakub Dawidek return (ENOENT); 1254820a0de9SPawel Jakub Dawidek /* 1255820a0de9SPawel Jakub Dawidek * If jail's chroot directory is set to "/" we should be able to see 1256820a0de9SPawel Jakub Dawidek * all mount-points from inside a jail. 1257820a0de9SPawel Jakub Dawidek * This is ugly check, but this is the only situation when jail's 1258820a0de9SPawel Jakub Dawidek * directory ends with '/'. 1259820a0de9SPawel Jakub Dawidek */ 1260820a0de9SPawel Jakub Dawidek if (strcmp(pr->pr_path, "/") == 0) 1261820a0de9SPawel Jakub Dawidek return (0); 1262820a0de9SPawel Jakub Dawidek len = strlen(pr->pr_path); 1263820a0de9SPawel Jakub Dawidek sp = &mp->mnt_stat; 1264820a0de9SPawel Jakub Dawidek if (strncmp(pr->pr_path, sp->f_mntonname, len) != 0) 1265820a0de9SPawel Jakub Dawidek return (ENOENT); 1266820a0de9SPawel Jakub Dawidek /* 1267820a0de9SPawel Jakub Dawidek * Be sure that we don't have situation where jail's root directory 1268820a0de9SPawel Jakub Dawidek * is "/some/path" and mount point is "/some/pathpath". 1269820a0de9SPawel Jakub Dawidek */ 1270820a0de9SPawel Jakub Dawidek if (sp->f_mntonname[len] != '\0' && sp->f_mntonname[len] != '/') 1271820a0de9SPawel Jakub Dawidek return (ENOENT); 1272f08df373SRobert Watson return (0); 1273f08df373SRobert Watson } 1274820a0de9SPawel Jakub Dawidek 1275820a0de9SPawel Jakub Dawidek void 1276820a0de9SPawel Jakub Dawidek prison_enforce_statfs(struct ucred *cred, struct mount *mp, struct statfs *sp) 1277820a0de9SPawel Jakub Dawidek { 1278820a0de9SPawel Jakub Dawidek char jpath[MAXPATHLEN]; 1279820a0de9SPawel Jakub Dawidek struct prison *pr; 1280820a0de9SPawel Jakub Dawidek size_t len; 1281820a0de9SPawel Jakub Dawidek 1282820a0de9SPawel Jakub Dawidek if (!jailed(cred) || jail_enforce_statfs == 0) 1283820a0de9SPawel Jakub Dawidek return; 1284820a0de9SPawel Jakub Dawidek pr = cred->cr_prison; 1285820a0de9SPawel Jakub Dawidek if (prison_canseemount(cred, mp) != 0) { 1286820a0de9SPawel Jakub Dawidek bzero(sp->f_mntonname, sizeof(sp->f_mntonname)); 1287820a0de9SPawel Jakub Dawidek strlcpy(sp->f_mntonname, "[restricted]", 1288820a0de9SPawel Jakub Dawidek sizeof(sp->f_mntonname)); 1289820a0de9SPawel Jakub Dawidek return; 1290820a0de9SPawel Jakub Dawidek } 1291820a0de9SPawel Jakub Dawidek if (pr->pr_root->v_mount == mp) { 1292820a0de9SPawel Jakub Dawidek /* 1293820a0de9SPawel Jakub Dawidek * Clear current buffer data, so we are sure nothing from 1294820a0de9SPawel Jakub Dawidek * the valid path left there. 1295820a0de9SPawel Jakub Dawidek */ 1296820a0de9SPawel Jakub Dawidek bzero(sp->f_mntonname, sizeof(sp->f_mntonname)); 1297820a0de9SPawel Jakub Dawidek *sp->f_mntonname = '/'; 1298820a0de9SPawel Jakub Dawidek return; 1299820a0de9SPawel Jakub Dawidek } 1300820a0de9SPawel Jakub Dawidek /* 1301820a0de9SPawel Jakub Dawidek * If jail's chroot directory is set to "/" we should be able to see 1302820a0de9SPawel Jakub Dawidek * all mount-points from inside a jail. 1303820a0de9SPawel Jakub Dawidek */ 1304820a0de9SPawel Jakub Dawidek if (strcmp(pr->pr_path, "/") == 0) 1305820a0de9SPawel Jakub Dawidek return; 1306820a0de9SPawel Jakub Dawidek len = strlen(pr->pr_path); 1307820a0de9SPawel Jakub Dawidek strlcpy(jpath, sp->f_mntonname + len, sizeof(jpath)); 1308820a0de9SPawel Jakub Dawidek /* 1309820a0de9SPawel Jakub Dawidek * Clear current buffer data, so we are sure nothing from 1310820a0de9SPawel Jakub Dawidek * the valid path left there. 1311820a0de9SPawel Jakub Dawidek */ 1312820a0de9SPawel Jakub Dawidek bzero(sp->f_mntonname, sizeof(sp->f_mntonname)); 1313820a0de9SPawel Jakub Dawidek if (*jpath == '\0') { 1314820a0de9SPawel Jakub Dawidek /* Should never happen. */ 1315820a0de9SPawel Jakub Dawidek *sp->f_mntonname = '/'; 1316820a0de9SPawel Jakub Dawidek } else { 1317820a0de9SPawel Jakub Dawidek strlcpy(sp->f_mntonname, jpath, sizeof(sp->f_mntonname)); 1318820a0de9SPawel Jakub Dawidek } 1319f08df373SRobert Watson } 1320f08df373SRobert Watson 1321800c9408SRobert Watson /* 1322800c9408SRobert Watson * Check with permission for a specific privilege is granted within jail. We 1323800c9408SRobert Watson * have a specific list of accepted privileges; the rest are denied. 1324800c9408SRobert Watson */ 1325800c9408SRobert Watson int 1326800c9408SRobert Watson prison_priv_check(struct ucred *cred, int priv) 1327800c9408SRobert Watson { 1328800c9408SRobert Watson 1329800c9408SRobert Watson if (!jailed(cred)) 1330800c9408SRobert Watson return (0); 1331800c9408SRobert Watson 1332800c9408SRobert Watson switch (priv) { 1333800c9408SRobert Watson 1334800c9408SRobert Watson /* 1335800c9408SRobert Watson * Allow ktrace privileges for root in jail. 1336800c9408SRobert Watson */ 1337800c9408SRobert Watson case PRIV_KTRACE: 1338800c9408SRobert Watson 1339c3c1b5e6SRobert Watson #if 0 1340800c9408SRobert Watson /* 1341800c9408SRobert Watson * Allow jailed processes to configure audit identity and 1342800c9408SRobert Watson * submit audit records (login, etc). In the future we may 1343800c9408SRobert Watson * want to further refine the relationship between audit and 1344800c9408SRobert Watson * jail. 1345800c9408SRobert Watson */ 1346800c9408SRobert Watson case PRIV_AUDIT_GETAUDIT: 1347800c9408SRobert Watson case PRIV_AUDIT_SETAUDIT: 1348800c9408SRobert Watson case PRIV_AUDIT_SUBMIT: 1349c3c1b5e6SRobert Watson #endif 1350800c9408SRobert Watson 1351800c9408SRobert Watson /* 1352800c9408SRobert Watson * Allow jailed processes to manipulate process UNIX 1353800c9408SRobert Watson * credentials in any way they see fit. 1354800c9408SRobert Watson */ 1355800c9408SRobert Watson case PRIV_CRED_SETUID: 1356800c9408SRobert Watson case PRIV_CRED_SETEUID: 1357800c9408SRobert Watson case PRIV_CRED_SETGID: 1358800c9408SRobert Watson case PRIV_CRED_SETEGID: 1359800c9408SRobert Watson case PRIV_CRED_SETGROUPS: 1360800c9408SRobert Watson case PRIV_CRED_SETREUID: 1361800c9408SRobert Watson case PRIV_CRED_SETREGID: 1362800c9408SRobert Watson case PRIV_CRED_SETRESUID: 1363800c9408SRobert Watson case PRIV_CRED_SETRESGID: 1364800c9408SRobert Watson 1365800c9408SRobert Watson /* 1366800c9408SRobert Watson * Jail implements visibility constraints already, so allow 1367800c9408SRobert Watson * jailed root to override uid/gid-based constraints. 1368800c9408SRobert Watson */ 1369800c9408SRobert Watson case PRIV_SEEOTHERGIDS: 1370800c9408SRobert Watson case PRIV_SEEOTHERUIDS: 1371800c9408SRobert Watson 1372800c9408SRobert Watson /* 1373800c9408SRobert Watson * Jail implements inter-process debugging limits already, so 1374800c9408SRobert Watson * allow jailed root various debugging privileges. 1375800c9408SRobert Watson */ 1376800c9408SRobert Watson case PRIV_DEBUG_DIFFCRED: 1377800c9408SRobert Watson case PRIV_DEBUG_SUGID: 1378800c9408SRobert Watson case PRIV_DEBUG_UNPRIV: 1379800c9408SRobert Watson 1380800c9408SRobert Watson /* 1381800c9408SRobert Watson * Allow jail to set various resource limits and login 1382800c9408SRobert Watson * properties, and for now, exceed process resource limits. 1383800c9408SRobert Watson */ 1384800c9408SRobert Watson case PRIV_PROC_LIMIT: 1385800c9408SRobert Watson case PRIV_PROC_SETLOGIN: 1386800c9408SRobert Watson case PRIV_PROC_SETRLIMIT: 1387800c9408SRobert Watson 1388800c9408SRobert Watson /* 1389800c9408SRobert Watson * System V and POSIX IPC privileges are granted in jail. 1390800c9408SRobert Watson */ 1391800c9408SRobert Watson case PRIV_IPC_READ: 1392800c9408SRobert Watson case PRIV_IPC_WRITE: 1393800c9408SRobert Watson case PRIV_IPC_ADMIN: 1394800c9408SRobert Watson case PRIV_IPC_MSGSIZE: 1395800c9408SRobert Watson case PRIV_MQ_ADMIN: 1396800c9408SRobert Watson 1397800c9408SRobert Watson /* 1398800c9408SRobert Watson * Jail implements its own inter-process limits, so allow 1399800c9408SRobert Watson * root processes in jail to change scheduling on other 1400800c9408SRobert Watson * processes in the same jail. Likewise for signalling. 1401800c9408SRobert Watson */ 1402800c9408SRobert Watson case PRIV_SCHED_DIFFCRED: 1403413628a7SBjoern A. Zeeb case PRIV_SCHED_CPUSET: 1404800c9408SRobert Watson case PRIV_SIGNAL_DIFFCRED: 1405800c9408SRobert Watson case PRIV_SIGNAL_SUGID: 1406800c9408SRobert Watson 1407800c9408SRobert Watson /* 1408800c9408SRobert Watson * Allow jailed processes to write to sysctls marked as jail 1409800c9408SRobert Watson * writable. 1410800c9408SRobert Watson */ 1411800c9408SRobert Watson case PRIV_SYSCTL_WRITEJAIL: 1412800c9408SRobert Watson 1413800c9408SRobert Watson /* 1414800c9408SRobert Watson * Allow root in jail to manage a variety of quota 1415e82d0201SRobert Watson * properties. These should likely be conditional on a 1416e82d0201SRobert Watson * configuration option. 1417800c9408SRobert Watson */ 141895b091d2SRobert Watson case PRIV_VFS_GETQUOTA: 141995b091d2SRobert Watson case PRIV_VFS_SETQUOTA: 1420800c9408SRobert Watson 1421800c9408SRobert Watson /* 1422800c9408SRobert Watson * Since Jail relies on chroot() to implement file system 1423800c9408SRobert Watson * protections, grant many VFS privileges to root in jail. 1424800c9408SRobert Watson * Be careful to exclude mount-related and NFS-related 1425800c9408SRobert Watson * privileges. 1426800c9408SRobert Watson */ 1427800c9408SRobert Watson case PRIV_VFS_READ: 1428800c9408SRobert Watson case PRIV_VFS_WRITE: 1429800c9408SRobert Watson case PRIV_VFS_ADMIN: 1430800c9408SRobert Watson case PRIV_VFS_EXEC: 1431800c9408SRobert Watson case PRIV_VFS_LOOKUP: 1432800c9408SRobert Watson case PRIV_VFS_BLOCKRESERVE: /* XXXRW: Slightly surprising. */ 1433800c9408SRobert Watson case PRIV_VFS_CHFLAGS_DEV: 1434800c9408SRobert Watson case PRIV_VFS_CHOWN: 1435800c9408SRobert Watson case PRIV_VFS_CHROOT: 1436bb531912SPawel Jakub Dawidek case PRIV_VFS_RETAINSUGID: 1437800c9408SRobert Watson case PRIV_VFS_FCHROOT: 1438800c9408SRobert Watson case PRIV_VFS_LINK: 1439800c9408SRobert Watson case PRIV_VFS_SETGID: 1440e41966dcSRobert Watson case PRIV_VFS_STAT: 1441800c9408SRobert Watson case PRIV_VFS_STICKYFILE: 1442800c9408SRobert Watson return (0); 1443800c9408SRobert Watson 1444800c9408SRobert Watson /* 1445800c9408SRobert Watson * Depending on the global setting, allow privilege of 1446800c9408SRobert Watson * setting system flags. 1447800c9408SRobert Watson */ 1448800c9408SRobert Watson case PRIV_VFS_SYSFLAGS: 1449800c9408SRobert Watson if (jail_chflags_allowed) 1450800c9408SRobert Watson return (0); 1451800c9408SRobert Watson else 1452800c9408SRobert Watson return (EPERM); 1453800c9408SRobert Watson 1454800c9408SRobert Watson /* 1455f3a8d2f9SPawel Jakub Dawidek * Depending on the global setting, allow privilege of 1456f3a8d2f9SPawel Jakub Dawidek * mounting/unmounting file systems. 1457f3a8d2f9SPawel Jakub Dawidek */ 1458f3a8d2f9SPawel Jakub Dawidek case PRIV_VFS_MOUNT: 1459f3a8d2f9SPawel Jakub Dawidek case PRIV_VFS_UNMOUNT: 1460f3a8d2f9SPawel Jakub Dawidek case PRIV_VFS_MOUNT_NONUSER: 146124b0502eSPawel Jakub Dawidek case PRIV_VFS_MOUNT_OWNER: 1462f3a8d2f9SPawel Jakub Dawidek if (jail_mount_allowed) 1463f3a8d2f9SPawel Jakub Dawidek return (0); 1464f3a8d2f9SPawel Jakub Dawidek else 1465f3a8d2f9SPawel Jakub Dawidek return (EPERM); 1466f3a8d2f9SPawel Jakub Dawidek 1467f3a8d2f9SPawel Jakub Dawidek /* 14684b084056SRobert Watson * Allow jailed root to bind reserved ports and reuse in-use 14694b084056SRobert Watson * ports. 1470800c9408SRobert Watson */ 1471800c9408SRobert Watson case PRIV_NETINET_RESERVEDPORT: 14724b084056SRobert Watson case PRIV_NETINET_REUSEPORT: 1473800c9408SRobert Watson return (0); 1474800c9408SRobert Watson 1475800c9408SRobert Watson /* 147679ba3952SBjoern A. Zeeb * Allow jailed root to set certian IPv4/6 (option) headers. 147779ba3952SBjoern A. Zeeb */ 147879ba3952SBjoern A. Zeeb case PRIV_NETINET_SETHDROPTS: 147979ba3952SBjoern A. Zeeb return (0); 148079ba3952SBjoern A. Zeeb 148179ba3952SBjoern A. Zeeb /* 1482800c9408SRobert Watson * Conditionally allow creating raw sockets in jail. 1483800c9408SRobert Watson */ 1484800c9408SRobert Watson case PRIV_NETINET_RAW: 1485800c9408SRobert Watson if (jail_allow_raw_sockets) 1486800c9408SRobert Watson return (0); 1487800c9408SRobert Watson else 1488800c9408SRobert Watson return (EPERM); 1489800c9408SRobert Watson 1490800c9408SRobert Watson /* 1491800c9408SRobert Watson * Since jail implements its own visibility limits on netstat 1492800c9408SRobert Watson * sysctls, allow getcred. This allows identd to work in 1493800c9408SRobert Watson * jail. 1494800c9408SRobert Watson */ 1495800c9408SRobert Watson case PRIV_NETINET_GETCRED: 1496800c9408SRobert Watson return (0); 1497800c9408SRobert Watson 1498800c9408SRobert Watson default: 1499800c9408SRobert Watson /* 1500800c9408SRobert Watson * In all remaining cases, deny the privilege request. This 1501800c9408SRobert Watson * includes almost all network privileges, many system 1502800c9408SRobert Watson * configuration privileges. 1503800c9408SRobert Watson */ 1504800c9408SRobert Watson return (EPERM); 1505800c9408SRobert Watson } 1506800c9408SRobert Watson } 1507800c9408SRobert Watson 1508fd7a8150SMike Barcroft static int 1509fd7a8150SMike Barcroft sysctl_jail_list(SYSCTL_HANDLER_ARGS) 1510fd7a8150SMike Barcroft { 1511fd7a8150SMike Barcroft struct xprison *xp, *sxp; 1512fd7a8150SMike Barcroft struct prison *pr; 1513413628a7SBjoern A. Zeeb char *p; 1514413628a7SBjoern A. Zeeb size_t len; 1515fd7a8150SMike Barcroft int count, error; 1516fd7a8150SMike Barcroft 15177f4704c0SPawel Jakub Dawidek if (jailed(req->td->td_ucred)) 1518679a1060SRobert Watson return (0); 1519fd7a8150SMike Barcroft 1520dc68a633SPawel Jakub Dawidek sx_slock(&allprison_lock); 1521dc68a633SPawel Jakub Dawidek if ((count = prisoncount) == 0) { 1522dc68a633SPawel Jakub Dawidek sx_sunlock(&allprison_lock); 1523fd7a8150SMike Barcroft return (0); 1524dc68a633SPawel Jakub Dawidek } 1525fd7a8150SMike Barcroft 1526413628a7SBjoern A. Zeeb len = sizeof(*xp) * count; 1527413628a7SBjoern A. Zeeb LIST_FOREACH(pr, &allprison, pr_list) { 1528413628a7SBjoern A. Zeeb #ifdef INET 1529413628a7SBjoern A. Zeeb len += pr->pr_ip4s * sizeof(struct in_addr); 1530413628a7SBjoern A. Zeeb #endif 1531413628a7SBjoern A. Zeeb #ifdef INET6 1532413628a7SBjoern A. Zeeb len += pr->pr_ip6s * sizeof(struct in6_addr); 1533413628a7SBjoern A. Zeeb #endif 1534413628a7SBjoern A. Zeeb } 1535413628a7SBjoern A. Zeeb 1536413628a7SBjoern A. Zeeb sxp = xp = malloc(len, M_TEMP, M_WAITOK | M_ZERO); 1537fd7a8150SMike Barcroft 1538fd7a8150SMike Barcroft LIST_FOREACH(pr, &allprison, pr_list) { 1539fd7a8150SMike Barcroft xp->pr_version = XPRISON_VERSION; 1540fd7a8150SMike Barcroft xp->pr_id = pr->pr_id; 1541413628a7SBjoern A. Zeeb xp->pr_state = pr->pr_state; 1542413628a7SBjoern A. Zeeb xp->pr_cpusetid = pr->pr_cpuset->cs_id; 1543b63b0c65SPawel Jakub Dawidek strlcpy(xp->pr_path, pr->pr_path, sizeof(xp->pr_path)); 1544b63b0c65SPawel Jakub Dawidek mtx_lock(&pr->pr_mtx); 1545b63b0c65SPawel Jakub Dawidek strlcpy(xp->pr_host, pr->pr_host, sizeof(xp->pr_host)); 1546413628a7SBjoern A. Zeeb strlcpy(xp->pr_name, pr->pr_name, sizeof(xp->pr_name)); 1547fd7a8150SMike Barcroft mtx_unlock(&pr->pr_mtx); 1548413628a7SBjoern A. Zeeb #ifdef INET 1549413628a7SBjoern A. Zeeb xp->pr_ip4s = pr->pr_ip4s; 1550413628a7SBjoern A. Zeeb #endif 1551413628a7SBjoern A. Zeeb #ifdef INET6 1552413628a7SBjoern A. Zeeb xp->pr_ip6s = pr->pr_ip6s; 1553413628a7SBjoern A. Zeeb #endif 1554413628a7SBjoern A. Zeeb p = (char *)(xp + 1); 1555413628a7SBjoern A. Zeeb #ifdef INET 1556413628a7SBjoern A. Zeeb if (pr->pr_ip4s > 0) { 1557413628a7SBjoern A. Zeeb bcopy(pr->pr_ip4, (struct in_addr *)p, 1558413628a7SBjoern A. Zeeb pr->pr_ip4s * sizeof(struct in_addr)); 1559413628a7SBjoern A. Zeeb p += (pr->pr_ip4s * sizeof(struct in_addr)); 1560413628a7SBjoern A. Zeeb } 1561413628a7SBjoern A. Zeeb #endif 1562413628a7SBjoern A. Zeeb #ifdef INET6 1563413628a7SBjoern A. Zeeb if (pr->pr_ip6s > 0) { 1564413628a7SBjoern A. Zeeb bcopy(pr->pr_ip6, (struct in6_addr *)p, 1565413628a7SBjoern A. Zeeb pr->pr_ip6s * sizeof(struct in6_addr)); 1566413628a7SBjoern A. Zeeb p += (pr->pr_ip6s * sizeof(struct in6_addr)); 1567413628a7SBjoern A. Zeeb } 1568413628a7SBjoern A. Zeeb #endif 1569413628a7SBjoern A. Zeeb xp = (struct xprison *)p; 1570fd7a8150SMike Barcroft } 1571dc68a633SPawel Jakub Dawidek sx_sunlock(&allprison_lock); 1572fd7a8150SMike Barcroft 1573413628a7SBjoern A. Zeeb error = SYSCTL_OUT(req, sxp, len); 1574fd7a8150SMike Barcroft free(sxp, M_TEMP); 1575fd7a8150SMike Barcroft return (error); 1576fd7a8150SMike Barcroft } 1577fd7a8150SMike Barcroft 1578f3b86a5fSEd Schouten SYSCTL_OID(_security_jail, OID_AUTO, list, 1579f3b86a5fSEd Schouten CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 0, 1580f3b86a5fSEd Schouten sysctl_jail_list, "S", "List of active jails"); 1581461167c2SPawel Jakub Dawidek 1582461167c2SPawel Jakub Dawidek static int 1583461167c2SPawel Jakub Dawidek sysctl_jail_jailed(SYSCTL_HANDLER_ARGS) 1584461167c2SPawel Jakub Dawidek { 1585461167c2SPawel Jakub Dawidek int error, injail; 1586461167c2SPawel Jakub Dawidek 1587461167c2SPawel Jakub Dawidek injail = jailed(req->td->td_ucred); 1588461167c2SPawel Jakub Dawidek error = SYSCTL_OUT(req, &injail, sizeof(injail)); 1589461167c2SPawel Jakub Dawidek 1590461167c2SPawel Jakub Dawidek return (error); 1591461167c2SPawel Jakub Dawidek } 1592f3b86a5fSEd Schouten SYSCTL_PROC(_security_jail, OID_AUTO, jailed, 1593f3b86a5fSEd Schouten CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 0, 1594f3b86a5fSEd Schouten sysctl_jail_jailed, "I", "Process in jail?"); 1595413628a7SBjoern A. Zeeb 1596413628a7SBjoern A. Zeeb #ifdef DDB 1597413628a7SBjoern A. Zeeb DB_SHOW_COMMAND(jails, db_show_jails) 1598413628a7SBjoern A. Zeeb { 1599413628a7SBjoern A. Zeeb struct prison *pr; 1600413628a7SBjoern A. Zeeb #ifdef INET 1601413628a7SBjoern A. Zeeb struct in_addr ia; 1602413628a7SBjoern A. Zeeb #endif 1603413628a7SBjoern A. Zeeb #ifdef INET6 1604413628a7SBjoern A. Zeeb char ip6buf[INET6_ADDRSTRLEN]; 1605413628a7SBjoern A. Zeeb #endif 1606413628a7SBjoern A. Zeeb const char *state; 1607413628a7SBjoern A. Zeeb #if defined(INET) || defined(INET6) 1608413628a7SBjoern A. Zeeb int i; 1609413628a7SBjoern A. Zeeb #endif 1610413628a7SBjoern A. Zeeb 1611413628a7SBjoern A. Zeeb db_printf( 1612413628a7SBjoern A. Zeeb " JID pr_ref pr_nprocs pr_ip4s pr_ip6s\n"); 1613413628a7SBjoern A. Zeeb db_printf( 1614413628a7SBjoern A. Zeeb " Hostname Path\n"); 1615413628a7SBjoern A. Zeeb db_printf( 1616413628a7SBjoern A. Zeeb " Name State\n"); 1617413628a7SBjoern A. Zeeb db_printf( 1618413628a7SBjoern A. Zeeb " Cpusetid\n"); 1619413628a7SBjoern A. Zeeb db_printf( 1620413628a7SBjoern A. Zeeb " IP Address(es)\n"); 1621413628a7SBjoern A. Zeeb LIST_FOREACH(pr, &allprison, pr_list) { 1622413628a7SBjoern A. Zeeb db_printf("%6d %6d %9d %7d %7d\n", 1623413628a7SBjoern A. Zeeb pr->pr_id, pr->pr_ref, pr->pr_nprocs, 1624413628a7SBjoern A. Zeeb pr->pr_ip4s, pr->pr_ip6s); 1625413628a7SBjoern A. Zeeb db_printf("%6s %-29.29s %.74s\n", 1626413628a7SBjoern A. Zeeb "", pr->pr_host, pr->pr_path); 16270f1fe22dSBjoern A. Zeeb if (pr->pr_state < 0 || pr->pr_state >= (int)((sizeof( 1628413628a7SBjoern A. Zeeb prison_states) / sizeof(struct prison_state)))) 1629413628a7SBjoern A. Zeeb state = "(bogus)"; 1630413628a7SBjoern A. Zeeb else 1631413628a7SBjoern A. Zeeb state = prison_states[pr->pr_state].state_name; 1632413628a7SBjoern A. Zeeb db_printf("%6s %-29.29s %.74s\n", 16330f1fe22dSBjoern A. Zeeb "", (pr->pr_name[0] != '\0') ? pr->pr_name : "", state); 1634413628a7SBjoern A. Zeeb db_printf("%6s %-6d\n", 1635413628a7SBjoern A. Zeeb "", pr->pr_cpuset->cs_id); 1636413628a7SBjoern A. Zeeb #ifdef INET 1637413628a7SBjoern A. Zeeb for (i=0; i < pr->pr_ip4s; i++) { 1638413628a7SBjoern A. Zeeb ia.s_addr = pr->pr_ip4[i].s_addr; 1639413628a7SBjoern A. Zeeb db_printf("%6s %s\n", "", inet_ntoa(ia)); 1640413628a7SBjoern A. Zeeb } 1641413628a7SBjoern A. Zeeb #endif 1642413628a7SBjoern A. Zeeb #ifdef INET6 1643413628a7SBjoern A. Zeeb for (i=0; i < pr->pr_ip6s; i++) 1644413628a7SBjoern A. Zeeb db_printf("%6s %s\n", 1645413628a7SBjoern A. Zeeb "", ip6_sprintf(ip6buf, &pr->pr_ip6[i])); 1646413628a7SBjoern A. Zeeb #endif /* INET6 */ 1647413628a7SBjoern A. Zeeb if (db_pager_quit) 1648413628a7SBjoern A. Zeeb break; 1649413628a7SBjoern A. Zeeb } 1650413628a7SBjoern A. Zeeb } 1651413628a7SBjoern A. Zeeb #endif /* DDB */ 1652