19454b2d8SWarner Losh /*- 2413628a7SBjoern A. Zeeb * Copyright (c) 1999 Poul-Henning Kamp. 3413628a7SBjoern A. Zeeb * Copyright (c) 2008 Bjoern A. Zeeb. 4b38ff370SJamie Gritton * Copyright (c) 2009 James Gritton. 5413628a7SBjoern A. Zeeb * All rights reserved. 6b9f0b66cSBjoern A. Zeeb * 7b9f0b66cSBjoern A. Zeeb * Redistribution and use in source and binary forms, with or without 8b9f0b66cSBjoern A. Zeeb * modification, are permitted provided that the following conditions 9b9f0b66cSBjoern A. Zeeb * are met: 10b9f0b66cSBjoern A. Zeeb * 1. Redistributions of source code must retain the above copyright 11b9f0b66cSBjoern A. Zeeb * notice, this list of conditions and the following disclaimer. 12b9f0b66cSBjoern A. Zeeb * 2. Redistributions in binary form must reproduce the above copyright 13b9f0b66cSBjoern A. Zeeb * notice, this list of conditions and the following disclaimer in the 14b9f0b66cSBjoern A. Zeeb * documentation and/or other materials provided with the distribution. 15b9f0b66cSBjoern A. Zeeb * 16b9f0b66cSBjoern A. Zeeb * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17b9f0b66cSBjoern A. Zeeb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18b9f0b66cSBjoern A. Zeeb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19b9f0b66cSBjoern A. Zeeb * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20b9f0b66cSBjoern A. Zeeb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21b9f0b66cSBjoern A. Zeeb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22b9f0b66cSBjoern A. Zeeb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23b9f0b66cSBjoern A. Zeeb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24b9f0b66cSBjoern A. Zeeb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25b9f0b66cSBjoern A. Zeeb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26b9f0b66cSBjoern A. Zeeb * SUCH DAMAGE. 2707901f22SPoul-Henning Kamp */ 2875c13541SPoul-Henning Kamp 29677b542eSDavid E. O'Brien #include <sys/cdefs.h> 30677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$"); 31677b542eSDavid E. O'Brien 32413628a7SBjoern A. Zeeb #include "opt_ddb.h" 33413628a7SBjoern A. Zeeb #include "opt_inet.h" 34413628a7SBjoern A. Zeeb #include "opt_inet6.h" 3546e3b1cbSPawel Jakub Dawidek #include "opt_mac.h" 3646e3b1cbSPawel Jakub Dawidek 3775c13541SPoul-Henning Kamp #include <sys/param.h> 3875c13541SPoul-Henning Kamp #include <sys/types.h> 3975c13541SPoul-Henning Kamp #include <sys/kernel.h> 4075c13541SPoul-Henning Kamp #include <sys/systm.h> 4175c13541SPoul-Henning Kamp #include <sys/errno.h> 4275c13541SPoul-Henning Kamp #include <sys/sysproto.h> 4375c13541SPoul-Henning Kamp #include <sys/malloc.h> 44800c9408SRobert Watson #include <sys/priv.h> 4575c13541SPoul-Henning Kamp #include <sys/proc.h> 46b3059e09SRobert Watson #include <sys/taskqueue.h> 4757b4252eSKonstantin Belousov #include <sys/fcntl.h> 4875c13541SPoul-Henning Kamp #include <sys/jail.h> 4901137630SRobert Watson #include <sys/lock.h> 5001137630SRobert Watson #include <sys/mutex.h> 51b38ff370SJamie Gritton #include <sys/osd.h> 52dc68a633SPawel Jakub Dawidek #include <sys/sx.h> 53fd7a8150SMike Barcroft #include <sys/namei.h> 54820a0de9SPawel Jakub Dawidek #include <sys/mount.h> 55fd7a8150SMike Barcroft #include <sys/queue.h> 5675c13541SPoul-Henning Kamp #include <sys/socket.h> 57fd7a8150SMike Barcroft #include <sys/syscallsubr.h> 5883f1e257SRobert Watson #include <sys/sysctl.h> 59fd7a8150SMike Barcroft #include <sys/vnode.h> 60603724d3SBjoern A. Zeeb #include <sys/vimage.h> 6175c13541SPoul-Henning Kamp #include <net/if.h> 6275c13541SPoul-Henning Kamp #include <netinet/in.h> 63413628a7SBjoern A. Zeeb #ifdef DDB 64413628a7SBjoern A. Zeeb #include <ddb/ddb.h> 65413628a7SBjoern A. Zeeb #ifdef INET6 66413628a7SBjoern A. Zeeb #include <netinet6/in6_var.h> 67413628a7SBjoern A. Zeeb #endif /* INET6 */ 68413628a7SBjoern A. Zeeb #endif /* DDB */ 6975c13541SPoul-Henning Kamp 70aed55708SRobert Watson #include <security/mac/mac_framework.h> 71aed55708SRobert Watson 7275c13541SPoul-Henning Kamp MALLOC_DEFINE(M_PRISON, "prison", "Prison structures"); 7375c13541SPoul-Henning Kamp 74d0615c64SAndrew R. Reiter SYSCTL_NODE(_security, OID_AUTO, jail, CTLFLAG_RW, 0, 7583f1e257SRobert Watson "Jail rules"); 7683f1e257SRobert Watson 7783f1e257SRobert Watson int jail_set_hostname_allowed = 1; 78d0615c64SAndrew R. Reiter SYSCTL_INT(_security_jail, OID_AUTO, set_hostname_allowed, CTLFLAG_RW, 7983f1e257SRobert Watson &jail_set_hostname_allowed, 0, 8083f1e257SRobert Watson "Processes in jail can set their hostnames"); 8183f1e257SRobert Watson 827cadc266SRobert Watson int jail_socket_unixiproute_only = 1; 83d0615c64SAndrew R. Reiter SYSCTL_INT(_security_jail, OID_AUTO, socket_unixiproute_only, CTLFLAG_RW, 847cadc266SRobert Watson &jail_socket_unixiproute_only, 0, 85413628a7SBjoern A. Zeeb "Processes in jail are limited to creating UNIX/IP/route sockets only"); 867cadc266SRobert Watson 87cb1f0db9SRobert Watson int jail_sysvipc_allowed = 0; 88d0615c64SAndrew R. Reiter SYSCTL_INT(_security_jail, OID_AUTO, sysvipc_allowed, CTLFLAG_RW, 89cb1f0db9SRobert Watson &jail_sysvipc_allowed, 0, 90cb1f0db9SRobert Watson "Processes in jail can use System V IPC primitives"); 91cb1f0db9SRobert Watson 92820a0de9SPawel Jakub Dawidek static int jail_enforce_statfs = 2; 93820a0de9SPawel Jakub Dawidek SYSCTL_INT(_security_jail, OID_AUTO, enforce_statfs, CTLFLAG_RW, 94820a0de9SPawel Jakub Dawidek &jail_enforce_statfs, 0, 95820a0de9SPawel Jakub Dawidek "Processes in jail cannot see all mounted file systems"); 96f08df373SRobert Watson 975a59cefcSBosko Milekic int jail_allow_raw_sockets = 0; 985a59cefcSBosko Milekic SYSCTL_INT(_security_jail, OID_AUTO, allow_raw_sockets, CTLFLAG_RW, 995a59cefcSBosko Milekic &jail_allow_raw_sockets, 0, 1005a59cefcSBosko Milekic "Prison root can create raw sockets"); 1015a59cefcSBosko Milekic 10279653046SColin Percival int jail_chflags_allowed = 0; 10379653046SColin Percival SYSCTL_INT(_security_jail, OID_AUTO, chflags_allowed, CTLFLAG_RW, 10479653046SColin Percival &jail_chflags_allowed, 0, 10579653046SColin Percival "Processes in jail can alter system file flags"); 10679653046SColin Percival 107f3a8d2f9SPawel Jakub Dawidek int jail_mount_allowed = 0; 108f3a8d2f9SPawel Jakub Dawidek SYSCTL_INT(_security_jail, OID_AUTO, mount_allowed, CTLFLAG_RW, 109f3a8d2f9SPawel Jakub Dawidek &jail_mount_allowed, 0, 110f3a8d2f9SPawel Jakub Dawidek "Processes in jail can mount/unmount jail-friendly file systems"); 111f3a8d2f9SPawel Jakub Dawidek 112413628a7SBjoern A. Zeeb int jail_max_af_ips = 255; 113413628a7SBjoern A. Zeeb SYSCTL_INT(_security_jail, OID_AUTO, jail_max_af_ips, CTLFLAG_RW, 114413628a7SBjoern A. Zeeb &jail_max_af_ips, 0, 115413628a7SBjoern A. Zeeb "Number of IP addresses a jail may have at most per address family"); 116413628a7SBjoern A. Zeeb 1172110d913SXin LI /* allprison, lastprid, and prisoncount are protected by allprison_lock. */ 118dc68a633SPawel Jakub Dawidek struct sx allprison_lock; 119b38ff370SJamie Gritton SX_SYSINIT(allprison_lock, &allprison_lock, "allprison"); 120b38ff370SJamie Gritton struct prisonlist allprison = TAILQ_HEAD_INITIALIZER(allprison); 1212110d913SXin LI int lastprid = 0; 122fd7a8150SMike Barcroft int prisoncount = 0; 123fd7a8150SMike Barcroft 124b38ff370SJamie Gritton static int do_jail_attach(struct thread *td, struct prison *pr); 125b3059e09SRobert Watson static void prison_complete(void *context, int pending); 126b38ff370SJamie Gritton static void prison_deref(struct prison *pr, int flags); 127413628a7SBjoern A. Zeeb #ifdef INET 1288571af59SJamie Gritton static int _prison_check_ip4(struct prison *pr, struct in_addr *ia); 129413628a7SBjoern A. Zeeb #endif 130413628a7SBjoern A. Zeeb #ifdef INET6 1318571af59SJamie Gritton static int _prison_check_ip6(struct prison *pr, struct in6_addr *ia6); 132413628a7SBjoern A. Zeeb #endif 133af7bd9a4SJamie Gritton static int sysctl_jail_list(SYSCTL_HANDLER_ARGS); 134fd7a8150SMike Barcroft 135b38ff370SJamie Gritton /* Flags for prison_deref */ 136b38ff370SJamie Gritton #define PD_DEREF 0x01 137b38ff370SJamie Gritton #define PD_DEUREF 0x02 138b38ff370SJamie Gritton #define PD_LOCKED 0x04 139b38ff370SJamie Gritton #define PD_LIST_SLOCKED 0x08 140b38ff370SJamie Gritton #define PD_LIST_XLOCKED 0x10 141fd7a8150SMike Barcroft 142413628a7SBjoern A. Zeeb #ifdef INET 143413628a7SBjoern A. Zeeb static int 144413628a7SBjoern A. Zeeb qcmp_v4(const void *ip1, const void *ip2) 145413628a7SBjoern A. Zeeb { 146413628a7SBjoern A. Zeeb in_addr_t iaa, iab; 147413628a7SBjoern A. Zeeb 148413628a7SBjoern A. Zeeb /* 149413628a7SBjoern A. Zeeb * We need to compare in HBO here to get the list sorted as expected 150413628a7SBjoern A. Zeeb * by the result of the code. Sorting NBO addresses gives you 151413628a7SBjoern A. Zeeb * interesting results. If you do not understand, do not try. 152413628a7SBjoern A. Zeeb */ 153413628a7SBjoern A. Zeeb iaa = ntohl(((const struct in_addr *)ip1)->s_addr); 154413628a7SBjoern A. Zeeb iab = ntohl(((const struct in_addr *)ip2)->s_addr); 155413628a7SBjoern A. Zeeb 156413628a7SBjoern A. Zeeb /* 157413628a7SBjoern A. Zeeb * Do not simply return the difference of the two numbers, the int is 158413628a7SBjoern A. Zeeb * not wide enough. 159413628a7SBjoern A. Zeeb */ 160413628a7SBjoern A. Zeeb if (iaa > iab) 161413628a7SBjoern A. Zeeb return (1); 162413628a7SBjoern A. Zeeb else if (iaa < iab) 163413628a7SBjoern A. Zeeb return (-1); 164413628a7SBjoern A. Zeeb else 165413628a7SBjoern A. Zeeb return (0); 166413628a7SBjoern A. Zeeb } 167413628a7SBjoern A. Zeeb #endif 168413628a7SBjoern A. Zeeb 169413628a7SBjoern A. Zeeb #ifdef INET6 170413628a7SBjoern A. Zeeb static int 171413628a7SBjoern A. Zeeb qcmp_v6(const void *ip1, const void *ip2) 172413628a7SBjoern A. Zeeb { 173413628a7SBjoern A. Zeeb const struct in6_addr *ia6a, *ia6b; 174413628a7SBjoern A. Zeeb int i, rc; 175413628a7SBjoern A. Zeeb 176413628a7SBjoern A. Zeeb ia6a = (const struct in6_addr *)ip1; 177413628a7SBjoern A. Zeeb ia6b = (const struct in6_addr *)ip2; 178413628a7SBjoern A. Zeeb 179413628a7SBjoern A. Zeeb rc = 0; 180413628a7SBjoern A. Zeeb for (i = 0; rc == 0 && i < sizeof(struct in6_addr); i++) { 181413628a7SBjoern A. Zeeb if (ia6a->s6_addr[i] > ia6b->s6_addr[i]) 182413628a7SBjoern A. Zeeb rc = 1; 183413628a7SBjoern A. Zeeb else if (ia6a->s6_addr[i] < ia6b->s6_addr[i]) 184413628a7SBjoern A. Zeeb rc = -1; 185413628a7SBjoern A. Zeeb } 186413628a7SBjoern A. Zeeb return (rc); 187413628a7SBjoern A. Zeeb } 188413628a7SBjoern A. Zeeb #endif 189413628a7SBjoern A. Zeeb 190116734c4SMatthew Dillon /* 1919ddb7954SMike Barcroft * struct jail_args { 1929ddb7954SMike Barcroft * struct jail *jail; 1939ddb7954SMike Barcroft * }; 194116734c4SMatthew Dillon */ 19575c13541SPoul-Henning Kamp int 1969ddb7954SMike Barcroft jail(struct thread *td, struct jail_args *uap) 19775c13541SPoul-Henning Kamp { 198b38ff370SJamie Gritton struct iovec optiov[10]; 199b38ff370SJamie Gritton struct uio opt; 200b38ff370SJamie Gritton char *u_path, *u_hostname, *u_name; 201b38ff370SJamie Gritton #ifdef INET 202b38ff370SJamie Gritton struct in_addr *u_ip4; 203b38ff370SJamie Gritton #endif 204b38ff370SJamie Gritton #ifdef INET6 205b38ff370SJamie Gritton struct in6_addr *u_ip6; 206b38ff370SJamie Gritton #endif 207413628a7SBjoern A. Zeeb uint32_t version; 208413628a7SBjoern A. Zeeb int error; 209413628a7SBjoern A. Zeeb 210413628a7SBjoern A. Zeeb error = copyin(uap->jail, &version, sizeof(uint32_t)); 211413628a7SBjoern A. Zeeb if (error) 212413628a7SBjoern A. Zeeb return (error); 213413628a7SBjoern A. Zeeb 214413628a7SBjoern A. Zeeb switch (version) { 215413628a7SBjoern A. Zeeb case 0: 216413628a7SBjoern A. Zeeb { 217b38ff370SJamie Gritton /* FreeBSD single IPv4 jails. */ 218413628a7SBjoern A. Zeeb struct jail_v0 j0; 219413628a7SBjoern A. Zeeb 220413628a7SBjoern A. Zeeb error = copyin(uap->jail, &j0, sizeof(struct jail_v0)); 221413628a7SBjoern A. Zeeb if (error) 222413628a7SBjoern A. Zeeb return (error); 223b38ff370SJamie Gritton u_path = malloc(MAXPATHLEN + MAXHOSTNAMELEN, M_TEMP, M_WAITOK); 224b38ff370SJamie Gritton u_hostname = u_path + MAXPATHLEN; 225b38ff370SJamie Gritton opt.uio_iov = optiov; 226b38ff370SJamie Gritton opt.uio_iovcnt = 4; 227b38ff370SJamie Gritton opt.uio_offset = -1; 228b38ff370SJamie Gritton opt.uio_resid = -1; 229b38ff370SJamie Gritton opt.uio_segflg = UIO_SYSSPACE; 230b38ff370SJamie Gritton opt.uio_rw = UIO_READ; 231b38ff370SJamie Gritton opt.uio_td = td; 232b38ff370SJamie Gritton optiov[0].iov_base = "path"; 233b38ff370SJamie Gritton optiov[0].iov_len = sizeof("path"); 234b38ff370SJamie Gritton optiov[1].iov_base = u_path; 235b38ff370SJamie Gritton error = 236b38ff370SJamie Gritton copyinstr(j0.path, u_path, MAXPATHLEN, &optiov[1].iov_len); 237b38ff370SJamie Gritton if (error) { 238b38ff370SJamie Gritton free(u_path, M_TEMP); 239b38ff370SJamie Gritton return (error); 240b38ff370SJamie Gritton } 241b38ff370SJamie Gritton optiov[2].iov_base = "host.hostname"; 242b38ff370SJamie Gritton optiov[2].iov_len = sizeof("host.hostname"); 243b38ff370SJamie Gritton optiov[3].iov_base = u_hostname; 244b38ff370SJamie Gritton error = copyinstr(j0.hostname, u_hostname, MAXHOSTNAMELEN, 245b38ff370SJamie Gritton &optiov[3].iov_len); 246b38ff370SJamie Gritton if (error) { 247b38ff370SJamie Gritton free(u_path, M_TEMP); 248b38ff370SJamie Gritton return (error); 249b38ff370SJamie Gritton } 250b38ff370SJamie Gritton #ifdef INET 251b38ff370SJamie Gritton optiov[opt.uio_iovcnt].iov_base = "ip4.addr"; 252b38ff370SJamie Gritton optiov[opt.uio_iovcnt].iov_len = sizeof("ip4.addr"); 253b38ff370SJamie Gritton opt.uio_iovcnt++; 254b38ff370SJamie Gritton optiov[opt.uio_iovcnt].iov_base = &j0.ip_number; 255b38ff370SJamie Gritton j0.ip_number = htonl(j0.ip_number); 256b38ff370SJamie Gritton optiov[opt.uio_iovcnt].iov_len = sizeof(j0.ip_number); 257b38ff370SJamie Gritton opt.uio_iovcnt++; 258b38ff370SJamie Gritton #endif 259413628a7SBjoern A. Zeeb break; 260413628a7SBjoern A. Zeeb } 261413628a7SBjoern A. Zeeb 262413628a7SBjoern A. Zeeb case 1: 263413628a7SBjoern A. Zeeb /* 264413628a7SBjoern A. Zeeb * Version 1 was used by multi-IPv4 jail implementations 265413628a7SBjoern A. Zeeb * that never made it into the official kernel. 266413628a7SBjoern A. Zeeb */ 267413628a7SBjoern A. Zeeb return (EINVAL); 268413628a7SBjoern A. Zeeb 269413628a7SBjoern A. Zeeb case 2: /* JAIL_API_VERSION */ 270b38ff370SJamie Gritton { 271413628a7SBjoern A. Zeeb /* FreeBSD multi-IPv4/IPv6,noIP jails. */ 272b38ff370SJamie Gritton struct jail j; 273b38ff370SJamie Gritton size_t tmplen; 274b38ff370SJamie Gritton 275413628a7SBjoern A. Zeeb error = copyin(uap->jail, &j, sizeof(struct jail)); 276413628a7SBjoern A. Zeeb if (error) 277413628a7SBjoern A. Zeeb return (error); 278b38ff370SJamie Gritton tmplen = MAXPATHLEN + MAXHOSTNAMELEN + MAXHOSTNAMELEN; 279b38ff370SJamie Gritton #ifdef INET 280b38ff370SJamie Gritton if (j.ip4s > jail_max_af_ips) 281b38ff370SJamie Gritton return (EINVAL); 282b38ff370SJamie Gritton tmplen += j.ip4s * sizeof(struct in_addr); 283b38ff370SJamie Gritton #else 284b38ff370SJamie Gritton if (j.ip4s > 0) 285b38ff370SJamie Gritton return (EINVAL); 286b38ff370SJamie Gritton #endif 287b38ff370SJamie Gritton #ifdef INET6 288b38ff370SJamie Gritton if (j.ip6s > jail_max_af_ips) 289b38ff370SJamie Gritton return (EINVAL); 290b38ff370SJamie Gritton tmplen += j.ip6s * sizeof(struct in6_addr); 291b38ff370SJamie Gritton #else 292b38ff370SJamie Gritton if (j.ip6s > 0) 293b38ff370SJamie Gritton return (EINVAL); 294b38ff370SJamie Gritton #endif 295b38ff370SJamie Gritton u_path = malloc(tmplen, M_TEMP, M_WAITOK); 296b38ff370SJamie Gritton u_hostname = u_path + MAXPATHLEN; 297b38ff370SJamie Gritton u_name = u_hostname + MAXHOSTNAMELEN; 298b38ff370SJamie Gritton #ifdef INET 299b38ff370SJamie Gritton u_ip4 = (struct in_addr *)(u_name + MAXHOSTNAMELEN); 300b38ff370SJamie Gritton #endif 301b38ff370SJamie Gritton #ifdef INET6 302b38ff370SJamie Gritton #ifdef INET 303b38ff370SJamie Gritton u_ip6 = (struct in6_addr *)(u_ip4 + j.ip4s); 304b38ff370SJamie Gritton #else 305b38ff370SJamie Gritton u_ip6 = (struct in6_addr *)(u_name + MAXHOSTNAMELEN); 306b38ff370SJamie Gritton #endif 307b38ff370SJamie Gritton #endif 308b38ff370SJamie Gritton opt.uio_iov = optiov; 309b38ff370SJamie Gritton opt.uio_iovcnt = 4; 310b38ff370SJamie Gritton opt.uio_offset = -1; 311b38ff370SJamie Gritton opt.uio_resid = -1; 312b38ff370SJamie Gritton opt.uio_segflg = UIO_SYSSPACE; 313b38ff370SJamie Gritton opt.uio_rw = UIO_READ; 314b38ff370SJamie Gritton opt.uio_td = td; 315b38ff370SJamie Gritton optiov[0].iov_base = "path"; 316b38ff370SJamie Gritton optiov[0].iov_len = sizeof("path"); 317b38ff370SJamie Gritton optiov[1].iov_base = u_path; 318b38ff370SJamie Gritton error = 319b38ff370SJamie Gritton copyinstr(j.path, u_path, MAXPATHLEN, &optiov[1].iov_len); 320b38ff370SJamie Gritton if (error) { 321b38ff370SJamie Gritton free(u_path, M_TEMP); 322b38ff370SJamie Gritton return (error); 323b38ff370SJamie Gritton } 324b38ff370SJamie Gritton optiov[2].iov_base = "host.hostname"; 325b38ff370SJamie Gritton optiov[2].iov_len = sizeof("host.hostname"); 326b38ff370SJamie Gritton optiov[3].iov_base = u_hostname; 327b38ff370SJamie Gritton error = copyinstr(j.hostname, u_hostname, MAXHOSTNAMELEN, 328b38ff370SJamie Gritton &optiov[3].iov_len); 329b38ff370SJamie Gritton if (error) { 330b38ff370SJamie Gritton free(u_path, M_TEMP); 331b38ff370SJamie Gritton return (error); 332b38ff370SJamie Gritton } 333b38ff370SJamie Gritton if (j.jailname != NULL) { 334b38ff370SJamie Gritton optiov[opt.uio_iovcnt].iov_base = "name"; 335b38ff370SJamie Gritton optiov[opt.uio_iovcnt].iov_len = sizeof("name"); 336b38ff370SJamie Gritton opt.uio_iovcnt++; 337b38ff370SJamie Gritton optiov[opt.uio_iovcnt].iov_base = u_name; 338b38ff370SJamie Gritton error = copyinstr(j.jailname, u_name, MAXHOSTNAMELEN, 339b38ff370SJamie Gritton &optiov[opt.uio_iovcnt].iov_len); 340b38ff370SJamie Gritton if (error) { 341b38ff370SJamie Gritton free(u_path, M_TEMP); 342b38ff370SJamie Gritton return (error); 343b38ff370SJamie Gritton } 344b38ff370SJamie Gritton opt.uio_iovcnt++; 345b38ff370SJamie Gritton } 346b38ff370SJamie Gritton #ifdef INET 347b38ff370SJamie Gritton optiov[opt.uio_iovcnt].iov_base = "ip4.addr"; 348b38ff370SJamie Gritton optiov[opt.uio_iovcnt].iov_len = sizeof("ip4.addr"); 349b38ff370SJamie Gritton opt.uio_iovcnt++; 350b38ff370SJamie Gritton optiov[opt.uio_iovcnt].iov_base = u_ip4; 351b38ff370SJamie Gritton optiov[opt.uio_iovcnt].iov_len = 352b38ff370SJamie Gritton j.ip4s * sizeof(struct in_addr); 353b38ff370SJamie Gritton error = copyin(j.ip4, u_ip4, optiov[opt.uio_iovcnt].iov_len); 354b38ff370SJamie Gritton if (error) { 355b38ff370SJamie Gritton free(u_path, M_TEMP); 356b38ff370SJamie Gritton return (error); 357b38ff370SJamie Gritton } 358b38ff370SJamie Gritton opt.uio_iovcnt++; 359b38ff370SJamie Gritton #endif 360b38ff370SJamie Gritton #ifdef INET6 361b38ff370SJamie Gritton optiov[opt.uio_iovcnt].iov_base = "ip6.addr"; 362b38ff370SJamie Gritton optiov[opt.uio_iovcnt].iov_len = sizeof("ip6.addr"); 363b38ff370SJamie Gritton opt.uio_iovcnt++; 364b38ff370SJamie Gritton optiov[opt.uio_iovcnt].iov_base = u_ip6; 365b38ff370SJamie Gritton optiov[opt.uio_iovcnt].iov_len = 366b38ff370SJamie Gritton j.ip6s * sizeof(struct in6_addr); 367b38ff370SJamie Gritton error = copyin(j.ip6, u_ip6, optiov[opt.uio_iovcnt].iov_len); 368b38ff370SJamie Gritton if (error) { 369b38ff370SJamie Gritton free(u_path, M_TEMP); 370b38ff370SJamie Gritton return (error); 371b38ff370SJamie Gritton } 372b38ff370SJamie Gritton opt.uio_iovcnt++; 373b38ff370SJamie Gritton #endif 374413628a7SBjoern A. Zeeb break; 375b38ff370SJamie Gritton } 376413628a7SBjoern A. Zeeb 377413628a7SBjoern A. Zeeb default: 378413628a7SBjoern A. Zeeb /* Sci-Fi jails are not supported, sorry. */ 379413628a7SBjoern A. Zeeb return (EINVAL); 380413628a7SBjoern A. Zeeb } 381b38ff370SJamie Gritton error = kern_jail_set(td, &opt, JAIL_CREATE | JAIL_ATTACH); 382b38ff370SJamie Gritton free(u_path, M_TEMP); 383b38ff370SJamie Gritton return (error); 384b38ff370SJamie Gritton } 385b38ff370SJamie Gritton 386b38ff370SJamie Gritton /* 387b38ff370SJamie Gritton * struct jail_set_args { 388b38ff370SJamie Gritton * struct iovec *iovp; 389b38ff370SJamie Gritton * unsigned int iovcnt; 390b38ff370SJamie Gritton * int flags; 391b38ff370SJamie Gritton * }; 392b38ff370SJamie Gritton */ 393b38ff370SJamie Gritton int 394b38ff370SJamie Gritton jail_set(struct thread *td, struct jail_set_args *uap) 395b38ff370SJamie Gritton { 396b38ff370SJamie Gritton struct uio *auio; 397b38ff370SJamie Gritton int error; 398b38ff370SJamie Gritton 399b38ff370SJamie Gritton /* Check that we have an even number of iovecs. */ 400b38ff370SJamie Gritton if (uap->iovcnt & 1) 401b38ff370SJamie Gritton return (EINVAL); 402b38ff370SJamie Gritton 403b38ff370SJamie Gritton error = copyinuio(uap->iovp, uap->iovcnt, &auio); 404b38ff370SJamie Gritton if (error) 405b38ff370SJamie Gritton return (error); 406b38ff370SJamie Gritton error = kern_jail_set(td, auio, uap->flags); 407b38ff370SJamie Gritton free(auio, M_IOV); 408b38ff370SJamie Gritton return (error); 409413628a7SBjoern A. Zeeb } 410413628a7SBjoern A. Zeeb 411413628a7SBjoern A. Zeeb int 412b38ff370SJamie Gritton kern_jail_set(struct thread *td, struct uio *optuio, int flags) 413413628a7SBjoern A. Zeeb { 414fd7a8150SMike Barcroft struct nameidata nd; 415b38ff370SJamie Gritton #ifdef INET 416b38ff370SJamie Gritton struct in_addr *ip4; 417413628a7SBjoern A. Zeeb #endif 418b38ff370SJamie Gritton #ifdef INET6 419b38ff370SJamie Gritton struct in6_addr *ip6; 420b38ff370SJamie Gritton #endif 421b38ff370SJamie Gritton struct vfsopt *opt; 422b38ff370SJamie Gritton struct vfsoptlist *opts; 423b38ff370SJamie Gritton struct prison *pr, *deadpr, *tpr; 424b38ff370SJamie Gritton struct vnode *root; 425b38ff370SJamie Gritton char *errmsg, *host, *name, *p, *path; 426b38ff370SJamie Gritton void *op; 427b38ff370SJamie Gritton int created, cuflags, error, errmsg_len, errmsg_pos; 428b38ff370SJamie Gritton int gotslevel, jid, len; 429b38ff370SJamie Gritton int slevel, vfslocked; 430d465a41dSBjoern A. Zeeb #if defined(INET) || defined(INET6) 431b38ff370SJamie Gritton int ii; 432413628a7SBjoern A. Zeeb #endif 433413628a7SBjoern A. Zeeb #ifdef INET 434b38ff370SJamie Gritton int ip4s; 435413628a7SBjoern A. Zeeb #endif 436b38ff370SJamie Gritton #ifdef INET6 437b38ff370SJamie Gritton int ip6s; 438b38ff370SJamie Gritton #endif 439b38ff370SJamie Gritton unsigned pr_flags, ch_flags; 440b38ff370SJamie Gritton char numbuf[12]; 441b38ff370SJamie Gritton 442b38ff370SJamie Gritton error = priv_check(td, PRIV_JAIL_SET); 443b38ff370SJamie Gritton if (!error && (flags & JAIL_ATTACH)) 444b38ff370SJamie Gritton error = priv_check(td, PRIV_JAIL_ATTACH); 445b38ff370SJamie Gritton if (error) 44675c13541SPoul-Henning Kamp return (error); 447b38ff370SJamie Gritton if (flags & ~JAIL_SET_MASK) 448b38ff370SJamie Gritton return (EINVAL); 449b38ff370SJamie Gritton 450b38ff370SJamie Gritton /* 451b38ff370SJamie Gritton * Check all the parameters before committing to anything. Not all 452b38ff370SJamie Gritton * errors can be caught early, but we may as well try. Also, this 453b38ff370SJamie Gritton * takes care of some expensive stuff (path lookup) before getting 454b38ff370SJamie Gritton * the allprison lock. 455b38ff370SJamie Gritton * 456b38ff370SJamie Gritton * XXX Jails are not filesystems, and jail parameters are not mount 457b38ff370SJamie Gritton * options. But it makes more sense to re-use the vfsopt code 458b38ff370SJamie Gritton * than duplicate it under a different name. 459b38ff370SJamie Gritton */ 460b38ff370SJamie Gritton error = vfs_buildopts(optuio, &opts); 461b38ff370SJamie Gritton if (error) 462b38ff370SJamie Gritton return (error); 463b38ff370SJamie Gritton #ifdef INET 464b38ff370SJamie Gritton ip4 = NULL; 465b38ff370SJamie Gritton #endif 466b38ff370SJamie Gritton #ifdef INET6 467b38ff370SJamie Gritton ip6 = NULL; 468b38ff370SJamie Gritton #endif 469b38ff370SJamie Gritton 470b38ff370SJamie Gritton error = vfs_copyopt(opts, "jid", &jid, sizeof(jid)); 471b38ff370SJamie Gritton if (error == ENOENT) 472b38ff370SJamie Gritton jid = 0; 473b38ff370SJamie Gritton else if (error != 0) 474b38ff370SJamie Gritton goto done_free; 475b38ff370SJamie Gritton 476b38ff370SJamie Gritton error = vfs_copyopt(opts, "securelevel", &slevel, sizeof(slevel)); 477b38ff370SJamie Gritton if (error == ENOENT) 478b38ff370SJamie Gritton gotslevel = 0; 479b38ff370SJamie Gritton else if (error != 0) 480b38ff370SJamie Gritton goto done_free; 481b38ff370SJamie Gritton else 482b38ff370SJamie Gritton gotslevel = 1; 483b38ff370SJamie Gritton 484b38ff370SJamie Gritton pr_flags = ch_flags = 0; 485b38ff370SJamie Gritton vfs_flagopt(opts, "persist", &pr_flags, PR_PERSIST); 486b38ff370SJamie Gritton vfs_flagopt(opts, "nopersist", &ch_flags, PR_PERSIST); 487b38ff370SJamie Gritton ch_flags |= pr_flags; 488b38ff370SJamie Gritton if ((flags & (JAIL_CREATE | JAIL_UPDATE | JAIL_ATTACH)) == JAIL_CREATE 489b38ff370SJamie Gritton && !(pr_flags & PR_PERSIST)) { 490b38ff370SJamie Gritton error = EINVAL; 491b38ff370SJamie Gritton vfs_opterror(opts, "new jail must persist or attach"); 492b38ff370SJamie Gritton goto done_errmsg; 493b38ff370SJamie Gritton } 494b38ff370SJamie Gritton 495b38ff370SJamie Gritton error = vfs_getopt(opts, "name", (void **)&name, &len); 496b38ff370SJamie Gritton if (error == ENOENT) 497b38ff370SJamie Gritton name = NULL; 498b38ff370SJamie Gritton else if (error != 0) 499b38ff370SJamie Gritton goto done_free; 500b38ff370SJamie Gritton else { 501b38ff370SJamie Gritton if (len == 0 || name[len - 1] != '\0') { 502b38ff370SJamie Gritton error = EINVAL; 503b38ff370SJamie Gritton goto done_free; 504b38ff370SJamie Gritton } 505b38ff370SJamie Gritton if (len > MAXHOSTNAMELEN) { 506b38ff370SJamie Gritton error = ENAMETOOLONG; 507b38ff370SJamie Gritton goto done_free; 508b38ff370SJamie Gritton } 509b38ff370SJamie Gritton } 510b38ff370SJamie Gritton 511b38ff370SJamie Gritton error = vfs_getopt(opts, "host.hostname", (void **)&host, &len); 512b38ff370SJamie Gritton if (error == ENOENT) 513b38ff370SJamie Gritton host = NULL; 514b38ff370SJamie Gritton else if (error != 0) 515b38ff370SJamie Gritton goto done_free; 516b38ff370SJamie Gritton else { 517b38ff370SJamie Gritton if (len == 0 || host[len - 1] != '\0') { 518b38ff370SJamie Gritton error = EINVAL; 519b38ff370SJamie Gritton goto done_free; 520b38ff370SJamie Gritton } 521b38ff370SJamie Gritton if (len > MAXHOSTNAMELEN) { 522b38ff370SJamie Gritton error = ENAMETOOLONG; 523b38ff370SJamie Gritton goto done_free; 524b38ff370SJamie Gritton } 525b38ff370SJamie Gritton } 526b38ff370SJamie Gritton 527b38ff370SJamie Gritton #ifdef INET 528b38ff370SJamie Gritton error = vfs_getopt(opts, "ip4.addr", &op, &ip4s); 529b38ff370SJamie Gritton if (error == ENOENT) 530b38ff370SJamie Gritton ip4s = -1; 531b38ff370SJamie Gritton else if (error != 0) 532b38ff370SJamie Gritton goto done_free; 533b38ff370SJamie Gritton else if (ip4s & (sizeof(*ip4) - 1)) { 534b38ff370SJamie Gritton error = EINVAL; 535b38ff370SJamie Gritton goto done_free; 536b38ff370SJamie Gritton } else if (ip4s > 0) { 537b38ff370SJamie Gritton ip4s /= sizeof(*ip4); 538b38ff370SJamie Gritton if (ip4s > jail_max_af_ips) { 539b38ff370SJamie Gritton error = EINVAL; 540b38ff370SJamie Gritton vfs_opterror(opts, "too many IPv4 addresses"); 541b38ff370SJamie Gritton goto done_errmsg; 542b38ff370SJamie Gritton } 543b38ff370SJamie Gritton ip4 = malloc(ip4s * sizeof(*ip4), M_PRISON, M_WAITOK); 544b38ff370SJamie Gritton bcopy(op, ip4, ip4s * sizeof(*ip4)); 545b38ff370SJamie Gritton /* 546b38ff370SJamie Gritton * IP addresses are all sorted but ip[0] to preserve the 547b38ff370SJamie Gritton * primary IP address as given from userland. This special IP 548b38ff370SJamie Gritton * is used for unbound outgoing connections as well for 549b38ff370SJamie Gritton * "loopback" traffic. 550b38ff370SJamie Gritton */ 551b38ff370SJamie Gritton if (ip4s > 1) 552b38ff370SJamie Gritton qsort(ip4 + 1, ip4s - 1, sizeof(*ip4), qcmp_v4); 553b38ff370SJamie Gritton /* 554b38ff370SJamie Gritton * Check for duplicate addresses and do some simple zero and 555b38ff370SJamie Gritton * broadcast checks. If users give other bogus addresses it is 556b38ff370SJamie Gritton * their problem. 557b38ff370SJamie Gritton * 558b38ff370SJamie Gritton * We do not have to care about byte order for these checks so 559b38ff370SJamie Gritton * we will do them in NBO. 560b38ff370SJamie Gritton */ 561b38ff370SJamie Gritton for (ii = 0; ii < ip4s; ii++) { 562b38ff370SJamie Gritton if (ip4[ii].s_addr == INADDR_ANY || 563b38ff370SJamie Gritton ip4[ii].s_addr == INADDR_BROADCAST) { 564b38ff370SJamie Gritton error = EINVAL; 565b38ff370SJamie Gritton goto done_free; 566b38ff370SJamie Gritton } 567b38ff370SJamie Gritton if ((ii+1) < ip4s && 568b38ff370SJamie Gritton (ip4[0].s_addr == ip4[ii+1].s_addr || 569b38ff370SJamie Gritton ip4[ii].s_addr == ip4[ii+1].s_addr)) { 570b38ff370SJamie Gritton error = EINVAL; 571b38ff370SJamie Gritton goto done_free; 572b38ff370SJamie Gritton } 573b38ff370SJamie Gritton } 574b38ff370SJamie Gritton } 575b38ff370SJamie Gritton #endif 576b38ff370SJamie Gritton 577b38ff370SJamie Gritton #ifdef INET6 578b38ff370SJamie Gritton error = vfs_getopt(opts, "ip6.addr", &op, &ip6s); 579b38ff370SJamie Gritton if (error == ENOENT) 580b38ff370SJamie Gritton ip6s = -1; 581b38ff370SJamie Gritton else if (error != 0) 582b38ff370SJamie Gritton goto done_free; 583b38ff370SJamie Gritton else if (ip6s & (sizeof(*ip6) - 1)) { 584b38ff370SJamie Gritton error = EINVAL; 585b38ff370SJamie Gritton goto done_free; 586b38ff370SJamie Gritton } else if (ip6s > 0) { 587b38ff370SJamie Gritton ip6s /= sizeof(*ip6); 588b38ff370SJamie Gritton if (ip6s > jail_max_af_ips) { 589b38ff370SJamie Gritton error = EINVAL; 590b38ff370SJamie Gritton vfs_opterror(opts, "too many IPv6 addresses"); 591b38ff370SJamie Gritton goto done_errmsg; 592b38ff370SJamie Gritton } 593b38ff370SJamie Gritton ip6 = malloc(ip6s * sizeof(*ip6), M_PRISON, M_WAITOK); 594b38ff370SJamie Gritton bcopy(op, ip6, ip6s * sizeof(*ip6)); 595b38ff370SJamie Gritton if (ip6s > 1) 596b38ff370SJamie Gritton qsort(ip6 + 1, ip6s - 1, sizeof(*ip6), qcmp_v6); 597b38ff370SJamie Gritton for (ii = 0; ii < ip6s; ii++) { 598b38ff370SJamie Gritton if (IN6_IS_ADDR_UNSPECIFIED(&ip6[0])) { 599b38ff370SJamie Gritton error = EINVAL; 600b38ff370SJamie Gritton goto done_free; 601b38ff370SJamie Gritton } 602b38ff370SJamie Gritton if ((ii+1) < ip6s && 603b38ff370SJamie Gritton (IN6_ARE_ADDR_EQUAL(&ip6[0], &ip6[ii+1]) || 604b38ff370SJamie Gritton IN6_ARE_ADDR_EQUAL(&ip6[ii], &ip6[ii+1]))) 605b38ff370SJamie Gritton { 606b38ff370SJamie Gritton error = EINVAL; 607b38ff370SJamie Gritton goto done_free; 608b38ff370SJamie Gritton } 609b38ff370SJamie Gritton } 610b38ff370SJamie Gritton } 611b38ff370SJamie Gritton #endif 612b38ff370SJamie Gritton 613b38ff370SJamie Gritton root = NULL; 614b38ff370SJamie Gritton error = vfs_getopt(opts, "path", (void **)&path, &len); 615b38ff370SJamie Gritton if (error == ENOENT) 616b38ff370SJamie Gritton path = NULL; 617b38ff370SJamie Gritton else if (error != 0) 618b38ff370SJamie Gritton goto done_free; 619b38ff370SJamie Gritton else { 620b38ff370SJamie Gritton if (flags & JAIL_UPDATE) { 621b38ff370SJamie Gritton error = EINVAL; 622b38ff370SJamie Gritton vfs_opterror(opts, 623b38ff370SJamie Gritton "path cannot be changed after creation"); 624b38ff370SJamie Gritton goto done_errmsg; 625b38ff370SJamie Gritton } 626b38ff370SJamie Gritton if (len == 0 || path[len - 1] != '\0') { 627b38ff370SJamie Gritton error = EINVAL; 628b38ff370SJamie Gritton goto done_free; 629b38ff370SJamie Gritton } 630b38ff370SJamie Gritton if (len > MAXPATHLEN) { 631b38ff370SJamie Gritton error = ENAMETOOLONG; 632b38ff370SJamie Gritton goto done_free; 633b38ff370SJamie Gritton } 634b38ff370SJamie Gritton if (len < 2 || (len == 2 && path[0] == '/')) 635b38ff370SJamie Gritton path = NULL; 636b38ff370SJamie Gritton else { 637b38ff370SJamie Gritton NDINIT(&nd, LOOKUP, MPSAFE | FOLLOW, UIO_SYSSPACE, 638b38ff370SJamie Gritton path, td); 639b38ff370SJamie Gritton error = namei(&nd); 640b38ff370SJamie Gritton if (error) 641b38ff370SJamie Gritton goto done_free; 642b38ff370SJamie Gritton vfslocked = NDHASGIANT(&nd); 643b38ff370SJamie Gritton root = nd.ni_vp; 644b38ff370SJamie Gritton NDFREE(&nd, NDF_ONLY_PNBUF); 645b38ff370SJamie Gritton if (root->v_type != VDIR) { 646b38ff370SJamie Gritton error = ENOTDIR; 647b38ff370SJamie Gritton vrele(root); 648b38ff370SJamie Gritton VFS_UNLOCK_GIANT(vfslocked); 649b38ff370SJamie Gritton goto done_free; 650b38ff370SJamie Gritton } 651b38ff370SJamie Gritton VFS_UNLOCK_GIANT(vfslocked); 652b38ff370SJamie Gritton } 653b38ff370SJamie Gritton } 654b38ff370SJamie Gritton 655b38ff370SJamie Gritton /* 656b38ff370SJamie Gritton * Grab the allprison lock before letting modules check their 657b38ff370SJamie Gritton * parameters. Once we have it, do not let go so we'll have a 658b38ff370SJamie Gritton * consistent view of the OSD list. 659b38ff370SJamie Gritton */ 660b38ff370SJamie Gritton sx_xlock(&allprison_lock); 661b38ff370SJamie Gritton error = osd_jail_call(NULL, PR_METHOD_CHECK, opts); 662b38ff370SJamie Gritton if (error) 663b38ff370SJamie Gritton goto done_unlock_list; 664b38ff370SJamie Gritton 665b38ff370SJamie Gritton /* By now, all parameters should have been noted. */ 666b38ff370SJamie Gritton TAILQ_FOREACH(opt, opts, link) { 667b38ff370SJamie Gritton if (!opt->seen && strcmp(opt->name, "errmsg")) { 668b38ff370SJamie Gritton error = EINVAL; 669b38ff370SJamie Gritton vfs_opterror(opts, "unknown parameter: %s", opt->name); 670b38ff370SJamie Gritton goto done_unlock_list; 671b38ff370SJamie Gritton } 672b38ff370SJamie Gritton } 673b38ff370SJamie Gritton 674b38ff370SJamie Gritton /* 675b38ff370SJamie Gritton * See if we are creating a new record or updating an existing one. 676b38ff370SJamie Gritton * This abuses the file error codes ENOENT and EEXIST. 677b38ff370SJamie Gritton */ 678b38ff370SJamie Gritton cuflags = flags & (JAIL_CREATE | JAIL_UPDATE); 679b38ff370SJamie Gritton if (!cuflags) { 680b38ff370SJamie Gritton error = EINVAL; 681b38ff370SJamie Gritton vfs_opterror(opts, "no valid operation (create or update)"); 682b38ff370SJamie Gritton goto done_unlock_list; 683b38ff370SJamie Gritton } 684b38ff370SJamie Gritton pr = NULL; 685b38ff370SJamie Gritton if (jid != 0) { 686b38ff370SJamie Gritton /* See if a requested jid already exists. */ 687b38ff370SJamie Gritton if (jid < 0) { 688b38ff370SJamie Gritton error = EINVAL; 689b38ff370SJamie Gritton vfs_opterror(opts, "negative jid"); 690b38ff370SJamie Gritton goto done_unlock_list; 691b38ff370SJamie Gritton } 692b38ff370SJamie Gritton pr = prison_find(jid); 693b38ff370SJamie Gritton if (pr != NULL) { 694b38ff370SJamie Gritton /* Create: jid must not exist. */ 695b38ff370SJamie Gritton if (cuflags == JAIL_CREATE) { 696b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 697b38ff370SJamie Gritton error = EEXIST; 698b38ff370SJamie Gritton vfs_opterror(opts, "jail %d already exists", 699b38ff370SJamie Gritton jid); 700b38ff370SJamie Gritton goto done_unlock_list; 701b38ff370SJamie Gritton } 702b38ff370SJamie Gritton if (pr->pr_uref == 0) { 703b38ff370SJamie Gritton if (!(flags & JAIL_DYING)) { 704b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 705b38ff370SJamie Gritton error = ENOENT; 706b38ff370SJamie Gritton vfs_opterror(opts, "jail %d is dying", 707b38ff370SJamie Gritton jid); 708b38ff370SJamie Gritton goto done_unlock_list; 709b38ff370SJamie Gritton } else if ((flags & JAIL_ATTACH) || 710b38ff370SJamie Gritton (pr_flags & PR_PERSIST)) { 711b38ff370SJamie Gritton /* 712b38ff370SJamie Gritton * A dying jail might be resurrected 713b38ff370SJamie Gritton * (via attach or persist), but first 714b38ff370SJamie Gritton * it must determine if another jail 715b38ff370SJamie Gritton * has claimed its name. Accomplish 716b38ff370SJamie Gritton * this by implicitly re-setting the 717b38ff370SJamie Gritton * name. 718b38ff370SJamie Gritton */ 719b38ff370SJamie Gritton if (name == NULL) 720b38ff370SJamie Gritton name = pr->pr_name; 721b38ff370SJamie Gritton } 722b38ff370SJamie Gritton } 723b38ff370SJamie Gritton } 724b38ff370SJamie Gritton if (pr == NULL) { 725b38ff370SJamie Gritton /* Update: jid must exist. */ 726b38ff370SJamie Gritton if (cuflags == JAIL_UPDATE) { 727b38ff370SJamie Gritton error = ENOENT; 728b38ff370SJamie Gritton vfs_opterror(opts, "jail %d not found", jid); 729b38ff370SJamie Gritton goto done_unlock_list; 730b38ff370SJamie Gritton } 731b38ff370SJamie Gritton } 732b38ff370SJamie Gritton } 733b38ff370SJamie Gritton /* 734b38ff370SJamie Gritton * If the caller provided a name, look for a jail by that name. 735b38ff370SJamie Gritton * This has different semantics for creates and updates keyed by jid 736b38ff370SJamie Gritton * (where the name must not already exist in a different jail), 737b38ff370SJamie Gritton * and updates keyed by the name itself (where the name must exist 738b38ff370SJamie Gritton * because that is the jail being updated). 739b38ff370SJamie Gritton */ 740b38ff370SJamie Gritton if (name != NULL) { 741b38ff370SJamie Gritton if (name[0] != '\0') { 742b38ff370SJamie Gritton deadpr = NULL; 743b38ff370SJamie Gritton name_again: 744b38ff370SJamie Gritton TAILQ_FOREACH(tpr, &allprison, pr_list) { 745b38ff370SJamie Gritton if (tpr != pr && tpr->pr_ref > 0 && 746b38ff370SJamie Gritton !strcmp(tpr->pr_name, name)) { 747b38ff370SJamie Gritton if (pr == NULL && 748b38ff370SJamie Gritton cuflags != JAIL_CREATE) { 749b38ff370SJamie Gritton mtx_lock(&tpr->pr_mtx); 750b38ff370SJamie Gritton if (tpr->pr_ref > 0) { 751b38ff370SJamie Gritton /* 752b38ff370SJamie Gritton * Use this jail 753b38ff370SJamie Gritton * for updates. 754b38ff370SJamie Gritton */ 755b38ff370SJamie Gritton if (tpr->pr_uref > 0) { 756b38ff370SJamie Gritton pr = tpr; 757b38ff370SJamie Gritton break; 758b38ff370SJamie Gritton } 759b38ff370SJamie Gritton deadpr = tpr; 760b38ff370SJamie Gritton } 761b38ff370SJamie Gritton mtx_unlock(&tpr->pr_mtx); 762b38ff370SJamie Gritton } else if (tpr->pr_uref > 0) { 763b38ff370SJamie Gritton /* 764b38ff370SJamie Gritton * Create, or update(jid): 765b38ff370SJamie Gritton * name must not exist in an 766b38ff370SJamie Gritton * active jail. 767b38ff370SJamie Gritton */ 768b38ff370SJamie Gritton error = EEXIST; 769b38ff370SJamie Gritton if (pr != NULL) 770b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 771b38ff370SJamie Gritton vfs_opterror(opts, 772b38ff370SJamie Gritton "jail \"%s\" already exists", 773b38ff370SJamie Gritton name); 774b38ff370SJamie Gritton goto done_unlock_list; 775b38ff370SJamie Gritton } 776b38ff370SJamie Gritton } 777b38ff370SJamie Gritton } 778b38ff370SJamie Gritton /* If no active jail is found, use a dying one. */ 779b38ff370SJamie Gritton if (deadpr != NULL && pr == NULL) { 780b38ff370SJamie Gritton if (flags & JAIL_DYING) { 781b38ff370SJamie Gritton mtx_lock(&deadpr->pr_mtx); 782b38ff370SJamie Gritton if (deadpr->pr_ref == 0) { 783b38ff370SJamie Gritton mtx_unlock(&deadpr->pr_mtx); 784b38ff370SJamie Gritton goto name_again; 785b38ff370SJamie Gritton } 786b38ff370SJamie Gritton pr = deadpr; 787b38ff370SJamie Gritton } else if (cuflags == JAIL_UPDATE) { 788b38ff370SJamie Gritton error = ENOENT; 789b38ff370SJamie Gritton vfs_opterror(opts, 790b38ff370SJamie Gritton "jail \"%s\" is dying", name); 791b38ff370SJamie Gritton goto done_unlock_list; 792b38ff370SJamie Gritton } 793b38ff370SJamie Gritton } 794b38ff370SJamie Gritton /* Update: name must exist if no jid. */ 795b38ff370SJamie Gritton else if (cuflags == JAIL_UPDATE && pr == NULL) { 796b38ff370SJamie Gritton error = ENOENT; 797b38ff370SJamie Gritton vfs_opterror(opts, "jail \"%s\" not found", 798b38ff370SJamie Gritton name); 799b38ff370SJamie Gritton goto done_unlock_list; 800b38ff370SJamie Gritton } 801b38ff370SJamie Gritton } 802b38ff370SJamie Gritton } 803b38ff370SJamie Gritton /* Update: must provide a jid or name. */ 804b38ff370SJamie Gritton else if (cuflags == JAIL_UPDATE && pr == NULL) { 805b38ff370SJamie Gritton error = ENOENT; 806b38ff370SJamie Gritton vfs_opterror(opts, "update specified no jail"); 807b38ff370SJamie Gritton goto done_unlock_list; 808b38ff370SJamie Gritton } 809b38ff370SJamie Gritton 810b38ff370SJamie Gritton /* If there's no prison to update, create a new one and link it in. */ 811b38ff370SJamie Gritton if (pr == NULL) { 812b38ff370SJamie Gritton created = 1; 813b38ff370SJamie Gritton pr = malloc(sizeof(*pr), M_PRISON, M_WAITOK | M_ZERO); 814b38ff370SJamie Gritton if (jid == 0) { 815b38ff370SJamie Gritton /* Find the next free jid. */ 816b38ff370SJamie Gritton jid = lastprid + 1; 817b38ff370SJamie Gritton findnext: 818b38ff370SJamie Gritton if (jid == JAIL_MAX) 819b38ff370SJamie Gritton jid = 1; 820b38ff370SJamie Gritton TAILQ_FOREACH(tpr, &allprison, pr_list) { 821b38ff370SJamie Gritton if (tpr->pr_id < jid) 822b38ff370SJamie Gritton continue; 823b38ff370SJamie Gritton if (tpr->pr_id > jid || tpr->pr_ref == 0) { 824b38ff370SJamie Gritton TAILQ_INSERT_BEFORE(tpr, pr, pr_list); 825b38ff370SJamie Gritton break; 826b38ff370SJamie Gritton } 827b38ff370SJamie Gritton if (jid == lastprid) { 828b38ff370SJamie Gritton error = EAGAIN; 829b38ff370SJamie Gritton vfs_opterror(opts, 830b38ff370SJamie Gritton "no available jail IDs"); 831b38ff370SJamie Gritton free(pr, M_PRISON); 832b38ff370SJamie Gritton goto done_unlock_list; 833b38ff370SJamie Gritton } 834b38ff370SJamie Gritton jid++; 835b38ff370SJamie Gritton goto findnext; 836b38ff370SJamie Gritton } 837b38ff370SJamie Gritton lastprid = jid; 838b38ff370SJamie Gritton } else { 839b38ff370SJamie Gritton /* 840b38ff370SJamie Gritton * The jail already has a jid (that did not yet exist), 841b38ff370SJamie Gritton * so just find where to insert it. 842b38ff370SJamie Gritton */ 843b38ff370SJamie Gritton TAILQ_FOREACH(tpr, &allprison, pr_list) 844b38ff370SJamie Gritton if (tpr->pr_id >= jid) { 845b38ff370SJamie Gritton TAILQ_INSERT_BEFORE(tpr, pr, pr_list); 846b38ff370SJamie Gritton break; 847b38ff370SJamie Gritton } 848b38ff370SJamie Gritton } 849b38ff370SJamie Gritton if (tpr == NULL) 850b38ff370SJamie Gritton TAILQ_INSERT_TAIL(&allprison, pr, pr_list); 851b38ff370SJamie Gritton prisoncount++; 852b38ff370SJamie Gritton 853b38ff370SJamie Gritton pr->pr_id = jid; 854b38ff370SJamie Gritton if (name == NULL) 855b38ff370SJamie Gritton name = ""; 856b38ff370SJamie Gritton if (path == NULL) { 857b38ff370SJamie Gritton path = "/"; 858b38ff370SJamie Gritton root = rootvnode; 859b38ff370SJamie Gritton vref(root); 860b38ff370SJamie Gritton } 861b38ff370SJamie Gritton 862b38ff370SJamie Gritton mtx_init(&pr->pr_mtx, "jail mutex", NULL, MTX_DEF); 863b38ff370SJamie Gritton 864b38ff370SJamie Gritton /* 865b38ff370SJamie Gritton * Allocate a dedicated cpuset for each jail. 866b38ff370SJamie Gritton * Unlike other initial settings, this may return an erorr. 867b38ff370SJamie Gritton */ 868b38ff370SJamie Gritton error = cpuset_create_root(td, &pr->pr_cpuset); 869b38ff370SJamie Gritton if (error) { 870b38ff370SJamie Gritton prison_deref(pr, PD_LIST_XLOCKED); 871b38ff370SJamie Gritton goto done_releroot; 872b38ff370SJamie Gritton } 873b38ff370SJamie Gritton 874b38ff370SJamie Gritton mtx_lock(&pr->pr_mtx); 875b38ff370SJamie Gritton /* 876b38ff370SJamie Gritton * New prisons do not yet have a reference, because we do not 877b38ff370SJamie Gritton * want other to see the incomplete prison once the 878b38ff370SJamie Gritton * allprison_lock is downgraded. 879b38ff370SJamie Gritton */ 880b38ff370SJamie Gritton } else { 881b38ff370SJamie Gritton created = 0; 882b38ff370SJamie Gritton /* 883b38ff370SJamie Gritton * Grab a reference for existing prisons, to ensure they 884b38ff370SJamie Gritton * continue to exist for the duration of the call. 885b38ff370SJamie Gritton */ 886b38ff370SJamie Gritton pr->pr_ref++; 887b38ff370SJamie Gritton } 888b38ff370SJamie Gritton 889b38ff370SJamie Gritton /* Do final error checking before setting anything. */ 890b38ff370SJamie Gritton error = 0; 891b38ff370SJamie Gritton #if defined(INET) || defined(INET6) 892b38ff370SJamie Gritton if ( 893b38ff370SJamie Gritton #ifdef INET 894b38ff370SJamie Gritton ip4s > 0 895b38ff370SJamie Gritton #ifdef INET6 896b38ff370SJamie Gritton || 897b38ff370SJamie Gritton #endif 898b38ff370SJamie Gritton #endif 899b38ff370SJamie Gritton #ifdef INET6 900b38ff370SJamie Gritton ip6s > 0 901b38ff370SJamie Gritton #endif 902b38ff370SJamie Gritton ) 903b38ff370SJamie Gritton /* 904b38ff370SJamie Gritton * Check for conflicting IP addresses. We permit them if there 905b38ff370SJamie Gritton * is no more than 1 IP on each jail. If there is a duplicate 906b38ff370SJamie Gritton * on a jail with more than one IP stop checking and return 907b38ff370SJamie Gritton * error. 908b38ff370SJamie Gritton */ 909b38ff370SJamie Gritton TAILQ_FOREACH(tpr, &allprison, pr_list) { 910b38ff370SJamie Gritton if (tpr == pr || tpr->pr_uref == 0) 911b38ff370SJamie Gritton continue; 912b38ff370SJamie Gritton #ifdef INET 913b38ff370SJamie Gritton if ((ip4s > 0 && tpr->pr_ip4s > 1) || 914b38ff370SJamie Gritton (ip4s > 1 && tpr->pr_ip4s > 0)) 915b38ff370SJamie Gritton for (ii = 0; ii < ip4s; ii++) 916b38ff370SJamie Gritton if (_prison_check_ip4(tpr, 917b38ff370SJamie Gritton &ip4[ii]) == 0) { 918b38ff370SJamie Gritton error = EINVAL; 919b38ff370SJamie Gritton vfs_opterror(opts, 920b38ff370SJamie Gritton "IPv4 addresses clash"); 921b38ff370SJamie Gritton goto done_deref_locked; 922b38ff370SJamie Gritton } 923b38ff370SJamie Gritton #endif 924b38ff370SJamie Gritton #ifdef INET6 925b38ff370SJamie Gritton if ((ip6s > 0 && tpr->pr_ip6s > 1) || 926b38ff370SJamie Gritton (ip6s > 1 && tpr->pr_ip6s > 0)) 927b38ff370SJamie Gritton for (ii = 0; ii < ip6s; ii++) 928b38ff370SJamie Gritton if (_prison_check_ip6(tpr, 929b38ff370SJamie Gritton &ip6[ii]) == 0) { 930b38ff370SJamie Gritton error = EINVAL; 931b38ff370SJamie Gritton vfs_opterror(opts, 932b38ff370SJamie Gritton "IPv6 addresses clash"); 933b38ff370SJamie Gritton goto done_deref_locked; 934b38ff370SJamie Gritton } 935b38ff370SJamie Gritton #endif 936b38ff370SJamie Gritton } 937b38ff370SJamie Gritton #endif 938b38ff370SJamie Gritton if (error == 0 && name != NULL) { 939b38ff370SJamie Gritton /* Give a default name of the jid. */ 940b38ff370SJamie Gritton if (name[0] == '\0') 941b38ff370SJamie Gritton snprintf(name = numbuf, sizeof(numbuf), "%d", jid); 942b38ff370SJamie Gritton else if (strtoul(name, &p, 10) != jid && *p == '\0') { 943b38ff370SJamie Gritton error = EINVAL; 944b38ff370SJamie Gritton vfs_opterror(opts, "name cannot be numeric"); 945b38ff370SJamie Gritton } 946b38ff370SJamie Gritton } 947b38ff370SJamie Gritton if (error) { 948b38ff370SJamie Gritton done_deref_locked: 949b38ff370SJamie Gritton /* 950b38ff370SJamie Gritton * Some parameter had an error so do not set anything. 951b38ff370SJamie Gritton * If this is a new jail, it will go away without ever 952b38ff370SJamie Gritton * having been seen. 953b38ff370SJamie Gritton */ 954b38ff370SJamie Gritton prison_deref(pr, created 955b38ff370SJamie Gritton ? PD_LOCKED | PD_LIST_XLOCKED 956b38ff370SJamie Gritton : PD_DEREF | PD_LOCKED | PD_LIST_XLOCKED); 957b38ff370SJamie Gritton goto done_releroot; 958b38ff370SJamie Gritton } 959b38ff370SJamie Gritton 960b38ff370SJamie Gritton /* Set the parameters of the prison. */ 961b38ff370SJamie Gritton #ifdef INET 962b38ff370SJamie Gritton if (ip4s >= 0) { 963b38ff370SJamie Gritton pr->pr_ip4s = ip4s; 964b38ff370SJamie Gritton free(pr->pr_ip4, M_PRISON); 965b38ff370SJamie Gritton pr->pr_ip4 = ip4; 966b38ff370SJamie Gritton ip4 = NULL; 967b38ff370SJamie Gritton } 968b38ff370SJamie Gritton #endif 969b38ff370SJamie Gritton #ifdef INET6 970b38ff370SJamie Gritton if (ip6s >= 0) { 971b38ff370SJamie Gritton pr->pr_ip6s = ip6s; 972b38ff370SJamie Gritton free(pr->pr_ip6, M_PRISON); 973b38ff370SJamie Gritton pr->pr_ip6 = ip6; 974b38ff370SJamie Gritton ip6 = NULL; 975b38ff370SJamie Gritton } 976b38ff370SJamie Gritton #endif 977b38ff370SJamie Gritton if (gotslevel) 978b38ff370SJamie Gritton pr->pr_securelevel = slevel; 979b38ff370SJamie Gritton if (name != NULL) 980b38ff370SJamie Gritton strlcpy(pr->pr_name, name, sizeof(pr->pr_name)); 981b38ff370SJamie Gritton if (path != NULL) { 982b38ff370SJamie Gritton strlcpy(pr->pr_path, path, sizeof(pr->pr_path)); 983b38ff370SJamie Gritton pr->pr_root = root; 984b38ff370SJamie Gritton } 985b38ff370SJamie Gritton if (host != NULL) 986b38ff370SJamie Gritton strlcpy(pr->pr_host, host, sizeof(pr->pr_host)); 987b38ff370SJamie Gritton /* 988b38ff370SJamie Gritton * Persistent prisons get an extra reference, and prisons losing their 989b38ff370SJamie Gritton * persist flag lose that reference. Only do this for existing prisons 990b38ff370SJamie Gritton * for now, so new ones will remain unseen until after the module 991b38ff370SJamie Gritton * handlers have completed. 992b38ff370SJamie Gritton */ 993b38ff370SJamie Gritton if (!created && (ch_flags & PR_PERSIST & (pr_flags ^ pr->pr_flags))) { 994b38ff370SJamie Gritton if (pr_flags & PR_PERSIST) { 995b38ff370SJamie Gritton pr->pr_ref++; 996b38ff370SJamie Gritton pr->pr_uref++; 997b38ff370SJamie Gritton } else { 998b38ff370SJamie Gritton pr->pr_ref--; 999b38ff370SJamie Gritton pr->pr_uref--; 1000b38ff370SJamie Gritton } 1001b38ff370SJamie Gritton } 1002b38ff370SJamie Gritton pr->pr_flags = (pr->pr_flags & ~ch_flags) | pr_flags; 1003b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 1004b38ff370SJamie Gritton 1005b38ff370SJamie Gritton /* Let the modules do their work. */ 1006b38ff370SJamie Gritton sx_downgrade(&allprison_lock); 1007b38ff370SJamie Gritton if (created) { 1008b38ff370SJamie Gritton error = osd_jail_call(pr, PR_METHOD_CREATE, opts); 1009b38ff370SJamie Gritton if (error) { 1010b38ff370SJamie Gritton prison_deref(pr, PD_LIST_SLOCKED); 1011b38ff370SJamie Gritton goto done_errmsg; 1012b38ff370SJamie Gritton } 1013b38ff370SJamie Gritton } 1014b38ff370SJamie Gritton error = osd_jail_call(pr, PR_METHOD_SET, opts); 1015b38ff370SJamie Gritton if (error) { 1016b38ff370SJamie Gritton prison_deref(pr, created 1017b38ff370SJamie Gritton ? PD_LIST_SLOCKED 1018b38ff370SJamie Gritton : PD_DEREF | PD_LIST_SLOCKED); 1019b38ff370SJamie Gritton goto done_errmsg; 1020b38ff370SJamie Gritton } 1021b38ff370SJamie Gritton 1022b38ff370SJamie Gritton /* Attach this process to the prison if requested. */ 1023b38ff370SJamie Gritton if (flags & JAIL_ATTACH) { 1024b38ff370SJamie Gritton mtx_lock(&pr->pr_mtx); 1025b38ff370SJamie Gritton error = do_jail_attach(td, pr); 1026b38ff370SJamie Gritton if (error) { 1027b38ff370SJamie Gritton vfs_opterror(opts, "attach failed"); 1028b38ff370SJamie Gritton if (!created) 1029b38ff370SJamie Gritton prison_deref(pr, PD_DEREF); 1030b38ff370SJamie Gritton goto done_errmsg; 1031b38ff370SJamie Gritton } 1032b38ff370SJamie Gritton } 1033b38ff370SJamie Gritton 1034b38ff370SJamie Gritton /* 1035b38ff370SJamie Gritton * Now that it is all there, drop the temporary reference from existing 1036b38ff370SJamie Gritton * prisons. Or add a reference to newly created persistent prisons 1037b38ff370SJamie Gritton * (which was not done earlier so that the prison would not be publicly 1038b38ff370SJamie Gritton * visible). 1039b38ff370SJamie Gritton */ 1040b38ff370SJamie Gritton if (!created) { 1041b38ff370SJamie Gritton prison_deref(pr, (flags & JAIL_ATTACH) 1042b38ff370SJamie Gritton ? PD_DEREF 1043b38ff370SJamie Gritton : PD_DEREF | PD_LIST_SLOCKED); 1044b38ff370SJamie Gritton } else { 1045b38ff370SJamie Gritton if (pr_flags & PR_PERSIST) { 1046b38ff370SJamie Gritton mtx_lock(&pr->pr_mtx); 1047b38ff370SJamie Gritton pr->pr_ref++; 1048b38ff370SJamie Gritton pr->pr_uref++; 1049b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 1050b38ff370SJamie Gritton } 1051b38ff370SJamie Gritton if (!(flags & JAIL_ATTACH)) 1052b38ff370SJamie Gritton sx_sunlock(&allprison_lock); 1053b38ff370SJamie Gritton } 1054b38ff370SJamie Gritton td->td_retval[0] = pr->pr_id; 1055b38ff370SJamie Gritton goto done_errmsg; 1056b38ff370SJamie Gritton 1057b38ff370SJamie Gritton done_unlock_list: 1058b38ff370SJamie Gritton sx_xunlock(&allprison_lock); 1059b38ff370SJamie Gritton done_releroot: 1060b38ff370SJamie Gritton if (root != NULL) { 1061b38ff370SJamie Gritton vfslocked = VFS_LOCK_GIANT(root->v_mount); 1062b38ff370SJamie Gritton vrele(root); 1063b38ff370SJamie Gritton VFS_UNLOCK_GIANT(vfslocked); 1064b38ff370SJamie Gritton } 1065b38ff370SJamie Gritton done_errmsg: 1066b38ff370SJamie Gritton if (error) { 1067b38ff370SJamie Gritton vfs_getopt(opts, "errmsg", (void **)&errmsg, &errmsg_len); 1068b38ff370SJamie Gritton if (errmsg_len > 0) { 1069b38ff370SJamie Gritton errmsg_pos = 2 * vfs_getopt_pos(opts, "errmsg") + 1; 1070b38ff370SJamie Gritton if (errmsg_pos > 0) { 1071b38ff370SJamie Gritton if (optuio->uio_segflg == UIO_SYSSPACE) 1072b38ff370SJamie Gritton bcopy(errmsg, 1073b38ff370SJamie Gritton optuio->uio_iov[errmsg_pos].iov_base, 1074b38ff370SJamie Gritton errmsg_len); 1075b38ff370SJamie Gritton else 1076b38ff370SJamie Gritton copyout(errmsg, 1077b38ff370SJamie Gritton optuio->uio_iov[errmsg_pos].iov_base, 1078b38ff370SJamie Gritton errmsg_len); 1079b38ff370SJamie Gritton } 1080b38ff370SJamie Gritton } 1081b38ff370SJamie Gritton } 1082b38ff370SJamie Gritton done_free: 1083b38ff370SJamie Gritton #ifdef INET 1084b38ff370SJamie Gritton free(ip4, M_PRISON); 1085b38ff370SJamie Gritton #endif 1086b38ff370SJamie Gritton #ifdef INET6 1087b38ff370SJamie Gritton free(ip6, M_PRISON); 1088b38ff370SJamie Gritton #endif 1089b38ff370SJamie Gritton vfs_freeopts(opts); 1090b38ff370SJamie Gritton return (error); 1091b38ff370SJamie Gritton } 1092b38ff370SJamie Gritton 1093b38ff370SJamie Gritton /* 1094b38ff370SJamie Gritton * Sysctl nodes to describe jail parameters. Maximum length of string 1095b38ff370SJamie Gritton * parameters is returned in the string itself, and the other parameters 1096b38ff370SJamie Gritton * exist merely to make themselves and their types known. 1097b38ff370SJamie Gritton */ 1098b38ff370SJamie Gritton SYSCTL_NODE(_security_jail, OID_AUTO, param, CTLFLAG_RW, 0, 1099b38ff370SJamie Gritton "Jail parameters"); 1100b38ff370SJamie Gritton 1101b38ff370SJamie Gritton int 1102b38ff370SJamie Gritton sysctl_jail_param(SYSCTL_HANDLER_ARGS) 1103b38ff370SJamie Gritton { 1104b38ff370SJamie Gritton int i; 1105b38ff370SJamie Gritton long l; 1106b38ff370SJamie Gritton size_t s; 1107b38ff370SJamie Gritton char numbuf[12]; 1108b38ff370SJamie Gritton 1109b38ff370SJamie Gritton switch (oidp->oid_kind & CTLTYPE) 1110b38ff370SJamie Gritton { 1111b38ff370SJamie Gritton case CTLTYPE_LONG: 1112b38ff370SJamie Gritton case CTLTYPE_ULONG: 1113b38ff370SJamie Gritton l = 0; 1114b38ff370SJamie Gritton #ifdef SCTL_MASK32 1115b38ff370SJamie Gritton if (!(req->flags & SCTL_MASK32)) 1116b38ff370SJamie Gritton #endif 1117b38ff370SJamie Gritton return (SYSCTL_OUT(req, &l, sizeof(l))); 1118b38ff370SJamie Gritton case CTLTYPE_INT: 1119b38ff370SJamie Gritton case CTLTYPE_UINT: 1120b38ff370SJamie Gritton i = 0; 1121b38ff370SJamie Gritton return (SYSCTL_OUT(req, &i, sizeof(i))); 1122b38ff370SJamie Gritton case CTLTYPE_STRING: 1123b38ff370SJamie Gritton snprintf(numbuf, sizeof(numbuf), "%d", arg2); 1124b38ff370SJamie Gritton return 1125b38ff370SJamie Gritton (sysctl_handle_string(oidp, numbuf, sizeof(numbuf), req)); 1126b38ff370SJamie Gritton case CTLTYPE_STRUCT: 1127b38ff370SJamie Gritton s = (size_t)arg2; 1128b38ff370SJamie Gritton return (SYSCTL_OUT(req, &s, sizeof(s))); 1129b38ff370SJamie Gritton } 1130b38ff370SJamie Gritton return (0); 1131b38ff370SJamie Gritton } 1132b38ff370SJamie Gritton 1133b38ff370SJamie Gritton SYSCTL_JAIL_PARAM(, jid, CTLTYPE_INT | CTLFLAG_RD, "I", "Jail ID"); 1134b38ff370SJamie Gritton SYSCTL_JAIL_PARAM_STRING(, name, CTLFLAG_RW, MAXHOSTNAMELEN, "Jail name"); 1135b38ff370SJamie Gritton SYSCTL_JAIL_PARAM(, cpuset, CTLTYPE_INT | CTLFLAG_RD, "I", "Jail cpuset ID"); 1136b38ff370SJamie Gritton SYSCTL_JAIL_PARAM_STRING(, path, CTLFLAG_RD, MAXPATHLEN, "Jail root path"); 1137b38ff370SJamie Gritton SYSCTL_JAIL_PARAM(, securelevel, CTLTYPE_INT | CTLFLAG_RW, 1138b38ff370SJamie Gritton "I", "Jail secure level"); 1139b38ff370SJamie Gritton SYSCTL_JAIL_PARAM(, persist, CTLTYPE_INT | CTLFLAG_RW, 1140b38ff370SJamie Gritton "B", "Jail persistence"); 1141b38ff370SJamie Gritton SYSCTL_JAIL_PARAM(, dying, CTLTYPE_INT | CTLFLAG_RD, 1142b38ff370SJamie Gritton "B", "Jail is in the process of shutting down"); 1143b38ff370SJamie Gritton 1144b38ff370SJamie Gritton SYSCTL_JAIL_PARAM_NODE(host, "Jail host info"); 1145b38ff370SJamie Gritton SYSCTL_JAIL_PARAM_STRING(_host, hostname, CTLFLAG_RW, MAXHOSTNAMELEN, 1146b38ff370SJamie Gritton "Jail hostname"); 1147b38ff370SJamie Gritton 1148b38ff370SJamie Gritton #ifdef INET 1149b38ff370SJamie Gritton SYSCTL_JAIL_PARAM_NODE(ip4, "Jail IPv4 address virtualization"); 1150b38ff370SJamie Gritton SYSCTL_JAIL_PARAM_STRUCT(_ip4, addr, CTLFLAG_RW, sizeof(struct in_addr), 1151b38ff370SJamie Gritton "S,in_addr,a", "Jail IPv4 addresses"); 1152b38ff370SJamie Gritton #endif 1153b38ff370SJamie Gritton #ifdef INET6 1154b38ff370SJamie Gritton SYSCTL_JAIL_PARAM_NODE(ip6, "Jail IPv6 address virtualization"); 1155b38ff370SJamie Gritton SYSCTL_JAIL_PARAM_STRUCT(_ip6, addr, CTLFLAG_RW, sizeof(struct in6_addr), 1156b38ff370SJamie Gritton "S,in6_addr,a", "Jail IPv6 addresses"); 1157b38ff370SJamie Gritton #endif 1158b38ff370SJamie Gritton 1159b38ff370SJamie Gritton 1160b38ff370SJamie Gritton /* 1161b38ff370SJamie Gritton * struct jail_get_args { 1162b38ff370SJamie Gritton * struct iovec *iovp; 1163b38ff370SJamie Gritton * unsigned int iovcnt; 1164b38ff370SJamie Gritton * int flags; 1165b38ff370SJamie Gritton * }; 1166b38ff370SJamie Gritton */ 1167b38ff370SJamie Gritton int 1168b38ff370SJamie Gritton jail_get(struct thread *td, struct jail_get_args *uap) 1169b38ff370SJamie Gritton { 1170b38ff370SJamie Gritton struct uio *auio; 1171b38ff370SJamie Gritton int error; 1172b38ff370SJamie Gritton 1173b38ff370SJamie Gritton /* Check that we have an even number of iovecs. */ 1174b38ff370SJamie Gritton if (uap->iovcnt & 1) 1175b38ff370SJamie Gritton return (EINVAL); 1176b38ff370SJamie Gritton 1177b38ff370SJamie Gritton error = copyinuio(uap->iovp, uap->iovcnt, &auio); 1178b38ff370SJamie Gritton if (error) 1179b38ff370SJamie Gritton return (error); 1180b38ff370SJamie Gritton error = kern_jail_get(td, auio, uap->flags); 1181b38ff370SJamie Gritton if (error == 0) 1182b38ff370SJamie Gritton error = copyout(auio->uio_iov, uap->iovp, 1183b38ff370SJamie Gritton uap->iovcnt * sizeof (struct iovec)); 1184b38ff370SJamie Gritton free(auio, M_IOV); 1185b38ff370SJamie Gritton return (error); 1186b38ff370SJamie Gritton } 1187b38ff370SJamie Gritton 1188b38ff370SJamie Gritton int 1189b38ff370SJamie Gritton kern_jail_get(struct thread *td, struct uio *optuio, int flags) 1190b38ff370SJamie Gritton { 1191b38ff370SJamie Gritton struct prison *pr; 1192b38ff370SJamie Gritton struct vfsopt *opt; 1193b38ff370SJamie Gritton struct vfsoptlist *opts; 1194b38ff370SJamie Gritton char *errmsg, *name; 1195b38ff370SJamie Gritton int error, errmsg_len, errmsg_pos, i, jid, len, locked, pos; 1196b38ff370SJamie Gritton 1197b38ff370SJamie Gritton if (flags & ~JAIL_GET_MASK) 1198b38ff370SJamie Gritton return (EINVAL); 1199b38ff370SJamie Gritton 1200b38ff370SJamie Gritton /* Get the parameter list. */ 1201b38ff370SJamie Gritton error = vfs_buildopts(optuio, &opts); 1202b38ff370SJamie Gritton if (error) 1203b38ff370SJamie Gritton return (error); 1204b38ff370SJamie Gritton errmsg_pos = vfs_getopt_pos(opts, "errmsg"); 1205b38ff370SJamie Gritton 12061e2a13e6SJamie Gritton /* Don't allow a jailed process to see any jails, not even its own. */ 12071e2a13e6SJamie Gritton if (jailed(td->td_ucred)) { 12081e2a13e6SJamie Gritton vfs_opterror(opts, "jail not found"); 12091e2a13e6SJamie Gritton return (ENOENT); 12101e2a13e6SJamie Gritton } 12111e2a13e6SJamie Gritton 1212b38ff370SJamie Gritton /* 1213b38ff370SJamie Gritton * Find the prison specified by one of: lastjid, jid, name. 1214b38ff370SJamie Gritton */ 1215b38ff370SJamie Gritton sx_slock(&allprison_lock); 1216b38ff370SJamie Gritton error = vfs_copyopt(opts, "lastjid", &jid, sizeof(jid)); 1217b38ff370SJamie Gritton if (error == 0) { 1218b38ff370SJamie Gritton TAILQ_FOREACH(pr, &allprison, pr_list) { 1219b38ff370SJamie Gritton if (pr->pr_id > jid) { 1220b38ff370SJamie Gritton mtx_lock(&pr->pr_mtx); 1221b38ff370SJamie Gritton if (pr->pr_ref > 0 && 1222b38ff370SJamie Gritton (pr->pr_uref > 0 || (flags & JAIL_DYING))) 1223b38ff370SJamie Gritton break; 1224b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 1225b38ff370SJamie Gritton } 1226b38ff370SJamie Gritton } 1227b38ff370SJamie Gritton if (pr != NULL) 1228b38ff370SJamie Gritton goto found_prison; 1229b38ff370SJamie Gritton error = ENOENT; 1230b38ff370SJamie Gritton vfs_opterror(opts, "no jail after %d", jid); 1231b38ff370SJamie Gritton goto done_unlock_list; 1232b38ff370SJamie Gritton } else if (error != ENOENT) 1233b38ff370SJamie Gritton goto done_unlock_list; 1234b38ff370SJamie Gritton 1235b38ff370SJamie Gritton error = vfs_copyopt(opts, "jid", &jid, sizeof(jid)); 1236b38ff370SJamie Gritton if (error == 0) { 1237b38ff370SJamie Gritton if (jid != 0) { 1238b38ff370SJamie Gritton pr = prison_find(jid); 1239b38ff370SJamie Gritton if (pr != NULL) { 1240b38ff370SJamie Gritton if (pr->pr_uref == 0 && !(flags & JAIL_DYING)) { 1241b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 1242b38ff370SJamie Gritton error = ENOENT; 1243b38ff370SJamie Gritton vfs_opterror(opts, "jail %d is dying", 1244b38ff370SJamie Gritton jid); 1245b38ff370SJamie Gritton goto done_unlock_list; 1246b38ff370SJamie Gritton } 1247b38ff370SJamie Gritton goto found_prison; 1248b38ff370SJamie Gritton } 1249b38ff370SJamie Gritton error = ENOENT; 1250b38ff370SJamie Gritton vfs_opterror(opts, "jail %d not found", jid); 1251b38ff370SJamie Gritton goto done_unlock_list; 1252b38ff370SJamie Gritton } 1253b38ff370SJamie Gritton } else if (error != ENOENT) 1254b38ff370SJamie Gritton goto done_unlock_list; 1255b38ff370SJamie Gritton 1256b38ff370SJamie Gritton error = vfs_getopt(opts, "name", (void **)&name, &len); 1257b38ff370SJamie Gritton if (error == 0) { 1258b38ff370SJamie Gritton if (len == 0 || name[len - 1] != '\0') { 1259b38ff370SJamie Gritton error = EINVAL; 1260b38ff370SJamie Gritton goto done_unlock_list; 1261b38ff370SJamie Gritton } 1262b38ff370SJamie Gritton pr = prison_find_name(name); 1263b38ff370SJamie Gritton if (pr != NULL) { 1264b38ff370SJamie Gritton if (pr->pr_uref == 0 && !(flags & JAIL_DYING)) { 1265b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 1266b38ff370SJamie Gritton error = ENOENT; 1267b38ff370SJamie Gritton vfs_opterror(opts, "jail \"%s\" is dying", 1268b38ff370SJamie Gritton name); 1269b38ff370SJamie Gritton goto done_unlock_list; 1270b38ff370SJamie Gritton } 1271b38ff370SJamie Gritton goto found_prison; 1272b38ff370SJamie Gritton } 1273b38ff370SJamie Gritton error = ENOENT; 1274b38ff370SJamie Gritton vfs_opterror(opts, "jail \"%s\" not found", name); 1275b38ff370SJamie Gritton goto done_unlock_list; 1276b38ff370SJamie Gritton } else if (error != ENOENT) 1277b38ff370SJamie Gritton goto done_unlock_list; 1278b38ff370SJamie Gritton 1279b38ff370SJamie Gritton vfs_opterror(opts, "no jail specified"); 1280b38ff370SJamie Gritton error = ENOENT; 1281b38ff370SJamie Gritton goto done_unlock_list; 1282b38ff370SJamie Gritton 1283b38ff370SJamie Gritton found_prison: 1284b38ff370SJamie Gritton /* Get the parameters of the prison. */ 1285b38ff370SJamie Gritton pr->pr_ref++; 1286b38ff370SJamie Gritton locked = PD_LOCKED; 1287b38ff370SJamie Gritton td->td_retval[0] = pr->pr_id; 1288b38ff370SJamie Gritton error = vfs_setopt(opts, "jid", &pr->pr_id, sizeof(pr->pr_id)); 1289b38ff370SJamie Gritton if (error != 0 && error != ENOENT) 1290b38ff370SJamie Gritton goto done_deref; 1291b38ff370SJamie Gritton error = vfs_setopts(opts, "name", pr->pr_name); 1292b38ff370SJamie Gritton if (error != 0 && error != ENOENT) 1293b38ff370SJamie Gritton goto done_deref; 1294b38ff370SJamie Gritton error = vfs_setopt(opts, "cpuset", &pr->pr_cpuset->cs_id, 1295b38ff370SJamie Gritton sizeof(pr->pr_cpuset->cs_id)); 1296b38ff370SJamie Gritton if (error != 0 && error != ENOENT) 1297b38ff370SJamie Gritton goto done_deref; 1298b38ff370SJamie Gritton error = vfs_setopts(opts, "path", pr->pr_path); 1299b38ff370SJamie Gritton if (error != 0 && error != ENOENT) 1300b38ff370SJamie Gritton goto done_deref; 1301b38ff370SJamie Gritton #ifdef INET 1302b38ff370SJamie Gritton error = vfs_setopt_part(opts, "ip4.addr", pr->pr_ip4, 1303b38ff370SJamie Gritton pr->pr_ip4s * sizeof(*pr->pr_ip4)); 1304b38ff370SJamie Gritton if (error != 0 && error != ENOENT) 1305b38ff370SJamie Gritton goto done_deref; 1306b38ff370SJamie Gritton #endif 1307b38ff370SJamie Gritton #ifdef INET6 1308b38ff370SJamie Gritton error = vfs_setopt_part(opts, "ip6.addr", pr->pr_ip6, 1309b38ff370SJamie Gritton pr->pr_ip6s * sizeof(*pr->pr_ip6)); 1310b38ff370SJamie Gritton if (error != 0 && error != ENOENT) 1311b38ff370SJamie Gritton goto done_deref; 1312b38ff370SJamie Gritton #endif 1313b38ff370SJamie Gritton error = vfs_setopt(opts, "securelevel", &pr->pr_securelevel, 1314b38ff370SJamie Gritton sizeof(pr->pr_securelevel)); 1315b38ff370SJamie Gritton if (error != 0 && error != ENOENT) 1316b38ff370SJamie Gritton goto done_deref; 1317b38ff370SJamie Gritton error = vfs_setopts(opts, "host.hostname", pr->pr_host); 1318b38ff370SJamie Gritton if (error != 0 && error != ENOENT) 1319b38ff370SJamie Gritton goto done_deref; 1320b38ff370SJamie Gritton i = pr->pr_flags & PR_PERSIST ? 1 : 0; 1321b38ff370SJamie Gritton error = vfs_setopt(opts, "persist", &i, sizeof(i)); 1322b38ff370SJamie Gritton if (error != 0 && error != ENOENT) 1323b38ff370SJamie Gritton goto done_deref; 1324b38ff370SJamie Gritton i = !i; 1325b38ff370SJamie Gritton error = vfs_setopt(opts, "nopersist", &i, sizeof(i)); 1326b38ff370SJamie Gritton if (error != 0 && error != ENOENT) 1327b38ff370SJamie Gritton goto done_deref; 1328b38ff370SJamie Gritton i = (pr->pr_uref == 0); 1329b38ff370SJamie Gritton error = vfs_setopt(opts, "dying", &i, sizeof(i)); 1330b38ff370SJamie Gritton if (error != 0 && error != ENOENT) 1331b38ff370SJamie Gritton goto done_deref; 1332b38ff370SJamie Gritton i = !i; 1333b38ff370SJamie Gritton error = vfs_setopt(opts, "nodying", &i, sizeof(i)); 1334b38ff370SJamie Gritton if (error != 0 && error != ENOENT) 1335b38ff370SJamie Gritton goto done_deref; 1336b38ff370SJamie Gritton 1337b38ff370SJamie Gritton /* Get the module parameters. */ 1338b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 1339b38ff370SJamie Gritton locked = 0; 1340b38ff370SJamie Gritton error = osd_jail_call(pr, PR_METHOD_GET, opts); 1341b38ff370SJamie Gritton if (error) 1342b38ff370SJamie Gritton goto done_deref; 1343b38ff370SJamie Gritton prison_deref(pr, PD_DEREF | PD_LIST_SLOCKED); 1344b38ff370SJamie Gritton 1345b38ff370SJamie Gritton /* By now, all parameters should have been noted. */ 1346b38ff370SJamie Gritton TAILQ_FOREACH(opt, opts, link) { 1347b38ff370SJamie Gritton if (!opt->seen && strcmp(opt->name, "errmsg")) { 1348b38ff370SJamie Gritton error = EINVAL; 1349b38ff370SJamie Gritton vfs_opterror(opts, "unknown parameter: %s", opt->name); 1350b38ff370SJamie Gritton goto done_errmsg; 1351b38ff370SJamie Gritton } 1352b38ff370SJamie Gritton } 1353b38ff370SJamie Gritton 1354b38ff370SJamie Gritton /* Write the fetched parameters back to userspace. */ 1355b38ff370SJamie Gritton error = 0; 1356b38ff370SJamie Gritton TAILQ_FOREACH(opt, opts, link) { 1357b38ff370SJamie Gritton if (opt->pos >= 0 && opt->pos != errmsg_pos) { 1358b38ff370SJamie Gritton pos = 2 * opt->pos + 1; 1359b38ff370SJamie Gritton optuio->uio_iov[pos].iov_len = opt->len; 1360b38ff370SJamie Gritton if (opt->value != NULL) { 1361b38ff370SJamie Gritton if (optuio->uio_segflg == UIO_SYSSPACE) { 1362b38ff370SJamie Gritton bcopy(opt->value, 1363b38ff370SJamie Gritton optuio->uio_iov[pos].iov_base, 1364b38ff370SJamie Gritton opt->len); 1365b38ff370SJamie Gritton } else { 1366b38ff370SJamie Gritton error = copyout(opt->value, 1367b38ff370SJamie Gritton optuio->uio_iov[pos].iov_base, 1368b38ff370SJamie Gritton opt->len); 1369b38ff370SJamie Gritton if (error) 1370b38ff370SJamie Gritton break; 1371b38ff370SJamie Gritton } 1372b38ff370SJamie Gritton } 1373b38ff370SJamie Gritton } 1374b38ff370SJamie Gritton } 1375b38ff370SJamie Gritton goto done_errmsg; 1376b38ff370SJamie Gritton 1377b38ff370SJamie Gritton done_deref: 1378b38ff370SJamie Gritton prison_deref(pr, locked | PD_DEREF | PD_LIST_SLOCKED); 1379b38ff370SJamie Gritton goto done_errmsg; 1380b38ff370SJamie Gritton 1381b38ff370SJamie Gritton done_unlock_list: 1382b38ff370SJamie Gritton sx_sunlock(&allprison_lock); 1383b38ff370SJamie Gritton done_errmsg: 1384b38ff370SJamie Gritton if (error && errmsg_pos >= 0) { 1385b38ff370SJamie Gritton vfs_getopt(opts, "errmsg", (void **)&errmsg, &errmsg_len); 1386b38ff370SJamie Gritton errmsg_pos = 2 * errmsg_pos + 1; 1387b38ff370SJamie Gritton if (errmsg_len > 0) { 1388b38ff370SJamie Gritton if (optuio->uio_segflg == UIO_SYSSPACE) 1389b38ff370SJamie Gritton bcopy(errmsg, 1390b38ff370SJamie Gritton optuio->uio_iov[errmsg_pos].iov_base, 1391b38ff370SJamie Gritton errmsg_len); 1392b38ff370SJamie Gritton else 1393b38ff370SJamie Gritton copyout(errmsg, 1394b38ff370SJamie Gritton optuio->uio_iov[errmsg_pos].iov_base, 1395b38ff370SJamie Gritton errmsg_len); 1396b38ff370SJamie Gritton } 1397b38ff370SJamie Gritton } 1398b38ff370SJamie Gritton vfs_freeopts(opts); 1399b38ff370SJamie Gritton return (error); 1400b38ff370SJamie Gritton } 1401b38ff370SJamie Gritton 1402b38ff370SJamie Gritton /* 1403b38ff370SJamie Gritton * struct jail_remove_args { 1404b38ff370SJamie Gritton * int jid; 1405b38ff370SJamie Gritton * }; 1406b38ff370SJamie Gritton */ 1407b38ff370SJamie Gritton int 1408b38ff370SJamie Gritton jail_remove(struct thread *td, struct jail_remove_args *uap) 1409b38ff370SJamie Gritton { 1410b38ff370SJamie Gritton struct prison *pr; 1411b38ff370SJamie Gritton struct proc *p; 1412b38ff370SJamie Gritton int deuref, error; 1413b38ff370SJamie Gritton 1414b38ff370SJamie Gritton error = priv_check(td, PRIV_JAIL_REMOVE); 1415b38ff370SJamie Gritton if (error) 1416b38ff370SJamie Gritton return (error); 1417b38ff370SJamie Gritton 1418b38ff370SJamie Gritton sx_xlock(&allprison_lock); 1419b38ff370SJamie Gritton pr = prison_find(uap->jid); 1420b38ff370SJamie Gritton if (pr == NULL) { 1421b38ff370SJamie Gritton sx_xunlock(&allprison_lock); 1422b38ff370SJamie Gritton return (EINVAL); 1423b38ff370SJamie Gritton } 1424b38ff370SJamie Gritton 1425b38ff370SJamie Gritton /* If the prison was persistent, it is not anymore. */ 1426b38ff370SJamie Gritton deuref = 0; 1427b38ff370SJamie Gritton if (pr->pr_flags & PR_PERSIST) { 1428b38ff370SJamie Gritton pr->pr_ref--; 1429b38ff370SJamie Gritton deuref = PD_DEUREF; 1430b38ff370SJamie Gritton pr->pr_flags &= ~PR_PERSIST; 1431b38ff370SJamie Gritton } 1432b38ff370SJamie Gritton 1433b38ff370SJamie Gritton /* If there are no references left, remove the prison now. */ 1434b38ff370SJamie Gritton if (pr->pr_ref == 0) { 1435b38ff370SJamie Gritton prison_deref(pr, 1436b38ff370SJamie Gritton deuref | PD_DEREF | PD_LOCKED | PD_LIST_XLOCKED); 1437b38ff370SJamie Gritton return (0); 1438b38ff370SJamie Gritton } 1439b38ff370SJamie Gritton 1440b38ff370SJamie Gritton /* 1441b38ff370SJamie Gritton * Keep a temporary reference to make sure this prison sticks around. 1442b38ff370SJamie Gritton */ 1443b38ff370SJamie Gritton pr->pr_ref++; 1444b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 1445b38ff370SJamie Gritton sx_xunlock(&allprison_lock); 1446b38ff370SJamie Gritton /* 1447b38ff370SJamie Gritton * Kill all processes unfortunate enough to be attached to this prison. 1448b38ff370SJamie Gritton */ 1449b38ff370SJamie Gritton sx_slock(&allproc_lock); 1450b38ff370SJamie Gritton LIST_FOREACH(p, &allproc, p_list) { 1451b38ff370SJamie Gritton PROC_LOCK(p); 1452b38ff370SJamie Gritton if (p->p_state != PRS_NEW && p->p_ucred && 1453b38ff370SJamie Gritton p->p_ucred->cr_prison == pr) 1454b38ff370SJamie Gritton psignal(p, SIGKILL); 1455b38ff370SJamie Gritton PROC_UNLOCK(p); 1456b38ff370SJamie Gritton } 1457b38ff370SJamie Gritton sx_sunlock(&allproc_lock); 1458b38ff370SJamie Gritton /* Remove the temporary reference. */ 1459b38ff370SJamie Gritton prison_deref(pr, deuref | PD_DEREF); 1460b38ff370SJamie Gritton return (0); 146175c13541SPoul-Henning Kamp } 146275c13541SPoul-Henning Kamp 14638571af59SJamie Gritton 1464fd7a8150SMike Barcroft /* 14659ddb7954SMike Barcroft * struct jail_attach_args { 14669ddb7954SMike Barcroft * int jid; 14679ddb7954SMike Barcroft * }; 1468fd7a8150SMike Barcroft */ 1469fd7a8150SMike Barcroft int 14709ddb7954SMike Barcroft jail_attach(struct thread *td, struct jail_attach_args *uap) 1471fd7a8150SMike Barcroft { 1472b38ff370SJamie Gritton struct prison *pr; 1473b38ff370SJamie Gritton int error; 1474b38ff370SJamie Gritton 1475b38ff370SJamie Gritton error = priv_check(td, PRIV_JAIL_ATTACH); 1476b38ff370SJamie Gritton if (error) 1477b38ff370SJamie Gritton return (error); 1478b38ff370SJamie Gritton 1479b38ff370SJamie Gritton sx_slock(&allprison_lock); 1480b38ff370SJamie Gritton pr = prison_find(uap->jid); 1481b38ff370SJamie Gritton if (pr == NULL) { 1482b38ff370SJamie Gritton sx_sunlock(&allprison_lock); 1483b38ff370SJamie Gritton return (EINVAL); 1484b38ff370SJamie Gritton } 1485b38ff370SJamie Gritton 1486b38ff370SJamie Gritton /* 1487b38ff370SJamie Gritton * Do not allow a process to attach to a prison that is not 1488b38ff370SJamie Gritton * considered to be "alive". 1489b38ff370SJamie Gritton */ 1490b38ff370SJamie Gritton if (pr->pr_uref == 0) { 1491b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 1492b38ff370SJamie Gritton sx_sunlock(&allprison_lock); 1493b38ff370SJamie Gritton return (EINVAL); 1494b38ff370SJamie Gritton } 1495b38ff370SJamie Gritton 1496b38ff370SJamie Gritton return (do_jail_attach(td, pr)); 1497b38ff370SJamie Gritton } 1498b38ff370SJamie Gritton 1499b38ff370SJamie Gritton static int 1500b38ff370SJamie Gritton do_jail_attach(struct thread *td, struct prison *pr) 1501b38ff370SJamie Gritton { 1502fd7a8150SMike Barcroft struct proc *p; 1503fd7a8150SMike Barcroft struct ucred *newcred, *oldcred; 1504453f7d53SChristian S.J. Peron int vfslocked, error; 1505fd7a8150SMike Barcroft 150657f22bd4SJacques Vidrine /* 150757f22bd4SJacques Vidrine * XXX: Note that there is a slight race here if two threads 150857f22bd4SJacques Vidrine * in the same privileged process attempt to attach to two 150957f22bd4SJacques Vidrine * different jails at the same time. It is important for 151057f22bd4SJacques Vidrine * user processes not to do this, or they might end up with 151157f22bd4SJacques Vidrine * a process root from one prison, but attached to the jail 151257f22bd4SJacques Vidrine * of another. 151357f22bd4SJacques Vidrine */ 1514fd7a8150SMike Barcroft pr->pr_ref++; 1515b38ff370SJamie Gritton pr->pr_uref++; 1516fd7a8150SMike Barcroft mtx_unlock(&pr->pr_mtx); 1517b38ff370SJamie Gritton 1518b38ff370SJamie Gritton /* Let modules do whatever they need to prepare for attaching. */ 1519b38ff370SJamie Gritton error = osd_jail_call(pr, PR_METHOD_ATTACH, td); 1520b38ff370SJamie Gritton if (error) { 1521b38ff370SJamie Gritton prison_deref(pr, PD_DEREF | PD_DEUREF | PD_LIST_SLOCKED); 1522b38ff370SJamie Gritton return (error); 1523b38ff370SJamie Gritton } 1524dc68a633SPawel Jakub Dawidek sx_sunlock(&allprison_lock); 1525fd7a8150SMike Barcroft 1526413628a7SBjoern A. Zeeb /* 1527413628a7SBjoern A. Zeeb * Reparent the newly attached process to this jail. 1528413628a7SBjoern A. Zeeb */ 1529b38ff370SJamie Gritton p = td->td_proc; 1530413628a7SBjoern A. Zeeb error = cpuset_setproc_update_set(p, pr->pr_cpuset); 1531413628a7SBjoern A. Zeeb if (error) 1532b38ff370SJamie Gritton goto e_revert_osd; 1533413628a7SBjoern A. Zeeb 1534453f7d53SChristian S.J. Peron vfslocked = VFS_LOCK_GIANT(pr->pr_root->v_mount); 1535cb05b60aSAttilio Rao vn_lock(pr->pr_root, LK_EXCLUSIVE | LK_RETRY); 1536fd7a8150SMike Barcroft if ((error = change_dir(pr->pr_root, td)) != 0) 1537fd7a8150SMike Barcroft goto e_unlock; 1538fd7a8150SMike Barcroft #ifdef MAC 153930d239bcSRobert Watson if ((error = mac_vnode_check_chroot(td->td_ucred, pr->pr_root))) 1540fd7a8150SMike Barcroft goto e_unlock; 1541fd7a8150SMike Barcroft #endif 154222db15c0SAttilio Rao VOP_UNLOCK(pr->pr_root, 0); 1543b38ff370SJamie Gritton if ((error = change_root(pr->pr_root, td))) 1544b38ff370SJamie Gritton goto e_unlock_giant; 1545453f7d53SChristian S.J. Peron VFS_UNLOCK_GIANT(vfslocked); 1546fd7a8150SMike Barcroft 1547fd7a8150SMike Barcroft newcred = crget(); 1548fd7a8150SMike Barcroft PROC_LOCK(p); 1549fd7a8150SMike Barcroft oldcred = p->p_ucred; 1550fd7a8150SMike Barcroft setsugid(p); 1551fd7a8150SMike Barcroft crcopy(newcred, oldcred); 155269c4ee54SJohn Baldwin newcred->cr_prison = pr; 1553fd7a8150SMike Barcroft p->p_ucred = newcred; 1554fd7a8150SMike Barcroft PROC_UNLOCK(p); 1555fd7a8150SMike Barcroft crfree(oldcred); 1556fd7a8150SMike Barcroft return (0); 1557fd7a8150SMike Barcroft e_unlock: 155822db15c0SAttilio Rao VOP_UNLOCK(pr->pr_root, 0); 1559b38ff370SJamie Gritton e_unlock_giant: 1560453f7d53SChristian S.J. Peron VFS_UNLOCK_GIANT(vfslocked); 1561b38ff370SJamie Gritton e_revert_osd: 1562b38ff370SJamie Gritton /* Tell modules this thread is still in its old jail after all. */ 1563b38ff370SJamie Gritton (void)osd_jail_call(td->td_ucred->cr_prison, PR_METHOD_ATTACH, td); 1564b38ff370SJamie Gritton prison_deref(pr, PD_DEREF | PD_DEUREF); 1565fd7a8150SMike Barcroft return (error); 1566fd7a8150SMike Barcroft } 1567fd7a8150SMike Barcroft 1568fd7a8150SMike Barcroft /* 1569fd7a8150SMike Barcroft * Returns a locked prison instance, or NULL on failure. 1570fd7a8150SMike Barcroft */ 157154b369c1SPawel Jakub Dawidek struct prison * 1572fd7a8150SMike Barcroft prison_find(int prid) 1573fd7a8150SMike Barcroft { 1574fd7a8150SMike Barcroft struct prison *pr; 1575fd7a8150SMike Barcroft 1576dc68a633SPawel Jakub Dawidek sx_assert(&allprison_lock, SX_LOCKED); 1577b38ff370SJamie Gritton TAILQ_FOREACH(pr, &allprison, pr_list) { 1578fd7a8150SMike Barcroft if (pr->pr_id == prid) { 1579fd7a8150SMike Barcroft mtx_lock(&pr->pr_mtx); 1580b38ff370SJamie Gritton if (pr->pr_ref > 0) 1581fd7a8150SMike Barcroft return (pr); 1582b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 1583fd7a8150SMike Barcroft } 1584fd7a8150SMike Barcroft } 1585fd7a8150SMike Barcroft return (NULL); 1586fd7a8150SMike Barcroft } 1587fd7a8150SMike Barcroft 1588b38ff370SJamie Gritton /* 1589b38ff370SJamie Gritton * Look for the named prison. Returns a locked prison or NULL. 1590b38ff370SJamie Gritton */ 1591b38ff370SJamie Gritton struct prison * 1592b38ff370SJamie Gritton prison_find_name(const char *name) 1593b38ff370SJamie Gritton { 1594b38ff370SJamie Gritton struct prison *pr, *deadpr; 1595b38ff370SJamie Gritton 1596b38ff370SJamie Gritton sx_assert(&allprison_lock, SX_LOCKED); 1597b38ff370SJamie Gritton again: 1598b38ff370SJamie Gritton deadpr = NULL; 1599b38ff370SJamie Gritton TAILQ_FOREACH(pr, &allprison, pr_list) { 1600b38ff370SJamie Gritton if (!strcmp(pr->pr_name, name)) { 1601b38ff370SJamie Gritton mtx_lock(&pr->pr_mtx); 1602b38ff370SJamie Gritton if (pr->pr_ref > 0) { 1603b38ff370SJamie Gritton if (pr->pr_uref > 0) 1604b38ff370SJamie Gritton return (pr); 1605b38ff370SJamie Gritton deadpr = pr; 1606b38ff370SJamie Gritton } 1607b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 1608b38ff370SJamie Gritton } 1609b38ff370SJamie Gritton } 1610b38ff370SJamie Gritton /* There was no valid prison - perhaps there was a dying one */ 1611b38ff370SJamie Gritton if (deadpr != NULL) { 1612b38ff370SJamie Gritton mtx_lock(&deadpr->pr_mtx); 1613b38ff370SJamie Gritton if (deadpr->pr_ref == 0) { 1614b38ff370SJamie Gritton mtx_unlock(&deadpr->pr_mtx); 1615b38ff370SJamie Gritton goto again; 1616b38ff370SJamie Gritton } 1617b38ff370SJamie Gritton } 1618b38ff370SJamie Gritton return (deadpr); 1619b38ff370SJamie Gritton } 1620b38ff370SJamie Gritton 1621b38ff370SJamie Gritton /* 1622b38ff370SJamie Gritton * Remove a prison reference. If that was the last reference, remove the 1623b38ff370SJamie Gritton * prison itself - but not in this context in case there are locks held. 1624b38ff370SJamie Gritton */ 162591421ba2SRobert Watson void 16261ba4a712SPawel Jakub Dawidek prison_free_locked(struct prison *pr) 162791421ba2SRobert Watson { 162891421ba2SRobert Watson 16291ba4a712SPawel Jakub Dawidek mtx_assert(&pr->pr_mtx, MA_OWNED); 163091421ba2SRobert Watson pr->pr_ref--; 163191421ba2SRobert Watson if (pr->pr_ref == 0) { 163201137630SRobert Watson mtx_unlock(&pr->pr_mtx); 1633c2cda609SPawel Jakub Dawidek TASK_INIT(&pr->pr_task, 0, prison_complete, pr); 1634c2cda609SPawel Jakub Dawidek taskqueue_enqueue(taskqueue_thread, &pr->pr_task); 1635c2cda609SPawel Jakub Dawidek return; 1636c2cda609SPawel Jakub Dawidek } 1637c2cda609SPawel Jakub Dawidek mtx_unlock(&pr->pr_mtx); 1638c2cda609SPawel Jakub Dawidek } 1639c2cda609SPawel Jakub Dawidek 16401ba4a712SPawel Jakub Dawidek void 16411ba4a712SPawel Jakub Dawidek prison_free(struct prison *pr) 16421ba4a712SPawel Jakub Dawidek { 16431ba4a712SPawel Jakub Dawidek 16441ba4a712SPawel Jakub Dawidek mtx_lock(&pr->pr_mtx); 16451ba4a712SPawel Jakub Dawidek prison_free_locked(pr); 16461ba4a712SPawel Jakub Dawidek } 16471ba4a712SPawel Jakub Dawidek 1648c2cda609SPawel Jakub Dawidek static void 1649c2cda609SPawel Jakub Dawidek prison_complete(void *context, int pending) 1650c2cda609SPawel Jakub Dawidek { 1651b38ff370SJamie Gritton 1652b38ff370SJamie Gritton prison_deref((struct prison *)context, 0); 1653b38ff370SJamie Gritton } 1654b38ff370SJamie Gritton 1655b38ff370SJamie Gritton /* 1656b38ff370SJamie Gritton * Remove a prison reference (usually). This internal version assumes no 1657b38ff370SJamie Gritton * mutexes are held, except perhaps the prison itself. If there are no more 1658b38ff370SJamie Gritton * references, release and delist the prison. On completion, the prison lock 1659b38ff370SJamie Gritton * and the allprison lock are both unlocked. 1660b38ff370SJamie Gritton */ 1661b38ff370SJamie Gritton static void 1662b38ff370SJamie Gritton prison_deref(struct prison *pr, int flags) 1663b38ff370SJamie Gritton { 1664c2cda609SPawel Jakub Dawidek int vfslocked; 1665c2cda609SPawel Jakub Dawidek 1666b38ff370SJamie Gritton if (!(flags & PD_LOCKED)) 1667b38ff370SJamie Gritton mtx_lock(&pr->pr_mtx); 1668b38ff370SJamie Gritton if (flags & PD_DEUREF) { 1669b38ff370SJamie Gritton pr->pr_uref--; 1670b38ff370SJamie Gritton /* Done if there were only user references to remove. */ 1671b38ff370SJamie Gritton if (!(flags & PD_DEREF)) { 1672b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 1673b38ff370SJamie Gritton if (flags & PD_LIST_SLOCKED) 1674b38ff370SJamie Gritton sx_sunlock(&allprison_lock); 1675b38ff370SJamie Gritton else if (flags & PD_LIST_XLOCKED) 1676b38ff370SJamie Gritton sx_xunlock(&allprison_lock); 1677b38ff370SJamie Gritton return; 1678b38ff370SJamie Gritton } 1679b38ff370SJamie Gritton } 1680b38ff370SJamie Gritton if (flags & PD_DEREF) 1681b38ff370SJamie Gritton pr->pr_ref--; 1682b38ff370SJamie Gritton /* If the prison still has references, nothing else to do. */ 1683b38ff370SJamie Gritton if (pr->pr_ref > 0) { 1684b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 1685b38ff370SJamie Gritton if (flags & PD_LIST_SLOCKED) 1686b38ff370SJamie Gritton sx_sunlock(&allprison_lock); 1687b38ff370SJamie Gritton else if (flags & PD_LIST_XLOCKED) 1688b38ff370SJamie Gritton sx_xunlock(&allprison_lock); 1689b38ff370SJamie Gritton return; 1690b38ff370SJamie Gritton } 1691c2cda609SPawel Jakub Dawidek 1692b38ff370SJamie Gritton KASSERT(pr->pr_uref == 0, 1693b38ff370SJamie Gritton ("%s: Trying to remove an active prison (jid=%d).", __func__, 1694b38ff370SJamie Gritton pr->pr_id)); 1695b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 1696b38ff370SJamie Gritton if (flags & PD_LIST_SLOCKED) { 1697b38ff370SJamie Gritton if (!sx_try_upgrade(&allprison_lock)) { 1698b38ff370SJamie Gritton sx_sunlock(&allprison_lock); 1699c2cda609SPawel Jakub Dawidek sx_xlock(&allprison_lock); 1700b38ff370SJamie Gritton } 1701b38ff370SJamie Gritton } else if (!(flags & PD_LIST_XLOCKED)) 1702b38ff370SJamie Gritton sx_xlock(&allprison_lock); 1703b38ff370SJamie Gritton 1704b38ff370SJamie Gritton TAILQ_REMOVE(&allprison, pr, pr_list); 1705fd7a8150SMike Barcroft prisoncount--; 17061ba4a712SPawel Jakub Dawidek sx_xunlock(&allprison_lock); 17071ba4a712SPawel Jakub Dawidek 1708b38ff370SJamie Gritton if (pr->pr_root != NULL) { 1709453f7d53SChristian S.J. Peron vfslocked = VFS_LOCK_GIANT(pr->pr_root->v_mount); 1710b3059e09SRobert Watson vrele(pr->pr_root); 1711453f7d53SChristian S.J. Peron VFS_UNLOCK_GIANT(vfslocked); 1712b38ff370SJamie Gritton } 1713b3059e09SRobert Watson mtx_destroy(&pr->pr_mtx); 1714413628a7SBjoern A. Zeeb #ifdef INET 1715413628a7SBjoern A. Zeeb free(pr->pr_ip4, M_PRISON); 1716413628a7SBjoern A. Zeeb #endif 1717b38ff370SJamie Gritton #ifdef INET6 1718b38ff370SJamie Gritton free(pr->pr_ip6, M_PRISON); 1719b38ff370SJamie Gritton #endif 1720b38ff370SJamie Gritton if (pr->pr_cpuset != NULL) 1721b38ff370SJamie Gritton cpuset_rel(pr->pr_cpuset); 1722b38ff370SJamie Gritton osd_jail_exit(pr); 17231ede983cSDag-Erling Smørgrav free(pr, M_PRISON); 1724b3059e09SRobert Watson } 1725b3059e09SRobert Watson 172691421ba2SRobert Watson void 17271ba4a712SPawel Jakub Dawidek prison_hold_locked(struct prison *pr) 17281ba4a712SPawel Jakub Dawidek { 17291ba4a712SPawel Jakub Dawidek 17301ba4a712SPawel Jakub Dawidek mtx_assert(&pr->pr_mtx, MA_OWNED); 17311ba4a712SPawel Jakub Dawidek KASSERT(pr->pr_ref > 0, 1732af7bd9a4SJamie Gritton ("Trying to hold dead prison (jid=%d).", pr->pr_id)); 17331ba4a712SPawel Jakub Dawidek pr->pr_ref++; 17341ba4a712SPawel Jakub Dawidek } 17351ba4a712SPawel Jakub Dawidek 17361ba4a712SPawel Jakub Dawidek void 173791421ba2SRobert Watson prison_hold(struct prison *pr) 173891421ba2SRobert Watson { 173991421ba2SRobert Watson 174001137630SRobert Watson mtx_lock(&pr->pr_mtx); 17411ba4a712SPawel Jakub Dawidek prison_hold_locked(pr); 174201137630SRobert Watson mtx_unlock(&pr->pr_mtx); 174301137630SRobert Watson } 174401137630SRobert Watson 1745413628a7SBjoern A. Zeeb void 1746413628a7SBjoern A. Zeeb prison_proc_hold(struct prison *pr) 174701137630SRobert Watson { 174801137630SRobert Watson 1749413628a7SBjoern A. Zeeb mtx_lock(&pr->pr_mtx); 1750b38ff370SJamie Gritton KASSERT(pr->pr_uref > 0, 1751b38ff370SJamie Gritton ("Cannot add a process to a non-alive prison (jid=%d)", pr->pr_id)); 1752b38ff370SJamie Gritton pr->pr_uref++; 1753413628a7SBjoern A. Zeeb mtx_unlock(&pr->pr_mtx); 175475c13541SPoul-Henning Kamp } 175575c13541SPoul-Henning Kamp 175675c13541SPoul-Henning Kamp void 1757413628a7SBjoern A. Zeeb prison_proc_free(struct prison *pr) 175875c13541SPoul-Henning Kamp { 1759413628a7SBjoern A. Zeeb 1760413628a7SBjoern A. Zeeb mtx_lock(&pr->pr_mtx); 1761b38ff370SJamie Gritton KASSERT(pr->pr_uref > 0, 1762b38ff370SJamie Gritton ("Trying to kill a process in a dead prison (jid=%d)", pr->pr_id)); 1763b38ff370SJamie Gritton prison_deref(pr, PD_DEUREF | PD_LOCKED); 1764413628a7SBjoern A. Zeeb } 1765413628a7SBjoern A. Zeeb 1766413628a7SBjoern A. Zeeb 1767413628a7SBjoern A. Zeeb #ifdef INET 1768413628a7SBjoern A. Zeeb /* 1769413628a7SBjoern A. Zeeb * Pass back primary IPv4 address of this jail. 1770413628a7SBjoern A. Zeeb * 1771413628a7SBjoern A. Zeeb * If not jailed return success but do not alter the address. Caller has to 17728571af59SJamie Gritton * make sure to initialize it correctly (e.g. INADDR_ANY). 1773413628a7SBjoern A. Zeeb * 1774b89e82ddSJamie Gritton * Returns 0 on success, EAFNOSUPPORT if the jail doesn't allow IPv4. 1775b89e82ddSJamie Gritton * Address returned in NBO. 1776413628a7SBjoern A. Zeeb */ 1777413628a7SBjoern A. Zeeb int 17781cecba0fSBjoern A. Zeeb prison_get_ip4(struct ucred *cred, struct in_addr *ia) 1779413628a7SBjoern A. Zeeb { 1780b38ff370SJamie Gritton struct prison *pr; 1781413628a7SBjoern A. Zeeb 1782413628a7SBjoern A. Zeeb KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 1783413628a7SBjoern A. Zeeb KASSERT(ia != NULL, ("%s: ia is NULL", __func__)); 178475c13541SPoul-Henning Kamp 178591421ba2SRobert Watson if (!jailed(cred)) 1786413628a7SBjoern A. Zeeb return (0); 1787b38ff370SJamie Gritton pr = cred->cr_prison; 1788b38ff370SJamie Gritton mtx_lock(&pr->pr_mtx); 1789b38ff370SJamie Gritton if (pr->pr_ip4 == NULL) { 1790b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 1791b89e82ddSJamie Gritton return (EAFNOSUPPORT); 1792b38ff370SJamie Gritton } 1793413628a7SBjoern A. Zeeb 1794b38ff370SJamie Gritton ia->s_addr = pr->pr_ip4[0].s_addr; 1795b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 1796413628a7SBjoern A. Zeeb return (0); 179775c13541SPoul-Henning Kamp } 1798413628a7SBjoern A. Zeeb 1799413628a7SBjoern A. Zeeb /* 1800413628a7SBjoern A. Zeeb * Make sure our (source) address is set to something meaningful to this 1801413628a7SBjoern A. Zeeb * jail. 1802413628a7SBjoern A. Zeeb * 1803b89e82ddSJamie Gritton * Returns 0 if not jailed or if address belongs to jail, EADDRNOTAVAIL if 1804b89e82ddSJamie Gritton * the address doesn't belong, or EAFNOSUPPORT if the jail doesn't allow IPv4. 1805b89e82ddSJamie Gritton * Address passed in in NBO and returned in NBO. 1806413628a7SBjoern A. Zeeb */ 1807413628a7SBjoern A. Zeeb int 1808413628a7SBjoern A. Zeeb prison_local_ip4(struct ucred *cred, struct in_addr *ia) 1809413628a7SBjoern A. Zeeb { 1810b38ff370SJamie Gritton struct prison *pr; 1811413628a7SBjoern A. Zeeb struct in_addr ia0; 1812b38ff370SJamie Gritton int error; 1813413628a7SBjoern A. Zeeb 1814413628a7SBjoern A. Zeeb KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 1815413628a7SBjoern A. Zeeb KASSERT(ia != NULL, ("%s: ia is NULL", __func__)); 1816413628a7SBjoern A. Zeeb 1817413628a7SBjoern A. Zeeb if (!jailed(cred)) 1818413628a7SBjoern A. Zeeb return (0); 1819b38ff370SJamie Gritton pr = cred->cr_prison; 1820b38ff370SJamie Gritton mtx_lock(&pr->pr_mtx); 1821b38ff370SJamie Gritton if (pr->pr_ip4 == NULL) { 1822b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 1823b89e82ddSJamie Gritton return (EAFNOSUPPORT); 1824b38ff370SJamie Gritton } 1825413628a7SBjoern A. Zeeb 1826413628a7SBjoern A. Zeeb ia0.s_addr = ntohl(ia->s_addr); 1827413628a7SBjoern A. Zeeb if (ia0.s_addr == INADDR_LOOPBACK) { 1828b38ff370SJamie Gritton ia->s_addr = pr->pr_ip4[0].s_addr; 1829b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 1830413628a7SBjoern A. Zeeb return (0); 1831413628a7SBjoern A. Zeeb } 1832413628a7SBjoern A. Zeeb 1833b89e82ddSJamie Gritton if (ia0.s_addr == INADDR_ANY) { 1834413628a7SBjoern A. Zeeb /* 1835413628a7SBjoern A. Zeeb * In case there is only 1 IPv4 address, bind directly. 1836413628a7SBjoern A. Zeeb */ 1837b38ff370SJamie Gritton if (pr->pr_ip4s == 1) 1838b38ff370SJamie Gritton ia->s_addr = pr->pr_ip4[0].s_addr; 1839b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 1840413628a7SBjoern A. Zeeb return (0); 1841413628a7SBjoern A. Zeeb } 1842413628a7SBjoern A. Zeeb 1843b38ff370SJamie Gritton error = _prison_check_ip4(pr, ia); 1844b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 1845b38ff370SJamie Gritton return (error); 1846413628a7SBjoern A. Zeeb } 1847413628a7SBjoern A. Zeeb 1848413628a7SBjoern A. Zeeb /* 1849413628a7SBjoern A. Zeeb * Rewrite destination address in case we will connect to loopback address. 1850413628a7SBjoern A. Zeeb * 1851b89e82ddSJamie Gritton * Returns 0 on success, EAFNOSUPPORT if the jail doesn't allow IPv4. 1852b89e82ddSJamie Gritton * Address passed in in NBO and returned in NBO. 1853413628a7SBjoern A. Zeeb */ 1854413628a7SBjoern A. Zeeb int 1855413628a7SBjoern A. Zeeb prison_remote_ip4(struct ucred *cred, struct in_addr *ia) 1856413628a7SBjoern A. Zeeb { 1857b38ff370SJamie Gritton struct prison *pr; 1858413628a7SBjoern A. Zeeb 1859413628a7SBjoern A. Zeeb KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 1860413628a7SBjoern A. Zeeb KASSERT(ia != NULL, ("%s: ia is NULL", __func__)); 1861413628a7SBjoern A. Zeeb 1862413628a7SBjoern A. Zeeb if (!jailed(cred)) 1863413628a7SBjoern A. Zeeb return (0); 1864b38ff370SJamie Gritton pr = cred->cr_prison; 1865b38ff370SJamie Gritton mtx_lock(&pr->pr_mtx); 1866b38ff370SJamie Gritton if (pr->pr_ip4 == NULL) { 1867b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 1868b89e82ddSJamie Gritton return (EAFNOSUPPORT); 1869b38ff370SJamie Gritton } 1870b89e82ddSJamie Gritton 1871413628a7SBjoern A. Zeeb if (ntohl(ia->s_addr) == INADDR_LOOPBACK) { 1872b38ff370SJamie Gritton ia->s_addr = pr->pr_ip4[0].s_addr; 1873b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 1874413628a7SBjoern A. Zeeb return (0); 1875413628a7SBjoern A. Zeeb } 1876413628a7SBjoern A. Zeeb 1877413628a7SBjoern A. Zeeb /* 1878413628a7SBjoern A. Zeeb * Return success because nothing had to be changed. 1879413628a7SBjoern A. Zeeb */ 1880b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 1881413628a7SBjoern A. Zeeb return (0); 1882413628a7SBjoern A. Zeeb } 1883413628a7SBjoern A. Zeeb 1884413628a7SBjoern A. Zeeb /* 1885b89e82ddSJamie Gritton * Check if given address belongs to the jail referenced by cred/prison. 1886413628a7SBjoern A. Zeeb * 1887b89e82ddSJamie Gritton * Returns 0 if not jailed or if address belongs to jail, EADDRNOTAVAIL if 1888b89e82ddSJamie Gritton * the address doesn't belong, or EAFNOSUPPORT if the jail doesn't allow IPv4. 1889b89e82ddSJamie Gritton * Address passed in in NBO. 1890413628a7SBjoern A. Zeeb */ 1891413628a7SBjoern A. Zeeb static int 1892413628a7SBjoern A. Zeeb _prison_check_ip4(struct prison *pr, struct in_addr *ia) 1893413628a7SBjoern A. Zeeb { 1894413628a7SBjoern A. Zeeb int i, a, z, d; 1895413628a7SBjoern A. Zeeb 1896413628a7SBjoern A. Zeeb /* 1897413628a7SBjoern A. Zeeb * Check the primary IP. 1898413628a7SBjoern A. Zeeb */ 1899413628a7SBjoern A. Zeeb if (pr->pr_ip4[0].s_addr == ia->s_addr) 1900b89e82ddSJamie Gritton return (0); 1901413628a7SBjoern A. Zeeb 1902413628a7SBjoern A. Zeeb /* 1903413628a7SBjoern A. Zeeb * All the other IPs are sorted so we can do a binary search. 1904413628a7SBjoern A. Zeeb */ 1905413628a7SBjoern A. Zeeb a = 0; 1906413628a7SBjoern A. Zeeb z = pr->pr_ip4s - 2; 1907413628a7SBjoern A. Zeeb while (a <= z) { 1908413628a7SBjoern A. Zeeb i = (a + z) / 2; 1909413628a7SBjoern A. Zeeb d = qcmp_v4(&pr->pr_ip4[i+1], ia); 1910413628a7SBjoern A. Zeeb if (d > 0) 1911413628a7SBjoern A. Zeeb z = i - 1; 1912413628a7SBjoern A. Zeeb else if (d < 0) 1913413628a7SBjoern A. Zeeb a = i + 1; 1914413628a7SBjoern A. Zeeb else 1915413628a7SBjoern A. Zeeb return (0); 191675c13541SPoul-Henning Kamp } 191775c13541SPoul-Henning Kamp 1918b89e82ddSJamie Gritton return (EADDRNOTAVAIL); 1919b89e82ddSJamie Gritton } 1920b89e82ddSJamie Gritton 192175c13541SPoul-Henning Kamp int 1922413628a7SBjoern A. Zeeb prison_check_ip4(struct ucred *cred, struct in_addr *ia) 1923413628a7SBjoern A. Zeeb { 1924b38ff370SJamie Gritton struct prison *pr; 1925b38ff370SJamie Gritton int error; 1926413628a7SBjoern A. Zeeb 1927413628a7SBjoern A. Zeeb KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 1928413628a7SBjoern A. Zeeb KASSERT(ia != NULL, ("%s: ia is NULL", __func__)); 1929413628a7SBjoern A. Zeeb 1930413628a7SBjoern A. Zeeb if (!jailed(cred)) 1931b89e82ddSJamie Gritton return (0); 1932b38ff370SJamie Gritton pr = cred->cr_prison; 1933b38ff370SJamie Gritton mtx_lock(&pr->pr_mtx); 1934b38ff370SJamie Gritton if (pr->pr_ip4 == NULL) { 1935b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 1936b89e82ddSJamie Gritton return (EAFNOSUPPORT); 1937b38ff370SJamie Gritton } 1938413628a7SBjoern A. Zeeb 1939b38ff370SJamie Gritton error = _prison_check_ip4(pr, ia); 1940b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 1941b38ff370SJamie Gritton return (error); 1942413628a7SBjoern A. Zeeb } 1943413628a7SBjoern A. Zeeb #endif 1944413628a7SBjoern A. Zeeb 1945413628a7SBjoern A. Zeeb #ifdef INET6 1946413628a7SBjoern A. Zeeb /* 1947413628a7SBjoern A. Zeeb * Pass back primary IPv6 address for this jail. 1948413628a7SBjoern A. Zeeb * 1949413628a7SBjoern A. Zeeb * If not jailed return success but do not alter the address. Caller has to 19508571af59SJamie Gritton * make sure to initialize it correctly (e.g. IN6ADDR_ANY_INIT). 1951413628a7SBjoern A. Zeeb * 1952b89e82ddSJamie Gritton * Returns 0 on success, EAFNOSUPPORT if the jail doesn't allow IPv6. 1953413628a7SBjoern A. Zeeb */ 1954413628a7SBjoern A. Zeeb int 19551cecba0fSBjoern A. Zeeb prison_get_ip6(struct ucred *cred, struct in6_addr *ia6) 1956413628a7SBjoern A. Zeeb { 1957b38ff370SJamie Gritton struct prison *pr; 1958413628a7SBjoern A. Zeeb 1959413628a7SBjoern A. Zeeb KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 1960413628a7SBjoern A. Zeeb KASSERT(ia6 != NULL, ("%s: ia6 is NULL", __func__)); 1961413628a7SBjoern A. Zeeb 1962413628a7SBjoern A. Zeeb if (!jailed(cred)) 1963413628a7SBjoern A. Zeeb return (0); 1964b38ff370SJamie Gritton pr = cred->cr_prison; 1965b38ff370SJamie Gritton mtx_lock(&pr->pr_mtx); 1966b38ff370SJamie Gritton if (pr->pr_ip6 == NULL) { 1967b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 1968b89e82ddSJamie Gritton return (EAFNOSUPPORT); 1969b38ff370SJamie Gritton } 1970b89e82ddSJamie Gritton 1971b38ff370SJamie Gritton bcopy(&pr->pr_ip6[0], ia6, sizeof(struct in6_addr)); 1972b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 1973413628a7SBjoern A. Zeeb return (0); 1974413628a7SBjoern A. Zeeb } 1975413628a7SBjoern A. Zeeb 1976413628a7SBjoern A. Zeeb /* 1977413628a7SBjoern A. Zeeb * Make sure our (source) address is set to something meaningful to this jail. 1978413628a7SBjoern A. Zeeb * 1979413628a7SBjoern A. Zeeb * v6only should be set based on (inp->inp_flags & IN6P_IPV6_V6ONLY != 0) 1980413628a7SBjoern A. Zeeb * when needed while binding. 1981413628a7SBjoern A. Zeeb * 1982b89e82ddSJamie Gritton * Returns 0 if not jailed or if address belongs to jail, EADDRNOTAVAIL if 1983b89e82ddSJamie Gritton * the address doesn't belong, or EAFNOSUPPORT if the jail doesn't allow IPv6. 1984413628a7SBjoern A. Zeeb */ 1985413628a7SBjoern A. Zeeb int 1986413628a7SBjoern A. Zeeb prison_local_ip6(struct ucred *cred, struct in6_addr *ia6, int v6only) 1987413628a7SBjoern A. Zeeb { 1988b38ff370SJamie Gritton struct prison *pr; 1989b38ff370SJamie Gritton int error; 1990413628a7SBjoern A. Zeeb 1991413628a7SBjoern A. Zeeb KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 1992413628a7SBjoern A. Zeeb KASSERT(ia6 != NULL, ("%s: ia6 is NULL", __func__)); 1993413628a7SBjoern A. Zeeb 1994413628a7SBjoern A. Zeeb if (!jailed(cred)) 1995413628a7SBjoern A. Zeeb return (0); 1996b38ff370SJamie Gritton pr = cred->cr_prison; 1997b38ff370SJamie Gritton mtx_lock(&pr->pr_mtx); 1998b38ff370SJamie Gritton if (pr->pr_ip6 == NULL) { 1999b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 2000b89e82ddSJamie Gritton return (EAFNOSUPPORT); 2001b38ff370SJamie Gritton } 2002b89e82ddSJamie Gritton 2003413628a7SBjoern A. Zeeb if (IN6_IS_ADDR_LOOPBACK(ia6)) { 2004b38ff370SJamie Gritton bcopy(&pr->pr_ip6[0], ia6, sizeof(struct in6_addr)); 2005b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 2006413628a7SBjoern A. Zeeb return (0); 2007413628a7SBjoern A. Zeeb } 2008413628a7SBjoern A. Zeeb 2009b89e82ddSJamie Gritton if (IN6_IS_ADDR_UNSPECIFIED(ia6)) { 2010413628a7SBjoern A. Zeeb /* 2011b89e82ddSJamie Gritton * In case there is only 1 IPv6 address, and v6only is true, 2012b89e82ddSJamie Gritton * then bind directly. 2013413628a7SBjoern A. Zeeb */ 2014b38ff370SJamie Gritton if (v6only != 0 && pr->pr_ip6s == 1) 2015b38ff370SJamie Gritton bcopy(&pr->pr_ip6[0], ia6, sizeof(struct in6_addr)); 2016b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 2017413628a7SBjoern A. Zeeb return (0); 2018413628a7SBjoern A. Zeeb } 2019b89e82ddSJamie Gritton 2020b38ff370SJamie Gritton error = _prison_check_ip6(pr, ia6); 2021b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 2022b38ff370SJamie Gritton return (error); 2023413628a7SBjoern A. Zeeb } 2024413628a7SBjoern A. Zeeb 2025413628a7SBjoern A. Zeeb /* 2026413628a7SBjoern A. Zeeb * Rewrite destination address in case we will connect to loopback address. 2027413628a7SBjoern A. Zeeb * 2028b89e82ddSJamie Gritton * Returns 0 on success, EAFNOSUPPORT if the jail doesn't allow IPv6. 2029413628a7SBjoern A. Zeeb */ 2030413628a7SBjoern A. Zeeb int 2031413628a7SBjoern A. Zeeb prison_remote_ip6(struct ucred *cred, struct in6_addr *ia6) 2032413628a7SBjoern A. Zeeb { 2033b38ff370SJamie Gritton struct prison *pr; 2034413628a7SBjoern A. Zeeb 2035413628a7SBjoern A. Zeeb KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 2036413628a7SBjoern A. Zeeb KASSERT(ia6 != NULL, ("%s: ia6 is NULL", __func__)); 2037413628a7SBjoern A. Zeeb 2038413628a7SBjoern A. Zeeb if (!jailed(cred)) 2039413628a7SBjoern A. Zeeb return (0); 2040b38ff370SJamie Gritton pr = cred->cr_prison; 2041b38ff370SJamie Gritton mtx_lock(&pr->pr_mtx); 2042b38ff370SJamie Gritton if (pr->pr_ip6 == NULL) { 2043b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 2044b89e82ddSJamie Gritton return (EAFNOSUPPORT); 2045b38ff370SJamie Gritton } 2046b89e82ddSJamie Gritton 2047413628a7SBjoern A. Zeeb if (IN6_IS_ADDR_LOOPBACK(ia6)) { 2048b38ff370SJamie Gritton bcopy(&pr->pr_ip6[0], ia6, sizeof(struct in6_addr)); 2049b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 2050413628a7SBjoern A. Zeeb return (0); 2051413628a7SBjoern A. Zeeb } 2052413628a7SBjoern A. Zeeb 2053413628a7SBjoern A. Zeeb /* 2054413628a7SBjoern A. Zeeb * Return success because nothing had to be changed. 2055413628a7SBjoern A. Zeeb */ 2056b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 2057413628a7SBjoern A. Zeeb return (0); 2058413628a7SBjoern A. Zeeb } 2059413628a7SBjoern A. Zeeb 2060413628a7SBjoern A. Zeeb /* 2061b89e82ddSJamie Gritton * Check if given address belongs to the jail referenced by cred/prison. 2062413628a7SBjoern A. Zeeb * 2063b89e82ddSJamie Gritton * Returns 0 if not jailed or if address belongs to jail, EADDRNOTAVAIL if 2064b89e82ddSJamie Gritton * the address doesn't belong, or EAFNOSUPPORT if the jail doesn't allow IPv6. 2065413628a7SBjoern A. Zeeb */ 2066413628a7SBjoern A. Zeeb static int 2067413628a7SBjoern A. Zeeb _prison_check_ip6(struct prison *pr, struct in6_addr *ia6) 2068413628a7SBjoern A. Zeeb { 2069413628a7SBjoern A. Zeeb int i, a, z, d; 2070413628a7SBjoern A. Zeeb 2071413628a7SBjoern A. Zeeb /* 2072413628a7SBjoern A. Zeeb * Check the primary IP. 2073413628a7SBjoern A. Zeeb */ 2074413628a7SBjoern A. Zeeb if (IN6_ARE_ADDR_EQUAL(&pr->pr_ip6[0], ia6)) 2075b89e82ddSJamie Gritton return (0); 2076413628a7SBjoern A. Zeeb 2077413628a7SBjoern A. Zeeb /* 2078413628a7SBjoern A. Zeeb * All the other IPs are sorted so we can do a binary search. 2079413628a7SBjoern A. Zeeb */ 2080413628a7SBjoern A. Zeeb a = 0; 2081413628a7SBjoern A. Zeeb z = pr->pr_ip6s - 2; 2082413628a7SBjoern A. Zeeb while (a <= z) { 2083413628a7SBjoern A. Zeeb i = (a + z) / 2; 2084413628a7SBjoern A. Zeeb d = qcmp_v6(&pr->pr_ip6[i+1], ia6); 2085413628a7SBjoern A. Zeeb if (d > 0) 2086413628a7SBjoern A. Zeeb z = i - 1; 2087413628a7SBjoern A. Zeeb else if (d < 0) 2088413628a7SBjoern A. Zeeb a = i + 1; 2089413628a7SBjoern A. Zeeb else 2090413628a7SBjoern A. Zeeb return (0); 2091413628a7SBjoern A. Zeeb } 2092413628a7SBjoern A. Zeeb 2093b89e82ddSJamie Gritton return (EADDRNOTAVAIL); 2094b89e82ddSJamie Gritton } 2095b89e82ddSJamie Gritton 2096413628a7SBjoern A. Zeeb int 2097413628a7SBjoern A. Zeeb prison_check_ip6(struct ucred *cred, struct in6_addr *ia6) 2098413628a7SBjoern A. Zeeb { 2099b38ff370SJamie Gritton struct prison *pr; 2100b38ff370SJamie Gritton int error; 2101413628a7SBjoern A. Zeeb 2102413628a7SBjoern A. Zeeb KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 2103413628a7SBjoern A. Zeeb KASSERT(ia6 != NULL, ("%s: ia6 is NULL", __func__)); 2104413628a7SBjoern A. Zeeb 2105413628a7SBjoern A. Zeeb if (!jailed(cred)) 2106b89e82ddSJamie Gritton return (0); 2107b38ff370SJamie Gritton pr = cred->cr_prison; 2108b38ff370SJamie Gritton mtx_lock(&pr->pr_mtx); 2109b38ff370SJamie Gritton if (pr->pr_ip6 == NULL) { 2110b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 2111b89e82ddSJamie Gritton return (EAFNOSUPPORT); 2112b38ff370SJamie Gritton } 2113413628a7SBjoern A. Zeeb 2114b38ff370SJamie Gritton error = _prison_check_ip6(pr, ia6); 2115b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 2116b38ff370SJamie Gritton return (error); 2117413628a7SBjoern A. Zeeb } 2118413628a7SBjoern A. Zeeb #endif 2119413628a7SBjoern A. Zeeb 2120413628a7SBjoern A. Zeeb /* 2121ca04ba64SJamie Gritton * Check if a jail supports the given address family. 2122ca04ba64SJamie Gritton * 2123ca04ba64SJamie Gritton * Returns 0 if not jailed or the address family is supported, EAFNOSUPPORT 2124ca04ba64SJamie Gritton * if not. 2125ca04ba64SJamie Gritton */ 2126ca04ba64SJamie Gritton int 2127ca04ba64SJamie Gritton prison_check_af(struct ucred *cred, int af) 2128ca04ba64SJamie Gritton { 2129ca04ba64SJamie Gritton int error; 2130ca04ba64SJamie Gritton 2131ca04ba64SJamie Gritton KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 2132ca04ba64SJamie Gritton 2133ca04ba64SJamie Gritton 2134ca04ba64SJamie Gritton if (!jailed(cred)) 2135ca04ba64SJamie Gritton return (0); 2136ca04ba64SJamie Gritton 2137ca04ba64SJamie Gritton error = 0; 2138ca04ba64SJamie Gritton switch (af) 2139ca04ba64SJamie Gritton { 2140ca04ba64SJamie Gritton #ifdef INET 2141ca04ba64SJamie Gritton case AF_INET: 2142ca04ba64SJamie Gritton if (cred->cr_prison->pr_ip4 == NULL) 2143ca04ba64SJamie Gritton error = EAFNOSUPPORT; 2144ca04ba64SJamie Gritton break; 2145ca04ba64SJamie Gritton #endif 2146ca04ba64SJamie Gritton #ifdef INET6 2147ca04ba64SJamie Gritton case AF_INET6: 2148ca04ba64SJamie Gritton if (cred->cr_prison->pr_ip6 == NULL) 2149ca04ba64SJamie Gritton error = EAFNOSUPPORT; 2150ca04ba64SJamie Gritton break; 2151ca04ba64SJamie Gritton #endif 2152ca04ba64SJamie Gritton case AF_LOCAL: 2153ca04ba64SJamie Gritton case AF_ROUTE: 2154ca04ba64SJamie Gritton break; 2155ca04ba64SJamie Gritton default: 2156ca04ba64SJamie Gritton if (jail_socket_unixiproute_only) 2157ca04ba64SJamie Gritton error = EAFNOSUPPORT; 2158ca04ba64SJamie Gritton } 2159ca04ba64SJamie Gritton return (error); 2160ca04ba64SJamie Gritton } 2161ca04ba64SJamie Gritton 2162ca04ba64SJamie Gritton /* 2163413628a7SBjoern A. Zeeb * Check if given address belongs to the jail referenced by cred (wrapper to 2164413628a7SBjoern A. Zeeb * prison_check_ip[46]). 2165413628a7SBjoern A. Zeeb * 2166b89e82ddSJamie Gritton * Returns 0 if not jailed or if address belongs to jail, EADDRNOTAVAIL if 2167b89e82ddSJamie Gritton * the address doesn't belong, or EAFNOSUPPORT if the jail doesn't allow 2168b89e82ddSJamie Gritton * the address family. IPv4 Address passed in in NBO. 2169413628a7SBjoern A. Zeeb */ 2170413628a7SBjoern A. Zeeb int 217191421ba2SRobert Watson prison_if(struct ucred *cred, struct sockaddr *sa) 217275c13541SPoul-Henning Kamp { 2173413628a7SBjoern A. Zeeb #ifdef INET 21749ddb7954SMike Barcroft struct sockaddr_in *sai; 2175413628a7SBjoern A. Zeeb #endif 2176413628a7SBjoern A. Zeeb #ifdef INET6 2177413628a7SBjoern A. Zeeb struct sockaddr_in6 *sai6; 2178413628a7SBjoern A. Zeeb #endif 2179b89e82ddSJamie Gritton int error; 218075c13541SPoul-Henning Kamp 2181413628a7SBjoern A. Zeeb KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 2182413628a7SBjoern A. Zeeb KASSERT(sa != NULL, ("%s: sa is NULL", __func__)); 2183413628a7SBjoern A. Zeeb 2184b89e82ddSJamie Gritton error = 0; 2185413628a7SBjoern A. Zeeb switch (sa->sa_family) 2186413628a7SBjoern A. Zeeb { 2187413628a7SBjoern A. Zeeb #ifdef INET 2188413628a7SBjoern A. Zeeb case AF_INET: 21899ddb7954SMike Barcroft sai = (struct sockaddr_in *)sa; 2190b89e82ddSJamie Gritton error = prison_check_ip4(cred, &sai->sin_addr); 2191413628a7SBjoern A. Zeeb break; 2192413628a7SBjoern A. Zeeb #endif 2193413628a7SBjoern A. Zeeb #ifdef INET6 2194413628a7SBjoern A. Zeeb case AF_INET6: 2195413628a7SBjoern A. Zeeb sai6 = (struct sockaddr_in6 *)sa; 2196b89e82ddSJamie Gritton error = prison_check_ip6(cred, &sai6->sin6_addr); 2197413628a7SBjoern A. Zeeb break; 2198413628a7SBjoern A. Zeeb #endif 2199413628a7SBjoern A. Zeeb default: 2200b89e82ddSJamie Gritton if (jailed(cred) && jail_socket_unixiproute_only) 2201b89e82ddSJamie Gritton error = EAFNOSUPPORT; 2202413628a7SBjoern A. Zeeb } 2203b89e82ddSJamie Gritton return (error); 220475c13541SPoul-Henning Kamp } 220591421ba2SRobert Watson 220691421ba2SRobert Watson /* 220791421ba2SRobert Watson * Return 0 if jails permit p1 to frob p2, otherwise ESRCH. 220891421ba2SRobert Watson */ 220991421ba2SRobert Watson int 22109ddb7954SMike Barcroft prison_check(struct ucred *cred1, struct ucred *cred2) 221191421ba2SRobert Watson { 221291421ba2SRobert Watson 221391421ba2SRobert Watson if (jailed(cred1)) { 221491421ba2SRobert Watson if (!jailed(cred2)) 221591421ba2SRobert Watson return (ESRCH); 221691421ba2SRobert Watson if (cred2->cr_prison != cred1->cr_prison) 221791421ba2SRobert Watson return (ESRCH); 221891421ba2SRobert Watson } 221929b02909SMarko Zec #ifdef VIMAGE 222029b02909SMarko Zec if (cred2->cr_vimage->v_procg != cred1->cr_vimage->v_procg) 222129b02909SMarko Zec return (ESRCH); 222229b02909SMarko Zec #endif 222391421ba2SRobert Watson 222491421ba2SRobert Watson return (0); 222591421ba2SRobert Watson } 222691421ba2SRobert Watson 222791421ba2SRobert Watson /* 222891421ba2SRobert Watson * Return 1 if the passed credential is in a jail, otherwise 0. 222991421ba2SRobert Watson */ 223091421ba2SRobert Watson int 22319ddb7954SMike Barcroft jailed(struct ucred *cred) 223291421ba2SRobert Watson { 223391421ba2SRobert Watson 223491421ba2SRobert Watson return (cred->cr_prison != NULL); 223591421ba2SRobert Watson } 22369484d0c0SRobert Drehmel 22379484d0c0SRobert Drehmel /* 22389484d0c0SRobert Drehmel * Return the correct hostname for the passed credential. 22399484d0c0SRobert Drehmel */ 2240ad1ff099SRobert Drehmel void 22419ddb7954SMike Barcroft getcredhostname(struct ucred *cred, char *buf, size_t size) 22429484d0c0SRobert Drehmel { 22438b615593SMarko Zec INIT_VPROCG(cred->cr_vimage->v_procg); 22449484d0c0SRobert Drehmel 2245ad1ff099SRobert Drehmel if (jailed(cred)) { 2246ad1ff099SRobert Drehmel mtx_lock(&cred->cr_prison->pr_mtx); 2247e80fb434SRobert Drehmel strlcpy(buf, cred->cr_prison->pr_host, size); 2248ad1ff099SRobert Drehmel mtx_unlock(&cred->cr_prison->pr_mtx); 22494f7d1876SRobert Watson } else { 22504f7d1876SRobert Watson mtx_lock(&hostname_mtx); 2251603724d3SBjoern A. Zeeb strlcpy(buf, V_hostname, size); 22524f7d1876SRobert Watson mtx_unlock(&hostname_mtx); 22534f7d1876SRobert Watson } 22549484d0c0SRobert Drehmel } 2255fd7a8150SMike Barcroft 2256f08df373SRobert Watson /* 2257820a0de9SPawel Jakub Dawidek * Determine whether the subject represented by cred can "see" 2258820a0de9SPawel Jakub Dawidek * status of a mount point. 2259820a0de9SPawel Jakub Dawidek * Returns: 0 for permitted, ENOENT otherwise. 2260820a0de9SPawel Jakub Dawidek * XXX: This function should be called cr_canseemount() and should be 2261820a0de9SPawel Jakub Dawidek * placed in kern_prot.c. 2262f08df373SRobert Watson */ 2263f08df373SRobert Watson int 2264820a0de9SPawel Jakub Dawidek prison_canseemount(struct ucred *cred, struct mount *mp) 2265f08df373SRobert Watson { 2266820a0de9SPawel Jakub Dawidek struct prison *pr; 2267820a0de9SPawel Jakub Dawidek struct statfs *sp; 2268820a0de9SPawel Jakub Dawidek size_t len; 2269f08df373SRobert Watson 2270820a0de9SPawel Jakub Dawidek if (!jailed(cred) || jail_enforce_statfs == 0) 2271820a0de9SPawel Jakub Dawidek return (0); 2272820a0de9SPawel Jakub Dawidek pr = cred->cr_prison; 2273820a0de9SPawel Jakub Dawidek if (pr->pr_root->v_mount == mp) 2274820a0de9SPawel Jakub Dawidek return (0); 2275820a0de9SPawel Jakub Dawidek if (jail_enforce_statfs == 2) 2276820a0de9SPawel Jakub Dawidek return (ENOENT); 2277820a0de9SPawel Jakub Dawidek /* 2278820a0de9SPawel Jakub Dawidek * If jail's chroot directory is set to "/" we should be able to see 2279820a0de9SPawel Jakub Dawidek * all mount-points from inside a jail. 2280820a0de9SPawel Jakub Dawidek * This is ugly check, but this is the only situation when jail's 2281820a0de9SPawel Jakub Dawidek * directory ends with '/'. 2282820a0de9SPawel Jakub Dawidek */ 2283820a0de9SPawel Jakub Dawidek if (strcmp(pr->pr_path, "/") == 0) 2284820a0de9SPawel Jakub Dawidek return (0); 2285820a0de9SPawel Jakub Dawidek len = strlen(pr->pr_path); 2286820a0de9SPawel Jakub Dawidek sp = &mp->mnt_stat; 2287820a0de9SPawel Jakub Dawidek if (strncmp(pr->pr_path, sp->f_mntonname, len) != 0) 2288820a0de9SPawel Jakub Dawidek return (ENOENT); 2289820a0de9SPawel Jakub Dawidek /* 2290820a0de9SPawel Jakub Dawidek * Be sure that we don't have situation where jail's root directory 2291820a0de9SPawel Jakub Dawidek * is "/some/path" and mount point is "/some/pathpath". 2292820a0de9SPawel Jakub Dawidek */ 2293820a0de9SPawel Jakub Dawidek if (sp->f_mntonname[len] != '\0' && sp->f_mntonname[len] != '/') 2294820a0de9SPawel Jakub Dawidek return (ENOENT); 2295f08df373SRobert Watson return (0); 2296f08df373SRobert Watson } 2297820a0de9SPawel Jakub Dawidek 2298820a0de9SPawel Jakub Dawidek void 2299820a0de9SPawel Jakub Dawidek prison_enforce_statfs(struct ucred *cred, struct mount *mp, struct statfs *sp) 2300820a0de9SPawel Jakub Dawidek { 2301820a0de9SPawel Jakub Dawidek char jpath[MAXPATHLEN]; 2302820a0de9SPawel Jakub Dawidek struct prison *pr; 2303820a0de9SPawel Jakub Dawidek size_t len; 2304820a0de9SPawel Jakub Dawidek 2305820a0de9SPawel Jakub Dawidek if (!jailed(cred) || jail_enforce_statfs == 0) 2306820a0de9SPawel Jakub Dawidek return; 2307820a0de9SPawel Jakub Dawidek pr = cred->cr_prison; 2308820a0de9SPawel Jakub Dawidek if (prison_canseemount(cred, mp) != 0) { 2309820a0de9SPawel Jakub Dawidek bzero(sp->f_mntonname, sizeof(sp->f_mntonname)); 2310820a0de9SPawel Jakub Dawidek strlcpy(sp->f_mntonname, "[restricted]", 2311820a0de9SPawel Jakub Dawidek sizeof(sp->f_mntonname)); 2312820a0de9SPawel Jakub Dawidek return; 2313820a0de9SPawel Jakub Dawidek } 2314820a0de9SPawel Jakub Dawidek if (pr->pr_root->v_mount == mp) { 2315820a0de9SPawel Jakub Dawidek /* 2316820a0de9SPawel Jakub Dawidek * Clear current buffer data, so we are sure nothing from 2317820a0de9SPawel Jakub Dawidek * the valid path left there. 2318820a0de9SPawel Jakub Dawidek */ 2319820a0de9SPawel Jakub Dawidek bzero(sp->f_mntonname, sizeof(sp->f_mntonname)); 2320820a0de9SPawel Jakub Dawidek *sp->f_mntonname = '/'; 2321820a0de9SPawel Jakub Dawidek return; 2322820a0de9SPawel Jakub Dawidek } 2323820a0de9SPawel Jakub Dawidek /* 2324820a0de9SPawel Jakub Dawidek * If jail's chroot directory is set to "/" we should be able to see 2325820a0de9SPawel Jakub Dawidek * all mount-points from inside a jail. 2326820a0de9SPawel Jakub Dawidek */ 2327820a0de9SPawel Jakub Dawidek if (strcmp(pr->pr_path, "/") == 0) 2328820a0de9SPawel Jakub Dawidek return; 2329820a0de9SPawel Jakub Dawidek len = strlen(pr->pr_path); 2330820a0de9SPawel Jakub Dawidek strlcpy(jpath, sp->f_mntonname + len, sizeof(jpath)); 2331820a0de9SPawel Jakub Dawidek /* 2332820a0de9SPawel Jakub Dawidek * Clear current buffer data, so we are sure nothing from 2333820a0de9SPawel Jakub Dawidek * the valid path left there. 2334820a0de9SPawel Jakub Dawidek */ 2335820a0de9SPawel Jakub Dawidek bzero(sp->f_mntonname, sizeof(sp->f_mntonname)); 2336820a0de9SPawel Jakub Dawidek if (*jpath == '\0') { 2337820a0de9SPawel Jakub Dawidek /* Should never happen. */ 2338820a0de9SPawel Jakub Dawidek *sp->f_mntonname = '/'; 2339820a0de9SPawel Jakub Dawidek } else { 2340820a0de9SPawel Jakub Dawidek strlcpy(sp->f_mntonname, jpath, sizeof(sp->f_mntonname)); 2341820a0de9SPawel Jakub Dawidek } 2342f08df373SRobert Watson } 2343f08df373SRobert Watson 2344800c9408SRobert Watson /* 2345800c9408SRobert Watson * Check with permission for a specific privilege is granted within jail. We 2346800c9408SRobert Watson * have a specific list of accepted privileges; the rest are denied. 2347800c9408SRobert Watson */ 2348800c9408SRobert Watson int 2349800c9408SRobert Watson prison_priv_check(struct ucred *cred, int priv) 2350800c9408SRobert Watson { 2351800c9408SRobert Watson 2352800c9408SRobert Watson if (!jailed(cred)) 2353800c9408SRobert Watson return (0); 2354800c9408SRobert Watson 2355800c9408SRobert Watson switch (priv) { 2356800c9408SRobert Watson 2357800c9408SRobert Watson /* 2358800c9408SRobert Watson * Allow ktrace privileges for root in jail. 2359800c9408SRobert Watson */ 2360800c9408SRobert Watson case PRIV_KTRACE: 2361800c9408SRobert Watson 2362c3c1b5e6SRobert Watson #if 0 2363800c9408SRobert Watson /* 2364800c9408SRobert Watson * Allow jailed processes to configure audit identity and 2365800c9408SRobert Watson * submit audit records (login, etc). In the future we may 2366800c9408SRobert Watson * want to further refine the relationship between audit and 2367800c9408SRobert Watson * jail. 2368800c9408SRobert Watson */ 2369800c9408SRobert Watson case PRIV_AUDIT_GETAUDIT: 2370800c9408SRobert Watson case PRIV_AUDIT_SETAUDIT: 2371800c9408SRobert Watson case PRIV_AUDIT_SUBMIT: 2372c3c1b5e6SRobert Watson #endif 2373800c9408SRobert Watson 2374800c9408SRobert Watson /* 2375800c9408SRobert Watson * Allow jailed processes to manipulate process UNIX 2376800c9408SRobert Watson * credentials in any way they see fit. 2377800c9408SRobert Watson */ 2378800c9408SRobert Watson case PRIV_CRED_SETUID: 2379800c9408SRobert Watson case PRIV_CRED_SETEUID: 2380800c9408SRobert Watson case PRIV_CRED_SETGID: 2381800c9408SRobert Watson case PRIV_CRED_SETEGID: 2382800c9408SRobert Watson case PRIV_CRED_SETGROUPS: 2383800c9408SRobert Watson case PRIV_CRED_SETREUID: 2384800c9408SRobert Watson case PRIV_CRED_SETREGID: 2385800c9408SRobert Watson case PRIV_CRED_SETRESUID: 2386800c9408SRobert Watson case PRIV_CRED_SETRESGID: 2387800c9408SRobert Watson 2388800c9408SRobert Watson /* 2389800c9408SRobert Watson * Jail implements visibility constraints already, so allow 2390800c9408SRobert Watson * jailed root to override uid/gid-based constraints. 2391800c9408SRobert Watson */ 2392800c9408SRobert Watson case PRIV_SEEOTHERGIDS: 2393800c9408SRobert Watson case PRIV_SEEOTHERUIDS: 2394800c9408SRobert Watson 2395800c9408SRobert Watson /* 2396800c9408SRobert Watson * Jail implements inter-process debugging limits already, so 2397800c9408SRobert Watson * allow jailed root various debugging privileges. 2398800c9408SRobert Watson */ 2399800c9408SRobert Watson case PRIV_DEBUG_DIFFCRED: 2400800c9408SRobert Watson case PRIV_DEBUG_SUGID: 2401800c9408SRobert Watson case PRIV_DEBUG_UNPRIV: 2402800c9408SRobert Watson 2403800c9408SRobert Watson /* 2404800c9408SRobert Watson * Allow jail to set various resource limits and login 2405800c9408SRobert Watson * properties, and for now, exceed process resource limits. 2406800c9408SRobert Watson */ 2407800c9408SRobert Watson case PRIV_PROC_LIMIT: 2408800c9408SRobert Watson case PRIV_PROC_SETLOGIN: 2409800c9408SRobert Watson case PRIV_PROC_SETRLIMIT: 2410800c9408SRobert Watson 2411800c9408SRobert Watson /* 2412800c9408SRobert Watson * System V and POSIX IPC privileges are granted in jail. 2413800c9408SRobert Watson */ 2414800c9408SRobert Watson case PRIV_IPC_READ: 2415800c9408SRobert Watson case PRIV_IPC_WRITE: 2416800c9408SRobert Watson case PRIV_IPC_ADMIN: 2417800c9408SRobert Watson case PRIV_IPC_MSGSIZE: 2418800c9408SRobert Watson case PRIV_MQ_ADMIN: 2419800c9408SRobert Watson 2420800c9408SRobert Watson /* 2421800c9408SRobert Watson * Jail implements its own inter-process limits, so allow 2422800c9408SRobert Watson * root processes in jail to change scheduling on other 2423800c9408SRobert Watson * processes in the same jail. Likewise for signalling. 2424800c9408SRobert Watson */ 2425800c9408SRobert Watson case PRIV_SCHED_DIFFCRED: 2426413628a7SBjoern A. Zeeb case PRIV_SCHED_CPUSET: 2427800c9408SRobert Watson case PRIV_SIGNAL_DIFFCRED: 2428800c9408SRobert Watson case PRIV_SIGNAL_SUGID: 2429800c9408SRobert Watson 2430800c9408SRobert Watson /* 2431800c9408SRobert Watson * Allow jailed processes to write to sysctls marked as jail 2432800c9408SRobert Watson * writable. 2433800c9408SRobert Watson */ 2434800c9408SRobert Watson case PRIV_SYSCTL_WRITEJAIL: 2435800c9408SRobert Watson 2436800c9408SRobert Watson /* 2437800c9408SRobert Watson * Allow root in jail to manage a variety of quota 2438e82d0201SRobert Watson * properties. These should likely be conditional on a 2439e82d0201SRobert Watson * configuration option. 2440800c9408SRobert Watson */ 244195b091d2SRobert Watson case PRIV_VFS_GETQUOTA: 244295b091d2SRobert Watson case PRIV_VFS_SETQUOTA: 2443800c9408SRobert Watson 2444800c9408SRobert Watson /* 2445800c9408SRobert Watson * Since Jail relies on chroot() to implement file system 2446800c9408SRobert Watson * protections, grant many VFS privileges to root in jail. 2447800c9408SRobert Watson * Be careful to exclude mount-related and NFS-related 2448800c9408SRobert Watson * privileges. 2449800c9408SRobert Watson */ 2450800c9408SRobert Watson case PRIV_VFS_READ: 2451800c9408SRobert Watson case PRIV_VFS_WRITE: 2452800c9408SRobert Watson case PRIV_VFS_ADMIN: 2453800c9408SRobert Watson case PRIV_VFS_EXEC: 2454800c9408SRobert Watson case PRIV_VFS_LOOKUP: 2455800c9408SRobert Watson case PRIV_VFS_BLOCKRESERVE: /* XXXRW: Slightly surprising. */ 2456800c9408SRobert Watson case PRIV_VFS_CHFLAGS_DEV: 2457800c9408SRobert Watson case PRIV_VFS_CHOWN: 2458800c9408SRobert Watson case PRIV_VFS_CHROOT: 2459bb531912SPawel Jakub Dawidek case PRIV_VFS_RETAINSUGID: 2460800c9408SRobert Watson case PRIV_VFS_FCHROOT: 2461800c9408SRobert Watson case PRIV_VFS_LINK: 2462800c9408SRobert Watson case PRIV_VFS_SETGID: 2463e41966dcSRobert Watson case PRIV_VFS_STAT: 2464800c9408SRobert Watson case PRIV_VFS_STICKYFILE: 2465800c9408SRobert Watson return (0); 2466800c9408SRobert Watson 2467800c9408SRobert Watson /* 2468800c9408SRobert Watson * Depending on the global setting, allow privilege of 2469800c9408SRobert Watson * setting system flags. 2470800c9408SRobert Watson */ 2471800c9408SRobert Watson case PRIV_VFS_SYSFLAGS: 2472800c9408SRobert Watson if (jail_chflags_allowed) 2473800c9408SRobert Watson return (0); 2474800c9408SRobert Watson else 2475800c9408SRobert Watson return (EPERM); 2476800c9408SRobert Watson 2477800c9408SRobert Watson /* 2478f3a8d2f9SPawel Jakub Dawidek * Depending on the global setting, allow privilege of 2479f3a8d2f9SPawel Jakub Dawidek * mounting/unmounting file systems. 2480f3a8d2f9SPawel Jakub Dawidek */ 2481f3a8d2f9SPawel Jakub Dawidek case PRIV_VFS_MOUNT: 2482f3a8d2f9SPawel Jakub Dawidek case PRIV_VFS_UNMOUNT: 2483f3a8d2f9SPawel Jakub Dawidek case PRIV_VFS_MOUNT_NONUSER: 248424b0502eSPawel Jakub Dawidek case PRIV_VFS_MOUNT_OWNER: 2485f3a8d2f9SPawel Jakub Dawidek if (jail_mount_allowed) 2486f3a8d2f9SPawel Jakub Dawidek return (0); 2487f3a8d2f9SPawel Jakub Dawidek else 2488f3a8d2f9SPawel Jakub Dawidek return (EPERM); 2489f3a8d2f9SPawel Jakub Dawidek 2490f3a8d2f9SPawel Jakub Dawidek /* 24914b084056SRobert Watson * Allow jailed root to bind reserved ports and reuse in-use 24924b084056SRobert Watson * ports. 2493800c9408SRobert Watson */ 2494800c9408SRobert Watson case PRIV_NETINET_RESERVEDPORT: 24954b084056SRobert Watson case PRIV_NETINET_REUSEPORT: 2496800c9408SRobert Watson return (0); 2497800c9408SRobert Watson 2498800c9408SRobert Watson /* 249979ba3952SBjoern A. Zeeb * Allow jailed root to set certian IPv4/6 (option) headers. 250079ba3952SBjoern A. Zeeb */ 250179ba3952SBjoern A. Zeeb case PRIV_NETINET_SETHDROPTS: 250279ba3952SBjoern A. Zeeb return (0); 250379ba3952SBjoern A. Zeeb 250479ba3952SBjoern A. Zeeb /* 2505800c9408SRobert Watson * Conditionally allow creating raw sockets in jail. 2506800c9408SRobert Watson */ 2507800c9408SRobert Watson case PRIV_NETINET_RAW: 2508800c9408SRobert Watson if (jail_allow_raw_sockets) 2509800c9408SRobert Watson return (0); 2510800c9408SRobert Watson else 2511800c9408SRobert Watson return (EPERM); 2512800c9408SRobert Watson 2513800c9408SRobert Watson /* 2514800c9408SRobert Watson * Since jail implements its own visibility limits on netstat 2515800c9408SRobert Watson * sysctls, allow getcred. This allows identd to work in 2516800c9408SRobert Watson * jail. 2517800c9408SRobert Watson */ 2518800c9408SRobert Watson case PRIV_NETINET_GETCRED: 2519800c9408SRobert Watson return (0); 2520800c9408SRobert Watson 2521800c9408SRobert Watson default: 2522800c9408SRobert Watson /* 2523800c9408SRobert Watson * In all remaining cases, deny the privilege request. This 2524800c9408SRobert Watson * includes almost all network privileges, many system 2525800c9408SRobert Watson * configuration privileges. 2526800c9408SRobert Watson */ 2527800c9408SRobert Watson return (EPERM); 2528800c9408SRobert Watson } 2529800c9408SRobert Watson } 2530800c9408SRobert Watson 2531fd7a8150SMike Barcroft static int 2532fd7a8150SMike Barcroft sysctl_jail_list(SYSCTL_HANDLER_ARGS) 2533fd7a8150SMike Barcroft { 2534b38ff370SJamie Gritton struct xprison *xp; 2535fd7a8150SMike Barcroft struct prison *pr; 2536b38ff370SJamie Gritton #ifdef INET 2537b38ff370SJamie Gritton struct in_addr *ip4 = NULL; 2538b38ff370SJamie Gritton int ip4s = 0; 2539b38ff370SJamie Gritton #endif 2540b38ff370SJamie Gritton #ifdef INET6 2541b38ff370SJamie Gritton struct in_addr *ip6 = NULL; 2542b38ff370SJamie Gritton int ip6s = 0; 2543b38ff370SJamie Gritton #endif 2544b38ff370SJamie Gritton int error; 2545fd7a8150SMike Barcroft 25467f4704c0SPawel Jakub Dawidek if (jailed(req->td->td_ucred)) 2547679a1060SRobert Watson return (0); 2548fd7a8150SMike Barcroft 2549b38ff370SJamie Gritton xp = malloc(sizeof(*xp), M_TEMP, M_WAITOK); 2550b38ff370SJamie Gritton error = 0; 2551dc68a633SPawel Jakub Dawidek sx_slock(&allprison_lock); 2552b38ff370SJamie Gritton TAILQ_FOREACH(pr, &allprison, pr_list) { 2553b38ff370SJamie Gritton again: 2554b38ff370SJamie Gritton mtx_lock(&pr->pr_mtx); 2555413628a7SBjoern A. Zeeb #ifdef INET 2556b38ff370SJamie Gritton if (pr->pr_ip4s > 0) { 2557b38ff370SJamie Gritton if (ip4s < pr->pr_ip4s) { 2558b38ff370SJamie Gritton ip4s = pr->pr_ip4s; 2559b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 2560b38ff370SJamie Gritton ip4 = realloc(ip4, ip4s * 2561b38ff370SJamie Gritton sizeof(struct in_addr), M_TEMP, M_WAITOK); 2562b38ff370SJamie Gritton goto again; 2563b38ff370SJamie Gritton } 2564b38ff370SJamie Gritton bcopy(pr->pr_ip4, ip4, 2565b38ff370SJamie Gritton pr->pr_ip4s * sizeof(struct in_addr)); 2566b38ff370SJamie Gritton } 2567413628a7SBjoern A. Zeeb #endif 2568413628a7SBjoern A. Zeeb #ifdef INET6 2569b38ff370SJamie Gritton if (pr->pr_ip6s > 0) { 2570b38ff370SJamie Gritton if (ip6s < pr->pr_ip6s) { 2571b38ff370SJamie Gritton ip6s = pr->pr_ip6s; 2572b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 2573b38ff370SJamie Gritton ip6 = realloc(ip6, ip6s * 2574b38ff370SJamie Gritton sizeof(struct in6_addr), M_TEMP, M_WAITOK); 2575b38ff370SJamie Gritton goto again; 2576413628a7SBjoern A. Zeeb } 2577b38ff370SJamie Gritton bcopy(pr->pr_ip6, ip6, 2578b38ff370SJamie Gritton pr->pr_ip6s * sizeof(struct in6_addr)); 2579b38ff370SJamie Gritton } 2580b38ff370SJamie Gritton #endif 2581b38ff370SJamie Gritton if (pr->pr_ref == 0) { 2582b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 2583b38ff370SJamie Gritton continue; 2584b38ff370SJamie Gritton } 2585b38ff370SJamie Gritton bzero(xp, sizeof(*xp)); 2586fd7a8150SMike Barcroft xp->pr_version = XPRISON_VERSION; 2587fd7a8150SMike Barcroft xp->pr_id = pr->pr_id; 2588b38ff370SJamie Gritton xp->pr_state = pr->pr_uref > 0 2589b38ff370SJamie Gritton ? PRISON_STATE_ALIVE : PRISON_STATE_DYING; 2590b63b0c65SPawel Jakub Dawidek strlcpy(xp->pr_path, pr->pr_path, sizeof(xp->pr_path)); 2591b63b0c65SPawel Jakub Dawidek strlcpy(xp->pr_host, pr->pr_host, sizeof(xp->pr_host)); 2592413628a7SBjoern A. Zeeb strlcpy(xp->pr_name, pr->pr_name, sizeof(xp->pr_name)); 2593413628a7SBjoern A. Zeeb #ifdef INET 2594413628a7SBjoern A. Zeeb xp->pr_ip4s = pr->pr_ip4s; 2595413628a7SBjoern A. Zeeb #endif 2596413628a7SBjoern A. Zeeb #ifdef INET6 2597413628a7SBjoern A. Zeeb xp->pr_ip6s = pr->pr_ip6s; 2598413628a7SBjoern A. Zeeb #endif 2599b38ff370SJamie Gritton mtx_unlock(&pr->pr_mtx); 2600b38ff370SJamie Gritton error = SYSCTL_OUT(req, xp, sizeof(*xp)); 2601b38ff370SJamie Gritton if (error) 2602b38ff370SJamie Gritton break; 2603413628a7SBjoern A. Zeeb #ifdef INET 2604b38ff370SJamie Gritton if (xp->pr_ip4s > 0) { 2605b38ff370SJamie Gritton error = SYSCTL_OUT(req, ip4, 2606b38ff370SJamie Gritton xp->pr_ip4s * sizeof(struct in_addr)); 2607b38ff370SJamie Gritton if (error) 2608b38ff370SJamie Gritton break; 2609413628a7SBjoern A. Zeeb } 2610413628a7SBjoern A. Zeeb #endif 2611413628a7SBjoern A. Zeeb #ifdef INET6 2612b38ff370SJamie Gritton if (xp->pr_ip6s > 0) { 2613b38ff370SJamie Gritton error = SYSCTL_OUT(req, ip6, 2614b38ff370SJamie Gritton xp->pr_ip6s * sizeof(struct in6_addr)); 2615b38ff370SJamie Gritton if (error) 2616b38ff370SJamie Gritton break; 2617413628a7SBjoern A. Zeeb } 2618413628a7SBjoern A. Zeeb #endif 2619fd7a8150SMike Barcroft } 2620dc68a633SPawel Jakub Dawidek sx_sunlock(&allprison_lock); 2621b38ff370SJamie Gritton free(xp, M_TEMP); 2622b38ff370SJamie Gritton #ifdef INET 2623b38ff370SJamie Gritton free(ip4, M_TEMP); 2624b38ff370SJamie Gritton #endif 2625b38ff370SJamie Gritton #ifdef INET6 2626b38ff370SJamie Gritton free(ip6, M_TEMP); 2627b38ff370SJamie Gritton #endif 2628fd7a8150SMike Barcroft return (error); 2629fd7a8150SMike Barcroft } 2630fd7a8150SMike Barcroft 2631f3b86a5fSEd Schouten SYSCTL_OID(_security_jail, OID_AUTO, list, 2632f3b86a5fSEd Schouten CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 0, 2633f3b86a5fSEd Schouten sysctl_jail_list, "S", "List of active jails"); 2634461167c2SPawel Jakub Dawidek 2635461167c2SPawel Jakub Dawidek static int 2636461167c2SPawel Jakub Dawidek sysctl_jail_jailed(SYSCTL_HANDLER_ARGS) 2637461167c2SPawel Jakub Dawidek { 2638461167c2SPawel Jakub Dawidek int error, injail; 2639461167c2SPawel Jakub Dawidek 2640461167c2SPawel Jakub Dawidek injail = jailed(req->td->td_ucred); 2641461167c2SPawel Jakub Dawidek error = SYSCTL_OUT(req, &injail, sizeof(injail)); 2642461167c2SPawel Jakub Dawidek 2643461167c2SPawel Jakub Dawidek return (error); 2644461167c2SPawel Jakub Dawidek } 2645f3b86a5fSEd Schouten SYSCTL_PROC(_security_jail, OID_AUTO, jailed, 2646f3b86a5fSEd Schouten CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 0, 2647f3b86a5fSEd Schouten sysctl_jail_jailed, "I", "Process in jail?"); 2648413628a7SBjoern A. Zeeb 2649413628a7SBjoern A. Zeeb #ifdef DDB 2650b38ff370SJamie Gritton 2651b38ff370SJamie Gritton static void 2652b38ff370SJamie Gritton db_show_prison(struct prison *pr) 2653413628a7SBjoern A. Zeeb { 2654b38ff370SJamie Gritton #if defined(INET) || defined(INET6) 2655b38ff370SJamie Gritton int ii; 2656413628a7SBjoern A. Zeeb #endif 2657413628a7SBjoern A. Zeeb #ifdef INET6 2658413628a7SBjoern A. Zeeb char ip6buf[INET6_ADDRSTRLEN]; 2659413628a7SBjoern A. Zeeb #endif 2660413628a7SBjoern A. Zeeb 2661b38ff370SJamie Gritton db_printf("prison %p:\n", pr); 2662b38ff370SJamie Gritton db_printf(" jid = %d\n", pr->pr_id); 2663b38ff370SJamie Gritton db_printf(" name = %s\n", pr->pr_name); 2664b38ff370SJamie Gritton db_printf(" ref = %d\n", pr->pr_ref); 2665b38ff370SJamie Gritton db_printf(" uref = %d\n", pr->pr_uref); 2666b38ff370SJamie Gritton db_printf(" path = %s\n", pr->pr_path); 2667b38ff370SJamie Gritton db_printf(" cpuset = %d\n", pr->pr_cpuset 2668b38ff370SJamie Gritton ? pr->pr_cpuset->cs_id : -1); 2669b38ff370SJamie Gritton db_printf(" root = %p\n", pr->pr_root); 2670b38ff370SJamie Gritton db_printf(" securelevel = %d\n", pr->pr_securelevel); 2671b38ff370SJamie Gritton db_printf(" flags = %x", pr->pr_flags); 2672b38ff370SJamie Gritton if (pr->pr_flags & PR_PERSIST) 2673b38ff370SJamie Gritton db_printf(" persist"); 2674b38ff370SJamie Gritton db_printf("\n"); 2675b38ff370SJamie Gritton db_printf(" host.hostname = %s\n", pr->pr_host); 2676413628a7SBjoern A. Zeeb #ifdef INET 2677b38ff370SJamie Gritton db_printf(" ip4s = %d\n", pr->pr_ip4s); 2678b38ff370SJamie Gritton for (ii = 0; ii < pr->pr_ip4s; ii++) 2679b38ff370SJamie Gritton db_printf(" %s %s\n", 2680b38ff370SJamie Gritton ii == 0 ? "ip4 =" : " ", 2681b38ff370SJamie Gritton inet_ntoa(pr->pr_ip4[ii])); 2682413628a7SBjoern A. Zeeb #endif 2683413628a7SBjoern A. Zeeb #ifdef INET6 2684b38ff370SJamie Gritton db_printf(" ip6s = %d\n", pr->pr_ip6s); 2685b38ff370SJamie Gritton for (ii = 0; ii < pr->pr_ip6s; ii++) 2686b38ff370SJamie Gritton db_printf(" %s %s\n", 2687b38ff370SJamie Gritton ii == 0 ? "ip6 =" : " ", 2688b38ff370SJamie Gritton ip6_sprintf(ip6buf, &pr->pr_ip6[ii])); 2689b38ff370SJamie Gritton #endif 2690b38ff370SJamie Gritton } 2691b38ff370SJamie Gritton 2692b38ff370SJamie Gritton DB_SHOW_COMMAND(prison, db_show_prison_command) 2693b38ff370SJamie Gritton { 2694b38ff370SJamie Gritton struct prison *pr; 2695b38ff370SJamie Gritton 2696b38ff370SJamie Gritton if (!have_addr) { 2697b38ff370SJamie Gritton /* Show all prisons in the list. */ 2698b38ff370SJamie Gritton TAILQ_FOREACH(pr, &allprison, pr_list) { 2699b38ff370SJamie Gritton db_show_prison(pr); 2700413628a7SBjoern A. Zeeb if (db_pager_quit) 2701413628a7SBjoern A. Zeeb break; 2702413628a7SBjoern A. Zeeb } 2703b38ff370SJamie Gritton return; 2704413628a7SBjoern A. Zeeb } 2705b38ff370SJamie Gritton 2706b38ff370SJamie Gritton /* Look for a prison with the ID and with references. */ 2707b38ff370SJamie Gritton TAILQ_FOREACH(pr, &allprison, pr_list) 2708b38ff370SJamie Gritton if (pr->pr_id == addr && pr->pr_ref > 0) 2709b38ff370SJamie Gritton break; 2710b38ff370SJamie Gritton if (pr == NULL) 2711b38ff370SJamie Gritton /* Look again, without requiring a reference. */ 2712b38ff370SJamie Gritton TAILQ_FOREACH(pr, &allprison, pr_list) 2713b38ff370SJamie Gritton if (pr->pr_id == addr) 2714b38ff370SJamie Gritton break; 2715b38ff370SJamie Gritton if (pr == NULL) 2716b38ff370SJamie Gritton /* Assume address points to a valid prison. */ 2717b38ff370SJamie Gritton pr = (struct prison *)addr; 2718b38ff370SJamie Gritton db_show_prison(pr); 2719b38ff370SJamie Gritton } 2720b38ff370SJamie Gritton 2721413628a7SBjoern A. Zeeb #endif /* DDB */ 2722