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 /* 1102413628a7SBjoern A. Zeeb * Check if given address belongs to the jail referenced by cred (wrapper to 1103413628a7SBjoern A. Zeeb * prison_check_ip[46]). 1104413628a7SBjoern A. Zeeb * 1105b89e82ddSJamie Gritton * Returns 0 if not jailed or if address belongs to jail, EADDRNOTAVAIL if 1106b89e82ddSJamie Gritton * the address doesn't belong, or EAFNOSUPPORT if the jail doesn't allow 1107b89e82ddSJamie Gritton * the address family. IPv4 Address passed in in NBO. 1108413628a7SBjoern A. Zeeb */ 1109413628a7SBjoern A. Zeeb int 111091421ba2SRobert Watson prison_if(struct ucred *cred, struct sockaddr *sa) 111175c13541SPoul-Henning Kamp { 1112413628a7SBjoern A. Zeeb #ifdef INET 11139ddb7954SMike Barcroft struct sockaddr_in *sai; 1114413628a7SBjoern A. Zeeb #endif 1115413628a7SBjoern A. Zeeb #ifdef INET6 1116413628a7SBjoern A. Zeeb struct sockaddr_in6 *sai6; 1117413628a7SBjoern A. Zeeb #endif 1118b89e82ddSJamie Gritton int error; 111975c13541SPoul-Henning Kamp 1120413628a7SBjoern A. Zeeb KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 1121413628a7SBjoern A. Zeeb KASSERT(sa != NULL, ("%s: sa is NULL", __func__)); 1122413628a7SBjoern A. Zeeb 1123b89e82ddSJamie Gritton error = 0; 1124413628a7SBjoern A. Zeeb switch (sa->sa_family) 1125413628a7SBjoern A. Zeeb { 1126413628a7SBjoern A. Zeeb #ifdef INET 1127413628a7SBjoern A. Zeeb case AF_INET: 11289ddb7954SMike Barcroft sai = (struct sockaddr_in *)sa; 1129b89e82ddSJamie Gritton error = prison_check_ip4(cred, &sai->sin_addr); 1130413628a7SBjoern A. Zeeb break; 1131413628a7SBjoern A. Zeeb #endif 1132413628a7SBjoern A. Zeeb #ifdef INET6 1133413628a7SBjoern A. Zeeb case AF_INET6: 1134413628a7SBjoern A. Zeeb sai6 = (struct sockaddr_in6 *)sa; 1135b89e82ddSJamie Gritton error = prison_check_ip6(cred, &sai6->sin6_addr); 1136413628a7SBjoern A. Zeeb break; 1137413628a7SBjoern A. Zeeb #endif 1138413628a7SBjoern A. Zeeb default: 1139b89e82ddSJamie Gritton if (jailed(cred) && jail_socket_unixiproute_only) 1140b89e82ddSJamie Gritton error = EAFNOSUPPORT; 1141413628a7SBjoern A. Zeeb } 1142b89e82ddSJamie Gritton return (error); 114375c13541SPoul-Henning Kamp } 114491421ba2SRobert Watson 114591421ba2SRobert Watson /* 114691421ba2SRobert Watson * Return 0 if jails permit p1 to frob p2, otherwise ESRCH. 114791421ba2SRobert Watson */ 114891421ba2SRobert Watson int 11499ddb7954SMike Barcroft prison_check(struct ucred *cred1, struct ucred *cred2) 115091421ba2SRobert Watson { 115191421ba2SRobert Watson 115291421ba2SRobert Watson if (jailed(cred1)) { 115391421ba2SRobert Watson if (!jailed(cred2)) 115491421ba2SRobert Watson return (ESRCH); 115591421ba2SRobert Watson if (cred2->cr_prison != cred1->cr_prison) 115691421ba2SRobert Watson return (ESRCH); 115791421ba2SRobert Watson } 115891421ba2SRobert Watson 115991421ba2SRobert Watson return (0); 116091421ba2SRobert Watson } 116191421ba2SRobert Watson 116291421ba2SRobert Watson /* 116391421ba2SRobert Watson * Return 1 if the passed credential is in a jail, otherwise 0. 116491421ba2SRobert Watson */ 116591421ba2SRobert Watson int 11669ddb7954SMike Barcroft jailed(struct ucred *cred) 116791421ba2SRobert Watson { 116891421ba2SRobert Watson 116991421ba2SRobert Watson return (cred->cr_prison != NULL); 117091421ba2SRobert Watson } 11719484d0c0SRobert Drehmel 11729484d0c0SRobert Drehmel /* 11739484d0c0SRobert Drehmel * Return the correct hostname for the passed credential. 11749484d0c0SRobert Drehmel */ 1175ad1ff099SRobert Drehmel void 11769ddb7954SMike Barcroft getcredhostname(struct ucred *cred, char *buf, size_t size) 11779484d0c0SRobert Drehmel { 11788b615593SMarko Zec INIT_VPROCG(cred->cr_vimage->v_procg); 11799484d0c0SRobert Drehmel 1180ad1ff099SRobert Drehmel if (jailed(cred)) { 1181ad1ff099SRobert Drehmel mtx_lock(&cred->cr_prison->pr_mtx); 1182e80fb434SRobert Drehmel strlcpy(buf, cred->cr_prison->pr_host, size); 1183ad1ff099SRobert Drehmel mtx_unlock(&cred->cr_prison->pr_mtx); 11844f7d1876SRobert Watson } else { 11854f7d1876SRobert Watson mtx_lock(&hostname_mtx); 1186603724d3SBjoern A. Zeeb strlcpy(buf, V_hostname, size); 11874f7d1876SRobert Watson mtx_unlock(&hostname_mtx); 11884f7d1876SRobert Watson } 11899484d0c0SRobert Drehmel } 1190fd7a8150SMike Barcroft 1191f08df373SRobert Watson /* 1192820a0de9SPawel Jakub Dawidek * Determine whether the subject represented by cred can "see" 1193820a0de9SPawel Jakub Dawidek * status of a mount point. 1194820a0de9SPawel Jakub Dawidek * Returns: 0 for permitted, ENOENT otherwise. 1195820a0de9SPawel Jakub Dawidek * XXX: This function should be called cr_canseemount() and should be 1196820a0de9SPawel Jakub Dawidek * placed in kern_prot.c. 1197f08df373SRobert Watson */ 1198f08df373SRobert Watson int 1199820a0de9SPawel Jakub Dawidek prison_canseemount(struct ucred *cred, struct mount *mp) 1200f08df373SRobert Watson { 1201820a0de9SPawel Jakub Dawidek struct prison *pr; 1202820a0de9SPawel Jakub Dawidek struct statfs *sp; 1203820a0de9SPawel Jakub Dawidek size_t len; 1204f08df373SRobert Watson 1205820a0de9SPawel Jakub Dawidek if (!jailed(cred) || jail_enforce_statfs == 0) 1206820a0de9SPawel Jakub Dawidek return (0); 1207820a0de9SPawel Jakub Dawidek pr = cred->cr_prison; 1208820a0de9SPawel Jakub Dawidek if (pr->pr_root->v_mount == mp) 1209820a0de9SPawel Jakub Dawidek return (0); 1210820a0de9SPawel Jakub Dawidek if (jail_enforce_statfs == 2) 1211820a0de9SPawel Jakub Dawidek return (ENOENT); 1212820a0de9SPawel Jakub Dawidek /* 1213820a0de9SPawel Jakub Dawidek * If jail's chroot directory is set to "/" we should be able to see 1214820a0de9SPawel Jakub Dawidek * all mount-points from inside a jail. 1215820a0de9SPawel Jakub Dawidek * This is ugly check, but this is the only situation when jail's 1216820a0de9SPawel Jakub Dawidek * directory ends with '/'. 1217820a0de9SPawel Jakub Dawidek */ 1218820a0de9SPawel Jakub Dawidek if (strcmp(pr->pr_path, "/") == 0) 1219820a0de9SPawel Jakub Dawidek return (0); 1220820a0de9SPawel Jakub Dawidek len = strlen(pr->pr_path); 1221820a0de9SPawel Jakub Dawidek sp = &mp->mnt_stat; 1222820a0de9SPawel Jakub Dawidek if (strncmp(pr->pr_path, sp->f_mntonname, len) != 0) 1223820a0de9SPawel Jakub Dawidek return (ENOENT); 1224820a0de9SPawel Jakub Dawidek /* 1225820a0de9SPawel Jakub Dawidek * Be sure that we don't have situation where jail's root directory 1226820a0de9SPawel Jakub Dawidek * is "/some/path" and mount point is "/some/pathpath". 1227820a0de9SPawel Jakub Dawidek */ 1228820a0de9SPawel Jakub Dawidek if (sp->f_mntonname[len] != '\0' && sp->f_mntonname[len] != '/') 1229820a0de9SPawel Jakub Dawidek return (ENOENT); 1230f08df373SRobert Watson return (0); 1231f08df373SRobert Watson } 1232820a0de9SPawel Jakub Dawidek 1233820a0de9SPawel Jakub Dawidek void 1234820a0de9SPawel Jakub Dawidek prison_enforce_statfs(struct ucred *cred, struct mount *mp, struct statfs *sp) 1235820a0de9SPawel Jakub Dawidek { 1236820a0de9SPawel Jakub Dawidek char jpath[MAXPATHLEN]; 1237820a0de9SPawel Jakub Dawidek struct prison *pr; 1238820a0de9SPawel Jakub Dawidek size_t len; 1239820a0de9SPawel Jakub Dawidek 1240820a0de9SPawel Jakub Dawidek if (!jailed(cred) || jail_enforce_statfs == 0) 1241820a0de9SPawel Jakub Dawidek return; 1242820a0de9SPawel Jakub Dawidek pr = cred->cr_prison; 1243820a0de9SPawel Jakub Dawidek if (prison_canseemount(cred, mp) != 0) { 1244820a0de9SPawel Jakub Dawidek bzero(sp->f_mntonname, sizeof(sp->f_mntonname)); 1245820a0de9SPawel Jakub Dawidek strlcpy(sp->f_mntonname, "[restricted]", 1246820a0de9SPawel Jakub Dawidek sizeof(sp->f_mntonname)); 1247820a0de9SPawel Jakub Dawidek return; 1248820a0de9SPawel Jakub Dawidek } 1249820a0de9SPawel Jakub Dawidek if (pr->pr_root->v_mount == mp) { 1250820a0de9SPawel Jakub Dawidek /* 1251820a0de9SPawel Jakub Dawidek * Clear current buffer data, so we are sure nothing from 1252820a0de9SPawel Jakub Dawidek * the valid path left there. 1253820a0de9SPawel Jakub Dawidek */ 1254820a0de9SPawel Jakub Dawidek bzero(sp->f_mntonname, sizeof(sp->f_mntonname)); 1255820a0de9SPawel Jakub Dawidek *sp->f_mntonname = '/'; 1256820a0de9SPawel Jakub Dawidek return; 1257820a0de9SPawel Jakub Dawidek } 1258820a0de9SPawel Jakub Dawidek /* 1259820a0de9SPawel Jakub Dawidek * If jail's chroot directory is set to "/" we should be able to see 1260820a0de9SPawel Jakub Dawidek * all mount-points from inside a jail. 1261820a0de9SPawel Jakub Dawidek */ 1262820a0de9SPawel Jakub Dawidek if (strcmp(pr->pr_path, "/") == 0) 1263820a0de9SPawel Jakub Dawidek return; 1264820a0de9SPawel Jakub Dawidek len = strlen(pr->pr_path); 1265820a0de9SPawel Jakub Dawidek strlcpy(jpath, sp->f_mntonname + len, sizeof(jpath)); 1266820a0de9SPawel Jakub Dawidek /* 1267820a0de9SPawel Jakub Dawidek * Clear current buffer data, so we are sure nothing from 1268820a0de9SPawel Jakub Dawidek * the valid path left there. 1269820a0de9SPawel Jakub Dawidek */ 1270820a0de9SPawel Jakub Dawidek bzero(sp->f_mntonname, sizeof(sp->f_mntonname)); 1271820a0de9SPawel Jakub Dawidek if (*jpath == '\0') { 1272820a0de9SPawel Jakub Dawidek /* Should never happen. */ 1273820a0de9SPawel Jakub Dawidek *sp->f_mntonname = '/'; 1274820a0de9SPawel Jakub Dawidek } else { 1275820a0de9SPawel Jakub Dawidek strlcpy(sp->f_mntonname, jpath, sizeof(sp->f_mntonname)); 1276820a0de9SPawel Jakub Dawidek } 1277f08df373SRobert Watson } 1278f08df373SRobert Watson 1279800c9408SRobert Watson /* 1280800c9408SRobert Watson * Check with permission for a specific privilege is granted within jail. We 1281800c9408SRobert Watson * have a specific list of accepted privileges; the rest are denied. 1282800c9408SRobert Watson */ 1283800c9408SRobert Watson int 1284800c9408SRobert Watson prison_priv_check(struct ucred *cred, int priv) 1285800c9408SRobert Watson { 1286800c9408SRobert Watson 1287800c9408SRobert Watson if (!jailed(cred)) 1288800c9408SRobert Watson return (0); 1289800c9408SRobert Watson 1290800c9408SRobert Watson switch (priv) { 1291800c9408SRobert Watson 1292800c9408SRobert Watson /* 1293800c9408SRobert Watson * Allow ktrace privileges for root in jail. 1294800c9408SRobert Watson */ 1295800c9408SRobert Watson case PRIV_KTRACE: 1296800c9408SRobert Watson 1297c3c1b5e6SRobert Watson #if 0 1298800c9408SRobert Watson /* 1299800c9408SRobert Watson * Allow jailed processes to configure audit identity and 1300800c9408SRobert Watson * submit audit records (login, etc). In the future we may 1301800c9408SRobert Watson * want to further refine the relationship between audit and 1302800c9408SRobert Watson * jail. 1303800c9408SRobert Watson */ 1304800c9408SRobert Watson case PRIV_AUDIT_GETAUDIT: 1305800c9408SRobert Watson case PRIV_AUDIT_SETAUDIT: 1306800c9408SRobert Watson case PRIV_AUDIT_SUBMIT: 1307c3c1b5e6SRobert Watson #endif 1308800c9408SRobert Watson 1309800c9408SRobert Watson /* 1310800c9408SRobert Watson * Allow jailed processes to manipulate process UNIX 1311800c9408SRobert Watson * credentials in any way they see fit. 1312800c9408SRobert Watson */ 1313800c9408SRobert Watson case PRIV_CRED_SETUID: 1314800c9408SRobert Watson case PRIV_CRED_SETEUID: 1315800c9408SRobert Watson case PRIV_CRED_SETGID: 1316800c9408SRobert Watson case PRIV_CRED_SETEGID: 1317800c9408SRobert Watson case PRIV_CRED_SETGROUPS: 1318800c9408SRobert Watson case PRIV_CRED_SETREUID: 1319800c9408SRobert Watson case PRIV_CRED_SETREGID: 1320800c9408SRobert Watson case PRIV_CRED_SETRESUID: 1321800c9408SRobert Watson case PRIV_CRED_SETRESGID: 1322800c9408SRobert Watson 1323800c9408SRobert Watson /* 1324800c9408SRobert Watson * Jail implements visibility constraints already, so allow 1325800c9408SRobert Watson * jailed root to override uid/gid-based constraints. 1326800c9408SRobert Watson */ 1327800c9408SRobert Watson case PRIV_SEEOTHERGIDS: 1328800c9408SRobert Watson case PRIV_SEEOTHERUIDS: 1329800c9408SRobert Watson 1330800c9408SRobert Watson /* 1331800c9408SRobert Watson * Jail implements inter-process debugging limits already, so 1332800c9408SRobert Watson * allow jailed root various debugging privileges. 1333800c9408SRobert Watson */ 1334800c9408SRobert Watson case PRIV_DEBUG_DIFFCRED: 1335800c9408SRobert Watson case PRIV_DEBUG_SUGID: 1336800c9408SRobert Watson case PRIV_DEBUG_UNPRIV: 1337800c9408SRobert Watson 1338800c9408SRobert Watson /* 1339800c9408SRobert Watson * Allow jail to set various resource limits and login 1340800c9408SRobert Watson * properties, and for now, exceed process resource limits. 1341800c9408SRobert Watson */ 1342800c9408SRobert Watson case PRIV_PROC_LIMIT: 1343800c9408SRobert Watson case PRIV_PROC_SETLOGIN: 1344800c9408SRobert Watson case PRIV_PROC_SETRLIMIT: 1345800c9408SRobert Watson 1346800c9408SRobert Watson /* 1347800c9408SRobert Watson * System V and POSIX IPC privileges are granted in jail. 1348800c9408SRobert Watson */ 1349800c9408SRobert Watson case PRIV_IPC_READ: 1350800c9408SRobert Watson case PRIV_IPC_WRITE: 1351800c9408SRobert Watson case PRIV_IPC_ADMIN: 1352800c9408SRobert Watson case PRIV_IPC_MSGSIZE: 1353800c9408SRobert Watson case PRIV_MQ_ADMIN: 1354800c9408SRobert Watson 1355800c9408SRobert Watson /* 1356800c9408SRobert Watson * Jail implements its own inter-process limits, so allow 1357800c9408SRobert Watson * root processes in jail to change scheduling on other 1358800c9408SRobert Watson * processes in the same jail. Likewise for signalling. 1359800c9408SRobert Watson */ 1360800c9408SRobert Watson case PRIV_SCHED_DIFFCRED: 1361413628a7SBjoern A. Zeeb case PRIV_SCHED_CPUSET: 1362800c9408SRobert Watson case PRIV_SIGNAL_DIFFCRED: 1363800c9408SRobert Watson case PRIV_SIGNAL_SUGID: 1364800c9408SRobert Watson 1365800c9408SRobert Watson /* 1366800c9408SRobert Watson * Allow jailed processes to write to sysctls marked as jail 1367800c9408SRobert Watson * writable. 1368800c9408SRobert Watson */ 1369800c9408SRobert Watson case PRIV_SYSCTL_WRITEJAIL: 1370800c9408SRobert Watson 1371800c9408SRobert Watson /* 1372800c9408SRobert Watson * Allow root in jail to manage a variety of quota 1373e82d0201SRobert Watson * properties. These should likely be conditional on a 1374e82d0201SRobert Watson * configuration option. 1375800c9408SRobert Watson */ 137695b091d2SRobert Watson case PRIV_VFS_GETQUOTA: 137795b091d2SRobert Watson case PRIV_VFS_SETQUOTA: 1378800c9408SRobert Watson 1379800c9408SRobert Watson /* 1380800c9408SRobert Watson * Since Jail relies on chroot() to implement file system 1381800c9408SRobert Watson * protections, grant many VFS privileges to root in jail. 1382800c9408SRobert Watson * Be careful to exclude mount-related and NFS-related 1383800c9408SRobert Watson * privileges. 1384800c9408SRobert Watson */ 1385800c9408SRobert Watson case PRIV_VFS_READ: 1386800c9408SRobert Watson case PRIV_VFS_WRITE: 1387800c9408SRobert Watson case PRIV_VFS_ADMIN: 1388800c9408SRobert Watson case PRIV_VFS_EXEC: 1389800c9408SRobert Watson case PRIV_VFS_LOOKUP: 1390800c9408SRobert Watson case PRIV_VFS_BLOCKRESERVE: /* XXXRW: Slightly surprising. */ 1391800c9408SRobert Watson case PRIV_VFS_CHFLAGS_DEV: 1392800c9408SRobert Watson case PRIV_VFS_CHOWN: 1393800c9408SRobert Watson case PRIV_VFS_CHROOT: 1394bb531912SPawel Jakub Dawidek case PRIV_VFS_RETAINSUGID: 1395800c9408SRobert Watson case PRIV_VFS_FCHROOT: 1396800c9408SRobert Watson case PRIV_VFS_LINK: 1397800c9408SRobert Watson case PRIV_VFS_SETGID: 1398e41966dcSRobert Watson case PRIV_VFS_STAT: 1399800c9408SRobert Watson case PRIV_VFS_STICKYFILE: 1400800c9408SRobert Watson return (0); 1401800c9408SRobert Watson 1402800c9408SRobert Watson /* 1403800c9408SRobert Watson * Depending on the global setting, allow privilege of 1404800c9408SRobert Watson * setting system flags. 1405800c9408SRobert Watson */ 1406800c9408SRobert Watson case PRIV_VFS_SYSFLAGS: 1407800c9408SRobert Watson if (jail_chflags_allowed) 1408800c9408SRobert Watson return (0); 1409800c9408SRobert Watson else 1410800c9408SRobert Watson return (EPERM); 1411800c9408SRobert Watson 1412800c9408SRobert Watson /* 1413f3a8d2f9SPawel Jakub Dawidek * Depending on the global setting, allow privilege of 1414f3a8d2f9SPawel Jakub Dawidek * mounting/unmounting file systems. 1415f3a8d2f9SPawel Jakub Dawidek */ 1416f3a8d2f9SPawel Jakub Dawidek case PRIV_VFS_MOUNT: 1417f3a8d2f9SPawel Jakub Dawidek case PRIV_VFS_UNMOUNT: 1418f3a8d2f9SPawel Jakub Dawidek case PRIV_VFS_MOUNT_NONUSER: 141924b0502eSPawel Jakub Dawidek case PRIV_VFS_MOUNT_OWNER: 1420f3a8d2f9SPawel Jakub Dawidek if (jail_mount_allowed) 1421f3a8d2f9SPawel Jakub Dawidek return (0); 1422f3a8d2f9SPawel Jakub Dawidek else 1423f3a8d2f9SPawel Jakub Dawidek return (EPERM); 1424f3a8d2f9SPawel Jakub Dawidek 1425f3a8d2f9SPawel Jakub Dawidek /* 14264b084056SRobert Watson * Allow jailed root to bind reserved ports and reuse in-use 14274b084056SRobert Watson * ports. 1428800c9408SRobert Watson */ 1429800c9408SRobert Watson case PRIV_NETINET_RESERVEDPORT: 14304b084056SRobert Watson case PRIV_NETINET_REUSEPORT: 1431800c9408SRobert Watson return (0); 1432800c9408SRobert Watson 1433800c9408SRobert Watson /* 143479ba3952SBjoern A. Zeeb * Allow jailed root to set certian IPv4/6 (option) headers. 143579ba3952SBjoern A. Zeeb */ 143679ba3952SBjoern A. Zeeb case PRIV_NETINET_SETHDROPTS: 143779ba3952SBjoern A. Zeeb return (0); 143879ba3952SBjoern A. Zeeb 143979ba3952SBjoern A. Zeeb /* 1440800c9408SRobert Watson * Conditionally allow creating raw sockets in jail. 1441800c9408SRobert Watson */ 1442800c9408SRobert Watson case PRIV_NETINET_RAW: 1443800c9408SRobert Watson if (jail_allow_raw_sockets) 1444800c9408SRobert Watson return (0); 1445800c9408SRobert Watson else 1446800c9408SRobert Watson return (EPERM); 1447800c9408SRobert Watson 1448800c9408SRobert Watson /* 1449800c9408SRobert Watson * Since jail implements its own visibility limits on netstat 1450800c9408SRobert Watson * sysctls, allow getcred. This allows identd to work in 1451800c9408SRobert Watson * jail. 1452800c9408SRobert Watson */ 1453800c9408SRobert Watson case PRIV_NETINET_GETCRED: 1454800c9408SRobert Watson return (0); 1455800c9408SRobert Watson 1456800c9408SRobert Watson default: 1457800c9408SRobert Watson /* 1458800c9408SRobert Watson * In all remaining cases, deny the privilege request. This 1459800c9408SRobert Watson * includes almost all network privileges, many system 1460800c9408SRobert Watson * configuration privileges. 1461800c9408SRobert Watson */ 1462800c9408SRobert Watson return (EPERM); 1463800c9408SRobert Watson } 1464800c9408SRobert Watson } 1465800c9408SRobert Watson 1466fd7a8150SMike Barcroft static int 1467fd7a8150SMike Barcroft sysctl_jail_list(SYSCTL_HANDLER_ARGS) 1468fd7a8150SMike Barcroft { 1469fd7a8150SMike Barcroft struct xprison *xp, *sxp; 1470fd7a8150SMike Barcroft struct prison *pr; 1471413628a7SBjoern A. Zeeb char *p; 1472413628a7SBjoern A. Zeeb size_t len; 1473fd7a8150SMike Barcroft int count, error; 1474fd7a8150SMike Barcroft 14757f4704c0SPawel Jakub Dawidek if (jailed(req->td->td_ucred)) 1476679a1060SRobert Watson return (0); 1477fd7a8150SMike Barcroft 1478dc68a633SPawel Jakub Dawidek sx_slock(&allprison_lock); 1479dc68a633SPawel Jakub Dawidek if ((count = prisoncount) == 0) { 1480dc68a633SPawel Jakub Dawidek sx_sunlock(&allprison_lock); 1481fd7a8150SMike Barcroft return (0); 1482dc68a633SPawel Jakub Dawidek } 1483fd7a8150SMike Barcroft 1484413628a7SBjoern A. Zeeb len = sizeof(*xp) * count; 1485413628a7SBjoern A. Zeeb LIST_FOREACH(pr, &allprison, pr_list) { 1486413628a7SBjoern A. Zeeb #ifdef INET 1487413628a7SBjoern A. Zeeb len += pr->pr_ip4s * sizeof(struct in_addr); 1488413628a7SBjoern A. Zeeb #endif 1489413628a7SBjoern A. Zeeb #ifdef INET6 1490413628a7SBjoern A. Zeeb len += pr->pr_ip6s * sizeof(struct in6_addr); 1491413628a7SBjoern A. Zeeb #endif 1492413628a7SBjoern A. Zeeb } 1493413628a7SBjoern A. Zeeb 1494413628a7SBjoern A. Zeeb sxp = xp = malloc(len, M_TEMP, M_WAITOK | M_ZERO); 1495fd7a8150SMike Barcroft 1496fd7a8150SMike Barcroft LIST_FOREACH(pr, &allprison, pr_list) { 1497fd7a8150SMike Barcroft xp->pr_version = XPRISON_VERSION; 1498fd7a8150SMike Barcroft xp->pr_id = pr->pr_id; 1499413628a7SBjoern A. Zeeb xp->pr_state = pr->pr_state; 1500413628a7SBjoern A. Zeeb xp->pr_cpusetid = pr->pr_cpuset->cs_id; 1501b63b0c65SPawel Jakub Dawidek strlcpy(xp->pr_path, pr->pr_path, sizeof(xp->pr_path)); 1502b63b0c65SPawel Jakub Dawidek mtx_lock(&pr->pr_mtx); 1503b63b0c65SPawel Jakub Dawidek strlcpy(xp->pr_host, pr->pr_host, sizeof(xp->pr_host)); 1504413628a7SBjoern A. Zeeb strlcpy(xp->pr_name, pr->pr_name, sizeof(xp->pr_name)); 1505fd7a8150SMike Barcroft mtx_unlock(&pr->pr_mtx); 1506413628a7SBjoern A. Zeeb #ifdef INET 1507413628a7SBjoern A. Zeeb xp->pr_ip4s = pr->pr_ip4s; 1508413628a7SBjoern A. Zeeb #endif 1509413628a7SBjoern A. Zeeb #ifdef INET6 1510413628a7SBjoern A. Zeeb xp->pr_ip6s = pr->pr_ip6s; 1511413628a7SBjoern A. Zeeb #endif 1512413628a7SBjoern A. Zeeb p = (char *)(xp + 1); 1513413628a7SBjoern A. Zeeb #ifdef INET 1514413628a7SBjoern A. Zeeb if (pr->pr_ip4s > 0) { 1515413628a7SBjoern A. Zeeb bcopy(pr->pr_ip4, (struct in_addr *)p, 1516413628a7SBjoern A. Zeeb pr->pr_ip4s * sizeof(struct in_addr)); 1517413628a7SBjoern A. Zeeb p += (pr->pr_ip4s * sizeof(struct in_addr)); 1518413628a7SBjoern A. Zeeb } 1519413628a7SBjoern A. Zeeb #endif 1520413628a7SBjoern A. Zeeb #ifdef INET6 1521413628a7SBjoern A. Zeeb if (pr->pr_ip6s > 0) { 1522413628a7SBjoern A. Zeeb bcopy(pr->pr_ip6, (struct in6_addr *)p, 1523413628a7SBjoern A. Zeeb pr->pr_ip6s * sizeof(struct in6_addr)); 1524413628a7SBjoern A. Zeeb p += (pr->pr_ip6s * sizeof(struct in6_addr)); 1525413628a7SBjoern A. Zeeb } 1526413628a7SBjoern A. Zeeb #endif 1527413628a7SBjoern A. Zeeb xp = (struct xprison *)p; 1528fd7a8150SMike Barcroft } 1529dc68a633SPawel Jakub Dawidek sx_sunlock(&allprison_lock); 1530fd7a8150SMike Barcroft 1531413628a7SBjoern A. Zeeb error = SYSCTL_OUT(req, sxp, len); 1532fd7a8150SMike Barcroft free(sxp, M_TEMP); 1533fd7a8150SMike Barcroft return (error); 1534fd7a8150SMike Barcroft } 1535fd7a8150SMike Barcroft 1536f3b86a5fSEd Schouten SYSCTL_OID(_security_jail, OID_AUTO, list, 1537f3b86a5fSEd Schouten CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 0, 1538f3b86a5fSEd Schouten sysctl_jail_list, "S", "List of active jails"); 1539461167c2SPawel Jakub Dawidek 1540461167c2SPawel Jakub Dawidek static int 1541461167c2SPawel Jakub Dawidek sysctl_jail_jailed(SYSCTL_HANDLER_ARGS) 1542461167c2SPawel Jakub Dawidek { 1543461167c2SPawel Jakub Dawidek int error, injail; 1544461167c2SPawel Jakub Dawidek 1545461167c2SPawel Jakub Dawidek injail = jailed(req->td->td_ucred); 1546461167c2SPawel Jakub Dawidek error = SYSCTL_OUT(req, &injail, sizeof(injail)); 1547461167c2SPawel Jakub Dawidek 1548461167c2SPawel Jakub Dawidek return (error); 1549461167c2SPawel Jakub Dawidek } 1550f3b86a5fSEd Schouten SYSCTL_PROC(_security_jail, OID_AUTO, jailed, 1551f3b86a5fSEd Schouten CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 0, 1552f3b86a5fSEd Schouten sysctl_jail_jailed, "I", "Process in jail?"); 1553413628a7SBjoern A. Zeeb 1554413628a7SBjoern A. Zeeb #ifdef DDB 1555413628a7SBjoern A. Zeeb DB_SHOW_COMMAND(jails, db_show_jails) 1556413628a7SBjoern A. Zeeb { 1557413628a7SBjoern A. Zeeb struct prison *pr; 1558413628a7SBjoern A. Zeeb #ifdef INET 1559413628a7SBjoern A. Zeeb struct in_addr ia; 1560413628a7SBjoern A. Zeeb #endif 1561413628a7SBjoern A. Zeeb #ifdef INET6 1562413628a7SBjoern A. Zeeb char ip6buf[INET6_ADDRSTRLEN]; 1563413628a7SBjoern A. Zeeb #endif 1564413628a7SBjoern A. Zeeb const char *state; 1565413628a7SBjoern A. Zeeb #if defined(INET) || defined(INET6) 1566413628a7SBjoern A. Zeeb int i; 1567413628a7SBjoern A. Zeeb #endif 1568413628a7SBjoern A. Zeeb 1569413628a7SBjoern A. Zeeb db_printf( 1570413628a7SBjoern A. Zeeb " JID pr_ref pr_nprocs pr_ip4s pr_ip6s\n"); 1571413628a7SBjoern A. Zeeb db_printf( 1572413628a7SBjoern A. Zeeb " Hostname Path\n"); 1573413628a7SBjoern A. Zeeb db_printf( 1574413628a7SBjoern A. Zeeb " Name State\n"); 1575413628a7SBjoern A. Zeeb db_printf( 1576413628a7SBjoern A. Zeeb " Cpusetid\n"); 1577413628a7SBjoern A. Zeeb db_printf( 1578413628a7SBjoern A. Zeeb " IP Address(es)\n"); 1579413628a7SBjoern A. Zeeb LIST_FOREACH(pr, &allprison, pr_list) { 1580413628a7SBjoern A. Zeeb db_printf("%6d %6d %9d %7d %7d\n", 1581413628a7SBjoern A. Zeeb pr->pr_id, pr->pr_ref, pr->pr_nprocs, 1582413628a7SBjoern A. Zeeb pr->pr_ip4s, pr->pr_ip6s); 1583413628a7SBjoern A. Zeeb db_printf("%6s %-29.29s %.74s\n", 1584413628a7SBjoern A. Zeeb "", pr->pr_host, pr->pr_path); 15850f1fe22dSBjoern A. Zeeb if (pr->pr_state < 0 || pr->pr_state >= (int)((sizeof( 1586413628a7SBjoern A. Zeeb prison_states) / sizeof(struct prison_state)))) 1587413628a7SBjoern A. Zeeb state = "(bogus)"; 1588413628a7SBjoern A. Zeeb else 1589413628a7SBjoern A. Zeeb state = prison_states[pr->pr_state].state_name; 1590413628a7SBjoern A. Zeeb db_printf("%6s %-29.29s %.74s\n", 15910f1fe22dSBjoern A. Zeeb "", (pr->pr_name[0] != '\0') ? pr->pr_name : "", state); 1592413628a7SBjoern A. Zeeb db_printf("%6s %-6d\n", 1593413628a7SBjoern A. Zeeb "", pr->pr_cpuset->cs_id); 1594413628a7SBjoern A. Zeeb #ifdef INET 1595413628a7SBjoern A. Zeeb for (i=0; i < pr->pr_ip4s; i++) { 1596413628a7SBjoern A. Zeeb ia.s_addr = pr->pr_ip4[i].s_addr; 1597413628a7SBjoern A. Zeeb db_printf("%6s %s\n", "", inet_ntoa(ia)); 1598413628a7SBjoern A. Zeeb } 1599413628a7SBjoern A. Zeeb #endif 1600413628a7SBjoern A. Zeeb #ifdef INET6 1601413628a7SBjoern A. Zeeb for (i=0; i < pr->pr_ip6s; i++) 1602413628a7SBjoern A. Zeeb db_printf("%6s %s\n", 1603413628a7SBjoern A. Zeeb "", ip6_sprintf(ip6buf, &pr->pr_ip6[i])); 1604413628a7SBjoern A. Zeeb #endif /* INET6 */ 1605413628a7SBjoern A. Zeeb if (db_pager_quit) 1606413628a7SBjoern A. Zeeb break; 1607413628a7SBjoern A. Zeeb } 1608413628a7SBjoern A. Zeeb } 1609413628a7SBjoern A. Zeeb #endif /* DDB */ 1610