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++) { 220413628a7SBjoern A. Zeeb if (_prison_check_ip4(pr, &p->pr_ip4[i])) 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++) { 229413628a7SBjoern A. Zeeb if (_prison_check_ip6(pr, &p->pr_ip6[i])) 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; 296413628a7SBjoern A. Zeeb } 297413628a7SBjoern A. Zeeb #endif 298413628a7SBjoern A. Zeeb #ifdef INET6 299413628a7SBjoern A. Zeeb if (j->ip6s > 0) { 300413628a7SBjoern A. Zeeb ip6 = (struct in6_addr *)malloc(j->ip6s * sizeof(struct in6_addr), 301413628a7SBjoern A. Zeeb M_PRISON, M_WAITOK | M_ZERO); 302413628a7SBjoern A. Zeeb error = copyin(j->ip6, ip6, j->ip6s * sizeof(struct in6_addr)); 303413628a7SBjoern A. Zeeb if (error) 304413628a7SBjoern A. Zeeb goto e_free_ip; 305413628a7SBjoern A. Zeeb /* Sort all but the first IPv6 address. */ 306413628a7SBjoern A. Zeeb if (j->ip6s > 1) 307413628a7SBjoern A. Zeeb qsort((ip6 + 1), j->ip6s - 1, 308413628a7SBjoern A. Zeeb sizeof(struct in6_addr), qcmp_v6); 309413628a7SBjoern A. Zeeb for (i=0; i<j->ip6s; i++) { 310413628a7SBjoern A. Zeeb if (IN6_IS_ADDR_UNSPECIFIED(&ip6[i])) { 311413628a7SBjoern A. Zeeb error = EINVAL; 312413628a7SBjoern A. Zeeb goto e_free_ip; 313413628a7SBjoern A. Zeeb } 314413628a7SBjoern A. Zeeb if ((i+1) < j->ip6s && 315413628a7SBjoern A. Zeeb (IN6_ARE_ADDR_EQUAL(&ip6[0], &ip6[i+1]) || 316413628a7SBjoern A. Zeeb IN6_ARE_ADDR_EQUAL(&ip6[i], &ip6[i+1]))) { 317413628a7SBjoern A. Zeeb error = EINVAL; 318413628a7SBjoern A. Zeeb goto e_free_ip; 319413628a7SBjoern A. Zeeb } 320413628a7SBjoern A. Zeeb } 321413628a7SBjoern A. Zeeb 322413628a7SBjoern A. Zeeb j->ip6 = ip6; 323413628a7SBjoern A. Zeeb } 324413628a7SBjoern A. Zeeb #endif 325413628a7SBjoern A. Zeeb return (0); 326413628a7SBjoern A. Zeeb 327413628a7SBjoern A. Zeeb e_free_ip: 328413628a7SBjoern A. Zeeb #ifdef INET6 329413628a7SBjoern A. Zeeb free(ip6, M_PRISON); 330413628a7SBjoern A. Zeeb #endif 331413628a7SBjoern A. Zeeb #ifdef INET 332413628a7SBjoern A. Zeeb free(ip4, M_PRISON); 333413628a7SBjoern A. Zeeb #endif 334413628a7SBjoern A. Zeeb return (error); 335413628a7SBjoern A. Zeeb } 336413628a7SBjoern A. Zeeb #endif /* INET || INET6 */ 337413628a7SBjoern A. Zeeb 338413628a7SBjoern A. Zeeb static int 339413628a7SBjoern A. Zeeb jail_handle_ips(struct jail *j) 340413628a7SBjoern A. Zeeb { 341413628a7SBjoern A. Zeeb #if defined(INET) || defined(INET6) 342413628a7SBjoern A. Zeeb int error; 343413628a7SBjoern A. Zeeb #endif 344413628a7SBjoern A. Zeeb 345413628a7SBjoern A. Zeeb /* 346413628a7SBjoern A. Zeeb * Finish conversion for older versions, copyin and setup IPs. 347413628a7SBjoern A. Zeeb */ 348413628a7SBjoern A. Zeeb switch (j->version) { 349413628a7SBjoern A. Zeeb case 0: 350413628a7SBjoern A. Zeeb { 351413628a7SBjoern A. Zeeb #ifdef INET 352413628a7SBjoern A. Zeeb /* FreeBSD single IPv4 jails. */ 353413628a7SBjoern A. Zeeb struct in_addr *ip4; 354413628a7SBjoern A. Zeeb 355413628a7SBjoern A. Zeeb if (j->ip4s == INADDR_ANY || j->ip4s == INADDR_BROADCAST) 356413628a7SBjoern A. Zeeb return (EINVAL); 357413628a7SBjoern A. Zeeb ip4 = (struct in_addr *)malloc(sizeof(struct in_addr), 358413628a7SBjoern A. Zeeb M_PRISON, M_WAITOK | M_ZERO); 359413628a7SBjoern A. Zeeb 360413628a7SBjoern A. Zeeb /* 361413628a7SBjoern A. Zeeb * Jail version 0 still used HBO for the IPv4 address. 362413628a7SBjoern A. Zeeb */ 363413628a7SBjoern A. Zeeb ip4->s_addr = htonl(j->ip4s); 364413628a7SBjoern A. Zeeb j->ip4s = 1; 365413628a7SBjoern A. Zeeb j->ip4 = ip4; 366413628a7SBjoern A. Zeeb break; 367413628a7SBjoern A. Zeeb #else 368413628a7SBjoern A. Zeeb return (EINVAL); 369413628a7SBjoern A. Zeeb #endif 370413628a7SBjoern A. Zeeb } 371413628a7SBjoern A. Zeeb 372413628a7SBjoern A. Zeeb case 1: 373413628a7SBjoern A. Zeeb /* 374413628a7SBjoern A. Zeeb * Version 1 was used by multi-IPv4 jail implementations 375413628a7SBjoern A. Zeeb * that never made it into the official kernel. 376413628a7SBjoern A. Zeeb * We should never hit this here; jail() should catch it. 377413628a7SBjoern A. Zeeb */ 378413628a7SBjoern A. Zeeb return (EINVAL); 379413628a7SBjoern A. Zeeb 380413628a7SBjoern A. Zeeb case 2: /* JAIL_API_VERSION */ 381413628a7SBjoern A. Zeeb /* FreeBSD multi-IPv4/IPv6,noIP jails. */ 382413628a7SBjoern A. Zeeb #if defined(INET) || defined(INET6) 383413628a7SBjoern A. Zeeb #ifdef INET 384413628a7SBjoern A. Zeeb if (j->ip4s > jail_max_af_ips) 385413628a7SBjoern A. Zeeb return (EINVAL); 386413628a7SBjoern A. Zeeb #else 387413628a7SBjoern A. Zeeb if (j->ip4s != 0) 388413628a7SBjoern A. Zeeb return (EINVAL); 389413628a7SBjoern A. Zeeb #endif 390413628a7SBjoern A. Zeeb #ifdef INET6 391413628a7SBjoern A. Zeeb if (j->ip6s > jail_max_af_ips) 392413628a7SBjoern A. Zeeb return (EINVAL); 393413628a7SBjoern A. Zeeb #else 394413628a7SBjoern A. Zeeb if (j->ip6s != 0) 395413628a7SBjoern A. Zeeb return (EINVAL); 396413628a7SBjoern A. Zeeb #endif 397413628a7SBjoern A. Zeeb error = jail_copyin_ips(j); 398413628a7SBjoern A. Zeeb if (error) 399413628a7SBjoern A. Zeeb return (error); 400413628a7SBjoern A. Zeeb #endif 401413628a7SBjoern A. Zeeb break; 402413628a7SBjoern A. Zeeb 403413628a7SBjoern A. Zeeb default: 404413628a7SBjoern A. Zeeb /* Sci-Fi jails are not supported, sorry. */ 405413628a7SBjoern A. Zeeb return (EINVAL); 406413628a7SBjoern A. Zeeb } 407413628a7SBjoern A. Zeeb 408413628a7SBjoern A. Zeeb return (0); 409413628a7SBjoern A. Zeeb } 410413628a7SBjoern A. Zeeb 411413628a7SBjoern A. Zeeb 412116734c4SMatthew Dillon /* 4139ddb7954SMike Barcroft * struct jail_args { 4149ddb7954SMike Barcroft * struct jail *jail; 4159ddb7954SMike Barcroft * }; 416116734c4SMatthew Dillon */ 41775c13541SPoul-Henning Kamp int 4189ddb7954SMike Barcroft jail(struct thread *td, struct jail_args *uap) 41975c13541SPoul-Henning Kamp { 420413628a7SBjoern A. Zeeb uint32_t version; 421413628a7SBjoern A. Zeeb int error; 422413628a7SBjoern A. Zeeb struct jail j; 423413628a7SBjoern A. Zeeb 424413628a7SBjoern A. Zeeb error = copyin(uap->jail, &version, sizeof(uint32_t)); 425413628a7SBjoern A. Zeeb if (error) 426413628a7SBjoern A. Zeeb return (error); 427413628a7SBjoern A. Zeeb 428413628a7SBjoern A. Zeeb switch (version) { 429413628a7SBjoern A. Zeeb case 0: 430413628a7SBjoern A. Zeeb /* FreeBSD single IPv4 jails. */ 431413628a7SBjoern A. Zeeb { 432413628a7SBjoern A. Zeeb struct jail_v0 j0; 433413628a7SBjoern A. Zeeb 434413628a7SBjoern A. Zeeb bzero(&j, sizeof(struct jail)); 435413628a7SBjoern A. Zeeb error = copyin(uap->jail, &j0, sizeof(struct jail_v0)); 436413628a7SBjoern A. Zeeb if (error) 437413628a7SBjoern A. Zeeb return (error); 438413628a7SBjoern A. Zeeb j.version = j0.version; 439413628a7SBjoern A. Zeeb j.path = j0.path; 440413628a7SBjoern A. Zeeb j.hostname = j0.hostname; 441413628a7SBjoern A. Zeeb j.ip4s = j0.ip_number; 442413628a7SBjoern A. Zeeb break; 443413628a7SBjoern A. Zeeb } 444413628a7SBjoern A. Zeeb 445413628a7SBjoern A. Zeeb case 1: 446413628a7SBjoern A. Zeeb /* 447413628a7SBjoern A. Zeeb * Version 1 was used by multi-IPv4 jail implementations 448413628a7SBjoern A. Zeeb * that never made it into the official kernel. 449413628a7SBjoern A. Zeeb */ 450413628a7SBjoern A. Zeeb return (EINVAL); 451413628a7SBjoern A. Zeeb 452413628a7SBjoern A. Zeeb case 2: /* JAIL_API_VERSION */ 453413628a7SBjoern A. Zeeb /* FreeBSD multi-IPv4/IPv6,noIP jails. */ 454413628a7SBjoern A. Zeeb error = copyin(uap->jail, &j, sizeof(struct jail)); 455413628a7SBjoern A. Zeeb if (error) 456413628a7SBjoern A. Zeeb return (error); 457413628a7SBjoern A. Zeeb break; 458413628a7SBjoern A. Zeeb 459413628a7SBjoern A. Zeeb default: 460413628a7SBjoern A. Zeeb /* Sci-Fi jails are not supported, sorry. */ 461413628a7SBjoern A. Zeeb return (EINVAL); 462413628a7SBjoern A. Zeeb } 463413628a7SBjoern A. Zeeb return (kern_jail(td, &j)); 464413628a7SBjoern A. Zeeb } 465413628a7SBjoern A. Zeeb 466413628a7SBjoern A. Zeeb int 467413628a7SBjoern A. Zeeb kern_jail(struct thread *td, struct jail *j) 468413628a7SBjoern A. Zeeb { 469fd7a8150SMike Barcroft struct nameidata nd; 4702110d913SXin LI struct prison *pr, *tpr; 471fd7a8150SMike Barcroft struct jail_attach_args jaa; 4722110d913SXin LI int vfslocked, error, tryprid; 47375c13541SPoul-Henning Kamp 474413628a7SBjoern A. Zeeb KASSERT(j != NULL, ("%s: j is NULL", __func__)); 475413628a7SBjoern A. Zeeb 476413628a7SBjoern A. Zeeb /* Handle addresses - convert old structs, copyin, check IPs. */ 477413628a7SBjoern A. Zeeb error = jail_handle_ips(j); 47875c13541SPoul-Henning Kamp if (error) 479a2f2b3afSJohn Baldwin return (error); 480a2f2b3afSJohn Baldwin 481413628a7SBjoern A. Zeeb /* Allocate struct prison and fill it with life. */ 4821ede983cSDag-Erling Smørgrav pr = malloc(sizeof(*pr), M_PRISON, M_WAITOK | M_ZERO); 4836008862bSJohn Baldwin mtx_init(&pr->pr_mtx, "jail mutex", NULL, MTX_DEF); 484fd7a8150SMike Barcroft pr->pr_ref = 1; 485413628a7SBjoern A. Zeeb error = copyinstr(j->path, &pr->pr_path, sizeof(pr->pr_path), NULL); 486fd7a8150SMike Barcroft if (error) 487fd7a8150SMike Barcroft goto e_killmtx; 488453f7d53SChristian S.J. Peron NDINIT(&nd, LOOKUP, MPSAFE | FOLLOW | LOCKLEAF, UIO_SYSSPACE, 489453f7d53SChristian S.J. Peron pr->pr_path, td); 490fd7a8150SMike Barcroft error = namei(&nd); 491453f7d53SChristian S.J. Peron if (error) 492fd7a8150SMike Barcroft goto e_killmtx; 493453f7d53SChristian S.J. Peron vfslocked = NDHASGIANT(&nd); 494fd7a8150SMike Barcroft pr->pr_root = nd.ni_vp; 49522db15c0SAttilio Rao VOP_UNLOCK(nd.ni_vp, 0); 496fd7a8150SMike Barcroft NDFREE(&nd, NDF_ONLY_PNBUF); 497453f7d53SChristian S.J. Peron VFS_UNLOCK_GIANT(vfslocked); 498413628a7SBjoern A. Zeeb error = copyinstr(j->hostname, &pr->pr_host, sizeof(pr->pr_host), NULL); 49975c13541SPoul-Henning Kamp if (error) 500fd7a8150SMike Barcroft goto e_dropvnref; 501413628a7SBjoern A. Zeeb if (j->jailname != NULL) { 502413628a7SBjoern A. Zeeb error = copyinstr(j->jailname, &pr->pr_name, 503413628a7SBjoern A. Zeeb sizeof(pr->pr_name), NULL); 504413628a7SBjoern A. Zeeb if (error) 505413628a7SBjoern A. Zeeb goto e_dropvnref; 506413628a7SBjoern A. Zeeb } 507413628a7SBjoern A. Zeeb if (j->ip4s > 0) { 508413628a7SBjoern A. Zeeb pr->pr_ip4 = j->ip4; 509413628a7SBjoern A. Zeeb pr->pr_ip4s = j->ip4s; 510413628a7SBjoern A. Zeeb } 511413628a7SBjoern A. Zeeb #ifdef INET6 512413628a7SBjoern A. Zeeb if (j->ip6s > 0) { 513413628a7SBjoern A. Zeeb pr->pr_ip6 = j->ip6; 514413628a7SBjoern A. Zeeb pr->pr_ip6s = j->ip6s; 515413628a7SBjoern A. Zeeb } 516413628a7SBjoern A. Zeeb #endif 517fd7a8150SMike Barcroft pr->pr_linux = NULL; 518fd7a8150SMike Barcroft pr->pr_securelevel = securelevel; 5191ba4a712SPawel Jakub Dawidek bzero(&pr->pr_osd, sizeof(pr->pr_osd)); 520fd7a8150SMike Barcroft 521413628a7SBjoern A. Zeeb /* 522413628a7SBjoern A. Zeeb * Pre-set prison state to ALIVE upon cration. This is needed so we 523413628a7SBjoern A. Zeeb * can later attach the process to it, etc (avoiding another extra 524413628a7SBjoern A. Zeeb * state for ther process of creation, complicating things). 525413628a7SBjoern A. Zeeb */ 526413628a7SBjoern A. Zeeb pr->pr_state = PRISON_STATE_ALIVE; 527413628a7SBjoern A. Zeeb 528413628a7SBjoern A. Zeeb /* Allocate a dedicated cpuset for each jail. */ 529413628a7SBjoern A. Zeeb error = cpuset_create_root(td, &pr->pr_cpuset); 530413628a7SBjoern A. Zeeb if (error) 531413628a7SBjoern A. Zeeb goto e_dropvnref; 532413628a7SBjoern A. Zeeb 533dc68a633SPawel Jakub Dawidek sx_xlock(&allprison_lock); 534413628a7SBjoern A. Zeeb /* Make sure we cannot run into problems with ambiguous bind()ings. */ 535413628a7SBjoern A. Zeeb error = prison_check_conflicting_ips(pr); 536413628a7SBjoern A. Zeeb if (error) { 537413628a7SBjoern A. Zeeb sx_xunlock(&allprison_lock); 538413628a7SBjoern A. Zeeb goto e_dropcpuset; 539413628a7SBjoern A. Zeeb } 540413628a7SBjoern A. Zeeb 541413628a7SBjoern A. Zeeb /* Determine next pr_id and add prison to allprison list. */ 5422110d913SXin LI tryprid = lastprid + 1; 5432110d913SXin LI if (tryprid == JAIL_MAX) 5442110d913SXin LI tryprid = 1; 5452110d913SXin LI next: 5462110d913SXin LI LIST_FOREACH(tpr, &allprison, pr_list) { 5472110d913SXin LI if (tpr->pr_id == tryprid) { 5482110d913SXin LI tryprid++; 5492110d913SXin LI if (tryprid == JAIL_MAX) { 5502110d913SXin LI sx_xunlock(&allprison_lock); 5512110d913SXin LI error = EAGAIN; 552413628a7SBjoern A. Zeeb goto e_dropcpuset; 5532110d913SXin LI } 5542110d913SXin LI goto next; 5552110d913SXin LI } 5562110d913SXin LI } 5572110d913SXin LI pr->pr_id = jaa.jid = lastprid = tryprid; 558fd7a8150SMike Barcroft LIST_INSERT_HEAD(&allprison, pr, pr_list); 559fd7a8150SMike Barcroft prisoncount++; 5601ba4a712SPawel Jakub Dawidek sx_xunlock(&allprison_lock); 561fd7a8150SMike Barcroft 562fd7a8150SMike Barcroft error = jail_attach(td, &jaa); 563a2f2b3afSJohn Baldwin if (error) 564fd7a8150SMike Barcroft goto e_dropprref; 565fd7a8150SMike Barcroft mtx_lock(&pr->pr_mtx); 566fd7a8150SMike Barcroft pr->pr_ref--; 567fd7a8150SMike Barcroft mtx_unlock(&pr->pr_mtx); 568fd7a8150SMike Barcroft td->td_retval[0] = jaa.jid; 56975c13541SPoul-Henning Kamp return (0); 570fd7a8150SMike Barcroft e_dropprref: 571dc68a633SPawel Jakub Dawidek sx_xlock(&allprison_lock); 572fd7a8150SMike Barcroft LIST_REMOVE(pr, pr_list); 573fd7a8150SMike Barcroft prisoncount--; 5741ba4a712SPawel Jakub Dawidek sx_xunlock(&allprison_lock); 575413628a7SBjoern A. Zeeb e_dropcpuset: 576413628a7SBjoern A. Zeeb cpuset_rel(pr->pr_cpuset); 577fd7a8150SMike Barcroft e_dropvnref: 578453f7d53SChristian S.J. Peron vfslocked = VFS_LOCK_GIANT(pr->pr_root->v_mount); 579fd7a8150SMike Barcroft vrele(pr->pr_root); 580453f7d53SChristian S.J. Peron VFS_UNLOCK_GIANT(vfslocked); 581fd7a8150SMike Barcroft e_killmtx: 582894db7b0SMaxime Henrion mtx_destroy(&pr->pr_mtx); 5831ede983cSDag-Erling Smørgrav free(pr, M_PRISON); 584413628a7SBjoern A. Zeeb #ifdef INET6 585413628a7SBjoern A. Zeeb free(j->ip6, M_PRISON); 586413628a7SBjoern A. Zeeb #endif 587413628a7SBjoern A. Zeeb #ifdef INET 588413628a7SBjoern A. Zeeb free(j->ip4, M_PRISON); 589413628a7SBjoern A. Zeeb #endif 59075c13541SPoul-Henning Kamp return (error); 59175c13541SPoul-Henning Kamp } 59275c13541SPoul-Henning Kamp 593fd7a8150SMike Barcroft /* 5949ddb7954SMike Barcroft * struct jail_attach_args { 5959ddb7954SMike Barcroft * int jid; 5969ddb7954SMike Barcroft * }; 597fd7a8150SMike Barcroft */ 598fd7a8150SMike Barcroft int 5999ddb7954SMike Barcroft jail_attach(struct thread *td, struct jail_attach_args *uap) 600fd7a8150SMike Barcroft { 601fd7a8150SMike Barcroft struct proc *p; 602fd7a8150SMike Barcroft struct ucred *newcred, *oldcred; 603fd7a8150SMike Barcroft struct prison *pr; 604453f7d53SChristian S.J. Peron int vfslocked, error; 605fd7a8150SMike Barcroft 60657f22bd4SJacques Vidrine /* 60757f22bd4SJacques Vidrine * XXX: Note that there is a slight race here if two threads 60857f22bd4SJacques Vidrine * in the same privileged process attempt to attach to two 60957f22bd4SJacques Vidrine * different jails at the same time. It is important for 61057f22bd4SJacques Vidrine * user processes not to do this, or they might end up with 61157f22bd4SJacques Vidrine * a process root from one prison, but attached to the jail 61257f22bd4SJacques Vidrine * of another. 61357f22bd4SJacques Vidrine */ 614800c9408SRobert Watson error = priv_check(td, PRIV_JAIL_ATTACH); 61557f22bd4SJacques Vidrine if (error) 61657f22bd4SJacques Vidrine return (error); 617fd7a8150SMike Barcroft 61857f22bd4SJacques Vidrine p = td->td_proc; 619dc68a633SPawel Jakub Dawidek sx_slock(&allprison_lock); 620fd7a8150SMike Barcroft pr = prison_find(uap->jid); 621fd7a8150SMike Barcroft if (pr == NULL) { 622dc68a633SPawel Jakub Dawidek sx_sunlock(&allprison_lock); 623fd7a8150SMike Barcroft return (EINVAL); 624fd7a8150SMike Barcroft } 625413628a7SBjoern A. Zeeb 626413628a7SBjoern A. Zeeb /* 627413628a7SBjoern A. Zeeb * Do not allow a process to attach to a prison that is not 628413628a7SBjoern A. Zeeb * considered to be "ALIVE". 629413628a7SBjoern A. Zeeb */ 630413628a7SBjoern A. Zeeb if (pr->pr_state != PRISON_STATE_ALIVE) { 631413628a7SBjoern A. Zeeb mtx_unlock(&pr->pr_mtx); 632413628a7SBjoern A. Zeeb sx_sunlock(&allprison_lock); 633413628a7SBjoern A. Zeeb return (EINVAL); 634413628a7SBjoern A. Zeeb } 635fd7a8150SMike Barcroft pr->pr_ref++; 636fd7a8150SMike Barcroft mtx_unlock(&pr->pr_mtx); 637dc68a633SPawel Jakub Dawidek sx_sunlock(&allprison_lock); 638fd7a8150SMike Barcroft 639413628a7SBjoern A. Zeeb /* 640413628a7SBjoern A. Zeeb * Reparent the newly attached process to this jail. 641413628a7SBjoern A. Zeeb */ 642413628a7SBjoern A. Zeeb error = cpuset_setproc_update_set(p, pr->pr_cpuset); 643413628a7SBjoern A. Zeeb if (error) 644413628a7SBjoern A. Zeeb goto e_unref; 645413628a7SBjoern A. Zeeb 646453f7d53SChristian S.J. Peron vfslocked = VFS_LOCK_GIANT(pr->pr_root->v_mount); 647cb05b60aSAttilio Rao vn_lock(pr->pr_root, LK_EXCLUSIVE | LK_RETRY); 648fd7a8150SMike Barcroft if ((error = change_dir(pr->pr_root, td)) != 0) 649fd7a8150SMike Barcroft goto e_unlock; 650fd7a8150SMike Barcroft #ifdef MAC 65130d239bcSRobert Watson if ((error = mac_vnode_check_chroot(td->td_ucred, pr->pr_root))) 652fd7a8150SMike Barcroft goto e_unlock; 653fd7a8150SMike Barcroft #endif 65422db15c0SAttilio Rao VOP_UNLOCK(pr->pr_root, 0); 655fd7a8150SMike Barcroft change_root(pr->pr_root, td); 656453f7d53SChristian S.J. Peron VFS_UNLOCK_GIANT(vfslocked); 657fd7a8150SMike Barcroft 658fd7a8150SMike Barcroft newcred = crget(); 659fd7a8150SMike Barcroft PROC_LOCK(p); 660fd7a8150SMike Barcroft oldcred = p->p_ucred; 661fd7a8150SMike Barcroft setsugid(p); 662fd7a8150SMike Barcroft crcopy(newcred, oldcred); 66369c4ee54SJohn Baldwin newcred->cr_prison = pr; 664fd7a8150SMike Barcroft p->p_ucred = newcred; 665413628a7SBjoern A. Zeeb prison_proc_hold(pr); 666fd7a8150SMike Barcroft PROC_UNLOCK(p); 667fd7a8150SMike Barcroft crfree(oldcred); 668fd7a8150SMike Barcroft return (0); 669fd7a8150SMike Barcroft e_unlock: 67022db15c0SAttilio Rao VOP_UNLOCK(pr->pr_root, 0); 671453f7d53SChristian S.J. Peron VFS_UNLOCK_GIANT(vfslocked); 672413628a7SBjoern A. Zeeb e_unref: 673fd7a8150SMike Barcroft mtx_lock(&pr->pr_mtx); 674fd7a8150SMike Barcroft pr->pr_ref--; 675fd7a8150SMike Barcroft mtx_unlock(&pr->pr_mtx); 676fd7a8150SMike Barcroft return (error); 677fd7a8150SMike Barcroft } 678fd7a8150SMike Barcroft 679fd7a8150SMike Barcroft /* 680fd7a8150SMike Barcroft * Returns a locked prison instance, or NULL on failure. 681fd7a8150SMike Barcroft */ 68254b369c1SPawel Jakub Dawidek struct prison * 683fd7a8150SMike Barcroft prison_find(int prid) 684fd7a8150SMike Barcroft { 685fd7a8150SMike Barcroft struct prison *pr; 686fd7a8150SMike Barcroft 687dc68a633SPawel Jakub Dawidek sx_assert(&allprison_lock, SX_LOCKED); 688fd7a8150SMike Barcroft LIST_FOREACH(pr, &allprison, pr_list) { 689fd7a8150SMike Barcroft if (pr->pr_id == prid) { 690fd7a8150SMike Barcroft mtx_lock(&pr->pr_mtx); 691c2cda609SPawel Jakub Dawidek if (pr->pr_ref == 0) { 692c2cda609SPawel Jakub Dawidek mtx_unlock(&pr->pr_mtx); 693c2cda609SPawel Jakub Dawidek break; 694c2cda609SPawel Jakub Dawidek } 695fd7a8150SMike Barcroft return (pr); 696fd7a8150SMike Barcroft } 697fd7a8150SMike Barcroft } 698fd7a8150SMike Barcroft return (NULL); 699fd7a8150SMike Barcroft } 700fd7a8150SMike Barcroft 70191421ba2SRobert Watson void 7021ba4a712SPawel Jakub Dawidek prison_free_locked(struct prison *pr) 70391421ba2SRobert Watson { 70491421ba2SRobert Watson 7051ba4a712SPawel Jakub Dawidek mtx_assert(&pr->pr_mtx, MA_OWNED); 70691421ba2SRobert Watson pr->pr_ref--; 70791421ba2SRobert Watson if (pr->pr_ref == 0) { 70801137630SRobert Watson mtx_unlock(&pr->pr_mtx); 709c2cda609SPawel Jakub Dawidek TASK_INIT(&pr->pr_task, 0, prison_complete, pr); 710c2cda609SPawel Jakub Dawidek taskqueue_enqueue(taskqueue_thread, &pr->pr_task); 711c2cda609SPawel Jakub Dawidek return; 712c2cda609SPawel Jakub Dawidek } 713c2cda609SPawel Jakub Dawidek mtx_unlock(&pr->pr_mtx); 714c2cda609SPawel Jakub Dawidek } 715c2cda609SPawel Jakub Dawidek 7161ba4a712SPawel Jakub Dawidek void 7171ba4a712SPawel Jakub Dawidek prison_free(struct prison *pr) 7181ba4a712SPawel Jakub Dawidek { 7191ba4a712SPawel Jakub Dawidek 7201ba4a712SPawel Jakub Dawidek mtx_lock(&pr->pr_mtx); 7211ba4a712SPawel Jakub Dawidek prison_free_locked(pr); 7221ba4a712SPawel Jakub Dawidek } 7231ba4a712SPawel Jakub Dawidek 724c2cda609SPawel Jakub Dawidek static void 725c2cda609SPawel Jakub Dawidek prison_complete(void *context, int pending) 726c2cda609SPawel Jakub Dawidek { 727c2cda609SPawel Jakub Dawidek struct prison *pr; 728c2cda609SPawel Jakub Dawidek int vfslocked; 729c2cda609SPawel Jakub Dawidek 730c2cda609SPawel Jakub Dawidek pr = (struct prison *)context; 731c2cda609SPawel Jakub Dawidek 732c2cda609SPawel Jakub Dawidek sx_xlock(&allprison_lock); 733264de85eSPawel Jakub Dawidek LIST_REMOVE(pr, pr_list); 734fd7a8150SMike Barcroft prisoncount--; 7351ba4a712SPawel Jakub Dawidek sx_xunlock(&allprison_lock); 7361ba4a712SPawel Jakub Dawidek 737413628a7SBjoern A. Zeeb cpuset_rel(pr->pr_cpuset); 738413628a7SBjoern A. Zeeb 7391ba4a712SPawel Jakub Dawidek /* Free all OSD associated to this jail. */ 7401ba4a712SPawel Jakub Dawidek osd_jail_exit(pr); 741b3059e09SRobert Watson 742453f7d53SChristian S.J. Peron vfslocked = VFS_LOCK_GIANT(pr->pr_root->v_mount); 743b3059e09SRobert Watson vrele(pr->pr_root); 744453f7d53SChristian S.J. Peron VFS_UNLOCK_GIANT(vfslocked); 745b3059e09SRobert Watson 746b3059e09SRobert Watson mtx_destroy(&pr->pr_mtx); 7471ede983cSDag-Erling Smørgrav free(pr->pr_linux, M_PRISON); 748413628a7SBjoern A. Zeeb #ifdef INET6 749413628a7SBjoern A. Zeeb free(pr->pr_ip6, M_PRISON); 750413628a7SBjoern A. Zeeb #endif 751413628a7SBjoern A. Zeeb #ifdef INET 752413628a7SBjoern A. Zeeb free(pr->pr_ip4, M_PRISON); 753413628a7SBjoern A. Zeeb #endif 7541ede983cSDag-Erling Smørgrav free(pr, M_PRISON); 755b3059e09SRobert Watson } 756b3059e09SRobert Watson 75791421ba2SRobert Watson void 7581ba4a712SPawel Jakub Dawidek prison_hold_locked(struct prison *pr) 7591ba4a712SPawel Jakub Dawidek { 7601ba4a712SPawel Jakub Dawidek 7611ba4a712SPawel Jakub Dawidek mtx_assert(&pr->pr_mtx, MA_OWNED); 7621ba4a712SPawel Jakub Dawidek KASSERT(pr->pr_ref > 0, 7631ba4a712SPawel Jakub Dawidek ("Trying to hold dead prison (id=%d).", pr->pr_id)); 7641ba4a712SPawel Jakub Dawidek pr->pr_ref++; 7651ba4a712SPawel Jakub Dawidek } 7661ba4a712SPawel Jakub Dawidek 7671ba4a712SPawel Jakub Dawidek void 76891421ba2SRobert Watson prison_hold(struct prison *pr) 76991421ba2SRobert Watson { 77091421ba2SRobert Watson 77101137630SRobert Watson mtx_lock(&pr->pr_mtx); 7721ba4a712SPawel Jakub Dawidek prison_hold_locked(pr); 77301137630SRobert Watson mtx_unlock(&pr->pr_mtx); 77401137630SRobert Watson } 77501137630SRobert Watson 776413628a7SBjoern A. Zeeb void 777413628a7SBjoern A. Zeeb prison_proc_hold(struct prison *pr) 77801137630SRobert Watson { 77901137630SRobert Watson 780413628a7SBjoern A. Zeeb mtx_lock(&pr->pr_mtx); 781413628a7SBjoern A. Zeeb KASSERT(pr->pr_state == PRISON_STATE_ALIVE, 782413628a7SBjoern A. Zeeb ("Cannot add a process to a non-alive prison (id=%d).", pr->pr_id)); 783413628a7SBjoern A. Zeeb pr->pr_nprocs++; 784413628a7SBjoern A. Zeeb mtx_unlock(&pr->pr_mtx); 78575c13541SPoul-Henning Kamp } 78675c13541SPoul-Henning Kamp 78775c13541SPoul-Henning Kamp void 788413628a7SBjoern A. Zeeb prison_proc_free(struct prison *pr) 78975c13541SPoul-Henning Kamp { 790413628a7SBjoern A. Zeeb 791413628a7SBjoern A. Zeeb mtx_lock(&pr->pr_mtx); 792413628a7SBjoern A. Zeeb KASSERT(pr->pr_state == PRISON_STATE_ALIVE && pr->pr_nprocs > 0, 793413628a7SBjoern A. Zeeb ("Trying to kill a process in a dead prison (id=%d).", pr->pr_id)); 794413628a7SBjoern A. Zeeb pr->pr_nprocs--; 795413628a7SBjoern A. Zeeb if (pr->pr_nprocs == 0) 796413628a7SBjoern A. Zeeb pr->pr_state = PRISON_STATE_DYING; 797413628a7SBjoern A. Zeeb mtx_unlock(&pr->pr_mtx); 798413628a7SBjoern A. Zeeb } 799413628a7SBjoern A. Zeeb 800413628a7SBjoern A. Zeeb 801413628a7SBjoern A. Zeeb #ifdef INET 802413628a7SBjoern A. Zeeb /* 803413628a7SBjoern A. Zeeb * Pass back primary IPv4 address of this jail. 804413628a7SBjoern A. Zeeb * 805413628a7SBjoern A. Zeeb * If not jailed return success but do not alter the address. Caller has to 806413628a7SBjoern A. Zeeb * make sure to intialize it correctly (INADDR_ANY). 807413628a7SBjoern A. Zeeb * 808413628a7SBjoern A. Zeeb * Returns 0 on success, 1 on error. Address returned in NBO. 809413628a7SBjoern A. Zeeb */ 810413628a7SBjoern A. Zeeb int 811413628a7SBjoern A. Zeeb prison_getip4(struct ucred *cred, struct in_addr *ia) 812413628a7SBjoern A. Zeeb { 813413628a7SBjoern A. Zeeb 814413628a7SBjoern A. Zeeb KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 815413628a7SBjoern A. Zeeb KASSERT(ia != NULL, ("%s: ia is NULL", __func__)); 81675c13541SPoul-Henning Kamp 81791421ba2SRobert Watson if (!jailed(cred)) 818413628a7SBjoern A. Zeeb /* Do not change address passed in. */ 819413628a7SBjoern A. Zeeb return (0); 820413628a7SBjoern A. Zeeb 821413628a7SBjoern A. Zeeb if (cred->cr_prison->pr_ip4 == NULL) 822413628a7SBjoern A. Zeeb return (1); 823413628a7SBjoern A. Zeeb 824413628a7SBjoern A. Zeeb ia->s_addr = cred->cr_prison->pr_ip4[0].s_addr; 825413628a7SBjoern A. Zeeb return (0); 82675c13541SPoul-Henning Kamp } 827413628a7SBjoern A. Zeeb 828413628a7SBjoern A. Zeeb /* 829413628a7SBjoern A. Zeeb * Make sure our (source) address is set to something meaningful to this 830413628a7SBjoern A. Zeeb * jail. 831413628a7SBjoern A. Zeeb * 832413628a7SBjoern A. Zeeb * Returns 0 on success, 1 on error. Address passed in in NBO and returned 833413628a7SBjoern A. Zeeb * in NBO. 834413628a7SBjoern A. Zeeb */ 835413628a7SBjoern A. Zeeb int 836413628a7SBjoern A. Zeeb prison_local_ip4(struct ucred *cred, struct in_addr *ia) 837413628a7SBjoern A. Zeeb { 838413628a7SBjoern A. Zeeb struct in_addr ia0; 839413628a7SBjoern A. Zeeb 840413628a7SBjoern A. Zeeb KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 841413628a7SBjoern A. Zeeb KASSERT(ia != NULL, ("%s: ia is NULL", __func__)); 842413628a7SBjoern A. Zeeb 843413628a7SBjoern A. Zeeb if (!jailed(cred)) 844413628a7SBjoern A. Zeeb return (0); 845413628a7SBjoern A. Zeeb if (cred->cr_prison->pr_ip4 == NULL) 846413628a7SBjoern A. Zeeb return (1); 847413628a7SBjoern A. Zeeb 848413628a7SBjoern A. Zeeb ia0.s_addr = ntohl(ia->s_addr); 849413628a7SBjoern A. Zeeb if (ia0.s_addr == INADDR_LOOPBACK) { 850413628a7SBjoern A. Zeeb ia->s_addr = cred->cr_prison->pr_ip4[0].s_addr; 851413628a7SBjoern A. Zeeb return (0); 852413628a7SBjoern A. Zeeb } 853413628a7SBjoern A. Zeeb 854413628a7SBjoern A. Zeeb /* 855413628a7SBjoern A. Zeeb * In case there is only 1 IPv4 address, bind directly. 856413628a7SBjoern A. Zeeb */ 857413628a7SBjoern A. Zeeb if (ia0.s_addr == INADDR_ANY && cred->cr_prison->pr_ip4s == 1) { 858413628a7SBjoern A. Zeeb ia->s_addr = cred->cr_prison->pr_ip4[0].s_addr; 859413628a7SBjoern A. Zeeb return (0); 860413628a7SBjoern A. Zeeb } 861413628a7SBjoern A. Zeeb 862413628a7SBjoern A. Zeeb if (ia0.s_addr == INADDR_ANY || prison_check_ip4(cred, ia)) 863413628a7SBjoern A. Zeeb return (0); 864413628a7SBjoern A. Zeeb 865413628a7SBjoern A. Zeeb return (1); 866413628a7SBjoern A. Zeeb } 867413628a7SBjoern A. Zeeb 868413628a7SBjoern A. Zeeb /* 869413628a7SBjoern A. Zeeb * Rewrite destination address in case we will connect to loopback address. 870413628a7SBjoern A. Zeeb * 871413628a7SBjoern A. Zeeb * Returns 0 on success, 1 on error. Address passed in in NBO and returned 872413628a7SBjoern A. Zeeb * in NBO. 873413628a7SBjoern A. Zeeb */ 874413628a7SBjoern A. Zeeb int 875413628a7SBjoern A. Zeeb prison_remote_ip4(struct ucred *cred, struct in_addr *ia) 876413628a7SBjoern A. Zeeb { 877413628a7SBjoern A. Zeeb 878413628a7SBjoern A. Zeeb KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 879413628a7SBjoern A. Zeeb KASSERT(ia != NULL, ("%s: ia is NULL", __func__)); 880413628a7SBjoern A. Zeeb 881413628a7SBjoern A. Zeeb if (!jailed(cred)) 882413628a7SBjoern A. Zeeb return (0); 883413628a7SBjoern A. Zeeb if (cred->cr_prison->pr_ip4 == NULL) 884413628a7SBjoern A. Zeeb return (1); 885413628a7SBjoern A. Zeeb if (ntohl(ia->s_addr) == INADDR_LOOPBACK) { 886413628a7SBjoern A. Zeeb ia->s_addr = cred->cr_prison->pr_ip4[0].s_addr; 887413628a7SBjoern A. Zeeb return (0); 888413628a7SBjoern A. Zeeb } 889413628a7SBjoern A. Zeeb 890413628a7SBjoern A. Zeeb /* 891413628a7SBjoern A. Zeeb * Return success because nothing had to be changed. 892413628a7SBjoern A. Zeeb */ 893413628a7SBjoern A. Zeeb return (0); 894413628a7SBjoern A. Zeeb } 895413628a7SBjoern A. Zeeb 896413628a7SBjoern A. Zeeb /* 897413628a7SBjoern A. Zeeb * Check if given address belongs to the jail referenced by cred. 898413628a7SBjoern A. Zeeb * 899413628a7SBjoern A. Zeeb * Returns 1 if address belongs to jail, 0 if not. Address passed in in NBO. 900413628a7SBjoern A. Zeeb */ 901413628a7SBjoern A. Zeeb static int 902413628a7SBjoern A. Zeeb _prison_check_ip4(struct prison *pr, struct in_addr *ia) 903413628a7SBjoern A. Zeeb { 904413628a7SBjoern A. Zeeb int i, a, z, d; 905413628a7SBjoern A. Zeeb 906413628a7SBjoern A. Zeeb if (pr->pr_ip4 == NULL) 907413628a7SBjoern A. Zeeb return (0); 908413628a7SBjoern A. Zeeb 909413628a7SBjoern A. Zeeb /* 910413628a7SBjoern A. Zeeb * Check the primary IP. 911413628a7SBjoern A. Zeeb */ 912413628a7SBjoern A. Zeeb if (pr->pr_ip4[0].s_addr == ia->s_addr) 913413628a7SBjoern A. Zeeb return (1); 914413628a7SBjoern A. Zeeb 915413628a7SBjoern A. Zeeb /* 916413628a7SBjoern A. Zeeb * All the other IPs are sorted so we can do a binary search. 917413628a7SBjoern A. Zeeb */ 918413628a7SBjoern A. Zeeb a = 0; 919413628a7SBjoern A. Zeeb z = pr->pr_ip4s - 2; 920413628a7SBjoern A. Zeeb while (a <= z) { 921413628a7SBjoern A. Zeeb i = (a + z) / 2; 922413628a7SBjoern A. Zeeb d = qcmp_v4(&pr->pr_ip4[i+1], ia); 923413628a7SBjoern A. Zeeb if (d > 0) 924413628a7SBjoern A. Zeeb z = i - 1; 925413628a7SBjoern A. Zeeb else if (d < 0) 926413628a7SBjoern A. Zeeb a = i + 1; 927413628a7SBjoern A. Zeeb else 928413628a7SBjoern A. Zeeb return (1); 929413628a7SBjoern A. Zeeb } 930413628a7SBjoern A. Zeeb return (0); 93175c13541SPoul-Henning Kamp } 93275c13541SPoul-Henning Kamp 93375c13541SPoul-Henning Kamp int 934413628a7SBjoern A. Zeeb prison_check_ip4(struct ucred *cred, struct in_addr *ia) 935413628a7SBjoern A. Zeeb { 936413628a7SBjoern A. Zeeb 937413628a7SBjoern A. Zeeb KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 938413628a7SBjoern A. Zeeb KASSERT(ia != NULL, ("%s: ia is NULL", __func__)); 939413628a7SBjoern A. Zeeb 940413628a7SBjoern A. Zeeb if (!jailed(cred)) 941413628a7SBjoern A. Zeeb return (1); 942413628a7SBjoern A. Zeeb 943413628a7SBjoern A. Zeeb return (_prison_check_ip4(cred->cr_prison, ia)); 944413628a7SBjoern A. Zeeb } 945413628a7SBjoern A. Zeeb #endif 946413628a7SBjoern A. Zeeb 947413628a7SBjoern A. Zeeb #ifdef INET6 948413628a7SBjoern A. Zeeb /* 949413628a7SBjoern A. Zeeb * Pass back primary IPv6 address for this jail. 950413628a7SBjoern A. Zeeb * 951413628a7SBjoern A. Zeeb * If not jailed return success but do not alter the address. Caller has to 952413628a7SBjoern A. Zeeb * make sure to intialize it correctly (IN6ADDR_ANY_INIT). 953413628a7SBjoern A. Zeeb * 954413628a7SBjoern A. Zeeb * Returns 0 on success, 1 on error. 955413628a7SBjoern A. Zeeb */ 956413628a7SBjoern A. Zeeb int 957413628a7SBjoern A. Zeeb prison_getip6(struct ucred *cred, struct in6_addr *ia6) 958413628a7SBjoern A. Zeeb { 959413628a7SBjoern A. Zeeb 960413628a7SBjoern A. Zeeb KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 961413628a7SBjoern A. Zeeb KASSERT(ia6 != NULL, ("%s: ia6 is NULL", __func__)); 962413628a7SBjoern A. Zeeb 963413628a7SBjoern A. Zeeb if (!jailed(cred)) 964413628a7SBjoern A. Zeeb return (0); 965413628a7SBjoern A. Zeeb if (cred->cr_prison->pr_ip6 == NULL) 966413628a7SBjoern A. Zeeb return (1); 967413628a7SBjoern A. Zeeb bcopy(&cred->cr_prison->pr_ip6[0], ia6, sizeof(struct in6_addr)); 968413628a7SBjoern A. Zeeb return (0); 969413628a7SBjoern A. Zeeb } 970413628a7SBjoern A. Zeeb 971413628a7SBjoern A. Zeeb /* 972413628a7SBjoern A. Zeeb * Make sure our (source) address is set to something meaningful to this jail. 973413628a7SBjoern A. Zeeb * 974413628a7SBjoern A. Zeeb * v6only should be set based on (inp->inp_flags & IN6P_IPV6_V6ONLY != 0) 975413628a7SBjoern A. Zeeb * when needed while binding. 976413628a7SBjoern A. Zeeb * 977413628a7SBjoern A. Zeeb * Returns 0 on success, 1 on error. 978413628a7SBjoern A. Zeeb */ 979413628a7SBjoern A. Zeeb int 980413628a7SBjoern A. Zeeb prison_local_ip6(struct ucred *cred, struct in6_addr *ia6, int v6only) 981413628a7SBjoern A. Zeeb { 982413628a7SBjoern A. Zeeb 983413628a7SBjoern A. Zeeb KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 984413628a7SBjoern A. Zeeb KASSERT(ia6 != NULL, ("%s: ia6 is NULL", __func__)); 985413628a7SBjoern A. Zeeb 986413628a7SBjoern A. Zeeb if (!jailed(cred)) 987413628a7SBjoern A. Zeeb return (0); 988413628a7SBjoern A. Zeeb if (cred->cr_prison->pr_ip6 == NULL) 989413628a7SBjoern A. Zeeb return (1); 990413628a7SBjoern A. Zeeb if (IN6_IS_ADDR_LOOPBACK(ia6)) { 991413628a7SBjoern A. Zeeb bcopy(&cred->cr_prison->pr_ip6[0], ia6, 992413628a7SBjoern A. Zeeb sizeof(struct in6_addr)); 993413628a7SBjoern A. Zeeb return (0); 994413628a7SBjoern A. Zeeb } 995413628a7SBjoern A. Zeeb 996413628a7SBjoern A. Zeeb /* 997413628a7SBjoern A. Zeeb * In case there is only 1 IPv6 address, and v6only is true, then 998413628a7SBjoern A. Zeeb * bind directly. 999413628a7SBjoern A. Zeeb */ 1000413628a7SBjoern A. Zeeb if (v6only != 0 && IN6_IS_ADDR_UNSPECIFIED(ia6) && 1001413628a7SBjoern A. Zeeb cred->cr_prison->pr_ip6s == 1) { 1002413628a7SBjoern A. Zeeb bcopy(&cred->cr_prison->pr_ip6[0], ia6, 1003413628a7SBjoern A. Zeeb sizeof(struct in6_addr)); 1004413628a7SBjoern A. Zeeb return (0); 1005413628a7SBjoern A. Zeeb } 1006413628a7SBjoern A. Zeeb if (IN6_IS_ADDR_UNSPECIFIED(ia6) || prison_check_ip6(cred, ia6)) 1007413628a7SBjoern A. Zeeb return (0); 1008413628a7SBjoern A. Zeeb return (1); 1009413628a7SBjoern A. Zeeb } 1010413628a7SBjoern A. Zeeb 1011413628a7SBjoern A. Zeeb /* 1012413628a7SBjoern A. Zeeb * Rewrite destination address in case we will connect to loopback address. 1013413628a7SBjoern A. Zeeb * 1014413628a7SBjoern A. Zeeb * Returns 0 on success, 1 on error. 1015413628a7SBjoern A. Zeeb */ 1016413628a7SBjoern A. Zeeb int 1017413628a7SBjoern A. Zeeb prison_remote_ip6(struct ucred *cred, struct in6_addr *ia6) 1018413628a7SBjoern A. Zeeb { 1019413628a7SBjoern A. Zeeb 1020413628a7SBjoern A. Zeeb KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 1021413628a7SBjoern A. Zeeb KASSERT(ia6 != NULL, ("%s: ia6 is NULL", __func__)); 1022413628a7SBjoern A. Zeeb 1023413628a7SBjoern A. Zeeb if (!jailed(cred)) 1024413628a7SBjoern A. Zeeb return (0); 1025413628a7SBjoern A. Zeeb if (cred->cr_prison->pr_ip6 == NULL) 1026413628a7SBjoern A. Zeeb return (1); 1027413628a7SBjoern A. Zeeb if (IN6_IS_ADDR_LOOPBACK(ia6)) { 1028413628a7SBjoern A. Zeeb bcopy(&cred->cr_prison->pr_ip6[0], ia6, 1029413628a7SBjoern A. Zeeb sizeof(struct in6_addr)); 1030413628a7SBjoern A. Zeeb return (0); 1031413628a7SBjoern A. Zeeb } 1032413628a7SBjoern A. Zeeb 1033413628a7SBjoern A. Zeeb /* 1034413628a7SBjoern A. Zeeb * Return success because nothing had to be changed. 1035413628a7SBjoern A. Zeeb */ 1036413628a7SBjoern A. Zeeb return (0); 1037413628a7SBjoern A. Zeeb } 1038413628a7SBjoern A. Zeeb 1039413628a7SBjoern A. Zeeb /* 1040413628a7SBjoern A. Zeeb * Check if given address belongs to the jail referenced by cred. 1041413628a7SBjoern A. Zeeb * 1042413628a7SBjoern A. Zeeb * Returns 1 if address belongs to jail, 0 if not. 1043413628a7SBjoern A. Zeeb */ 1044413628a7SBjoern A. Zeeb static int 1045413628a7SBjoern A. Zeeb _prison_check_ip6(struct prison *pr, struct in6_addr *ia6) 1046413628a7SBjoern A. Zeeb { 1047413628a7SBjoern A. Zeeb int i, a, z, d; 1048413628a7SBjoern A. Zeeb 1049413628a7SBjoern A. Zeeb if (pr->pr_ip6 == NULL) 1050413628a7SBjoern A. Zeeb return (0); 1051413628a7SBjoern A. Zeeb 1052413628a7SBjoern A. Zeeb /* 1053413628a7SBjoern A. Zeeb * Check the primary IP. 1054413628a7SBjoern A. Zeeb */ 1055413628a7SBjoern A. Zeeb if (IN6_ARE_ADDR_EQUAL(&pr->pr_ip6[0], ia6)) 1056413628a7SBjoern A. Zeeb return (1); 1057413628a7SBjoern A. Zeeb 1058413628a7SBjoern A. Zeeb /* 1059413628a7SBjoern A. Zeeb * All the other IPs are sorted so we can do a binary search. 1060413628a7SBjoern A. Zeeb */ 1061413628a7SBjoern A. Zeeb a = 0; 1062413628a7SBjoern A. Zeeb z = pr->pr_ip6s - 2; 1063413628a7SBjoern A. Zeeb while (a <= z) { 1064413628a7SBjoern A. Zeeb i = (a + z) / 2; 1065413628a7SBjoern A. Zeeb d = qcmp_v6(&pr->pr_ip6[i+1], ia6); 1066413628a7SBjoern A. Zeeb if (d > 0) 1067413628a7SBjoern A. Zeeb z = i - 1; 1068413628a7SBjoern A. Zeeb else if (d < 0) 1069413628a7SBjoern A. Zeeb a = i + 1; 1070413628a7SBjoern A. Zeeb else 1071413628a7SBjoern A. Zeeb return (1); 1072413628a7SBjoern A. Zeeb } 1073413628a7SBjoern A. Zeeb return (0); 1074413628a7SBjoern A. Zeeb } 1075413628a7SBjoern A. Zeeb 1076413628a7SBjoern A. Zeeb int 1077413628a7SBjoern A. Zeeb prison_check_ip6(struct ucred *cred, struct in6_addr *ia6) 1078413628a7SBjoern A. Zeeb { 1079413628a7SBjoern A. Zeeb 1080413628a7SBjoern A. Zeeb KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 1081413628a7SBjoern A. Zeeb KASSERT(ia6 != NULL, ("%s: ia6 is NULL", __func__)); 1082413628a7SBjoern A. Zeeb 1083413628a7SBjoern A. Zeeb if (!jailed(cred)) 1084413628a7SBjoern A. Zeeb return (1); 1085413628a7SBjoern A. Zeeb 1086413628a7SBjoern A. Zeeb return (_prison_check_ip6(cred->cr_prison, ia6)); 1087413628a7SBjoern A. Zeeb } 1088413628a7SBjoern A. Zeeb #endif 1089413628a7SBjoern A. Zeeb 1090413628a7SBjoern A. Zeeb /* 1091413628a7SBjoern A. Zeeb * Check if given address belongs to the jail referenced by cred (wrapper to 1092413628a7SBjoern A. Zeeb * prison_check_ip[46]). 1093413628a7SBjoern A. Zeeb * 1094413628a7SBjoern A. Zeeb * Returns 1 if address belongs to jail, 0 if not. IPv4 Address passed in in 1095413628a7SBjoern A. Zeeb * NBO. 1096413628a7SBjoern A. Zeeb */ 1097413628a7SBjoern A. Zeeb int 109891421ba2SRobert Watson prison_if(struct ucred *cred, struct sockaddr *sa) 109975c13541SPoul-Henning Kamp { 1100413628a7SBjoern A. Zeeb #ifdef INET 11019ddb7954SMike Barcroft struct sockaddr_in *sai; 1102413628a7SBjoern A. Zeeb #endif 1103413628a7SBjoern A. Zeeb #ifdef INET6 1104413628a7SBjoern A. Zeeb struct sockaddr_in6 *sai6; 1105413628a7SBjoern A. Zeeb #endif 110675c13541SPoul-Henning Kamp int ok; 110775c13541SPoul-Henning Kamp 1108413628a7SBjoern A. Zeeb KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 1109413628a7SBjoern A. Zeeb KASSERT(sa != NULL, ("%s: sa is NULL", __func__)); 1110413628a7SBjoern A. Zeeb 1111413628a7SBjoern A. Zeeb ok = 0; 1112413628a7SBjoern A. Zeeb switch(sa->sa_family) 1113413628a7SBjoern A. Zeeb { 1114413628a7SBjoern A. Zeeb #ifdef INET 1115413628a7SBjoern A. Zeeb case AF_INET: 11169ddb7954SMike Barcroft sai = (struct sockaddr_in *)sa; 1117413628a7SBjoern A. Zeeb if (prison_check_ip4(cred, &sai->sin_addr)) 11187cadc266SRobert Watson ok = 1; 1119413628a7SBjoern A. Zeeb break; 1120413628a7SBjoern A. Zeeb 1121413628a7SBjoern A. Zeeb #endif 1122413628a7SBjoern A. Zeeb #ifdef INET6 1123413628a7SBjoern A. Zeeb case AF_INET6: 1124413628a7SBjoern A. Zeeb sai6 = (struct sockaddr_in6 *)sa; 1125413628a7SBjoern A. Zeeb if (prison_check_ip6(cred, (struct in6_addr *)&sai6->sin6_addr)) 112675c13541SPoul-Henning Kamp ok = 1; 1127413628a7SBjoern A. Zeeb break; 1128413628a7SBjoern A. Zeeb 1129413628a7SBjoern A. Zeeb #endif 1130413628a7SBjoern A. Zeeb default: 1131413628a7SBjoern A. Zeeb if (!jail_socket_unixiproute_only) 1132413628a7SBjoern A. Zeeb ok = 1; 1133413628a7SBjoern A. Zeeb } 113475c13541SPoul-Henning Kamp return (ok); 113575c13541SPoul-Henning Kamp } 113691421ba2SRobert Watson 113791421ba2SRobert Watson /* 113891421ba2SRobert Watson * Return 0 if jails permit p1 to frob p2, otherwise ESRCH. 113991421ba2SRobert Watson */ 114091421ba2SRobert Watson int 11419ddb7954SMike Barcroft prison_check(struct ucred *cred1, struct ucred *cred2) 114291421ba2SRobert Watson { 114391421ba2SRobert Watson 114491421ba2SRobert Watson if (jailed(cred1)) { 114591421ba2SRobert Watson if (!jailed(cred2)) 114691421ba2SRobert Watson return (ESRCH); 114791421ba2SRobert Watson if (cred2->cr_prison != cred1->cr_prison) 114891421ba2SRobert Watson return (ESRCH); 114991421ba2SRobert Watson } 115091421ba2SRobert Watson 115191421ba2SRobert Watson return (0); 115291421ba2SRobert Watson } 115391421ba2SRobert Watson 115491421ba2SRobert Watson /* 115591421ba2SRobert Watson * Return 1 if the passed credential is in a jail, otherwise 0. 115691421ba2SRobert Watson */ 115791421ba2SRobert Watson int 11589ddb7954SMike Barcroft jailed(struct ucred *cred) 115991421ba2SRobert Watson { 116091421ba2SRobert Watson 116191421ba2SRobert Watson return (cred->cr_prison != NULL); 116291421ba2SRobert Watson } 11639484d0c0SRobert Drehmel 11649484d0c0SRobert Drehmel /* 11659484d0c0SRobert Drehmel * Return the correct hostname for the passed credential. 11669484d0c0SRobert Drehmel */ 1167ad1ff099SRobert Drehmel void 11689ddb7954SMike Barcroft getcredhostname(struct ucred *cred, char *buf, size_t size) 11699484d0c0SRobert Drehmel { 11708b615593SMarko Zec INIT_VPROCG(cred->cr_vimage->v_procg); 11719484d0c0SRobert Drehmel 1172ad1ff099SRobert Drehmel if (jailed(cred)) { 1173ad1ff099SRobert Drehmel mtx_lock(&cred->cr_prison->pr_mtx); 1174e80fb434SRobert Drehmel strlcpy(buf, cred->cr_prison->pr_host, size); 1175ad1ff099SRobert Drehmel mtx_unlock(&cred->cr_prison->pr_mtx); 11764f7d1876SRobert Watson } else { 11774f7d1876SRobert Watson mtx_lock(&hostname_mtx); 1178603724d3SBjoern A. Zeeb strlcpy(buf, V_hostname, size); 11794f7d1876SRobert Watson mtx_unlock(&hostname_mtx); 11804f7d1876SRobert Watson } 11819484d0c0SRobert Drehmel } 1182fd7a8150SMike Barcroft 1183f08df373SRobert Watson /* 1184820a0de9SPawel Jakub Dawidek * Determine whether the subject represented by cred can "see" 1185820a0de9SPawel Jakub Dawidek * status of a mount point. 1186820a0de9SPawel Jakub Dawidek * Returns: 0 for permitted, ENOENT otherwise. 1187820a0de9SPawel Jakub Dawidek * XXX: This function should be called cr_canseemount() and should be 1188820a0de9SPawel Jakub Dawidek * placed in kern_prot.c. 1189f08df373SRobert Watson */ 1190f08df373SRobert Watson int 1191820a0de9SPawel Jakub Dawidek prison_canseemount(struct ucred *cred, struct mount *mp) 1192f08df373SRobert Watson { 1193820a0de9SPawel Jakub Dawidek struct prison *pr; 1194820a0de9SPawel Jakub Dawidek struct statfs *sp; 1195820a0de9SPawel Jakub Dawidek size_t len; 1196f08df373SRobert Watson 1197820a0de9SPawel Jakub Dawidek if (!jailed(cred) || jail_enforce_statfs == 0) 1198820a0de9SPawel Jakub Dawidek return (0); 1199820a0de9SPawel Jakub Dawidek pr = cred->cr_prison; 1200820a0de9SPawel Jakub Dawidek if (pr->pr_root->v_mount == mp) 1201820a0de9SPawel Jakub Dawidek return (0); 1202820a0de9SPawel Jakub Dawidek if (jail_enforce_statfs == 2) 1203820a0de9SPawel Jakub Dawidek return (ENOENT); 1204820a0de9SPawel Jakub Dawidek /* 1205820a0de9SPawel Jakub Dawidek * If jail's chroot directory is set to "/" we should be able to see 1206820a0de9SPawel Jakub Dawidek * all mount-points from inside a jail. 1207820a0de9SPawel Jakub Dawidek * This is ugly check, but this is the only situation when jail's 1208820a0de9SPawel Jakub Dawidek * directory ends with '/'. 1209820a0de9SPawel Jakub Dawidek */ 1210820a0de9SPawel Jakub Dawidek if (strcmp(pr->pr_path, "/") == 0) 1211820a0de9SPawel Jakub Dawidek return (0); 1212820a0de9SPawel Jakub Dawidek len = strlen(pr->pr_path); 1213820a0de9SPawel Jakub Dawidek sp = &mp->mnt_stat; 1214820a0de9SPawel Jakub Dawidek if (strncmp(pr->pr_path, sp->f_mntonname, len) != 0) 1215820a0de9SPawel Jakub Dawidek return (ENOENT); 1216820a0de9SPawel Jakub Dawidek /* 1217820a0de9SPawel Jakub Dawidek * Be sure that we don't have situation where jail's root directory 1218820a0de9SPawel Jakub Dawidek * is "/some/path" and mount point is "/some/pathpath". 1219820a0de9SPawel Jakub Dawidek */ 1220820a0de9SPawel Jakub Dawidek if (sp->f_mntonname[len] != '\0' && sp->f_mntonname[len] != '/') 1221820a0de9SPawel Jakub Dawidek return (ENOENT); 1222f08df373SRobert Watson return (0); 1223f08df373SRobert Watson } 1224820a0de9SPawel Jakub Dawidek 1225820a0de9SPawel Jakub Dawidek void 1226820a0de9SPawel Jakub Dawidek prison_enforce_statfs(struct ucred *cred, struct mount *mp, struct statfs *sp) 1227820a0de9SPawel Jakub Dawidek { 1228820a0de9SPawel Jakub Dawidek char jpath[MAXPATHLEN]; 1229820a0de9SPawel Jakub Dawidek struct prison *pr; 1230820a0de9SPawel Jakub Dawidek size_t len; 1231820a0de9SPawel Jakub Dawidek 1232820a0de9SPawel Jakub Dawidek if (!jailed(cred) || jail_enforce_statfs == 0) 1233820a0de9SPawel Jakub Dawidek return; 1234820a0de9SPawel Jakub Dawidek pr = cred->cr_prison; 1235820a0de9SPawel Jakub Dawidek if (prison_canseemount(cred, mp) != 0) { 1236820a0de9SPawel Jakub Dawidek bzero(sp->f_mntonname, sizeof(sp->f_mntonname)); 1237820a0de9SPawel Jakub Dawidek strlcpy(sp->f_mntonname, "[restricted]", 1238820a0de9SPawel Jakub Dawidek sizeof(sp->f_mntonname)); 1239820a0de9SPawel Jakub Dawidek return; 1240820a0de9SPawel Jakub Dawidek } 1241820a0de9SPawel Jakub Dawidek if (pr->pr_root->v_mount == mp) { 1242820a0de9SPawel Jakub Dawidek /* 1243820a0de9SPawel Jakub Dawidek * Clear current buffer data, so we are sure nothing from 1244820a0de9SPawel Jakub Dawidek * the valid path left there. 1245820a0de9SPawel Jakub Dawidek */ 1246820a0de9SPawel Jakub Dawidek bzero(sp->f_mntonname, sizeof(sp->f_mntonname)); 1247820a0de9SPawel Jakub Dawidek *sp->f_mntonname = '/'; 1248820a0de9SPawel Jakub Dawidek return; 1249820a0de9SPawel Jakub Dawidek } 1250820a0de9SPawel Jakub Dawidek /* 1251820a0de9SPawel Jakub Dawidek * If jail's chroot directory is set to "/" we should be able to see 1252820a0de9SPawel Jakub Dawidek * all mount-points from inside a jail. 1253820a0de9SPawel Jakub Dawidek */ 1254820a0de9SPawel Jakub Dawidek if (strcmp(pr->pr_path, "/") == 0) 1255820a0de9SPawel Jakub Dawidek return; 1256820a0de9SPawel Jakub Dawidek len = strlen(pr->pr_path); 1257820a0de9SPawel Jakub Dawidek strlcpy(jpath, sp->f_mntonname + len, sizeof(jpath)); 1258820a0de9SPawel Jakub Dawidek /* 1259820a0de9SPawel Jakub Dawidek * Clear current buffer data, so we are sure nothing from 1260820a0de9SPawel Jakub Dawidek * the valid path left there. 1261820a0de9SPawel Jakub Dawidek */ 1262820a0de9SPawel Jakub Dawidek bzero(sp->f_mntonname, sizeof(sp->f_mntonname)); 1263820a0de9SPawel Jakub Dawidek if (*jpath == '\0') { 1264820a0de9SPawel Jakub Dawidek /* Should never happen. */ 1265820a0de9SPawel Jakub Dawidek *sp->f_mntonname = '/'; 1266820a0de9SPawel Jakub Dawidek } else { 1267820a0de9SPawel Jakub Dawidek strlcpy(sp->f_mntonname, jpath, sizeof(sp->f_mntonname)); 1268820a0de9SPawel Jakub Dawidek } 1269f08df373SRobert Watson } 1270f08df373SRobert Watson 1271800c9408SRobert Watson /* 1272800c9408SRobert Watson * Check with permission for a specific privilege is granted within jail. We 1273800c9408SRobert Watson * have a specific list of accepted privileges; the rest are denied. 1274800c9408SRobert Watson */ 1275800c9408SRobert Watson int 1276800c9408SRobert Watson prison_priv_check(struct ucred *cred, int priv) 1277800c9408SRobert Watson { 1278800c9408SRobert Watson 1279800c9408SRobert Watson if (!jailed(cred)) 1280800c9408SRobert Watson return (0); 1281800c9408SRobert Watson 1282800c9408SRobert Watson switch (priv) { 1283800c9408SRobert Watson 1284800c9408SRobert Watson /* 1285800c9408SRobert Watson * Allow ktrace privileges for root in jail. 1286800c9408SRobert Watson */ 1287800c9408SRobert Watson case PRIV_KTRACE: 1288800c9408SRobert Watson 1289c3c1b5e6SRobert Watson #if 0 1290800c9408SRobert Watson /* 1291800c9408SRobert Watson * Allow jailed processes to configure audit identity and 1292800c9408SRobert Watson * submit audit records (login, etc). In the future we may 1293800c9408SRobert Watson * want to further refine the relationship between audit and 1294800c9408SRobert Watson * jail. 1295800c9408SRobert Watson */ 1296800c9408SRobert Watson case PRIV_AUDIT_GETAUDIT: 1297800c9408SRobert Watson case PRIV_AUDIT_SETAUDIT: 1298800c9408SRobert Watson case PRIV_AUDIT_SUBMIT: 1299c3c1b5e6SRobert Watson #endif 1300800c9408SRobert Watson 1301800c9408SRobert Watson /* 1302800c9408SRobert Watson * Allow jailed processes to manipulate process UNIX 1303800c9408SRobert Watson * credentials in any way they see fit. 1304800c9408SRobert Watson */ 1305800c9408SRobert Watson case PRIV_CRED_SETUID: 1306800c9408SRobert Watson case PRIV_CRED_SETEUID: 1307800c9408SRobert Watson case PRIV_CRED_SETGID: 1308800c9408SRobert Watson case PRIV_CRED_SETEGID: 1309800c9408SRobert Watson case PRIV_CRED_SETGROUPS: 1310800c9408SRobert Watson case PRIV_CRED_SETREUID: 1311800c9408SRobert Watson case PRIV_CRED_SETREGID: 1312800c9408SRobert Watson case PRIV_CRED_SETRESUID: 1313800c9408SRobert Watson case PRIV_CRED_SETRESGID: 1314800c9408SRobert Watson 1315800c9408SRobert Watson /* 1316800c9408SRobert Watson * Jail implements visibility constraints already, so allow 1317800c9408SRobert Watson * jailed root to override uid/gid-based constraints. 1318800c9408SRobert Watson */ 1319800c9408SRobert Watson case PRIV_SEEOTHERGIDS: 1320800c9408SRobert Watson case PRIV_SEEOTHERUIDS: 1321800c9408SRobert Watson 1322800c9408SRobert Watson /* 1323800c9408SRobert Watson * Jail implements inter-process debugging limits already, so 1324800c9408SRobert Watson * allow jailed root various debugging privileges. 1325800c9408SRobert Watson */ 1326800c9408SRobert Watson case PRIV_DEBUG_DIFFCRED: 1327800c9408SRobert Watson case PRIV_DEBUG_SUGID: 1328800c9408SRobert Watson case PRIV_DEBUG_UNPRIV: 1329800c9408SRobert Watson 1330800c9408SRobert Watson /* 1331800c9408SRobert Watson * Allow jail to set various resource limits and login 1332800c9408SRobert Watson * properties, and for now, exceed process resource limits. 1333800c9408SRobert Watson */ 1334800c9408SRobert Watson case PRIV_PROC_LIMIT: 1335800c9408SRobert Watson case PRIV_PROC_SETLOGIN: 1336800c9408SRobert Watson case PRIV_PROC_SETRLIMIT: 1337800c9408SRobert Watson 1338800c9408SRobert Watson /* 1339800c9408SRobert Watson * System V and POSIX IPC privileges are granted in jail. 1340800c9408SRobert Watson */ 1341800c9408SRobert Watson case PRIV_IPC_READ: 1342800c9408SRobert Watson case PRIV_IPC_WRITE: 1343800c9408SRobert Watson case PRIV_IPC_ADMIN: 1344800c9408SRobert Watson case PRIV_IPC_MSGSIZE: 1345800c9408SRobert Watson case PRIV_MQ_ADMIN: 1346800c9408SRobert Watson 1347800c9408SRobert Watson /* 1348800c9408SRobert Watson * Jail implements its own inter-process limits, so allow 1349800c9408SRobert Watson * root processes in jail to change scheduling on other 1350800c9408SRobert Watson * processes in the same jail. Likewise for signalling. 1351800c9408SRobert Watson */ 1352800c9408SRobert Watson case PRIV_SCHED_DIFFCRED: 1353413628a7SBjoern A. Zeeb case PRIV_SCHED_CPUSET: 1354800c9408SRobert Watson case PRIV_SIGNAL_DIFFCRED: 1355800c9408SRobert Watson case PRIV_SIGNAL_SUGID: 1356800c9408SRobert Watson 1357800c9408SRobert Watson /* 1358800c9408SRobert Watson * Allow jailed processes to write to sysctls marked as jail 1359800c9408SRobert Watson * writable. 1360800c9408SRobert Watson */ 1361800c9408SRobert Watson case PRIV_SYSCTL_WRITEJAIL: 1362800c9408SRobert Watson 1363800c9408SRobert Watson /* 1364800c9408SRobert Watson * Allow root in jail to manage a variety of quota 1365e82d0201SRobert Watson * properties. These should likely be conditional on a 1366e82d0201SRobert Watson * configuration option. 1367800c9408SRobert Watson */ 136895b091d2SRobert Watson case PRIV_VFS_GETQUOTA: 136995b091d2SRobert Watson case PRIV_VFS_SETQUOTA: 1370800c9408SRobert Watson 1371800c9408SRobert Watson /* 1372800c9408SRobert Watson * Since Jail relies on chroot() to implement file system 1373800c9408SRobert Watson * protections, grant many VFS privileges to root in jail. 1374800c9408SRobert Watson * Be careful to exclude mount-related and NFS-related 1375800c9408SRobert Watson * privileges. 1376800c9408SRobert Watson */ 1377800c9408SRobert Watson case PRIV_VFS_READ: 1378800c9408SRobert Watson case PRIV_VFS_WRITE: 1379800c9408SRobert Watson case PRIV_VFS_ADMIN: 1380800c9408SRobert Watson case PRIV_VFS_EXEC: 1381800c9408SRobert Watson case PRIV_VFS_LOOKUP: 1382800c9408SRobert Watson case PRIV_VFS_BLOCKRESERVE: /* XXXRW: Slightly surprising. */ 1383800c9408SRobert Watson case PRIV_VFS_CHFLAGS_DEV: 1384800c9408SRobert Watson case PRIV_VFS_CHOWN: 1385800c9408SRobert Watson case PRIV_VFS_CHROOT: 1386bb531912SPawel Jakub Dawidek case PRIV_VFS_RETAINSUGID: 1387800c9408SRobert Watson case PRIV_VFS_FCHROOT: 1388800c9408SRobert Watson case PRIV_VFS_LINK: 1389800c9408SRobert Watson case PRIV_VFS_SETGID: 1390e41966dcSRobert Watson case PRIV_VFS_STAT: 1391800c9408SRobert Watson case PRIV_VFS_STICKYFILE: 1392800c9408SRobert Watson return (0); 1393800c9408SRobert Watson 1394800c9408SRobert Watson /* 1395800c9408SRobert Watson * Depending on the global setting, allow privilege of 1396800c9408SRobert Watson * setting system flags. 1397800c9408SRobert Watson */ 1398800c9408SRobert Watson case PRIV_VFS_SYSFLAGS: 1399800c9408SRobert Watson if (jail_chflags_allowed) 1400800c9408SRobert Watson return (0); 1401800c9408SRobert Watson else 1402800c9408SRobert Watson return (EPERM); 1403800c9408SRobert Watson 1404800c9408SRobert Watson /* 1405f3a8d2f9SPawel Jakub Dawidek * Depending on the global setting, allow privilege of 1406f3a8d2f9SPawel Jakub Dawidek * mounting/unmounting file systems. 1407f3a8d2f9SPawel Jakub Dawidek */ 1408f3a8d2f9SPawel Jakub Dawidek case PRIV_VFS_MOUNT: 1409f3a8d2f9SPawel Jakub Dawidek case PRIV_VFS_UNMOUNT: 1410f3a8d2f9SPawel Jakub Dawidek case PRIV_VFS_MOUNT_NONUSER: 141124b0502eSPawel Jakub Dawidek case PRIV_VFS_MOUNT_OWNER: 1412f3a8d2f9SPawel Jakub Dawidek if (jail_mount_allowed) 1413f3a8d2f9SPawel Jakub Dawidek return (0); 1414f3a8d2f9SPawel Jakub Dawidek else 1415f3a8d2f9SPawel Jakub Dawidek return (EPERM); 1416f3a8d2f9SPawel Jakub Dawidek 1417f3a8d2f9SPawel Jakub Dawidek /* 14184b084056SRobert Watson * Allow jailed root to bind reserved ports and reuse in-use 14194b084056SRobert Watson * ports. 1420800c9408SRobert Watson */ 1421800c9408SRobert Watson case PRIV_NETINET_RESERVEDPORT: 14224b084056SRobert Watson case PRIV_NETINET_REUSEPORT: 1423800c9408SRobert Watson return (0); 1424800c9408SRobert Watson 1425800c9408SRobert Watson /* 142679ba3952SBjoern A. Zeeb * Allow jailed root to set certian IPv4/6 (option) headers. 142779ba3952SBjoern A. Zeeb */ 142879ba3952SBjoern A. Zeeb case PRIV_NETINET_SETHDROPTS: 142979ba3952SBjoern A. Zeeb return (0); 143079ba3952SBjoern A. Zeeb 143179ba3952SBjoern A. Zeeb /* 1432800c9408SRobert Watson * Conditionally allow creating raw sockets in jail. 1433800c9408SRobert Watson */ 1434800c9408SRobert Watson case PRIV_NETINET_RAW: 1435800c9408SRobert Watson if (jail_allow_raw_sockets) 1436800c9408SRobert Watson return (0); 1437800c9408SRobert Watson else 1438800c9408SRobert Watson return (EPERM); 1439800c9408SRobert Watson 1440800c9408SRobert Watson /* 1441800c9408SRobert Watson * Since jail implements its own visibility limits on netstat 1442800c9408SRobert Watson * sysctls, allow getcred. This allows identd to work in 1443800c9408SRobert Watson * jail. 1444800c9408SRobert Watson */ 1445800c9408SRobert Watson case PRIV_NETINET_GETCRED: 1446800c9408SRobert Watson return (0); 1447800c9408SRobert Watson 1448800c9408SRobert Watson default: 1449800c9408SRobert Watson /* 1450800c9408SRobert Watson * In all remaining cases, deny the privilege request. This 1451800c9408SRobert Watson * includes almost all network privileges, many system 1452800c9408SRobert Watson * configuration privileges. 1453800c9408SRobert Watson */ 1454800c9408SRobert Watson return (EPERM); 1455800c9408SRobert Watson } 1456800c9408SRobert Watson } 1457800c9408SRobert Watson 1458fd7a8150SMike Barcroft static int 1459fd7a8150SMike Barcroft sysctl_jail_list(SYSCTL_HANDLER_ARGS) 1460fd7a8150SMike Barcroft { 1461fd7a8150SMike Barcroft struct xprison *xp, *sxp; 1462fd7a8150SMike Barcroft struct prison *pr; 1463413628a7SBjoern A. Zeeb char *p; 1464413628a7SBjoern A. Zeeb size_t len; 1465fd7a8150SMike Barcroft int count, error; 1466fd7a8150SMike Barcroft 14677f4704c0SPawel Jakub Dawidek if (jailed(req->td->td_ucred)) 1468679a1060SRobert Watson return (0); 1469fd7a8150SMike Barcroft 1470dc68a633SPawel Jakub Dawidek sx_slock(&allprison_lock); 1471dc68a633SPawel Jakub Dawidek if ((count = prisoncount) == 0) { 1472dc68a633SPawel Jakub Dawidek sx_sunlock(&allprison_lock); 1473fd7a8150SMike Barcroft return (0); 1474dc68a633SPawel Jakub Dawidek } 1475fd7a8150SMike Barcroft 1476413628a7SBjoern A. Zeeb len = sizeof(*xp) * count; 1477413628a7SBjoern A. Zeeb LIST_FOREACH(pr, &allprison, pr_list) { 1478413628a7SBjoern A. Zeeb #ifdef INET 1479413628a7SBjoern A. Zeeb len += pr->pr_ip4s * sizeof(struct in_addr); 1480413628a7SBjoern A. Zeeb #endif 1481413628a7SBjoern A. Zeeb #ifdef INET6 1482413628a7SBjoern A. Zeeb len += pr->pr_ip6s * sizeof(struct in6_addr); 1483413628a7SBjoern A. Zeeb #endif 1484413628a7SBjoern A. Zeeb } 1485413628a7SBjoern A. Zeeb 1486413628a7SBjoern A. Zeeb sxp = xp = malloc(len, M_TEMP, M_WAITOK | M_ZERO); 1487fd7a8150SMike Barcroft 1488fd7a8150SMike Barcroft LIST_FOREACH(pr, &allprison, pr_list) { 1489fd7a8150SMike Barcroft xp->pr_version = XPRISON_VERSION; 1490fd7a8150SMike Barcroft xp->pr_id = pr->pr_id; 1491413628a7SBjoern A. Zeeb xp->pr_state = pr->pr_state; 1492413628a7SBjoern A. Zeeb xp->pr_cpusetid = pr->pr_cpuset->cs_id; 1493b63b0c65SPawel Jakub Dawidek strlcpy(xp->pr_path, pr->pr_path, sizeof(xp->pr_path)); 1494b63b0c65SPawel Jakub Dawidek mtx_lock(&pr->pr_mtx); 1495b63b0c65SPawel Jakub Dawidek strlcpy(xp->pr_host, pr->pr_host, sizeof(xp->pr_host)); 1496413628a7SBjoern A. Zeeb strlcpy(xp->pr_name, pr->pr_name, sizeof(xp->pr_name)); 1497fd7a8150SMike Barcroft mtx_unlock(&pr->pr_mtx); 1498413628a7SBjoern A. Zeeb #ifdef INET 1499413628a7SBjoern A. Zeeb xp->pr_ip4s = pr->pr_ip4s; 1500413628a7SBjoern A. Zeeb #endif 1501413628a7SBjoern A. Zeeb #ifdef INET6 1502413628a7SBjoern A. Zeeb xp->pr_ip6s = pr->pr_ip6s; 1503413628a7SBjoern A. Zeeb #endif 1504413628a7SBjoern A. Zeeb p = (char *)(xp + 1); 1505413628a7SBjoern A. Zeeb #ifdef INET 1506413628a7SBjoern A. Zeeb if (pr->pr_ip4s > 0) { 1507413628a7SBjoern A. Zeeb bcopy(pr->pr_ip4, (struct in_addr *)p, 1508413628a7SBjoern A. Zeeb pr->pr_ip4s * sizeof(struct in_addr)); 1509413628a7SBjoern A. Zeeb p += (pr->pr_ip4s * sizeof(struct in_addr)); 1510413628a7SBjoern A. Zeeb } 1511413628a7SBjoern A. Zeeb #endif 1512413628a7SBjoern A. Zeeb #ifdef INET6 1513413628a7SBjoern A. Zeeb if (pr->pr_ip6s > 0) { 1514413628a7SBjoern A. Zeeb bcopy(pr->pr_ip6, (struct in6_addr *)p, 1515413628a7SBjoern A. Zeeb pr->pr_ip6s * sizeof(struct in6_addr)); 1516413628a7SBjoern A. Zeeb p += (pr->pr_ip6s * sizeof(struct in6_addr)); 1517413628a7SBjoern A. Zeeb } 1518413628a7SBjoern A. Zeeb #endif 1519413628a7SBjoern A. Zeeb xp = (struct xprison *)p; 1520fd7a8150SMike Barcroft } 1521dc68a633SPawel Jakub Dawidek sx_sunlock(&allprison_lock); 1522fd7a8150SMike Barcroft 1523413628a7SBjoern A. Zeeb error = SYSCTL_OUT(req, sxp, len); 1524fd7a8150SMike Barcroft free(sxp, M_TEMP); 1525fd7a8150SMike Barcroft return (error); 1526fd7a8150SMike Barcroft } 1527fd7a8150SMike Barcroft 1528fd7a8150SMike Barcroft SYSCTL_OID(_security_jail, OID_AUTO, list, CTLTYPE_STRUCT | CTLFLAG_RD, 1529fd7a8150SMike Barcroft NULL, 0, sysctl_jail_list, "S", "List of active jails"); 1530461167c2SPawel Jakub Dawidek 1531461167c2SPawel Jakub Dawidek static int 1532461167c2SPawel Jakub Dawidek sysctl_jail_jailed(SYSCTL_HANDLER_ARGS) 1533461167c2SPawel Jakub Dawidek { 1534461167c2SPawel Jakub Dawidek int error, injail; 1535461167c2SPawel Jakub Dawidek 1536461167c2SPawel Jakub Dawidek injail = jailed(req->td->td_ucred); 1537461167c2SPawel Jakub Dawidek error = SYSCTL_OUT(req, &injail, sizeof(injail)); 1538461167c2SPawel Jakub Dawidek 1539461167c2SPawel Jakub Dawidek return (error); 1540461167c2SPawel Jakub Dawidek } 1541461167c2SPawel Jakub Dawidek SYSCTL_PROC(_security_jail, OID_AUTO, jailed, CTLTYPE_INT | CTLFLAG_RD, 1542461167c2SPawel Jakub Dawidek NULL, 0, sysctl_jail_jailed, "I", "Process in jail?"); 1543413628a7SBjoern A. Zeeb 1544413628a7SBjoern A. Zeeb #ifdef DDB 1545413628a7SBjoern A. Zeeb DB_SHOW_COMMAND(jails, db_show_jails) 1546413628a7SBjoern A. Zeeb { 1547413628a7SBjoern A. Zeeb struct prison *pr; 1548413628a7SBjoern A. Zeeb #ifdef INET 1549413628a7SBjoern A. Zeeb struct in_addr ia; 1550413628a7SBjoern A. Zeeb #endif 1551413628a7SBjoern A. Zeeb #ifdef INET6 1552413628a7SBjoern A. Zeeb char ip6buf[INET6_ADDRSTRLEN]; 1553413628a7SBjoern A. Zeeb #endif 1554413628a7SBjoern A. Zeeb const char *state; 1555413628a7SBjoern A. Zeeb #if defined(INET) || defined(INET6) 1556413628a7SBjoern A. Zeeb int i; 1557413628a7SBjoern A. Zeeb #endif 1558413628a7SBjoern A. Zeeb 1559413628a7SBjoern A. Zeeb db_printf( 1560413628a7SBjoern A. Zeeb " JID pr_ref pr_nprocs pr_ip4s pr_ip6s\n"); 1561413628a7SBjoern A. Zeeb db_printf( 1562413628a7SBjoern A. Zeeb " Hostname Path\n"); 1563413628a7SBjoern A. Zeeb db_printf( 1564413628a7SBjoern A. Zeeb " Name State\n"); 1565413628a7SBjoern A. Zeeb db_printf( 1566413628a7SBjoern A. Zeeb " Cpusetid\n"); 1567413628a7SBjoern A. Zeeb db_printf( 1568413628a7SBjoern A. Zeeb " IP Address(es)\n"); 1569413628a7SBjoern A. Zeeb LIST_FOREACH(pr, &allprison, pr_list) { 1570413628a7SBjoern A. Zeeb db_printf("%6d %6d %9d %7d %7d\n", 1571413628a7SBjoern A. Zeeb pr->pr_id, pr->pr_ref, pr->pr_nprocs, 1572413628a7SBjoern A. Zeeb pr->pr_ip4s, pr->pr_ip6s); 1573413628a7SBjoern A. Zeeb db_printf("%6s %-29.29s %.74s\n", 1574413628a7SBjoern A. Zeeb "", pr->pr_host, pr->pr_path); 1575413628a7SBjoern A. Zeeb if (pr->pr_state < 0 || pr->pr_state > (int)((sizeof( 1576413628a7SBjoern A. Zeeb prison_states) / sizeof(struct prison_state)))) 1577413628a7SBjoern A. Zeeb state = "(bogus)"; 1578413628a7SBjoern A. Zeeb else 1579413628a7SBjoern A. Zeeb state = prison_states[pr->pr_state].state_name; 1580413628a7SBjoern A. Zeeb db_printf("%6s %-29.29s %.74s\n", 1581413628a7SBjoern A. Zeeb "", (pr->pr_name != NULL) ? pr->pr_name : "", state); 1582413628a7SBjoern A. Zeeb db_printf("%6s %-6d\n", 1583413628a7SBjoern A. Zeeb "", pr->pr_cpuset->cs_id); 1584413628a7SBjoern A. Zeeb #ifdef INET 1585413628a7SBjoern A. Zeeb for (i=0; i < pr->pr_ip4s; i++) { 1586413628a7SBjoern A. Zeeb ia.s_addr = pr->pr_ip4[i].s_addr; 1587413628a7SBjoern A. Zeeb db_printf("%6s %s\n", "", inet_ntoa(ia)); 1588413628a7SBjoern A. Zeeb } 1589413628a7SBjoern A. Zeeb #endif 1590413628a7SBjoern A. Zeeb #ifdef INET6 1591413628a7SBjoern A. Zeeb for (i=0; i < pr->pr_ip6s; i++) 1592413628a7SBjoern A. Zeeb db_printf("%6s %s\n", 1593413628a7SBjoern A. Zeeb "", ip6_sprintf(ip6buf, &pr->pr_ip6[i])); 1594413628a7SBjoern A. Zeeb #endif /* INET6 */ 1595413628a7SBjoern A. Zeeb if (db_pager_quit) 1596413628a7SBjoern A. Zeeb break; 1597413628a7SBjoern A. Zeeb } 1598413628a7SBjoern A. Zeeb } 1599413628a7SBjoern A. Zeeb #endif /* DDB */ 1600