1c6dfea0eSMarcel Moolenaar /*- 2c6dfea0eSMarcel Moolenaar * Copyright (c) 1999 Marcel Moolenaar 3c6dfea0eSMarcel Moolenaar * All rights reserved. 4c6dfea0eSMarcel Moolenaar * 5c6dfea0eSMarcel Moolenaar * Redistribution and use in source and binary forms, with or without 6c6dfea0eSMarcel Moolenaar * modification, are permitted provided that the following conditions 7c6dfea0eSMarcel Moolenaar * are met: 8c6dfea0eSMarcel Moolenaar * 1. Redistributions of source code must retain the above copyright 9c6dfea0eSMarcel Moolenaar * notice, this list of conditions and the following disclaimer 10c6dfea0eSMarcel Moolenaar * in this position and unchanged. 11c6dfea0eSMarcel Moolenaar * 2. Redistributions in binary form must reproduce the above copyright 12c6dfea0eSMarcel Moolenaar * notice, this list of conditions and the following disclaimer in the 13c6dfea0eSMarcel Moolenaar * documentation and/or other materials provided with the distribution. 14c6dfea0eSMarcel Moolenaar * 3. The name of the author may not be used to endorse or promote products 15bc34729cSMarcel Moolenaar * derived from this software without specific prior written permission. 16c6dfea0eSMarcel Moolenaar * 17c6dfea0eSMarcel Moolenaar * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18c6dfea0eSMarcel Moolenaar * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19c6dfea0eSMarcel Moolenaar * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20c6dfea0eSMarcel Moolenaar * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21c6dfea0eSMarcel Moolenaar * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22c6dfea0eSMarcel Moolenaar * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23c6dfea0eSMarcel Moolenaar * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24c6dfea0eSMarcel Moolenaar * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25c6dfea0eSMarcel Moolenaar * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26c6dfea0eSMarcel Moolenaar * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27c6dfea0eSMarcel Moolenaar */ 28c6dfea0eSMarcel Moolenaar 2916dbc7f2SDavid E. O'Brien #include <sys/cdefs.h> 3016dbc7f2SDavid E. O'Brien __FBSDID("$FreeBSD$"); 3116dbc7f2SDavid E. O'Brien 32c6dfea0eSMarcel Moolenaar #include <sys/param.h> 33c6dfea0eSMarcel Moolenaar #include <sys/kernel.h> 34c6dfea0eSMarcel Moolenaar #include <sys/systm.h> 35c6dfea0eSMarcel Moolenaar #include <sys/sysctl.h> 36c6dfea0eSMarcel Moolenaar #include <sys/proc.h> 37c6dfea0eSMarcel Moolenaar #include <sys/malloc.h> 387ae27ff4SJamie Gritton #include <sys/mount.h> 39c6dfea0eSMarcel Moolenaar #include <sys/jail.h> 4001137630SRobert Watson #include <sys/lock.h> 4101137630SRobert Watson #include <sys/mutex.h> 427ae27ff4SJamie Gritton #include <sys/sx.h> 43c6dfea0eSMarcel Moolenaar 44aefce619SRuslan Ermilov #include "opt_compat.h" 45aefce619SRuslan Ermilov 461997c537SDavid E. O'Brien #ifdef COMPAT_LINUX32 474af27623STim J. Robbins #include <machine/../linux32/linux.h> 481997c537SDavid E. O'Brien #else 491997c537SDavid E. O'Brien #include <machine/../linux/linux.h> 504af27623STim J. Robbins #endif 51607d46efSMarcel Moolenaar #include <compat/linux/linux_mib.h> 52c6dfea0eSMarcel Moolenaar 53c6dfea0eSMarcel Moolenaar struct linux_prison { 54c6dfea0eSMarcel Moolenaar char pr_osname[LINUX_MAX_UTSNAME]; 55c6dfea0eSMarcel Moolenaar char pr_osrelease[LINUX_MAX_UTSNAME]; 56c6dfea0eSMarcel Moolenaar int pr_oss_version; 57580dd797SDmitry Chagin int pr_osrel; 58c6dfea0eSMarcel Moolenaar }; 59c6dfea0eSMarcel Moolenaar 600304c731SJamie Gritton static struct linux_prison lprison0 = { 610304c731SJamie Gritton .pr_osname = "Linux", 620304c731SJamie Gritton .pr_osrelease = "2.6.16", 630304c731SJamie Gritton .pr_oss_version = 0x030600, 640304c731SJamie Gritton .pr_osrel = 2006016 650304c731SJamie Gritton }; 660304c731SJamie Gritton 677ae27ff4SJamie Gritton static unsigned linux_osd_jail_slot; 687ae27ff4SJamie Gritton 69c6dfea0eSMarcel Moolenaar SYSCTL_NODE(_compat, OID_AUTO, linux, CTLFLAG_RW, 0, 70c6dfea0eSMarcel Moolenaar "Linux mode"); 71c6dfea0eSMarcel Moolenaar 72c6dfea0eSMarcel Moolenaar static int 7382d9ae4eSPoul-Henning Kamp linux_sysctl_osname(SYSCTL_HANDLER_ARGS) 74c6dfea0eSMarcel Moolenaar { 75c6dfea0eSMarcel Moolenaar char osname[LINUX_MAX_UTSNAME]; 76c6dfea0eSMarcel Moolenaar int error; 77c6dfea0eSMarcel Moolenaar 78b62f75cfSJohn Baldwin linux_get_osname(req->td, osname); 79c6dfea0eSMarcel Moolenaar error = sysctl_handle_string(oidp, osname, LINUX_MAX_UTSNAME, req); 80c6dfea0eSMarcel Moolenaar if (error || req->newptr == NULL) 81c6dfea0eSMarcel Moolenaar return (error); 82b62f75cfSJohn Baldwin error = linux_set_osname(req->td, osname); 83c6dfea0eSMarcel Moolenaar return (error); 84c6dfea0eSMarcel Moolenaar } 85c6dfea0eSMarcel Moolenaar 86c6dfea0eSMarcel Moolenaar SYSCTL_PROC(_compat_linux, OID_AUTO, osname, 8784a8cad0SJamie Gritton CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_PRISON | CTLFLAG_MPSAFE, 88c6dfea0eSMarcel Moolenaar 0, 0, linux_sysctl_osname, "A", 89c6dfea0eSMarcel Moolenaar "Linux kernel OS name"); 90c6dfea0eSMarcel Moolenaar 91c6dfea0eSMarcel Moolenaar static int 9282d9ae4eSPoul-Henning Kamp linux_sysctl_osrelease(SYSCTL_HANDLER_ARGS) 93c6dfea0eSMarcel Moolenaar { 94c6dfea0eSMarcel Moolenaar char osrelease[LINUX_MAX_UTSNAME]; 95c6dfea0eSMarcel Moolenaar int error; 96c6dfea0eSMarcel Moolenaar 97b62f75cfSJohn Baldwin linux_get_osrelease(req->td, osrelease); 98c6dfea0eSMarcel Moolenaar error = sysctl_handle_string(oidp, osrelease, LINUX_MAX_UTSNAME, req); 99c6dfea0eSMarcel Moolenaar if (error || req->newptr == NULL) 100c6dfea0eSMarcel Moolenaar return (error); 101b62f75cfSJohn Baldwin error = linux_set_osrelease(req->td, osrelease); 102c6dfea0eSMarcel Moolenaar return (error); 103c6dfea0eSMarcel Moolenaar } 104c6dfea0eSMarcel Moolenaar 105c6dfea0eSMarcel Moolenaar SYSCTL_PROC(_compat_linux, OID_AUTO, osrelease, 10684a8cad0SJamie Gritton CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_PRISON | CTLFLAG_MPSAFE, 107c6dfea0eSMarcel Moolenaar 0, 0, linux_sysctl_osrelease, "A", 108c6dfea0eSMarcel Moolenaar "Linux kernel OS release"); 109c6dfea0eSMarcel Moolenaar 110c6dfea0eSMarcel Moolenaar static int 11182d9ae4eSPoul-Henning Kamp linux_sysctl_oss_version(SYSCTL_HANDLER_ARGS) 112c6dfea0eSMarcel Moolenaar { 113c6dfea0eSMarcel Moolenaar int oss_version; 114c6dfea0eSMarcel Moolenaar int error; 115c6dfea0eSMarcel Moolenaar 116b62f75cfSJohn Baldwin oss_version = linux_get_oss_version(req->td); 117c6dfea0eSMarcel Moolenaar error = sysctl_handle_int(oidp, &oss_version, 0, req); 118c6dfea0eSMarcel Moolenaar if (error || req->newptr == NULL) 119c6dfea0eSMarcel Moolenaar return (error); 120b62f75cfSJohn Baldwin error = linux_set_oss_version(req->td, oss_version); 121c6dfea0eSMarcel Moolenaar return (error); 122c6dfea0eSMarcel Moolenaar } 123c6dfea0eSMarcel Moolenaar 124c6dfea0eSMarcel Moolenaar SYSCTL_PROC(_compat_linux, OID_AUTO, oss_version, 12584a8cad0SJamie Gritton CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_PRISON | CTLFLAG_MPSAFE, 126c6dfea0eSMarcel Moolenaar 0, 0, linux_sysctl_oss_version, "I", 127c6dfea0eSMarcel Moolenaar "Linux OSS version"); 128c6dfea0eSMarcel Moolenaar 12901137630SRobert Watson /* 130580dd797SDmitry Chagin * Map the osrelease into integer 131580dd797SDmitry Chagin */ 132580dd797SDmitry Chagin static int 133580dd797SDmitry Chagin linux_map_osrel(char *osrelease, int *osrel) 134580dd797SDmitry Chagin { 135580dd797SDmitry Chagin char *sep, *eosrelease; 136580dd797SDmitry Chagin int len, v0, v1, v2, v; 137580dd797SDmitry Chagin 138580dd797SDmitry Chagin len = strlen(osrelease); 139580dd797SDmitry Chagin eosrelease = osrelease + len; 140580dd797SDmitry Chagin v0 = strtol(osrelease, &sep, 10); 141580dd797SDmitry Chagin if (osrelease == sep || sep + 1 >= eosrelease || *sep != '.') 142580dd797SDmitry Chagin return (EINVAL); 143580dd797SDmitry Chagin osrelease = sep + 1; 144580dd797SDmitry Chagin v1 = strtol(osrelease, &sep, 10); 145580dd797SDmitry Chagin if (osrelease == sep || sep + 1 >= eosrelease || *sep != '.') 146580dd797SDmitry Chagin return (EINVAL); 147580dd797SDmitry Chagin osrelease = sep + 1; 148580dd797SDmitry Chagin v2 = strtol(osrelease, &sep, 10); 149580dd797SDmitry Chagin if (osrelease == sep || sep != eosrelease) 150580dd797SDmitry Chagin return (EINVAL); 151580dd797SDmitry Chagin 152580dd797SDmitry Chagin v = v0 * 1000000 + v1 * 1000 + v2; 153580dd797SDmitry Chagin if (v < 1000000) 154580dd797SDmitry Chagin return (EINVAL); 155580dd797SDmitry Chagin 156580dd797SDmitry Chagin *osrel = v; 157580dd797SDmitry Chagin return (0); 158580dd797SDmitry Chagin } 159580dd797SDmitry Chagin 160580dd797SDmitry Chagin /* 1610304c731SJamie Gritton * Find a prison with Linux info. 1620304c731SJamie Gritton * Return the Linux info and the (locked) prison. 16301137630SRobert Watson */ 1647ae27ff4SJamie Gritton static struct linux_prison * 1650304c731SJamie Gritton linux_find_prison(struct prison *spr, struct prison **prp) 166c6dfea0eSMarcel Moolenaar { 1677ae27ff4SJamie Gritton struct prison *pr; 1687ae27ff4SJamie Gritton struct linux_prison *lpr; 169c6dfea0eSMarcel Moolenaar 1700304c731SJamie Gritton if (!linux_osd_jail_slot) 1710304c731SJamie Gritton /* In case osd_register failed. */ 1720304c731SJamie Gritton spr = &prison0; 1730304c731SJamie Gritton for (pr = spr;; pr = pr->pr_parent) { 174b62f75cfSJohn Baldwin mtx_lock(&pr->pr_mtx); 1750304c731SJamie Gritton lpr = (pr == &prison0) 1760304c731SJamie Gritton ? &lprison0 1770304c731SJamie Gritton : osd_jail_get(pr, linux_osd_jail_slot); 1780304c731SJamie Gritton if (lpr != NULL) 1790304c731SJamie Gritton break; 1807ae27ff4SJamie Gritton mtx_unlock(&pr->pr_mtx); 1810304c731SJamie Gritton } 1820304c731SJamie Gritton *prp = pr; 1837ae27ff4SJamie Gritton return (lpr); 1847ae27ff4SJamie Gritton } 1857ae27ff4SJamie Gritton 18601137630SRobert Watson /* 1870304c731SJamie Gritton * Ensure a prison has its own Linux info. If lprp is non-null, point it to 1880304c731SJamie Gritton * the Linux info and lock the prison. 1897ae27ff4SJamie Gritton */ 1907ae27ff4SJamie Gritton static int 1917ae27ff4SJamie Gritton linux_alloc_prison(struct prison *pr, struct linux_prison **lprp) 1927ae27ff4SJamie Gritton { 1930304c731SJamie Gritton struct prison *ppr; 1947ae27ff4SJamie Gritton struct linux_prison *lpr, *nlpr; 1957ae27ff4SJamie Gritton int error; 1967ae27ff4SJamie Gritton 1977ae27ff4SJamie Gritton /* If this prison already has Linux info, return that. */ 1987ae27ff4SJamie Gritton error = 0; 1990304c731SJamie Gritton lpr = linux_find_prison(pr, &ppr); 2000304c731SJamie Gritton if (ppr == pr) 2017ae27ff4SJamie Gritton goto done; 2027ae27ff4SJamie Gritton /* 2037ae27ff4SJamie Gritton * Allocate a new info record. Then check again, in case something 2047ae27ff4SJamie Gritton * changed during the allocation. 20501137630SRobert Watson */ 2060304c731SJamie Gritton mtx_unlock(&ppr->pr_mtx); 2077ae27ff4SJamie Gritton nlpr = malloc(sizeof(struct linux_prison), M_PRISON, M_WAITOK); 2080304c731SJamie Gritton lpr = linux_find_prison(pr, &ppr); 2090304c731SJamie Gritton if (ppr == pr) { 2107ae27ff4SJamie Gritton free(nlpr, M_PRISON); 2117ae27ff4SJamie Gritton goto done; 21201137630SRobert Watson } 2130304c731SJamie Gritton /* Inherit the initial values from the ancestor. */ 2140304c731SJamie Gritton mtx_lock(&pr->pr_mtx); 2157ae27ff4SJamie Gritton error = osd_jail_set(pr, linux_osd_jail_slot, nlpr); 2160304c731SJamie Gritton if (error == 0) { 2170304c731SJamie Gritton bcopy(lpr, nlpr, sizeof(*lpr)); 2187ae27ff4SJamie Gritton lpr = nlpr; 2190304c731SJamie Gritton } else { 2200304c731SJamie Gritton free(nlpr, M_PRISON); 2210304c731SJamie Gritton lpr = NULL; 2227ae27ff4SJamie Gritton } 2230304c731SJamie Gritton mtx_unlock(&ppr->pr_mtx); 2247ae27ff4SJamie Gritton done: 2257ae27ff4SJamie Gritton if (lprp != NULL) 2267ae27ff4SJamie Gritton *lprp = lpr; 2270304c731SJamie Gritton else 2280304c731SJamie Gritton mtx_unlock(&pr->pr_mtx); 2297ae27ff4SJamie Gritton return (error); 2307ae27ff4SJamie Gritton } 2317ae27ff4SJamie Gritton 2327ae27ff4SJamie Gritton /* 2337ae27ff4SJamie Gritton * Jail OSD methods for Linux prison data. 2347ae27ff4SJamie Gritton */ 2357ae27ff4SJamie Gritton static int 2367ae27ff4SJamie Gritton linux_prison_create(void *obj, void *data) 2377ae27ff4SJamie Gritton { 2387ae27ff4SJamie Gritton struct prison *pr = obj; 2397ae27ff4SJamie Gritton struct vfsoptlist *opts = data; 2407cbf7213SJamie Gritton int jsys; 2417ae27ff4SJamie Gritton 2427cbf7213SJamie Gritton if (vfs_copyopt(opts, "linux", &jsys, sizeof(jsys)) == 0 && 2437cbf7213SJamie Gritton jsys == JAIL_SYS_INHERIT) 2447ae27ff4SJamie Gritton return (0); 2457ae27ff4SJamie Gritton /* 2467ae27ff4SJamie Gritton * Inherit a prison's initial values from its parent 2477cbf7213SJamie Gritton * (different from JAIL_SYS_INHERIT which also inherits changes). 2487ae27ff4SJamie Gritton */ 2490304c731SJamie Gritton return linux_alloc_prison(pr, NULL); 2507ae27ff4SJamie Gritton } 2517ae27ff4SJamie Gritton 2527ae27ff4SJamie Gritton static int 2537ae27ff4SJamie Gritton linux_prison_check(void *obj __unused, void *data) 2547ae27ff4SJamie Gritton { 2557ae27ff4SJamie Gritton struct vfsoptlist *opts = data; 2567ae27ff4SJamie Gritton char *osname, *osrelease; 2577cbf7213SJamie Gritton int error, jsys, len, osrel, oss_version; 2587ae27ff4SJamie Gritton 2597ae27ff4SJamie Gritton /* Check that the parameters are correct. */ 2607cbf7213SJamie Gritton error = vfs_copyopt(opts, "linux", &jsys, sizeof(jsys)); 2617cbf7213SJamie Gritton if (error != ENOENT) { 2627cbf7213SJamie Gritton if (error != 0) 2637cbf7213SJamie Gritton return (error); 2647cbf7213SJamie Gritton if (jsys != JAIL_SYS_NEW && jsys != JAIL_SYS_INHERIT) 2657cbf7213SJamie Gritton return (EINVAL); 2667cbf7213SJamie Gritton } 2677ae27ff4SJamie Gritton error = vfs_getopt(opts, "linux.osname", (void **)&osname, &len); 2687ae27ff4SJamie Gritton if (error != ENOENT) { 2697ae27ff4SJamie Gritton if (error != 0) 2707ae27ff4SJamie Gritton return (error); 2717ae27ff4SJamie Gritton if (len == 0 || osname[len - 1] != '\0') 2727ae27ff4SJamie Gritton return (EINVAL); 2737ae27ff4SJamie Gritton if (len > LINUX_MAX_UTSNAME) { 2747ae27ff4SJamie Gritton vfs_opterror(opts, "linux.osname too long"); 2757ae27ff4SJamie Gritton return (ENAMETOOLONG); 2767ae27ff4SJamie Gritton } 2777ae27ff4SJamie Gritton } 2787ae27ff4SJamie Gritton error = vfs_getopt(opts, "linux.osrelease", (void **)&osrelease, &len); 2797ae27ff4SJamie Gritton if (error != ENOENT) { 2807ae27ff4SJamie Gritton if (error != 0) 2817ae27ff4SJamie Gritton return (error); 2827ae27ff4SJamie Gritton if (len == 0 || osrelease[len - 1] != '\0') 2837ae27ff4SJamie Gritton return (EINVAL); 2847ae27ff4SJamie Gritton if (len > LINUX_MAX_UTSNAME) { 2857ae27ff4SJamie Gritton vfs_opterror(opts, "linux.osrelease too long"); 2867ae27ff4SJamie Gritton return (ENAMETOOLONG); 2877ae27ff4SJamie Gritton } 2880304c731SJamie Gritton error = linux_map_osrel(osrelease, &osrel); 2890304c731SJamie Gritton if (error != 0) { 2900304c731SJamie Gritton vfs_opterror(opts, "linux.osrelease format error"); 2910304c731SJamie Gritton return (error); 2920304c731SJamie Gritton } 2937ae27ff4SJamie Gritton } 2947ae27ff4SJamie Gritton error = vfs_copyopt(opts, "linux.oss_version", &oss_version, 2957ae27ff4SJamie Gritton sizeof(oss_version)); 2967ae27ff4SJamie Gritton return (error == ENOENT ? 0 : error); 2977ae27ff4SJamie Gritton } 2987ae27ff4SJamie Gritton 2997ae27ff4SJamie Gritton static int 3007ae27ff4SJamie Gritton linux_prison_set(void *obj, void *data) 3017ae27ff4SJamie Gritton { 3027ae27ff4SJamie Gritton struct linux_prison *lpr; 3037ae27ff4SJamie Gritton struct prison *pr = obj; 3047ae27ff4SJamie Gritton struct vfsoptlist *opts = data; 3057ae27ff4SJamie Gritton char *osname, *osrelease; 3067cbf7213SJamie Gritton int error, gotversion, jsys, len, oss_version; 3077ae27ff4SJamie Gritton 3087ae27ff4SJamie Gritton /* Set the parameters, which should be correct. */ 3097cbf7213SJamie Gritton error = vfs_copyopt(opts, "linux", &jsys, sizeof(jsys)); 3107cbf7213SJamie Gritton if (error == ENOENT) 3117cbf7213SJamie Gritton jsys = -1; 3127ae27ff4SJamie Gritton error = vfs_getopt(opts, "linux.osname", (void **)&osname, &len); 3137ae27ff4SJamie Gritton if (error == ENOENT) 3147ae27ff4SJamie Gritton osname = NULL; 3157ae27ff4SJamie Gritton else 3167cbf7213SJamie Gritton jsys = JAIL_SYS_NEW; 3177ae27ff4SJamie Gritton error = vfs_getopt(opts, "linux.osrelease", (void **)&osrelease, &len); 3187ae27ff4SJamie Gritton if (error == ENOENT) 3197ae27ff4SJamie Gritton osrelease = NULL; 3207ae27ff4SJamie Gritton else 3217cbf7213SJamie Gritton jsys = JAIL_SYS_NEW; 3227ae27ff4SJamie Gritton error = vfs_copyopt(opts, "linux.oss_version", &oss_version, 3237ae27ff4SJamie Gritton sizeof(oss_version)); 3247cbf7213SJamie Gritton if (error == ENOENT) 3257cbf7213SJamie Gritton gotversion = 0; 3267cbf7213SJamie Gritton else { 3277cbf7213SJamie Gritton gotversion = 1; 3287cbf7213SJamie Gritton jsys = JAIL_SYS_NEW; 3297cbf7213SJamie Gritton } 3307cbf7213SJamie Gritton switch (jsys) { 3317cbf7213SJamie Gritton case JAIL_SYS_INHERIT: 3327cbf7213SJamie Gritton /* "linux=inherit": inherit the parent's Linux info. */ 3337ae27ff4SJamie Gritton mtx_lock(&pr->pr_mtx); 3347ae27ff4SJamie Gritton osd_jail_del(pr, linux_osd_jail_slot); 3357ae27ff4SJamie Gritton mtx_unlock(&pr->pr_mtx); 3367cbf7213SJamie Gritton break; 3377cbf7213SJamie Gritton case JAIL_SYS_NEW: 3387ae27ff4SJamie Gritton /* 3397cbf7213SJamie Gritton * "linux=new" or "linux.*": 3407ae27ff4SJamie Gritton * the prison gets its own Linux info. 3417ae27ff4SJamie Gritton */ 3427ae27ff4SJamie Gritton error = linux_alloc_prison(pr, &lpr); 3437ae27ff4SJamie Gritton if (error) { 3447ae27ff4SJamie Gritton mtx_unlock(&pr->pr_mtx); 3457ae27ff4SJamie Gritton return (error); 3467ae27ff4SJamie Gritton } 3477ae27ff4SJamie Gritton if (osrelease) { 348580dd797SDmitry Chagin error = linux_map_osrel(osrelease, &lpr->pr_osrel); 349580dd797SDmitry Chagin if (error) { 350580dd797SDmitry Chagin mtx_unlock(&pr->pr_mtx); 351580dd797SDmitry Chagin return (error); 352580dd797SDmitry Chagin } 3537ae27ff4SJamie Gritton strlcpy(lpr->pr_osrelease, osrelease, 3547ae27ff4SJamie Gritton LINUX_MAX_UTSNAME); 3557ae27ff4SJamie Gritton } 356580dd797SDmitry Chagin if (osname) 357580dd797SDmitry Chagin strlcpy(lpr->pr_osname, osname, LINUX_MAX_UTSNAME); 3587ae27ff4SJamie Gritton if (gotversion) 3597ae27ff4SJamie Gritton lpr->pr_oss_version = oss_version; 3607ae27ff4SJamie Gritton mtx_unlock(&pr->pr_mtx); 3617ae27ff4SJamie Gritton } 3627ae27ff4SJamie Gritton return (0); 3637ae27ff4SJamie Gritton } 3647ae27ff4SJamie Gritton 3657cbf7213SJamie Gritton SYSCTL_JAIL_PARAM_SYS_NODE(linux, CTLFLAG_RW, "Jail Linux parameters"); 3667ae27ff4SJamie Gritton SYSCTL_JAIL_PARAM_STRING(_linux, osname, CTLFLAG_RW, LINUX_MAX_UTSNAME, 3677ae27ff4SJamie Gritton "Jail Linux kernel OS name"); 3687ae27ff4SJamie Gritton SYSCTL_JAIL_PARAM_STRING(_linux, osrelease, CTLFLAG_RW, LINUX_MAX_UTSNAME, 3697ae27ff4SJamie Gritton "Jail Linux kernel OS release"); 3707ae27ff4SJamie Gritton SYSCTL_JAIL_PARAM(_linux, oss_version, CTLTYPE_INT | CTLFLAG_RW, 3717ae27ff4SJamie Gritton "I", "Jail Linux OSS version"); 3727ae27ff4SJamie Gritton 3737ae27ff4SJamie Gritton static int 3747ae27ff4SJamie Gritton linux_prison_get(void *obj, void *data) 3757ae27ff4SJamie Gritton { 3767ae27ff4SJamie Gritton struct linux_prison *lpr; 3770304c731SJamie Gritton struct prison *ppr; 3787ae27ff4SJamie Gritton struct prison *pr = obj; 3797ae27ff4SJamie Gritton struct vfsoptlist *opts = data; 3807ae27ff4SJamie Gritton int error, i; 3817ae27ff4SJamie Gritton 3820304c731SJamie Gritton static int version0; 3830304c731SJamie Gritton 3840304c731SJamie Gritton /* See if this prison is the one with the Linux info. */ 3850304c731SJamie Gritton lpr = linux_find_prison(pr, &ppr); 3867cbf7213SJamie Gritton i = (ppr == pr) ? JAIL_SYS_NEW : JAIL_SYS_INHERIT; 3877ae27ff4SJamie Gritton error = vfs_setopt(opts, "linux", &i, sizeof(i)); 3887ae27ff4SJamie Gritton if (error != 0 && error != ENOENT) 3897ae27ff4SJamie Gritton goto done; 3907cbf7213SJamie Gritton if (i) { 3917cbf7213SJamie Gritton error = vfs_setopts(opts, "linux.osname", lpr->pr_osname); 3927ae27ff4SJamie Gritton if (error != 0 && error != ENOENT) 3937ae27ff4SJamie Gritton goto done; 3947cbf7213SJamie Gritton error = vfs_setopts(opts, "linux.osrelease", lpr->pr_osrelease); 3957cbf7213SJamie Gritton if (error != 0 && error != ENOENT) 3967cbf7213SJamie Gritton goto done; 3977cbf7213SJamie Gritton error = vfs_setopt(opts, "linux.oss_version", 3987cbf7213SJamie Gritton &lpr->pr_oss_version, sizeof(lpr->pr_oss_version)); 3997cbf7213SJamie Gritton if (error != 0 && error != ENOENT) 4007cbf7213SJamie Gritton goto done; 4017cbf7213SJamie Gritton } else { 4027ae27ff4SJamie Gritton /* 4030304c731SJamie Gritton * If this prison is inheriting its Linux info, report 4040304c731SJamie Gritton * empty/zero parameters. 4057ae27ff4SJamie Gritton */ 4060304c731SJamie Gritton error = vfs_setopts(opts, "linux.osname", ""); 4070304c731SJamie Gritton if (error != 0 && error != ENOENT) 4080304c731SJamie Gritton goto done; 4090304c731SJamie Gritton error = vfs_setopts(opts, "linux.osrelease", ""); 4100304c731SJamie Gritton if (error != 0 && error != ENOENT) 4110304c731SJamie Gritton goto done; 4120304c731SJamie Gritton error = vfs_setopt(opts, "linux.oss_version", &version0, 4130304c731SJamie Gritton sizeof(lpr->pr_oss_version)); 4140304c731SJamie Gritton if (error != 0 && error != ENOENT) 4150304c731SJamie Gritton goto done; 4167ae27ff4SJamie Gritton } 4177ae27ff4SJamie Gritton error = 0; 4187ae27ff4SJamie Gritton 4197ae27ff4SJamie Gritton done: 4200304c731SJamie Gritton mtx_unlock(&ppr->pr_mtx); 4217ae27ff4SJamie Gritton return (error); 4227ae27ff4SJamie Gritton } 4237ae27ff4SJamie Gritton 4247ae27ff4SJamie Gritton static void 4257ae27ff4SJamie Gritton linux_prison_destructor(void *data) 4267ae27ff4SJamie Gritton { 4277ae27ff4SJamie Gritton 4287ae27ff4SJamie Gritton free(data, M_PRISON); 4297ae27ff4SJamie Gritton } 4307ae27ff4SJamie Gritton 4317ae27ff4SJamie Gritton void 4327ae27ff4SJamie Gritton linux_osd_jail_register(void) 4337ae27ff4SJamie Gritton { 4347ae27ff4SJamie Gritton struct prison *pr; 4357ae27ff4SJamie Gritton osd_method_t methods[PR_MAXMETHOD] = { 4367ae27ff4SJamie Gritton [PR_METHOD_CREATE] = linux_prison_create, 4377ae27ff4SJamie Gritton [PR_METHOD_GET] = linux_prison_get, 4387ae27ff4SJamie Gritton [PR_METHOD_SET] = linux_prison_set, 4397ae27ff4SJamie Gritton [PR_METHOD_CHECK] = linux_prison_check 4407ae27ff4SJamie Gritton }; 4417ae27ff4SJamie Gritton 4427ae27ff4SJamie Gritton linux_osd_jail_slot = 4437ae27ff4SJamie Gritton osd_jail_register(linux_prison_destructor, methods); 4447ae27ff4SJamie Gritton if (linux_osd_jail_slot > 0) { 4457ae27ff4SJamie Gritton /* Copy the system linux info to any current prisons. */ 4467ae27ff4SJamie Gritton sx_xlock(&allprison_lock); 4470304c731SJamie Gritton TAILQ_FOREACH(pr, &allprison, pr_list) 4487ae27ff4SJamie Gritton (void)linux_alloc_prison(pr, NULL); 4497ae27ff4SJamie Gritton sx_xunlock(&allprison_lock); 4507ae27ff4SJamie Gritton } 4517ae27ff4SJamie Gritton } 4527ae27ff4SJamie Gritton 4537ae27ff4SJamie Gritton void 4547ae27ff4SJamie Gritton linux_osd_jail_deregister(void) 4557ae27ff4SJamie Gritton { 4567ae27ff4SJamie Gritton 4577ae27ff4SJamie Gritton if (linux_osd_jail_slot) 4587ae27ff4SJamie Gritton osd_jail_deregister(linux_osd_jail_slot); 459c6dfea0eSMarcel Moolenaar } 460c6dfea0eSMarcel Moolenaar 46101137630SRobert Watson void 462b62f75cfSJohn Baldwin linux_get_osname(struct thread *td, char *dst) 463c6dfea0eSMarcel Moolenaar { 4647ae27ff4SJamie Gritton struct prison *pr; 4657ae27ff4SJamie Gritton struct linux_prison *lpr; 466c6dfea0eSMarcel Moolenaar 4670304c731SJamie Gritton lpr = linux_find_prison(td->td_ucred->cr_prison, &pr); 46801137630SRobert Watson bcopy(lpr->pr_osname, dst, LINUX_MAX_UTSNAME); 46901137630SRobert Watson mtx_unlock(&pr->pr_mtx); 4707ae27ff4SJamie Gritton } 471c6dfea0eSMarcel Moolenaar 472c6dfea0eSMarcel Moolenaar int 473b62f75cfSJohn Baldwin linux_set_osname(struct thread *td, char *osname) 474c6dfea0eSMarcel Moolenaar { 475b62f75cfSJohn Baldwin struct prison *pr; 476b62f75cfSJohn Baldwin struct linux_prison *lpr; 477c6dfea0eSMarcel Moolenaar 4780304c731SJamie Gritton lpr = linux_find_prison(td->td_ucred->cr_prison, &pr); 4797ae27ff4SJamie Gritton strlcpy(lpr->pr_osname, osname, LINUX_MAX_UTSNAME); 480b62f75cfSJohn Baldwin mtx_unlock(&pr->pr_mtx); 481c6dfea0eSMarcel Moolenaar return (0); 482c6dfea0eSMarcel Moolenaar } 483c6dfea0eSMarcel Moolenaar 48401137630SRobert Watson void 485b62f75cfSJohn Baldwin linux_get_osrelease(struct thread *td, char *dst) 486c6dfea0eSMarcel Moolenaar { 4877ae27ff4SJamie Gritton struct prison *pr; 48801137630SRobert Watson struct linux_prison *lpr; 489c6dfea0eSMarcel Moolenaar 4900304c731SJamie Gritton lpr = linux_find_prison(td->td_ucred->cr_prison, &pr); 4917ae27ff4SJamie Gritton bcopy(lpr->pr_osrelease, dst, LINUX_MAX_UTSNAME); 49201137630SRobert Watson mtx_unlock(&pr->pr_mtx); 4937ae27ff4SJamie Gritton } 494c6dfea0eSMarcel Moolenaar 495c6dfea0eSMarcel Moolenaar int 496580dd797SDmitry Chagin linux_kernver(struct thread *td) 4979ce8f9bcSAlexander Leidinger { 4989ce8f9bcSAlexander Leidinger struct prison *pr; 4999ce8f9bcSAlexander Leidinger struct linux_prison *lpr; 500580dd797SDmitry Chagin int osrel; 5019ce8f9bcSAlexander Leidinger 5020304c731SJamie Gritton lpr = linux_find_prison(td->td_ucred->cr_prison, &pr); 503580dd797SDmitry Chagin osrel = lpr->pr_osrel; 5047ae27ff4SJamie Gritton mtx_unlock(&pr->pr_mtx); 505580dd797SDmitry Chagin return (osrel); 5069ce8f9bcSAlexander Leidinger } 5079ce8f9bcSAlexander Leidinger 5089ce8f9bcSAlexander Leidinger int 509b62f75cfSJohn Baldwin linux_set_osrelease(struct thread *td, char *osrelease) 510c6dfea0eSMarcel Moolenaar { 511b62f75cfSJohn Baldwin struct prison *pr; 512b62f75cfSJohn Baldwin struct linux_prison *lpr; 513580dd797SDmitry Chagin int error; 5149ce8f9bcSAlexander Leidinger 5150304c731SJamie Gritton lpr = linux_find_prison(td->td_ucred->cr_prison, &pr); 516580dd797SDmitry Chagin error = linux_map_osrel(osrelease, &lpr->pr_osrel); 5170304c731SJamie Gritton if (error == 0) 5187ae27ff4SJamie Gritton strlcpy(lpr->pr_osrelease, osrelease, LINUX_MAX_UTSNAME); 519b62f75cfSJohn Baldwin mtx_unlock(&pr->pr_mtx); 520580dd797SDmitry Chagin return (error); 521580dd797SDmitry Chagin } 522c6dfea0eSMarcel Moolenaar 523c6dfea0eSMarcel Moolenaar int 524b62f75cfSJohn Baldwin linux_get_oss_version(struct thread *td) 525c6dfea0eSMarcel Moolenaar { 5267ae27ff4SJamie Gritton struct prison *pr; 5277ae27ff4SJamie Gritton struct linux_prison *lpr; 52801137630SRobert Watson int version; 52901137630SRobert Watson 5300304c731SJamie Gritton lpr = linux_find_prison(td->td_ucred->cr_prison, &pr); 53101137630SRobert Watson version = lpr->pr_oss_version; 532b62f75cfSJohn Baldwin mtx_unlock(&pr->pr_mtx); 53301137630SRobert Watson return (version); 534c6dfea0eSMarcel Moolenaar } 535c6dfea0eSMarcel Moolenaar 536c6dfea0eSMarcel Moolenaar int 537b62f75cfSJohn Baldwin linux_set_oss_version(struct thread *td, int oss_version) 538c6dfea0eSMarcel Moolenaar { 539b62f75cfSJohn Baldwin struct prison *pr; 540b62f75cfSJohn Baldwin struct linux_prison *lpr; 541c6dfea0eSMarcel Moolenaar 5420304c731SJamie Gritton lpr = linux_find_prison(td->td_ucred->cr_prison, &pr); 543c6dfea0eSMarcel Moolenaar lpr->pr_oss_version = oss_version; 544b62f75cfSJohn Baldwin mtx_unlock(&pr->pr_mtx); 545c6dfea0eSMarcel Moolenaar return (0); 546c6dfea0eSMarcel Moolenaar } 54724593369SJonathan Lemon 5484ec3ea90SDmitry Chagin #if defined(DEBUG) || defined(KTR) 54924593369SJonathan Lemon 55067b60513SPeter Wemm u_char linux_debug_map[howmany(LINUX_SYS_MAXSYSCALL, sizeof(u_char))]; 55124593369SJonathan Lemon 552ec0b1e67SPeter Wemm static int 55324593369SJonathan Lemon linux_debug(int syscall, int toggle, int global) 55424593369SJonathan Lemon { 55524593369SJonathan Lemon 55624593369SJonathan Lemon if (global) { 55724593369SJonathan Lemon char c = toggle ? 0 : 0xff; 55824593369SJonathan Lemon 55924593369SJonathan Lemon memset(linux_debug_map, c, sizeof(linux_debug_map)); 56024593369SJonathan Lemon return (0); 56124593369SJonathan Lemon } 56224593369SJonathan Lemon if (syscall < 0 || syscall >= LINUX_SYS_MAXSYSCALL) 56324593369SJonathan Lemon return (EINVAL); 56424593369SJonathan Lemon if (toggle) 56524593369SJonathan Lemon clrbit(linux_debug_map, syscall); 56624593369SJonathan Lemon else 56724593369SJonathan Lemon setbit(linux_debug_map, syscall); 56824593369SJonathan Lemon return (0); 56924593369SJonathan Lemon } 57024593369SJonathan Lemon 57124593369SJonathan Lemon /* 572b90faaf3SDima Dorfman * Usage: sysctl linux.debug=<syscall_nr>.<0/1> 57324593369SJonathan Lemon * 574b90faaf3SDima Dorfman * E.g.: sysctl linux.debug=21.0 57524593369SJonathan Lemon * 57624593369SJonathan Lemon * As a special case, syscall "all" will apply to all syscalls globally. 57724593369SJonathan Lemon */ 57824593369SJonathan Lemon #define LINUX_MAX_DEBUGSTR 16 57924593369SJonathan Lemon static int 58024593369SJonathan Lemon linux_sysctl_debug(SYSCTL_HANDLER_ARGS) 58124593369SJonathan Lemon { 58224593369SJonathan Lemon char value[LINUX_MAX_DEBUGSTR], *p; 58324593369SJonathan Lemon int error, sysc, toggle; 58424593369SJonathan Lemon int global = 0; 58524593369SJonathan Lemon 58624593369SJonathan Lemon value[0] = '\0'; 58724593369SJonathan Lemon error = sysctl_handle_string(oidp, value, LINUX_MAX_DEBUGSTR, req); 58824593369SJonathan Lemon if (error || req->newptr == NULL) 58924593369SJonathan Lemon return (error); 59024593369SJonathan Lemon for (p = value; *p != '\0' && *p != '.'; p++); 59124593369SJonathan Lemon if (*p == '\0') 59224593369SJonathan Lemon return (EINVAL); 59324593369SJonathan Lemon *p++ = '\0'; 59424593369SJonathan Lemon sysc = strtol(value, NULL, 0); 59524593369SJonathan Lemon toggle = strtol(p, NULL, 0); 59624593369SJonathan Lemon if (strcmp(value, "all") == 0) 59724593369SJonathan Lemon global = 1; 59824593369SJonathan Lemon error = linux_debug(sysc, toggle, global); 59924593369SJonathan Lemon return (error); 60024593369SJonathan Lemon } 60124593369SJonathan Lemon 60224593369SJonathan Lemon SYSCTL_PROC(_compat_linux, OID_AUTO, debug, 60324593369SJonathan Lemon CTLTYPE_STRING | CTLFLAG_RW, 60424593369SJonathan Lemon 0, 0, linux_sysctl_debug, "A", 60524593369SJonathan Lemon "Linux debugging control"); 60624593369SJonathan Lemon 6074ec3ea90SDmitry Chagin #endif /* DEBUG || KTR */ 608