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 53c6dfea0eSMarcel Moolenaar static char linux_osname[LINUX_MAX_UTSNAME] = "Linux"; 54c6dfea0eSMarcel Moolenaar 55c6dfea0eSMarcel Moolenaar static int 5682d9ae4eSPoul-Henning Kamp linux_sysctl_osname(SYSCTL_HANDLER_ARGS) 57c6dfea0eSMarcel Moolenaar { 58c6dfea0eSMarcel Moolenaar char osname[LINUX_MAX_UTSNAME]; 59c6dfea0eSMarcel Moolenaar int error; 60c6dfea0eSMarcel Moolenaar 6101137630SRobert Watson linux_get_osname(req->td->td_proc, osname); 62c6dfea0eSMarcel Moolenaar error = sysctl_handle_string(oidp, osname, LINUX_MAX_UTSNAME, req); 63c6dfea0eSMarcel Moolenaar if (error || req->newptr == NULL) 64c6dfea0eSMarcel Moolenaar return (error); 65ce178806SRobert Watson error = linux_set_osname(req->td->td_proc, osname); 66c6dfea0eSMarcel Moolenaar return (error); 67c6dfea0eSMarcel Moolenaar } 68c6dfea0eSMarcel Moolenaar 69c6dfea0eSMarcel Moolenaar SYSCTL_PROC(_compat_linux, OID_AUTO, osname, 70c6dfea0eSMarcel Moolenaar CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_PRISON, 71c6dfea0eSMarcel Moolenaar 0, 0, linux_sysctl_osname, "A", 72c6dfea0eSMarcel Moolenaar "Linux kernel OS name"); 73c6dfea0eSMarcel Moolenaar 745002a60fSMarcel Moolenaar static char linux_osrelease[LINUX_MAX_UTSNAME] = "2.4.2"; 75c6dfea0eSMarcel Moolenaar 76c6dfea0eSMarcel Moolenaar static int 7782d9ae4eSPoul-Henning Kamp linux_sysctl_osrelease(SYSCTL_HANDLER_ARGS) 78c6dfea0eSMarcel Moolenaar { 79c6dfea0eSMarcel Moolenaar char osrelease[LINUX_MAX_UTSNAME]; 80c6dfea0eSMarcel Moolenaar int error; 81c6dfea0eSMarcel Moolenaar 8201137630SRobert Watson linux_get_osrelease(req->td->td_proc, osrelease); 83c6dfea0eSMarcel Moolenaar error = sysctl_handle_string(oidp, osrelease, LINUX_MAX_UTSNAME, req); 84c6dfea0eSMarcel Moolenaar if (error || req->newptr == NULL) 85c6dfea0eSMarcel Moolenaar return (error); 86ce178806SRobert Watson error = linux_set_osrelease(req->td->td_proc, osrelease); 87c6dfea0eSMarcel Moolenaar return (error); 88c6dfea0eSMarcel Moolenaar } 89c6dfea0eSMarcel Moolenaar 90c6dfea0eSMarcel Moolenaar SYSCTL_PROC(_compat_linux, OID_AUTO, osrelease, 91c6dfea0eSMarcel Moolenaar CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_PRISON, 92c6dfea0eSMarcel Moolenaar 0, 0, linux_sysctl_osrelease, "A", 93c6dfea0eSMarcel Moolenaar "Linux kernel OS release"); 94c6dfea0eSMarcel Moolenaar 95c6dfea0eSMarcel Moolenaar static int linux_oss_version = 0x030600; 96c6dfea0eSMarcel Moolenaar 97c6dfea0eSMarcel Moolenaar static int 9882d9ae4eSPoul-Henning Kamp linux_sysctl_oss_version(SYSCTL_HANDLER_ARGS) 99c6dfea0eSMarcel Moolenaar { 100c6dfea0eSMarcel Moolenaar int oss_version; 101c6dfea0eSMarcel Moolenaar int error; 102c6dfea0eSMarcel Moolenaar 103ce178806SRobert Watson oss_version = linux_get_oss_version(req->td->td_proc); 104c6dfea0eSMarcel Moolenaar error = sysctl_handle_int(oidp, &oss_version, 0, req); 105c6dfea0eSMarcel Moolenaar if (error || req->newptr == NULL) 106c6dfea0eSMarcel Moolenaar return (error); 107ce178806SRobert Watson error = linux_set_oss_version(req->td->td_proc, oss_version); 108c6dfea0eSMarcel Moolenaar return (error); 109c6dfea0eSMarcel Moolenaar } 110c6dfea0eSMarcel Moolenaar 111c6dfea0eSMarcel Moolenaar SYSCTL_PROC(_compat_linux, OID_AUTO, oss_version, 112c6dfea0eSMarcel Moolenaar CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_PRISON, 113c6dfea0eSMarcel Moolenaar 0, 0, linux_sysctl_oss_version, "I", 114c6dfea0eSMarcel Moolenaar "Linux OSS version"); 115c6dfea0eSMarcel Moolenaar 11601137630SRobert Watson /* 11701137630SRobert Watson * Returns holding the prison mutex if return non-NULL. 11801137630SRobert Watson */ 119c6dfea0eSMarcel Moolenaar static struct linux_prison * 12001137630SRobert Watson linux_get_prison(struct proc *p) 121c6dfea0eSMarcel Moolenaar { 122c6dfea0eSMarcel Moolenaar register struct prison *pr; 123c6dfea0eSMarcel Moolenaar register struct linux_prison *lpr; 124c6dfea0eSMarcel Moolenaar 12591421ba2SRobert Watson if (!jailed(p->p_ucred)) 126c6dfea0eSMarcel Moolenaar return (NULL); 127c6dfea0eSMarcel Moolenaar 12891421ba2SRobert Watson pr = p->p_ucred->cr_prison; 12991421ba2SRobert Watson 13001137630SRobert Watson /* 13101137630SRobert Watson * Rather than hold the prison mutex during allocation, check to 13201137630SRobert Watson * see if we need to allocate while holding the mutex, release it, 13301137630SRobert Watson * allocate, then once we've allocated the memory, check again to 13401137630SRobert Watson * see if it's still needed, and set if appropriate. If it's not, 13501137630SRobert Watson * we release the mutex again to FREE(), and grab it again so as 13601137630SRobert Watson * to release holding the lock. 13701137630SRobert Watson */ 13801137630SRobert Watson mtx_lock(&pr->pr_mtx); 139c6dfea0eSMarcel Moolenaar if (pr->pr_linux == NULL) { 14001137630SRobert Watson mtx_unlock(&pr->pr_mtx); 141c6dfea0eSMarcel Moolenaar MALLOC(lpr, struct linux_prison *, sizeof *lpr, 1427ec97432SMarcel Moolenaar M_PRISON, M_WAITOK|M_ZERO); 14301137630SRobert Watson mtx_lock(&pr->pr_mtx); 14401137630SRobert Watson if (pr->pr_linux == NULL) { 145c6dfea0eSMarcel Moolenaar pr->pr_linux = lpr; 14601137630SRobert Watson } else { 14701137630SRobert Watson mtx_unlock(&pr->pr_mtx); 14801137630SRobert Watson FREE(lpr, M_PRISON); 14901137630SRobert Watson mtx_lock(&pr->pr_mtx); 15001137630SRobert Watson } 151c6dfea0eSMarcel Moolenaar } 152c6dfea0eSMarcel Moolenaar 153c6dfea0eSMarcel Moolenaar return (pr->pr_linux); 154c6dfea0eSMarcel Moolenaar } 155c6dfea0eSMarcel Moolenaar 15601137630SRobert Watson void 15701137630SRobert Watson linux_get_osname(p, dst) 158c6dfea0eSMarcel Moolenaar struct proc *p; 15901137630SRobert Watson char *dst; 160c6dfea0eSMarcel Moolenaar { 161c6dfea0eSMarcel Moolenaar register struct prison *pr; 162c6dfea0eSMarcel Moolenaar register struct linux_prison *lpr; 163c6dfea0eSMarcel Moolenaar 16401137630SRobert Watson if (p->p_ucred->cr_prison == NULL) { 16501137630SRobert Watson bcopy(linux_osname, dst, LINUX_MAX_UTSNAME); 16601137630SRobert Watson return; 167c6dfea0eSMarcel Moolenaar } 168c6dfea0eSMarcel Moolenaar 16901137630SRobert Watson pr = p->p_ucred->cr_prison; 17001137630SRobert Watson 17101137630SRobert Watson mtx_lock(&pr->pr_mtx); 17201137630SRobert Watson if (pr->pr_linux != NULL) { 17301137630SRobert Watson lpr = (struct linux_prison *)pr->pr_linux; 17401137630SRobert Watson if (lpr->pr_osname[0]) { 17501137630SRobert Watson bcopy(lpr->pr_osname, dst, LINUX_MAX_UTSNAME); 17601137630SRobert Watson mtx_unlock(&pr->pr_mtx); 17701137630SRobert Watson return; 17801137630SRobert Watson } 17901137630SRobert Watson } 18001137630SRobert Watson mtx_unlock(&pr->pr_mtx); 18101137630SRobert Watson bcopy(linux_osname, dst, LINUX_MAX_UTSNAME); 182c6dfea0eSMarcel Moolenaar } 183c6dfea0eSMarcel Moolenaar 184c6dfea0eSMarcel Moolenaar int 185c6dfea0eSMarcel Moolenaar linux_set_osname(p, osname) 186c6dfea0eSMarcel Moolenaar struct proc *p; 187c6dfea0eSMarcel Moolenaar char *osname; 188c6dfea0eSMarcel Moolenaar { 189c6dfea0eSMarcel Moolenaar register struct linux_prison *lpr; 190c6dfea0eSMarcel Moolenaar 19101137630SRobert Watson lpr = linux_get_prison(p); 19201137630SRobert Watson if (lpr != NULL) { 193c6dfea0eSMarcel Moolenaar strcpy(lpr->pr_osname, osname); 19401137630SRobert Watson mtx_unlock(&p->p_ucred->cr_prison->pr_mtx); 19501137630SRobert Watson } else { 196c6dfea0eSMarcel Moolenaar strcpy(linux_osname, osname); 19701137630SRobert Watson } 198c6dfea0eSMarcel Moolenaar 199c6dfea0eSMarcel Moolenaar return (0); 200c6dfea0eSMarcel Moolenaar } 201c6dfea0eSMarcel Moolenaar 20201137630SRobert Watson void 20301137630SRobert Watson linux_get_osrelease(p, dst) 204c6dfea0eSMarcel Moolenaar struct proc *p; 20501137630SRobert Watson char *dst; 206c6dfea0eSMarcel Moolenaar { 207c6dfea0eSMarcel Moolenaar register struct prison *pr; 20801137630SRobert Watson struct linux_prison *lpr; 209c6dfea0eSMarcel Moolenaar 21001137630SRobert Watson if (p->p_ucred->cr_prison == NULL) { 21101137630SRobert Watson bcopy(linux_osrelease, dst, LINUX_MAX_UTSNAME); 21201137630SRobert Watson return; 213c6dfea0eSMarcel Moolenaar } 214c6dfea0eSMarcel Moolenaar 21501137630SRobert Watson pr = p->p_ucred->cr_prison; 21601137630SRobert Watson 21701137630SRobert Watson mtx_lock(&pr->pr_mtx); 21801137630SRobert Watson if (pr->pr_linux != NULL) { 21901137630SRobert Watson lpr = (struct linux_prison *) pr->pr_linux; 22001137630SRobert Watson if (lpr->pr_osrelease[0]) { 22101137630SRobert Watson bcopy(lpr->pr_osrelease, dst, LINUX_MAX_UTSNAME); 22201137630SRobert Watson mtx_unlock(&pr->pr_mtx); 22301137630SRobert Watson return; 22401137630SRobert Watson } 22501137630SRobert Watson } 22601137630SRobert Watson mtx_unlock(&pr->pr_mtx); 22701137630SRobert Watson bcopy(linux_osrelease, dst, LINUX_MAX_UTSNAME); 228c6dfea0eSMarcel Moolenaar } 229c6dfea0eSMarcel Moolenaar 230c6dfea0eSMarcel Moolenaar int 231c6dfea0eSMarcel Moolenaar linux_set_osrelease(p, osrelease) 232c6dfea0eSMarcel Moolenaar struct proc *p; 233c6dfea0eSMarcel Moolenaar char *osrelease; 234c6dfea0eSMarcel Moolenaar { 235c6dfea0eSMarcel Moolenaar register struct linux_prison *lpr; 236c6dfea0eSMarcel Moolenaar 23701137630SRobert Watson lpr = linux_get_prison(p); 23801137630SRobert Watson if (lpr != NULL) { 239c6dfea0eSMarcel Moolenaar strcpy(lpr->pr_osrelease, osrelease); 24001137630SRobert Watson mtx_unlock(&p->p_ucred->cr_prison->pr_mtx); 24101137630SRobert Watson } else { 242c6dfea0eSMarcel Moolenaar strcpy(linux_osrelease, osrelease); 24301137630SRobert Watson } 244c6dfea0eSMarcel Moolenaar 245c6dfea0eSMarcel Moolenaar return (0); 246c6dfea0eSMarcel Moolenaar } 247c6dfea0eSMarcel Moolenaar 248c6dfea0eSMarcel Moolenaar int 249c6dfea0eSMarcel Moolenaar linux_get_oss_version(p) 250c6dfea0eSMarcel Moolenaar struct proc *p; 251c6dfea0eSMarcel Moolenaar { 252c6dfea0eSMarcel Moolenaar register struct prison *pr; 253c6dfea0eSMarcel Moolenaar register struct linux_prison *lpr; 25401137630SRobert Watson int version; 25501137630SRobert Watson 25601137630SRobert Watson if (p->p_ucred->cr_prison == NULL) 25701137630SRobert Watson return (linux_oss_version); 258c6dfea0eSMarcel Moolenaar 25991421ba2SRobert Watson pr = p->p_ucred->cr_prison; 260c6dfea0eSMarcel Moolenaar 26101137630SRobert Watson mtx_lock(&pr->pr_mtx); 26201137630SRobert Watson if (pr->pr_linux != NULL) { 26301137630SRobert Watson lpr = (struct linux_prison *) pr->pr_linux; 26401137630SRobert Watson if (lpr->pr_oss_version) { 26501137630SRobert Watson version = lpr->pr_oss_version; 26601137630SRobert Watson } else { 26701137630SRobert Watson version = linux_oss_version; 26801137630SRobert Watson } 26901137630SRobert Watson } else { 27001137630SRobert Watson version = linux_oss_version; 27101137630SRobert Watson } 27201137630SRobert Watson mtx_unlock(&pr->pr_mtx); 27301137630SRobert Watson 27401137630SRobert Watson return (version); 275c6dfea0eSMarcel Moolenaar } 276c6dfea0eSMarcel Moolenaar 277c6dfea0eSMarcel Moolenaar int 278c6dfea0eSMarcel Moolenaar linux_set_oss_version(p, oss_version) 279c6dfea0eSMarcel Moolenaar struct proc *p; 280c6dfea0eSMarcel Moolenaar int oss_version; 281c6dfea0eSMarcel Moolenaar { 282c6dfea0eSMarcel Moolenaar register struct linux_prison *lpr; 283c6dfea0eSMarcel Moolenaar 28401137630SRobert Watson lpr = linux_get_prison(p); 28501137630SRobert Watson if (lpr != NULL) { 286c6dfea0eSMarcel Moolenaar lpr->pr_oss_version = oss_version; 28701137630SRobert Watson mtx_unlock(&p->p_ucred->cr_prison->pr_mtx); 28801137630SRobert Watson } else { 289c6dfea0eSMarcel Moolenaar linux_oss_version = oss_version; 29001137630SRobert Watson } 291c6dfea0eSMarcel Moolenaar 292c6dfea0eSMarcel Moolenaar return (0); 293c6dfea0eSMarcel Moolenaar } 29424593369SJonathan Lemon 29524593369SJonathan Lemon #ifdef DEBUG 29624593369SJonathan Lemon 29767b60513SPeter Wemm u_char linux_debug_map[howmany(LINUX_SYS_MAXSYSCALL, sizeof(u_char))]; 29824593369SJonathan Lemon 299ec0b1e67SPeter Wemm static int 30024593369SJonathan Lemon linux_debug(int syscall, int toggle, int global) 30124593369SJonathan Lemon { 30224593369SJonathan Lemon 30324593369SJonathan Lemon if (global) { 30424593369SJonathan Lemon char c = toggle ? 0 : 0xff; 30524593369SJonathan Lemon 30624593369SJonathan Lemon memset(linux_debug_map, c, sizeof(linux_debug_map)); 30724593369SJonathan Lemon return (0); 30824593369SJonathan Lemon } 30924593369SJonathan Lemon if (syscall < 0 || syscall >= LINUX_SYS_MAXSYSCALL) 31024593369SJonathan Lemon return (EINVAL); 31124593369SJonathan Lemon if (toggle) 31224593369SJonathan Lemon clrbit(linux_debug_map, syscall); 31324593369SJonathan Lemon else 31424593369SJonathan Lemon setbit(linux_debug_map, syscall); 31524593369SJonathan Lemon return (0); 31624593369SJonathan Lemon } 31724593369SJonathan Lemon 31824593369SJonathan Lemon /* 31924593369SJonathan Lemon * Usage: sysctl -w linux.debug=<syscall_nr>.<0/1> 32024593369SJonathan Lemon * 32124593369SJonathan Lemon * E.g.: sysctl -w linux.debug=21.0 32224593369SJonathan Lemon * 32324593369SJonathan Lemon * As a special case, syscall "all" will apply to all syscalls globally. 32424593369SJonathan Lemon */ 32524593369SJonathan Lemon #define LINUX_MAX_DEBUGSTR 16 32624593369SJonathan Lemon static int 32724593369SJonathan Lemon linux_sysctl_debug(SYSCTL_HANDLER_ARGS) 32824593369SJonathan Lemon { 32924593369SJonathan Lemon char value[LINUX_MAX_DEBUGSTR], *p; 33024593369SJonathan Lemon int error, sysc, toggle; 33124593369SJonathan Lemon int global = 0; 33224593369SJonathan Lemon 33324593369SJonathan Lemon value[0] = '\0'; 33424593369SJonathan Lemon error = sysctl_handle_string(oidp, value, LINUX_MAX_DEBUGSTR, req); 33524593369SJonathan Lemon if (error || req->newptr == NULL) 33624593369SJonathan Lemon return (error); 33724593369SJonathan Lemon for (p = value; *p != '\0' && *p != '.'; p++); 33824593369SJonathan Lemon if (*p == '\0') 33924593369SJonathan Lemon return (EINVAL); 34024593369SJonathan Lemon *p++ = '\0'; 34124593369SJonathan Lemon sysc = strtol(value, NULL, 0); 34224593369SJonathan Lemon toggle = strtol(p, NULL, 0); 34324593369SJonathan Lemon if (strcmp(value, "all") == 0) 34424593369SJonathan Lemon global = 1; 34524593369SJonathan Lemon error = linux_debug(sysc, toggle, global); 34624593369SJonathan Lemon return (error); 34724593369SJonathan Lemon } 34824593369SJonathan Lemon 34924593369SJonathan Lemon SYSCTL_PROC(_compat_linux, OID_AUTO, debug, 35024593369SJonathan Lemon CTLTYPE_STRING | CTLFLAG_RW, 35124593369SJonathan Lemon 0, 0, linux_sysctl_debug, "A", 35224593369SJonathan Lemon "Linux debugging control"); 35324593369SJonathan Lemon 35424593369SJonathan Lemon #endif /* DEBUG */ 355