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 * 2828065282SPeter Wemm * $FreeBSD$ 29c6dfea0eSMarcel Moolenaar */ 30c6dfea0eSMarcel Moolenaar 31c6dfea0eSMarcel Moolenaar #include <sys/param.h> 32c6dfea0eSMarcel Moolenaar #include <sys/kernel.h> 33c6dfea0eSMarcel Moolenaar #include <sys/systm.h> 34c6dfea0eSMarcel Moolenaar #include <sys/sysctl.h> 35c6dfea0eSMarcel Moolenaar #include <sys/proc.h> 36c6dfea0eSMarcel Moolenaar #include <sys/malloc.h> 37c6dfea0eSMarcel Moolenaar #include <sys/jail.h> 3801137630SRobert Watson #include <sys/lock.h> 3901137630SRobert Watson #include <sys/mutex.h> 40c6dfea0eSMarcel Moolenaar 41607d46efSMarcel Moolenaar #include <machine/../linux/linux.h> 42607d46efSMarcel Moolenaar #include <compat/linux/linux_mib.h> 43c6dfea0eSMarcel Moolenaar 44c6dfea0eSMarcel Moolenaar struct linux_prison { 45c6dfea0eSMarcel Moolenaar char pr_osname[LINUX_MAX_UTSNAME]; 46c6dfea0eSMarcel Moolenaar char pr_osrelease[LINUX_MAX_UTSNAME]; 47c6dfea0eSMarcel Moolenaar int pr_oss_version; 48c6dfea0eSMarcel Moolenaar }; 49c6dfea0eSMarcel Moolenaar 50c6dfea0eSMarcel Moolenaar SYSCTL_NODE(_compat, OID_AUTO, linux, CTLFLAG_RW, 0, 51c6dfea0eSMarcel Moolenaar "Linux mode"); 52c6dfea0eSMarcel Moolenaar 53b62f75cfSJohn Baldwin static struct mtx osname_lock; 54b62f75cfSJohn Baldwin MTX_SYSINIT(linux_osname, &osname_lock, "linux osname", MTX_DEF); 55b62f75cfSJohn Baldwin 56c6dfea0eSMarcel Moolenaar static char linux_osname[LINUX_MAX_UTSNAME] = "Linux"; 57c6dfea0eSMarcel Moolenaar 58c6dfea0eSMarcel Moolenaar static int 5982d9ae4eSPoul-Henning Kamp linux_sysctl_osname(SYSCTL_HANDLER_ARGS) 60c6dfea0eSMarcel Moolenaar { 61c6dfea0eSMarcel Moolenaar char osname[LINUX_MAX_UTSNAME]; 62c6dfea0eSMarcel Moolenaar int error; 63c6dfea0eSMarcel Moolenaar 64b62f75cfSJohn Baldwin linux_get_osname(req->td, osname); 65c6dfea0eSMarcel Moolenaar error = sysctl_handle_string(oidp, osname, LINUX_MAX_UTSNAME, req); 66c6dfea0eSMarcel Moolenaar if (error || req->newptr == NULL) 67c6dfea0eSMarcel Moolenaar return (error); 68b62f75cfSJohn Baldwin error = linux_set_osname(req->td, osname); 69c6dfea0eSMarcel Moolenaar return (error); 70c6dfea0eSMarcel Moolenaar } 71c6dfea0eSMarcel Moolenaar 72c6dfea0eSMarcel Moolenaar SYSCTL_PROC(_compat_linux, OID_AUTO, osname, 73c6dfea0eSMarcel Moolenaar CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_PRISON, 74c6dfea0eSMarcel Moolenaar 0, 0, linux_sysctl_osname, "A", 75c6dfea0eSMarcel Moolenaar "Linux kernel OS name"); 76c6dfea0eSMarcel Moolenaar 775002a60fSMarcel Moolenaar static char linux_osrelease[LINUX_MAX_UTSNAME] = "2.4.2"; 78c6dfea0eSMarcel Moolenaar 79c6dfea0eSMarcel Moolenaar static int 8082d9ae4eSPoul-Henning Kamp linux_sysctl_osrelease(SYSCTL_HANDLER_ARGS) 81c6dfea0eSMarcel Moolenaar { 82c6dfea0eSMarcel Moolenaar char osrelease[LINUX_MAX_UTSNAME]; 83c6dfea0eSMarcel Moolenaar int error; 84c6dfea0eSMarcel Moolenaar 85b62f75cfSJohn Baldwin linux_get_osrelease(req->td, osrelease); 86c6dfea0eSMarcel Moolenaar error = sysctl_handle_string(oidp, osrelease, LINUX_MAX_UTSNAME, req); 87c6dfea0eSMarcel Moolenaar if (error || req->newptr == NULL) 88c6dfea0eSMarcel Moolenaar return (error); 89b62f75cfSJohn Baldwin error = linux_set_osrelease(req->td, osrelease); 90c6dfea0eSMarcel Moolenaar return (error); 91c6dfea0eSMarcel Moolenaar } 92c6dfea0eSMarcel Moolenaar 93c6dfea0eSMarcel Moolenaar SYSCTL_PROC(_compat_linux, OID_AUTO, osrelease, 94c6dfea0eSMarcel Moolenaar CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_PRISON, 95c6dfea0eSMarcel Moolenaar 0, 0, linux_sysctl_osrelease, "A", 96c6dfea0eSMarcel Moolenaar "Linux kernel OS release"); 97c6dfea0eSMarcel Moolenaar 98c6dfea0eSMarcel Moolenaar static int linux_oss_version = 0x030600; 99c6dfea0eSMarcel Moolenaar 100c6dfea0eSMarcel Moolenaar static int 10182d9ae4eSPoul-Henning Kamp linux_sysctl_oss_version(SYSCTL_HANDLER_ARGS) 102c6dfea0eSMarcel Moolenaar { 103c6dfea0eSMarcel Moolenaar int oss_version; 104c6dfea0eSMarcel Moolenaar int error; 105c6dfea0eSMarcel Moolenaar 106b62f75cfSJohn Baldwin oss_version = linux_get_oss_version(req->td); 107c6dfea0eSMarcel Moolenaar error = sysctl_handle_int(oidp, &oss_version, 0, req); 108c6dfea0eSMarcel Moolenaar if (error || req->newptr == NULL) 109c6dfea0eSMarcel Moolenaar return (error); 110b62f75cfSJohn Baldwin error = linux_set_oss_version(req->td, oss_version); 111c6dfea0eSMarcel Moolenaar return (error); 112c6dfea0eSMarcel Moolenaar } 113c6dfea0eSMarcel Moolenaar 114c6dfea0eSMarcel Moolenaar SYSCTL_PROC(_compat_linux, OID_AUTO, oss_version, 115c6dfea0eSMarcel Moolenaar CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_PRISON, 116c6dfea0eSMarcel Moolenaar 0, 0, linux_sysctl_oss_version, "I", 117c6dfea0eSMarcel Moolenaar "Linux OSS version"); 118c6dfea0eSMarcel Moolenaar 11901137630SRobert Watson /* 12001137630SRobert Watson * Returns holding the prison mutex if return non-NULL. 12101137630SRobert Watson */ 122b62f75cfSJohn Baldwin static struct prison * 123b62f75cfSJohn Baldwin linux_get_prison(struct thread *td) 124c6dfea0eSMarcel Moolenaar { 125c6dfea0eSMarcel Moolenaar register struct prison *pr; 126c6dfea0eSMarcel Moolenaar register struct linux_prison *lpr; 127c6dfea0eSMarcel Moolenaar 128b62f75cfSJohn Baldwin KASSERT(td == curthread, ("linux_get_prison() called on !curthread")); 129b62f75cfSJohn Baldwin if (!jailed(td->td_ucred)) 130c6dfea0eSMarcel Moolenaar return (NULL); 131b62f75cfSJohn Baldwin pr = td->td_ucred->cr_prison; 132b62f75cfSJohn Baldwin mtx_lock(&pr->pr_mtx); 133b62f75cfSJohn Baldwin if (pr->pr_linux == NULL) { 13401137630SRobert Watson /* 135b62f75cfSJohn Baldwin * If we don't have a linux prison structure yet, allocate 136b62f75cfSJohn Baldwin * one. We have to handle the race where another thread 137b62f75cfSJohn Baldwin * could be adding a linux prison to this process already. 13801137630SRobert Watson */ 13901137630SRobert Watson mtx_unlock(&pr->pr_mtx); 140b62f75cfSJohn Baldwin lpr = malloc(sizeof(struct linux_prison), M_PRISON, 141b62f75cfSJohn Baldwin M_WAITOK | M_ZERO); 14201137630SRobert Watson mtx_lock(&pr->pr_mtx); 143b62f75cfSJohn Baldwin if (pr->pr_linux == NULL) 144c6dfea0eSMarcel Moolenaar pr->pr_linux = lpr; 145b62f75cfSJohn Baldwin else 146b62f75cfSJohn Baldwin free(lpr, M_PRISON); 14701137630SRobert Watson } 148b62f75cfSJohn Baldwin return (pr); 149c6dfea0eSMarcel Moolenaar } 150c6dfea0eSMarcel Moolenaar 15101137630SRobert Watson void 152b62f75cfSJohn Baldwin linux_get_osname(struct thread *td, char *dst) 153c6dfea0eSMarcel Moolenaar { 154c6dfea0eSMarcel Moolenaar register struct prison *pr; 155c6dfea0eSMarcel Moolenaar register struct linux_prison *lpr; 156c6dfea0eSMarcel Moolenaar 157b62f75cfSJohn Baldwin pr = td->td_ucred->cr_prison; 158b62f75cfSJohn Baldwin if (pr != NULL) { 15901137630SRobert Watson mtx_lock(&pr->pr_mtx); 16001137630SRobert Watson if (pr->pr_linux != NULL) { 16101137630SRobert Watson lpr = (struct linux_prison *)pr->pr_linux; 16201137630SRobert Watson if (lpr->pr_osname[0]) { 16301137630SRobert Watson bcopy(lpr->pr_osname, dst, LINUX_MAX_UTSNAME); 16401137630SRobert Watson mtx_unlock(&pr->pr_mtx); 16501137630SRobert Watson return; 16601137630SRobert Watson } 16701137630SRobert Watson } 16801137630SRobert Watson mtx_unlock(&pr->pr_mtx); 169b62f75cfSJohn Baldwin } 170b62f75cfSJohn Baldwin 171b62f75cfSJohn Baldwin mtx_lock(&osname_lock); 17201137630SRobert Watson bcopy(linux_osname, dst, LINUX_MAX_UTSNAME); 173b62f75cfSJohn Baldwin mtx_unlock(&osname_lock); 174c6dfea0eSMarcel Moolenaar } 175c6dfea0eSMarcel Moolenaar 176c6dfea0eSMarcel Moolenaar int 177b62f75cfSJohn Baldwin linux_set_osname(struct thread *td, char *osname) 178c6dfea0eSMarcel Moolenaar { 179b62f75cfSJohn Baldwin struct prison *pr; 180b62f75cfSJohn Baldwin struct linux_prison *lpr; 181c6dfea0eSMarcel Moolenaar 182b62f75cfSJohn Baldwin pr = linux_get_prison(td); 183b62f75cfSJohn Baldwin if (pr != NULL) { 184b62f75cfSJohn Baldwin lpr = (struct linux_prison *)pr->pr_linux; 185c6dfea0eSMarcel Moolenaar strcpy(lpr->pr_osname, osname); 186b62f75cfSJohn Baldwin mtx_unlock(&pr->pr_mtx); 18701137630SRobert Watson } else { 188b62f75cfSJohn Baldwin mtx_lock(&osname_lock); 189c6dfea0eSMarcel Moolenaar strcpy(linux_osname, osname); 190b62f75cfSJohn Baldwin mtx_unlock(&osname_lock); 19101137630SRobert Watson } 192c6dfea0eSMarcel Moolenaar 193c6dfea0eSMarcel Moolenaar return (0); 194c6dfea0eSMarcel Moolenaar } 195c6dfea0eSMarcel Moolenaar 19601137630SRobert Watson void 197b62f75cfSJohn Baldwin linux_get_osrelease(struct thread *td, char *dst) 198c6dfea0eSMarcel Moolenaar { 199c6dfea0eSMarcel Moolenaar register struct prison *pr; 20001137630SRobert Watson struct linux_prison *lpr; 201c6dfea0eSMarcel Moolenaar 202b62f75cfSJohn Baldwin pr = td->td_ucred->cr_prison; 203b62f75cfSJohn Baldwin if (pr != NULL) { 20401137630SRobert Watson mtx_lock(&pr->pr_mtx); 20501137630SRobert Watson if (pr->pr_linux != NULL) { 20601137630SRobert Watson lpr = (struct linux_prison *)pr->pr_linux; 20701137630SRobert Watson if (lpr->pr_osrelease[0]) { 208b62f75cfSJohn Baldwin bcopy(lpr->pr_osrelease, dst, 209b62f75cfSJohn Baldwin LINUX_MAX_UTSNAME); 21001137630SRobert Watson mtx_unlock(&pr->pr_mtx); 21101137630SRobert Watson return; 21201137630SRobert Watson } 21301137630SRobert Watson } 21401137630SRobert Watson mtx_unlock(&pr->pr_mtx); 215b62f75cfSJohn Baldwin } 216b62f75cfSJohn Baldwin 217b62f75cfSJohn Baldwin mtx_lock(&osname_lock); 21801137630SRobert Watson bcopy(linux_osrelease, dst, LINUX_MAX_UTSNAME); 219b62f75cfSJohn Baldwin mtx_unlock(&osname_lock); 220c6dfea0eSMarcel Moolenaar } 221c6dfea0eSMarcel Moolenaar 222c6dfea0eSMarcel Moolenaar int 223b62f75cfSJohn Baldwin linux_set_osrelease(struct thread *td, char *osrelease) 224c6dfea0eSMarcel Moolenaar { 225b62f75cfSJohn Baldwin struct prison *pr; 226b62f75cfSJohn Baldwin struct linux_prison *lpr; 227c6dfea0eSMarcel Moolenaar 228b62f75cfSJohn Baldwin pr = linux_get_prison(td); 229b62f75cfSJohn Baldwin if (pr != NULL) { 230b62f75cfSJohn Baldwin lpr = (struct linux_prison *)pr->pr_linux; 231c6dfea0eSMarcel Moolenaar strcpy(lpr->pr_osrelease, osrelease); 232b62f75cfSJohn Baldwin mtx_unlock(&pr->pr_mtx); 23301137630SRobert Watson } else { 234b62f75cfSJohn Baldwin mtx_lock(&osname_lock); 235c6dfea0eSMarcel Moolenaar strcpy(linux_osrelease, osrelease); 236b62f75cfSJohn Baldwin mtx_unlock(&osname_lock); 23701137630SRobert Watson } 238c6dfea0eSMarcel Moolenaar 239c6dfea0eSMarcel Moolenaar return (0); 240c6dfea0eSMarcel Moolenaar } 241c6dfea0eSMarcel Moolenaar 242c6dfea0eSMarcel Moolenaar int 243b62f75cfSJohn Baldwin linux_get_oss_version(struct thread *td) 244c6dfea0eSMarcel Moolenaar { 245c6dfea0eSMarcel Moolenaar register struct prison *pr; 246c6dfea0eSMarcel Moolenaar register struct linux_prison *lpr; 24701137630SRobert Watson int version; 24801137630SRobert Watson 249b62f75cfSJohn Baldwin pr = td->td_ucred->cr_prison; 250b62f75cfSJohn Baldwin if (pr != NULL) { 25101137630SRobert Watson mtx_lock(&pr->pr_mtx); 25201137630SRobert Watson if (pr->pr_linux != NULL) { 25301137630SRobert Watson lpr = (struct linux_prison *)pr->pr_linux; 25401137630SRobert Watson if (lpr->pr_oss_version) { 25501137630SRobert Watson version = lpr->pr_oss_version; 256b62f75cfSJohn Baldwin mtx_unlock(&pr->pr_mtx); 257b62f75cfSJohn Baldwin return (version); 25801137630SRobert Watson } 25901137630SRobert Watson } 26001137630SRobert Watson mtx_unlock(&pr->pr_mtx); 261b62f75cfSJohn Baldwin } 26201137630SRobert Watson 263b62f75cfSJohn Baldwin mtx_lock(&osname_lock); 264b62f75cfSJohn Baldwin version = linux_oss_version; 265b62f75cfSJohn Baldwin mtx_unlock(&osname_lock); 26601137630SRobert Watson return (version); 267c6dfea0eSMarcel Moolenaar } 268c6dfea0eSMarcel Moolenaar 269c6dfea0eSMarcel Moolenaar int 270b62f75cfSJohn Baldwin linux_set_oss_version(struct thread *td, int oss_version) 271c6dfea0eSMarcel Moolenaar { 272b62f75cfSJohn Baldwin struct prison *pr; 273b62f75cfSJohn Baldwin struct linux_prison *lpr; 274c6dfea0eSMarcel Moolenaar 275b62f75cfSJohn Baldwin pr = linux_get_prison(td); 276b62f75cfSJohn Baldwin if (pr != NULL) { 277b62f75cfSJohn Baldwin lpr = (struct linux_prison *)pr->pr_linux; 278c6dfea0eSMarcel Moolenaar lpr->pr_oss_version = oss_version; 279b62f75cfSJohn Baldwin mtx_unlock(&pr->pr_mtx); 28001137630SRobert Watson } else { 281b62f75cfSJohn Baldwin mtx_lock(&osname_lock); 282c6dfea0eSMarcel Moolenaar linux_oss_version = oss_version; 283b62f75cfSJohn Baldwin mtx_unlock(&osname_lock); 28401137630SRobert Watson } 285c6dfea0eSMarcel Moolenaar 286c6dfea0eSMarcel Moolenaar return (0); 287c6dfea0eSMarcel Moolenaar } 28824593369SJonathan Lemon 28924593369SJonathan Lemon #ifdef DEBUG 29024593369SJonathan Lemon 29167b60513SPeter Wemm u_char linux_debug_map[howmany(LINUX_SYS_MAXSYSCALL, sizeof(u_char))]; 29224593369SJonathan Lemon 293ec0b1e67SPeter Wemm static int 29424593369SJonathan Lemon linux_debug(int syscall, int toggle, int global) 29524593369SJonathan Lemon { 29624593369SJonathan Lemon 29724593369SJonathan Lemon if (global) { 29824593369SJonathan Lemon char c = toggle ? 0 : 0xff; 29924593369SJonathan Lemon 30024593369SJonathan Lemon memset(linux_debug_map, c, sizeof(linux_debug_map)); 30124593369SJonathan Lemon return (0); 30224593369SJonathan Lemon } 30324593369SJonathan Lemon if (syscall < 0 || syscall >= LINUX_SYS_MAXSYSCALL) 30424593369SJonathan Lemon return (EINVAL); 30524593369SJonathan Lemon if (toggle) 30624593369SJonathan Lemon clrbit(linux_debug_map, syscall); 30724593369SJonathan Lemon else 30824593369SJonathan Lemon setbit(linux_debug_map, syscall); 30924593369SJonathan Lemon return (0); 31024593369SJonathan Lemon } 31124593369SJonathan Lemon 31224593369SJonathan Lemon /* 313b90faaf3SDima Dorfman * Usage: sysctl linux.debug=<syscall_nr>.<0/1> 31424593369SJonathan Lemon * 315b90faaf3SDima Dorfman * E.g.: sysctl linux.debug=21.0 31624593369SJonathan Lemon * 31724593369SJonathan Lemon * As a special case, syscall "all" will apply to all syscalls globally. 31824593369SJonathan Lemon */ 31924593369SJonathan Lemon #define LINUX_MAX_DEBUGSTR 16 32024593369SJonathan Lemon static int 32124593369SJonathan Lemon linux_sysctl_debug(SYSCTL_HANDLER_ARGS) 32224593369SJonathan Lemon { 32324593369SJonathan Lemon char value[LINUX_MAX_DEBUGSTR], *p; 32424593369SJonathan Lemon int error, sysc, toggle; 32524593369SJonathan Lemon int global = 0; 32624593369SJonathan Lemon 32724593369SJonathan Lemon value[0] = '\0'; 32824593369SJonathan Lemon error = sysctl_handle_string(oidp, value, LINUX_MAX_DEBUGSTR, req); 32924593369SJonathan Lemon if (error || req->newptr == NULL) 33024593369SJonathan Lemon return (error); 33124593369SJonathan Lemon for (p = value; *p != '\0' && *p != '.'; p++); 33224593369SJonathan Lemon if (*p == '\0') 33324593369SJonathan Lemon return (EINVAL); 33424593369SJonathan Lemon *p++ = '\0'; 33524593369SJonathan Lemon sysc = strtol(value, NULL, 0); 33624593369SJonathan Lemon toggle = strtol(p, NULL, 0); 33724593369SJonathan Lemon if (strcmp(value, "all") == 0) 33824593369SJonathan Lemon global = 1; 33924593369SJonathan Lemon error = linux_debug(sysc, toggle, global); 34024593369SJonathan Lemon return (error); 34124593369SJonathan Lemon } 34224593369SJonathan Lemon 34324593369SJonathan Lemon SYSCTL_PROC(_compat_linux, OID_AUTO, debug, 34424593369SJonathan Lemon CTLTYPE_STRING | CTLFLAG_RW, 34524593369SJonathan Lemon 0, 0, linux_sysctl_debug, "A", 34624593369SJonathan Lemon "Linux debugging control"); 34724593369SJonathan Lemon 34824593369SJonathan Lemon #endif /* DEBUG */ 349