kern_jail.c revision 196592
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 196592 2009-08-27 16:15:51Z jamie $"); 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 80192895Sjamie/* prison0 describes what is "real" about the system. */ 81192895Sjamiestruct prison prison0 = { 82192895Sjamie .pr_id = 0, 83192895Sjamie .pr_name = "0", 84192895Sjamie .pr_ref = 1, 85192895Sjamie .pr_uref = 1, 86192895Sjamie .pr_path = "/", 87192895Sjamie .pr_securelevel = -1, 88194762Sjamie .pr_childmax = JAIL_MAX, 89195944Sjamie .pr_hostuuid = DEFAULT_HOSTUUID, 90192895Sjamie .pr_children = LIST_HEAD_INITIALIZER(&prison0.pr_children), 91196176Sbz#ifdef VIMAGE 92196176Sbz .pr_flags = PR_HOST|PR_VNET, 93196176Sbz#else 94193066Sjamie .pr_flags = PR_HOST, 95196176Sbz#endif 96192895Sjamie .pr_allow = PR_ALLOW_ALL, 97192895Sjamie}; 98192895SjamieMTX_SYSINIT(prison0, &prison0.pr_mtx, "jail mutex", MTX_DEF); 9957163Srwatson 100192895Sjamie/* allprison and lastprid are protected by allprison_lock. */ 101168401Spjdstruct sx allprison_lock; 102191673SjamieSX_SYSINIT(allprison_lock, &allprison_lock, "allprison"); 103191673Sjamiestruct prisonlist allprison = TAILQ_HEAD_INITIALIZER(allprison); 104179881Sdelphijint lastprid = 0; 105113275Smike 106191673Sjamiestatic int do_jail_attach(struct thread *td, struct prison *pr); 107190466Sjamiestatic void prison_complete(void *context, int pending); 108191673Sjamiestatic void prison_deref(struct prison *pr, int flags); 109192895Sjamiestatic char *prison_path(struct prison *pr1, struct prison *pr2); 110192895Sjamiestatic void prison_remove_one(struct prison *pr); 111185435Sbz#ifdef INET 112190466Sjamiestatic int _prison_check_ip4(struct prison *pr, struct in_addr *ia); 113192895Sjamiestatic int prison_restrict_ip4(struct prison *pr, struct in_addr *newip4); 114185435Sbz#endif 115185435Sbz#ifdef INET6 116190466Sjamiestatic int _prison_check_ip6(struct prison *pr, struct in6_addr *ia6); 117192895Sjamiestatic int prison_restrict_ip6(struct prison *pr, struct in6_addr *newip6); 118185435Sbz#endif 119113275Smike 120191673Sjamie/* Flags for prison_deref */ 121191673Sjamie#define PD_DEREF 0x01 122191673Sjamie#define PD_DEUREF 0x02 123191673Sjamie#define PD_LOCKED 0x04 124191673Sjamie#define PD_LIST_SLOCKED 0x08 125191673Sjamie#define PD_LIST_XLOCKED 0x10 126113275Smike 127192895Sjamie/* 128192895Sjamie * Parameter names corresponding to PR_* flag values 129192895Sjamie */ 130192895Sjamiestatic char *pr_flag_names[] = { 131192895Sjamie [0] = "persist", 132192895Sjamie}; 133192895Sjamie 134192895Sjamiestatic char *pr_flag_nonames[] = { 135192895Sjamie [0] = "nopersist", 136195870Sjamie}; 137195870Sjamie 138195870Sjamiestruct jailsys_flags { 139195870Sjamie const char *name; 140195870Sjamie unsigned disable; 141195870Sjamie unsigned new; 142195870Sjamie} pr_flag_jailsys[] = { 143195870Sjamie { "host", 0, PR_HOST }, 144195870Sjamie#ifdef VIMAGE 145195870Sjamie { "vnet", 0, PR_VNET }, 146195870Sjamie#endif 147192895Sjamie#ifdef INET 148195870Sjamie { "ip4", PR_IP4_USER | PR_IP4_DISABLE, PR_IP4_USER }, 149192895Sjamie#endif 150192895Sjamie#ifdef INET6 151195870Sjamie { "ip6", PR_IP6_USER | PR_IP6_DISABLE, PR_IP6_USER }, 152192895Sjamie#endif 153192895Sjamie}; 154192895Sjamie 155192895Sjamiestatic char *pr_allow_names[] = { 156192895Sjamie "allow.set_hostname", 157192895Sjamie "allow.sysvipc", 158192895Sjamie "allow.raw_sockets", 159192895Sjamie "allow.chflags", 160192895Sjamie "allow.mount", 161192895Sjamie "allow.quotas", 162192895Sjamie "allow.socket_af", 163192895Sjamie}; 164192895Sjamie 165192895Sjamiestatic char *pr_allow_nonames[] = { 166192895Sjamie "allow.noset_hostname", 167192895Sjamie "allow.nosysvipc", 168192895Sjamie "allow.noraw_sockets", 169192895Sjamie "allow.nochflags", 170192895Sjamie "allow.nomount", 171192895Sjamie "allow.noquotas", 172192895Sjamie "allow.nosocket_af", 173192895Sjamie}; 174192895Sjamie 175196002Sjamie#define JAIL_DEFAULT_ALLOW PR_ALLOW_SET_HOSTNAME 176196002Sjamie#define JAIL_DEFAULT_ENFORCE_STATFS 2 177192895Sjamiestatic unsigned jail_default_allow = JAIL_DEFAULT_ALLOW; 178196002Sjamiestatic int jail_default_enforce_statfs = JAIL_DEFAULT_ENFORCE_STATFS; 179192895Sjamie#if defined(INET) || defined(INET6) 180193865Sjamiestatic unsigned jail_max_af_ips = 255; 181192895Sjamie#endif 182192895Sjamie 183192895Sjamie#ifdef INET 184185435Sbzstatic int 185185435Sbzqcmp_v4(const void *ip1, const void *ip2) 186185435Sbz{ 187185435Sbz in_addr_t iaa, iab; 188185435Sbz 189185435Sbz /* 190185435Sbz * We need to compare in HBO here to get the list sorted as expected 191185435Sbz * by the result of the code. Sorting NBO addresses gives you 192185435Sbz * interesting results. If you do not understand, do not try. 193185435Sbz */ 194185435Sbz iaa = ntohl(((const struct in_addr *)ip1)->s_addr); 195185435Sbz iab = ntohl(((const struct in_addr *)ip2)->s_addr); 196185435Sbz 197185435Sbz /* 198185435Sbz * Do not simply return the difference of the two numbers, the int is 199185435Sbz * not wide enough. 200185435Sbz */ 201185435Sbz if (iaa > iab) 202185435Sbz return (1); 203185435Sbz else if (iaa < iab) 204185435Sbz return (-1); 205185435Sbz else 206185435Sbz return (0); 207185435Sbz} 208185435Sbz#endif 209185435Sbz 210185435Sbz#ifdef INET6 211185435Sbzstatic int 212185435Sbzqcmp_v6(const void *ip1, const void *ip2) 213185435Sbz{ 214185435Sbz const struct in6_addr *ia6a, *ia6b; 215185435Sbz int i, rc; 216185435Sbz 217185435Sbz ia6a = (const struct in6_addr *)ip1; 218185435Sbz ia6b = (const struct in6_addr *)ip2; 219185435Sbz 220185435Sbz rc = 0; 221190466Sjamie for (i = 0; rc == 0 && i < sizeof(struct in6_addr); i++) { 222185435Sbz if (ia6a->s6_addr[i] > ia6b->s6_addr[i]) 223185435Sbz rc = 1; 224185435Sbz else if (ia6a->s6_addr[i] < ia6b->s6_addr[i]) 225185435Sbz rc = -1; 226185435Sbz } 227185435Sbz return (rc); 228185435Sbz} 229185435Sbz#endif 230185435Sbz 231191673Sjamie/* 232191673Sjamie * struct jail_args { 233191673Sjamie * struct jail *jail; 234191673Sjamie * }; 235191673Sjamie */ 236191673Sjamieint 237191673Sjamiejail(struct thread *td, struct jail_args *uap) 238185435Sbz{ 239191673Sjamie uint32_t version; 240191673Sjamie int error; 241192895Sjamie struct jail j; 242185435Sbz 243191673Sjamie error = copyin(uap->jail, &version, sizeof(uint32_t)); 244191673Sjamie if (error) 245191673Sjamie return (error); 246185435Sbz 247191673Sjamie switch (version) { 248191673Sjamie case 0: 249191673Sjamie { 250191673Sjamie struct jail_v0 j0; 251185435Sbz 252192895Sjamie /* FreeBSD single IPv4 jails. */ 253192895Sjamie bzero(&j, sizeof(struct jail)); 254191673Sjamie error = copyin(uap->jail, &j0, sizeof(struct jail_v0)); 255191673Sjamie if (error) 256191673Sjamie return (error); 257192895Sjamie j.version = j0.version; 258192895Sjamie j.path = j0.path; 259192895Sjamie j.hostname = j0.hostname; 260192895Sjamie j.ip4s = j0.ip_number; 261191673Sjamie break; 262191673Sjamie } 263191673Sjamie 264191673Sjamie case 1: 265185435Sbz /* 266191673Sjamie * Version 1 was used by multi-IPv4 jail implementations 267191673Sjamie * that never made it into the official kernel. 268185435Sbz */ 269191673Sjamie return (EINVAL); 270185435Sbz 271191673Sjamie case 2: /* JAIL_API_VERSION */ 272191673Sjamie /* FreeBSD multi-IPv4/IPv6,noIP jails. */ 273191673Sjamie error = copyin(uap->jail, &j, sizeof(struct jail)); 274191673Sjamie if (error) 275191673Sjamie return (error); 276192895Sjamie break; 277192895Sjamie 278192895Sjamie default: 279192895Sjamie /* Sci-Fi jails are not supported, sorry. */ 280192895Sjamie return (EINVAL); 281192895Sjamie } 282192895Sjamie return (kern_jail(td, &j)); 283192895Sjamie} 284192895Sjamie 285192895Sjamieint 286192895Sjamiekern_jail(struct thread *td, struct jail *j) 287192895Sjamie{ 288193865Sjamie struct iovec optiov[2 * (4 289193865Sjamie + sizeof(pr_allow_names) / sizeof(pr_allow_names[0]) 290193865Sjamie#ifdef INET 291193865Sjamie + 1 292193865Sjamie#endif 293193865Sjamie#ifdef INET6 294193865Sjamie + 1 295193865Sjamie#endif 296193865Sjamie )]; 297192895Sjamie struct uio opt; 298192895Sjamie char *u_path, *u_hostname, *u_name; 299185435Sbz#ifdef INET 300193865Sjamie uint32_t ip4s; 301192895Sjamie struct in_addr *u_ip4; 302192895Sjamie#endif 303192895Sjamie#ifdef INET6 304192895Sjamie struct in6_addr *u_ip6; 305192895Sjamie#endif 306192895Sjamie size_t tmplen; 307192895Sjamie int error, enforce_statfs, fi; 308192895Sjamie 309192895Sjamie bzero(&optiov, sizeof(optiov)); 310192895Sjamie opt.uio_iov = optiov; 311192895Sjamie opt.uio_iovcnt = 0; 312192895Sjamie opt.uio_offset = -1; 313192895Sjamie opt.uio_resid = -1; 314192895Sjamie opt.uio_segflg = UIO_SYSSPACE; 315192895Sjamie opt.uio_rw = UIO_READ; 316192895Sjamie opt.uio_td = td; 317192895Sjamie 318192895Sjamie /* Set permissions for top-level jails from sysctls. */ 319192895Sjamie if (!jailed(td->td_ucred)) { 320192895Sjamie for (fi = 0; fi < sizeof(pr_allow_names) / 321192895Sjamie sizeof(pr_allow_names[0]); fi++) { 322192895Sjamie optiov[opt.uio_iovcnt].iov_base = 323192895Sjamie (jail_default_allow & (1 << fi)) 324192895Sjamie ? pr_allow_names[fi] : pr_allow_nonames[fi]; 325192895Sjamie optiov[opt.uio_iovcnt].iov_len = 326192895Sjamie strlen(optiov[opt.uio_iovcnt].iov_base) + 1; 327192895Sjamie opt.uio_iovcnt += 2; 328192895Sjamie } 329192895Sjamie optiov[opt.uio_iovcnt].iov_base = "enforce_statfs"; 330192895Sjamie optiov[opt.uio_iovcnt].iov_len = sizeof("enforce_statfs"); 331192895Sjamie opt.uio_iovcnt++; 332192895Sjamie enforce_statfs = jail_default_enforce_statfs; 333192895Sjamie optiov[opt.uio_iovcnt].iov_base = &enforce_statfs; 334192895Sjamie optiov[opt.uio_iovcnt].iov_len = sizeof(enforce_statfs); 335192895Sjamie opt.uio_iovcnt++; 336192895Sjamie } 337192895Sjamie 338192895Sjamie tmplen = MAXPATHLEN + MAXHOSTNAMELEN + MAXHOSTNAMELEN; 339192895Sjamie#ifdef INET 340192895Sjamie ip4s = (j->version == 0) ? 1 : j->ip4s; 341192895Sjamie if (ip4s > jail_max_af_ips) 342192895Sjamie return (EINVAL); 343192895Sjamie tmplen += ip4s * sizeof(struct in_addr); 344191673Sjamie#else 345192895Sjamie if (j->ip4s > 0) 346192895Sjamie return (EINVAL); 347191673Sjamie#endif 348191673Sjamie#ifdef INET6 349192895Sjamie if (j->ip6s > jail_max_af_ips) 350192895Sjamie return (EINVAL); 351192895Sjamie tmplen += j->ip6s * sizeof(struct in6_addr); 352191673Sjamie#else 353192895Sjamie if (j->ip6s > 0) 354192895Sjamie return (EINVAL); 355191673Sjamie#endif 356192895Sjamie u_path = malloc(tmplen, M_TEMP, M_WAITOK); 357192895Sjamie u_hostname = u_path + MAXPATHLEN; 358192895Sjamie u_name = u_hostname + MAXHOSTNAMELEN; 359191673Sjamie#ifdef INET 360192895Sjamie u_ip4 = (struct in_addr *)(u_name + MAXHOSTNAMELEN); 361191673Sjamie#endif 362191673Sjamie#ifdef INET6 363191673Sjamie#ifdef INET 364192895Sjamie u_ip6 = (struct in6_addr *)(u_ip4 + ip4s); 365191673Sjamie#else 366192895Sjamie u_ip6 = (struct in6_addr *)(u_name + MAXHOSTNAMELEN); 367191673Sjamie#endif 368191673Sjamie#endif 369192895Sjamie optiov[opt.uio_iovcnt].iov_base = "path"; 370192895Sjamie optiov[opt.uio_iovcnt].iov_len = sizeof("path"); 371192895Sjamie opt.uio_iovcnt++; 372192895Sjamie optiov[opt.uio_iovcnt].iov_base = u_path; 373192895Sjamie error = copyinstr(j->path, u_path, MAXPATHLEN, 374192895Sjamie &optiov[opt.uio_iovcnt].iov_len); 375192895Sjamie if (error) { 376192895Sjamie free(u_path, M_TEMP); 377192895Sjamie return (error); 378192895Sjamie } 379192895Sjamie opt.uio_iovcnt++; 380192895Sjamie optiov[opt.uio_iovcnt].iov_base = "host.hostname"; 381192895Sjamie optiov[opt.uio_iovcnt].iov_len = sizeof("host.hostname"); 382192895Sjamie opt.uio_iovcnt++; 383192895Sjamie optiov[opt.uio_iovcnt].iov_base = u_hostname; 384192895Sjamie error = copyinstr(j->hostname, u_hostname, MAXHOSTNAMELEN, 385192895Sjamie &optiov[opt.uio_iovcnt].iov_len); 386192895Sjamie if (error) { 387192895Sjamie free(u_path, M_TEMP); 388192895Sjamie return (error); 389192895Sjamie } 390192895Sjamie opt.uio_iovcnt++; 391192895Sjamie if (j->jailname != NULL) { 392192895Sjamie optiov[opt.uio_iovcnt].iov_base = "name"; 393192895Sjamie optiov[opt.uio_iovcnt].iov_len = sizeof("name"); 394192895Sjamie opt.uio_iovcnt++; 395192895Sjamie optiov[opt.uio_iovcnt].iov_base = u_name; 396192895Sjamie error = copyinstr(j->jailname, u_name, MAXHOSTNAMELEN, 397192895Sjamie &optiov[opt.uio_iovcnt].iov_len); 398191673Sjamie if (error) { 399191673Sjamie free(u_path, M_TEMP); 400191673Sjamie return (error); 401191673Sjamie } 402192895Sjamie opt.uio_iovcnt++; 403192895Sjamie } 404191673Sjamie#ifdef INET 405192895Sjamie optiov[opt.uio_iovcnt].iov_base = "ip4.addr"; 406192895Sjamie optiov[opt.uio_iovcnt].iov_len = sizeof("ip4.addr"); 407192895Sjamie opt.uio_iovcnt++; 408192895Sjamie optiov[opt.uio_iovcnt].iov_base = u_ip4; 409192895Sjamie optiov[opt.uio_iovcnt].iov_len = ip4s * sizeof(struct in_addr); 410192895Sjamie if (j->version == 0) 411192895Sjamie u_ip4->s_addr = j->ip4s; 412192895Sjamie else { 413192895Sjamie error = copyin(j->ip4, u_ip4, optiov[opt.uio_iovcnt].iov_len); 414191673Sjamie if (error) { 415191673Sjamie free(u_path, M_TEMP); 416191673Sjamie return (error); 417191673Sjamie } 418192895Sjamie } 419192895Sjamie opt.uio_iovcnt++; 420185435Sbz#endif 421185435Sbz#ifdef INET6 422192895Sjamie optiov[opt.uio_iovcnt].iov_base = "ip6.addr"; 423192895Sjamie optiov[opt.uio_iovcnt].iov_len = sizeof("ip6.addr"); 424192895Sjamie opt.uio_iovcnt++; 425192895Sjamie optiov[opt.uio_iovcnt].iov_base = u_ip6; 426192895Sjamie optiov[opt.uio_iovcnt].iov_len = j->ip6s * sizeof(struct in6_addr); 427192895Sjamie error = copyin(j->ip6, u_ip6, optiov[opt.uio_iovcnt].iov_len); 428192895Sjamie if (error) { 429192895Sjamie free(u_path, M_TEMP); 430192895Sjamie return (error); 431192895Sjamie } 432192895Sjamie opt.uio_iovcnt++; 433185435Sbz#endif 434192895Sjamie KASSERT(opt.uio_iovcnt <= sizeof(optiov) / sizeof(optiov[0]), 435192895Sjamie ("kern_jail: too many iovecs (%d)", opt.uio_iovcnt)); 436191673Sjamie error = kern_jail_set(td, &opt, JAIL_CREATE | JAIL_ATTACH); 437191673Sjamie free(u_path, M_TEMP); 438191673Sjamie return (error); 439185435Sbz} 440185435Sbz 441192895Sjamie 442191673Sjamie/* 443191673Sjamie * struct jail_set_args { 444191673Sjamie * struct iovec *iovp; 445191673Sjamie * unsigned int iovcnt; 446191673Sjamie * int flags; 447191673Sjamie * }; 448191673Sjamie */ 449191673Sjamieint 450191673Sjamiejail_set(struct thread *td, struct jail_set_args *uap) 451185435Sbz{ 452191673Sjamie struct uio *auio; 453191673Sjamie int error; 454191673Sjamie 455191673Sjamie /* Check that we have an even number of iovecs. */ 456191673Sjamie if (uap->iovcnt & 1) 457191673Sjamie return (EINVAL); 458191673Sjamie 459191673Sjamie error = copyinuio(uap->iovp, uap->iovcnt, &auio); 460191673Sjamie if (error) 461191673Sjamie return (error); 462191673Sjamie error = kern_jail_set(td, auio, uap->flags); 463191673Sjamie free(auio, M_IOV); 464191673Sjamie return (error); 465191673Sjamie} 466191673Sjamie 467191673Sjamieint 468191673Sjamiekern_jail_set(struct thread *td, struct uio *optuio, int flags) 469191673Sjamie{ 470191673Sjamie struct nameidata nd; 471185435Sbz#ifdef INET 472190466Sjamie struct in_addr *ip4; 473185435Sbz#endif 474185435Sbz#ifdef INET6 475185435Sbz struct in6_addr *ip6; 476185435Sbz#endif 477191673Sjamie struct vfsopt *opt; 478191673Sjamie struct vfsoptlist *opts; 479196135Sbz struct prison *pr, *deadpr, *mypr, *ppr, *tpr; 480191673Sjamie struct vnode *root; 481193066Sjamie char *domain, *errmsg, *host, *name, *p, *path, *uuid; 482192895Sjamie#if defined(INET) || defined(INET6) 483196135Sbz struct prison *tppr; 484191673Sjamie void *op; 485192895Sjamie#endif 486193066Sjamie unsigned long hid; 487192895Sjamie size_t namelen, onamelen; 488192895Sjamie int created, cuflags, descend, enforce, error, errmsg_len, errmsg_pos; 489195870Sjamie int gotchildmax, gotenforce, gothid, gotslevel; 490195870Sjamie int fi, jid, jsys, len, level; 491194762Sjamie int childmax, slevel, vfslocked; 492191673Sjamie#if defined(INET) || defined(INET6) 493192895Sjamie int ii, ij; 494191673Sjamie#endif 495191673Sjamie#ifdef INET 496195974Sjamie int ip4s, redo_ip4; 497191673Sjamie#endif 498191673Sjamie#ifdef INET6 499195974Sjamie int ip6s, redo_ip6; 500191673Sjamie#endif 501191673Sjamie unsigned pr_flags, ch_flags; 502192895Sjamie unsigned pr_allow, ch_allow, tallow; 503191673Sjamie char numbuf[12]; 504185435Sbz 505191673Sjamie error = priv_check(td, PRIV_JAIL_SET); 506191673Sjamie if (!error && (flags & JAIL_ATTACH)) 507191673Sjamie error = priv_check(td, PRIV_JAIL_ATTACH); 508191673Sjamie if (error) 509191673Sjamie return (error); 510192895Sjamie mypr = ppr = td->td_ucred->cr_prison; 511194762Sjamie if ((flags & JAIL_CREATE) && mypr->pr_childmax == 0) 512192895Sjamie return (EPERM); 513191673Sjamie if (flags & ~JAIL_SET_MASK) 514191673Sjamie return (EINVAL); 515191673Sjamie 516185435Sbz /* 517191673Sjamie * Check all the parameters before committing to anything. Not all 518191673Sjamie * errors can be caught early, but we may as well try. Also, this 519191673Sjamie * takes care of some expensive stuff (path lookup) before getting 520191673Sjamie * the allprison lock. 521185435Sbz * 522191673Sjamie * XXX Jails are not filesystems, and jail parameters are not mount 523191673Sjamie * options. But it makes more sense to re-use the vfsopt code 524191673Sjamie * than duplicate it under a different name. 525185435Sbz */ 526191673Sjamie error = vfs_buildopts(optuio, &opts); 527191673Sjamie if (error) 528191673Sjamie return (error); 529185435Sbz#ifdef INET 530185435Sbz ip4 = NULL; 531185435Sbz#endif 532185435Sbz#ifdef INET6 533185435Sbz ip6 = NULL; 534185435Sbz#endif 535191673Sjamie 536191673Sjamie error = vfs_copyopt(opts, "jid", &jid, sizeof(jid)); 537191673Sjamie if (error == ENOENT) 538191673Sjamie jid = 0; 539191673Sjamie else if (error != 0) 540191673Sjamie goto done_free; 541191673Sjamie 542191673Sjamie error = vfs_copyopt(opts, "securelevel", &slevel, sizeof(slevel)); 543191673Sjamie if (error == ENOENT) 544191673Sjamie gotslevel = 0; 545191673Sjamie else if (error != 0) 546191673Sjamie goto done_free; 547191673Sjamie else 548191673Sjamie gotslevel = 1; 549191673Sjamie 550194762Sjamie error = 551194762Sjamie vfs_copyopt(opts, "children.max", &childmax, sizeof(childmax)); 552194762Sjamie if (error == ENOENT) 553194762Sjamie gotchildmax = 0; 554194762Sjamie else if (error != 0) 555194762Sjamie goto done_free; 556194762Sjamie else 557194762Sjamie gotchildmax = 1; 558194762Sjamie 559192895Sjamie error = vfs_copyopt(opts, "enforce_statfs", &enforce, sizeof(enforce)); 560192895Sjamie gotenforce = (error == 0); 561192895Sjamie if (gotenforce) { 562192895Sjamie if (enforce < 0 || enforce > 2) 563192895Sjamie return (EINVAL); 564192895Sjamie } else if (error != ENOENT) 565192895Sjamie goto done_free; 566192895Sjamie 567191673Sjamie pr_flags = ch_flags = 0; 568192895Sjamie for (fi = 0; fi < sizeof(pr_flag_names) / sizeof(pr_flag_names[0]); 569192895Sjamie fi++) { 570192895Sjamie if (pr_flag_names[fi] == NULL) 571192895Sjamie continue; 572192895Sjamie vfs_flagopt(opts, pr_flag_names[fi], &pr_flags, 1 << fi); 573192895Sjamie vfs_flagopt(opts, pr_flag_nonames[fi], &ch_flags, 1 << fi); 574192895Sjamie } 575191673Sjamie ch_flags |= pr_flags; 576195870Sjamie for (fi = 0; fi < sizeof(pr_flag_jailsys) / sizeof(pr_flag_jailsys[0]); 577195870Sjamie fi++) { 578195870Sjamie error = vfs_copyopt(opts, pr_flag_jailsys[fi].name, &jsys, 579195870Sjamie sizeof(jsys)); 580195870Sjamie if (error == ENOENT) 581195870Sjamie continue; 582195870Sjamie if (error != 0) 583195870Sjamie goto done_free; 584195870Sjamie switch (jsys) { 585195870Sjamie case JAIL_SYS_DISABLE: 586195870Sjamie if (!pr_flag_jailsys[fi].disable) { 587195870Sjamie error = EINVAL; 588195870Sjamie goto done_free; 589195870Sjamie } 590195870Sjamie pr_flags |= pr_flag_jailsys[fi].disable; 591195870Sjamie break; 592195870Sjamie case JAIL_SYS_NEW: 593195870Sjamie pr_flags |= pr_flag_jailsys[fi].new; 594195870Sjamie break; 595195870Sjamie case JAIL_SYS_INHERIT: 596195870Sjamie break; 597195870Sjamie default: 598195870Sjamie error = EINVAL; 599195870Sjamie goto done_free; 600195870Sjamie } 601195870Sjamie ch_flags |= 602195870Sjamie pr_flag_jailsys[fi].new | pr_flag_jailsys[fi].disable; 603195870Sjamie } 604191673Sjamie if ((flags & (JAIL_CREATE | JAIL_UPDATE | JAIL_ATTACH)) == JAIL_CREATE 605191673Sjamie && !(pr_flags & PR_PERSIST)) { 606191673Sjamie error = EINVAL; 607191673Sjamie vfs_opterror(opts, "new jail must persist or attach"); 608191673Sjamie goto done_errmsg; 609191673Sjamie } 610194251Sjamie#ifdef VIMAGE 611194251Sjamie if ((flags & JAIL_UPDATE) && (ch_flags & PR_VNET)) { 612194251Sjamie error = EINVAL; 613194251Sjamie vfs_opterror(opts, "vnet cannot be changed after creation"); 614194251Sjamie goto done_errmsg; 615194251Sjamie } 616194251Sjamie#endif 617195974Sjamie#ifdef INET 618195974Sjamie if ((flags & JAIL_UPDATE) && (ch_flags & PR_IP4_USER)) { 619195974Sjamie error = EINVAL; 620195974Sjamie vfs_opterror(opts, "ip4 cannot be changed after creation"); 621195974Sjamie goto done_errmsg; 622195974Sjamie } 623195974Sjamie#endif 624195974Sjamie#ifdef INET6 625195974Sjamie if ((flags & JAIL_UPDATE) && (ch_flags & PR_IP6_USER)) { 626195974Sjamie error = EINVAL; 627195974Sjamie vfs_opterror(opts, "ip6 cannot be changed after creation"); 628195974Sjamie goto done_errmsg; 629195974Sjamie } 630195974Sjamie#endif 631191673Sjamie 632192895Sjamie pr_allow = ch_allow = 0; 633192895Sjamie for (fi = 0; fi < sizeof(pr_allow_names) / sizeof(pr_allow_names[0]); 634192895Sjamie fi++) { 635192895Sjamie vfs_flagopt(opts, pr_allow_names[fi], &pr_allow, 1 << fi); 636192895Sjamie vfs_flagopt(opts, pr_allow_nonames[fi], &ch_allow, 1 << fi); 637192895Sjamie } 638192895Sjamie ch_allow |= pr_allow; 639192895Sjamie 640191673Sjamie error = vfs_getopt(opts, "name", (void **)&name, &len); 641191673Sjamie if (error == ENOENT) 642191673Sjamie name = NULL; 643191673Sjamie else if (error != 0) 644191673Sjamie goto done_free; 645191673Sjamie else { 646191673Sjamie if (len == 0 || name[len - 1] != '\0') { 647191673Sjamie error = EINVAL; 648191673Sjamie goto done_free; 649191673Sjamie } 650191673Sjamie if (len > MAXHOSTNAMELEN) { 651191673Sjamie error = ENAMETOOLONG; 652191673Sjamie goto done_free; 653191673Sjamie } 654191673Sjamie } 655191673Sjamie 656191673Sjamie error = vfs_getopt(opts, "host.hostname", (void **)&host, &len); 657191673Sjamie if (error == ENOENT) 658191673Sjamie host = NULL; 659191673Sjamie else if (error != 0) 660191673Sjamie goto done_free; 661191673Sjamie else { 662193066Sjamie ch_flags |= PR_HOST; 663193066Sjamie pr_flags |= PR_HOST; 664191673Sjamie if (len == 0 || host[len - 1] != '\0') { 665191673Sjamie error = EINVAL; 666191673Sjamie goto done_free; 667191673Sjamie } 668191673Sjamie if (len > MAXHOSTNAMELEN) { 669191673Sjamie error = ENAMETOOLONG; 670191673Sjamie goto done_free; 671191673Sjamie } 672191673Sjamie } 673191673Sjamie 674193066Sjamie error = vfs_getopt(opts, "host.domainname", (void **)&domain, &len); 675193066Sjamie if (error == ENOENT) 676193066Sjamie domain = NULL; 677193066Sjamie else if (error != 0) 678193066Sjamie goto done_free; 679193066Sjamie else { 680193066Sjamie ch_flags |= PR_HOST; 681193066Sjamie pr_flags |= PR_HOST; 682193066Sjamie if (len == 0 || domain[len - 1] != '\0') { 683193066Sjamie error = EINVAL; 684193066Sjamie goto done_free; 685193066Sjamie } 686193066Sjamie if (len > MAXHOSTNAMELEN) { 687193066Sjamie error = ENAMETOOLONG; 688193066Sjamie goto done_free; 689193066Sjamie } 690193066Sjamie } 691193066Sjamie 692193066Sjamie error = vfs_getopt(opts, "host.hostuuid", (void **)&uuid, &len); 693193066Sjamie if (error == ENOENT) 694193066Sjamie uuid = NULL; 695193066Sjamie else if (error != 0) 696193066Sjamie goto done_free; 697193066Sjamie else { 698193066Sjamie ch_flags |= PR_HOST; 699193066Sjamie pr_flags |= PR_HOST; 700193066Sjamie if (len == 0 || uuid[len - 1] != '\0') { 701193066Sjamie error = EINVAL; 702193066Sjamie goto done_free; 703193066Sjamie } 704193066Sjamie if (len > HOSTUUIDLEN) { 705193066Sjamie error = ENAMETOOLONG; 706193066Sjamie goto done_free; 707193066Sjamie } 708193066Sjamie } 709193066Sjamie 710193066Sjamie#ifdef COMPAT_IA32 711193066Sjamie if (td->td_proc->p_sysent->sv_flags & SV_IA32) { 712193066Sjamie uint32_t hid32; 713193066Sjamie 714193066Sjamie error = vfs_copyopt(opts, "host.hostid", &hid32, sizeof(hid32)); 715193066Sjamie hid = hid32; 716193066Sjamie } else 717193066Sjamie#endif 718193066Sjamie error = vfs_copyopt(opts, "host.hostid", &hid, sizeof(hid)); 719193066Sjamie if (error == ENOENT) 720193066Sjamie gothid = 0; 721193066Sjamie else if (error != 0) 722193066Sjamie goto done_free; 723193066Sjamie else { 724193066Sjamie gothid = 1; 725193066Sjamie ch_flags |= PR_HOST; 726193066Sjamie pr_flags |= PR_HOST; 727193066Sjamie } 728193066Sjamie 729185435Sbz#ifdef INET 730191673Sjamie error = vfs_getopt(opts, "ip4.addr", &op, &ip4s); 731191673Sjamie if (error == ENOENT) 732195870Sjamie ip4s = (pr_flags & PR_IP4_DISABLE) ? 0 : -1; 733191673Sjamie else if (error != 0) 734191673Sjamie goto done_free; 735191673Sjamie else if (ip4s & (sizeof(*ip4) - 1)) { 736191673Sjamie error = EINVAL; 737191673Sjamie goto done_free; 738192895Sjamie } else { 739195870Sjamie ch_flags |= PR_IP4_USER | PR_IP4_DISABLE; 740195870Sjamie if (ip4s == 0) 741195870Sjamie pr_flags |= PR_IP4_USER | PR_IP4_DISABLE; 742195870Sjamie else { 743195870Sjamie pr_flags = (pr_flags & ~PR_IP4_DISABLE) | PR_IP4_USER; 744192895Sjamie ip4s /= sizeof(*ip4); 745192895Sjamie if (ip4s > jail_max_af_ips) { 746185435Sbz error = EINVAL; 747192895Sjamie vfs_opterror(opts, "too many IPv4 addresses"); 748192895Sjamie goto done_errmsg; 749185435Sbz } 750195974Sjamie ip4 = malloc(ip4s * sizeof(*ip4), M_PRISON, M_WAITOK); 751192895Sjamie bcopy(op, ip4, ip4s * sizeof(*ip4)); 752192895Sjamie /* 753192895Sjamie * IP addresses are all sorted but ip[0] to preserve 754192895Sjamie * the primary IP address as given from userland. 755192895Sjamie * This special IP is used for unbound outgoing 756192895Sjamie * connections as well for "loopback" traffic. 757192895Sjamie */ 758192895Sjamie if (ip4s > 1) 759192895Sjamie qsort(ip4 + 1, ip4s - 1, sizeof(*ip4), qcmp_v4); 760192895Sjamie /* 761192895Sjamie * Check for duplicate addresses and do some simple 762192895Sjamie * zero and broadcast checks. If users give other bogus 763192895Sjamie * addresses it is their problem. 764192895Sjamie * 765192895Sjamie * We do not have to care about byte order for these 766192895Sjamie * checks so we will do them in NBO. 767192895Sjamie */ 768192895Sjamie for (ii = 0; ii < ip4s; ii++) { 769192895Sjamie if (ip4[ii].s_addr == INADDR_ANY || 770192895Sjamie ip4[ii].s_addr == INADDR_BROADCAST) { 771192895Sjamie error = EINVAL; 772192895Sjamie goto done_free; 773192895Sjamie } 774192895Sjamie if ((ii+1) < ip4s && 775192895Sjamie (ip4[0].s_addr == ip4[ii+1].s_addr || 776192895Sjamie ip4[ii].s_addr == ip4[ii+1].s_addr)) { 777192895Sjamie error = EINVAL; 778192895Sjamie goto done_free; 779192895Sjamie } 780192895Sjamie } 781185435Sbz } 782191673Sjamie } 783191673Sjamie#endif 784185435Sbz 785185435Sbz#ifdef INET6 786191673Sjamie error = vfs_getopt(opts, "ip6.addr", &op, &ip6s); 787191673Sjamie if (error == ENOENT) 788195870Sjamie ip6s = (pr_flags & PR_IP6_DISABLE) ? 0 : -1; 789191673Sjamie else if (error != 0) 790191673Sjamie goto done_free; 791191673Sjamie else if (ip6s & (sizeof(*ip6) - 1)) { 792191673Sjamie error = EINVAL; 793191673Sjamie goto done_free; 794192895Sjamie } else { 795195870Sjamie ch_flags |= PR_IP6_USER | PR_IP6_DISABLE; 796195870Sjamie if (ip6s == 0) 797195870Sjamie pr_flags |= PR_IP6_USER | PR_IP6_DISABLE; 798195870Sjamie else { 799195870Sjamie pr_flags = (pr_flags & ~PR_IP6_DISABLE) | PR_IP6_USER; 800192895Sjamie ip6s /= sizeof(*ip6); 801192895Sjamie if (ip6s > jail_max_af_ips) { 802185435Sbz error = EINVAL; 803192895Sjamie vfs_opterror(opts, "too many IPv6 addresses"); 804192895Sjamie goto done_errmsg; 805185435Sbz } 806195974Sjamie ip6 = malloc(ip6s * sizeof(*ip6), M_PRISON, M_WAITOK); 807192895Sjamie bcopy(op, ip6, ip6s * sizeof(*ip6)); 808192895Sjamie if (ip6s > 1) 809192895Sjamie qsort(ip6 + 1, ip6s - 1, sizeof(*ip6), qcmp_v6); 810192895Sjamie for (ii = 0; ii < ip6s; ii++) { 811192895Sjamie if (IN6_IS_ADDR_UNSPECIFIED(&ip6[ii])) { 812192895Sjamie error = EINVAL; 813192895Sjamie goto done_free; 814192895Sjamie } 815192895Sjamie if ((ii+1) < ip6s && 816192895Sjamie (IN6_ARE_ADDR_EQUAL(&ip6[0], &ip6[ii+1]) || 817192895Sjamie IN6_ARE_ADDR_EQUAL(&ip6[ii], &ip6[ii+1]))) 818192895Sjamie { 819192895Sjamie error = EINVAL; 820192895Sjamie goto done_free; 821192895Sjamie } 822192895Sjamie } 823185435Sbz } 824191673Sjamie } 825185435Sbz#endif 826185435Sbz 827195945Sjamie#if defined(VIMAGE) && (defined(INET) || defined(INET6)) 828195945Sjamie if ((ch_flags & PR_VNET) && (ch_flags & (PR_IP4_USER | PR_IP6_USER))) { 829195945Sjamie error = EINVAL; 830195945Sjamie vfs_opterror(opts, 831195945Sjamie "vnet jails cannot have IP address restrictions"); 832195945Sjamie goto done_errmsg; 833195945Sjamie } 834195945Sjamie#endif 835195945Sjamie 836191673Sjamie root = NULL; 837191673Sjamie error = vfs_getopt(opts, "path", (void **)&path, &len); 838191673Sjamie if (error == ENOENT) 839191673Sjamie path = NULL; 840191673Sjamie else if (error != 0) 841191673Sjamie goto done_free; 842191673Sjamie else { 843191673Sjamie if (flags & JAIL_UPDATE) { 844191673Sjamie error = EINVAL; 845191673Sjamie vfs_opterror(opts, 846191673Sjamie "path cannot be changed after creation"); 847191673Sjamie goto done_errmsg; 848191673Sjamie } 849191673Sjamie if (len == 0 || path[len - 1] != '\0') { 850191673Sjamie error = EINVAL; 851191673Sjamie goto done_free; 852191673Sjamie } 853191673Sjamie if (len < 2 || (len == 2 && path[0] == '/')) 854191673Sjamie path = NULL; 855191673Sjamie else { 856192895Sjamie /* Leave room for a real-root full pathname. */ 857192895Sjamie if (len + (path[0] == '/' && strcmp(mypr->pr_path, "/") 858192895Sjamie ? strlen(mypr->pr_path) : 0) > MAXPATHLEN) { 859192895Sjamie error = ENAMETOOLONG; 860192895Sjamie goto done_free; 861192895Sjamie } 862191673Sjamie NDINIT(&nd, LOOKUP, MPSAFE | FOLLOW, UIO_SYSSPACE, 863191673Sjamie path, td); 864191673Sjamie error = namei(&nd); 865191673Sjamie if (error) 866191673Sjamie goto done_free; 867191673Sjamie vfslocked = NDHASGIANT(&nd); 868191673Sjamie root = nd.ni_vp; 869191673Sjamie NDFREE(&nd, NDF_ONLY_PNBUF); 870191673Sjamie if (root->v_type != VDIR) { 871191673Sjamie error = ENOTDIR; 872191673Sjamie vrele(root); 873191673Sjamie VFS_UNLOCK_GIANT(vfslocked); 874191673Sjamie goto done_free; 875191673Sjamie } 876191673Sjamie VFS_UNLOCK_GIANT(vfslocked); 877191673Sjamie } 878191673Sjamie } 879185435Sbz 880191673Sjamie /* 881191673Sjamie * Grab the allprison lock before letting modules check their 882191673Sjamie * parameters. Once we have it, do not let go so we'll have a 883191673Sjamie * consistent view of the OSD list. 884191673Sjamie */ 885191673Sjamie sx_xlock(&allprison_lock); 886191673Sjamie error = osd_jail_call(NULL, PR_METHOD_CHECK, opts); 887191673Sjamie if (error) 888191673Sjamie goto done_unlock_list; 889185435Sbz 890191673Sjamie /* By now, all parameters should have been noted. */ 891191673Sjamie TAILQ_FOREACH(opt, opts, link) { 892191673Sjamie if (!opt->seen && strcmp(opt->name, "errmsg")) { 893191673Sjamie error = EINVAL; 894191673Sjamie vfs_opterror(opts, "unknown parameter: %s", opt->name); 895191673Sjamie goto done_unlock_list; 896191673Sjamie } 897191673Sjamie } 898191673Sjamie 899185435Sbz /* 900191673Sjamie * See if we are creating a new record or updating an existing one. 901191673Sjamie * This abuses the file error codes ENOENT and EEXIST. 902185435Sbz */ 903191673Sjamie cuflags = flags & (JAIL_CREATE | JAIL_UPDATE); 904191673Sjamie if (!cuflags) { 905191673Sjamie error = EINVAL; 906191673Sjamie vfs_opterror(opts, "no valid operation (create or update)"); 907191673Sjamie goto done_unlock_list; 908191673Sjamie } 909191673Sjamie pr = NULL; 910191673Sjamie if (jid != 0) { 911192895Sjamie /* 912192895Sjamie * See if a requested jid already exists. There is an 913192895Sjamie * information leak here if the jid exists but is not within 914192895Sjamie * the caller's jail hierarchy. Jail creators will get EEXIST 915192895Sjamie * even though they cannot see the jail, and CREATE | UPDATE 916192895Sjamie * will return ENOENT which is not normally a valid error. 917192895Sjamie */ 918191673Sjamie if (jid < 0) { 919191673Sjamie error = EINVAL; 920191673Sjamie vfs_opterror(opts, "negative jid"); 921191673Sjamie goto done_unlock_list; 922191673Sjamie } 923191673Sjamie pr = prison_find(jid); 924191673Sjamie if (pr != NULL) { 925192895Sjamie ppr = pr->pr_parent; 926191673Sjamie /* Create: jid must not exist. */ 927191673Sjamie if (cuflags == JAIL_CREATE) { 928191673Sjamie mtx_unlock(&pr->pr_mtx); 929191673Sjamie error = EEXIST; 930191673Sjamie vfs_opterror(opts, "jail %d already exists", 931191673Sjamie jid); 932191673Sjamie goto done_unlock_list; 933191673Sjamie } 934192895Sjamie if (!prison_ischild(mypr, pr)) { 935192895Sjamie mtx_unlock(&pr->pr_mtx); 936192895Sjamie pr = NULL; 937192895Sjamie } else if (pr->pr_uref == 0) { 938191673Sjamie if (!(flags & JAIL_DYING)) { 939191673Sjamie mtx_unlock(&pr->pr_mtx); 940191673Sjamie error = ENOENT; 941191673Sjamie vfs_opterror(opts, "jail %d is dying", 942191673Sjamie jid); 943191673Sjamie goto done_unlock_list; 944191673Sjamie } else if ((flags & JAIL_ATTACH) || 945191673Sjamie (pr_flags & PR_PERSIST)) { 946191673Sjamie /* 947191673Sjamie * A dying jail might be resurrected 948191673Sjamie * (via attach or persist), but first 949191673Sjamie * it must determine if another jail 950191673Sjamie * has claimed its name. Accomplish 951191673Sjamie * this by implicitly re-setting the 952191673Sjamie * name. 953191673Sjamie */ 954191673Sjamie if (name == NULL) 955192895Sjamie name = prison_name(mypr, pr); 956191673Sjamie } 957191673Sjamie } 958191673Sjamie } 959191673Sjamie if (pr == NULL) { 960191673Sjamie /* Update: jid must exist. */ 961191673Sjamie if (cuflags == JAIL_UPDATE) { 962191673Sjamie error = ENOENT; 963191673Sjamie vfs_opterror(opts, "jail %d not found", jid); 964191673Sjamie goto done_unlock_list; 965191673Sjamie } 966191673Sjamie } 967191673Sjamie } 968191673Sjamie /* 969191673Sjamie * If the caller provided a name, look for a jail by that name. 970191673Sjamie * This has different semantics for creates and updates keyed by jid 971191673Sjamie * (where the name must not already exist in a different jail), 972191673Sjamie * and updates keyed by the name itself (where the name must exist 973191673Sjamie * because that is the jail being updated). 974191673Sjamie */ 975191673Sjamie if (name != NULL) { 976192895Sjamie p = strrchr(name, '.'); 977192895Sjamie if (p != NULL) { 978192895Sjamie /* 979192895Sjamie * This is a hierarchical name. Split it into the 980192895Sjamie * parent and child names, and make sure the parent 981192895Sjamie * exists or matches an already found jail. 982192895Sjamie */ 983192895Sjamie *p = '\0'; 984192895Sjamie if (pr != NULL) { 985192895Sjamie if (strncmp(name, ppr->pr_name, p - name) || 986192895Sjamie ppr->pr_name[p - name] != '\0') { 987192895Sjamie mtx_unlock(&pr->pr_mtx); 988192895Sjamie error = EINVAL; 989192895Sjamie vfs_opterror(opts, 990192895Sjamie "cannot change jail's parent"); 991192895Sjamie goto done_unlock_list; 992192895Sjamie } 993192895Sjamie } else { 994192895Sjamie ppr = prison_find_name(mypr, name); 995192895Sjamie if (ppr == NULL) { 996192895Sjamie error = ENOENT; 997192895Sjamie vfs_opterror(opts, 998192895Sjamie "jail \"%s\" not found", name); 999192895Sjamie goto done_unlock_list; 1000192895Sjamie } 1001192895Sjamie mtx_unlock(&ppr->pr_mtx); 1002192895Sjamie } 1003192895Sjamie name = p + 1; 1004192895Sjamie } 1005191673Sjamie if (name[0] != '\0') { 1006192895Sjamie namelen = 1007192895Sjamie (ppr == &prison0) ? 0 : strlen(ppr->pr_name) + 1; 1008192895Sjamie name_again: 1009191673Sjamie deadpr = NULL; 1010192895Sjamie FOREACH_PRISON_CHILD(ppr, tpr) { 1011191673Sjamie if (tpr != pr && tpr->pr_ref > 0 && 1012192895Sjamie !strcmp(tpr->pr_name + namelen, name)) { 1013191673Sjamie if (pr == NULL && 1014191673Sjamie cuflags != JAIL_CREATE) { 1015191673Sjamie mtx_lock(&tpr->pr_mtx); 1016191673Sjamie if (tpr->pr_ref > 0) { 1017191673Sjamie /* 1018191673Sjamie * Use this jail 1019191673Sjamie * for updates. 1020191673Sjamie */ 1021191673Sjamie if (tpr->pr_uref > 0) { 1022191673Sjamie pr = tpr; 1023191673Sjamie break; 1024191673Sjamie } 1025191673Sjamie deadpr = tpr; 1026191673Sjamie } 1027191673Sjamie mtx_unlock(&tpr->pr_mtx); 1028191673Sjamie } else if (tpr->pr_uref > 0) { 1029191673Sjamie /* 1030191673Sjamie * Create, or update(jid): 1031191673Sjamie * name must not exist in an 1032192895Sjamie * active sibling jail. 1033191673Sjamie */ 1034191673Sjamie error = EEXIST; 1035191673Sjamie if (pr != NULL) 1036191673Sjamie mtx_unlock(&pr->pr_mtx); 1037191673Sjamie vfs_opterror(opts, 1038191673Sjamie "jail \"%s\" already exists", 1039191673Sjamie name); 1040191673Sjamie goto done_unlock_list; 1041191673Sjamie } 1042191673Sjamie } 1043191673Sjamie } 1044191673Sjamie /* If no active jail is found, use a dying one. */ 1045191673Sjamie if (deadpr != NULL && pr == NULL) { 1046191673Sjamie if (flags & JAIL_DYING) { 1047191673Sjamie mtx_lock(&deadpr->pr_mtx); 1048191673Sjamie if (deadpr->pr_ref == 0) { 1049191673Sjamie mtx_unlock(&deadpr->pr_mtx); 1050191673Sjamie goto name_again; 1051191673Sjamie } 1052191673Sjamie pr = deadpr; 1053191673Sjamie } else if (cuflags == JAIL_UPDATE) { 1054191673Sjamie error = ENOENT; 1055191673Sjamie vfs_opterror(opts, 1056191673Sjamie "jail \"%s\" is dying", name); 1057191673Sjamie goto done_unlock_list; 1058191673Sjamie } 1059191673Sjamie } 1060191673Sjamie /* Update: name must exist if no jid. */ 1061191673Sjamie else if (cuflags == JAIL_UPDATE && pr == NULL) { 1062191673Sjamie error = ENOENT; 1063191673Sjamie vfs_opterror(opts, "jail \"%s\" not found", 1064191673Sjamie name); 1065191673Sjamie goto done_unlock_list; 1066191673Sjamie } 1067191673Sjamie } 1068191673Sjamie } 1069191673Sjamie /* Update: must provide a jid or name. */ 1070191673Sjamie else if (cuflags == JAIL_UPDATE && pr == NULL) { 1071191673Sjamie error = ENOENT; 1072191673Sjamie vfs_opterror(opts, "update specified no jail"); 1073191673Sjamie goto done_unlock_list; 1074191673Sjamie } 1075185435Sbz 1076191673Sjamie /* If there's no prison to update, create a new one and link it in. */ 1077191673Sjamie if (pr == NULL) { 1078194762Sjamie for (tpr = mypr; tpr != NULL; tpr = tpr->pr_parent) 1079194762Sjamie if (tpr->pr_childcount >= tpr->pr_childmax) { 1080194762Sjamie error = EPERM; 1081194762Sjamie vfs_opterror(opts, "prison limit exceeded"); 1082194762Sjamie goto done_unlock_list; 1083194762Sjamie } 1084191673Sjamie created = 1; 1085192895Sjamie mtx_lock(&ppr->pr_mtx); 1086192895Sjamie if (ppr->pr_ref == 0 || (ppr->pr_flags & PR_REMOVE)) { 1087192895Sjamie mtx_unlock(&ppr->pr_mtx); 1088192895Sjamie error = ENOENT; 1089192895Sjamie vfs_opterror(opts, "parent jail went away!"); 1090192895Sjamie goto done_unlock_list; 1091192895Sjamie } 1092192895Sjamie ppr->pr_ref++; 1093192895Sjamie ppr->pr_uref++; 1094192895Sjamie mtx_unlock(&ppr->pr_mtx); 1095191673Sjamie pr = malloc(sizeof(*pr), M_PRISON, M_WAITOK | M_ZERO); 1096191673Sjamie if (jid == 0) { 1097191673Sjamie /* Find the next free jid. */ 1098191673Sjamie jid = lastprid + 1; 1099191673Sjamie findnext: 1100191673Sjamie if (jid == JAIL_MAX) 1101191673Sjamie jid = 1; 1102191673Sjamie TAILQ_FOREACH(tpr, &allprison, pr_list) { 1103191673Sjamie if (tpr->pr_id < jid) 1104191673Sjamie continue; 1105191673Sjamie if (tpr->pr_id > jid || tpr->pr_ref == 0) { 1106191673Sjamie TAILQ_INSERT_BEFORE(tpr, pr, pr_list); 1107191673Sjamie break; 1108191673Sjamie } 1109191673Sjamie if (jid == lastprid) { 1110191673Sjamie error = EAGAIN; 1111191673Sjamie vfs_opterror(opts, 1112191673Sjamie "no available jail IDs"); 1113191673Sjamie free(pr, M_PRISON); 1114192895Sjamie prison_deref(ppr, PD_DEREF | 1115192895Sjamie PD_DEUREF | PD_LIST_XLOCKED); 1116192895Sjamie goto done_releroot; 1117191673Sjamie } 1118191673Sjamie jid++; 1119191673Sjamie goto findnext; 1120191673Sjamie } 1121191673Sjamie lastprid = jid; 1122191673Sjamie } else { 1123191673Sjamie /* 1124191673Sjamie * The jail already has a jid (that did not yet exist), 1125191673Sjamie * so just find where to insert it. 1126191673Sjamie */ 1127191673Sjamie TAILQ_FOREACH(tpr, &allprison, pr_list) 1128191673Sjamie if (tpr->pr_id >= jid) { 1129191673Sjamie TAILQ_INSERT_BEFORE(tpr, pr, pr_list); 1130191673Sjamie break; 1131191673Sjamie } 1132191673Sjamie } 1133191673Sjamie if (tpr == NULL) 1134191673Sjamie TAILQ_INSERT_TAIL(&allprison, pr, pr_list); 1135192895Sjamie LIST_INSERT_HEAD(&ppr->pr_children, pr, pr_sibling); 1136192895Sjamie for (tpr = ppr; tpr != NULL; tpr = tpr->pr_parent) 1137194762Sjamie tpr->pr_childcount++; 1138185435Sbz 1139192895Sjamie pr->pr_parent = ppr; 1140191673Sjamie pr->pr_id = jid; 1141192895Sjamie 1142192895Sjamie /* Set some default values, and inherit some from the parent. */ 1143191673Sjamie if (name == NULL) 1144191673Sjamie name = ""; 1145191673Sjamie if (path == NULL) { 1146191673Sjamie path = "/"; 1147192895Sjamie root = mypr->pr_root; 1148191673Sjamie vref(root); 1149191673Sjamie } 1150195944Sjamie strlcpy(pr->pr_hostuuid, DEFAULT_HOSTUUID, HOSTUUIDLEN); 1151195944Sjamie pr->pr_flags |= PR_HOST; 1152195945Sjamie#if defined(INET) || defined(INET6) 1153195945Sjamie#ifdef VIMAGE 1154195945Sjamie if (!(pr_flags & PR_VNET)) 1155195945Sjamie#endif 1156195945Sjamie { 1157192895Sjamie#ifdef INET 1158195974Sjamie if (!(ch_flags & PR_IP4_USER)) 1159195974Sjamie pr->pr_flags |= 1160195974Sjamie PR_IP4 | PR_IP4_USER | PR_IP4_DISABLE; 1161195974Sjamie else if (!(pr_flags & PR_IP4_USER)) { 1162195974Sjamie pr->pr_flags |= ppr->pr_flags & PR_IP4; 1163195974Sjamie if (ppr->pr_ip4 != NULL) { 1164195974Sjamie pr->pr_ip4s = ppr->pr_ip4s; 1165195974Sjamie pr->pr_ip4 = malloc(pr->pr_ip4s * 1166195974Sjamie sizeof(struct in_addr), M_PRISON, 1167195974Sjamie M_WAITOK); 1168195974Sjamie bcopy(ppr->pr_ip4, pr->pr_ip4, 1169195974Sjamie pr->pr_ip4s * sizeof(*pr->pr_ip4)); 1170195974Sjamie } 1171195974Sjamie } 1172192895Sjamie#endif 1173192895Sjamie#ifdef INET6 1174195974Sjamie if (!(ch_flags & PR_IP6_USER)) 1175195974Sjamie pr->pr_flags |= 1176195974Sjamie PR_IP6 | PR_IP6_USER | PR_IP6_DISABLE; 1177195974Sjamie else if (!(pr_flags & PR_IP6_USER)) { 1178195974Sjamie pr->pr_flags |= ppr->pr_flags & PR_IP6; 1179195974Sjamie if (ppr->pr_ip6 != NULL) { 1180195974Sjamie pr->pr_ip6s = ppr->pr_ip6s; 1181195974Sjamie pr->pr_ip6 = malloc(pr->pr_ip6s * 1182195974Sjamie sizeof(struct in6_addr), M_PRISON, 1183195974Sjamie M_WAITOK); 1184195974Sjamie bcopy(ppr->pr_ip6, pr->pr_ip6, 1185195974Sjamie pr->pr_ip6s * sizeof(*pr->pr_ip6)); 1186195974Sjamie } 1187195974Sjamie } 1188192895Sjamie#endif 1189195945Sjamie } 1190195945Sjamie#endif 1191192895Sjamie pr->pr_securelevel = ppr->pr_securelevel; 1192192895Sjamie pr->pr_allow = JAIL_DEFAULT_ALLOW & ppr->pr_allow; 1193196002Sjamie pr->pr_enforce_statfs = JAIL_DEFAULT_ENFORCE_STATFS; 1194191673Sjamie 1195192895Sjamie LIST_INIT(&pr->pr_children); 1196192895Sjamie mtx_init(&pr->pr_mtx, "jail mutex", NULL, MTX_DEF | MTX_DUPOK); 1197191673Sjamie 1198194251Sjamie#ifdef VIMAGE 1199194251Sjamie /* Allocate a new vnet if specified. */ 1200194251Sjamie pr->pr_vnet = (pr_flags & PR_VNET) 1201194251Sjamie ? vnet_alloc() : ppr->pr_vnet; 1202194251Sjamie#endif 1203185435Sbz /* 1204191673Sjamie * Allocate a dedicated cpuset for each jail. 1205191673Sjamie * Unlike other initial settings, this may return an erorr. 1206185435Sbz */ 1207192895Sjamie error = cpuset_create_root(ppr, &pr->pr_cpuset); 1208191673Sjamie if (error) { 1209191673Sjamie prison_deref(pr, PD_LIST_XLOCKED); 1210191673Sjamie goto done_releroot; 1211191673Sjamie } 1212185435Sbz 1213191673Sjamie mtx_lock(&pr->pr_mtx); 1214185435Sbz /* 1215191673Sjamie * New prisons do not yet have a reference, because we do not 1216191673Sjamie * want other to see the incomplete prison once the 1217191673Sjamie * allprison_lock is downgraded. 1218185435Sbz */ 1219191673Sjamie } else { 1220191673Sjamie created = 0; 1221195974Sjamie /* 1222195974Sjamie * Grab a reference for existing prisons, to ensure they 1223195974Sjamie * continue to exist for the duration of the call. 1224195974Sjamie */ 1225195974Sjamie pr->pr_ref++; 1226195945Sjamie#if defined(VIMAGE) && (defined(INET) || defined(INET6)) 1227195945Sjamie if ((pr->pr_flags & PR_VNET) && 1228195945Sjamie (ch_flags & (PR_IP4_USER | PR_IP6_USER))) { 1229195945Sjamie error = EINVAL; 1230195945Sjamie vfs_opterror(opts, 1231195945Sjamie "vnet jails cannot have IP address restrictions"); 1232195945Sjamie goto done_deref_locked; 1233195945Sjamie } 1234195945Sjamie#endif 1235195974Sjamie#ifdef INET 1236195974Sjamie if (PR_IP4_USER & ch_flags & (pr_flags ^ pr->pr_flags)) { 1237195974Sjamie error = EINVAL; 1238195974Sjamie vfs_opterror(opts, 1239195974Sjamie "ip4 cannot be changed after creation"); 1240195974Sjamie goto done_deref_locked; 1241195974Sjamie } 1242195974Sjamie#endif 1243195974Sjamie#ifdef INET6 1244195974Sjamie if (PR_IP6_USER & ch_flags & (pr_flags ^ pr->pr_flags)) { 1245195974Sjamie error = EINVAL; 1246195974Sjamie vfs_opterror(opts, 1247195974Sjamie "ip6 cannot be changed after creation"); 1248195974Sjamie goto done_deref_locked; 1249195974Sjamie } 1250195974Sjamie#endif 1251191673Sjamie } 1252185435Sbz 1253191673Sjamie /* Do final error checking before setting anything. */ 1254192895Sjamie if (gotslevel) { 1255192895Sjamie if (slevel < ppr->pr_securelevel) { 1256192895Sjamie error = EPERM; 1257192895Sjamie goto done_deref_locked; 1258192895Sjamie } 1259192895Sjamie } 1260194762Sjamie if (gotchildmax) { 1261194762Sjamie if (childmax >= ppr->pr_childmax) { 1262194762Sjamie error = EPERM; 1263194762Sjamie goto done_deref_locked; 1264194762Sjamie } 1265194762Sjamie } 1266192895Sjamie if (gotenforce) { 1267192895Sjamie if (enforce < ppr->pr_enforce_statfs) { 1268192895Sjamie error = EPERM; 1269192895Sjamie goto done_deref_locked; 1270192895Sjamie } 1271192895Sjamie } 1272185435Sbz#ifdef INET 1273195974Sjamie if (ip4s > 0) { 1274192895Sjamie if (ppr->pr_flags & PR_IP4) { 1275195974Sjamie /* 1276195974Sjamie * Make sure the new set of IP addresses is a 1277195974Sjamie * subset of the parent's list. Don't worry 1278195974Sjamie * about the parent being unlocked, as any 1279195974Sjamie * setting is done with allprison_lock held. 1280195974Sjamie */ 1281195974Sjamie for (ij = 0; ij < ppr->pr_ip4s; ij++) 1282195974Sjamie if (ip4[0].s_addr == ppr->pr_ip4[ij].s_addr) 1283195974Sjamie break; 1284195974Sjamie if (ij == ppr->pr_ip4s) { 1285195974Sjamie error = EPERM; 1286195974Sjamie goto done_deref_locked; 1287195974Sjamie } 1288195974Sjamie if (ip4s > 1) { 1289195974Sjamie for (ii = ij = 1; ii < ip4s; ii++) { 1290195974Sjamie if (ip4[ii].s_addr == 1291195974Sjamie ppr->pr_ip4[0].s_addr) 1292195974Sjamie continue; 1293195974Sjamie for (; ij < ppr->pr_ip4s; ij++) 1294195974Sjamie if (ip4[ii].s_addr == 1295195974Sjamie ppr->pr_ip4[ij].s_addr) 1296195974Sjamie break; 1297195974Sjamie if (ij == ppr->pr_ip4s) 1298195974Sjamie break; 1299192895Sjamie } 1300192895Sjamie if (ij == ppr->pr_ip4s) { 1301192895Sjamie error = EPERM; 1302192895Sjamie goto done_deref_locked; 1303192895Sjamie } 1304192895Sjamie } 1305192895Sjamie } 1306195974Sjamie /* 1307195974Sjamie * Check for conflicting IP addresses. We permit them 1308195974Sjamie * if there is no more than one IP on each jail. If 1309195974Sjamie * there is a duplicate on a jail with more than one 1310195974Sjamie * IP stop checking and return error. 1311195974Sjamie */ 1312195974Sjamie tppr = ppr; 1313195945Sjamie#ifdef VIMAGE 1314195974Sjamie for (; tppr != &prison0; tppr = tppr->pr_parent) 1315195974Sjamie if (tppr->pr_flags & PR_VNET) 1316195974Sjamie break; 1317195945Sjamie#endif 1318195974Sjamie FOREACH_PRISON_DESCENDANT(tppr, tpr, descend) { 1319195974Sjamie if (tpr == pr || 1320195945Sjamie#ifdef VIMAGE 1321195974Sjamie (tpr != tppr && (tpr->pr_flags & PR_VNET)) || 1322195945Sjamie#endif 1323195974Sjamie tpr->pr_uref == 0) { 1324192895Sjamie descend = 0; 1325195974Sjamie continue; 1326195974Sjamie } 1327195974Sjamie if (!(tpr->pr_flags & PR_IP4_USER)) 1328195974Sjamie continue; 1329195974Sjamie descend = 0; 1330195974Sjamie if (tpr->pr_ip4 == NULL || 1331195974Sjamie (ip4s == 1 && tpr->pr_ip4s == 1)) 1332195974Sjamie continue; 1333195974Sjamie for (ii = 0; ii < ip4s; ii++) { 1334195974Sjamie if (_prison_check_ip4(tpr, &ip4[ii]) == 0) { 1335195974Sjamie error = EADDRINUSE; 1336195974Sjamie vfs_opterror(opts, 1337195974Sjamie "IPv4 addresses clash"); 1338195974Sjamie goto done_deref_locked; 1339192895Sjamie } 1340192895Sjamie } 1341192895Sjamie } 1342192895Sjamie } 1343185435Sbz#endif 1344191673Sjamie#ifdef INET6 1345195974Sjamie if (ip6s > 0) { 1346192895Sjamie if (ppr->pr_flags & PR_IP6) { 1347195974Sjamie /* 1348195974Sjamie * Make sure the new set of IP addresses is a 1349195974Sjamie * subset of the parent's list. 1350195974Sjamie */ 1351195974Sjamie for (ij = 0; ij < ppr->pr_ip6s; ij++) 1352195974Sjamie if (IN6_ARE_ADDR_EQUAL(&ip6[0], 1353195974Sjamie &ppr->pr_ip6[ij])) 1354195974Sjamie break; 1355195974Sjamie if (ij == ppr->pr_ip6s) { 1356195974Sjamie error = EPERM; 1357195974Sjamie goto done_deref_locked; 1358195974Sjamie } 1359195974Sjamie if (ip6s > 1) { 1360195974Sjamie for (ii = ij = 1; ii < ip6s; ii++) { 1361195974Sjamie if (IN6_ARE_ADDR_EQUAL(&ip6[ii], 1362195974Sjamie &ppr->pr_ip6[0])) 1363195974Sjamie continue; 1364195974Sjamie for (; ij < ppr->pr_ip6s; ij++) 1365195974Sjamie if (IN6_ARE_ADDR_EQUAL( 1366195974Sjamie &ip6[ii], &ppr->pr_ip6[ij])) 1367195974Sjamie break; 1368195974Sjamie if (ij == ppr->pr_ip6s) 1369195974Sjamie break; 1370192895Sjamie } 1371192895Sjamie if (ij == ppr->pr_ip6s) { 1372192895Sjamie error = EPERM; 1373192895Sjamie goto done_deref_locked; 1374192895Sjamie } 1375192895Sjamie } 1376192895Sjamie } 1377195974Sjamie /* Check for conflicting IP addresses. */ 1378195974Sjamie tppr = ppr; 1379195945Sjamie#ifdef VIMAGE 1380195974Sjamie for (; tppr != &prison0; tppr = tppr->pr_parent) 1381195974Sjamie if (tppr->pr_flags & PR_VNET) 1382195974Sjamie break; 1383195945Sjamie#endif 1384195974Sjamie FOREACH_PRISON_DESCENDANT(tppr, tpr, descend) { 1385195974Sjamie if (tpr == pr || 1386195945Sjamie#ifdef VIMAGE 1387195974Sjamie (tpr != tppr && (tpr->pr_flags & PR_VNET)) || 1388195945Sjamie#endif 1389195974Sjamie tpr->pr_uref == 0) { 1390192895Sjamie descend = 0; 1391195974Sjamie continue; 1392195974Sjamie } 1393195974Sjamie if (!(tpr->pr_flags & PR_IP6_USER)) 1394195974Sjamie continue; 1395195974Sjamie descend = 0; 1396195974Sjamie if (tpr->pr_ip6 == NULL || 1397195974Sjamie (ip6s == 1 && tpr->pr_ip6s == 1)) 1398195974Sjamie continue; 1399195974Sjamie for (ii = 0; ii < ip6s; ii++) { 1400195974Sjamie if (_prison_check_ip6(tpr, &ip6[ii]) == 0) { 1401195974Sjamie error = EADDRINUSE; 1402195974Sjamie vfs_opterror(opts, 1403195974Sjamie "IPv6 addresses clash"); 1404195974Sjamie goto done_deref_locked; 1405192895Sjamie } 1406192895Sjamie } 1407191673Sjamie } 1408192895Sjamie } 1409191673Sjamie#endif 1410192895Sjamie onamelen = namelen = 0; 1411192895Sjamie if (name != NULL) { 1412191673Sjamie /* Give a default name of the jid. */ 1413191673Sjamie if (name[0] == '\0') 1414191673Sjamie snprintf(name = numbuf, sizeof(numbuf), "%d", jid); 1415191673Sjamie else if (strtoul(name, &p, 10) != jid && *p == '\0') { 1416191673Sjamie error = EINVAL; 1417191673Sjamie vfs_opterror(opts, "name cannot be numeric"); 1418192895Sjamie goto done_deref_locked; 1419191673Sjamie } 1420191673Sjamie /* 1421192895Sjamie * Make sure the name isn't too long for the prison or its 1422192895Sjamie * children. 1423191673Sjamie */ 1424192895Sjamie onamelen = strlen(pr->pr_name); 1425192895Sjamie namelen = strlen(name); 1426192895Sjamie if (strlen(ppr->pr_name) + namelen + 2 > sizeof(pr->pr_name)) { 1427192895Sjamie error = ENAMETOOLONG; 1428192895Sjamie goto done_deref_locked; 1429192895Sjamie } 1430192895Sjamie FOREACH_PRISON_DESCENDANT(pr, tpr, descend) { 1431192895Sjamie if (strlen(tpr->pr_name) + (namelen - onamelen) >= 1432192895Sjamie sizeof(pr->pr_name)) { 1433192895Sjamie error = ENAMETOOLONG; 1434192895Sjamie goto done_deref_locked; 1435192895Sjamie } 1436192895Sjamie } 1437191673Sjamie } 1438192895Sjamie if (pr_allow & ~ppr->pr_allow) { 1439192895Sjamie error = EPERM; 1440192895Sjamie goto done_deref_locked; 1441192895Sjamie } 1442185435Sbz 1443191673Sjamie /* Set the parameters of the prison. */ 1444191673Sjamie#ifdef INET 1445192895Sjamie redo_ip4 = 0; 1446195974Sjamie if (pr_flags & PR_IP4_USER) { 1447195974Sjamie pr->pr_flags |= PR_IP4; 1448195974Sjamie free(pr->pr_ip4, M_PRISON); 1449195974Sjamie pr->pr_ip4s = ip4s; 1450195974Sjamie pr->pr_ip4 = ip4; 1451195974Sjamie ip4 = NULL; 1452192895Sjamie FOREACH_PRISON_DESCENDANT_LOCKED(pr, tpr, descend) { 1453195945Sjamie#ifdef VIMAGE 1454195945Sjamie if (tpr->pr_flags & PR_VNET) { 1455195945Sjamie descend = 0; 1456195945Sjamie continue; 1457195945Sjamie } 1458195945Sjamie#endif 1459192895Sjamie if (prison_restrict_ip4(tpr, NULL)) { 1460192895Sjamie redo_ip4 = 1; 1461192895Sjamie descend = 0; 1462192895Sjamie } 1463192895Sjamie } 1464185435Sbz } 1465191673Sjamie#endif 1466191673Sjamie#ifdef INET6 1467192895Sjamie redo_ip6 = 0; 1468195974Sjamie if (pr_flags & PR_IP6_USER) { 1469195974Sjamie pr->pr_flags |= PR_IP6; 1470195974Sjamie free(pr->pr_ip6, M_PRISON); 1471195974Sjamie pr->pr_ip6s = ip6s; 1472195974Sjamie pr->pr_ip6 = ip6; 1473195974Sjamie ip6 = NULL; 1474192895Sjamie FOREACH_PRISON_DESCENDANT_LOCKED(pr, tpr, descend) { 1475195945Sjamie#ifdef VIMAGE 1476195945Sjamie if (tpr->pr_flags & PR_VNET) { 1477195945Sjamie descend = 0; 1478195945Sjamie continue; 1479195945Sjamie } 1480195945Sjamie#endif 1481192895Sjamie if (prison_restrict_ip6(tpr, NULL)) { 1482192895Sjamie redo_ip6 = 1; 1483192895Sjamie descend = 0; 1484192895Sjamie } 1485192895Sjamie } 1486191673Sjamie } 1487191673Sjamie#endif 1488192895Sjamie if (gotslevel) { 1489191673Sjamie pr->pr_securelevel = slevel; 1490192895Sjamie /* Set all child jails to be at least this level. */ 1491192895Sjamie FOREACH_PRISON_DESCENDANT_LOCKED(pr, tpr, descend) 1492192895Sjamie if (tpr->pr_securelevel < slevel) 1493192895Sjamie tpr->pr_securelevel = slevel; 1494192895Sjamie } 1495194762Sjamie if (gotchildmax) { 1496194762Sjamie pr->pr_childmax = childmax; 1497194762Sjamie /* Set all child jails to under this limit. */ 1498194762Sjamie FOREACH_PRISON_DESCENDANT_LOCKED_LEVEL(pr, tpr, descend, level) 1499194762Sjamie if (tpr->pr_childmax > childmax - level) 1500194762Sjamie tpr->pr_childmax = childmax > level 1501194762Sjamie ? childmax - level : 0; 1502194762Sjamie } 1503192895Sjamie if (gotenforce) { 1504192895Sjamie pr->pr_enforce_statfs = enforce; 1505192895Sjamie /* Pass this restriction on to the children. */ 1506192895Sjamie FOREACH_PRISON_DESCENDANT_LOCKED(pr, tpr, descend) 1507192895Sjamie if (tpr->pr_enforce_statfs < enforce) 1508192895Sjamie tpr->pr_enforce_statfs = enforce; 1509192895Sjamie } 1510192895Sjamie if (name != NULL) { 1511192895Sjamie if (ppr == &prison0) 1512192895Sjamie strlcpy(pr->pr_name, name, sizeof(pr->pr_name)); 1513192895Sjamie else 1514192895Sjamie snprintf(pr->pr_name, sizeof(pr->pr_name), "%s.%s", 1515192895Sjamie ppr->pr_name, name); 1516192895Sjamie /* Change this component of child names. */ 1517192895Sjamie FOREACH_PRISON_DESCENDANT_LOCKED(pr, tpr, descend) { 1518192895Sjamie bcopy(tpr->pr_name + onamelen, tpr->pr_name + namelen, 1519192895Sjamie strlen(tpr->pr_name + onamelen) + 1); 1520192895Sjamie bcopy(pr->pr_name, tpr->pr_name, namelen); 1521192895Sjamie } 1522192895Sjamie } 1523191673Sjamie if (path != NULL) { 1524192895Sjamie /* Try to keep a real-rooted full pathname. */ 1525192895Sjamie if (path[0] == '/' && strcmp(mypr->pr_path, "/")) 1526192895Sjamie snprintf(pr->pr_path, sizeof(pr->pr_path), "%s%s", 1527192895Sjamie mypr->pr_path, path); 1528192895Sjamie else 1529192895Sjamie strlcpy(pr->pr_path, path, sizeof(pr->pr_path)); 1530191673Sjamie pr->pr_root = root; 1531191673Sjamie } 1532193066Sjamie if (PR_HOST & ch_flags & ~pr_flags) { 1533193066Sjamie if (pr->pr_flags & PR_HOST) { 1534193066Sjamie /* 1535193066Sjamie * Copy the parent's host info. As with pr_ip4 above, 1536193066Sjamie * the lack of a lock on the parent is not a problem; 1537193066Sjamie * it is always set with allprison_lock at least 1538193066Sjamie * shared, and is held exclusively here. 1539193066Sjamie */ 1540194118Sjamie strlcpy(pr->pr_hostname, pr->pr_parent->pr_hostname, 1541194118Sjamie sizeof(pr->pr_hostname)); 1542194118Sjamie strlcpy(pr->pr_domainname, pr->pr_parent->pr_domainname, 1543194118Sjamie sizeof(pr->pr_domainname)); 1544194118Sjamie strlcpy(pr->pr_hostuuid, pr->pr_parent->pr_hostuuid, 1545194118Sjamie sizeof(pr->pr_hostuuid)); 1546193066Sjamie pr->pr_hostid = pr->pr_parent->pr_hostid; 1547193066Sjamie } 1548193066Sjamie } else if (host != NULL || domain != NULL || uuid != NULL || gothid) { 1549193066Sjamie /* Set this prison, and any descendants without PR_HOST. */ 1550193066Sjamie if (host != NULL) 1551194118Sjamie strlcpy(pr->pr_hostname, host, sizeof(pr->pr_hostname)); 1552193066Sjamie if (domain != NULL) 1553194118Sjamie strlcpy(pr->pr_domainname, domain, 1554194118Sjamie sizeof(pr->pr_domainname)); 1555193066Sjamie if (uuid != NULL) 1556194118Sjamie strlcpy(pr->pr_hostuuid, uuid, sizeof(pr->pr_hostuuid)); 1557193066Sjamie if (gothid) 1558193066Sjamie pr->pr_hostid = hid; 1559193066Sjamie FOREACH_PRISON_DESCENDANT_LOCKED(pr, tpr, descend) { 1560193066Sjamie if (tpr->pr_flags & PR_HOST) 1561193066Sjamie descend = 0; 1562193066Sjamie else { 1563193066Sjamie if (host != NULL) 1564194118Sjamie strlcpy(tpr->pr_hostname, 1565194118Sjamie pr->pr_hostname, 1566194118Sjamie sizeof(tpr->pr_hostname)); 1567193066Sjamie if (domain != NULL) 1568194118Sjamie strlcpy(tpr->pr_domainname, 1569194118Sjamie pr->pr_domainname, 1570194118Sjamie sizeof(tpr->pr_domainname)); 1571193066Sjamie if (uuid != NULL) 1572194118Sjamie strlcpy(tpr->pr_hostuuid, 1573194118Sjamie pr->pr_hostuuid, 1574194118Sjamie sizeof(tpr->pr_hostuuid)); 1575193066Sjamie if (gothid) 1576193066Sjamie tpr->pr_hostid = hid; 1577193066Sjamie } 1578193066Sjamie } 1579193066Sjamie } 1580192895Sjamie if ((tallow = ch_allow & ~pr_allow)) { 1581192895Sjamie /* Clear allow bits in all children. */ 1582192895Sjamie FOREACH_PRISON_DESCENDANT_LOCKED(pr, tpr, descend) 1583192895Sjamie tpr->pr_allow &= ~tallow; 1584192895Sjamie } 1585192895Sjamie pr->pr_allow = (pr->pr_allow & ~ch_allow) | pr_allow; 1586191673Sjamie /* 1587191673Sjamie * Persistent prisons get an extra reference, and prisons losing their 1588191673Sjamie * persist flag lose that reference. Only do this for existing prisons 1589191673Sjamie * for now, so new ones will remain unseen until after the module 1590191673Sjamie * handlers have completed. 1591191673Sjamie */ 1592191673Sjamie if (!created && (ch_flags & PR_PERSIST & (pr_flags ^ pr->pr_flags))) { 1593191673Sjamie if (pr_flags & PR_PERSIST) { 1594191673Sjamie pr->pr_ref++; 1595191673Sjamie pr->pr_uref++; 1596191673Sjamie } else { 1597191673Sjamie pr->pr_ref--; 1598191673Sjamie pr->pr_uref--; 1599191673Sjamie } 1600191673Sjamie } 1601191673Sjamie pr->pr_flags = (pr->pr_flags & ~ch_flags) | pr_flags; 1602191673Sjamie mtx_unlock(&pr->pr_mtx); 1603185435Sbz 1604192895Sjamie /* Locks may have prevented a complete restriction of child IP 1605192895Sjamie * addresses. If so, allocate some more memory and try again. 1606192895Sjamie */ 1607192895Sjamie#ifdef INET 1608192895Sjamie while (redo_ip4) { 1609192895Sjamie ip4s = pr->pr_ip4s; 1610192895Sjamie ip4 = malloc(ip4s * sizeof(*ip4), M_PRISON, M_WAITOK); 1611192895Sjamie mtx_lock(&pr->pr_mtx); 1612192895Sjamie redo_ip4 = 0; 1613192895Sjamie FOREACH_PRISON_DESCENDANT_LOCKED(pr, tpr, descend) { 1614195945Sjamie#ifdef VIMAGE 1615195945Sjamie if (tpr->pr_flags & PR_VNET) { 1616195945Sjamie descend = 0; 1617195945Sjamie continue; 1618195945Sjamie } 1619195945Sjamie#endif 1620192895Sjamie if (prison_restrict_ip4(tpr, ip4)) { 1621192895Sjamie if (ip4 != NULL) 1622192895Sjamie ip4 = NULL; 1623192895Sjamie else 1624192895Sjamie redo_ip4 = 1; 1625192895Sjamie } 1626192895Sjamie } 1627192895Sjamie mtx_unlock(&pr->pr_mtx); 1628192895Sjamie } 1629192895Sjamie#endif 1630192895Sjamie#ifdef INET6 1631192895Sjamie while (redo_ip6) { 1632192895Sjamie ip6s = pr->pr_ip6s; 1633192895Sjamie ip6 = malloc(ip6s * sizeof(*ip6), M_PRISON, M_WAITOK); 1634192895Sjamie mtx_lock(&pr->pr_mtx); 1635192895Sjamie redo_ip6 = 0; 1636192895Sjamie FOREACH_PRISON_DESCENDANT_LOCKED(pr, tpr, descend) { 1637195945Sjamie#ifdef VIMAGE 1638195945Sjamie if (tpr->pr_flags & PR_VNET) { 1639195945Sjamie descend = 0; 1640195945Sjamie continue; 1641195945Sjamie } 1642195945Sjamie#endif 1643192895Sjamie if (prison_restrict_ip6(tpr, ip6)) { 1644192895Sjamie if (ip6 != NULL) 1645192895Sjamie ip6 = NULL; 1646192895Sjamie else 1647192895Sjamie redo_ip6 = 1; 1648192895Sjamie } 1649192895Sjamie } 1650192895Sjamie mtx_unlock(&pr->pr_mtx); 1651192895Sjamie } 1652192895Sjamie#endif 1653192895Sjamie 1654191673Sjamie /* Let the modules do their work. */ 1655191673Sjamie sx_downgrade(&allprison_lock); 1656191673Sjamie if (created) { 1657191673Sjamie error = osd_jail_call(pr, PR_METHOD_CREATE, opts); 1658191673Sjamie if (error) { 1659191673Sjamie prison_deref(pr, PD_LIST_SLOCKED); 1660191673Sjamie goto done_errmsg; 1661191673Sjamie } 1662191673Sjamie } 1663191673Sjamie error = osd_jail_call(pr, PR_METHOD_SET, opts); 1664191673Sjamie if (error) { 1665191673Sjamie prison_deref(pr, created 1666191673Sjamie ? PD_LIST_SLOCKED 1667191673Sjamie : PD_DEREF | PD_LIST_SLOCKED); 1668191673Sjamie goto done_errmsg; 1669191673Sjamie } 1670191673Sjamie 1671191673Sjamie /* Attach this process to the prison if requested. */ 1672191673Sjamie if (flags & JAIL_ATTACH) { 1673191673Sjamie mtx_lock(&pr->pr_mtx); 1674191673Sjamie error = do_jail_attach(td, pr); 1675191673Sjamie if (error) { 1676191673Sjamie vfs_opterror(opts, "attach failed"); 1677191673Sjamie if (!created) 1678191673Sjamie prison_deref(pr, PD_DEREF); 1679191673Sjamie goto done_errmsg; 1680191673Sjamie } 1681191673Sjamie } 1682191673Sjamie 1683191673Sjamie /* 1684191673Sjamie * Now that it is all there, drop the temporary reference from existing 1685191673Sjamie * prisons. Or add a reference to newly created persistent prisons 1686191673Sjamie * (which was not done earlier so that the prison would not be publicly 1687191673Sjamie * visible). 1688191673Sjamie */ 1689191673Sjamie if (!created) { 1690191673Sjamie prison_deref(pr, (flags & JAIL_ATTACH) 1691191673Sjamie ? PD_DEREF 1692191673Sjamie : PD_DEREF | PD_LIST_SLOCKED); 1693191673Sjamie } else { 1694191673Sjamie if (pr_flags & PR_PERSIST) { 1695191673Sjamie mtx_lock(&pr->pr_mtx); 1696191673Sjamie pr->pr_ref++; 1697191673Sjamie pr->pr_uref++; 1698191673Sjamie mtx_unlock(&pr->pr_mtx); 1699191673Sjamie } 1700191673Sjamie if (!(flags & JAIL_ATTACH)) 1701191673Sjamie sx_sunlock(&allprison_lock); 1702191673Sjamie } 1703191673Sjamie td->td_retval[0] = pr->pr_id; 1704191673Sjamie goto done_errmsg; 1705191673Sjamie 1706192895Sjamie done_deref_locked: 1707192895Sjamie prison_deref(pr, created 1708192895Sjamie ? PD_LOCKED | PD_LIST_XLOCKED 1709192895Sjamie : PD_DEREF | PD_LOCKED | PD_LIST_XLOCKED); 1710192895Sjamie goto done_releroot; 1711191673Sjamie done_unlock_list: 1712191673Sjamie sx_xunlock(&allprison_lock); 1713191673Sjamie done_releroot: 1714191673Sjamie if (root != NULL) { 1715191673Sjamie vfslocked = VFS_LOCK_GIANT(root->v_mount); 1716191673Sjamie vrele(root); 1717191673Sjamie VFS_UNLOCK_GIANT(vfslocked); 1718191673Sjamie } 1719191673Sjamie done_errmsg: 1720191673Sjamie if (error) { 1721191673Sjamie vfs_getopt(opts, "errmsg", (void **)&errmsg, &errmsg_len); 1722191673Sjamie if (errmsg_len > 0) { 1723191673Sjamie errmsg_pos = 2 * vfs_getopt_pos(opts, "errmsg") + 1; 1724191673Sjamie if (errmsg_pos > 0) { 1725191673Sjamie if (optuio->uio_segflg == UIO_SYSSPACE) 1726191673Sjamie bcopy(errmsg, 1727191673Sjamie optuio->uio_iov[errmsg_pos].iov_base, 1728191673Sjamie errmsg_len); 1729191673Sjamie else 1730191673Sjamie copyout(errmsg, 1731191673Sjamie optuio->uio_iov[errmsg_pos].iov_base, 1732191673Sjamie errmsg_len); 1733191673Sjamie } 1734191673Sjamie } 1735191673Sjamie } 1736191673Sjamie done_free: 1737191673Sjamie#ifdef INET 1738191673Sjamie free(ip4, M_PRISON); 1739191673Sjamie#endif 1740191673Sjamie#ifdef INET6 1741191673Sjamie free(ip6, M_PRISON); 1742191673Sjamie#endif 1743191673Sjamie vfs_freeopts(opts); 1744191673Sjamie return (error); 1745191673Sjamie} 1746191673Sjamie 1747191673Sjamie 174882710Sdillon/* 1749191673Sjamie * struct jail_get_args { 1750191673Sjamie * struct iovec *iovp; 1751191673Sjamie * unsigned int iovcnt; 1752191673Sjamie * int flags; 1753114168Smike * }; 175482710Sdillon */ 175546155Sphkint 1756191673Sjamiejail_get(struct thread *td, struct jail_get_args *uap) 175746155Sphk{ 1758191673Sjamie struct uio *auio; 1759185435Sbz int error; 1760185435Sbz 1761191673Sjamie /* Check that we have an even number of iovecs. */ 1762191673Sjamie if (uap->iovcnt & 1) 1763191673Sjamie return (EINVAL); 1764191673Sjamie 1765191673Sjamie error = copyinuio(uap->iovp, uap->iovcnt, &auio); 1766185435Sbz if (error) 1767185435Sbz return (error); 1768191673Sjamie error = kern_jail_get(td, auio, uap->flags); 1769191673Sjamie if (error == 0) 1770191673Sjamie error = copyout(auio->uio_iov, uap->iovp, 1771191673Sjamie uap->iovcnt * sizeof (struct iovec)); 1772191673Sjamie free(auio, M_IOV); 1773191673Sjamie return (error); 1774191673Sjamie} 1775185435Sbz 1776191673Sjamieint 1777191673Sjamiekern_jail_get(struct thread *td, struct uio *optuio, int flags) 1778191673Sjamie{ 1779192895Sjamie struct prison *pr, *mypr; 1780191673Sjamie struct vfsopt *opt; 1781191673Sjamie struct vfsoptlist *opts; 1782191673Sjamie char *errmsg, *name; 1783192895Sjamie int error, errmsg_len, errmsg_pos, fi, i, jid, len, locked, pos; 1784185435Sbz 1785191673Sjamie if (flags & ~JAIL_GET_MASK) 1786191673Sjamie return (EINVAL); 1787185435Sbz 1788191673Sjamie /* Get the parameter list. */ 1789191673Sjamie error = vfs_buildopts(optuio, &opts); 1790191673Sjamie if (error) 1791191673Sjamie return (error); 1792191673Sjamie errmsg_pos = vfs_getopt_pos(opts, "errmsg"); 1793192895Sjamie mypr = td->td_ucred->cr_prison; 1794185435Sbz 1795191673Sjamie /* 1796191673Sjamie * Find the prison specified by one of: lastjid, jid, name. 1797191673Sjamie */ 1798191673Sjamie sx_slock(&allprison_lock); 1799191673Sjamie error = vfs_copyopt(opts, "lastjid", &jid, sizeof(jid)); 1800191673Sjamie if (error == 0) { 1801191673Sjamie TAILQ_FOREACH(pr, &allprison, pr_list) { 1802192895Sjamie if (pr->pr_id > jid && prison_ischild(mypr, pr)) { 1803191673Sjamie mtx_lock(&pr->pr_mtx); 1804191673Sjamie if (pr->pr_ref > 0 && 1805191673Sjamie (pr->pr_uref > 0 || (flags & JAIL_DYING))) 1806191673Sjamie break; 1807191673Sjamie mtx_unlock(&pr->pr_mtx); 1808191673Sjamie } 1809191673Sjamie } 1810191673Sjamie if (pr != NULL) 1811191673Sjamie goto found_prison; 1812191673Sjamie error = ENOENT; 1813191673Sjamie vfs_opterror(opts, "no jail after %d", jid); 1814191673Sjamie goto done_unlock_list; 1815191673Sjamie } else if (error != ENOENT) 1816191673Sjamie goto done_unlock_list; 1817185435Sbz 1818191673Sjamie error = vfs_copyopt(opts, "jid", &jid, sizeof(jid)); 1819191673Sjamie if (error == 0) { 1820191673Sjamie if (jid != 0) { 1821192895Sjamie pr = prison_find_child(mypr, jid); 1822191673Sjamie if (pr != NULL) { 1823191673Sjamie if (pr->pr_uref == 0 && !(flags & JAIL_DYING)) { 1824191673Sjamie mtx_unlock(&pr->pr_mtx); 1825191673Sjamie error = ENOENT; 1826191673Sjamie vfs_opterror(opts, "jail %d is dying", 1827191673Sjamie jid); 1828191673Sjamie goto done_unlock_list; 1829191673Sjamie } 1830191673Sjamie goto found_prison; 1831191673Sjamie } 1832191673Sjamie error = ENOENT; 1833191673Sjamie vfs_opterror(opts, "jail %d not found", jid); 1834191673Sjamie goto done_unlock_list; 1835191673Sjamie } 1836191673Sjamie } else if (error != ENOENT) 1837191673Sjamie goto done_unlock_list; 183846155Sphk 1839191673Sjamie error = vfs_getopt(opts, "name", (void **)&name, &len); 1840191673Sjamie if (error == 0) { 1841191673Sjamie if (len == 0 || name[len - 1] != '\0') { 1842191673Sjamie error = EINVAL; 1843191673Sjamie goto done_unlock_list; 1844191673Sjamie } 1845192895Sjamie pr = prison_find_name(mypr, name); 1846191673Sjamie if (pr != NULL) { 1847191673Sjamie if (pr->pr_uref == 0 && !(flags & JAIL_DYING)) { 1848191673Sjamie mtx_unlock(&pr->pr_mtx); 1849191673Sjamie error = ENOENT; 1850191673Sjamie vfs_opterror(opts, "jail \"%s\" is dying", 1851191673Sjamie name); 1852191673Sjamie goto done_unlock_list; 1853191673Sjamie } 1854191673Sjamie goto found_prison; 1855191673Sjamie } 1856191673Sjamie error = ENOENT; 1857191673Sjamie vfs_opterror(opts, "jail \"%s\" not found", name); 1858191673Sjamie goto done_unlock_list; 1859191673Sjamie } else if (error != ENOENT) 1860191673Sjamie goto done_unlock_list; 1861185435Sbz 1862191673Sjamie vfs_opterror(opts, "no jail specified"); 1863191673Sjamie error = ENOENT; 1864191673Sjamie goto done_unlock_list; 1865191673Sjamie 1866191673Sjamie found_prison: 1867191673Sjamie /* Get the parameters of the prison. */ 1868191673Sjamie pr->pr_ref++; 1869191673Sjamie locked = PD_LOCKED; 1870191673Sjamie td->td_retval[0] = pr->pr_id; 1871191673Sjamie error = vfs_setopt(opts, "jid", &pr->pr_id, sizeof(pr->pr_id)); 1872191673Sjamie if (error != 0 && error != ENOENT) 1873191673Sjamie goto done_deref; 1874192895Sjamie i = (pr->pr_parent == mypr) ? 0 : pr->pr_parent->pr_id; 1875192895Sjamie error = vfs_setopt(opts, "parent", &i, sizeof(i)); 1876191673Sjamie if (error != 0 && error != ENOENT) 1877191673Sjamie goto done_deref; 1878192895Sjamie error = vfs_setopts(opts, "name", prison_name(mypr, pr)); 1879192895Sjamie if (error != 0 && error != ENOENT) 1880192895Sjamie goto done_deref; 1881192895Sjamie error = vfs_setopt(opts, "cpuset.id", &pr->pr_cpuset->cs_id, 1882191673Sjamie sizeof(pr->pr_cpuset->cs_id)); 1883191673Sjamie if (error != 0 && error != ENOENT) 1884191673Sjamie goto done_deref; 1885192895Sjamie error = vfs_setopts(opts, "path", prison_path(mypr, pr)); 1886191673Sjamie if (error != 0 && error != ENOENT) 1887191673Sjamie goto done_deref; 1888191673Sjamie#ifdef INET 1889191673Sjamie error = vfs_setopt_part(opts, "ip4.addr", pr->pr_ip4, 1890191673Sjamie pr->pr_ip4s * sizeof(*pr->pr_ip4)); 1891191673Sjamie if (error != 0 && error != ENOENT) 1892191673Sjamie goto done_deref; 1893191673Sjamie#endif 1894191673Sjamie#ifdef INET6 1895191673Sjamie error = vfs_setopt_part(opts, "ip6.addr", pr->pr_ip6, 1896191673Sjamie pr->pr_ip6s * sizeof(*pr->pr_ip6)); 1897191673Sjamie if (error != 0 && error != ENOENT) 1898191673Sjamie goto done_deref; 1899191673Sjamie#endif 1900191673Sjamie error = vfs_setopt(opts, "securelevel", &pr->pr_securelevel, 1901191673Sjamie sizeof(pr->pr_securelevel)); 1902191673Sjamie if (error != 0 && error != ENOENT) 1903191673Sjamie goto done_deref; 1904194762Sjamie error = vfs_setopt(opts, "children.cur", &pr->pr_childcount, 1905194762Sjamie sizeof(pr->pr_childcount)); 1906194762Sjamie if (error != 0 && error != ENOENT) 1907194762Sjamie goto done_deref; 1908194762Sjamie error = vfs_setopt(opts, "children.max", &pr->pr_childmax, 1909194762Sjamie sizeof(pr->pr_childmax)); 1910194762Sjamie if (error != 0 && error != ENOENT) 1911194762Sjamie goto done_deref; 1912194118Sjamie error = vfs_setopts(opts, "host.hostname", pr->pr_hostname); 1913191673Sjamie if (error != 0 && error != ENOENT) 1914191673Sjamie goto done_deref; 1915194118Sjamie error = vfs_setopts(opts, "host.domainname", pr->pr_domainname); 1916193066Sjamie if (error != 0 && error != ENOENT) 1917193066Sjamie goto done_deref; 1918194118Sjamie error = vfs_setopts(opts, "host.hostuuid", pr->pr_hostuuid); 1919193066Sjamie if (error != 0 && error != ENOENT) 1920193066Sjamie goto done_deref; 1921193066Sjamie#ifdef COMPAT_IA32 1922193066Sjamie if (td->td_proc->p_sysent->sv_flags & SV_IA32) { 1923193066Sjamie uint32_t hid32 = pr->pr_hostid; 1924193066Sjamie 1925193066Sjamie error = vfs_setopt(opts, "host.hostid", &hid32, sizeof(hid32)); 1926193066Sjamie } else 1927193066Sjamie#endif 1928193066Sjamie error = vfs_setopt(opts, "host.hostid", &pr->pr_hostid, 1929193066Sjamie sizeof(pr->pr_hostid)); 1930193066Sjamie if (error != 0 && error != ENOENT) 1931193066Sjamie goto done_deref; 1932192895Sjamie error = vfs_setopt(opts, "enforce_statfs", &pr->pr_enforce_statfs, 1933192895Sjamie sizeof(pr->pr_enforce_statfs)); 1934191673Sjamie if (error != 0 && error != ENOENT) 1935191673Sjamie goto done_deref; 1936192895Sjamie for (fi = 0; fi < sizeof(pr_flag_names) / sizeof(pr_flag_names[0]); 1937192895Sjamie fi++) { 1938192895Sjamie if (pr_flag_names[fi] == NULL) 1939192895Sjamie continue; 1940192895Sjamie i = (pr->pr_flags & (1 << fi)) ? 1 : 0; 1941192895Sjamie error = vfs_setopt(opts, pr_flag_names[fi], &i, sizeof(i)); 1942192895Sjamie if (error != 0 && error != ENOENT) 1943192895Sjamie goto done_deref; 1944192895Sjamie i = !i; 1945192895Sjamie error = vfs_setopt(opts, pr_flag_nonames[fi], &i, sizeof(i)); 1946192895Sjamie if (error != 0 && error != ENOENT) 1947192895Sjamie goto done_deref; 1948192895Sjamie } 1949195870Sjamie for (fi = 0; fi < sizeof(pr_flag_jailsys) / sizeof(pr_flag_jailsys[0]); 1950195870Sjamie fi++) { 1951195870Sjamie i = pr->pr_flags & 1952195870Sjamie (pr_flag_jailsys[fi].disable | pr_flag_jailsys[fi].new); 1953195870Sjamie i = pr_flag_jailsys[fi].disable && 1954195870Sjamie (i == pr_flag_jailsys[fi].disable) ? JAIL_SYS_DISABLE 1955195870Sjamie : (i == pr_flag_jailsys[fi].new) ? JAIL_SYS_NEW 1956195870Sjamie : JAIL_SYS_INHERIT; 1957195870Sjamie error = 1958195870Sjamie vfs_setopt(opts, pr_flag_jailsys[fi].name, &i, sizeof(i)); 1959195870Sjamie if (error != 0 && error != ENOENT) 1960195870Sjamie goto done_deref; 1961195870Sjamie } 1962192895Sjamie for (fi = 0; fi < sizeof(pr_allow_names) / sizeof(pr_allow_names[0]); 1963192895Sjamie fi++) { 1964192895Sjamie if (pr_allow_names[fi] == NULL) 1965192895Sjamie continue; 1966192895Sjamie i = (pr->pr_allow & (1 << fi)) ? 1 : 0; 1967192895Sjamie error = vfs_setopt(opts, pr_allow_names[fi], &i, sizeof(i)); 1968192895Sjamie if (error != 0 && error != ENOENT) 1969192895Sjamie goto done_deref; 1970192895Sjamie i = !i; 1971192895Sjamie error = vfs_setopt(opts, pr_allow_nonames[fi], &i, sizeof(i)); 1972192895Sjamie if (error != 0 && error != ENOENT) 1973192895Sjamie goto done_deref; 1974192895Sjamie } 1975191673Sjamie i = (pr->pr_uref == 0); 1976191673Sjamie error = vfs_setopt(opts, "dying", &i, sizeof(i)); 1977191673Sjamie if (error != 0 && error != ENOENT) 1978191673Sjamie goto done_deref; 1979191673Sjamie i = !i; 1980191673Sjamie error = vfs_setopt(opts, "nodying", &i, sizeof(i)); 1981191673Sjamie if (error != 0 && error != ENOENT) 1982191673Sjamie goto done_deref; 1983191673Sjamie 1984191673Sjamie /* Get the module parameters. */ 1985191673Sjamie mtx_unlock(&pr->pr_mtx); 1986191673Sjamie locked = 0; 1987191673Sjamie error = osd_jail_call(pr, PR_METHOD_GET, opts); 198846155Sphk if (error) 1989191673Sjamie goto done_deref; 1990191673Sjamie prison_deref(pr, PD_DEREF | PD_LIST_SLOCKED); 199184828Sjhb 1992191673Sjamie /* By now, all parameters should have been noted. */ 1993191673Sjamie TAILQ_FOREACH(opt, opts, link) { 1994191673Sjamie if (!opt->seen && strcmp(opt->name, "errmsg")) { 1995191673Sjamie error = EINVAL; 1996191673Sjamie vfs_opterror(opts, "unknown parameter: %s", opt->name); 1997191673Sjamie goto done_errmsg; 1998191673Sjamie } 1999185435Sbz } 2000191673Sjamie 2001191673Sjamie /* Write the fetched parameters back to userspace. */ 2002191673Sjamie error = 0; 2003191673Sjamie TAILQ_FOREACH(opt, opts, link) { 2004191673Sjamie if (opt->pos >= 0 && opt->pos != errmsg_pos) { 2005191673Sjamie pos = 2 * opt->pos + 1; 2006191673Sjamie optuio->uio_iov[pos].iov_len = opt->len; 2007191673Sjamie if (opt->value != NULL) { 2008191673Sjamie if (optuio->uio_segflg == UIO_SYSSPACE) { 2009191673Sjamie bcopy(opt->value, 2010191673Sjamie optuio->uio_iov[pos].iov_base, 2011191673Sjamie opt->len); 2012191673Sjamie } else { 2013191673Sjamie error = copyout(opt->value, 2014191673Sjamie optuio->uio_iov[pos].iov_base, 2015191673Sjamie opt->len); 2016191673Sjamie if (error) 2017191673Sjamie break; 2018191673Sjamie } 2019191673Sjamie } 2020191673Sjamie } 2021185435Sbz } 2022191673Sjamie goto done_errmsg; 2023191673Sjamie 2024191673Sjamie done_deref: 2025191673Sjamie prison_deref(pr, locked | PD_DEREF | PD_LIST_SLOCKED); 2026191673Sjamie goto done_errmsg; 2027191673Sjamie 2028191673Sjamie done_unlock_list: 2029191673Sjamie sx_sunlock(&allprison_lock); 2030191673Sjamie done_errmsg: 2031191673Sjamie if (error && errmsg_pos >= 0) { 2032191673Sjamie vfs_getopt(opts, "errmsg", (void **)&errmsg, &errmsg_len); 2033191673Sjamie errmsg_pos = 2 * errmsg_pos + 1; 2034191673Sjamie if (errmsg_len > 0) { 2035191673Sjamie if (optuio->uio_segflg == UIO_SYSSPACE) 2036191673Sjamie bcopy(errmsg, 2037191673Sjamie optuio->uio_iov[errmsg_pos].iov_base, 2038191673Sjamie errmsg_len); 2039191673Sjamie else 2040191673Sjamie copyout(errmsg, 2041191673Sjamie optuio->uio_iov[errmsg_pos].iov_base, 2042191673Sjamie errmsg_len); 2043191673Sjamie } 2044185435Sbz } 2045191673Sjamie vfs_freeopts(opts); 2046191673Sjamie return (error); 2047191673Sjamie} 2048113275Smike 2049192895Sjamie 2050191673Sjamie/* 2051191673Sjamie * struct jail_remove_args { 2052191673Sjamie * int jid; 2053191673Sjamie * }; 2054191673Sjamie */ 2055191673Sjamieint 2056191673Sjamiejail_remove(struct thread *td, struct jail_remove_args *uap) 2057191673Sjamie{ 2058192895Sjamie struct prison *pr, *cpr, *lpr, *tpr; 2059192895Sjamie int descend, error; 2060185435Sbz 2061191673Sjamie error = priv_check(td, PRIV_JAIL_REMOVE); 2062185435Sbz if (error) 2063191673Sjamie return (error); 2064185435Sbz 2065185435Sbz sx_xlock(&allprison_lock); 2066192895Sjamie pr = prison_find_child(td->td_ucred->cr_prison, uap->jid); 2067191673Sjamie if (pr == NULL) { 2068185435Sbz sx_xunlock(&allprison_lock); 2069191673Sjamie return (EINVAL); 2070185435Sbz } 2071185435Sbz 2072192895Sjamie /* Remove all descendants of this prison, then remove this prison. */ 2073192895Sjamie pr->pr_ref++; 2074192895Sjamie pr->pr_flags |= PR_REMOVE; 2075192895Sjamie if (!LIST_EMPTY(&pr->pr_children)) { 2076192895Sjamie mtx_unlock(&pr->pr_mtx); 2077192895Sjamie lpr = NULL; 2078192895Sjamie FOREACH_PRISON_DESCENDANT(pr, cpr, descend) { 2079192895Sjamie mtx_lock(&cpr->pr_mtx); 2080192895Sjamie if (cpr->pr_ref > 0) { 2081192895Sjamie tpr = cpr; 2082192895Sjamie cpr->pr_ref++; 2083192895Sjamie cpr->pr_flags |= PR_REMOVE; 2084192895Sjamie } else { 2085192895Sjamie /* Already removed - do not do it again. */ 2086192895Sjamie tpr = NULL; 2087192895Sjamie } 2088192895Sjamie mtx_unlock(&cpr->pr_mtx); 2089192895Sjamie if (lpr != NULL) { 2090192895Sjamie mtx_lock(&lpr->pr_mtx); 2091192895Sjamie prison_remove_one(lpr); 2092192895Sjamie sx_xlock(&allprison_lock); 2093192895Sjamie } 2094192895Sjamie lpr = tpr; 2095192895Sjamie } 2096192895Sjamie if (lpr != NULL) { 2097192895Sjamie mtx_lock(&lpr->pr_mtx); 2098192895Sjamie prison_remove_one(lpr); 2099192895Sjamie sx_xlock(&allprison_lock); 2100192895Sjamie } 2101192895Sjamie mtx_lock(&pr->pr_mtx); 2102192895Sjamie } 2103192895Sjamie prison_remove_one(pr); 2104192895Sjamie return (0); 2105192895Sjamie} 2106192895Sjamie 2107192895Sjamiestatic void 2108192895Sjamieprison_remove_one(struct prison *pr) 2109192895Sjamie{ 2110192895Sjamie struct proc *p; 2111192895Sjamie int deuref; 2112192895Sjamie 2113191673Sjamie /* If the prison was persistent, it is not anymore. */ 2114191673Sjamie deuref = 0; 2115191673Sjamie if (pr->pr_flags & PR_PERSIST) { 2116191673Sjamie pr->pr_ref--; 2117191673Sjamie deuref = PD_DEUREF; 2118191673Sjamie pr->pr_flags &= ~PR_PERSIST; 2119179881Sdelphij } 2120113275Smike 2121192895Sjamie /* 2122192895Sjamie * jail_remove added a reference. If that's the only one, remove 2123192895Sjamie * the prison now. 2124192895Sjamie */ 2125192895Sjamie KASSERT(pr->pr_ref > 0, 2126192895Sjamie ("prison_remove_one removing a dead prison (jid=%d)", pr->pr_id)); 2127192895Sjamie if (pr->pr_ref == 1) { 2128191673Sjamie prison_deref(pr, 2129191673Sjamie deuref | PD_DEREF | PD_LOCKED | PD_LIST_XLOCKED); 2130192895Sjamie return; 2131191673Sjamie } 2132191673Sjamie 2133113275Smike mtx_unlock(&pr->pr_mtx); 2134191673Sjamie sx_xunlock(&allprison_lock); 2135191673Sjamie /* 2136191673Sjamie * Kill all processes unfortunate enough to be attached to this prison. 2137191673Sjamie */ 2138191673Sjamie sx_slock(&allproc_lock); 2139191673Sjamie LIST_FOREACH(p, &allproc, p_list) { 2140191673Sjamie PROC_LOCK(p); 2141191673Sjamie if (p->p_state != PRS_NEW && p->p_ucred && 2142191673Sjamie p->p_ucred->cr_prison == pr) 2143191673Sjamie psignal(p, SIGKILL); 2144191673Sjamie PROC_UNLOCK(p); 2145191673Sjamie } 2146191673Sjamie sx_sunlock(&allproc_lock); 2147192895Sjamie /* Remove the temporary reference added by jail_remove. */ 2148191673Sjamie prison_deref(pr, deuref | PD_DEREF); 2149113275Smike} 2150113275Smike 2151190466Sjamie 2152113275Smike/* 2153114168Smike * struct jail_attach_args { 2154114168Smike * int jid; 2155114168Smike * }; 2156113275Smike */ 2157113275Smikeint 2158114168Smikejail_attach(struct thread *td, struct jail_attach_args *uap) 2159113275Smike{ 2160113275Smike struct prison *pr; 2161191673Sjamie int error; 2162167309Spjd 2163164032Srwatson error = priv_check(td, PRIV_JAIL_ATTACH); 2164126023Snectar if (error) 2165126023Snectar return (error); 2166126023Snectar 2167168401Spjd sx_slock(&allprison_lock); 2168192895Sjamie pr = prison_find_child(td->td_ucred->cr_prison, uap->jid); 2169113275Smike if (pr == NULL) { 2170168401Spjd sx_sunlock(&allprison_lock); 2171113275Smike return (EINVAL); 2172113275Smike } 2173185435Sbz 2174185435Sbz /* 2175185435Sbz * Do not allow a process to attach to a prison that is not 2176191673Sjamie * considered to be "alive". 2177185435Sbz */ 2178191673Sjamie if (pr->pr_uref == 0) { 2179185435Sbz mtx_unlock(&pr->pr_mtx); 2180185435Sbz sx_sunlock(&allprison_lock); 2181185435Sbz return (EINVAL); 2182185435Sbz } 2183191673Sjamie 2184191673Sjamie return (do_jail_attach(td, pr)); 2185191673Sjamie} 2186191673Sjamie 2187191673Sjamiestatic int 2188191673Sjamiedo_jail_attach(struct thread *td, struct prison *pr) 2189191673Sjamie{ 2190192895Sjamie struct prison *ppr; 2191191673Sjamie struct proc *p; 2192191673Sjamie struct ucred *newcred, *oldcred; 2193191673Sjamie int vfslocked, error; 2194191673Sjamie 2195191673Sjamie /* 2196191673Sjamie * XXX: Note that there is a slight race here if two threads 2197191673Sjamie * in the same privileged process attempt to attach to two 2198191673Sjamie * different jails at the same time. It is important for 2199191673Sjamie * user processes not to do this, or they might end up with 2200191673Sjamie * a process root from one prison, but attached to the jail 2201191673Sjamie * of another. 2202191673Sjamie */ 2203113275Smike pr->pr_ref++; 2204191673Sjamie pr->pr_uref++; 2205113275Smike mtx_unlock(&pr->pr_mtx); 2206191673Sjamie 2207191673Sjamie /* Let modules do whatever they need to prepare for attaching. */ 2208191673Sjamie error = osd_jail_call(pr, PR_METHOD_ATTACH, td); 2209191673Sjamie if (error) { 2210191673Sjamie prison_deref(pr, PD_DEREF | PD_DEUREF | PD_LIST_SLOCKED); 2211191673Sjamie return (error); 2212191673Sjamie } 2213168401Spjd sx_sunlock(&allprison_lock); 2214113275Smike 2215185435Sbz /* 2216185435Sbz * Reparent the newly attached process to this jail. 2217185435Sbz */ 2218192895Sjamie ppr = td->td_ucred->cr_prison; 2219191673Sjamie p = td->td_proc; 2220185435Sbz error = cpuset_setproc_update_set(p, pr->pr_cpuset); 2221185435Sbz if (error) 2222191673Sjamie goto e_revert_osd; 2223185435Sbz 2224150652Scsjp vfslocked = VFS_LOCK_GIANT(pr->pr_root->v_mount); 2225175202Sattilio vn_lock(pr->pr_root, LK_EXCLUSIVE | LK_RETRY); 2226113275Smike if ((error = change_dir(pr->pr_root, td)) != 0) 2227113275Smike goto e_unlock; 2228113275Smike#ifdef MAC 2229172930Srwatson if ((error = mac_vnode_check_chroot(td->td_ucred, pr->pr_root))) 2230113275Smike goto e_unlock; 2231113275Smike#endif 2232175294Sattilio VOP_UNLOCK(pr->pr_root, 0); 2233191673Sjamie if ((error = change_root(pr->pr_root, td))) 2234191673Sjamie goto e_unlock_giant; 2235150652Scsjp VFS_UNLOCK_GIANT(vfslocked); 2236113275Smike 223784828Sjhb newcred = crget(); 223884828Sjhb PROC_LOCK(p); 223984828Sjhb oldcred = p->p_ucred; 2240113275Smike setsugid(p); 224184828Sjhb crcopy(newcred, oldcred); 2242113630Sjhb newcred->cr_prison = pr; 224384828Sjhb p->p_ucred = newcred; 224484828Sjhb PROC_UNLOCK(p); 224584828Sjhb crfree(oldcred); 2246192895Sjamie prison_deref(ppr, PD_DEREF | PD_DEUREF); 224746155Sphk return (0); 2248191673Sjamie e_unlock: 2249175294Sattilio VOP_UNLOCK(pr->pr_root, 0); 2250191673Sjamie e_unlock_giant: 2251150652Scsjp VFS_UNLOCK_GIANT(vfslocked); 2252191673Sjamie e_revert_osd: 2253191673Sjamie /* Tell modules this thread is still in its old jail after all. */ 2254192895Sjamie (void)osd_jail_call(ppr, PR_METHOD_ATTACH, td); 2255191673Sjamie prison_deref(pr, PD_DEREF | PD_DEUREF); 225646155Sphk return (error); 225746155Sphk} 225846155Sphk 2259192895Sjamie 2260113275Smike/* 2261113275Smike * Returns a locked prison instance, or NULL on failure. 2262113275Smike */ 2263168399Spjdstruct prison * 2264113275Smikeprison_find(int prid) 2265113275Smike{ 2266113275Smike struct prison *pr; 2267113275Smike 2268168401Spjd sx_assert(&allprison_lock, SX_LOCKED); 2269191673Sjamie TAILQ_FOREACH(pr, &allprison, pr_list) { 2270113275Smike if (pr->pr_id == prid) { 2271113275Smike mtx_lock(&pr->pr_mtx); 2272191673Sjamie if (pr->pr_ref > 0) 2273191673Sjamie return (pr); 2274191673Sjamie mtx_unlock(&pr->pr_mtx); 2275113275Smike } 2276113275Smike } 2277113275Smike return (NULL); 2278113275Smike} 2279113275Smike 2280191673Sjamie/* 2281192895Sjamie * Find a prison that is a descendant of mypr. Returns a locked prison or NULL. 2282191673Sjamie */ 2283191673Sjamiestruct prison * 2284192895Sjamieprison_find_child(struct prison *mypr, int prid) 2285191673Sjamie{ 2286192895Sjamie struct prison *pr; 2287192895Sjamie int descend; 2288192895Sjamie 2289192895Sjamie sx_assert(&allprison_lock, SX_LOCKED); 2290192895Sjamie FOREACH_PRISON_DESCENDANT(mypr, pr, descend) { 2291192895Sjamie if (pr->pr_id == prid) { 2292192895Sjamie mtx_lock(&pr->pr_mtx); 2293192895Sjamie if (pr->pr_ref > 0) 2294192895Sjamie return (pr); 2295192895Sjamie mtx_unlock(&pr->pr_mtx); 2296192895Sjamie } 2297192895Sjamie } 2298192895Sjamie return (NULL); 2299192895Sjamie} 2300192895Sjamie 2301192895Sjamie/* 2302192895Sjamie * Look for the name relative to mypr. Returns a locked prison or NULL. 2303192895Sjamie */ 2304192895Sjamiestruct prison * 2305192895Sjamieprison_find_name(struct prison *mypr, const char *name) 2306192895Sjamie{ 2307191673Sjamie struct prison *pr, *deadpr; 2308192895Sjamie size_t mylen; 2309192895Sjamie int descend; 2310191673Sjamie 2311191673Sjamie sx_assert(&allprison_lock, SX_LOCKED); 2312192895Sjamie mylen = (mypr == &prison0) ? 0 : strlen(mypr->pr_name) + 1; 2313191673Sjamie again: 2314191673Sjamie deadpr = NULL; 2315192895Sjamie FOREACH_PRISON_DESCENDANT(mypr, pr, descend) { 2316192895Sjamie if (!strcmp(pr->pr_name + mylen, name)) { 2317191673Sjamie mtx_lock(&pr->pr_mtx); 2318191673Sjamie if (pr->pr_ref > 0) { 2319191673Sjamie if (pr->pr_uref > 0) 2320191673Sjamie return (pr); 2321191673Sjamie deadpr = pr; 2322191673Sjamie } 2323191673Sjamie mtx_unlock(&pr->pr_mtx); 2324191673Sjamie } 2325191673Sjamie } 2326192895Sjamie /* There was no valid prison - perhaps there was a dying one. */ 2327191673Sjamie if (deadpr != NULL) { 2328191673Sjamie mtx_lock(&deadpr->pr_mtx); 2329191673Sjamie if (deadpr->pr_ref == 0) { 2330191673Sjamie mtx_unlock(&deadpr->pr_mtx); 2331191673Sjamie goto again; 2332191673Sjamie } 2333191673Sjamie } 2334191673Sjamie return (deadpr); 2335191673Sjamie} 2336191673Sjamie 2337191673Sjamie/* 2338192895Sjamie * See if a prison has the specific flag set. 2339192895Sjamie */ 2340192895Sjamieint 2341192895Sjamieprison_flag(struct ucred *cred, unsigned flag) 2342192895Sjamie{ 2343192895Sjamie 2344192895Sjamie /* This is an atomic read, so no locking is necessary. */ 2345192895Sjamie return (cred->cr_prison->pr_flags & flag); 2346192895Sjamie} 2347192895Sjamie 2348192895Sjamieint 2349192895Sjamieprison_allow(struct ucred *cred, unsigned flag) 2350192895Sjamie{ 2351192895Sjamie 2352192895Sjamie /* This is an atomic read, so no locking is necessary. */ 2353192895Sjamie return (cred->cr_prison->pr_allow & flag); 2354192895Sjamie} 2355192895Sjamie 2356192895Sjamie/* 2357191673Sjamie * Remove a prison reference. If that was the last reference, remove the 2358191673Sjamie * prison itself - but not in this context in case there are locks held. 2359191673Sjamie */ 236072786Srwatsonvoid 2361185029Spjdprison_free_locked(struct prison *pr) 236272786Srwatson{ 236372786Srwatson 2364185029Spjd mtx_assert(&pr->pr_mtx, MA_OWNED); 236572786Srwatson pr->pr_ref--; 236672786Srwatson if (pr->pr_ref == 0) { 2367168483Spjd mtx_unlock(&pr->pr_mtx); 2368124882Srwatson TASK_INIT(&pr->pr_task, 0, prison_complete, pr); 2369144660Sjeff taskqueue_enqueue(taskqueue_thread, &pr->pr_task); 237087275Srwatson return; 237172786Srwatson } 237287275Srwatson mtx_unlock(&pr->pr_mtx); 237372786Srwatson} 237472786Srwatson 2375185029Spjdvoid 2376185029Spjdprison_free(struct prison *pr) 2377185029Spjd{ 2378185029Spjd 2379185029Spjd mtx_lock(&pr->pr_mtx); 2380185029Spjd prison_free_locked(pr); 2381185029Spjd} 2382185029Spjd 2383124882Srwatsonstatic void 2384124882Srwatsonprison_complete(void *context, int pending) 2385124882Srwatson{ 2386191673Sjamie 2387191673Sjamie prison_deref((struct prison *)context, 0); 2388191673Sjamie} 2389191673Sjamie 2390191673Sjamie/* 2391191673Sjamie * Remove a prison reference (usually). This internal version assumes no 2392191673Sjamie * mutexes are held, except perhaps the prison itself. If there are no more 2393191673Sjamie * references, release and delist the prison. On completion, the prison lock 2394191673Sjamie * and the allprison lock are both unlocked. 2395191673Sjamie */ 2396191673Sjamiestatic void 2397191673Sjamieprison_deref(struct prison *pr, int flags) 2398191673Sjamie{ 2399192895Sjamie struct prison *ppr, *tpr; 2400150652Scsjp int vfslocked; 2401124882Srwatson 2402191673Sjamie if (!(flags & PD_LOCKED)) 2403191673Sjamie mtx_lock(&pr->pr_mtx); 2404192895Sjamie /* Decrement the user references in a separate loop. */ 2405191673Sjamie if (flags & PD_DEUREF) { 2406192895Sjamie for (tpr = pr;; tpr = tpr->pr_parent) { 2407192895Sjamie if (tpr != pr) 2408192895Sjamie mtx_lock(&tpr->pr_mtx); 2409192895Sjamie if (--tpr->pr_uref > 0) 2410192895Sjamie break; 2411192895Sjamie KASSERT(tpr != &prison0, ("prison0 pr_uref=0")); 2412192895Sjamie mtx_unlock(&tpr->pr_mtx); 2413192895Sjamie } 2414191673Sjamie /* Done if there were only user references to remove. */ 2415191673Sjamie if (!(flags & PD_DEREF)) { 2416192895Sjamie mtx_unlock(&tpr->pr_mtx); 2417191673Sjamie if (flags & PD_LIST_SLOCKED) 2418191673Sjamie sx_sunlock(&allprison_lock); 2419191673Sjamie else if (flags & PD_LIST_XLOCKED) 2420191673Sjamie sx_xunlock(&allprison_lock); 2421191673Sjamie return; 2422191673Sjamie } 2423192895Sjamie if (tpr != pr) { 2424192895Sjamie mtx_unlock(&tpr->pr_mtx); 2425192895Sjamie mtx_lock(&pr->pr_mtx); 2426192895Sjamie } 2427191673Sjamie } 2428124882Srwatson 2429192895Sjamie for (;;) { 2430192895Sjamie if (flags & PD_DEREF) 2431192895Sjamie pr->pr_ref--; 2432192895Sjamie /* If the prison still has references, nothing else to do. */ 2433192895Sjamie if (pr->pr_ref > 0) { 2434192895Sjamie mtx_unlock(&pr->pr_mtx); 2435192895Sjamie if (flags & PD_LIST_SLOCKED) 2436192895Sjamie sx_sunlock(&allprison_lock); 2437192895Sjamie else if (flags & PD_LIST_XLOCKED) 2438192895Sjamie sx_xunlock(&allprison_lock); 2439192895Sjamie return; 2440191673Sjamie } 2441191673Sjamie 2442192895Sjamie mtx_unlock(&pr->pr_mtx); 2443192895Sjamie if (flags & PD_LIST_SLOCKED) { 2444192895Sjamie if (!sx_try_upgrade(&allprison_lock)) { 2445192895Sjamie sx_sunlock(&allprison_lock); 2446192895Sjamie sx_xlock(&allprison_lock); 2447192895Sjamie } 2448192895Sjamie } else if (!(flags & PD_LIST_XLOCKED)) 2449192895Sjamie sx_xlock(&allprison_lock); 2450168489Spjd 2451192895Sjamie TAILQ_REMOVE(&allprison, pr, pr_list); 2452192895Sjamie LIST_REMOVE(pr, pr_sibling); 2453192895Sjamie ppr = pr->pr_parent; 2454192895Sjamie for (tpr = ppr; tpr != NULL; tpr = tpr->pr_parent) 2455194762Sjamie tpr->pr_childcount--; 2456196592Sjamie sx_xunlock(&allprison_lock); 2457192895Sjamie 2458194251Sjamie#ifdef VIMAGE 2459196505Szec if (pr->pr_vnet != ppr->pr_vnet) 2460194251Sjamie vnet_destroy(pr->pr_vnet); 2461194251Sjamie#endif 2462192895Sjamie if (pr->pr_root != NULL) { 2463192895Sjamie vfslocked = VFS_LOCK_GIANT(pr->pr_root->v_mount); 2464192895Sjamie vrele(pr->pr_root); 2465192895Sjamie VFS_UNLOCK_GIANT(vfslocked); 2466192895Sjamie } 2467192895Sjamie mtx_destroy(&pr->pr_mtx); 2468191673Sjamie#ifdef INET 2469192895Sjamie free(pr->pr_ip4, M_PRISON); 2470191673Sjamie#endif 2471185435Sbz#ifdef INET6 2472192895Sjamie free(pr->pr_ip6, M_PRISON); 2473185435Sbz#endif 2474192895Sjamie if (pr->pr_cpuset != NULL) 2475192895Sjamie cpuset_rel(pr->pr_cpuset); 2476192895Sjamie osd_jail_exit(pr); 2477192895Sjamie free(pr, M_PRISON); 2478192895Sjamie 2479192895Sjamie /* Removing a prison frees a reference on its parent. */ 2480192895Sjamie pr = ppr; 2481192895Sjamie mtx_lock(&pr->pr_mtx); 2482196592Sjamie flags = PD_DEREF; 2483192895Sjamie } 2484124882Srwatson} 2485124882Srwatson 248672786Srwatsonvoid 2487185029Spjdprison_hold_locked(struct prison *pr) 248872786Srwatson{ 248972786Srwatson 2490185029Spjd mtx_assert(&pr->pr_mtx, MA_OWNED); 2491168489Spjd KASSERT(pr->pr_ref > 0, 2492191671Sjamie ("Trying to hold dead prison (jid=%d).", pr->pr_id)); 249372786Srwatson pr->pr_ref++; 2494185029Spjd} 2495185029Spjd 2496185029Spjdvoid 2497185029Spjdprison_hold(struct prison *pr) 2498185029Spjd{ 2499185029Spjd 2500185029Spjd mtx_lock(&pr->pr_mtx); 2501185029Spjd prison_hold_locked(pr); 250287275Srwatson mtx_unlock(&pr->pr_mtx); 250372786Srwatson} 250472786Srwatson 2505185435Sbzvoid 2506185435Sbzprison_proc_hold(struct prison *pr) 250787275Srwatson{ 250887275Srwatson 2509185435Sbz mtx_lock(&pr->pr_mtx); 2510191673Sjamie KASSERT(pr->pr_uref > 0, 2511191673Sjamie ("Cannot add a process to a non-alive prison (jid=%d)", pr->pr_id)); 2512191673Sjamie pr->pr_uref++; 2513185435Sbz mtx_unlock(&pr->pr_mtx); 251487275Srwatson} 251587275Srwatson 2516185435Sbzvoid 2517185435Sbzprison_proc_free(struct prison *pr) 2518185435Sbz{ 2519185435Sbz 2520185435Sbz mtx_lock(&pr->pr_mtx); 2521191673Sjamie KASSERT(pr->pr_uref > 0, 2522191673Sjamie ("Trying to kill a process in a dead prison (jid=%d)", pr->pr_id)); 2523191673Sjamie prison_deref(pr, PD_DEUREF | PD_LOCKED); 2524185435Sbz} 2525185435Sbz 2526185435Sbz 2527185435Sbz#ifdef INET 2528185435Sbz/* 2529192895Sjamie * Restrict a prison's IP address list with its parent's, possibly replacing 2530192895Sjamie * it. Return true if the replacement buffer was used (or would have been). 2531192895Sjamie */ 2532192895Sjamiestatic int 2533192895Sjamieprison_restrict_ip4(struct prison *pr, struct in_addr *newip4) 2534192895Sjamie{ 2535192895Sjamie int ii, ij, used; 2536192895Sjamie struct prison *ppr; 2537192895Sjamie 2538192895Sjamie ppr = pr->pr_parent; 2539192895Sjamie if (!(pr->pr_flags & PR_IP4_USER)) { 2540192895Sjamie /* This has no user settings, so just copy the parent's list. */ 2541192895Sjamie if (pr->pr_ip4s < ppr->pr_ip4s) { 2542192895Sjamie /* 2543192895Sjamie * There's no room for the parent's list. Use the 2544192895Sjamie * new list buffer, which is assumed to be big enough 2545192895Sjamie * (if it was passed). If there's no buffer, try to 2546192895Sjamie * allocate one. 2547192895Sjamie */ 2548192895Sjamie used = 1; 2549192895Sjamie if (newip4 == NULL) { 2550192895Sjamie newip4 = malloc(ppr->pr_ip4s * sizeof(*newip4), 2551192895Sjamie M_PRISON, M_NOWAIT); 2552192895Sjamie if (newip4 != NULL) 2553192895Sjamie used = 0; 2554192895Sjamie } 2555192895Sjamie if (newip4 != NULL) { 2556192895Sjamie bcopy(ppr->pr_ip4, newip4, 2557192895Sjamie ppr->pr_ip4s * sizeof(*newip4)); 2558192895Sjamie free(pr->pr_ip4, M_PRISON); 2559192895Sjamie pr->pr_ip4 = newip4; 2560192895Sjamie pr->pr_ip4s = ppr->pr_ip4s; 2561192895Sjamie } 2562192895Sjamie return (used); 2563192895Sjamie } 2564192895Sjamie pr->pr_ip4s = ppr->pr_ip4s; 2565192895Sjamie if (pr->pr_ip4s > 0) 2566192895Sjamie bcopy(ppr->pr_ip4, pr->pr_ip4, 2567192895Sjamie pr->pr_ip4s * sizeof(*newip4)); 2568192895Sjamie else if (pr->pr_ip4 != NULL) { 2569192895Sjamie free(pr->pr_ip4, M_PRISON); 2570192895Sjamie pr->pr_ip4 = NULL; 2571192895Sjamie } 2572195974Sjamie } else if (pr->pr_ip4s > 0) { 2573192895Sjamie /* Remove addresses that aren't in the parent. */ 2574192895Sjamie for (ij = 0; ij < ppr->pr_ip4s; ij++) 2575192895Sjamie if (pr->pr_ip4[0].s_addr == ppr->pr_ip4[ij].s_addr) 2576192895Sjamie break; 2577192895Sjamie if (ij < ppr->pr_ip4s) 2578192895Sjamie ii = 1; 2579192895Sjamie else { 2580192895Sjamie bcopy(pr->pr_ip4 + 1, pr->pr_ip4, 2581192895Sjamie --pr->pr_ip4s * sizeof(*pr->pr_ip4)); 2582192895Sjamie ii = 0; 2583192895Sjamie } 2584192895Sjamie for (ij = 1; ii < pr->pr_ip4s; ) { 2585192895Sjamie if (pr->pr_ip4[ii].s_addr == ppr->pr_ip4[0].s_addr) { 2586192895Sjamie ii++; 2587192895Sjamie continue; 2588192895Sjamie } 2589192895Sjamie switch (ij >= ppr->pr_ip4s ? -1 : 2590192895Sjamie qcmp_v4(&pr->pr_ip4[ii], &ppr->pr_ip4[ij])) { 2591192895Sjamie case -1: 2592192895Sjamie bcopy(pr->pr_ip4 + ii + 1, pr->pr_ip4 + ii, 2593192895Sjamie (--pr->pr_ip4s - ii) * sizeof(*pr->pr_ip4)); 2594192895Sjamie break; 2595192895Sjamie case 0: 2596192895Sjamie ii++; 2597192895Sjamie ij++; 2598192895Sjamie break; 2599192895Sjamie case 1: 2600192895Sjamie ij++; 2601192895Sjamie break; 2602192895Sjamie } 2603192895Sjamie } 2604192895Sjamie if (pr->pr_ip4s == 0) { 2605195870Sjamie pr->pr_flags |= PR_IP4_DISABLE; 2606192895Sjamie free(pr->pr_ip4, M_PRISON); 2607192895Sjamie pr->pr_ip4 = NULL; 2608192895Sjamie } 2609192895Sjamie } 2610192895Sjamie return (0); 2611192895Sjamie} 2612192895Sjamie 2613192895Sjamie/* 2614185435Sbz * Pass back primary IPv4 address of this jail. 2615185435Sbz * 2616192895Sjamie * If not restricted return success but do not alter the address. Caller has 2617192895Sjamie * to make sure to initialize it correctly (e.g. INADDR_ANY). 2618185435Sbz * 2619188144Sjamie * Returns 0 on success, EAFNOSUPPORT if the jail doesn't allow IPv4. 2620188144Sjamie * Address returned in NBO. 2621185435Sbz */ 262246155Sphkint 2623187684Sbzprison_get_ip4(struct ucred *cred, struct in_addr *ia) 262446155Sphk{ 2625191673Sjamie struct prison *pr; 262646155Sphk 2627185435Sbz KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 2628185435Sbz KASSERT(ia != NULL, ("%s: ia is NULL", __func__)); 2629185435Sbz 2630192895Sjamie pr = cred->cr_prison; 2631192895Sjamie if (!(pr->pr_flags & PR_IP4)) 263246155Sphk return (0); 2633191673Sjamie mtx_lock(&pr->pr_mtx); 2634192895Sjamie if (!(pr->pr_flags & PR_IP4)) { 2635192895Sjamie mtx_unlock(&pr->pr_mtx); 2636192895Sjamie return (0); 2637192895Sjamie } 2638191673Sjamie if (pr->pr_ip4 == NULL) { 2639191673Sjamie mtx_unlock(&pr->pr_mtx); 2640188144Sjamie return (EAFNOSUPPORT); 2641191673Sjamie } 2642185435Sbz 2643191673Sjamie ia->s_addr = pr->pr_ip4[0].s_addr; 2644191673Sjamie mtx_unlock(&pr->pr_mtx); 2645185435Sbz return (0); 2646185435Sbz} 2647185435Sbz 2648185435Sbz/* 2649192895Sjamie * Return true if pr1 and pr2 have the same IPv4 address restrictions. 2650192895Sjamie */ 2651192895Sjamieint 2652192895Sjamieprison_equal_ip4(struct prison *pr1, struct prison *pr2) 2653192895Sjamie{ 2654192895Sjamie 2655192895Sjamie if (pr1 == pr2) 2656192895Sjamie return (1); 2657192895Sjamie 2658192895Sjamie /* 2659195974Sjamie * No need to lock since the PR_IP4_USER flag can't be altered for 2660195974Sjamie * existing prisons. 2661192895Sjamie */ 2662195945Sjamie while (pr1 != &prison0 && 2663195945Sjamie#ifdef VIMAGE 2664195945Sjamie !(pr1->pr_flags & PR_VNET) && 2665195945Sjamie#endif 2666195945Sjamie !(pr1->pr_flags & PR_IP4_USER)) 2667192895Sjamie pr1 = pr1->pr_parent; 2668195945Sjamie while (pr2 != &prison0 && 2669195945Sjamie#ifdef VIMAGE 2670195945Sjamie !(pr2->pr_flags & PR_VNET) && 2671195945Sjamie#endif 2672195945Sjamie !(pr2->pr_flags & PR_IP4_USER)) 2673192895Sjamie pr2 = pr2->pr_parent; 2674192895Sjamie return (pr1 == pr2); 2675192895Sjamie} 2676192895Sjamie 2677192895Sjamie/* 2678185435Sbz * Make sure our (source) address is set to something meaningful to this 2679185435Sbz * jail. 2680185435Sbz * 2681192895Sjamie * Returns 0 if jail doesn't restrict IPv4 or if address belongs to jail, 2682192895Sjamie * EADDRNOTAVAIL if the address doesn't belong, or EAFNOSUPPORT if the jail 2683192895Sjamie * doesn't allow IPv4. Address passed in in NBO and returned in NBO. 2684185435Sbz */ 2685185435Sbzint 2686185435Sbzprison_local_ip4(struct ucred *cred, struct in_addr *ia) 2687185435Sbz{ 2688191673Sjamie struct prison *pr; 2689185435Sbz struct in_addr ia0; 2690191673Sjamie int error; 2691185435Sbz 2692185435Sbz KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 2693185435Sbz KASSERT(ia != NULL, ("%s: ia is NULL", __func__)); 2694185435Sbz 2695192895Sjamie pr = cred->cr_prison; 2696192895Sjamie if (!(pr->pr_flags & PR_IP4)) 269746155Sphk return (0); 2698191673Sjamie mtx_lock(&pr->pr_mtx); 2699192895Sjamie if (!(pr->pr_flags & PR_IP4)) { 2700192895Sjamie mtx_unlock(&pr->pr_mtx); 2701192895Sjamie return (0); 2702192895Sjamie } 2703191673Sjamie if (pr->pr_ip4 == NULL) { 2704191673Sjamie mtx_unlock(&pr->pr_mtx); 2705188144Sjamie return (EAFNOSUPPORT); 2706191673Sjamie } 2707185435Sbz 2708185435Sbz ia0.s_addr = ntohl(ia->s_addr); 2709185435Sbz if (ia0.s_addr == INADDR_LOOPBACK) { 2710191673Sjamie ia->s_addr = pr->pr_ip4[0].s_addr; 2711191673Sjamie mtx_unlock(&pr->pr_mtx); 2712185435Sbz return (0); 271346155Sphk } 2714185435Sbz 2715188144Sjamie if (ia0.s_addr == INADDR_ANY) { 2716188144Sjamie /* 2717188144Sjamie * In case there is only 1 IPv4 address, bind directly. 2718188144Sjamie */ 2719191673Sjamie if (pr->pr_ip4s == 1) 2720191673Sjamie ia->s_addr = pr->pr_ip4[0].s_addr; 2721191673Sjamie mtx_unlock(&pr->pr_mtx); 2722185435Sbz return (0); 2723185435Sbz } 2724185435Sbz 2725191673Sjamie error = _prison_check_ip4(pr, ia); 2726191673Sjamie mtx_unlock(&pr->pr_mtx); 2727191673Sjamie return (error); 2728185435Sbz} 2729185435Sbz 2730185435Sbz/* 2731185435Sbz * Rewrite destination address in case we will connect to loopback address. 2732185435Sbz * 2733188144Sjamie * Returns 0 on success, EAFNOSUPPORT if the jail doesn't allow IPv4. 2734188144Sjamie * Address passed in in NBO and returned in NBO. 2735185435Sbz */ 2736185435Sbzint 2737185435Sbzprison_remote_ip4(struct ucred *cred, struct in_addr *ia) 2738185435Sbz{ 2739191673Sjamie struct prison *pr; 2740185435Sbz 2741185435Sbz KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 2742185435Sbz KASSERT(ia != NULL, ("%s: ia is NULL", __func__)); 2743185435Sbz 2744192895Sjamie pr = cred->cr_prison; 2745192895Sjamie if (!(pr->pr_flags & PR_IP4)) 2746185435Sbz return (0); 2747191673Sjamie mtx_lock(&pr->pr_mtx); 2748192895Sjamie if (!(pr->pr_flags & PR_IP4)) { 2749192895Sjamie mtx_unlock(&pr->pr_mtx); 2750192895Sjamie return (0); 2751192895Sjamie } 2752191673Sjamie if (pr->pr_ip4 == NULL) { 2753191673Sjamie mtx_unlock(&pr->pr_mtx); 2754188144Sjamie return (EAFNOSUPPORT); 2755191673Sjamie } 2756188144Sjamie 2757185435Sbz if (ntohl(ia->s_addr) == INADDR_LOOPBACK) { 2758191673Sjamie ia->s_addr = pr->pr_ip4[0].s_addr; 2759191673Sjamie mtx_unlock(&pr->pr_mtx); 2760185435Sbz return (0); 2761185435Sbz } 2762185435Sbz 2763185435Sbz /* 2764185435Sbz * Return success because nothing had to be changed. 2765185435Sbz */ 2766191673Sjamie mtx_unlock(&pr->pr_mtx); 2767185435Sbz return (0); 2768185435Sbz} 2769185435Sbz 2770185435Sbz/* 2771188144Sjamie * Check if given address belongs to the jail referenced by cred/prison. 2772185435Sbz * 2773192895Sjamie * Returns 0 if jail doesn't restrict IPv4 or if address belongs to jail, 2774192895Sjamie * EADDRNOTAVAIL if the address doesn't belong, or EAFNOSUPPORT if the jail 2775192895Sjamie * doesn't allow IPv4. Address passed in in NBO. 2776185435Sbz */ 2777185435Sbzstatic int 2778185435Sbz_prison_check_ip4(struct prison *pr, struct in_addr *ia) 2779185435Sbz{ 2780185435Sbz int i, a, z, d; 2781185435Sbz 2782185435Sbz /* 2783185435Sbz * Check the primary IP. 2784185435Sbz */ 2785185435Sbz if (pr->pr_ip4[0].s_addr == ia->s_addr) 2786188144Sjamie return (0); 2787185435Sbz 2788185435Sbz /* 2789185435Sbz * All the other IPs are sorted so we can do a binary search. 2790185435Sbz */ 2791185435Sbz a = 0; 2792185435Sbz z = pr->pr_ip4s - 2; 2793185435Sbz while (a <= z) { 2794185435Sbz i = (a + z) / 2; 2795185435Sbz d = qcmp_v4(&pr->pr_ip4[i+1], ia); 2796185435Sbz if (d > 0) 2797185435Sbz z = i - 1; 2798185435Sbz else if (d < 0) 2799185435Sbz a = i + 1; 280081114Srwatson else 2801188144Sjamie return (0); 2802185435Sbz } 2803188144Sjamie 2804188144Sjamie return (EADDRNOTAVAIL); 2805185435Sbz} 2806185435Sbz 2807185435Sbzint 2808185435Sbzprison_check_ip4(struct ucred *cred, struct in_addr *ia) 2809185435Sbz{ 2810191673Sjamie struct prison *pr; 2811191673Sjamie int error; 2812185435Sbz 2813185435Sbz KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 2814185435Sbz KASSERT(ia != NULL, ("%s: ia is NULL", __func__)); 2815185435Sbz 2816192895Sjamie pr = cred->cr_prison; 2817192895Sjamie if (!(pr->pr_flags & PR_IP4)) 2818188144Sjamie return (0); 2819191673Sjamie mtx_lock(&pr->pr_mtx); 2820192895Sjamie if (!(pr->pr_flags & PR_IP4)) { 2821192895Sjamie mtx_unlock(&pr->pr_mtx); 2822192895Sjamie return (0); 2823192895Sjamie } 2824191673Sjamie if (pr->pr_ip4 == NULL) { 2825191673Sjamie mtx_unlock(&pr->pr_mtx); 2826188144Sjamie return (EAFNOSUPPORT); 2827191673Sjamie } 2828185435Sbz 2829191673Sjamie error = _prison_check_ip4(pr, ia); 2830191673Sjamie mtx_unlock(&pr->pr_mtx); 2831191673Sjamie return (error); 2832185435Sbz} 2833185435Sbz#endif 2834185435Sbz 2835185435Sbz#ifdef INET6 2836192895Sjamiestatic int 2837192895Sjamieprison_restrict_ip6(struct prison *pr, struct in6_addr *newip6) 2838192895Sjamie{ 2839192895Sjamie int ii, ij, used; 2840192895Sjamie struct prison *ppr; 2841192895Sjamie 2842192895Sjamie ppr = pr->pr_parent; 2843192895Sjamie if (!(pr->pr_flags & PR_IP6_USER)) { 2844192895Sjamie /* This has no user settings, so just copy the parent's list. */ 2845192895Sjamie if (pr->pr_ip6s < ppr->pr_ip6s) { 2846192895Sjamie /* 2847192895Sjamie * There's no room for the parent's list. Use the 2848192895Sjamie * new list buffer, which is assumed to be big enough 2849192895Sjamie * (if it was passed). If there's no buffer, try to 2850192895Sjamie * allocate one. 2851192895Sjamie */ 2852192895Sjamie used = 1; 2853192895Sjamie if (newip6 == NULL) { 2854192895Sjamie newip6 = malloc(ppr->pr_ip6s * sizeof(*newip6), 2855192895Sjamie M_PRISON, M_NOWAIT); 2856192895Sjamie if (newip6 != NULL) 2857192895Sjamie used = 0; 2858192895Sjamie } 2859192895Sjamie if (newip6 != NULL) { 2860192895Sjamie bcopy(ppr->pr_ip6, newip6, 2861192895Sjamie ppr->pr_ip6s * sizeof(*newip6)); 2862192895Sjamie free(pr->pr_ip6, M_PRISON); 2863192895Sjamie pr->pr_ip6 = newip6; 2864192895Sjamie pr->pr_ip6s = ppr->pr_ip6s; 2865192895Sjamie } 2866192895Sjamie return (used); 2867192895Sjamie } 2868192895Sjamie pr->pr_ip6s = ppr->pr_ip6s; 2869192895Sjamie if (pr->pr_ip6s > 0) 2870192895Sjamie bcopy(ppr->pr_ip6, pr->pr_ip6, 2871192895Sjamie pr->pr_ip6s * sizeof(*newip6)); 2872192895Sjamie else if (pr->pr_ip6 != NULL) { 2873192895Sjamie free(pr->pr_ip6, M_PRISON); 2874192895Sjamie pr->pr_ip6 = NULL; 2875192895Sjamie } 2876195974Sjamie } else if (pr->pr_ip6s > 0) { 2877192895Sjamie /* Remove addresses that aren't in the parent. */ 2878192895Sjamie for (ij = 0; ij < ppr->pr_ip6s; ij++) 2879192895Sjamie if (IN6_ARE_ADDR_EQUAL(&pr->pr_ip6[0], 2880192895Sjamie &ppr->pr_ip6[ij])) 2881192895Sjamie break; 2882192895Sjamie if (ij < ppr->pr_ip6s) 2883192895Sjamie ii = 1; 2884192895Sjamie else { 2885192895Sjamie bcopy(pr->pr_ip6 + 1, pr->pr_ip6, 2886192895Sjamie --pr->pr_ip6s * sizeof(*pr->pr_ip6)); 2887192895Sjamie ii = 0; 2888192895Sjamie } 2889192895Sjamie for (ij = 1; ii < pr->pr_ip6s; ) { 2890192895Sjamie if (IN6_ARE_ADDR_EQUAL(&pr->pr_ip6[ii], 2891192895Sjamie &ppr->pr_ip6[0])) { 2892192895Sjamie ii++; 2893192895Sjamie continue; 2894192895Sjamie } 2895192895Sjamie switch (ij >= ppr->pr_ip4s ? -1 : 2896192895Sjamie qcmp_v6(&pr->pr_ip6[ii], &ppr->pr_ip6[ij])) { 2897192895Sjamie case -1: 2898192895Sjamie bcopy(pr->pr_ip6 + ii + 1, pr->pr_ip6 + ii, 2899192895Sjamie (--pr->pr_ip6s - ii) * sizeof(*pr->pr_ip6)); 2900192895Sjamie break; 2901192895Sjamie case 0: 2902192895Sjamie ii++; 2903192895Sjamie ij++; 2904192895Sjamie break; 2905192895Sjamie case 1: 2906192895Sjamie ij++; 2907192895Sjamie break; 2908192895Sjamie } 2909192895Sjamie } 2910192895Sjamie if (pr->pr_ip6s == 0) { 2911195870Sjamie pr->pr_flags |= PR_IP6_DISABLE; 2912192895Sjamie free(pr->pr_ip6, M_PRISON); 2913192895Sjamie pr->pr_ip6 = NULL; 2914192895Sjamie } 2915192895Sjamie } 2916192895Sjamie return 0; 2917192895Sjamie} 2918192895Sjamie 2919185435Sbz/* 2920185435Sbz * Pass back primary IPv6 address for this jail. 2921185435Sbz * 2922192895Sjamie * If not restricted return success but do not alter the address. Caller has 2923192895Sjamie * to make sure to initialize it correctly (e.g. IN6ADDR_ANY_INIT). 2924185435Sbz * 2925188144Sjamie * Returns 0 on success, EAFNOSUPPORT if the jail doesn't allow IPv6. 2926185435Sbz */ 2927185435Sbzint 2928187684Sbzprison_get_ip6(struct ucred *cred, struct in6_addr *ia6) 2929185435Sbz{ 2930191673Sjamie struct prison *pr; 2931185435Sbz 2932185435Sbz KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 2933185435Sbz KASSERT(ia6 != NULL, ("%s: ia6 is NULL", __func__)); 2934185435Sbz 2935192895Sjamie pr = cred->cr_prison; 2936192895Sjamie if (!(pr->pr_flags & PR_IP6)) 293781114Srwatson return (0); 2938191673Sjamie mtx_lock(&pr->pr_mtx); 2939192895Sjamie if (!(pr->pr_flags & PR_IP6)) { 2940192895Sjamie mtx_unlock(&pr->pr_mtx); 2941192895Sjamie return (0); 2942192895Sjamie } 2943191673Sjamie if (pr->pr_ip6 == NULL) { 2944191673Sjamie mtx_unlock(&pr->pr_mtx); 2945188144Sjamie return (EAFNOSUPPORT); 2946191673Sjamie } 2947188144Sjamie 2948191673Sjamie bcopy(&pr->pr_ip6[0], ia6, sizeof(struct in6_addr)); 2949191673Sjamie mtx_unlock(&pr->pr_mtx); 2950185435Sbz return (0); 2951185435Sbz} 2952185435Sbz 2953185435Sbz/* 2954192895Sjamie * Return true if pr1 and pr2 have the same IPv6 address restrictions. 2955192895Sjamie */ 2956192895Sjamieint 2957192895Sjamieprison_equal_ip6(struct prison *pr1, struct prison *pr2) 2958192895Sjamie{ 2959192895Sjamie 2960192895Sjamie if (pr1 == pr2) 2961192895Sjamie return (1); 2962192895Sjamie 2963195945Sjamie while (pr1 != &prison0 && 2964195945Sjamie#ifdef VIMAGE 2965195945Sjamie !(pr1->pr_flags & PR_VNET) && 2966195945Sjamie#endif 2967195945Sjamie !(pr1->pr_flags & PR_IP6_USER)) 2968192895Sjamie pr1 = pr1->pr_parent; 2969195945Sjamie while (pr2 != &prison0 && 2970195945Sjamie#ifdef VIMAGE 2971195945Sjamie !(pr2->pr_flags & PR_VNET) && 2972195945Sjamie#endif 2973195945Sjamie !(pr2->pr_flags & PR_IP6_USER)) 2974192895Sjamie pr2 = pr2->pr_parent; 2975192895Sjamie return (pr1 == pr2); 2976192895Sjamie} 2977192895Sjamie 2978192895Sjamie/* 2979185435Sbz * Make sure our (source) address is set to something meaningful to this jail. 2980185435Sbz * 2981185435Sbz * v6only should be set based on (inp->inp_flags & IN6P_IPV6_V6ONLY != 0) 2982185435Sbz * when needed while binding. 2983185435Sbz * 2984192895Sjamie * Returns 0 if jail doesn't restrict IPv6 or if address belongs to jail, 2985192895Sjamie * EADDRNOTAVAIL if the address doesn't belong, or EAFNOSUPPORT if the jail 2986192895Sjamie * doesn't allow IPv6. 2987185435Sbz */ 2988185435Sbzint 2989185435Sbzprison_local_ip6(struct ucred *cred, struct in6_addr *ia6, int v6only) 2990185435Sbz{ 2991191673Sjamie struct prison *pr; 2992191673Sjamie int error; 2993185435Sbz 2994185435Sbz KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 2995185435Sbz KASSERT(ia6 != NULL, ("%s: ia6 is NULL", __func__)); 2996185435Sbz 2997192895Sjamie pr = cred->cr_prison; 2998192895Sjamie if (!(pr->pr_flags & PR_IP6)) 2999185435Sbz return (0); 3000191673Sjamie mtx_lock(&pr->pr_mtx); 3001192895Sjamie if (!(pr->pr_flags & PR_IP6)) { 3002192895Sjamie mtx_unlock(&pr->pr_mtx); 3003192895Sjamie return (0); 3004192895Sjamie } 3005191673Sjamie if (pr->pr_ip6 == NULL) { 3006191673Sjamie mtx_unlock(&pr->pr_mtx); 3007188144Sjamie return (EAFNOSUPPORT); 3008191673Sjamie } 3009188144Sjamie 3010185435Sbz if (IN6_IS_ADDR_LOOPBACK(ia6)) { 3011191673Sjamie bcopy(&pr->pr_ip6[0], ia6, sizeof(struct in6_addr)); 3012191673Sjamie mtx_unlock(&pr->pr_mtx); 3013185435Sbz return (0); 301481114Srwatson } 3015185435Sbz 3016188144Sjamie if (IN6_IS_ADDR_UNSPECIFIED(ia6)) { 3017188144Sjamie /* 3018188144Sjamie * In case there is only 1 IPv6 address, and v6only is true, 3019188144Sjamie * then bind directly. 3020188144Sjamie */ 3021191673Sjamie if (v6only != 0 && pr->pr_ip6s == 1) 3022191673Sjamie bcopy(&pr->pr_ip6[0], ia6, sizeof(struct in6_addr)); 3023191673Sjamie mtx_unlock(&pr->pr_mtx); 3024185435Sbz return (0); 3025185435Sbz } 3026188144Sjamie 3027191673Sjamie error = _prison_check_ip6(pr, ia6); 3028191673Sjamie mtx_unlock(&pr->pr_mtx); 3029191673Sjamie return (error); 3030185435Sbz} 3031185435Sbz 3032185435Sbz/* 3033185435Sbz * Rewrite destination address in case we will connect to loopback address. 3034185435Sbz * 3035188144Sjamie * Returns 0 on success, EAFNOSUPPORT if the jail doesn't allow IPv6. 3036185435Sbz */ 3037185435Sbzint 3038185435Sbzprison_remote_ip6(struct ucred *cred, struct in6_addr *ia6) 3039185435Sbz{ 3040191673Sjamie struct prison *pr; 3041185435Sbz 3042185435Sbz KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 3043185435Sbz KASSERT(ia6 != NULL, ("%s: ia6 is NULL", __func__)); 3044185435Sbz 3045192895Sjamie pr = cred->cr_prison; 3046192895Sjamie if (!(pr->pr_flags & PR_IP6)) 3047185435Sbz return (0); 3048191673Sjamie mtx_lock(&pr->pr_mtx); 3049192895Sjamie if (!(pr->pr_flags & PR_IP6)) { 3050192895Sjamie mtx_unlock(&pr->pr_mtx); 3051192895Sjamie return (0); 3052192895Sjamie } 3053191673Sjamie if (pr->pr_ip6 == NULL) { 3054191673Sjamie mtx_unlock(&pr->pr_mtx); 3055188144Sjamie return (EAFNOSUPPORT); 3056191673Sjamie } 3057188144Sjamie 3058185435Sbz if (IN6_IS_ADDR_LOOPBACK(ia6)) { 3059191673Sjamie bcopy(&pr->pr_ip6[0], ia6, sizeof(struct in6_addr)); 3060191673Sjamie mtx_unlock(&pr->pr_mtx); 3061185435Sbz return (0); 3062185435Sbz } 3063185435Sbz 3064185435Sbz /* 3065185435Sbz * Return success because nothing had to be changed. 3066185435Sbz */ 3067191673Sjamie mtx_unlock(&pr->pr_mtx); 306846155Sphk return (0); 306946155Sphk} 307046155Sphk 3071185435Sbz/* 3072188144Sjamie * Check if given address belongs to the jail referenced by cred/prison. 3073185435Sbz * 3074192895Sjamie * Returns 0 if jail doesn't restrict IPv6 or if address belongs to jail, 3075192895Sjamie * EADDRNOTAVAIL if the address doesn't belong, or EAFNOSUPPORT if the jail 3076192895Sjamie * doesn't allow IPv6. 3077185435Sbz */ 3078185435Sbzstatic int 3079185435Sbz_prison_check_ip6(struct prison *pr, struct in6_addr *ia6) 308046155Sphk{ 3081185435Sbz int i, a, z, d; 308246155Sphk 3083185435Sbz /* 3084185435Sbz * Check the primary IP. 3085185435Sbz */ 3086185435Sbz if (IN6_ARE_ADDR_EQUAL(&pr->pr_ip6[0], ia6)) 3087188144Sjamie return (0); 3088185435Sbz 3089185435Sbz /* 3090185435Sbz * All the other IPs are sorted so we can do a binary search. 3091185435Sbz */ 3092185435Sbz a = 0; 3093185435Sbz z = pr->pr_ip6s - 2; 3094185435Sbz while (a <= z) { 3095185435Sbz i = (a + z) / 2; 3096185435Sbz d = qcmp_v6(&pr->pr_ip6[i+1], ia6); 3097185435Sbz if (d > 0) 3098185435Sbz z = i - 1; 3099185435Sbz else if (d < 0) 3100185435Sbz a = i + 1; 310146155Sphk else 3102188144Sjamie return (0); 310346155Sphk } 3104188144Sjamie 3105188144Sjamie return (EADDRNOTAVAIL); 310646155Sphk} 310746155Sphk 310846155Sphkint 3109185435Sbzprison_check_ip6(struct ucred *cred, struct in6_addr *ia6) 3110185435Sbz{ 3111191673Sjamie struct prison *pr; 3112191673Sjamie int error; 3113185435Sbz 3114185435Sbz KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 3115185435Sbz KASSERT(ia6 != NULL, ("%s: ia6 is NULL", __func__)); 3116185435Sbz 3117192895Sjamie pr = cred->cr_prison; 3118192895Sjamie if (!(pr->pr_flags & PR_IP6)) 3119188144Sjamie return (0); 3120191673Sjamie mtx_lock(&pr->pr_mtx); 3121192895Sjamie if (!(pr->pr_flags & PR_IP6)) { 3122192895Sjamie mtx_unlock(&pr->pr_mtx); 3123192895Sjamie return (0); 3124192895Sjamie } 3125191673Sjamie if (pr->pr_ip6 == NULL) { 3126191673Sjamie mtx_unlock(&pr->pr_mtx); 3127188144Sjamie return (EAFNOSUPPORT); 3128191673Sjamie } 3129185435Sbz 3130191673Sjamie error = _prison_check_ip6(pr, ia6); 3131191673Sjamie mtx_unlock(&pr->pr_mtx); 3132191673Sjamie return (error); 3133185435Sbz} 3134185435Sbz#endif 3135185435Sbz 3136185435Sbz/* 3137188146Sjamie * Check if a jail supports the given address family. 3138188146Sjamie * 3139188146Sjamie * Returns 0 if not jailed or the address family is supported, EAFNOSUPPORT 3140188146Sjamie * if not. 3141188146Sjamie */ 3142188146Sjamieint 3143188146Sjamieprison_check_af(struct ucred *cred, int af) 3144188146Sjamie{ 3145192895Sjamie struct prison *pr; 3146188146Sjamie int error; 3147188146Sjamie 3148188146Sjamie KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 3149188146Sjamie 3150192895Sjamie pr = cred->cr_prison; 3151194923Sjamie#ifdef VIMAGE 3152194915Sjamie /* Prisons with their own network stack are not limited. */ 3153194915Sjamie if (pr->pr_flags & PR_VNET) 3154194915Sjamie return (0); 3155194923Sjamie#endif 3156194915Sjamie 3157188146Sjamie error = 0; 3158188146Sjamie switch (af) 3159188146Sjamie { 3160188146Sjamie#ifdef INET 3161188146Sjamie case AF_INET: 3162192895Sjamie if (pr->pr_flags & PR_IP4) 3163192895Sjamie { 3164192895Sjamie mtx_lock(&pr->pr_mtx); 3165192895Sjamie if ((pr->pr_flags & PR_IP4) && pr->pr_ip4 == NULL) 3166192895Sjamie error = EAFNOSUPPORT; 3167192895Sjamie mtx_unlock(&pr->pr_mtx); 3168192895Sjamie } 3169188146Sjamie break; 3170188146Sjamie#endif 3171188146Sjamie#ifdef INET6 3172188146Sjamie case AF_INET6: 3173192895Sjamie if (pr->pr_flags & PR_IP6) 3174192895Sjamie { 3175192895Sjamie mtx_lock(&pr->pr_mtx); 3176192895Sjamie if ((pr->pr_flags & PR_IP6) && pr->pr_ip6 == NULL) 3177192895Sjamie error = EAFNOSUPPORT; 3178192895Sjamie mtx_unlock(&pr->pr_mtx); 3179192895Sjamie } 3180188146Sjamie break; 3181188146Sjamie#endif 3182188146Sjamie case AF_LOCAL: 3183188146Sjamie case AF_ROUTE: 3184188146Sjamie break; 3185188146Sjamie default: 3186192895Sjamie if (!(pr->pr_allow & PR_ALLOW_SOCKET_AF)) 3187188146Sjamie error = EAFNOSUPPORT; 3188188146Sjamie } 3189188146Sjamie return (error); 3190188146Sjamie} 3191188146Sjamie 3192188146Sjamie/* 3193185435Sbz * Check if given address belongs to the jail referenced by cred (wrapper to 3194185435Sbz * prison_check_ip[46]). 3195185435Sbz * 3196192895Sjamie * Returns 0 if jail doesn't restrict the address family or if address belongs 3197192895Sjamie * to jail, EADDRNOTAVAIL if the address doesn't belong, or EAFNOSUPPORT if 3198192895Sjamie * the jail doesn't allow the address family. IPv4 Address passed in in NBO. 3199185435Sbz */ 3200185435Sbzint 320172786Srwatsonprison_if(struct ucred *cred, struct sockaddr *sa) 320246155Sphk{ 3203185435Sbz#ifdef INET 3204114168Smike struct sockaddr_in *sai; 3205185435Sbz#endif 3206185435Sbz#ifdef INET6 3207185435Sbz struct sockaddr_in6 *sai6; 3208185435Sbz#endif 3209188144Sjamie int error; 321046155Sphk 3211185435Sbz KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 3212185435Sbz KASSERT(sa != NULL, ("%s: sa is NULL", __func__)); 3213185435Sbz 3214188144Sjamie error = 0; 3215188144Sjamie switch (sa->sa_family) 3216185435Sbz { 3217185435Sbz#ifdef INET 3218185435Sbz case AF_INET: 3219185435Sbz sai = (struct sockaddr_in *)sa; 3220188144Sjamie error = prison_check_ip4(cred, &sai->sin_addr); 3221185435Sbz break; 3222185435Sbz#endif 3223185435Sbz#ifdef INET6 3224185435Sbz case AF_INET6: 3225185435Sbz sai6 = (struct sockaddr_in6 *)sa; 3226188144Sjamie error = prison_check_ip6(cred, &sai6->sin6_addr); 3227185435Sbz break; 3228185435Sbz#endif 3229185435Sbz default: 3230192895Sjamie if (!(cred->cr_prison->pr_allow & PR_ALLOW_SOCKET_AF)) 3231188144Sjamie error = EAFNOSUPPORT; 3232185435Sbz } 3233188144Sjamie return (error); 323446155Sphk} 323572786Srwatson 323672786Srwatson/* 323772786Srwatson * Return 0 if jails permit p1 to frob p2, otherwise ESRCH. 323872786Srwatson */ 323972786Srwatsonint 3240114168Smikeprison_check(struct ucred *cred1, struct ucred *cred2) 324172786Srwatson{ 324272786Srwatson 3243192895Sjamie return ((cred1->cr_prison == cred2->cr_prison || 3244192895Sjamie prison_ischild(cred1->cr_prison, cred2->cr_prison)) ? 0 : ESRCH); 3245192895Sjamie} 324672786Srwatson 3247192895Sjamie/* 3248192895Sjamie * Return 1 if p2 is a child of p1, otherwise 0. 3249192895Sjamie */ 3250192895Sjamieint 3251192895Sjamieprison_ischild(struct prison *pr1, struct prison *pr2) 3252192895Sjamie{ 3253192895Sjamie 3254192895Sjamie for (pr2 = pr2->pr_parent; pr2 != NULL; pr2 = pr2->pr_parent) 3255192895Sjamie if (pr1 == pr2) 3256192895Sjamie return (1); 325772786Srwatson return (0); 325872786Srwatson} 325972786Srwatson 326072786Srwatson/* 326172786Srwatson * Return 1 if the passed credential is in a jail, otherwise 0. 326272786Srwatson */ 326372786Srwatsonint 3264114168Smikejailed(struct ucred *cred) 326572786Srwatson{ 326672786Srwatson 3267192895Sjamie return (cred->cr_prison != &prison0); 326872786Srwatson} 326991384Srobert 327091384Srobert/* 3271194090Sjamie * Return the correct hostname (domainname, et al) for the passed credential. 327291384Srobert */ 327391391Srobertvoid 3274114168Smikegetcredhostname(struct ucred *cred, char *buf, size_t size) 327591384Srobert{ 3276193066Sjamie struct prison *pr; 327791384Srobert 3278194090Sjamie /* 3279194090Sjamie * A NULL credential can be used to shortcut to the physical 3280194090Sjamie * system's hostname. 3281194090Sjamie */ 3282193066Sjamie pr = (cred != NULL) ? cred->cr_prison : &prison0; 3283193066Sjamie mtx_lock(&pr->pr_mtx); 3284194118Sjamie strlcpy(buf, pr->pr_hostname, size); 3285193066Sjamie mtx_unlock(&pr->pr_mtx); 328691384Srobert} 3287113275Smike 3288194090Sjamievoid 3289194090Sjamiegetcreddomainname(struct ucred *cred, char *buf, size_t size) 3290194090Sjamie{ 3291194090Sjamie 3292194090Sjamie mtx_lock(&cred->cr_prison->pr_mtx); 3293194118Sjamie strlcpy(buf, cred->cr_prison->pr_domainname, size); 3294194090Sjamie mtx_unlock(&cred->cr_prison->pr_mtx); 3295194090Sjamie} 3296194090Sjamie 3297194090Sjamievoid 3298194090Sjamiegetcredhostuuid(struct ucred *cred, char *buf, size_t size) 3299194090Sjamie{ 3300194090Sjamie 3301194090Sjamie mtx_lock(&cred->cr_prison->pr_mtx); 3302194118Sjamie strlcpy(buf, cred->cr_prison->pr_hostuuid, size); 3303194090Sjamie mtx_unlock(&cred->cr_prison->pr_mtx); 3304194090Sjamie} 3305194090Sjamie 3306194090Sjamievoid 3307194090Sjamiegetcredhostid(struct ucred *cred, unsigned long *hostid) 3308194090Sjamie{ 3309194090Sjamie 3310194090Sjamie mtx_lock(&cred->cr_prison->pr_mtx); 3311194090Sjamie *hostid = cred->cr_prison->pr_hostid; 3312194090Sjamie mtx_unlock(&cred->cr_prison->pr_mtx); 3313194090Sjamie} 3314194090Sjamie 3315196176Sbz#ifdef VIMAGE 3316125804Srwatson/* 3317196176Sbz * Determine whether the prison represented by cred owns 3318196176Sbz * its vnet rather than having it inherited. 3319196176Sbz * 3320196176Sbz * Returns 1 in case the prison owns the vnet, 0 otherwise. 3321196176Sbz */ 3322196176Sbzint 3323196176Sbzprison_owns_vnet(struct ucred *cred) 3324196176Sbz{ 3325196176Sbz 3326196176Sbz /* 3327196176Sbz * vnets cannot be added/removed after jail creation, 3328196176Sbz * so no need to lock here. 3329196176Sbz */ 3330196176Sbz return (cred->cr_prison->pr_flags & PR_VNET ? 1 : 0); 3331196176Sbz} 3332196176Sbz#endif 3333196176Sbz 3334196176Sbz/* 3335147185Spjd * Determine whether the subject represented by cred can "see" 3336147185Spjd * status of a mount point. 3337147185Spjd * Returns: 0 for permitted, ENOENT otherwise. 3338147185Spjd * XXX: This function should be called cr_canseemount() and should be 3339147185Spjd * placed in kern_prot.c. 3340125804Srwatson */ 3341125804Srwatsonint 3342147185Spjdprison_canseemount(struct ucred *cred, struct mount *mp) 3343125804Srwatson{ 3344147185Spjd struct prison *pr; 3345147185Spjd struct statfs *sp; 3346147185Spjd size_t len; 3347125804Srwatson 3348192895Sjamie pr = cred->cr_prison; 3349192895Sjamie if (pr->pr_enforce_statfs == 0) 3350147185Spjd return (0); 3351147185Spjd if (pr->pr_root->v_mount == mp) 3352147185Spjd return (0); 3353192895Sjamie if (pr->pr_enforce_statfs == 2) 3354147185Spjd return (ENOENT); 3355147185Spjd /* 3356147185Spjd * If jail's chroot directory is set to "/" we should be able to see 3357147185Spjd * all mount-points from inside a jail. 3358147185Spjd * This is ugly check, but this is the only situation when jail's 3359147185Spjd * directory ends with '/'. 3360147185Spjd */ 3361147185Spjd if (strcmp(pr->pr_path, "/") == 0) 3362147185Spjd return (0); 3363147185Spjd len = strlen(pr->pr_path); 3364147185Spjd sp = &mp->mnt_stat; 3365147185Spjd if (strncmp(pr->pr_path, sp->f_mntonname, len) != 0) 3366147185Spjd return (ENOENT); 3367147185Spjd /* 3368147185Spjd * Be sure that we don't have situation where jail's root directory 3369147185Spjd * is "/some/path" and mount point is "/some/pathpath". 3370147185Spjd */ 3371147185Spjd if (sp->f_mntonname[len] != '\0' && sp->f_mntonname[len] != '/') 3372147185Spjd return (ENOENT); 3373147185Spjd return (0); 3374147185Spjd} 3375147185Spjd 3376147185Spjdvoid 3377147185Spjdprison_enforce_statfs(struct ucred *cred, struct mount *mp, struct statfs *sp) 3378147185Spjd{ 3379147185Spjd char jpath[MAXPATHLEN]; 3380147185Spjd struct prison *pr; 3381147185Spjd size_t len; 3382147185Spjd 3383192895Sjamie pr = cred->cr_prison; 3384192895Sjamie if (pr->pr_enforce_statfs == 0) 3385147185Spjd return; 3386147185Spjd if (prison_canseemount(cred, mp) != 0) { 3387147185Spjd bzero(sp->f_mntonname, sizeof(sp->f_mntonname)); 3388147185Spjd strlcpy(sp->f_mntonname, "[restricted]", 3389147185Spjd sizeof(sp->f_mntonname)); 3390147185Spjd return; 3391125804Srwatson } 3392147185Spjd if (pr->pr_root->v_mount == mp) { 3393147185Spjd /* 3394147185Spjd * Clear current buffer data, so we are sure nothing from 3395147185Spjd * the valid path left there. 3396147185Spjd */ 3397147185Spjd bzero(sp->f_mntonname, sizeof(sp->f_mntonname)); 3398147185Spjd *sp->f_mntonname = '/'; 3399147185Spjd return; 3400147185Spjd } 3401147185Spjd /* 3402147185Spjd * If jail's chroot directory is set to "/" we should be able to see 3403147185Spjd * all mount-points from inside a jail. 3404147185Spjd */ 3405147185Spjd if (strcmp(pr->pr_path, "/") == 0) 3406147185Spjd return; 3407147185Spjd len = strlen(pr->pr_path); 3408147185Spjd strlcpy(jpath, sp->f_mntonname + len, sizeof(jpath)); 3409147185Spjd /* 3410147185Spjd * Clear current buffer data, so we are sure nothing from 3411147185Spjd * the valid path left there. 3412147185Spjd */ 3413147185Spjd bzero(sp->f_mntonname, sizeof(sp->f_mntonname)); 3414147185Spjd if (*jpath == '\0') { 3415147185Spjd /* Should never happen. */ 3416147185Spjd *sp->f_mntonname = '/'; 3417147185Spjd } else { 3418147185Spjd strlcpy(sp->f_mntonname, jpath, sizeof(sp->f_mntonname)); 3419147185Spjd } 3420125804Srwatson} 3421125804Srwatson 3422164032Srwatson/* 3423164032Srwatson * Check with permission for a specific privilege is granted within jail. We 3424164032Srwatson * have a specific list of accepted privileges; the rest are denied. 3425164032Srwatson */ 3426164032Srwatsonint 3427164032Srwatsonprison_priv_check(struct ucred *cred, int priv) 3428164032Srwatson{ 3429164032Srwatson 3430164032Srwatson if (!jailed(cred)) 3431164032Srwatson return (0); 3432164032Srwatson 3433194915Sjamie#ifdef VIMAGE 3434194915Sjamie /* 3435194915Sjamie * Privileges specific to prisons with a virtual network stack. 3436194915Sjamie * There might be a duplicate entry here in case the privilege 3437194915Sjamie * is only granted conditionally in the legacy jail case. 3438194915Sjamie */ 3439164032Srwatson switch (priv) { 3440194915Sjamie#ifdef notyet 3441194915Sjamie /* 3442194915Sjamie * NFS-specific privileges. 3443194915Sjamie */ 3444194915Sjamie case PRIV_NFS_DAEMON: 3445194915Sjamie case PRIV_NFS_LOCKD: 3446194915Sjamie#endif 3447194915Sjamie /* 3448194915Sjamie * Network stack privileges. 3449194915Sjamie */ 3450194915Sjamie case PRIV_NET_BRIDGE: 3451194915Sjamie case PRIV_NET_GRE: 3452194915Sjamie case PRIV_NET_BPF: 3453194915Sjamie case PRIV_NET_RAW: /* Dup, cond. in legacy jail case. */ 3454194915Sjamie case PRIV_NET_ROUTE: 3455194915Sjamie case PRIV_NET_TAP: 3456194915Sjamie case PRIV_NET_SETIFMTU: 3457194915Sjamie case PRIV_NET_SETIFFLAGS: 3458194915Sjamie case PRIV_NET_SETIFCAP: 3459194915Sjamie case PRIV_NET_SETIFNAME : 3460194915Sjamie case PRIV_NET_SETIFMETRIC: 3461194915Sjamie case PRIV_NET_SETIFPHYS: 3462194915Sjamie case PRIV_NET_SETIFMAC: 3463194915Sjamie case PRIV_NET_ADDMULTI: 3464194915Sjamie case PRIV_NET_DELMULTI: 3465194915Sjamie case PRIV_NET_HWIOCTL: 3466194915Sjamie case PRIV_NET_SETLLADDR: 3467194915Sjamie case PRIV_NET_ADDIFGROUP: 3468194915Sjamie case PRIV_NET_DELIFGROUP: 3469194915Sjamie case PRIV_NET_IFCREATE: 3470194915Sjamie case PRIV_NET_IFDESTROY: 3471194915Sjamie case PRIV_NET_ADDIFADDR: 3472194915Sjamie case PRIV_NET_DELIFADDR: 3473194915Sjamie case PRIV_NET_LAGG: 3474194915Sjamie case PRIV_NET_GIF: 3475194915Sjamie case PRIV_NET_SETIFVNET: 3476164032Srwatson 3477164032Srwatson /* 3478194915Sjamie * 802.11-related privileges. 3479194915Sjamie */ 3480194915Sjamie case PRIV_NET80211_GETKEY: 3481194915Sjamie#ifdef notyet 3482194915Sjamie case PRIV_NET80211_MANAGE: /* XXX-BZ discuss with sam@ */ 3483194915Sjamie#endif 3484194915Sjamie 3485194915Sjamie#ifdef notyet 3486194915Sjamie /* 3487194915Sjamie * AppleTalk privileges. 3488194915Sjamie */ 3489194915Sjamie case PRIV_NETATALK_RESERVEDPORT: 3490194915Sjamie 3491194915Sjamie /* 3492194915Sjamie * ATM privileges. 3493194915Sjamie */ 3494194915Sjamie case PRIV_NETATM_CFG: 3495194915Sjamie case PRIV_NETATM_ADD: 3496194915Sjamie case PRIV_NETATM_DEL: 3497194915Sjamie case PRIV_NETATM_SET: 3498194915Sjamie 3499194915Sjamie /* 3500194915Sjamie * Bluetooth privileges. 3501194915Sjamie */ 3502194915Sjamie case PRIV_NETBLUETOOTH_RAW: 3503194915Sjamie#endif 3504194915Sjamie 3505194915Sjamie /* 3506194915Sjamie * Netgraph and netgraph module privileges. 3507194915Sjamie */ 3508194915Sjamie case PRIV_NETGRAPH_CONTROL: 3509194915Sjamie#ifdef notyet 3510194915Sjamie case PRIV_NETGRAPH_TTY: 3511194915Sjamie#endif 3512194915Sjamie 3513194915Sjamie /* 3514194915Sjamie * IPv4 and IPv6 privileges. 3515194915Sjamie */ 3516194915Sjamie case PRIV_NETINET_IPFW: 3517194915Sjamie case PRIV_NETINET_DIVERT: 3518194915Sjamie case PRIV_NETINET_PF: 3519194915Sjamie case PRIV_NETINET_DUMMYNET: 3520194915Sjamie case PRIV_NETINET_CARP: 3521194915Sjamie case PRIV_NETINET_MROUTE: 3522194915Sjamie case PRIV_NETINET_RAW: 3523194915Sjamie case PRIV_NETINET_ADDRCTRL6: 3524194915Sjamie case PRIV_NETINET_ND6: 3525194915Sjamie case PRIV_NETINET_SCOPE6: 3526194915Sjamie case PRIV_NETINET_ALIFETIME6: 3527194915Sjamie case PRIV_NETINET_IPSEC: 3528194915Sjamie case PRIV_NETINET_BINDANY: 3529194915Sjamie 3530194915Sjamie#ifdef notyet 3531194915Sjamie /* 3532194915Sjamie * IPX/SPX privileges. 3533194915Sjamie */ 3534194915Sjamie case PRIV_NETIPX_RESERVEDPORT: 3535194915Sjamie case PRIV_NETIPX_RAW: 3536194915Sjamie 3537194915Sjamie /* 3538194915Sjamie * NCP privileges. 3539194915Sjamie */ 3540194915Sjamie case PRIV_NETNCP: 3541194915Sjamie 3542194915Sjamie /* 3543194915Sjamie * SMB privileges. 3544194915Sjamie */ 3545194915Sjamie case PRIV_NETSMB: 3546194915Sjamie#endif 3547194915Sjamie 3548194915Sjamie /* 3549194915Sjamie * No default: or deny here. 3550194915Sjamie * In case of no permit fall through to next switch(). 3551194915Sjamie */ 3552194915Sjamie if (cred->cr_prison->pr_flags & PR_VNET) 3553194915Sjamie return (0); 3554194915Sjamie } 3555194915Sjamie#endif /* VIMAGE */ 3556194915Sjamie 3557194915Sjamie switch (priv) { 3558194915Sjamie 3559194915Sjamie /* 3560164032Srwatson * Allow ktrace privileges for root in jail. 3561164032Srwatson */ 3562164032Srwatson case PRIV_KTRACE: 3563164032Srwatson 3564166827Srwatson#if 0 3565164032Srwatson /* 3566164032Srwatson * Allow jailed processes to configure audit identity and 3567164032Srwatson * submit audit records (login, etc). In the future we may 3568164032Srwatson * want to further refine the relationship between audit and 3569164032Srwatson * jail. 3570164032Srwatson */ 3571164032Srwatson case PRIV_AUDIT_GETAUDIT: 3572164032Srwatson case PRIV_AUDIT_SETAUDIT: 3573164032Srwatson case PRIV_AUDIT_SUBMIT: 3574166827Srwatson#endif 3575164032Srwatson 3576164032Srwatson /* 3577164032Srwatson * Allow jailed processes to manipulate process UNIX 3578164032Srwatson * credentials in any way they see fit. 3579164032Srwatson */ 3580164032Srwatson case PRIV_CRED_SETUID: 3581164032Srwatson case PRIV_CRED_SETEUID: 3582164032Srwatson case PRIV_CRED_SETGID: 3583164032Srwatson case PRIV_CRED_SETEGID: 3584164032Srwatson case PRIV_CRED_SETGROUPS: 3585164032Srwatson case PRIV_CRED_SETREUID: 3586164032Srwatson case PRIV_CRED_SETREGID: 3587164032Srwatson case PRIV_CRED_SETRESUID: 3588164032Srwatson case PRIV_CRED_SETRESGID: 3589164032Srwatson 3590164032Srwatson /* 3591164032Srwatson * Jail implements visibility constraints already, so allow 3592164032Srwatson * jailed root to override uid/gid-based constraints. 3593164032Srwatson */ 3594164032Srwatson case PRIV_SEEOTHERGIDS: 3595164032Srwatson case PRIV_SEEOTHERUIDS: 3596164032Srwatson 3597164032Srwatson /* 3598164032Srwatson * Jail implements inter-process debugging limits already, so 3599164032Srwatson * allow jailed root various debugging privileges. 3600164032Srwatson */ 3601164032Srwatson case PRIV_DEBUG_DIFFCRED: 3602164032Srwatson case PRIV_DEBUG_SUGID: 3603164032Srwatson case PRIV_DEBUG_UNPRIV: 3604164032Srwatson 3605164032Srwatson /* 3606164032Srwatson * Allow jail to set various resource limits and login 3607164032Srwatson * properties, and for now, exceed process resource limits. 3608164032Srwatson */ 3609164032Srwatson case PRIV_PROC_LIMIT: 3610164032Srwatson case PRIV_PROC_SETLOGIN: 3611164032Srwatson case PRIV_PROC_SETRLIMIT: 3612164032Srwatson 3613164032Srwatson /* 3614164032Srwatson * System V and POSIX IPC privileges are granted in jail. 3615164032Srwatson */ 3616164032Srwatson case PRIV_IPC_READ: 3617164032Srwatson case PRIV_IPC_WRITE: 3618164032Srwatson case PRIV_IPC_ADMIN: 3619164032Srwatson case PRIV_IPC_MSGSIZE: 3620164032Srwatson case PRIV_MQ_ADMIN: 3621164032Srwatson 3622164032Srwatson /* 3623192895Sjamie * Jail operations within a jail work on child jails. 3624192895Sjamie */ 3625192895Sjamie case PRIV_JAIL_ATTACH: 3626192895Sjamie case PRIV_JAIL_SET: 3627192895Sjamie case PRIV_JAIL_REMOVE: 3628192895Sjamie 3629192895Sjamie /* 3630164032Srwatson * Jail implements its own inter-process limits, so allow 3631164032Srwatson * root processes in jail to change scheduling on other 3632164032Srwatson * processes in the same jail. Likewise for signalling. 3633164032Srwatson */ 3634164032Srwatson case PRIV_SCHED_DIFFCRED: 3635185435Sbz case PRIV_SCHED_CPUSET: 3636164032Srwatson case PRIV_SIGNAL_DIFFCRED: 3637164032Srwatson case PRIV_SIGNAL_SUGID: 3638164032Srwatson 3639164032Srwatson /* 3640164032Srwatson * Allow jailed processes to write to sysctls marked as jail 3641164032Srwatson * writable. 3642164032Srwatson */ 3643164032Srwatson case PRIV_SYSCTL_WRITEJAIL: 3644164032Srwatson 3645164032Srwatson /* 3646164032Srwatson * Allow root in jail to manage a variety of quota 3647166831Srwatson * properties. These should likely be conditional on a 3648166831Srwatson * configuration option. 3649164032Srwatson */ 3650166832Srwatson case PRIV_VFS_GETQUOTA: 3651166832Srwatson case PRIV_VFS_SETQUOTA: 3652164032Srwatson 3653164032Srwatson /* 3654164032Srwatson * Since Jail relies on chroot() to implement file system 3655164032Srwatson * protections, grant many VFS privileges to root in jail. 3656164032Srwatson * Be careful to exclude mount-related and NFS-related 3657164032Srwatson * privileges. 3658164032Srwatson */ 3659164032Srwatson case PRIV_VFS_READ: 3660164032Srwatson case PRIV_VFS_WRITE: 3661164032Srwatson case PRIV_VFS_ADMIN: 3662164032Srwatson case PRIV_VFS_EXEC: 3663164032Srwatson case PRIV_VFS_LOOKUP: 3664164032Srwatson case PRIV_VFS_BLOCKRESERVE: /* XXXRW: Slightly surprising. */ 3665164032Srwatson case PRIV_VFS_CHFLAGS_DEV: 3666164032Srwatson case PRIV_VFS_CHOWN: 3667164032Srwatson case PRIV_VFS_CHROOT: 3668167152Spjd case PRIV_VFS_RETAINSUGID: 3669164032Srwatson case PRIV_VFS_FCHROOT: 3670164032Srwatson case PRIV_VFS_LINK: 3671164032Srwatson case PRIV_VFS_SETGID: 3672172860Srwatson case PRIV_VFS_STAT: 3673164032Srwatson case PRIV_VFS_STICKYFILE: 3674164032Srwatson return (0); 3675164032Srwatson 3676164032Srwatson /* 3677164032Srwatson * Depending on the global setting, allow privilege of 3678164032Srwatson * setting system flags. 3679164032Srwatson */ 3680164032Srwatson case PRIV_VFS_SYSFLAGS: 3681192895Sjamie if (cred->cr_prison->pr_allow & PR_ALLOW_CHFLAGS) 3682164032Srwatson return (0); 3683164032Srwatson else 3684164032Srwatson return (EPERM); 3685164032Srwatson 3686164032Srwatson /* 3687168396Spjd * Depending on the global setting, allow privilege of 3688168396Spjd * mounting/unmounting file systems. 3689168396Spjd */ 3690168396Spjd case PRIV_VFS_MOUNT: 3691168396Spjd case PRIV_VFS_UNMOUNT: 3692168396Spjd case PRIV_VFS_MOUNT_NONUSER: 3693168699Spjd case PRIV_VFS_MOUNT_OWNER: 3694192895Sjamie if (cred->cr_prison->pr_allow & PR_ALLOW_MOUNT) 3695168396Spjd return (0); 3696168396Spjd else 3697168396Spjd return (EPERM); 3698168396Spjd 3699168396Spjd /* 3700168591Srwatson * Allow jailed root to bind reserved ports and reuse in-use 3701168591Srwatson * ports. 3702164032Srwatson */ 3703164032Srwatson case PRIV_NETINET_RESERVEDPORT: 3704168591Srwatson case PRIV_NETINET_REUSEPORT: 3705164032Srwatson return (0); 3706164032Srwatson 3707164032Srwatson /* 3708175630Sbz * Allow jailed root to set certian IPv4/6 (option) headers. 3709175630Sbz */ 3710175630Sbz case PRIV_NETINET_SETHDROPTS: 3711175630Sbz return (0); 3712175630Sbz 3713175630Sbz /* 3714164032Srwatson * Conditionally allow creating raw sockets in jail. 3715164032Srwatson */ 3716164032Srwatson case PRIV_NETINET_RAW: 3717192895Sjamie if (cred->cr_prison->pr_allow & PR_ALLOW_RAW_SOCKETS) 3718164032Srwatson return (0); 3719164032Srwatson else 3720164032Srwatson return (EPERM); 3721164032Srwatson 3722164032Srwatson /* 3723164032Srwatson * Since jail implements its own visibility limits on netstat 3724164032Srwatson * sysctls, allow getcred. This allows identd to work in 3725164032Srwatson * jail. 3726164032Srwatson */ 3727164032Srwatson case PRIV_NETINET_GETCRED: 3728164032Srwatson return (0); 3729164032Srwatson 3730164032Srwatson default: 3731164032Srwatson /* 3732164032Srwatson * In all remaining cases, deny the privilege request. This 3733164032Srwatson * includes almost all network privileges, many system 3734164032Srwatson * configuration privileges. 3735164032Srwatson */ 3736164032Srwatson return (EPERM); 3737164032Srwatson } 3738164032Srwatson} 3739164032Srwatson 3740192895Sjamie/* 3741192895Sjamie * Return the part of pr2's name that is relative to pr1, or the whole name 3742192895Sjamie * if it does not directly follow. 3743192895Sjamie */ 3744192895Sjamie 3745192895Sjamiechar * 3746192895Sjamieprison_name(struct prison *pr1, struct prison *pr2) 3747192895Sjamie{ 3748192895Sjamie char *name; 3749192895Sjamie 3750192895Sjamie /* Jails see themselves as "0" (if they see themselves at all). */ 3751192895Sjamie if (pr1 == pr2) 3752192895Sjamie return "0"; 3753192895Sjamie name = pr2->pr_name; 3754192895Sjamie if (prison_ischild(pr1, pr2)) { 3755192895Sjamie /* 3756192895Sjamie * pr1 isn't locked (and allprison_lock may not be either) 3757192895Sjamie * so its length can't be counted on. But the number of dots 3758192895Sjamie * can be counted on - and counted. 3759192895Sjamie */ 3760192895Sjamie for (; pr1 != &prison0; pr1 = pr1->pr_parent) 3761192895Sjamie name = strchr(name, '.') + 1; 3762192895Sjamie } 3763192895Sjamie return (name); 3764192895Sjamie} 3765192895Sjamie 3766192895Sjamie/* 3767192895Sjamie * Return the part of pr2's path that is relative to pr1, or the whole path 3768192895Sjamie * if it does not directly follow. 3769192895Sjamie */ 3770192895Sjamiestatic char * 3771192895Sjamieprison_path(struct prison *pr1, struct prison *pr2) 3772192895Sjamie{ 3773192895Sjamie char *path1, *path2; 3774192895Sjamie int len1; 3775192895Sjamie 3776192895Sjamie path1 = pr1->pr_path; 3777192895Sjamie path2 = pr2->pr_path; 3778192895Sjamie if (!strcmp(path1, "/")) 3779192895Sjamie return (path2); 3780192895Sjamie len1 = strlen(path1); 3781192895Sjamie if (strncmp(path1, path2, len1)) 3782192895Sjamie return (path2); 3783192895Sjamie if (path2[len1] == '\0') 3784192895Sjamie return "/"; 3785192895Sjamie if (path2[len1] == '/') 3786192895Sjamie return (path2 + len1); 3787192895Sjamie return (path2); 3788192895Sjamie} 3789192895Sjamie 3790192895Sjamie 3791192895Sjamie/* 3792192895Sjamie * Jail-related sysctls. 3793192895Sjamie */ 3794192895SjamieSYSCTL_NODE(_security, OID_AUTO, jail, CTLFLAG_RW, 0, 3795192895Sjamie "Jails"); 3796192895Sjamie 3797113275Smikestatic int 3798113275Smikesysctl_jail_list(SYSCTL_HANDLER_ARGS) 3799113275Smike{ 3800191673Sjamie struct xprison *xp; 3801192895Sjamie struct prison *pr, *cpr; 3802191673Sjamie#ifdef INET 3803191673Sjamie struct in_addr *ip4 = NULL; 3804191673Sjamie int ip4s = 0; 3805191673Sjamie#endif 3806191673Sjamie#ifdef INET6 3807191673Sjamie struct in_addr *ip6 = NULL; 3808191673Sjamie int ip6s = 0; 3809191673Sjamie#endif 3810192895Sjamie int descend, error; 3811113275Smike 3812191673Sjamie xp = malloc(sizeof(*xp), M_TEMP, M_WAITOK); 3813192895Sjamie pr = req->td->td_ucred->cr_prison; 3814191673Sjamie error = 0; 3815168401Spjd sx_slock(&allprison_lock); 3816192895Sjamie FOREACH_PRISON_DESCENDANT(pr, cpr, descend) { 3817192895Sjamie#if defined(INET) || defined(INET6) 3818191673Sjamie again: 3819192895Sjamie#endif 3820192895Sjamie mtx_lock(&cpr->pr_mtx); 3821185435Sbz#ifdef INET 3822192895Sjamie if (cpr->pr_ip4s > 0) { 3823192895Sjamie if (ip4s < cpr->pr_ip4s) { 3824192895Sjamie ip4s = cpr->pr_ip4s; 3825192895Sjamie mtx_unlock(&cpr->pr_mtx); 3826191673Sjamie ip4 = realloc(ip4, ip4s * 3827191673Sjamie sizeof(struct in_addr), M_TEMP, M_WAITOK); 3828191673Sjamie goto again; 3829191673Sjamie } 3830192895Sjamie bcopy(cpr->pr_ip4, ip4, 3831192895Sjamie cpr->pr_ip4s * sizeof(struct in_addr)); 3832191673Sjamie } 3833185435Sbz#endif 3834185435Sbz#ifdef INET6 3835192895Sjamie if (cpr->pr_ip6s > 0) { 3836192895Sjamie if (ip6s < cpr->pr_ip6s) { 3837192895Sjamie ip6s = cpr->pr_ip6s; 3838192895Sjamie mtx_unlock(&cpr->pr_mtx); 3839191673Sjamie ip6 = realloc(ip6, ip6s * 3840191673Sjamie sizeof(struct in6_addr), M_TEMP, M_WAITOK); 3841191673Sjamie goto again; 3842191673Sjamie } 3843192895Sjamie bcopy(cpr->pr_ip6, ip6, 3844192895Sjamie cpr->pr_ip6s * sizeof(struct in6_addr)); 3845191673Sjamie } 3846185435Sbz#endif 3847192895Sjamie if (cpr->pr_ref == 0) { 3848192895Sjamie mtx_unlock(&cpr->pr_mtx); 3849191673Sjamie continue; 3850191673Sjamie } 3851191673Sjamie bzero(xp, sizeof(*xp)); 3852113275Smike xp->pr_version = XPRISON_VERSION; 3853192895Sjamie xp->pr_id = cpr->pr_id; 3854192895Sjamie xp->pr_state = cpr->pr_uref > 0 3855191673Sjamie ? PRISON_STATE_ALIVE : PRISON_STATE_DYING; 3856192895Sjamie strlcpy(xp->pr_path, prison_path(pr, cpr), sizeof(xp->pr_path)); 3857194118Sjamie strlcpy(xp->pr_host, cpr->pr_hostname, sizeof(xp->pr_host)); 3858192895Sjamie strlcpy(xp->pr_name, prison_name(pr, cpr), sizeof(xp->pr_name)); 3859185435Sbz#ifdef INET 3860192895Sjamie xp->pr_ip4s = cpr->pr_ip4s; 3861185435Sbz#endif 3862185435Sbz#ifdef INET6 3863192895Sjamie xp->pr_ip6s = cpr->pr_ip6s; 3864185435Sbz#endif 3865192895Sjamie mtx_unlock(&cpr->pr_mtx); 3866191673Sjamie error = SYSCTL_OUT(req, xp, sizeof(*xp)); 3867191673Sjamie if (error) 3868191673Sjamie break; 3869185435Sbz#ifdef INET 3870191673Sjamie if (xp->pr_ip4s > 0) { 3871191673Sjamie error = SYSCTL_OUT(req, ip4, 3872191673Sjamie xp->pr_ip4s * sizeof(struct in_addr)); 3873191673Sjamie if (error) 3874191673Sjamie break; 3875185435Sbz } 3876185435Sbz#endif 3877185435Sbz#ifdef INET6 3878191673Sjamie if (xp->pr_ip6s > 0) { 3879191673Sjamie error = SYSCTL_OUT(req, ip6, 3880191673Sjamie xp->pr_ip6s * sizeof(struct in6_addr)); 3881191673Sjamie if (error) 3882191673Sjamie break; 3883185435Sbz } 3884185435Sbz#endif 3885113275Smike } 3886168401Spjd sx_sunlock(&allprison_lock); 3887191673Sjamie free(xp, M_TEMP); 3888191673Sjamie#ifdef INET 3889191673Sjamie free(ip4, M_TEMP); 3890191673Sjamie#endif 3891191673Sjamie#ifdef INET6 3892191673Sjamie free(ip6, M_TEMP); 3893191673Sjamie#endif 3894167354Spjd return (error); 3895113275Smike} 3896113275Smike 3897187864SedSYSCTL_OID(_security_jail, OID_AUTO, list, 3898187864Sed CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 0, 3899187864Sed sysctl_jail_list, "S", "List of active jails"); 3900126004Spjd 3901126004Spjdstatic int 3902126004Spjdsysctl_jail_jailed(SYSCTL_HANDLER_ARGS) 3903126004Spjd{ 3904126004Spjd int error, injail; 3905126004Spjd 3906126004Spjd injail = jailed(req->td->td_ucred); 3907126004Spjd error = SYSCTL_OUT(req, &injail, sizeof(injail)); 3908126004Spjd 3909126004Spjd return (error); 3910126004Spjd} 3911192895Sjamie 3912187864SedSYSCTL_PROC(_security_jail, OID_AUTO, jailed, 3913187864Sed CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 0, 3914187864Sed sysctl_jail_jailed, "I", "Process in jail?"); 3915185435Sbz 3916192895Sjamie#if defined(INET) || defined(INET6) 3917193865SjamieSYSCTL_UINT(_security_jail, OID_AUTO, jail_max_af_ips, CTLFLAG_RW, 3918192895Sjamie &jail_max_af_ips, 0, 3919192895Sjamie "Number of IP addresses a jail may have at most per address family"); 3920192895Sjamie#endif 3921192895Sjamie 3922192895Sjamie/* 3923192895Sjamie * Default parameters for jail(2) compatability. For historical reasons, 3924192895Sjamie * the sysctl names have varying similarity to the parameter names. Prisons 3925192895Sjamie * just see their own parameters, and can't change them. 3926192895Sjamie */ 3927192895Sjamiestatic int 3928192895Sjamiesysctl_jail_default_allow(SYSCTL_HANDLER_ARGS) 3929192895Sjamie{ 3930192895Sjamie struct prison *pr; 3931192895Sjamie int allow, error, i; 3932192895Sjamie 3933192895Sjamie pr = req->td->td_ucred->cr_prison; 3934192895Sjamie allow = (pr == &prison0) ? jail_default_allow : pr->pr_allow; 3935192895Sjamie 3936192895Sjamie /* Get the current flag value, and convert it to a boolean. */ 3937192895Sjamie i = (allow & arg2) ? 1 : 0; 3938192895Sjamie if (arg1 != NULL) 3939192895Sjamie i = !i; 3940192895Sjamie error = sysctl_handle_int(oidp, &i, 0, req); 3941192895Sjamie if (error || !req->newptr) 3942192895Sjamie return (error); 3943192895Sjamie i = i ? arg2 : 0; 3944192895Sjamie if (arg1 != NULL) 3945192895Sjamie i ^= arg2; 3946192895Sjamie /* 3947192895Sjamie * The sysctls don't have CTLFLAGS_PRISON, so assume prison0 3948192895Sjamie * for writing. 3949192895Sjamie */ 3950192895Sjamie mtx_lock(&prison0.pr_mtx); 3951192895Sjamie jail_default_allow = (jail_default_allow & ~arg2) | i; 3952192895Sjamie mtx_unlock(&prison0.pr_mtx); 3953192895Sjamie return (0); 3954192895Sjamie} 3955192895Sjamie 3956192895SjamieSYSCTL_PROC(_security_jail, OID_AUTO, set_hostname_allowed, 3957192895Sjamie CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, 3958192895Sjamie NULL, PR_ALLOW_SET_HOSTNAME, sysctl_jail_default_allow, "I", 3959192895Sjamie "Processes in jail can set their hostnames"); 3960192895SjamieSYSCTL_PROC(_security_jail, OID_AUTO, socket_unixiproute_only, 3961192895Sjamie CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, 3962192895Sjamie (void *)1, PR_ALLOW_SOCKET_AF, sysctl_jail_default_allow, "I", 3963192895Sjamie "Processes in jail are limited to creating UNIX/IP/route sockets only"); 3964192895SjamieSYSCTL_PROC(_security_jail, OID_AUTO, sysvipc_allowed, 3965192895Sjamie CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, 3966192895Sjamie NULL, PR_ALLOW_SYSVIPC, sysctl_jail_default_allow, "I", 3967192895Sjamie "Processes in jail can use System V IPC primitives"); 3968192895SjamieSYSCTL_PROC(_security_jail, OID_AUTO, allow_raw_sockets, 3969192895Sjamie CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, 3970192895Sjamie NULL, PR_ALLOW_RAW_SOCKETS, sysctl_jail_default_allow, "I", 3971192895Sjamie "Prison root can create raw sockets"); 3972192895SjamieSYSCTL_PROC(_security_jail, OID_AUTO, chflags_allowed, 3973192895Sjamie CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, 3974192895Sjamie NULL, PR_ALLOW_CHFLAGS, sysctl_jail_default_allow, "I", 3975192895Sjamie "Processes in jail can alter system file flags"); 3976192895SjamieSYSCTL_PROC(_security_jail, OID_AUTO, mount_allowed, 3977192895Sjamie CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, 3978192895Sjamie NULL, PR_ALLOW_MOUNT, sysctl_jail_default_allow, "I", 3979192895Sjamie "Processes in jail can mount/unmount jail-friendly file systems"); 3980192895Sjamie 3981192895Sjamiestatic int 3982192895Sjamiesysctl_jail_default_level(SYSCTL_HANDLER_ARGS) 3983192895Sjamie{ 3984192895Sjamie struct prison *pr; 3985192895Sjamie int level, error; 3986192895Sjamie 3987192895Sjamie pr = req->td->td_ucred->cr_prison; 3988192895Sjamie level = (pr == &prison0) ? *(int *)arg1 : *(int *)((char *)pr + arg2); 3989192895Sjamie error = sysctl_handle_int(oidp, &level, 0, req); 3990192895Sjamie if (error || !req->newptr) 3991192895Sjamie return (error); 3992192895Sjamie *(int *)arg1 = level; 3993192895Sjamie return (0); 3994192895Sjamie} 3995192895Sjamie 3996192895SjamieSYSCTL_PROC(_security_jail, OID_AUTO, enforce_statfs, 3997192895Sjamie CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, 3998192895Sjamie &jail_default_enforce_statfs, offsetof(struct prison, pr_enforce_statfs), 3999192895Sjamie sysctl_jail_default_level, "I", 4000192895Sjamie "Processes in jail cannot see all mounted file systems"); 4001192895Sjamie 4002192895Sjamie/* 4003192895Sjamie * Nodes to describe jail parameters. Maximum length of string parameters 4004192895Sjamie * is returned in the string itself, and the other parameters exist merely 4005192895Sjamie * to make themselves and their types known. 4006192895Sjamie */ 4007192895SjamieSYSCTL_NODE(_security_jail, OID_AUTO, param, CTLFLAG_RW, 0, 4008192895Sjamie "Jail parameters"); 4009192895Sjamie 4010192895Sjamieint 4011192895Sjamiesysctl_jail_param(SYSCTL_HANDLER_ARGS) 4012192895Sjamie{ 4013192895Sjamie int i; 4014192895Sjamie long l; 4015192895Sjamie size_t s; 4016192895Sjamie char numbuf[12]; 4017192895Sjamie 4018192895Sjamie switch (oidp->oid_kind & CTLTYPE) 4019192895Sjamie { 4020192895Sjamie case CTLTYPE_LONG: 4021192895Sjamie case CTLTYPE_ULONG: 4022192895Sjamie l = 0; 4023192895Sjamie#ifdef SCTL_MASK32 4024192895Sjamie if (!(req->flags & SCTL_MASK32)) 4025192895Sjamie#endif 4026192895Sjamie return (SYSCTL_OUT(req, &l, sizeof(l))); 4027192895Sjamie case CTLTYPE_INT: 4028192895Sjamie case CTLTYPE_UINT: 4029192895Sjamie i = 0; 4030192895Sjamie return (SYSCTL_OUT(req, &i, sizeof(i))); 4031192895Sjamie case CTLTYPE_STRING: 4032192895Sjamie snprintf(numbuf, sizeof(numbuf), "%d", arg2); 4033192895Sjamie return 4034192895Sjamie (sysctl_handle_string(oidp, numbuf, sizeof(numbuf), req)); 4035192895Sjamie case CTLTYPE_STRUCT: 4036192895Sjamie s = (size_t)arg2; 4037192895Sjamie return (SYSCTL_OUT(req, &s, sizeof(s))); 4038192895Sjamie } 4039192895Sjamie return (0); 4040192895Sjamie} 4041192895Sjamie 4042192895SjamieSYSCTL_JAIL_PARAM(, jid, CTLTYPE_INT | CTLFLAG_RDTUN, "I", "Jail ID"); 4043192895SjamieSYSCTL_JAIL_PARAM(, parent, CTLTYPE_INT | CTLFLAG_RD, "I", "Jail parent ID"); 4044192895SjamieSYSCTL_JAIL_PARAM_STRING(, name, CTLFLAG_RW, MAXHOSTNAMELEN, "Jail name"); 4045192895SjamieSYSCTL_JAIL_PARAM_STRING(, path, CTLFLAG_RDTUN, MAXPATHLEN, "Jail root path"); 4046192895SjamieSYSCTL_JAIL_PARAM(, securelevel, CTLTYPE_INT | CTLFLAG_RW, 4047192895Sjamie "I", "Jail secure level"); 4048192895SjamieSYSCTL_JAIL_PARAM(, enforce_statfs, CTLTYPE_INT | CTLFLAG_RW, 4049192895Sjamie "I", "Jail cannot see all mounted file systems"); 4050192895SjamieSYSCTL_JAIL_PARAM(, persist, CTLTYPE_INT | CTLFLAG_RW, 4051192895Sjamie "B", "Jail persistence"); 4052194251Sjamie#ifdef VIMAGE 4053194251SjamieSYSCTL_JAIL_PARAM(, vnet, CTLTYPE_INT | CTLFLAG_RDTUN, 4054195870Sjamie "E,jailsys", "Virtual network stack"); 4055194251Sjamie#endif 4056192895SjamieSYSCTL_JAIL_PARAM(, dying, CTLTYPE_INT | CTLFLAG_RD, 4057192895Sjamie "B", "Jail is in the process of shutting down"); 4058192895Sjamie 4059194762SjamieSYSCTL_JAIL_PARAM_NODE(children, "Number of child jails"); 4060194762SjamieSYSCTL_JAIL_PARAM(_children, cur, CTLTYPE_INT | CTLFLAG_RD, 4061194762Sjamie "I", "Current number of child jails"); 4062194762SjamieSYSCTL_JAIL_PARAM(_children, max, CTLTYPE_INT | CTLFLAG_RW, 4063194762Sjamie "I", "Maximum number of child jails"); 4064194762Sjamie 4065195870SjamieSYSCTL_JAIL_PARAM_SYS_NODE(host, CTLFLAG_RW, "Jail host info"); 4066192895SjamieSYSCTL_JAIL_PARAM_STRING(_host, hostname, CTLFLAG_RW, MAXHOSTNAMELEN, 4067192895Sjamie "Jail hostname"); 4068193066SjamieSYSCTL_JAIL_PARAM_STRING(_host, domainname, CTLFLAG_RW, MAXHOSTNAMELEN, 4069193066Sjamie "Jail NIS domainname"); 4070193066SjamieSYSCTL_JAIL_PARAM_STRING(_host, hostuuid, CTLFLAG_RW, HOSTUUIDLEN, 4071193066Sjamie "Jail host UUID"); 4072193066SjamieSYSCTL_JAIL_PARAM(_host, hostid, CTLTYPE_ULONG | CTLFLAG_RW, 4073193066Sjamie "LU", "Jail host ID"); 4074192895Sjamie 4075192895SjamieSYSCTL_JAIL_PARAM_NODE(cpuset, "Jail cpuset"); 4076192895SjamieSYSCTL_JAIL_PARAM(_cpuset, id, CTLTYPE_INT | CTLFLAG_RD, "I", "Jail cpuset ID"); 4077192895Sjamie 4078192895Sjamie#ifdef INET 4079195974SjamieSYSCTL_JAIL_PARAM_SYS_NODE(ip4, CTLFLAG_RDTUN, 4080195974Sjamie "Jail IPv4 address virtualization"); 4081192895SjamieSYSCTL_JAIL_PARAM_STRUCT(_ip4, addr, CTLFLAG_RW, sizeof(struct in_addr), 4082192895Sjamie "S,in_addr,a", "Jail IPv4 addresses"); 4083192895Sjamie#endif 4084192895Sjamie#ifdef INET6 4085195974SjamieSYSCTL_JAIL_PARAM_SYS_NODE(ip6, CTLFLAG_RDTUN, 4086195974Sjamie "Jail IPv6 address virtualization"); 4087192895SjamieSYSCTL_JAIL_PARAM_STRUCT(_ip6, addr, CTLFLAG_RW, sizeof(struct in6_addr), 4088192895Sjamie "S,in6_addr,a", "Jail IPv6 addresses"); 4089192895Sjamie#endif 4090192895Sjamie 4091192895SjamieSYSCTL_JAIL_PARAM_NODE(allow, "Jail permission flags"); 4092192895SjamieSYSCTL_JAIL_PARAM(_allow, set_hostname, CTLTYPE_INT | CTLFLAG_RW, 4093192895Sjamie "B", "Jail may set hostname"); 4094192895SjamieSYSCTL_JAIL_PARAM(_allow, sysvipc, CTLTYPE_INT | CTLFLAG_RW, 4095192895Sjamie "B", "Jail may use SYSV IPC"); 4096192895SjamieSYSCTL_JAIL_PARAM(_allow, raw_sockets, CTLTYPE_INT | CTLFLAG_RW, 4097192895Sjamie "B", "Jail may create raw sockets"); 4098192895SjamieSYSCTL_JAIL_PARAM(_allow, chflags, CTLTYPE_INT | CTLFLAG_RW, 4099192895Sjamie "B", "Jail may alter system file flags"); 4100192895SjamieSYSCTL_JAIL_PARAM(_allow, mount, CTLTYPE_INT | CTLFLAG_RW, 4101192895Sjamie "B", "Jail may mount/unmount jail-friendly file systems"); 4102192895SjamieSYSCTL_JAIL_PARAM(_allow, quotas, CTLTYPE_INT | CTLFLAG_RW, 4103192895Sjamie "B", "Jail may set file quotas"); 4104192895SjamieSYSCTL_JAIL_PARAM(_allow, socket_af, CTLTYPE_INT | CTLFLAG_RW, 4105192895Sjamie "B", "Jail may create sockets other than just UNIX/IPv4/IPv6/route"); 4106192895Sjamie 4107192895Sjamie 4108185435Sbz#ifdef DDB 4109191673Sjamie 4110191673Sjamiestatic void 4111191673Sjamiedb_show_prison(struct prison *pr) 4112185435Sbz{ 4113192895Sjamie int fi; 4114191673Sjamie#if defined(INET) || defined(INET6) 4115191673Sjamie int ii; 4116185435Sbz#endif 4117195870Sjamie unsigned jsf; 4118185435Sbz#ifdef INET6 4119185435Sbz char ip6buf[INET6_ADDRSTRLEN]; 4120185435Sbz#endif 4121185435Sbz 4122191673Sjamie db_printf("prison %p:\n", pr); 4123191673Sjamie db_printf(" jid = %d\n", pr->pr_id); 4124191673Sjamie db_printf(" name = %s\n", pr->pr_name); 4125192895Sjamie db_printf(" parent = %p\n", pr->pr_parent); 4126191673Sjamie db_printf(" ref = %d\n", pr->pr_ref); 4127191673Sjamie db_printf(" uref = %d\n", pr->pr_uref); 4128191673Sjamie db_printf(" path = %s\n", pr->pr_path); 4129191673Sjamie db_printf(" cpuset = %d\n", pr->pr_cpuset 4130191673Sjamie ? pr->pr_cpuset->cs_id : -1); 4131194251Sjamie#ifdef VIMAGE 4132194251Sjamie db_printf(" vnet = %p\n", pr->pr_vnet); 4133194251Sjamie#endif 4134191673Sjamie db_printf(" root = %p\n", pr->pr_root); 4135191673Sjamie db_printf(" securelevel = %d\n", pr->pr_securelevel); 4136194762Sjamie db_printf(" childcount = %d\n", pr->pr_childcount); 4137192895Sjamie db_printf(" child = %p\n", LIST_FIRST(&pr->pr_children)); 4138192895Sjamie db_printf(" sibling = %p\n", LIST_NEXT(pr, pr_sibling)); 4139191673Sjamie db_printf(" flags = %x", pr->pr_flags); 4140192895Sjamie for (fi = 0; fi < sizeof(pr_flag_names) / sizeof(pr_flag_names[0]); 4141192895Sjamie fi++) 4142192895Sjamie if (pr_flag_names[fi] != NULL && (pr->pr_flags & (1 << fi))) 4143192895Sjamie db_printf(" %s", pr_flag_names[fi]); 4144195870Sjamie for (fi = 0; fi < sizeof(pr_flag_jailsys) / sizeof(pr_flag_jailsys[0]); 4145195870Sjamie fi++) { 4146195870Sjamie jsf = pr->pr_flags & 4147195870Sjamie (pr_flag_jailsys[fi].disable | pr_flag_jailsys[fi].new); 4148195870Sjamie db_printf(" %-16s= %s\n", pr_flag_jailsys[fi].name, 4149195870Sjamie pr_flag_jailsys[fi].disable && 4150195870Sjamie (jsf == pr_flag_jailsys[fi].disable) ? "disable" 4151195870Sjamie : (jsf == pr_flag_jailsys[fi].new) ? "new" 4152195870Sjamie : "inherit"); 4153195870Sjamie } 4154192895Sjamie db_printf(" allow = %x", pr->pr_allow); 4155192895Sjamie for (fi = 0; fi < sizeof(pr_allow_names) / sizeof(pr_allow_names[0]); 4156192895Sjamie fi++) 4157192895Sjamie if (pr_allow_names[fi] != NULL && (pr->pr_allow & (1 << fi))) 4158192895Sjamie db_printf(" %s", pr_allow_names[fi]); 4159191673Sjamie db_printf("\n"); 4160192895Sjamie db_printf(" enforce_statfs = %d\n", pr->pr_enforce_statfs); 4161194118Sjamie db_printf(" host.hostname = %s\n", pr->pr_hostname); 4162194118Sjamie db_printf(" host.domainname = %s\n", pr->pr_domainname); 4163194118Sjamie db_printf(" host.hostuuid = %s\n", pr->pr_hostuuid); 4164193066Sjamie db_printf(" host.hostid = %lu\n", pr->pr_hostid); 4165185435Sbz#ifdef INET 4166191673Sjamie db_printf(" ip4s = %d\n", pr->pr_ip4s); 4167191673Sjamie for (ii = 0; ii < pr->pr_ip4s; ii++) 4168191673Sjamie db_printf(" %s %s\n", 4169191673Sjamie ii == 0 ? "ip4 =" : " ", 4170191673Sjamie inet_ntoa(pr->pr_ip4[ii])); 4171185435Sbz#endif 4172185435Sbz#ifdef INET6 4173191673Sjamie db_printf(" ip6s = %d\n", pr->pr_ip6s); 4174191673Sjamie for (ii = 0; ii < pr->pr_ip6s; ii++) 4175191673Sjamie db_printf(" %s %s\n", 4176191673Sjamie ii == 0 ? "ip6 =" : " ", 4177191673Sjamie ip6_sprintf(ip6buf, &pr->pr_ip6[ii])); 4178191673Sjamie#endif 4179191673Sjamie} 4180191673Sjamie 4181191673SjamieDB_SHOW_COMMAND(prison, db_show_prison_command) 4182191673Sjamie{ 4183191673Sjamie struct prison *pr; 4184191673Sjamie 4185191673Sjamie if (!have_addr) { 4186192895Sjamie /* 4187192895Sjamie * Show all prisons in the list, and prison0 which is not 4188192895Sjamie * listed. 4189192895Sjamie */ 4190192895Sjamie db_show_prison(&prison0); 4191192895Sjamie if (!db_pager_quit) { 4192192895Sjamie TAILQ_FOREACH(pr, &allprison, pr_list) { 4193192895Sjamie db_show_prison(pr); 4194192895Sjamie if (db_pager_quit) 4195192895Sjamie break; 4196192895Sjamie } 4197191673Sjamie } 4198191673Sjamie return; 4199191673Sjamie } 4200191673Sjamie 4201192895Sjamie if (addr == 0) 4202192895Sjamie pr = &prison0; 4203192895Sjamie else { 4204192895Sjamie /* Look for a prison with the ID and with references. */ 4205191673Sjamie TAILQ_FOREACH(pr, &allprison, pr_list) 4206192895Sjamie if (pr->pr_id == addr && pr->pr_ref > 0) 4207191673Sjamie break; 4208192895Sjamie if (pr == NULL) 4209192895Sjamie /* Look again, without requiring a reference. */ 4210192895Sjamie TAILQ_FOREACH(pr, &allprison, pr_list) 4211192895Sjamie if (pr->pr_id == addr) 4212192895Sjamie break; 4213192895Sjamie if (pr == NULL) 4214192895Sjamie /* Assume address points to a valid prison. */ 4215192895Sjamie pr = (struct prison *)addr; 4216192895Sjamie } 4217191673Sjamie db_show_prison(pr); 4218185435Sbz} 4219191673Sjamie 4220185435Sbz#endif /* DDB */ 4221