kern_jail.c revision 187684
1139804Simp/*- 2185435Sbz * Copyright (c) 1999 Poul-Henning Kamp. 3185435Sbz * Copyright (c) 2008 Bjoern A. Zeeb. 4185435Sbz * All rights reserved. 5185404Sbz * 6185404Sbz * Redistribution and use in source and binary forms, with or without 7185404Sbz * modification, are permitted provided that the following conditions 8185404Sbz * are met: 9185404Sbz * 1. Redistributions of source code must retain the above copyright 10185404Sbz * notice, this list of conditions and the following disclaimer. 11185404Sbz * 2. Redistributions in binary form must reproduce the above copyright 12185404Sbz * notice, this list of conditions and the following disclaimer in the 13185404Sbz * documentation and/or other materials provided with the distribution. 14185404Sbz * 15185404Sbz * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16185404Sbz * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17185404Sbz * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18185404Sbz * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19185404Sbz * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20185404Sbz * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21185404Sbz * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22185404Sbz * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23185404Sbz * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24185404Sbz * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25185404Sbz * SUCH DAMAGE. 2646197Sphk */ 2746155Sphk 28116182Sobrien#include <sys/cdefs.h> 29116182Sobrien__FBSDID("$FreeBSD: head/sys/kern/kern_jail.c 187684 2009-01-25 10:11:58Z bz $"); 30116182Sobrien 31185435Sbz#include "opt_ddb.h" 32185435Sbz#include "opt_inet.h" 33185435Sbz#include "opt_inet6.h" 34131177Spjd#include "opt_mac.h" 35131177Spjd 3646155Sphk#include <sys/param.h> 3746155Sphk#include <sys/types.h> 3846155Sphk#include <sys/kernel.h> 3946155Sphk#include <sys/systm.h> 4046155Sphk#include <sys/errno.h> 4146155Sphk#include <sys/sysproto.h> 4246155Sphk#include <sys/malloc.h> 43164032Srwatson#include <sys/priv.h> 4446155Sphk#include <sys/proc.h> 45124882Srwatson#include <sys/taskqueue.h> 46177785Skib#include <sys/fcntl.h> 4746155Sphk#include <sys/jail.h> 4887275Srwatson#include <sys/lock.h> 4987275Srwatson#include <sys/mutex.h> 50168401Spjd#include <sys/sx.h> 51113275Smike#include <sys/namei.h> 52147185Spjd#include <sys/mount.h> 53113275Smike#include <sys/queue.h> 5446155Sphk#include <sys/socket.h> 55113275Smike#include <sys/syscallsubr.h> 5657163Srwatson#include <sys/sysctl.h> 57113275Smike#include <sys/vnode.h> 58181803Sbz#include <sys/vimage.h> 59185029Spjd#include <sys/osd.h> 6046155Sphk#include <net/if.h> 6146155Sphk#include <netinet/in.h> 62185435Sbz#ifdef DDB 63185435Sbz#include <ddb/ddb.h> 64185435Sbz#ifdef INET6 65185435Sbz#include <netinet6/in6_var.h> 66185435Sbz#endif /* INET6 */ 67185435Sbz#endif /* DDB */ 6846155Sphk 69163606Srwatson#include <security/mac/mac_framework.h> 70163606Srwatson 7146155SphkMALLOC_DEFINE(M_PRISON, "prison", "Prison structures"); 7246155Sphk 7389414SarrSYSCTL_NODE(_security, OID_AUTO, jail, CTLFLAG_RW, 0, 7457163Srwatson "Jail rules"); 7557163Srwatson 7657163Srwatsonint jail_set_hostname_allowed = 1; 7789414SarrSYSCTL_INT(_security_jail, OID_AUTO, set_hostname_allowed, CTLFLAG_RW, 7857163Srwatson &jail_set_hostname_allowed, 0, 7957163Srwatson "Processes in jail can set their hostnames"); 8057163Srwatson 8161235Srwatsonint jail_socket_unixiproute_only = 1; 8289414SarrSYSCTL_INT(_security_jail, OID_AUTO, socket_unixiproute_only, CTLFLAG_RW, 8361235Srwatson &jail_socket_unixiproute_only, 0, 84185435Sbz "Processes in jail are limited to creating UNIX/IP/route sockets only"); 8561235Srwatson 8668024Srwatsonint jail_sysvipc_allowed = 0; 8789414SarrSYSCTL_INT(_security_jail, OID_AUTO, sysvipc_allowed, CTLFLAG_RW, 8868024Srwatson &jail_sysvipc_allowed, 0, 8968024Srwatson "Processes in jail can use System V IPC primitives"); 9068024Srwatson 91147185Spjdstatic int jail_enforce_statfs = 2; 92147185SpjdSYSCTL_INT(_security_jail, OID_AUTO, enforce_statfs, CTLFLAG_RW, 93147185Spjd &jail_enforce_statfs, 0, 94147185Spjd "Processes in jail cannot see all mounted file systems"); 95125804Srwatson 96128664Sbmilekicint jail_allow_raw_sockets = 0; 97128664SbmilekicSYSCTL_INT(_security_jail, OID_AUTO, allow_raw_sockets, CTLFLAG_RW, 98128664Sbmilekic &jail_allow_raw_sockets, 0, 99128664Sbmilekic "Prison root can create raw sockets"); 100128664Sbmilekic 101141543Scpercivaint jail_chflags_allowed = 0; 102141543ScpercivaSYSCTL_INT(_security_jail, OID_AUTO, chflags_allowed, CTLFLAG_RW, 103141543Scperciva &jail_chflags_allowed, 0, 104141543Scperciva "Processes in jail can alter system file flags"); 105141543Scperciva 106168396Spjdint jail_mount_allowed = 0; 107168396SpjdSYSCTL_INT(_security_jail, OID_AUTO, mount_allowed, CTLFLAG_RW, 108168396Spjd &jail_mount_allowed, 0, 109168396Spjd "Processes in jail can mount/unmount jail-friendly file systems"); 110168396Spjd 111185435Sbzint jail_max_af_ips = 255; 112185435SbzSYSCTL_INT(_security_jail, OID_AUTO, jail_max_af_ips, CTLFLAG_RW, 113185435Sbz &jail_max_af_ips, 0, 114185435Sbz "Number of IP addresses a jail may have at most per address family"); 115185435Sbz 116179881Sdelphij/* allprison, lastprid, and prisoncount are protected by allprison_lock. */ 117179881Sdelphijstruct prisonlist allprison; 118168401Spjdstruct sx allprison_lock; 119179881Sdelphijint lastprid = 0; 120113275Smikeint prisoncount = 0; 121113275Smike 122113275Smikestatic void init_prison(void *); 123124882Srwatsonstatic void prison_complete(void *context, int pending); 124113275Smikestatic int sysctl_jail_list(SYSCTL_HANDLER_ARGS); 125185435Sbz#ifdef INET 126185435Sbzstatic int _prison_check_ip4(struct prison *, struct in_addr *); 127185435Sbz#endif 128185435Sbz#ifdef INET6 129185435Sbzstatic int _prison_check_ip6(struct prison *, struct in6_addr *); 130185435Sbz#endif 131113275Smike 132113275Smikestatic void 133113275Smikeinit_prison(void *data __unused) 134113275Smike{ 135113275Smike 136179881Sdelphij sx_init(&allprison_lock, "allprison"); 137179881Sdelphij LIST_INIT(&allprison); 138113275Smike} 139113275Smike 140113275SmikeSYSINIT(prison, SI_SUB_INTRINSIC, SI_ORDER_ANY, init_prison, NULL); 141113275Smike 142185435Sbz#ifdef INET 143185435Sbzstatic int 144185435Sbzqcmp_v4(const void *ip1, const void *ip2) 145185435Sbz{ 146185435Sbz in_addr_t iaa, iab; 147185435Sbz 148185435Sbz /* 149185435Sbz * We need to compare in HBO here to get the list sorted as expected 150185435Sbz * by the result of the code. Sorting NBO addresses gives you 151185435Sbz * interesting results. If you do not understand, do not try. 152185435Sbz */ 153185435Sbz iaa = ntohl(((const struct in_addr *)ip1)->s_addr); 154185435Sbz iab = ntohl(((const struct in_addr *)ip2)->s_addr); 155185435Sbz 156185435Sbz /* 157185435Sbz * Do not simply return the difference of the two numbers, the int is 158185435Sbz * not wide enough. 159185435Sbz */ 160185435Sbz if (iaa > iab) 161185435Sbz return (1); 162185435Sbz else if (iaa < iab) 163185435Sbz return (-1); 164185435Sbz else 165185435Sbz return (0); 166185435Sbz} 167185435Sbz#endif 168185435Sbz 169185435Sbz#ifdef INET6 170185435Sbzstatic int 171185435Sbzqcmp_v6(const void *ip1, const void *ip2) 172185435Sbz{ 173185435Sbz const struct in6_addr *ia6a, *ia6b; 174185435Sbz int i, rc; 175185435Sbz 176185435Sbz ia6a = (const struct in6_addr *)ip1; 177185435Sbz ia6b = (const struct in6_addr *)ip2; 178185435Sbz 179185435Sbz rc = 0; 180185435Sbz for (i=0; rc == 0 && i < sizeof(struct in6_addr); i++) { 181185435Sbz if (ia6a->s6_addr[i] > ia6b->s6_addr[i]) 182185435Sbz rc = 1; 183185435Sbz else if (ia6a->s6_addr[i] < ia6b->s6_addr[i]) 184185435Sbz rc = -1; 185185435Sbz } 186185435Sbz return (rc); 187185435Sbz} 188185435Sbz#endif 189185435Sbz 190185435Sbz#if defined(INET) || defined(INET6) 191185435Sbzstatic int 192185435Sbzprison_check_conflicting_ips(struct prison *p) 193185435Sbz{ 194185435Sbz struct prison *pr; 195185435Sbz int i; 196185435Sbz 197185435Sbz sx_assert(&allprison_lock, SX_LOCKED); 198185435Sbz 199185435Sbz if (p->pr_ip4s == 0 && p->pr_ip6s == 0) 200185435Sbz return (0); 201185435Sbz 202185435Sbz LIST_FOREACH(pr, &allprison, pr_list) { 203185435Sbz /* 204185435Sbz * Skip 'dying' prisons to avoid problems when 205185435Sbz * restarting multi-IP jails. 206185435Sbz */ 207185435Sbz if (pr->pr_state == PRISON_STATE_DYING) 208185435Sbz continue; 209185435Sbz 210185435Sbz /* 211185435Sbz * We permit conflicting IPs if there is no 212185435Sbz * more than 1 IP on eeach jail. 213185435Sbz * In case there is one duplicate on a jail with 214185435Sbz * more than one IP stop checking and return error. 215185435Sbz */ 216185435Sbz#ifdef INET 217185435Sbz if ((p->pr_ip4s >= 1 && pr->pr_ip4s > 1) || 218185435Sbz (p->pr_ip4s > 1 && pr->pr_ip4s >= 1)) { 219185435Sbz for (i = 0; i < p->pr_ip4s; i++) { 220185435Sbz if (_prison_check_ip4(pr, &p->pr_ip4[i])) 221185435Sbz return (EINVAL); 222185435Sbz } 223185435Sbz } 224185435Sbz#endif 225185435Sbz#ifdef INET6 226185435Sbz if ((p->pr_ip6s >= 1 && pr->pr_ip6s > 1) || 227185435Sbz (p->pr_ip6s > 1 && pr->pr_ip6s >= 1)) { 228185435Sbz for (i = 0; i < p->pr_ip6s; i++) { 229185435Sbz if (_prison_check_ip6(pr, &p->pr_ip6[i])) 230185435Sbz return (EINVAL); 231185435Sbz } 232185435Sbz } 233185435Sbz#endif 234185435Sbz } 235185435Sbz 236185435Sbz return (0); 237185435Sbz} 238185435Sbz 239185435Sbzstatic int 240185435Sbzjail_copyin_ips(struct jail *j) 241185435Sbz{ 242185435Sbz#ifdef INET 243185435Sbz struct in_addr *ip4; 244185435Sbz#endif 245185435Sbz#ifdef INET6 246185435Sbz struct in6_addr *ip6; 247185435Sbz#endif 248185435Sbz int error, i; 249185435Sbz 250185435Sbz /* 251185435Sbz * Copy in addresses, check for duplicate addresses and do some 252185435Sbz * simple 0 and broadcast checks. If users give other bogus addresses 253185435Sbz * it is their problem. 254185435Sbz * 255185435Sbz * IP addresses are all sorted but ip[0] to preserve the primary IP 256185435Sbz * address as given from userland. This special IP is used for 257185435Sbz * unbound outgoing connections as well for "loopback" traffic. 258185435Sbz */ 259185435Sbz#ifdef INET 260185435Sbz ip4 = NULL; 261185435Sbz#endif 262185435Sbz#ifdef INET6 263185435Sbz ip6 = NULL; 264185435Sbz#endif 265185435Sbz#ifdef INET 266185435Sbz if (j->ip4s > 0) { 267185435Sbz ip4 = (struct in_addr *)malloc(j->ip4s * sizeof(struct in_addr), 268185435Sbz M_PRISON, M_WAITOK | M_ZERO); 269185435Sbz error = copyin(j->ip4, ip4, j->ip4s * sizeof(struct in_addr)); 270185435Sbz if (error) 271185435Sbz goto e_free_ip; 272185435Sbz /* Sort all but the first IPv4 address. */ 273185435Sbz if (j->ip4s > 1) 274185435Sbz qsort((ip4 + 1), j->ip4s - 1, 275185435Sbz sizeof(struct in_addr), qcmp_v4); 276185435Sbz 277185435Sbz /* 278185435Sbz * We do not have to care about byte order for these checks 279185435Sbz * so we will do them in NBO. 280185435Sbz */ 281185435Sbz for (i=0; i<j->ip4s; i++) { 282185435Sbz if (ip4[i].s_addr == htonl(INADDR_ANY) || 283185435Sbz ip4[i].s_addr == htonl(INADDR_BROADCAST)) { 284185435Sbz error = EINVAL; 285185435Sbz goto e_free_ip; 286185435Sbz } 287185435Sbz if ((i+1) < j->ip4s && 288185435Sbz (ip4[0].s_addr == ip4[i+1].s_addr || 289185435Sbz ip4[i].s_addr == ip4[i+1].s_addr)) { 290185435Sbz error = EINVAL; 291185435Sbz goto e_free_ip; 292185435Sbz } 293185435Sbz } 294185435Sbz 295185435Sbz j->ip4 = ip4; 296186606Spho } else 297186606Spho j->ip4 = NULL; 298185435Sbz#endif 299185435Sbz#ifdef INET6 300185435Sbz if (j->ip6s > 0) { 301185435Sbz ip6 = (struct in6_addr *)malloc(j->ip6s * sizeof(struct in6_addr), 302185435Sbz M_PRISON, M_WAITOK | M_ZERO); 303185435Sbz error = copyin(j->ip6, ip6, j->ip6s * sizeof(struct in6_addr)); 304185435Sbz if (error) 305185435Sbz goto e_free_ip; 306185435Sbz /* Sort all but the first IPv6 address. */ 307185435Sbz if (j->ip6s > 1) 308185435Sbz qsort((ip6 + 1), j->ip6s - 1, 309185435Sbz sizeof(struct in6_addr), qcmp_v6); 310185435Sbz for (i=0; i<j->ip6s; i++) { 311185435Sbz if (IN6_IS_ADDR_UNSPECIFIED(&ip6[i])) { 312185435Sbz error = EINVAL; 313185435Sbz goto e_free_ip; 314185435Sbz } 315185435Sbz if ((i+1) < j->ip6s && 316185435Sbz (IN6_ARE_ADDR_EQUAL(&ip6[0], &ip6[i+1]) || 317185435Sbz IN6_ARE_ADDR_EQUAL(&ip6[i], &ip6[i+1]))) { 318185435Sbz error = EINVAL; 319185435Sbz goto e_free_ip; 320185435Sbz } 321185435Sbz } 322185435Sbz 323185435Sbz j->ip6 = ip6; 324186606Spho } else 325186606Spho j->ip6 = NULL; 326185435Sbz#endif 327185435Sbz return (0); 328185435Sbz 329185435Sbze_free_ip: 330185435Sbz#ifdef INET6 331185435Sbz free(ip6, M_PRISON); 332185435Sbz#endif 333185435Sbz#ifdef INET 334185435Sbz free(ip4, M_PRISON); 335185435Sbz#endif 336185435Sbz return (error); 337185435Sbz} 338185435Sbz#endif /* INET || INET6 */ 339185435Sbz 340185435Sbzstatic int 341185435Sbzjail_handle_ips(struct jail *j) 342185435Sbz{ 343185435Sbz#if defined(INET) || defined(INET6) 344185435Sbz int error; 345185435Sbz#endif 346185435Sbz 347185435Sbz /* 348185435Sbz * Finish conversion for older versions, copyin and setup IPs. 349185435Sbz */ 350185435Sbz switch (j->version) { 351185435Sbz case 0: 352185435Sbz { 353185435Sbz#ifdef INET 354185435Sbz /* FreeBSD single IPv4 jails. */ 355185435Sbz struct in_addr *ip4; 356185435Sbz 357185435Sbz if (j->ip4s == INADDR_ANY || j->ip4s == INADDR_BROADCAST) 358185435Sbz return (EINVAL); 359185435Sbz ip4 = (struct in_addr *)malloc(sizeof(struct in_addr), 360185435Sbz M_PRISON, M_WAITOK | M_ZERO); 361185435Sbz 362185435Sbz /* 363185435Sbz * Jail version 0 still used HBO for the IPv4 address. 364185435Sbz */ 365185435Sbz ip4->s_addr = htonl(j->ip4s); 366185435Sbz j->ip4s = 1; 367185435Sbz j->ip4 = ip4; 368185435Sbz break; 369185435Sbz#else 370185435Sbz return (EINVAL); 371185435Sbz#endif 372185435Sbz } 373185435Sbz 374185435Sbz case 1: 375185435Sbz /* 376185435Sbz * Version 1 was used by multi-IPv4 jail implementations 377185435Sbz * that never made it into the official kernel. 378185435Sbz * We should never hit this here; jail() should catch it. 379185435Sbz */ 380185435Sbz return (EINVAL); 381185435Sbz 382185435Sbz case 2: /* JAIL_API_VERSION */ 383185435Sbz /* FreeBSD multi-IPv4/IPv6,noIP jails. */ 384185435Sbz#if defined(INET) || defined(INET6) 385185435Sbz#ifdef INET 386185435Sbz if (j->ip4s > jail_max_af_ips) 387185435Sbz return (EINVAL); 388185435Sbz#else 389185435Sbz if (j->ip4s != 0) 390185435Sbz return (EINVAL); 391185435Sbz#endif 392185435Sbz#ifdef INET6 393185435Sbz if (j->ip6s > jail_max_af_ips) 394185435Sbz return (EINVAL); 395185435Sbz#else 396185435Sbz if (j->ip6s != 0) 397185435Sbz return (EINVAL); 398185435Sbz#endif 399185435Sbz error = jail_copyin_ips(j); 400185435Sbz if (error) 401185435Sbz return (error); 402185435Sbz#endif 403185435Sbz break; 404185435Sbz 405185435Sbz default: 406185435Sbz /* Sci-Fi jails are not supported, sorry. */ 407185435Sbz return (EINVAL); 408185435Sbz } 409185435Sbz 410185435Sbz return (0); 411185435Sbz} 412185435Sbz 413185435Sbz 41482710Sdillon/* 415114168Smike * struct jail_args { 416114168Smike * struct jail *jail; 417114168Smike * }; 41882710Sdillon */ 41946155Sphkint 420114168Smikejail(struct thread *td, struct jail_args *uap) 42146155Sphk{ 422185435Sbz uint32_t version; 423185435Sbz int error; 424185435Sbz struct jail j; 425185435Sbz 426185435Sbz error = copyin(uap->jail, &version, sizeof(uint32_t)); 427185435Sbz if (error) 428185435Sbz return (error); 429185435Sbz 430185435Sbz switch (version) { 431185435Sbz case 0: 432185435Sbz /* FreeBSD single IPv4 jails. */ 433185435Sbz { 434185435Sbz struct jail_v0 j0; 435185435Sbz 436185435Sbz bzero(&j, sizeof(struct jail)); 437185435Sbz error = copyin(uap->jail, &j0, sizeof(struct jail_v0)); 438185435Sbz if (error) 439185435Sbz return (error); 440185435Sbz j.version = j0.version; 441185435Sbz j.path = j0.path; 442185435Sbz j.hostname = j0.hostname; 443185435Sbz j.ip4s = j0.ip_number; 444185435Sbz break; 445185435Sbz } 446185435Sbz 447185435Sbz case 1: 448185435Sbz /* 449185435Sbz * Version 1 was used by multi-IPv4 jail implementations 450185435Sbz * that never made it into the official kernel. 451185435Sbz */ 452185435Sbz return (EINVAL); 453185435Sbz 454185435Sbz case 2: /* JAIL_API_VERSION */ 455185435Sbz /* FreeBSD multi-IPv4/IPv6,noIP jails. */ 456185435Sbz error = copyin(uap->jail, &j, sizeof(struct jail)); 457185435Sbz if (error) 458185435Sbz return (error); 459185435Sbz break; 460185435Sbz 461185435Sbz default: 462185435Sbz /* Sci-Fi jails are not supported, sorry. */ 463185435Sbz return (EINVAL); 464185435Sbz } 465185435Sbz return (kern_jail(td, &j)); 466185435Sbz} 467185435Sbz 468185435Sbzint 469185435Sbzkern_jail(struct thread *td, struct jail *j) 470185435Sbz{ 471113275Smike struct nameidata nd; 472179881Sdelphij struct prison *pr, *tpr; 473113275Smike struct jail_attach_args jaa; 474179881Sdelphij int vfslocked, error, tryprid; 47546155Sphk 476185435Sbz KASSERT(j != NULL, ("%s: j is NULL", __func__)); 477185435Sbz 478185435Sbz /* Handle addresses - convert old structs, copyin, check IPs. */ 479185435Sbz error = jail_handle_ips(j); 48046155Sphk if (error) 48184828Sjhb return (error); 48284828Sjhb 483185435Sbz /* Allocate struct prison and fill it with life. */ 484184205Sdes pr = malloc(sizeof(*pr), M_PRISON, M_WAITOK | M_ZERO); 48593818Sjhb mtx_init(&pr->pr_mtx, "jail mutex", NULL, MTX_DEF); 486113275Smike pr->pr_ref = 1; 487185435Sbz error = copyinstr(j->path, &pr->pr_path, sizeof(pr->pr_path), NULL); 488113275Smike if (error) 489113275Smike goto e_killmtx; 490150652Scsjp NDINIT(&nd, LOOKUP, MPSAFE | FOLLOW | LOCKLEAF, UIO_SYSSPACE, 491150652Scsjp pr->pr_path, td); 492113275Smike error = namei(&nd); 493150652Scsjp if (error) 494113275Smike goto e_killmtx; 495150652Scsjp vfslocked = NDHASGIANT(&nd); 496113275Smike pr->pr_root = nd.ni_vp; 497175294Sattilio VOP_UNLOCK(nd.ni_vp, 0); 498113275Smike NDFREE(&nd, NDF_ONLY_PNBUF); 499150652Scsjp VFS_UNLOCK_GIANT(vfslocked); 500185435Sbz error = copyinstr(j->hostname, &pr->pr_host, sizeof(pr->pr_host), NULL); 50184828Sjhb if (error) 502113275Smike goto e_dropvnref; 503185435Sbz if (j->jailname != NULL) { 504185435Sbz error = copyinstr(j->jailname, &pr->pr_name, 505185435Sbz sizeof(pr->pr_name), NULL); 506185435Sbz if (error) 507185435Sbz goto e_dropvnref; 508185435Sbz } 509185435Sbz if (j->ip4s > 0) { 510185435Sbz pr->pr_ip4 = j->ip4; 511185435Sbz pr->pr_ip4s = j->ip4s; 512185435Sbz } 513185435Sbz#ifdef INET6 514185435Sbz if (j->ip6s > 0) { 515185435Sbz pr->pr_ip6 = j->ip6; 516185435Sbz pr->pr_ip6s = j->ip6s; 517185435Sbz } 518185435Sbz#endif 519113275Smike pr->pr_linux = NULL; 520113275Smike pr->pr_securelevel = securelevel; 521185029Spjd bzero(&pr->pr_osd, sizeof(pr->pr_osd)); 522113275Smike 523185435Sbz /* 524185435Sbz * Pre-set prison state to ALIVE upon cration. This is needed so we 525185435Sbz * can later attach the process to it, etc (avoiding another extra 526185435Sbz * state for ther process of creation, complicating things). 527185435Sbz */ 528185435Sbz pr->pr_state = PRISON_STATE_ALIVE; 529185435Sbz 530185435Sbz /* Allocate a dedicated cpuset for each jail. */ 531185435Sbz error = cpuset_create_root(td, &pr->pr_cpuset); 532185435Sbz if (error) 533185435Sbz goto e_dropvnref; 534185435Sbz 535185435Sbz sx_xlock(&allprison_lock); 536185435Sbz /* Make sure we cannot run into problems with ambiguous bind()ings. */ 537185441Sbz#if defined(INET) || defined(INET6) 538185435Sbz error = prison_check_conflicting_ips(pr); 539185435Sbz if (error) { 540185435Sbz sx_xunlock(&allprison_lock); 541185435Sbz goto e_dropcpuset; 542185435Sbz } 543185441Sbz#endif 544185435Sbz 545179881Sdelphij /* Determine next pr_id and add prison to allprison list. */ 546179881Sdelphij tryprid = lastprid + 1; 547179881Sdelphij if (tryprid == JAIL_MAX) 548179881Sdelphij tryprid = 1; 549179881Sdelphijnext: 550179881Sdelphij LIST_FOREACH(tpr, &allprison, pr_list) { 551179881Sdelphij if (tpr->pr_id == tryprid) { 552179881Sdelphij tryprid++; 553179881Sdelphij if (tryprid == JAIL_MAX) { 554179881Sdelphij sx_xunlock(&allprison_lock); 555179881Sdelphij error = EAGAIN; 556185435Sbz goto e_dropcpuset; 557179881Sdelphij } 558179881Sdelphij goto next; 559179881Sdelphij } 560179881Sdelphij } 561179881Sdelphij pr->pr_id = jaa.jid = lastprid = tryprid; 562113275Smike LIST_INSERT_HEAD(&allprison, pr, pr_list); 563113275Smike prisoncount++; 564185029Spjd sx_xunlock(&allprison_lock); 565113275Smike 566113275Smike error = jail_attach(td, &jaa); 567113275Smike if (error) 568113275Smike goto e_dropprref; 569113275Smike mtx_lock(&pr->pr_mtx); 570113275Smike pr->pr_ref--; 571113275Smike mtx_unlock(&pr->pr_mtx); 572113275Smike td->td_retval[0] = jaa.jid; 573113275Smike return (0); 574113275Smikee_dropprref: 575168401Spjd sx_xlock(&allprison_lock); 576113275Smike LIST_REMOVE(pr, pr_list); 577113275Smike prisoncount--; 578185029Spjd sx_xunlock(&allprison_lock); 579185435Sbze_dropcpuset: 580185435Sbz cpuset_rel(pr->pr_cpuset); 581113275Smikee_dropvnref: 582150652Scsjp vfslocked = VFS_LOCK_GIANT(pr->pr_root->v_mount); 583113275Smike vrele(pr->pr_root); 584150652Scsjp VFS_UNLOCK_GIANT(vfslocked); 585113275Smikee_killmtx: 586113275Smike mtx_destroy(&pr->pr_mtx); 587184205Sdes free(pr, M_PRISON); 588185435Sbz#ifdef INET6 589185435Sbz free(j->ip6, M_PRISON); 590185435Sbz#endif 591185435Sbz#ifdef INET 592185435Sbz free(j->ip4, M_PRISON); 593185435Sbz#endif 594113275Smike return (error); 595113275Smike} 596113275Smike 597113275Smike/* 598114168Smike * struct jail_attach_args { 599114168Smike * int jid; 600114168Smike * }; 601113275Smike */ 602113275Smikeint 603114168Smikejail_attach(struct thread *td, struct jail_attach_args *uap) 604113275Smike{ 605113275Smike struct proc *p; 606113275Smike struct ucred *newcred, *oldcred; 607113275Smike struct prison *pr; 608150652Scsjp int vfslocked, error; 609167309Spjd 610126023Snectar /* 611126023Snectar * XXX: Note that there is a slight race here if two threads 612126023Snectar * in the same privileged process attempt to attach to two 613126023Snectar * different jails at the same time. It is important for 614126023Snectar * user processes not to do this, or they might end up with 615126023Snectar * a process root from one prison, but attached to the jail 616126023Snectar * of another. 617126023Snectar */ 618164032Srwatson error = priv_check(td, PRIV_JAIL_ATTACH); 619126023Snectar if (error) 620126023Snectar return (error); 621126023Snectar 622113275Smike p = td->td_proc; 623168401Spjd sx_slock(&allprison_lock); 624113275Smike pr = prison_find(uap->jid); 625113275Smike if (pr == NULL) { 626168401Spjd sx_sunlock(&allprison_lock); 627113275Smike return (EINVAL); 628113275Smike } 629185435Sbz 630185435Sbz /* 631185435Sbz * Do not allow a process to attach to a prison that is not 632185435Sbz * considered to be "ALIVE". 633185435Sbz */ 634185435Sbz if (pr->pr_state != PRISON_STATE_ALIVE) { 635185435Sbz mtx_unlock(&pr->pr_mtx); 636185435Sbz sx_sunlock(&allprison_lock); 637185435Sbz return (EINVAL); 638185435Sbz } 639113275Smike pr->pr_ref++; 640113275Smike mtx_unlock(&pr->pr_mtx); 641168401Spjd sx_sunlock(&allprison_lock); 642113275Smike 643185435Sbz /* 644185435Sbz * Reparent the newly attached process to this jail. 645185435Sbz */ 646185435Sbz error = cpuset_setproc_update_set(p, pr->pr_cpuset); 647185435Sbz if (error) 648185435Sbz goto e_unref; 649185435Sbz 650150652Scsjp vfslocked = VFS_LOCK_GIANT(pr->pr_root->v_mount); 651175202Sattilio vn_lock(pr->pr_root, LK_EXCLUSIVE | LK_RETRY); 652113275Smike if ((error = change_dir(pr->pr_root, td)) != 0) 653113275Smike goto e_unlock; 654113275Smike#ifdef MAC 655172930Srwatson if ((error = mac_vnode_check_chroot(td->td_ucred, pr->pr_root))) 656113275Smike goto e_unlock; 657113275Smike#endif 658175294Sattilio VOP_UNLOCK(pr->pr_root, 0); 659113275Smike change_root(pr->pr_root, td); 660150652Scsjp VFS_UNLOCK_GIANT(vfslocked); 661113275Smike 66284828Sjhb newcred = crget(); 66384828Sjhb PROC_LOCK(p); 66484828Sjhb oldcred = p->p_ucred; 665113275Smike setsugid(p); 66684828Sjhb crcopy(newcred, oldcred); 667113630Sjhb newcred->cr_prison = pr; 66884828Sjhb p->p_ucred = newcred; 669185435Sbz prison_proc_hold(pr); 67084828Sjhb PROC_UNLOCK(p); 67184828Sjhb crfree(oldcred); 67246155Sphk return (0); 673113275Smikee_unlock: 674175294Sattilio VOP_UNLOCK(pr->pr_root, 0); 675150652Scsjp VFS_UNLOCK_GIANT(vfslocked); 676185435Sbze_unref: 677113275Smike mtx_lock(&pr->pr_mtx); 678113275Smike pr->pr_ref--; 679113275Smike mtx_unlock(&pr->pr_mtx); 68046155Sphk return (error); 68146155Sphk} 68246155Sphk 683113275Smike/* 684113275Smike * Returns a locked prison instance, or NULL on failure. 685113275Smike */ 686168399Spjdstruct prison * 687113275Smikeprison_find(int prid) 688113275Smike{ 689113275Smike struct prison *pr; 690113275Smike 691168401Spjd sx_assert(&allprison_lock, SX_LOCKED); 692113275Smike LIST_FOREACH(pr, &allprison, pr_list) { 693113275Smike if (pr->pr_id == prid) { 694113275Smike mtx_lock(&pr->pr_mtx); 695168489Spjd if (pr->pr_ref == 0) { 696168489Spjd mtx_unlock(&pr->pr_mtx); 697168489Spjd break; 698168489Spjd } 699113275Smike return (pr); 700113275Smike } 701113275Smike } 702113275Smike return (NULL); 703113275Smike} 704113275Smike 70572786Srwatsonvoid 706185029Spjdprison_free_locked(struct prison *pr) 70772786Srwatson{ 70872786Srwatson 709185029Spjd mtx_assert(&pr->pr_mtx, MA_OWNED); 71072786Srwatson pr->pr_ref--; 71172786Srwatson if (pr->pr_ref == 0) { 712168483Spjd mtx_unlock(&pr->pr_mtx); 713124882Srwatson TASK_INIT(&pr->pr_task, 0, prison_complete, pr); 714144660Sjeff taskqueue_enqueue(taskqueue_thread, &pr->pr_task); 71587275Srwatson return; 71672786Srwatson } 71787275Srwatson mtx_unlock(&pr->pr_mtx); 71872786Srwatson} 71972786Srwatson 720185029Spjdvoid 721185029Spjdprison_free(struct prison *pr) 722185029Spjd{ 723185029Spjd 724185029Spjd mtx_lock(&pr->pr_mtx); 725185029Spjd prison_free_locked(pr); 726185029Spjd} 727185029Spjd 728124882Srwatsonstatic void 729124882Srwatsonprison_complete(void *context, int pending) 730124882Srwatson{ 731124882Srwatson struct prison *pr; 732150652Scsjp int vfslocked; 733124882Srwatson 734124882Srwatson pr = (struct prison *)context; 735124882Srwatson 736168489Spjd sx_xlock(&allprison_lock); 737168489Spjd LIST_REMOVE(pr, pr_list); 738168489Spjd prisoncount--; 739185029Spjd sx_xunlock(&allprison_lock); 740168489Spjd 741185435Sbz cpuset_rel(pr->pr_cpuset); 742185435Sbz 743185029Spjd /* Free all OSD associated to this jail. */ 744185029Spjd osd_jail_exit(pr); 745185029Spjd 746150652Scsjp vfslocked = VFS_LOCK_GIANT(pr->pr_root->v_mount); 747124882Srwatson vrele(pr->pr_root); 748150652Scsjp VFS_UNLOCK_GIANT(vfslocked); 749124882Srwatson 750124882Srwatson mtx_destroy(&pr->pr_mtx); 751185435Sbz free(pr->pr_linux, M_PRISON); 752185435Sbz#ifdef INET6 753185435Sbz free(pr->pr_ip6, M_PRISON); 754185435Sbz#endif 755185435Sbz#ifdef INET 756185435Sbz free(pr->pr_ip4, M_PRISON); 757185435Sbz#endif 758184205Sdes free(pr, M_PRISON); 759124882Srwatson} 760124882Srwatson 76172786Srwatsonvoid 762185029Spjdprison_hold_locked(struct prison *pr) 76372786Srwatson{ 76472786Srwatson 765185029Spjd mtx_assert(&pr->pr_mtx, MA_OWNED); 766168489Spjd KASSERT(pr->pr_ref > 0, 767168489Spjd ("Trying to hold dead prison (id=%d).", pr->pr_id)); 76872786Srwatson pr->pr_ref++; 769185029Spjd} 770185029Spjd 771185029Spjdvoid 772185029Spjdprison_hold(struct prison *pr) 773185029Spjd{ 774185029Spjd 775185029Spjd mtx_lock(&pr->pr_mtx); 776185029Spjd prison_hold_locked(pr); 77787275Srwatson mtx_unlock(&pr->pr_mtx); 77872786Srwatson} 77972786Srwatson 780185435Sbzvoid 781185435Sbzprison_proc_hold(struct prison *pr) 78287275Srwatson{ 78387275Srwatson 784185435Sbz mtx_lock(&pr->pr_mtx); 785185435Sbz KASSERT(pr->pr_state == PRISON_STATE_ALIVE, 786185435Sbz ("Cannot add a process to a non-alive prison (id=%d).", pr->pr_id)); 787185435Sbz pr->pr_nprocs++; 788185435Sbz mtx_unlock(&pr->pr_mtx); 78987275Srwatson} 79087275Srwatson 791185435Sbzvoid 792185435Sbzprison_proc_free(struct prison *pr) 793185435Sbz{ 794185435Sbz 795185435Sbz mtx_lock(&pr->pr_mtx); 796185435Sbz KASSERT(pr->pr_state == PRISON_STATE_ALIVE && pr->pr_nprocs > 0, 797185435Sbz ("Trying to kill a process in a dead prison (id=%d).", pr->pr_id)); 798185435Sbz pr->pr_nprocs--; 799185435Sbz if (pr->pr_nprocs == 0) 800185435Sbz pr->pr_state = PRISON_STATE_DYING; 801185435Sbz mtx_unlock(&pr->pr_mtx); 802185435Sbz} 803185435Sbz 804185435Sbz 805185435Sbz#ifdef INET 806185435Sbz/* 807185435Sbz * Pass back primary IPv4 address of this jail. 808185435Sbz * 809185435Sbz * If not jailed return success but do not alter the address. Caller has to 810185435Sbz * make sure to intialize it correctly (INADDR_ANY). 811185435Sbz * 812185435Sbz * Returns 0 on success, 1 on error. Address returned in NBO. 813185435Sbz */ 81446155Sphkint 815187684Sbzprison_get_ip4(struct ucred *cred, struct in_addr *ia) 81646155Sphk{ 81746155Sphk 818185435Sbz KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 819185435Sbz KASSERT(ia != NULL, ("%s: ia is NULL", __func__)); 820185435Sbz 82172786Srwatson if (!jailed(cred)) 822185435Sbz /* Do not change address passed in. */ 82346155Sphk return (0); 824185435Sbz 825185435Sbz if (cred->cr_prison->pr_ip4 == NULL) 826185435Sbz return (1); 827185435Sbz 828185435Sbz ia->s_addr = cred->cr_prison->pr_ip4[0].s_addr; 829185435Sbz return (0); 830185435Sbz} 831185435Sbz 832185435Sbz/* 833185435Sbz * Make sure our (source) address is set to something meaningful to this 834185435Sbz * jail. 835185435Sbz * 836185435Sbz * Returns 0 on success, 1 on error. Address passed in in NBO and returned 837185435Sbz * in NBO. 838185435Sbz */ 839185435Sbzint 840185435Sbzprison_local_ip4(struct ucred *cred, struct in_addr *ia) 841185435Sbz{ 842185435Sbz struct in_addr ia0; 843185435Sbz 844185435Sbz KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 845185435Sbz KASSERT(ia != NULL, ("%s: ia is NULL", __func__)); 846185435Sbz 847185435Sbz if (!jailed(cred)) 84846155Sphk return (0); 849185435Sbz if (cred->cr_prison->pr_ip4 == NULL) 850185435Sbz return (1); 851185435Sbz 852185435Sbz ia0.s_addr = ntohl(ia->s_addr); 853185435Sbz if (ia0.s_addr == INADDR_LOOPBACK) { 854185435Sbz ia->s_addr = cred->cr_prison->pr_ip4[0].s_addr; 855185435Sbz return (0); 85646155Sphk } 857185435Sbz 858185435Sbz /* 859185435Sbz * In case there is only 1 IPv4 address, bind directly. 860185435Sbz */ 861185435Sbz if (ia0.s_addr == INADDR_ANY && cred->cr_prison->pr_ip4s == 1) { 862185435Sbz ia->s_addr = cred->cr_prison->pr_ip4[0].s_addr; 863185435Sbz return (0); 864185435Sbz } 865185435Sbz 866185435Sbz if (ia0.s_addr == INADDR_ANY || prison_check_ip4(cred, ia)) 867185435Sbz return (0); 868185435Sbz 869185435Sbz return (1); 870185435Sbz} 871185435Sbz 872185435Sbz/* 873185435Sbz * Rewrite destination address in case we will connect to loopback address. 874185435Sbz * 875185435Sbz * Returns 0 on success, 1 on error. Address passed in in NBO and returned 876185435Sbz * in NBO. 877185435Sbz */ 878185435Sbzint 879185435Sbzprison_remote_ip4(struct ucred *cred, struct in_addr *ia) 880185435Sbz{ 881185435Sbz 882185435Sbz KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 883185435Sbz KASSERT(ia != NULL, ("%s: ia is NULL", __func__)); 884185435Sbz 885185435Sbz if (!jailed(cred)) 886185435Sbz return (0); 887185435Sbz if (cred->cr_prison->pr_ip4 == NULL) 888185435Sbz return (1); 889185435Sbz if (ntohl(ia->s_addr) == INADDR_LOOPBACK) { 890185435Sbz ia->s_addr = cred->cr_prison->pr_ip4[0].s_addr; 891185435Sbz return (0); 892185435Sbz } 893185435Sbz 894185435Sbz /* 895185435Sbz * Return success because nothing had to be changed. 896185435Sbz */ 897185435Sbz return (0); 898185435Sbz} 899185435Sbz 900185435Sbz/* 901185435Sbz * Check if given address belongs to the jail referenced by cred. 902185435Sbz * 903185435Sbz * Returns 1 if address belongs to jail, 0 if not. Address passed in in NBO. 904185435Sbz */ 905185435Sbzstatic int 906185435Sbz_prison_check_ip4(struct prison *pr, struct in_addr *ia) 907185435Sbz{ 908185435Sbz int i, a, z, d; 909185435Sbz 910185435Sbz if (pr->pr_ip4 == NULL) 911185435Sbz return (0); 912185435Sbz 913185435Sbz /* 914185435Sbz * Check the primary IP. 915185435Sbz */ 916185435Sbz if (pr->pr_ip4[0].s_addr == ia->s_addr) 917185435Sbz return (1); 918185435Sbz 919185435Sbz /* 920185435Sbz * All the other IPs are sorted so we can do a binary search. 921185435Sbz */ 922185435Sbz a = 0; 923185435Sbz z = pr->pr_ip4s - 2; 924185435Sbz while (a <= z) { 925185435Sbz i = (a + z) / 2; 926185435Sbz d = qcmp_v4(&pr->pr_ip4[i+1], ia); 927185435Sbz if (d > 0) 928185435Sbz z = i - 1; 929185435Sbz else if (d < 0) 930185435Sbz a = i + 1; 93181114Srwatson else 932185435Sbz return (1); 933185435Sbz } 934185435Sbz return (0); 935185435Sbz} 936185435Sbz 937185435Sbzint 938185435Sbzprison_check_ip4(struct ucred *cred, struct in_addr *ia) 939185435Sbz{ 940185435Sbz 941185435Sbz KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 942185435Sbz KASSERT(ia != NULL, ("%s: ia is NULL", __func__)); 943185435Sbz 944185435Sbz if (!jailed(cred)) 945185435Sbz return (1); 946185435Sbz 947185435Sbz return (_prison_check_ip4(cred->cr_prison, ia)); 948185435Sbz} 949185435Sbz#endif 950185435Sbz 951185435Sbz#ifdef INET6 952185435Sbz/* 953185435Sbz * Pass back primary IPv6 address for this jail. 954185435Sbz * 955185435Sbz * If not jailed return success but do not alter the address. Caller has to 956185435Sbz * make sure to intialize it correctly (IN6ADDR_ANY_INIT). 957185435Sbz * 958185435Sbz * Returns 0 on success, 1 on error. 959185435Sbz */ 960185435Sbzint 961187684Sbzprison_get_ip6(struct ucred *cred, struct in6_addr *ia6) 962185435Sbz{ 963185435Sbz 964185435Sbz KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 965185435Sbz KASSERT(ia6 != NULL, ("%s: ia6 is NULL", __func__)); 966185435Sbz 967185435Sbz if (!jailed(cred)) 96881114Srwatson return (0); 969185435Sbz if (cred->cr_prison->pr_ip6 == NULL) 970185435Sbz return (1); 971185435Sbz bcopy(&cred->cr_prison->pr_ip6[0], ia6, sizeof(struct in6_addr)); 972185435Sbz return (0); 973185435Sbz} 974185435Sbz 975185435Sbz/* 976185435Sbz * Make sure our (source) address is set to something meaningful to this jail. 977185435Sbz * 978185435Sbz * v6only should be set based on (inp->inp_flags & IN6P_IPV6_V6ONLY != 0) 979185435Sbz * when needed while binding. 980185435Sbz * 981185435Sbz * Returns 0 on success, 1 on error. 982185435Sbz */ 983185435Sbzint 984185435Sbzprison_local_ip6(struct ucred *cred, struct in6_addr *ia6, int v6only) 985185435Sbz{ 986185435Sbz 987185435Sbz KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 988185435Sbz KASSERT(ia6 != NULL, ("%s: ia6 is NULL", __func__)); 989185435Sbz 990185435Sbz if (!jailed(cred)) 991185435Sbz return (0); 992185435Sbz if (cred->cr_prison->pr_ip6 == NULL) 993185435Sbz return (1); 994185435Sbz if (IN6_IS_ADDR_LOOPBACK(ia6)) { 995185435Sbz bcopy(&cred->cr_prison->pr_ip6[0], ia6, 996185435Sbz sizeof(struct in6_addr)); 997185435Sbz return (0); 99881114Srwatson } 999185435Sbz 1000185435Sbz /* 1001185435Sbz * In case there is only 1 IPv6 address, and v6only is true, then 1002185435Sbz * bind directly. 1003185435Sbz */ 1004185435Sbz if (v6only != 0 && IN6_IS_ADDR_UNSPECIFIED(ia6) && 1005185435Sbz cred->cr_prison->pr_ip6s == 1) { 1006185435Sbz bcopy(&cred->cr_prison->pr_ip6[0], ia6, 1007185435Sbz sizeof(struct in6_addr)); 1008185435Sbz return (0); 1009185435Sbz } 1010185435Sbz if (IN6_IS_ADDR_UNSPECIFIED(ia6) || prison_check_ip6(cred, ia6)) 1011185435Sbz return (0); 1012185435Sbz return (1); 1013185435Sbz} 1014185435Sbz 1015185435Sbz/* 1016185435Sbz * Rewrite destination address in case we will connect to loopback address. 1017185435Sbz * 1018185435Sbz * Returns 0 on success, 1 on error. 1019185435Sbz */ 1020185435Sbzint 1021185435Sbzprison_remote_ip6(struct ucred *cred, struct in6_addr *ia6) 1022185435Sbz{ 1023185435Sbz 1024185435Sbz KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 1025185435Sbz KASSERT(ia6 != NULL, ("%s: ia6 is NULL", __func__)); 1026185435Sbz 1027185435Sbz if (!jailed(cred)) 1028185435Sbz return (0); 1029185435Sbz if (cred->cr_prison->pr_ip6 == NULL) 103046155Sphk return (1); 1031185435Sbz if (IN6_IS_ADDR_LOOPBACK(ia6)) { 1032185435Sbz bcopy(&cred->cr_prison->pr_ip6[0], ia6, 1033185435Sbz sizeof(struct in6_addr)); 1034185435Sbz return (0); 1035185435Sbz } 1036185435Sbz 1037185435Sbz /* 1038185435Sbz * Return success because nothing had to be changed. 1039185435Sbz */ 104046155Sphk return (0); 104146155Sphk} 104246155Sphk 1043185435Sbz/* 1044185435Sbz * Check if given address belongs to the jail referenced by cred. 1045185435Sbz * 1046185435Sbz * Returns 1 if address belongs to jail, 0 if not. 1047185435Sbz */ 1048185435Sbzstatic int 1049185435Sbz_prison_check_ip6(struct prison *pr, struct in6_addr *ia6) 105046155Sphk{ 1051185435Sbz int i, a, z, d; 105246155Sphk 1053185435Sbz if (pr->pr_ip6 == NULL) 1054185435Sbz return (0); 1055185435Sbz 1056185435Sbz /* 1057185435Sbz * Check the primary IP. 1058185435Sbz */ 1059185435Sbz if (IN6_ARE_ADDR_EQUAL(&pr->pr_ip6[0], ia6)) 1060185435Sbz return (1); 1061185435Sbz 1062185435Sbz /* 1063185435Sbz * All the other IPs are sorted so we can do a binary search. 1064185435Sbz */ 1065185435Sbz a = 0; 1066185435Sbz z = pr->pr_ip6s - 2; 1067185435Sbz while (a <= z) { 1068185435Sbz i = (a + z) / 2; 1069185435Sbz d = qcmp_v6(&pr->pr_ip6[i+1], ia6); 1070185435Sbz if (d > 0) 1071185435Sbz z = i - 1; 1072185435Sbz else if (d < 0) 1073185435Sbz a = i + 1; 107446155Sphk else 1075185435Sbz return (1); 107646155Sphk } 1077185435Sbz return (0); 107846155Sphk} 107946155Sphk 108046155Sphkint 1081185435Sbzprison_check_ip6(struct ucred *cred, struct in6_addr *ia6) 1082185435Sbz{ 1083185435Sbz 1084185435Sbz KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 1085185435Sbz KASSERT(ia6 != NULL, ("%s: ia6 is NULL", __func__)); 1086185435Sbz 1087185435Sbz if (!jailed(cred)) 1088185435Sbz return (1); 1089185435Sbz 1090185435Sbz return (_prison_check_ip6(cred->cr_prison, ia6)); 1091185435Sbz} 1092185435Sbz#endif 1093185435Sbz 1094185435Sbz/* 1095185435Sbz * Check if given address belongs to the jail referenced by cred (wrapper to 1096185435Sbz * prison_check_ip[46]). 1097185435Sbz * 1098185435Sbz * Returns 1 if address belongs to jail, 0 if not. IPv4 Address passed in in 1099185435Sbz * NBO. 1100185435Sbz */ 1101185435Sbzint 110272786Srwatsonprison_if(struct ucred *cred, struct sockaddr *sa) 110346155Sphk{ 1104185435Sbz#ifdef INET 1105114168Smike struct sockaddr_in *sai; 1106185435Sbz#endif 1107185435Sbz#ifdef INET6 1108185435Sbz struct sockaddr_in6 *sai6; 1109185435Sbz#endif 111046155Sphk int ok; 111146155Sphk 1112185435Sbz KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 1113185435Sbz KASSERT(sa != NULL, ("%s: sa is NULL", __func__)); 1114185435Sbz 1115185435Sbz ok = 0; 1116185435Sbz switch(sa->sa_family) 1117185435Sbz { 1118185435Sbz#ifdef INET 1119185435Sbz case AF_INET: 1120185435Sbz sai = (struct sockaddr_in *)sa; 1121185435Sbz if (prison_check_ip4(cred, &sai->sin_addr)) 1122185435Sbz ok = 1; 1123185435Sbz break; 1124185435Sbz 1125185435Sbz#endif 1126185435Sbz#ifdef INET6 1127185435Sbz case AF_INET6: 1128185435Sbz sai6 = (struct sockaddr_in6 *)sa; 1129185435Sbz if (prison_check_ip6(cred, (struct in6_addr *)&sai6->sin6_addr)) 1130185435Sbz ok = 1; 1131185435Sbz break; 1132185435Sbz 1133185435Sbz#endif 1134185435Sbz default: 1135185435Sbz if (!jail_socket_unixiproute_only) 1136185435Sbz ok = 1; 1137185435Sbz } 113846155Sphk return (ok); 113946155Sphk} 114072786Srwatson 114172786Srwatson/* 114272786Srwatson * Return 0 if jails permit p1 to frob p2, otherwise ESRCH. 114372786Srwatson */ 114472786Srwatsonint 1145114168Smikeprison_check(struct ucred *cred1, struct ucred *cred2) 114672786Srwatson{ 114772786Srwatson 114872786Srwatson if (jailed(cred1)) { 114972786Srwatson if (!jailed(cred2)) 115072786Srwatson return (ESRCH); 115172786Srwatson if (cred2->cr_prison != cred1->cr_prison) 115272786Srwatson return (ESRCH); 115372786Srwatson } 115472786Srwatson 115572786Srwatson return (0); 115672786Srwatson} 115772786Srwatson 115872786Srwatson/* 115972786Srwatson * Return 1 if the passed credential is in a jail, otherwise 0. 116072786Srwatson */ 116172786Srwatsonint 1162114168Smikejailed(struct ucred *cred) 116372786Srwatson{ 116472786Srwatson 116572786Srwatson return (cred->cr_prison != NULL); 116672786Srwatson} 116791384Srobert 116891384Srobert/* 116991384Srobert * Return the correct hostname for the passed credential. 117091384Srobert */ 117191391Srobertvoid 1172114168Smikegetcredhostname(struct ucred *cred, char *buf, size_t size) 117391384Srobert{ 1174183550Szec INIT_VPROCG(cred->cr_vimage->v_procg); 117591384Srobert 117691391Srobert if (jailed(cred)) { 117791391Srobert mtx_lock(&cred->cr_prison->pr_mtx); 1178105354Srobert strlcpy(buf, cred->cr_prison->pr_host, size); 117991391Srobert mtx_unlock(&cred->cr_prison->pr_mtx); 1180180291Srwatson } else { 1181180291Srwatson mtx_lock(&hostname_mtx); 1182181803Sbz strlcpy(buf, V_hostname, size); 1183180291Srwatson mtx_unlock(&hostname_mtx); 1184180291Srwatson } 118591384Srobert} 1186113275Smike 1187125804Srwatson/* 1188147185Spjd * Determine whether the subject represented by cred can "see" 1189147185Spjd * status of a mount point. 1190147185Spjd * Returns: 0 for permitted, ENOENT otherwise. 1191147185Spjd * XXX: This function should be called cr_canseemount() and should be 1192147185Spjd * placed in kern_prot.c. 1193125804Srwatson */ 1194125804Srwatsonint 1195147185Spjdprison_canseemount(struct ucred *cred, struct mount *mp) 1196125804Srwatson{ 1197147185Spjd struct prison *pr; 1198147185Spjd struct statfs *sp; 1199147185Spjd size_t len; 1200125804Srwatson 1201147185Spjd if (!jailed(cred) || jail_enforce_statfs == 0) 1202147185Spjd return (0); 1203147185Spjd pr = cred->cr_prison; 1204147185Spjd if (pr->pr_root->v_mount == mp) 1205147185Spjd return (0); 1206147185Spjd if (jail_enforce_statfs == 2) 1207147185Spjd return (ENOENT); 1208147185Spjd /* 1209147185Spjd * If jail's chroot directory is set to "/" we should be able to see 1210147185Spjd * all mount-points from inside a jail. 1211147185Spjd * This is ugly check, but this is the only situation when jail's 1212147185Spjd * directory ends with '/'. 1213147185Spjd */ 1214147185Spjd if (strcmp(pr->pr_path, "/") == 0) 1215147185Spjd return (0); 1216147185Spjd len = strlen(pr->pr_path); 1217147185Spjd sp = &mp->mnt_stat; 1218147185Spjd if (strncmp(pr->pr_path, sp->f_mntonname, len) != 0) 1219147185Spjd return (ENOENT); 1220147185Spjd /* 1221147185Spjd * Be sure that we don't have situation where jail's root directory 1222147185Spjd * is "/some/path" and mount point is "/some/pathpath". 1223147185Spjd */ 1224147185Spjd if (sp->f_mntonname[len] != '\0' && sp->f_mntonname[len] != '/') 1225147185Spjd return (ENOENT); 1226147185Spjd return (0); 1227147185Spjd} 1228147185Spjd 1229147185Spjdvoid 1230147185Spjdprison_enforce_statfs(struct ucred *cred, struct mount *mp, struct statfs *sp) 1231147185Spjd{ 1232147185Spjd char jpath[MAXPATHLEN]; 1233147185Spjd struct prison *pr; 1234147185Spjd size_t len; 1235147185Spjd 1236147185Spjd if (!jailed(cred) || jail_enforce_statfs == 0) 1237147185Spjd return; 1238147185Spjd pr = cred->cr_prison; 1239147185Spjd if (prison_canseemount(cred, mp) != 0) { 1240147185Spjd bzero(sp->f_mntonname, sizeof(sp->f_mntonname)); 1241147185Spjd strlcpy(sp->f_mntonname, "[restricted]", 1242147185Spjd sizeof(sp->f_mntonname)); 1243147185Spjd return; 1244125804Srwatson } 1245147185Spjd if (pr->pr_root->v_mount == mp) { 1246147185Spjd /* 1247147185Spjd * Clear current buffer data, so we are sure nothing from 1248147185Spjd * the valid path left there. 1249147185Spjd */ 1250147185Spjd bzero(sp->f_mntonname, sizeof(sp->f_mntonname)); 1251147185Spjd *sp->f_mntonname = '/'; 1252147185Spjd return; 1253147185Spjd } 1254147185Spjd /* 1255147185Spjd * If jail's chroot directory is set to "/" we should be able to see 1256147185Spjd * all mount-points from inside a jail. 1257147185Spjd */ 1258147185Spjd if (strcmp(pr->pr_path, "/") == 0) 1259147185Spjd return; 1260147185Spjd len = strlen(pr->pr_path); 1261147185Spjd strlcpy(jpath, sp->f_mntonname + len, sizeof(jpath)); 1262147185Spjd /* 1263147185Spjd * Clear current buffer data, so we are sure nothing from 1264147185Spjd * the valid path left there. 1265147185Spjd */ 1266147185Spjd bzero(sp->f_mntonname, sizeof(sp->f_mntonname)); 1267147185Spjd if (*jpath == '\0') { 1268147185Spjd /* Should never happen. */ 1269147185Spjd *sp->f_mntonname = '/'; 1270147185Spjd } else { 1271147185Spjd strlcpy(sp->f_mntonname, jpath, sizeof(sp->f_mntonname)); 1272147185Spjd } 1273125804Srwatson} 1274125804Srwatson 1275164032Srwatson/* 1276164032Srwatson * Check with permission for a specific privilege is granted within jail. We 1277164032Srwatson * have a specific list of accepted privileges; the rest are denied. 1278164032Srwatson */ 1279164032Srwatsonint 1280164032Srwatsonprison_priv_check(struct ucred *cred, int priv) 1281164032Srwatson{ 1282164032Srwatson 1283164032Srwatson if (!jailed(cred)) 1284164032Srwatson return (0); 1285164032Srwatson 1286164032Srwatson switch (priv) { 1287164032Srwatson 1288164032Srwatson /* 1289164032Srwatson * Allow ktrace privileges for root in jail. 1290164032Srwatson */ 1291164032Srwatson case PRIV_KTRACE: 1292164032Srwatson 1293166827Srwatson#if 0 1294164032Srwatson /* 1295164032Srwatson * Allow jailed processes to configure audit identity and 1296164032Srwatson * submit audit records (login, etc). In the future we may 1297164032Srwatson * want to further refine the relationship between audit and 1298164032Srwatson * jail. 1299164032Srwatson */ 1300164032Srwatson case PRIV_AUDIT_GETAUDIT: 1301164032Srwatson case PRIV_AUDIT_SETAUDIT: 1302164032Srwatson case PRIV_AUDIT_SUBMIT: 1303166827Srwatson#endif 1304164032Srwatson 1305164032Srwatson /* 1306164032Srwatson * Allow jailed processes to manipulate process UNIX 1307164032Srwatson * credentials in any way they see fit. 1308164032Srwatson */ 1309164032Srwatson case PRIV_CRED_SETUID: 1310164032Srwatson case PRIV_CRED_SETEUID: 1311164032Srwatson case PRIV_CRED_SETGID: 1312164032Srwatson case PRIV_CRED_SETEGID: 1313164032Srwatson case PRIV_CRED_SETGROUPS: 1314164032Srwatson case PRIV_CRED_SETREUID: 1315164032Srwatson case PRIV_CRED_SETREGID: 1316164032Srwatson case PRIV_CRED_SETRESUID: 1317164032Srwatson case PRIV_CRED_SETRESGID: 1318164032Srwatson 1319164032Srwatson /* 1320164032Srwatson * Jail implements visibility constraints already, so allow 1321164032Srwatson * jailed root to override uid/gid-based constraints. 1322164032Srwatson */ 1323164032Srwatson case PRIV_SEEOTHERGIDS: 1324164032Srwatson case PRIV_SEEOTHERUIDS: 1325164032Srwatson 1326164032Srwatson /* 1327164032Srwatson * Jail implements inter-process debugging limits already, so 1328164032Srwatson * allow jailed root various debugging privileges. 1329164032Srwatson */ 1330164032Srwatson case PRIV_DEBUG_DIFFCRED: 1331164032Srwatson case PRIV_DEBUG_SUGID: 1332164032Srwatson case PRIV_DEBUG_UNPRIV: 1333164032Srwatson 1334164032Srwatson /* 1335164032Srwatson * Allow jail to set various resource limits and login 1336164032Srwatson * properties, and for now, exceed process resource limits. 1337164032Srwatson */ 1338164032Srwatson case PRIV_PROC_LIMIT: 1339164032Srwatson case PRIV_PROC_SETLOGIN: 1340164032Srwatson case PRIV_PROC_SETRLIMIT: 1341164032Srwatson 1342164032Srwatson /* 1343164032Srwatson * System V and POSIX IPC privileges are granted in jail. 1344164032Srwatson */ 1345164032Srwatson case PRIV_IPC_READ: 1346164032Srwatson case PRIV_IPC_WRITE: 1347164032Srwatson case PRIV_IPC_ADMIN: 1348164032Srwatson case PRIV_IPC_MSGSIZE: 1349164032Srwatson case PRIV_MQ_ADMIN: 1350164032Srwatson 1351164032Srwatson /* 1352164032Srwatson * Jail implements its own inter-process limits, so allow 1353164032Srwatson * root processes in jail to change scheduling on other 1354164032Srwatson * processes in the same jail. Likewise for signalling. 1355164032Srwatson */ 1356164032Srwatson case PRIV_SCHED_DIFFCRED: 1357185435Sbz case PRIV_SCHED_CPUSET: 1358164032Srwatson case PRIV_SIGNAL_DIFFCRED: 1359164032Srwatson case PRIV_SIGNAL_SUGID: 1360164032Srwatson 1361164032Srwatson /* 1362164032Srwatson * Allow jailed processes to write to sysctls marked as jail 1363164032Srwatson * writable. 1364164032Srwatson */ 1365164032Srwatson case PRIV_SYSCTL_WRITEJAIL: 1366164032Srwatson 1367164032Srwatson /* 1368164032Srwatson * Allow root in jail to manage a variety of quota 1369166831Srwatson * properties. These should likely be conditional on a 1370166831Srwatson * configuration option. 1371164032Srwatson */ 1372166832Srwatson case PRIV_VFS_GETQUOTA: 1373166832Srwatson case PRIV_VFS_SETQUOTA: 1374164032Srwatson 1375164032Srwatson /* 1376164032Srwatson * Since Jail relies on chroot() to implement file system 1377164032Srwatson * protections, grant many VFS privileges to root in jail. 1378164032Srwatson * Be careful to exclude mount-related and NFS-related 1379164032Srwatson * privileges. 1380164032Srwatson */ 1381164032Srwatson case PRIV_VFS_READ: 1382164032Srwatson case PRIV_VFS_WRITE: 1383164032Srwatson case PRIV_VFS_ADMIN: 1384164032Srwatson case PRIV_VFS_EXEC: 1385164032Srwatson case PRIV_VFS_LOOKUP: 1386164032Srwatson case PRIV_VFS_BLOCKRESERVE: /* XXXRW: Slightly surprising. */ 1387164032Srwatson case PRIV_VFS_CHFLAGS_DEV: 1388164032Srwatson case PRIV_VFS_CHOWN: 1389164032Srwatson case PRIV_VFS_CHROOT: 1390167152Spjd case PRIV_VFS_RETAINSUGID: 1391164032Srwatson case PRIV_VFS_FCHROOT: 1392164032Srwatson case PRIV_VFS_LINK: 1393164032Srwatson case PRIV_VFS_SETGID: 1394172860Srwatson case PRIV_VFS_STAT: 1395164032Srwatson case PRIV_VFS_STICKYFILE: 1396164032Srwatson return (0); 1397164032Srwatson 1398164032Srwatson /* 1399164032Srwatson * Depending on the global setting, allow privilege of 1400164032Srwatson * setting system flags. 1401164032Srwatson */ 1402164032Srwatson case PRIV_VFS_SYSFLAGS: 1403164032Srwatson if (jail_chflags_allowed) 1404164032Srwatson return (0); 1405164032Srwatson else 1406164032Srwatson return (EPERM); 1407164032Srwatson 1408164032Srwatson /* 1409168396Spjd * Depending on the global setting, allow privilege of 1410168396Spjd * mounting/unmounting file systems. 1411168396Spjd */ 1412168396Spjd case PRIV_VFS_MOUNT: 1413168396Spjd case PRIV_VFS_UNMOUNT: 1414168396Spjd case PRIV_VFS_MOUNT_NONUSER: 1415168699Spjd case PRIV_VFS_MOUNT_OWNER: 1416168396Spjd if (jail_mount_allowed) 1417168396Spjd return (0); 1418168396Spjd else 1419168396Spjd return (EPERM); 1420168396Spjd 1421168396Spjd /* 1422168591Srwatson * Allow jailed root to bind reserved ports and reuse in-use 1423168591Srwatson * ports. 1424164032Srwatson */ 1425164032Srwatson case PRIV_NETINET_RESERVEDPORT: 1426168591Srwatson case PRIV_NETINET_REUSEPORT: 1427164032Srwatson return (0); 1428164032Srwatson 1429164032Srwatson /* 1430175630Sbz * Allow jailed root to set certian IPv4/6 (option) headers. 1431175630Sbz */ 1432175630Sbz case PRIV_NETINET_SETHDROPTS: 1433175630Sbz return (0); 1434175630Sbz 1435175630Sbz /* 1436164032Srwatson * Conditionally allow creating raw sockets in jail. 1437164032Srwatson */ 1438164032Srwatson case PRIV_NETINET_RAW: 1439164032Srwatson if (jail_allow_raw_sockets) 1440164032Srwatson return (0); 1441164032Srwatson else 1442164032Srwatson return (EPERM); 1443164032Srwatson 1444164032Srwatson /* 1445164032Srwatson * Since jail implements its own visibility limits on netstat 1446164032Srwatson * sysctls, allow getcred. This allows identd to work in 1447164032Srwatson * jail. 1448164032Srwatson */ 1449164032Srwatson case PRIV_NETINET_GETCRED: 1450164032Srwatson return (0); 1451164032Srwatson 1452164032Srwatson default: 1453164032Srwatson /* 1454164032Srwatson * In all remaining cases, deny the privilege request. This 1455164032Srwatson * includes almost all network privileges, many system 1456164032Srwatson * configuration privileges. 1457164032Srwatson */ 1458164032Srwatson return (EPERM); 1459164032Srwatson } 1460164032Srwatson} 1461164032Srwatson 1462113275Smikestatic int 1463113275Smikesysctl_jail_list(SYSCTL_HANDLER_ARGS) 1464113275Smike{ 1465113275Smike struct xprison *xp, *sxp; 1466113275Smike struct prison *pr; 1467185435Sbz char *p; 1468185435Sbz size_t len; 1469113275Smike int count, error; 1470113275Smike 1471127020Spjd if (jailed(req->td->td_ucred)) 1472125806Srwatson return (0); 1473113275Smike 1474168401Spjd sx_slock(&allprison_lock); 1475168401Spjd if ((count = prisoncount) == 0) { 1476168401Spjd sx_sunlock(&allprison_lock); 1477113275Smike return (0); 1478168401Spjd } 1479113275Smike 1480185435Sbz len = sizeof(*xp) * count; 1481185435Sbz LIST_FOREACH(pr, &allprison, pr_list) { 1482185435Sbz#ifdef INET 1483185435Sbz len += pr->pr_ip4s * sizeof(struct in_addr); 1484185435Sbz#endif 1485185435Sbz#ifdef INET6 1486185435Sbz len += pr->pr_ip6s * sizeof(struct in6_addr); 1487185435Sbz#endif 1488185435Sbz } 1489167309Spjd 1490185435Sbz sxp = xp = malloc(len, M_TEMP, M_WAITOK | M_ZERO); 1491185435Sbz 1492113275Smike LIST_FOREACH(pr, &allprison, pr_list) { 1493113275Smike xp->pr_version = XPRISON_VERSION; 1494113275Smike xp->pr_id = pr->pr_id; 1495185435Sbz xp->pr_state = pr->pr_state; 1496185435Sbz xp->pr_cpusetid = pr->pr_cpuset->cs_id; 1497113275Smike strlcpy(xp->pr_path, pr->pr_path, sizeof(xp->pr_path)); 1498168487Spjd mtx_lock(&pr->pr_mtx); 1499113275Smike strlcpy(xp->pr_host, pr->pr_host, sizeof(xp->pr_host)); 1500185435Sbz strlcpy(xp->pr_name, pr->pr_name, sizeof(xp->pr_name)); 1501113275Smike mtx_unlock(&pr->pr_mtx); 1502185435Sbz#ifdef INET 1503185435Sbz xp->pr_ip4s = pr->pr_ip4s; 1504185435Sbz#endif 1505185435Sbz#ifdef INET6 1506185435Sbz xp->pr_ip6s = pr->pr_ip6s; 1507185435Sbz#endif 1508185435Sbz p = (char *)(xp + 1); 1509185435Sbz#ifdef INET 1510185435Sbz if (pr->pr_ip4s > 0) { 1511185435Sbz bcopy(pr->pr_ip4, (struct in_addr *)p, 1512185435Sbz pr->pr_ip4s * sizeof(struct in_addr)); 1513185435Sbz p += (pr->pr_ip4s * sizeof(struct in_addr)); 1514185435Sbz } 1515185435Sbz#endif 1516185435Sbz#ifdef INET6 1517185435Sbz if (pr->pr_ip6s > 0) { 1518185435Sbz bcopy(pr->pr_ip6, (struct in6_addr *)p, 1519185435Sbz pr->pr_ip6s * sizeof(struct in6_addr)); 1520185435Sbz p += (pr->pr_ip6s * sizeof(struct in6_addr)); 1521185435Sbz } 1522185435Sbz#endif 1523185435Sbz xp = (struct xprison *)p; 1524113275Smike } 1525168401Spjd sx_sunlock(&allprison_lock); 1526113275Smike 1527185435Sbz error = SYSCTL_OUT(req, sxp, len); 1528113275Smike free(sxp, M_TEMP); 1529167354Spjd return (error); 1530113275Smike} 1531113275Smike 1532113275SmikeSYSCTL_OID(_security_jail, OID_AUTO, list, CTLTYPE_STRUCT | CTLFLAG_RD, 1533113275Smike NULL, 0, sysctl_jail_list, "S", "List of active jails"); 1534126004Spjd 1535126004Spjdstatic int 1536126004Spjdsysctl_jail_jailed(SYSCTL_HANDLER_ARGS) 1537126004Spjd{ 1538126004Spjd int error, injail; 1539126004Spjd 1540126004Spjd injail = jailed(req->td->td_ucred); 1541126004Spjd error = SYSCTL_OUT(req, &injail, sizeof(injail)); 1542126004Spjd 1543126004Spjd return (error); 1544126004Spjd} 1545126004SpjdSYSCTL_PROC(_security_jail, OID_AUTO, jailed, CTLTYPE_INT | CTLFLAG_RD, 1546126004Spjd NULL, 0, sysctl_jail_jailed, "I", "Process in jail?"); 1547185435Sbz 1548185435Sbz#ifdef DDB 1549185435SbzDB_SHOW_COMMAND(jails, db_show_jails) 1550185435Sbz{ 1551185435Sbz struct prison *pr; 1552185435Sbz#ifdef INET 1553185435Sbz struct in_addr ia; 1554185435Sbz#endif 1555185435Sbz#ifdef INET6 1556185435Sbz char ip6buf[INET6_ADDRSTRLEN]; 1557185435Sbz#endif 1558185435Sbz const char *state; 1559185435Sbz#if defined(INET) || defined(INET6) 1560185435Sbz int i; 1561185435Sbz#endif 1562185435Sbz 1563185435Sbz db_printf( 1564185435Sbz " JID pr_ref pr_nprocs pr_ip4s pr_ip6s\n"); 1565185435Sbz db_printf( 1566185435Sbz " Hostname Path\n"); 1567185435Sbz db_printf( 1568185435Sbz " Name State\n"); 1569185435Sbz db_printf( 1570185435Sbz " Cpusetid\n"); 1571185435Sbz db_printf( 1572185435Sbz " IP Address(es)\n"); 1573185435Sbz LIST_FOREACH(pr, &allprison, pr_list) { 1574185435Sbz db_printf("%6d %6d %9d %7d %7d\n", 1575185435Sbz pr->pr_id, pr->pr_ref, pr->pr_nprocs, 1576185435Sbz pr->pr_ip4s, pr->pr_ip6s); 1577185435Sbz db_printf("%6s %-29.29s %.74s\n", 1578185435Sbz "", pr->pr_host, pr->pr_path); 1579185899Sbz if (pr->pr_state < 0 || pr->pr_state >= (int)((sizeof( 1580185435Sbz prison_states) / sizeof(struct prison_state)))) 1581185435Sbz state = "(bogus)"; 1582185435Sbz else 1583185435Sbz state = prison_states[pr->pr_state].state_name; 1584185435Sbz db_printf("%6s %-29.29s %.74s\n", 1585185899Sbz "", (pr->pr_name[0] != '\0') ? pr->pr_name : "", state); 1586185435Sbz db_printf("%6s %-6d\n", 1587185435Sbz "", pr->pr_cpuset->cs_id); 1588185435Sbz#ifdef INET 1589185435Sbz for (i=0; i < pr->pr_ip4s; i++) { 1590185435Sbz ia.s_addr = pr->pr_ip4[i].s_addr; 1591185435Sbz db_printf("%6s %s\n", "", inet_ntoa(ia)); 1592185435Sbz } 1593185435Sbz#endif 1594185435Sbz#ifdef INET6 1595185435Sbz for (i=0; i < pr->pr_ip6s; i++) 1596185435Sbz db_printf("%6s %s\n", 1597185435Sbz "", ip6_sprintf(ip6buf, &pr->pr_ip6[i])); 1598185435Sbz#endif /* INET6 */ 1599185435Sbz if (db_pager_quit) 1600185435Sbz break; 1601185435Sbz } 1602185435Sbz} 1603185435Sbz#endif /* DDB */ 1604