kern_jail.c revision 193066
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 193066 2009-05-29 21:27:12Z jamie $"); 31116182Sobrien 32193066Sjamie#include "opt_compat.h" 33185435Sbz#include "opt_ddb.h" 34185435Sbz#include "opt_inet.h" 35185435Sbz#include "opt_inet6.h" 36131177Spjd#include "opt_mac.h" 37131177Spjd 3846155Sphk#include <sys/param.h> 3946155Sphk#include <sys/types.h> 4046155Sphk#include <sys/kernel.h> 4146155Sphk#include <sys/systm.h> 4246155Sphk#include <sys/errno.h> 4346155Sphk#include <sys/sysproto.h> 4446155Sphk#include <sys/malloc.h> 45192895Sjamie#include <sys/osd.h> 46164032Srwatson#include <sys/priv.h> 4746155Sphk#include <sys/proc.h> 48124882Srwatson#include <sys/taskqueue.h> 49177785Skib#include <sys/fcntl.h> 5046155Sphk#include <sys/jail.h> 5187275Srwatson#include <sys/lock.h> 5287275Srwatson#include <sys/mutex.h> 53168401Spjd#include <sys/sx.h> 54193066Sjamie#include <sys/sysent.h> 55113275Smike#include <sys/namei.h> 56147185Spjd#include <sys/mount.h> 57113275Smike#include <sys/queue.h> 5846155Sphk#include <sys/socket.h> 59113275Smike#include <sys/syscallsubr.h> 6057163Srwatson#include <sys/sysctl.h> 61113275Smike#include <sys/vnode.h> 62181803Sbz#include <sys/vimage.h> 6346155Sphk#include <net/if.h> 6446155Sphk#include <netinet/in.h> 65185435Sbz#ifdef DDB 66185435Sbz#include <ddb/ddb.h> 67185435Sbz#ifdef INET6 68185435Sbz#include <netinet6/in6_var.h> 69185435Sbz#endif /* INET6 */ 70185435Sbz#endif /* DDB */ 7146155Sphk 72163606Srwatson#include <security/mac/mac_framework.h> 73163606Srwatson 7446155SphkMALLOC_DEFINE(M_PRISON, "prison", "Prison structures"); 7546155Sphk 76192895Sjamie/* prison0 describes what is "real" about the system. */ 77192895Sjamiestruct prison prison0 = { 78192895Sjamie .pr_id = 0, 79192895Sjamie .pr_name = "0", 80192895Sjamie .pr_ref = 1, 81192895Sjamie .pr_uref = 1, 82192895Sjamie .pr_path = "/", 83192895Sjamie .pr_securelevel = -1, 84193066Sjamie .pr_uuid = "00000000-0000-0000-0000-000000000000", 85192895Sjamie .pr_children = LIST_HEAD_INITIALIZER(&prison0.pr_children), 86193066Sjamie .pr_flags = PR_HOST, 87192895Sjamie .pr_allow = PR_ALLOW_ALL, 88192895Sjamie}; 89192895SjamieMTX_SYSINIT(prison0, &prison0.pr_mtx, "jail mutex", MTX_DEF); 9057163Srwatson 91192895Sjamie/* allprison and lastprid are protected by allprison_lock. */ 92168401Spjdstruct sx allprison_lock; 93191673SjamieSX_SYSINIT(allprison_lock, &allprison_lock, "allprison"); 94191673Sjamiestruct prisonlist allprison = TAILQ_HEAD_INITIALIZER(allprison); 95179881Sdelphijint lastprid = 0; 96113275Smike 97191673Sjamiestatic int do_jail_attach(struct thread *td, struct prison *pr); 98190466Sjamiestatic void prison_complete(void *context, int pending); 99191673Sjamiestatic void prison_deref(struct prison *pr, int flags); 100192895Sjamiestatic char *prison_path(struct prison *pr1, struct prison *pr2); 101192895Sjamiestatic void prison_remove_one(struct prison *pr); 102185435Sbz#ifdef INET 103190466Sjamiestatic int _prison_check_ip4(struct prison *pr, struct in_addr *ia); 104192895Sjamiestatic int prison_restrict_ip4(struct prison *pr, struct in_addr *newip4); 105185435Sbz#endif 106185435Sbz#ifdef INET6 107190466Sjamiestatic int _prison_check_ip6(struct prison *pr, struct in6_addr *ia6); 108192895Sjamiestatic int prison_restrict_ip6(struct prison *pr, struct in6_addr *newip6); 109185435Sbz#endif 110113275Smike 111191673Sjamie/* Flags for prison_deref */ 112191673Sjamie#define PD_DEREF 0x01 113191673Sjamie#define PD_DEUREF 0x02 114191673Sjamie#define PD_LOCKED 0x04 115191673Sjamie#define PD_LIST_SLOCKED 0x08 116191673Sjamie#define PD_LIST_XLOCKED 0x10 117113275Smike 118192895Sjamie/* 119192895Sjamie * Parameter names corresponding to PR_* flag values 120192895Sjamie */ 121192895Sjamiestatic char *pr_flag_names[] = { 122192895Sjamie [0] = "persist", 123193066Sjamie "host", 124185435Sbz#ifdef INET 125193066Sjamie "ip4", 126192895Sjamie#endif 127192895Sjamie#ifdef INET6 128192895Sjamie [3] = "ip6", 129192895Sjamie#endif 130192895Sjamie}; 131192895Sjamie 132192895Sjamiestatic char *pr_flag_nonames[] = { 133192895Sjamie [0] = "nopersist", 134193066Sjamie "nohost", 135192895Sjamie#ifdef INET 136193066Sjamie "noip4", 137192895Sjamie#endif 138192895Sjamie#ifdef INET6 139192895Sjamie [3] = "noip6", 140192895Sjamie#endif 141192895Sjamie}; 142192895Sjamie 143192895Sjamiestatic char *pr_allow_names[] = { 144192895Sjamie "allow.set_hostname", 145192895Sjamie "allow.sysvipc", 146192895Sjamie "allow.raw_sockets", 147192895Sjamie "allow.chflags", 148192895Sjamie "allow.mount", 149192895Sjamie "allow.quotas", 150192895Sjamie "allow.jails", 151192895Sjamie "allow.socket_af", 152192895Sjamie}; 153192895Sjamie 154192895Sjamiestatic char *pr_allow_nonames[] = { 155192895Sjamie "allow.noset_hostname", 156192895Sjamie "allow.nosysvipc", 157192895Sjamie "allow.noraw_sockets", 158192895Sjamie "allow.nochflags", 159192895Sjamie "allow.nomount", 160192895Sjamie "allow.noquotas", 161192895Sjamie "allow.nojails", 162192895Sjamie "allow.nosocket_af", 163192895Sjamie}; 164192895Sjamie 165192895Sjamie#define JAIL_DEFAULT_ALLOW PR_ALLOW_SET_HOSTNAME 166192895Sjamiestatic unsigned jail_default_allow = JAIL_DEFAULT_ALLOW; 167192895Sjamiestatic int jail_default_enforce_statfs = 2; 168192895Sjamie#if defined(INET) || defined(INET6) 169192895Sjamiestatic int jail_max_af_ips = 255; 170192895Sjamie#endif 171192895Sjamie 172192895Sjamie#ifdef INET 173185435Sbzstatic int 174185435Sbzqcmp_v4(const void *ip1, const void *ip2) 175185435Sbz{ 176185435Sbz in_addr_t iaa, iab; 177185435Sbz 178185435Sbz /* 179185435Sbz * We need to compare in HBO here to get the list sorted as expected 180185435Sbz * by the result of the code. Sorting NBO addresses gives you 181185435Sbz * interesting results. If you do not understand, do not try. 182185435Sbz */ 183185435Sbz iaa = ntohl(((const struct in_addr *)ip1)->s_addr); 184185435Sbz iab = ntohl(((const struct in_addr *)ip2)->s_addr); 185185435Sbz 186185435Sbz /* 187185435Sbz * Do not simply return the difference of the two numbers, the int is 188185435Sbz * not wide enough. 189185435Sbz */ 190185435Sbz if (iaa > iab) 191185435Sbz return (1); 192185435Sbz else if (iaa < iab) 193185435Sbz return (-1); 194185435Sbz else 195185435Sbz return (0); 196185435Sbz} 197185435Sbz#endif 198185435Sbz 199185435Sbz#ifdef INET6 200185435Sbzstatic int 201185435Sbzqcmp_v6(const void *ip1, const void *ip2) 202185435Sbz{ 203185435Sbz const struct in6_addr *ia6a, *ia6b; 204185435Sbz int i, rc; 205185435Sbz 206185435Sbz ia6a = (const struct in6_addr *)ip1; 207185435Sbz ia6b = (const struct in6_addr *)ip2; 208185435Sbz 209185435Sbz rc = 0; 210190466Sjamie for (i = 0; rc == 0 && i < sizeof(struct in6_addr); i++) { 211185435Sbz if (ia6a->s6_addr[i] > ia6b->s6_addr[i]) 212185435Sbz rc = 1; 213185435Sbz else if (ia6a->s6_addr[i] < ia6b->s6_addr[i]) 214185435Sbz rc = -1; 215185435Sbz } 216185435Sbz return (rc); 217185435Sbz} 218185435Sbz#endif 219185435Sbz 220191673Sjamie/* 221191673Sjamie * struct jail_args { 222191673Sjamie * struct jail *jail; 223191673Sjamie * }; 224191673Sjamie */ 225191673Sjamieint 226191673Sjamiejail(struct thread *td, struct jail_args *uap) 227185435Sbz{ 228191673Sjamie uint32_t version; 229191673Sjamie int error; 230192895Sjamie struct jail j; 231185435Sbz 232191673Sjamie error = copyin(uap->jail, &version, sizeof(uint32_t)); 233191673Sjamie if (error) 234191673Sjamie return (error); 235185435Sbz 236191673Sjamie switch (version) { 237191673Sjamie case 0: 238191673Sjamie { 239191673Sjamie struct jail_v0 j0; 240185435Sbz 241192895Sjamie /* FreeBSD single IPv4 jails. */ 242192895Sjamie bzero(&j, sizeof(struct jail)); 243191673Sjamie error = copyin(uap->jail, &j0, sizeof(struct jail_v0)); 244191673Sjamie if (error) 245191673Sjamie return (error); 246192895Sjamie j.version = j0.version; 247192895Sjamie j.path = j0.path; 248192895Sjamie j.hostname = j0.hostname; 249192895Sjamie j.ip4s = j0.ip_number; 250191673Sjamie break; 251191673Sjamie } 252191673Sjamie 253191673Sjamie case 1: 254185435Sbz /* 255191673Sjamie * Version 1 was used by multi-IPv4 jail implementations 256191673Sjamie * that never made it into the official kernel. 257185435Sbz */ 258191673Sjamie return (EINVAL); 259185435Sbz 260191673Sjamie case 2: /* JAIL_API_VERSION */ 261191673Sjamie /* FreeBSD multi-IPv4/IPv6,noIP jails. */ 262191673Sjamie error = copyin(uap->jail, &j, sizeof(struct jail)); 263191673Sjamie if (error) 264191673Sjamie return (error); 265192895Sjamie break; 266192895Sjamie 267192895Sjamie default: 268192895Sjamie /* Sci-Fi jails are not supported, sorry. */ 269192895Sjamie return (EINVAL); 270192895Sjamie } 271192895Sjamie return (kern_jail(td, &j)); 272192895Sjamie} 273192895Sjamie 274192895Sjamieint 275192895Sjamiekern_jail(struct thread *td, struct jail *j) 276192895Sjamie{ 277192895Sjamie struct iovec optiov[24]; 278192895Sjamie struct uio opt; 279192895Sjamie char *u_path, *u_hostname, *u_name; 280185435Sbz#ifdef INET 281192895Sjamie int ip4s; 282192895Sjamie struct in_addr *u_ip4; 283192895Sjamie#endif 284192895Sjamie#ifdef INET6 285192895Sjamie struct in6_addr *u_ip6; 286192895Sjamie#endif 287192895Sjamie size_t tmplen; 288192895Sjamie int error, enforce_statfs, fi; 289192895Sjamie 290192895Sjamie bzero(&optiov, sizeof(optiov)); 291192895Sjamie opt.uio_iov = optiov; 292192895Sjamie opt.uio_iovcnt = 0; 293192895Sjamie opt.uio_offset = -1; 294192895Sjamie opt.uio_resid = -1; 295192895Sjamie opt.uio_segflg = UIO_SYSSPACE; 296192895Sjamie opt.uio_rw = UIO_READ; 297192895Sjamie opt.uio_td = td; 298192895Sjamie 299192895Sjamie /* Set permissions for top-level jails from sysctls. */ 300192895Sjamie if (!jailed(td->td_ucred)) { 301192895Sjamie for (fi = 0; fi < sizeof(pr_allow_names) / 302192895Sjamie sizeof(pr_allow_names[0]); fi++) { 303192895Sjamie optiov[opt.uio_iovcnt].iov_base = 304192895Sjamie (jail_default_allow & (1 << fi)) 305192895Sjamie ? pr_allow_names[fi] : pr_allow_nonames[fi]; 306192895Sjamie optiov[opt.uio_iovcnt].iov_len = 307192895Sjamie strlen(optiov[opt.uio_iovcnt].iov_base) + 1; 308192895Sjamie opt.uio_iovcnt += 2; 309192895Sjamie } 310192895Sjamie optiov[opt.uio_iovcnt].iov_base = "enforce_statfs"; 311192895Sjamie optiov[opt.uio_iovcnt].iov_len = sizeof("enforce_statfs"); 312192895Sjamie opt.uio_iovcnt++; 313192895Sjamie enforce_statfs = jail_default_enforce_statfs; 314192895Sjamie optiov[opt.uio_iovcnt].iov_base = &enforce_statfs; 315192895Sjamie optiov[opt.uio_iovcnt].iov_len = sizeof(enforce_statfs); 316192895Sjamie opt.uio_iovcnt++; 317192895Sjamie } 318192895Sjamie 319192895Sjamie tmplen = MAXPATHLEN + MAXHOSTNAMELEN + MAXHOSTNAMELEN; 320192895Sjamie#ifdef INET 321192895Sjamie ip4s = (j->version == 0) ? 1 : j->ip4s; 322192895Sjamie if (ip4s > jail_max_af_ips) 323192895Sjamie return (EINVAL); 324192895Sjamie tmplen += ip4s * sizeof(struct in_addr); 325191673Sjamie#else 326192895Sjamie if (j->ip4s > 0) 327192895Sjamie return (EINVAL); 328191673Sjamie#endif 329191673Sjamie#ifdef INET6 330192895Sjamie if (j->ip6s > jail_max_af_ips) 331192895Sjamie return (EINVAL); 332192895Sjamie tmplen += j->ip6s * sizeof(struct in6_addr); 333191673Sjamie#else 334192895Sjamie if (j->ip6s > 0) 335192895Sjamie return (EINVAL); 336191673Sjamie#endif 337192895Sjamie u_path = malloc(tmplen, M_TEMP, M_WAITOK); 338192895Sjamie u_hostname = u_path + MAXPATHLEN; 339192895Sjamie u_name = u_hostname + MAXHOSTNAMELEN; 340191673Sjamie#ifdef INET 341192895Sjamie u_ip4 = (struct in_addr *)(u_name + MAXHOSTNAMELEN); 342191673Sjamie#endif 343191673Sjamie#ifdef INET6 344191673Sjamie#ifdef INET 345192895Sjamie u_ip6 = (struct in6_addr *)(u_ip4 + ip4s); 346191673Sjamie#else 347192895Sjamie u_ip6 = (struct in6_addr *)(u_name + MAXHOSTNAMELEN); 348191673Sjamie#endif 349191673Sjamie#endif 350192895Sjamie optiov[opt.uio_iovcnt].iov_base = "path"; 351192895Sjamie optiov[opt.uio_iovcnt].iov_len = sizeof("path"); 352192895Sjamie opt.uio_iovcnt++; 353192895Sjamie optiov[opt.uio_iovcnt].iov_base = u_path; 354192895Sjamie error = copyinstr(j->path, u_path, MAXPATHLEN, 355192895Sjamie &optiov[opt.uio_iovcnt].iov_len); 356192895Sjamie if (error) { 357192895Sjamie free(u_path, M_TEMP); 358192895Sjamie return (error); 359192895Sjamie } 360192895Sjamie opt.uio_iovcnt++; 361192895Sjamie optiov[opt.uio_iovcnt].iov_base = "host.hostname"; 362192895Sjamie optiov[opt.uio_iovcnt].iov_len = sizeof("host.hostname"); 363192895Sjamie opt.uio_iovcnt++; 364192895Sjamie optiov[opt.uio_iovcnt].iov_base = u_hostname; 365192895Sjamie error = copyinstr(j->hostname, u_hostname, MAXHOSTNAMELEN, 366192895Sjamie &optiov[opt.uio_iovcnt].iov_len); 367192895Sjamie if (error) { 368192895Sjamie free(u_path, M_TEMP); 369192895Sjamie return (error); 370192895Sjamie } 371192895Sjamie opt.uio_iovcnt++; 372192895Sjamie if (j->jailname != NULL) { 373192895Sjamie optiov[opt.uio_iovcnt].iov_base = "name"; 374192895Sjamie optiov[opt.uio_iovcnt].iov_len = sizeof("name"); 375192895Sjamie opt.uio_iovcnt++; 376192895Sjamie optiov[opt.uio_iovcnt].iov_base = u_name; 377192895Sjamie error = copyinstr(j->jailname, u_name, MAXHOSTNAMELEN, 378192895Sjamie &optiov[opt.uio_iovcnt].iov_len); 379191673Sjamie if (error) { 380191673Sjamie free(u_path, M_TEMP); 381191673Sjamie return (error); 382191673Sjamie } 383192895Sjamie opt.uio_iovcnt++; 384192895Sjamie } 385191673Sjamie#ifdef INET 386192895Sjamie optiov[opt.uio_iovcnt].iov_base = "ip4.addr"; 387192895Sjamie optiov[opt.uio_iovcnt].iov_len = sizeof("ip4.addr"); 388192895Sjamie opt.uio_iovcnt++; 389192895Sjamie optiov[opt.uio_iovcnt].iov_base = u_ip4; 390192895Sjamie optiov[opt.uio_iovcnt].iov_len = ip4s * sizeof(struct in_addr); 391192895Sjamie if (j->version == 0) 392192895Sjamie u_ip4->s_addr = j->ip4s; 393192895Sjamie else { 394192895Sjamie error = copyin(j->ip4, u_ip4, optiov[opt.uio_iovcnt].iov_len); 395191673Sjamie if (error) { 396191673Sjamie free(u_path, M_TEMP); 397191673Sjamie return (error); 398191673Sjamie } 399192895Sjamie } 400192895Sjamie opt.uio_iovcnt++; 401185435Sbz#endif 402185435Sbz#ifdef INET6 403192895Sjamie optiov[opt.uio_iovcnt].iov_base = "ip6.addr"; 404192895Sjamie optiov[opt.uio_iovcnt].iov_len = sizeof("ip6.addr"); 405192895Sjamie opt.uio_iovcnt++; 406192895Sjamie optiov[opt.uio_iovcnt].iov_base = u_ip6; 407192895Sjamie optiov[opt.uio_iovcnt].iov_len = j->ip6s * sizeof(struct in6_addr); 408192895Sjamie error = copyin(j->ip6, u_ip6, optiov[opt.uio_iovcnt].iov_len); 409192895Sjamie if (error) { 410192895Sjamie free(u_path, M_TEMP); 411192895Sjamie return (error); 412192895Sjamie } 413192895Sjamie opt.uio_iovcnt++; 414185435Sbz#endif 415192895Sjamie KASSERT(opt.uio_iovcnt <= sizeof(optiov) / sizeof(optiov[0]), 416192895Sjamie ("kern_jail: too many iovecs (%d)", opt.uio_iovcnt)); 417191673Sjamie error = kern_jail_set(td, &opt, JAIL_CREATE | JAIL_ATTACH); 418191673Sjamie free(u_path, M_TEMP); 419191673Sjamie return (error); 420185435Sbz} 421185435Sbz 422192895Sjamie 423191673Sjamie/* 424191673Sjamie * struct jail_set_args { 425191673Sjamie * struct iovec *iovp; 426191673Sjamie * unsigned int iovcnt; 427191673Sjamie * int flags; 428191673Sjamie * }; 429191673Sjamie */ 430191673Sjamieint 431191673Sjamiejail_set(struct thread *td, struct jail_set_args *uap) 432185435Sbz{ 433191673Sjamie struct uio *auio; 434191673Sjamie int error; 435191673Sjamie 436191673Sjamie /* Check that we have an even number of iovecs. */ 437191673Sjamie if (uap->iovcnt & 1) 438191673Sjamie return (EINVAL); 439191673Sjamie 440191673Sjamie error = copyinuio(uap->iovp, uap->iovcnt, &auio); 441191673Sjamie if (error) 442191673Sjamie return (error); 443191673Sjamie error = kern_jail_set(td, auio, uap->flags); 444191673Sjamie free(auio, M_IOV); 445191673Sjamie return (error); 446191673Sjamie} 447191673Sjamie 448191673Sjamieint 449191673Sjamiekern_jail_set(struct thread *td, struct uio *optuio, int flags) 450191673Sjamie{ 451191673Sjamie struct nameidata nd; 452185435Sbz#ifdef INET 453190466Sjamie struct in_addr *ip4; 454185435Sbz#endif 455185435Sbz#ifdef INET6 456185435Sbz struct in6_addr *ip6; 457185435Sbz#endif 458191673Sjamie struct vfsopt *opt; 459191673Sjamie struct vfsoptlist *opts; 460192895Sjamie struct prison *pr, *deadpr, *mypr, *ppr, *tpr; 461191673Sjamie struct vnode *root; 462193066Sjamie char *domain, *errmsg, *host, *name, *p, *path, *uuid; 463192895Sjamie#if defined(INET) || defined(INET6) 464191673Sjamie void *op; 465192895Sjamie#endif 466193066Sjamie unsigned long hid; 467192895Sjamie size_t namelen, onamelen; 468192895Sjamie int created, cuflags, descend, enforce, error, errmsg_len, errmsg_pos; 469193066Sjamie int gotenforce, gothid, gotslevel, fi, jid, len; 470191673Sjamie int slevel, vfslocked; 471191673Sjamie#if defined(INET) || defined(INET6) 472192895Sjamie int ii, ij; 473191673Sjamie#endif 474191673Sjamie#ifdef INET 475192895Sjamie int ip4s, ip4a, redo_ip4; 476191673Sjamie#endif 477191673Sjamie#ifdef INET6 478192895Sjamie int ip6s, ip6a, redo_ip6; 479191673Sjamie#endif 480191673Sjamie unsigned pr_flags, ch_flags; 481192895Sjamie unsigned pr_allow, ch_allow, tallow; 482191673Sjamie char numbuf[12]; 483185435Sbz 484191673Sjamie error = priv_check(td, PRIV_JAIL_SET); 485191673Sjamie if (!error && (flags & JAIL_ATTACH)) 486191673Sjamie error = priv_check(td, PRIV_JAIL_ATTACH); 487191673Sjamie if (error) 488191673Sjamie return (error); 489192895Sjamie mypr = ppr = td->td_ucred->cr_prison; 490192895Sjamie if ((flags & JAIL_CREATE) && !(mypr->pr_allow & PR_ALLOW_JAILS)) 491192895Sjamie return (EPERM); 492191673Sjamie if (flags & ~JAIL_SET_MASK) 493191673Sjamie return (EINVAL); 494191673Sjamie 495185435Sbz /* 496191673Sjamie * Check all the parameters before committing to anything. Not all 497191673Sjamie * errors can be caught early, but we may as well try. Also, this 498191673Sjamie * takes care of some expensive stuff (path lookup) before getting 499191673Sjamie * the allprison lock. 500185435Sbz * 501191673Sjamie * XXX Jails are not filesystems, and jail parameters are not mount 502191673Sjamie * options. But it makes more sense to re-use the vfsopt code 503191673Sjamie * than duplicate it under a different name. 504185435Sbz */ 505191673Sjamie error = vfs_buildopts(optuio, &opts); 506191673Sjamie if (error) 507191673Sjamie return (error); 508185435Sbz#ifdef INET 509192895Sjamie ip4a = 0; 510185435Sbz ip4 = NULL; 511185435Sbz#endif 512185435Sbz#ifdef INET6 513192895Sjamie ip6a = 0; 514185435Sbz ip6 = NULL; 515185435Sbz#endif 516191673Sjamie 517192895Sjamie#if defined(INET) || defined(INET6) 518192895Sjamie again: 519192895Sjamie#endif 520191673Sjamie error = vfs_copyopt(opts, "jid", &jid, sizeof(jid)); 521191673Sjamie if (error == ENOENT) 522191673Sjamie jid = 0; 523191673Sjamie else if (error != 0) 524191673Sjamie goto done_free; 525191673Sjamie 526191673Sjamie error = vfs_copyopt(opts, "securelevel", &slevel, sizeof(slevel)); 527191673Sjamie if (error == ENOENT) 528191673Sjamie gotslevel = 0; 529191673Sjamie else if (error != 0) 530191673Sjamie goto done_free; 531191673Sjamie else 532191673Sjamie gotslevel = 1; 533191673Sjamie 534192895Sjamie error = vfs_copyopt(opts, "enforce_statfs", &enforce, sizeof(enforce)); 535192895Sjamie gotenforce = (error == 0); 536192895Sjamie if (gotenforce) { 537192895Sjamie if (enforce < 0 || enforce > 2) 538192895Sjamie return (EINVAL); 539192895Sjamie } else if (error != ENOENT) 540192895Sjamie goto done_free; 541192895Sjamie 542191673Sjamie pr_flags = ch_flags = 0; 543192895Sjamie for (fi = 0; fi < sizeof(pr_flag_names) / sizeof(pr_flag_names[0]); 544192895Sjamie fi++) { 545192895Sjamie if (pr_flag_names[fi] == NULL) 546192895Sjamie continue; 547192895Sjamie vfs_flagopt(opts, pr_flag_names[fi], &pr_flags, 1 << fi); 548192895Sjamie vfs_flagopt(opts, pr_flag_nonames[fi], &ch_flags, 1 << fi); 549192895Sjamie } 550191673Sjamie ch_flags |= pr_flags; 551191673Sjamie if ((flags & (JAIL_CREATE | JAIL_UPDATE | JAIL_ATTACH)) == JAIL_CREATE 552191673Sjamie && !(pr_flags & PR_PERSIST)) { 553191673Sjamie error = EINVAL; 554191673Sjamie vfs_opterror(opts, "new jail must persist or attach"); 555191673Sjamie goto done_errmsg; 556191673Sjamie } 557191673Sjamie 558192895Sjamie pr_allow = ch_allow = 0; 559192895Sjamie for (fi = 0; fi < sizeof(pr_allow_names) / sizeof(pr_allow_names[0]); 560192895Sjamie fi++) { 561192895Sjamie vfs_flagopt(opts, pr_allow_names[fi], &pr_allow, 1 << fi); 562192895Sjamie vfs_flagopt(opts, pr_allow_nonames[fi], &ch_allow, 1 << fi); 563192895Sjamie } 564192895Sjamie ch_allow |= pr_allow; 565192895Sjamie 566191673Sjamie error = vfs_getopt(opts, "name", (void **)&name, &len); 567191673Sjamie if (error == ENOENT) 568191673Sjamie name = NULL; 569191673Sjamie else if (error != 0) 570191673Sjamie goto done_free; 571191673Sjamie else { 572191673Sjamie if (len == 0 || name[len - 1] != '\0') { 573191673Sjamie error = EINVAL; 574191673Sjamie goto done_free; 575191673Sjamie } 576191673Sjamie if (len > MAXHOSTNAMELEN) { 577191673Sjamie error = ENAMETOOLONG; 578191673Sjamie goto done_free; 579191673Sjamie } 580191673Sjamie } 581191673Sjamie 582191673Sjamie error = vfs_getopt(opts, "host.hostname", (void **)&host, &len); 583191673Sjamie if (error == ENOENT) 584191673Sjamie host = NULL; 585191673Sjamie else if (error != 0) 586191673Sjamie goto done_free; 587191673Sjamie else { 588193066Sjamie ch_flags |= PR_HOST; 589193066Sjamie pr_flags |= PR_HOST; 590191673Sjamie if (len == 0 || host[len - 1] != '\0') { 591191673Sjamie error = EINVAL; 592191673Sjamie goto done_free; 593191673Sjamie } 594191673Sjamie if (len > MAXHOSTNAMELEN) { 595191673Sjamie error = ENAMETOOLONG; 596191673Sjamie goto done_free; 597191673Sjamie } 598191673Sjamie } 599191673Sjamie 600193066Sjamie error = vfs_getopt(opts, "host.domainname", (void **)&domain, &len); 601193066Sjamie if (error == ENOENT) 602193066Sjamie domain = NULL; 603193066Sjamie else if (error != 0) 604193066Sjamie goto done_free; 605193066Sjamie else { 606193066Sjamie ch_flags |= PR_HOST; 607193066Sjamie pr_flags |= PR_HOST; 608193066Sjamie if (len == 0 || domain[len - 1] != '\0') { 609193066Sjamie error = EINVAL; 610193066Sjamie goto done_free; 611193066Sjamie } 612193066Sjamie if (len > MAXHOSTNAMELEN) { 613193066Sjamie error = ENAMETOOLONG; 614193066Sjamie goto done_free; 615193066Sjamie } 616193066Sjamie } 617193066Sjamie 618193066Sjamie error = vfs_getopt(opts, "host.hostuuid", (void **)&uuid, &len); 619193066Sjamie if (error == ENOENT) 620193066Sjamie uuid = NULL; 621193066Sjamie else if (error != 0) 622193066Sjamie goto done_free; 623193066Sjamie else { 624193066Sjamie ch_flags |= PR_HOST; 625193066Sjamie pr_flags |= PR_HOST; 626193066Sjamie if (len == 0 || uuid[len - 1] != '\0') { 627193066Sjamie error = EINVAL; 628193066Sjamie goto done_free; 629193066Sjamie } 630193066Sjamie if (len > HOSTUUIDLEN) { 631193066Sjamie error = ENAMETOOLONG; 632193066Sjamie goto done_free; 633193066Sjamie } 634193066Sjamie } 635193066Sjamie 636193066Sjamie#ifdef COMPAT_IA32 637193066Sjamie if (td->td_proc->p_sysent->sv_flags & SV_IA32) { 638193066Sjamie uint32_t hid32; 639193066Sjamie 640193066Sjamie error = vfs_copyopt(opts, "host.hostid", &hid32, sizeof(hid32)); 641193066Sjamie hid = hid32; 642193066Sjamie } else 643193066Sjamie#endif 644193066Sjamie error = vfs_copyopt(opts, "host.hostid", &hid, sizeof(hid)); 645193066Sjamie if (error == ENOENT) 646193066Sjamie gothid = 0; 647193066Sjamie else if (error != 0) 648193066Sjamie goto done_free; 649193066Sjamie else { 650193066Sjamie gothid = 1; 651193066Sjamie ch_flags |= PR_HOST; 652193066Sjamie pr_flags |= PR_HOST; 653193066Sjamie } 654193066Sjamie 655192895Sjamie /* This might be the second time around for this option. */ 656185435Sbz#ifdef INET 657191673Sjamie error = vfs_getopt(opts, "ip4.addr", &op, &ip4s); 658191673Sjamie if (error == ENOENT) 659191673Sjamie ip4s = -1; 660191673Sjamie else if (error != 0) 661191673Sjamie goto done_free; 662191673Sjamie else if (ip4s & (sizeof(*ip4) - 1)) { 663191673Sjamie error = EINVAL; 664191673Sjamie goto done_free; 665192895Sjamie } else { 666192895Sjamie ch_flags |= PR_IP4_USER; 667192895Sjamie pr_flags |= PR_IP4_USER; 668192895Sjamie if (ip4s > 0) { 669192895Sjamie ip4s /= sizeof(*ip4); 670192895Sjamie if (ip4s > jail_max_af_ips) { 671185435Sbz error = EINVAL; 672192895Sjamie vfs_opterror(opts, "too many IPv4 addresses"); 673192895Sjamie goto done_errmsg; 674185435Sbz } 675192895Sjamie if (ip4a < ip4s) { 676192895Sjamie ip4a = ip4s; 677192895Sjamie free(ip4, M_PRISON); 678192895Sjamie ip4 = NULL; 679185435Sbz } 680192895Sjamie if (ip4 == NULL) 681192895Sjamie ip4 = malloc(ip4a * sizeof(*ip4), M_PRISON, 682192895Sjamie M_WAITOK); 683192895Sjamie bcopy(op, ip4, ip4s * sizeof(*ip4)); 684192895Sjamie /* 685192895Sjamie * IP addresses are all sorted but ip[0] to preserve 686192895Sjamie * the primary IP address as given from userland. 687192895Sjamie * This special IP is used for unbound outgoing 688192895Sjamie * connections as well for "loopback" traffic. 689192895Sjamie */ 690192895Sjamie if (ip4s > 1) 691192895Sjamie qsort(ip4 + 1, ip4s - 1, sizeof(*ip4), qcmp_v4); 692192895Sjamie /* 693192895Sjamie * Check for duplicate addresses and do some simple 694192895Sjamie * zero and broadcast checks. If users give other bogus 695192895Sjamie * addresses it is their problem. 696192895Sjamie * 697192895Sjamie * We do not have to care about byte order for these 698192895Sjamie * checks so we will do them in NBO. 699192895Sjamie */ 700192895Sjamie for (ii = 0; ii < ip4s; ii++) { 701192895Sjamie if (ip4[ii].s_addr == INADDR_ANY || 702192895Sjamie ip4[ii].s_addr == INADDR_BROADCAST) { 703192895Sjamie error = EINVAL; 704192895Sjamie goto done_free; 705192895Sjamie } 706192895Sjamie if ((ii+1) < ip4s && 707192895Sjamie (ip4[0].s_addr == ip4[ii+1].s_addr || 708192895Sjamie ip4[ii].s_addr == ip4[ii+1].s_addr)) { 709192895Sjamie error = EINVAL; 710192895Sjamie goto done_free; 711192895Sjamie } 712192895Sjamie } 713185435Sbz } 714191673Sjamie } 715191673Sjamie#endif 716185435Sbz 717185435Sbz#ifdef INET6 718191673Sjamie error = vfs_getopt(opts, "ip6.addr", &op, &ip6s); 719191673Sjamie if (error == ENOENT) 720191673Sjamie ip6s = -1; 721191673Sjamie else if (error != 0) 722191673Sjamie goto done_free; 723191673Sjamie else if (ip6s & (sizeof(*ip6) - 1)) { 724191673Sjamie error = EINVAL; 725191673Sjamie goto done_free; 726192895Sjamie } else { 727192895Sjamie ch_flags |= PR_IP6_USER; 728192895Sjamie pr_flags |= PR_IP6_USER; 729192895Sjamie if (ip6s > 0) { 730192895Sjamie ip6s /= sizeof(*ip6); 731192895Sjamie if (ip6s > jail_max_af_ips) { 732185435Sbz error = EINVAL; 733192895Sjamie vfs_opterror(opts, "too many IPv6 addresses"); 734192895Sjamie goto done_errmsg; 735185435Sbz } 736192895Sjamie if (ip6a < ip6s) { 737192895Sjamie ip6a = ip6s; 738192895Sjamie free(ip6, M_PRISON); 739192895Sjamie ip6 = NULL; 740185435Sbz } 741192895Sjamie if (ip6 == NULL) 742192895Sjamie ip6 = malloc(ip6a * sizeof(*ip6), M_PRISON, 743192895Sjamie M_WAITOK); 744192895Sjamie bcopy(op, ip6, ip6s * sizeof(*ip6)); 745192895Sjamie if (ip6s > 1) 746192895Sjamie qsort(ip6 + 1, ip6s - 1, sizeof(*ip6), qcmp_v6); 747192895Sjamie for (ii = 0; ii < ip6s; ii++) { 748192895Sjamie if (IN6_IS_ADDR_UNSPECIFIED(&ip6[ii])) { 749192895Sjamie error = EINVAL; 750192895Sjamie goto done_free; 751192895Sjamie } 752192895Sjamie if ((ii+1) < ip6s && 753192895Sjamie (IN6_ARE_ADDR_EQUAL(&ip6[0], &ip6[ii+1]) || 754192895Sjamie IN6_ARE_ADDR_EQUAL(&ip6[ii], &ip6[ii+1]))) 755192895Sjamie { 756192895Sjamie error = EINVAL; 757192895Sjamie goto done_free; 758192895Sjamie } 759192895Sjamie } 760185435Sbz } 761191673Sjamie } 762185435Sbz#endif 763185435Sbz 764191673Sjamie root = NULL; 765191673Sjamie error = vfs_getopt(opts, "path", (void **)&path, &len); 766191673Sjamie if (error == ENOENT) 767191673Sjamie path = NULL; 768191673Sjamie else if (error != 0) 769191673Sjamie goto done_free; 770191673Sjamie else { 771191673Sjamie if (flags & JAIL_UPDATE) { 772191673Sjamie error = EINVAL; 773191673Sjamie vfs_opterror(opts, 774191673Sjamie "path cannot be changed after creation"); 775191673Sjamie goto done_errmsg; 776191673Sjamie } 777191673Sjamie if (len == 0 || path[len - 1] != '\0') { 778191673Sjamie error = EINVAL; 779191673Sjamie goto done_free; 780191673Sjamie } 781191673Sjamie if (len < 2 || (len == 2 && path[0] == '/')) 782191673Sjamie path = NULL; 783191673Sjamie else { 784192895Sjamie /* Leave room for a real-root full pathname. */ 785192895Sjamie if (len + (path[0] == '/' && strcmp(mypr->pr_path, "/") 786192895Sjamie ? strlen(mypr->pr_path) : 0) > MAXPATHLEN) { 787192895Sjamie error = ENAMETOOLONG; 788192895Sjamie goto done_free; 789192895Sjamie } 790191673Sjamie NDINIT(&nd, LOOKUP, MPSAFE | FOLLOW, UIO_SYSSPACE, 791191673Sjamie path, td); 792191673Sjamie error = namei(&nd); 793191673Sjamie if (error) 794191673Sjamie goto done_free; 795191673Sjamie vfslocked = NDHASGIANT(&nd); 796191673Sjamie root = nd.ni_vp; 797191673Sjamie NDFREE(&nd, NDF_ONLY_PNBUF); 798191673Sjamie if (root->v_type != VDIR) { 799191673Sjamie error = ENOTDIR; 800191673Sjamie vrele(root); 801191673Sjamie VFS_UNLOCK_GIANT(vfslocked); 802191673Sjamie goto done_free; 803191673Sjamie } 804191673Sjamie VFS_UNLOCK_GIANT(vfslocked); 805191673Sjamie } 806191673Sjamie } 807185435Sbz 808191673Sjamie /* 809191673Sjamie * Grab the allprison lock before letting modules check their 810191673Sjamie * parameters. Once we have it, do not let go so we'll have a 811191673Sjamie * consistent view of the OSD list. 812191673Sjamie */ 813191673Sjamie sx_xlock(&allprison_lock); 814191673Sjamie error = osd_jail_call(NULL, PR_METHOD_CHECK, opts); 815191673Sjamie if (error) 816191673Sjamie goto done_unlock_list; 817185435Sbz 818191673Sjamie /* By now, all parameters should have been noted. */ 819191673Sjamie TAILQ_FOREACH(opt, opts, link) { 820191673Sjamie if (!opt->seen && strcmp(opt->name, "errmsg")) { 821191673Sjamie error = EINVAL; 822191673Sjamie vfs_opterror(opts, "unknown parameter: %s", opt->name); 823191673Sjamie goto done_unlock_list; 824191673Sjamie } 825191673Sjamie } 826191673Sjamie 827185435Sbz /* 828191673Sjamie * See if we are creating a new record or updating an existing one. 829191673Sjamie * This abuses the file error codes ENOENT and EEXIST. 830185435Sbz */ 831191673Sjamie cuflags = flags & (JAIL_CREATE | JAIL_UPDATE); 832191673Sjamie if (!cuflags) { 833191673Sjamie error = EINVAL; 834191673Sjamie vfs_opterror(opts, "no valid operation (create or update)"); 835191673Sjamie goto done_unlock_list; 836191673Sjamie } 837191673Sjamie pr = NULL; 838191673Sjamie if (jid != 0) { 839192895Sjamie /* 840192895Sjamie * See if a requested jid already exists. There is an 841192895Sjamie * information leak here if the jid exists but is not within 842192895Sjamie * the caller's jail hierarchy. Jail creators will get EEXIST 843192895Sjamie * even though they cannot see the jail, and CREATE | UPDATE 844192895Sjamie * will return ENOENT which is not normally a valid error. 845192895Sjamie */ 846191673Sjamie if (jid < 0) { 847191673Sjamie error = EINVAL; 848191673Sjamie vfs_opterror(opts, "negative jid"); 849191673Sjamie goto done_unlock_list; 850191673Sjamie } 851191673Sjamie pr = prison_find(jid); 852191673Sjamie if (pr != NULL) { 853192895Sjamie ppr = pr->pr_parent; 854191673Sjamie /* Create: jid must not exist. */ 855191673Sjamie if (cuflags == JAIL_CREATE) { 856191673Sjamie mtx_unlock(&pr->pr_mtx); 857191673Sjamie error = EEXIST; 858191673Sjamie vfs_opterror(opts, "jail %d already exists", 859191673Sjamie jid); 860191673Sjamie goto done_unlock_list; 861191673Sjamie } 862192895Sjamie if (!prison_ischild(mypr, pr)) { 863192895Sjamie mtx_unlock(&pr->pr_mtx); 864192895Sjamie pr = NULL; 865192895Sjamie } else if (pr->pr_uref == 0) { 866191673Sjamie if (!(flags & JAIL_DYING)) { 867191673Sjamie mtx_unlock(&pr->pr_mtx); 868191673Sjamie error = ENOENT; 869191673Sjamie vfs_opterror(opts, "jail %d is dying", 870191673Sjamie jid); 871191673Sjamie goto done_unlock_list; 872191673Sjamie } else if ((flags & JAIL_ATTACH) || 873191673Sjamie (pr_flags & PR_PERSIST)) { 874191673Sjamie /* 875191673Sjamie * A dying jail might be resurrected 876191673Sjamie * (via attach or persist), but first 877191673Sjamie * it must determine if another jail 878191673Sjamie * has claimed its name. Accomplish 879191673Sjamie * this by implicitly re-setting the 880191673Sjamie * name. 881191673Sjamie */ 882191673Sjamie if (name == NULL) 883192895Sjamie name = prison_name(mypr, pr); 884191673Sjamie } 885191673Sjamie } 886191673Sjamie } 887191673Sjamie if (pr == NULL) { 888191673Sjamie /* Update: jid must exist. */ 889191673Sjamie if (cuflags == JAIL_UPDATE) { 890191673Sjamie error = ENOENT; 891191673Sjamie vfs_opterror(opts, "jail %d not found", jid); 892191673Sjamie goto done_unlock_list; 893191673Sjamie } 894191673Sjamie } 895191673Sjamie } 896191673Sjamie /* 897191673Sjamie * If the caller provided a name, look for a jail by that name. 898191673Sjamie * This has different semantics for creates and updates keyed by jid 899191673Sjamie * (where the name must not already exist in a different jail), 900191673Sjamie * and updates keyed by the name itself (where the name must exist 901191673Sjamie * because that is the jail being updated). 902191673Sjamie */ 903191673Sjamie if (name != NULL) { 904192895Sjamie p = strrchr(name, '.'); 905192895Sjamie if (p != NULL) { 906192895Sjamie /* 907192895Sjamie * This is a hierarchical name. Split it into the 908192895Sjamie * parent and child names, and make sure the parent 909192895Sjamie * exists or matches an already found jail. 910192895Sjamie */ 911192895Sjamie *p = '\0'; 912192895Sjamie if (pr != NULL) { 913192895Sjamie if (strncmp(name, ppr->pr_name, p - name) || 914192895Sjamie ppr->pr_name[p - name] != '\0') { 915192895Sjamie mtx_unlock(&pr->pr_mtx); 916192895Sjamie error = EINVAL; 917192895Sjamie vfs_opterror(opts, 918192895Sjamie "cannot change jail's parent"); 919192895Sjamie goto done_unlock_list; 920192895Sjamie } 921192895Sjamie } else { 922192895Sjamie ppr = prison_find_name(mypr, name); 923192895Sjamie if (ppr == NULL) { 924192895Sjamie error = ENOENT; 925192895Sjamie vfs_opterror(opts, 926192895Sjamie "jail \"%s\" not found", name); 927192895Sjamie goto done_unlock_list; 928192895Sjamie } 929192895Sjamie mtx_unlock(&ppr->pr_mtx); 930192895Sjamie } 931192895Sjamie name = p + 1; 932192895Sjamie } 933191673Sjamie if (name[0] != '\0') { 934192895Sjamie namelen = 935192895Sjamie (ppr == &prison0) ? 0 : strlen(ppr->pr_name) + 1; 936192895Sjamie name_again: 937191673Sjamie deadpr = NULL; 938192895Sjamie FOREACH_PRISON_CHILD(ppr, tpr) { 939191673Sjamie if (tpr != pr && tpr->pr_ref > 0 && 940192895Sjamie !strcmp(tpr->pr_name + namelen, name)) { 941191673Sjamie if (pr == NULL && 942191673Sjamie cuflags != JAIL_CREATE) { 943191673Sjamie mtx_lock(&tpr->pr_mtx); 944191673Sjamie if (tpr->pr_ref > 0) { 945191673Sjamie /* 946191673Sjamie * Use this jail 947191673Sjamie * for updates. 948191673Sjamie */ 949191673Sjamie if (tpr->pr_uref > 0) { 950191673Sjamie pr = tpr; 951191673Sjamie break; 952191673Sjamie } 953191673Sjamie deadpr = tpr; 954191673Sjamie } 955191673Sjamie mtx_unlock(&tpr->pr_mtx); 956191673Sjamie } else if (tpr->pr_uref > 0) { 957191673Sjamie /* 958191673Sjamie * Create, or update(jid): 959191673Sjamie * name must not exist in an 960192895Sjamie * active sibling jail. 961191673Sjamie */ 962191673Sjamie error = EEXIST; 963191673Sjamie if (pr != NULL) 964191673Sjamie mtx_unlock(&pr->pr_mtx); 965191673Sjamie vfs_opterror(opts, 966191673Sjamie "jail \"%s\" already exists", 967191673Sjamie name); 968191673Sjamie goto done_unlock_list; 969191673Sjamie } 970191673Sjamie } 971191673Sjamie } 972191673Sjamie /* If no active jail is found, use a dying one. */ 973191673Sjamie if (deadpr != NULL && pr == NULL) { 974191673Sjamie if (flags & JAIL_DYING) { 975191673Sjamie mtx_lock(&deadpr->pr_mtx); 976191673Sjamie if (deadpr->pr_ref == 0) { 977191673Sjamie mtx_unlock(&deadpr->pr_mtx); 978191673Sjamie goto name_again; 979191673Sjamie } 980191673Sjamie pr = deadpr; 981191673Sjamie } else if (cuflags == JAIL_UPDATE) { 982191673Sjamie error = ENOENT; 983191673Sjamie vfs_opterror(opts, 984191673Sjamie "jail \"%s\" is dying", name); 985191673Sjamie goto done_unlock_list; 986191673Sjamie } 987191673Sjamie } 988191673Sjamie /* Update: name must exist if no jid. */ 989191673Sjamie else if (cuflags == JAIL_UPDATE && pr == NULL) { 990191673Sjamie error = ENOENT; 991191673Sjamie vfs_opterror(opts, "jail \"%s\" not found", 992191673Sjamie name); 993191673Sjamie goto done_unlock_list; 994191673Sjamie } 995191673Sjamie } 996191673Sjamie } 997191673Sjamie /* Update: must provide a jid or name. */ 998191673Sjamie else if (cuflags == JAIL_UPDATE && pr == NULL) { 999191673Sjamie error = ENOENT; 1000191673Sjamie vfs_opterror(opts, "update specified no jail"); 1001191673Sjamie goto done_unlock_list; 1002191673Sjamie } 1003185435Sbz 1004191673Sjamie /* If there's no prison to update, create a new one and link it in. */ 1005191673Sjamie if (pr == NULL) { 1006191673Sjamie created = 1; 1007192895Sjamie mtx_lock(&ppr->pr_mtx); 1008192895Sjamie if (ppr->pr_ref == 0 || (ppr->pr_flags & PR_REMOVE)) { 1009192895Sjamie mtx_unlock(&ppr->pr_mtx); 1010192895Sjamie error = ENOENT; 1011192895Sjamie vfs_opterror(opts, "parent jail went away!"); 1012192895Sjamie goto done_unlock_list; 1013192895Sjamie } 1014192895Sjamie ppr->pr_ref++; 1015192895Sjamie ppr->pr_uref++; 1016192895Sjamie mtx_unlock(&ppr->pr_mtx); 1017191673Sjamie pr = malloc(sizeof(*pr), M_PRISON, M_WAITOK | M_ZERO); 1018191673Sjamie if (jid == 0) { 1019191673Sjamie /* Find the next free jid. */ 1020191673Sjamie jid = lastprid + 1; 1021191673Sjamie findnext: 1022191673Sjamie if (jid == JAIL_MAX) 1023191673Sjamie jid = 1; 1024191673Sjamie TAILQ_FOREACH(tpr, &allprison, pr_list) { 1025191673Sjamie if (tpr->pr_id < jid) 1026191673Sjamie continue; 1027191673Sjamie if (tpr->pr_id > jid || tpr->pr_ref == 0) { 1028191673Sjamie TAILQ_INSERT_BEFORE(tpr, pr, pr_list); 1029191673Sjamie break; 1030191673Sjamie } 1031191673Sjamie if (jid == lastprid) { 1032191673Sjamie error = EAGAIN; 1033191673Sjamie vfs_opterror(opts, 1034191673Sjamie "no available jail IDs"); 1035191673Sjamie free(pr, M_PRISON); 1036192895Sjamie prison_deref(ppr, PD_DEREF | 1037192895Sjamie PD_DEUREF | PD_LIST_XLOCKED); 1038192895Sjamie goto done_releroot; 1039191673Sjamie } 1040191673Sjamie jid++; 1041191673Sjamie goto findnext; 1042191673Sjamie } 1043191673Sjamie lastprid = jid; 1044191673Sjamie } else { 1045191673Sjamie /* 1046191673Sjamie * The jail already has a jid (that did not yet exist), 1047191673Sjamie * so just find where to insert it. 1048191673Sjamie */ 1049191673Sjamie TAILQ_FOREACH(tpr, &allprison, pr_list) 1050191673Sjamie if (tpr->pr_id >= jid) { 1051191673Sjamie TAILQ_INSERT_BEFORE(tpr, pr, pr_list); 1052191673Sjamie break; 1053191673Sjamie } 1054191673Sjamie } 1055191673Sjamie if (tpr == NULL) 1056191673Sjamie TAILQ_INSERT_TAIL(&allprison, pr, pr_list); 1057192895Sjamie LIST_INSERT_HEAD(&ppr->pr_children, pr, pr_sibling); 1058192895Sjamie for (tpr = ppr; tpr != NULL; tpr = tpr->pr_parent) 1059192895Sjamie tpr->pr_prisoncount++; 1060185435Sbz 1061192895Sjamie pr->pr_parent = ppr; 1062191673Sjamie pr->pr_id = jid; 1063192895Sjamie 1064192895Sjamie /* Set some default values, and inherit some from the parent. */ 1065191673Sjamie if (name == NULL) 1066191673Sjamie name = ""; 1067193066Sjamie if (host != NULL || domain != NULL || uuid != NULL || gothid) { 1068193066Sjamie if (host == NULL) 1069193066Sjamie host = ppr->pr_host; 1070193066Sjamie if (domain == NULL) 1071193066Sjamie domain = ppr->pr_domain; 1072193066Sjamie if (uuid == NULL) 1073193066Sjamie uuid = ppr->pr_uuid; 1074193066Sjamie if (!gothid) 1075193066Sjamie hid = ppr->pr_hostid; 1076193066Sjamie } 1077191673Sjamie if (path == NULL) { 1078191673Sjamie path = "/"; 1079192895Sjamie root = mypr->pr_root; 1080191673Sjamie vref(root); 1081191673Sjamie } 1082192895Sjamie#ifdef INET 1083192895Sjamie pr->pr_flags |= ppr->pr_flags & PR_IP4; 1084192895Sjamie pr->pr_ip4s = ppr->pr_ip4s; 1085192895Sjamie if (ppr->pr_ip4 != NULL) { 1086192895Sjamie pr->pr_ip4 = malloc(pr->pr_ip4s * 1087192895Sjamie sizeof(struct in_addr), M_PRISON, M_WAITOK); 1088192895Sjamie bcopy(ppr->pr_ip4, pr->pr_ip4, 1089192895Sjamie pr->pr_ip4s * sizeof(*pr->pr_ip4)); 1090192895Sjamie } 1091192895Sjamie#endif 1092192895Sjamie#ifdef INET6 1093192895Sjamie pr->pr_flags |= ppr->pr_flags & PR_IP6; 1094192895Sjamie pr->pr_ip6s = ppr->pr_ip6s; 1095192895Sjamie if (ppr->pr_ip6 != NULL) { 1096192895Sjamie pr->pr_ip6 = malloc(pr->pr_ip6s * 1097192895Sjamie sizeof(struct in6_addr), M_PRISON, M_WAITOK); 1098192895Sjamie bcopy(ppr->pr_ip6, pr->pr_ip6, 1099192895Sjamie pr->pr_ip6s * sizeof(*pr->pr_ip6)); 1100192895Sjamie } 1101192895Sjamie#endif 1102192895Sjamie pr->pr_securelevel = ppr->pr_securelevel; 1103192895Sjamie pr->pr_allow = JAIL_DEFAULT_ALLOW & ppr->pr_allow; 1104192895Sjamie pr->pr_enforce_statfs = ppr->pr_enforce_statfs; 1105191673Sjamie 1106192895Sjamie LIST_INIT(&pr->pr_children); 1107192895Sjamie mtx_init(&pr->pr_mtx, "jail mutex", NULL, MTX_DEF | MTX_DUPOK); 1108191673Sjamie 1109185435Sbz /* 1110191673Sjamie * Allocate a dedicated cpuset for each jail. 1111191673Sjamie * Unlike other initial settings, this may return an erorr. 1112185435Sbz */ 1113192895Sjamie error = cpuset_create_root(ppr, &pr->pr_cpuset); 1114191673Sjamie if (error) { 1115191673Sjamie prison_deref(pr, PD_LIST_XLOCKED); 1116191673Sjamie goto done_releroot; 1117191673Sjamie } 1118185435Sbz 1119191673Sjamie mtx_lock(&pr->pr_mtx); 1120185435Sbz /* 1121191673Sjamie * New prisons do not yet have a reference, because we do not 1122191673Sjamie * want other to see the incomplete prison once the 1123191673Sjamie * allprison_lock is downgraded. 1124185435Sbz */ 1125191673Sjamie } else { 1126191673Sjamie created = 0; 1127191673Sjamie /* 1128191673Sjamie * Grab a reference for existing prisons, to ensure they 1129191673Sjamie * continue to exist for the duration of the call. 1130191673Sjamie */ 1131191673Sjamie pr->pr_ref++; 1132191673Sjamie } 1133185435Sbz 1134191673Sjamie /* Do final error checking before setting anything. */ 1135192895Sjamie if (gotslevel) { 1136192895Sjamie if (slevel < ppr->pr_securelevel) { 1137192895Sjamie error = EPERM; 1138192895Sjamie goto done_deref_locked; 1139192895Sjamie } 1140192895Sjamie } 1141192895Sjamie if (gotenforce) { 1142192895Sjamie if (enforce < ppr->pr_enforce_statfs) { 1143192895Sjamie error = EPERM; 1144192895Sjamie goto done_deref_locked; 1145192895Sjamie } 1146192895Sjamie } 1147185435Sbz#ifdef INET 1148192895Sjamie if (ch_flags & PR_IP4_USER) { 1149192895Sjamie if (ppr->pr_flags & PR_IP4) { 1150192895Sjamie if (!(pr_flags & PR_IP4_USER)) { 1151192895Sjamie /* 1152192895Sjamie * Silently ignore attempts to make the IP 1153192895Sjamie * addresses unrestricted when the parent is 1154192895Sjamie * restricted; in other words, interpret 1155192895Sjamie * "unrestricted" as "as unrestricted as 1156192895Sjamie * possible". 1157192895Sjamie */ 1158192895Sjamie ip4s = ppr->pr_ip4s; 1159192895Sjamie if (ip4s == 0) { 1160192895Sjamie free(ip4, M_PRISON); 1161192895Sjamie ip4 = NULL; 1162192895Sjamie } else if (ip4s <= ip4a) { 1163192895Sjamie /* Inherit the parent's address(es). */ 1164192895Sjamie bcopy(ppr->pr_ip4, ip4, 1165192895Sjamie ip4s * sizeof(*ip4)); 1166192895Sjamie } else { 1167192895Sjamie /* 1168192895Sjamie * There's no room for the parent's 1169192895Sjamie * address list. Allocate some more. 1170192895Sjamie */ 1171192895Sjamie ip4a = ip4s; 1172192895Sjamie free(ip4, M_PRISON); 1173192895Sjamie ip4 = malloc(ip4a * sizeof(*ip4), 1174192895Sjamie M_PRISON, M_NOWAIT); 1175192895Sjamie if (ip4 != NULL) 1176192895Sjamie bcopy(ppr->pr_ip4, ip4, 1177192895Sjamie ip4s * sizeof(*ip4)); 1178192895Sjamie else { 1179192895Sjamie /* Allocation failed without 1180192895Sjamie * sleeping. Unlocking the 1181192895Sjamie * prison now will invalidate 1182192895Sjamie * some checks and prematurely 1183192895Sjamie * show an unfinished new jail. 1184192895Sjamie * So let go of everything and 1185192895Sjamie * start over. 1186192895Sjamie */ 1187192895Sjamie prison_deref(pr, created 1188192895Sjamie ? PD_LOCKED | 1189192895Sjamie PD_LIST_XLOCKED 1190192895Sjamie : PD_DEREF | PD_LOCKED | 1191192895Sjamie PD_LIST_XLOCKED); 1192192895Sjamie if (root != NULL) { 1193192895Sjamie vfslocked = 1194192895Sjamie VFS_LOCK_GIANT( 1195192895Sjamie root->v_mount); 1196192895Sjamie vrele(root); 1197192895Sjamie VFS_UNLOCK_GIANT( 1198192895Sjamie vfslocked); 1199192895Sjamie } 1200192895Sjamie ip4 = malloc(ip4a * 1201192895Sjamie sizeof(*ip4), M_PRISON, 1202192895Sjamie M_WAITOK); 1203192895Sjamie goto again; 1204192895Sjamie } 1205192895Sjamie } 1206192895Sjamie } else if (ip4s > 0) { 1207192895Sjamie /* 1208192895Sjamie * Make sure the new set of IP addresses is a 1209192895Sjamie * subset of the parent's list. Don't worry 1210192895Sjamie * about the parent being unlocked, as any 1211192895Sjamie * setting is done with allprison_lock held. 1212192895Sjamie */ 1213192895Sjamie for (ij = 0; ij < ppr->pr_ip4s; ij++) 1214192895Sjamie if (ip4[0].s_addr == 1215192895Sjamie ppr->pr_ip4[ij].s_addr) 1216192895Sjamie break; 1217192895Sjamie if (ij == ppr->pr_ip4s) { 1218192895Sjamie error = EPERM; 1219192895Sjamie goto done_deref_locked; 1220192895Sjamie } 1221192895Sjamie if (ip4s > 1) { 1222192895Sjamie for (ii = ij = 1; ii < ip4s; ii++) { 1223192895Sjamie if (ip4[ii].s_addr == 1224192895Sjamie ppr->pr_ip4[0].s_addr) 1225192895Sjamie continue; 1226192895Sjamie for (; ij < ppr->pr_ip4s; ij++) 1227192895Sjamie if (ip4[ii].s_addr == 1228192895Sjamie ppr->pr_ip4[ij].s_addr) 1229192895Sjamie break; 1230192895Sjamie if (ij == ppr->pr_ip4s) 1231192895Sjamie break; 1232192895Sjamie } 1233192895Sjamie if (ij == ppr->pr_ip4s) { 1234192895Sjamie error = EPERM; 1235192895Sjamie goto done_deref_locked; 1236192895Sjamie } 1237192895Sjamie } 1238192895Sjamie } 1239192895Sjamie } 1240192895Sjamie if (ip4s > 0) { 1241192895Sjamie /* 1242192895Sjamie * Check for conflicting IP addresses. We permit them 1243192895Sjamie * if there is no more than one IP on each jail. If 1244192895Sjamie * there is a duplicate on a jail with more than one 1245192895Sjamie * IP stop checking and return error. 1246192895Sjamie */ 1247192895Sjamie FOREACH_PRISON_DESCENDANT(&prison0, tpr, descend) { 1248192895Sjamie if (tpr == pr || tpr->pr_uref == 0) { 1249192895Sjamie descend = 0; 1250192895Sjamie continue; 1251192895Sjamie } 1252192895Sjamie if (!(tpr->pr_flags & PR_IP4_USER)) 1253192895Sjamie continue; 1254192895Sjamie descend = 0; 1255192895Sjamie if (tpr->pr_ip4 == NULL || 1256192895Sjamie (ip4s == 1 && tpr->pr_ip4s == 1)) 1257192895Sjamie continue; 1258192895Sjamie for (ii = 0; ii < ip4s; ii++) { 1259191673Sjamie if (_prison_check_ip4(tpr, 1260191673Sjamie &ip4[ii]) == 0) { 1261192895Sjamie error = EADDRINUSE; 1262191673Sjamie vfs_opterror(opts, 1263191673Sjamie "IPv4 addresses clash"); 1264191673Sjamie goto done_deref_locked; 1265191673Sjamie } 1266192895Sjamie } 1267192895Sjamie } 1268192895Sjamie } 1269192895Sjamie } 1270185435Sbz#endif 1271191673Sjamie#ifdef INET6 1272192895Sjamie if (ch_flags & PR_IP6_USER) { 1273192895Sjamie if (ppr->pr_flags & PR_IP6) { 1274192895Sjamie if (!(pr_flags & PR_IP6_USER)) { 1275192895Sjamie /* 1276192895Sjamie * Silently ignore attempts to make the IP 1277192895Sjamie * addresses unrestricted when the parent is 1278192895Sjamie * restricted. 1279192895Sjamie */ 1280192895Sjamie ip6s = ppr->pr_ip6s; 1281192895Sjamie if (ip6s == 0) { 1282192895Sjamie free(ip6, M_PRISON); 1283192895Sjamie ip6 = NULL; 1284192895Sjamie } else if (ip6s <= ip6a) { 1285192895Sjamie /* Inherit the parent's address(es). */ 1286192895Sjamie bcopy(ppr->pr_ip6, ip6, 1287192895Sjamie ip6s * sizeof(*ip6)); 1288192895Sjamie } else { 1289192895Sjamie /* 1290192895Sjamie * There's no room for the parent's 1291192895Sjamie * address list. 1292192895Sjamie */ 1293192895Sjamie ip6a = ip6s; 1294192895Sjamie free(ip6, M_PRISON); 1295192895Sjamie ip6 = malloc(ip6a * sizeof(*ip6), 1296192895Sjamie M_PRISON, M_NOWAIT); 1297192895Sjamie if (ip6 != NULL) 1298192895Sjamie bcopy(ppr->pr_ip6, ip6, 1299192895Sjamie ip6s * sizeof(*ip6)); 1300192895Sjamie else { 1301192895Sjamie prison_deref(pr, created 1302192895Sjamie ? PD_LOCKED | 1303192895Sjamie PD_LIST_XLOCKED 1304192895Sjamie : PD_DEREF | PD_LOCKED | 1305192895Sjamie PD_LIST_XLOCKED); 1306192895Sjamie if (root != NULL) { 1307192895Sjamie vfslocked = 1308192895Sjamie VFS_LOCK_GIANT( 1309192895Sjamie root->v_mount); 1310192895Sjamie vrele(root); 1311192895Sjamie VFS_UNLOCK_GIANT( 1312192895Sjamie vfslocked); 1313192895Sjamie } 1314192895Sjamie ip6 = malloc(ip6a * 1315192895Sjamie sizeof(*ip6), M_PRISON, 1316192895Sjamie M_WAITOK); 1317192895Sjamie goto again; 1318192895Sjamie } 1319192895Sjamie } 1320192895Sjamie } else if (ip6s > 0) { 1321192895Sjamie /* 1322192895Sjamie * Make sure the new set of IP addresses is a 1323192895Sjamie * subset of the parent's list. 1324192895Sjamie */ 1325192895Sjamie for (ij = 0; ij < ppr->pr_ip6s; ij++) 1326192895Sjamie if (IN6_ARE_ADDR_EQUAL(&ip6[0], 1327192895Sjamie &ppr->pr_ip6[ij])) 1328192895Sjamie break; 1329192895Sjamie if (ij == ppr->pr_ip6s) { 1330192895Sjamie error = EPERM; 1331192895Sjamie goto done_deref_locked; 1332192895Sjamie } 1333192895Sjamie if (ip6s > 1) { 1334192895Sjamie for (ii = ij = 1; ii < ip6s; ii++) { 1335192895Sjamie if (IN6_ARE_ADDR_EQUAL(&ip6[ii], 1336192895Sjamie &ppr->pr_ip6[0])) 1337192895Sjamie continue; 1338192895Sjamie for (; ij < ppr->pr_ip6s; ij++) 1339192895Sjamie if (IN6_ARE_ADDR_EQUAL( 1340192895Sjamie &ip6[ii], 1341192895Sjamie &ppr->pr_ip6[ij])) 1342192895Sjamie break; 1343192895Sjamie if (ij == ppr->pr_ip6s) 1344192895Sjamie break; 1345192895Sjamie } 1346192895Sjamie if (ij == ppr->pr_ip6s) { 1347192895Sjamie error = EPERM; 1348192895Sjamie goto done_deref_locked; 1349192895Sjamie } 1350192895Sjamie } 1351192895Sjamie } 1352192895Sjamie } 1353192895Sjamie if (ip6s > 0) { 1354192895Sjamie /* Check for conflicting IP addresses. */ 1355192895Sjamie FOREACH_PRISON_DESCENDANT(&prison0, tpr, descend) { 1356192895Sjamie if (tpr == pr || tpr->pr_uref == 0) { 1357192895Sjamie descend = 0; 1358192895Sjamie continue; 1359192895Sjamie } 1360192895Sjamie if (!(tpr->pr_flags & PR_IP6_USER)) 1361192895Sjamie continue; 1362192895Sjamie descend = 0; 1363192895Sjamie if (tpr->pr_ip6 == NULL || 1364192895Sjamie (ip6s == 1 && tpr->pr_ip6s == 1)) 1365192895Sjamie continue; 1366192895Sjamie for (ii = 0; ii < ip6s; ii++) { 1367191673Sjamie if (_prison_check_ip6(tpr, 1368191673Sjamie &ip6[ii]) == 0) { 1369192895Sjamie error = EADDRINUSE; 1370191673Sjamie vfs_opterror(opts, 1371191673Sjamie "IPv6 addresses clash"); 1372191673Sjamie goto done_deref_locked; 1373191673Sjamie } 1374192895Sjamie } 1375192895Sjamie } 1376191673Sjamie } 1377192895Sjamie } 1378191673Sjamie#endif 1379192895Sjamie onamelen = namelen = 0; 1380192895Sjamie if (name != NULL) { 1381191673Sjamie /* Give a default name of the jid. */ 1382191673Sjamie if (name[0] == '\0') 1383191673Sjamie snprintf(name = numbuf, sizeof(numbuf), "%d", jid); 1384191673Sjamie else if (strtoul(name, &p, 10) != jid && *p == '\0') { 1385191673Sjamie error = EINVAL; 1386191673Sjamie vfs_opterror(opts, "name cannot be numeric"); 1387192895Sjamie goto done_deref_locked; 1388191673Sjamie } 1389191673Sjamie /* 1390192895Sjamie * Make sure the name isn't too long for the prison or its 1391192895Sjamie * children. 1392191673Sjamie */ 1393192895Sjamie onamelen = strlen(pr->pr_name); 1394192895Sjamie namelen = strlen(name); 1395192895Sjamie if (strlen(ppr->pr_name) + namelen + 2 > sizeof(pr->pr_name)) { 1396192895Sjamie error = ENAMETOOLONG; 1397192895Sjamie goto done_deref_locked; 1398192895Sjamie } 1399192895Sjamie FOREACH_PRISON_DESCENDANT(pr, tpr, descend) { 1400192895Sjamie if (strlen(tpr->pr_name) + (namelen - onamelen) >= 1401192895Sjamie sizeof(pr->pr_name)) { 1402192895Sjamie error = ENAMETOOLONG; 1403192895Sjamie goto done_deref_locked; 1404192895Sjamie } 1405192895Sjamie } 1406191673Sjamie } 1407192895Sjamie if (pr_allow & ~ppr->pr_allow) { 1408192895Sjamie error = EPERM; 1409192895Sjamie goto done_deref_locked; 1410192895Sjamie } 1411185435Sbz 1412191673Sjamie /* Set the parameters of the prison. */ 1413191673Sjamie#ifdef INET 1414192895Sjamie redo_ip4 = 0; 1415192895Sjamie if (ch_flags & PR_IP4_USER) { 1416192895Sjamie if (pr_flags & PR_IP4_USER) { 1417192895Sjamie /* Some restriction set. */ 1418192895Sjamie pr->pr_flags |= PR_IP4; 1419192895Sjamie if (ip4s >= 0) { 1420192895Sjamie free(pr->pr_ip4, M_PRISON); 1421192895Sjamie pr->pr_ip4s = ip4s; 1422192895Sjamie pr->pr_ip4 = ip4; 1423192895Sjamie ip4 = NULL; 1424192895Sjamie } 1425192895Sjamie } else if (ppr->pr_flags & PR_IP4) { 1426192895Sjamie /* This restriction cleared, but keep inherited. */ 1427192895Sjamie free(pr->pr_ip4, M_PRISON); 1428192895Sjamie pr->pr_ip4s = ip4s; 1429192895Sjamie pr->pr_ip4 = ip4; 1430192895Sjamie ip4 = NULL; 1431192895Sjamie } else { 1432192895Sjamie /* Restriction cleared, now unrestricted. */ 1433192895Sjamie pr->pr_flags &= ~PR_IP4; 1434192895Sjamie free(pr->pr_ip4, M_PRISON); 1435192895Sjamie pr->pr_ip4s = 0; 1436192895Sjamie } 1437192895Sjamie FOREACH_PRISON_DESCENDANT_LOCKED(pr, tpr, descend) { 1438192895Sjamie if (prison_restrict_ip4(tpr, NULL)) { 1439192895Sjamie redo_ip4 = 1; 1440192895Sjamie descend = 0; 1441192895Sjamie } 1442192895Sjamie } 1443185435Sbz } 1444191673Sjamie#endif 1445191673Sjamie#ifdef INET6 1446192895Sjamie redo_ip6 = 0; 1447192895Sjamie if (ch_flags & PR_IP6_USER) { 1448192895Sjamie if (pr_flags & PR_IP6_USER) { 1449192895Sjamie /* Some restriction set. */ 1450192895Sjamie pr->pr_flags |= PR_IP6; 1451192895Sjamie if (ip6s >= 0) { 1452192895Sjamie free(pr->pr_ip6, M_PRISON); 1453192895Sjamie pr->pr_ip6s = ip6s; 1454192895Sjamie pr->pr_ip6 = ip6; 1455192895Sjamie ip6 = NULL; 1456192895Sjamie } 1457192895Sjamie } else if (ppr->pr_flags & PR_IP6) { 1458192895Sjamie /* This restriction cleared, but keep inherited. */ 1459192895Sjamie free(pr->pr_ip6, M_PRISON); 1460192895Sjamie pr->pr_ip6s = ip6s; 1461192895Sjamie pr->pr_ip6 = ip6; 1462192895Sjamie ip6 = NULL; 1463192895Sjamie } else { 1464192895Sjamie /* Restriction cleared, now unrestricted. */ 1465192895Sjamie pr->pr_flags &= ~PR_IP6; 1466192895Sjamie free(pr->pr_ip6, M_PRISON); 1467192895Sjamie pr->pr_ip6s = 0; 1468192895Sjamie } 1469192895Sjamie FOREACH_PRISON_DESCENDANT_LOCKED(pr, tpr, descend) { 1470192895Sjamie if (prison_restrict_ip6(tpr, NULL)) { 1471192895Sjamie redo_ip6 = 1; 1472192895Sjamie descend = 0; 1473192895Sjamie } 1474192895Sjamie } 1475191673Sjamie } 1476191673Sjamie#endif 1477192895Sjamie if (gotslevel) { 1478191673Sjamie pr->pr_securelevel = slevel; 1479192895Sjamie /* Set all child jails to be at least this level. */ 1480192895Sjamie FOREACH_PRISON_DESCENDANT_LOCKED(pr, tpr, descend) 1481192895Sjamie if (tpr->pr_securelevel < slevel) 1482192895Sjamie tpr->pr_securelevel = slevel; 1483192895Sjamie } 1484192895Sjamie if (gotenforce) { 1485192895Sjamie pr->pr_enforce_statfs = enforce; 1486192895Sjamie /* Pass this restriction on to the children. */ 1487192895Sjamie FOREACH_PRISON_DESCENDANT_LOCKED(pr, tpr, descend) 1488192895Sjamie if (tpr->pr_enforce_statfs < enforce) 1489192895Sjamie tpr->pr_enforce_statfs = enforce; 1490192895Sjamie } 1491192895Sjamie if (name != NULL) { 1492192895Sjamie if (ppr == &prison0) 1493192895Sjamie strlcpy(pr->pr_name, name, sizeof(pr->pr_name)); 1494192895Sjamie else 1495192895Sjamie snprintf(pr->pr_name, sizeof(pr->pr_name), "%s.%s", 1496192895Sjamie ppr->pr_name, name); 1497192895Sjamie /* Change this component of child names. */ 1498192895Sjamie FOREACH_PRISON_DESCENDANT_LOCKED(pr, tpr, descend) { 1499192895Sjamie bcopy(tpr->pr_name + onamelen, tpr->pr_name + namelen, 1500192895Sjamie strlen(tpr->pr_name + onamelen) + 1); 1501192895Sjamie bcopy(pr->pr_name, tpr->pr_name, namelen); 1502192895Sjamie } 1503192895Sjamie } 1504191673Sjamie if (path != NULL) { 1505192895Sjamie /* Try to keep a real-rooted full pathname. */ 1506192895Sjamie if (path[0] == '/' && strcmp(mypr->pr_path, "/")) 1507192895Sjamie snprintf(pr->pr_path, sizeof(pr->pr_path), "%s%s", 1508192895Sjamie mypr->pr_path, path); 1509192895Sjamie else 1510192895Sjamie strlcpy(pr->pr_path, path, sizeof(pr->pr_path)); 1511191673Sjamie pr->pr_root = root; 1512191673Sjamie } 1513193066Sjamie if (PR_HOST & ch_flags & ~pr_flags) { 1514193066Sjamie if (pr->pr_flags & PR_HOST) { 1515193066Sjamie /* 1516193066Sjamie * Copy the parent's host info. As with pr_ip4 above, 1517193066Sjamie * the lack of a lock on the parent is not a problem; 1518193066Sjamie * it is always set with allprison_lock at least 1519193066Sjamie * shared, and is held exclusively here. 1520193066Sjamie */ 1521193066Sjamie strlcpy(pr->pr_host, pr->pr_parent->pr_host, 1522193066Sjamie sizeof(pr->pr_host)); 1523193066Sjamie strlcpy(pr->pr_domain, pr->pr_parent->pr_domain, 1524193066Sjamie sizeof(pr->pr_domain)); 1525193066Sjamie strlcpy(pr->pr_uuid, pr->pr_parent->pr_uuid, 1526193066Sjamie sizeof(pr->pr_uuid)); 1527193066Sjamie pr->pr_hostid = pr->pr_parent->pr_hostid; 1528193066Sjamie } 1529193066Sjamie } else if (host != NULL || domain != NULL || uuid != NULL || gothid) { 1530193066Sjamie /* Set this prison, and any descendants without PR_HOST. */ 1531193066Sjamie if (host != NULL) 1532193066Sjamie strlcpy(pr->pr_host, host, sizeof(pr->pr_host)); 1533193066Sjamie if (domain != NULL) 1534193066Sjamie strlcpy(pr->pr_domain, domain, sizeof(pr->pr_domain)); 1535193066Sjamie if (uuid != NULL) 1536193066Sjamie strlcpy(pr->pr_uuid, uuid, sizeof(pr->pr_uuid)); 1537193066Sjamie if (gothid) 1538193066Sjamie pr->pr_hostid = hid; 1539193066Sjamie FOREACH_PRISON_DESCENDANT_LOCKED(pr, tpr, descend) { 1540193066Sjamie if (tpr->pr_flags & PR_HOST) 1541193066Sjamie descend = 0; 1542193066Sjamie else { 1543193066Sjamie if (host != NULL) 1544193066Sjamie strlcpy(tpr->pr_host, pr->pr_host, 1545193066Sjamie sizeof(tpr->pr_host)); 1546193066Sjamie if (domain != NULL) 1547193066Sjamie strlcpy(tpr->pr_domain, pr->pr_domain, 1548193066Sjamie sizeof(tpr->pr_domain)); 1549193066Sjamie if (uuid != NULL) 1550193066Sjamie strlcpy(tpr->pr_uuid, pr->pr_uuid, 1551193066Sjamie sizeof(tpr->pr_uuid)); 1552193066Sjamie if (gothid) 1553193066Sjamie tpr->pr_hostid = hid; 1554193066Sjamie } 1555193066Sjamie } 1556193066Sjamie } 1557192895Sjamie if ((tallow = ch_allow & ~pr_allow)) { 1558192895Sjamie /* Clear allow bits in all children. */ 1559192895Sjamie FOREACH_PRISON_DESCENDANT_LOCKED(pr, tpr, descend) 1560192895Sjamie tpr->pr_allow &= ~tallow; 1561192895Sjamie } 1562192895Sjamie pr->pr_allow = (pr->pr_allow & ~ch_allow) | pr_allow; 1563191673Sjamie /* 1564191673Sjamie * Persistent prisons get an extra reference, and prisons losing their 1565191673Sjamie * persist flag lose that reference. Only do this for existing prisons 1566191673Sjamie * for now, so new ones will remain unseen until after the module 1567191673Sjamie * handlers have completed. 1568191673Sjamie */ 1569191673Sjamie if (!created && (ch_flags & PR_PERSIST & (pr_flags ^ pr->pr_flags))) { 1570191673Sjamie if (pr_flags & PR_PERSIST) { 1571191673Sjamie pr->pr_ref++; 1572191673Sjamie pr->pr_uref++; 1573191673Sjamie } else { 1574191673Sjamie pr->pr_ref--; 1575191673Sjamie pr->pr_uref--; 1576191673Sjamie } 1577191673Sjamie } 1578191673Sjamie pr->pr_flags = (pr->pr_flags & ~ch_flags) | pr_flags; 1579191673Sjamie mtx_unlock(&pr->pr_mtx); 1580185435Sbz 1581192895Sjamie /* Locks may have prevented a complete restriction of child IP 1582192895Sjamie * addresses. If so, allocate some more memory and try again. 1583192895Sjamie */ 1584192895Sjamie#ifdef INET 1585192895Sjamie while (redo_ip4) { 1586192895Sjamie ip4s = pr->pr_ip4s; 1587192895Sjamie ip4 = malloc(ip4s * sizeof(*ip4), M_PRISON, M_WAITOK); 1588192895Sjamie mtx_lock(&pr->pr_mtx); 1589192895Sjamie redo_ip4 = 0; 1590192895Sjamie FOREACH_PRISON_DESCENDANT_LOCKED(pr, tpr, descend) { 1591192895Sjamie if (prison_restrict_ip4(tpr, ip4)) { 1592192895Sjamie if (ip4 != NULL) 1593192895Sjamie ip4 = NULL; 1594192895Sjamie else 1595192895Sjamie redo_ip4 = 1; 1596192895Sjamie } 1597192895Sjamie } 1598192895Sjamie mtx_unlock(&pr->pr_mtx); 1599192895Sjamie } 1600192895Sjamie#endif 1601192895Sjamie#ifdef INET6 1602192895Sjamie while (redo_ip6) { 1603192895Sjamie ip6s = pr->pr_ip6s; 1604192895Sjamie ip6 = malloc(ip6s * sizeof(*ip6), M_PRISON, M_WAITOK); 1605192895Sjamie mtx_lock(&pr->pr_mtx); 1606192895Sjamie redo_ip6 = 0; 1607192895Sjamie FOREACH_PRISON_DESCENDANT_LOCKED(pr, tpr, descend) { 1608192895Sjamie if (prison_restrict_ip6(tpr, ip6)) { 1609192895Sjamie if (ip6 != NULL) 1610192895Sjamie ip6 = NULL; 1611192895Sjamie else 1612192895Sjamie redo_ip6 = 1; 1613192895Sjamie } 1614192895Sjamie } 1615192895Sjamie mtx_unlock(&pr->pr_mtx); 1616192895Sjamie } 1617192895Sjamie#endif 1618192895Sjamie 1619191673Sjamie /* Let the modules do their work. */ 1620191673Sjamie sx_downgrade(&allprison_lock); 1621191673Sjamie if (created) { 1622191673Sjamie error = osd_jail_call(pr, PR_METHOD_CREATE, opts); 1623191673Sjamie if (error) { 1624191673Sjamie prison_deref(pr, PD_LIST_SLOCKED); 1625191673Sjamie goto done_errmsg; 1626191673Sjamie } 1627191673Sjamie } 1628191673Sjamie error = osd_jail_call(pr, PR_METHOD_SET, opts); 1629191673Sjamie if (error) { 1630191673Sjamie prison_deref(pr, created 1631191673Sjamie ? PD_LIST_SLOCKED 1632191673Sjamie : PD_DEREF | PD_LIST_SLOCKED); 1633191673Sjamie goto done_errmsg; 1634191673Sjamie } 1635191673Sjamie 1636191673Sjamie /* Attach this process to the prison if requested. */ 1637191673Sjamie if (flags & JAIL_ATTACH) { 1638191673Sjamie mtx_lock(&pr->pr_mtx); 1639191673Sjamie error = do_jail_attach(td, pr); 1640191673Sjamie if (error) { 1641191673Sjamie vfs_opterror(opts, "attach failed"); 1642191673Sjamie if (!created) 1643191673Sjamie prison_deref(pr, PD_DEREF); 1644191673Sjamie goto done_errmsg; 1645191673Sjamie } 1646191673Sjamie } 1647191673Sjamie 1648191673Sjamie /* 1649191673Sjamie * Now that it is all there, drop the temporary reference from existing 1650191673Sjamie * prisons. Or add a reference to newly created persistent prisons 1651191673Sjamie * (which was not done earlier so that the prison would not be publicly 1652191673Sjamie * visible). 1653191673Sjamie */ 1654191673Sjamie if (!created) { 1655191673Sjamie prison_deref(pr, (flags & JAIL_ATTACH) 1656191673Sjamie ? PD_DEREF 1657191673Sjamie : PD_DEREF | PD_LIST_SLOCKED); 1658191673Sjamie } else { 1659191673Sjamie if (pr_flags & PR_PERSIST) { 1660191673Sjamie mtx_lock(&pr->pr_mtx); 1661191673Sjamie pr->pr_ref++; 1662191673Sjamie pr->pr_uref++; 1663191673Sjamie mtx_unlock(&pr->pr_mtx); 1664191673Sjamie } 1665191673Sjamie if (!(flags & JAIL_ATTACH)) 1666191673Sjamie sx_sunlock(&allprison_lock); 1667191673Sjamie } 1668191673Sjamie td->td_retval[0] = pr->pr_id; 1669191673Sjamie goto done_errmsg; 1670191673Sjamie 1671192895Sjamie done_deref_locked: 1672192895Sjamie prison_deref(pr, created 1673192895Sjamie ? PD_LOCKED | PD_LIST_XLOCKED 1674192895Sjamie : PD_DEREF | PD_LOCKED | PD_LIST_XLOCKED); 1675192895Sjamie goto done_releroot; 1676191673Sjamie done_unlock_list: 1677191673Sjamie sx_xunlock(&allprison_lock); 1678191673Sjamie done_releroot: 1679191673Sjamie if (root != NULL) { 1680191673Sjamie vfslocked = VFS_LOCK_GIANT(root->v_mount); 1681191673Sjamie vrele(root); 1682191673Sjamie VFS_UNLOCK_GIANT(vfslocked); 1683191673Sjamie } 1684191673Sjamie done_errmsg: 1685191673Sjamie if (error) { 1686191673Sjamie vfs_getopt(opts, "errmsg", (void **)&errmsg, &errmsg_len); 1687191673Sjamie if (errmsg_len > 0) { 1688191673Sjamie errmsg_pos = 2 * vfs_getopt_pos(opts, "errmsg") + 1; 1689191673Sjamie if (errmsg_pos > 0) { 1690191673Sjamie if (optuio->uio_segflg == UIO_SYSSPACE) 1691191673Sjamie bcopy(errmsg, 1692191673Sjamie optuio->uio_iov[errmsg_pos].iov_base, 1693191673Sjamie errmsg_len); 1694191673Sjamie else 1695191673Sjamie copyout(errmsg, 1696191673Sjamie optuio->uio_iov[errmsg_pos].iov_base, 1697191673Sjamie errmsg_len); 1698191673Sjamie } 1699191673Sjamie } 1700191673Sjamie } 1701191673Sjamie done_free: 1702191673Sjamie#ifdef INET 1703191673Sjamie free(ip4, M_PRISON); 1704191673Sjamie#endif 1705191673Sjamie#ifdef INET6 1706191673Sjamie free(ip6, M_PRISON); 1707191673Sjamie#endif 1708191673Sjamie vfs_freeopts(opts); 1709191673Sjamie return (error); 1710191673Sjamie} 1711191673Sjamie 1712191673Sjamie 171382710Sdillon/* 1714191673Sjamie * struct jail_get_args { 1715191673Sjamie * struct iovec *iovp; 1716191673Sjamie * unsigned int iovcnt; 1717191673Sjamie * int flags; 1718114168Smike * }; 171982710Sdillon */ 172046155Sphkint 1721191673Sjamiejail_get(struct thread *td, struct jail_get_args *uap) 172246155Sphk{ 1723191673Sjamie struct uio *auio; 1724185435Sbz int error; 1725185435Sbz 1726191673Sjamie /* Check that we have an even number of iovecs. */ 1727191673Sjamie if (uap->iovcnt & 1) 1728191673Sjamie return (EINVAL); 1729191673Sjamie 1730191673Sjamie error = copyinuio(uap->iovp, uap->iovcnt, &auio); 1731185435Sbz if (error) 1732185435Sbz return (error); 1733191673Sjamie error = kern_jail_get(td, auio, uap->flags); 1734191673Sjamie if (error == 0) 1735191673Sjamie error = copyout(auio->uio_iov, uap->iovp, 1736191673Sjamie uap->iovcnt * sizeof (struct iovec)); 1737191673Sjamie free(auio, M_IOV); 1738191673Sjamie return (error); 1739191673Sjamie} 1740185435Sbz 1741191673Sjamieint 1742191673Sjamiekern_jail_get(struct thread *td, struct uio *optuio, int flags) 1743191673Sjamie{ 1744192895Sjamie struct prison *pr, *mypr; 1745191673Sjamie struct vfsopt *opt; 1746191673Sjamie struct vfsoptlist *opts; 1747191673Sjamie char *errmsg, *name; 1748192895Sjamie int error, errmsg_len, errmsg_pos, fi, i, jid, len, locked, pos; 1749185435Sbz 1750191673Sjamie if (flags & ~JAIL_GET_MASK) 1751191673Sjamie return (EINVAL); 1752185435Sbz 1753191673Sjamie /* Get the parameter list. */ 1754191673Sjamie error = vfs_buildopts(optuio, &opts); 1755191673Sjamie if (error) 1756191673Sjamie return (error); 1757191673Sjamie errmsg_pos = vfs_getopt_pos(opts, "errmsg"); 1758192895Sjamie mypr = td->td_ucred->cr_prison; 1759185435Sbz 1760191673Sjamie /* 1761191673Sjamie * Find the prison specified by one of: lastjid, jid, name. 1762191673Sjamie */ 1763191673Sjamie sx_slock(&allprison_lock); 1764191673Sjamie error = vfs_copyopt(opts, "lastjid", &jid, sizeof(jid)); 1765191673Sjamie if (error == 0) { 1766191673Sjamie TAILQ_FOREACH(pr, &allprison, pr_list) { 1767192895Sjamie if (pr->pr_id > jid && prison_ischild(mypr, pr)) { 1768191673Sjamie mtx_lock(&pr->pr_mtx); 1769191673Sjamie if (pr->pr_ref > 0 && 1770191673Sjamie (pr->pr_uref > 0 || (flags & JAIL_DYING))) 1771191673Sjamie break; 1772191673Sjamie mtx_unlock(&pr->pr_mtx); 1773191673Sjamie } 1774191673Sjamie } 1775191673Sjamie if (pr != NULL) 1776191673Sjamie goto found_prison; 1777191673Sjamie error = ENOENT; 1778191673Sjamie vfs_opterror(opts, "no jail after %d", jid); 1779191673Sjamie goto done_unlock_list; 1780191673Sjamie } else if (error != ENOENT) 1781191673Sjamie goto done_unlock_list; 1782185435Sbz 1783191673Sjamie error = vfs_copyopt(opts, "jid", &jid, sizeof(jid)); 1784191673Sjamie if (error == 0) { 1785191673Sjamie if (jid != 0) { 1786192895Sjamie pr = prison_find_child(mypr, jid); 1787191673Sjamie if (pr != NULL) { 1788191673Sjamie if (pr->pr_uref == 0 && !(flags & JAIL_DYING)) { 1789191673Sjamie mtx_unlock(&pr->pr_mtx); 1790191673Sjamie error = ENOENT; 1791191673Sjamie vfs_opterror(opts, "jail %d is dying", 1792191673Sjamie jid); 1793191673Sjamie goto done_unlock_list; 1794191673Sjamie } 1795191673Sjamie goto found_prison; 1796191673Sjamie } 1797191673Sjamie error = ENOENT; 1798191673Sjamie vfs_opterror(opts, "jail %d not found", jid); 1799191673Sjamie goto done_unlock_list; 1800191673Sjamie } 1801191673Sjamie } else if (error != ENOENT) 1802191673Sjamie goto done_unlock_list; 180346155Sphk 1804191673Sjamie error = vfs_getopt(opts, "name", (void **)&name, &len); 1805191673Sjamie if (error == 0) { 1806191673Sjamie if (len == 0 || name[len - 1] != '\0') { 1807191673Sjamie error = EINVAL; 1808191673Sjamie goto done_unlock_list; 1809191673Sjamie } 1810192895Sjamie pr = prison_find_name(mypr, name); 1811191673Sjamie if (pr != NULL) { 1812191673Sjamie if (pr->pr_uref == 0 && !(flags & JAIL_DYING)) { 1813191673Sjamie mtx_unlock(&pr->pr_mtx); 1814191673Sjamie error = ENOENT; 1815191673Sjamie vfs_opterror(opts, "jail \"%s\" is dying", 1816191673Sjamie name); 1817191673Sjamie goto done_unlock_list; 1818191673Sjamie } 1819191673Sjamie goto found_prison; 1820191673Sjamie } 1821191673Sjamie error = ENOENT; 1822191673Sjamie vfs_opterror(opts, "jail \"%s\" not found", name); 1823191673Sjamie goto done_unlock_list; 1824191673Sjamie } else if (error != ENOENT) 1825191673Sjamie goto done_unlock_list; 1826185435Sbz 1827191673Sjamie vfs_opterror(opts, "no jail specified"); 1828191673Sjamie error = ENOENT; 1829191673Sjamie goto done_unlock_list; 1830191673Sjamie 1831191673Sjamie found_prison: 1832191673Sjamie /* Get the parameters of the prison. */ 1833191673Sjamie pr->pr_ref++; 1834191673Sjamie locked = PD_LOCKED; 1835191673Sjamie td->td_retval[0] = pr->pr_id; 1836191673Sjamie error = vfs_setopt(opts, "jid", &pr->pr_id, sizeof(pr->pr_id)); 1837191673Sjamie if (error != 0 && error != ENOENT) 1838191673Sjamie goto done_deref; 1839192895Sjamie i = (pr->pr_parent == mypr) ? 0 : pr->pr_parent->pr_id; 1840192895Sjamie error = vfs_setopt(opts, "parent", &i, sizeof(i)); 1841191673Sjamie if (error != 0 && error != ENOENT) 1842191673Sjamie goto done_deref; 1843192895Sjamie error = vfs_setopts(opts, "name", prison_name(mypr, pr)); 1844192895Sjamie if (error != 0 && error != ENOENT) 1845192895Sjamie goto done_deref; 1846192895Sjamie error = vfs_setopt(opts, "cpuset.id", &pr->pr_cpuset->cs_id, 1847191673Sjamie sizeof(pr->pr_cpuset->cs_id)); 1848191673Sjamie if (error != 0 && error != ENOENT) 1849191673Sjamie goto done_deref; 1850192895Sjamie error = vfs_setopts(opts, "path", prison_path(mypr, pr)); 1851191673Sjamie if (error != 0 && error != ENOENT) 1852191673Sjamie goto done_deref; 1853191673Sjamie#ifdef INET 1854191673Sjamie error = vfs_setopt_part(opts, "ip4.addr", pr->pr_ip4, 1855191673Sjamie pr->pr_ip4s * sizeof(*pr->pr_ip4)); 1856191673Sjamie if (error != 0 && error != ENOENT) 1857191673Sjamie goto done_deref; 1858191673Sjamie#endif 1859191673Sjamie#ifdef INET6 1860191673Sjamie error = vfs_setopt_part(opts, "ip6.addr", pr->pr_ip6, 1861191673Sjamie pr->pr_ip6s * sizeof(*pr->pr_ip6)); 1862191673Sjamie if (error != 0 && error != ENOENT) 1863191673Sjamie goto done_deref; 1864191673Sjamie#endif 1865191673Sjamie error = vfs_setopt(opts, "securelevel", &pr->pr_securelevel, 1866191673Sjamie sizeof(pr->pr_securelevel)); 1867191673Sjamie if (error != 0 && error != ENOENT) 1868191673Sjamie goto done_deref; 1869191673Sjamie error = vfs_setopts(opts, "host.hostname", pr->pr_host); 1870191673Sjamie if (error != 0 && error != ENOENT) 1871191673Sjamie goto done_deref; 1872193066Sjamie error = vfs_setopts(opts, "host.domainname", pr->pr_domain); 1873193066Sjamie if (error != 0 && error != ENOENT) 1874193066Sjamie goto done_deref; 1875193066Sjamie error = vfs_setopts(opts, "host.hostuuid", pr->pr_uuid); 1876193066Sjamie if (error != 0 && error != ENOENT) 1877193066Sjamie goto done_deref; 1878193066Sjamie#ifdef COMPAT_IA32 1879193066Sjamie if (td->td_proc->p_sysent->sv_flags & SV_IA32) { 1880193066Sjamie uint32_t hid32 = pr->pr_hostid; 1881193066Sjamie 1882193066Sjamie error = vfs_setopt(opts, "host.hostid", &hid32, sizeof(hid32)); 1883193066Sjamie } else 1884193066Sjamie#endif 1885193066Sjamie error = vfs_setopt(opts, "host.hostid", &pr->pr_hostid, 1886193066Sjamie sizeof(pr->pr_hostid)); 1887193066Sjamie if (error != 0 && error != ENOENT) 1888193066Sjamie goto done_deref; 1889192895Sjamie error = vfs_setopt(opts, "enforce_statfs", &pr->pr_enforce_statfs, 1890192895Sjamie sizeof(pr->pr_enforce_statfs)); 1891191673Sjamie if (error != 0 && error != ENOENT) 1892191673Sjamie goto done_deref; 1893192895Sjamie for (fi = 0; fi < sizeof(pr_flag_names) / sizeof(pr_flag_names[0]); 1894192895Sjamie fi++) { 1895192895Sjamie if (pr_flag_names[fi] == NULL) 1896192895Sjamie continue; 1897192895Sjamie i = (pr->pr_flags & (1 << fi)) ? 1 : 0; 1898192895Sjamie error = vfs_setopt(opts, pr_flag_names[fi], &i, sizeof(i)); 1899192895Sjamie if (error != 0 && error != ENOENT) 1900192895Sjamie goto done_deref; 1901192895Sjamie i = !i; 1902192895Sjamie error = vfs_setopt(opts, pr_flag_nonames[fi], &i, sizeof(i)); 1903192895Sjamie if (error != 0 && error != ENOENT) 1904192895Sjamie goto done_deref; 1905192895Sjamie } 1906192895Sjamie for (fi = 0; fi < sizeof(pr_allow_names) / sizeof(pr_allow_names[0]); 1907192895Sjamie fi++) { 1908192895Sjamie if (pr_allow_names[fi] == NULL) 1909192895Sjamie continue; 1910192895Sjamie i = (pr->pr_allow & (1 << fi)) ? 1 : 0; 1911192895Sjamie error = vfs_setopt(opts, pr_allow_names[fi], &i, sizeof(i)); 1912192895Sjamie if (error != 0 && error != ENOENT) 1913192895Sjamie goto done_deref; 1914192895Sjamie i = !i; 1915192895Sjamie error = vfs_setopt(opts, pr_allow_nonames[fi], &i, sizeof(i)); 1916192895Sjamie if (error != 0 && error != ENOENT) 1917192895Sjamie goto done_deref; 1918192895Sjamie } 1919191673Sjamie i = (pr->pr_uref == 0); 1920191673Sjamie error = vfs_setopt(opts, "dying", &i, sizeof(i)); 1921191673Sjamie if (error != 0 && error != ENOENT) 1922191673Sjamie goto done_deref; 1923191673Sjamie i = !i; 1924191673Sjamie error = vfs_setopt(opts, "nodying", &i, sizeof(i)); 1925191673Sjamie if (error != 0 && error != ENOENT) 1926191673Sjamie goto done_deref; 1927191673Sjamie 1928191673Sjamie /* Get the module parameters. */ 1929191673Sjamie mtx_unlock(&pr->pr_mtx); 1930191673Sjamie locked = 0; 1931191673Sjamie error = osd_jail_call(pr, PR_METHOD_GET, opts); 193246155Sphk if (error) 1933191673Sjamie goto done_deref; 1934191673Sjamie prison_deref(pr, PD_DEREF | PD_LIST_SLOCKED); 193584828Sjhb 1936191673Sjamie /* By now, all parameters should have been noted. */ 1937191673Sjamie TAILQ_FOREACH(opt, opts, link) { 1938191673Sjamie if (!opt->seen && strcmp(opt->name, "errmsg")) { 1939191673Sjamie error = EINVAL; 1940191673Sjamie vfs_opterror(opts, "unknown parameter: %s", opt->name); 1941191673Sjamie goto done_errmsg; 1942191673Sjamie } 1943185435Sbz } 1944191673Sjamie 1945191673Sjamie /* Write the fetched parameters back to userspace. */ 1946191673Sjamie error = 0; 1947191673Sjamie TAILQ_FOREACH(opt, opts, link) { 1948191673Sjamie if (opt->pos >= 0 && opt->pos != errmsg_pos) { 1949191673Sjamie pos = 2 * opt->pos + 1; 1950191673Sjamie optuio->uio_iov[pos].iov_len = opt->len; 1951191673Sjamie if (opt->value != NULL) { 1952191673Sjamie if (optuio->uio_segflg == UIO_SYSSPACE) { 1953191673Sjamie bcopy(opt->value, 1954191673Sjamie optuio->uio_iov[pos].iov_base, 1955191673Sjamie opt->len); 1956191673Sjamie } else { 1957191673Sjamie error = copyout(opt->value, 1958191673Sjamie optuio->uio_iov[pos].iov_base, 1959191673Sjamie opt->len); 1960191673Sjamie if (error) 1961191673Sjamie break; 1962191673Sjamie } 1963191673Sjamie } 1964191673Sjamie } 1965185435Sbz } 1966191673Sjamie goto done_errmsg; 1967191673Sjamie 1968191673Sjamie done_deref: 1969191673Sjamie prison_deref(pr, locked | PD_DEREF | PD_LIST_SLOCKED); 1970191673Sjamie goto done_errmsg; 1971191673Sjamie 1972191673Sjamie done_unlock_list: 1973191673Sjamie sx_sunlock(&allprison_lock); 1974191673Sjamie done_errmsg: 1975191673Sjamie if (error && errmsg_pos >= 0) { 1976191673Sjamie vfs_getopt(opts, "errmsg", (void **)&errmsg, &errmsg_len); 1977191673Sjamie errmsg_pos = 2 * errmsg_pos + 1; 1978191673Sjamie if (errmsg_len > 0) { 1979191673Sjamie if (optuio->uio_segflg == UIO_SYSSPACE) 1980191673Sjamie bcopy(errmsg, 1981191673Sjamie optuio->uio_iov[errmsg_pos].iov_base, 1982191673Sjamie errmsg_len); 1983191673Sjamie else 1984191673Sjamie copyout(errmsg, 1985191673Sjamie optuio->uio_iov[errmsg_pos].iov_base, 1986191673Sjamie errmsg_len); 1987191673Sjamie } 1988185435Sbz } 1989191673Sjamie vfs_freeopts(opts); 1990191673Sjamie return (error); 1991191673Sjamie} 1992113275Smike 1993192895Sjamie 1994191673Sjamie/* 1995191673Sjamie * struct jail_remove_args { 1996191673Sjamie * int jid; 1997191673Sjamie * }; 1998191673Sjamie */ 1999191673Sjamieint 2000191673Sjamiejail_remove(struct thread *td, struct jail_remove_args *uap) 2001191673Sjamie{ 2002192895Sjamie struct prison *pr, *cpr, *lpr, *tpr; 2003192895Sjamie int descend, error; 2004185435Sbz 2005191673Sjamie error = priv_check(td, PRIV_JAIL_REMOVE); 2006185435Sbz if (error) 2007191673Sjamie return (error); 2008185435Sbz 2009185435Sbz sx_xlock(&allprison_lock); 2010192895Sjamie pr = prison_find_child(td->td_ucred->cr_prison, uap->jid); 2011191673Sjamie if (pr == NULL) { 2012185435Sbz sx_xunlock(&allprison_lock); 2013191673Sjamie return (EINVAL); 2014185435Sbz } 2015185435Sbz 2016192895Sjamie /* Remove all descendants of this prison, then remove this prison. */ 2017192895Sjamie pr->pr_ref++; 2018192895Sjamie pr->pr_flags |= PR_REMOVE; 2019192895Sjamie if (!LIST_EMPTY(&pr->pr_children)) { 2020192895Sjamie mtx_unlock(&pr->pr_mtx); 2021192895Sjamie lpr = NULL; 2022192895Sjamie FOREACH_PRISON_DESCENDANT(pr, cpr, descend) { 2023192895Sjamie mtx_lock(&cpr->pr_mtx); 2024192895Sjamie if (cpr->pr_ref > 0) { 2025192895Sjamie tpr = cpr; 2026192895Sjamie cpr->pr_ref++; 2027192895Sjamie cpr->pr_flags |= PR_REMOVE; 2028192895Sjamie } else { 2029192895Sjamie /* Already removed - do not do it again. */ 2030192895Sjamie tpr = NULL; 2031192895Sjamie } 2032192895Sjamie mtx_unlock(&cpr->pr_mtx); 2033192895Sjamie if (lpr != NULL) { 2034192895Sjamie mtx_lock(&lpr->pr_mtx); 2035192895Sjamie prison_remove_one(lpr); 2036192895Sjamie sx_xlock(&allprison_lock); 2037192895Sjamie } 2038192895Sjamie lpr = tpr; 2039192895Sjamie } 2040192895Sjamie if (lpr != NULL) { 2041192895Sjamie mtx_lock(&lpr->pr_mtx); 2042192895Sjamie prison_remove_one(lpr); 2043192895Sjamie sx_xlock(&allprison_lock); 2044192895Sjamie } 2045192895Sjamie mtx_lock(&pr->pr_mtx); 2046192895Sjamie } 2047192895Sjamie prison_remove_one(pr); 2048192895Sjamie return (0); 2049192895Sjamie} 2050192895Sjamie 2051192895Sjamiestatic void 2052192895Sjamieprison_remove_one(struct prison *pr) 2053192895Sjamie{ 2054192895Sjamie struct proc *p; 2055192895Sjamie int deuref; 2056192895Sjamie 2057191673Sjamie /* If the prison was persistent, it is not anymore. */ 2058191673Sjamie deuref = 0; 2059191673Sjamie if (pr->pr_flags & PR_PERSIST) { 2060191673Sjamie pr->pr_ref--; 2061191673Sjamie deuref = PD_DEUREF; 2062191673Sjamie pr->pr_flags &= ~PR_PERSIST; 2063179881Sdelphij } 2064113275Smike 2065192895Sjamie /* 2066192895Sjamie * jail_remove added a reference. If that's the only one, remove 2067192895Sjamie * the prison now. 2068192895Sjamie */ 2069192895Sjamie KASSERT(pr->pr_ref > 0, 2070192895Sjamie ("prison_remove_one removing a dead prison (jid=%d)", pr->pr_id)); 2071192895Sjamie if (pr->pr_ref == 1) { 2072191673Sjamie prison_deref(pr, 2073191673Sjamie deuref | PD_DEREF | PD_LOCKED | PD_LIST_XLOCKED); 2074192895Sjamie return; 2075191673Sjamie } 2076191673Sjamie 2077113275Smike mtx_unlock(&pr->pr_mtx); 2078191673Sjamie sx_xunlock(&allprison_lock); 2079191673Sjamie /* 2080191673Sjamie * Kill all processes unfortunate enough to be attached to this prison. 2081191673Sjamie */ 2082191673Sjamie sx_slock(&allproc_lock); 2083191673Sjamie LIST_FOREACH(p, &allproc, p_list) { 2084191673Sjamie PROC_LOCK(p); 2085191673Sjamie if (p->p_state != PRS_NEW && p->p_ucred && 2086191673Sjamie p->p_ucred->cr_prison == pr) 2087191673Sjamie psignal(p, SIGKILL); 2088191673Sjamie PROC_UNLOCK(p); 2089191673Sjamie } 2090191673Sjamie sx_sunlock(&allproc_lock); 2091192895Sjamie /* Remove the temporary reference added by jail_remove. */ 2092191673Sjamie prison_deref(pr, deuref | PD_DEREF); 2093113275Smike} 2094113275Smike 2095190466Sjamie 2096113275Smike/* 2097114168Smike * struct jail_attach_args { 2098114168Smike * int jid; 2099114168Smike * }; 2100113275Smike */ 2101113275Smikeint 2102114168Smikejail_attach(struct thread *td, struct jail_attach_args *uap) 2103113275Smike{ 2104113275Smike struct prison *pr; 2105191673Sjamie int error; 2106167309Spjd 2107164032Srwatson error = priv_check(td, PRIV_JAIL_ATTACH); 2108126023Snectar if (error) 2109126023Snectar return (error); 2110126023Snectar 2111168401Spjd sx_slock(&allprison_lock); 2112192895Sjamie pr = prison_find_child(td->td_ucred->cr_prison, uap->jid); 2113113275Smike if (pr == NULL) { 2114168401Spjd sx_sunlock(&allprison_lock); 2115113275Smike return (EINVAL); 2116113275Smike } 2117185435Sbz 2118185435Sbz /* 2119185435Sbz * Do not allow a process to attach to a prison that is not 2120191673Sjamie * considered to be "alive". 2121185435Sbz */ 2122191673Sjamie if (pr->pr_uref == 0) { 2123185435Sbz mtx_unlock(&pr->pr_mtx); 2124185435Sbz sx_sunlock(&allprison_lock); 2125185435Sbz return (EINVAL); 2126185435Sbz } 2127191673Sjamie 2128191673Sjamie return (do_jail_attach(td, pr)); 2129191673Sjamie} 2130191673Sjamie 2131191673Sjamiestatic int 2132191673Sjamiedo_jail_attach(struct thread *td, struct prison *pr) 2133191673Sjamie{ 2134192895Sjamie struct prison *ppr; 2135191673Sjamie struct proc *p; 2136191673Sjamie struct ucred *newcred, *oldcred; 2137191673Sjamie int vfslocked, error; 2138191673Sjamie 2139191673Sjamie /* 2140191673Sjamie * XXX: Note that there is a slight race here if two threads 2141191673Sjamie * in the same privileged process attempt to attach to two 2142191673Sjamie * different jails at the same time. It is important for 2143191673Sjamie * user processes not to do this, or they might end up with 2144191673Sjamie * a process root from one prison, but attached to the jail 2145191673Sjamie * of another. 2146191673Sjamie */ 2147113275Smike pr->pr_ref++; 2148191673Sjamie pr->pr_uref++; 2149113275Smike mtx_unlock(&pr->pr_mtx); 2150191673Sjamie 2151191673Sjamie /* Let modules do whatever they need to prepare for attaching. */ 2152191673Sjamie error = osd_jail_call(pr, PR_METHOD_ATTACH, td); 2153191673Sjamie if (error) { 2154191673Sjamie prison_deref(pr, PD_DEREF | PD_DEUREF | PD_LIST_SLOCKED); 2155191673Sjamie return (error); 2156191673Sjamie } 2157168401Spjd sx_sunlock(&allprison_lock); 2158113275Smike 2159185435Sbz /* 2160185435Sbz * Reparent the newly attached process to this jail. 2161185435Sbz */ 2162192895Sjamie ppr = td->td_ucred->cr_prison; 2163191673Sjamie p = td->td_proc; 2164185435Sbz error = cpuset_setproc_update_set(p, pr->pr_cpuset); 2165185435Sbz if (error) 2166191673Sjamie goto e_revert_osd; 2167185435Sbz 2168150652Scsjp vfslocked = VFS_LOCK_GIANT(pr->pr_root->v_mount); 2169175202Sattilio vn_lock(pr->pr_root, LK_EXCLUSIVE | LK_RETRY); 2170113275Smike if ((error = change_dir(pr->pr_root, td)) != 0) 2171113275Smike goto e_unlock; 2172113275Smike#ifdef MAC 2173172930Srwatson if ((error = mac_vnode_check_chroot(td->td_ucred, pr->pr_root))) 2174113275Smike goto e_unlock; 2175113275Smike#endif 2176175294Sattilio VOP_UNLOCK(pr->pr_root, 0); 2177191673Sjamie if ((error = change_root(pr->pr_root, td))) 2178191673Sjamie goto e_unlock_giant; 2179150652Scsjp VFS_UNLOCK_GIANT(vfslocked); 2180113275Smike 218184828Sjhb newcred = crget(); 218284828Sjhb PROC_LOCK(p); 218384828Sjhb oldcred = p->p_ucred; 2184113275Smike setsugid(p); 218584828Sjhb crcopy(newcred, oldcred); 2186113630Sjhb newcred->cr_prison = pr; 218784828Sjhb p->p_ucred = newcred; 218884828Sjhb PROC_UNLOCK(p); 218984828Sjhb crfree(oldcred); 2190192895Sjamie prison_deref(ppr, PD_DEREF | PD_DEUREF); 219146155Sphk return (0); 2192191673Sjamie e_unlock: 2193175294Sattilio VOP_UNLOCK(pr->pr_root, 0); 2194191673Sjamie e_unlock_giant: 2195150652Scsjp VFS_UNLOCK_GIANT(vfslocked); 2196191673Sjamie e_revert_osd: 2197191673Sjamie /* Tell modules this thread is still in its old jail after all. */ 2198192895Sjamie (void)osd_jail_call(ppr, PR_METHOD_ATTACH, td); 2199191673Sjamie prison_deref(pr, PD_DEREF | PD_DEUREF); 220046155Sphk return (error); 220146155Sphk} 220246155Sphk 2203192895Sjamie 2204113275Smike/* 2205113275Smike * Returns a locked prison instance, or NULL on failure. 2206113275Smike */ 2207168399Spjdstruct prison * 2208113275Smikeprison_find(int prid) 2209113275Smike{ 2210113275Smike struct prison *pr; 2211113275Smike 2212168401Spjd sx_assert(&allprison_lock, SX_LOCKED); 2213191673Sjamie TAILQ_FOREACH(pr, &allprison, pr_list) { 2214113275Smike if (pr->pr_id == prid) { 2215113275Smike mtx_lock(&pr->pr_mtx); 2216191673Sjamie if (pr->pr_ref > 0) 2217191673Sjamie return (pr); 2218191673Sjamie mtx_unlock(&pr->pr_mtx); 2219113275Smike } 2220113275Smike } 2221113275Smike return (NULL); 2222113275Smike} 2223113275Smike 2224191673Sjamie/* 2225192895Sjamie * Find a prison that is a descendant of mypr. Returns a locked prison or NULL. 2226191673Sjamie */ 2227191673Sjamiestruct prison * 2228192895Sjamieprison_find_child(struct prison *mypr, int prid) 2229191673Sjamie{ 2230192895Sjamie struct prison *pr; 2231192895Sjamie int descend; 2232192895Sjamie 2233192895Sjamie sx_assert(&allprison_lock, SX_LOCKED); 2234192895Sjamie FOREACH_PRISON_DESCENDANT(mypr, pr, descend) { 2235192895Sjamie if (pr->pr_id == prid) { 2236192895Sjamie mtx_lock(&pr->pr_mtx); 2237192895Sjamie if (pr->pr_ref > 0) 2238192895Sjamie return (pr); 2239192895Sjamie mtx_unlock(&pr->pr_mtx); 2240192895Sjamie } 2241192895Sjamie } 2242192895Sjamie return (NULL); 2243192895Sjamie} 2244192895Sjamie 2245192895Sjamie/* 2246192895Sjamie * Look for the name relative to mypr. Returns a locked prison or NULL. 2247192895Sjamie */ 2248192895Sjamiestruct prison * 2249192895Sjamieprison_find_name(struct prison *mypr, const char *name) 2250192895Sjamie{ 2251191673Sjamie struct prison *pr, *deadpr; 2252192895Sjamie size_t mylen; 2253192895Sjamie int descend; 2254191673Sjamie 2255191673Sjamie sx_assert(&allprison_lock, SX_LOCKED); 2256192895Sjamie mylen = (mypr == &prison0) ? 0 : strlen(mypr->pr_name) + 1; 2257191673Sjamie again: 2258191673Sjamie deadpr = NULL; 2259192895Sjamie FOREACH_PRISON_DESCENDANT(mypr, pr, descend) { 2260192895Sjamie if (!strcmp(pr->pr_name + mylen, name)) { 2261191673Sjamie mtx_lock(&pr->pr_mtx); 2262191673Sjamie if (pr->pr_ref > 0) { 2263191673Sjamie if (pr->pr_uref > 0) 2264191673Sjamie return (pr); 2265191673Sjamie deadpr = pr; 2266191673Sjamie } 2267191673Sjamie mtx_unlock(&pr->pr_mtx); 2268191673Sjamie } 2269191673Sjamie } 2270192895Sjamie /* There was no valid prison - perhaps there was a dying one. */ 2271191673Sjamie if (deadpr != NULL) { 2272191673Sjamie mtx_lock(&deadpr->pr_mtx); 2273191673Sjamie if (deadpr->pr_ref == 0) { 2274191673Sjamie mtx_unlock(&deadpr->pr_mtx); 2275191673Sjamie goto again; 2276191673Sjamie } 2277191673Sjamie } 2278191673Sjamie return (deadpr); 2279191673Sjamie} 2280191673Sjamie 2281191673Sjamie/* 2282192895Sjamie * See if a prison has the specific flag set. 2283192895Sjamie */ 2284192895Sjamieint 2285192895Sjamieprison_flag(struct ucred *cred, unsigned flag) 2286192895Sjamie{ 2287192895Sjamie 2288192895Sjamie /* This is an atomic read, so no locking is necessary. */ 2289192895Sjamie return (cred->cr_prison->pr_flags & flag); 2290192895Sjamie} 2291192895Sjamie 2292192895Sjamieint 2293192895Sjamieprison_allow(struct ucred *cred, unsigned flag) 2294192895Sjamie{ 2295192895Sjamie 2296192895Sjamie /* This is an atomic read, so no locking is necessary. */ 2297192895Sjamie return (cred->cr_prison->pr_allow & flag); 2298192895Sjamie} 2299192895Sjamie 2300192895Sjamie/* 2301191673Sjamie * Remove a prison reference. If that was the last reference, remove the 2302191673Sjamie * prison itself - but not in this context in case there are locks held. 2303191673Sjamie */ 230472786Srwatsonvoid 2305185029Spjdprison_free_locked(struct prison *pr) 230672786Srwatson{ 230772786Srwatson 2308185029Spjd mtx_assert(&pr->pr_mtx, MA_OWNED); 230972786Srwatson pr->pr_ref--; 231072786Srwatson if (pr->pr_ref == 0) { 2311168483Spjd mtx_unlock(&pr->pr_mtx); 2312124882Srwatson TASK_INIT(&pr->pr_task, 0, prison_complete, pr); 2313144660Sjeff taskqueue_enqueue(taskqueue_thread, &pr->pr_task); 231487275Srwatson return; 231572786Srwatson } 231687275Srwatson mtx_unlock(&pr->pr_mtx); 231772786Srwatson} 231872786Srwatson 2319185029Spjdvoid 2320185029Spjdprison_free(struct prison *pr) 2321185029Spjd{ 2322185029Spjd 2323185029Spjd mtx_lock(&pr->pr_mtx); 2324185029Spjd prison_free_locked(pr); 2325185029Spjd} 2326185029Spjd 2327124882Srwatsonstatic void 2328124882Srwatsonprison_complete(void *context, int pending) 2329124882Srwatson{ 2330191673Sjamie 2331191673Sjamie prison_deref((struct prison *)context, 0); 2332191673Sjamie} 2333191673Sjamie 2334191673Sjamie/* 2335191673Sjamie * Remove a prison reference (usually). This internal version assumes no 2336191673Sjamie * mutexes are held, except perhaps the prison itself. If there are no more 2337191673Sjamie * references, release and delist the prison. On completion, the prison lock 2338191673Sjamie * and the allprison lock are both unlocked. 2339191673Sjamie */ 2340191673Sjamiestatic void 2341191673Sjamieprison_deref(struct prison *pr, int flags) 2342191673Sjamie{ 2343192895Sjamie struct prison *ppr, *tpr; 2344150652Scsjp int vfslocked; 2345124882Srwatson 2346191673Sjamie if (!(flags & PD_LOCKED)) 2347191673Sjamie mtx_lock(&pr->pr_mtx); 2348192895Sjamie /* Decrement the user references in a separate loop. */ 2349191673Sjamie if (flags & PD_DEUREF) { 2350192895Sjamie for (tpr = pr;; tpr = tpr->pr_parent) { 2351192895Sjamie if (tpr != pr) 2352192895Sjamie mtx_lock(&tpr->pr_mtx); 2353192895Sjamie if (--tpr->pr_uref > 0) 2354192895Sjamie break; 2355192895Sjamie KASSERT(tpr != &prison0, ("prison0 pr_uref=0")); 2356192895Sjamie mtx_unlock(&tpr->pr_mtx); 2357192895Sjamie } 2358191673Sjamie /* Done if there were only user references to remove. */ 2359191673Sjamie if (!(flags & PD_DEREF)) { 2360192895Sjamie mtx_unlock(&tpr->pr_mtx); 2361191673Sjamie if (flags & PD_LIST_SLOCKED) 2362191673Sjamie sx_sunlock(&allprison_lock); 2363191673Sjamie else if (flags & PD_LIST_XLOCKED) 2364191673Sjamie sx_xunlock(&allprison_lock); 2365191673Sjamie return; 2366191673Sjamie } 2367192895Sjamie if (tpr != pr) { 2368192895Sjamie mtx_unlock(&tpr->pr_mtx); 2369192895Sjamie mtx_lock(&pr->pr_mtx); 2370192895Sjamie } 2371191673Sjamie } 2372124882Srwatson 2373192895Sjamie for (;;) { 2374192895Sjamie if (flags & PD_DEREF) 2375192895Sjamie pr->pr_ref--; 2376192895Sjamie /* If the prison still has references, nothing else to do. */ 2377192895Sjamie if (pr->pr_ref > 0) { 2378192895Sjamie mtx_unlock(&pr->pr_mtx); 2379192895Sjamie if (flags & PD_LIST_SLOCKED) 2380192895Sjamie sx_sunlock(&allprison_lock); 2381192895Sjamie else if (flags & PD_LIST_XLOCKED) 2382192895Sjamie sx_xunlock(&allprison_lock); 2383192895Sjamie return; 2384191673Sjamie } 2385191673Sjamie 2386192895Sjamie mtx_unlock(&pr->pr_mtx); 2387192895Sjamie if (flags & PD_LIST_SLOCKED) { 2388192895Sjamie if (!sx_try_upgrade(&allprison_lock)) { 2389192895Sjamie sx_sunlock(&allprison_lock); 2390192895Sjamie sx_xlock(&allprison_lock); 2391192895Sjamie } 2392192895Sjamie } else if (!(flags & PD_LIST_XLOCKED)) 2393192895Sjamie sx_xlock(&allprison_lock); 2394168489Spjd 2395192895Sjamie TAILQ_REMOVE(&allprison, pr, pr_list); 2396192895Sjamie LIST_REMOVE(pr, pr_sibling); 2397192895Sjamie ppr = pr->pr_parent; 2398192895Sjamie for (tpr = ppr; tpr != NULL; tpr = tpr->pr_parent) 2399192895Sjamie tpr->pr_prisoncount--; 2400192895Sjamie sx_downgrade(&allprison_lock); 2401192895Sjamie 2402192895Sjamie if (pr->pr_root != NULL) { 2403192895Sjamie vfslocked = VFS_LOCK_GIANT(pr->pr_root->v_mount); 2404192895Sjamie vrele(pr->pr_root); 2405192895Sjamie VFS_UNLOCK_GIANT(vfslocked); 2406192895Sjamie } 2407192895Sjamie mtx_destroy(&pr->pr_mtx); 2408191673Sjamie#ifdef INET 2409192895Sjamie free(pr->pr_ip4, M_PRISON); 2410191673Sjamie#endif 2411185435Sbz#ifdef INET6 2412192895Sjamie free(pr->pr_ip6, M_PRISON); 2413185435Sbz#endif 2414192895Sjamie if (pr->pr_cpuset != NULL) 2415192895Sjamie cpuset_rel(pr->pr_cpuset); 2416192895Sjamie osd_jail_exit(pr); 2417192895Sjamie free(pr, M_PRISON); 2418192895Sjamie 2419192895Sjamie /* Removing a prison frees a reference on its parent. */ 2420192895Sjamie pr = ppr; 2421192895Sjamie mtx_lock(&pr->pr_mtx); 2422192895Sjamie flags = PD_DEREF | PD_LIST_SLOCKED; 2423192895Sjamie } 2424124882Srwatson} 2425124882Srwatson 242672786Srwatsonvoid 2427185029Spjdprison_hold_locked(struct prison *pr) 242872786Srwatson{ 242972786Srwatson 2430185029Spjd mtx_assert(&pr->pr_mtx, MA_OWNED); 2431168489Spjd KASSERT(pr->pr_ref > 0, 2432191671Sjamie ("Trying to hold dead prison (jid=%d).", pr->pr_id)); 243372786Srwatson pr->pr_ref++; 2434185029Spjd} 2435185029Spjd 2436185029Spjdvoid 2437185029Spjdprison_hold(struct prison *pr) 2438185029Spjd{ 2439185029Spjd 2440185029Spjd mtx_lock(&pr->pr_mtx); 2441185029Spjd prison_hold_locked(pr); 244287275Srwatson mtx_unlock(&pr->pr_mtx); 244372786Srwatson} 244472786Srwatson 2445185435Sbzvoid 2446185435Sbzprison_proc_hold(struct prison *pr) 244787275Srwatson{ 244887275Srwatson 2449185435Sbz mtx_lock(&pr->pr_mtx); 2450191673Sjamie KASSERT(pr->pr_uref > 0, 2451191673Sjamie ("Cannot add a process to a non-alive prison (jid=%d)", pr->pr_id)); 2452191673Sjamie pr->pr_uref++; 2453185435Sbz mtx_unlock(&pr->pr_mtx); 245487275Srwatson} 245587275Srwatson 2456185435Sbzvoid 2457185435Sbzprison_proc_free(struct prison *pr) 2458185435Sbz{ 2459185435Sbz 2460185435Sbz mtx_lock(&pr->pr_mtx); 2461191673Sjamie KASSERT(pr->pr_uref > 0, 2462191673Sjamie ("Trying to kill a process in a dead prison (jid=%d)", pr->pr_id)); 2463191673Sjamie prison_deref(pr, PD_DEUREF | PD_LOCKED); 2464185435Sbz} 2465185435Sbz 2466185435Sbz 2467185435Sbz#ifdef INET 2468185435Sbz/* 2469192895Sjamie * Restrict a prison's IP address list with its parent's, possibly replacing 2470192895Sjamie * it. Return true if the replacement buffer was used (or would have been). 2471192895Sjamie */ 2472192895Sjamiestatic int 2473192895Sjamieprison_restrict_ip4(struct prison *pr, struct in_addr *newip4) 2474192895Sjamie{ 2475192895Sjamie int ii, ij, used; 2476192895Sjamie struct prison *ppr; 2477192895Sjamie 2478192895Sjamie ppr = pr->pr_parent; 2479192895Sjamie if (!(pr->pr_flags & PR_IP4_USER)) { 2480192895Sjamie /* This has no user settings, so just copy the parent's list. */ 2481192895Sjamie if (pr->pr_ip4s < ppr->pr_ip4s) { 2482192895Sjamie /* 2483192895Sjamie * There's no room for the parent's list. Use the 2484192895Sjamie * new list buffer, which is assumed to be big enough 2485192895Sjamie * (if it was passed). If there's no buffer, try to 2486192895Sjamie * allocate one. 2487192895Sjamie */ 2488192895Sjamie used = 1; 2489192895Sjamie if (newip4 == NULL) { 2490192895Sjamie newip4 = malloc(ppr->pr_ip4s * sizeof(*newip4), 2491192895Sjamie M_PRISON, M_NOWAIT); 2492192895Sjamie if (newip4 != NULL) 2493192895Sjamie used = 0; 2494192895Sjamie } 2495192895Sjamie if (newip4 != NULL) { 2496192895Sjamie bcopy(ppr->pr_ip4, newip4, 2497192895Sjamie ppr->pr_ip4s * sizeof(*newip4)); 2498192895Sjamie free(pr->pr_ip4, M_PRISON); 2499192895Sjamie pr->pr_ip4 = newip4; 2500192895Sjamie pr->pr_ip4s = ppr->pr_ip4s; 2501192895Sjamie pr->pr_flags |= PR_IP4; 2502192895Sjamie } 2503192895Sjamie return (used); 2504192895Sjamie } 2505192895Sjamie pr->pr_ip4s = ppr->pr_ip4s; 2506192895Sjamie if (pr->pr_ip4s > 0) 2507192895Sjamie bcopy(ppr->pr_ip4, pr->pr_ip4, 2508192895Sjamie pr->pr_ip4s * sizeof(*newip4)); 2509192895Sjamie else if (pr->pr_ip4 != NULL) { 2510192895Sjamie free(pr->pr_ip4, M_PRISON); 2511192895Sjamie pr->pr_ip4 = NULL; 2512192895Sjamie } 2513192895Sjamie pr->pr_flags = 2514192895Sjamie (pr->pr_flags & ~PR_IP4) | (ppr->pr_flags & PR_IP4); 2515192895Sjamie } else if (pr->pr_ip4s > 0 && (ppr->pr_flags & PR_IP4)) { 2516192895Sjamie /* Remove addresses that aren't in the parent. */ 2517192895Sjamie for (ij = 0; ij < ppr->pr_ip4s; ij++) 2518192895Sjamie if (pr->pr_ip4[0].s_addr == ppr->pr_ip4[ij].s_addr) 2519192895Sjamie break; 2520192895Sjamie if (ij < ppr->pr_ip4s) 2521192895Sjamie ii = 1; 2522192895Sjamie else { 2523192895Sjamie bcopy(pr->pr_ip4 + 1, pr->pr_ip4, 2524192895Sjamie --pr->pr_ip4s * sizeof(*pr->pr_ip4)); 2525192895Sjamie ii = 0; 2526192895Sjamie } 2527192895Sjamie for (ij = 1; ii < pr->pr_ip4s; ) { 2528192895Sjamie if (pr->pr_ip4[ii].s_addr == ppr->pr_ip4[0].s_addr) { 2529192895Sjamie ii++; 2530192895Sjamie continue; 2531192895Sjamie } 2532192895Sjamie switch (ij >= ppr->pr_ip4s ? -1 : 2533192895Sjamie qcmp_v4(&pr->pr_ip4[ii], &ppr->pr_ip4[ij])) { 2534192895Sjamie case -1: 2535192895Sjamie bcopy(pr->pr_ip4 + ii + 1, pr->pr_ip4 + ii, 2536192895Sjamie (--pr->pr_ip4s - ii) * sizeof(*pr->pr_ip4)); 2537192895Sjamie break; 2538192895Sjamie case 0: 2539192895Sjamie ii++; 2540192895Sjamie ij++; 2541192895Sjamie break; 2542192895Sjamie case 1: 2543192895Sjamie ij++; 2544192895Sjamie break; 2545192895Sjamie } 2546192895Sjamie } 2547192895Sjamie if (pr->pr_ip4s == 0) { 2548192895Sjamie free(pr->pr_ip4, M_PRISON); 2549192895Sjamie pr->pr_ip4 = NULL; 2550192895Sjamie } 2551192895Sjamie } 2552192895Sjamie return (0); 2553192895Sjamie} 2554192895Sjamie 2555192895Sjamie/* 2556185435Sbz * Pass back primary IPv4 address of this jail. 2557185435Sbz * 2558192895Sjamie * If not restricted return success but do not alter the address. Caller has 2559192895Sjamie * to make sure to initialize it correctly (e.g. INADDR_ANY). 2560185435Sbz * 2561188144Sjamie * Returns 0 on success, EAFNOSUPPORT if the jail doesn't allow IPv4. 2562188144Sjamie * Address returned in NBO. 2563185435Sbz */ 256446155Sphkint 2565187684Sbzprison_get_ip4(struct ucred *cred, struct in_addr *ia) 256646155Sphk{ 2567191673Sjamie struct prison *pr; 256846155Sphk 2569185435Sbz KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 2570185435Sbz KASSERT(ia != NULL, ("%s: ia is NULL", __func__)); 2571185435Sbz 2572192895Sjamie pr = cred->cr_prison; 2573192895Sjamie if (!(pr->pr_flags & PR_IP4)) 257446155Sphk return (0); 2575191673Sjamie mtx_lock(&pr->pr_mtx); 2576192895Sjamie if (!(pr->pr_flags & PR_IP4)) { 2577192895Sjamie mtx_unlock(&pr->pr_mtx); 2578192895Sjamie return (0); 2579192895Sjamie } 2580191673Sjamie if (pr->pr_ip4 == NULL) { 2581191673Sjamie mtx_unlock(&pr->pr_mtx); 2582188144Sjamie return (EAFNOSUPPORT); 2583191673Sjamie } 2584185435Sbz 2585191673Sjamie ia->s_addr = pr->pr_ip4[0].s_addr; 2586191673Sjamie mtx_unlock(&pr->pr_mtx); 2587185435Sbz return (0); 2588185435Sbz} 2589185435Sbz 2590185435Sbz/* 2591192895Sjamie * Return true if pr1 and pr2 have the same IPv4 address restrictions. 2592192895Sjamie */ 2593192895Sjamieint 2594192895Sjamieprison_equal_ip4(struct prison *pr1, struct prison *pr2) 2595192895Sjamie{ 2596192895Sjamie 2597192895Sjamie if (pr1 == pr2) 2598192895Sjamie return (1); 2599192895Sjamie 2600192895Sjamie /* 2601192895Sjamie * jail_set maintains an exclusive hold on allprison_lock while it 2602192895Sjamie * changes the IP addresses, so only a shared hold is needed. This is 2603192895Sjamie * easier than locking the two prisons which would require finding the 2604192895Sjamie * proper locking order and end up needing allprison_lock anyway. 2605192895Sjamie */ 2606192895Sjamie sx_slock(&allprison_lock); 2607192895Sjamie while (pr1 != &prison0 && !(pr1->pr_flags & PR_IP4_USER)) 2608192895Sjamie pr1 = pr1->pr_parent; 2609192895Sjamie while (pr2 != &prison0 && !(pr2->pr_flags & PR_IP4_USER)) 2610192895Sjamie pr2 = pr2->pr_parent; 2611192895Sjamie sx_sunlock(&allprison_lock); 2612192895Sjamie return (pr1 == pr2); 2613192895Sjamie} 2614192895Sjamie 2615192895Sjamie/* 2616185435Sbz * Make sure our (source) address is set to something meaningful to this 2617185435Sbz * jail. 2618185435Sbz * 2619192895Sjamie * Returns 0 if jail doesn't restrict IPv4 or if address belongs to jail, 2620192895Sjamie * EADDRNOTAVAIL if the address doesn't belong, or EAFNOSUPPORT if the jail 2621192895Sjamie * doesn't allow IPv4. Address passed in in NBO and returned in NBO. 2622185435Sbz */ 2623185435Sbzint 2624185435Sbzprison_local_ip4(struct ucred *cred, struct in_addr *ia) 2625185435Sbz{ 2626191673Sjamie struct prison *pr; 2627185435Sbz struct in_addr ia0; 2628191673Sjamie int error; 2629185435Sbz 2630185435Sbz KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 2631185435Sbz KASSERT(ia != NULL, ("%s: ia is NULL", __func__)); 2632185435Sbz 2633192895Sjamie pr = cred->cr_prison; 2634192895Sjamie if (!(pr->pr_flags & PR_IP4)) 263546155Sphk return (0); 2636191673Sjamie mtx_lock(&pr->pr_mtx); 2637192895Sjamie if (!(pr->pr_flags & PR_IP4)) { 2638192895Sjamie mtx_unlock(&pr->pr_mtx); 2639192895Sjamie return (0); 2640192895Sjamie } 2641191673Sjamie if (pr->pr_ip4 == NULL) { 2642191673Sjamie mtx_unlock(&pr->pr_mtx); 2643188144Sjamie return (EAFNOSUPPORT); 2644191673Sjamie } 2645185435Sbz 2646185435Sbz ia0.s_addr = ntohl(ia->s_addr); 2647185435Sbz if (ia0.s_addr == INADDR_LOOPBACK) { 2648191673Sjamie ia->s_addr = pr->pr_ip4[0].s_addr; 2649191673Sjamie mtx_unlock(&pr->pr_mtx); 2650185435Sbz return (0); 265146155Sphk } 2652185435Sbz 2653188144Sjamie if (ia0.s_addr == INADDR_ANY) { 2654188144Sjamie /* 2655188144Sjamie * In case there is only 1 IPv4 address, bind directly. 2656188144Sjamie */ 2657191673Sjamie if (pr->pr_ip4s == 1) 2658191673Sjamie ia->s_addr = pr->pr_ip4[0].s_addr; 2659191673Sjamie mtx_unlock(&pr->pr_mtx); 2660185435Sbz return (0); 2661185435Sbz } 2662185435Sbz 2663191673Sjamie error = _prison_check_ip4(pr, ia); 2664191673Sjamie mtx_unlock(&pr->pr_mtx); 2665191673Sjamie return (error); 2666185435Sbz} 2667185435Sbz 2668185435Sbz/* 2669185435Sbz * Rewrite destination address in case we will connect to loopback address. 2670185435Sbz * 2671188144Sjamie * Returns 0 on success, EAFNOSUPPORT if the jail doesn't allow IPv4. 2672188144Sjamie * Address passed in in NBO and returned in NBO. 2673185435Sbz */ 2674185435Sbzint 2675185435Sbzprison_remote_ip4(struct ucred *cred, struct in_addr *ia) 2676185435Sbz{ 2677191673Sjamie struct prison *pr; 2678185435Sbz 2679185435Sbz KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 2680185435Sbz KASSERT(ia != NULL, ("%s: ia is NULL", __func__)); 2681185435Sbz 2682192895Sjamie pr = cred->cr_prison; 2683192895Sjamie if (!(pr->pr_flags & PR_IP4)) 2684185435Sbz return (0); 2685191673Sjamie mtx_lock(&pr->pr_mtx); 2686192895Sjamie if (!(pr->pr_flags & PR_IP4)) { 2687192895Sjamie mtx_unlock(&pr->pr_mtx); 2688192895Sjamie return (0); 2689192895Sjamie } 2690191673Sjamie if (pr->pr_ip4 == NULL) { 2691191673Sjamie mtx_unlock(&pr->pr_mtx); 2692188144Sjamie return (EAFNOSUPPORT); 2693191673Sjamie } 2694188144Sjamie 2695185435Sbz if (ntohl(ia->s_addr) == INADDR_LOOPBACK) { 2696191673Sjamie ia->s_addr = pr->pr_ip4[0].s_addr; 2697191673Sjamie mtx_unlock(&pr->pr_mtx); 2698185435Sbz return (0); 2699185435Sbz } 2700185435Sbz 2701185435Sbz /* 2702185435Sbz * Return success because nothing had to be changed. 2703185435Sbz */ 2704191673Sjamie mtx_unlock(&pr->pr_mtx); 2705185435Sbz return (0); 2706185435Sbz} 2707185435Sbz 2708185435Sbz/* 2709188144Sjamie * Check if given address belongs to the jail referenced by cred/prison. 2710185435Sbz * 2711192895Sjamie * Returns 0 if jail doesn't restrict IPv4 or if address belongs to jail, 2712192895Sjamie * EADDRNOTAVAIL if the address doesn't belong, or EAFNOSUPPORT if the jail 2713192895Sjamie * doesn't allow IPv4. Address passed in in NBO. 2714185435Sbz */ 2715185435Sbzstatic int 2716185435Sbz_prison_check_ip4(struct prison *pr, struct in_addr *ia) 2717185435Sbz{ 2718185435Sbz int i, a, z, d; 2719185435Sbz 2720185435Sbz /* 2721185435Sbz * Check the primary IP. 2722185435Sbz */ 2723185435Sbz if (pr->pr_ip4[0].s_addr == ia->s_addr) 2724188144Sjamie return (0); 2725185435Sbz 2726185435Sbz /* 2727185435Sbz * All the other IPs are sorted so we can do a binary search. 2728185435Sbz */ 2729185435Sbz a = 0; 2730185435Sbz z = pr->pr_ip4s - 2; 2731185435Sbz while (a <= z) { 2732185435Sbz i = (a + z) / 2; 2733185435Sbz d = qcmp_v4(&pr->pr_ip4[i+1], ia); 2734185435Sbz if (d > 0) 2735185435Sbz z = i - 1; 2736185435Sbz else if (d < 0) 2737185435Sbz a = i + 1; 273881114Srwatson else 2739188144Sjamie return (0); 2740185435Sbz } 2741188144Sjamie 2742188144Sjamie return (EADDRNOTAVAIL); 2743185435Sbz} 2744185435Sbz 2745185435Sbzint 2746185435Sbzprison_check_ip4(struct ucred *cred, struct in_addr *ia) 2747185435Sbz{ 2748191673Sjamie struct prison *pr; 2749191673Sjamie int error; 2750185435Sbz 2751185435Sbz KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 2752185435Sbz KASSERT(ia != NULL, ("%s: ia is NULL", __func__)); 2753185435Sbz 2754192895Sjamie pr = cred->cr_prison; 2755192895Sjamie if (!(pr->pr_flags & PR_IP4)) 2756188144Sjamie return (0); 2757191673Sjamie mtx_lock(&pr->pr_mtx); 2758192895Sjamie if (!(pr->pr_flags & PR_IP4)) { 2759192895Sjamie mtx_unlock(&pr->pr_mtx); 2760192895Sjamie return (0); 2761192895Sjamie } 2762191673Sjamie if (pr->pr_ip4 == NULL) { 2763191673Sjamie mtx_unlock(&pr->pr_mtx); 2764188144Sjamie return (EAFNOSUPPORT); 2765191673Sjamie } 2766185435Sbz 2767191673Sjamie error = _prison_check_ip4(pr, ia); 2768191673Sjamie mtx_unlock(&pr->pr_mtx); 2769191673Sjamie return (error); 2770185435Sbz} 2771185435Sbz#endif 2772185435Sbz 2773185435Sbz#ifdef INET6 2774192895Sjamiestatic int 2775192895Sjamieprison_restrict_ip6(struct prison *pr, struct in6_addr *newip6) 2776192895Sjamie{ 2777192895Sjamie int ii, ij, used; 2778192895Sjamie struct prison *ppr; 2779192895Sjamie 2780192895Sjamie ppr = pr->pr_parent; 2781192895Sjamie if (!(pr->pr_flags & PR_IP6_USER)) { 2782192895Sjamie /* This has no user settings, so just copy the parent's list. */ 2783192895Sjamie if (pr->pr_ip6s < ppr->pr_ip6s) { 2784192895Sjamie /* 2785192895Sjamie * There's no room for the parent's list. Use the 2786192895Sjamie * new list buffer, which is assumed to be big enough 2787192895Sjamie * (if it was passed). If there's no buffer, try to 2788192895Sjamie * allocate one. 2789192895Sjamie */ 2790192895Sjamie used = 1; 2791192895Sjamie if (newip6 == NULL) { 2792192895Sjamie newip6 = malloc(ppr->pr_ip6s * sizeof(*newip6), 2793192895Sjamie M_PRISON, M_NOWAIT); 2794192895Sjamie if (newip6 != NULL) 2795192895Sjamie used = 0; 2796192895Sjamie } 2797192895Sjamie if (newip6 != NULL) { 2798192895Sjamie bcopy(ppr->pr_ip6, newip6, 2799192895Sjamie ppr->pr_ip6s * sizeof(*newip6)); 2800192895Sjamie free(pr->pr_ip6, M_PRISON); 2801192895Sjamie pr->pr_ip6 = newip6; 2802192895Sjamie pr->pr_ip6s = ppr->pr_ip6s; 2803192895Sjamie pr->pr_flags |= PR_IP6; 2804192895Sjamie } 2805192895Sjamie return (used); 2806192895Sjamie } 2807192895Sjamie pr->pr_ip6s = ppr->pr_ip6s; 2808192895Sjamie if (pr->pr_ip6s > 0) 2809192895Sjamie bcopy(ppr->pr_ip6, pr->pr_ip6, 2810192895Sjamie pr->pr_ip6s * sizeof(*newip6)); 2811192895Sjamie else if (pr->pr_ip6 != NULL) { 2812192895Sjamie free(pr->pr_ip6, M_PRISON); 2813192895Sjamie pr->pr_ip6 = NULL; 2814192895Sjamie } 2815192895Sjamie pr->pr_flags = 2816192895Sjamie (pr->pr_flags & ~PR_IP6) | (ppr->pr_flags & PR_IP6); 2817192895Sjamie } else if (pr->pr_ip6s > 0 && (ppr->pr_flags & PR_IP6)) { 2818192895Sjamie /* Remove addresses that aren't in the parent. */ 2819192895Sjamie for (ij = 0; ij < ppr->pr_ip6s; ij++) 2820192895Sjamie if (IN6_ARE_ADDR_EQUAL(&pr->pr_ip6[0], 2821192895Sjamie &ppr->pr_ip6[ij])) 2822192895Sjamie break; 2823192895Sjamie if (ij < ppr->pr_ip6s) 2824192895Sjamie ii = 1; 2825192895Sjamie else { 2826192895Sjamie bcopy(pr->pr_ip6 + 1, pr->pr_ip6, 2827192895Sjamie --pr->pr_ip6s * sizeof(*pr->pr_ip6)); 2828192895Sjamie ii = 0; 2829192895Sjamie } 2830192895Sjamie for (ij = 1; ii < pr->pr_ip6s; ) { 2831192895Sjamie if (IN6_ARE_ADDR_EQUAL(&pr->pr_ip6[ii], 2832192895Sjamie &ppr->pr_ip6[0])) { 2833192895Sjamie ii++; 2834192895Sjamie continue; 2835192895Sjamie } 2836192895Sjamie switch (ij >= ppr->pr_ip4s ? -1 : 2837192895Sjamie qcmp_v6(&pr->pr_ip6[ii], &ppr->pr_ip6[ij])) { 2838192895Sjamie case -1: 2839192895Sjamie bcopy(pr->pr_ip6 + ii + 1, pr->pr_ip6 + ii, 2840192895Sjamie (--pr->pr_ip6s - ii) * sizeof(*pr->pr_ip6)); 2841192895Sjamie break; 2842192895Sjamie case 0: 2843192895Sjamie ii++; 2844192895Sjamie ij++; 2845192895Sjamie break; 2846192895Sjamie case 1: 2847192895Sjamie ij++; 2848192895Sjamie break; 2849192895Sjamie } 2850192895Sjamie } 2851192895Sjamie if (pr->pr_ip6s == 0) { 2852192895Sjamie free(pr->pr_ip6, M_PRISON); 2853192895Sjamie pr->pr_ip6 = NULL; 2854192895Sjamie } 2855192895Sjamie } 2856192895Sjamie return 0; 2857192895Sjamie} 2858192895Sjamie 2859185435Sbz/* 2860185435Sbz * Pass back primary IPv6 address for this jail. 2861185435Sbz * 2862192895Sjamie * If not restricted return success but do not alter the address. Caller has 2863192895Sjamie * to make sure to initialize it correctly (e.g. IN6ADDR_ANY_INIT). 2864185435Sbz * 2865188144Sjamie * Returns 0 on success, EAFNOSUPPORT if the jail doesn't allow IPv6. 2866185435Sbz */ 2867185435Sbzint 2868187684Sbzprison_get_ip6(struct ucred *cred, struct in6_addr *ia6) 2869185435Sbz{ 2870191673Sjamie struct prison *pr; 2871185435Sbz 2872185435Sbz KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 2873185435Sbz KASSERT(ia6 != NULL, ("%s: ia6 is NULL", __func__)); 2874185435Sbz 2875192895Sjamie pr = cred->cr_prison; 2876192895Sjamie if (!(pr->pr_flags & PR_IP6)) 287781114Srwatson return (0); 2878191673Sjamie mtx_lock(&pr->pr_mtx); 2879192895Sjamie if (!(pr->pr_flags & PR_IP6)) { 2880192895Sjamie mtx_unlock(&pr->pr_mtx); 2881192895Sjamie return (0); 2882192895Sjamie } 2883191673Sjamie if (pr->pr_ip6 == NULL) { 2884191673Sjamie mtx_unlock(&pr->pr_mtx); 2885188144Sjamie return (EAFNOSUPPORT); 2886191673Sjamie } 2887188144Sjamie 2888191673Sjamie bcopy(&pr->pr_ip6[0], ia6, sizeof(struct in6_addr)); 2889191673Sjamie mtx_unlock(&pr->pr_mtx); 2890185435Sbz return (0); 2891185435Sbz} 2892185435Sbz 2893185435Sbz/* 2894192895Sjamie * Return true if pr1 and pr2 have the same IPv6 address restrictions. 2895192895Sjamie */ 2896192895Sjamieint 2897192895Sjamieprison_equal_ip6(struct prison *pr1, struct prison *pr2) 2898192895Sjamie{ 2899192895Sjamie 2900192895Sjamie if (pr1 == pr2) 2901192895Sjamie return (1); 2902192895Sjamie 2903192895Sjamie sx_slock(&allprison_lock); 2904192895Sjamie while (pr1 != &prison0 && !(pr1->pr_flags & PR_IP6_USER)) 2905192895Sjamie pr1 = pr1->pr_parent; 2906192895Sjamie while (pr2 != &prison0 && !(pr2->pr_flags & PR_IP6_USER)) 2907192895Sjamie pr2 = pr2->pr_parent; 2908192895Sjamie sx_sunlock(&allprison_lock); 2909192895Sjamie return (pr1 == pr2); 2910192895Sjamie} 2911192895Sjamie 2912192895Sjamie/* 2913185435Sbz * Make sure our (source) address is set to something meaningful to this jail. 2914185435Sbz * 2915185435Sbz * v6only should be set based on (inp->inp_flags & IN6P_IPV6_V6ONLY != 0) 2916185435Sbz * when needed while binding. 2917185435Sbz * 2918192895Sjamie * Returns 0 if jail doesn't restrict IPv6 or if address belongs to jail, 2919192895Sjamie * EADDRNOTAVAIL if the address doesn't belong, or EAFNOSUPPORT if the jail 2920192895Sjamie * doesn't allow IPv6. 2921185435Sbz */ 2922185435Sbzint 2923185435Sbzprison_local_ip6(struct ucred *cred, struct in6_addr *ia6, int v6only) 2924185435Sbz{ 2925191673Sjamie struct prison *pr; 2926191673Sjamie int error; 2927185435Sbz 2928185435Sbz KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 2929185435Sbz KASSERT(ia6 != NULL, ("%s: ia6 is NULL", __func__)); 2930185435Sbz 2931192895Sjamie pr = cred->cr_prison; 2932192895Sjamie if (!(pr->pr_flags & PR_IP6)) 2933185435Sbz return (0); 2934191673Sjamie mtx_lock(&pr->pr_mtx); 2935192895Sjamie if (!(pr->pr_flags & PR_IP6)) { 2936192895Sjamie mtx_unlock(&pr->pr_mtx); 2937192895Sjamie return (0); 2938192895Sjamie } 2939191673Sjamie if (pr->pr_ip6 == NULL) { 2940191673Sjamie mtx_unlock(&pr->pr_mtx); 2941188144Sjamie return (EAFNOSUPPORT); 2942191673Sjamie } 2943188144Sjamie 2944185435Sbz if (IN6_IS_ADDR_LOOPBACK(ia6)) { 2945191673Sjamie bcopy(&pr->pr_ip6[0], ia6, sizeof(struct in6_addr)); 2946191673Sjamie mtx_unlock(&pr->pr_mtx); 2947185435Sbz return (0); 294881114Srwatson } 2949185435Sbz 2950188144Sjamie if (IN6_IS_ADDR_UNSPECIFIED(ia6)) { 2951188144Sjamie /* 2952188144Sjamie * In case there is only 1 IPv6 address, and v6only is true, 2953188144Sjamie * then bind directly. 2954188144Sjamie */ 2955191673Sjamie if (v6only != 0 && pr->pr_ip6s == 1) 2956191673Sjamie bcopy(&pr->pr_ip6[0], ia6, sizeof(struct in6_addr)); 2957191673Sjamie mtx_unlock(&pr->pr_mtx); 2958185435Sbz return (0); 2959185435Sbz } 2960188144Sjamie 2961191673Sjamie error = _prison_check_ip6(pr, ia6); 2962191673Sjamie mtx_unlock(&pr->pr_mtx); 2963191673Sjamie return (error); 2964185435Sbz} 2965185435Sbz 2966185435Sbz/* 2967185435Sbz * Rewrite destination address in case we will connect to loopback address. 2968185435Sbz * 2969188144Sjamie * Returns 0 on success, EAFNOSUPPORT if the jail doesn't allow IPv6. 2970185435Sbz */ 2971185435Sbzint 2972185435Sbzprison_remote_ip6(struct ucred *cred, struct in6_addr *ia6) 2973185435Sbz{ 2974191673Sjamie struct prison *pr; 2975185435Sbz 2976185435Sbz KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 2977185435Sbz KASSERT(ia6 != NULL, ("%s: ia6 is NULL", __func__)); 2978185435Sbz 2979192895Sjamie pr = cred->cr_prison; 2980192895Sjamie if (!(pr->pr_flags & PR_IP6)) 2981185435Sbz return (0); 2982191673Sjamie mtx_lock(&pr->pr_mtx); 2983192895Sjamie if (!(pr->pr_flags & PR_IP6)) { 2984192895Sjamie mtx_unlock(&pr->pr_mtx); 2985192895Sjamie return (0); 2986192895Sjamie } 2987191673Sjamie if (pr->pr_ip6 == NULL) { 2988191673Sjamie mtx_unlock(&pr->pr_mtx); 2989188144Sjamie return (EAFNOSUPPORT); 2990191673Sjamie } 2991188144Sjamie 2992185435Sbz if (IN6_IS_ADDR_LOOPBACK(ia6)) { 2993191673Sjamie bcopy(&pr->pr_ip6[0], ia6, sizeof(struct in6_addr)); 2994191673Sjamie mtx_unlock(&pr->pr_mtx); 2995185435Sbz return (0); 2996185435Sbz } 2997185435Sbz 2998185435Sbz /* 2999185435Sbz * Return success because nothing had to be changed. 3000185435Sbz */ 3001191673Sjamie mtx_unlock(&pr->pr_mtx); 300246155Sphk return (0); 300346155Sphk} 300446155Sphk 3005185435Sbz/* 3006188144Sjamie * Check if given address belongs to the jail referenced by cred/prison. 3007185435Sbz * 3008192895Sjamie * Returns 0 if jail doesn't restrict IPv6 or if address belongs to jail, 3009192895Sjamie * EADDRNOTAVAIL if the address doesn't belong, or EAFNOSUPPORT if the jail 3010192895Sjamie * doesn't allow IPv6. 3011185435Sbz */ 3012185435Sbzstatic int 3013185435Sbz_prison_check_ip6(struct prison *pr, struct in6_addr *ia6) 301446155Sphk{ 3015185435Sbz int i, a, z, d; 301646155Sphk 3017185435Sbz /* 3018185435Sbz * Check the primary IP. 3019185435Sbz */ 3020185435Sbz if (IN6_ARE_ADDR_EQUAL(&pr->pr_ip6[0], ia6)) 3021188144Sjamie return (0); 3022185435Sbz 3023185435Sbz /* 3024185435Sbz * All the other IPs are sorted so we can do a binary search. 3025185435Sbz */ 3026185435Sbz a = 0; 3027185435Sbz z = pr->pr_ip6s - 2; 3028185435Sbz while (a <= z) { 3029185435Sbz i = (a + z) / 2; 3030185435Sbz d = qcmp_v6(&pr->pr_ip6[i+1], ia6); 3031185435Sbz if (d > 0) 3032185435Sbz z = i - 1; 3033185435Sbz else if (d < 0) 3034185435Sbz a = i + 1; 303546155Sphk else 3036188144Sjamie return (0); 303746155Sphk } 3038188144Sjamie 3039188144Sjamie return (EADDRNOTAVAIL); 304046155Sphk} 304146155Sphk 304246155Sphkint 3043185435Sbzprison_check_ip6(struct ucred *cred, struct in6_addr *ia6) 3044185435Sbz{ 3045191673Sjamie struct prison *pr; 3046191673Sjamie int error; 3047185435Sbz 3048185435Sbz KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 3049185435Sbz KASSERT(ia6 != NULL, ("%s: ia6 is NULL", __func__)); 3050185435Sbz 3051192895Sjamie pr = cred->cr_prison; 3052192895Sjamie if (!(pr->pr_flags & PR_IP6)) 3053188144Sjamie return (0); 3054191673Sjamie mtx_lock(&pr->pr_mtx); 3055192895Sjamie if (!(pr->pr_flags & PR_IP6)) { 3056192895Sjamie mtx_unlock(&pr->pr_mtx); 3057192895Sjamie return (0); 3058192895Sjamie } 3059191673Sjamie if (pr->pr_ip6 == NULL) { 3060191673Sjamie mtx_unlock(&pr->pr_mtx); 3061188144Sjamie return (EAFNOSUPPORT); 3062191673Sjamie } 3063185435Sbz 3064191673Sjamie error = _prison_check_ip6(pr, ia6); 3065191673Sjamie mtx_unlock(&pr->pr_mtx); 3066191673Sjamie return (error); 3067185435Sbz} 3068185435Sbz#endif 3069185435Sbz 3070185435Sbz/* 3071188146Sjamie * Check if a jail supports the given address family. 3072188146Sjamie * 3073188146Sjamie * Returns 0 if not jailed or the address family is supported, EAFNOSUPPORT 3074188146Sjamie * if not. 3075188146Sjamie */ 3076188146Sjamieint 3077188146Sjamieprison_check_af(struct ucred *cred, int af) 3078188146Sjamie{ 3079192895Sjamie struct prison *pr; 3080188146Sjamie int error; 3081188146Sjamie 3082188146Sjamie KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 3083188146Sjamie 3084192895Sjamie pr = cred->cr_prison; 3085188146Sjamie error = 0; 3086188146Sjamie switch (af) 3087188146Sjamie { 3088188146Sjamie#ifdef INET 3089188146Sjamie case AF_INET: 3090192895Sjamie if (pr->pr_flags & PR_IP4) 3091192895Sjamie { 3092192895Sjamie mtx_lock(&pr->pr_mtx); 3093192895Sjamie if ((pr->pr_flags & PR_IP4) && pr->pr_ip4 == NULL) 3094192895Sjamie error = EAFNOSUPPORT; 3095192895Sjamie mtx_unlock(&pr->pr_mtx); 3096192895Sjamie } 3097188146Sjamie break; 3098188146Sjamie#endif 3099188146Sjamie#ifdef INET6 3100188146Sjamie case AF_INET6: 3101192895Sjamie if (pr->pr_flags & PR_IP6) 3102192895Sjamie { 3103192895Sjamie mtx_lock(&pr->pr_mtx); 3104192895Sjamie if ((pr->pr_flags & PR_IP6) && pr->pr_ip6 == NULL) 3105192895Sjamie error = EAFNOSUPPORT; 3106192895Sjamie mtx_unlock(&pr->pr_mtx); 3107192895Sjamie } 3108188146Sjamie break; 3109188146Sjamie#endif 3110188146Sjamie case AF_LOCAL: 3111188146Sjamie case AF_ROUTE: 3112188146Sjamie break; 3113188146Sjamie default: 3114192895Sjamie if (!(pr->pr_allow & PR_ALLOW_SOCKET_AF)) 3115188146Sjamie error = EAFNOSUPPORT; 3116188146Sjamie } 3117188146Sjamie return (error); 3118188146Sjamie} 3119188146Sjamie 3120188146Sjamie/* 3121185435Sbz * Check if given address belongs to the jail referenced by cred (wrapper to 3122185435Sbz * prison_check_ip[46]). 3123185435Sbz * 3124192895Sjamie * Returns 0 if jail doesn't restrict the address family or if address belongs 3125192895Sjamie * to jail, EADDRNOTAVAIL if the address doesn't belong, or EAFNOSUPPORT if 3126192895Sjamie * the jail doesn't allow the address family. IPv4 Address passed in in NBO. 3127185435Sbz */ 3128185435Sbzint 312972786Srwatsonprison_if(struct ucred *cred, struct sockaddr *sa) 313046155Sphk{ 3131185435Sbz#ifdef INET 3132114168Smike struct sockaddr_in *sai; 3133185435Sbz#endif 3134185435Sbz#ifdef INET6 3135185435Sbz struct sockaddr_in6 *sai6; 3136185435Sbz#endif 3137188144Sjamie int error; 313846155Sphk 3139185435Sbz KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 3140185435Sbz KASSERT(sa != NULL, ("%s: sa is NULL", __func__)); 3141185435Sbz 3142188144Sjamie error = 0; 3143188144Sjamie switch (sa->sa_family) 3144185435Sbz { 3145185435Sbz#ifdef INET 3146185435Sbz case AF_INET: 3147185435Sbz sai = (struct sockaddr_in *)sa; 3148188144Sjamie error = prison_check_ip4(cred, &sai->sin_addr); 3149185435Sbz break; 3150185435Sbz#endif 3151185435Sbz#ifdef INET6 3152185435Sbz case AF_INET6: 3153185435Sbz sai6 = (struct sockaddr_in6 *)sa; 3154188144Sjamie error = prison_check_ip6(cred, &sai6->sin6_addr); 3155185435Sbz break; 3156185435Sbz#endif 3157185435Sbz default: 3158192895Sjamie if (!(cred->cr_prison->pr_allow & PR_ALLOW_SOCKET_AF)) 3159188144Sjamie error = EAFNOSUPPORT; 3160185435Sbz } 3161188144Sjamie return (error); 316246155Sphk} 316372786Srwatson 316472786Srwatson/* 316572786Srwatson * Return 0 if jails permit p1 to frob p2, otherwise ESRCH. 316672786Srwatson */ 316772786Srwatsonint 3168114168Smikeprison_check(struct ucred *cred1, struct ucred *cred2) 316972786Srwatson{ 317072786Srwatson 3171191915Szec#ifdef VIMAGE 3172191915Szec if (cred2->cr_vimage->v_procg != cred1->cr_vimage->v_procg) 3173191915Szec return (ESRCH); 3174191915Szec#endif 3175192895Sjamie return ((cred1->cr_prison == cred2->cr_prison || 3176192895Sjamie prison_ischild(cred1->cr_prison, cred2->cr_prison)) ? 0 : ESRCH); 3177192895Sjamie} 317872786Srwatson 3179192895Sjamie/* 3180192895Sjamie * Return 1 if p2 is a child of p1, otherwise 0. 3181192895Sjamie */ 3182192895Sjamieint 3183192895Sjamieprison_ischild(struct prison *pr1, struct prison *pr2) 3184192895Sjamie{ 3185192895Sjamie 3186192895Sjamie for (pr2 = pr2->pr_parent; pr2 != NULL; pr2 = pr2->pr_parent) 3187192895Sjamie if (pr1 == pr2) 3188192895Sjamie return (1); 318972786Srwatson return (0); 319072786Srwatson} 319172786Srwatson 319272786Srwatson/* 319372786Srwatson * Return 1 if the passed credential is in a jail, otherwise 0. 319472786Srwatson */ 319572786Srwatsonint 3196114168Smikejailed(struct ucred *cred) 319772786Srwatson{ 319872786Srwatson 3199192895Sjamie return (cred->cr_prison != &prison0); 320072786Srwatson} 320191384Srobert 320291384Srobert/* 320391384Srobert * Return the correct hostname for the passed credential. 320491384Srobert */ 320591391Srobertvoid 3206114168Smikegetcredhostname(struct ucred *cred, char *buf, size_t size) 320791384Srobert{ 3208193066Sjamie struct prison *pr; 320991384Srobert 3210193066Sjamie pr = (cred != NULL) ? cred->cr_prison : &prison0; 3211193066Sjamie mtx_lock(&pr->pr_mtx); 3212193066Sjamie strlcpy(buf, pr->pr_host, size); 3213193066Sjamie mtx_unlock(&pr->pr_mtx); 321491384Srobert} 3215113275Smike 3216125804Srwatson/* 3217147185Spjd * Determine whether the subject represented by cred can "see" 3218147185Spjd * status of a mount point. 3219147185Spjd * Returns: 0 for permitted, ENOENT otherwise. 3220147185Spjd * XXX: This function should be called cr_canseemount() and should be 3221147185Spjd * placed in kern_prot.c. 3222125804Srwatson */ 3223125804Srwatsonint 3224147185Spjdprison_canseemount(struct ucred *cred, struct mount *mp) 3225125804Srwatson{ 3226147185Spjd struct prison *pr; 3227147185Spjd struct statfs *sp; 3228147185Spjd size_t len; 3229125804Srwatson 3230192895Sjamie pr = cred->cr_prison; 3231192895Sjamie if (pr->pr_enforce_statfs == 0) 3232147185Spjd return (0); 3233147185Spjd if (pr->pr_root->v_mount == mp) 3234147185Spjd return (0); 3235192895Sjamie if (pr->pr_enforce_statfs == 2) 3236147185Spjd return (ENOENT); 3237147185Spjd /* 3238147185Spjd * If jail's chroot directory is set to "/" we should be able to see 3239147185Spjd * all mount-points from inside a jail. 3240147185Spjd * This is ugly check, but this is the only situation when jail's 3241147185Spjd * directory ends with '/'. 3242147185Spjd */ 3243147185Spjd if (strcmp(pr->pr_path, "/") == 0) 3244147185Spjd return (0); 3245147185Spjd len = strlen(pr->pr_path); 3246147185Spjd sp = &mp->mnt_stat; 3247147185Spjd if (strncmp(pr->pr_path, sp->f_mntonname, len) != 0) 3248147185Spjd return (ENOENT); 3249147185Spjd /* 3250147185Spjd * Be sure that we don't have situation where jail's root directory 3251147185Spjd * is "/some/path" and mount point is "/some/pathpath". 3252147185Spjd */ 3253147185Spjd if (sp->f_mntonname[len] != '\0' && sp->f_mntonname[len] != '/') 3254147185Spjd return (ENOENT); 3255147185Spjd return (0); 3256147185Spjd} 3257147185Spjd 3258147185Spjdvoid 3259147185Spjdprison_enforce_statfs(struct ucred *cred, struct mount *mp, struct statfs *sp) 3260147185Spjd{ 3261147185Spjd char jpath[MAXPATHLEN]; 3262147185Spjd struct prison *pr; 3263147185Spjd size_t len; 3264147185Spjd 3265192895Sjamie pr = cred->cr_prison; 3266192895Sjamie if (pr->pr_enforce_statfs == 0) 3267147185Spjd return; 3268147185Spjd if (prison_canseemount(cred, mp) != 0) { 3269147185Spjd bzero(sp->f_mntonname, sizeof(sp->f_mntonname)); 3270147185Spjd strlcpy(sp->f_mntonname, "[restricted]", 3271147185Spjd sizeof(sp->f_mntonname)); 3272147185Spjd return; 3273125804Srwatson } 3274147185Spjd if (pr->pr_root->v_mount == mp) { 3275147185Spjd /* 3276147185Spjd * Clear current buffer data, so we are sure nothing from 3277147185Spjd * the valid path left there. 3278147185Spjd */ 3279147185Spjd bzero(sp->f_mntonname, sizeof(sp->f_mntonname)); 3280147185Spjd *sp->f_mntonname = '/'; 3281147185Spjd return; 3282147185Spjd } 3283147185Spjd /* 3284147185Spjd * If jail's chroot directory is set to "/" we should be able to see 3285147185Spjd * all mount-points from inside a jail. 3286147185Spjd */ 3287147185Spjd if (strcmp(pr->pr_path, "/") == 0) 3288147185Spjd return; 3289147185Spjd len = strlen(pr->pr_path); 3290147185Spjd strlcpy(jpath, sp->f_mntonname + len, sizeof(jpath)); 3291147185Spjd /* 3292147185Spjd * Clear current buffer data, so we are sure nothing from 3293147185Spjd * the valid path left there. 3294147185Spjd */ 3295147185Spjd bzero(sp->f_mntonname, sizeof(sp->f_mntonname)); 3296147185Spjd if (*jpath == '\0') { 3297147185Spjd /* Should never happen. */ 3298147185Spjd *sp->f_mntonname = '/'; 3299147185Spjd } else { 3300147185Spjd strlcpy(sp->f_mntonname, jpath, sizeof(sp->f_mntonname)); 3301147185Spjd } 3302125804Srwatson} 3303125804Srwatson 3304164032Srwatson/* 3305164032Srwatson * Check with permission for a specific privilege is granted within jail. We 3306164032Srwatson * have a specific list of accepted privileges; the rest are denied. 3307164032Srwatson */ 3308164032Srwatsonint 3309164032Srwatsonprison_priv_check(struct ucred *cred, int priv) 3310164032Srwatson{ 3311164032Srwatson 3312164032Srwatson if (!jailed(cred)) 3313164032Srwatson return (0); 3314164032Srwatson 3315164032Srwatson switch (priv) { 3316164032Srwatson 3317164032Srwatson /* 3318164032Srwatson * Allow ktrace privileges for root in jail. 3319164032Srwatson */ 3320164032Srwatson case PRIV_KTRACE: 3321164032Srwatson 3322166827Srwatson#if 0 3323164032Srwatson /* 3324164032Srwatson * Allow jailed processes to configure audit identity and 3325164032Srwatson * submit audit records (login, etc). In the future we may 3326164032Srwatson * want to further refine the relationship between audit and 3327164032Srwatson * jail. 3328164032Srwatson */ 3329164032Srwatson case PRIV_AUDIT_GETAUDIT: 3330164032Srwatson case PRIV_AUDIT_SETAUDIT: 3331164032Srwatson case PRIV_AUDIT_SUBMIT: 3332166827Srwatson#endif 3333164032Srwatson 3334164032Srwatson /* 3335164032Srwatson * Allow jailed processes to manipulate process UNIX 3336164032Srwatson * credentials in any way they see fit. 3337164032Srwatson */ 3338164032Srwatson case PRIV_CRED_SETUID: 3339164032Srwatson case PRIV_CRED_SETEUID: 3340164032Srwatson case PRIV_CRED_SETGID: 3341164032Srwatson case PRIV_CRED_SETEGID: 3342164032Srwatson case PRIV_CRED_SETGROUPS: 3343164032Srwatson case PRIV_CRED_SETREUID: 3344164032Srwatson case PRIV_CRED_SETREGID: 3345164032Srwatson case PRIV_CRED_SETRESUID: 3346164032Srwatson case PRIV_CRED_SETRESGID: 3347164032Srwatson 3348164032Srwatson /* 3349164032Srwatson * Jail implements visibility constraints already, so allow 3350164032Srwatson * jailed root to override uid/gid-based constraints. 3351164032Srwatson */ 3352164032Srwatson case PRIV_SEEOTHERGIDS: 3353164032Srwatson case PRIV_SEEOTHERUIDS: 3354164032Srwatson 3355164032Srwatson /* 3356164032Srwatson * Jail implements inter-process debugging limits already, so 3357164032Srwatson * allow jailed root various debugging privileges. 3358164032Srwatson */ 3359164032Srwatson case PRIV_DEBUG_DIFFCRED: 3360164032Srwatson case PRIV_DEBUG_SUGID: 3361164032Srwatson case PRIV_DEBUG_UNPRIV: 3362164032Srwatson 3363164032Srwatson /* 3364164032Srwatson * Allow jail to set various resource limits and login 3365164032Srwatson * properties, and for now, exceed process resource limits. 3366164032Srwatson */ 3367164032Srwatson case PRIV_PROC_LIMIT: 3368164032Srwatson case PRIV_PROC_SETLOGIN: 3369164032Srwatson case PRIV_PROC_SETRLIMIT: 3370164032Srwatson 3371164032Srwatson /* 3372164032Srwatson * System V and POSIX IPC privileges are granted in jail. 3373164032Srwatson */ 3374164032Srwatson case PRIV_IPC_READ: 3375164032Srwatson case PRIV_IPC_WRITE: 3376164032Srwatson case PRIV_IPC_ADMIN: 3377164032Srwatson case PRIV_IPC_MSGSIZE: 3378164032Srwatson case PRIV_MQ_ADMIN: 3379164032Srwatson 3380164032Srwatson /* 3381192895Sjamie * Jail operations within a jail work on child jails. 3382192895Sjamie */ 3383192895Sjamie case PRIV_JAIL_ATTACH: 3384192895Sjamie case PRIV_JAIL_SET: 3385192895Sjamie case PRIV_JAIL_REMOVE: 3386192895Sjamie 3387192895Sjamie /* 3388164032Srwatson * Jail implements its own inter-process limits, so allow 3389164032Srwatson * root processes in jail to change scheduling on other 3390164032Srwatson * processes in the same jail. Likewise for signalling. 3391164032Srwatson */ 3392164032Srwatson case PRIV_SCHED_DIFFCRED: 3393185435Sbz case PRIV_SCHED_CPUSET: 3394164032Srwatson case PRIV_SIGNAL_DIFFCRED: 3395164032Srwatson case PRIV_SIGNAL_SUGID: 3396164032Srwatson 3397164032Srwatson /* 3398164032Srwatson * Allow jailed processes to write to sysctls marked as jail 3399164032Srwatson * writable. 3400164032Srwatson */ 3401164032Srwatson case PRIV_SYSCTL_WRITEJAIL: 3402164032Srwatson 3403164032Srwatson /* 3404164032Srwatson * Allow root in jail to manage a variety of quota 3405166831Srwatson * properties. These should likely be conditional on a 3406166831Srwatson * configuration option. 3407164032Srwatson */ 3408166832Srwatson case PRIV_VFS_GETQUOTA: 3409166832Srwatson case PRIV_VFS_SETQUOTA: 3410164032Srwatson 3411164032Srwatson /* 3412164032Srwatson * Since Jail relies on chroot() to implement file system 3413164032Srwatson * protections, grant many VFS privileges to root in jail. 3414164032Srwatson * Be careful to exclude mount-related and NFS-related 3415164032Srwatson * privileges. 3416164032Srwatson */ 3417164032Srwatson case PRIV_VFS_READ: 3418164032Srwatson case PRIV_VFS_WRITE: 3419164032Srwatson case PRIV_VFS_ADMIN: 3420164032Srwatson case PRIV_VFS_EXEC: 3421164032Srwatson case PRIV_VFS_LOOKUP: 3422164032Srwatson case PRIV_VFS_BLOCKRESERVE: /* XXXRW: Slightly surprising. */ 3423164032Srwatson case PRIV_VFS_CHFLAGS_DEV: 3424164032Srwatson case PRIV_VFS_CHOWN: 3425164032Srwatson case PRIV_VFS_CHROOT: 3426167152Spjd case PRIV_VFS_RETAINSUGID: 3427164032Srwatson case PRIV_VFS_FCHROOT: 3428164032Srwatson case PRIV_VFS_LINK: 3429164032Srwatson case PRIV_VFS_SETGID: 3430172860Srwatson case PRIV_VFS_STAT: 3431164032Srwatson case PRIV_VFS_STICKYFILE: 3432164032Srwatson return (0); 3433164032Srwatson 3434164032Srwatson /* 3435164032Srwatson * Depending on the global setting, allow privilege of 3436164032Srwatson * setting system flags. 3437164032Srwatson */ 3438164032Srwatson case PRIV_VFS_SYSFLAGS: 3439192895Sjamie if (cred->cr_prison->pr_allow & PR_ALLOW_CHFLAGS) 3440164032Srwatson return (0); 3441164032Srwatson else 3442164032Srwatson return (EPERM); 3443164032Srwatson 3444164032Srwatson /* 3445168396Spjd * Depending on the global setting, allow privilege of 3446168396Spjd * mounting/unmounting file systems. 3447168396Spjd */ 3448168396Spjd case PRIV_VFS_MOUNT: 3449168396Spjd case PRIV_VFS_UNMOUNT: 3450168396Spjd case PRIV_VFS_MOUNT_NONUSER: 3451168699Spjd case PRIV_VFS_MOUNT_OWNER: 3452192895Sjamie if (cred->cr_prison->pr_allow & PR_ALLOW_MOUNT) 3453168396Spjd return (0); 3454168396Spjd else 3455168396Spjd return (EPERM); 3456168396Spjd 3457168396Spjd /* 3458168591Srwatson * Allow jailed root to bind reserved ports and reuse in-use 3459168591Srwatson * ports. 3460164032Srwatson */ 3461164032Srwatson case PRIV_NETINET_RESERVEDPORT: 3462168591Srwatson case PRIV_NETINET_REUSEPORT: 3463164032Srwatson return (0); 3464164032Srwatson 3465164032Srwatson /* 3466175630Sbz * Allow jailed root to set certian IPv4/6 (option) headers. 3467175630Sbz */ 3468175630Sbz case PRIV_NETINET_SETHDROPTS: 3469175630Sbz return (0); 3470175630Sbz 3471175630Sbz /* 3472164032Srwatson * Conditionally allow creating raw sockets in jail. 3473164032Srwatson */ 3474164032Srwatson case PRIV_NETINET_RAW: 3475192895Sjamie if (cred->cr_prison->pr_allow & PR_ALLOW_RAW_SOCKETS) 3476164032Srwatson return (0); 3477164032Srwatson else 3478164032Srwatson return (EPERM); 3479164032Srwatson 3480164032Srwatson /* 3481164032Srwatson * Since jail implements its own visibility limits on netstat 3482164032Srwatson * sysctls, allow getcred. This allows identd to work in 3483164032Srwatson * jail. 3484164032Srwatson */ 3485164032Srwatson case PRIV_NETINET_GETCRED: 3486164032Srwatson return (0); 3487164032Srwatson 3488164032Srwatson default: 3489164032Srwatson /* 3490164032Srwatson * In all remaining cases, deny the privilege request. This 3491164032Srwatson * includes almost all network privileges, many system 3492164032Srwatson * configuration privileges. 3493164032Srwatson */ 3494164032Srwatson return (EPERM); 3495164032Srwatson } 3496164032Srwatson} 3497164032Srwatson 3498192895Sjamie/* 3499192895Sjamie * Return the part of pr2's name that is relative to pr1, or the whole name 3500192895Sjamie * if it does not directly follow. 3501192895Sjamie */ 3502192895Sjamie 3503192895Sjamiechar * 3504192895Sjamieprison_name(struct prison *pr1, struct prison *pr2) 3505192895Sjamie{ 3506192895Sjamie char *name; 3507192895Sjamie 3508192895Sjamie /* Jails see themselves as "0" (if they see themselves at all). */ 3509192895Sjamie if (pr1 == pr2) 3510192895Sjamie return "0"; 3511192895Sjamie name = pr2->pr_name; 3512192895Sjamie if (prison_ischild(pr1, pr2)) { 3513192895Sjamie /* 3514192895Sjamie * pr1 isn't locked (and allprison_lock may not be either) 3515192895Sjamie * so its length can't be counted on. But the number of dots 3516192895Sjamie * can be counted on - and counted. 3517192895Sjamie */ 3518192895Sjamie for (; pr1 != &prison0; pr1 = pr1->pr_parent) 3519192895Sjamie name = strchr(name, '.') + 1; 3520192895Sjamie } 3521192895Sjamie return (name); 3522192895Sjamie} 3523192895Sjamie 3524192895Sjamie/* 3525192895Sjamie * Return the part of pr2's path that is relative to pr1, or the whole path 3526192895Sjamie * if it does not directly follow. 3527192895Sjamie */ 3528192895Sjamiestatic char * 3529192895Sjamieprison_path(struct prison *pr1, struct prison *pr2) 3530192895Sjamie{ 3531192895Sjamie char *path1, *path2; 3532192895Sjamie int len1; 3533192895Sjamie 3534192895Sjamie path1 = pr1->pr_path; 3535192895Sjamie path2 = pr2->pr_path; 3536192895Sjamie if (!strcmp(path1, "/")) 3537192895Sjamie return (path2); 3538192895Sjamie len1 = strlen(path1); 3539192895Sjamie if (strncmp(path1, path2, len1)) 3540192895Sjamie return (path2); 3541192895Sjamie if (path2[len1] == '\0') 3542192895Sjamie return "/"; 3543192895Sjamie if (path2[len1] == '/') 3544192895Sjamie return (path2 + len1); 3545192895Sjamie return (path2); 3546192895Sjamie} 3547192895Sjamie 3548192895Sjamie 3549192895Sjamie/* 3550192895Sjamie * Jail-related sysctls. 3551192895Sjamie */ 3552192895SjamieSYSCTL_NODE(_security, OID_AUTO, jail, CTLFLAG_RW, 0, 3553192895Sjamie "Jails"); 3554192895Sjamie 3555113275Smikestatic int 3556113275Smikesysctl_jail_list(SYSCTL_HANDLER_ARGS) 3557113275Smike{ 3558191673Sjamie struct xprison *xp; 3559192895Sjamie struct prison *pr, *cpr; 3560191673Sjamie#ifdef INET 3561191673Sjamie struct in_addr *ip4 = NULL; 3562191673Sjamie int ip4s = 0; 3563191673Sjamie#endif 3564191673Sjamie#ifdef INET6 3565191673Sjamie struct in_addr *ip6 = NULL; 3566191673Sjamie int ip6s = 0; 3567191673Sjamie#endif 3568192895Sjamie int descend, error; 3569113275Smike 3570191673Sjamie xp = malloc(sizeof(*xp), M_TEMP, M_WAITOK); 3571192895Sjamie pr = req->td->td_ucred->cr_prison; 3572191673Sjamie error = 0; 3573168401Spjd sx_slock(&allprison_lock); 3574192895Sjamie FOREACH_PRISON_DESCENDANT(pr, cpr, descend) { 3575192895Sjamie#if defined(INET) || defined(INET6) 3576191673Sjamie again: 3577192895Sjamie#endif 3578192895Sjamie mtx_lock(&cpr->pr_mtx); 3579185435Sbz#ifdef INET 3580192895Sjamie if (cpr->pr_ip4s > 0) { 3581192895Sjamie if (ip4s < cpr->pr_ip4s) { 3582192895Sjamie ip4s = cpr->pr_ip4s; 3583192895Sjamie mtx_unlock(&cpr->pr_mtx); 3584191673Sjamie ip4 = realloc(ip4, ip4s * 3585191673Sjamie sizeof(struct in_addr), M_TEMP, M_WAITOK); 3586191673Sjamie goto again; 3587191673Sjamie } 3588192895Sjamie bcopy(cpr->pr_ip4, ip4, 3589192895Sjamie cpr->pr_ip4s * sizeof(struct in_addr)); 3590191673Sjamie } 3591185435Sbz#endif 3592185435Sbz#ifdef INET6 3593192895Sjamie if (cpr->pr_ip6s > 0) { 3594192895Sjamie if (ip6s < cpr->pr_ip6s) { 3595192895Sjamie ip6s = cpr->pr_ip6s; 3596192895Sjamie mtx_unlock(&cpr->pr_mtx); 3597191673Sjamie ip6 = realloc(ip6, ip6s * 3598191673Sjamie sizeof(struct in6_addr), M_TEMP, M_WAITOK); 3599191673Sjamie goto again; 3600191673Sjamie } 3601192895Sjamie bcopy(cpr->pr_ip6, ip6, 3602192895Sjamie cpr->pr_ip6s * sizeof(struct in6_addr)); 3603191673Sjamie } 3604185435Sbz#endif 3605192895Sjamie if (cpr->pr_ref == 0) { 3606192895Sjamie mtx_unlock(&cpr->pr_mtx); 3607191673Sjamie continue; 3608191673Sjamie } 3609191673Sjamie bzero(xp, sizeof(*xp)); 3610113275Smike xp->pr_version = XPRISON_VERSION; 3611192895Sjamie xp->pr_id = cpr->pr_id; 3612192895Sjamie xp->pr_state = cpr->pr_uref > 0 3613191673Sjamie ? PRISON_STATE_ALIVE : PRISON_STATE_DYING; 3614192895Sjamie strlcpy(xp->pr_path, prison_path(pr, cpr), sizeof(xp->pr_path)); 3615192895Sjamie strlcpy(xp->pr_host, cpr->pr_host, sizeof(xp->pr_host)); 3616192895Sjamie strlcpy(xp->pr_name, prison_name(pr, cpr), sizeof(xp->pr_name)); 3617185435Sbz#ifdef INET 3618192895Sjamie xp->pr_ip4s = cpr->pr_ip4s; 3619185435Sbz#endif 3620185435Sbz#ifdef INET6 3621192895Sjamie xp->pr_ip6s = cpr->pr_ip6s; 3622185435Sbz#endif 3623192895Sjamie mtx_unlock(&cpr->pr_mtx); 3624191673Sjamie error = SYSCTL_OUT(req, xp, sizeof(*xp)); 3625191673Sjamie if (error) 3626191673Sjamie break; 3627185435Sbz#ifdef INET 3628191673Sjamie if (xp->pr_ip4s > 0) { 3629191673Sjamie error = SYSCTL_OUT(req, ip4, 3630191673Sjamie xp->pr_ip4s * sizeof(struct in_addr)); 3631191673Sjamie if (error) 3632191673Sjamie break; 3633185435Sbz } 3634185435Sbz#endif 3635185435Sbz#ifdef INET6 3636191673Sjamie if (xp->pr_ip6s > 0) { 3637191673Sjamie error = SYSCTL_OUT(req, ip6, 3638191673Sjamie xp->pr_ip6s * sizeof(struct in6_addr)); 3639191673Sjamie if (error) 3640191673Sjamie break; 3641185435Sbz } 3642185435Sbz#endif 3643113275Smike } 3644168401Spjd sx_sunlock(&allprison_lock); 3645191673Sjamie free(xp, M_TEMP); 3646191673Sjamie#ifdef INET 3647191673Sjamie free(ip4, M_TEMP); 3648191673Sjamie#endif 3649191673Sjamie#ifdef INET6 3650191673Sjamie free(ip6, M_TEMP); 3651191673Sjamie#endif 3652167354Spjd return (error); 3653113275Smike} 3654113275Smike 3655187864SedSYSCTL_OID(_security_jail, OID_AUTO, list, 3656187864Sed CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 0, 3657187864Sed sysctl_jail_list, "S", "List of active jails"); 3658126004Spjd 3659126004Spjdstatic int 3660126004Spjdsysctl_jail_jailed(SYSCTL_HANDLER_ARGS) 3661126004Spjd{ 3662126004Spjd int error, injail; 3663126004Spjd 3664126004Spjd injail = jailed(req->td->td_ucred); 3665126004Spjd error = SYSCTL_OUT(req, &injail, sizeof(injail)); 3666126004Spjd 3667126004Spjd return (error); 3668126004Spjd} 3669192895Sjamie 3670187864SedSYSCTL_PROC(_security_jail, OID_AUTO, jailed, 3671187864Sed CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 0, 3672187864Sed sysctl_jail_jailed, "I", "Process in jail?"); 3673185435Sbz 3674192895Sjamie#if defined(INET) || defined(INET6) 3675192895SjamieSYSCTL_INT(_security_jail, OID_AUTO, jail_max_af_ips, CTLFLAG_RW, 3676192895Sjamie &jail_max_af_ips, 0, 3677192895Sjamie "Number of IP addresses a jail may have at most per address family"); 3678192895Sjamie#endif 3679192895Sjamie 3680192895Sjamie/* 3681192895Sjamie * Default parameters for jail(2) compatability. For historical reasons, 3682192895Sjamie * the sysctl names have varying similarity to the parameter names. Prisons 3683192895Sjamie * just see their own parameters, and can't change them. 3684192895Sjamie */ 3685192895Sjamiestatic int 3686192895Sjamiesysctl_jail_default_allow(SYSCTL_HANDLER_ARGS) 3687192895Sjamie{ 3688192895Sjamie struct prison *pr; 3689192895Sjamie int allow, error, i; 3690192895Sjamie 3691192895Sjamie pr = req->td->td_ucred->cr_prison; 3692192895Sjamie allow = (pr == &prison0) ? jail_default_allow : pr->pr_allow; 3693192895Sjamie 3694192895Sjamie /* Get the current flag value, and convert it to a boolean. */ 3695192895Sjamie i = (allow & arg2) ? 1 : 0; 3696192895Sjamie if (arg1 != NULL) 3697192895Sjamie i = !i; 3698192895Sjamie error = sysctl_handle_int(oidp, &i, 0, req); 3699192895Sjamie if (error || !req->newptr) 3700192895Sjamie return (error); 3701192895Sjamie i = i ? arg2 : 0; 3702192895Sjamie if (arg1 != NULL) 3703192895Sjamie i ^= arg2; 3704192895Sjamie /* 3705192895Sjamie * The sysctls don't have CTLFLAGS_PRISON, so assume prison0 3706192895Sjamie * for writing. 3707192895Sjamie */ 3708192895Sjamie mtx_lock(&prison0.pr_mtx); 3709192895Sjamie jail_default_allow = (jail_default_allow & ~arg2) | i; 3710192895Sjamie mtx_unlock(&prison0.pr_mtx); 3711192895Sjamie return (0); 3712192895Sjamie} 3713192895Sjamie 3714192895SjamieSYSCTL_PROC(_security_jail, OID_AUTO, set_hostname_allowed, 3715192895Sjamie CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, 3716192895Sjamie NULL, PR_ALLOW_SET_HOSTNAME, sysctl_jail_default_allow, "I", 3717192895Sjamie "Processes in jail can set their hostnames"); 3718192895SjamieSYSCTL_PROC(_security_jail, OID_AUTO, socket_unixiproute_only, 3719192895Sjamie CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, 3720192895Sjamie (void *)1, PR_ALLOW_SOCKET_AF, sysctl_jail_default_allow, "I", 3721192895Sjamie "Processes in jail are limited to creating UNIX/IP/route sockets only"); 3722192895SjamieSYSCTL_PROC(_security_jail, OID_AUTO, sysvipc_allowed, 3723192895Sjamie CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, 3724192895Sjamie NULL, PR_ALLOW_SYSVIPC, sysctl_jail_default_allow, "I", 3725192895Sjamie "Processes in jail can use System V IPC primitives"); 3726192895SjamieSYSCTL_PROC(_security_jail, OID_AUTO, allow_raw_sockets, 3727192895Sjamie CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, 3728192895Sjamie NULL, PR_ALLOW_RAW_SOCKETS, sysctl_jail_default_allow, "I", 3729192895Sjamie "Prison root can create raw sockets"); 3730192895SjamieSYSCTL_PROC(_security_jail, OID_AUTO, chflags_allowed, 3731192895Sjamie CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, 3732192895Sjamie NULL, PR_ALLOW_CHFLAGS, sysctl_jail_default_allow, "I", 3733192895Sjamie "Processes in jail can alter system file flags"); 3734192895SjamieSYSCTL_PROC(_security_jail, OID_AUTO, mount_allowed, 3735192895Sjamie CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, 3736192895Sjamie NULL, PR_ALLOW_MOUNT, sysctl_jail_default_allow, "I", 3737192895Sjamie "Processes in jail can mount/unmount jail-friendly file systems"); 3738192895Sjamie 3739192895Sjamiestatic int 3740192895Sjamiesysctl_jail_default_level(SYSCTL_HANDLER_ARGS) 3741192895Sjamie{ 3742192895Sjamie struct prison *pr; 3743192895Sjamie int level, error; 3744192895Sjamie 3745192895Sjamie pr = req->td->td_ucred->cr_prison; 3746192895Sjamie level = (pr == &prison0) ? *(int *)arg1 : *(int *)((char *)pr + arg2); 3747192895Sjamie error = sysctl_handle_int(oidp, &level, 0, req); 3748192895Sjamie if (error || !req->newptr) 3749192895Sjamie return (error); 3750192895Sjamie *(int *)arg1 = level; 3751192895Sjamie return (0); 3752192895Sjamie} 3753192895Sjamie 3754192895SjamieSYSCTL_PROC(_security_jail, OID_AUTO, enforce_statfs, 3755192895Sjamie CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, 3756192895Sjamie &jail_default_enforce_statfs, offsetof(struct prison, pr_enforce_statfs), 3757192895Sjamie sysctl_jail_default_level, "I", 3758192895Sjamie "Processes in jail cannot see all mounted file systems"); 3759192895Sjamie 3760192895Sjamie/* 3761192895Sjamie * Nodes to describe jail parameters. Maximum length of string parameters 3762192895Sjamie * is returned in the string itself, and the other parameters exist merely 3763192895Sjamie * to make themselves and their types known. 3764192895Sjamie */ 3765192895SjamieSYSCTL_NODE(_security_jail, OID_AUTO, param, CTLFLAG_RW, 0, 3766192895Sjamie "Jail parameters"); 3767192895Sjamie 3768192895Sjamieint 3769192895Sjamiesysctl_jail_param(SYSCTL_HANDLER_ARGS) 3770192895Sjamie{ 3771192895Sjamie int i; 3772192895Sjamie long l; 3773192895Sjamie size_t s; 3774192895Sjamie char numbuf[12]; 3775192895Sjamie 3776192895Sjamie switch (oidp->oid_kind & CTLTYPE) 3777192895Sjamie { 3778192895Sjamie case CTLTYPE_LONG: 3779192895Sjamie case CTLTYPE_ULONG: 3780192895Sjamie l = 0; 3781192895Sjamie#ifdef SCTL_MASK32 3782192895Sjamie if (!(req->flags & SCTL_MASK32)) 3783192895Sjamie#endif 3784192895Sjamie return (SYSCTL_OUT(req, &l, sizeof(l))); 3785192895Sjamie case CTLTYPE_INT: 3786192895Sjamie case CTLTYPE_UINT: 3787192895Sjamie i = 0; 3788192895Sjamie return (SYSCTL_OUT(req, &i, sizeof(i))); 3789192895Sjamie case CTLTYPE_STRING: 3790192895Sjamie snprintf(numbuf, sizeof(numbuf), "%d", arg2); 3791192895Sjamie return 3792192895Sjamie (sysctl_handle_string(oidp, numbuf, sizeof(numbuf), req)); 3793192895Sjamie case CTLTYPE_STRUCT: 3794192895Sjamie s = (size_t)arg2; 3795192895Sjamie return (SYSCTL_OUT(req, &s, sizeof(s))); 3796192895Sjamie } 3797192895Sjamie return (0); 3798192895Sjamie} 3799192895Sjamie 3800192895SjamieSYSCTL_JAIL_PARAM(, jid, CTLTYPE_INT | CTLFLAG_RDTUN, "I", "Jail ID"); 3801192895SjamieSYSCTL_JAIL_PARAM(, parent, CTLTYPE_INT | CTLFLAG_RD, "I", "Jail parent ID"); 3802192895SjamieSYSCTL_JAIL_PARAM_STRING(, name, CTLFLAG_RW, MAXHOSTNAMELEN, "Jail name"); 3803192895SjamieSYSCTL_JAIL_PARAM_STRING(, path, CTLFLAG_RDTUN, MAXPATHLEN, "Jail root path"); 3804192895SjamieSYSCTL_JAIL_PARAM(, securelevel, CTLTYPE_INT | CTLFLAG_RW, 3805192895Sjamie "I", "Jail secure level"); 3806192895SjamieSYSCTL_JAIL_PARAM(, enforce_statfs, CTLTYPE_INT | CTLFLAG_RW, 3807192895Sjamie "I", "Jail cannot see all mounted file systems"); 3808192895SjamieSYSCTL_JAIL_PARAM(, persist, CTLTYPE_INT | CTLFLAG_RW, 3809192895Sjamie "B", "Jail persistence"); 3810192895SjamieSYSCTL_JAIL_PARAM(, dying, CTLTYPE_INT | CTLFLAG_RD, 3811192895Sjamie "B", "Jail is in the process of shutting down"); 3812192895Sjamie 3813192895SjamieSYSCTL_JAIL_PARAM_NODE(host, "Jail host info"); 3814193066SjamieSYSCTL_JAIL_PARAM(, nohost, CTLTYPE_INT | CTLFLAG_RW, 3815193066Sjamie "BN", "Jail w/ no host info"); 3816192895SjamieSYSCTL_JAIL_PARAM_STRING(_host, hostname, CTLFLAG_RW, MAXHOSTNAMELEN, 3817192895Sjamie "Jail hostname"); 3818193066SjamieSYSCTL_JAIL_PARAM_STRING(_host, domainname, CTLFLAG_RW, MAXHOSTNAMELEN, 3819193066Sjamie "Jail NIS domainname"); 3820193066SjamieSYSCTL_JAIL_PARAM_STRING(_host, hostuuid, CTLFLAG_RW, HOSTUUIDLEN, 3821193066Sjamie "Jail host UUID"); 3822193066SjamieSYSCTL_JAIL_PARAM(_host, hostid, CTLTYPE_ULONG | CTLFLAG_RW, 3823193066Sjamie "LU", "Jail host ID"); 3824192895Sjamie 3825192895SjamieSYSCTL_JAIL_PARAM_NODE(cpuset, "Jail cpuset"); 3826192895SjamieSYSCTL_JAIL_PARAM(_cpuset, id, CTLTYPE_INT | CTLFLAG_RD, "I", "Jail cpuset ID"); 3827192895Sjamie 3828192895Sjamie#ifdef INET 3829192895SjamieSYSCTL_JAIL_PARAM_NODE(ip4, "Jail IPv4 address virtualization"); 3830192895SjamieSYSCTL_JAIL_PARAM(, noip4, CTLTYPE_INT | CTLFLAG_RW, 3831192895Sjamie "BN", "Jail w/ no IP address virtualization"); 3832192895SjamieSYSCTL_JAIL_PARAM_STRUCT(_ip4, addr, CTLFLAG_RW, sizeof(struct in_addr), 3833192895Sjamie "S,in_addr,a", "Jail IPv4 addresses"); 3834192895Sjamie#endif 3835192895Sjamie#ifdef INET6 3836192895SjamieSYSCTL_JAIL_PARAM_NODE(ip6, "Jail IPv6 address virtualization"); 3837192895SjamieSYSCTL_JAIL_PARAM(, noip6, CTLTYPE_INT | CTLFLAG_RW, 3838192895Sjamie "BN", "Jail w/ no IP address virtualization"); 3839192895SjamieSYSCTL_JAIL_PARAM_STRUCT(_ip6, addr, CTLFLAG_RW, sizeof(struct in6_addr), 3840192895Sjamie "S,in6_addr,a", "Jail IPv6 addresses"); 3841192895Sjamie#endif 3842192895Sjamie 3843192895SjamieSYSCTL_JAIL_PARAM_NODE(allow, "Jail permission flags"); 3844192895SjamieSYSCTL_JAIL_PARAM(_allow, set_hostname, CTLTYPE_INT | CTLFLAG_RW, 3845192895Sjamie "B", "Jail may set hostname"); 3846192895SjamieSYSCTL_JAIL_PARAM(_allow, sysvipc, CTLTYPE_INT | CTLFLAG_RW, 3847192895Sjamie "B", "Jail may use SYSV IPC"); 3848192895SjamieSYSCTL_JAIL_PARAM(_allow, raw_sockets, CTLTYPE_INT | CTLFLAG_RW, 3849192895Sjamie "B", "Jail may create raw sockets"); 3850192895SjamieSYSCTL_JAIL_PARAM(_allow, chflags, CTLTYPE_INT | CTLFLAG_RW, 3851192895Sjamie "B", "Jail may alter system file flags"); 3852192895SjamieSYSCTL_JAIL_PARAM(_allow, mount, CTLTYPE_INT | CTLFLAG_RW, 3853192895Sjamie "B", "Jail may mount/unmount jail-friendly file systems"); 3854192895SjamieSYSCTL_JAIL_PARAM(_allow, quotas, CTLTYPE_INT | CTLFLAG_RW, 3855192895Sjamie "B", "Jail may set file quotas"); 3856192895SjamieSYSCTL_JAIL_PARAM(_allow, jails, CTLTYPE_INT | CTLFLAG_RW, 3857192895Sjamie "B", "Jail may create child jails"); 3858192895SjamieSYSCTL_JAIL_PARAM(_allow, socket_af, CTLTYPE_INT | CTLFLAG_RW, 3859192895Sjamie "B", "Jail may create sockets other than just UNIX/IPv4/IPv6/route"); 3860192895Sjamie 3861192895Sjamie 3862185435Sbz#ifdef DDB 3863191673Sjamie 3864191673Sjamiestatic void 3865191673Sjamiedb_show_prison(struct prison *pr) 3866185435Sbz{ 3867192895Sjamie int fi; 3868191673Sjamie#if defined(INET) || defined(INET6) 3869191673Sjamie int ii; 3870185435Sbz#endif 3871185435Sbz#ifdef INET6 3872185435Sbz char ip6buf[INET6_ADDRSTRLEN]; 3873185435Sbz#endif 3874185435Sbz 3875191673Sjamie db_printf("prison %p:\n", pr); 3876191673Sjamie db_printf(" jid = %d\n", pr->pr_id); 3877191673Sjamie db_printf(" name = %s\n", pr->pr_name); 3878192895Sjamie db_printf(" parent = %p\n", pr->pr_parent); 3879191673Sjamie db_printf(" ref = %d\n", pr->pr_ref); 3880191673Sjamie db_printf(" uref = %d\n", pr->pr_uref); 3881191673Sjamie db_printf(" path = %s\n", pr->pr_path); 3882191673Sjamie db_printf(" cpuset = %d\n", pr->pr_cpuset 3883191673Sjamie ? pr->pr_cpuset->cs_id : -1); 3884191673Sjamie db_printf(" root = %p\n", pr->pr_root); 3885191673Sjamie db_printf(" securelevel = %d\n", pr->pr_securelevel); 3886192895Sjamie db_printf(" child = %p\n", LIST_FIRST(&pr->pr_children)); 3887192895Sjamie db_printf(" sibling = %p\n", LIST_NEXT(pr, pr_sibling)); 3888191673Sjamie db_printf(" flags = %x", pr->pr_flags); 3889192895Sjamie for (fi = 0; fi < sizeof(pr_flag_names) / sizeof(pr_flag_names[0]); 3890192895Sjamie fi++) 3891192895Sjamie if (pr_flag_names[fi] != NULL && (pr->pr_flags & (1 << fi))) 3892192895Sjamie db_printf(" %s", pr_flag_names[fi]); 3893192895Sjamie db_printf(" allow = %x", pr->pr_allow); 3894192895Sjamie for (fi = 0; fi < sizeof(pr_allow_names) / sizeof(pr_allow_names[0]); 3895192895Sjamie fi++) 3896192895Sjamie if (pr_allow_names[fi] != NULL && (pr->pr_allow & (1 << fi))) 3897192895Sjamie db_printf(" %s", pr_allow_names[fi]); 3898191673Sjamie db_printf("\n"); 3899192895Sjamie db_printf(" enforce_statfs = %d\n", pr->pr_enforce_statfs); 3900191673Sjamie db_printf(" host.hostname = %s\n", pr->pr_host); 3901193066Sjamie db_printf(" host.domainname = %s\n", pr->pr_domain); 3902193066Sjamie db_printf(" host.hostuuid = %s\n", pr->pr_uuid); 3903193066Sjamie db_printf(" host.hostid = %lu\n", pr->pr_hostid); 3904185435Sbz#ifdef INET 3905191673Sjamie db_printf(" ip4s = %d\n", pr->pr_ip4s); 3906191673Sjamie for (ii = 0; ii < pr->pr_ip4s; ii++) 3907191673Sjamie db_printf(" %s %s\n", 3908191673Sjamie ii == 0 ? "ip4 =" : " ", 3909191673Sjamie inet_ntoa(pr->pr_ip4[ii])); 3910185435Sbz#endif 3911185435Sbz#ifdef INET6 3912191673Sjamie db_printf(" ip6s = %d\n", pr->pr_ip6s); 3913191673Sjamie for (ii = 0; ii < pr->pr_ip6s; ii++) 3914191673Sjamie db_printf(" %s %s\n", 3915191673Sjamie ii == 0 ? "ip6 =" : " ", 3916191673Sjamie ip6_sprintf(ip6buf, &pr->pr_ip6[ii])); 3917191673Sjamie#endif 3918191673Sjamie} 3919191673Sjamie 3920191673SjamieDB_SHOW_COMMAND(prison, db_show_prison_command) 3921191673Sjamie{ 3922191673Sjamie struct prison *pr; 3923191673Sjamie 3924191673Sjamie if (!have_addr) { 3925192895Sjamie /* 3926192895Sjamie * Show all prisons in the list, and prison0 which is not 3927192895Sjamie * listed. 3928192895Sjamie */ 3929192895Sjamie db_show_prison(&prison0); 3930192895Sjamie if (!db_pager_quit) { 3931192895Sjamie TAILQ_FOREACH(pr, &allprison, pr_list) { 3932192895Sjamie db_show_prison(pr); 3933192895Sjamie if (db_pager_quit) 3934192895Sjamie break; 3935192895Sjamie } 3936191673Sjamie } 3937191673Sjamie return; 3938191673Sjamie } 3939191673Sjamie 3940192895Sjamie if (addr == 0) 3941192895Sjamie pr = &prison0; 3942192895Sjamie else { 3943192895Sjamie /* Look for a prison with the ID and with references. */ 3944191673Sjamie TAILQ_FOREACH(pr, &allprison, pr_list) 3945192895Sjamie if (pr->pr_id == addr && pr->pr_ref > 0) 3946191673Sjamie break; 3947192895Sjamie if (pr == NULL) 3948192895Sjamie /* Look again, without requiring a reference. */ 3949192895Sjamie TAILQ_FOREACH(pr, &allprison, pr_list) 3950192895Sjamie if (pr->pr_id == addr) 3951192895Sjamie break; 3952192895Sjamie if (pr == NULL) 3953192895Sjamie /* Assume address points to a valid prison. */ 3954192895Sjamie pr = (struct prison *)addr; 3955192895Sjamie } 3956191673Sjamie db_show_prison(pr); 3957185435Sbz} 3958191673Sjamie 3959185435Sbz#endif /* DDB */ 3960