kern_jail.c revision 216861
1139804Simp/*- 2185435Sbz * Copyright (c) 1999 Poul-Henning Kamp. 3185435Sbz * Copyright (c) 2008 Bjoern A. Zeeb. 4191673Sjamie * Copyright (c) 2009 James Gritton. 5185435Sbz * All rights reserved. 6190466Sjamie * 7185404Sbz * Redistribution and use in source and binary forms, with or without 8185404Sbz * modification, are permitted provided that the following conditions 9185404Sbz * are met: 10185404Sbz * 1. Redistributions of source code must retain the above copyright 11185404Sbz * notice, this list of conditions and the following disclaimer. 12185404Sbz * 2. Redistributions in binary form must reproduce the above copyright 13185404Sbz * notice, this list of conditions and the following disclaimer in the 14185404Sbz * documentation and/or other materials provided with the distribution. 15185404Sbz * 16185404Sbz * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17185404Sbz * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18185404Sbz * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19185404Sbz * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20185404Sbz * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21185404Sbz * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22185404Sbz * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23185404Sbz * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24185404Sbz * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25185404Sbz * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26185404Sbz * SUCH DAMAGE. 2746197Sphk */ 2846155Sphk 29116182Sobrien#include <sys/cdefs.h> 30116182Sobrien__FBSDID("$FreeBSD: head/sys/kern/kern_jail.c 216861 2010-12-31 22:49:13Z bz $"); 31116182Sobrien 32193066Sjamie#include "opt_compat.h" 33185435Sbz#include "opt_ddb.h" 34185435Sbz#include "opt_inet.h" 35185435Sbz#include "opt_inet6.h" 36131177Spjd 3746155Sphk#include <sys/param.h> 3846155Sphk#include <sys/types.h> 3946155Sphk#include <sys/kernel.h> 4046155Sphk#include <sys/systm.h> 4146155Sphk#include <sys/errno.h> 4246155Sphk#include <sys/sysproto.h> 4346155Sphk#include <sys/malloc.h> 44192895Sjamie#include <sys/osd.h> 45164032Srwatson#include <sys/priv.h> 4646155Sphk#include <sys/proc.h> 47124882Srwatson#include <sys/taskqueue.h> 48177785Skib#include <sys/fcntl.h> 4946155Sphk#include <sys/jail.h> 5087275Srwatson#include <sys/lock.h> 5187275Srwatson#include <sys/mutex.h> 52168401Spjd#include <sys/sx.h> 53193066Sjamie#include <sys/sysent.h> 54113275Smike#include <sys/namei.h> 55147185Spjd#include <sys/mount.h> 56113275Smike#include <sys/queue.h> 5746155Sphk#include <sys/socket.h> 58113275Smike#include <sys/syscallsubr.h> 5957163Srwatson#include <sys/sysctl.h> 60113275Smike#include <sys/vnode.h> 61196019Srwatson 6246155Sphk#include <net/if.h> 63196019Srwatson#include <net/vnet.h> 64196019Srwatson 6546155Sphk#include <netinet/in.h> 66196019Srwatson 67185435Sbz#ifdef DDB 68185435Sbz#include <ddb/ddb.h> 69185435Sbz#ifdef INET6 70185435Sbz#include <netinet6/in6_var.h> 71185435Sbz#endif /* INET6 */ 72185435Sbz#endif /* DDB */ 7346155Sphk 74163606Srwatson#include <security/mac/mac_framework.h> 75163606Srwatson 76195944Sjamie#define DEFAULT_HOSTUUID "00000000-0000-0000-0000-000000000000" 77195944Sjamie 7846155SphkMALLOC_DEFINE(M_PRISON, "prison", "Prison structures"); 7946155Sphk 80202468Sbz/* Keep struct prison prison0 and some code in kern_jail_set() readable. */ 81202468Sbz#ifdef INET 82202468Sbz#ifdef INET6 83202468Sbz#define _PR_IP_SADDRSEL PR_IP4_SADDRSEL|PR_IP6_SADDRSEL 84202468Sbz#else 85202468Sbz#define _PR_IP_SADDRSEL PR_IP4_SADDRSEL 86202468Sbz#endif 87202468Sbz#else /* !INET */ 88202468Sbz#ifdef INET6 89202468Sbz#define _PR_IP_SADDRSEL PR_IP6_SADDRSEL 90202468Sbz#else 91202468Sbz#define _PR_IP_SADDRSEL 0 92202468Sbz#endif 93202468Sbz#endif 94202468Sbz 95192895Sjamie/* prison0 describes what is "real" about the system. */ 96192895Sjamiestruct prison prison0 = { 97192895Sjamie .pr_id = 0, 98192895Sjamie .pr_name = "0", 99192895Sjamie .pr_ref = 1, 100192895Sjamie .pr_uref = 1, 101192895Sjamie .pr_path = "/", 102192895Sjamie .pr_securelevel = -1, 103194762Sjamie .pr_childmax = JAIL_MAX, 104195944Sjamie .pr_hostuuid = DEFAULT_HOSTUUID, 105201145Santoine .pr_children = LIST_HEAD_INITIALIZER(prison0.pr_children), 106196176Sbz#ifdef VIMAGE 107202468Sbz .pr_flags = PR_HOST|PR_VNET|_PR_IP_SADDRSEL, 108196176Sbz#else 109202468Sbz .pr_flags = PR_HOST|_PR_IP_SADDRSEL, 110196176Sbz#endif 111192895Sjamie .pr_allow = PR_ALLOW_ALL, 112192895Sjamie}; 113192895SjamieMTX_SYSINIT(prison0, &prison0.pr_mtx, "jail mutex", MTX_DEF); 11457163Srwatson 115192895Sjamie/* allprison and lastprid are protected by allprison_lock. */ 116168401Spjdstruct sx allprison_lock; 117191673SjamieSX_SYSINIT(allprison_lock, &allprison_lock, "allprison"); 118191673Sjamiestruct prisonlist allprison = TAILQ_HEAD_INITIALIZER(allprison); 119179881Sdelphijint lastprid = 0; 120113275Smike 121191673Sjamiestatic int do_jail_attach(struct thread *td, struct prison *pr); 122190466Sjamiestatic void prison_complete(void *context, int pending); 123191673Sjamiestatic void prison_deref(struct prison *pr, int flags); 124192895Sjamiestatic char *prison_path(struct prison *pr1, struct prison *pr2); 125192895Sjamiestatic void prison_remove_one(struct prison *pr); 126185435Sbz#ifdef INET 127190466Sjamiestatic int _prison_check_ip4(struct prison *pr, struct in_addr *ia); 128192895Sjamiestatic int prison_restrict_ip4(struct prison *pr, struct in_addr *newip4); 129185435Sbz#endif 130185435Sbz#ifdef INET6 131190466Sjamiestatic int _prison_check_ip6(struct prison *pr, struct in6_addr *ia6); 132192895Sjamiestatic int prison_restrict_ip6(struct prison *pr, struct in6_addr *newip6); 133185435Sbz#endif 134113275Smike 135191673Sjamie/* Flags for prison_deref */ 136191673Sjamie#define PD_DEREF 0x01 137191673Sjamie#define PD_DEUREF 0x02 138191673Sjamie#define PD_LOCKED 0x04 139191673Sjamie#define PD_LIST_SLOCKED 0x08 140191673Sjamie#define PD_LIST_XLOCKED 0x10 141113275Smike 142192895Sjamie/* 143216861Sbz * Parameter names corresponding to PR_* flag values. Size values are for kvm 144216861Sbz * as we cannot figure out the size of a sparse array, or an array without a 145216861Sbz * terminating entry. 146192895Sjamie */ 147192895Sjamiestatic char *pr_flag_names[] = { 148192895Sjamie [0] = "persist", 149202468Sbz#ifdef INET 150202468Sbz [7] = "ip4.saddrsel", 151202468Sbz#endif 152202468Sbz#ifdef INET6 153202468Sbz [8] = "ip6.saddrsel", 154202468Sbz#endif 155192895Sjamie}; 156216861Sbzconst size_t pr_flag_names_size = sizeof(pr_flag_names); 157192895Sjamie 158192895Sjamiestatic char *pr_flag_nonames[] = { 159192895Sjamie [0] = "nopersist", 160202468Sbz#ifdef INET 161202468Sbz [7] = "ip4.nosaddrsel", 162202468Sbz#endif 163202468Sbz#ifdef INET6 164202468Sbz [8] = "ip6.nosaddrsel", 165202468Sbz#endif 166195870Sjamie}; 167216861Sbzconst size_t pr_flag_nonames_size = sizeof(pr_flag_nonames); 168195870Sjamie 169195870Sjamiestruct jailsys_flags { 170195870Sjamie const char *name; 171195870Sjamie unsigned disable; 172195870Sjamie unsigned new; 173195870Sjamie} pr_flag_jailsys[] = { 174195870Sjamie { "host", 0, PR_HOST }, 175195870Sjamie#ifdef VIMAGE 176195870Sjamie { "vnet", 0, PR_VNET }, 177195870Sjamie#endif 178192895Sjamie#ifdef INET 179195870Sjamie { "ip4", PR_IP4_USER | PR_IP4_DISABLE, PR_IP4_USER }, 180192895Sjamie#endif 181192895Sjamie#ifdef INET6 182195870Sjamie { "ip6", PR_IP6_USER | PR_IP6_DISABLE, PR_IP6_USER }, 183192895Sjamie#endif 184192895Sjamie}; 185216861Sbzconst size_t pr_flag_jailsys_size = sizeof(pr_flag_jailsys); 186192895Sjamie 187192895Sjamiestatic char *pr_allow_names[] = { 188192895Sjamie "allow.set_hostname", 189192895Sjamie "allow.sysvipc", 190192895Sjamie "allow.raw_sockets", 191192895Sjamie "allow.chflags", 192192895Sjamie "allow.mount", 193192895Sjamie "allow.quotas", 194192895Sjamie "allow.socket_af", 195192895Sjamie}; 196216861Sbzconst size_t pr_allow_names_size = sizeof(pr_allow_names); 197192895Sjamie 198192895Sjamiestatic char *pr_allow_nonames[] = { 199192895Sjamie "allow.noset_hostname", 200192895Sjamie "allow.nosysvipc", 201192895Sjamie "allow.noraw_sockets", 202192895Sjamie "allow.nochflags", 203192895Sjamie "allow.nomount", 204192895Sjamie "allow.noquotas", 205192895Sjamie "allow.nosocket_af", 206192895Sjamie}; 207216861Sbzconst size_t pr_allow_nonames_size = sizeof(pr_allow_nonames); 208192895Sjamie 209196002Sjamie#define JAIL_DEFAULT_ALLOW PR_ALLOW_SET_HOSTNAME 210196002Sjamie#define JAIL_DEFAULT_ENFORCE_STATFS 2 211192895Sjamiestatic unsigned jail_default_allow = JAIL_DEFAULT_ALLOW; 212196002Sjamiestatic int jail_default_enforce_statfs = JAIL_DEFAULT_ENFORCE_STATFS; 213192895Sjamie#if defined(INET) || defined(INET6) 214193865Sjamiestatic unsigned jail_max_af_ips = 255; 215192895Sjamie#endif 216192895Sjamie 217192895Sjamie#ifdef INET 218185435Sbzstatic int 219185435Sbzqcmp_v4(const void *ip1, const void *ip2) 220185435Sbz{ 221185435Sbz in_addr_t iaa, iab; 222185435Sbz 223185435Sbz /* 224185435Sbz * We need to compare in HBO here to get the list sorted as expected 225185435Sbz * by the result of the code. Sorting NBO addresses gives you 226185435Sbz * interesting results. If you do not understand, do not try. 227185435Sbz */ 228185435Sbz iaa = ntohl(((const struct in_addr *)ip1)->s_addr); 229185435Sbz iab = ntohl(((const struct in_addr *)ip2)->s_addr); 230185435Sbz 231185435Sbz /* 232185435Sbz * Do not simply return the difference of the two numbers, the int is 233185435Sbz * not wide enough. 234185435Sbz */ 235185435Sbz if (iaa > iab) 236185435Sbz return (1); 237185435Sbz else if (iaa < iab) 238185435Sbz return (-1); 239185435Sbz else 240185435Sbz return (0); 241185435Sbz} 242185435Sbz#endif 243185435Sbz 244185435Sbz#ifdef INET6 245185435Sbzstatic int 246185435Sbzqcmp_v6(const void *ip1, const void *ip2) 247185435Sbz{ 248185435Sbz const struct in6_addr *ia6a, *ia6b; 249185435Sbz int i, rc; 250185435Sbz 251185435Sbz ia6a = (const struct in6_addr *)ip1; 252185435Sbz ia6b = (const struct in6_addr *)ip2; 253185435Sbz 254185435Sbz rc = 0; 255190466Sjamie for (i = 0; rc == 0 && i < sizeof(struct in6_addr); i++) { 256185435Sbz if (ia6a->s6_addr[i] > ia6b->s6_addr[i]) 257185435Sbz rc = 1; 258185435Sbz else if (ia6a->s6_addr[i] < ia6b->s6_addr[i]) 259185435Sbz rc = -1; 260185435Sbz } 261185435Sbz return (rc); 262185435Sbz} 263185435Sbz#endif 264185435Sbz 265191673Sjamie/* 266191673Sjamie * struct jail_args { 267191673Sjamie * struct jail *jail; 268191673Sjamie * }; 269191673Sjamie */ 270191673Sjamieint 271191673Sjamiejail(struct thread *td, struct jail_args *uap) 272185435Sbz{ 273191673Sjamie uint32_t version; 274191673Sjamie int error; 275192895Sjamie struct jail j; 276185435Sbz 277191673Sjamie error = copyin(uap->jail, &version, sizeof(uint32_t)); 278191673Sjamie if (error) 279191673Sjamie return (error); 280185435Sbz 281191673Sjamie switch (version) { 282191673Sjamie case 0: 283191673Sjamie { 284191673Sjamie struct jail_v0 j0; 285185435Sbz 286192895Sjamie /* FreeBSD single IPv4 jails. */ 287192895Sjamie bzero(&j, sizeof(struct jail)); 288191673Sjamie error = copyin(uap->jail, &j0, sizeof(struct jail_v0)); 289191673Sjamie if (error) 290191673Sjamie return (error); 291192895Sjamie j.version = j0.version; 292192895Sjamie j.path = j0.path; 293192895Sjamie j.hostname = j0.hostname; 294192895Sjamie j.ip4s = j0.ip_number; 295191673Sjamie break; 296191673Sjamie } 297191673Sjamie 298191673Sjamie case 1: 299185435Sbz /* 300191673Sjamie * Version 1 was used by multi-IPv4 jail implementations 301191673Sjamie * that never made it into the official kernel. 302185435Sbz */ 303191673Sjamie return (EINVAL); 304185435Sbz 305191673Sjamie case 2: /* JAIL_API_VERSION */ 306191673Sjamie /* FreeBSD multi-IPv4/IPv6,noIP jails. */ 307191673Sjamie error = copyin(uap->jail, &j, sizeof(struct jail)); 308191673Sjamie if (error) 309191673Sjamie return (error); 310192895Sjamie break; 311192895Sjamie 312192895Sjamie default: 313192895Sjamie /* Sci-Fi jails are not supported, sorry. */ 314192895Sjamie return (EINVAL); 315192895Sjamie } 316192895Sjamie return (kern_jail(td, &j)); 317192895Sjamie} 318192895Sjamie 319192895Sjamieint 320192895Sjamiekern_jail(struct thread *td, struct jail *j) 321192895Sjamie{ 322193865Sjamie struct iovec optiov[2 * (4 323193865Sjamie + sizeof(pr_allow_names) / sizeof(pr_allow_names[0]) 324193865Sjamie#ifdef INET 325193865Sjamie + 1 326193865Sjamie#endif 327193865Sjamie#ifdef INET6 328193865Sjamie + 1 329193865Sjamie#endif 330193865Sjamie )]; 331192895Sjamie struct uio opt; 332192895Sjamie char *u_path, *u_hostname, *u_name; 333185435Sbz#ifdef INET 334193865Sjamie uint32_t ip4s; 335192895Sjamie struct in_addr *u_ip4; 336192895Sjamie#endif 337192895Sjamie#ifdef INET6 338192895Sjamie struct in6_addr *u_ip6; 339192895Sjamie#endif 340192895Sjamie size_t tmplen; 341192895Sjamie int error, enforce_statfs, fi; 342192895Sjamie 343192895Sjamie bzero(&optiov, sizeof(optiov)); 344192895Sjamie opt.uio_iov = optiov; 345192895Sjamie opt.uio_iovcnt = 0; 346192895Sjamie opt.uio_offset = -1; 347192895Sjamie opt.uio_resid = -1; 348192895Sjamie opt.uio_segflg = UIO_SYSSPACE; 349192895Sjamie opt.uio_rw = UIO_READ; 350192895Sjamie opt.uio_td = td; 351192895Sjamie 352192895Sjamie /* Set permissions for top-level jails from sysctls. */ 353192895Sjamie if (!jailed(td->td_ucred)) { 354192895Sjamie for (fi = 0; fi < sizeof(pr_allow_names) / 355192895Sjamie sizeof(pr_allow_names[0]); fi++) { 356192895Sjamie optiov[opt.uio_iovcnt].iov_base = 357192895Sjamie (jail_default_allow & (1 << fi)) 358192895Sjamie ? pr_allow_names[fi] : pr_allow_nonames[fi]; 359192895Sjamie optiov[opt.uio_iovcnt].iov_len = 360192895Sjamie strlen(optiov[opt.uio_iovcnt].iov_base) + 1; 361192895Sjamie opt.uio_iovcnt += 2; 362192895Sjamie } 363192895Sjamie optiov[opt.uio_iovcnt].iov_base = "enforce_statfs"; 364192895Sjamie optiov[opt.uio_iovcnt].iov_len = sizeof("enforce_statfs"); 365192895Sjamie opt.uio_iovcnt++; 366192895Sjamie enforce_statfs = jail_default_enforce_statfs; 367192895Sjamie optiov[opt.uio_iovcnt].iov_base = &enforce_statfs; 368192895Sjamie optiov[opt.uio_iovcnt].iov_len = sizeof(enforce_statfs); 369192895Sjamie opt.uio_iovcnt++; 370192895Sjamie } 371192895Sjamie 372192895Sjamie tmplen = MAXPATHLEN + MAXHOSTNAMELEN + MAXHOSTNAMELEN; 373192895Sjamie#ifdef INET 374192895Sjamie ip4s = (j->version == 0) ? 1 : j->ip4s; 375192895Sjamie if (ip4s > jail_max_af_ips) 376192895Sjamie return (EINVAL); 377192895Sjamie tmplen += ip4s * sizeof(struct in_addr); 378191673Sjamie#else 379192895Sjamie if (j->ip4s > 0) 380192895Sjamie return (EINVAL); 381191673Sjamie#endif 382191673Sjamie#ifdef INET6 383192895Sjamie if (j->ip6s > jail_max_af_ips) 384192895Sjamie return (EINVAL); 385192895Sjamie tmplen += j->ip6s * sizeof(struct in6_addr); 386191673Sjamie#else 387192895Sjamie if (j->ip6s > 0) 388192895Sjamie return (EINVAL); 389191673Sjamie#endif 390192895Sjamie u_path = malloc(tmplen, M_TEMP, M_WAITOK); 391192895Sjamie u_hostname = u_path + MAXPATHLEN; 392192895Sjamie u_name = u_hostname + MAXHOSTNAMELEN; 393191673Sjamie#ifdef INET 394192895Sjamie u_ip4 = (struct in_addr *)(u_name + MAXHOSTNAMELEN); 395191673Sjamie#endif 396191673Sjamie#ifdef INET6 397191673Sjamie#ifdef INET 398192895Sjamie u_ip6 = (struct in6_addr *)(u_ip4 + ip4s); 399191673Sjamie#else 400192895Sjamie u_ip6 = (struct in6_addr *)(u_name + MAXHOSTNAMELEN); 401191673Sjamie#endif 402191673Sjamie#endif 403192895Sjamie optiov[opt.uio_iovcnt].iov_base = "path"; 404192895Sjamie optiov[opt.uio_iovcnt].iov_len = sizeof("path"); 405192895Sjamie opt.uio_iovcnt++; 406192895Sjamie optiov[opt.uio_iovcnt].iov_base = u_path; 407192895Sjamie error = copyinstr(j->path, u_path, MAXPATHLEN, 408192895Sjamie &optiov[opt.uio_iovcnt].iov_len); 409192895Sjamie if (error) { 410192895Sjamie free(u_path, M_TEMP); 411192895Sjamie return (error); 412192895Sjamie } 413192895Sjamie opt.uio_iovcnt++; 414192895Sjamie optiov[opt.uio_iovcnt].iov_base = "host.hostname"; 415192895Sjamie optiov[opt.uio_iovcnt].iov_len = sizeof("host.hostname"); 416192895Sjamie opt.uio_iovcnt++; 417192895Sjamie optiov[opt.uio_iovcnt].iov_base = u_hostname; 418192895Sjamie error = copyinstr(j->hostname, u_hostname, MAXHOSTNAMELEN, 419192895Sjamie &optiov[opt.uio_iovcnt].iov_len); 420192895Sjamie if (error) { 421192895Sjamie free(u_path, M_TEMP); 422192895Sjamie return (error); 423192895Sjamie } 424192895Sjamie opt.uio_iovcnt++; 425192895Sjamie if (j->jailname != NULL) { 426192895Sjamie optiov[opt.uio_iovcnt].iov_base = "name"; 427192895Sjamie optiov[opt.uio_iovcnt].iov_len = sizeof("name"); 428192895Sjamie opt.uio_iovcnt++; 429192895Sjamie optiov[opt.uio_iovcnt].iov_base = u_name; 430192895Sjamie error = copyinstr(j->jailname, u_name, MAXHOSTNAMELEN, 431192895Sjamie &optiov[opt.uio_iovcnt].iov_len); 432191673Sjamie if (error) { 433191673Sjamie free(u_path, M_TEMP); 434191673Sjamie return (error); 435191673Sjamie } 436192895Sjamie opt.uio_iovcnt++; 437192895Sjamie } 438191673Sjamie#ifdef INET 439192895Sjamie optiov[opt.uio_iovcnt].iov_base = "ip4.addr"; 440192895Sjamie optiov[opt.uio_iovcnt].iov_len = sizeof("ip4.addr"); 441192895Sjamie opt.uio_iovcnt++; 442192895Sjamie optiov[opt.uio_iovcnt].iov_base = u_ip4; 443192895Sjamie optiov[opt.uio_iovcnt].iov_len = ip4s * sizeof(struct in_addr); 444192895Sjamie if (j->version == 0) 445192895Sjamie u_ip4->s_addr = j->ip4s; 446192895Sjamie else { 447192895Sjamie error = copyin(j->ip4, u_ip4, optiov[opt.uio_iovcnt].iov_len); 448191673Sjamie if (error) { 449191673Sjamie free(u_path, M_TEMP); 450191673Sjamie return (error); 451191673Sjamie } 452192895Sjamie } 453192895Sjamie opt.uio_iovcnt++; 454185435Sbz#endif 455185435Sbz#ifdef INET6 456192895Sjamie optiov[opt.uio_iovcnt].iov_base = "ip6.addr"; 457192895Sjamie optiov[opt.uio_iovcnt].iov_len = sizeof("ip6.addr"); 458192895Sjamie opt.uio_iovcnt++; 459192895Sjamie optiov[opt.uio_iovcnt].iov_base = u_ip6; 460192895Sjamie optiov[opt.uio_iovcnt].iov_len = j->ip6s * sizeof(struct in6_addr); 461192895Sjamie error = copyin(j->ip6, u_ip6, optiov[opt.uio_iovcnt].iov_len); 462192895Sjamie if (error) { 463192895Sjamie free(u_path, M_TEMP); 464192895Sjamie return (error); 465192895Sjamie } 466192895Sjamie opt.uio_iovcnt++; 467185435Sbz#endif 468192895Sjamie KASSERT(opt.uio_iovcnt <= sizeof(optiov) / sizeof(optiov[0]), 469192895Sjamie ("kern_jail: too many iovecs (%d)", opt.uio_iovcnt)); 470191673Sjamie error = kern_jail_set(td, &opt, JAIL_CREATE | JAIL_ATTACH); 471191673Sjamie free(u_path, M_TEMP); 472191673Sjamie return (error); 473185435Sbz} 474185435Sbz 475192895Sjamie 476191673Sjamie/* 477191673Sjamie * struct jail_set_args { 478191673Sjamie * struct iovec *iovp; 479191673Sjamie * unsigned int iovcnt; 480191673Sjamie * int flags; 481191673Sjamie * }; 482191673Sjamie */ 483191673Sjamieint 484191673Sjamiejail_set(struct thread *td, struct jail_set_args *uap) 485185435Sbz{ 486191673Sjamie struct uio *auio; 487191673Sjamie int error; 488191673Sjamie 489191673Sjamie /* Check that we have an even number of iovecs. */ 490191673Sjamie if (uap->iovcnt & 1) 491191673Sjamie return (EINVAL); 492191673Sjamie 493191673Sjamie error = copyinuio(uap->iovp, uap->iovcnt, &auio); 494191673Sjamie if (error) 495191673Sjamie return (error); 496191673Sjamie error = kern_jail_set(td, auio, uap->flags); 497191673Sjamie free(auio, M_IOV); 498191673Sjamie return (error); 499191673Sjamie} 500191673Sjamie 501191673Sjamieint 502191673Sjamiekern_jail_set(struct thread *td, struct uio *optuio, int flags) 503191673Sjamie{ 504191673Sjamie struct nameidata nd; 505185435Sbz#ifdef INET 506190466Sjamie struct in_addr *ip4; 507185435Sbz#endif 508185435Sbz#ifdef INET6 509185435Sbz struct in6_addr *ip6; 510185435Sbz#endif 511191673Sjamie struct vfsopt *opt; 512191673Sjamie struct vfsoptlist *opts; 513196135Sbz struct prison *pr, *deadpr, *mypr, *ppr, *tpr; 514191673Sjamie struct vnode *root; 515196835Sjamie char *domain, *errmsg, *host, *name, *namelc, *p, *path, *uuid; 516192895Sjamie#if defined(INET) || defined(INET6) 517196135Sbz struct prison *tppr; 518191673Sjamie void *op; 519192895Sjamie#endif 520193066Sjamie unsigned long hid; 521192895Sjamie size_t namelen, onamelen; 522192895Sjamie int created, cuflags, descend, enforce, error, errmsg_len, errmsg_pos; 523195870Sjamie int gotchildmax, gotenforce, gothid, gotslevel; 524195870Sjamie int fi, jid, jsys, len, level; 525194762Sjamie int childmax, slevel, vfslocked; 526191673Sjamie#if defined(INET) || defined(INET6) 527192895Sjamie int ii, ij; 528191673Sjamie#endif 529191673Sjamie#ifdef INET 530195974Sjamie int ip4s, redo_ip4; 531191673Sjamie#endif 532191673Sjamie#ifdef INET6 533195974Sjamie int ip6s, redo_ip6; 534191673Sjamie#endif 535191673Sjamie unsigned pr_flags, ch_flags; 536192895Sjamie unsigned pr_allow, ch_allow, tallow; 537191673Sjamie char numbuf[12]; 538185435Sbz 539191673Sjamie error = priv_check(td, PRIV_JAIL_SET); 540191673Sjamie if (!error && (flags & JAIL_ATTACH)) 541191673Sjamie error = priv_check(td, PRIV_JAIL_ATTACH); 542191673Sjamie if (error) 543191673Sjamie return (error); 544192895Sjamie mypr = ppr = td->td_ucred->cr_prison; 545194762Sjamie if ((flags & JAIL_CREATE) && mypr->pr_childmax == 0) 546192895Sjamie return (EPERM); 547191673Sjamie if (flags & ~JAIL_SET_MASK) 548191673Sjamie return (EINVAL); 549191673Sjamie 550185435Sbz /* 551191673Sjamie * Check all the parameters before committing to anything. Not all 552191673Sjamie * errors can be caught early, but we may as well try. Also, this 553191673Sjamie * takes care of some expensive stuff (path lookup) before getting 554191673Sjamie * the allprison lock. 555185435Sbz * 556191673Sjamie * XXX Jails are not filesystems, and jail parameters are not mount 557191673Sjamie * options. But it makes more sense to re-use the vfsopt code 558191673Sjamie * than duplicate it under a different name. 559185435Sbz */ 560191673Sjamie error = vfs_buildopts(optuio, &opts); 561191673Sjamie if (error) 562191673Sjamie return (error); 563185435Sbz#ifdef INET 564185435Sbz ip4 = NULL; 565185435Sbz#endif 566185435Sbz#ifdef INET6 567185435Sbz ip6 = NULL; 568185435Sbz#endif 569191673Sjamie 570191673Sjamie error = vfs_copyopt(opts, "jid", &jid, sizeof(jid)); 571191673Sjamie if (error == ENOENT) 572191673Sjamie jid = 0; 573191673Sjamie else if (error != 0) 574191673Sjamie goto done_free; 575191673Sjamie 576191673Sjamie error = vfs_copyopt(opts, "securelevel", &slevel, sizeof(slevel)); 577191673Sjamie if (error == ENOENT) 578191673Sjamie gotslevel = 0; 579191673Sjamie else if (error != 0) 580191673Sjamie goto done_free; 581191673Sjamie else 582191673Sjamie gotslevel = 1; 583191673Sjamie 584194762Sjamie error = 585194762Sjamie vfs_copyopt(opts, "children.max", &childmax, sizeof(childmax)); 586194762Sjamie if (error == ENOENT) 587194762Sjamie gotchildmax = 0; 588194762Sjamie else if (error != 0) 589194762Sjamie goto done_free; 590194762Sjamie else 591194762Sjamie gotchildmax = 1; 592194762Sjamie 593192895Sjamie error = vfs_copyopt(opts, "enforce_statfs", &enforce, sizeof(enforce)); 594212436Sjamie if (error == ENOENT) 595212436Sjamie gotenforce = 0; 596212436Sjamie else if (error != 0) 597192895Sjamie goto done_free; 598212436Sjamie else if (enforce < 0 || enforce > 2) { 599212436Sjamie error = EINVAL; 600212436Sjamie goto done_free; 601212436Sjamie } else 602212436Sjamie gotenforce = 1; 603192895Sjamie 604191673Sjamie pr_flags = ch_flags = 0; 605192895Sjamie for (fi = 0; fi < sizeof(pr_flag_names) / sizeof(pr_flag_names[0]); 606192895Sjamie fi++) { 607192895Sjamie if (pr_flag_names[fi] == NULL) 608192895Sjamie continue; 609192895Sjamie vfs_flagopt(opts, pr_flag_names[fi], &pr_flags, 1 << fi); 610192895Sjamie vfs_flagopt(opts, pr_flag_nonames[fi], &ch_flags, 1 << fi); 611192895Sjamie } 612191673Sjamie ch_flags |= pr_flags; 613195870Sjamie for (fi = 0; fi < sizeof(pr_flag_jailsys) / sizeof(pr_flag_jailsys[0]); 614195870Sjamie fi++) { 615195870Sjamie error = vfs_copyopt(opts, pr_flag_jailsys[fi].name, &jsys, 616195870Sjamie sizeof(jsys)); 617195870Sjamie if (error == ENOENT) 618195870Sjamie continue; 619195870Sjamie if (error != 0) 620195870Sjamie goto done_free; 621195870Sjamie switch (jsys) { 622195870Sjamie case JAIL_SYS_DISABLE: 623195870Sjamie if (!pr_flag_jailsys[fi].disable) { 624195870Sjamie error = EINVAL; 625195870Sjamie goto done_free; 626195870Sjamie } 627195870Sjamie pr_flags |= pr_flag_jailsys[fi].disable; 628195870Sjamie break; 629195870Sjamie case JAIL_SYS_NEW: 630195870Sjamie pr_flags |= pr_flag_jailsys[fi].new; 631195870Sjamie break; 632195870Sjamie case JAIL_SYS_INHERIT: 633195870Sjamie break; 634195870Sjamie default: 635195870Sjamie error = EINVAL; 636195870Sjamie goto done_free; 637195870Sjamie } 638195870Sjamie ch_flags |= 639195870Sjamie pr_flag_jailsys[fi].new | pr_flag_jailsys[fi].disable; 640195870Sjamie } 641211085Sjamie if ((flags & (JAIL_CREATE | JAIL_UPDATE | JAIL_ATTACH)) == JAIL_CREATE 642211085Sjamie && !(pr_flags & PR_PERSIST)) { 643211085Sjamie error = EINVAL; 644211085Sjamie vfs_opterror(opts, "new jail must persist or attach"); 645211085Sjamie goto done_errmsg; 646211085Sjamie } 647194251Sjamie#ifdef VIMAGE 648194251Sjamie if ((flags & JAIL_UPDATE) && (ch_flags & PR_VNET)) { 649194251Sjamie error = EINVAL; 650194251Sjamie vfs_opterror(opts, "vnet cannot be changed after creation"); 651194251Sjamie goto done_errmsg; 652194251Sjamie } 653194251Sjamie#endif 654195974Sjamie#ifdef INET 655195974Sjamie if ((flags & JAIL_UPDATE) && (ch_flags & PR_IP4_USER)) { 656195974Sjamie error = EINVAL; 657195974Sjamie vfs_opterror(opts, "ip4 cannot be changed after creation"); 658195974Sjamie goto done_errmsg; 659195974Sjamie } 660195974Sjamie#endif 661195974Sjamie#ifdef INET6 662195974Sjamie if ((flags & JAIL_UPDATE) && (ch_flags & PR_IP6_USER)) { 663195974Sjamie error = EINVAL; 664195974Sjamie vfs_opterror(opts, "ip6 cannot be changed after creation"); 665195974Sjamie goto done_errmsg; 666195974Sjamie } 667195974Sjamie#endif 668191673Sjamie 669192895Sjamie pr_allow = ch_allow = 0; 670192895Sjamie for (fi = 0; fi < sizeof(pr_allow_names) / sizeof(pr_allow_names[0]); 671192895Sjamie fi++) { 672192895Sjamie vfs_flagopt(opts, pr_allow_names[fi], &pr_allow, 1 << fi); 673192895Sjamie vfs_flagopt(opts, pr_allow_nonames[fi], &ch_allow, 1 << fi); 674192895Sjamie } 675192895Sjamie ch_allow |= pr_allow; 676192895Sjamie 677191673Sjamie error = vfs_getopt(opts, "name", (void **)&name, &len); 678191673Sjamie if (error == ENOENT) 679191673Sjamie name = NULL; 680191673Sjamie else if (error != 0) 681191673Sjamie goto done_free; 682191673Sjamie else { 683191673Sjamie if (len == 0 || name[len - 1] != '\0') { 684191673Sjamie error = EINVAL; 685191673Sjamie goto done_free; 686191673Sjamie } 687191673Sjamie if (len > MAXHOSTNAMELEN) { 688191673Sjamie error = ENAMETOOLONG; 689191673Sjamie goto done_free; 690191673Sjamie } 691191673Sjamie } 692191673Sjamie 693191673Sjamie error = vfs_getopt(opts, "host.hostname", (void **)&host, &len); 694191673Sjamie if (error == ENOENT) 695191673Sjamie host = NULL; 696191673Sjamie else if (error != 0) 697191673Sjamie goto done_free; 698191673Sjamie else { 699193066Sjamie ch_flags |= PR_HOST; 700193066Sjamie pr_flags |= PR_HOST; 701191673Sjamie if (len == 0 || host[len - 1] != '\0') { 702191673Sjamie error = EINVAL; 703191673Sjamie goto done_free; 704191673Sjamie } 705191673Sjamie if (len > MAXHOSTNAMELEN) { 706191673Sjamie error = ENAMETOOLONG; 707191673Sjamie goto done_free; 708191673Sjamie } 709191673Sjamie } 710191673Sjamie 711193066Sjamie error = vfs_getopt(opts, "host.domainname", (void **)&domain, &len); 712193066Sjamie if (error == ENOENT) 713193066Sjamie domain = NULL; 714193066Sjamie else if (error != 0) 715193066Sjamie goto done_free; 716193066Sjamie else { 717193066Sjamie ch_flags |= PR_HOST; 718193066Sjamie pr_flags |= PR_HOST; 719193066Sjamie if (len == 0 || domain[len - 1] != '\0') { 720193066Sjamie error = EINVAL; 721193066Sjamie goto done_free; 722193066Sjamie } 723193066Sjamie if (len > MAXHOSTNAMELEN) { 724193066Sjamie error = ENAMETOOLONG; 725193066Sjamie goto done_free; 726193066Sjamie } 727193066Sjamie } 728193066Sjamie 729193066Sjamie error = vfs_getopt(opts, "host.hostuuid", (void **)&uuid, &len); 730193066Sjamie if (error == ENOENT) 731193066Sjamie uuid = NULL; 732193066Sjamie else if (error != 0) 733193066Sjamie goto done_free; 734193066Sjamie else { 735193066Sjamie ch_flags |= PR_HOST; 736193066Sjamie pr_flags |= PR_HOST; 737193066Sjamie if (len == 0 || uuid[len - 1] != '\0') { 738193066Sjamie error = EINVAL; 739193066Sjamie goto done_free; 740193066Sjamie } 741193066Sjamie if (len > HOSTUUIDLEN) { 742193066Sjamie error = ENAMETOOLONG; 743193066Sjamie goto done_free; 744193066Sjamie } 745193066Sjamie } 746193066Sjamie 747205014Snwhitehorn#ifdef COMPAT_FREEBSD32 748205014Snwhitehorn if (td->td_proc->p_sysent->sv_flags & SV_ILP32) { 749193066Sjamie uint32_t hid32; 750193066Sjamie 751193066Sjamie error = vfs_copyopt(opts, "host.hostid", &hid32, sizeof(hid32)); 752193066Sjamie hid = hid32; 753193066Sjamie } else 754193066Sjamie#endif 755193066Sjamie error = vfs_copyopt(opts, "host.hostid", &hid, sizeof(hid)); 756193066Sjamie if (error == ENOENT) 757193066Sjamie gothid = 0; 758193066Sjamie else if (error != 0) 759193066Sjamie goto done_free; 760193066Sjamie else { 761193066Sjamie gothid = 1; 762193066Sjamie ch_flags |= PR_HOST; 763193066Sjamie pr_flags |= PR_HOST; 764193066Sjamie } 765193066Sjamie 766185435Sbz#ifdef INET 767191673Sjamie error = vfs_getopt(opts, "ip4.addr", &op, &ip4s); 768191673Sjamie if (error == ENOENT) 769195870Sjamie ip4s = (pr_flags & PR_IP4_DISABLE) ? 0 : -1; 770191673Sjamie else if (error != 0) 771191673Sjamie goto done_free; 772191673Sjamie else if (ip4s & (sizeof(*ip4) - 1)) { 773191673Sjamie error = EINVAL; 774191673Sjamie goto done_free; 775192895Sjamie } else { 776195870Sjamie ch_flags |= PR_IP4_USER | PR_IP4_DISABLE; 777195870Sjamie if (ip4s == 0) 778195870Sjamie pr_flags |= PR_IP4_USER | PR_IP4_DISABLE; 779195870Sjamie else { 780195870Sjamie pr_flags = (pr_flags & ~PR_IP4_DISABLE) | PR_IP4_USER; 781192895Sjamie ip4s /= sizeof(*ip4); 782192895Sjamie if (ip4s > jail_max_af_ips) { 783185435Sbz error = EINVAL; 784192895Sjamie vfs_opterror(opts, "too many IPv4 addresses"); 785192895Sjamie goto done_errmsg; 786185435Sbz } 787195974Sjamie ip4 = malloc(ip4s * sizeof(*ip4), M_PRISON, M_WAITOK); 788192895Sjamie bcopy(op, ip4, ip4s * sizeof(*ip4)); 789192895Sjamie /* 790192895Sjamie * IP addresses are all sorted but ip[0] to preserve 791192895Sjamie * the primary IP address as given from userland. 792192895Sjamie * This special IP is used for unbound outgoing 793202116Sbz * connections as well for "loopback" traffic in case 794202116Sbz * source address selection cannot find any more fitting 795202116Sbz * address to connect from. 796192895Sjamie */ 797192895Sjamie if (ip4s > 1) 798192895Sjamie qsort(ip4 + 1, ip4s - 1, sizeof(*ip4), qcmp_v4); 799192895Sjamie /* 800192895Sjamie * Check for duplicate addresses and do some simple 801192895Sjamie * zero and broadcast checks. If users give other bogus 802192895Sjamie * addresses it is their problem. 803192895Sjamie * 804192895Sjamie * We do not have to care about byte order for these 805192895Sjamie * checks so we will do them in NBO. 806192895Sjamie */ 807192895Sjamie for (ii = 0; ii < ip4s; ii++) { 808192895Sjamie if (ip4[ii].s_addr == INADDR_ANY || 809192895Sjamie ip4[ii].s_addr == INADDR_BROADCAST) { 810192895Sjamie error = EINVAL; 811192895Sjamie goto done_free; 812192895Sjamie } 813192895Sjamie if ((ii+1) < ip4s && 814192895Sjamie (ip4[0].s_addr == ip4[ii+1].s_addr || 815192895Sjamie ip4[ii].s_addr == ip4[ii+1].s_addr)) { 816192895Sjamie error = EINVAL; 817192895Sjamie goto done_free; 818192895Sjamie } 819192895Sjamie } 820185435Sbz } 821191673Sjamie } 822191673Sjamie#endif 823185435Sbz 824185435Sbz#ifdef INET6 825191673Sjamie error = vfs_getopt(opts, "ip6.addr", &op, &ip6s); 826191673Sjamie if (error == ENOENT) 827195870Sjamie ip6s = (pr_flags & PR_IP6_DISABLE) ? 0 : -1; 828191673Sjamie else if (error != 0) 829191673Sjamie goto done_free; 830191673Sjamie else if (ip6s & (sizeof(*ip6) - 1)) { 831191673Sjamie error = EINVAL; 832191673Sjamie goto done_free; 833192895Sjamie } else { 834195870Sjamie ch_flags |= PR_IP6_USER | PR_IP6_DISABLE; 835195870Sjamie if (ip6s == 0) 836195870Sjamie pr_flags |= PR_IP6_USER | PR_IP6_DISABLE; 837195870Sjamie else { 838195870Sjamie pr_flags = (pr_flags & ~PR_IP6_DISABLE) | PR_IP6_USER; 839192895Sjamie ip6s /= sizeof(*ip6); 840192895Sjamie if (ip6s > jail_max_af_ips) { 841185435Sbz error = EINVAL; 842192895Sjamie vfs_opterror(opts, "too many IPv6 addresses"); 843192895Sjamie goto done_errmsg; 844185435Sbz } 845195974Sjamie ip6 = malloc(ip6s * sizeof(*ip6), M_PRISON, M_WAITOK); 846192895Sjamie bcopy(op, ip6, ip6s * sizeof(*ip6)); 847192895Sjamie if (ip6s > 1) 848192895Sjamie qsort(ip6 + 1, ip6s - 1, sizeof(*ip6), qcmp_v6); 849192895Sjamie for (ii = 0; ii < ip6s; ii++) { 850192895Sjamie if (IN6_IS_ADDR_UNSPECIFIED(&ip6[ii])) { 851192895Sjamie error = EINVAL; 852192895Sjamie goto done_free; 853192895Sjamie } 854192895Sjamie if ((ii+1) < ip6s && 855192895Sjamie (IN6_ARE_ADDR_EQUAL(&ip6[0], &ip6[ii+1]) || 856192895Sjamie IN6_ARE_ADDR_EQUAL(&ip6[ii], &ip6[ii+1]))) 857192895Sjamie { 858192895Sjamie error = EINVAL; 859192895Sjamie goto done_free; 860192895Sjamie } 861192895Sjamie } 862185435Sbz } 863191673Sjamie } 864185435Sbz#endif 865185435Sbz 866195945Sjamie#if defined(VIMAGE) && (defined(INET) || defined(INET6)) 867195945Sjamie if ((ch_flags & PR_VNET) && (ch_flags & (PR_IP4_USER | PR_IP6_USER))) { 868195945Sjamie error = EINVAL; 869195945Sjamie vfs_opterror(opts, 870195945Sjamie "vnet jails cannot have IP address restrictions"); 871195945Sjamie goto done_errmsg; 872195945Sjamie } 873195945Sjamie#endif 874195945Sjamie 875191673Sjamie root = NULL; 876191673Sjamie error = vfs_getopt(opts, "path", (void **)&path, &len); 877191673Sjamie if (error == ENOENT) 878191673Sjamie path = NULL; 879191673Sjamie else if (error != 0) 880191673Sjamie goto done_free; 881191673Sjamie else { 882191673Sjamie if (flags & JAIL_UPDATE) { 883191673Sjamie error = EINVAL; 884191673Sjamie vfs_opterror(opts, 885191673Sjamie "path cannot be changed after creation"); 886191673Sjamie goto done_errmsg; 887191673Sjamie } 888191673Sjamie if (len == 0 || path[len - 1] != '\0') { 889191673Sjamie error = EINVAL; 890191673Sjamie goto done_free; 891191673Sjamie } 892191673Sjamie if (len < 2 || (len == 2 && path[0] == '/')) 893191673Sjamie path = NULL; 894191673Sjamie else { 895192895Sjamie /* Leave room for a real-root full pathname. */ 896192895Sjamie if (len + (path[0] == '/' && strcmp(mypr->pr_path, "/") 897192895Sjamie ? strlen(mypr->pr_path) : 0) > MAXPATHLEN) { 898192895Sjamie error = ENAMETOOLONG; 899192895Sjamie goto done_free; 900192895Sjamie } 901191673Sjamie NDINIT(&nd, LOOKUP, MPSAFE | FOLLOW, UIO_SYSSPACE, 902191673Sjamie path, td); 903191673Sjamie error = namei(&nd); 904191673Sjamie if (error) 905191673Sjamie goto done_free; 906191673Sjamie vfslocked = NDHASGIANT(&nd); 907191673Sjamie root = nd.ni_vp; 908191673Sjamie NDFREE(&nd, NDF_ONLY_PNBUF); 909191673Sjamie if (root->v_type != VDIR) { 910191673Sjamie error = ENOTDIR; 911191673Sjamie vrele(root); 912191673Sjamie VFS_UNLOCK_GIANT(vfslocked); 913191673Sjamie goto done_free; 914191673Sjamie } 915191673Sjamie VFS_UNLOCK_GIANT(vfslocked); 916191673Sjamie } 917191673Sjamie } 918185435Sbz 919191673Sjamie /* 920191673Sjamie * Grab the allprison lock before letting modules check their 921191673Sjamie * parameters. Once we have it, do not let go so we'll have a 922191673Sjamie * consistent view of the OSD list. 923191673Sjamie */ 924191673Sjamie sx_xlock(&allprison_lock); 925191673Sjamie error = osd_jail_call(NULL, PR_METHOD_CHECK, opts); 926191673Sjamie if (error) 927191673Sjamie goto done_unlock_list; 928185435Sbz 929191673Sjamie /* By now, all parameters should have been noted. */ 930191673Sjamie TAILQ_FOREACH(opt, opts, link) { 931191673Sjamie if (!opt->seen && strcmp(opt->name, "errmsg")) { 932191673Sjamie error = EINVAL; 933191673Sjamie vfs_opterror(opts, "unknown parameter: %s", opt->name); 934191673Sjamie goto done_unlock_list; 935191673Sjamie } 936191673Sjamie } 937191673Sjamie 938185435Sbz /* 939191673Sjamie * See if we are creating a new record or updating an existing one. 940191673Sjamie * This abuses the file error codes ENOENT and EEXIST. 941185435Sbz */ 942191673Sjamie cuflags = flags & (JAIL_CREATE | JAIL_UPDATE); 943191673Sjamie if (!cuflags) { 944191673Sjamie error = EINVAL; 945191673Sjamie vfs_opterror(opts, "no valid operation (create or update)"); 946191673Sjamie goto done_unlock_list; 947191673Sjamie } 948191673Sjamie pr = NULL; 949196835Sjamie namelc = NULL; 950196835Sjamie if (cuflags == JAIL_CREATE && jid == 0 && name != NULL) { 951196835Sjamie namelc = strrchr(name, '.'); 952196835Sjamie jid = strtoul(namelc != NULL ? namelc + 1 : name, &p, 10); 953196835Sjamie if (*p != '\0') 954196835Sjamie jid = 0; 955196835Sjamie } 956191673Sjamie if (jid != 0) { 957192895Sjamie /* 958192895Sjamie * See if a requested jid already exists. There is an 959192895Sjamie * information leak here if the jid exists but is not within 960192895Sjamie * the caller's jail hierarchy. Jail creators will get EEXIST 961192895Sjamie * even though they cannot see the jail, and CREATE | UPDATE 962192895Sjamie * will return ENOENT which is not normally a valid error. 963192895Sjamie */ 964191673Sjamie if (jid < 0) { 965191673Sjamie error = EINVAL; 966191673Sjamie vfs_opterror(opts, "negative jid"); 967191673Sjamie goto done_unlock_list; 968191673Sjamie } 969191673Sjamie pr = prison_find(jid); 970191673Sjamie if (pr != NULL) { 971192895Sjamie ppr = pr->pr_parent; 972191673Sjamie /* Create: jid must not exist. */ 973191673Sjamie if (cuflags == JAIL_CREATE) { 974191673Sjamie mtx_unlock(&pr->pr_mtx); 975191673Sjamie error = EEXIST; 976191673Sjamie vfs_opterror(opts, "jail %d already exists", 977191673Sjamie jid); 978191673Sjamie goto done_unlock_list; 979191673Sjamie } 980192895Sjamie if (!prison_ischild(mypr, pr)) { 981192895Sjamie mtx_unlock(&pr->pr_mtx); 982192895Sjamie pr = NULL; 983192895Sjamie } else if (pr->pr_uref == 0) { 984191673Sjamie if (!(flags & JAIL_DYING)) { 985191673Sjamie mtx_unlock(&pr->pr_mtx); 986191673Sjamie error = ENOENT; 987191673Sjamie vfs_opterror(opts, "jail %d is dying", 988191673Sjamie jid); 989191673Sjamie goto done_unlock_list; 990191673Sjamie } else if ((flags & JAIL_ATTACH) || 991191673Sjamie (pr_flags & PR_PERSIST)) { 992191673Sjamie /* 993191673Sjamie * A dying jail might be resurrected 994191673Sjamie * (via attach or persist), but first 995191673Sjamie * it must determine if another jail 996191673Sjamie * has claimed its name. Accomplish 997191673Sjamie * this by implicitly re-setting the 998191673Sjamie * name. 999191673Sjamie */ 1000191673Sjamie if (name == NULL) 1001192895Sjamie name = prison_name(mypr, pr); 1002191673Sjamie } 1003191673Sjamie } 1004191673Sjamie } 1005191673Sjamie if (pr == NULL) { 1006191673Sjamie /* Update: jid must exist. */ 1007191673Sjamie if (cuflags == JAIL_UPDATE) { 1008191673Sjamie error = ENOENT; 1009191673Sjamie vfs_opterror(opts, "jail %d not found", jid); 1010191673Sjamie goto done_unlock_list; 1011191673Sjamie } 1012191673Sjamie } 1013191673Sjamie } 1014191673Sjamie /* 1015191673Sjamie * If the caller provided a name, look for a jail by that name. 1016191673Sjamie * This has different semantics for creates and updates keyed by jid 1017191673Sjamie * (where the name must not already exist in a different jail), 1018191673Sjamie * and updates keyed by the name itself (where the name must exist 1019191673Sjamie * because that is the jail being updated). 1020191673Sjamie */ 1021191673Sjamie if (name != NULL) { 1022196835Sjamie namelc = strrchr(name, '.'); 1023196835Sjamie if (namelc == NULL) 1024196835Sjamie namelc = name; 1025196835Sjamie else { 1026192895Sjamie /* 1027192895Sjamie * This is a hierarchical name. Split it into the 1028192895Sjamie * parent and child names, and make sure the parent 1029192895Sjamie * exists or matches an already found jail. 1030192895Sjamie */ 1031196835Sjamie *namelc = '\0'; 1032192895Sjamie if (pr != NULL) { 1033196835Sjamie if (strncmp(name, ppr->pr_name, namelc - name) 1034196835Sjamie || ppr->pr_name[namelc - name] != '\0') { 1035192895Sjamie mtx_unlock(&pr->pr_mtx); 1036192895Sjamie error = EINVAL; 1037192895Sjamie vfs_opterror(opts, 1038192895Sjamie "cannot change jail's parent"); 1039192895Sjamie goto done_unlock_list; 1040192895Sjamie } 1041192895Sjamie } else { 1042192895Sjamie ppr = prison_find_name(mypr, name); 1043192895Sjamie if (ppr == NULL) { 1044192895Sjamie error = ENOENT; 1045192895Sjamie vfs_opterror(opts, 1046192895Sjamie "jail \"%s\" not found", name); 1047192895Sjamie goto done_unlock_list; 1048192895Sjamie } 1049192895Sjamie mtx_unlock(&ppr->pr_mtx); 1050192895Sjamie } 1051196835Sjamie name = ++namelc; 1052192895Sjamie } 1053191673Sjamie if (name[0] != '\0') { 1054192895Sjamie namelen = 1055192895Sjamie (ppr == &prison0) ? 0 : strlen(ppr->pr_name) + 1; 1056192895Sjamie name_again: 1057191673Sjamie deadpr = NULL; 1058192895Sjamie FOREACH_PRISON_CHILD(ppr, tpr) { 1059191673Sjamie if (tpr != pr && tpr->pr_ref > 0 && 1060192895Sjamie !strcmp(tpr->pr_name + namelen, name)) { 1061191673Sjamie if (pr == NULL && 1062191673Sjamie cuflags != JAIL_CREATE) { 1063191673Sjamie mtx_lock(&tpr->pr_mtx); 1064191673Sjamie if (tpr->pr_ref > 0) { 1065191673Sjamie /* 1066191673Sjamie * Use this jail 1067191673Sjamie * for updates. 1068191673Sjamie */ 1069191673Sjamie if (tpr->pr_uref > 0) { 1070191673Sjamie pr = tpr; 1071191673Sjamie break; 1072191673Sjamie } 1073191673Sjamie deadpr = tpr; 1074191673Sjamie } 1075191673Sjamie mtx_unlock(&tpr->pr_mtx); 1076191673Sjamie } else if (tpr->pr_uref > 0) { 1077191673Sjamie /* 1078191673Sjamie * Create, or update(jid): 1079191673Sjamie * name must not exist in an 1080192895Sjamie * active sibling jail. 1081191673Sjamie */ 1082191673Sjamie error = EEXIST; 1083191673Sjamie if (pr != NULL) 1084191673Sjamie mtx_unlock(&pr->pr_mtx); 1085191673Sjamie vfs_opterror(opts, 1086191673Sjamie "jail \"%s\" already exists", 1087191673Sjamie name); 1088191673Sjamie goto done_unlock_list; 1089191673Sjamie } 1090191673Sjamie } 1091191673Sjamie } 1092191673Sjamie /* If no active jail is found, use a dying one. */ 1093191673Sjamie if (deadpr != NULL && pr == NULL) { 1094191673Sjamie if (flags & JAIL_DYING) { 1095191673Sjamie mtx_lock(&deadpr->pr_mtx); 1096191673Sjamie if (deadpr->pr_ref == 0) { 1097191673Sjamie mtx_unlock(&deadpr->pr_mtx); 1098191673Sjamie goto name_again; 1099191673Sjamie } 1100191673Sjamie pr = deadpr; 1101191673Sjamie } else if (cuflags == JAIL_UPDATE) { 1102191673Sjamie error = ENOENT; 1103191673Sjamie vfs_opterror(opts, 1104191673Sjamie "jail \"%s\" is dying", name); 1105191673Sjamie goto done_unlock_list; 1106191673Sjamie } 1107191673Sjamie } 1108191673Sjamie /* Update: name must exist if no jid. */ 1109191673Sjamie else if (cuflags == JAIL_UPDATE && pr == NULL) { 1110191673Sjamie error = ENOENT; 1111191673Sjamie vfs_opterror(opts, "jail \"%s\" not found", 1112191673Sjamie name); 1113191673Sjamie goto done_unlock_list; 1114191673Sjamie } 1115191673Sjamie } 1116191673Sjamie } 1117191673Sjamie /* Update: must provide a jid or name. */ 1118191673Sjamie else if (cuflags == JAIL_UPDATE && pr == NULL) { 1119191673Sjamie error = ENOENT; 1120191673Sjamie vfs_opterror(opts, "update specified no jail"); 1121191673Sjamie goto done_unlock_list; 1122191673Sjamie } 1123185435Sbz 1124191673Sjamie /* If there's no prison to update, create a new one and link it in. */ 1125191673Sjamie if (pr == NULL) { 1126194762Sjamie for (tpr = mypr; tpr != NULL; tpr = tpr->pr_parent) 1127194762Sjamie if (tpr->pr_childcount >= tpr->pr_childmax) { 1128194762Sjamie error = EPERM; 1129194762Sjamie vfs_opterror(opts, "prison limit exceeded"); 1130194762Sjamie goto done_unlock_list; 1131194762Sjamie } 1132191673Sjamie created = 1; 1133192895Sjamie mtx_lock(&ppr->pr_mtx); 1134192895Sjamie if (ppr->pr_ref == 0 || (ppr->pr_flags & PR_REMOVE)) { 1135192895Sjamie mtx_unlock(&ppr->pr_mtx); 1136192895Sjamie error = ENOENT; 1137192895Sjamie vfs_opterror(opts, "parent jail went away!"); 1138192895Sjamie goto done_unlock_list; 1139192895Sjamie } 1140192895Sjamie ppr->pr_ref++; 1141192895Sjamie ppr->pr_uref++; 1142192895Sjamie mtx_unlock(&ppr->pr_mtx); 1143191673Sjamie pr = malloc(sizeof(*pr), M_PRISON, M_WAITOK | M_ZERO); 1144191673Sjamie if (jid == 0) { 1145191673Sjamie /* Find the next free jid. */ 1146191673Sjamie jid = lastprid + 1; 1147191673Sjamie findnext: 1148191673Sjamie if (jid == JAIL_MAX) 1149191673Sjamie jid = 1; 1150191673Sjamie TAILQ_FOREACH(tpr, &allprison, pr_list) { 1151191673Sjamie if (tpr->pr_id < jid) 1152191673Sjamie continue; 1153191673Sjamie if (tpr->pr_id > jid || tpr->pr_ref == 0) { 1154191673Sjamie TAILQ_INSERT_BEFORE(tpr, pr, pr_list); 1155191673Sjamie break; 1156191673Sjamie } 1157191673Sjamie if (jid == lastprid) { 1158191673Sjamie error = EAGAIN; 1159191673Sjamie vfs_opterror(opts, 1160191673Sjamie "no available jail IDs"); 1161191673Sjamie free(pr, M_PRISON); 1162192895Sjamie prison_deref(ppr, PD_DEREF | 1163192895Sjamie PD_DEUREF | PD_LIST_XLOCKED); 1164192895Sjamie goto done_releroot; 1165191673Sjamie } 1166191673Sjamie jid++; 1167191673Sjamie goto findnext; 1168191673Sjamie } 1169191673Sjamie lastprid = jid; 1170191673Sjamie } else { 1171191673Sjamie /* 1172191673Sjamie * The jail already has a jid (that did not yet exist), 1173191673Sjamie * so just find where to insert it. 1174191673Sjamie */ 1175191673Sjamie TAILQ_FOREACH(tpr, &allprison, pr_list) 1176191673Sjamie if (tpr->pr_id >= jid) { 1177191673Sjamie TAILQ_INSERT_BEFORE(tpr, pr, pr_list); 1178191673Sjamie break; 1179191673Sjamie } 1180191673Sjamie } 1181191673Sjamie if (tpr == NULL) 1182191673Sjamie TAILQ_INSERT_TAIL(&allprison, pr, pr_list); 1183192895Sjamie LIST_INSERT_HEAD(&ppr->pr_children, pr, pr_sibling); 1184192895Sjamie for (tpr = ppr; tpr != NULL; tpr = tpr->pr_parent) 1185194762Sjamie tpr->pr_childcount++; 1186185435Sbz 1187192895Sjamie pr->pr_parent = ppr; 1188191673Sjamie pr->pr_id = jid; 1189192895Sjamie 1190192895Sjamie /* Set some default values, and inherit some from the parent. */ 1191191673Sjamie if (name == NULL) 1192191673Sjamie name = ""; 1193191673Sjamie if (path == NULL) { 1194191673Sjamie path = "/"; 1195192895Sjamie root = mypr->pr_root; 1196191673Sjamie vref(root); 1197191673Sjamie } 1198195944Sjamie strlcpy(pr->pr_hostuuid, DEFAULT_HOSTUUID, HOSTUUIDLEN); 1199195944Sjamie pr->pr_flags |= PR_HOST; 1200195945Sjamie#if defined(INET) || defined(INET6) 1201195945Sjamie#ifdef VIMAGE 1202195945Sjamie if (!(pr_flags & PR_VNET)) 1203195945Sjamie#endif 1204195945Sjamie { 1205192895Sjamie#ifdef INET 1206195974Sjamie if (!(ch_flags & PR_IP4_USER)) 1207195974Sjamie pr->pr_flags |= 1208195974Sjamie PR_IP4 | PR_IP4_USER | PR_IP4_DISABLE; 1209195974Sjamie else if (!(pr_flags & PR_IP4_USER)) { 1210195974Sjamie pr->pr_flags |= ppr->pr_flags & PR_IP4; 1211195974Sjamie if (ppr->pr_ip4 != NULL) { 1212195974Sjamie pr->pr_ip4s = ppr->pr_ip4s; 1213195974Sjamie pr->pr_ip4 = malloc(pr->pr_ip4s * 1214195974Sjamie sizeof(struct in_addr), M_PRISON, 1215195974Sjamie M_WAITOK); 1216195974Sjamie bcopy(ppr->pr_ip4, pr->pr_ip4, 1217195974Sjamie pr->pr_ip4s * sizeof(*pr->pr_ip4)); 1218195974Sjamie } 1219195974Sjamie } 1220192895Sjamie#endif 1221192895Sjamie#ifdef INET6 1222195974Sjamie if (!(ch_flags & PR_IP6_USER)) 1223195974Sjamie pr->pr_flags |= 1224195974Sjamie PR_IP6 | PR_IP6_USER | PR_IP6_DISABLE; 1225195974Sjamie else if (!(pr_flags & PR_IP6_USER)) { 1226195974Sjamie pr->pr_flags |= ppr->pr_flags & PR_IP6; 1227195974Sjamie if (ppr->pr_ip6 != NULL) { 1228195974Sjamie pr->pr_ip6s = ppr->pr_ip6s; 1229195974Sjamie pr->pr_ip6 = malloc(pr->pr_ip6s * 1230195974Sjamie sizeof(struct in6_addr), M_PRISON, 1231195974Sjamie M_WAITOK); 1232195974Sjamie bcopy(ppr->pr_ip6, pr->pr_ip6, 1233195974Sjamie pr->pr_ip6s * sizeof(*pr->pr_ip6)); 1234195974Sjamie } 1235195974Sjamie } 1236192895Sjamie#endif 1237195945Sjamie } 1238195945Sjamie#endif 1239202468Sbz /* Source address selection is always on by default. */ 1240202468Sbz pr->pr_flags |= _PR_IP_SADDRSEL; 1241202468Sbz 1242192895Sjamie pr->pr_securelevel = ppr->pr_securelevel; 1243192895Sjamie pr->pr_allow = JAIL_DEFAULT_ALLOW & ppr->pr_allow; 1244196002Sjamie pr->pr_enforce_statfs = JAIL_DEFAULT_ENFORCE_STATFS; 1245191673Sjamie 1246192895Sjamie LIST_INIT(&pr->pr_children); 1247192895Sjamie mtx_init(&pr->pr_mtx, "jail mutex", NULL, MTX_DEF | MTX_DUPOK); 1248191673Sjamie 1249194251Sjamie#ifdef VIMAGE 1250194251Sjamie /* Allocate a new vnet if specified. */ 1251194251Sjamie pr->pr_vnet = (pr_flags & PR_VNET) 1252194251Sjamie ? vnet_alloc() : ppr->pr_vnet; 1253194251Sjamie#endif 1254185435Sbz /* 1255191673Sjamie * Allocate a dedicated cpuset for each jail. 1256191673Sjamie * Unlike other initial settings, this may return an erorr. 1257185435Sbz */ 1258192895Sjamie error = cpuset_create_root(ppr, &pr->pr_cpuset); 1259191673Sjamie if (error) { 1260191673Sjamie prison_deref(pr, PD_LIST_XLOCKED); 1261191673Sjamie goto done_releroot; 1262191673Sjamie } 1263185435Sbz 1264191673Sjamie mtx_lock(&pr->pr_mtx); 1265185435Sbz /* 1266191673Sjamie * New prisons do not yet have a reference, because we do not 1267191673Sjamie * want other to see the incomplete prison once the 1268191673Sjamie * allprison_lock is downgraded. 1269185435Sbz */ 1270191673Sjamie } else { 1271191673Sjamie created = 0; 1272195974Sjamie /* 1273195974Sjamie * Grab a reference for existing prisons, to ensure they 1274195974Sjamie * continue to exist for the duration of the call. 1275195974Sjamie */ 1276195974Sjamie pr->pr_ref++; 1277195945Sjamie#if defined(VIMAGE) && (defined(INET) || defined(INET6)) 1278195945Sjamie if ((pr->pr_flags & PR_VNET) && 1279195945Sjamie (ch_flags & (PR_IP4_USER | PR_IP6_USER))) { 1280195945Sjamie error = EINVAL; 1281195945Sjamie vfs_opterror(opts, 1282195945Sjamie "vnet jails cannot have IP address restrictions"); 1283195945Sjamie goto done_deref_locked; 1284195945Sjamie } 1285195945Sjamie#endif 1286195974Sjamie#ifdef INET 1287195974Sjamie if (PR_IP4_USER & ch_flags & (pr_flags ^ pr->pr_flags)) { 1288195974Sjamie error = EINVAL; 1289195974Sjamie vfs_opterror(opts, 1290195974Sjamie "ip4 cannot be changed after creation"); 1291195974Sjamie goto done_deref_locked; 1292195974Sjamie } 1293195974Sjamie#endif 1294195974Sjamie#ifdef INET6 1295195974Sjamie if (PR_IP6_USER & ch_flags & (pr_flags ^ pr->pr_flags)) { 1296195974Sjamie error = EINVAL; 1297195974Sjamie vfs_opterror(opts, 1298195974Sjamie "ip6 cannot be changed after creation"); 1299195974Sjamie goto done_deref_locked; 1300195974Sjamie } 1301195974Sjamie#endif 1302191673Sjamie } 1303185435Sbz 1304191673Sjamie /* Do final error checking before setting anything. */ 1305192895Sjamie if (gotslevel) { 1306192895Sjamie if (slevel < ppr->pr_securelevel) { 1307192895Sjamie error = EPERM; 1308192895Sjamie goto done_deref_locked; 1309192895Sjamie } 1310192895Sjamie } 1311194762Sjamie if (gotchildmax) { 1312194762Sjamie if (childmax >= ppr->pr_childmax) { 1313194762Sjamie error = EPERM; 1314194762Sjamie goto done_deref_locked; 1315194762Sjamie } 1316194762Sjamie } 1317192895Sjamie if (gotenforce) { 1318192895Sjamie if (enforce < ppr->pr_enforce_statfs) { 1319192895Sjamie error = EPERM; 1320192895Sjamie goto done_deref_locked; 1321192895Sjamie } 1322192895Sjamie } 1323185435Sbz#ifdef INET 1324195974Sjamie if (ip4s > 0) { 1325192895Sjamie if (ppr->pr_flags & PR_IP4) { 1326195974Sjamie /* 1327195974Sjamie * Make sure the new set of IP addresses is a 1328195974Sjamie * subset of the parent's list. Don't worry 1329195974Sjamie * about the parent being unlocked, as any 1330195974Sjamie * setting is done with allprison_lock held. 1331195974Sjamie */ 1332195974Sjamie for (ij = 0; ij < ppr->pr_ip4s; ij++) 1333195974Sjamie if (ip4[0].s_addr == ppr->pr_ip4[ij].s_addr) 1334195974Sjamie break; 1335195974Sjamie if (ij == ppr->pr_ip4s) { 1336195974Sjamie error = EPERM; 1337195974Sjamie goto done_deref_locked; 1338195974Sjamie } 1339195974Sjamie if (ip4s > 1) { 1340195974Sjamie for (ii = ij = 1; ii < ip4s; ii++) { 1341195974Sjamie if (ip4[ii].s_addr == 1342195974Sjamie ppr->pr_ip4[0].s_addr) 1343195974Sjamie continue; 1344195974Sjamie for (; ij < ppr->pr_ip4s; ij++) 1345195974Sjamie if (ip4[ii].s_addr == 1346195974Sjamie ppr->pr_ip4[ij].s_addr) 1347195974Sjamie break; 1348195974Sjamie if (ij == ppr->pr_ip4s) 1349195974Sjamie break; 1350192895Sjamie } 1351192895Sjamie if (ij == ppr->pr_ip4s) { 1352192895Sjamie error = EPERM; 1353192895Sjamie goto done_deref_locked; 1354192895Sjamie } 1355192895Sjamie } 1356192895Sjamie } 1357195974Sjamie /* 1358195974Sjamie * Check for conflicting IP addresses. We permit them 1359195974Sjamie * if there is no more than one IP on each jail. If 1360195974Sjamie * there is a duplicate on a jail with more than one 1361195974Sjamie * IP stop checking and return error. 1362195974Sjamie */ 1363195974Sjamie tppr = ppr; 1364195945Sjamie#ifdef VIMAGE 1365195974Sjamie for (; tppr != &prison0; tppr = tppr->pr_parent) 1366195974Sjamie if (tppr->pr_flags & PR_VNET) 1367195974Sjamie break; 1368195945Sjamie#endif 1369195974Sjamie FOREACH_PRISON_DESCENDANT(tppr, tpr, descend) { 1370195974Sjamie if (tpr == pr || 1371195945Sjamie#ifdef VIMAGE 1372195974Sjamie (tpr != tppr && (tpr->pr_flags & PR_VNET)) || 1373195945Sjamie#endif 1374195974Sjamie tpr->pr_uref == 0) { 1375192895Sjamie descend = 0; 1376195974Sjamie continue; 1377195974Sjamie } 1378195974Sjamie if (!(tpr->pr_flags & PR_IP4_USER)) 1379195974Sjamie continue; 1380195974Sjamie descend = 0; 1381195974Sjamie if (tpr->pr_ip4 == NULL || 1382195974Sjamie (ip4s == 1 && tpr->pr_ip4s == 1)) 1383195974Sjamie continue; 1384195974Sjamie for (ii = 0; ii < ip4s; ii++) { 1385195974Sjamie if (_prison_check_ip4(tpr, &ip4[ii]) == 0) { 1386195974Sjamie error = EADDRINUSE; 1387195974Sjamie vfs_opterror(opts, 1388195974Sjamie "IPv4 addresses clash"); 1389195974Sjamie goto done_deref_locked; 1390192895Sjamie } 1391192895Sjamie } 1392192895Sjamie } 1393192895Sjamie } 1394185435Sbz#endif 1395191673Sjamie#ifdef INET6 1396195974Sjamie if (ip6s > 0) { 1397192895Sjamie if (ppr->pr_flags & PR_IP6) { 1398195974Sjamie /* 1399195974Sjamie * Make sure the new set of IP addresses is a 1400195974Sjamie * subset of the parent's list. 1401195974Sjamie */ 1402195974Sjamie for (ij = 0; ij < ppr->pr_ip6s; ij++) 1403195974Sjamie if (IN6_ARE_ADDR_EQUAL(&ip6[0], 1404195974Sjamie &ppr->pr_ip6[ij])) 1405195974Sjamie break; 1406195974Sjamie if (ij == ppr->pr_ip6s) { 1407195974Sjamie error = EPERM; 1408195974Sjamie goto done_deref_locked; 1409195974Sjamie } 1410195974Sjamie if (ip6s > 1) { 1411195974Sjamie for (ii = ij = 1; ii < ip6s; ii++) { 1412195974Sjamie if (IN6_ARE_ADDR_EQUAL(&ip6[ii], 1413195974Sjamie &ppr->pr_ip6[0])) 1414195974Sjamie continue; 1415195974Sjamie for (; ij < ppr->pr_ip6s; ij++) 1416195974Sjamie if (IN6_ARE_ADDR_EQUAL( 1417195974Sjamie &ip6[ii], &ppr->pr_ip6[ij])) 1418195974Sjamie break; 1419195974Sjamie if (ij == ppr->pr_ip6s) 1420195974Sjamie break; 1421192895Sjamie } 1422192895Sjamie if (ij == ppr->pr_ip6s) { 1423192895Sjamie error = EPERM; 1424192895Sjamie goto done_deref_locked; 1425192895Sjamie } 1426192895Sjamie } 1427192895Sjamie } 1428195974Sjamie /* Check for conflicting IP addresses. */ 1429195974Sjamie tppr = ppr; 1430195945Sjamie#ifdef VIMAGE 1431195974Sjamie for (; tppr != &prison0; tppr = tppr->pr_parent) 1432195974Sjamie if (tppr->pr_flags & PR_VNET) 1433195974Sjamie break; 1434195945Sjamie#endif 1435195974Sjamie FOREACH_PRISON_DESCENDANT(tppr, tpr, descend) { 1436195974Sjamie if (tpr == pr || 1437195945Sjamie#ifdef VIMAGE 1438195974Sjamie (tpr != tppr && (tpr->pr_flags & PR_VNET)) || 1439195945Sjamie#endif 1440195974Sjamie tpr->pr_uref == 0) { 1441192895Sjamie descend = 0; 1442195974Sjamie continue; 1443195974Sjamie } 1444195974Sjamie if (!(tpr->pr_flags & PR_IP6_USER)) 1445195974Sjamie continue; 1446195974Sjamie descend = 0; 1447195974Sjamie if (tpr->pr_ip6 == NULL || 1448195974Sjamie (ip6s == 1 && tpr->pr_ip6s == 1)) 1449195974Sjamie continue; 1450195974Sjamie for (ii = 0; ii < ip6s; ii++) { 1451195974Sjamie if (_prison_check_ip6(tpr, &ip6[ii]) == 0) { 1452195974Sjamie error = EADDRINUSE; 1453195974Sjamie vfs_opterror(opts, 1454195974Sjamie "IPv6 addresses clash"); 1455195974Sjamie goto done_deref_locked; 1456192895Sjamie } 1457192895Sjamie } 1458191673Sjamie } 1459192895Sjamie } 1460191673Sjamie#endif 1461192895Sjamie onamelen = namelen = 0; 1462192895Sjamie if (name != NULL) { 1463191673Sjamie /* Give a default name of the jid. */ 1464191673Sjamie if (name[0] == '\0') 1465191673Sjamie snprintf(name = numbuf, sizeof(numbuf), "%d", jid); 1466196835Sjamie else if (*namelc == '0' || (strtoul(namelc, &p, 10) != jid && 1467196835Sjamie *p == '\0')) { 1468191673Sjamie error = EINVAL; 1469196835Sjamie vfs_opterror(opts, 1470196835Sjamie "name cannot be numeric (unless it is the jid)"); 1471192895Sjamie goto done_deref_locked; 1472191673Sjamie } 1473191673Sjamie /* 1474192895Sjamie * Make sure the name isn't too long for the prison or its 1475192895Sjamie * children. 1476191673Sjamie */ 1477192895Sjamie onamelen = strlen(pr->pr_name); 1478192895Sjamie namelen = strlen(name); 1479192895Sjamie if (strlen(ppr->pr_name) + namelen + 2 > sizeof(pr->pr_name)) { 1480192895Sjamie error = ENAMETOOLONG; 1481192895Sjamie goto done_deref_locked; 1482192895Sjamie } 1483192895Sjamie FOREACH_PRISON_DESCENDANT(pr, tpr, descend) { 1484192895Sjamie if (strlen(tpr->pr_name) + (namelen - onamelen) >= 1485192895Sjamie sizeof(pr->pr_name)) { 1486192895Sjamie error = ENAMETOOLONG; 1487192895Sjamie goto done_deref_locked; 1488192895Sjamie } 1489192895Sjamie } 1490191673Sjamie } 1491192895Sjamie if (pr_allow & ~ppr->pr_allow) { 1492192895Sjamie error = EPERM; 1493192895Sjamie goto done_deref_locked; 1494192895Sjamie } 1495185435Sbz 1496191673Sjamie /* Set the parameters of the prison. */ 1497191673Sjamie#ifdef INET 1498192895Sjamie redo_ip4 = 0; 1499195974Sjamie if (pr_flags & PR_IP4_USER) { 1500195974Sjamie pr->pr_flags |= PR_IP4; 1501195974Sjamie free(pr->pr_ip4, M_PRISON); 1502195974Sjamie pr->pr_ip4s = ip4s; 1503195974Sjamie pr->pr_ip4 = ip4; 1504195974Sjamie ip4 = NULL; 1505192895Sjamie FOREACH_PRISON_DESCENDANT_LOCKED(pr, tpr, descend) { 1506195945Sjamie#ifdef VIMAGE 1507195945Sjamie if (tpr->pr_flags & PR_VNET) { 1508195945Sjamie descend = 0; 1509195945Sjamie continue; 1510195945Sjamie } 1511195945Sjamie#endif 1512192895Sjamie if (prison_restrict_ip4(tpr, NULL)) { 1513192895Sjamie redo_ip4 = 1; 1514192895Sjamie descend = 0; 1515192895Sjamie } 1516192895Sjamie } 1517185435Sbz } 1518191673Sjamie#endif 1519191673Sjamie#ifdef INET6 1520192895Sjamie redo_ip6 = 0; 1521195974Sjamie if (pr_flags & PR_IP6_USER) { 1522195974Sjamie pr->pr_flags |= PR_IP6; 1523195974Sjamie free(pr->pr_ip6, M_PRISON); 1524195974Sjamie pr->pr_ip6s = ip6s; 1525195974Sjamie pr->pr_ip6 = ip6; 1526195974Sjamie ip6 = NULL; 1527192895Sjamie FOREACH_PRISON_DESCENDANT_LOCKED(pr, tpr, descend) { 1528195945Sjamie#ifdef VIMAGE 1529195945Sjamie if (tpr->pr_flags & PR_VNET) { 1530195945Sjamie descend = 0; 1531195945Sjamie continue; 1532195945Sjamie } 1533195945Sjamie#endif 1534192895Sjamie if (prison_restrict_ip6(tpr, NULL)) { 1535192895Sjamie redo_ip6 = 1; 1536192895Sjamie descend = 0; 1537192895Sjamie } 1538192895Sjamie } 1539191673Sjamie } 1540191673Sjamie#endif 1541192895Sjamie if (gotslevel) { 1542191673Sjamie pr->pr_securelevel = slevel; 1543192895Sjamie /* Set all child jails to be at least this level. */ 1544192895Sjamie FOREACH_PRISON_DESCENDANT_LOCKED(pr, tpr, descend) 1545192895Sjamie if (tpr->pr_securelevel < slevel) 1546192895Sjamie tpr->pr_securelevel = slevel; 1547192895Sjamie } 1548194762Sjamie if (gotchildmax) { 1549194762Sjamie pr->pr_childmax = childmax; 1550194762Sjamie /* Set all child jails to under this limit. */ 1551194762Sjamie FOREACH_PRISON_DESCENDANT_LOCKED_LEVEL(pr, tpr, descend, level) 1552194762Sjamie if (tpr->pr_childmax > childmax - level) 1553194762Sjamie tpr->pr_childmax = childmax > level 1554194762Sjamie ? childmax - level : 0; 1555194762Sjamie } 1556192895Sjamie if (gotenforce) { 1557192895Sjamie pr->pr_enforce_statfs = enforce; 1558192895Sjamie /* Pass this restriction on to the children. */ 1559192895Sjamie FOREACH_PRISON_DESCENDANT_LOCKED(pr, tpr, descend) 1560192895Sjamie if (tpr->pr_enforce_statfs < enforce) 1561192895Sjamie tpr->pr_enforce_statfs = enforce; 1562192895Sjamie } 1563192895Sjamie if (name != NULL) { 1564192895Sjamie if (ppr == &prison0) 1565192895Sjamie strlcpy(pr->pr_name, name, sizeof(pr->pr_name)); 1566192895Sjamie else 1567192895Sjamie snprintf(pr->pr_name, sizeof(pr->pr_name), "%s.%s", 1568192895Sjamie ppr->pr_name, name); 1569192895Sjamie /* Change this component of child names. */ 1570192895Sjamie FOREACH_PRISON_DESCENDANT_LOCKED(pr, tpr, descend) { 1571192895Sjamie bcopy(tpr->pr_name + onamelen, tpr->pr_name + namelen, 1572192895Sjamie strlen(tpr->pr_name + onamelen) + 1); 1573192895Sjamie bcopy(pr->pr_name, tpr->pr_name, namelen); 1574192895Sjamie } 1575192895Sjamie } 1576191673Sjamie if (path != NULL) { 1577192895Sjamie /* Try to keep a real-rooted full pathname. */ 1578192895Sjamie if (path[0] == '/' && strcmp(mypr->pr_path, "/")) 1579192895Sjamie snprintf(pr->pr_path, sizeof(pr->pr_path), "%s%s", 1580192895Sjamie mypr->pr_path, path); 1581192895Sjamie else 1582192895Sjamie strlcpy(pr->pr_path, path, sizeof(pr->pr_path)); 1583191673Sjamie pr->pr_root = root; 1584191673Sjamie } 1585193066Sjamie if (PR_HOST & ch_flags & ~pr_flags) { 1586193066Sjamie if (pr->pr_flags & PR_HOST) { 1587193066Sjamie /* 1588193066Sjamie * Copy the parent's host info. As with pr_ip4 above, 1589193066Sjamie * the lack of a lock on the parent is not a problem; 1590193066Sjamie * it is always set with allprison_lock at least 1591193066Sjamie * shared, and is held exclusively here. 1592193066Sjamie */ 1593194118Sjamie strlcpy(pr->pr_hostname, pr->pr_parent->pr_hostname, 1594194118Sjamie sizeof(pr->pr_hostname)); 1595194118Sjamie strlcpy(pr->pr_domainname, pr->pr_parent->pr_domainname, 1596194118Sjamie sizeof(pr->pr_domainname)); 1597194118Sjamie strlcpy(pr->pr_hostuuid, pr->pr_parent->pr_hostuuid, 1598194118Sjamie sizeof(pr->pr_hostuuid)); 1599193066Sjamie pr->pr_hostid = pr->pr_parent->pr_hostid; 1600193066Sjamie } 1601193066Sjamie } else if (host != NULL || domain != NULL || uuid != NULL || gothid) { 1602193066Sjamie /* Set this prison, and any descendants without PR_HOST. */ 1603193066Sjamie if (host != NULL) 1604194118Sjamie strlcpy(pr->pr_hostname, host, sizeof(pr->pr_hostname)); 1605193066Sjamie if (domain != NULL) 1606194118Sjamie strlcpy(pr->pr_domainname, domain, 1607194118Sjamie sizeof(pr->pr_domainname)); 1608193066Sjamie if (uuid != NULL) 1609194118Sjamie strlcpy(pr->pr_hostuuid, uuid, sizeof(pr->pr_hostuuid)); 1610193066Sjamie if (gothid) 1611193066Sjamie pr->pr_hostid = hid; 1612193066Sjamie FOREACH_PRISON_DESCENDANT_LOCKED(pr, tpr, descend) { 1613193066Sjamie if (tpr->pr_flags & PR_HOST) 1614193066Sjamie descend = 0; 1615193066Sjamie else { 1616193066Sjamie if (host != NULL) 1617194118Sjamie strlcpy(tpr->pr_hostname, 1618194118Sjamie pr->pr_hostname, 1619194118Sjamie sizeof(tpr->pr_hostname)); 1620193066Sjamie if (domain != NULL) 1621194118Sjamie strlcpy(tpr->pr_domainname, 1622194118Sjamie pr->pr_domainname, 1623194118Sjamie sizeof(tpr->pr_domainname)); 1624193066Sjamie if (uuid != NULL) 1625194118Sjamie strlcpy(tpr->pr_hostuuid, 1626194118Sjamie pr->pr_hostuuid, 1627194118Sjamie sizeof(tpr->pr_hostuuid)); 1628193066Sjamie if (gothid) 1629193066Sjamie tpr->pr_hostid = hid; 1630193066Sjamie } 1631193066Sjamie } 1632193066Sjamie } 1633192895Sjamie if ((tallow = ch_allow & ~pr_allow)) { 1634192895Sjamie /* Clear allow bits in all children. */ 1635192895Sjamie FOREACH_PRISON_DESCENDANT_LOCKED(pr, tpr, descend) 1636192895Sjamie tpr->pr_allow &= ~tallow; 1637192895Sjamie } 1638192895Sjamie pr->pr_allow = (pr->pr_allow & ~ch_allow) | pr_allow; 1639191673Sjamie /* 1640191673Sjamie * Persistent prisons get an extra reference, and prisons losing their 1641191673Sjamie * persist flag lose that reference. Only do this for existing prisons 1642191673Sjamie * for now, so new ones will remain unseen until after the module 1643191673Sjamie * handlers have completed. 1644191673Sjamie */ 1645191673Sjamie if (!created && (ch_flags & PR_PERSIST & (pr_flags ^ pr->pr_flags))) { 1646191673Sjamie if (pr_flags & PR_PERSIST) { 1647191673Sjamie pr->pr_ref++; 1648191673Sjamie pr->pr_uref++; 1649191673Sjamie } else { 1650191673Sjamie pr->pr_ref--; 1651191673Sjamie pr->pr_uref--; 1652191673Sjamie } 1653191673Sjamie } 1654191673Sjamie pr->pr_flags = (pr->pr_flags & ~ch_flags) | pr_flags; 1655191673Sjamie mtx_unlock(&pr->pr_mtx); 1656185435Sbz 1657192895Sjamie /* Locks may have prevented a complete restriction of child IP 1658192895Sjamie * addresses. If so, allocate some more memory and try again. 1659192895Sjamie */ 1660192895Sjamie#ifdef INET 1661192895Sjamie while (redo_ip4) { 1662192895Sjamie ip4s = pr->pr_ip4s; 1663192895Sjamie ip4 = malloc(ip4s * sizeof(*ip4), M_PRISON, M_WAITOK); 1664192895Sjamie mtx_lock(&pr->pr_mtx); 1665192895Sjamie redo_ip4 = 0; 1666192895Sjamie FOREACH_PRISON_DESCENDANT_LOCKED(pr, tpr, descend) { 1667195945Sjamie#ifdef VIMAGE 1668195945Sjamie if (tpr->pr_flags & PR_VNET) { 1669195945Sjamie descend = 0; 1670195945Sjamie continue; 1671195945Sjamie } 1672195945Sjamie#endif 1673192895Sjamie if (prison_restrict_ip4(tpr, ip4)) { 1674192895Sjamie if (ip4 != NULL) 1675192895Sjamie ip4 = NULL; 1676192895Sjamie else 1677192895Sjamie redo_ip4 = 1; 1678192895Sjamie } 1679192895Sjamie } 1680192895Sjamie mtx_unlock(&pr->pr_mtx); 1681192895Sjamie } 1682192895Sjamie#endif 1683192895Sjamie#ifdef INET6 1684192895Sjamie while (redo_ip6) { 1685192895Sjamie ip6s = pr->pr_ip6s; 1686192895Sjamie ip6 = malloc(ip6s * sizeof(*ip6), M_PRISON, M_WAITOK); 1687192895Sjamie mtx_lock(&pr->pr_mtx); 1688192895Sjamie redo_ip6 = 0; 1689192895Sjamie FOREACH_PRISON_DESCENDANT_LOCKED(pr, tpr, descend) { 1690195945Sjamie#ifdef VIMAGE 1691195945Sjamie if (tpr->pr_flags & PR_VNET) { 1692195945Sjamie descend = 0; 1693195945Sjamie continue; 1694195945Sjamie } 1695195945Sjamie#endif 1696192895Sjamie if (prison_restrict_ip6(tpr, ip6)) { 1697192895Sjamie if (ip6 != NULL) 1698192895Sjamie ip6 = NULL; 1699192895Sjamie else 1700192895Sjamie redo_ip6 = 1; 1701192895Sjamie } 1702192895Sjamie } 1703192895Sjamie mtx_unlock(&pr->pr_mtx); 1704192895Sjamie } 1705192895Sjamie#endif 1706192895Sjamie 1707191673Sjamie /* Let the modules do their work. */ 1708191673Sjamie sx_downgrade(&allprison_lock); 1709191673Sjamie if (created) { 1710191673Sjamie error = osd_jail_call(pr, PR_METHOD_CREATE, opts); 1711191673Sjamie if (error) { 1712191673Sjamie prison_deref(pr, PD_LIST_SLOCKED); 1713191673Sjamie goto done_errmsg; 1714191673Sjamie } 1715191673Sjamie } 1716191673Sjamie error = osd_jail_call(pr, PR_METHOD_SET, opts); 1717191673Sjamie if (error) { 1718191673Sjamie prison_deref(pr, created 1719191673Sjamie ? PD_LIST_SLOCKED 1720191673Sjamie : PD_DEREF | PD_LIST_SLOCKED); 1721191673Sjamie goto done_errmsg; 1722191673Sjamie } 1723191673Sjamie 1724191673Sjamie /* Attach this process to the prison if requested. */ 1725191673Sjamie if (flags & JAIL_ATTACH) { 1726191673Sjamie mtx_lock(&pr->pr_mtx); 1727191673Sjamie error = do_jail_attach(td, pr); 1728191673Sjamie if (error) { 1729191673Sjamie vfs_opterror(opts, "attach failed"); 1730191673Sjamie if (!created) 1731191673Sjamie prison_deref(pr, PD_DEREF); 1732191673Sjamie goto done_errmsg; 1733191673Sjamie } 1734191673Sjamie } 1735191673Sjamie 1736191673Sjamie /* 1737191673Sjamie * Now that it is all there, drop the temporary reference from existing 1738191673Sjamie * prisons. Or add a reference to newly created persistent prisons 1739191673Sjamie * (which was not done earlier so that the prison would not be publicly 1740191673Sjamie * visible). 1741191673Sjamie */ 1742191673Sjamie if (!created) { 1743191673Sjamie prison_deref(pr, (flags & JAIL_ATTACH) 1744191673Sjamie ? PD_DEREF 1745191673Sjamie : PD_DEREF | PD_LIST_SLOCKED); 1746191673Sjamie } else { 1747191673Sjamie if (pr_flags & PR_PERSIST) { 1748191673Sjamie mtx_lock(&pr->pr_mtx); 1749191673Sjamie pr->pr_ref++; 1750191673Sjamie pr->pr_uref++; 1751191673Sjamie mtx_unlock(&pr->pr_mtx); 1752191673Sjamie } 1753191673Sjamie if (!(flags & JAIL_ATTACH)) 1754191673Sjamie sx_sunlock(&allprison_lock); 1755191673Sjamie } 1756191673Sjamie td->td_retval[0] = pr->pr_id; 1757191673Sjamie goto done_errmsg; 1758191673Sjamie 1759192895Sjamie done_deref_locked: 1760192895Sjamie prison_deref(pr, created 1761192895Sjamie ? PD_LOCKED | PD_LIST_XLOCKED 1762192895Sjamie : PD_DEREF | PD_LOCKED | PD_LIST_XLOCKED); 1763192895Sjamie goto done_releroot; 1764191673Sjamie done_unlock_list: 1765191673Sjamie sx_xunlock(&allprison_lock); 1766191673Sjamie done_releroot: 1767191673Sjamie if (root != NULL) { 1768191673Sjamie vfslocked = VFS_LOCK_GIANT(root->v_mount); 1769191673Sjamie vrele(root); 1770191673Sjamie VFS_UNLOCK_GIANT(vfslocked); 1771191673Sjamie } 1772191673Sjamie done_errmsg: 1773191673Sjamie if (error) { 1774191673Sjamie vfs_getopt(opts, "errmsg", (void **)&errmsg, &errmsg_len); 1775191673Sjamie if (errmsg_len > 0) { 1776191673Sjamie errmsg_pos = 2 * vfs_getopt_pos(opts, "errmsg") + 1; 1777191673Sjamie if (errmsg_pos > 0) { 1778191673Sjamie if (optuio->uio_segflg == UIO_SYSSPACE) 1779191673Sjamie bcopy(errmsg, 1780191673Sjamie optuio->uio_iov[errmsg_pos].iov_base, 1781191673Sjamie errmsg_len); 1782191673Sjamie else 1783191673Sjamie copyout(errmsg, 1784191673Sjamie optuio->uio_iov[errmsg_pos].iov_base, 1785191673Sjamie errmsg_len); 1786191673Sjamie } 1787191673Sjamie } 1788191673Sjamie } 1789191673Sjamie done_free: 1790191673Sjamie#ifdef INET 1791191673Sjamie free(ip4, M_PRISON); 1792191673Sjamie#endif 1793191673Sjamie#ifdef INET6 1794191673Sjamie free(ip6, M_PRISON); 1795191673Sjamie#endif 1796191673Sjamie vfs_freeopts(opts); 1797191673Sjamie return (error); 1798191673Sjamie} 1799191673Sjamie 1800191673Sjamie 180182710Sdillon/* 1802191673Sjamie * struct jail_get_args { 1803191673Sjamie * struct iovec *iovp; 1804191673Sjamie * unsigned int iovcnt; 1805191673Sjamie * int flags; 1806114168Smike * }; 180782710Sdillon */ 180846155Sphkint 1809191673Sjamiejail_get(struct thread *td, struct jail_get_args *uap) 181046155Sphk{ 1811191673Sjamie struct uio *auio; 1812185435Sbz int error; 1813185435Sbz 1814191673Sjamie /* Check that we have an even number of iovecs. */ 1815191673Sjamie if (uap->iovcnt & 1) 1816191673Sjamie return (EINVAL); 1817191673Sjamie 1818191673Sjamie error = copyinuio(uap->iovp, uap->iovcnt, &auio); 1819185435Sbz if (error) 1820185435Sbz return (error); 1821191673Sjamie error = kern_jail_get(td, auio, uap->flags); 1822191673Sjamie if (error == 0) 1823191673Sjamie error = copyout(auio->uio_iov, uap->iovp, 1824191673Sjamie uap->iovcnt * sizeof (struct iovec)); 1825191673Sjamie free(auio, M_IOV); 1826191673Sjamie return (error); 1827191673Sjamie} 1828185435Sbz 1829191673Sjamieint 1830191673Sjamiekern_jail_get(struct thread *td, struct uio *optuio, int flags) 1831191673Sjamie{ 1832192895Sjamie struct prison *pr, *mypr; 1833191673Sjamie struct vfsopt *opt; 1834191673Sjamie struct vfsoptlist *opts; 1835191673Sjamie char *errmsg, *name; 1836192895Sjamie int error, errmsg_len, errmsg_pos, fi, i, jid, len, locked, pos; 1837185435Sbz 1838191673Sjamie if (flags & ~JAIL_GET_MASK) 1839191673Sjamie return (EINVAL); 1840185435Sbz 1841191673Sjamie /* Get the parameter list. */ 1842191673Sjamie error = vfs_buildopts(optuio, &opts); 1843191673Sjamie if (error) 1844191673Sjamie return (error); 1845191673Sjamie errmsg_pos = vfs_getopt_pos(opts, "errmsg"); 1846192895Sjamie mypr = td->td_ucred->cr_prison; 1847185435Sbz 1848191673Sjamie /* 1849191673Sjamie * Find the prison specified by one of: lastjid, jid, name. 1850191673Sjamie */ 1851191673Sjamie sx_slock(&allprison_lock); 1852191673Sjamie error = vfs_copyopt(opts, "lastjid", &jid, sizeof(jid)); 1853191673Sjamie if (error == 0) { 1854191673Sjamie TAILQ_FOREACH(pr, &allprison, pr_list) { 1855192895Sjamie if (pr->pr_id > jid && prison_ischild(mypr, pr)) { 1856191673Sjamie mtx_lock(&pr->pr_mtx); 1857191673Sjamie if (pr->pr_ref > 0 && 1858191673Sjamie (pr->pr_uref > 0 || (flags & JAIL_DYING))) 1859191673Sjamie break; 1860191673Sjamie mtx_unlock(&pr->pr_mtx); 1861191673Sjamie } 1862191673Sjamie } 1863191673Sjamie if (pr != NULL) 1864191673Sjamie goto found_prison; 1865191673Sjamie error = ENOENT; 1866191673Sjamie vfs_opterror(opts, "no jail after %d", jid); 1867191673Sjamie goto done_unlock_list; 1868191673Sjamie } else if (error != ENOENT) 1869191673Sjamie goto done_unlock_list; 1870185435Sbz 1871191673Sjamie error = vfs_copyopt(opts, "jid", &jid, sizeof(jid)); 1872191673Sjamie if (error == 0) { 1873191673Sjamie if (jid != 0) { 1874192895Sjamie pr = prison_find_child(mypr, jid); 1875191673Sjamie if (pr != NULL) { 1876191673Sjamie if (pr->pr_uref == 0 && !(flags & JAIL_DYING)) { 1877191673Sjamie mtx_unlock(&pr->pr_mtx); 1878191673Sjamie error = ENOENT; 1879191673Sjamie vfs_opterror(opts, "jail %d is dying", 1880191673Sjamie jid); 1881191673Sjamie goto done_unlock_list; 1882191673Sjamie } 1883191673Sjamie goto found_prison; 1884191673Sjamie } 1885191673Sjamie error = ENOENT; 1886191673Sjamie vfs_opterror(opts, "jail %d not found", jid); 1887191673Sjamie goto done_unlock_list; 1888191673Sjamie } 1889191673Sjamie } else if (error != ENOENT) 1890191673Sjamie goto done_unlock_list; 189146155Sphk 1892191673Sjamie error = vfs_getopt(opts, "name", (void **)&name, &len); 1893191673Sjamie if (error == 0) { 1894191673Sjamie if (len == 0 || name[len - 1] != '\0') { 1895191673Sjamie error = EINVAL; 1896191673Sjamie goto done_unlock_list; 1897191673Sjamie } 1898192895Sjamie pr = prison_find_name(mypr, name); 1899191673Sjamie if (pr != NULL) { 1900191673Sjamie if (pr->pr_uref == 0 && !(flags & JAIL_DYING)) { 1901191673Sjamie mtx_unlock(&pr->pr_mtx); 1902191673Sjamie error = ENOENT; 1903191673Sjamie vfs_opterror(opts, "jail \"%s\" is dying", 1904191673Sjamie name); 1905191673Sjamie goto done_unlock_list; 1906191673Sjamie } 1907191673Sjamie goto found_prison; 1908191673Sjamie } 1909191673Sjamie error = ENOENT; 1910191673Sjamie vfs_opterror(opts, "jail \"%s\" not found", name); 1911191673Sjamie goto done_unlock_list; 1912191673Sjamie } else if (error != ENOENT) 1913191673Sjamie goto done_unlock_list; 1914185435Sbz 1915191673Sjamie vfs_opterror(opts, "no jail specified"); 1916191673Sjamie error = ENOENT; 1917191673Sjamie goto done_unlock_list; 1918191673Sjamie 1919191673Sjamie found_prison: 1920191673Sjamie /* Get the parameters of the prison. */ 1921191673Sjamie pr->pr_ref++; 1922191673Sjamie locked = PD_LOCKED; 1923191673Sjamie td->td_retval[0] = pr->pr_id; 1924191673Sjamie error = vfs_setopt(opts, "jid", &pr->pr_id, sizeof(pr->pr_id)); 1925191673Sjamie if (error != 0 && error != ENOENT) 1926191673Sjamie goto done_deref; 1927192895Sjamie i = (pr->pr_parent == mypr) ? 0 : pr->pr_parent->pr_id; 1928192895Sjamie error = vfs_setopt(opts, "parent", &i, sizeof(i)); 1929191673Sjamie if (error != 0 && error != ENOENT) 1930191673Sjamie goto done_deref; 1931192895Sjamie error = vfs_setopts(opts, "name", prison_name(mypr, pr)); 1932192895Sjamie if (error != 0 && error != ENOENT) 1933192895Sjamie goto done_deref; 1934192895Sjamie error = vfs_setopt(opts, "cpuset.id", &pr->pr_cpuset->cs_id, 1935191673Sjamie sizeof(pr->pr_cpuset->cs_id)); 1936191673Sjamie if (error != 0 && error != ENOENT) 1937191673Sjamie goto done_deref; 1938192895Sjamie error = vfs_setopts(opts, "path", prison_path(mypr, pr)); 1939191673Sjamie if (error != 0 && error != ENOENT) 1940191673Sjamie goto done_deref; 1941191673Sjamie#ifdef INET 1942191673Sjamie error = vfs_setopt_part(opts, "ip4.addr", pr->pr_ip4, 1943191673Sjamie pr->pr_ip4s * sizeof(*pr->pr_ip4)); 1944191673Sjamie if (error != 0 && error != ENOENT) 1945191673Sjamie goto done_deref; 1946191673Sjamie#endif 1947191673Sjamie#ifdef INET6 1948191673Sjamie error = vfs_setopt_part(opts, "ip6.addr", pr->pr_ip6, 1949191673Sjamie pr->pr_ip6s * sizeof(*pr->pr_ip6)); 1950191673Sjamie if (error != 0 && error != ENOENT) 1951191673Sjamie goto done_deref; 1952191673Sjamie#endif 1953191673Sjamie error = vfs_setopt(opts, "securelevel", &pr->pr_securelevel, 1954191673Sjamie sizeof(pr->pr_securelevel)); 1955191673Sjamie if (error != 0 && error != ENOENT) 1956191673Sjamie goto done_deref; 1957194762Sjamie error = vfs_setopt(opts, "children.cur", &pr->pr_childcount, 1958194762Sjamie sizeof(pr->pr_childcount)); 1959194762Sjamie if (error != 0 && error != ENOENT) 1960194762Sjamie goto done_deref; 1961194762Sjamie error = vfs_setopt(opts, "children.max", &pr->pr_childmax, 1962194762Sjamie sizeof(pr->pr_childmax)); 1963194762Sjamie if (error != 0 && error != ENOENT) 1964194762Sjamie goto done_deref; 1965194118Sjamie error = vfs_setopts(opts, "host.hostname", pr->pr_hostname); 1966191673Sjamie if (error != 0 && error != ENOENT) 1967191673Sjamie goto done_deref; 1968194118Sjamie error = vfs_setopts(opts, "host.domainname", pr->pr_domainname); 1969193066Sjamie if (error != 0 && error != ENOENT) 1970193066Sjamie goto done_deref; 1971194118Sjamie error = vfs_setopts(opts, "host.hostuuid", pr->pr_hostuuid); 1972193066Sjamie if (error != 0 && error != ENOENT) 1973193066Sjamie goto done_deref; 1974205014Snwhitehorn#ifdef COMPAT_FREEBSD32 1975205014Snwhitehorn if (td->td_proc->p_sysent->sv_flags & SV_ILP32) { 1976193066Sjamie uint32_t hid32 = pr->pr_hostid; 1977193066Sjamie 1978193066Sjamie error = vfs_setopt(opts, "host.hostid", &hid32, sizeof(hid32)); 1979193066Sjamie } else 1980193066Sjamie#endif 1981193066Sjamie error = vfs_setopt(opts, "host.hostid", &pr->pr_hostid, 1982193066Sjamie sizeof(pr->pr_hostid)); 1983193066Sjamie if (error != 0 && error != ENOENT) 1984193066Sjamie goto done_deref; 1985192895Sjamie error = vfs_setopt(opts, "enforce_statfs", &pr->pr_enforce_statfs, 1986192895Sjamie sizeof(pr->pr_enforce_statfs)); 1987191673Sjamie if (error != 0 && error != ENOENT) 1988191673Sjamie goto done_deref; 1989192895Sjamie for (fi = 0; fi < sizeof(pr_flag_names) / sizeof(pr_flag_names[0]); 1990192895Sjamie fi++) { 1991192895Sjamie if (pr_flag_names[fi] == NULL) 1992192895Sjamie continue; 1993192895Sjamie i = (pr->pr_flags & (1 << fi)) ? 1 : 0; 1994192895Sjamie error = vfs_setopt(opts, pr_flag_names[fi], &i, sizeof(i)); 1995192895Sjamie if (error != 0 && error != ENOENT) 1996192895Sjamie goto done_deref; 1997192895Sjamie i = !i; 1998192895Sjamie error = vfs_setopt(opts, pr_flag_nonames[fi], &i, sizeof(i)); 1999192895Sjamie if (error != 0 && error != ENOENT) 2000192895Sjamie goto done_deref; 2001192895Sjamie } 2002195870Sjamie for (fi = 0; fi < sizeof(pr_flag_jailsys) / sizeof(pr_flag_jailsys[0]); 2003195870Sjamie fi++) { 2004195870Sjamie i = pr->pr_flags & 2005195870Sjamie (pr_flag_jailsys[fi].disable | pr_flag_jailsys[fi].new); 2006195870Sjamie i = pr_flag_jailsys[fi].disable && 2007195870Sjamie (i == pr_flag_jailsys[fi].disable) ? JAIL_SYS_DISABLE 2008195870Sjamie : (i == pr_flag_jailsys[fi].new) ? JAIL_SYS_NEW 2009195870Sjamie : JAIL_SYS_INHERIT; 2010195870Sjamie error = 2011195870Sjamie vfs_setopt(opts, pr_flag_jailsys[fi].name, &i, sizeof(i)); 2012195870Sjamie if (error != 0 && error != ENOENT) 2013195870Sjamie goto done_deref; 2014195870Sjamie } 2015192895Sjamie for (fi = 0; fi < sizeof(pr_allow_names) / sizeof(pr_allow_names[0]); 2016192895Sjamie fi++) { 2017192895Sjamie if (pr_allow_names[fi] == NULL) 2018192895Sjamie continue; 2019192895Sjamie i = (pr->pr_allow & (1 << fi)) ? 1 : 0; 2020192895Sjamie error = vfs_setopt(opts, pr_allow_names[fi], &i, sizeof(i)); 2021192895Sjamie if (error != 0 && error != ENOENT) 2022192895Sjamie goto done_deref; 2023192895Sjamie i = !i; 2024192895Sjamie error = vfs_setopt(opts, pr_allow_nonames[fi], &i, sizeof(i)); 2025192895Sjamie if (error != 0 && error != ENOENT) 2026192895Sjamie goto done_deref; 2027192895Sjamie } 2028191673Sjamie i = (pr->pr_uref == 0); 2029191673Sjamie error = vfs_setopt(opts, "dying", &i, sizeof(i)); 2030191673Sjamie if (error != 0 && error != ENOENT) 2031191673Sjamie goto done_deref; 2032191673Sjamie i = !i; 2033191673Sjamie error = vfs_setopt(opts, "nodying", &i, sizeof(i)); 2034191673Sjamie if (error != 0 && error != ENOENT) 2035191673Sjamie goto done_deref; 2036191673Sjamie 2037191673Sjamie /* Get the module parameters. */ 2038191673Sjamie mtx_unlock(&pr->pr_mtx); 2039191673Sjamie locked = 0; 2040191673Sjamie error = osd_jail_call(pr, PR_METHOD_GET, opts); 204146155Sphk if (error) 2042191673Sjamie goto done_deref; 2043191673Sjamie prison_deref(pr, PD_DEREF | PD_LIST_SLOCKED); 204484828Sjhb 2045191673Sjamie /* By now, all parameters should have been noted. */ 2046191673Sjamie TAILQ_FOREACH(opt, opts, link) { 2047191673Sjamie if (!opt->seen && strcmp(opt->name, "errmsg")) { 2048191673Sjamie error = EINVAL; 2049191673Sjamie vfs_opterror(opts, "unknown parameter: %s", opt->name); 2050191673Sjamie goto done_errmsg; 2051191673Sjamie } 2052185435Sbz } 2053191673Sjamie 2054191673Sjamie /* Write the fetched parameters back to userspace. */ 2055191673Sjamie error = 0; 2056191673Sjamie TAILQ_FOREACH(opt, opts, link) { 2057191673Sjamie if (opt->pos >= 0 && opt->pos != errmsg_pos) { 2058191673Sjamie pos = 2 * opt->pos + 1; 2059191673Sjamie optuio->uio_iov[pos].iov_len = opt->len; 2060191673Sjamie if (opt->value != NULL) { 2061191673Sjamie if (optuio->uio_segflg == UIO_SYSSPACE) { 2062191673Sjamie bcopy(opt->value, 2063191673Sjamie optuio->uio_iov[pos].iov_base, 2064191673Sjamie opt->len); 2065191673Sjamie } else { 2066191673Sjamie error = copyout(opt->value, 2067191673Sjamie optuio->uio_iov[pos].iov_base, 2068191673Sjamie opt->len); 2069191673Sjamie if (error) 2070191673Sjamie break; 2071191673Sjamie } 2072191673Sjamie } 2073191673Sjamie } 2074185435Sbz } 2075191673Sjamie goto done_errmsg; 2076191673Sjamie 2077191673Sjamie done_deref: 2078191673Sjamie prison_deref(pr, locked | PD_DEREF | PD_LIST_SLOCKED); 2079191673Sjamie goto done_errmsg; 2080191673Sjamie 2081191673Sjamie done_unlock_list: 2082191673Sjamie sx_sunlock(&allprison_lock); 2083191673Sjamie done_errmsg: 2084191673Sjamie if (error && errmsg_pos >= 0) { 2085191673Sjamie vfs_getopt(opts, "errmsg", (void **)&errmsg, &errmsg_len); 2086191673Sjamie errmsg_pos = 2 * errmsg_pos + 1; 2087191673Sjamie if (errmsg_len > 0) { 2088191673Sjamie if (optuio->uio_segflg == UIO_SYSSPACE) 2089191673Sjamie bcopy(errmsg, 2090191673Sjamie optuio->uio_iov[errmsg_pos].iov_base, 2091191673Sjamie errmsg_len); 2092191673Sjamie else 2093191673Sjamie copyout(errmsg, 2094191673Sjamie optuio->uio_iov[errmsg_pos].iov_base, 2095191673Sjamie errmsg_len); 2096191673Sjamie } 2097185435Sbz } 2098191673Sjamie vfs_freeopts(opts); 2099191673Sjamie return (error); 2100191673Sjamie} 2101113275Smike 2102192895Sjamie 2103191673Sjamie/* 2104191673Sjamie * struct jail_remove_args { 2105191673Sjamie * int jid; 2106191673Sjamie * }; 2107191673Sjamie */ 2108191673Sjamieint 2109191673Sjamiejail_remove(struct thread *td, struct jail_remove_args *uap) 2110191673Sjamie{ 2111192895Sjamie struct prison *pr, *cpr, *lpr, *tpr; 2112192895Sjamie int descend, error; 2113185435Sbz 2114191673Sjamie error = priv_check(td, PRIV_JAIL_REMOVE); 2115185435Sbz if (error) 2116191673Sjamie return (error); 2117185435Sbz 2118185435Sbz sx_xlock(&allprison_lock); 2119192895Sjamie pr = prison_find_child(td->td_ucred->cr_prison, uap->jid); 2120191673Sjamie if (pr == NULL) { 2121185435Sbz sx_xunlock(&allprison_lock); 2122191673Sjamie return (EINVAL); 2123185435Sbz } 2124185435Sbz 2125192895Sjamie /* Remove all descendants of this prison, then remove this prison. */ 2126192895Sjamie pr->pr_ref++; 2127192895Sjamie pr->pr_flags |= PR_REMOVE; 2128192895Sjamie if (!LIST_EMPTY(&pr->pr_children)) { 2129192895Sjamie mtx_unlock(&pr->pr_mtx); 2130192895Sjamie lpr = NULL; 2131192895Sjamie FOREACH_PRISON_DESCENDANT(pr, cpr, descend) { 2132192895Sjamie mtx_lock(&cpr->pr_mtx); 2133192895Sjamie if (cpr->pr_ref > 0) { 2134192895Sjamie tpr = cpr; 2135192895Sjamie cpr->pr_ref++; 2136192895Sjamie cpr->pr_flags |= PR_REMOVE; 2137192895Sjamie } else { 2138192895Sjamie /* Already removed - do not do it again. */ 2139192895Sjamie tpr = NULL; 2140192895Sjamie } 2141192895Sjamie mtx_unlock(&cpr->pr_mtx); 2142192895Sjamie if (lpr != NULL) { 2143192895Sjamie mtx_lock(&lpr->pr_mtx); 2144192895Sjamie prison_remove_one(lpr); 2145192895Sjamie sx_xlock(&allprison_lock); 2146192895Sjamie } 2147192895Sjamie lpr = tpr; 2148192895Sjamie } 2149192895Sjamie if (lpr != NULL) { 2150192895Sjamie mtx_lock(&lpr->pr_mtx); 2151192895Sjamie prison_remove_one(lpr); 2152192895Sjamie sx_xlock(&allprison_lock); 2153192895Sjamie } 2154192895Sjamie mtx_lock(&pr->pr_mtx); 2155192895Sjamie } 2156192895Sjamie prison_remove_one(pr); 2157192895Sjamie return (0); 2158192895Sjamie} 2159192895Sjamie 2160192895Sjamiestatic void 2161192895Sjamieprison_remove_one(struct prison *pr) 2162192895Sjamie{ 2163192895Sjamie struct proc *p; 2164192895Sjamie int deuref; 2165192895Sjamie 2166191673Sjamie /* If the prison was persistent, it is not anymore. */ 2167191673Sjamie deuref = 0; 2168191673Sjamie if (pr->pr_flags & PR_PERSIST) { 2169191673Sjamie pr->pr_ref--; 2170191673Sjamie deuref = PD_DEUREF; 2171191673Sjamie pr->pr_flags &= ~PR_PERSIST; 2172179881Sdelphij } 2173113275Smike 2174192895Sjamie /* 2175192895Sjamie * jail_remove added a reference. If that's the only one, remove 2176192895Sjamie * the prison now. 2177192895Sjamie */ 2178192895Sjamie KASSERT(pr->pr_ref > 0, 2179192895Sjamie ("prison_remove_one removing a dead prison (jid=%d)", pr->pr_id)); 2180192895Sjamie if (pr->pr_ref == 1) { 2181191673Sjamie prison_deref(pr, 2182191673Sjamie deuref | PD_DEREF | PD_LOCKED | PD_LIST_XLOCKED); 2183192895Sjamie return; 2184191673Sjamie } 2185191673Sjamie 2186113275Smike mtx_unlock(&pr->pr_mtx); 2187191673Sjamie sx_xunlock(&allprison_lock); 2188191673Sjamie /* 2189191673Sjamie * Kill all processes unfortunate enough to be attached to this prison. 2190191673Sjamie */ 2191191673Sjamie sx_slock(&allproc_lock); 2192191673Sjamie LIST_FOREACH(p, &allproc, p_list) { 2193191673Sjamie PROC_LOCK(p); 2194191673Sjamie if (p->p_state != PRS_NEW && p->p_ucred && 2195191673Sjamie p->p_ucred->cr_prison == pr) 2196191673Sjamie psignal(p, SIGKILL); 2197191673Sjamie PROC_UNLOCK(p); 2198191673Sjamie } 2199191673Sjamie sx_sunlock(&allproc_lock); 2200192895Sjamie /* Remove the temporary reference added by jail_remove. */ 2201191673Sjamie prison_deref(pr, deuref | PD_DEREF); 2202113275Smike} 2203113275Smike 2204190466Sjamie 2205113275Smike/* 2206114168Smike * struct jail_attach_args { 2207114168Smike * int jid; 2208114168Smike * }; 2209113275Smike */ 2210113275Smikeint 2211114168Smikejail_attach(struct thread *td, struct jail_attach_args *uap) 2212113275Smike{ 2213113275Smike struct prison *pr; 2214191673Sjamie int error; 2215167309Spjd 2216164032Srwatson error = priv_check(td, PRIV_JAIL_ATTACH); 2217126023Snectar if (error) 2218126023Snectar return (error); 2219126023Snectar 2220168401Spjd sx_slock(&allprison_lock); 2221192895Sjamie pr = prison_find_child(td->td_ucred->cr_prison, uap->jid); 2222113275Smike if (pr == NULL) { 2223168401Spjd sx_sunlock(&allprison_lock); 2224113275Smike return (EINVAL); 2225113275Smike } 2226185435Sbz 2227185435Sbz /* 2228185435Sbz * Do not allow a process to attach to a prison that is not 2229191673Sjamie * considered to be "alive". 2230185435Sbz */ 2231191673Sjamie if (pr->pr_uref == 0) { 2232185435Sbz mtx_unlock(&pr->pr_mtx); 2233185435Sbz sx_sunlock(&allprison_lock); 2234185435Sbz return (EINVAL); 2235185435Sbz } 2236191673Sjamie 2237191673Sjamie return (do_jail_attach(td, pr)); 2238191673Sjamie} 2239191673Sjamie 2240191673Sjamiestatic int 2241191673Sjamiedo_jail_attach(struct thread *td, struct prison *pr) 2242191673Sjamie{ 2243192895Sjamie struct prison *ppr; 2244191673Sjamie struct proc *p; 2245191673Sjamie struct ucred *newcred, *oldcred; 2246191673Sjamie int vfslocked, error; 2247191673Sjamie 2248191673Sjamie /* 2249191673Sjamie * XXX: Note that there is a slight race here if two threads 2250191673Sjamie * in the same privileged process attempt to attach to two 2251191673Sjamie * different jails at the same time. It is important for 2252191673Sjamie * user processes not to do this, or they might end up with 2253191673Sjamie * a process root from one prison, but attached to the jail 2254191673Sjamie * of another. 2255191673Sjamie */ 2256113275Smike pr->pr_ref++; 2257191673Sjamie pr->pr_uref++; 2258113275Smike mtx_unlock(&pr->pr_mtx); 2259191673Sjamie 2260191673Sjamie /* Let modules do whatever they need to prepare for attaching. */ 2261191673Sjamie error = osd_jail_call(pr, PR_METHOD_ATTACH, td); 2262191673Sjamie if (error) { 2263191673Sjamie prison_deref(pr, PD_DEREF | PD_DEUREF | PD_LIST_SLOCKED); 2264191673Sjamie return (error); 2265191673Sjamie } 2266168401Spjd sx_sunlock(&allprison_lock); 2267113275Smike 2268185435Sbz /* 2269185435Sbz * Reparent the newly attached process to this jail. 2270185435Sbz */ 2271192895Sjamie ppr = td->td_ucred->cr_prison; 2272191673Sjamie p = td->td_proc; 2273185435Sbz error = cpuset_setproc_update_set(p, pr->pr_cpuset); 2274185435Sbz if (error) 2275191673Sjamie goto e_revert_osd; 2276185435Sbz 2277150652Scsjp vfslocked = VFS_LOCK_GIANT(pr->pr_root->v_mount); 2278175202Sattilio vn_lock(pr->pr_root, LK_EXCLUSIVE | LK_RETRY); 2279113275Smike if ((error = change_dir(pr->pr_root, td)) != 0) 2280113275Smike goto e_unlock; 2281113275Smike#ifdef MAC 2282172930Srwatson if ((error = mac_vnode_check_chroot(td->td_ucred, pr->pr_root))) 2283113275Smike goto e_unlock; 2284113275Smike#endif 2285175294Sattilio VOP_UNLOCK(pr->pr_root, 0); 2286191673Sjamie if ((error = change_root(pr->pr_root, td))) 2287191673Sjamie goto e_unlock_giant; 2288150652Scsjp VFS_UNLOCK_GIANT(vfslocked); 2289113275Smike 229084828Sjhb newcred = crget(); 229184828Sjhb PROC_LOCK(p); 229284828Sjhb oldcred = p->p_ucred; 2293113275Smike setsugid(p); 229484828Sjhb crcopy(newcred, oldcred); 2295113630Sjhb newcred->cr_prison = pr; 229684828Sjhb p->p_ucred = newcred; 229784828Sjhb PROC_UNLOCK(p); 229884828Sjhb crfree(oldcred); 2299192895Sjamie prison_deref(ppr, PD_DEREF | PD_DEUREF); 230046155Sphk return (0); 2301191673Sjamie e_unlock: 2302175294Sattilio VOP_UNLOCK(pr->pr_root, 0); 2303191673Sjamie e_unlock_giant: 2304150652Scsjp VFS_UNLOCK_GIANT(vfslocked); 2305191673Sjamie e_revert_osd: 2306191673Sjamie /* Tell modules this thread is still in its old jail after all. */ 2307192895Sjamie (void)osd_jail_call(ppr, PR_METHOD_ATTACH, td); 2308191673Sjamie prison_deref(pr, PD_DEREF | PD_DEUREF); 230946155Sphk return (error); 231046155Sphk} 231146155Sphk 2312192895Sjamie 2313113275Smike/* 2314113275Smike * Returns a locked prison instance, or NULL on failure. 2315113275Smike */ 2316168399Spjdstruct prison * 2317113275Smikeprison_find(int prid) 2318113275Smike{ 2319113275Smike struct prison *pr; 2320113275Smike 2321168401Spjd sx_assert(&allprison_lock, SX_LOCKED); 2322191673Sjamie TAILQ_FOREACH(pr, &allprison, pr_list) { 2323113275Smike if (pr->pr_id == prid) { 2324113275Smike mtx_lock(&pr->pr_mtx); 2325191673Sjamie if (pr->pr_ref > 0) 2326191673Sjamie return (pr); 2327191673Sjamie mtx_unlock(&pr->pr_mtx); 2328113275Smike } 2329113275Smike } 2330113275Smike return (NULL); 2331113275Smike} 2332113275Smike 2333191673Sjamie/* 2334192895Sjamie * Find a prison that is a descendant of mypr. Returns a locked prison or NULL. 2335191673Sjamie */ 2336191673Sjamiestruct prison * 2337192895Sjamieprison_find_child(struct prison *mypr, int prid) 2338191673Sjamie{ 2339192895Sjamie struct prison *pr; 2340192895Sjamie int descend; 2341192895Sjamie 2342192895Sjamie sx_assert(&allprison_lock, SX_LOCKED); 2343192895Sjamie FOREACH_PRISON_DESCENDANT(mypr, pr, descend) { 2344192895Sjamie if (pr->pr_id == prid) { 2345192895Sjamie mtx_lock(&pr->pr_mtx); 2346192895Sjamie if (pr->pr_ref > 0) 2347192895Sjamie return (pr); 2348192895Sjamie mtx_unlock(&pr->pr_mtx); 2349192895Sjamie } 2350192895Sjamie } 2351192895Sjamie return (NULL); 2352192895Sjamie} 2353192895Sjamie 2354192895Sjamie/* 2355192895Sjamie * Look for the name relative to mypr. Returns a locked prison or NULL. 2356192895Sjamie */ 2357192895Sjamiestruct prison * 2358192895Sjamieprison_find_name(struct prison *mypr, const char *name) 2359192895Sjamie{ 2360191673Sjamie struct prison *pr, *deadpr; 2361192895Sjamie size_t mylen; 2362192895Sjamie int descend; 2363191673Sjamie 2364191673Sjamie sx_assert(&allprison_lock, SX_LOCKED); 2365192895Sjamie mylen = (mypr == &prison0) ? 0 : strlen(mypr->pr_name) + 1; 2366191673Sjamie again: 2367191673Sjamie deadpr = NULL; 2368192895Sjamie FOREACH_PRISON_DESCENDANT(mypr, pr, descend) { 2369192895Sjamie if (!strcmp(pr->pr_name + mylen, name)) { 2370191673Sjamie mtx_lock(&pr->pr_mtx); 2371191673Sjamie if (pr->pr_ref > 0) { 2372191673Sjamie if (pr->pr_uref > 0) 2373191673Sjamie return (pr); 2374191673Sjamie deadpr = pr; 2375191673Sjamie } 2376191673Sjamie mtx_unlock(&pr->pr_mtx); 2377191673Sjamie } 2378191673Sjamie } 2379192895Sjamie /* There was no valid prison - perhaps there was a dying one. */ 2380191673Sjamie if (deadpr != NULL) { 2381191673Sjamie mtx_lock(&deadpr->pr_mtx); 2382191673Sjamie if (deadpr->pr_ref == 0) { 2383191673Sjamie mtx_unlock(&deadpr->pr_mtx); 2384191673Sjamie goto again; 2385191673Sjamie } 2386191673Sjamie } 2387191673Sjamie return (deadpr); 2388191673Sjamie} 2389191673Sjamie 2390191673Sjamie/* 2391192895Sjamie * See if a prison has the specific flag set. 2392192895Sjamie */ 2393192895Sjamieint 2394192895Sjamieprison_flag(struct ucred *cred, unsigned flag) 2395192895Sjamie{ 2396192895Sjamie 2397192895Sjamie /* This is an atomic read, so no locking is necessary. */ 2398192895Sjamie return (cred->cr_prison->pr_flags & flag); 2399192895Sjamie} 2400192895Sjamie 2401192895Sjamieint 2402192895Sjamieprison_allow(struct ucred *cred, unsigned flag) 2403192895Sjamie{ 2404192895Sjamie 2405192895Sjamie /* This is an atomic read, so no locking is necessary. */ 2406192895Sjamie return (cred->cr_prison->pr_allow & flag); 2407192895Sjamie} 2408192895Sjamie 2409192895Sjamie/* 2410191673Sjamie * Remove a prison reference. If that was the last reference, remove the 2411191673Sjamie * prison itself - but not in this context in case there are locks held. 2412191673Sjamie */ 241372786Srwatsonvoid 2414185029Spjdprison_free_locked(struct prison *pr) 241572786Srwatson{ 241672786Srwatson 2417185029Spjd mtx_assert(&pr->pr_mtx, MA_OWNED); 241872786Srwatson pr->pr_ref--; 241972786Srwatson if (pr->pr_ref == 0) { 2420168483Spjd mtx_unlock(&pr->pr_mtx); 2421124882Srwatson TASK_INIT(&pr->pr_task, 0, prison_complete, pr); 2422144660Sjeff taskqueue_enqueue(taskqueue_thread, &pr->pr_task); 242387275Srwatson return; 242472786Srwatson } 242587275Srwatson mtx_unlock(&pr->pr_mtx); 242672786Srwatson} 242772786Srwatson 2428185029Spjdvoid 2429185029Spjdprison_free(struct prison *pr) 2430185029Spjd{ 2431185029Spjd 2432185029Spjd mtx_lock(&pr->pr_mtx); 2433185029Spjd prison_free_locked(pr); 2434185029Spjd} 2435185029Spjd 2436124882Srwatsonstatic void 2437124882Srwatsonprison_complete(void *context, int pending) 2438124882Srwatson{ 2439191673Sjamie 2440191673Sjamie prison_deref((struct prison *)context, 0); 2441191673Sjamie} 2442191673Sjamie 2443191673Sjamie/* 2444191673Sjamie * Remove a prison reference (usually). This internal version assumes no 2445191673Sjamie * mutexes are held, except perhaps the prison itself. If there are no more 2446191673Sjamie * references, release and delist the prison. On completion, the prison lock 2447191673Sjamie * and the allprison lock are both unlocked. 2448191673Sjamie */ 2449191673Sjamiestatic void 2450191673Sjamieprison_deref(struct prison *pr, int flags) 2451191673Sjamie{ 2452192895Sjamie struct prison *ppr, *tpr; 2453150652Scsjp int vfslocked; 2454124882Srwatson 2455191673Sjamie if (!(flags & PD_LOCKED)) 2456191673Sjamie mtx_lock(&pr->pr_mtx); 2457192895Sjamie /* Decrement the user references in a separate loop. */ 2458191673Sjamie if (flags & PD_DEUREF) { 2459192895Sjamie for (tpr = pr;; tpr = tpr->pr_parent) { 2460192895Sjamie if (tpr != pr) 2461192895Sjamie mtx_lock(&tpr->pr_mtx); 2462192895Sjamie if (--tpr->pr_uref > 0) 2463192895Sjamie break; 2464192895Sjamie KASSERT(tpr != &prison0, ("prison0 pr_uref=0")); 2465192895Sjamie mtx_unlock(&tpr->pr_mtx); 2466192895Sjamie } 2467191673Sjamie /* Done if there were only user references to remove. */ 2468191673Sjamie if (!(flags & PD_DEREF)) { 2469192895Sjamie mtx_unlock(&tpr->pr_mtx); 2470191673Sjamie if (flags & PD_LIST_SLOCKED) 2471191673Sjamie sx_sunlock(&allprison_lock); 2472191673Sjamie else if (flags & PD_LIST_XLOCKED) 2473191673Sjamie sx_xunlock(&allprison_lock); 2474191673Sjamie return; 2475191673Sjamie } 2476192895Sjamie if (tpr != pr) { 2477192895Sjamie mtx_unlock(&tpr->pr_mtx); 2478192895Sjamie mtx_lock(&pr->pr_mtx); 2479192895Sjamie } 2480191673Sjamie } 2481124882Srwatson 2482192895Sjamie for (;;) { 2483192895Sjamie if (flags & PD_DEREF) 2484192895Sjamie pr->pr_ref--; 2485192895Sjamie /* If the prison still has references, nothing else to do. */ 2486192895Sjamie if (pr->pr_ref > 0) { 2487192895Sjamie mtx_unlock(&pr->pr_mtx); 2488192895Sjamie if (flags & PD_LIST_SLOCKED) 2489192895Sjamie sx_sunlock(&allprison_lock); 2490192895Sjamie else if (flags & PD_LIST_XLOCKED) 2491192895Sjamie sx_xunlock(&allprison_lock); 2492192895Sjamie return; 2493191673Sjamie } 2494191673Sjamie 2495192895Sjamie mtx_unlock(&pr->pr_mtx); 2496192895Sjamie if (flags & PD_LIST_SLOCKED) { 2497192895Sjamie if (!sx_try_upgrade(&allprison_lock)) { 2498192895Sjamie sx_sunlock(&allprison_lock); 2499192895Sjamie sx_xlock(&allprison_lock); 2500192895Sjamie } 2501192895Sjamie } else if (!(flags & PD_LIST_XLOCKED)) 2502192895Sjamie sx_xlock(&allprison_lock); 2503168489Spjd 2504192895Sjamie TAILQ_REMOVE(&allprison, pr, pr_list); 2505192895Sjamie LIST_REMOVE(pr, pr_sibling); 2506192895Sjamie ppr = pr->pr_parent; 2507192895Sjamie for (tpr = ppr; tpr != NULL; tpr = tpr->pr_parent) 2508194762Sjamie tpr->pr_childcount--; 2509196592Sjamie sx_xunlock(&allprison_lock); 2510192895Sjamie 2511194251Sjamie#ifdef VIMAGE 2512196505Szec if (pr->pr_vnet != ppr->pr_vnet) 2513194251Sjamie vnet_destroy(pr->pr_vnet); 2514194251Sjamie#endif 2515192895Sjamie if (pr->pr_root != NULL) { 2516192895Sjamie vfslocked = VFS_LOCK_GIANT(pr->pr_root->v_mount); 2517192895Sjamie vrele(pr->pr_root); 2518192895Sjamie VFS_UNLOCK_GIANT(vfslocked); 2519192895Sjamie } 2520192895Sjamie mtx_destroy(&pr->pr_mtx); 2521191673Sjamie#ifdef INET 2522192895Sjamie free(pr->pr_ip4, M_PRISON); 2523191673Sjamie#endif 2524185435Sbz#ifdef INET6 2525192895Sjamie free(pr->pr_ip6, M_PRISON); 2526185435Sbz#endif 2527192895Sjamie if (pr->pr_cpuset != NULL) 2528192895Sjamie cpuset_rel(pr->pr_cpuset); 2529192895Sjamie osd_jail_exit(pr); 2530192895Sjamie free(pr, M_PRISON); 2531192895Sjamie 2532192895Sjamie /* Removing a prison frees a reference on its parent. */ 2533192895Sjamie pr = ppr; 2534192895Sjamie mtx_lock(&pr->pr_mtx); 2535196592Sjamie flags = PD_DEREF; 2536192895Sjamie } 2537124882Srwatson} 2538124882Srwatson 253972786Srwatsonvoid 2540185029Spjdprison_hold_locked(struct prison *pr) 254172786Srwatson{ 254272786Srwatson 2543185029Spjd mtx_assert(&pr->pr_mtx, MA_OWNED); 2544168489Spjd KASSERT(pr->pr_ref > 0, 2545191671Sjamie ("Trying to hold dead prison (jid=%d).", pr->pr_id)); 254672786Srwatson pr->pr_ref++; 2547185029Spjd} 2548185029Spjd 2549185029Spjdvoid 2550185029Spjdprison_hold(struct prison *pr) 2551185029Spjd{ 2552185029Spjd 2553185029Spjd mtx_lock(&pr->pr_mtx); 2554185029Spjd prison_hold_locked(pr); 255587275Srwatson mtx_unlock(&pr->pr_mtx); 255672786Srwatson} 255772786Srwatson 2558185435Sbzvoid 2559185435Sbzprison_proc_hold(struct prison *pr) 256087275Srwatson{ 256187275Srwatson 2562185435Sbz mtx_lock(&pr->pr_mtx); 2563191673Sjamie KASSERT(pr->pr_uref > 0, 2564191673Sjamie ("Cannot add a process to a non-alive prison (jid=%d)", pr->pr_id)); 2565191673Sjamie pr->pr_uref++; 2566185435Sbz mtx_unlock(&pr->pr_mtx); 256787275Srwatson} 256887275Srwatson 2569185435Sbzvoid 2570185435Sbzprison_proc_free(struct prison *pr) 2571185435Sbz{ 2572185435Sbz 2573185435Sbz mtx_lock(&pr->pr_mtx); 2574191673Sjamie KASSERT(pr->pr_uref > 0, 2575191673Sjamie ("Trying to kill a process in a dead prison (jid=%d)", pr->pr_id)); 2576191673Sjamie prison_deref(pr, PD_DEUREF | PD_LOCKED); 2577185435Sbz} 2578185435Sbz 2579185435Sbz 2580185435Sbz#ifdef INET 2581185435Sbz/* 2582192895Sjamie * Restrict a prison's IP address list with its parent's, possibly replacing 2583192895Sjamie * it. Return true if the replacement buffer was used (or would have been). 2584192895Sjamie */ 2585192895Sjamiestatic int 2586192895Sjamieprison_restrict_ip4(struct prison *pr, struct in_addr *newip4) 2587192895Sjamie{ 2588192895Sjamie int ii, ij, used; 2589192895Sjamie struct prison *ppr; 2590192895Sjamie 2591192895Sjamie ppr = pr->pr_parent; 2592192895Sjamie if (!(pr->pr_flags & PR_IP4_USER)) { 2593192895Sjamie /* This has no user settings, so just copy the parent's list. */ 2594192895Sjamie if (pr->pr_ip4s < ppr->pr_ip4s) { 2595192895Sjamie /* 2596192895Sjamie * There's no room for the parent's list. Use the 2597192895Sjamie * new list buffer, which is assumed to be big enough 2598192895Sjamie * (if it was passed). If there's no buffer, try to 2599192895Sjamie * allocate one. 2600192895Sjamie */ 2601192895Sjamie used = 1; 2602192895Sjamie if (newip4 == NULL) { 2603192895Sjamie newip4 = malloc(ppr->pr_ip4s * sizeof(*newip4), 2604192895Sjamie M_PRISON, M_NOWAIT); 2605192895Sjamie if (newip4 != NULL) 2606192895Sjamie used = 0; 2607192895Sjamie } 2608192895Sjamie if (newip4 != NULL) { 2609192895Sjamie bcopy(ppr->pr_ip4, newip4, 2610192895Sjamie ppr->pr_ip4s * sizeof(*newip4)); 2611192895Sjamie free(pr->pr_ip4, M_PRISON); 2612192895Sjamie pr->pr_ip4 = newip4; 2613192895Sjamie pr->pr_ip4s = ppr->pr_ip4s; 2614192895Sjamie } 2615192895Sjamie return (used); 2616192895Sjamie } 2617192895Sjamie pr->pr_ip4s = ppr->pr_ip4s; 2618192895Sjamie if (pr->pr_ip4s > 0) 2619192895Sjamie bcopy(ppr->pr_ip4, pr->pr_ip4, 2620192895Sjamie pr->pr_ip4s * sizeof(*newip4)); 2621192895Sjamie else if (pr->pr_ip4 != NULL) { 2622192895Sjamie free(pr->pr_ip4, M_PRISON); 2623192895Sjamie pr->pr_ip4 = NULL; 2624192895Sjamie } 2625195974Sjamie } else if (pr->pr_ip4s > 0) { 2626192895Sjamie /* Remove addresses that aren't in the parent. */ 2627192895Sjamie for (ij = 0; ij < ppr->pr_ip4s; ij++) 2628192895Sjamie if (pr->pr_ip4[0].s_addr == ppr->pr_ip4[ij].s_addr) 2629192895Sjamie break; 2630192895Sjamie if (ij < ppr->pr_ip4s) 2631192895Sjamie ii = 1; 2632192895Sjamie else { 2633192895Sjamie bcopy(pr->pr_ip4 + 1, pr->pr_ip4, 2634192895Sjamie --pr->pr_ip4s * sizeof(*pr->pr_ip4)); 2635192895Sjamie ii = 0; 2636192895Sjamie } 2637192895Sjamie for (ij = 1; ii < pr->pr_ip4s; ) { 2638192895Sjamie if (pr->pr_ip4[ii].s_addr == ppr->pr_ip4[0].s_addr) { 2639192895Sjamie ii++; 2640192895Sjamie continue; 2641192895Sjamie } 2642192895Sjamie switch (ij >= ppr->pr_ip4s ? -1 : 2643192895Sjamie qcmp_v4(&pr->pr_ip4[ii], &ppr->pr_ip4[ij])) { 2644192895Sjamie case -1: 2645192895Sjamie bcopy(pr->pr_ip4 + ii + 1, pr->pr_ip4 + ii, 2646192895Sjamie (--pr->pr_ip4s - ii) * sizeof(*pr->pr_ip4)); 2647192895Sjamie break; 2648192895Sjamie case 0: 2649192895Sjamie ii++; 2650192895Sjamie ij++; 2651192895Sjamie break; 2652192895Sjamie case 1: 2653192895Sjamie ij++; 2654192895Sjamie break; 2655192895Sjamie } 2656192895Sjamie } 2657192895Sjamie if (pr->pr_ip4s == 0) { 2658195870Sjamie pr->pr_flags |= PR_IP4_DISABLE; 2659192895Sjamie free(pr->pr_ip4, M_PRISON); 2660192895Sjamie pr->pr_ip4 = NULL; 2661192895Sjamie } 2662192895Sjamie } 2663192895Sjamie return (0); 2664192895Sjamie} 2665192895Sjamie 2666192895Sjamie/* 2667185435Sbz * Pass back primary IPv4 address of this jail. 2668185435Sbz * 2669192895Sjamie * If not restricted return success but do not alter the address. Caller has 2670192895Sjamie * to make sure to initialize it correctly (e.g. INADDR_ANY). 2671185435Sbz * 2672188144Sjamie * Returns 0 on success, EAFNOSUPPORT if the jail doesn't allow IPv4. 2673188144Sjamie * Address returned in NBO. 2674185435Sbz */ 267546155Sphkint 2676187684Sbzprison_get_ip4(struct ucred *cred, struct in_addr *ia) 267746155Sphk{ 2678191673Sjamie struct prison *pr; 267946155Sphk 2680185435Sbz KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 2681185435Sbz KASSERT(ia != NULL, ("%s: ia is NULL", __func__)); 2682185435Sbz 2683192895Sjamie pr = cred->cr_prison; 2684192895Sjamie if (!(pr->pr_flags & PR_IP4)) 268546155Sphk return (0); 2686191673Sjamie mtx_lock(&pr->pr_mtx); 2687192895Sjamie if (!(pr->pr_flags & PR_IP4)) { 2688192895Sjamie mtx_unlock(&pr->pr_mtx); 2689192895Sjamie return (0); 2690192895Sjamie } 2691191673Sjamie if (pr->pr_ip4 == NULL) { 2692191673Sjamie mtx_unlock(&pr->pr_mtx); 2693188144Sjamie return (EAFNOSUPPORT); 2694191673Sjamie } 2695185435Sbz 2696191673Sjamie ia->s_addr = pr->pr_ip4[0].s_addr; 2697191673Sjamie mtx_unlock(&pr->pr_mtx); 2698185435Sbz return (0); 2699185435Sbz} 2700185435Sbz 2701185435Sbz/* 2702202468Sbz * Return 1 if we should do proper source address selection or are not jailed. 2703202468Sbz * We will return 0 if we should bypass source address selection in favour 2704202468Sbz * of the primary jail IPv4 address. Only in this case *ia will be updated and 2705202468Sbz * returned in NBO. 2706202468Sbz * Return EAFNOSUPPORT, in case this jail does not allow IPv4. 2707202468Sbz */ 2708202468Sbzint 2709202468Sbzprison_saddrsel_ip4(struct ucred *cred, struct in_addr *ia) 2710202468Sbz{ 2711202468Sbz struct prison *pr; 2712202468Sbz struct in_addr lia; 2713202468Sbz int error; 2714202468Sbz 2715202468Sbz KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 2716202468Sbz KASSERT(ia != NULL, ("%s: ia is NULL", __func__)); 2717202468Sbz 2718202468Sbz if (!jailed(cred)) 2719202468Sbz return (1); 2720202468Sbz 2721202468Sbz pr = cred->cr_prison; 2722202468Sbz if (pr->pr_flags & PR_IP4_SADDRSEL) 2723202468Sbz return (1); 2724202468Sbz 2725202468Sbz lia.s_addr = INADDR_ANY; 2726202468Sbz error = prison_get_ip4(cred, &lia); 2727202468Sbz if (error) 2728202468Sbz return (error); 2729202468Sbz if (lia.s_addr == INADDR_ANY) 2730202468Sbz return (1); 2731202468Sbz 2732202468Sbz ia->s_addr = lia.s_addr; 2733202468Sbz return (0); 2734202468Sbz} 2735202468Sbz 2736202468Sbz/* 2737192895Sjamie * Return true if pr1 and pr2 have the same IPv4 address restrictions. 2738192895Sjamie */ 2739192895Sjamieint 2740192895Sjamieprison_equal_ip4(struct prison *pr1, struct prison *pr2) 2741192895Sjamie{ 2742192895Sjamie 2743192895Sjamie if (pr1 == pr2) 2744192895Sjamie return (1); 2745192895Sjamie 2746192895Sjamie /* 2747195974Sjamie * No need to lock since the PR_IP4_USER flag can't be altered for 2748195974Sjamie * existing prisons. 2749192895Sjamie */ 2750195945Sjamie while (pr1 != &prison0 && 2751195945Sjamie#ifdef VIMAGE 2752195945Sjamie !(pr1->pr_flags & PR_VNET) && 2753195945Sjamie#endif 2754195945Sjamie !(pr1->pr_flags & PR_IP4_USER)) 2755192895Sjamie pr1 = pr1->pr_parent; 2756195945Sjamie while (pr2 != &prison0 && 2757195945Sjamie#ifdef VIMAGE 2758195945Sjamie !(pr2->pr_flags & PR_VNET) && 2759195945Sjamie#endif 2760195945Sjamie !(pr2->pr_flags & PR_IP4_USER)) 2761192895Sjamie pr2 = pr2->pr_parent; 2762192895Sjamie return (pr1 == pr2); 2763192895Sjamie} 2764192895Sjamie 2765192895Sjamie/* 2766185435Sbz * Make sure our (source) address is set to something meaningful to this 2767185435Sbz * jail. 2768185435Sbz * 2769192895Sjamie * Returns 0 if jail doesn't restrict IPv4 or if address belongs to jail, 2770192895Sjamie * EADDRNOTAVAIL if the address doesn't belong, or EAFNOSUPPORT if the jail 2771192895Sjamie * doesn't allow IPv4. Address passed in in NBO and returned in NBO. 2772185435Sbz */ 2773185435Sbzint 2774185435Sbzprison_local_ip4(struct ucred *cred, struct in_addr *ia) 2775185435Sbz{ 2776191673Sjamie struct prison *pr; 2777185435Sbz struct in_addr ia0; 2778191673Sjamie int error; 2779185435Sbz 2780185435Sbz KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 2781185435Sbz KASSERT(ia != NULL, ("%s: ia is NULL", __func__)); 2782185435Sbz 2783192895Sjamie pr = cred->cr_prison; 2784192895Sjamie if (!(pr->pr_flags & PR_IP4)) 278546155Sphk return (0); 2786191673Sjamie mtx_lock(&pr->pr_mtx); 2787192895Sjamie if (!(pr->pr_flags & PR_IP4)) { 2788192895Sjamie mtx_unlock(&pr->pr_mtx); 2789192895Sjamie return (0); 2790192895Sjamie } 2791191673Sjamie if (pr->pr_ip4 == NULL) { 2792191673Sjamie mtx_unlock(&pr->pr_mtx); 2793188144Sjamie return (EAFNOSUPPORT); 2794191673Sjamie } 2795185435Sbz 2796185435Sbz ia0.s_addr = ntohl(ia->s_addr); 2797185435Sbz if (ia0.s_addr == INADDR_LOOPBACK) { 2798191673Sjamie ia->s_addr = pr->pr_ip4[0].s_addr; 2799191673Sjamie mtx_unlock(&pr->pr_mtx); 2800185435Sbz return (0); 280146155Sphk } 2802185435Sbz 2803188144Sjamie if (ia0.s_addr == INADDR_ANY) { 2804188144Sjamie /* 2805188144Sjamie * In case there is only 1 IPv4 address, bind directly. 2806188144Sjamie */ 2807191673Sjamie if (pr->pr_ip4s == 1) 2808191673Sjamie ia->s_addr = pr->pr_ip4[0].s_addr; 2809191673Sjamie mtx_unlock(&pr->pr_mtx); 2810185435Sbz return (0); 2811185435Sbz } 2812185435Sbz 2813191673Sjamie error = _prison_check_ip4(pr, ia); 2814191673Sjamie mtx_unlock(&pr->pr_mtx); 2815191673Sjamie return (error); 2816185435Sbz} 2817185435Sbz 2818185435Sbz/* 2819185435Sbz * Rewrite destination address in case we will connect to loopback address. 2820185435Sbz * 2821188144Sjamie * Returns 0 on success, EAFNOSUPPORT if the jail doesn't allow IPv4. 2822188144Sjamie * Address passed in in NBO and returned in NBO. 2823185435Sbz */ 2824185435Sbzint 2825185435Sbzprison_remote_ip4(struct ucred *cred, struct in_addr *ia) 2826185435Sbz{ 2827191673Sjamie struct prison *pr; 2828185435Sbz 2829185435Sbz KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 2830185435Sbz KASSERT(ia != NULL, ("%s: ia is NULL", __func__)); 2831185435Sbz 2832192895Sjamie pr = cred->cr_prison; 2833192895Sjamie if (!(pr->pr_flags & PR_IP4)) 2834185435Sbz return (0); 2835191673Sjamie mtx_lock(&pr->pr_mtx); 2836192895Sjamie if (!(pr->pr_flags & PR_IP4)) { 2837192895Sjamie mtx_unlock(&pr->pr_mtx); 2838192895Sjamie return (0); 2839192895Sjamie } 2840191673Sjamie if (pr->pr_ip4 == NULL) { 2841191673Sjamie mtx_unlock(&pr->pr_mtx); 2842188144Sjamie return (EAFNOSUPPORT); 2843191673Sjamie } 2844188144Sjamie 2845185435Sbz if (ntohl(ia->s_addr) == INADDR_LOOPBACK) { 2846191673Sjamie ia->s_addr = pr->pr_ip4[0].s_addr; 2847191673Sjamie mtx_unlock(&pr->pr_mtx); 2848185435Sbz return (0); 2849185435Sbz } 2850185435Sbz 2851185435Sbz /* 2852185435Sbz * Return success because nothing had to be changed. 2853185435Sbz */ 2854191673Sjamie mtx_unlock(&pr->pr_mtx); 2855185435Sbz return (0); 2856185435Sbz} 2857185435Sbz 2858185435Sbz/* 2859188144Sjamie * Check if given address belongs to the jail referenced by cred/prison. 2860185435Sbz * 2861192895Sjamie * Returns 0 if jail doesn't restrict IPv4 or if address belongs to jail, 2862192895Sjamie * EADDRNOTAVAIL if the address doesn't belong, or EAFNOSUPPORT if the jail 2863192895Sjamie * doesn't allow IPv4. Address passed in in NBO. 2864185435Sbz */ 2865185435Sbzstatic int 2866185435Sbz_prison_check_ip4(struct prison *pr, struct in_addr *ia) 2867185435Sbz{ 2868185435Sbz int i, a, z, d; 2869185435Sbz 2870185435Sbz /* 2871185435Sbz * Check the primary IP. 2872185435Sbz */ 2873185435Sbz if (pr->pr_ip4[0].s_addr == ia->s_addr) 2874188144Sjamie return (0); 2875185435Sbz 2876185435Sbz /* 2877185435Sbz * All the other IPs are sorted so we can do a binary search. 2878185435Sbz */ 2879185435Sbz a = 0; 2880185435Sbz z = pr->pr_ip4s - 2; 2881185435Sbz while (a <= z) { 2882185435Sbz i = (a + z) / 2; 2883185435Sbz d = qcmp_v4(&pr->pr_ip4[i+1], ia); 2884185435Sbz if (d > 0) 2885185435Sbz z = i - 1; 2886185435Sbz else if (d < 0) 2887185435Sbz a = i + 1; 288881114Srwatson else 2889188144Sjamie return (0); 2890185435Sbz } 2891188144Sjamie 2892188144Sjamie return (EADDRNOTAVAIL); 2893185435Sbz} 2894185435Sbz 2895185435Sbzint 2896185435Sbzprison_check_ip4(struct ucred *cred, struct in_addr *ia) 2897185435Sbz{ 2898191673Sjamie struct prison *pr; 2899191673Sjamie int error; 2900185435Sbz 2901185435Sbz KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 2902185435Sbz KASSERT(ia != NULL, ("%s: ia is NULL", __func__)); 2903185435Sbz 2904192895Sjamie pr = cred->cr_prison; 2905192895Sjamie if (!(pr->pr_flags & PR_IP4)) 2906188144Sjamie return (0); 2907191673Sjamie mtx_lock(&pr->pr_mtx); 2908192895Sjamie if (!(pr->pr_flags & PR_IP4)) { 2909192895Sjamie mtx_unlock(&pr->pr_mtx); 2910192895Sjamie return (0); 2911192895Sjamie } 2912191673Sjamie if (pr->pr_ip4 == NULL) { 2913191673Sjamie mtx_unlock(&pr->pr_mtx); 2914188144Sjamie return (EAFNOSUPPORT); 2915191673Sjamie } 2916185435Sbz 2917191673Sjamie error = _prison_check_ip4(pr, ia); 2918191673Sjamie mtx_unlock(&pr->pr_mtx); 2919191673Sjamie return (error); 2920185435Sbz} 2921185435Sbz#endif 2922185435Sbz 2923185435Sbz#ifdef INET6 2924192895Sjamiestatic int 2925192895Sjamieprison_restrict_ip6(struct prison *pr, struct in6_addr *newip6) 2926192895Sjamie{ 2927192895Sjamie int ii, ij, used; 2928192895Sjamie struct prison *ppr; 2929192895Sjamie 2930192895Sjamie ppr = pr->pr_parent; 2931192895Sjamie if (!(pr->pr_flags & PR_IP6_USER)) { 2932192895Sjamie /* This has no user settings, so just copy the parent's list. */ 2933192895Sjamie if (pr->pr_ip6s < ppr->pr_ip6s) { 2934192895Sjamie /* 2935192895Sjamie * There's no room for the parent's list. Use the 2936192895Sjamie * new list buffer, which is assumed to be big enough 2937192895Sjamie * (if it was passed). If there's no buffer, try to 2938192895Sjamie * allocate one. 2939192895Sjamie */ 2940192895Sjamie used = 1; 2941192895Sjamie if (newip6 == NULL) { 2942192895Sjamie newip6 = malloc(ppr->pr_ip6s * sizeof(*newip6), 2943192895Sjamie M_PRISON, M_NOWAIT); 2944192895Sjamie if (newip6 != NULL) 2945192895Sjamie used = 0; 2946192895Sjamie } 2947192895Sjamie if (newip6 != NULL) { 2948192895Sjamie bcopy(ppr->pr_ip6, newip6, 2949192895Sjamie ppr->pr_ip6s * sizeof(*newip6)); 2950192895Sjamie free(pr->pr_ip6, M_PRISON); 2951192895Sjamie pr->pr_ip6 = newip6; 2952192895Sjamie pr->pr_ip6s = ppr->pr_ip6s; 2953192895Sjamie } 2954192895Sjamie return (used); 2955192895Sjamie } 2956192895Sjamie pr->pr_ip6s = ppr->pr_ip6s; 2957192895Sjamie if (pr->pr_ip6s > 0) 2958192895Sjamie bcopy(ppr->pr_ip6, pr->pr_ip6, 2959192895Sjamie pr->pr_ip6s * sizeof(*newip6)); 2960192895Sjamie else if (pr->pr_ip6 != NULL) { 2961192895Sjamie free(pr->pr_ip6, M_PRISON); 2962192895Sjamie pr->pr_ip6 = NULL; 2963192895Sjamie } 2964195974Sjamie } else if (pr->pr_ip6s > 0) { 2965192895Sjamie /* Remove addresses that aren't in the parent. */ 2966192895Sjamie for (ij = 0; ij < ppr->pr_ip6s; ij++) 2967192895Sjamie if (IN6_ARE_ADDR_EQUAL(&pr->pr_ip6[0], 2968192895Sjamie &ppr->pr_ip6[ij])) 2969192895Sjamie break; 2970192895Sjamie if (ij < ppr->pr_ip6s) 2971192895Sjamie ii = 1; 2972192895Sjamie else { 2973192895Sjamie bcopy(pr->pr_ip6 + 1, pr->pr_ip6, 2974192895Sjamie --pr->pr_ip6s * sizeof(*pr->pr_ip6)); 2975192895Sjamie ii = 0; 2976192895Sjamie } 2977192895Sjamie for (ij = 1; ii < pr->pr_ip6s; ) { 2978192895Sjamie if (IN6_ARE_ADDR_EQUAL(&pr->pr_ip6[ii], 2979192895Sjamie &ppr->pr_ip6[0])) { 2980192895Sjamie ii++; 2981192895Sjamie continue; 2982192895Sjamie } 2983192895Sjamie switch (ij >= ppr->pr_ip4s ? -1 : 2984192895Sjamie qcmp_v6(&pr->pr_ip6[ii], &ppr->pr_ip6[ij])) { 2985192895Sjamie case -1: 2986192895Sjamie bcopy(pr->pr_ip6 + ii + 1, pr->pr_ip6 + ii, 2987192895Sjamie (--pr->pr_ip6s - ii) * sizeof(*pr->pr_ip6)); 2988192895Sjamie break; 2989192895Sjamie case 0: 2990192895Sjamie ii++; 2991192895Sjamie ij++; 2992192895Sjamie break; 2993192895Sjamie case 1: 2994192895Sjamie ij++; 2995192895Sjamie break; 2996192895Sjamie } 2997192895Sjamie } 2998192895Sjamie if (pr->pr_ip6s == 0) { 2999195870Sjamie pr->pr_flags |= PR_IP6_DISABLE; 3000192895Sjamie free(pr->pr_ip6, M_PRISON); 3001192895Sjamie pr->pr_ip6 = NULL; 3002192895Sjamie } 3003192895Sjamie } 3004192895Sjamie return 0; 3005192895Sjamie} 3006192895Sjamie 3007185435Sbz/* 3008185435Sbz * Pass back primary IPv6 address for this jail. 3009185435Sbz * 3010192895Sjamie * If not restricted return success but do not alter the address. Caller has 3011192895Sjamie * to make sure to initialize it correctly (e.g. IN6ADDR_ANY_INIT). 3012185435Sbz * 3013188144Sjamie * Returns 0 on success, EAFNOSUPPORT if the jail doesn't allow IPv6. 3014185435Sbz */ 3015185435Sbzint 3016187684Sbzprison_get_ip6(struct ucred *cred, struct in6_addr *ia6) 3017185435Sbz{ 3018191673Sjamie struct prison *pr; 3019185435Sbz 3020185435Sbz KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 3021185435Sbz KASSERT(ia6 != NULL, ("%s: ia6 is NULL", __func__)); 3022185435Sbz 3023192895Sjamie pr = cred->cr_prison; 3024192895Sjamie if (!(pr->pr_flags & PR_IP6)) 302581114Srwatson return (0); 3026191673Sjamie mtx_lock(&pr->pr_mtx); 3027192895Sjamie if (!(pr->pr_flags & PR_IP6)) { 3028192895Sjamie mtx_unlock(&pr->pr_mtx); 3029192895Sjamie return (0); 3030192895Sjamie } 3031191673Sjamie if (pr->pr_ip6 == NULL) { 3032191673Sjamie mtx_unlock(&pr->pr_mtx); 3033188144Sjamie return (EAFNOSUPPORT); 3034191673Sjamie } 3035188144Sjamie 3036191673Sjamie bcopy(&pr->pr_ip6[0], ia6, sizeof(struct in6_addr)); 3037191673Sjamie mtx_unlock(&pr->pr_mtx); 3038185435Sbz return (0); 3039185435Sbz} 3040185435Sbz 3041185435Sbz/* 3042202468Sbz * Return 1 if we should do proper source address selection or are not jailed. 3043202468Sbz * We will return 0 if we should bypass source address selection in favour 3044202468Sbz * of the primary jail IPv6 address. Only in this case *ia will be updated and 3045202468Sbz * returned in NBO. 3046202468Sbz * Return EAFNOSUPPORT, in case this jail does not allow IPv6. 3047202468Sbz */ 3048202468Sbzint 3049202468Sbzprison_saddrsel_ip6(struct ucred *cred, struct in6_addr *ia6) 3050202468Sbz{ 3051202468Sbz struct prison *pr; 3052202468Sbz struct in6_addr lia6; 3053202468Sbz int error; 3054202468Sbz 3055202468Sbz KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 3056202468Sbz KASSERT(ia6 != NULL, ("%s: ia6 is NULL", __func__)); 3057202468Sbz 3058202468Sbz if (!jailed(cred)) 3059202468Sbz return (1); 3060202468Sbz 3061202468Sbz pr = cred->cr_prison; 3062202468Sbz if (pr->pr_flags & PR_IP6_SADDRSEL) 3063202468Sbz return (1); 3064202468Sbz 3065202468Sbz lia6 = in6addr_any; 3066202468Sbz error = prison_get_ip6(cred, &lia6); 3067202468Sbz if (error) 3068202468Sbz return (error); 3069202468Sbz if (IN6_IS_ADDR_UNSPECIFIED(&lia6)) 3070202468Sbz return (1); 3071202468Sbz 3072202468Sbz bcopy(&lia6, ia6, sizeof(struct in6_addr)); 3073202468Sbz return (0); 3074202468Sbz} 3075202468Sbz 3076202468Sbz/* 3077192895Sjamie * Return true if pr1 and pr2 have the same IPv6 address restrictions. 3078192895Sjamie */ 3079192895Sjamieint 3080192895Sjamieprison_equal_ip6(struct prison *pr1, struct prison *pr2) 3081192895Sjamie{ 3082192895Sjamie 3083192895Sjamie if (pr1 == pr2) 3084192895Sjamie return (1); 3085192895Sjamie 3086195945Sjamie while (pr1 != &prison0 && 3087195945Sjamie#ifdef VIMAGE 3088195945Sjamie !(pr1->pr_flags & PR_VNET) && 3089195945Sjamie#endif 3090195945Sjamie !(pr1->pr_flags & PR_IP6_USER)) 3091192895Sjamie pr1 = pr1->pr_parent; 3092195945Sjamie while (pr2 != &prison0 && 3093195945Sjamie#ifdef VIMAGE 3094195945Sjamie !(pr2->pr_flags & PR_VNET) && 3095195945Sjamie#endif 3096195945Sjamie !(pr2->pr_flags & PR_IP6_USER)) 3097192895Sjamie pr2 = pr2->pr_parent; 3098192895Sjamie return (pr1 == pr2); 3099192895Sjamie} 3100192895Sjamie 3101192895Sjamie/* 3102185435Sbz * Make sure our (source) address is set to something meaningful to this jail. 3103185435Sbz * 3104185435Sbz * v6only should be set based on (inp->inp_flags & IN6P_IPV6_V6ONLY != 0) 3105185435Sbz * when needed while binding. 3106185435Sbz * 3107192895Sjamie * Returns 0 if jail doesn't restrict IPv6 or if address belongs to jail, 3108192895Sjamie * EADDRNOTAVAIL if the address doesn't belong, or EAFNOSUPPORT if the jail 3109192895Sjamie * doesn't allow IPv6. 3110185435Sbz */ 3111185435Sbzint 3112185435Sbzprison_local_ip6(struct ucred *cred, struct in6_addr *ia6, int v6only) 3113185435Sbz{ 3114191673Sjamie struct prison *pr; 3115191673Sjamie int error; 3116185435Sbz 3117185435Sbz KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 3118185435Sbz KASSERT(ia6 != NULL, ("%s: ia6 is NULL", __func__)); 3119185435Sbz 3120192895Sjamie pr = cred->cr_prison; 3121192895Sjamie if (!(pr->pr_flags & PR_IP6)) 3122185435Sbz return (0); 3123191673Sjamie mtx_lock(&pr->pr_mtx); 3124192895Sjamie if (!(pr->pr_flags & PR_IP6)) { 3125192895Sjamie mtx_unlock(&pr->pr_mtx); 3126192895Sjamie return (0); 3127192895Sjamie } 3128191673Sjamie if (pr->pr_ip6 == NULL) { 3129191673Sjamie mtx_unlock(&pr->pr_mtx); 3130188144Sjamie return (EAFNOSUPPORT); 3131191673Sjamie } 3132188144Sjamie 3133185435Sbz if (IN6_IS_ADDR_LOOPBACK(ia6)) { 3134191673Sjamie bcopy(&pr->pr_ip6[0], ia6, sizeof(struct in6_addr)); 3135191673Sjamie mtx_unlock(&pr->pr_mtx); 3136185435Sbz return (0); 313781114Srwatson } 3138185435Sbz 3139188144Sjamie if (IN6_IS_ADDR_UNSPECIFIED(ia6)) { 3140188144Sjamie /* 3141188144Sjamie * In case there is only 1 IPv6 address, and v6only is true, 3142188144Sjamie * then bind directly. 3143188144Sjamie */ 3144191673Sjamie if (v6only != 0 && pr->pr_ip6s == 1) 3145191673Sjamie bcopy(&pr->pr_ip6[0], ia6, sizeof(struct in6_addr)); 3146191673Sjamie mtx_unlock(&pr->pr_mtx); 3147185435Sbz return (0); 3148185435Sbz } 3149188144Sjamie 3150191673Sjamie error = _prison_check_ip6(pr, ia6); 3151191673Sjamie mtx_unlock(&pr->pr_mtx); 3152191673Sjamie return (error); 3153185435Sbz} 3154185435Sbz 3155185435Sbz/* 3156185435Sbz * Rewrite destination address in case we will connect to loopback address. 3157185435Sbz * 3158188144Sjamie * Returns 0 on success, EAFNOSUPPORT if the jail doesn't allow IPv6. 3159185435Sbz */ 3160185435Sbzint 3161185435Sbzprison_remote_ip6(struct ucred *cred, struct in6_addr *ia6) 3162185435Sbz{ 3163191673Sjamie struct prison *pr; 3164185435Sbz 3165185435Sbz KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 3166185435Sbz KASSERT(ia6 != NULL, ("%s: ia6 is NULL", __func__)); 3167185435Sbz 3168192895Sjamie pr = cred->cr_prison; 3169192895Sjamie if (!(pr->pr_flags & PR_IP6)) 3170185435Sbz return (0); 3171191673Sjamie mtx_lock(&pr->pr_mtx); 3172192895Sjamie if (!(pr->pr_flags & PR_IP6)) { 3173192895Sjamie mtx_unlock(&pr->pr_mtx); 3174192895Sjamie return (0); 3175192895Sjamie } 3176191673Sjamie if (pr->pr_ip6 == NULL) { 3177191673Sjamie mtx_unlock(&pr->pr_mtx); 3178188144Sjamie return (EAFNOSUPPORT); 3179191673Sjamie } 3180188144Sjamie 3181185435Sbz if (IN6_IS_ADDR_LOOPBACK(ia6)) { 3182191673Sjamie bcopy(&pr->pr_ip6[0], ia6, sizeof(struct in6_addr)); 3183191673Sjamie mtx_unlock(&pr->pr_mtx); 3184185435Sbz return (0); 3185185435Sbz } 3186185435Sbz 3187185435Sbz /* 3188185435Sbz * Return success because nothing had to be changed. 3189185435Sbz */ 3190191673Sjamie mtx_unlock(&pr->pr_mtx); 319146155Sphk return (0); 319246155Sphk} 319346155Sphk 3194185435Sbz/* 3195188144Sjamie * Check if given address belongs to the jail referenced by cred/prison. 3196185435Sbz * 3197192895Sjamie * Returns 0 if jail doesn't restrict IPv6 or if address belongs to jail, 3198192895Sjamie * EADDRNOTAVAIL if the address doesn't belong, or EAFNOSUPPORT if the jail 3199192895Sjamie * doesn't allow IPv6. 3200185435Sbz */ 3201185435Sbzstatic int 3202185435Sbz_prison_check_ip6(struct prison *pr, struct in6_addr *ia6) 320346155Sphk{ 3204185435Sbz int i, a, z, d; 320546155Sphk 3206185435Sbz /* 3207185435Sbz * Check the primary IP. 3208185435Sbz */ 3209185435Sbz if (IN6_ARE_ADDR_EQUAL(&pr->pr_ip6[0], ia6)) 3210188144Sjamie return (0); 3211185435Sbz 3212185435Sbz /* 3213185435Sbz * All the other IPs are sorted so we can do a binary search. 3214185435Sbz */ 3215185435Sbz a = 0; 3216185435Sbz z = pr->pr_ip6s - 2; 3217185435Sbz while (a <= z) { 3218185435Sbz i = (a + z) / 2; 3219185435Sbz d = qcmp_v6(&pr->pr_ip6[i+1], ia6); 3220185435Sbz if (d > 0) 3221185435Sbz z = i - 1; 3222185435Sbz else if (d < 0) 3223185435Sbz a = i + 1; 322446155Sphk else 3225188144Sjamie return (0); 322646155Sphk } 3227188144Sjamie 3228188144Sjamie return (EADDRNOTAVAIL); 322946155Sphk} 323046155Sphk 323146155Sphkint 3232185435Sbzprison_check_ip6(struct ucred *cred, struct in6_addr *ia6) 3233185435Sbz{ 3234191673Sjamie struct prison *pr; 3235191673Sjamie int error; 3236185435Sbz 3237185435Sbz KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 3238185435Sbz KASSERT(ia6 != NULL, ("%s: ia6 is NULL", __func__)); 3239185435Sbz 3240192895Sjamie pr = cred->cr_prison; 3241192895Sjamie if (!(pr->pr_flags & PR_IP6)) 3242188144Sjamie return (0); 3243191673Sjamie mtx_lock(&pr->pr_mtx); 3244192895Sjamie if (!(pr->pr_flags & PR_IP6)) { 3245192895Sjamie mtx_unlock(&pr->pr_mtx); 3246192895Sjamie return (0); 3247192895Sjamie } 3248191673Sjamie if (pr->pr_ip6 == NULL) { 3249191673Sjamie mtx_unlock(&pr->pr_mtx); 3250188144Sjamie return (EAFNOSUPPORT); 3251191673Sjamie } 3252185435Sbz 3253191673Sjamie error = _prison_check_ip6(pr, ia6); 3254191673Sjamie mtx_unlock(&pr->pr_mtx); 3255191673Sjamie return (error); 3256185435Sbz} 3257185435Sbz#endif 3258185435Sbz 3259185435Sbz/* 3260188146Sjamie * Check if a jail supports the given address family. 3261188146Sjamie * 3262188146Sjamie * Returns 0 if not jailed or the address family is supported, EAFNOSUPPORT 3263188146Sjamie * if not. 3264188146Sjamie */ 3265188146Sjamieint 3266188146Sjamieprison_check_af(struct ucred *cred, int af) 3267188146Sjamie{ 3268192895Sjamie struct prison *pr; 3269188146Sjamie int error; 3270188146Sjamie 3271188146Sjamie KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 3272188146Sjamie 3273192895Sjamie pr = cred->cr_prison; 3274194923Sjamie#ifdef VIMAGE 3275194915Sjamie /* Prisons with their own network stack are not limited. */ 3276200473Sbz if (prison_owns_vnet(cred)) 3277194915Sjamie return (0); 3278194923Sjamie#endif 3279194915Sjamie 3280188146Sjamie error = 0; 3281188146Sjamie switch (af) 3282188146Sjamie { 3283188146Sjamie#ifdef INET 3284188146Sjamie case AF_INET: 3285192895Sjamie if (pr->pr_flags & PR_IP4) 3286192895Sjamie { 3287192895Sjamie mtx_lock(&pr->pr_mtx); 3288192895Sjamie if ((pr->pr_flags & PR_IP4) && pr->pr_ip4 == NULL) 3289192895Sjamie error = EAFNOSUPPORT; 3290192895Sjamie mtx_unlock(&pr->pr_mtx); 3291192895Sjamie } 3292188146Sjamie break; 3293188146Sjamie#endif 3294188146Sjamie#ifdef INET6 3295188146Sjamie case AF_INET6: 3296192895Sjamie if (pr->pr_flags & PR_IP6) 3297192895Sjamie { 3298192895Sjamie mtx_lock(&pr->pr_mtx); 3299192895Sjamie if ((pr->pr_flags & PR_IP6) && pr->pr_ip6 == NULL) 3300192895Sjamie error = EAFNOSUPPORT; 3301192895Sjamie mtx_unlock(&pr->pr_mtx); 3302192895Sjamie } 3303188146Sjamie break; 3304188146Sjamie#endif 3305188146Sjamie case AF_LOCAL: 3306188146Sjamie case AF_ROUTE: 3307188146Sjamie break; 3308188146Sjamie default: 3309192895Sjamie if (!(pr->pr_allow & PR_ALLOW_SOCKET_AF)) 3310188146Sjamie error = EAFNOSUPPORT; 3311188146Sjamie } 3312188146Sjamie return (error); 3313188146Sjamie} 3314188146Sjamie 3315188146Sjamie/* 3316185435Sbz * Check if given address belongs to the jail referenced by cred (wrapper to 3317185435Sbz * prison_check_ip[46]). 3318185435Sbz * 3319192895Sjamie * Returns 0 if jail doesn't restrict the address family or if address belongs 3320192895Sjamie * to jail, EADDRNOTAVAIL if the address doesn't belong, or EAFNOSUPPORT if 3321192895Sjamie * the jail doesn't allow the address family. IPv4 Address passed in in NBO. 3322185435Sbz */ 3323185435Sbzint 332472786Srwatsonprison_if(struct ucred *cred, struct sockaddr *sa) 332546155Sphk{ 3326185435Sbz#ifdef INET 3327114168Smike struct sockaddr_in *sai; 3328185435Sbz#endif 3329185435Sbz#ifdef INET6 3330185435Sbz struct sockaddr_in6 *sai6; 3331185435Sbz#endif 3332188144Sjamie int error; 333346155Sphk 3334185435Sbz KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 3335185435Sbz KASSERT(sa != NULL, ("%s: sa is NULL", __func__)); 3336185435Sbz 3337200473Sbz#ifdef VIMAGE 3338200473Sbz if (prison_owns_vnet(cred)) 3339200473Sbz return (0); 3340200473Sbz#endif 3341200473Sbz 3342188144Sjamie error = 0; 3343188144Sjamie switch (sa->sa_family) 3344185435Sbz { 3345185435Sbz#ifdef INET 3346185435Sbz case AF_INET: 3347185435Sbz sai = (struct sockaddr_in *)sa; 3348188144Sjamie error = prison_check_ip4(cred, &sai->sin_addr); 3349185435Sbz break; 3350185435Sbz#endif 3351185435Sbz#ifdef INET6 3352185435Sbz case AF_INET6: 3353185435Sbz sai6 = (struct sockaddr_in6 *)sa; 3354188144Sjamie error = prison_check_ip6(cred, &sai6->sin6_addr); 3355185435Sbz break; 3356185435Sbz#endif 3357185435Sbz default: 3358192895Sjamie if (!(cred->cr_prison->pr_allow & PR_ALLOW_SOCKET_AF)) 3359188144Sjamie error = EAFNOSUPPORT; 3360185435Sbz } 3361188144Sjamie return (error); 336246155Sphk} 336372786Srwatson 336472786Srwatson/* 336572786Srwatson * Return 0 if jails permit p1 to frob p2, otherwise ESRCH. 336672786Srwatson */ 336772786Srwatsonint 3368114168Smikeprison_check(struct ucred *cred1, struct ucred *cred2) 336972786Srwatson{ 337072786Srwatson 3371192895Sjamie return ((cred1->cr_prison == cred2->cr_prison || 3372192895Sjamie prison_ischild(cred1->cr_prison, cred2->cr_prison)) ? 0 : ESRCH); 3373192895Sjamie} 337472786Srwatson 3375192895Sjamie/* 3376192895Sjamie * Return 1 if p2 is a child of p1, otherwise 0. 3377192895Sjamie */ 3378192895Sjamieint 3379192895Sjamieprison_ischild(struct prison *pr1, struct prison *pr2) 3380192895Sjamie{ 3381192895Sjamie 3382192895Sjamie for (pr2 = pr2->pr_parent; pr2 != NULL; pr2 = pr2->pr_parent) 3383192895Sjamie if (pr1 == pr2) 3384192895Sjamie return (1); 338572786Srwatson return (0); 338672786Srwatson} 338772786Srwatson 338872786Srwatson/* 338972786Srwatson * Return 1 if the passed credential is in a jail, otherwise 0. 339072786Srwatson */ 339172786Srwatsonint 3392114168Smikejailed(struct ucred *cred) 339372786Srwatson{ 339472786Srwatson 3395192895Sjamie return (cred->cr_prison != &prison0); 339672786Srwatson} 339791384Srobert 339891384Srobert/* 3399200473Sbz * Return 1 if the passed credential is in a jail and that jail does not 3400200473Sbz * have its own virtual network stack, otherwise 0. 3401200473Sbz */ 3402200473Sbzint 3403200473Sbzjailed_without_vnet(struct ucred *cred) 3404200473Sbz{ 3405200473Sbz 3406200473Sbz if (!jailed(cred)) 3407200473Sbz return (0); 3408200473Sbz#ifdef VIMAGE 3409200473Sbz if (prison_owns_vnet(cred)) 3410200473Sbz return (0); 3411200473Sbz#endif 3412200473Sbz 3413200473Sbz return (1); 3414200473Sbz} 3415200473Sbz 3416200473Sbz/* 3417194090Sjamie * Return the correct hostname (domainname, et al) for the passed credential. 341891384Srobert */ 341991391Srobertvoid 3420114168Smikegetcredhostname(struct ucred *cred, char *buf, size_t size) 342191384Srobert{ 3422193066Sjamie struct prison *pr; 342391384Srobert 3424194090Sjamie /* 3425194090Sjamie * A NULL credential can be used to shortcut to the physical 3426194090Sjamie * system's hostname. 3427194090Sjamie */ 3428193066Sjamie pr = (cred != NULL) ? cred->cr_prison : &prison0; 3429193066Sjamie mtx_lock(&pr->pr_mtx); 3430194118Sjamie strlcpy(buf, pr->pr_hostname, size); 3431193066Sjamie mtx_unlock(&pr->pr_mtx); 343291384Srobert} 3433113275Smike 3434194090Sjamievoid 3435194090Sjamiegetcreddomainname(struct ucred *cred, char *buf, size_t size) 3436194090Sjamie{ 3437194090Sjamie 3438194090Sjamie mtx_lock(&cred->cr_prison->pr_mtx); 3439194118Sjamie strlcpy(buf, cred->cr_prison->pr_domainname, size); 3440194090Sjamie mtx_unlock(&cred->cr_prison->pr_mtx); 3441194090Sjamie} 3442194090Sjamie 3443194090Sjamievoid 3444194090Sjamiegetcredhostuuid(struct ucred *cred, char *buf, size_t size) 3445194090Sjamie{ 3446194090Sjamie 3447194090Sjamie mtx_lock(&cred->cr_prison->pr_mtx); 3448194118Sjamie strlcpy(buf, cred->cr_prison->pr_hostuuid, size); 3449194090Sjamie mtx_unlock(&cred->cr_prison->pr_mtx); 3450194090Sjamie} 3451194090Sjamie 3452194090Sjamievoid 3453194090Sjamiegetcredhostid(struct ucred *cred, unsigned long *hostid) 3454194090Sjamie{ 3455194090Sjamie 3456194090Sjamie mtx_lock(&cred->cr_prison->pr_mtx); 3457194090Sjamie *hostid = cred->cr_prison->pr_hostid; 3458194090Sjamie mtx_unlock(&cred->cr_prison->pr_mtx); 3459194090Sjamie} 3460194090Sjamie 3461196176Sbz#ifdef VIMAGE 3462125804Srwatson/* 3463196176Sbz * Determine whether the prison represented by cred owns 3464196176Sbz * its vnet rather than having it inherited. 3465196176Sbz * 3466196176Sbz * Returns 1 in case the prison owns the vnet, 0 otherwise. 3467196176Sbz */ 3468196176Sbzint 3469196176Sbzprison_owns_vnet(struct ucred *cred) 3470196176Sbz{ 3471196176Sbz 3472196176Sbz /* 3473196176Sbz * vnets cannot be added/removed after jail creation, 3474196176Sbz * so no need to lock here. 3475196176Sbz */ 3476196176Sbz return (cred->cr_prison->pr_flags & PR_VNET ? 1 : 0); 3477196176Sbz} 3478196176Sbz#endif 3479196176Sbz 3480196176Sbz/* 3481147185Spjd * Determine whether the subject represented by cred can "see" 3482147185Spjd * status of a mount point. 3483147185Spjd * Returns: 0 for permitted, ENOENT otherwise. 3484147185Spjd * XXX: This function should be called cr_canseemount() and should be 3485147185Spjd * placed in kern_prot.c. 3486125804Srwatson */ 3487125804Srwatsonint 3488147185Spjdprison_canseemount(struct ucred *cred, struct mount *mp) 3489125804Srwatson{ 3490147185Spjd struct prison *pr; 3491147185Spjd struct statfs *sp; 3492147185Spjd size_t len; 3493125804Srwatson 3494192895Sjamie pr = cred->cr_prison; 3495192895Sjamie if (pr->pr_enforce_statfs == 0) 3496147185Spjd return (0); 3497147185Spjd if (pr->pr_root->v_mount == mp) 3498147185Spjd return (0); 3499192895Sjamie if (pr->pr_enforce_statfs == 2) 3500147185Spjd return (ENOENT); 3501147185Spjd /* 3502147185Spjd * If jail's chroot directory is set to "/" we should be able to see 3503147185Spjd * all mount-points from inside a jail. 3504147185Spjd * This is ugly check, but this is the only situation when jail's 3505147185Spjd * directory ends with '/'. 3506147185Spjd */ 3507147185Spjd if (strcmp(pr->pr_path, "/") == 0) 3508147185Spjd return (0); 3509147185Spjd len = strlen(pr->pr_path); 3510147185Spjd sp = &mp->mnt_stat; 3511147185Spjd if (strncmp(pr->pr_path, sp->f_mntonname, len) != 0) 3512147185Spjd return (ENOENT); 3513147185Spjd /* 3514147185Spjd * Be sure that we don't have situation where jail's root directory 3515147185Spjd * is "/some/path" and mount point is "/some/pathpath". 3516147185Spjd */ 3517147185Spjd if (sp->f_mntonname[len] != '\0' && sp->f_mntonname[len] != '/') 3518147185Spjd return (ENOENT); 3519147185Spjd return (0); 3520147185Spjd} 3521147185Spjd 3522147185Spjdvoid 3523147185Spjdprison_enforce_statfs(struct ucred *cred, struct mount *mp, struct statfs *sp) 3524147185Spjd{ 3525147185Spjd char jpath[MAXPATHLEN]; 3526147185Spjd struct prison *pr; 3527147185Spjd size_t len; 3528147185Spjd 3529192895Sjamie pr = cred->cr_prison; 3530192895Sjamie if (pr->pr_enforce_statfs == 0) 3531147185Spjd return; 3532147185Spjd if (prison_canseemount(cred, mp) != 0) { 3533147185Spjd bzero(sp->f_mntonname, sizeof(sp->f_mntonname)); 3534147185Spjd strlcpy(sp->f_mntonname, "[restricted]", 3535147185Spjd sizeof(sp->f_mntonname)); 3536147185Spjd return; 3537125804Srwatson } 3538147185Spjd if (pr->pr_root->v_mount == mp) { 3539147185Spjd /* 3540147185Spjd * Clear current buffer data, so we are sure nothing from 3541147185Spjd * the valid path left there. 3542147185Spjd */ 3543147185Spjd bzero(sp->f_mntonname, sizeof(sp->f_mntonname)); 3544147185Spjd *sp->f_mntonname = '/'; 3545147185Spjd return; 3546147185Spjd } 3547147185Spjd /* 3548147185Spjd * If jail's chroot directory is set to "/" we should be able to see 3549147185Spjd * all mount-points from inside a jail. 3550147185Spjd */ 3551147185Spjd if (strcmp(pr->pr_path, "/") == 0) 3552147185Spjd return; 3553147185Spjd len = strlen(pr->pr_path); 3554147185Spjd strlcpy(jpath, sp->f_mntonname + len, sizeof(jpath)); 3555147185Spjd /* 3556147185Spjd * Clear current buffer data, so we are sure nothing from 3557147185Spjd * the valid path left there. 3558147185Spjd */ 3559147185Spjd bzero(sp->f_mntonname, sizeof(sp->f_mntonname)); 3560147185Spjd if (*jpath == '\0') { 3561147185Spjd /* Should never happen. */ 3562147185Spjd *sp->f_mntonname = '/'; 3563147185Spjd } else { 3564147185Spjd strlcpy(sp->f_mntonname, jpath, sizeof(sp->f_mntonname)); 3565147185Spjd } 3566125804Srwatson} 3567125804Srwatson 3568164032Srwatson/* 3569164032Srwatson * Check with permission for a specific privilege is granted within jail. We 3570164032Srwatson * have a specific list of accepted privileges; the rest are denied. 3571164032Srwatson */ 3572164032Srwatsonint 3573164032Srwatsonprison_priv_check(struct ucred *cred, int priv) 3574164032Srwatson{ 3575164032Srwatson 3576164032Srwatson if (!jailed(cred)) 3577164032Srwatson return (0); 3578164032Srwatson 3579194915Sjamie#ifdef VIMAGE 3580194915Sjamie /* 3581194915Sjamie * Privileges specific to prisons with a virtual network stack. 3582194915Sjamie * There might be a duplicate entry here in case the privilege 3583194915Sjamie * is only granted conditionally in the legacy jail case. 3584194915Sjamie */ 3585164032Srwatson switch (priv) { 3586194915Sjamie#ifdef notyet 3587194915Sjamie /* 3588194915Sjamie * NFS-specific privileges. 3589194915Sjamie */ 3590194915Sjamie case PRIV_NFS_DAEMON: 3591194915Sjamie case PRIV_NFS_LOCKD: 3592194915Sjamie#endif 3593194915Sjamie /* 3594194915Sjamie * Network stack privileges. 3595194915Sjamie */ 3596194915Sjamie case PRIV_NET_BRIDGE: 3597194915Sjamie case PRIV_NET_GRE: 3598194915Sjamie case PRIV_NET_BPF: 3599194915Sjamie case PRIV_NET_RAW: /* Dup, cond. in legacy jail case. */ 3600194915Sjamie case PRIV_NET_ROUTE: 3601194915Sjamie case PRIV_NET_TAP: 3602194915Sjamie case PRIV_NET_SETIFMTU: 3603194915Sjamie case PRIV_NET_SETIFFLAGS: 3604194915Sjamie case PRIV_NET_SETIFCAP: 3605203052Sdelphij case PRIV_NET_SETIFDESCR: 3606194915Sjamie case PRIV_NET_SETIFNAME : 3607194915Sjamie case PRIV_NET_SETIFMETRIC: 3608194915Sjamie case PRIV_NET_SETIFPHYS: 3609194915Sjamie case PRIV_NET_SETIFMAC: 3610194915Sjamie case PRIV_NET_ADDMULTI: 3611194915Sjamie case PRIV_NET_DELMULTI: 3612194915Sjamie case PRIV_NET_HWIOCTL: 3613194915Sjamie case PRIV_NET_SETLLADDR: 3614194915Sjamie case PRIV_NET_ADDIFGROUP: 3615194915Sjamie case PRIV_NET_DELIFGROUP: 3616194915Sjamie case PRIV_NET_IFCREATE: 3617194915Sjamie case PRIV_NET_IFDESTROY: 3618194915Sjamie case PRIV_NET_ADDIFADDR: 3619194915Sjamie case PRIV_NET_DELIFADDR: 3620194915Sjamie case PRIV_NET_LAGG: 3621194915Sjamie case PRIV_NET_GIF: 3622194915Sjamie case PRIV_NET_SETIFVNET: 3623164032Srwatson 3624164032Srwatson /* 3625194915Sjamie * 802.11-related privileges. 3626194915Sjamie */ 3627194915Sjamie case PRIV_NET80211_GETKEY: 3628194915Sjamie#ifdef notyet 3629194915Sjamie case PRIV_NET80211_MANAGE: /* XXX-BZ discuss with sam@ */ 3630194915Sjamie#endif 3631194915Sjamie 3632194915Sjamie#ifdef notyet 3633194915Sjamie /* 3634194915Sjamie * AppleTalk privileges. 3635194915Sjamie */ 3636194915Sjamie case PRIV_NETATALK_RESERVEDPORT: 3637194915Sjamie 3638194915Sjamie /* 3639194915Sjamie * ATM privileges. 3640194915Sjamie */ 3641194915Sjamie case PRIV_NETATM_CFG: 3642194915Sjamie case PRIV_NETATM_ADD: 3643194915Sjamie case PRIV_NETATM_DEL: 3644194915Sjamie case PRIV_NETATM_SET: 3645194915Sjamie 3646194915Sjamie /* 3647194915Sjamie * Bluetooth privileges. 3648194915Sjamie */ 3649194915Sjamie case PRIV_NETBLUETOOTH_RAW: 3650194915Sjamie#endif 3651194915Sjamie 3652194915Sjamie /* 3653194915Sjamie * Netgraph and netgraph module privileges. 3654194915Sjamie */ 3655194915Sjamie case PRIV_NETGRAPH_CONTROL: 3656194915Sjamie#ifdef notyet 3657194915Sjamie case PRIV_NETGRAPH_TTY: 3658194915Sjamie#endif 3659194915Sjamie 3660194915Sjamie /* 3661194915Sjamie * IPv4 and IPv6 privileges. 3662194915Sjamie */ 3663194915Sjamie case PRIV_NETINET_IPFW: 3664194915Sjamie case PRIV_NETINET_DIVERT: 3665194915Sjamie case PRIV_NETINET_PF: 3666194915Sjamie case PRIV_NETINET_DUMMYNET: 3667194915Sjamie case PRIV_NETINET_CARP: 3668194915Sjamie case PRIV_NETINET_MROUTE: 3669194915Sjamie case PRIV_NETINET_RAW: 3670194915Sjamie case PRIV_NETINET_ADDRCTRL6: 3671194915Sjamie case PRIV_NETINET_ND6: 3672194915Sjamie case PRIV_NETINET_SCOPE6: 3673194915Sjamie case PRIV_NETINET_ALIFETIME6: 3674194915Sjamie case PRIV_NETINET_IPSEC: 3675194915Sjamie case PRIV_NETINET_BINDANY: 3676194915Sjamie 3677194915Sjamie#ifdef notyet 3678194915Sjamie /* 3679194915Sjamie * IPX/SPX privileges. 3680194915Sjamie */ 3681194915Sjamie case PRIV_NETIPX_RESERVEDPORT: 3682194915Sjamie case PRIV_NETIPX_RAW: 3683194915Sjamie 3684194915Sjamie /* 3685194915Sjamie * NCP privileges. 3686194915Sjamie */ 3687194915Sjamie case PRIV_NETNCP: 3688194915Sjamie 3689194915Sjamie /* 3690194915Sjamie * SMB privileges. 3691194915Sjamie */ 3692194915Sjamie case PRIV_NETSMB: 3693194915Sjamie#endif 3694194915Sjamie 3695194915Sjamie /* 3696194915Sjamie * No default: or deny here. 3697194915Sjamie * In case of no permit fall through to next switch(). 3698194915Sjamie */ 3699194915Sjamie if (cred->cr_prison->pr_flags & PR_VNET) 3700194915Sjamie return (0); 3701194915Sjamie } 3702194915Sjamie#endif /* VIMAGE */ 3703194915Sjamie 3704194915Sjamie switch (priv) { 3705194915Sjamie 3706194915Sjamie /* 3707164032Srwatson * Allow ktrace privileges for root in jail. 3708164032Srwatson */ 3709164032Srwatson case PRIV_KTRACE: 3710164032Srwatson 3711166827Srwatson#if 0 3712164032Srwatson /* 3713164032Srwatson * Allow jailed processes to configure audit identity and 3714164032Srwatson * submit audit records (login, etc). In the future we may 3715164032Srwatson * want to further refine the relationship between audit and 3716164032Srwatson * jail. 3717164032Srwatson */ 3718164032Srwatson case PRIV_AUDIT_GETAUDIT: 3719164032Srwatson case PRIV_AUDIT_SETAUDIT: 3720164032Srwatson case PRIV_AUDIT_SUBMIT: 3721166827Srwatson#endif 3722164032Srwatson 3723164032Srwatson /* 3724164032Srwatson * Allow jailed processes to manipulate process UNIX 3725164032Srwatson * credentials in any way they see fit. 3726164032Srwatson */ 3727164032Srwatson case PRIV_CRED_SETUID: 3728164032Srwatson case PRIV_CRED_SETEUID: 3729164032Srwatson case PRIV_CRED_SETGID: 3730164032Srwatson case PRIV_CRED_SETEGID: 3731164032Srwatson case PRIV_CRED_SETGROUPS: 3732164032Srwatson case PRIV_CRED_SETREUID: 3733164032Srwatson case PRIV_CRED_SETREGID: 3734164032Srwatson case PRIV_CRED_SETRESUID: 3735164032Srwatson case PRIV_CRED_SETRESGID: 3736164032Srwatson 3737164032Srwatson /* 3738164032Srwatson * Jail implements visibility constraints already, so allow 3739164032Srwatson * jailed root to override uid/gid-based constraints. 3740164032Srwatson */ 3741164032Srwatson case PRIV_SEEOTHERGIDS: 3742164032Srwatson case PRIV_SEEOTHERUIDS: 3743164032Srwatson 3744164032Srwatson /* 3745164032Srwatson * Jail implements inter-process debugging limits already, so 3746164032Srwatson * allow jailed root various debugging privileges. 3747164032Srwatson */ 3748164032Srwatson case PRIV_DEBUG_DIFFCRED: 3749164032Srwatson case PRIV_DEBUG_SUGID: 3750164032Srwatson case PRIV_DEBUG_UNPRIV: 3751164032Srwatson 3752164032Srwatson /* 3753164032Srwatson * Allow jail to set various resource limits and login 3754164032Srwatson * properties, and for now, exceed process resource limits. 3755164032Srwatson */ 3756164032Srwatson case PRIV_PROC_LIMIT: 3757164032Srwatson case PRIV_PROC_SETLOGIN: 3758164032Srwatson case PRIV_PROC_SETRLIMIT: 3759164032Srwatson 3760164032Srwatson /* 3761164032Srwatson * System V and POSIX IPC privileges are granted in jail. 3762164032Srwatson */ 3763164032Srwatson case PRIV_IPC_READ: 3764164032Srwatson case PRIV_IPC_WRITE: 3765164032Srwatson case PRIV_IPC_ADMIN: 3766164032Srwatson case PRIV_IPC_MSGSIZE: 3767164032Srwatson case PRIV_MQ_ADMIN: 3768164032Srwatson 3769164032Srwatson /* 3770192895Sjamie * Jail operations within a jail work on child jails. 3771192895Sjamie */ 3772192895Sjamie case PRIV_JAIL_ATTACH: 3773192895Sjamie case PRIV_JAIL_SET: 3774192895Sjamie case PRIV_JAIL_REMOVE: 3775192895Sjamie 3776192895Sjamie /* 3777164032Srwatson * Jail implements its own inter-process limits, so allow 3778164032Srwatson * root processes in jail to change scheduling on other 3779164032Srwatson * processes in the same jail. Likewise for signalling. 3780164032Srwatson */ 3781164032Srwatson case PRIV_SCHED_DIFFCRED: 3782185435Sbz case PRIV_SCHED_CPUSET: 3783164032Srwatson case PRIV_SIGNAL_DIFFCRED: 3784164032Srwatson case PRIV_SIGNAL_SUGID: 3785164032Srwatson 3786164032Srwatson /* 3787164032Srwatson * Allow jailed processes to write to sysctls marked as jail 3788164032Srwatson * writable. 3789164032Srwatson */ 3790164032Srwatson case PRIV_SYSCTL_WRITEJAIL: 3791164032Srwatson 3792164032Srwatson /* 3793164032Srwatson * Allow root in jail to manage a variety of quota 3794166831Srwatson * properties. These should likely be conditional on a 3795166831Srwatson * configuration option. 3796164032Srwatson */ 3797166832Srwatson case PRIV_VFS_GETQUOTA: 3798166832Srwatson case PRIV_VFS_SETQUOTA: 3799164032Srwatson 3800164032Srwatson /* 3801164032Srwatson * Since Jail relies on chroot() to implement file system 3802164032Srwatson * protections, grant many VFS privileges to root in jail. 3803164032Srwatson * Be careful to exclude mount-related and NFS-related 3804164032Srwatson * privileges. 3805164032Srwatson */ 3806164032Srwatson case PRIV_VFS_READ: 3807164032Srwatson case PRIV_VFS_WRITE: 3808164032Srwatson case PRIV_VFS_ADMIN: 3809164032Srwatson case PRIV_VFS_EXEC: 3810164032Srwatson case PRIV_VFS_LOOKUP: 3811164032Srwatson case PRIV_VFS_BLOCKRESERVE: /* XXXRW: Slightly surprising. */ 3812164032Srwatson case PRIV_VFS_CHFLAGS_DEV: 3813164032Srwatson case PRIV_VFS_CHOWN: 3814164032Srwatson case PRIV_VFS_CHROOT: 3815167152Spjd case PRIV_VFS_RETAINSUGID: 3816164032Srwatson case PRIV_VFS_FCHROOT: 3817164032Srwatson case PRIV_VFS_LINK: 3818164032Srwatson case PRIV_VFS_SETGID: 3819172860Srwatson case PRIV_VFS_STAT: 3820164032Srwatson case PRIV_VFS_STICKYFILE: 3821164032Srwatson return (0); 3822164032Srwatson 3823164032Srwatson /* 3824164032Srwatson * Depending on the global setting, allow privilege of 3825164032Srwatson * setting system flags. 3826164032Srwatson */ 3827164032Srwatson case PRIV_VFS_SYSFLAGS: 3828192895Sjamie if (cred->cr_prison->pr_allow & PR_ALLOW_CHFLAGS) 3829164032Srwatson return (0); 3830164032Srwatson else 3831164032Srwatson return (EPERM); 3832164032Srwatson 3833164032Srwatson /* 3834168396Spjd * Depending on the global setting, allow privilege of 3835168396Spjd * mounting/unmounting file systems. 3836168396Spjd */ 3837168396Spjd case PRIV_VFS_MOUNT: 3838168396Spjd case PRIV_VFS_UNMOUNT: 3839168396Spjd case PRIV_VFS_MOUNT_NONUSER: 3840168699Spjd case PRIV_VFS_MOUNT_OWNER: 3841192895Sjamie if (cred->cr_prison->pr_allow & PR_ALLOW_MOUNT) 3842168396Spjd return (0); 3843168396Spjd else 3844168396Spjd return (EPERM); 3845168396Spjd 3846168396Spjd /* 3847168591Srwatson * Allow jailed root to bind reserved ports and reuse in-use 3848168591Srwatson * ports. 3849164032Srwatson */ 3850164032Srwatson case PRIV_NETINET_RESERVEDPORT: 3851168591Srwatson case PRIV_NETINET_REUSEPORT: 3852164032Srwatson return (0); 3853164032Srwatson 3854164032Srwatson /* 3855175630Sbz * Allow jailed root to set certian IPv4/6 (option) headers. 3856175630Sbz */ 3857175630Sbz case PRIV_NETINET_SETHDROPTS: 3858175630Sbz return (0); 3859175630Sbz 3860175630Sbz /* 3861164032Srwatson * Conditionally allow creating raw sockets in jail. 3862164032Srwatson */ 3863164032Srwatson case PRIV_NETINET_RAW: 3864192895Sjamie if (cred->cr_prison->pr_allow & PR_ALLOW_RAW_SOCKETS) 3865164032Srwatson return (0); 3866164032Srwatson else 3867164032Srwatson return (EPERM); 3868164032Srwatson 3869164032Srwatson /* 3870164032Srwatson * Since jail implements its own visibility limits on netstat 3871164032Srwatson * sysctls, allow getcred. This allows identd to work in 3872164032Srwatson * jail. 3873164032Srwatson */ 3874164032Srwatson case PRIV_NETINET_GETCRED: 3875164032Srwatson return (0); 3876164032Srwatson 3877164032Srwatson default: 3878164032Srwatson /* 3879164032Srwatson * In all remaining cases, deny the privilege request. This 3880164032Srwatson * includes almost all network privileges, many system 3881164032Srwatson * configuration privileges. 3882164032Srwatson */ 3883164032Srwatson return (EPERM); 3884164032Srwatson } 3885164032Srwatson} 3886164032Srwatson 3887192895Sjamie/* 3888192895Sjamie * Return the part of pr2's name that is relative to pr1, or the whole name 3889192895Sjamie * if it does not directly follow. 3890192895Sjamie */ 3891192895Sjamie 3892192895Sjamiechar * 3893192895Sjamieprison_name(struct prison *pr1, struct prison *pr2) 3894192895Sjamie{ 3895192895Sjamie char *name; 3896192895Sjamie 3897192895Sjamie /* Jails see themselves as "0" (if they see themselves at all). */ 3898192895Sjamie if (pr1 == pr2) 3899192895Sjamie return "0"; 3900192895Sjamie name = pr2->pr_name; 3901192895Sjamie if (prison_ischild(pr1, pr2)) { 3902192895Sjamie /* 3903192895Sjamie * pr1 isn't locked (and allprison_lock may not be either) 3904192895Sjamie * so its length can't be counted on. But the number of dots 3905192895Sjamie * can be counted on - and counted. 3906192895Sjamie */ 3907192895Sjamie for (; pr1 != &prison0; pr1 = pr1->pr_parent) 3908192895Sjamie name = strchr(name, '.') + 1; 3909192895Sjamie } 3910192895Sjamie return (name); 3911192895Sjamie} 3912192895Sjamie 3913192895Sjamie/* 3914192895Sjamie * Return the part of pr2's path that is relative to pr1, or the whole path 3915192895Sjamie * if it does not directly follow. 3916192895Sjamie */ 3917192895Sjamiestatic char * 3918192895Sjamieprison_path(struct prison *pr1, struct prison *pr2) 3919192895Sjamie{ 3920192895Sjamie char *path1, *path2; 3921192895Sjamie int len1; 3922192895Sjamie 3923192895Sjamie path1 = pr1->pr_path; 3924192895Sjamie path2 = pr2->pr_path; 3925192895Sjamie if (!strcmp(path1, "/")) 3926192895Sjamie return (path2); 3927192895Sjamie len1 = strlen(path1); 3928192895Sjamie if (strncmp(path1, path2, len1)) 3929192895Sjamie return (path2); 3930192895Sjamie if (path2[len1] == '\0') 3931192895Sjamie return "/"; 3932192895Sjamie if (path2[len1] == '/') 3933192895Sjamie return (path2 + len1); 3934192895Sjamie return (path2); 3935192895Sjamie} 3936192895Sjamie 3937192895Sjamie 3938192895Sjamie/* 3939192895Sjamie * Jail-related sysctls. 3940192895Sjamie */ 3941192895SjamieSYSCTL_NODE(_security, OID_AUTO, jail, CTLFLAG_RW, 0, 3942192895Sjamie "Jails"); 3943192895Sjamie 3944113275Smikestatic int 3945113275Smikesysctl_jail_list(SYSCTL_HANDLER_ARGS) 3946113275Smike{ 3947191673Sjamie struct xprison *xp; 3948192895Sjamie struct prison *pr, *cpr; 3949191673Sjamie#ifdef INET 3950191673Sjamie struct in_addr *ip4 = NULL; 3951191673Sjamie int ip4s = 0; 3952191673Sjamie#endif 3953191673Sjamie#ifdef INET6 3954208803Scperciva struct in6_addr *ip6 = NULL; 3955191673Sjamie int ip6s = 0; 3956191673Sjamie#endif 3957192895Sjamie int descend, error; 3958113275Smike 3959191673Sjamie xp = malloc(sizeof(*xp), M_TEMP, M_WAITOK); 3960192895Sjamie pr = req->td->td_ucred->cr_prison; 3961191673Sjamie error = 0; 3962168401Spjd sx_slock(&allprison_lock); 3963192895Sjamie FOREACH_PRISON_DESCENDANT(pr, cpr, descend) { 3964192895Sjamie#if defined(INET) || defined(INET6) 3965191673Sjamie again: 3966192895Sjamie#endif 3967192895Sjamie mtx_lock(&cpr->pr_mtx); 3968185435Sbz#ifdef INET 3969192895Sjamie if (cpr->pr_ip4s > 0) { 3970192895Sjamie if (ip4s < cpr->pr_ip4s) { 3971192895Sjamie ip4s = cpr->pr_ip4s; 3972192895Sjamie mtx_unlock(&cpr->pr_mtx); 3973191673Sjamie ip4 = realloc(ip4, ip4s * 3974191673Sjamie sizeof(struct in_addr), M_TEMP, M_WAITOK); 3975191673Sjamie goto again; 3976191673Sjamie } 3977192895Sjamie bcopy(cpr->pr_ip4, ip4, 3978192895Sjamie cpr->pr_ip4s * sizeof(struct in_addr)); 3979191673Sjamie } 3980185435Sbz#endif 3981185435Sbz#ifdef INET6 3982192895Sjamie if (cpr->pr_ip6s > 0) { 3983192895Sjamie if (ip6s < cpr->pr_ip6s) { 3984192895Sjamie ip6s = cpr->pr_ip6s; 3985192895Sjamie mtx_unlock(&cpr->pr_mtx); 3986191673Sjamie ip6 = realloc(ip6, ip6s * 3987191673Sjamie sizeof(struct in6_addr), M_TEMP, M_WAITOK); 3988191673Sjamie goto again; 3989191673Sjamie } 3990192895Sjamie bcopy(cpr->pr_ip6, ip6, 3991192895Sjamie cpr->pr_ip6s * sizeof(struct in6_addr)); 3992191673Sjamie } 3993185435Sbz#endif 3994192895Sjamie if (cpr->pr_ref == 0) { 3995192895Sjamie mtx_unlock(&cpr->pr_mtx); 3996191673Sjamie continue; 3997191673Sjamie } 3998191673Sjamie bzero(xp, sizeof(*xp)); 3999113275Smike xp->pr_version = XPRISON_VERSION; 4000192895Sjamie xp->pr_id = cpr->pr_id; 4001192895Sjamie xp->pr_state = cpr->pr_uref > 0 4002191673Sjamie ? PRISON_STATE_ALIVE : PRISON_STATE_DYING; 4003192895Sjamie strlcpy(xp->pr_path, prison_path(pr, cpr), sizeof(xp->pr_path)); 4004194118Sjamie strlcpy(xp->pr_host, cpr->pr_hostname, sizeof(xp->pr_host)); 4005192895Sjamie strlcpy(xp->pr_name, prison_name(pr, cpr), sizeof(xp->pr_name)); 4006185435Sbz#ifdef INET 4007192895Sjamie xp->pr_ip4s = cpr->pr_ip4s; 4008185435Sbz#endif 4009185435Sbz#ifdef INET6 4010192895Sjamie xp->pr_ip6s = cpr->pr_ip6s; 4011185435Sbz#endif 4012192895Sjamie mtx_unlock(&cpr->pr_mtx); 4013191673Sjamie error = SYSCTL_OUT(req, xp, sizeof(*xp)); 4014191673Sjamie if (error) 4015191673Sjamie break; 4016185435Sbz#ifdef INET 4017191673Sjamie if (xp->pr_ip4s > 0) { 4018191673Sjamie error = SYSCTL_OUT(req, ip4, 4019191673Sjamie xp->pr_ip4s * sizeof(struct in_addr)); 4020191673Sjamie if (error) 4021191673Sjamie break; 4022185435Sbz } 4023185435Sbz#endif 4024185435Sbz#ifdef INET6 4025191673Sjamie if (xp->pr_ip6s > 0) { 4026191673Sjamie error = SYSCTL_OUT(req, ip6, 4027191673Sjamie xp->pr_ip6s * sizeof(struct in6_addr)); 4028191673Sjamie if (error) 4029191673Sjamie break; 4030185435Sbz } 4031185435Sbz#endif 4032113275Smike } 4033168401Spjd sx_sunlock(&allprison_lock); 4034191673Sjamie free(xp, M_TEMP); 4035191673Sjamie#ifdef INET 4036191673Sjamie free(ip4, M_TEMP); 4037191673Sjamie#endif 4038191673Sjamie#ifdef INET6 4039191673Sjamie free(ip6, M_TEMP); 4040191673Sjamie#endif 4041167354Spjd return (error); 4042113275Smike} 4043113275Smike 4044187864SedSYSCTL_OID(_security_jail, OID_AUTO, list, 4045187864Sed CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 0, 4046187864Sed sysctl_jail_list, "S", "List of active jails"); 4047126004Spjd 4048126004Spjdstatic int 4049126004Spjdsysctl_jail_jailed(SYSCTL_HANDLER_ARGS) 4050126004Spjd{ 4051126004Spjd int error, injail; 4052126004Spjd 4053126004Spjd injail = jailed(req->td->td_ucred); 4054126004Spjd error = SYSCTL_OUT(req, &injail, sizeof(injail)); 4055126004Spjd 4056126004Spjd return (error); 4057126004Spjd} 4058192895Sjamie 4059187864SedSYSCTL_PROC(_security_jail, OID_AUTO, jailed, 4060187864Sed CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 0, 4061187864Sed sysctl_jail_jailed, "I", "Process in jail?"); 4062185435Sbz 4063192895Sjamie#if defined(INET) || defined(INET6) 4064193865SjamieSYSCTL_UINT(_security_jail, OID_AUTO, jail_max_af_ips, CTLFLAG_RW, 4065192895Sjamie &jail_max_af_ips, 0, 4066192895Sjamie "Number of IP addresses a jail may have at most per address family"); 4067192895Sjamie#endif 4068192895Sjamie 4069192895Sjamie/* 4070192895Sjamie * Default parameters for jail(2) compatability. For historical reasons, 4071192895Sjamie * the sysctl names have varying similarity to the parameter names. Prisons 4072192895Sjamie * just see their own parameters, and can't change them. 4073192895Sjamie */ 4074192895Sjamiestatic int 4075192895Sjamiesysctl_jail_default_allow(SYSCTL_HANDLER_ARGS) 4076192895Sjamie{ 4077192895Sjamie struct prison *pr; 4078192895Sjamie int allow, error, i; 4079192895Sjamie 4080192895Sjamie pr = req->td->td_ucred->cr_prison; 4081192895Sjamie allow = (pr == &prison0) ? jail_default_allow : pr->pr_allow; 4082192895Sjamie 4083192895Sjamie /* Get the current flag value, and convert it to a boolean. */ 4084192895Sjamie i = (allow & arg2) ? 1 : 0; 4085192895Sjamie if (arg1 != NULL) 4086192895Sjamie i = !i; 4087192895Sjamie error = sysctl_handle_int(oidp, &i, 0, req); 4088192895Sjamie if (error || !req->newptr) 4089192895Sjamie return (error); 4090192895Sjamie i = i ? arg2 : 0; 4091192895Sjamie if (arg1 != NULL) 4092192895Sjamie i ^= arg2; 4093192895Sjamie /* 4094192895Sjamie * The sysctls don't have CTLFLAGS_PRISON, so assume prison0 4095192895Sjamie * for writing. 4096192895Sjamie */ 4097192895Sjamie mtx_lock(&prison0.pr_mtx); 4098192895Sjamie jail_default_allow = (jail_default_allow & ~arg2) | i; 4099192895Sjamie mtx_unlock(&prison0.pr_mtx); 4100192895Sjamie return (0); 4101192895Sjamie} 4102192895Sjamie 4103192895SjamieSYSCTL_PROC(_security_jail, OID_AUTO, set_hostname_allowed, 4104192895Sjamie CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, 4105192895Sjamie NULL, PR_ALLOW_SET_HOSTNAME, sysctl_jail_default_allow, "I", 4106192895Sjamie "Processes in jail can set their hostnames"); 4107192895SjamieSYSCTL_PROC(_security_jail, OID_AUTO, socket_unixiproute_only, 4108192895Sjamie CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, 4109192895Sjamie (void *)1, PR_ALLOW_SOCKET_AF, sysctl_jail_default_allow, "I", 4110192895Sjamie "Processes in jail are limited to creating UNIX/IP/route sockets only"); 4111192895SjamieSYSCTL_PROC(_security_jail, OID_AUTO, sysvipc_allowed, 4112192895Sjamie CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, 4113192895Sjamie NULL, PR_ALLOW_SYSVIPC, sysctl_jail_default_allow, "I", 4114192895Sjamie "Processes in jail can use System V IPC primitives"); 4115192895SjamieSYSCTL_PROC(_security_jail, OID_AUTO, allow_raw_sockets, 4116192895Sjamie CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, 4117192895Sjamie NULL, PR_ALLOW_RAW_SOCKETS, sysctl_jail_default_allow, "I", 4118192895Sjamie "Prison root can create raw sockets"); 4119192895SjamieSYSCTL_PROC(_security_jail, OID_AUTO, chflags_allowed, 4120192895Sjamie CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, 4121192895Sjamie NULL, PR_ALLOW_CHFLAGS, sysctl_jail_default_allow, "I", 4122192895Sjamie "Processes in jail can alter system file flags"); 4123192895SjamieSYSCTL_PROC(_security_jail, OID_AUTO, mount_allowed, 4124192895Sjamie CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, 4125192895Sjamie NULL, PR_ALLOW_MOUNT, sysctl_jail_default_allow, "I", 4126192895Sjamie "Processes in jail can mount/unmount jail-friendly file systems"); 4127192895Sjamie 4128192895Sjamiestatic int 4129192895Sjamiesysctl_jail_default_level(SYSCTL_HANDLER_ARGS) 4130192895Sjamie{ 4131192895Sjamie struct prison *pr; 4132192895Sjamie int level, error; 4133192895Sjamie 4134192895Sjamie pr = req->td->td_ucred->cr_prison; 4135192895Sjamie level = (pr == &prison0) ? *(int *)arg1 : *(int *)((char *)pr + arg2); 4136192895Sjamie error = sysctl_handle_int(oidp, &level, 0, req); 4137192895Sjamie if (error || !req->newptr) 4138192895Sjamie return (error); 4139192895Sjamie *(int *)arg1 = level; 4140192895Sjamie return (0); 4141192895Sjamie} 4142192895Sjamie 4143192895SjamieSYSCTL_PROC(_security_jail, OID_AUTO, enforce_statfs, 4144192895Sjamie CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, 4145192895Sjamie &jail_default_enforce_statfs, offsetof(struct prison, pr_enforce_statfs), 4146192895Sjamie sysctl_jail_default_level, "I", 4147192895Sjamie "Processes in jail cannot see all mounted file systems"); 4148192895Sjamie 4149192895Sjamie/* 4150192895Sjamie * Nodes to describe jail parameters. Maximum length of string parameters 4151192895Sjamie * is returned in the string itself, and the other parameters exist merely 4152192895Sjamie * to make themselves and their types known. 4153192895Sjamie */ 4154192895SjamieSYSCTL_NODE(_security_jail, OID_AUTO, param, CTLFLAG_RW, 0, 4155192895Sjamie "Jail parameters"); 4156192895Sjamie 4157192895Sjamieint 4158192895Sjamiesysctl_jail_param(SYSCTL_HANDLER_ARGS) 4159192895Sjamie{ 4160192895Sjamie int i; 4161192895Sjamie long l; 4162192895Sjamie size_t s; 4163192895Sjamie char numbuf[12]; 4164192895Sjamie 4165192895Sjamie switch (oidp->oid_kind & CTLTYPE) 4166192895Sjamie { 4167192895Sjamie case CTLTYPE_LONG: 4168192895Sjamie case CTLTYPE_ULONG: 4169192895Sjamie l = 0; 4170192895Sjamie#ifdef SCTL_MASK32 4171192895Sjamie if (!(req->flags & SCTL_MASK32)) 4172192895Sjamie#endif 4173192895Sjamie return (SYSCTL_OUT(req, &l, sizeof(l))); 4174192895Sjamie case CTLTYPE_INT: 4175192895Sjamie case CTLTYPE_UINT: 4176192895Sjamie i = 0; 4177192895Sjamie return (SYSCTL_OUT(req, &i, sizeof(i))); 4178192895Sjamie case CTLTYPE_STRING: 4179192895Sjamie snprintf(numbuf, sizeof(numbuf), "%d", arg2); 4180192895Sjamie return 4181192895Sjamie (sysctl_handle_string(oidp, numbuf, sizeof(numbuf), req)); 4182192895Sjamie case CTLTYPE_STRUCT: 4183192895Sjamie s = (size_t)arg2; 4184192895Sjamie return (SYSCTL_OUT(req, &s, sizeof(s))); 4185192895Sjamie } 4186192895Sjamie return (0); 4187192895Sjamie} 4188192895Sjamie 4189192895SjamieSYSCTL_JAIL_PARAM(, jid, CTLTYPE_INT | CTLFLAG_RDTUN, "I", "Jail ID"); 4190192895SjamieSYSCTL_JAIL_PARAM(, parent, CTLTYPE_INT | CTLFLAG_RD, "I", "Jail parent ID"); 4191192895SjamieSYSCTL_JAIL_PARAM_STRING(, name, CTLFLAG_RW, MAXHOSTNAMELEN, "Jail name"); 4192192895SjamieSYSCTL_JAIL_PARAM_STRING(, path, CTLFLAG_RDTUN, MAXPATHLEN, "Jail root path"); 4193192895SjamieSYSCTL_JAIL_PARAM(, securelevel, CTLTYPE_INT | CTLFLAG_RW, 4194192895Sjamie "I", "Jail secure level"); 4195192895SjamieSYSCTL_JAIL_PARAM(, enforce_statfs, CTLTYPE_INT | CTLFLAG_RW, 4196192895Sjamie "I", "Jail cannot see all mounted file systems"); 4197192895SjamieSYSCTL_JAIL_PARAM(, persist, CTLTYPE_INT | CTLFLAG_RW, 4198192895Sjamie "B", "Jail persistence"); 4199194251Sjamie#ifdef VIMAGE 4200194251SjamieSYSCTL_JAIL_PARAM(, vnet, CTLTYPE_INT | CTLFLAG_RDTUN, 4201195870Sjamie "E,jailsys", "Virtual network stack"); 4202194251Sjamie#endif 4203192895SjamieSYSCTL_JAIL_PARAM(, dying, CTLTYPE_INT | CTLFLAG_RD, 4204192895Sjamie "B", "Jail is in the process of shutting down"); 4205192895Sjamie 4206194762SjamieSYSCTL_JAIL_PARAM_NODE(children, "Number of child jails"); 4207194762SjamieSYSCTL_JAIL_PARAM(_children, cur, CTLTYPE_INT | CTLFLAG_RD, 4208194762Sjamie "I", "Current number of child jails"); 4209194762SjamieSYSCTL_JAIL_PARAM(_children, max, CTLTYPE_INT | CTLFLAG_RW, 4210194762Sjamie "I", "Maximum number of child jails"); 4211194762Sjamie 4212195870SjamieSYSCTL_JAIL_PARAM_SYS_NODE(host, CTLFLAG_RW, "Jail host info"); 4213192895SjamieSYSCTL_JAIL_PARAM_STRING(_host, hostname, CTLFLAG_RW, MAXHOSTNAMELEN, 4214192895Sjamie "Jail hostname"); 4215193066SjamieSYSCTL_JAIL_PARAM_STRING(_host, domainname, CTLFLAG_RW, MAXHOSTNAMELEN, 4216193066Sjamie "Jail NIS domainname"); 4217193066SjamieSYSCTL_JAIL_PARAM_STRING(_host, hostuuid, CTLFLAG_RW, HOSTUUIDLEN, 4218193066Sjamie "Jail host UUID"); 4219193066SjamieSYSCTL_JAIL_PARAM(_host, hostid, CTLTYPE_ULONG | CTLFLAG_RW, 4220193066Sjamie "LU", "Jail host ID"); 4221192895Sjamie 4222192895SjamieSYSCTL_JAIL_PARAM_NODE(cpuset, "Jail cpuset"); 4223192895SjamieSYSCTL_JAIL_PARAM(_cpuset, id, CTLTYPE_INT | CTLFLAG_RD, "I", "Jail cpuset ID"); 4224192895Sjamie 4225192895Sjamie#ifdef INET 4226195974SjamieSYSCTL_JAIL_PARAM_SYS_NODE(ip4, CTLFLAG_RDTUN, 4227195974Sjamie "Jail IPv4 address virtualization"); 4228192895SjamieSYSCTL_JAIL_PARAM_STRUCT(_ip4, addr, CTLFLAG_RW, sizeof(struct in_addr), 4229192895Sjamie "S,in_addr,a", "Jail IPv4 addresses"); 4230202468SbzSYSCTL_JAIL_PARAM(_ip4, saddrsel, CTLTYPE_INT | CTLFLAG_RW, 4231202468Sbz "B", "Do (not) use IPv4 source address selection rather than the " 4232202468Sbz "primary jail IPv4 address."); 4233192895Sjamie#endif 4234192895Sjamie#ifdef INET6 4235195974SjamieSYSCTL_JAIL_PARAM_SYS_NODE(ip6, CTLFLAG_RDTUN, 4236195974Sjamie "Jail IPv6 address virtualization"); 4237192895SjamieSYSCTL_JAIL_PARAM_STRUCT(_ip6, addr, CTLFLAG_RW, sizeof(struct in6_addr), 4238192895Sjamie "S,in6_addr,a", "Jail IPv6 addresses"); 4239202468SbzSYSCTL_JAIL_PARAM(_ip6, saddrsel, CTLTYPE_INT | CTLFLAG_RW, 4240202468Sbz "B", "Do (not) use IPv6 source address selection rather than the " 4241202468Sbz "primary jail IPv6 address."); 4242192895Sjamie#endif 4243192895Sjamie 4244192895SjamieSYSCTL_JAIL_PARAM_NODE(allow, "Jail permission flags"); 4245192895SjamieSYSCTL_JAIL_PARAM(_allow, set_hostname, CTLTYPE_INT | CTLFLAG_RW, 4246192895Sjamie "B", "Jail may set hostname"); 4247192895SjamieSYSCTL_JAIL_PARAM(_allow, sysvipc, CTLTYPE_INT | CTLFLAG_RW, 4248192895Sjamie "B", "Jail may use SYSV IPC"); 4249192895SjamieSYSCTL_JAIL_PARAM(_allow, raw_sockets, CTLTYPE_INT | CTLFLAG_RW, 4250192895Sjamie "B", "Jail may create raw sockets"); 4251192895SjamieSYSCTL_JAIL_PARAM(_allow, chflags, CTLTYPE_INT | CTLFLAG_RW, 4252192895Sjamie "B", "Jail may alter system file flags"); 4253192895SjamieSYSCTL_JAIL_PARAM(_allow, mount, CTLTYPE_INT | CTLFLAG_RW, 4254192895Sjamie "B", "Jail may mount/unmount jail-friendly file systems"); 4255192895SjamieSYSCTL_JAIL_PARAM(_allow, quotas, CTLTYPE_INT | CTLFLAG_RW, 4256192895Sjamie "B", "Jail may set file quotas"); 4257192895SjamieSYSCTL_JAIL_PARAM(_allow, socket_af, CTLTYPE_INT | CTLFLAG_RW, 4258192895Sjamie "B", "Jail may create sockets other than just UNIX/IPv4/IPv6/route"); 4259192895Sjamie 4260192895Sjamie 4261185435Sbz#ifdef DDB 4262191673Sjamie 4263191673Sjamiestatic void 4264191673Sjamiedb_show_prison(struct prison *pr) 4265185435Sbz{ 4266192895Sjamie int fi; 4267191673Sjamie#if defined(INET) || defined(INET6) 4268191673Sjamie int ii; 4269185435Sbz#endif 4270195870Sjamie unsigned jsf; 4271185435Sbz#ifdef INET6 4272185435Sbz char ip6buf[INET6_ADDRSTRLEN]; 4273185435Sbz#endif 4274185435Sbz 4275191673Sjamie db_printf("prison %p:\n", pr); 4276191673Sjamie db_printf(" jid = %d\n", pr->pr_id); 4277191673Sjamie db_printf(" name = %s\n", pr->pr_name); 4278192895Sjamie db_printf(" parent = %p\n", pr->pr_parent); 4279191673Sjamie db_printf(" ref = %d\n", pr->pr_ref); 4280191673Sjamie db_printf(" uref = %d\n", pr->pr_uref); 4281191673Sjamie db_printf(" path = %s\n", pr->pr_path); 4282191673Sjamie db_printf(" cpuset = %d\n", pr->pr_cpuset 4283191673Sjamie ? pr->pr_cpuset->cs_id : -1); 4284194251Sjamie#ifdef VIMAGE 4285194251Sjamie db_printf(" vnet = %p\n", pr->pr_vnet); 4286194251Sjamie#endif 4287191673Sjamie db_printf(" root = %p\n", pr->pr_root); 4288191673Sjamie db_printf(" securelevel = %d\n", pr->pr_securelevel); 4289202123Sbz db_printf(" children.max = %d\n", pr->pr_childmax); 4290202123Sbz db_printf(" children.cur = %d\n", pr->pr_childcount); 4291192895Sjamie db_printf(" child = %p\n", LIST_FIRST(&pr->pr_children)); 4292192895Sjamie db_printf(" sibling = %p\n", LIST_NEXT(pr, pr_sibling)); 4293202123Sbz db_printf(" flags = 0x%x", pr->pr_flags); 4294192895Sjamie for (fi = 0; fi < sizeof(pr_flag_names) / sizeof(pr_flag_names[0]); 4295192895Sjamie fi++) 4296192895Sjamie if (pr_flag_names[fi] != NULL && (pr->pr_flags & (1 << fi))) 4297192895Sjamie db_printf(" %s", pr_flag_names[fi]); 4298195870Sjamie for (fi = 0; fi < sizeof(pr_flag_jailsys) / sizeof(pr_flag_jailsys[0]); 4299195870Sjamie fi++) { 4300195870Sjamie jsf = pr->pr_flags & 4301195870Sjamie (pr_flag_jailsys[fi].disable | pr_flag_jailsys[fi].new); 4302195870Sjamie db_printf(" %-16s= %s\n", pr_flag_jailsys[fi].name, 4303195870Sjamie pr_flag_jailsys[fi].disable && 4304195870Sjamie (jsf == pr_flag_jailsys[fi].disable) ? "disable" 4305195870Sjamie : (jsf == pr_flag_jailsys[fi].new) ? "new" 4306195870Sjamie : "inherit"); 4307195870Sjamie } 4308202123Sbz db_printf(" allow = 0x%x", pr->pr_allow); 4309192895Sjamie for (fi = 0; fi < sizeof(pr_allow_names) / sizeof(pr_allow_names[0]); 4310192895Sjamie fi++) 4311192895Sjamie if (pr_allow_names[fi] != NULL && (pr->pr_allow & (1 << fi))) 4312192895Sjamie db_printf(" %s", pr_allow_names[fi]); 4313191673Sjamie db_printf("\n"); 4314192895Sjamie db_printf(" enforce_statfs = %d\n", pr->pr_enforce_statfs); 4315194118Sjamie db_printf(" host.hostname = %s\n", pr->pr_hostname); 4316194118Sjamie db_printf(" host.domainname = %s\n", pr->pr_domainname); 4317194118Sjamie db_printf(" host.hostuuid = %s\n", pr->pr_hostuuid); 4318193066Sjamie db_printf(" host.hostid = %lu\n", pr->pr_hostid); 4319185435Sbz#ifdef INET 4320191673Sjamie db_printf(" ip4s = %d\n", pr->pr_ip4s); 4321191673Sjamie for (ii = 0; ii < pr->pr_ip4s; ii++) 4322191673Sjamie db_printf(" %s %s\n", 4323202123Sbz ii == 0 ? "ip4.addr =" : " ", 4324191673Sjamie inet_ntoa(pr->pr_ip4[ii])); 4325185435Sbz#endif 4326185435Sbz#ifdef INET6 4327191673Sjamie db_printf(" ip6s = %d\n", pr->pr_ip6s); 4328191673Sjamie for (ii = 0; ii < pr->pr_ip6s; ii++) 4329191673Sjamie db_printf(" %s %s\n", 4330202123Sbz ii == 0 ? "ip6.addr =" : " ", 4331191673Sjamie ip6_sprintf(ip6buf, &pr->pr_ip6[ii])); 4332191673Sjamie#endif 4333191673Sjamie} 4334191673Sjamie 4335191673SjamieDB_SHOW_COMMAND(prison, db_show_prison_command) 4336191673Sjamie{ 4337191673Sjamie struct prison *pr; 4338191673Sjamie 4339191673Sjamie if (!have_addr) { 4340192895Sjamie /* 4341192895Sjamie * Show all prisons in the list, and prison0 which is not 4342192895Sjamie * listed. 4343192895Sjamie */ 4344192895Sjamie db_show_prison(&prison0); 4345192895Sjamie if (!db_pager_quit) { 4346192895Sjamie TAILQ_FOREACH(pr, &allprison, pr_list) { 4347192895Sjamie db_show_prison(pr); 4348192895Sjamie if (db_pager_quit) 4349192895Sjamie break; 4350192895Sjamie } 4351191673Sjamie } 4352191673Sjamie return; 4353191673Sjamie } 4354191673Sjamie 4355192895Sjamie if (addr == 0) 4356192895Sjamie pr = &prison0; 4357192895Sjamie else { 4358192895Sjamie /* Look for a prison with the ID and with references. */ 4359191673Sjamie TAILQ_FOREACH(pr, &allprison, pr_list) 4360192895Sjamie if (pr->pr_id == addr && pr->pr_ref > 0) 4361191673Sjamie break; 4362192895Sjamie if (pr == NULL) 4363192895Sjamie /* Look again, without requiring a reference. */ 4364192895Sjamie TAILQ_FOREACH(pr, &allprison, pr_list) 4365192895Sjamie if (pr->pr_id == addr) 4366192895Sjamie break; 4367192895Sjamie if (pr == NULL) 4368192895Sjamie /* Assume address points to a valid prison. */ 4369192895Sjamie pr = (struct prison *)addr; 4370192895Sjamie } 4371191673Sjamie db_show_prison(pr); 4372185435Sbz} 4373191673Sjamie 4374185435Sbz#endif /* DDB */ 4375