kern_jail.c revision 195945
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 195945 2009-07-29 16:46:59Z jamie $"); 31116182Sobrien 32193066Sjamie#include "opt_compat.h" 33185435Sbz#include "opt_ddb.h" 34185435Sbz#include "opt_inet.h" 35185435Sbz#include "opt_inet6.h" 36131177Spjd 3746155Sphk#include <sys/param.h> 3846155Sphk#include <sys/types.h> 3946155Sphk#include <sys/kernel.h> 4046155Sphk#include <sys/systm.h> 4146155Sphk#include <sys/errno.h> 4246155Sphk#include <sys/sysproto.h> 4346155Sphk#include <sys/malloc.h> 44192895Sjamie#include <sys/osd.h> 45164032Srwatson#include <sys/priv.h> 4646155Sphk#include <sys/proc.h> 47124882Srwatson#include <sys/taskqueue.h> 48177785Skib#include <sys/fcntl.h> 4946155Sphk#include <sys/jail.h> 5087275Srwatson#include <sys/lock.h> 5187275Srwatson#include <sys/mutex.h> 52168401Spjd#include <sys/sx.h> 53193066Sjamie#include <sys/sysent.h> 54113275Smike#include <sys/namei.h> 55147185Spjd#include <sys/mount.h> 56113275Smike#include <sys/queue.h> 5746155Sphk#include <sys/socket.h> 58113275Smike#include <sys/syscallsubr.h> 5957163Srwatson#include <sys/sysctl.h> 60113275Smike#include <sys/vnode.h> 61181803Sbz#include <sys/vimage.h> 6246155Sphk#include <net/if.h> 6346155Sphk#include <netinet/in.h> 64185435Sbz#ifdef DDB 65185435Sbz#include <ddb/ddb.h> 66185435Sbz#ifdef INET6 67185435Sbz#include <netinet6/in6_var.h> 68185435Sbz#endif /* INET6 */ 69185435Sbz#endif /* DDB */ 7046155Sphk 71163606Srwatson#include <security/mac/mac_framework.h> 72163606Srwatson 73195944Sjamie#define DEFAULT_HOSTUUID "00000000-0000-0000-0000-000000000000" 74195944Sjamie 7546155SphkMALLOC_DEFINE(M_PRISON, "prison", "Prison structures"); 7646155Sphk 77192895Sjamie/* prison0 describes what is "real" about the system. */ 78192895Sjamiestruct prison prison0 = { 79192895Sjamie .pr_id = 0, 80192895Sjamie .pr_name = "0", 81192895Sjamie .pr_ref = 1, 82192895Sjamie .pr_uref = 1, 83192895Sjamie .pr_path = "/", 84192895Sjamie .pr_securelevel = -1, 85194762Sjamie .pr_childmax = JAIL_MAX, 86195944Sjamie .pr_hostuuid = DEFAULT_HOSTUUID, 87192895Sjamie .pr_children = LIST_HEAD_INITIALIZER(&prison0.pr_children), 88193066Sjamie .pr_flags = PR_HOST, 89192895Sjamie .pr_allow = PR_ALLOW_ALL, 90192895Sjamie}; 91192895SjamieMTX_SYSINIT(prison0, &prison0.pr_mtx, "jail mutex", MTX_DEF); 9257163Srwatson 93192895Sjamie/* allprison and lastprid are protected by allprison_lock. */ 94168401Spjdstruct sx allprison_lock; 95191673SjamieSX_SYSINIT(allprison_lock, &allprison_lock, "allprison"); 96191673Sjamiestruct prisonlist allprison = TAILQ_HEAD_INITIALIZER(allprison); 97179881Sdelphijint lastprid = 0; 98113275Smike 99191673Sjamiestatic int do_jail_attach(struct thread *td, struct prison *pr); 100190466Sjamiestatic void prison_complete(void *context, int pending); 101191673Sjamiestatic void prison_deref(struct prison *pr, int flags); 102192895Sjamiestatic char *prison_path(struct prison *pr1, struct prison *pr2); 103192895Sjamiestatic void prison_remove_one(struct prison *pr); 104185435Sbz#ifdef INET 105190466Sjamiestatic int _prison_check_ip4(struct prison *pr, struct in_addr *ia); 106192895Sjamiestatic int prison_restrict_ip4(struct prison *pr, struct in_addr *newip4); 107185435Sbz#endif 108185435Sbz#ifdef INET6 109190466Sjamiestatic int _prison_check_ip6(struct prison *pr, struct in6_addr *ia6); 110192895Sjamiestatic int prison_restrict_ip6(struct prison *pr, struct in6_addr *newip6); 111185435Sbz#endif 112113275Smike 113191673Sjamie/* Flags for prison_deref */ 114191673Sjamie#define PD_DEREF 0x01 115191673Sjamie#define PD_DEUREF 0x02 116191673Sjamie#define PD_LOCKED 0x04 117191673Sjamie#define PD_LIST_SLOCKED 0x08 118191673Sjamie#define PD_LIST_XLOCKED 0x10 119113275Smike 120192895Sjamie/* 121192895Sjamie * Parameter names corresponding to PR_* flag values 122192895Sjamie */ 123192895Sjamiestatic char *pr_flag_names[] = { 124192895Sjamie [0] = "persist", 125192895Sjamie}; 126192895Sjamie 127192895Sjamiestatic char *pr_flag_nonames[] = { 128192895Sjamie [0] = "nopersist", 129195870Sjamie}; 130195870Sjamie 131195870Sjamiestruct jailsys_flags { 132195870Sjamie const char *name; 133195870Sjamie unsigned disable; 134195870Sjamie unsigned new; 135195870Sjamie} pr_flag_jailsys[] = { 136195870Sjamie { "host", 0, PR_HOST }, 137195870Sjamie#ifdef VIMAGE 138195870Sjamie { "vnet", 0, PR_VNET }, 139195870Sjamie#endif 140192895Sjamie#ifdef INET 141195870Sjamie { "ip4", PR_IP4_USER | PR_IP4_DISABLE, PR_IP4_USER }, 142192895Sjamie#endif 143192895Sjamie#ifdef INET6 144195870Sjamie { "ip6", PR_IP6_USER | PR_IP6_DISABLE, PR_IP6_USER }, 145192895Sjamie#endif 146192895Sjamie}; 147192895Sjamie 148192895Sjamiestatic char *pr_allow_names[] = { 149192895Sjamie "allow.set_hostname", 150192895Sjamie "allow.sysvipc", 151192895Sjamie "allow.raw_sockets", 152192895Sjamie "allow.chflags", 153192895Sjamie "allow.mount", 154192895Sjamie "allow.quotas", 155192895Sjamie "allow.socket_af", 156192895Sjamie}; 157192895Sjamie 158192895Sjamiestatic char *pr_allow_nonames[] = { 159192895Sjamie "allow.noset_hostname", 160192895Sjamie "allow.nosysvipc", 161192895Sjamie "allow.noraw_sockets", 162192895Sjamie "allow.nochflags", 163192895Sjamie "allow.nomount", 164192895Sjamie "allow.noquotas", 165192895Sjamie "allow.nosocket_af", 166192895Sjamie}; 167192895Sjamie 168192895Sjamie#define JAIL_DEFAULT_ALLOW PR_ALLOW_SET_HOSTNAME 169192895Sjamiestatic unsigned jail_default_allow = JAIL_DEFAULT_ALLOW; 170192895Sjamiestatic int jail_default_enforce_statfs = 2; 171192895Sjamie#if defined(INET) || defined(INET6) 172193865Sjamiestatic unsigned jail_max_af_ips = 255; 173192895Sjamie#endif 174192895Sjamie 175192895Sjamie#ifdef INET 176185435Sbzstatic int 177185435Sbzqcmp_v4(const void *ip1, const void *ip2) 178185435Sbz{ 179185435Sbz in_addr_t iaa, iab; 180185435Sbz 181185435Sbz /* 182185435Sbz * We need to compare in HBO here to get the list sorted as expected 183185435Sbz * by the result of the code. Sorting NBO addresses gives you 184185435Sbz * interesting results. If you do not understand, do not try. 185185435Sbz */ 186185435Sbz iaa = ntohl(((const struct in_addr *)ip1)->s_addr); 187185435Sbz iab = ntohl(((const struct in_addr *)ip2)->s_addr); 188185435Sbz 189185435Sbz /* 190185435Sbz * Do not simply return the difference of the two numbers, the int is 191185435Sbz * not wide enough. 192185435Sbz */ 193185435Sbz if (iaa > iab) 194185435Sbz return (1); 195185435Sbz else if (iaa < iab) 196185435Sbz return (-1); 197185435Sbz else 198185435Sbz return (0); 199185435Sbz} 200185435Sbz#endif 201185435Sbz 202185435Sbz#ifdef INET6 203185435Sbzstatic int 204185435Sbzqcmp_v6(const void *ip1, const void *ip2) 205185435Sbz{ 206185435Sbz const struct in6_addr *ia6a, *ia6b; 207185435Sbz int i, rc; 208185435Sbz 209185435Sbz ia6a = (const struct in6_addr *)ip1; 210185435Sbz ia6b = (const struct in6_addr *)ip2; 211185435Sbz 212185435Sbz rc = 0; 213190466Sjamie for (i = 0; rc == 0 && i < sizeof(struct in6_addr); i++) { 214185435Sbz if (ia6a->s6_addr[i] > ia6b->s6_addr[i]) 215185435Sbz rc = 1; 216185435Sbz else if (ia6a->s6_addr[i] < ia6b->s6_addr[i]) 217185435Sbz rc = -1; 218185435Sbz } 219185435Sbz return (rc); 220185435Sbz} 221185435Sbz#endif 222185435Sbz 223191673Sjamie/* 224191673Sjamie * struct jail_args { 225191673Sjamie * struct jail *jail; 226191673Sjamie * }; 227191673Sjamie */ 228191673Sjamieint 229191673Sjamiejail(struct thread *td, struct jail_args *uap) 230185435Sbz{ 231191673Sjamie uint32_t version; 232191673Sjamie int error; 233192895Sjamie struct jail j; 234185435Sbz 235191673Sjamie error = copyin(uap->jail, &version, sizeof(uint32_t)); 236191673Sjamie if (error) 237191673Sjamie return (error); 238185435Sbz 239191673Sjamie switch (version) { 240191673Sjamie case 0: 241191673Sjamie { 242191673Sjamie struct jail_v0 j0; 243185435Sbz 244192895Sjamie /* FreeBSD single IPv4 jails. */ 245192895Sjamie bzero(&j, sizeof(struct jail)); 246191673Sjamie error = copyin(uap->jail, &j0, sizeof(struct jail_v0)); 247191673Sjamie if (error) 248191673Sjamie return (error); 249192895Sjamie j.version = j0.version; 250192895Sjamie j.path = j0.path; 251192895Sjamie j.hostname = j0.hostname; 252192895Sjamie j.ip4s = j0.ip_number; 253191673Sjamie break; 254191673Sjamie } 255191673Sjamie 256191673Sjamie case 1: 257185435Sbz /* 258191673Sjamie * Version 1 was used by multi-IPv4 jail implementations 259191673Sjamie * that never made it into the official kernel. 260185435Sbz */ 261191673Sjamie return (EINVAL); 262185435Sbz 263191673Sjamie case 2: /* JAIL_API_VERSION */ 264191673Sjamie /* FreeBSD multi-IPv4/IPv6,noIP jails. */ 265191673Sjamie error = copyin(uap->jail, &j, sizeof(struct jail)); 266191673Sjamie if (error) 267191673Sjamie return (error); 268192895Sjamie break; 269192895Sjamie 270192895Sjamie default: 271192895Sjamie /* Sci-Fi jails are not supported, sorry. */ 272192895Sjamie return (EINVAL); 273192895Sjamie } 274192895Sjamie return (kern_jail(td, &j)); 275192895Sjamie} 276192895Sjamie 277192895Sjamieint 278192895Sjamiekern_jail(struct thread *td, struct jail *j) 279192895Sjamie{ 280193865Sjamie struct iovec optiov[2 * (4 281193865Sjamie + sizeof(pr_allow_names) / sizeof(pr_allow_names[0]) 282193865Sjamie#ifdef INET 283193865Sjamie + 1 284193865Sjamie#endif 285193865Sjamie#ifdef INET6 286193865Sjamie + 1 287193865Sjamie#endif 288193865Sjamie )]; 289192895Sjamie struct uio opt; 290192895Sjamie char *u_path, *u_hostname, *u_name; 291185435Sbz#ifdef INET 292193865Sjamie uint32_t ip4s; 293192895Sjamie struct in_addr *u_ip4; 294192895Sjamie#endif 295192895Sjamie#ifdef INET6 296192895Sjamie struct in6_addr *u_ip6; 297192895Sjamie#endif 298192895Sjamie size_t tmplen; 299192895Sjamie int error, enforce_statfs, fi; 300192895Sjamie 301192895Sjamie bzero(&optiov, sizeof(optiov)); 302192895Sjamie opt.uio_iov = optiov; 303192895Sjamie opt.uio_iovcnt = 0; 304192895Sjamie opt.uio_offset = -1; 305192895Sjamie opt.uio_resid = -1; 306192895Sjamie opt.uio_segflg = UIO_SYSSPACE; 307192895Sjamie opt.uio_rw = UIO_READ; 308192895Sjamie opt.uio_td = td; 309192895Sjamie 310192895Sjamie /* Set permissions for top-level jails from sysctls. */ 311192895Sjamie if (!jailed(td->td_ucred)) { 312192895Sjamie for (fi = 0; fi < sizeof(pr_allow_names) / 313192895Sjamie sizeof(pr_allow_names[0]); fi++) { 314192895Sjamie optiov[opt.uio_iovcnt].iov_base = 315192895Sjamie (jail_default_allow & (1 << fi)) 316192895Sjamie ? pr_allow_names[fi] : pr_allow_nonames[fi]; 317192895Sjamie optiov[opt.uio_iovcnt].iov_len = 318192895Sjamie strlen(optiov[opt.uio_iovcnt].iov_base) + 1; 319192895Sjamie opt.uio_iovcnt += 2; 320192895Sjamie } 321192895Sjamie optiov[opt.uio_iovcnt].iov_base = "enforce_statfs"; 322192895Sjamie optiov[opt.uio_iovcnt].iov_len = sizeof("enforce_statfs"); 323192895Sjamie opt.uio_iovcnt++; 324192895Sjamie enforce_statfs = jail_default_enforce_statfs; 325192895Sjamie optiov[opt.uio_iovcnt].iov_base = &enforce_statfs; 326192895Sjamie optiov[opt.uio_iovcnt].iov_len = sizeof(enforce_statfs); 327192895Sjamie opt.uio_iovcnt++; 328192895Sjamie } 329192895Sjamie 330192895Sjamie tmplen = MAXPATHLEN + MAXHOSTNAMELEN + MAXHOSTNAMELEN; 331192895Sjamie#ifdef INET 332192895Sjamie ip4s = (j->version == 0) ? 1 : j->ip4s; 333192895Sjamie if (ip4s > jail_max_af_ips) 334192895Sjamie return (EINVAL); 335192895Sjamie tmplen += ip4s * sizeof(struct in_addr); 336191673Sjamie#else 337192895Sjamie if (j->ip4s > 0) 338192895Sjamie return (EINVAL); 339191673Sjamie#endif 340191673Sjamie#ifdef INET6 341192895Sjamie if (j->ip6s > jail_max_af_ips) 342192895Sjamie return (EINVAL); 343192895Sjamie tmplen += j->ip6s * sizeof(struct in6_addr); 344191673Sjamie#else 345192895Sjamie if (j->ip6s > 0) 346192895Sjamie return (EINVAL); 347191673Sjamie#endif 348192895Sjamie u_path = malloc(tmplen, M_TEMP, M_WAITOK); 349192895Sjamie u_hostname = u_path + MAXPATHLEN; 350192895Sjamie u_name = u_hostname + MAXHOSTNAMELEN; 351191673Sjamie#ifdef INET 352192895Sjamie u_ip4 = (struct in_addr *)(u_name + MAXHOSTNAMELEN); 353191673Sjamie#endif 354191673Sjamie#ifdef INET6 355191673Sjamie#ifdef INET 356192895Sjamie u_ip6 = (struct in6_addr *)(u_ip4 + ip4s); 357191673Sjamie#else 358192895Sjamie u_ip6 = (struct in6_addr *)(u_name + MAXHOSTNAMELEN); 359191673Sjamie#endif 360191673Sjamie#endif 361192895Sjamie optiov[opt.uio_iovcnt].iov_base = "path"; 362192895Sjamie optiov[opt.uio_iovcnt].iov_len = sizeof("path"); 363192895Sjamie opt.uio_iovcnt++; 364192895Sjamie optiov[opt.uio_iovcnt].iov_base = u_path; 365192895Sjamie error = copyinstr(j->path, u_path, MAXPATHLEN, 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 optiov[opt.uio_iovcnt].iov_base = "host.hostname"; 373192895Sjamie optiov[opt.uio_iovcnt].iov_len = sizeof("host.hostname"); 374192895Sjamie opt.uio_iovcnt++; 375192895Sjamie optiov[opt.uio_iovcnt].iov_base = u_hostname; 376192895Sjamie error = copyinstr(j->hostname, u_hostname, MAXHOSTNAMELEN, 377192895Sjamie &optiov[opt.uio_iovcnt].iov_len); 378192895Sjamie if (error) { 379192895Sjamie free(u_path, M_TEMP); 380192895Sjamie return (error); 381192895Sjamie } 382192895Sjamie opt.uio_iovcnt++; 383192895Sjamie if (j->jailname != NULL) { 384192895Sjamie optiov[opt.uio_iovcnt].iov_base = "name"; 385192895Sjamie optiov[opt.uio_iovcnt].iov_len = sizeof("name"); 386192895Sjamie opt.uio_iovcnt++; 387192895Sjamie optiov[opt.uio_iovcnt].iov_base = u_name; 388192895Sjamie error = copyinstr(j->jailname, u_name, MAXHOSTNAMELEN, 389192895Sjamie &optiov[opt.uio_iovcnt].iov_len); 390191673Sjamie if (error) { 391191673Sjamie free(u_path, M_TEMP); 392191673Sjamie return (error); 393191673Sjamie } 394192895Sjamie opt.uio_iovcnt++; 395192895Sjamie } 396191673Sjamie#ifdef INET 397192895Sjamie optiov[opt.uio_iovcnt].iov_base = "ip4.addr"; 398192895Sjamie optiov[opt.uio_iovcnt].iov_len = sizeof("ip4.addr"); 399192895Sjamie opt.uio_iovcnt++; 400192895Sjamie optiov[opt.uio_iovcnt].iov_base = u_ip4; 401192895Sjamie optiov[opt.uio_iovcnt].iov_len = ip4s * sizeof(struct in_addr); 402192895Sjamie if (j->version == 0) 403192895Sjamie u_ip4->s_addr = j->ip4s; 404192895Sjamie else { 405192895Sjamie error = copyin(j->ip4, u_ip4, optiov[opt.uio_iovcnt].iov_len); 406191673Sjamie if (error) { 407191673Sjamie free(u_path, M_TEMP); 408191673Sjamie return (error); 409191673Sjamie } 410192895Sjamie } 411192895Sjamie opt.uio_iovcnt++; 412185435Sbz#endif 413185435Sbz#ifdef INET6 414192895Sjamie optiov[opt.uio_iovcnt].iov_base = "ip6.addr"; 415192895Sjamie optiov[opt.uio_iovcnt].iov_len = sizeof("ip6.addr"); 416192895Sjamie opt.uio_iovcnt++; 417192895Sjamie optiov[opt.uio_iovcnt].iov_base = u_ip6; 418192895Sjamie optiov[opt.uio_iovcnt].iov_len = j->ip6s * sizeof(struct in6_addr); 419192895Sjamie error = copyin(j->ip6, u_ip6, optiov[opt.uio_iovcnt].iov_len); 420192895Sjamie if (error) { 421192895Sjamie free(u_path, M_TEMP); 422192895Sjamie return (error); 423192895Sjamie } 424192895Sjamie opt.uio_iovcnt++; 425185435Sbz#endif 426192895Sjamie KASSERT(opt.uio_iovcnt <= sizeof(optiov) / sizeof(optiov[0]), 427192895Sjamie ("kern_jail: too many iovecs (%d)", opt.uio_iovcnt)); 428191673Sjamie error = kern_jail_set(td, &opt, JAIL_CREATE | JAIL_ATTACH); 429191673Sjamie free(u_path, M_TEMP); 430191673Sjamie return (error); 431185435Sbz} 432185435Sbz 433192895Sjamie 434191673Sjamie/* 435191673Sjamie * struct jail_set_args { 436191673Sjamie * struct iovec *iovp; 437191673Sjamie * unsigned int iovcnt; 438191673Sjamie * int flags; 439191673Sjamie * }; 440191673Sjamie */ 441191673Sjamieint 442191673Sjamiejail_set(struct thread *td, struct jail_set_args *uap) 443185435Sbz{ 444191673Sjamie struct uio *auio; 445191673Sjamie int error; 446191673Sjamie 447191673Sjamie /* Check that we have an even number of iovecs. */ 448191673Sjamie if (uap->iovcnt & 1) 449191673Sjamie return (EINVAL); 450191673Sjamie 451191673Sjamie error = copyinuio(uap->iovp, uap->iovcnt, &auio); 452191673Sjamie if (error) 453191673Sjamie return (error); 454191673Sjamie error = kern_jail_set(td, auio, uap->flags); 455191673Sjamie free(auio, M_IOV); 456191673Sjamie return (error); 457191673Sjamie} 458191673Sjamie 459191673Sjamieint 460191673Sjamiekern_jail_set(struct thread *td, struct uio *optuio, int flags) 461191673Sjamie{ 462191673Sjamie struct nameidata nd; 463185435Sbz#ifdef INET 464190466Sjamie struct in_addr *ip4; 465185435Sbz#endif 466185435Sbz#ifdef INET6 467185435Sbz struct in6_addr *ip6; 468185435Sbz#endif 469191673Sjamie struct vfsopt *opt; 470191673Sjamie struct vfsoptlist *opts; 471195945Sjamie struct prison *pr, *deadpr, *mypr, *ppr, *tpr, *tppr; 472191673Sjamie struct vnode *root; 473193066Sjamie char *domain, *errmsg, *host, *name, *p, *path, *uuid; 474192895Sjamie#if defined(INET) || defined(INET6) 475191673Sjamie void *op; 476192895Sjamie#endif 477193066Sjamie unsigned long hid; 478192895Sjamie size_t namelen, onamelen; 479192895Sjamie int created, cuflags, descend, enforce, error, errmsg_len, errmsg_pos; 480195870Sjamie int gotchildmax, gotenforce, gothid, gotslevel; 481195870Sjamie int fi, jid, jsys, len, level; 482194762Sjamie int childmax, slevel, vfslocked; 483191673Sjamie#if defined(INET) || defined(INET6) 484192895Sjamie int ii, ij; 485191673Sjamie#endif 486191673Sjamie#ifdef INET 487192895Sjamie int ip4s, ip4a, redo_ip4; 488191673Sjamie#endif 489191673Sjamie#ifdef INET6 490192895Sjamie int ip6s, ip6a, redo_ip6; 491191673Sjamie#endif 492191673Sjamie unsigned pr_flags, ch_flags; 493192895Sjamie unsigned pr_allow, ch_allow, tallow; 494191673Sjamie char numbuf[12]; 495185435Sbz 496191673Sjamie error = priv_check(td, PRIV_JAIL_SET); 497191673Sjamie if (!error && (flags & JAIL_ATTACH)) 498191673Sjamie error = priv_check(td, PRIV_JAIL_ATTACH); 499191673Sjamie if (error) 500191673Sjamie return (error); 501192895Sjamie mypr = ppr = td->td_ucred->cr_prison; 502194762Sjamie if ((flags & JAIL_CREATE) && mypr->pr_childmax == 0) 503192895Sjamie return (EPERM); 504191673Sjamie if (flags & ~JAIL_SET_MASK) 505191673Sjamie return (EINVAL); 506191673Sjamie 507185435Sbz /* 508191673Sjamie * Check all the parameters before committing to anything. Not all 509191673Sjamie * errors can be caught early, but we may as well try. Also, this 510191673Sjamie * takes care of some expensive stuff (path lookup) before getting 511191673Sjamie * the allprison lock. 512185435Sbz * 513191673Sjamie * XXX Jails are not filesystems, and jail parameters are not mount 514191673Sjamie * options. But it makes more sense to re-use the vfsopt code 515191673Sjamie * than duplicate it under a different name. 516185435Sbz */ 517191673Sjamie error = vfs_buildopts(optuio, &opts); 518191673Sjamie if (error) 519191673Sjamie return (error); 520185435Sbz#ifdef INET 521192895Sjamie ip4a = 0; 522185435Sbz ip4 = NULL; 523185435Sbz#endif 524185435Sbz#ifdef INET6 525192895Sjamie ip6a = 0; 526185435Sbz ip6 = NULL; 527185435Sbz#endif 528191673Sjamie 529192895Sjamie#if defined(INET) || defined(INET6) 530192895Sjamie again: 531192895Sjamie#endif 532191673Sjamie error = vfs_copyopt(opts, "jid", &jid, sizeof(jid)); 533191673Sjamie if (error == ENOENT) 534191673Sjamie jid = 0; 535191673Sjamie else if (error != 0) 536191673Sjamie goto done_free; 537191673Sjamie 538191673Sjamie error = vfs_copyopt(opts, "securelevel", &slevel, sizeof(slevel)); 539191673Sjamie if (error == ENOENT) 540191673Sjamie gotslevel = 0; 541191673Sjamie else if (error != 0) 542191673Sjamie goto done_free; 543191673Sjamie else 544191673Sjamie gotslevel = 1; 545191673Sjamie 546194762Sjamie error = 547194762Sjamie vfs_copyopt(opts, "children.max", &childmax, sizeof(childmax)); 548194762Sjamie if (error == ENOENT) 549194762Sjamie gotchildmax = 0; 550194762Sjamie else if (error != 0) 551194762Sjamie goto done_free; 552194762Sjamie else 553194762Sjamie gotchildmax = 1; 554194762Sjamie 555192895Sjamie error = vfs_copyopt(opts, "enforce_statfs", &enforce, sizeof(enforce)); 556192895Sjamie gotenforce = (error == 0); 557192895Sjamie if (gotenforce) { 558192895Sjamie if (enforce < 0 || enforce > 2) 559192895Sjamie return (EINVAL); 560192895Sjamie } else if (error != ENOENT) 561192895Sjamie goto done_free; 562192895Sjamie 563191673Sjamie pr_flags = ch_flags = 0; 564192895Sjamie for (fi = 0; fi < sizeof(pr_flag_names) / sizeof(pr_flag_names[0]); 565192895Sjamie fi++) { 566192895Sjamie if (pr_flag_names[fi] == NULL) 567192895Sjamie continue; 568192895Sjamie vfs_flagopt(opts, pr_flag_names[fi], &pr_flags, 1 << fi); 569192895Sjamie vfs_flagopt(opts, pr_flag_nonames[fi], &ch_flags, 1 << fi); 570192895Sjamie } 571191673Sjamie ch_flags |= pr_flags; 572195870Sjamie for (fi = 0; fi < sizeof(pr_flag_jailsys) / sizeof(pr_flag_jailsys[0]); 573195870Sjamie fi++) { 574195870Sjamie error = vfs_copyopt(opts, pr_flag_jailsys[fi].name, &jsys, 575195870Sjamie sizeof(jsys)); 576195870Sjamie if (error == ENOENT) 577195870Sjamie continue; 578195870Sjamie if (error != 0) 579195870Sjamie goto done_free; 580195870Sjamie switch (jsys) { 581195870Sjamie case JAIL_SYS_DISABLE: 582195870Sjamie if (!pr_flag_jailsys[fi].disable) { 583195870Sjamie error = EINVAL; 584195870Sjamie goto done_free; 585195870Sjamie } 586195870Sjamie pr_flags |= pr_flag_jailsys[fi].disable; 587195870Sjamie break; 588195870Sjamie case JAIL_SYS_NEW: 589195870Sjamie pr_flags |= pr_flag_jailsys[fi].new; 590195870Sjamie break; 591195870Sjamie case JAIL_SYS_INHERIT: 592195870Sjamie break; 593195870Sjamie default: 594195870Sjamie error = EINVAL; 595195870Sjamie goto done_free; 596195870Sjamie } 597195870Sjamie ch_flags |= 598195870Sjamie pr_flag_jailsys[fi].new | pr_flag_jailsys[fi].disable; 599195870Sjamie } 600191673Sjamie if ((flags & (JAIL_CREATE | JAIL_UPDATE | JAIL_ATTACH)) == JAIL_CREATE 601191673Sjamie && !(pr_flags & PR_PERSIST)) { 602191673Sjamie error = EINVAL; 603191673Sjamie vfs_opterror(opts, "new jail must persist or attach"); 604191673Sjamie goto done_errmsg; 605191673Sjamie } 606194251Sjamie#ifdef VIMAGE 607194251Sjamie if ((flags & JAIL_UPDATE) && (ch_flags & PR_VNET)) { 608194251Sjamie error = EINVAL; 609194251Sjamie vfs_opterror(opts, "vnet cannot be changed after creation"); 610194251Sjamie goto done_errmsg; 611194251Sjamie } 612194251Sjamie#endif 613191673Sjamie 614192895Sjamie pr_allow = ch_allow = 0; 615192895Sjamie for (fi = 0; fi < sizeof(pr_allow_names) / sizeof(pr_allow_names[0]); 616192895Sjamie fi++) { 617192895Sjamie vfs_flagopt(opts, pr_allow_names[fi], &pr_allow, 1 << fi); 618192895Sjamie vfs_flagopt(opts, pr_allow_nonames[fi], &ch_allow, 1 << fi); 619192895Sjamie } 620192895Sjamie ch_allow |= pr_allow; 621192895Sjamie 622191673Sjamie error = vfs_getopt(opts, "name", (void **)&name, &len); 623191673Sjamie if (error == ENOENT) 624191673Sjamie name = NULL; 625191673Sjamie else if (error != 0) 626191673Sjamie goto done_free; 627191673Sjamie else { 628191673Sjamie if (len == 0 || name[len - 1] != '\0') { 629191673Sjamie error = EINVAL; 630191673Sjamie goto done_free; 631191673Sjamie } 632191673Sjamie if (len > MAXHOSTNAMELEN) { 633191673Sjamie error = ENAMETOOLONG; 634191673Sjamie goto done_free; 635191673Sjamie } 636191673Sjamie } 637191673Sjamie 638191673Sjamie error = vfs_getopt(opts, "host.hostname", (void **)&host, &len); 639191673Sjamie if (error == ENOENT) 640191673Sjamie host = NULL; 641191673Sjamie else if (error != 0) 642191673Sjamie goto done_free; 643191673Sjamie else { 644193066Sjamie ch_flags |= PR_HOST; 645193066Sjamie pr_flags |= PR_HOST; 646191673Sjamie if (len == 0 || host[len - 1] != '\0') { 647191673Sjamie error = EINVAL; 648191673Sjamie goto done_free; 649191673Sjamie } 650191673Sjamie if (len > MAXHOSTNAMELEN) { 651191673Sjamie error = ENAMETOOLONG; 652191673Sjamie goto done_free; 653191673Sjamie } 654191673Sjamie } 655191673Sjamie 656193066Sjamie error = vfs_getopt(opts, "host.domainname", (void **)&domain, &len); 657193066Sjamie if (error == ENOENT) 658193066Sjamie domain = NULL; 659193066Sjamie else if (error != 0) 660193066Sjamie goto done_free; 661193066Sjamie else { 662193066Sjamie ch_flags |= PR_HOST; 663193066Sjamie pr_flags |= PR_HOST; 664193066Sjamie if (len == 0 || domain[len - 1] != '\0') { 665193066Sjamie error = EINVAL; 666193066Sjamie goto done_free; 667193066Sjamie } 668193066Sjamie if (len > MAXHOSTNAMELEN) { 669193066Sjamie error = ENAMETOOLONG; 670193066Sjamie goto done_free; 671193066Sjamie } 672193066Sjamie } 673193066Sjamie 674193066Sjamie error = vfs_getopt(opts, "host.hostuuid", (void **)&uuid, &len); 675193066Sjamie if (error == ENOENT) 676193066Sjamie uuid = NULL; 677193066Sjamie else if (error != 0) 678193066Sjamie goto done_free; 679193066Sjamie else { 680193066Sjamie ch_flags |= PR_HOST; 681193066Sjamie pr_flags |= PR_HOST; 682193066Sjamie if (len == 0 || uuid[len - 1] != '\0') { 683193066Sjamie error = EINVAL; 684193066Sjamie goto done_free; 685193066Sjamie } 686193066Sjamie if (len > HOSTUUIDLEN) { 687193066Sjamie error = ENAMETOOLONG; 688193066Sjamie goto done_free; 689193066Sjamie } 690193066Sjamie } 691193066Sjamie 692193066Sjamie#ifdef COMPAT_IA32 693193066Sjamie if (td->td_proc->p_sysent->sv_flags & SV_IA32) { 694193066Sjamie uint32_t hid32; 695193066Sjamie 696193066Sjamie error = vfs_copyopt(opts, "host.hostid", &hid32, sizeof(hid32)); 697193066Sjamie hid = hid32; 698193066Sjamie } else 699193066Sjamie#endif 700193066Sjamie error = vfs_copyopt(opts, "host.hostid", &hid, sizeof(hid)); 701193066Sjamie if (error == ENOENT) 702193066Sjamie gothid = 0; 703193066Sjamie else if (error != 0) 704193066Sjamie goto done_free; 705193066Sjamie else { 706193066Sjamie gothid = 1; 707193066Sjamie ch_flags |= PR_HOST; 708193066Sjamie pr_flags |= PR_HOST; 709193066Sjamie } 710193066Sjamie 711192895Sjamie /* This might be the second time around for this option. */ 712185435Sbz#ifdef INET 713191673Sjamie error = vfs_getopt(opts, "ip4.addr", &op, &ip4s); 714191673Sjamie if (error == ENOENT) 715195870Sjamie ip4s = (pr_flags & PR_IP4_DISABLE) ? 0 : -1; 716191673Sjamie else if (error != 0) 717191673Sjamie goto done_free; 718191673Sjamie else if (ip4s & (sizeof(*ip4) - 1)) { 719191673Sjamie error = EINVAL; 720191673Sjamie goto done_free; 721192895Sjamie } else { 722195870Sjamie ch_flags |= PR_IP4_USER | PR_IP4_DISABLE; 723195870Sjamie if (ip4s == 0) 724195870Sjamie pr_flags |= PR_IP4_USER | PR_IP4_DISABLE; 725195870Sjamie else { 726195870Sjamie pr_flags = (pr_flags & ~PR_IP4_DISABLE) | PR_IP4_USER; 727192895Sjamie ip4s /= sizeof(*ip4); 728192895Sjamie if (ip4s > jail_max_af_ips) { 729185435Sbz error = EINVAL; 730192895Sjamie vfs_opterror(opts, "too many IPv4 addresses"); 731192895Sjamie goto done_errmsg; 732185435Sbz } 733192895Sjamie if (ip4a < ip4s) { 734192895Sjamie ip4a = ip4s; 735192895Sjamie free(ip4, M_PRISON); 736192895Sjamie ip4 = NULL; 737185435Sbz } 738192895Sjamie if (ip4 == NULL) 739192895Sjamie ip4 = malloc(ip4a * sizeof(*ip4), M_PRISON, 740192895Sjamie M_WAITOK); 741192895Sjamie bcopy(op, ip4, ip4s * sizeof(*ip4)); 742192895Sjamie /* 743192895Sjamie * IP addresses are all sorted but ip[0] to preserve 744192895Sjamie * the primary IP address as given from userland. 745192895Sjamie * This special IP is used for unbound outgoing 746192895Sjamie * connections as well for "loopback" traffic. 747192895Sjamie */ 748192895Sjamie if (ip4s > 1) 749192895Sjamie qsort(ip4 + 1, ip4s - 1, sizeof(*ip4), qcmp_v4); 750192895Sjamie /* 751192895Sjamie * Check for duplicate addresses and do some simple 752192895Sjamie * zero and broadcast checks. If users give other bogus 753192895Sjamie * addresses it is their problem. 754192895Sjamie * 755192895Sjamie * We do not have to care about byte order for these 756192895Sjamie * checks so we will do them in NBO. 757192895Sjamie */ 758192895Sjamie for (ii = 0; ii < ip4s; ii++) { 759192895Sjamie if (ip4[ii].s_addr == INADDR_ANY || 760192895Sjamie ip4[ii].s_addr == INADDR_BROADCAST) { 761192895Sjamie error = EINVAL; 762192895Sjamie goto done_free; 763192895Sjamie } 764192895Sjamie if ((ii+1) < ip4s && 765192895Sjamie (ip4[0].s_addr == ip4[ii+1].s_addr || 766192895Sjamie ip4[ii].s_addr == ip4[ii+1].s_addr)) { 767192895Sjamie error = EINVAL; 768192895Sjamie goto done_free; 769192895Sjamie } 770192895Sjamie } 771185435Sbz } 772191673Sjamie } 773191673Sjamie#endif 774185435Sbz 775185435Sbz#ifdef INET6 776191673Sjamie error = vfs_getopt(opts, "ip6.addr", &op, &ip6s); 777191673Sjamie if (error == ENOENT) 778195870Sjamie ip6s = (pr_flags & PR_IP6_DISABLE) ? 0 : -1; 779191673Sjamie else if (error != 0) 780191673Sjamie goto done_free; 781191673Sjamie else if (ip6s & (sizeof(*ip6) - 1)) { 782191673Sjamie error = EINVAL; 783191673Sjamie goto done_free; 784192895Sjamie } else { 785195870Sjamie ch_flags |= PR_IP6_USER | PR_IP6_DISABLE; 786195870Sjamie if (ip6s == 0) 787195870Sjamie pr_flags |= PR_IP6_USER | PR_IP6_DISABLE; 788195870Sjamie else { 789195870Sjamie pr_flags = (pr_flags & ~PR_IP6_DISABLE) | PR_IP6_USER; 790192895Sjamie ip6s /= sizeof(*ip6); 791192895Sjamie if (ip6s > jail_max_af_ips) { 792185435Sbz error = EINVAL; 793192895Sjamie vfs_opterror(opts, "too many IPv6 addresses"); 794192895Sjamie goto done_errmsg; 795185435Sbz } 796192895Sjamie if (ip6a < ip6s) { 797192895Sjamie ip6a = ip6s; 798192895Sjamie free(ip6, M_PRISON); 799192895Sjamie ip6 = NULL; 800185435Sbz } 801192895Sjamie if (ip6 == NULL) 802192895Sjamie ip6 = malloc(ip6a * sizeof(*ip6), M_PRISON, 803192895Sjamie M_WAITOK); 804192895Sjamie bcopy(op, ip6, ip6s * sizeof(*ip6)); 805192895Sjamie if (ip6s > 1) 806192895Sjamie qsort(ip6 + 1, ip6s - 1, sizeof(*ip6), qcmp_v6); 807192895Sjamie for (ii = 0; ii < ip6s; ii++) { 808192895Sjamie if (IN6_IS_ADDR_UNSPECIFIED(&ip6[ii])) { 809192895Sjamie error = EINVAL; 810192895Sjamie goto done_free; 811192895Sjamie } 812192895Sjamie if ((ii+1) < ip6s && 813192895Sjamie (IN6_ARE_ADDR_EQUAL(&ip6[0], &ip6[ii+1]) || 814192895Sjamie IN6_ARE_ADDR_EQUAL(&ip6[ii], &ip6[ii+1]))) 815192895Sjamie { 816192895Sjamie error = EINVAL; 817192895Sjamie goto done_free; 818192895Sjamie } 819192895Sjamie } 820185435Sbz } 821191673Sjamie } 822185435Sbz#endif 823185435Sbz 824195945Sjamie#if defined(VIMAGE) && (defined(INET) || defined(INET6)) 825195945Sjamie if ((ch_flags & PR_VNET) && (ch_flags & (PR_IP4_USER | PR_IP6_USER))) { 826195945Sjamie error = EINVAL; 827195945Sjamie vfs_opterror(opts, 828195945Sjamie "vnet jails cannot have IP address restrictions"); 829195945Sjamie goto done_errmsg; 830195945Sjamie } 831195945Sjamie#endif 832195945Sjamie 833191673Sjamie root = NULL; 834191673Sjamie error = vfs_getopt(opts, "path", (void **)&path, &len); 835191673Sjamie if (error == ENOENT) 836191673Sjamie path = NULL; 837191673Sjamie else if (error != 0) 838191673Sjamie goto done_free; 839191673Sjamie else { 840191673Sjamie if (flags & JAIL_UPDATE) { 841191673Sjamie error = EINVAL; 842191673Sjamie vfs_opterror(opts, 843191673Sjamie "path cannot be changed after creation"); 844191673Sjamie goto done_errmsg; 845191673Sjamie } 846191673Sjamie if (len == 0 || path[len - 1] != '\0') { 847191673Sjamie error = EINVAL; 848191673Sjamie goto done_free; 849191673Sjamie } 850191673Sjamie if (len < 2 || (len == 2 && path[0] == '/')) 851191673Sjamie path = NULL; 852191673Sjamie else { 853192895Sjamie /* Leave room for a real-root full pathname. */ 854192895Sjamie if (len + (path[0] == '/' && strcmp(mypr->pr_path, "/") 855192895Sjamie ? strlen(mypr->pr_path) : 0) > MAXPATHLEN) { 856192895Sjamie error = ENAMETOOLONG; 857192895Sjamie goto done_free; 858192895Sjamie } 859191673Sjamie NDINIT(&nd, LOOKUP, MPSAFE | FOLLOW, UIO_SYSSPACE, 860191673Sjamie path, td); 861191673Sjamie error = namei(&nd); 862191673Sjamie if (error) 863191673Sjamie goto done_free; 864191673Sjamie vfslocked = NDHASGIANT(&nd); 865191673Sjamie root = nd.ni_vp; 866191673Sjamie NDFREE(&nd, NDF_ONLY_PNBUF); 867191673Sjamie if (root->v_type != VDIR) { 868191673Sjamie error = ENOTDIR; 869191673Sjamie vrele(root); 870191673Sjamie VFS_UNLOCK_GIANT(vfslocked); 871191673Sjamie goto done_free; 872191673Sjamie } 873191673Sjamie VFS_UNLOCK_GIANT(vfslocked); 874191673Sjamie } 875191673Sjamie } 876185435Sbz 877191673Sjamie /* 878191673Sjamie * Grab the allprison lock before letting modules check their 879191673Sjamie * parameters. Once we have it, do not let go so we'll have a 880191673Sjamie * consistent view of the OSD list. 881191673Sjamie */ 882191673Sjamie sx_xlock(&allprison_lock); 883191673Sjamie error = osd_jail_call(NULL, PR_METHOD_CHECK, opts); 884191673Sjamie if (error) 885191673Sjamie goto done_unlock_list; 886185435Sbz 887191673Sjamie /* By now, all parameters should have been noted. */ 888191673Sjamie TAILQ_FOREACH(opt, opts, link) { 889191673Sjamie if (!opt->seen && strcmp(opt->name, "errmsg")) { 890191673Sjamie error = EINVAL; 891191673Sjamie vfs_opterror(opts, "unknown parameter: %s", opt->name); 892191673Sjamie goto done_unlock_list; 893191673Sjamie } 894191673Sjamie } 895191673Sjamie 896185435Sbz /* 897191673Sjamie * See if we are creating a new record or updating an existing one. 898191673Sjamie * This abuses the file error codes ENOENT and EEXIST. 899185435Sbz */ 900191673Sjamie cuflags = flags & (JAIL_CREATE | JAIL_UPDATE); 901191673Sjamie if (!cuflags) { 902191673Sjamie error = EINVAL; 903191673Sjamie vfs_opterror(opts, "no valid operation (create or update)"); 904191673Sjamie goto done_unlock_list; 905191673Sjamie } 906191673Sjamie pr = NULL; 907191673Sjamie if (jid != 0) { 908192895Sjamie /* 909192895Sjamie * See if a requested jid already exists. There is an 910192895Sjamie * information leak here if the jid exists but is not within 911192895Sjamie * the caller's jail hierarchy. Jail creators will get EEXIST 912192895Sjamie * even though they cannot see the jail, and CREATE | UPDATE 913192895Sjamie * will return ENOENT which is not normally a valid error. 914192895Sjamie */ 915191673Sjamie if (jid < 0) { 916191673Sjamie error = EINVAL; 917191673Sjamie vfs_opterror(opts, "negative jid"); 918191673Sjamie goto done_unlock_list; 919191673Sjamie } 920191673Sjamie pr = prison_find(jid); 921191673Sjamie if (pr != NULL) { 922192895Sjamie ppr = pr->pr_parent; 923191673Sjamie /* Create: jid must not exist. */ 924191673Sjamie if (cuflags == JAIL_CREATE) { 925191673Sjamie mtx_unlock(&pr->pr_mtx); 926191673Sjamie error = EEXIST; 927191673Sjamie vfs_opterror(opts, "jail %d already exists", 928191673Sjamie jid); 929191673Sjamie goto done_unlock_list; 930191673Sjamie } 931192895Sjamie if (!prison_ischild(mypr, pr)) { 932192895Sjamie mtx_unlock(&pr->pr_mtx); 933192895Sjamie pr = NULL; 934192895Sjamie } else if (pr->pr_uref == 0) { 935191673Sjamie if (!(flags & JAIL_DYING)) { 936191673Sjamie mtx_unlock(&pr->pr_mtx); 937191673Sjamie error = ENOENT; 938191673Sjamie vfs_opterror(opts, "jail %d is dying", 939191673Sjamie jid); 940191673Sjamie goto done_unlock_list; 941191673Sjamie } else if ((flags & JAIL_ATTACH) || 942191673Sjamie (pr_flags & PR_PERSIST)) { 943191673Sjamie /* 944191673Sjamie * A dying jail might be resurrected 945191673Sjamie * (via attach or persist), but first 946191673Sjamie * it must determine if another jail 947191673Sjamie * has claimed its name. Accomplish 948191673Sjamie * this by implicitly re-setting the 949191673Sjamie * name. 950191673Sjamie */ 951191673Sjamie if (name == NULL) 952192895Sjamie name = prison_name(mypr, pr); 953191673Sjamie } 954191673Sjamie } 955191673Sjamie } 956191673Sjamie if (pr == NULL) { 957191673Sjamie /* Update: jid must exist. */ 958191673Sjamie if (cuflags == JAIL_UPDATE) { 959191673Sjamie error = ENOENT; 960191673Sjamie vfs_opterror(opts, "jail %d not found", jid); 961191673Sjamie goto done_unlock_list; 962191673Sjamie } 963191673Sjamie } 964191673Sjamie } 965191673Sjamie /* 966191673Sjamie * If the caller provided a name, look for a jail by that name. 967191673Sjamie * This has different semantics for creates and updates keyed by jid 968191673Sjamie * (where the name must not already exist in a different jail), 969191673Sjamie * and updates keyed by the name itself (where the name must exist 970191673Sjamie * because that is the jail being updated). 971191673Sjamie */ 972191673Sjamie if (name != NULL) { 973192895Sjamie p = strrchr(name, '.'); 974192895Sjamie if (p != NULL) { 975192895Sjamie /* 976192895Sjamie * This is a hierarchical name. Split it into the 977192895Sjamie * parent and child names, and make sure the parent 978192895Sjamie * exists or matches an already found jail. 979192895Sjamie */ 980192895Sjamie *p = '\0'; 981192895Sjamie if (pr != NULL) { 982192895Sjamie if (strncmp(name, ppr->pr_name, p - name) || 983192895Sjamie ppr->pr_name[p - name] != '\0') { 984192895Sjamie mtx_unlock(&pr->pr_mtx); 985192895Sjamie error = EINVAL; 986192895Sjamie vfs_opterror(opts, 987192895Sjamie "cannot change jail's parent"); 988192895Sjamie goto done_unlock_list; 989192895Sjamie } 990192895Sjamie } else { 991192895Sjamie ppr = prison_find_name(mypr, name); 992192895Sjamie if (ppr == NULL) { 993192895Sjamie error = ENOENT; 994192895Sjamie vfs_opterror(opts, 995192895Sjamie "jail \"%s\" not found", name); 996192895Sjamie goto done_unlock_list; 997192895Sjamie } 998192895Sjamie mtx_unlock(&ppr->pr_mtx); 999192895Sjamie } 1000192895Sjamie name = p + 1; 1001192895Sjamie } 1002191673Sjamie if (name[0] != '\0') { 1003192895Sjamie namelen = 1004192895Sjamie (ppr == &prison0) ? 0 : strlen(ppr->pr_name) + 1; 1005192895Sjamie name_again: 1006191673Sjamie deadpr = NULL; 1007192895Sjamie FOREACH_PRISON_CHILD(ppr, tpr) { 1008191673Sjamie if (tpr != pr && tpr->pr_ref > 0 && 1009192895Sjamie !strcmp(tpr->pr_name + namelen, name)) { 1010191673Sjamie if (pr == NULL && 1011191673Sjamie cuflags != JAIL_CREATE) { 1012191673Sjamie mtx_lock(&tpr->pr_mtx); 1013191673Sjamie if (tpr->pr_ref > 0) { 1014191673Sjamie /* 1015191673Sjamie * Use this jail 1016191673Sjamie * for updates. 1017191673Sjamie */ 1018191673Sjamie if (tpr->pr_uref > 0) { 1019191673Sjamie pr = tpr; 1020191673Sjamie break; 1021191673Sjamie } 1022191673Sjamie deadpr = tpr; 1023191673Sjamie } 1024191673Sjamie mtx_unlock(&tpr->pr_mtx); 1025191673Sjamie } else if (tpr->pr_uref > 0) { 1026191673Sjamie /* 1027191673Sjamie * Create, or update(jid): 1028191673Sjamie * name must not exist in an 1029192895Sjamie * active sibling jail. 1030191673Sjamie */ 1031191673Sjamie error = EEXIST; 1032191673Sjamie if (pr != NULL) 1033191673Sjamie mtx_unlock(&pr->pr_mtx); 1034191673Sjamie vfs_opterror(opts, 1035191673Sjamie "jail \"%s\" already exists", 1036191673Sjamie name); 1037191673Sjamie goto done_unlock_list; 1038191673Sjamie } 1039191673Sjamie } 1040191673Sjamie } 1041191673Sjamie /* If no active jail is found, use a dying one. */ 1042191673Sjamie if (deadpr != NULL && pr == NULL) { 1043191673Sjamie if (flags & JAIL_DYING) { 1044191673Sjamie mtx_lock(&deadpr->pr_mtx); 1045191673Sjamie if (deadpr->pr_ref == 0) { 1046191673Sjamie mtx_unlock(&deadpr->pr_mtx); 1047191673Sjamie goto name_again; 1048191673Sjamie } 1049191673Sjamie pr = deadpr; 1050191673Sjamie } else if (cuflags == JAIL_UPDATE) { 1051191673Sjamie error = ENOENT; 1052191673Sjamie vfs_opterror(opts, 1053191673Sjamie "jail \"%s\" is dying", name); 1054191673Sjamie goto done_unlock_list; 1055191673Sjamie } 1056191673Sjamie } 1057191673Sjamie /* Update: name must exist if no jid. */ 1058191673Sjamie else if (cuflags == JAIL_UPDATE && pr == NULL) { 1059191673Sjamie error = ENOENT; 1060191673Sjamie vfs_opterror(opts, "jail \"%s\" not found", 1061191673Sjamie name); 1062191673Sjamie goto done_unlock_list; 1063191673Sjamie } 1064191673Sjamie } 1065191673Sjamie } 1066191673Sjamie /* Update: must provide a jid or name. */ 1067191673Sjamie else if (cuflags == JAIL_UPDATE && pr == NULL) { 1068191673Sjamie error = ENOENT; 1069191673Sjamie vfs_opterror(opts, "update specified no jail"); 1070191673Sjamie goto done_unlock_list; 1071191673Sjamie } 1072185435Sbz 1073191673Sjamie /* If there's no prison to update, create a new one and link it in. */ 1074191673Sjamie if (pr == NULL) { 1075194762Sjamie for (tpr = mypr; tpr != NULL; tpr = tpr->pr_parent) 1076194762Sjamie if (tpr->pr_childcount >= tpr->pr_childmax) { 1077194762Sjamie error = EPERM; 1078194762Sjamie vfs_opterror(opts, "prison limit exceeded"); 1079194762Sjamie goto done_unlock_list; 1080194762Sjamie } 1081191673Sjamie created = 1; 1082192895Sjamie mtx_lock(&ppr->pr_mtx); 1083192895Sjamie if (ppr->pr_ref == 0 || (ppr->pr_flags & PR_REMOVE)) { 1084192895Sjamie mtx_unlock(&ppr->pr_mtx); 1085192895Sjamie error = ENOENT; 1086192895Sjamie vfs_opterror(opts, "parent jail went away!"); 1087192895Sjamie goto done_unlock_list; 1088192895Sjamie } 1089192895Sjamie ppr->pr_ref++; 1090192895Sjamie ppr->pr_uref++; 1091192895Sjamie mtx_unlock(&ppr->pr_mtx); 1092191673Sjamie pr = malloc(sizeof(*pr), M_PRISON, M_WAITOK | M_ZERO); 1093191673Sjamie if (jid == 0) { 1094191673Sjamie /* Find the next free jid. */ 1095191673Sjamie jid = lastprid + 1; 1096191673Sjamie findnext: 1097191673Sjamie if (jid == JAIL_MAX) 1098191673Sjamie jid = 1; 1099191673Sjamie TAILQ_FOREACH(tpr, &allprison, pr_list) { 1100191673Sjamie if (tpr->pr_id < jid) 1101191673Sjamie continue; 1102191673Sjamie if (tpr->pr_id > jid || tpr->pr_ref == 0) { 1103191673Sjamie TAILQ_INSERT_BEFORE(tpr, pr, pr_list); 1104191673Sjamie break; 1105191673Sjamie } 1106191673Sjamie if (jid == lastprid) { 1107191673Sjamie error = EAGAIN; 1108191673Sjamie vfs_opterror(opts, 1109191673Sjamie "no available jail IDs"); 1110191673Sjamie free(pr, M_PRISON); 1111192895Sjamie prison_deref(ppr, PD_DEREF | 1112192895Sjamie PD_DEUREF | PD_LIST_XLOCKED); 1113192895Sjamie goto done_releroot; 1114191673Sjamie } 1115191673Sjamie jid++; 1116191673Sjamie goto findnext; 1117191673Sjamie } 1118191673Sjamie lastprid = jid; 1119191673Sjamie } else { 1120191673Sjamie /* 1121191673Sjamie * The jail already has a jid (that did not yet exist), 1122191673Sjamie * so just find where to insert it. 1123191673Sjamie */ 1124191673Sjamie TAILQ_FOREACH(tpr, &allprison, pr_list) 1125191673Sjamie if (tpr->pr_id >= jid) { 1126191673Sjamie TAILQ_INSERT_BEFORE(tpr, pr, pr_list); 1127191673Sjamie break; 1128191673Sjamie } 1129191673Sjamie } 1130191673Sjamie if (tpr == NULL) 1131191673Sjamie TAILQ_INSERT_TAIL(&allprison, pr, pr_list); 1132192895Sjamie LIST_INSERT_HEAD(&ppr->pr_children, pr, pr_sibling); 1133192895Sjamie for (tpr = ppr; tpr != NULL; tpr = tpr->pr_parent) 1134194762Sjamie tpr->pr_childcount++; 1135185435Sbz 1136192895Sjamie pr->pr_parent = ppr; 1137191673Sjamie pr->pr_id = jid; 1138192895Sjamie 1139192895Sjamie /* Set some default values, and inherit some from the parent. */ 1140191673Sjamie if (name == NULL) 1141191673Sjamie name = ""; 1142191673Sjamie if (path == NULL) { 1143191673Sjamie path = "/"; 1144192895Sjamie root = mypr->pr_root; 1145191673Sjamie vref(root); 1146191673Sjamie } 1147195944Sjamie strlcpy(pr->pr_hostuuid, DEFAULT_HOSTUUID, HOSTUUIDLEN); 1148195944Sjamie pr->pr_flags |= PR_HOST; 1149195945Sjamie#if defined(INET) || defined(INET6) 1150195945Sjamie#ifdef VIMAGE 1151195945Sjamie if (!(pr_flags & PR_VNET)) 1152195945Sjamie#endif 1153195945Sjamie { 1154192895Sjamie#ifdef INET 1155195945Sjamie pr->pr_flags |= PR_IP4 | PR_IP4_USER | PR_IP4_DISABLE; 1156192895Sjamie#endif 1157192895Sjamie#ifdef INET6 1158195945Sjamie pr->pr_flags |= PR_IP6 | PR_IP6_USER | PR_IP6_DISABLE; 1159192895Sjamie#endif 1160195945Sjamie } 1161195945Sjamie#endif 1162192895Sjamie pr->pr_securelevel = ppr->pr_securelevel; 1163192895Sjamie pr->pr_allow = JAIL_DEFAULT_ALLOW & ppr->pr_allow; 1164192895Sjamie pr->pr_enforce_statfs = ppr->pr_enforce_statfs; 1165191673Sjamie 1166192895Sjamie LIST_INIT(&pr->pr_children); 1167192895Sjamie mtx_init(&pr->pr_mtx, "jail mutex", NULL, MTX_DEF | MTX_DUPOK); 1168191673Sjamie 1169194251Sjamie#ifdef VIMAGE 1170194251Sjamie /* Allocate a new vnet if specified. */ 1171194251Sjamie pr->pr_vnet = (pr_flags & PR_VNET) 1172194251Sjamie ? vnet_alloc() : ppr->pr_vnet; 1173194251Sjamie#endif 1174185435Sbz /* 1175191673Sjamie * Allocate a dedicated cpuset for each jail. 1176191673Sjamie * Unlike other initial settings, this may return an erorr. 1177185435Sbz */ 1178192895Sjamie error = cpuset_create_root(ppr, &pr->pr_cpuset); 1179191673Sjamie if (error) { 1180191673Sjamie prison_deref(pr, PD_LIST_XLOCKED); 1181191673Sjamie goto done_releroot; 1182191673Sjamie } 1183185435Sbz 1184191673Sjamie mtx_lock(&pr->pr_mtx); 1185185435Sbz /* 1186191673Sjamie * New prisons do not yet have a reference, because we do not 1187191673Sjamie * want other to see the incomplete prison once the 1188191673Sjamie * allprison_lock is downgraded. 1189185435Sbz */ 1190191673Sjamie } else { 1191191673Sjamie created = 0; 1192195945Sjamie#if defined(VIMAGE) && (defined(INET) || defined(INET6)) 1193195945Sjamie if ((pr->pr_flags & PR_VNET) && 1194195945Sjamie (ch_flags & (PR_IP4_USER | PR_IP6_USER))) { 1195195945Sjamie error = EINVAL; 1196195945Sjamie vfs_opterror(opts, 1197195945Sjamie "vnet jails cannot have IP address restrictions"); 1198195945Sjamie goto done_deref_locked; 1199195945Sjamie } 1200195945Sjamie#endif 1201191673Sjamie /* 1202191673Sjamie * Grab a reference for existing prisons, to ensure they 1203191673Sjamie * continue to exist for the duration of the call. 1204191673Sjamie */ 1205191673Sjamie pr->pr_ref++; 1206191673Sjamie } 1207185435Sbz 1208191673Sjamie /* Do final error checking before setting anything. */ 1209192895Sjamie if (gotslevel) { 1210192895Sjamie if (slevel < ppr->pr_securelevel) { 1211192895Sjamie error = EPERM; 1212192895Sjamie goto done_deref_locked; 1213192895Sjamie } 1214192895Sjamie } 1215194762Sjamie if (gotchildmax) { 1216194762Sjamie if (childmax >= ppr->pr_childmax) { 1217194762Sjamie error = EPERM; 1218194762Sjamie goto done_deref_locked; 1219194762Sjamie } 1220194762Sjamie } 1221192895Sjamie if (gotenforce) { 1222192895Sjamie if (enforce < ppr->pr_enforce_statfs) { 1223192895Sjamie error = EPERM; 1224192895Sjamie goto done_deref_locked; 1225192895Sjamie } 1226192895Sjamie } 1227185435Sbz#ifdef INET 1228192895Sjamie if (ch_flags & PR_IP4_USER) { 1229192895Sjamie if (ppr->pr_flags & PR_IP4) { 1230192895Sjamie if (!(pr_flags & PR_IP4_USER)) { 1231192895Sjamie /* 1232192895Sjamie * Silently ignore attempts to make the IP 1233192895Sjamie * addresses unrestricted when the parent is 1234192895Sjamie * restricted; in other words, interpret 1235192895Sjamie * "unrestricted" as "as unrestricted as 1236192895Sjamie * possible". 1237192895Sjamie */ 1238192895Sjamie ip4s = ppr->pr_ip4s; 1239192895Sjamie if (ip4s == 0) { 1240192895Sjamie free(ip4, M_PRISON); 1241192895Sjamie ip4 = NULL; 1242192895Sjamie } else if (ip4s <= ip4a) { 1243192895Sjamie /* Inherit the parent's address(es). */ 1244192895Sjamie bcopy(ppr->pr_ip4, ip4, 1245192895Sjamie ip4s * sizeof(*ip4)); 1246192895Sjamie } else { 1247192895Sjamie /* 1248192895Sjamie * There's no room for the parent's 1249192895Sjamie * address list. Allocate some more. 1250192895Sjamie */ 1251192895Sjamie ip4a = ip4s; 1252192895Sjamie free(ip4, M_PRISON); 1253192895Sjamie ip4 = malloc(ip4a * sizeof(*ip4), 1254192895Sjamie M_PRISON, M_NOWAIT); 1255192895Sjamie if (ip4 != NULL) 1256192895Sjamie bcopy(ppr->pr_ip4, ip4, 1257192895Sjamie ip4s * sizeof(*ip4)); 1258192895Sjamie else { 1259192895Sjamie /* Allocation failed without 1260192895Sjamie * sleeping. Unlocking the 1261192895Sjamie * prison now will invalidate 1262192895Sjamie * some checks and prematurely 1263192895Sjamie * show an unfinished new jail. 1264192895Sjamie * So let go of everything and 1265192895Sjamie * start over. 1266192895Sjamie */ 1267192895Sjamie prison_deref(pr, created 1268192895Sjamie ? PD_LOCKED | 1269192895Sjamie PD_LIST_XLOCKED 1270192895Sjamie : PD_DEREF | PD_LOCKED | 1271192895Sjamie PD_LIST_XLOCKED); 1272192895Sjamie if (root != NULL) { 1273192895Sjamie vfslocked = 1274192895Sjamie VFS_LOCK_GIANT( 1275192895Sjamie root->v_mount); 1276192895Sjamie vrele(root); 1277192895Sjamie VFS_UNLOCK_GIANT( 1278192895Sjamie vfslocked); 1279192895Sjamie } 1280192895Sjamie ip4 = malloc(ip4a * 1281192895Sjamie sizeof(*ip4), M_PRISON, 1282192895Sjamie M_WAITOK); 1283192895Sjamie goto again; 1284192895Sjamie } 1285192895Sjamie } 1286192895Sjamie } else if (ip4s > 0) { 1287192895Sjamie /* 1288192895Sjamie * Make sure the new set of IP addresses is a 1289192895Sjamie * subset of the parent's list. Don't worry 1290192895Sjamie * about the parent being unlocked, as any 1291192895Sjamie * setting is done with allprison_lock held. 1292192895Sjamie */ 1293192895Sjamie for (ij = 0; ij < ppr->pr_ip4s; ij++) 1294192895Sjamie if (ip4[0].s_addr == 1295192895Sjamie ppr->pr_ip4[ij].s_addr) 1296192895Sjamie break; 1297192895Sjamie if (ij == ppr->pr_ip4s) { 1298192895Sjamie error = EPERM; 1299192895Sjamie goto done_deref_locked; 1300192895Sjamie } 1301192895Sjamie if (ip4s > 1) { 1302192895Sjamie for (ii = ij = 1; ii < ip4s; ii++) { 1303192895Sjamie if (ip4[ii].s_addr == 1304192895Sjamie ppr->pr_ip4[0].s_addr) 1305192895Sjamie continue; 1306192895Sjamie for (; ij < ppr->pr_ip4s; ij++) 1307192895Sjamie if (ip4[ii].s_addr == 1308192895Sjamie ppr->pr_ip4[ij].s_addr) 1309192895Sjamie break; 1310192895Sjamie if (ij == ppr->pr_ip4s) 1311192895Sjamie break; 1312192895Sjamie } 1313192895Sjamie if (ij == ppr->pr_ip4s) { 1314192895Sjamie error = EPERM; 1315192895Sjamie goto done_deref_locked; 1316192895Sjamie } 1317192895Sjamie } 1318192895Sjamie } 1319192895Sjamie } 1320192895Sjamie if (ip4s > 0) { 1321192895Sjamie /* 1322192895Sjamie * Check for conflicting IP addresses. We permit them 1323192895Sjamie * if there is no more than one IP on each jail. If 1324192895Sjamie * there is a duplicate on a jail with more than one 1325192895Sjamie * IP stop checking and return error. 1326192895Sjamie */ 1327195945Sjamie tppr = ppr; 1328195945Sjamie#ifdef VIMAGE 1329195945Sjamie for (; tppr != &prison0; tppr = tppr->pr_parent) 1330195945Sjamie if (tppr->pr_flags & PR_VNET) 1331195945Sjamie break; 1332195945Sjamie#endif 1333195945Sjamie FOREACH_PRISON_DESCENDANT(tppr, tpr, descend) { 1334195945Sjamie if (tpr == pr || 1335195945Sjamie#ifdef VIMAGE 1336195945Sjamie (tpr != tppr && 1337195945Sjamie (tpr->pr_flags & PR_VNET)) || 1338195945Sjamie#endif 1339195945Sjamie tpr->pr_uref == 0) { 1340192895Sjamie descend = 0; 1341192895Sjamie continue; 1342192895Sjamie } 1343192895Sjamie if (!(tpr->pr_flags & PR_IP4_USER)) 1344192895Sjamie continue; 1345192895Sjamie descend = 0; 1346192895Sjamie if (tpr->pr_ip4 == NULL || 1347192895Sjamie (ip4s == 1 && tpr->pr_ip4s == 1)) 1348192895Sjamie continue; 1349192895Sjamie for (ii = 0; ii < ip4s; ii++) { 1350191673Sjamie if (_prison_check_ip4(tpr, 1351191673Sjamie &ip4[ii]) == 0) { 1352192895Sjamie error = EADDRINUSE; 1353191673Sjamie vfs_opterror(opts, 1354191673Sjamie "IPv4 addresses clash"); 1355191673Sjamie goto done_deref_locked; 1356191673Sjamie } 1357192895Sjamie } 1358192895Sjamie } 1359192895Sjamie } 1360192895Sjamie } 1361185435Sbz#endif 1362191673Sjamie#ifdef INET6 1363192895Sjamie if (ch_flags & PR_IP6_USER) { 1364192895Sjamie if (ppr->pr_flags & PR_IP6) { 1365192895Sjamie if (!(pr_flags & PR_IP6_USER)) { 1366192895Sjamie /* 1367192895Sjamie * Silently ignore attempts to make the IP 1368192895Sjamie * addresses unrestricted when the parent is 1369192895Sjamie * restricted. 1370192895Sjamie */ 1371192895Sjamie ip6s = ppr->pr_ip6s; 1372192895Sjamie if (ip6s == 0) { 1373192895Sjamie free(ip6, M_PRISON); 1374192895Sjamie ip6 = NULL; 1375192895Sjamie } else if (ip6s <= ip6a) { 1376192895Sjamie /* Inherit the parent's address(es). */ 1377192895Sjamie bcopy(ppr->pr_ip6, ip6, 1378192895Sjamie ip6s * sizeof(*ip6)); 1379192895Sjamie } else { 1380192895Sjamie /* 1381192895Sjamie * There's no room for the parent's 1382192895Sjamie * address list. 1383192895Sjamie */ 1384192895Sjamie ip6a = ip6s; 1385192895Sjamie free(ip6, M_PRISON); 1386192895Sjamie ip6 = malloc(ip6a * sizeof(*ip6), 1387192895Sjamie M_PRISON, M_NOWAIT); 1388192895Sjamie if (ip6 != NULL) 1389192895Sjamie bcopy(ppr->pr_ip6, ip6, 1390192895Sjamie ip6s * sizeof(*ip6)); 1391192895Sjamie else { 1392192895Sjamie prison_deref(pr, created 1393192895Sjamie ? PD_LOCKED | 1394192895Sjamie PD_LIST_XLOCKED 1395192895Sjamie : PD_DEREF | PD_LOCKED | 1396192895Sjamie PD_LIST_XLOCKED); 1397192895Sjamie if (root != NULL) { 1398192895Sjamie vfslocked = 1399192895Sjamie VFS_LOCK_GIANT( 1400192895Sjamie root->v_mount); 1401192895Sjamie vrele(root); 1402192895Sjamie VFS_UNLOCK_GIANT( 1403192895Sjamie vfslocked); 1404192895Sjamie } 1405192895Sjamie ip6 = malloc(ip6a * 1406192895Sjamie sizeof(*ip6), M_PRISON, 1407192895Sjamie M_WAITOK); 1408192895Sjamie goto again; 1409192895Sjamie } 1410192895Sjamie } 1411192895Sjamie } else if (ip6s > 0) { 1412192895Sjamie /* 1413192895Sjamie * Make sure the new set of IP addresses is a 1414192895Sjamie * subset of the parent's list. 1415192895Sjamie */ 1416192895Sjamie for (ij = 0; ij < ppr->pr_ip6s; ij++) 1417192895Sjamie if (IN6_ARE_ADDR_EQUAL(&ip6[0], 1418192895Sjamie &ppr->pr_ip6[ij])) 1419192895Sjamie break; 1420192895Sjamie if (ij == ppr->pr_ip6s) { 1421192895Sjamie error = EPERM; 1422192895Sjamie goto done_deref_locked; 1423192895Sjamie } 1424192895Sjamie if (ip6s > 1) { 1425192895Sjamie for (ii = ij = 1; ii < ip6s; ii++) { 1426192895Sjamie if (IN6_ARE_ADDR_EQUAL(&ip6[ii], 1427192895Sjamie &ppr->pr_ip6[0])) 1428192895Sjamie continue; 1429192895Sjamie for (; ij < ppr->pr_ip6s; ij++) 1430192895Sjamie if (IN6_ARE_ADDR_EQUAL( 1431192895Sjamie &ip6[ii], 1432192895Sjamie &ppr->pr_ip6[ij])) 1433192895Sjamie break; 1434192895Sjamie if (ij == ppr->pr_ip6s) 1435192895Sjamie break; 1436192895Sjamie } 1437192895Sjamie if (ij == ppr->pr_ip6s) { 1438192895Sjamie error = EPERM; 1439192895Sjamie goto done_deref_locked; 1440192895Sjamie } 1441192895Sjamie } 1442192895Sjamie } 1443192895Sjamie } 1444192895Sjamie if (ip6s > 0) { 1445192895Sjamie /* Check for conflicting IP addresses. */ 1446195945Sjamie tppr = ppr; 1447195945Sjamie#ifdef VIMAGE 1448195945Sjamie for (; tppr != &prison0; tppr = tppr->pr_parent) 1449195945Sjamie if (tppr->pr_flags & PR_VNET) 1450195945Sjamie break; 1451195945Sjamie#endif 1452195945Sjamie FOREACH_PRISON_DESCENDANT(tppr, tpr, descend) { 1453195945Sjamie if (tpr == pr || 1454195945Sjamie#ifdef VIMAGE 1455195945Sjamie (tpr != tppr && 1456195945Sjamie (tpr->pr_flags & PR_VNET)) || 1457195945Sjamie#endif 1458195945Sjamie tpr->pr_uref == 0) { 1459192895Sjamie descend = 0; 1460192895Sjamie continue; 1461192895Sjamie } 1462192895Sjamie if (!(tpr->pr_flags & PR_IP6_USER)) 1463192895Sjamie continue; 1464192895Sjamie descend = 0; 1465192895Sjamie if (tpr->pr_ip6 == NULL || 1466192895Sjamie (ip6s == 1 && tpr->pr_ip6s == 1)) 1467192895Sjamie continue; 1468192895Sjamie for (ii = 0; ii < ip6s; ii++) { 1469191673Sjamie if (_prison_check_ip6(tpr, 1470191673Sjamie &ip6[ii]) == 0) { 1471192895Sjamie error = EADDRINUSE; 1472191673Sjamie vfs_opterror(opts, 1473191673Sjamie "IPv6 addresses clash"); 1474191673Sjamie goto done_deref_locked; 1475191673Sjamie } 1476192895Sjamie } 1477192895Sjamie } 1478191673Sjamie } 1479192895Sjamie } 1480191673Sjamie#endif 1481192895Sjamie onamelen = namelen = 0; 1482192895Sjamie if (name != NULL) { 1483191673Sjamie /* Give a default name of the jid. */ 1484191673Sjamie if (name[0] == '\0') 1485191673Sjamie snprintf(name = numbuf, sizeof(numbuf), "%d", jid); 1486191673Sjamie else if (strtoul(name, &p, 10) != jid && *p == '\0') { 1487191673Sjamie error = EINVAL; 1488191673Sjamie vfs_opterror(opts, "name cannot be numeric"); 1489192895Sjamie goto done_deref_locked; 1490191673Sjamie } 1491191673Sjamie /* 1492192895Sjamie * Make sure the name isn't too long for the prison or its 1493192895Sjamie * children. 1494191673Sjamie */ 1495192895Sjamie onamelen = strlen(pr->pr_name); 1496192895Sjamie namelen = strlen(name); 1497192895Sjamie if (strlen(ppr->pr_name) + namelen + 2 > sizeof(pr->pr_name)) { 1498192895Sjamie error = ENAMETOOLONG; 1499192895Sjamie goto done_deref_locked; 1500192895Sjamie } 1501192895Sjamie FOREACH_PRISON_DESCENDANT(pr, tpr, descend) { 1502192895Sjamie if (strlen(tpr->pr_name) + (namelen - onamelen) >= 1503192895Sjamie sizeof(pr->pr_name)) { 1504192895Sjamie error = ENAMETOOLONG; 1505192895Sjamie goto done_deref_locked; 1506192895Sjamie } 1507192895Sjamie } 1508191673Sjamie } 1509192895Sjamie if (pr_allow & ~ppr->pr_allow) { 1510192895Sjamie error = EPERM; 1511192895Sjamie goto done_deref_locked; 1512192895Sjamie } 1513185435Sbz 1514191673Sjamie /* Set the parameters of the prison. */ 1515191673Sjamie#ifdef INET 1516192895Sjamie redo_ip4 = 0; 1517192895Sjamie if (ch_flags & PR_IP4_USER) { 1518192895Sjamie if (pr_flags & PR_IP4_USER) { 1519192895Sjamie /* Some restriction set. */ 1520192895Sjamie pr->pr_flags |= PR_IP4; 1521192895Sjamie if (ip4s >= 0) { 1522192895Sjamie free(pr->pr_ip4, M_PRISON); 1523192895Sjamie pr->pr_ip4s = ip4s; 1524192895Sjamie pr->pr_ip4 = ip4; 1525192895Sjamie ip4 = NULL; 1526192895Sjamie } 1527192895Sjamie } else if (ppr->pr_flags & PR_IP4) { 1528192895Sjamie /* This restriction cleared, but keep inherited. */ 1529192895Sjamie free(pr->pr_ip4, M_PRISON); 1530192895Sjamie pr->pr_ip4s = ip4s; 1531192895Sjamie pr->pr_ip4 = ip4; 1532192895Sjamie ip4 = NULL; 1533192895Sjamie } else { 1534192895Sjamie /* Restriction cleared, now unrestricted. */ 1535192895Sjamie pr->pr_flags &= ~PR_IP4; 1536192895Sjamie free(pr->pr_ip4, M_PRISON); 1537192895Sjamie pr->pr_ip4s = 0; 1538192895Sjamie } 1539192895Sjamie FOREACH_PRISON_DESCENDANT_LOCKED(pr, tpr, descend) { 1540195945Sjamie#ifdef VIMAGE 1541195945Sjamie if (tpr->pr_flags & PR_VNET) { 1542195945Sjamie descend = 0; 1543195945Sjamie continue; 1544195945Sjamie } 1545195945Sjamie#endif 1546192895Sjamie if (prison_restrict_ip4(tpr, NULL)) { 1547192895Sjamie redo_ip4 = 1; 1548192895Sjamie descend = 0; 1549192895Sjamie } 1550192895Sjamie } 1551185435Sbz } 1552191673Sjamie#endif 1553191673Sjamie#ifdef INET6 1554192895Sjamie redo_ip6 = 0; 1555192895Sjamie if (ch_flags & PR_IP6_USER) { 1556192895Sjamie if (pr_flags & PR_IP6_USER) { 1557192895Sjamie /* Some restriction set. */ 1558192895Sjamie pr->pr_flags |= PR_IP6; 1559192895Sjamie if (ip6s >= 0) { 1560192895Sjamie free(pr->pr_ip6, M_PRISON); 1561192895Sjamie pr->pr_ip6s = ip6s; 1562192895Sjamie pr->pr_ip6 = ip6; 1563192895Sjamie ip6 = NULL; 1564192895Sjamie } 1565192895Sjamie } else if (ppr->pr_flags & PR_IP6) { 1566192895Sjamie /* This restriction cleared, but keep inherited. */ 1567192895Sjamie free(pr->pr_ip6, M_PRISON); 1568192895Sjamie pr->pr_ip6s = ip6s; 1569192895Sjamie pr->pr_ip6 = ip6; 1570192895Sjamie ip6 = NULL; 1571192895Sjamie } else { 1572192895Sjamie /* Restriction cleared, now unrestricted. */ 1573192895Sjamie pr->pr_flags &= ~PR_IP6; 1574192895Sjamie free(pr->pr_ip6, M_PRISON); 1575192895Sjamie pr->pr_ip6s = 0; 1576192895Sjamie } 1577192895Sjamie FOREACH_PRISON_DESCENDANT_LOCKED(pr, tpr, descend) { 1578195945Sjamie#ifdef VIMAGE 1579195945Sjamie if (tpr->pr_flags & PR_VNET) { 1580195945Sjamie descend = 0; 1581195945Sjamie continue; 1582195945Sjamie } 1583195945Sjamie#endif 1584192895Sjamie if (prison_restrict_ip6(tpr, NULL)) { 1585192895Sjamie redo_ip6 = 1; 1586192895Sjamie descend = 0; 1587192895Sjamie } 1588192895Sjamie } 1589191673Sjamie } 1590191673Sjamie#endif 1591192895Sjamie if (gotslevel) { 1592191673Sjamie pr->pr_securelevel = slevel; 1593192895Sjamie /* Set all child jails to be at least this level. */ 1594192895Sjamie FOREACH_PRISON_DESCENDANT_LOCKED(pr, tpr, descend) 1595192895Sjamie if (tpr->pr_securelevel < slevel) 1596192895Sjamie tpr->pr_securelevel = slevel; 1597192895Sjamie } 1598194762Sjamie if (gotchildmax) { 1599194762Sjamie pr->pr_childmax = childmax; 1600194762Sjamie /* Set all child jails to under this limit. */ 1601194762Sjamie FOREACH_PRISON_DESCENDANT_LOCKED_LEVEL(pr, tpr, descend, level) 1602194762Sjamie if (tpr->pr_childmax > childmax - level) 1603194762Sjamie tpr->pr_childmax = childmax > level 1604194762Sjamie ? childmax - level : 0; 1605194762Sjamie } 1606192895Sjamie if (gotenforce) { 1607192895Sjamie pr->pr_enforce_statfs = enforce; 1608192895Sjamie /* Pass this restriction on to the children. */ 1609192895Sjamie FOREACH_PRISON_DESCENDANT_LOCKED(pr, tpr, descend) 1610192895Sjamie if (tpr->pr_enforce_statfs < enforce) 1611192895Sjamie tpr->pr_enforce_statfs = enforce; 1612192895Sjamie } 1613192895Sjamie if (name != NULL) { 1614192895Sjamie if (ppr == &prison0) 1615192895Sjamie strlcpy(pr->pr_name, name, sizeof(pr->pr_name)); 1616192895Sjamie else 1617192895Sjamie snprintf(pr->pr_name, sizeof(pr->pr_name), "%s.%s", 1618192895Sjamie ppr->pr_name, name); 1619192895Sjamie /* Change this component of child names. */ 1620192895Sjamie FOREACH_PRISON_DESCENDANT_LOCKED(pr, tpr, descend) { 1621192895Sjamie bcopy(tpr->pr_name + onamelen, tpr->pr_name + namelen, 1622192895Sjamie strlen(tpr->pr_name + onamelen) + 1); 1623192895Sjamie bcopy(pr->pr_name, tpr->pr_name, namelen); 1624192895Sjamie } 1625192895Sjamie } 1626191673Sjamie if (path != NULL) { 1627192895Sjamie /* Try to keep a real-rooted full pathname. */ 1628192895Sjamie if (path[0] == '/' && strcmp(mypr->pr_path, "/")) 1629192895Sjamie snprintf(pr->pr_path, sizeof(pr->pr_path), "%s%s", 1630192895Sjamie mypr->pr_path, path); 1631192895Sjamie else 1632192895Sjamie strlcpy(pr->pr_path, path, sizeof(pr->pr_path)); 1633191673Sjamie pr->pr_root = root; 1634191673Sjamie } 1635193066Sjamie if (PR_HOST & ch_flags & ~pr_flags) { 1636193066Sjamie if (pr->pr_flags & PR_HOST) { 1637193066Sjamie /* 1638193066Sjamie * Copy the parent's host info. As with pr_ip4 above, 1639193066Sjamie * the lack of a lock on the parent is not a problem; 1640193066Sjamie * it is always set with allprison_lock at least 1641193066Sjamie * shared, and is held exclusively here. 1642193066Sjamie */ 1643194118Sjamie strlcpy(pr->pr_hostname, pr->pr_parent->pr_hostname, 1644194118Sjamie sizeof(pr->pr_hostname)); 1645194118Sjamie strlcpy(pr->pr_domainname, pr->pr_parent->pr_domainname, 1646194118Sjamie sizeof(pr->pr_domainname)); 1647194118Sjamie strlcpy(pr->pr_hostuuid, pr->pr_parent->pr_hostuuid, 1648194118Sjamie sizeof(pr->pr_hostuuid)); 1649193066Sjamie pr->pr_hostid = pr->pr_parent->pr_hostid; 1650193066Sjamie } 1651193066Sjamie } else if (host != NULL || domain != NULL || uuid != NULL || gothid) { 1652193066Sjamie /* Set this prison, and any descendants without PR_HOST. */ 1653193066Sjamie if (host != NULL) 1654194118Sjamie strlcpy(pr->pr_hostname, host, sizeof(pr->pr_hostname)); 1655193066Sjamie if (domain != NULL) 1656194118Sjamie strlcpy(pr->pr_domainname, domain, 1657194118Sjamie sizeof(pr->pr_domainname)); 1658193066Sjamie if (uuid != NULL) 1659194118Sjamie strlcpy(pr->pr_hostuuid, uuid, sizeof(pr->pr_hostuuid)); 1660193066Sjamie if (gothid) 1661193066Sjamie pr->pr_hostid = hid; 1662193066Sjamie FOREACH_PRISON_DESCENDANT_LOCKED(pr, tpr, descend) { 1663193066Sjamie if (tpr->pr_flags & PR_HOST) 1664193066Sjamie descend = 0; 1665193066Sjamie else { 1666193066Sjamie if (host != NULL) 1667194118Sjamie strlcpy(tpr->pr_hostname, 1668194118Sjamie pr->pr_hostname, 1669194118Sjamie sizeof(tpr->pr_hostname)); 1670193066Sjamie if (domain != NULL) 1671194118Sjamie strlcpy(tpr->pr_domainname, 1672194118Sjamie pr->pr_domainname, 1673194118Sjamie sizeof(tpr->pr_domainname)); 1674193066Sjamie if (uuid != NULL) 1675194118Sjamie strlcpy(tpr->pr_hostuuid, 1676194118Sjamie pr->pr_hostuuid, 1677194118Sjamie sizeof(tpr->pr_hostuuid)); 1678193066Sjamie if (gothid) 1679193066Sjamie tpr->pr_hostid = hid; 1680193066Sjamie } 1681193066Sjamie } 1682193066Sjamie } 1683192895Sjamie if ((tallow = ch_allow & ~pr_allow)) { 1684192895Sjamie /* Clear allow bits in all children. */ 1685192895Sjamie FOREACH_PRISON_DESCENDANT_LOCKED(pr, tpr, descend) 1686192895Sjamie tpr->pr_allow &= ~tallow; 1687192895Sjamie } 1688192895Sjamie pr->pr_allow = (pr->pr_allow & ~ch_allow) | pr_allow; 1689191673Sjamie /* 1690191673Sjamie * Persistent prisons get an extra reference, and prisons losing their 1691191673Sjamie * persist flag lose that reference. Only do this for existing prisons 1692191673Sjamie * for now, so new ones will remain unseen until after the module 1693191673Sjamie * handlers have completed. 1694191673Sjamie */ 1695191673Sjamie if (!created && (ch_flags & PR_PERSIST & (pr_flags ^ pr->pr_flags))) { 1696191673Sjamie if (pr_flags & PR_PERSIST) { 1697191673Sjamie pr->pr_ref++; 1698191673Sjamie pr->pr_uref++; 1699191673Sjamie } else { 1700191673Sjamie pr->pr_ref--; 1701191673Sjamie pr->pr_uref--; 1702191673Sjamie } 1703191673Sjamie } 1704191673Sjamie pr->pr_flags = (pr->pr_flags & ~ch_flags) | pr_flags; 1705191673Sjamie mtx_unlock(&pr->pr_mtx); 1706185435Sbz 1707192895Sjamie /* Locks may have prevented a complete restriction of child IP 1708192895Sjamie * addresses. If so, allocate some more memory and try again. 1709192895Sjamie */ 1710192895Sjamie#ifdef INET 1711192895Sjamie while (redo_ip4) { 1712192895Sjamie ip4s = pr->pr_ip4s; 1713192895Sjamie ip4 = malloc(ip4s * sizeof(*ip4), M_PRISON, M_WAITOK); 1714192895Sjamie mtx_lock(&pr->pr_mtx); 1715192895Sjamie redo_ip4 = 0; 1716192895Sjamie FOREACH_PRISON_DESCENDANT_LOCKED(pr, tpr, descend) { 1717195945Sjamie#ifdef VIMAGE 1718195945Sjamie if (tpr->pr_flags & PR_VNET) { 1719195945Sjamie descend = 0; 1720195945Sjamie continue; 1721195945Sjamie } 1722195945Sjamie#endif 1723192895Sjamie if (prison_restrict_ip4(tpr, ip4)) { 1724192895Sjamie if (ip4 != NULL) 1725192895Sjamie ip4 = NULL; 1726192895Sjamie else 1727192895Sjamie redo_ip4 = 1; 1728192895Sjamie } 1729192895Sjamie } 1730192895Sjamie mtx_unlock(&pr->pr_mtx); 1731192895Sjamie } 1732192895Sjamie#endif 1733192895Sjamie#ifdef INET6 1734192895Sjamie while (redo_ip6) { 1735192895Sjamie ip6s = pr->pr_ip6s; 1736192895Sjamie ip6 = malloc(ip6s * sizeof(*ip6), M_PRISON, M_WAITOK); 1737192895Sjamie mtx_lock(&pr->pr_mtx); 1738192895Sjamie redo_ip6 = 0; 1739192895Sjamie FOREACH_PRISON_DESCENDANT_LOCKED(pr, tpr, descend) { 1740195945Sjamie#ifdef VIMAGE 1741195945Sjamie if (tpr->pr_flags & PR_VNET) { 1742195945Sjamie descend = 0; 1743195945Sjamie continue; 1744195945Sjamie } 1745195945Sjamie#endif 1746192895Sjamie if (prison_restrict_ip6(tpr, ip6)) { 1747192895Sjamie if (ip6 != NULL) 1748192895Sjamie ip6 = NULL; 1749192895Sjamie else 1750192895Sjamie redo_ip6 = 1; 1751192895Sjamie } 1752192895Sjamie } 1753192895Sjamie mtx_unlock(&pr->pr_mtx); 1754192895Sjamie } 1755192895Sjamie#endif 1756192895Sjamie 1757191673Sjamie /* Let the modules do their work. */ 1758191673Sjamie sx_downgrade(&allprison_lock); 1759191673Sjamie if (created) { 1760191673Sjamie error = osd_jail_call(pr, PR_METHOD_CREATE, opts); 1761191673Sjamie if (error) { 1762191673Sjamie prison_deref(pr, PD_LIST_SLOCKED); 1763191673Sjamie goto done_errmsg; 1764191673Sjamie } 1765191673Sjamie } 1766191673Sjamie error = osd_jail_call(pr, PR_METHOD_SET, opts); 1767191673Sjamie if (error) { 1768191673Sjamie prison_deref(pr, created 1769191673Sjamie ? PD_LIST_SLOCKED 1770191673Sjamie : PD_DEREF | PD_LIST_SLOCKED); 1771191673Sjamie goto done_errmsg; 1772191673Sjamie } 1773191673Sjamie 1774191673Sjamie /* Attach this process to the prison if requested. */ 1775191673Sjamie if (flags & JAIL_ATTACH) { 1776191673Sjamie mtx_lock(&pr->pr_mtx); 1777191673Sjamie error = do_jail_attach(td, pr); 1778191673Sjamie if (error) { 1779191673Sjamie vfs_opterror(opts, "attach failed"); 1780191673Sjamie if (!created) 1781191673Sjamie prison_deref(pr, PD_DEREF); 1782191673Sjamie goto done_errmsg; 1783191673Sjamie } 1784191673Sjamie } 1785191673Sjamie 1786191673Sjamie /* 1787191673Sjamie * Now that it is all there, drop the temporary reference from existing 1788191673Sjamie * prisons. Or add a reference to newly created persistent prisons 1789191673Sjamie * (which was not done earlier so that the prison would not be publicly 1790191673Sjamie * visible). 1791191673Sjamie */ 1792191673Sjamie if (!created) { 1793191673Sjamie prison_deref(pr, (flags & JAIL_ATTACH) 1794191673Sjamie ? PD_DEREF 1795191673Sjamie : PD_DEREF | PD_LIST_SLOCKED); 1796191673Sjamie } else { 1797191673Sjamie if (pr_flags & PR_PERSIST) { 1798191673Sjamie mtx_lock(&pr->pr_mtx); 1799191673Sjamie pr->pr_ref++; 1800191673Sjamie pr->pr_uref++; 1801191673Sjamie mtx_unlock(&pr->pr_mtx); 1802191673Sjamie } 1803191673Sjamie if (!(flags & JAIL_ATTACH)) 1804191673Sjamie sx_sunlock(&allprison_lock); 1805191673Sjamie } 1806191673Sjamie td->td_retval[0] = pr->pr_id; 1807191673Sjamie goto done_errmsg; 1808191673Sjamie 1809192895Sjamie done_deref_locked: 1810192895Sjamie prison_deref(pr, created 1811192895Sjamie ? PD_LOCKED | PD_LIST_XLOCKED 1812192895Sjamie : PD_DEREF | PD_LOCKED | PD_LIST_XLOCKED); 1813192895Sjamie goto done_releroot; 1814191673Sjamie done_unlock_list: 1815191673Sjamie sx_xunlock(&allprison_lock); 1816191673Sjamie done_releroot: 1817191673Sjamie if (root != NULL) { 1818191673Sjamie vfslocked = VFS_LOCK_GIANT(root->v_mount); 1819191673Sjamie vrele(root); 1820191673Sjamie VFS_UNLOCK_GIANT(vfslocked); 1821191673Sjamie } 1822191673Sjamie done_errmsg: 1823191673Sjamie if (error) { 1824191673Sjamie vfs_getopt(opts, "errmsg", (void **)&errmsg, &errmsg_len); 1825191673Sjamie if (errmsg_len > 0) { 1826191673Sjamie errmsg_pos = 2 * vfs_getopt_pos(opts, "errmsg") + 1; 1827191673Sjamie if (errmsg_pos > 0) { 1828191673Sjamie if (optuio->uio_segflg == UIO_SYSSPACE) 1829191673Sjamie bcopy(errmsg, 1830191673Sjamie optuio->uio_iov[errmsg_pos].iov_base, 1831191673Sjamie errmsg_len); 1832191673Sjamie else 1833191673Sjamie copyout(errmsg, 1834191673Sjamie optuio->uio_iov[errmsg_pos].iov_base, 1835191673Sjamie errmsg_len); 1836191673Sjamie } 1837191673Sjamie } 1838191673Sjamie } 1839191673Sjamie done_free: 1840191673Sjamie#ifdef INET 1841191673Sjamie free(ip4, M_PRISON); 1842191673Sjamie#endif 1843191673Sjamie#ifdef INET6 1844191673Sjamie free(ip6, M_PRISON); 1845191673Sjamie#endif 1846191673Sjamie vfs_freeopts(opts); 1847191673Sjamie return (error); 1848191673Sjamie} 1849191673Sjamie 1850191673Sjamie 185182710Sdillon/* 1852191673Sjamie * struct jail_get_args { 1853191673Sjamie * struct iovec *iovp; 1854191673Sjamie * unsigned int iovcnt; 1855191673Sjamie * int flags; 1856114168Smike * }; 185782710Sdillon */ 185846155Sphkint 1859191673Sjamiejail_get(struct thread *td, struct jail_get_args *uap) 186046155Sphk{ 1861191673Sjamie struct uio *auio; 1862185435Sbz int error; 1863185435Sbz 1864191673Sjamie /* Check that we have an even number of iovecs. */ 1865191673Sjamie if (uap->iovcnt & 1) 1866191673Sjamie return (EINVAL); 1867191673Sjamie 1868191673Sjamie error = copyinuio(uap->iovp, uap->iovcnt, &auio); 1869185435Sbz if (error) 1870185435Sbz return (error); 1871191673Sjamie error = kern_jail_get(td, auio, uap->flags); 1872191673Sjamie if (error == 0) 1873191673Sjamie error = copyout(auio->uio_iov, uap->iovp, 1874191673Sjamie uap->iovcnt * sizeof (struct iovec)); 1875191673Sjamie free(auio, M_IOV); 1876191673Sjamie return (error); 1877191673Sjamie} 1878185435Sbz 1879191673Sjamieint 1880191673Sjamiekern_jail_get(struct thread *td, struct uio *optuio, int flags) 1881191673Sjamie{ 1882192895Sjamie struct prison *pr, *mypr; 1883191673Sjamie struct vfsopt *opt; 1884191673Sjamie struct vfsoptlist *opts; 1885191673Sjamie char *errmsg, *name; 1886192895Sjamie int error, errmsg_len, errmsg_pos, fi, i, jid, len, locked, pos; 1887185435Sbz 1888191673Sjamie if (flags & ~JAIL_GET_MASK) 1889191673Sjamie return (EINVAL); 1890185435Sbz 1891191673Sjamie /* Get the parameter list. */ 1892191673Sjamie error = vfs_buildopts(optuio, &opts); 1893191673Sjamie if (error) 1894191673Sjamie return (error); 1895191673Sjamie errmsg_pos = vfs_getopt_pos(opts, "errmsg"); 1896192895Sjamie mypr = td->td_ucred->cr_prison; 1897185435Sbz 1898191673Sjamie /* 1899191673Sjamie * Find the prison specified by one of: lastjid, jid, name. 1900191673Sjamie */ 1901191673Sjamie sx_slock(&allprison_lock); 1902191673Sjamie error = vfs_copyopt(opts, "lastjid", &jid, sizeof(jid)); 1903191673Sjamie if (error == 0) { 1904191673Sjamie TAILQ_FOREACH(pr, &allprison, pr_list) { 1905192895Sjamie if (pr->pr_id > jid && prison_ischild(mypr, pr)) { 1906191673Sjamie mtx_lock(&pr->pr_mtx); 1907191673Sjamie if (pr->pr_ref > 0 && 1908191673Sjamie (pr->pr_uref > 0 || (flags & JAIL_DYING))) 1909191673Sjamie break; 1910191673Sjamie mtx_unlock(&pr->pr_mtx); 1911191673Sjamie } 1912191673Sjamie } 1913191673Sjamie if (pr != NULL) 1914191673Sjamie goto found_prison; 1915191673Sjamie error = ENOENT; 1916191673Sjamie vfs_opterror(opts, "no jail after %d", jid); 1917191673Sjamie goto done_unlock_list; 1918191673Sjamie } else if (error != ENOENT) 1919191673Sjamie goto done_unlock_list; 1920185435Sbz 1921191673Sjamie error = vfs_copyopt(opts, "jid", &jid, sizeof(jid)); 1922191673Sjamie if (error == 0) { 1923191673Sjamie if (jid != 0) { 1924192895Sjamie pr = prison_find_child(mypr, jid); 1925191673Sjamie if (pr != NULL) { 1926191673Sjamie if (pr->pr_uref == 0 && !(flags & JAIL_DYING)) { 1927191673Sjamie mtx_unlock(&pr->pr_mtx); 1928191673Sjamie error = ENOENT; 1929191673Sjamie vfs_opterror(opts, "jail %d is dying", 1930191673Sjamie jid); 1931191673Sjamie goto done_unlock_list; 1932191673Sjamie } 1933191673Sjamie goto found_prison; 1934191673Sjamie } 1935191673Sjamie error = ENOENT; 1936191673Sjamie vfs_opterror(opts, "jail %d not found", jid); 1937191673Sjamie goto done_unlock_list; 1938191673Sjamie } 1939191673Sjamie } else if (error != ENOENT) 1940191673Sjamie goto done_unlock_list; 194146155Sphk 1942191673Sjamie error = vfs_getopt(opts, "name", (void **)&name, &len); 1943191673Sjamie if (error == 0) { 1944191673Sjamie if (len == 0 || name[len - 1] != '\0') { 1945191673Sjamie error = EINVAL; 1946191673Sjamie goto done_unlock_list; 1947191673Sjamie } 1948192895Sjamie pr = prison_find_name(mypr, name); 1949191673Sjamie if (pr != NULL) { 1950191673Sjamie if (pr->pr_uref == 0 && !(flags & JAIL_DYING)) { 1951191673Sjamie mtx_unlock(&pr->pr_mtx); 1952191673Sjamie error = ENOENT; 1953191673Sjamie vfs_opterror(opts, "jail \"%s\" is dying", 1954191673Sjamie name); 1955191673Sjamie goto done_unlock_list; 1956191673Sjamie } 1957191673Sjamie goto found_prison; 1958191673Sjamie } 1959191673Sjamie error = ENOENT; 1960191673Sjamie vfs_opterror(opts, "jail \"%s\" not found", name); 1961191673Sjamie goto done_unlock_list; 1962191673Sjamie } else if (error != ENOENT) 1963191673Sjamie goto done_unlock_list; 1964185435Sbz 1965191673Sjamie vfs_opterror(opts, "no jail specified"); 1966191673Sjamie error = ENOENT; 1967191673Sjamie goto done_unlock_list; 1968191673Sjamie 1969191673Sjamie found_prison: 1970191673Sjamie /* Get the parameters of the prison. */ 1971191673Sjamie pr->pr_ref++; 1972191673Sjamie locked = PD_LOCKED; 1973191673Sjamie td->td_retval[0] = pr->pr_id; 1974191673Sjamie error = vfs_setopt(opts, "jid", &pr->pr_id, sizeof(pr->pr_id)); 1975191673Sjamie if (error != 0 && error != ENOENT) 1976191673Sjamie goto done_deref; 1977192895Sjamie i = (pr->pr_parent == mypr) ? 0 : pr->pr_parent->pr_id; 1978192895Sjamie error = vfs_setopt(opts, "parent", &i, sizeof(i)); 1979191673Sjamie if (error != 0 && error != ENOENT) 1980191673Sjamie goto done_deref; 1981192895Sjamie error = vfs_setopts(opts, "name", prison_name(mypr, pr)); 1982192895Sjamie if (error != 0 && error != ENOENT) 1983192895Sjamie goto done_deref; 1984192895Sjamie error = vfs_setopt(opts, "cpuset.id", &pr->pr_cpuset->cs_id, 1985191673Sjamie sizeof(pr->pr_cpuset->cs_id)); 1986191673Sjamie if (error != 0 && error != ENOENT) 1987191673Sjamie goto done_deref; 1988192895Sjamie error = vfs_setopts(opts, "path", prison_path(mypr, pr)); 1989191673Sjamie if (error != 0 && error != ENOENT) 1990191673Sjamie goto done_deref; 1991191673Sjamie#ifdef INET 1992191673Sjamie error = vfs_setopt_part(opts, "ip4.addr", pr->pr_ip4, 1993191673Sjamie pr->pr_ip4s * sizeof(*pr->pr_ip4)); 1994191673Sjamie if (error != 0 && error != ENOENT) 1995191673Sjamie goto done_deref; 1996191673Sjamie#endif 1997191673Sjamie#ifdef INET6 1998191673Sjamie error = vfs_setopt_part(opts, "ip6.addr", pr->pr_ip6, 1999191673Sjamie pr->pr_ip6s * sizeof(*pr->pr_ip6)); 2000191673Sjamie if (error != 0 && error != ENOENT) 2001191673Sjamie goto done_deref; 2002191673Sjamie#endif 2003191673Sjamie error = vfs_setopt(opts, "securelevel", &pr->pr_securelevel, 2004191673Sjamie sizeof(pr->pr_securelevel)); 2005191673Sjamie if (error != 0 && error != ENOENT) 2006191673Sjamie goto done_deref; 2007194762Sjamie error = vfs_setopt(opts, "children.cur", &pr->pr_childcount, 2008194762Sjamie sizeof(pr->pr_childcount)); 2009194762Sjamie if (error != 0 && error != ENOENT) 2010194762Sjamie goto done_deref; 2011194762Sjamie error = vfs_setopt(opts, "children.max", &pr->pr_childmax, 2012194762Sjamie sizeof(pr->pr_childmax)); 2013194762Sjamie if (error != 0 && error != ENOENT) 2014194762Sjamie goto done_deref; 2015194118Sjamie error = vfs_setopts(opts, "host.hostname", pr->pr_hostname); 2016191673Sjamie if (error != 0 && error != ENOENT) 2017191673Sjamie goto done_deref; 2018194118Sjamie error = vfs_setopts(opts, "host.domainname", pr->pr_domainname); 2019193066Sjamie if (error != 0 && error != ENOENT) 2020193066Sjamie goto done_deref; 2021194118Sjamie error = vfs_setopts(opts, "host.hostuuid", pr->pr_hostuuid); 2022193066Sjamie if (error != 0 && error != ENOENT) 2023193066Sjamie goto done_deref; 2024193066Sjamie#ifdef COMPAT_IA32 2025193066Sjamie if (td->td_proc->p_sysent->sv_flags & SV_IA32) { 2026193066Sjamie uint32_t hid32 = pr->pr_hostid; 2027193066Sjamie 2028193066Sjamie error = vfs_setopt(opts, "host.hostid", &hid32, sizeof(hid32)); 2029193066Sjamie } else 2030193066Sjamie#endif 2031193066Sjamie error = vfs_setopt(opts, "host.hostid", &pr->pr_hostid, 2032193066Sjamie sizeof(pr->pr_hostid)); 2033193066Sjamie if (error != 0 && error != ENOENT) 2034193066Sjamie goto done_deref; 2035192895Sjamie error = vfs_setopt(opts, "enforce_statfs", &pr->pr_enforce_statfs, 2036192895Sjamie sizeof(pr->pr_enforce_statfs)); 2037191673Sjamie if (error != 0 && error != ENOENT) 2038191673Sjamie goto done_deref; 2039192895Sjamie for (fi = 0; fi < sizeof(pr_flag_names) / sizeof(pr_flag_names[0]); 2040192895Sjamie fi++) { 2041192895Sjamie if (pr_flag_names[fi] == NULL) 2042192895Sjamie continue; 2043192895Sjamie i = (pr->pr_flags & (1 << fi)) ? 1 : 0; 2044192895Sjamie error = vfs_setopt(opts, pr_flag_names[fi], &i, sizeof(i)); 2045192895Sjamie if (error != 0 && error != ENOENT) 2046192895Sjamie goto done_deref; 2047192895Sjamie i = !i; 2048192895Sjamie error = vfs_setopt(opts, pr_flag_nonames[fi], &i, sizeof(i)); 2049192895Sjamie if (error != 0 && error != ENOENT) 2050192895Sjamie goto done_deref; 2051192895Sjamie } 2052195870Sjamie for (fi = 0; fi < sizeof(pr_flag_jailsys) / sizeof(pr_flag_jailsys[0]); 2053195870Sjamie fi++) { 2054195870Sjamie i = pr->pr_flags & 2055195870Sjamie (pr_flag_jailsys[fi].disable | pr_flag_jailsys[fi].new); 2056195870Sjamie i = pr_flag_jailsys[fi].disable && 2057195870Sjamie (i == pr_flag_jailsys[fi].disable) ? JAIL_SYS_DISABLE 2058195870Sjamie : (i == pr_flag_jailsys[fi].new) ? JAIL_SYS_NEW 2059195870Sjamie : JAIL_SYS_INHERIT; 2060195870Sjamie error = 2061195870Sjamie vfs_setopt(opts, pr_flag_jailsys[fi].name, &i, sizeof(i)); 2062195870Sjamie if (error != 0 && error != ENOENT) 2063195870Sjamie goto done_deref; 2064195870Sjamie } 2065192895Sjamie for (fi = 0; fi < sizeof(pr_allow_names) / sizeof(pr_allow_names[0]); 2066192895Sjamie fi++) { 2067192895Sjamie if (pr_allow_names[fi] == NULL) 2068192895Sjamie continue; 2069192895Sjamie i = (pr->pr_allow & (1 << fi)) ? 1 : 0; 2070192895Sjamie error = vfs_setopt(opts, pr_allow_names[fi], &i, sizeof(i)); 2071192895Sjamie if (error != 0 && error != ENOENT) 2072192895Sjamie goto done_deref; 2073192895Sjamie i = !i; 2074192895Sjamie error = vfs_setopt(opts, pr_allow_nonames[fi], &i, sizeof(i)); 2075192895Sjamie if (error != 0 && error != ENOENT) 2076192895Sjamie goto done_deref; 2077192895Sjamie } 2078191673Sjamie i = (pr->pr_uref == 0); 2079191673Sjamie error = vfs_setopt(opts, "dying", &i, sizeof(i)); 2080191673Sjamie if (error != 0 && error != ENOENT) 2081191673Sjamie goto done_deref; 2082191673Sjamie i = !i; 2083191673Sjamie error = vfs_setopt(opts, "nodying", &i, sizeof(i)); 2084191673Sjamie if (error != 0 && error != ENOENT) 2085191673Sjamie goto done_deref; 2086191673Sjamie 2087191673Sjamie /* Get the module parameters. */ 2088191673Sjamie mtx_unlock(&pr->pr_mtx); 2089191673Sjamie locked = 0; 2090191673Sjamie error = osd_jail_call(pr, PR_METHOD_GET, opts); 209146155Sphk if (error) 2092191673Sjamie goto done_deref; 2093191673Sjamie prison_deref(pr, PD_DEREF | PD_LIST_SLOCKED); 209484828Sjhb 2095191673Sjamie /* By now, all parameters should have been noted. */ 2096191673Sjamie TAILQ_FOREACH(opt, opts, link) { 2097191673Sjamie if (!opt->seen && strcmp(opt->name, "errmsg")) { 2098191673Sjamie error = EINVAL; 2099191673Sjamie vfs_opterror(opts, "unknown parameter: %s", opt->name); 2100191673Sjamie goto done_errmsg; 2101191673Sjamie } 2102185435Sbz } 2103191673Sjamie 2104191673Sjamie /* Write the fetched parameters back to userspace. */ 2105191673Sjamie error = 0; 2106191673Sjamie TAILQ_FOREACH(opt, opts, link) { 2107191673Sjamie if (opt->pos >= 0 && opt->pos != errmsg_pos) { 2108191673Sjamie pos = 2 * opt->pos + 1; 2109191673Sjamie optuio->uio_iov[pos].iov_len = opt->len; 2110191673Sjamie if (opt->value != NULL) { 2111191673Sjamie if (optuio->uio_segflg == UIO_SYSSPACE) { 2112191673Sjamie bcopy(opt->value, 2113191673Sjamie optuio->uio_iov[pos].iov_base, 2114191673Sjamie opt->len); 2115191673Sjamie } else { 2116191673Sjamie error = copyout(opt->value, 2117191673Sjamie optuio->uio_iov[pos].iov_base, 2118191673Sjamie opt->len); 2119191673Sjamie if (error) 2120191673Sjamie break; 2121191673Sjamie } 2122191673Sjamie } 2123191673Sjamie } 2124185435Sbz } 2125191673Sjamie goto done_errmsg; 2126191673Sjamie 2127191673Sjamie done_deref: 2128191673Sjamie prison_deref(pr, locked | PD_DEREF | PD_LIST_SLOCKED); 2129191673Sjamie goto done_errmsg; 2130191673Sjamie 2131191673Sjamie done_unlock_list: 2132191673Sjamie sx_sunlock(&allprison_lock); 2133191673Sjamie done_errmsg: 2134191673Sjamie if (error && errmsg_pos >= 0) { 2135191673Sjamie vfs_getopt(opts, "errmsg", (void **)&errmsg, &errmsg_len); 2136191673Sjamie errmsg_pos = 2 * errmsg_pos + 1; 2137191673Sjamie if (errmsg_len > 0) { 2138191673Sjamie if (optuio->uio_segflg == UIO_SYSSPACE) 2139191673Sjamie bcopy(errmsg, 2140191673Sjamie optuio->uio_iov[errmsg_pos].iov_base, 2141191673Sjamie errmsg_len); 2142191673Sjamie else 2143191673Sjamie copyout(errmsg, 2144191673Sjamie optuio->uio_iov[errmsg_pos].iov_base, 2145191673Sjamie errmsg_len); 2146191673Sjamie } 2147185435Sbz } 2148191673Sjamie vfs_freeopts(opts); 2149191673Sjamie return (error); 2150191673Sjamie} 2151113275Smike 2152192895Sjamie 2153191673Sjamie/* 2154191673Sjamie * struct jail_remove_args { 2155191673Sjamie * int jid; 2156191673Sjamie * }; 2157191673Sjamie */ 2158191673Sjamieint 2159191673Sjamiejail_remove(struct thread *td, struct jail_remove_args *uap) 2160191673Sjamie{ 2161192895Sjamie struct prison *pr, *cpr, *lpr, *tpr; 2162192895Sjamie int descend, error; 2163185435Sbz 2164191673Sjamie error = priv_check(td, PRIV_JAIL_REMOVE); 2165185435Sbz if (error) 2166191673Sjamie return (error); 2167185435Sbz 2168185435Sbz sx_xlock(&allprison_lock); 2169192895Sjamie pr = prison_find_child(td->td_ucred->cr_prison, uap->jid); 2170191673Sjamie if (pr == NULL) { 2171185435Sbz sx_xunlock(&allprison_lock); 2172191673Sjamie return (EINVAL); 2173185435Sbz } 2174185435Sbz 2175192895Sjamie /* Remove all descendants of this prison, then remove this prison. */ 2176192895Sjamie pr->pr_ref++; 2177192895Sjamie pr->pr_flags |= PR_REMOVE; 2178192895Sjamie if (!LIST_EMPTY(&pr->pr_children)) { 2179192895Sjamie mtx_unlock(&pr->pr_mtx); 2180192895Sjamie lpr = NULL; 2181192895Sjamie FOREACH_PRISON_DESCENDANT(pr, cpr, descend) { 2182192895Sjamie mtx_lock(&cpr->pr_mtx); 2183192895Sjamie if (cpr->pr_ref > 0) { 2184192895Sjamie tpr = cpr; 2185192895Sjamie cpr->pr_ref++; 2186192895Sjamie cpr->pr_flags |= PR_REMOVE; 2187192895Sjamie } else { 2188192895Sjamie /* Already removed - do not do it again. */ 2189192895Sjamie tpr = NULL; 2190192895Sjamie } 2191192895Sjamie mtx_unlock(&cpr->pr_mtx); 2192192895Sjamie if (lpr != NULL) { 2193192895Sjamie mtx_lock(&lpr->pr_mtx); 2194192895Sjamie prison_remove_one(lpr); 2195192895Sjamie sx_xlock(&allprison_lock); 2196192895Sjamie } 2197192895Sjamie lpr = tpr; 2198192895Sjamie } 2199192895Sjamie if (lpr != NULL) { 2200192895Sjamie mtx_lock(&lpr->pr_mtx); 2201192895Sjamie prison_remove_one(lpr); 2202192895Sjamie sx_xlock(&allprison_lock); 2203192895Sjamie } 2204192895Sjamie mtx_lock(&pr->pr_mtx); 2205192895Sjamie } 2206192895Sjamie prison_remove_one(pr); 2207192895Sjamie return (0); 2208192895Sjamie} 2209192895Sjamie 2210192895Sjamiestatic void 2211192895Sjamieprison_remove_one(struct prison *pr) 2212192895Sjamie{ 2213192895Sjamie struct proc *p; 2214192895Sjamie int deuref; 2215192895Sjamie 2216191673Sjamie /* If the prison was persistent, it is not anymore. */ 2217191673Sjamie deuref = 0; 2218191673Sjamie if (pr->pr_flags & PR_PERSIST) { 2219191673Sjamie pr->pr_ref--; 2220191673Sjamie deuref = PD_DEUREF; 2221191673Sjamie pr->pr_flags &= ~PR_PERSIST; 2222179881Sdelphij } 2223113275Smike 2224192895Sjamie /* 2225192895Sjamie * jail_remove added a reference. If that's the only one, remove 2226192895Sjamie * the prison now. 2227192895Sjamie */ 2228192895Sjamie KASSERT(pr->pr_ref > 0, 2229192895Sjamie ("prison_remove_one removing a dead prison (jid=%d)", pr->pr_id)); 2230192895Sjamie if (pr->pr_ref == 1) { 2231191673Sjamie prison_deref(pr, 2232191673Sjamie deuref | PD_DEREF | PD_LOCKED | PD_LIST_XLOCKED); 2233192895Sjamie return; 2234191673Sjamie } 2235191673Sjamie 2236113275Smike mtx_unlock(&pr->pr_mtx); 2237191673Sjamie sx_xunlock(&allprison_lock); 2238191673Sjamie /* 2239191673Sjamie * Kill all processes unfortunate enough to be attached to this prison. 2240191673Sjamie */ 2241191673Sjamie sx_slock(&allproc_lock); 2242191673Sjamie LIST_FOREACH(p, &allproc, p_list) { 2243191673Sjamie PROC_LOCK(p); 2244191673Sjamie if (p->p_state != PRS_NEW && p->p_ucred && 2245191673Sjamie p->p_ucred->cr_prison == pr) 2246191673Sjamie psignal(p, SIGKILL); 2247191673Sjamie PROC_UNLOCK(p); 2248191673Sjamie } 2249191673Sjamie sx_sunlock(&allproc_lock); 2250192895Sjamie /* Remove the temporary reference added by jail_remove. */ 2251191673Sjamie prison_deref(pr, deuref | PD_DEREF); 2252113275Smike} 2253113275Smike 2254190466Sjamie 2255113275Smike/* 2256114168Smike * struct jail_attach_args { 2257114168Smike * int jid; 2258114168Smike * }; 2259113275Smike */ 2260113275Smikeint 2261114168Smikejail_attach(struct thread *td, struct jail_attach_args *uap) 2262113275Smike{ 2263113275Smike struct prison *pr; 2264191673Sjamie int error; 2265167309Spjd 2266164032Srwatson error = priv_check(td, PRIV_JAIL_ATTACH); 2267126023Snectar if (error) 2268126023Snectar return (error); 2269126023Snectar 2270168401Spjd sx_slock(&allprison_lock); 2271192895Sjamie pr = prison_find_child(td->td_ucred->cr_prison, uap->jid); 2272113275Smike if (pr == NULL) { 2273168401Spjd sx_sunlock(&allprison_lock); 2274113275Smike return (EINVAL); 2275113275Smike } 2276185435Sbz 2277185435Sbz /* 2278185435Sbz * Do not allow a process to attach to a prison that is not 2279191673Sjamie * considered to be "alive". 2280185435Sbz */ 2281191673Sjamie if (pr->pr_uref == 0) { 2282185435Sbz mtx_unlock(&pr->pr_mtx); 2283185435Sbz sx_sunlock(&allprison_lock); 2284185435Sbz return (EINVAL); 2285185435Sbz } 2286191673Sjamie 2287191673Sjamie return (do_jail_attach(td, pr)); 2288191673Sjamie} 2289191673Sjamie 2290191673Sjamiestatic int 2291191673Sjamiedo_jail_attach(struct thread *td, struct prison *pr) 2292191673Sjamie{ 2293192895Sjamie struct prison *ppr; 2294191673Sjamie struct proc *p; 2295191673Sjamie struct ucred *newcred, *oldcred; 2296191673Sjamie int vfslocked, error; 2297191673Sjamie 2298191673Sjamie /* 2299191673Sjamie * XXX: Note that there is a slight race here if two threads 2300191673Sjamie * in the same privileged process attempt to attach to two 2301191673Sjamie * different jails at the same time. It is important for 2302191673Sjamie * user processes not to do this, or they might end up with 2303191673Sjamie * a process root from one prison, but attached to the jail 2304191673Sjamie * of another. 2305191673Sjamie */ 2306113275Smike pr->pr_ref++; 2307191673Sjamie pr->pr_uref++; 2308113275Smike mtx_unlock(&pr->pr_mtx); 2309191673Sjamie 2310191673Sjamie /* Let modules do whatever they need to prepare for attaching. */ 2311191673Sjamie error = osd_jail_call(pr, PR_METHOD_ATTACH, td); 2312191673Sjamie if (error) { 2313191673Sjamie prison_deref(pr, PD_DEREF | PD_DEUREF | PD_LIST_SLOCKED); 2314191673Sjamie return (error); 2315191673Sjamie } 2316168401Spjd sx_sunlock(&allprison_lock); 2317113275Smike 2318185435Sbz /* 2319185435Sbz * Reparent the newly attached process to this jail. 2320185435Sbz */ 2321192895Sjamie ppr = td->td_ucred->cr_prison; 2322191673Sjamie p = td->td_proc; 2323185435Sbz error = cpuset_setproc_update_set(p, pr->pr_cpuset); 2324185435Sbz if (error) 2325191673Sjamie goto e_revert_osd; 2326185435Sbz 2327150652Scsjp vfslocked = VFS_LOCK_GIANT(pr->pr_root->v_mount); 2328175202Sattilio vn_lock(pr->pr_root, LK_EXCLUSIVE | LK_RETRY); 2329113275Smike if ((error = change_dir(pr->pr_root, td)) != 0) 2330113275Smike goto e_unlock; 2331113275Smike#ifdef MAC 2332172930Srwatson if ((error = mac_vnode_check_chroot(td->td_ucred, pr->pr_root))) 2333113275Smike goto e_unlock; 2334113275Smike#endif 2335175294Sattilio VOP_UNLOCK(pr->pr_root, 0); 2336191673Sjamie if ((error = change_root(pr->pr_root, td))) 2337191673Sjamie goto e_unlock_giant; 2338150652Scsjp VFS_UNLOCK_GIANT(vfslocked); 2339113275Smike 234084828Sjhb newcred = crget(); 234184828Sjhb PROC_LOCK(p); 234284828Sjhb oldcred = p->p_ucred; 2343113275Smike setsugid(p); 234484828Sjhb crcopy(newcred, oldcred); 2345113630Sjhb newcred->cr_prison = pr; 234684828Sjhb p->p_ucred = newcred; 234784828Sjhb PROC_UNLOCK(p); 234884828Sjhb crfree(oldcred); 2349192895Sjamie prison_deref(ppr, PD_DEREF | PD_DEUREF); 235046155Sphk return (0); 2351191673Sjamie e_unlock: 2352175294Sattilio VOP_UNLOCK(pr->pr_root, 0); 2353191673Sjamie e_unlock_giant: 2354150652Scsjp VFS_UNLOCK_GIANT(vfslocked); 2355191673Sjamie e_revert_osd: 2356191673Sjamie /* Tell modules this thread is still in its old jail after all. */ 2357192895Sjamie (void)osd_jail_call(ppr, PR_METHOD_ATTACH, td); 2358191673Sjamie prison_deref(pr, PD_DEREF | PD_DEUREF); 235946155Sphk return (error); 236046155Sphk} 236146155Sphk 2362192895Sjamie 2363113275Smike/* 2364113275Smike * Returns a locked prison instance, or NULL on failure. 2365113275Smike */ 2366168399Spjdstruct prison * 2367113275Smikeprison_find(int prid) 2368113275Smike{ 2369113275Smike struct prison *pr; 2370113275Smike 2371168401Spjd sx_assert(&allprison_lock, SX_LOCKED); 2372191673Sjamie TAILQ_FOREACH(pr, &allprison, pr_list) { 2373113275Smike if (pr->pr_id == prid) { 2374113275Smike mtx_lock(&pr->pr_mtx); 2375191673Sjamie if (pr->pr_ref > 0) 2376191673Sjamie return (pr); 2377191673Sjamie mtx_unlock(&pr->pr_mtx); 2378113275Smike } 2379113275Smike } 2380113275Smike return (NULL); 2381113275Smike} 2382113275Smike 2383191673Sjamie/* 2384192895Sjamie * Find a prison that is a descendant of mypr. Returns a locked prison or NULL. 2385191673Sjamie */ 2386191673Sjamiestruct prison * 2387192895Sjamieprison_find_child(struct prison *mypr, int prid) 2388191673Sjamie{ 2389192895Sjamie struct prison *pr; 2390192895Sjamie int descend; 2391192895Sjamie 2392192895Sjamie sx_assert(&allprison_lock, SX_LOCKED); 2393192895Sjamie FOREACH_PRISON_DESCENDANT(mypr, pr, descend) { 2394192895Sjamie if (pr->pr_id == prid) { 2395192895Sjamie mtx_lock(&pr->pr_mtx); 2396192895Sjamie if (pr->pr_ref > 0) 2397192895Sjamie return (pr); 2398192895Sjamie mtx_unlock(&pr->pr_mtx); 2399192895Sjamie } 2400192895Sjamie } 2401192895Sjamie return (NULL); 2402192895Sjamie} 2403192895Sjamie 2404192895Sjamie/* 2405192895Sjamie * Look for the name relative to mypr. Returns a locked prison or NULL. 2406192895Sjamie */ 2407192895Sjamiestruct prison * 2408192895Sjamieprison_find_name(struct prison *mypr, const char *name) 2409192895Sjamie{ 2410191673Sjamie struct prison *pr, *deadpr; 2411192895Sjamie size_t mylen; 2412192895Sjamie int descend; 2413191673Sjamie 2414191673Sjamie sx_assert(&allprison_lock, SX_LOCKED); 2415192895Sjamie mylen = (mypr == &prison0) ? 0 : strlen(mypr->pr_name) + 1; 2416191673Sjamie again: 2417191673Sjamie deadpr = NULL; 2418192895Sjamie FOREACH_PRISON_DESCENDANT(mypr, pr, descend) { 2419192895Sjamie if (!strcmp(pr->pr_name + mylen, name)) { 2420191673Sjamie mtx_lock(&pr->pr_mtx); 2421191673Sjamie if (pr->pr_ref > 0) { 2422191673Sjamie if (pr->pr_uref > 0) 2423191673Sjamie return (pr); 2424191673Sjamie deadpr = pr; 2425191673Sjamie } 2426191673Sjamie mtx_unlock(&pr->pr_mtx); 2427191673Sjamie } 2428191673Sjamie } 2429192895Sjamie /* There was no valid prison - perhaps there was a dying one. */ 2430191673Sjamie if (deadpr != NULL) { 2431191673Sjamie mtx_lock(&deadpr->pr_mtx); 2432191673Sjamie if (deadpr->pr_ref == 0) { 2433191673Sjamie mtx_unlock(&deadpr->pr_mtx); 2434191673Sjamie goto again; 2435191673Sjamie } 2436191673Sjamie } 2437191673Sjamie return (deadpr); 2438191673Sjamie} 2439191673Sjamie 2440191673Sjamie/* 2441192895Sjamie * See if a prison has the specific flag set. 2442192895Sjamie */ 2443192895Sjamieint 2444192895Sjamieprison_flag(struct ucred *cred, unsigned flag) 2445192895Sjamie{ 2446192895Sjamie 2447192895Sjamie /* This is an atomic read, so no locking is necessary. */ 2448192895Sjamie return (cred->cr_prison->pr_flags & flag); 2449192895Sjamie} 2450192895Sjamie 2451192895Sjamieint 2452192895Sjamieprison_allow(struct ucred *cred, unsigned flag) 2453192895Sjamie{ 2454192895Sjamie 2455192895Sjamie /* This is an atomic read, so no locking is necessary. */ 2456192895Sjamie return (cred->cr_prison->pr_allow & flag); 2457192895Sjamie} 2458192895Sjamie 2459192895Sjamie/* 2460191673Sjamie * Remove a prison reference. If that was the last reference, remove the 2461191673Sjamie * prison itself - but not in this context in case there are locks held. 2462191673Sjamie */ 246372786Srwatsonvoid 2464185029Spjdprison_free_locked(struct prison *pr) 246572786Srwatson{ 246672786Srwatson 2467185029Spjd mtx_assert(&pr->pr_mtx, MA_OWNED); 246872786Srwatson pr->pr_ref--; 246972786Srwatson if (pr->pr_ref == 0) { 2470168483Spjd mtx_unlock(&pr->pr_mtx); 2471124882Srwatson TASK_INIT(&pr->pr_task, 0, prison_complete, pr); 2472144660Sjeff taskqueue_enqueue(taskqueue_thread, &pr->pr_task); 247387275Srwatson return; 247472786Srwatson } 247587275Srwatson mtx_unlock(&pr->pr_mtx); 247672786Srwatson} 247772786Srwatson 2478185029Spjdvoid 2479185029Spjdprison_free(struct prison *pr) 2480185029Spjd{ 2481185029Spjd 2482185029Spjd mtx_lock(&pr->pr_mtx); 2483185029Spjd prison_free_locked(pr); 2484185029Spjd} 2485185029Spjd 2486124882Srwatsonstatic void 2487124882Srwatsonprison_complete(void *context, int pending) 2488124882Srwatson{ 2489191673Sjamie 2490191673Sjamie prison_deref((struct prison *)context, 0); 2491191673Sjamie} 2492191673Sjamie 2493191673Sjamie/* 2494191673Sjamie * Remove a prison reference (usually). This internal version assumes no 2495191673Sjamie * mutexes are held, except perhaps the prison itself. If there are no more 2496191673Sjamie * references, release and delist the prison. On completion, the prison lock 2497191673Sjamie * and the allprison lock are both unlocked. 2498191673Sjamie */ 2499191673Sjamiestatic void 2500191673Sjamieprison_deref(struct prison *pr, int flags) 2501191673Sjamie{ 2502192895Sjamie struct prison *ppr, *tpr; 2503150652Scsjp int vfslocked; 2504124882Srwatson 2505191673Sjamie if (!(flags & PD_LOCKED)) 2506191673Sjamie mtx_lock(&pr->pr_mtx); 2507192895Sjamie /* Decrement the user references in a separate loop. */ 2508191673Sjamie if (flags & PD_DEUREF) { 2509192895Sjamie for (tpr = pr;; tpr = tpr->pr_parent) { 2510192895Sjamie if (tpr != pr) 2511192895Sjamie mtx_lock(&tpr->pr_mtx); 2512192895Sjamie if (--tpr->pr_uref > 0) 2513192895Sjamie break; 2514192895Sjamie KASSERT(tpr != &prison0, ("prison0 pr_uref=0")); 2515192895Sjamie mtx_unlock(&tpr->pr_mtx); 2516192895Sjamie } 2517191673Sjamie /* Done if there were only user references to remove. */ 2518191673Sjamie if (!(flags & PD_DEREF)) { 2519192895Sjamie mtx_unlock(&tpr->pr_mtx); 2520191673Sjamie if (flags & PD_LIST_SLOCKED) 2521191673Sjamie sx_sunlock(&allprison_lock); 2522191673Sjamie else if (flags & PD_LIST_XLOCKED) 2523191673Sjamie sx_xunlock(&allprison_lock); 2524191673Sjamie return; 2525191673Sjamie } 2526192895Sjamie if (tpr != pr) { 2527192895Sjamie mtx_unlock(&tpr->pr_mtx); 2528192895Sjamie mtx_lock(&pr->pr_mtx); 2529192895Sjamie } 2530191673Sjamie } 2531124882Srwatson 2532192895Sjamie for (;;) { 2533192895Sjamie if (flags & PD_DEREF) 2534192895Sjamie pr->pr_ref--; 2535192895Sjamie /* If the prison still has references, nothing else to do. */ 2536192895Sjamie if (pr->pr_ref > 0) { 2537192895Sjamie mtx_unlock(&pr->pr_mtx); 2538192895Sjamie if (flags & PD_LIST_SLOCKED) 2539192895Sjamie sx_sunlock(&allprison_lock); 2540192895Sjamie else if (flags & PD_LIST_XLOCKED) 2541192895Sjamie sx_xunlock(&allprison_lock); 2542192895Sjamie return; 2543191673Sjamie } 2544191673Sjamie 2545192895Sjamie mtx_unlock(&pr->pr_mtx); 2546192895Sjamie if (flags & PD_LIST_SLOCKED) { 2547192895Sjamie if (!sx_try_upgrade(&allprison_lock)) { 2548192895Sjamie sx_sunlock(&allprison_lock); 2549192895Sjamie sx_xlock(&allprison_lock); 2550192895Sjamie } 2551192895Sjamie } else if (!(flags & PD_LIST_XLOCKED)) 2552192895Sjamie sx_xlock(&allprison_lock); 2553168489Spjd 2554192895Sjamie TAILQ_REMOVE(&allprison, pr, pr_list); 2555192895Sjamie LIST_REMOVE(pr, pr_sibling); 2556192895Sjamie ppr = pr->pr_parent; 2557192895Sjamie for (tpr = ppr; tpr != NULL; tpr = tpr->pr_parent) 2558194762Sjamie tpr->pr_childcount--; 2559192895Sjamie sx_downgrade(&allprison_lock); 2560192895Sjamie 2561194251Sjamie#ifdef VIMAGE 2562194251Sjamie if (pr->pr_flags & PR_VNET) 2563194251Sjamie vnet_destroy(pr->pr_vnet); 2564194251Sjamie#endif 2565192895Sjamie if (pr->pr_root != NULL) { 2566192895Sjamie vfslocked = VFS_LOCK_GIANT(pr->pr_root->v_mount); 2567192895Sjamie vrele(pr->pr_root); 2568192895Sjamie VFS_UNLOCK_GIANT(vfslocked); 2569192895Sjamie } 2570192895Sjamie mtx_destroy(&pr->pr_mtx); 2571191673Sjamie#ifdef INET 2572192895Sjamie free(pr->pr_ip4, M_PRISON); 2573191673Sjamie#endif 2574185435Sbz#ifdef INET6 2575192895Sjamie free(pr->pr_ip6, M_PRISON); 2576185435Sbz#endif 2577192895Sjamie if (pr->pr_cpuset != NULL) 2578192895Sjamie cpuset_rel(pr->pr_cpuset); 2579192895Sjamie osd_jail_exit(pr); 2580192895Sjamie free(pr, M_PRISON); 2581192895Sjamie 2582192895Sjamie /* Removing a prison frees a reference on its parent. */ 2583192895Sjamie pr = ppr; 2584192895Sjamie mtx_lock(&pr->pr_mtx); 2585192895Sjamie flags = PD_DEREF | PD_LIST_SLOCKED; 2586192895Sjamie } 2587124882Srwatson} 2588124882Srwatson 258972786Srwatsonvoid 2590185029Spjdprison_hold_locked(struct prison *pr) 259172786Srwatson{ 259272786Srwatson 2593185029Spjd mtx_assert(&pr->pr_mtx, MA_OWNED); 2594168489Spjd KASSERT(pr->pr_ref > 0, 2595191671Sjamie ("Trying to hold dead prison (jid=%d).", pr->pr_id)); 259672786Srwatson pr->pr_ref++; 2597185029Spjd} 2598185029Spjd 2599185029Spjdvoid 2600185029Spjdprison_hold(struct prison *pr) 2601185029Spjd{ 2602185029Spjd 2603185029Spjd mtx_lock(&pr->pr_mtx); 2604185029Spjd prison_hold_locked(pr); 260587275Srwatson mtx_unlock(&pr->pr_mtx); 260672786Srwatson} 260772786Srwatson 2608185435Sbzvoid 2609185435Sbzprison_proc_hold(struct prison *pr) 261087275Srwatson{ 261187275Srwatson 2612185435Sbz mtx_lock(&pr->pr_mtx); 2613191673Sjamie KASSERT(pr->pr_uref > 0, 2614191673Sjamie ("Cannot add a process to a non-alive prison (jid=%d)", pr->pr_id)); 2615191673Sjamie pr->pr_uref++; 2616185435Sbz mtx_unlock(&pr->pr_mtx); 261787275Srwatson} 261887275Srwatson 2619185435Sbzvoid 2620185435Sbzprison_proc_free(struct prison *pr) 2621185435Sbz{ 2622185435Sbz 2623185435Sbz mtx_lock(&pr->pr_mtx); 2624191673Sjamie KASSERT(pr->pr_uref > 0, 2625191673Sjamie ("Trying to kill a process in a dead prison (jid=%d)", pr->pr_id)); 2626191673Sjamie prison_deref(pr, PD_DEUREF | PD_LOCKED); 2627185435Sbz} 2628185435Sbz 2629185435Sbz 2630185435Sbz#ifdef INET 2631185435Sbz/* 2632192895Sjamie * Restrict a prison's IP address list with its parent's, possibly replacing 2633192895Sjamie * it. Return true if the replacement buffer was used (or would have been). 2634192895Sjamie */ 2635192895Sjamiestatic int 2636192895Sjamieprison_restrict_ip4(struct prison *pr, struct in_addr *newip4) 2637192895Sjamie{ 2638192895Sjamie int ii, ij, used; 2639192895Sjamie struct prison *ppr; 2640192895Sjamie 2641192895Sjamie ppr = pr->pr_parent; 2642192895Sjamie if (!(pr->pr_flags & PR_IP4_USER)) { 2643192895Sjamie /* This has no user settings, so just copy the parent's list. */ 2644192895Sjamie if (pr->pr_ip4s < ppr->pr_ip4s) { 2645192895Sjamie /* 2646192895Sjamie * There's no room for the parent's list. Use the 2647192895Sjamie * new list buffer, which is assumed to be big enough 2648192895Sjamie * (if it was passed). If there's no buffer, try to 2649192895Sjamie * allocate one. 2650192895Sjamie */ 2651192895Sjamie used = 1; 2652192895Sjamie if (newip4 == NULL) { 2653192895Sjamie newip4 = malloc(ppr->pr_ip4s * sizeof(*newip4), 2654192895Sjamie M_PRISON, M_NOWAIT); 2655192895Sjamie if (newip4 != NULL) 2656192895Sjamie used = 0; 2657192895Sjamie } 2658192895Sjamie if (newip4 != NULL) { 2659192895Sjamie bcopy(ppr->pr_ip4, newip4, 2660192895Sjamie ppr->pr_ip4s * sizeof(*newip4)); 2661192895Sjamie free(pr->pr_ip4, M_PRISON); 2662192895Sjamie pr->pr_ip4 = newip4; 2663192895Sjamie pr->pr_ip4s = ppr->pr_ip4s; 2664192895Sjamie pr->pr_flags |= PR_IP4; 2665192895Sjamie } 2666192895Sjamie return (used); 2667192895Sjamie } 2668192895Sjamie pr->pr_ip4s = ppr->pr_ip4s; 2669192895Sjamie if (pr->pr_ip4s > 0) 2670192895Sjamie bcopy(ppr->pr_ip4, pr->pr_ip4, 2671192895Sjamie pr->pr_ip4s * sizeof(*newip4)); 2672192895Sjamie else if (pr->pr_ip4 != NULL) { 2673192895Sjamie free(pr->pr_ip4, M_PRISON); 2674192895Sjamie pr->pr_ip4 = NULL; 2675192895Sjamie } 2676192895Sjamie pr->pr_flags = 2677192895Sjamie (pr->pr_flags & ~PR_IP4) | (ppr->pr_flags & PR_IP4); 2678192895Sjamie } else if (pr->pr_ip4s > 0 && (ppr->pr_flags & PR_IP4)) { 2679192895Sjamie /* Remove addresses that aren't in the parent. */ 2680192895Sjamie for (ij = 0; ij < ppr->pr_ip4s; ij++) 2681192895Sjamie if (pr->pr_ip4[0].s_addr == ppr->pr_ip4[ij].s_addr) 2682192895Sjamie break; 2683192895Sjamie if (ij < ppr->pr_ip4s) 2684192895Sjamie ii = 1; 2685192895Sjamie else { 2686192895Sjamie bcopy(pr->pr_ip4 + 1, pr->pr_ip4, 2687192895Sjamie --pr->pr_ip4s * sizeof(*pr->pr_ip4)); 2688192895Sjamie ii = 0; 2689192895Sjamie } 2690192895Sjamie for (ij = 1; ii < pr->pr_ip4s; ) { 2691192895Sjamie if (pr->pr_ip4[ii].s_addr == ppr->pr_ip4[0].s_addr) { 2692192895Sjamie ii++; 2693192895Sjamie continue; 2694192895Sjamie } 2695192895Sjamie switch (ij >= ppr->pr_ip4s ? -1 : 2696192895Sjamie qcmp_v4(&pr->pr_ip4[ii], &ppr->pr_ip4[ij])) { 2697192895Sjamie case -1: 2698192895Sjamie bcopy(pr->pr_ip4 + ii + 1, pr->pr_ip4 + ii, 2699192895Sjamie (--pr->pr_ip4s - ii) * sizeof(*pr->pr_ip4)); 2700192895Sjamie break; 2701192895Sjamie case 0: 2702192895Sjamie ii++; 2703192895Sjamie ij++; 2704192895Sjamie break; 2705192895Sjamie case 1: 2706192895Sjamie ij++; 2707192895Sjamie break; 2708192895Sjamie } 2709192895Sjamie } 2710192895Sjamie if (pr->pr_ip4s == 0) { 2711195870Sjamie pr->pr_flags |= PR_IP4_DISABLE; 2712192895Sjamie free(pr->pr_ip4, M_PRISON); 2713192895Sjamie pr->pr_ip4 = NULL; 2714192895Sjamie } 2715192895Sjamie } 2716192895Sjamie return (0); 2717192895Sjamie} 2718192895Sjamie 2719192895Sjamie/* 2720185435Sbz * Pass back primary IPv4 address of this jail. 2721185435Sbz * 2722192895Sjamie * If not restricted return success but do not alter the address. Caller has 2723192895Sjamie * to make sure to initialize it correctly (e.g. INADDR_ANY). 2724185435Sbz * 2725188144Sjamie * Returns 0 on success, EAFNOSUPPORT if the jail doesn't allow IPv4. 2726188144Sjamie * Address returned in NBO. 2727185435Sbz */ 272846155Sphkint 2729187684Sbzprison_get_ip4(struct ucred *cred, struct in_addr *ia) 273046155Sphk{ 2731191673Sjamie struct prison *pr; 273246155Sphk 2733185435Sbz KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 2734185435Sbz KASSERT(ia != NULL, ("%s: ia is NULL", __func__)); 2735185435Sbz 2736192895Sjamie pr = cred->cr_prison; 2737192895Sjamie if (!(pr->pr_flags & PR_IP4)) 273846155Sphk return (0); 2739191673Sjamie mtx_lock(&pr->pr_mtx); 2740192895Sjamie if (!(pr->pr_flags & PR_IP4)) { 2741192895Sjamie mtx_unlock(&pr->pr_mtx); 2742192895Sjamie return (0); 2743192895Sjamie } 2744191673Sjamie if (pr->pr_ip4 == NULL) { 2745191673Sjamie mtx_unlock(&pr->pr_mtx); 2746188144Sjamie return (EAFNOSUPPORT); 2747191673Sjamie } 2748185435Sbz 2749191673Sjamie ia->s_addr = pr->pr_ip4[0].s_addr; 2750191673Sjamie mtx_unlock(&pr->pr_mtx); 2751185435Sbz return (0); 2752185435Sbz} 2753185435Sbz 2754185435Sbz/* 2755192895Sjamie * Return true if pr1 and pr2 have the same IPv4 address restrictions. 2756192895Sjamie */ 2757192895Sjamieint 2758192895Sjamieprison_equal_ip4(struct prison *pr1, struct prison *pr2) 2759192895Sjamie{ 2760192895Sjamie 2761192895Sjamie if (pr1 == pr2) 2762192895Sjamie return (1); 2763192895Sjamie 2764192895Sjamie /* 2765192895Sjamie * jail_set maintains an exclusive hold on allprison_lock while it 2766192895Sjamie * changes the IP addresses, so only a shared hold is needed. This is 2767192895Sjamie * easier than locking the two prisons which would require finding the 2768192895Sjamie * proper locking order and end up needing allprison_lock anyway. 2769192895Sjamie */ 2770192895Sjamie sx_slock(&allprison_lock); 2771195945Sjamie while (pr1 != &prison0 && 2772195945Sjamie#ifdef VIMAGE 2773195945Sjamie !(pr1->pr_flags & PR_VNET) && 2774195945Sjamie#endif 2775195945Sjamie !(pr1->pr_flags & PR_IP4_USER)) 2776192895Sjamie pr1 = pr1->pr_parent; 2777195945Sjamie while (pr2 != &prison0 && 2778195945Sjamie#ifdef VIMAGE 2779195945Sjamie !(pr2->pr_flags & PR_VNET) && 2780195945Sjamie#endif 2781195945Sjamie !(pr2->pr_flags & PR_IP4_USER)) 2782192895Sjamie pr2 = pr2->pr_parent; 2783192895Sjamie sx_sunlock(&allprison_lock); 2784192895Sjamie return (pr1 == pr2); 2785192895Sjamie} 2786192895Sjamie 2787192895Sjamie/* 2788185435Sbz * Make sure our (source) address is set to something meaningful to this 2789185435Sbz * jail. 2790185435Sbz * 2791192895Sjamie * Returns 0 if jail doesn't restrict IPv4 or if address belongs to jail, 2792192895Sjamie * EADDRNOTAVAIL if the address doesn't belong, or EAFNOSUPPORT if the jail 2793192895Sjamie * doesn't allow IPv4. Address passed in in NBO and returned in NBO. 2794185435Sbz */ 2795185435Sbzint 2796185435Sbzprison_local_ip4(struct ucred *cred, struct in_addr *ia) 2797185435Sbz{ 2798191673Sjamie struct prison *pr; 2799185435Sbz struct in_addr ia0; 2800191673Sjamie int error; 2801185435Sbz 2802185435Sbz KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 2803185435Sbz KASSERT(ia != NULL, ("%s: ia is NULL", __func__)); 2804185435Sbz 2805192895Sjamie pr = cred->cr_prison; 2806192895Sjamie if (!(pr->pr_flags & PR_IP4)) 280746155Sphk return (0); 2808191673Sjamie mtx_lock(&pr->pr_mtx); 2809192895Sjamie if (!(pr->pr_flags & PR_IP4)) { 2810192895Sjamie mtx_unlock(&pr->pr_mtx); 2811192895Sjamie return (0); 2812192895Sjamie } 2813191673Sjamie if (pr->pr_ip4 == NULL) { 2814191673Sjamie mtx_unlock(&pr->pr_mtx); 2815188144Sjamie return (EAFNOSUPPORT); 2816191673Sjamie } 2817185435Sbz 2818185435Sbz ia0.s_addr = ntohl(ia->s_addr); 2819185435Sbz if (ia0.s_addr == INADDR_LOOPBACK) { 2820191673Sjamie ia->s_addr = pr->pr_ip4[0].s_addr; 2821191673Sjamie mtx_unlock(&pr->pr_mtx); 2822185435Sbz return (0); 282346155Sphk } 2824185435Sbz 2825188144Sjamie if (ia0.s_addr == INADDR_ANY) { 2826188144Sjamie /* 2827188144Sjamie * In case there is only 1 IPv4 address, bind directly. 2828188144Sjamie */ 2829191673Sjamie if (pr->pr_ip4s == 1) 2830191673Sjamie ia->s_addr = pr->pr_ip4[0].s_addr; 2831191673Sjamie mtx_unlock(&pr->pr_mtx); 2832185435Sbz return (0); 2833185435Sbz } 2834185435Sbz 2835191673Sjamie error = _prison_check_ip4(pr, ia); 2836191673Sjamie mtx_unlock(&pr->pr_mtx); 2837191673Sjamie return (error); 2838185435Sbz} 2839185435Sbz 2840185435Sbz/* 2841185435Sbz * Rewrite destination address in case we will connect to loopback address. 2842185435Sbz * 2843188144Sjamie * Returns 0 on success, EAFNOSUPPORT if the jail doesn't allow IPv4. 2844188144Sjamie * Address passed in in NBO and returned in NBO. 2845185435Sbz */ 2846185435Sbzint 2847185435Sbzprison_remote_ip4(struct ucred *cred, struct in_addr *ia) 2848185435Sbz{ 2849191673Sjamie struct prison *pr; 2850185435Sbz 2851185435Sbz KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 2852185435Sbz KASSERT(ia != NULL, ("%s: ia is NULL", __func__)); 2853185435Sbz 2854192895Sjamie pr = cred->cr_prison; 2855192895Sjamie if (!(pr->pr_flags & PR_IP4)) 2856185435Sbz return (0); 2857191673Sjamie mtx_lock(&pr->pr_mtx); 2858192895Sjamie if (!(pr->pr_flags & PR_IP4)) { 2859192895Sjamie mtx_unlock(&pr->pr_mtx); 2860192895Sjamie return (0); 2861192895Sjamie } 2862191673Sjamie if (pr->pr_ip4 == NULL) { 2863191673Sjamie mtx_unlock(&pr->pr_mtx); 2864188144Sjamie return (EAFNOSUPPORT); 2865191673Sjamie } 2866188144Sjamie 2867185435Sbz if (ntohl(ia->s_addr) == INADDR_LOOPBACK) { 2868191673Sjamie ia->s_addr = pr->pr_ip4[0].s_addr; 2869191673Sjamie mtx_unlock(&pr->pr_mtx); 2870185435Sbz return (0); 2871185435Sbz } 2872185435Sbz 2873185435Sbz /* 2874185435Sbz * Return success because nothing had to be changed. 2875185435Sbz */ 2876191673Sjamie mtx_unlock(&pr->pr_mtx); 2877185435Sbz return (0); 2878185435Sbz} 2879185435Sbz 2880185435Sbz/* 2881188144Sjamie * Check if given address belongs to the jail referenced by cred/prison. 2882185435Sbz * 2883192895Sjamie * Returns 0 if jail doesn't restrict IPv4 or if address belongs to jail, 2884192895Sjamie * EADDRNOTAVAIL if the address doesn't belong, or EAFNOSUPPORT if the jail 2885192895Sjamie * doesn't allow IPv4. Address passed in in NBO. 2886185435Sbz */ 2887185435Sbzstatic int 2888185435Sbz_prison_check_ip4(struct prison *pr, struct in_addr *ia) 2889185435Sbz{ 2890185435Sbz int i, a, z, d; 2891185435Sbz 2892185435Sbz /* 2893185435Sbz * Check the primary IP. 2894185435Sbz */ 2895185435Sbz if (pr->pr_ip4[0].s_addr == ia->s_addr) 2896188144Sjamie return (0); 2897185435Sbz 2898185435Sbz /* 2899185435Sbz * All the other IPs are sorted so we can do a binary search. 2900185435Sbz */ 2901185435Sbz a = 0; 2902185435Sbz z = pr->pr_ip4s - 2; 2903185435Sbz while (a <= z) { 2904185435Sbz i = (a + z) / 2; 2905185435Sbz d = qcmp_v4(&pr->pr_ip4[i+1], ia); 2906185435Sbz if (d > 0) 2907185435Sbz z = i - 1; 2908185435Sbz else if (d < 0) 2909185435Sbz a = i + 1; 291081114Srwatson else 2911188144Sjamie return (0); 2912185435Sbz } 2913188144Sjamie 2914188144Sjamie return (EADDRNOTAVAIL); 2915185435Sbz} 2916185435Sbz 2917185435Sbzint 2918185435Sbzprison_check_ip4(struct ucred *cred, struct in_addr *ia) 2919185435Sbz{ 2920191673Sjamie struct prison *pr; 2921191673Sjamie int error; 2922185435Sbz 2923185435Sbz KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 2924185435Sbz KASSERT(ia != NULL, ("%s: ia is NULL", __func__)); 2925185435Sbz 2926192895Sjamie pr = cred->cr_prison; 2927192895Sjamie if (!(pr->pr_flags & PR_IP4)) 2928188144Sjamie return (0); 2929191673Sjamie mtx_lock(&pr->pr_mtx); 2930192895Sjamie if (!(pr->pr_flags & PR_IP4)) { 2931192895Sjamie mtx_unlock(&pr->pr_mtx); 2932192895Sjamie return (0); 2933192895Sjamie } 2934191673Sjamie if (pr->pr_ip4 == NULL) { 2935191673Sjamie mtx_unlock(&pr->pr_mtx); 2936188144Sjamie return (EAFNOSUPPORT); 2937191673Sjamie } 2938185435Sbz 2939191673Sjamie error = _prison_check_ip4(pr, ia); 2940191673Sjamie mtx_unlock(&pr->pr_mtx); 2941191673Sjamie return (error); 2942185435Sbz} 2943185435Sbz#endif 2944185435Sbz 2945185435Sbz#ifdef INET6 2946192895Sjamiestatic int 2947192895Sjamieprison_restrict_ip6(struct prison *pr, struct in6_addr *newip6) 2948192895Sjamie{ 2949192895Sjamie int ii, ij, used; 2950192895Sjamie struct prison *ppr; 2951192895Sjamie 2952192895Sjamie ppr = pr->pr_parent; 2953192895Sjamie if (!(pr->pr_flags & PR_IP6_USER)) { 2954192895Sjamie /* This has no user settings, so just copy the parent's list. */ 2955192895Sjamie if (pr->pr_ip6s < ppr->pr_ip6s) { 2956192895Sjamie /* 2957192895Sjamie * There's no room for the parent's list. Use the 2958192895Sjamie * new list buffer, which is assumed to be big enough 2959192895Sjamie * (if it was passed). If there's no buffer, try to 2960192895Sjamie * allocate one. 2961192895Sjamie */ 2962192895Sjamie used = 1; 2963192895Sjamie if (newip6 == NULL) { 2964192895Sjamie newip6 = malloc(ppr->pr_ip6s * sizeof(*newip6), 2965192895Sjamie M_PRISON, M_NOWAIT); 2966192895Sjamie if (newip6 != NULL) 2967192895Sjamie used = 0; 2968192895Sjamie } 2969192895Sjamie if (newip6 != NULL) { 2970192895Sjamie bcopy(ppr->pr_ip6, newip6, 2971192895Sjamie ppr->pr_ip6s * sizeof(*newip6)); 2972192895Sjamie free(pr->pr_ip6, M_PRISON); 2973192895Sjamie pr->pr_ip6 = newip6; 2974192895Sjamie pr->pr_ip6s = ppr->pr_ip6s; 2975192895Sjamie pr->pr_flags |= PR_IP6; 2976192895Sjamie } 2977192895Sjamie return (used); 2978192895Sjamie } 2979192895Sjamie pr->pr_ip6s = ppr->pr_ip6s; 2980192895Sjamie if (pr->pr_ip6s > 0) 2981192895Sjamie bcopy(ppr->pr_ip6, pr->pr_ip6, 2982192895Sjamie pr->pr_ip6s * sizeof(*newip6)); 2983192895Sjamie else if (pr->pr_ip6 != NULL) { 2984192895Sjamie free(pr->pr_ip6, M_PRISON); 2985192895Sjamie pr->pr_ip6 = NULL; 2986192895Sjamie } 2987192895Sjamie pr->pr_flags = 2988192895Sjamie (pr->pr_flags & ~PR_IP6) | (ppr->pr_flags & PR_IP6); 2989192895Sjamie } else if (pr->pr_ip6s > 0 && (ppr->pr_flags & PR_IP6)) { 2990192895Sjamie /* Remove addresses that aren't in the parent. */ 2991192895Sjamie for (ij = 0; ij < ppr->pr_ip6s; ij++) 2992192895Sjamie if (IN6_ARE_ADDR_EQUAL(&pr->pr_ip6[0], 2993192895Sjamie &ppr->pr_ip6[ij])) 2994192895Sjamie break; 2995192895Sjamie if (ij < ppr->pr_ip6s) 2996192895Sjamie ii = 1; 2997192895Sjamie else { 2998192895Sjamie bcopy(pr->pr_ip6 + 1, pr->pr_ip6, 2999192895Sjamie --pr->pr_ip6s * sizeof(*pr->pr_ip6)); 3000192895Sjamie ii = 0; 3001192895Sjamie } 3002192895Sjamie for (ij = 1; ii < pr->pr_ip6s; ) { 3003192895Sjamie if (IN6_ARE_ADDR_EQUAL(&pr->pr_ip6[ii], 3004192895Sjamie &ppr->pr_ip6[0])) { 3005192895Sjamie ii++; 3006192895Sjamie continue; 3007192895Sjamie } 3008192895Sjamie switch (ij >= ppr->pr_ip4s ? -1 : 3009192895Sjamie qcmp_v6(&pr->pr_ip6[ii], &ppr->pr_ip6[ij])) { 3010192895Sjamie case -1: 3011192895Sjamie bcopy(pr->pr_ip6 + ii + 1, pr->pr_ip6 + ii, 3012192895Sjamie (--pr->pr_ip6s - ii) * sizeof(*pr->pr_ip6)); 3013192895Sjamie break; 3014192895Sjamie case 0: 3015192895Sjamie ii++; 3016192895Sjamie ij++; 3017192895Sjamie break; 3018192895Sjamie case 1: 3019192895Sjamie ij++; 3020192895Sjamie break; 3021192895Sjamie } 3022192895Sjamie } 3023192895Sjamie if (pr->pr_ip6s == 0) { 3024195870Sjamie pr->pr_flags |= PR_IP6_DISABLE; 3025192895Sjamie free(pr->pr_ip6, M_PRISON); 3026192895Sjamie pr->pr_ip6 = NULL; 3027192895Sjamie } 3028192895Sjamie } 3029192895Sjamie return 0; 3030192895Sjamie} 3031192895Sjamie 3032185435Sbz/* 3033185435Sbz * Pass back primary IPv6 address for this jail. 3034185435Sbz * 3035192895Sjamie * If not restricted return success but do not alter the address. Caller has 3036192895Sjamie * to make sure to initialize it correctly (e.g. IN6ADDR_ANY_INIT). 3037185435Sbz * 3038188144Sjamie * Returns 0 on success, EAFNOSUPPORT if the jail doesn't allow IPv6. 3039185435Sbz */ 3040185435Sbzint 3041187684Sbzprison_get_ip6(struct ucred *cred, struct in6_addr *ia6) 3042185435Sbz{ 3043191673Sjamie struct prison *pr; 3044185435Sbz 3045185435Sbz KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 3046185435Sbz KASSERT(ia6 != NULL, ("%s: ia6 is NULL", __func__)); 3047185435Sbz 3048192895Sjamie pr = cred->cr_prison; 3049192895Sjamie if (!(pr->pr_flags & PR_IP6)) 305081114Srwatson return (0); 3051191673Sjamie mtx_lock(&pr->pr_mtx); 3052192895Sjamie if (!(pr->pr_flags & PR_IP6)) { 3053192895Sjamie mtx_unlock(&pr->pr_mtx); 3054192895Sjamie return (0); 3055192895Sjamie } 3056191673Sjamie if (pr->pr_ip6 == NULL) { 3057191673Sjamie mtx_unlock(&pr->pr_mtx); 3058188144Sjamie return (EAFNOSUPPORT); 3059191673Sjamie } 3060188144Sjamie 3061191673Sjamie bcopy(&pr->pr_ip6[0], ia6, sizeof(struct in6_addr)); 3062191673Sjamie mtx_unlock(&pr->pr_mtx); 3063185435Sbz return (0); 3064185435Sbz} 3065185435Sbz 3066185435Sbz/* 3067192895Sjamie * Return true if pr1 and pr2 have the same IPv6 address restrictions. 3068192895Sjamie */ 3069192895Sjamieint 3070192895Sjamieprison_equal_ip6(struct prison *pr1, struct prison *pr2) 3071192895Sjamie{ 3072192895Sjamie 3073192895Sjamie if (pr1 == pr2) 3074192895Sjamie return (1); 3075192895Sjamie 3076192895Sjamie sx_slock(&allprison_lock); 3077195945Sjamie while (pr1 != &prison0 && 3078195945Sjamie#ifdef VIMAGE 3079195945Sjamie !(pr1->pr_flags & PR_VNET) && 3080195945Sjamie#endif 3081195945Sjamie !(pr1->pr_flags & PR_IP6_USER)) 3082192895Sjamie pr1 = pr1->pr_parent; 3083195945Sjamie while (pr2 != &prison0 && 3084195945Sjamie#ifdef VIMAGE 3085195945Sjamie !(pr2->pr_flags & PR_VNET) && 3086195945Sjamie#endif 3087195945Sjamie !(pr2->pr_flags & PR_IP6_USER)) 3088192895Sjamie pr2 = pr2->pr_parent; 3089192895Sjamie sx_sunlock(&allprison_lock); 3090192895Sjamie return (pr1 == pr2); 3091192895Sjamie} 3092192895Sjamie 3093192895Sjamie/* 3094185435Sbz * Make sure our (source) address is set to something meaningful to this jail. 3095185435Sbz * 3096185435Sbz * v6only should be set based on (inp->inp_flags & IN6P_IPV6_V6ONLY != 0) 3097185435Sbz * when needed while binding. 3098185435Sbz * 3099192895Sjamie * Returns 0 if jail doesn't restrict IPv6 or if address belongs to jail, 3100192895Sjamie * EADDRNOTAVAIL if the address doesn't belong, or EAFNOSUPPORT if the jail 3101192895Sjamie * doesn't allow IPv6. 3102185435Sbz */ 3103185435Sbzint 3104185435Sbzprison_local_ip6(struct ucred *cred, struct in6_addr *ia6, int v6only) 3105185435Sbz{ 3106191673Sjamie struct prison *pr; 3107191673Sjamie int error; 3108185435Sbz 3109185435Sbz KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 3110185435Sbz KASSERT(ia6 != NULL, ("%s: ia6 is NULL", __func__)); 3111185435Sbz 3112192895Sjamie pr = cred->cr_prison; 3113192895Sjamie if (!(pr->pr_flags & PR_IP6)) 3114185435Sbz return (0); 3115191673Sjamie mtx_lock(&pr->pr_mtx); 3116192895Sjamie if (!(pr->pr_flags & PR_IP6)) { 3117192895Sjamie mtx_unlock(&pr->pr_mtx); 3118192895Sjamie return (0); 3119192895Sjamie } 3120191673Sjamie if (pr->pr_ip6 == NULL) { 3121191673Sjamie mtx_unlock(&pr->pr_mtx); 3122188144Sjamie return (EAFNOSUPPORT); 3123191673Sjamie } 3124188144Sjamie 3125185435Sbz if (IN6_IS_ADDR_LOOPBACK(ia6)) { 3126191673Sjamie bcopy(&pr->pr_ip6[0], ia6, sizeof(struct in6_addr)); 3127191673Sjamie mtx_unlock(&pr->pr_mtx); 3128185435Sbz return (0); 312981114Srwatson } 3130185435Sbz 3131188144Sjamie if (IN6_IS_ADDR_UNSPECIFIED(ia6)) { 3132188144Sjamie /* 3133188144Sjamie * In case there is only 1 IPv6 address, and v6only is true, 3134188144Sjamie * then bind directly. 3135188144Sjamie */ 3136191673Sjamie if (v6only != 0 && pr->pr_ip6s == 1) 3137191673Sjamie bcopy(&pr->pr_ip6[0], ia6, sizeof(struct in6_addr)); 3138191673Sjamie mtx_unlock(&pr->pr_mtx); 3139185435Sbz return (0); 3140185435Sbz } 3141188144Sjamie 3142191673Sjamie error = _prison_check_ip6(pr, ia6); 3143191673Sjamie mtx_unlock(&pr->pr_mtx); 3144191673Sjamie return (error); 3145185435Sbz} 3146185435Sbz 3147185435Sbz/* 3148185435Sbz * Rewrite destination address in case we will connect to loopback address. 3149185435Sbz * 3150188144Sjamie * Returns 0 on success, EAFNOSUPPORT if the jail doesn't allow IPv6. 3151185435Sbz */ 3152185435Sbzint 3153185435Sbzprison_remote_ip6(struct ucred *cred, struct in6_addr *ia6) 3154185435Sbz{ 3155191673Sjamie struct prison *pr; 3156185435Sbz 3157185435Sbz KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 3158185435Sbz KASSERT(ia6 != NULL, ("%s: ia6 is NULL", __func__)); 3159185435Sbz 3160192895Sjamie pr = cred->cr_prison; 3161192895Sjamie if (!(pr->pr_flags & PR_IP6)) 3162185435Sbz return (0); 3163191673Sjamie mtx_lock(&pr->pr_mtx); 3164192895Sjamie if (!(pr->pr_flags & PR_IP6)) { 3165192895Sjamie mtx_unlock(&pr->pr_mtx); 3166192895Sjamie return (0); 3167192895Sjamie } 3168191673Sjamie if (pr->pr_ip6 == NULL) { 3169191673Sjamie mtx_unlock(&pr->pr_mtx); 3170188144Sjamie return (EAFNOSUPPORT); 3171191673Sjamie } 3172188144Sjamie 3173185435Sbz if (IN6_IS_ADDR_LOOPBACK(ia6)) { 3174191673Sjamie bcopy(&pr->pr_ip6[0], ia6, sizeof(struct in6_addr)); 3175191673Sjamie mtx_unlock(&pr->pr_mtx); 3176185435Sbz return (0); 3177185435Sbz } 3178185435Sbz 3179185435Sbz /* 3180185435Sbz * Return success because nothing had to be changed. 3181185435Sbz */ 3182191673Sjamie mtx_unlock(&pr->pr_mtx); 318346155Sphk return (0); 318446155Sphk} 318546155Sphk 3186185435Sbz/* 3187188144Sjamie * Check if given address belongs to the jail referenced by cred/prison. 3188185435Sbz * 3189192895Sjamie * Returns 0 if jail doesn't restrict IPv6 or if address belongs to jail, 3190192895Sjamie * EADDRNOTAVAIL if the address doesn't belong, or EAFNOSUPPORT if the jail 3191192895Sjamie * doesn't allow IPv6. 3192185435Sbz */ 3193185435Sbzstatic int 3194185435Sbz_prison_check_ip6(struct prison *pr, struct in6_addr *ia6) 319546155Sphk{ 3196185435Sbz int i, a, z, d; 319746155Sphk 3198185435Sbz /* 3199185435Sbz * Check the primary IP. 3200185435Sbz */ 3201185435Sbz if (IN6_ARE_ADDR_EQUAL(&pr->pr_ip6[0], ia6)) 3202188144Sjamie return (0); 3203185435Sbz 3204185435Sbz /* 3205185435Sbz * All the other IPs are sorted so we can do a binary search. 3206185435Sbz */ 3207185435Sbz a = 0; 3208185435Sbz z = pr->pr_ip6s - 2; 3209185435Sbz while (a <= z) { 3210185435Sbz i = (a + z) / 2; 3211185435Sbz d = qcmp_v6(&pr->pr_ip6[i+1], ia6); 3212185435Sbz if (d > 0) 3213185435Sbz z = i - 1; 3214185435Sbz else if (d < 0) 3215185435Sbz a = i + 1; 321646155Sphk else 3217188144Sjamie return (0); 321846155Sphk } 3219188144Sjamie 3220188144Sjamie return (EADDRNOTAVAIL); 322146155Sphk} 322246155Sphk 322346155Sphkint 3224185435Sbzprison_check_ip6(struct ucred *cred, struct in6_addr *ia6) 3225185435Sbz{ 3226191673Sjamie struct prison *pr; 3227191673Sjamie int error; 3228185435Sbz 3229185435Sbz KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 3230185435Sbz KASSERT(ia6 != NULL, ("%s: ia6 is NULL", __func__)); 3231185435Sbz 3232192895Sjamie pr = cred->cr_prison; 3233192895Sjamie if (!(pr->pr_flags & PR_IP6)) 3234188144Sjamie return (0); 3235191673Sjamie mtx_lock(&pr->pr_mtx); 3236192895Sjamie if (!(pr->pr_flags & PR_IP6)) { 3237192895Sjamie mtx_unlock(&pr->pr_mtx); 3238192895Sjamie return (0); 3239192895Sjamie } 3240191673Sjamie if (pr->pr_ip6 == NULL) { 3241191673Sjamie mtx_unlock(&pr->pr_mtx); 3242188144Sjamie return (EAFNOSUPPORT); 3243191673Sjamie } 3244185435Sbz 3245191673Sjamie error = _prison_check_ip6(pr, ia6); 3246191673Sjamie mtx_unlock(&pr->pr_mtx); 3247191673Sjamie return (error); 3248185435Sbz} 3249185435Sbz#endif 3250185435Sbz 3251185435Sbz/* 3252188146Sjamie * Check if a jail supports the given address family. 3253188146Sjamie * 3254188146Sjamie * Returns 0 if not jailed or the address family is supported, EAFNOSUPPORT 3255188146Sjamie * if not. 3256188146Sjamie */ 3257188146Sjamieint 3258188146Sjamieprison_check_af(struct ucred *cred, int af) 3259188146Sjamie{ 3260192895Sjamie struct prison *pr; 3261188146Sjamie int error; 3262188146Sjamie 3263188146Sjamie KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 3264188146Sjamie 3265192895Sjamie pr = cred->cr_prison; 3266194923Sjamie#ifdef VIMAGE 3267194915Sjamie /* Prisons with their own network stack are not limited. */ 3268194915Sjamie if (pr->pr_flags & PR_VNET) 3269194915Sjamie return (0); 3270194923Sjamie#endif 3271194915Sjamie 3272188146Sjamie error = 0; 3273188146Sjamie switch (af) 3274188146Sjamie { 3275188146Sjamie#ifdef INET 3276188146Sjamie case AF_INET: 3277192895Sjamie if (pr->pr_flags & PR_IP4) 3278192895Sjamie { 3279192895Sjamie mtx_lock(&pr->pr_mtx); 3280192895Sjamie if ((pr->pr_flags & PR_IP4) && pr->pr_ip4 == NULL) 3281192895Sjamie error = EAFNOSUPPORT; 3282192895Sjamie mtx_unlock(&pr->pr_mtx); 3283192895Sjamie } 3284188146Sjamie break; 3285188146Sjamie#endif 3286188146Sjamie#ifdef INET6 3287188146Sjamie case AF_INET6: 3288192895Sjamie if (pr->pr_flags & PR_IP6) 3289192895Sjamie { 3290192895Sjamie mtx_lock(&pr->pr_mtx); 3291192895Sjamie if ((pr->pr_flags & PR_IP6) && pr->pr_ip6 == NULL) 3292192895Sjamie error = EAFNOSUPPORT; 3293192895Sjamie mtx_unlock(&pr->pr_mtx); 3294192895Sjamie } 3295188146Sjamie break; 3296188146Sjamie#endif 3297188146Sjamie case AF_LOCAL: 3298188146Sjamie case AF_ROUTE: 3299188146Sjamie break; 3300188146Sjamie default: 3301192895Sjamie if (!(pr->pr_allow & PR_ALLOW_SOCKET_AF)) 3302188146Sjamie error = EAFNOSUPPORT; 3303188146Sjamie } 3304188146Sjamie return (error); 3305188146Sjamie} 3306188146Sjamie 3307188146Sjamie/* 3308185435Sbz * Check if given address belongs to the jail referenced by cred (wrapper to 3309185435Sbz * prison_check_ip[46]). 3310185435Sbz * 3311192895Sjamie * Returns 0 if jail doesn't restrict the address family or if address belongs 3312192895Sjamie * to jail, EADDRNOTAVAIL if the address doesn't belong, or EAFNOSUPPORT if 3313192895Sjamie * the jail doesn't allow the address family. IPv4 Address passed in in NBO. 3314185435Sbz */ 3315185435Sbzint 331672786Srwatsonprison_if(struct ucred *cred, struct sockaddr *sa) 331746155Sphk{ 3318185435Sbz#ifdef INET 3319114168Smike struct sockaddr_in *sai; 3320185435Sbz#endif 3321185435Sbz#ifdef INET6 3322185435Sbz struct sockaddr_in6 *sai6; 3323185435Sbz#endif 3324188144Sjamie int error; 332546155Sphk 3326185435Sbz KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 3327185435Sbz KASSERT(sa != NULL, ("%s: sa is NULL", __func__)); 3328185435Sbz 3329188144Sjamie error = 0; 3330188144Sjamie switch (sa->sa_family) 3331185435Sbz { 3332185435Sbz#ifdef INET 3333185435Sbz case AF_INET: 3334185435Sbz sai = (struct sockaddr_in *)sa; 3335188144Sjamie error = prison_check_ip4(cred, &sai->sin_addr); 3336185435Sbz break; 3337185435Sbz#endif 3338185435Sbz#ifdef INET6 3339185435Sbz case AF_INET6: 3340185435Sbz sai6 = (struct sockaddr_in6 *)sa; 3341188144Sjamie error = prison_check_ip6(cred, &sai6->sin6_addr); 3342185435Sbz break; 3343185435Sbz#endif 3344185435Sbz default: 3345192895Sjamie if (!(cred->cr_prison->pr_allow & PR_ALLOW_SOCKET_AF)) 3346188144Sjamie error = EAFNOSUPPORT; 3347185435Sbz } 3348188144Sjamie return (error); 334946155Sphk} 335072786Srwatson 335172786Srwatson/* 335272786Srwatson * Return 0 if jails permit p1 to frob p2, otherwise ESRCH. 335372786Srwatson */ 335472786Srwatsonint 3355114168Smikeprison_check(struct ucred *cred1, struct ucred *cred2) 335672786Srwatson{ 335772786Srwatson 3358192895Sjamie return ((cred1->cr_prison == cred2->cr_prison || 3359192895Sjamie prison_ischild(cred1->cr_prison, cred2->cr_prison)) ? 0 : ESRCH); 3360192895Sjamie} 336172786Srwatson 3362192895Sjamie/* 3363192895Sjamie * Return 1 if p2 is a child of p1, otherwise 0. 3364192895Sjamie */ 3365192895Sjamieint 3366192895Sjamieprison_ischild(struct prison *pr1, struct prison *pr2) 3367192895Sjamie{ 3368192895Sjamie 3369192895Sjamie for (pr2 = pr2->pr_parent; pr2 != NULL; pr2 = pr2->pr_parent) 3370192895Sjamie if (pr1 == pr2) 3371192895Sjamie return (1); 337272786Srwatson return (0); 337372786Srwatson} 337472786Srwatson 337572786Srwatson/* 337672786Srwatson * Return 1 if the passed credential is in a jail, otherwise 0. 337772786Srwatson */ 337872786Srwatsonint 3379114168Smikejailed(struct ucred *cred) 338072786Srwatson{ 338172786Srwatson 3382192895Sjamie return (cred->cr_prison != &prison0); 338372786Srwatson} 338491384Srobert 338591384Srobert/* 3386194090Sjamie * Return the correct hostname (domainname, et al) for the passed credential. 338791384Srobert */ 338891391Srobertvoid 3389114168Smikegetcredhostname(struct ucred *cred, char *buf, size_t size) 339091384Srobert{ 3391193066Sjamie struct prison *pr; 339291384Srobert 3393194090Sjamie /* 3394194090Sjamie * A NULL credential can be used to shortcut to the physical 3395194090Sjamie * system's hostname. 3396194090Sjamie */ 3397193066Sjamie pr = (cred != NULL) ? cred->cr_prison : &prison0; 3398193066Sjamie mtx_lock(&pr->pr_mtx); 3399194118Sjamie strlcpy(buf, pr->pr_hostname, size); 3400193066Sjamie mtx_unlock(&pr->pr_mtx); 340191384Srobert} 3402113275Smike 3403194090Sjamievoid 3404194090Sjamiegetcreddomainname(struct ucred *cred, char *buf, size_t size) 3405194090Sjamie{ 3406194090Sjamie 3407194090Sjamie mtx_lock(&cred->cr_prison->pr_mtx); 3408194118Sjamie strlcpy(buf, cred->cr_prison->pr_domainname, size); 3409194090Sjamie mtx_unlock(&cred->cr_prison->pr_mtx); 3410194090Sjamie} 3411194090Sjamie 3412194090Sjamievoid 3413194090Sjamiegetcredhostuuid(struct ucred *cred, char *buf, size_t size) 3414194090Sjamie{ 3415194090Sjamie 3416194090Sjamie mtx_lock(&cred->cr_prison->pr_mtx); 3417194118Sjamie strlcpy(buf, cred->cr_prison->pr_hostuuid, size); 3418194090Sjamie mtx_unlock(&cred->cr_prison->pr_mtx); 3419194090Sjamie} 3420194090Sjamie 3421194090Sjamievoid 3422194090Sjamiegetcredhostid(struct ucred *cred, unsigned long *hostid) 3423194090Sjamie{ 3424194090Sjamie 3425194090Sjamie mtx_lock(&cred->cr_prison->pr_mtx); 3426194090Sjamie *hostid = cred->cr_prison->pr_hostid; 3427194090Sjamie mtx_unlock(&cred->cr_prison->pr_mtx); 3428194090Sjamie} 3429194090Sjamie 3430125804Srwatson/* 3431147185Spjd * Determine whether the subject represented by cred can "see" 3432147185Spjd * status of a mount point. 3433147185Spjd * Returns: 0 for permitted, ENOENT otherwise. 3434147185Spjd * XXX: This function should be called cr_canseemount() and should be 3435147185Spjd * placed in kern_prot.c. 3436125804Srwatson */ 3437125804Srwatsonint 3438147185Spjdprison_canseemount(struct ucred *cred, struct mount *mp) 3439125804Srwatson{ 3440147185Spjd struct prison *pr; 3441147185Spjd struct statfs *sp; 3442147185Spjd size_t len; 3443125804Srwatson 3444192895Sjamie pr = cred->cr_prison; 3445192895Sjamie if (pr->pr_enforce_statfs == 0) 3446147185Spjd return (0); 3447147185Spjd if (pr->pr_root->v_mount == mp) 3448147185Spjd return (0); 3449192895Sjamie if (pr->pr_enforce_statfs == 2) 3450147185Spjd return (ENOENT); 3451147185Spjd /* 3452147185Spjd * If jail's chroot directory is set to "/" we should be able to see 3453147185Spjd * all mount-points from inside a jail. 3454147185Spjd * This is ugly check, but this is the only situation when jail's 3455147185Spjd * directory ends with '/'. 3456147185Spjd */ 3457147185Spjd if (strcmp(pr->pr_path, "/") == 0) 3458147185Spjd return (0); 3459147185Spjd len = strlen(pr->pr_path); 3460147185Spjd sp = &mp->mnt_stat; 3461147185Spjd if (strncmp(pr->pr_path, sp->f_mntonname, len) != 0) 3462147185Spjd return (ENOENT); 3463147185Spjd /* 3464147185Spjd * Be sure that we don't have situation where jail's root directory 3465147185Spjd * is "/some/path" and mount point is "/some/pathpath". 3466147185Spjd */ 3467147185Spjd if (sp->f_mntonname[len] != '\0' && sp->f_mntonname[len] != '/') 3468147185Spjd return (ENOENT); 3469147185Spjd return (0); 3470147185Spjd} 3471147185Spjd 3472147185Spjdvoid 3473147185Spjdprison_enforce_statfs(struct ucred *cred, struct mount *mp, struct statfs *sp) 3474147185Spjd{ 3475147185Spjd char jpath[MAXPATHLEN]; 3476147185Spjd struct prison *pr; 3477147185Spjd size_t len; 3478147185Spjd 3479192895Sjamie pr = cred->cr_prison; 3480192895Sjamie if (pr->pr_enforce_statfs == 0) 3481147185Spjd return; 3482147185Spjd if (prison_canseemount(cred, mp) != 0) { 3483147185Spjd bzero(sp->f_mntonname, sizeof(sp->f_mntonname)); 3484147185Spjd strlcpy(sp->f_mntonname, "[restricted]", 3485147185Spjd sizeof(sp->f_mntonname)); 3486147185Spjd return; 3487125804Srwatson } 3488147185Spjd if (pr->pr_root->v_mount == mp) { 3489147185Spjd /* 3490147185Spjd * Clear current buffer data, so we are sure nothing from 3491147185Spjd * the valid path left there. 3492147185Spjd */ 3493147185Spjd bzero(sp->f_mntonname, sizeof(sp->f_mntonname)); 3494147185Spjd *sp->f_mntonname = '/'; 3495147185Spjd return; 3496147185Spjd } 3497147185Spjd /* 3498147185Spjd * If jail's chroot directory is set to "/" we should be able to see 3499147185Spjd * all mount-points from inside a jail. 3500147185Spjd */ 3501147185Spjd if (strcmp(pr->pr_path, "/") == 0) 3502147185Spjd return; 3503147185Spjd len = strlen(pr->pr_path); 3504147185Spjd strlcpy(jpath, sp->f_mntonname + len, sizeof(jpath)); 3505147185Spjd /* 3506147185Spjd * Clear current buffer data, so we are sure nothing from 3507147185Spjd * the valid path left there. 3508147185Spjd */ 3509147185Spjd bzero(sp->f_mntonname, sizeof(sp->f_mntonname)); 3510147185Spjd if (*jpath == '\0') { 3511147185Spjd /* Should never happen. */ 3512147185Spjd *sp->f_mntonname = '/'; 3513147185Spjd } else { 3514147185Spjd strlcpy(sp->f_mntonname, jpath, sizeof(sp->f_mntonname)); 3515147185Spjd } 3516125804Srwatson} 3517125804Srwatson 3518164032Srwatson/* 3519164032Srwatson * Check with permission for a specific privilege is granted within jail. We 3520164032Srwatson * have a specific list of accepted privileges; the rest are denied. 3521164032Srwatson */ 3522164032Srwatsonint 3523164032Srwatsonprison_priv_check(struct ucred *cred, int priv) 3524164032Srwatson{ 3525164032Srwatson 3526164032Srwatson if (!jailed(cred)) 3527164032Srwatson return (0); 3528164032Srwatson 3529194915Sjamie#ifdef VIMAGE 3530194915Sjamie /* 3531194915Sjamie * Privileges specific to prisons with a virtual network stack. 3532194915Sjamie * There might be a duplicate entry here in case the privilege 3533194915Sjamie * is only granted conditionally in the legacy jail case. 3534194915Sjamie */ 3535164032Srwatson switch (priv) { 3536194915Sjamie#ifdef notyet 3537194915Sjamie /* 3538194915Sjamie * NFS-specific privileges. 3539194915Sjamie */ 3540194915Sjamie case PRIV_NFS_DAEMON: 3541194915Sjamie case PRIV_NFS_LOCKD: 3542194915Sjamie#endif 3543194915Sjamie /* 3544194915Sjamie * Network stack privileges. 3545194915Sjamie */ 3546194915Sjamie case PRIV_NET_BRIDGE: 3547194915Sjamie case PRIV_NET_GRE: 3548194915Sjamie case PRIV_NET_BPF: 3549194915Sjamie case PRIV_NET_RAW: /* Dup, cond. in legacy jail case. */ 3550194915Sjamie case PRIV_NET_ROUTE: 3551194915Sjamie case PRIV_NET_TAP: 3552194915Sjamie case PRIV_NET_SETIFMTU: 3553194915Sjamie case PRIV_NET_SETIFFLAGS: 3554194915Sjamie case PRIV_NET_SETIFCAP: 3555194915Sjamie case PRIV_NET_SETIFNAME : 3556194915Sjamie case PRIV_NET_SETIFMETRIC: 3557194915Sjamie case PRIV_NET_SETIFPHYS: 3558194915Sjamie case PRIV_NET_SETIFMAC: 3559194915Sjamie case PRIV_NET_ADDMULTI: 3560194915Sjamie case PRIV_NET_DELMULTI: 3561194915Sjamie case PRIV_NET_HWIOCTL: 3562194915Sjamie case PRIV_NET_SETLLADDR: 3563194915Sjamie case PRIV_NET_ADDIFGROUP: 3564194915Sjamie case PRIV_NET_DELIFGROUP: 3565194915Sjamie case PRIV_NET_IFCREATE: 3566194915Sjamie case PRIV_NET_IFDESTROY: 3567194915Sjamie case PRIV_NET_ADDIFADDR: 3568194915Sjamie case PRIV_NET_DELIFADDR: 3569194915Sjamie case PRIV_NET_LAGG: 3570194915Sjamie case PRIV_NET_GIF: 3571194915Sjamie case PRIV_NET_SETIFVNET: 3572164032Srwatson 3573164032Srwatson /* 3574194915Sjamie * 802.11-related privileges. 3575194915Sjamie */ 3576194915Sjamie case PRIV_NET80211_GETKEY: 3577194915Sjamie#ifdef notyet 3578194915Sjamie case PRIV_NET80211_MANAGE: /* XXX-BZ discuss with sam@ */ 3579194915Sjamie#endif 3580194915Sjamie 3581194915Sjamie#ifdef notyet 3582194915Sjamie /* 3583194915Sjamie * AppleTalk privileges. 3584194915Sjamie */ 3585194915Sjamie case PRIV_NETATALK_RESERVEDPORT: 3586194915Sjamie 3587194915Sjamie /* 3588194915Sjamie * ATM privileges. 3589194915Sjamie */ 3590194915Sjamie case PRIV_NETATM_CFG: 3591194915Sjamie case PRIV_NETATM_ADD: 3592194915Sjamie case PRIV_NETATM_DEL: 3593194915Sjamie case PRIV_NETATM_SET: 3594194915Sjamie 3595194915Sjamie /* 3596194915Sjamie * Bluetooth privileges. 3597194915Sjamie */ 3598194915Sjamie case PRIV_NETBLUETOOTH_RAW: 3599194915Sjamie#endif 3600194915Sjamie 3601194915Sjamie /* 3602194915Sjamie * Netgraph and netgraph module privileges. 3603194915Sjamie */ 3604194915Sjamie case PRIV_NETGRAPH_CONTROL: 3605194915Sjamie#ifdef notyet 3606194915Sjamie case PRIV_NETGRAPH_TTY: 3607194915Sjamie#endif 3608194915Sjamie 3609194915Sjamie /* 3610194915Sjamie * IPv4 and IPv6 privileges. 3611194915Sjamie */ 3612194915Sjamie case PRIV_NETINET_IPFW: 3613194915Sjamie case PRIV_NETINET_DIVERT: 3614194915Sjamie case PRIV_NETINET_PF: 3615194915Sjamie case PRIV_NETINET_DUMMYNET: 3616194915Sjamie case PRIV_NETINET_CARP: 3617194915Sjamie case PRIV_NETINET_MROUTE: 3618194915Sjamie case PRIV_NETINET_RAW: 3619194915Sjamie case PRIV_NETINET_ADDRCTRL6: 3620194915Sjamie case PRIV_NETINET_ND6: 3621194915Sjamie case PRIV_NETINET_SCOPE6: 3622194915Sjamie case PRIV_NETINET_ALIFETIME6: 3623194915Sjamie case PRIV_NETINET_IPSEC: 3624194915Sjamie case PRIV_NETINET_BINDANY: 3625194915Sjamie 3626194915Sjamie#ifdef notyet 3627194915Sjamie /* 3628194915Sjamie * IPX/SPX privileges. 3629194915Sjamie */ 3630194915Sjamie case PRIV_NETIPX_RESERVEDPORT: 3631194915Sjamie case PRIV_NETIPX_RAW: 3632194915Sjamie 3633194915Sjamie /* 3634194915Sjamie * NCP privileges. 3635194915Sjamie */ 3636194915Sjamie case PRIV_NETNCP: 3637194915Sjamie 3638194915Sjamie /* 3639194915Sjamie * SMB privileges. 3640194915Sjamie */ 3641194915Sjamie case PRIV_NETSMB: 3642194915Sjamie#endif 3643194915Sjamie 3644194915Sjamie /* 3645194915Sjamie * No default: or deny here. 3646194915Sjamie * In case of no permit fall through to next switch(). 3647194915Sjamie */ 3648194915Sjamie if (cred->cr_prison->pr_flags & PR_VNET) 3649194915Sjamie return (0); 3650194915Sjamie } 3651194915Sjamie#endif /* VIMAGE */ 3652194915Sjamie 3653194915Sjamie switch (priv) { 3654194915Sjamie 3655194915Sjamie /* 3656164032Srwatson * Allow ktrace privileges for root in jail. 3657164032Srwatson */ 3658164032Srwatson case PRIV_KTRACE: 3659164032Srwatson 3660166827Srwatson#if 0 3661164032Srwatson /* 3662164032Srwatson * Allow jailed processes to configure audit identity and 3663164032Srwatson * submit audit records (login, etc). In the future we may 3664164032Srwatson * want to further refine the relationship between audit and 3665164032Srwatson * jail. 3666164032Srwatson */ 3667164032Srwatson case PRIV_AUDIT_GETAUDIT: 3668164032Srwatson case PRIV_AUDIT_SETAUDIT: 3669164032Srwatson case PRIV_AUDIT_SUBMIT: 3670166827Srwatson#endif 3671164032Srwatson 3672164032Srwatson /* 3673164032Srwatson * Allow jailed processes to manipulate process UNIX 3674164032Srwatson * credentials in any way they see fit. 3675164032Srwatson */ 3676164032Srwatson case PRIV_CRED_SETUID: 3677164032Srwatson case PRIV_CRED_SETEUID: 3678164032Srwatson case PRIV_CRED_SETGID: 3679164032Srwatson case PRIV_CRED_SETEGID: 3680164032Srwatson case PRIV_CRED_SETGROUPS: 3681164032Srwatson case PRIV_CRED_SETREUID: 3682164032Srwatson case PRIV_CRED_SETREGID: 3683164032Srwatson case PRIV_CRED_SETRESUID: 3684164032Srwatson case PRIV_CRED_SETRESGID: 3685164032Srwatson 3686164032Srwatson /* 3687164032Srwatson * Jail implements visibility constraints already, so allow 3688164032Srwatson * jailed root to override uid/gid-based constraints. 3689164032Srwatson */ 3690164032Srwatson case PRIV_SEEOTHERGIDS: 3691164032Srwatson case PRIV_SEEOTHERUIDS: 3692164032Srwatson 3693164032Srwatson /* 3694164032Srwatson * Jail implements inter-process debugging limits already, so 3695164032Srwatson * allow jailed root various debugging privileges. 3696164032Srwatson */ 3697164032Srwatson case PRIV_DEBUG_DIFFCRED: 3698164032Srwatson case PRIV_DEBUG_SUGID: 3699164032Srwatson case PRIV_DEBUG_UNPRIV: 3700164032Srwatson 3701164032Srwatson /* 3702164032Srwatson * Allow jail to set various resource limits and login 3703164032Srwatson * properties, and for now, exceed process resource limits. 3704164032Srwatson */ 3705164032Srwatson case PRIV_PROC_LIMIT: 3706164032Srwatson case PRIV_PROC_SETLOGIN: 3707164032Srwatson case PRIV_PROC_SETRLIMIT: 3708164032Srwatson 3709164032Srwatson /* 3710164032Srwatson * System V and POSIX IPC privileges are granted in jail. 3711164032Srwatson */ 3712164032Srwatson case PRIV_IPC_READ: 3713164032Srwatson case PRIV_IPC_WRITE: 3714164032Srwatson case PRIV_IPC_ADMIN: 3715164032Srwatson case PRIV_IPC_MSGSIZE: 3716164032Srwatson case PRIV_MQ_ADMIN: 3717164032Srwatson 3718164032Srwatson /* 3719192895Sjamie * Jail operations within a jail work on child jails. 3720192895Sjamie */ 3721192895Sjamie case PRIV_JAIL_ATTACH: 3722192895Sjamie case PRIV_JAIL_SET: 3723192895Sjamie case PRIV_JAIL_REMOVE: 3724192895Sjamie 3725192895Sjamie /* 3726164032Srwatson * Jail implements its own inter-process limits, so allow 3727164032Srwatson * root processes in jail to change scheduling on other 3728164032Srwatson * processes in the same jail. Likewise for signalling. 3729164032Srwatson */ 3730164032Srwatson case PRIV_SCHED_DIFFCRED: 3731185435Sbz case PRIV_SCHED_CPUSET: 3732164032Srwatson case PRIV_SIGNAL_DIFFCRED: 3733164032Srwatson case PRIV_SIGNAL_SUGID: 3734164032Srwatson 3735164032Srwatson /* 3736164032Srwatson * Allow jailed processes to write to sysctls marked as jail 3737164032Srwatson * writable. 3738164032Srwatson */ 3739164032Srwatson case PRIV_SYSCTL_WRITEJAIL: 3740164032Srwatson 3741164032Srwatson /* 3742164032Srwatson * Allow root in jail to manage a variety of quota 3743166831Srwatson * properties. These should likely be conditional on a 3744166831Srwatson * configuration option. 3745164032Srwatson */ 3746166832Srwatson case PRIV_VFS_GETQUOTA: 3747166832Srwatson case PRIV_VFS_SETQUOTA: 3748164032Srwatson 3749164032Srwatson /* 3750164032Srwatson * Since Jail relies on chroot() to implement file system 3751164032Srwatson * protections, grant many VFS privileges to root in jail. 3752164032Srwatson * Be careful to exclude mount-related and NFS-related 3753164032Srwatson * privileges. 3754164032Srwatson */ 3755164032Srwatson case PRIV_VFS_READ: 3756164032Srwatson case PRIV_VFS_WRITE: 3757164032Srwatson case PRIV_VFS_ADMIN: 3758164032Srwatson case PRIV_VFS_EXEC: 3759164032Srwatson case PRIV_VFS_LOOKUP: 3760164032Srwatson case PRIV_VFS_BLOCKRESERVE: /* XXXRW: Slightly surprising. */ 3761164032Srwatson case PRIV_VFS_CHFLAGS_DEV: 3762164032Srwatson case PRIV_VFS_CHOWN: 3763164032Srwatson case PRIV_VFS_CHROOT: 3764167152Spjd case PRIV_VFS_RETAINSUGID: 3765164032Srwatson case PRIV_VFS_FCHROOT: 3766164032Srwatson case PRIV_VFS_LINK: 3767164032Srwatson case PRIV_VFS_SETGID: 3768172860Srwatson case PRIV_VFS_STAT: 3769164032Srwatson case PRIV_VFS_STICKYFILE: 3770164032Srwatson return (0); 3771164032Srwatson 3772164032Srwatson /* 3773164032Srwatson * Depending on the global setting, allow privilege of 3774164032Srwatson * setting system flags. 3775164032Srwatson */ 3776164032Srwatson case PRIV_VFS_SYSFLAGS: 3777192895Sjamie if (cred->cr_prison->pr_allow & PR_ALLOW_CHFLAGS) 3778164032Srwatson return (0); 3779164032Srwatson else 3780164032Srwatson return (EPERM); 3781164032Srwatson 3782164032Srwatson /* 3783168396Spjd * Depending on the global setting, allow privilege of 3784168396Spjd * mounting/unmounting file systems. 3785168396Spjd */ 3786168396Spjd case PRIV_VFS_MOUNT: 3787168396Spjd case PRIV_VFS_UNMOUNT: 3788168396Spjd case PRIV_VFS_MOUNT_NONUSER: 3789168699Spjd case PRIV_VFS_MOUNT_OWNER: 3790192895Sjamie if (cred->cr_prison->pr_allow & PR_ALLOW_MOUNT) 3791168396Spjd return (0); 3792168396Spjd else 3793168396Spjd return (EPERM); 3794168396Spjd 3795168396Spjd /* 3796168591Srwatson * Allow jailed root to bind reserved ports and reuse in-use 3797168591Srwatson * ports. 3798164032Srwatson */ 3799164032Srwatson case PRIV_NETINET_RESERVEDPORT: 3800168591Srwatson case PRIV_NETINET_REUSEPORT: 3801164032Srwatson return (0); 3802164032Srwatson 3803164032Srwatson /* 3804175630Sbz * Allow jailed root to set certian IPv4/6 (option) headers. 3805175630Sbz */ 3806175630Sbz case PRIV_NETINET_SETHDROPTS: 3807175630Sbz return (0); 3808175630Sbz 3809175630Sbz /* 3810164032Srwatson * Conditionally allow creating raw sockets in jail. 3811164032Srwatson */ 3812164032Srwatson case PRIV_NETINET_RAW: 3813192895Sjamie if (cred->cr_prison->pr_allow & PR_ALLOW_RAW_SOCKETS) 3814164032Srwatson return (0); 3815164032Srwatson else 3816164032Srwatson return (EPERM); 3817164032Srwatson 3818164032Srwatson /* 3819164032Srwatson * Since jail implements its own visibility limits on netstat 3820164032Srwatson * sysctls, allow getcred. This allows identd to work in 3821164032Srwatson * jail. 3822164032Srwatson */ 3823164032Srwatson case PRIV_NETINET_GETCRED: 3824164032Srwatson return (0); 3825164032Srwatson 3826164032Srwatson default: 3827164032Srwatson /* 3828164032Srwatson * In all remaining cases, deny the privilege request. This 3829164032Srwatson * includes almost all network privileges, many system 3830164032Srwatson * configuration privileges. 3831164032Srwatson */ 3832164032Srwatson return (EPERM); 3833164032Srwatson } 3834164032Srwatson} 3835164032Srwatson 3836192895Sjamie/* 3837192895Sjamie * Return the part of pr2's name that is relative to pr1, or the whole name 3838192895Sjamie * if it does not directly follow. 3839192895Sjamie */ 3840192895Sjamie 3841192895Sjamiechar * 3842192895Sjamieprison_name(struct prison *pr1, struct prison *pr2) 3843192895Sjamie{ 3844192895Sjamie char *name; 3845192895Sjamie 3846192895Sjamie /* Jails see themselves as "0" (if they see themselves at all). */ 3847192895Sjamie if (pr1 == pr2) 3848192895Sjamie return "0"; 3849192895Sjamie name = pr2->pr_name; 3850192895Sjamie if (prison_ischild(pr1, pr2)) { 3851192895Sjamie /* 3852192895Sjamie * pr1 isn't locked (and allprison_lock may not be either) 3853192895Sjamie * so its length can't be counted on. But the number of dots 3854192895Sjamie * can be counted on - and counted. 3855192895Sjamie */ 3856192895Sjamie for (; pr1 != &prison0; pr1 = pr1->pr_parent) 3857192895Sjamie name = strchr(name, '.') + 1; 3858192895Sjamie } 3859192895Sjamie return (name); 3860192895Sjamie} 3861192895Sjamie 3862192895Sjamie/* 3863192895Sjamie * Return the part of pr2's path that is relative to pr1, or the whole path 3864192895Sjamie * if it does not directly follow. 3865192895Sjamie */ 3866192895Sjamiestatic char * 3867192895Sjamieprison_path(struct prison *pr1, struct prison *pr2) 3868192895Sjamie{ 3869192895Sjamie char *path1, *path2; 3870192895Sjamie int len1; 3871192895Sjamie 3872192895Sjamie path1 = pr1->pr_path; 3873192895Sjamie path2 = pr2->pr_path; 3874192895Sjamie if (!strcmp(path1, "/")) 3875192895Sjamie return (path2); 3876192895Sjamie len1 = strlen(path1); 3877192895Sjamie if (strncmp(path1, path2, len1)) 3878192895Sjamie return (path2); 3879192895Sjamie if (path2[len1] == '\0') 3880192895Sjamie return "/"; 3881192895Sjamie if (path2[len1] == '/') 3882192895Sjamie return (path2 + len1); 3883192895Sjamie return (path2); 3884192895Sjamie} 3885192895Sjamie 3886192895Sjamie 3887192895Sjamie/* 3888192895Sjamie * Jail-related sysctls. 3889192895Sjamie */ 3890192895SjamieSYSCTL_NODE(_security, OID_AUTO, jail, CTLFLAG_RW, 0, 3891192895Sjamie "Jails"); 3892192895Sjamie 3893113275Smikestatic int 3894113275Smikesysctl_jail_list(SYSCTL_HANDLER_ARGS) 3895113275Smike{ 3896191673Sjamie struct xprison *xp; 3897192895Sjamie struct prison *pr, *cpr; 3898191673Sjamie#ifdef INET 3899191673Sjamie struct in_addr *ip4 = NULL; 3900191673Sjamie int ip4s = 0; 3901191673Sjamie#endif 3902191673Sjamie#ifdef INET6 3903191673Sjamie struct in_addr *ip6 = NULL; 3904191673Sjamie int ip6s = 0; 3905191673Sjamie#endif 3906192895Sjamie int descend, error; 3907113275Smike 3908191673Sjamie xp = malloc(sizeof(*xp), M_TEMP, M_WAITOK); 3909192895Sjamie pr = req->td->td_ucred->cr_prison; 3910191673Sjamie error = 0; 3911168401Spjd sx_slock(&allprison_lock); 3912192895Sjamie FOREACH_PRISON_DESCENDANT(pr, cpr, descend) { 3913192895Sjamie#if defined(INET) || defined(INET6) 3914191673Sjamie again: 3915192895Sjamie#endif 3916192895Sjamie mtx_lock(&cpr->pr_mtx); 3917185435Sbz#ifdef INET 3918192895Sjamie if (cpr->pr_ip4s > 0) { 3919192895Sjamie if (ip4s < cpr->pr_ip4s) { 3920192895Sjamie ip4s = cpr->pr_ip4s; 3921192895Sjamie mtx_unlock(&cpr->pr_mtx); 3922191673Sjamie ip4 = realloc(ip4, ip4s * 3923191673Sjamie sizeof(struct in_addr), M_TEMP, M_WAITOK); 3924191673Sjamie goto again; 3925191673Sjamie } 3926192895Sjamie bcopy(cpr->pr_ip4, ip4, 3927192895Sjamie cpr->pr_ip4s * sizeof(struct in_addr)); 3928191673Sjamie } 3929185435Sbz#endif 3930185435Sbz#ifdef INET6 3931192895Sjamie if (cpr->pr_ip6s > 0) { 3932192895Sjamie if (ip6s < cpr->pr_ip6s) { 3933192895Sjamie ip6s = cpr->pr_ip6s; 3934192895Sjamie mtx_unlock(&cpr->pr_mtx); 3935191673Sjamie ip6 = realloc(ip6, ip6s * 3936191673Sjamie sizeof(struct in6_addr), M_TEMP, M_WAITOK); 3937191673Sjamie goto again; 3938191673Sjamie } 3939192895Sjamie bcopy(cpr->pr_ip6, ip6, 3940192895Sjamie cpr->pr_ip6s * sizeof(struct in6_addr)); 3941191673Sjamie } 3942185435Sbz#endif 3943192895Sjamie if (cpr->pr_ref == 0) { 3944192895Sjamie mtx_unlock(&cpr->pr_mtx); 3945191673Sjamie continue; 3946191673Sjamie } 3947191673Sjamie bzero(xp, sizeof(*xp)); 3948113275Smike xp->pr_version = XPRISON_VERSION; 3949192895Sjamie xp->pr_id = cpr->pr_id; 3950192895Sjamie xp->pr_state = cpr->pr_uref > 0 3951191673Sjamie ? PRISON_STATE_ALIVE : PRISON_STATE_DYING; 3952192895Sjamie strlcpy(xp->pr_path, prison_path(pr, cpr), sizeof(xp->pr_path)); 3953194118Sjamie strlcpy(xp->pr_host, cpr->pr_hostname, sizeof(xp->pr_host)); 3954192895Sjamie strlcpy(xp->pr_name, prison_name(pr, cpr), sizeof(xp->pr_name)); 3955185435Sbz#ifdef INET 3956192895Sjamie xp->pr_ip4s = cpr->pr_ip4s; 3957185435Sbz#endif 3958185435Sbz#ifdef INET6 3959192895Sjamie xp->pr_ip6s = cpr->pr_ip6s; 3960185435Sbz#endif 3961192895Sjamie mtx_unlock(&cpr->pr_mtx); 3962191673Sjamie error = SYSCTL_OUT(req, xp, sizeof(*xp)); 3963191673Sjamie if (error) 3964191673Sjamie break; 3965185435Sbz#ifdef INET 3966191673Sjamie if (xp->pr_ip4s > 0) { 3967191673Sjamie error = SYSCTL_OUT(req, ip4, 3968191673Sjamie xp->pr_ip4s * sizeof(struct in_addr)); 3969191673Sjamie if (error) 3970191673Sjamie break; 3971185435Sbz } 3972185435Sbz#endif 3973185435Sbz#ifdef INET6 3974191673Sjamie if (xp->pr_ip6s > 0) { 3975191673Sjamie error = SYSCTL_OUT(req, ip6, 3976191673Sjamie xp->pr_ip6s * sizeof(struct in6_addr)); 3977191673Sjamie if (error) 3978191673Sjamie break; 3979185435Sbz } 3980185435Sbz#endif 3981113275Smike } 3982168401Spjd sx_sunlock(&allprison_lock); 3983191673Sjamie free(xp, M_TEMP); 3984191673Sjamie#ifdef INET 3985191673Sjamie free(ip4, M_TEMP); 3986191673Sjamie#endif 3987191673Sjamie#ifdef INET6 3988191673Sjamie free(ip6, M_TEMP); 3989191673Sjamie#endif 3990167354Spjd return (error); 3991113275Smike} 3992113275Smike 3993187864SedSYSCTL_OID(_security_jail, OID_AUTO, list, 3994187864Sed CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 0, 3995187864Sed sysctl_jail_list, "S", "List of active jails"); 3996126004Spjd 3997126004Spjdstatic int 3998126004Spjdsysctl_jail_jailed(SYSCTL_HANDLER_ARGS) 3999126004Spjd{ 4000126004Spjd int error, injail; 4001126004Spjd 4002126004Spjd injail = jailed(req->td->td_ucred); 4003126004Spjd error = SYSCTL_OUT(req, &injail, sizeof(injail)); 4004126004Spjd 4005126004Spjd return (error); 4006126004Spjd} 4007192895Sjamie 4008187864SedSYSCTL_PROC(_security_jail, OID_AUTO, jailed, 4009187864Sed CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 0, 4010187864Sed sysctl_jail_jailed, "I", "Process in jail?"); 4011185435Sbz 4012192895Sjamie#if defined(INET) || defined(INET6) 4013193865SjamieSYSCTL_UINT(_security_jail, OID_AUTO, jail_max_af_ips, CTLFLAG_RW, 4014192895Sjamie &jail_max_af_ips, 0, 4015192895Sjamie "Number of IP addresses a jail may have at most per address family"); 4016192895Sjamie#endif 4017192895Sjamie 4018192895Sjamie/* 4019192895Sjamie * Default parameters for jail(2) compatability. For historical reasons, 4020192895Sjamie * the sysctl names have varying similarity to the parameter names. Prisons 4021192895Sjamie * just see their own parameters, and can't change them. 4022192895Sjamie */ 4023192895Sjamiestatic int 4024192895Sjamiesysctl_jail_default_allow(SYSCTL_HANDLER_ARGS) 4025192895Sjamie{ 4026192895Sjamie struct prison *pr; 4027192895Sjamie int allow, error, i; 4028192895Sjamie 4029192895Sjamie pr = req->td->td_ucred->cr_prison; 4030192895Sjamie allow = (pr == &prison0) ? jail_default_allow : pr->pr_allow; 4031192895Sjamie 4032192895Sjamie /* Get the current flag value, and convert it to a boolean. */ 4033192895Sjamie i = (allow & arg2) ? 1 : 0; 4034192895Sjamie if (arg1 != NULL) 4035192895Sjamie i = !i; 4036192895Sjamie error = sysctl_handle_int(oidp, &i, 0, req); 4037192895Sjamie if (error || !req->newptr) 4038192895Sjamie return (error); 4039192895Sjamie i = i ? arg2 : 0; 4040192895Sjamie if (arg1 != NULL) 4041192895Sjamie i ^= arg2; 4042192895Sjamie /* 4043192895Sjamie * The sysctls don't have CTLFLAGS_PRISON, so assume prison0 4044192895Sjamie * for writing. 4045192895Sjamie */ 4046192895Sjamie mtx_lock(&prison0.pr_mtx); 4047192895Sjamie jail_default_allow = (jail_default_allow & ~arg2) | i; 4048192895Sjamie mtx_unlock(&prison0.pr_mtx); 4049192895Sjamie return (0); 4050192895Sjamie} 4051192895Sjamie 4052192895SjamieSYSCTL_PROC(_security_jail, OID_AUTO, set_hostname_allowed, 4053192895Sjamie CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, 4054192895Sjamie NULL, PR_ALLOW_SET_HOSTNAME, sysctl_jail_default_allow, "I", 4055192895Sjamie "Processes in jail can set their hostnames"); 4056192895SjamieSYSCTL_PROC(_security_jail, OID_AUTO, socket_unixiproute_only, 4057192895Sjamie CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, 4058192895Sjamie (void *)1, PR_ALLOW_SOCKET_AF, sysctl_jail_default_allow, "I", 4059192895Sjamie "Processes in jail are limited to creating UNIX/IP/route sockets only"); 4060192895SjamieSYSCTL_PROC(_security_jail, OID_AUTO, sysvipc_allowed, 4061192895Sjamie CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, 4062192895Sjamie NULL, PR_ALLOW_SYSVIPC, sysctl_jail_default_allow, "I", 4063192895Sjamie "Processes in jail can use System V IPC primitives"); 4064192895SjamieSYSCTL_PROC(_security_jail, OID_AUTO, allow_raw_sockets, 4065192895Sjamie CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, 4066192895Sjamie NULL, PR_ALLOW_RAW_SOCKETS, sysctl_jail_default_allow, "I", 4067192895Sjamie "Prison root can create raw sockets"); 4068192895SjamieSYSCTL_PROC(_security_jail, OID_AUTO, chflags_allowed, 4069192895Sjamie CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, 4070192895Sjamie NULL, PR_ALLOW_CHFLAGS, sysctl_jail_default_allow, "I", 4071192895Sjamie "Processes in jail can alter system file flags"); 4072192895SjamieSYSCTL_PROC(_security_jail, OID_AUTO, mount_allowed, 4073192895Sjamie CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, 4074192895Sjamie NULL, PR_ALLOW_MOUNT, sysctl_jail_default_allow, "I", 4075192895Sjamie "Processes in jail can mount/unmount jail-friendly file systems"); 4076192895Sjamie 4077192895Sjamiestatic int 4078192895Sjamiesysctl_jail_default_level(SYSCTL_HANDLER_ARGS) 4079192895Sjamie{ 4080192895Sjamie struct prison *pr; 4081192895Sjamie int level, error; 4082192895Sjamie 4083192895Sjamie pr = req->td->td_ucred->cr_prison; 4084192895Sjamie level = (pr == &prison0) ? *(int *)arg1 : *(int *)((char *)pr + arg2); 4085192895Sjamie error = sysctl_handle_int(oidp, &level, 0, req); 4086192895Sjamie if (error || !req->newptr) 4087192895Sjamie return (error); 4088192895Sjamie *(int *)arg1 = level; 4089192895Sjamie return (0); 4090192895Sjamie} 4091192895Sjamie 4092192895SjamieSYSCTL_PROC(_security_jail, OID_AUTO, enforce_statfs, 4093192895Sjamie CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, 4094192895Sjamie &jail_default_enforce_statfs, offsetof(struct prison, pr_enforce_statfs), 4095192895Sjamie sysctl_jail_default_level, "I", 4096192895Sjamie "Processes in jail cannot see all mounted file systems"); 4097192895Sjamie 4098192895Sjamie/* 4099192895Sjamie * Nodes to describe jail parameters. Maximum length of string parameters 4100192895Sjamie * is returned in the string itself, and the other parameters exist merely 4101192895Sjamie * to make themselves and their types known. 4102192895Sjamie */ 4103192895SjamieSYSCTL_NODE(_security_jail, OID_AUTO, param, CTLFLAG_RW, 0, 4104192895Sjamie "Jail parameters"); 4105192895Sjamie 4106192895Sjamieint 4107192895Sjamiesysctl_jail_param(SYSCTL_HANDLER_ARGS) 4108192895Sjamie{ 4109192895Sjamie int i; 4110192895Sjamie long l; 4111192895Sjamie size_t s; 4112192895Sjamie char numbuf[12]; 4113192895Sjamie 4114192895Sjamie switch (oidp->oid_kind & CTLTYPE) 4115192895Sjamie { 4116192895Sjamie case CTLTYPE_LONG: 4117192895Sjamie case CTLTYPE_ULONG: 4118192895Sjamie l = 0; 4119192895Sjamie#ifdef SCTL_MASK32 4120192895Sjamie if (!(req->flags & SCTL_MASK32)) 4121192895Sjamie#endif 4122192895Sjamie return (SYSCTL_OUT(req, &l, sizeof(l))); 4123192895Sjamie case CTLTYPE_INT: 4124192895Sjamie case CTLTYPE_UINT: 4125192895Sjamie i = 0; 4126192895Sjamie return (SYSCTL_OUT(req, &i, sizeof(i))); 4127192895Sjamie case CTLTYPE_STRING: 4128192895Sjamie snprintf(numbuf, sizeof(numbuf), "%d", arg2); 4129192895Sjamie return 4130192895Sjamie (sysctl_handle_string(oidp, numbuf, sizeof(numbuf), req)); 4131192895Sjamie case CTLTYPE_STRUCT: 4132192895Sjamie s = (size_t)arg2; 4133192895Sjamie return (SYSCTL_OUT(req, &s, sizeof(s))); 4134192895Sjamie } 4135192895Sjamie return (0); 4136192895Sjamie} 4137192895Sjamie 4138192895SjamieSYSCTL_JAIL_PARAM(, jid, CTLTYPE_INT | CTLFLAG_RDTUN, "I", "Jail ID"); 4139192895SjamieSYSCTL_JAIL_PARAM(, parent, CTLTYPE_INT | CTLFLAG_RD, "I", "Jail parent ID"); 4140192895SjamieSYSCTL_JAIL_PARAM_STRING(, name, CTLFLAG_RW, MAXHOSTNAMELEN, "Jail name"); 4141192895SjamieSYSCTL_JAIL_PARAM_STRING(, path, CTLFLAG_RDTUN, MAXPATHLEN, "Jail root path"); 4142192895SjamieSYSCTL_JAIL_PARAM(, securelevel, CTLTYPE_INT | CTLFLAG_RW, 4143192895Sjamie "I", "Jail secure level"); 4144192895SjamieSYSCTL_JAIL_PARAM(, enforce_statfs, CTLTYPE_INT | CTLFLAG_RW, 4145192895Sjamie "I", "Jail cannot see all mounted file systems"); 4146192895SjamieSYSCTL_JAIL_PARAM(, persist, CTLTYPE_INT | CTLFLAG_RW, 4147192895Sjamie "B", "Jail persistence"); 4148194251Sjamie#ifdef VIMAGE 4149194251SjamieSYSCTL_JAIL_PARAM(, vnet, CTLTYPE_INT | CTLFLAG_RDTUN, 4150195870Sjamie "E,jailsys", "Virtual network stack"); 4151194251Sjamie#endif 4152192895SjamieSYSCTL_JAIL_PARAM(, dying, CTLTYPE_INT | CTLFLAG_RD, 4153192895Sjamie "B", "Jail is in the process of shutting down"); 4154192895Sjamie 4155194762SjamieSYSCTL_JAIL_PARAM_NODE(children, "Number of child jails"); 4156194762SjamieSYSCTL_JAIL_PARAM(_children, cur, CTLTYPE_INT | CTLFLAG_RD, 4157194762Sjamie "I", "Current number of child jails"); 4158194762SjamieSYSCTL_JAIL_PARAM(_children, max, CTLTYPE_INT | CTLFLAG_RW, 4159194762Sjamie "I", "Maximum number of child jails"); 4160194762Sjamie 4161195870SjamieSYSCTL_JAIL_PARAM_SYS_NODE(host, CTLFLAG_RW, "Jail host info"); 4162192895SjamieSYSCTL_JAIL_PARAM_STRING(_host, hostname, CTLFLAG_RW, MAXHOSTNAMELEN, 4163192895Sjamie "Jail hostname"); 4164193066SjamieSYSCTL_JAIL_PARAM_STRING(_host, domainname, CTLFLAG_RW, MAXHOSTNAMELEN, 4165193066Sjamie "Jail NIS domainname"); 4166193066SjamieSYSCTL_JAIL_PARAM_STRING(_host, hostuuid, CTLFLAG_RW, HOSTUUIDLEN, 4167193066Sjamie "Jail host UUID"); 4168193066SjamieSYSCTL_JAIL_PARAM(_host, hostid, CTLTYPE_ULONG | CTLFLAG_RW, 4169193066Sjamie "LU", "Jail host ID"); 4170192895Sjamie 4171192895SjamieSYSCTL_JAIL_PARAM_NODE(cpuset, "Jail cpuset"); 4172192895SjamieSYSCTL_JAIL_PARAM(_cpuset, id, CTLTYPE_INT | CTLFLAG_RD, "I", "Jail cpuset ID"); 4173192895Sjamie 4174192895Sjamie#ifdef INET 4175195870SjamieSYSCTL_JAIL_PARAM_SYS_NODE(ip4, CTLFLAG_RW, "Jail IPv4 address virtualization"); 4176192895SjamieSYSCTL_JAIL_PARAM_STRUCT(_ip4, addr, CTLFLAG_RW, sizeof(struct in_addr), 4177192895Sjamie "S,in_addr,a", "Jail IPv4 addresses"); 4178192895Sjamie#endif 4179192895Sjamie#ifdef INET6 4180195870SjamieSYSCTL_JAIL_PARAM_SYS_NODE(ip6, CTLFLAG_RW, "Jail IPv6 address virtualization"); 4181192895SjamieSYSCTL_JAIL_PARAM_STRUCT(_ip6, addr, CTLFLAG_RW, sizeof(struct in6_addr), 4182192895Sjamie "S,in6_addr,a", "Jail IPv6 addresses"); 4183192895Sjamie#endif 4184192895Sjamie 4185192895SjamieSYSCTL_JAIL_PARAM_NODE(allow, "Jail permission flags"); 4186192895SjamieSYSCTL_JAIL_PARAM(_allow, set_hostname, CTLTYPE_INT | CTLFLAG_RW, 4187192895Sjamie "B", "Jail may set hostname"); 4188192895SjamieSYSCTL_JAIL_PARAM(_allow, sysvipc, CTLTYPE_INT | CTLFLAG_RW, 4189192895Sjamie "B", "Jail may use SYSV IPC"); 4190192895SjamieSYSCTL_JAIL_PARAM(_allow, raw_sockets, CTLTYPE_INT | CTLFLAG_RW, 4191192895Sjamie "B", "Jail may create raw sockets"); 4192192895SjamieSYSCTL_JAIL_PARAM(_allow, chflags, CTLTYPE_INT | CTLFLAG_RW, 4193192895Sjamie "B", "Jail may alter system file flags"); 4194192895SjamieSYSCTL_JAIL_PARAM(_allow, mount, CTLTYPE_INT | CTLFLAG_RW, 4195192895Sjamie "B", "Jail may mount/unmount jail-friendly file systems"); 4196192895SjamieSYSCTL_JAIL_PARAM(_allow, quotas, CTLTYPE_INT | CTLFLAG_RW, 4197192895Sjamie "B", "Jail may set file quotas"); 4198192895SjamieSYSCTL_JAIL_PARAM(_allow, socket_af, CTLTYPE_INT | CTLFLAG_RW, 4199192895Sjamie "B", "Jail may create sockets other than just UNIX/IPv4/IPv6/route"); 4200192895Sjamie 4201192895Sjamie 4202185435Sbz#ifdef DDB 4203191673Sjamie 4204191673Sjamiestatic void 4205191673Sjamiedb_show_prison(struct prison *pr) 4206185435Sbz{ 4207192895Sjamie int fi; 4208191673Sjamie#if defined(INET) || defined(INET6) 4209191673Sjamie int ii; 4210185435Sbz#endif 4211195870Sjamie unsigned jsf; 4212185435Sbz#ifdef INET6 4213185435Sbz char ip6buf[INET6_ADDRSTRLEN]; 4214185435Sbz#endif 4215185435Sbz 4216191673Sjamie db_printf("prison %p:\n", pr); 4217191673Sjamie db_printf(" jid = %d\n", pr->pr_id); 4218191673Sjamie db_printf(" name = %s\n", pr->pr_name); 4219192895Sjamie db_printf(" parent = %p\n", pr->pr_parent); 4220191673Sjamie db_printf(" ref = %d\n", pr->pr_ref); 4221191673Sjamie db_printf(" uref = %d\n", pr->pr_uref); 4222191673Sjamie db_printf(" path = %s\n", pr->pr_path); 4223191673Sjamie db_printf(" cpuset = %d\n", pr->pr_cpuset 4224191673Sjamie ? pr->pr_cpuset->cs_id : -1); 4225194251Sjamie#ifdef VIMAGE 4226194251Sjamie db_printf(" vnet = %p\n", pr->pr_vnet); 4227194251Sjamie#endif 4228191673Sjamie db_printf(" root = %p\n", pr->pr_root); 4229191673Sjamie db_printf(" securelevel = %d\n", pr->pr_securelevel); 4230194762Sjamie db_printf(" childcount = %d\n", pr->pr_childcount); 4231192895Sjamie db_printf(" child = %p\n", LIST_FIRST(&pr->pr_children)); 4232192895Sjamie db_printf(" sibling = %p\n", LIST_NEXT(pr, pr_sibling)); 4233191673Sjamie db_printf(" flags = %x", pr->pr_flags); 4234192895Sjamie for (fi = 0; fi < sizeof(pr_flag_names) / sizeof(pr_flag_names[0]); 4235192895Sjamie fi++) 4236192895Sjamie if (pr_flag_names[fi] != NULL && (pr->pr_flags & (1 << fi))) 4237192895Sjamie db_printf(" %s", pr_flag_names[fi]); 4238195870Sjamie for (fi = 0; fi < sizeof(pr_flag_jailsys) / sizeof(pr_flag_jailsys[0]); 4239195870Sjamie fi++) { 4240195870Sjamie jsf = pr->pr_flags & 4241195870Sjamie (pr_flag_jailsys[fi].disable | pr_flag_jailsys[fi].new); 4242195870Sjamie db_printf(" %-16s= %s\n", pr_flag_jailsys[fi].name, 4243195870Sjamie pr_flag_jailsys[fi].disable && 4244195870Sjamie (jsf == pr_flag_jailsys[fi].disable) ? "disable" 4245195870Sjamie : (jsf == pr_flag_jailsys[fi].new) ? "new" 4246195870Sjamie : "inherit"); 4247195870Sjamie } 4248192895Sjamie db_printf(" allow = %x", pr->pr_allow); 4249192895Sjamie for (fi = 0; fi < sizeof(pr_allow_names) / sizeof(pr_allow_names[0]); 4250192895Sjamie fi++) 4251192895Sjamie if (pr_allow_names[fi] != NULL && (pr->pr_allow & (1 << fi))) 4252192895Sjamie db_printf(" %s", pr_allow_names[fi]); 4253191673Sjamie db_printf("\n"); 4254192895Sjamie db_printf(" enforce_statfs = %d\n", pr->pr_enforce_statfs); 4255194118Sjamie db_printf(" host.hostname = %s\n", pr->pr_hostname); 4256194118Sjamie db_printf(" host.domainname = %s\n", pr->pr_domainname); 4257194118Sjamie db_printf(" host.hostuuid = %s\n", pr->pr_hostuuid); 4258193066Sjamie db_printf(" host.hostid = %lu\n", pr->pr_hostid); 4259185435Sbz#ifdef INET 4260191673Sjamie db_printf(" ip4s = %d\n", pr->pr_ip4s); 4261191673Sjamie for (ii = 0; ii < pr->pr_ip4s; ii++) 4262191673Sjamie db_printf(" %s %s\n", 4263191673Sjamie ii == 0 ? "ip4 =" : " ", 4264191673Sjamie inet_ntoa(pr->pr_ip4[ii])); 4265185435Sbz#endif 4266185435Sbz#ifdef INET6 4267191673Sjamie db_printf(" ip6s = %d\n", pr->pr_ip6s); 4268191673Sjamie for (ii = 0; ii < pr->pr_ip6s; ii++) 4269191673Sjamie db_printf(" %s %s\n", 4270191673Sjamie ii == 0 ? "ip6 =" : " ", 4271191673Sjamie ip6_sprintf(ip6buf, &pr->pr_ip6[ii])); 4272191673Sjamie#endif 4273191673Sjamie} 4274191673Sjamie 4275191673SjamieDB_SHOW_COMMAND(prison, db_show_prison_command) 4276191673Sjamie{ 4277191673Sjamie struct prison *pr; 4278191673Sjamie 4279191673Sjamie if (!have_addr) { 4280192895Sjamie /* 4281192895Sjamie * Show all prisons in the list, and prison0 which is not 4282192895Sjamie * listed. 4283192895Sjamie */ 4284192895Sjamie db_show_prison(&prison0); 4285192895Sjamie if (!db_pager_quit) { 4286192895Sjamie TAILQ_FOREACH(pr, &allprison, pr_list) { 4287192895Sjamie db_show_prison(pr); 4288192895Sjamie if (db_pager_quit) 4289192895Sjamie break; 4290192895Sjamie } 4291191673Sjamie } 4292191673Sjamie return; 4293191673Sjamie } 4294191673Sjamie 4295192895Sjamie if (addr == 0) 4296192895Sjamie pr = &prison0; 4297192895Sjamie else { 4298192895Sjamie /* Look for a prison with the ID and with references. */ 4299191673Sjamie TAILQ_FOREACH(pr, &allprison, pr_list) 4300192895Sjamie if (pr->pr_id == addr && pr->pr_ref > 0) 4301191673Sjamie break; 4302192895Sjamie if (pr == NULL) 4303192895Sjamie /* Look again, without requiring a reference. */ 4304192895Sjamie TAILQ_FOREACH(pr, &allprison, pr_list) 4305192895Sjamie if (pr->pr_id == addr) 4306192895Sjamie break; 4307192895Sjamie if (pr == NULL) 4308192895Sjamie /* Assume address points to a valid prison. */ 4309192895Sjamie pr = (struct prison *)addr; 4310192895Sjamie } 4311191673Sjamie db_show_prison(pr); 4312185435Sbz} 4313191673Sjamie 4314185435Sbz#endif /* DDB */ 4315