1ea0fabbcSTim J. Robbins /*- 2ea0fabbcSTim J. Robbins * Copyright (c) 2004 Tim J. Robbins 3ea0fabbcSTim J. Robbins * Copyright (c) 2003 Peter Wemm 4ea0fabbcSTim J. Robbins * Copyright (c) 2002 Doug Rabson 5ea0fabbcSTim J. Robbins * Copyright (c) 1998-1999 Andrew Gallatin 6ea0fabbcSTim J. Robbins * Copyright (c) 1994-1996 S�ren Schmidt 7ea0fabbcSTim J. Robbins * All rights reserved. 8ea0fabbcSTim J. Robbins * 9ea0fabbcSTim J. Robbins * Redistribution and use in source and binary forms, with or without 10ea0fabbcSTim J. Robbins * modification, are permitted provided that the following conditions 11ea0fabbcSTim J. Robbins * are met: 12ea0fabbcSTim J. Robbins * 1. Redistributions of source code must retain the above copyright 13ea0fabbcSTim J. Robbins * notice, this list of conditions and the following disclaimer 14ea0fabbcSTim J. Robbins * in this position and unchanged. 15ea0fabbcSTim J. Robbins * 2. Redistributions in binary form must reproduce the above copyright 16ea0fabbcSTim J. Robbins * notice, this list of conditions and the following disclaimer in the 17ea0fabbcSTim J. Robbins * documentation and/or other materials provided with the distribution. 18ea0fabbcSTim J. Robbins * 3. The name of the author may not be used to endorse or promote products 19ea0fabbcSTim J. Robbins * derived from this software without specific prior written permission 20ea0fabbcSTim J. Robbins * 21ea0fabbcSTim J. Robbins * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22ea0fabbcSTim J. Robbins * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23ea0fabbcSTim J. Robbins * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24ea0fabbcSTim J. Robbins * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25ea0fabbcSTim J. Robbins * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26ea0fabbcSTim J. Robbins * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27ea0fabbcSTim J. Robbins * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28ea0fabbcSTim J. Robbins * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29ea0fabbcSTim J. Robbins * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30ea0fabbcSTim J. Robbins * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31ea0fabbcSTim J. Robbins */ 32ea0fabbcSTim J. Robbins 33ea0fabbcSTim J. Robbins #include <sys/cdefs.h> 34ea0fabbcSTim J. Robbins __FBSDID("$FreeBSD$"); 35aefce619SRuslan Ermilov #include "opt_compat.h" 36ea0fabbcSTim J. Robbins 37841c0c7eSNathan Whitehorn #ifndef COMPAT_FREEBSD32 38841c0c7eSNathan Whitehorn #error "Unable to compile Linux-emulator due to missing COMPAT_FREEBSD32 option!" 39ea0fabbcSTim J. Robbins #endif 40ea0fabbcSTim J. Robbins 41ea0fabbcSTim J. Robbins #define __ELF_WORD_SIZE 32 42ea0fabbcSTim J. Robbins 43ea0fabbcSTim J. Robbins #include <sys/param.h> 44ea0fabbcSTim J. Robbins #include <sys/systm.h> 45ea0fabbcSTim J. Robbins #include <sys/exec.h> 4648b05c3fSKonstantin Belousov #include <sys/fcntl.h> 47ea0fabbcSTim J. Robbins #include <sys/imgact.h> 48ea0fabbcSTim J. Robbins #include <sys/imgact_elf.h> 49ea0fabbcSTim J. Robbins #include <sys/kernel.h> 50ea0fabbcSTim J. Robbins #include <sys/lock.h> 51ea0fabbcSTim J. Robbins #include <sys/malloc.h> 52ea0fabbcSTim J. Robbins #include <sys/module.h> 53ea0fabbcSTim J. Robbins #include <sys/mutex.h> 54ea0fabbcSTim J. Robbins #include <sys/proc.h> 556004362eSDavid Schultz #include <sys/resourcevar.h> 56ea0fabbcSTim J. Robbins #include <sys/signalvar.h> 57ea0fabbcSTim J. Robbins #include <sys/sysctl.h> 58ea0fabbcSTim J. Robbins #include <sys/syscallsubr.h> 59ea0fabbcSTim J. Robbins #include <sys/sysent.h> 60ea0fabbcSTim J. Robbins #include <sys/sysproto.h> 61ea0fabbcSTim J. Robbins #include <sys/vnode.h> 627c09e6c0SAlexander Leidinger #include <sys/eventhandler.h> 63ea0fabbcSTim J. Robbins 64ea0fabbcSTim J. Robbins #include <vm/vm.h> 65ea0fabbcSTim J. Robbins #include <vm/pmap.h> 66ea0fabbcSTim J. Robbins #include <vm/vm_extern.h> 67ea0fabbcSTim J. Robbins #include <vm/vm_map.h> 68ea0fabbcSTim J. Robbins #include <vm/vm_object.h> 69ea0fabbcSTim J. Robbins #include <vm/vm_page.h> 70ea0fabbcSTim J. Robbins #include <vm/vm_param.h> 71ea0fabbcSTim J. Robbins 72ea0fabbcSTim J. Robbins #include <machine/cpu.h> 73ea0fabbcSTim J. Robbins #include <machine/md_var.h> 746004362eSDavid Schultz #include <machine/pcb.h> 75ea0fabbcSTim J. Robbins #include <machine/specialreg.h> 76ea0fabbcSTim J. Robbins 77ea0fabbcSTim J. Robbins #include <amd64/linux32/linux.h> 78ea0fabbcSTim J. Robbins #include <amd64/linux32/linux32_proto.h> 79d789bfd5SDmitry Chagin #include <compat/linux/linux_futex.h> 807c09e6c0SAlexander Leidinger #include <compat/linux/linux_emul.h> 81ea0fabbcSTim J. Robbins #include <compat/linux/linux_mib.h> 824d7c2e8aSDmitry Chagin #include <compat/linux/linux_misc.h> 83ea0fabbcSTim J. Robbins #include <compat/linux/linux_signal.h> 84ea0fabbcSTim J. Robbins #include <compat/linux/linux_util.h> 85ea0fabbcSTim J. Robbins 86ea0fabbcSTim J. Robbins MODULE_VERSION(linux, 1); 87ea0fabbcSTim J. Robbins 88ea0fabbcSTim J. Robbins MALLOC_DEFINE(M_LINUX, "linux", "Linux mode structures"); 89ea0fabbcSTim J. Robbins 90ea0fabbcSTim J. Robbins #define AUXARGS_ENTRY_32(pos, id, val) \ 91ea0fabbcSTim J. Robbins do { \ 92ea0fabbcSTim J. Robbins suword32(pos++, id); \ 93ea0fabbcSTim J. Robbins suword32(pos++, val); \ 94ea0fabbcSTim J. Robbins } while (0) 95ea0fabbcSTim J. Robbins 96ea0fabbcSTim J. Robbins #if BYTE_ORDER == LITTLE_ENDIAN 97ea0fabbcSTim J. Robbins #define SHELLMAGIC 0x2123 /* #! */ 98ea0fabbcSTim J. Robbins #else 99ea0fabbcSTim J. Robbins #define SHELLMAGIC 0x2321 100ea0fabbcSTim J. Robbins #endif 101ea0fabbcSTim J. Robbins 102ea0fabbcSTim J. Robbins /* 103ea0fabbcSTim J. Robbins * Allow the sendsig functions to use the ldebug() facility 104ea0fabbcSTim J. Robbins * even though they are not syscalls themselves. Map them 105ea0fabbcSTim J. Robbins * to syscall 0. This is slightly less bogus than using 106ea0fabbcSTim J. Robbins * ldebug(sigreturn). 107ea0fabbcSTim J. Robbins */ 108ea0fabbcSTim J. Robbins #define LINUX_SYS_linux_rt_sendsig 0 109ea0fabbcSTim J. Robbins #define LINUX_SYS_linux_sendsig 0 110ea0fabbcSTim J. Robbins 1114d7c2e8aSDmitry Chagin const char *linux_platform = "i686"; 1124d7c2e8aSDmitry Chagin static int linux_szplatform; 113ea0fabbcSTim J. Robbins extern char linux_sigcode[]; 114ea0fabbcSTim J. Robbins extern int linux_szsigcode; 115ea0fabbcSTim J. Robbins 116ea0fabbcSTim J. Robbins extern struct sysent linux_sysent[LINUX_SYS_MAXSYSCALL]; 117ea0fabbcSTim J. Robbins 118ea0fabbcSTim J. Robbins SET_DECLARE(linux_ioctl_handler_set, struct linux_ioctl_handler); 119387196bfSDoug Ambrisko SET_DECLARE(linux_device_handler_set, struct linux_device_handler); 120ea0fabbcSTim J. Robbins 121ea0fabbcSTim J. Robbins static int elf_linux_fixup(register_t **stack_base, 122ea0fabbcSTim J. Robbins struct image_params *iparams); 123ea0fabbcSTim J. Robbins static register_t *linux_copyout_strings(struct image_params *imgp); 1249104847fSDavid Xu static void linux_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask); 125a107d8aaSNathan Whitehorn static void exec_linux_setregs(struct thread *td, 126a107d8aaSNathan Whitehorn struct image_params *imgp, u_long stack); 12719059a13SJohn Baldwin static void linux32_fixlimit(struct rlimit *rl, int which); 12889ffc202SBjoern A. Zeeb static boolean_t linux32_trans_osrel(const Elf_Note *note, int32_t *osrel); 129ea0fabbcSTim J. Robbins 1307c09e6c0SAlexander Leidinger static eventhandler_tag linux_exit_tag; 1317c09e6c0SAlexander Leidinger static eventhandler_tag linux_schedtail_tag; 1327c09e6c0SAlexander Leidinger static eventhandler_tag linux_exec_tag; 1337c09e6c0SAlexander Leidinger 134ea0fabbcSTim J. Robbins /* 135ea0fabbcSTim J. Robbins * Linux syscalls return negative errno's, we do positive and map them 13650e422f0SAlexander Leidinger * Reference: 13750e422f0SAlexander Leidinger * FreeBSD: src/sys/sys/errno.h 13850e422f0SAlexander Leidinger * Linux: linux-2.6.17.8/include/asm-generic/errno-base.h 13950e422f0SAlexander Leidinger * linux-2.6.17.8/include/asm-generic/errno.h 140ea0fabbcSTim J. Robbins */ 141ea0fabbcSTim J. Robbins static int bsd_to_linux_errno[ELAST + 1] = { 142ea0fabbcSTim J. Robbins -0, -1, -2, -3, -4, -5, -6, -7, -8, -9, 143ea0fabbcSTim J. Robbins -10, -35, -12, -13, -14, -15, -16, -17, -18, -19, 144ea0fabbcSTim J. Robbins -20, -21, -22, -23, -24, -25, -26, -27, -28, -29, 145ea0fabbcSTim J. Robbins -30, -31, -32, -33, -34, -11,-115,-114, -88, -89, 146ea0fabbcSTim J. Robbins -90, -91, -92, -93, -94, -95, -96, -97, -98, -99, 147ea0fabbcSTim J. Robbins -100,-101,-102,-103,-104,-105,-106,-107,-108,-109, 148ea0fabbcSTim J. Robbins -110,-111, -40, -36,-112,-113, -39, -11, -87,-122, 149ea0fabbcSTim J. Robbins -116, -66, -6, -6, -6, -6, -6, -37, -38, -9, 15050e422f0SAlexander Leidinger -6, -6, -43, -42, -75,-125, -84, -95, -16, -74, 15150e422f0SAlexander Leidinger -72, -67, -71 152ea0fabbcSTim J. Robbins }; 153ea0fabbcSTim J. Robbins 154ea0fabbcSTim J. Robbins int bsd_to_linux_signal[LINUX_SIGTBLSZ] = { 155ea0fabbcSTim J. Robbins LINUX_SIGHUP, LINUX_SIGINT, LINUX_SIGQUIT, LINUX_SIGILL, 156ea0fabbcSTim J. Robbins LINUX_SIGTRAP, LINUX_SIGABRT, 0, LINUX_SIGFPE, 157ea0fabbcSTim J. Robbins LINUX_SIGKILL, LINUX_SIGBUS, LINUX_SIGSEGV, LINUX_SIGSYS, 158ea0fabbcSTim J. Robbins LINUX_SIGPIPE, LINUX_SIGALRM, LINUX_SIGTERM, LINUX_SIGURG, 159ea0fabbcSTim J. Robbins LINUX_SIGSTOP, LINUX_SIGTSTP, LINUX_SIGCONT, LINUX_SIGCHLD, 160ea0fabbcSTim J. Robbins LINUX_SIGTTIN, LINUX_SIGTTOU, LINUX_SIGIO, LINUX_SIGXCPU, 161ea0fabbcSTim J. Robbins LINUX_SIGXFSZ, LINUX_SIGVTALRM, LINUX_SIGPROF, LINUX_SIGWINCH, 162ea0fabbcSTim J. Robbins 0, LINUX_SIGUSR1, LINUX_SIGUSR2 163ea0fabbcSTim J. Robbins }; 164ea0fabbcSTim J. Robbins 165ea0fabbcSTim J. Robbins int linux_to_bsd_signal[LINUX_SIGTBLSZ] = { 166ea0fabbcSTim J. Robbins SIGHUP, SIGINT, SIGQUIT, SIGILL, 167ea0fabbcSTim J. Robbins SIGTRAP, SIGABRT, SIGBUS, SIGFPE, 168ea0fabbcSTim J. Robbins SIGKILL, SIGUSR1, SIGSEGV, SIGUSR2, 169ea0fabbcSTim J. Robbins SIGPIPE, SIGALRM, SIGTERM, SIGBUS, 170ea0fabbcSTim J. Robbins SIGCHLD, SIGCONT, SIGSTOP, SIGTSTP, 171ea0fabbcSTim J. Robbins SIGTTIN, SIGTTOU, SIGURG, SIGXCPU, 172ea0fabbcSTim J. Robbins SIGXFSZ, SIGVTALRM, SIGPROF, SIGWINCH, 173ea0fabbcSTim J. Robbins SIGIO, SIGURG, SIGSYS 174ea0fabbcSTim J. Robbins }; 175ea0fabbcSTim J. Robbins 176ea0fabbcSTim J. Robbins #define LINUX_T_UNKNOWN 255 177ea0fabbcSTim J. Robbins static int _bsd_to_linux_trapcode[] = { 178ea0fabbcSTim J. Robbins LINUX_T_UNKNOWN, /* 0 */ 179ea0fabbcSTim J. Robbins 6, /* 1 T_PRIVINFLT */ 180ea0fabbcSTim J. Robbins LINUX_T_UNKNOWN, /* 2 */ 181ea0fabbcSTim J. Robbins 3, /* 3 T_BPTFLT */ 182ea0fabbcSTim J. Robbins LINUX_T_UNKNOWN, /* 4 */ 183ea0fabbcSTim J. Robbins LINUX_T_UNKNOWN, /* 5 */ 184ea0fabbcSTim J. Robbins 16, /* 6 T_ARITHTRAP */ 185ea0fabbcSTim J. Robbins 254, /* 7 T_ASTFLT */ 186ea0fabbcSTim J. Robbins LINUX_T_UNKNOWN, /* 8 */ 187ea0fabbcSTim J. Robbins 13, /* 9 T_PROTFLT */ 188ea0fabbcSTim J. Robbins 1, /* 10 T_TRCTRAP */ 189ea0fabbcSTim J. Robbins LINUX_T_UNKNOWN, /* 11 */ 190ea0fabbcSTim J. Robbins 14, /* 12 T_PAGEFLT */ 191ea0fabbcSTim J. Robbins LINUX_T_UNKNOWN, /* 13 */ 192ea0fabbcSTim J. Robbins 17, /* 14 T_ALIGNFLT */ 193ea0fabbcSTim J. Robbins LINUX_T_UNKNOWN, /* 15 */ 194ea0fabbcSTim J. Robbins LINUX_T_UNKNOWN, /* 16 */ 195ea0fabbcSTim J. Robbins LINUX_T_UNKNOWN, /* 17 */ 196ea0fabbcSTim J. Robbins 0, /* 18 T_DIVIDE */ 197ea0fabbcSTim J. Robbins 2, /* 19 T_NMI */ 198ea0fabbcSTim J. Robbins 4, /* 20 T_OFLOW */ 199ea0fabbcSTim J. Robbins 5, /* 21 T_BOUND */ 200ea0fabbcSTim J. Robbins 7, /* 22 T_DNA */ 201ea0fabbcSTim J. Robbins 8, /* 23 T_DOUBLEFLT */ 202ea0fabbcSTim J. Robbins 9, /* 24 T_FPOPFLT */ 203ea0fabbcSTim J. Robbins 10, /* 25 T_TSSFLT */ 204ea0fabbcSTim J. Robbins 11, /* 26 T_SEGNPFLT */ 205ea0fabbcSTim J. Robbins 12, /* 27 T_STKFLT */ 206ea0fabbcSTim J. Robbins 18, /* 28 T_MCHK */ 207ea0fabbcSTim J. Robbins 19, /* 29 T_XMMFLT */ 208ea0fabbcSTim J. Robbins 15 /* 30 T_RESERVED */ 209ea0fabbcSTim J. Robbins }; 210ea0fabbcSTim J. Robbins #define bsd_to_linux_trapcode(code) \ 211ea0fabbcSTim J. Robbins ((code)<sizeof(_bsd_to_linux_trapcode)/sizeof(*_bsd_to_linux_trapcode)? \ 212ea0fabbcSTim J. Robbins _bsd_to_linux_trapcode[(code)]: \ 213ea0fabbcSTim J. Robbins LINUX_T_UNKNOWN) 214ea0fabbcSTim J. Robbins 215ea0fabbcSTim J. Robbins struct linux32_ps_strings { 216ea0fabbcSTim J. Robbins u_int32_t ps_argvstr; /* first of 0 or more argument strings */ 217f2c7668eSDavid Schultz u_int ps_nargvstr; /* the number of argument strings */ 218ea0fabbcSTim J. Robbins u_int32_t ps_envstr; /* first of 0 or more environment strings */ 219f2c7668eSDavid Schultz u_int ps_nenvstr; /* the number of environment strings */ 220ea0fabbcSTim J. Robbins }; 221ea0fabbcSTim J. Robbins 222ea0fabbcSTim J. Robbins /* 223ea0fabbcSTim J. Robbins * If FreeBSD & Linux have a difference of opinion about what a trap 224ea0fabbcSTim J. Robbins * means, deal with it here. 225ea0fabbcSTim J. Robbins * 226ea0fabbcSTim J. Robbins * MPSAFE 227ea0fabbcSTim J. Robbins */ 228ea0fabbcSTim J. Robbins static int 229ea0fabbcSTim J. Robbins translate_traps(int signal, int trap_code) 230ea0fabbcSTim J. Robbins { 231ea0fabbcSTim J. Robbins if (signal != SIGBUS) 232ea0fabbcSTim J. Robbins return signal; 233ea0fabbcSTim J. Robbins switch (trap_code) { 234ea0fabbcSTim J. Robbins case T_PROTFLT: 235ea0fabbcSTim J. Robbins case T_TSSFLT: 236ea0fabbcSTim J. Robbins case T_DOUBLEFLT: 237ea0fabbcSTim J. Robbins case T_PAGEFLT: 238ea0fabbcSTim J. Robbins return SIGSEGV; 239ea0fabbcSTim J. Robbins default: 240ea0fabbcSTim J. Robbins return signal; 241ea0fabbcSTim J. Robbins } 242ea0fabbcSTim J. Robbins } 243ea0fabbcSTim J. Robbins 244ea0fabbcSTim J. Robbins static int 245ea0fabbcSTim J. Robbins elf_linux_fixup(register_t **stack_base, struct image_params *imgp) 246ea0fabbcSTim J. Robbins { 247ea0fabbcSTim J. Robbins Elf32_Auxargs *args; 248ea0fabbcSTim J. Robbins Elf32_Addr *base; 2494d7c2e8aSDmitry Chagin Elf32_Addr *pos, *uplatform; 2504d7c2e8aSDmitry Chagin struct linux32_ps_strings *arginfo; 2514d7c2e8aSDmitry Chagin 2524d7c2e8aSDmitry Chagin arginfo = (struct linux32_ps_strings *)LINUX32_PS_STRINGS; 2534d7c2e8aSDmitry Chagin uplatform = (Elf32_Addr *)((caddr_t)arginfo - linux_szsigcode - 2544d7c2e8aSDmitry Chagin linux_szplatform); 255ea0fabbcSTim J. Robbins 2566617724cSJeff Roberson KASSERT(curthread->td_proc == imgp->proc, 257ea0fabbcSTim J. Robbins ("unsafe elf_linux_fixup(), should be curproc")); 258ea0fabbcSTim J. Robbins base = (Elf32_Addr *)*stack_base; 259ea0fabbcSTim J. Robbins args = (Elf32_Auxargs *)imgp->auxargs; 260610ecfe0SMaxim Sobolev pos = base + (imgp->args->argc + imgp->args->envc + 2); 261ea0fabbcSTim J. Robbins 2624d7c2e8aSDmitry Chagin AUXARGS_ENTRY_32(pos, LINUX_AT_HWCAP, cpu_feature); 2638d30f381SDmitry Chagin 2648d30f381SDmitry Chagin /* 2658d30f381SDmitry Chagin * Do not export AT_CLKTCK when emulating Linux kernel prior to 2.4.0, 2668d30f381SDmitry Chagin * as it has appeared in the 2.4.0-rc7 first time. 2678d30f381SDmitry Chagin * Being exported, AT_CLKTCK is returned by sysconf(_SC_CLK_TCK), 2688d30f381SDmitry Chagin * glibc falls back to the hard-coded CLK_TCK value when aux entry 2698d30f381SDmitry Chagin * is not present. 2708d30f381SDmitry Chagin * Also see linux_times() implementation. 2718d30f381SDmitry Chagin */ 2728d30f381SDmitry Chagin if (linux_kernver(curthread) >= LINUX_KERNVER_2004000) 2731ca16454SDmitry Chagin AUXARGS_ENTRY_32(pos, LINUX_AT_CLKTCK, stclohz); 274ea0fabbcSTim J. Robbins AUXARGS_ENTRY_32(pos, AT_PHDR, args->phdr); 275ea0fabbcSTim J. Robbins AUXARGS_ENTRY_32(pos, AT_PHENT, args->phent); 276ea0fabbcSTim J. Robbins AUXARGS_ENTRY_32(pos, AT_PHNUM, args->phnum); 277ea0fabbcSTim J. Robbins AUXARGS_ENTRY_32(pos, AT_PAGESZ, args->pagesz); 278ea0fabbcSTim J. Robbins AUXARGS_ENTRY_32(pos, AT_FLAGS, args->flags); 279ea0fabbcSTim J. Robbins AUXARGS_ENTRY_32(pos, AT_ENTRY, args->entry); 280ea0fabbcSTim J. Robbins AUXARGS_ENTRY_32(pos, AT_BASE, args->base); 2814d7c2e8aSDmitry Chagin AUXARGS_ENTRY_32(pos, LINUX_AT_SECURE, 0); 282ea0fabbcSTim J. Robbins AUXARGS_ENTRY_32(pos, AT_UID, imgp->proc->p_ucred->cr_ruid); 283ea0fabbcSTim J. Robbins AUXARGS_ENTRY_32(pos, AT_EUID, imgp->proc->p_ucred->cr_svuid); 284ea0fabbcSTim J. Robbins AUXARGS_ENTRY_32(pos, AT_GID, imgp->proc->p_ucred->cr_rgid); 285ea0fabbcSTim J. Robbins AUXARGS_ENTRY_32(pos, AT_EGID, imgp->proc->p_ucred->cr_svgid); 2864d7c2e8aSDmitry Chagin AUXARGS_ENTRY_32(pos, LINUX_AT_PLATFORM, PTROUT(uplatform)); 2874d7c2e8aSDmitry Chagin if (args->execfd != -1) 2884d7c2e8aSDmitry Chagin AUXARGS_ENTRY_32(pos, AT_EXECFD, args->execfd); 289ea0fabbcSTim J. Robbins AUXARGS_ENTRY_32(pos, AT_NULL, 0); 290ea0fabbcSTim J. Robbins 291ea0fabbcSTim J. Robbins free(imgp->auxargs, M_TEMP); 292ea0fabbcSTim J. Robbins imgp->auxargs = NULL; 293ea0fabbcSTim J. Robbins 294ea0fabbcSTim J. Robbins base--; 295610ecfe0SMaxim Sobolev suword32(base, (uint32_t)imgp->args->argc); 296ea0fabbcSTim J. Robbins *stack_base = (register_t *)base; 297ea0fabbcSTim J. Robbins return 0; 298ea0fabbcSTim J. Robbins } 299ea0fabbcSTim J. Robbins 300ea0fabbcSTim J. Robbins extern unsigned long linux_sznonrtsigcode; 301ea0fabbcSTim J. Robbins 302ea0fabbcSTim J. Robbins static void 3039104847fSDavid Xu linux_rt_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) 304ea0fabbcSTim J. Robbins { 305ea0fabbcSTim J. Robbins struct thread *td = curthread; 306ea0fabbcSTim J. Robbins struct proc *p = td->td_proc; 307ea0fabbcSTim J. Robbins struct sigacts *psp; 308ea0fabbcSTim J. Robbins struct trapframe *regs; 309ea0fabbcSTim J. Robbins struct l_rt_sigframe *fp, frame; 310ea0fabbcSTim J. Robbins int oonstack; 3119104847fSDavid Xu int sig; 3129104847fSDavid Xu int code; 313ea0fabbcSTim J. Robbins 3149104847fSDavid Xu sig = ksi->ksi_signo; 3159104847fSDavid Xu code = ksi->ksi_code; 316ea0fabbcSTim J. Robbins PROC_LOCK_ASSERT(p, MA_OWNED); 317ea0fabbcSTim J. Robbins psp = p->p_sigacts; 318ea0fabbcSTim J. Robbins mtx_assert(&psp->ps_mtx, MA_OWNED); 319ea0fabbcSTim J. Robbins regs = td->td_frame; 320ea0fabbcSTim J. Robbins oonstack = sigonstack(regs->tf_rsp); 321ea0fabbcSTim J. Robbins 322ea0fabbcSTim J. Robbins #ifdef DEBUG 323ea0fabbcSTim J. Robbins if (ldebug(rt_sendsig)) 324728ef954SJohn Baldwin printf(ARGS(rt_sendsig, "%p, %d, %p, %u"), 325ea0fabbcSTim J. Robbins catcher, sig, (void*)mask, code); 326ea0fabbcSTim J. Robbins #endif 327ea0fabbcSTim J. Robbins /* 328ea0fabbcSTim J. Robbins * Allocate space for the signal handler context. 329ea0fabbcSTim J. Robbins */ 330ea0fabbcSTim J. Robbins if ((td->td_pflags & TDP_ALTSTACK) && !oonstack && 331ea0fabbcSTim J. Robbins SIGISMEMBER(psp->ps_sigonstack, sig)) { 332ea0fabbcSTim J. Robbins fp = (struct l_rt_sigframe *)(td->td_sigstk.ss_sp + 333ea0fabbcSTim J. Robbins td->td_sigstk.ss_size - sizeof(struct l_rt_sigframe)); 334ea0fabbcSTim J. Robbins } else 335ea0fabbcSTim J. Robbins fp = (struct l_rt_sigframe *)regs->tf_rsp - 1; 336ea0fabbcSTim J. Robbins mtx_unlock(&psp->ps_mtx); 337ea0fabbcSTim J. Robbins 338ea0fabbcSTim J. Robbins /* 339ea0fabbcSTim J. Robbins * Build the argument list for the signal handler. 340ea0fabbcSTim J. Robbins */ 341ea0fabbcSTim J. Robbins if (p->p_sysent->sv_sigtbl) 342ea0fabbcSTim J. Robbins if (sig <= p->p_sysent->sv_sigsize) 343ea0fabbcSTim J. Robbins sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)]; 344ea0fabbcSTim J. Robbins 345ea0fabbcSTim J. Robbins bzero(&frame, sizeof(frame)); 346ea0fabbcSTim J. Robbins 347ea0fabbcSTim J. Robbins frame.sf_handler = PTROUT(catcher); 348ea0fabbcSTim J. Robbins frame.sf_sig = sig; 349ea0fabbcSTim J. Robbins frame.sf_siginfo = PTROUT(&fp->sf_si); 350ea0fabbcSTim J. Robbins frame.sf_ucontext = PTROUT(&fp->sf_sc); 351ea0fabbcSTim J. Robbins 352ea0fabbcSTim J. Robbins /* Fill in POSIX parts */ 353aa8b2011SKonstantin Belousov ksiginfo_to_lsiginfo(ksi, &frame.sf_si, sig); 354ea0fabbcSTim J. Robbins 355ea0fabbcSTim J. Robbins /* 356ea0fabbcSTim J. Robbins * Build the signal context to be used by sigreturn. 357ea0fabbcSTim J. Robbins */ 358ea0fabbcSTim J. Robbins frame.sf_sc.uc_flags = 0; /* XXX ??? */ 359ea0fabbcSTim J. Robbins frame.sf_sc.uc_link = 0; /* XXX ??? */ 360ea0fabbcSTim J. Robbins 361ea0fabbcSTim J. Robbins frame.sf_sc.uc_stack.ss_sp = PTROUT(td->td_sigstk.ss_sp); 362ea0fabbcSTim J. Robbins frame.sf_sc.uc_stack.ss_size = td->td_sigstk.ss_size; 363ea0fabbcSTim J. Robbins frame.sf_sc.uc_stack.ss_flags = (td->td_pflags & TDP_ALTSTACK) 364ea0fabbcSTim J. Robbins ? ((oonstack) ? LINUX_SS_ONSTACK : 0) : LINUX_SS_DISABLE; 365ea0fabbcSTim J. Robbins PROC_UNLOCK(p); 366ea0fabbcSTim J. Robbins 367ea0fabbcSTim J. Robbins bsd_to_linux_sigset(mask, &frame.sf_sc.uc_sigmask); 368ea0fabbcSTim J. Robbins 369ea0fabbcSTim J. Robbins frame.sf_sc.uc_mcontext.sc_mask = frame.sf_sc.uc_sigmask.__bits[0]; 370ea0fabbcSTim J. Robbins frame.sf_sc.uc_mcontext.sc_edi = regs->tf_rdi; 371ea0fabbcSTim J. Robbins frame.sf_sc.uc_mcontext.sc_esi = regs->tf_rsi; 372ea0fabbcSTim J. Robbins frame.sf_sc.uc_mcontext.sc_ebp = regs->tf_rbp; 373ea0fabbcSTim J. Robbins frame.sf_sc.uc_mcontext.sc_ebx = regs->tf_rbx; 374ea0fabbcSTim J. Robbins frame.sf_sc.uc_mcontext.sc_edx = regs->tf_rdx; 375ea0fabbcSTim J. Robbins frame.sf_sc.uc_mcontext.sc_ecx = regs->tf_rcx; 376ea0fabbcSTim J. Robbins frame.sf_sc.uc_mcontext.sc_eax = regs->tf_rax; 377ea0fabbcSTim J. Robbins frame.sf_sc.uc_mcontext.sc_eip = regs->tf_rip; 378ea0fabbcSTim J. Robbins frame.sf_sc.uc_mcontext.sc_cs = regs->tf_cs; 3792c66cccaSKonstantin Belousov frame.sf_sc.uc_mcontext.sc_gs = regs->tf_gs; 3802c66cccaSKonstantin Belousov frame.sf_sc.uc_mcontext.sc_fs = regs->tf_fs; 3812c66cccaSKonstantin Belousov frame.sf_sc.uc_mcontext.sc_es = regs->tf_es; 3822c66cccaSKonstantin Belousov frame.sf_sc.uc_mcontext.sc_ds = regs->tf_ds; 383ea0fabbcSTim J. Robbins frame.sf_sc.uc_mcontext.sc_eflags = regs->tf_rflags; 384ea0fabbcSTim J. Robbins frame.sf_sc.uc_mcontext.sc_esp_at_signal = regs->tf_rsp; 385ea0fabbcSTim J. Robbins frame.sf_sc.uc_mcontext.sc_ss = regs->tf_ss; 386ea0fabbcSTim J. Robbins frame.sf_sc.uc_mcontext.sc_err = regs->tf_err; 38796a2b635SKonstantin Belousov frame.sf_sc.uc_mcontext.sc_cr2 = (u_int32_t)(uintptr_t)ksi->ksi_addr; 388ea0fabbcSTim J. Robbins frame.sf_sc.uc_mcontext.sc_trapno = bsd_to_linux_trapcode(code); 389ea0fabbcSTim J. Robbins 390ea0fabbcSTim J. Robbins #ifdef DEBUG 391ea0fabbcSTim J. Robbins if (ldebug(rt_sendsig)) 392c680f6b1SDavid E. O'Brien printf(LMSG("rt_sendsig flags: 0x%x, sp: %p, ss: 0x%lx, mask: 0x%x"), 393ea0fabbcSTim J. Robbins frame.sf_sc.uc_stack.ss_flags, td->td_sigstk.ss_sp, 394ea0fabbcSTim J. Robbins td->td_sigstk.ss_size, frame.sf_sc.uc_mcontext.sc_mask); 395ea0fabbcSTim J. Robbins #endif 396ea0fabbcSTim J. Robbins 397ea0fabbcSTim J. Robbins if (copyout(&frame, fp, sizeof(frame)) != 0) { 398ea0fabbcSTim J. Robbins /* 399ea0fabbcSTim J. Robbins * Process has trashed its stack; give it an illegal 400ea0fabbcSTim J. Robbins * instruction to halt it in its tracks. 401ea0fabbcSTim J. Robbins */ 402ea0fabbcSTim J. Robbins #ifdef DEBUG 403ea0fabbcSTim J. Robbins if (ldebug(rt_sendsig)) 404ea0fabbcSTim J. Robbins printf(LMSG("rt_sendsig: bad stack %p, oonstack=%x"), 405ea0fabbcSTim J. Robbins fp, oonstack); 406ea0fabbcSTim J. Robbins #endif 407ea0fabbcSTim J. Robbins PROC_LOCK(p); 408ea0fabbcSTim J. Robbins sigexit(td, SIGILL); 409ea0fabbcSTim J. Robbins } 410ea0fabbcSTim J. Robbins 411ea0fabbcSTim J. Robbins /* 412ea0fabbcSTim J. Robbins * Build context to run handler in. 413ea0fabbcSTim J. Robbins */ 414ea0fabbcSTim J. Robbins regs->tf_rsp = PTROUT(fp); 415ea0fabbcSTim J. Robbins regs->tf_rip = LINUX32_PS_STRINGS - *(p->p_sysent->sv_szsigcode) + 416ea0fabbcSTim J. Robbins linux_sznonrtsigcode; 41722eca0bfSKonstantin Belousov regs->tf_rflags &= ~(PSL_T | PSL_D); 418ea0fabbcSTim J. Robbins regs->tf_cs = _ucode32sel; 419ea0fabbcSTim J. Robbins regs->tf_ss = _udatasel; 4202c66cccaSKonstantin Belousov regs->tf_ds = _udatasel; 4212c66cccaSKonstantin Belousov regs->tf_es = _udatasel; 4222c66cccaSKonstantin Belousov regs->tf_fs = _ufssel; 4232c66cccaSKonstantin Belousov regs->tf_gs = _ugssel; 4242c66cccaSKonstantin Belousov regs->tf_flags = TF_HASSEGS; 425a2622e5dSKonstantin Belousov td->td_pcb->pcb_full_iret = 1; 426ea0fabbcSTim J. Robbins PROC_LOCK(p); 427ea0fabbcSTim J. Robbins mtx_lock(&psp->ps_mtx); 428ea0fabbcSTim J. Robbins } 429ea0fabbcSTim J. Robbins 430ea0fabbcSTim J. Robbins 431ea0fabbcSTim J. Robbins /* 432ea0fabbcSTim J. Robbins * Send an interrupt to process. 433ea0fabbcSTim J. Robbins * 434ea0fabbcSTim J. Robbins * Stack is set up to allow sigcode stored 435ea0fabbcSTim J. Robbins * in u. to call routine, followed by kcall 436ea0fabbcSTim J. Robbins * to sigreturn routine below. After sigreturn 437ea0fabbcSTim J. Robbins * resets the signal mask, the stack, and the 438ea0fabbcSTim J. Robbins * frame pointer, it returns to the user 439ea0fabbcSTim J. Robbins * specified pc, psl. 440ea0fabbcSTim J. Robbins */ 441ea0fabbcSTim J. Robbins static void 4429104847fSDavid Xu linux_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) 443ea0fabbcSTim J. Robbins { 444ea0fabbcSTim J. Robbins struct thread *td = curthread; 445ea0fabbcSTim J. Robbins struct proc *p = td->td_proc; 446ea0fabbcSTim J. Robbins struct sigacts *psp; 447ea0fabbcSTim J. Robbins struct trapframe *regs; 448ea0fabbcSTim J. Robbins struct l_sigframe *fp, frame; 449ea0fabbcSTim J. Robbins l_sigset_t lmask; 450ea0fabbcSTim J. Robbins int oonstack, i; 4519104847fSDavid Xu int sig, code; 452ea0fabbcSTim J. Robbins 4539104847fSDavid Xu sig = ksi->ksi_signo; 4549104847fSDavid Xu code = ksi->ksi_code; 455ea0fabbcSTim J. Robbins PROC_LOCK_ASSERT(p, MA_OWNED); 456ea0fabbcSTim J. Robbins psp = p->p_sigacts; 457ea0fabbcSTim J. Robbins mtx_assert(&psp->ps_mtx, MA_OWNED); 458ea0fabbcSTim J. Robbins if (SIGISMEMBER(psp->ps_siginfo, sig)) { 459ea0fabbcSTim J. Robbins /* Signal handler installed with SA_SIGINFO. */ 4609104847fSDavid Xu linux_rt_sendsig(catcher, ksi, mask); 461ea0fabbcSTim J. Robbins return; 462ea0fabbcSTim J. Robbins } 463ea0fabbcSTim J. Robbins 464ea0fabbcSTim J. Robbins regs = td->td_frame; 465ea0fabbcSTim J. Robbins oonstack = sigonstack(regs->tf_rsp); 466ea0fabbcSTim J. Robbins 467ea0fabbcSTim J. Robbins #ifdef DEBUG 468ea0fabbcSTim J. Robbins if (ldebug(sendsig)) 469728ef954SJohn Baldwin printf(ARGS(sendsig, "%p, %d, %p, %u"), 470ea0fabbcSTim J. Robbins catcher, sig, (void*)mask, code); 471ea0fabbcSTim J. Robbins #endif 472ea0fabbcSTim J. Robbins 473ea0fabbcSTim J. Robbins /* 474ea0fabbcSTim J. Robbins * Allocate space for the signal handler context. 475ea0fabbcSTim J. Robbins */ 476ea0fabbcSTim J. Robbins if ((td->td_pflags & TDP_ALTSTACK) && !oonstack && 477ea0fabbcSTim J. Robbins SIGISMEMBER(psp->ps_sigonstack, sig)) { 478ea0fabbcSTim J. Robbins fp = (struct l_sigframe *)(td->td_sigstk.ss_sp + 479ea0fabbcSTim J. Robbins td->td_sigstk.ss_size - sizeof(struct l_sigframe)); 480ea0fabbcSTim J. Robbins } else 481ea0fabbcSTim J. Robbins fp = (struct l_sigframe *)regs->tf_rsp - 1; 482ea0fabbcSTim J. Robbins mtx_unlock(&psp->ps_mtx); 483ea0fabbcSTim J. Robbins PROC_UNLOCK(p); 484ea0fabbcSTim J. Robbins 485ea0fabbcSTim J. Robbins /* 486ea0fabbcSTim J. Robbins * Build the argument list for the signal handler. 487ea0fabbcSTim J. Robbins */ 488ea0fabbcSTim J. Robbins if (p->p_sysent->sv_sigtbl) 489ea0fabbcSTim J. Robbins if (sig <= p->p_sysent->sv_sigsize) 490ea0fabbcSTim J. Robbins sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)]; 491ea0fabbcSTim J. Robbins 492ea0fabbcSTim J. Robbins bzero(&frame, sizeof(frame)); 493ea0fabbcSTim J. Robbins 494ea0fabbcSTim J. Robbins frame.sf_handler = PTROUT(catcher); 495ea0fabbcSTim J. Robbins frame.sf_sig = sig; 496ea0fabbcSTim J. Robbins 497ea0fabbcSTim J. Robbins bsd_to_linux_sigset(mask, &lmask); 498ea0fabbcSTim J. Robbins 499ea0fabbcSTim J. Robbins /* 500ea0fabbcSTim J. Robbins * Build the signal context to be used by sigreturn. 501ea0fabbcSTim J. Robbins */ 502ea0fabbcSTim J. Robbins frame.sf_sc.sc_mask = lmask.__bits[0]; 5032c66cccaSKonstantin Belousov frame.sf_sc.sc_gs = regs->tf_gs; 5042c66cccaSKonstantin Belousov frame.sf_sc.sc_fs = regs->tf_fs; 5052c66cccaSKonstantin Belousov frame.sf_sc.sc_es = regs->tf_es; 5062c66cccaSKonstantin Belousov frame.sf_sc.sc_ds = regs->tf_ds; 507ea0fabbcSTim J. Robbins frame.sf_sc.sc_edi = regs->tf_rdi; 508ea0fabbcSTim J. Robbins frame.sf_sc.sc_esi = regs->tf_rsi; 509ea0fabbcSTim J. Robbins frame.sf_sc.sc_ebp = regs->tf_rbp; 510ea0fabbcSTim J. Robbins frame.sf_sc.sc_ebx = regs->tf_rbx; 511ea0fabbcSTim J. Robbins frame.sf_sc.sc_edx = regs->tf_rdx; 512ea0fabbcSTim J. Robbins frame.sf_sc.sc_ecx = regs->tf_rcx; 513ea0fabbcSTim J. Robbins frame.sf_sc.sc_eax = regs->tf_rax; 514ea0fabbcSTim J. Robbins frame.sf_sc.sc_eip = regs->tf_rip; 515ea0fabbcSTim J. Robbins frame.sf_sc.sc_cs = regs->tf_cs; 516ea0fabbcSTim J. Robbins frame.sf_sc.sc_eflags = regs->tf_rflags; 517ea0fabbcSTim J. Robbins frame.sf_sc.sc_esp_at_signal = regs->tf_rsp; 518ea0fabbcSTim J. Robbins frame.sf_sc.sc_ss = regs->tf_ss; 519ea0fabbcSTim J. Robbins frame.sf_sc.sc_err = regs->tf_err; 52096a2b635SKonstantin Belousov frame.sf_sc.sc_cr2 = (u_int32_t)(uintptr_t)ksi->ksi_addr; 521ea0fabbcSTim J. Robbins frame.sf_sc.sc_trapno = bsd_to_linux_trapcode(code); 522ea0fabbcSTim J. Robbins 523ea0fabbcSTim J. Robbins for (i = 0; i < (LINUX_NSIG_WORDS-1); i++) 524ea0fabbcSTim J. Robbins frame.sf_extramask[i] = lmask.__bits[i+1]; 525ea0fabbcSTim J. Robbins 526ea0fabbcSTim J. Robbins if (copyout(&frame, fp, sizeof(frame)) != 0) { 527ea0fabbcSTim J. Robbins /* 528ea0fabbcSTim J. Robbins * Process has trashed its stack; give it an illegal 529ea0fabbcSTim J. Robbins * instruction to halt it in its tracks. 530ea0fabbcSTim J. Robbins */ 531ea0fabbcSTim J. Robbins PROC_LOCK(p); 532ea0fabbcSTim J. Robbins sigexit(td, SIGILL); 533ea0fabbcSTim J. Robbins } 534ea0fabbcSTim J. Robbins 535ea0fabbcSTim J. Robbins /* 536ea0fabbcSTim J. Robbins * Build context to run handler in. 537ea0fabbcSTim J. Robbins */ 538ea0fabbcSTim J. Robbins regs->tf_rsp = PTROUT(fp); 539ea0fabbcSTim J. Robbins regs->tf_rip = LINUX32_PS_STRINGS - *(p->p_sysent->sv_szsigcode); 54022eca0bfSKonstantin Belousov regs->tf_rflags &= ~(PSL_T | PSL_D); 541ea0fabbcSTim J. Robbins regs->tf_cs = _ucode32sel; 542ea0fabbcSTim J. Robbins regs->tf_ss = _udatasel; 5432c66cccaSKonstantin Belousov regs->tf_ds = _udatasel; 5442c66cccaSKonstantin Belousov regs->tf_es = _udatasel; 5452c66cccaSKonstantin Belousov regs->tf_fs = _ufssel; 5462c66cccaSKonstantin Belousov regs->tf_gs = _ugssel; 5472c66cccaSKonstantin Belousov regs->tf_flags = TF_HASSEGS; 548a2622e5dSKonstantin Belousov td->td_pcb->pcb_full_iret = 1; 549ea0fabbcSTim J. Robbins PROC_LOCK(p); 550ea0fabbcSTim J. Robbins mtx_lock(&psp->ps_mtx); 551ea0fabbcSTim J. Robbins } 552ea0fabbcSTim J. Robbins 553ea0fabbcSTim J. Robbins /* 554ea0fabbcSTim J. Robbins * System call to cleanup state after a signal 555ea0fabbcSTim J. Robbins * has been taken. Reset signal mask and 556ea0fabbcSTim J. Robbins * stack state from context left by sendsig (above). 557ea0fabbcSTim J. Robbins * Return to previous pc and psl as specified by 558ea0fabbcSTim J. Robbins * context left by sendsig. Check carefully to 559ea0fabbcSTim J. Robbins * make sure that the user has not modified the 560ea0fabbcSTim J. Robbins * psl to gain improper privileges or to cause 561ea0fabbcSTim J. Robbins * a machine fault. 562ea0fabbcSTim J. Robbins */ 563ea0fabbcSTim J. Robbins int 564ea0fabbcSTim J. Robbins linux_sigreturn(struct thread *td, struct linux_sigreturn_args *args) 565ea0fabbcSTim J. Robbins { 566ea0fabbcSTim J. Robbins struct l_sigframe frame; 567ea0fabbcSTim J. Robbins struct trapframe *regs; 568d6e029adSKonstantin Belousov sigset_t bmask; 569ea0fabbcSTim J. Robbins l_sigset_t lmask; 570ea0fabbcSTim J. Robbins int eflags, i; 5719104847fSDavid Xu ksiginfo_t ksi; 572ea0fabbcSTim J. Robbins 573ea0fabbcSTim J. Robbins regs = td->td_frame; 574ea0fabbcSTim J. Robbins 575ea0fabbcSTim J. Robbins #ifdef DEBUG 576ea0fabbcSTim J. Robbins if (ldebug(sigreturn)) 577ea0fabbcSTim J. Robbins printf(ARGS(sigreturn, "%p"), (void *)args->sfp); 578ea0fabbcSTim J. Robbins #endif 579ea0fabbcSTim J. Robbins /* 580ea0fabbcSTim J. Robbins * The trampoline code hands us the sigframe. 581ea0fabbcSTim J. Robbins * It is unsafe to keep track of it ourselves, in the event that a 582ea0fabbcSTim J. Robbins * program jumps out of a signal handler. 583ea0fabbcSTim J. Robbins */ 584ea0fabbcSTim J. Robbins if (copyin(args->sfp, &frame, sizeof(frame)) != 0) 585ea0fabbcSTim J. Robbins return (EFAULT); 586ea0fabbcSTim J. Robbins 587ea0fabbcSTim J. Robbins /* 588ea0fabbcSTim J. Robbins * Check for security violations. 589ea0fabbcSTim J. Robbins */ 590ea0fabbcSTim J. Robbins #define EFLAGS_SECURE(ef, oef) ((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0) 591ea0fabbcSTim J. Robbins eflags = frame.sf_sc.sc_eflags; 592ea0fabbcSTim J. Robbins /* 593ea0fabbcSTim J. Robbins * XXX do allow users to change the privileged flag PSL_RF. The 594ea0fabbcSTim J. Robbins * cpu sets PSL_RF in tf_eflags for faults. Debuggers should 595ea0fabbcSTim J. Robbins * sometimes set it there too. tf_eflags is kept in the signal 596ea0fabbcSTim J. Robbins * context during signal handling and there is no other place 597ea0fabbcSTim J. Robbins * to remember it, so the PSL_RF bit may be corrupted by the 598ea0fabbcSTim J. Robbins * signal handler without us knowing. Corruption of the PSL_RF 599ea0fabbcSTim J. Robbins * bit at worst causes one more or one less debugger trap, so 600ea0fabbcSTim J. Robbins * allowing it is fairly harmless. 601ea0fabbcSTim J. Robbins */ 602ea0fabbcSTim J. Robbins if (!EFLAGS_SECURE(eflags & ~PSL_RF, regs->tf_rflags & ~PSL_RF)) 603ea0fabbcSTim J. Robbins return(EINVAL); 604ea0fabbcSTim J. Robbins 605ea0fabbcSTim J. Robbins /* 606ea0fabbcSTim J. Robbins * Don't allow users to load a valid privileged %cs. Let the 607ea0fabbcSTim J. Robbins * hardware check for invalid selectors, excess privilege in 608ea0fabbcSTim J. Robbins * other selectors, invalid %eip's and invalid %esp's. 609ea0fabbcSTim J. Robbins */ 610ea0fabbcSTim J. Robbins #define CS_SECURE(cs) (ISPL(cs) == SEL_UPL) 611ea0fabbcSTim J. Robbins if (!CS_SECURE(frame.sf_sc.sc_cs)) { 6129104847fSDavid Xu ksiginfo_init_trap(&ksi); 6139104847fSDavid Xu ksi.ksi_signo = SIGBUS; 6149104847fSDavid Xu ksi.ksi_code = BUS_OBJERR; 6159104847fSDavid Xu ksi.ksi_trapno = T_PROTFLT; 6169104847fSDavid Xu ksi.ksi_addr = (void *)regs->tf_rip; 6179104847fSDavid Xu trapsignal(td, &ksi); 618ea0fabbcSTim J. Robbins return(EINVAL); 619ea0fabbcSTim J. Robbins } 620ea0fabbcSTim J. Robbins 621ea0fabbcSTim J. Robbins lmask.__bits[0] = frame.sf_sc.sc_mask; 622ea0fabbcSTim J. Robbins for (i = 0; i < (LINUX_NSIG_WORDS-1); i++) 623ea0fabbcSTim J. Robbins lmask.__bits[i+1] = frame.sf_extramask[i]; 624d6e029adSKonstantin Belousov linux_to_bsd_sigset(&lmask, &bmask); 625d6e029adSKonstantin Belousov kern_sigprocmask(td, SIG_SETMASK, &bmask, NULL, 0); 626ea0fabbcSTim J. Robbins 627ea0fabbcSTim J. Robbins /* 628ea0fabbcSTim J. Robbins * Restore signal context. 629ea0fabbcSTim J. Robbins */ 630ea0fabbcSTim J. Robbins regs->tf_rdi = frame.sf_sc.sc_edi; 631ea0fabbcSTim J. Robbins regs->tf_rsi = frame.sf_sc.sc_esi; 632ea0fabbcSTim J. Robbins regs->tf_rbp = frame.sf_sc.sc_ebp; 633ea0fabbcSTim J. Robbins regs->tf_rbx = frame.sf_sc.sc_ebx; 634ea0fabbcSTim J. Robbins regs->tf_rdx = frame.sf_sc.sc_edx; 635ea0fabbcSTim J. Robbins regs->tf_rcx = frame.sf_sc.sc_ecx; 636ea0fabbcSTim J. Robbins regs->tf_rax = frame.sf_sc.sc_eax; 637ea0fabbcSTim J. Robbins regs->tf_rip = frame.sf_sc.sc_eip; 638ea0fabbcSTim J. Robbins regs->tf_cs = frame.sf_sc.sc_cs; 6392c66cccaSKonstantin Belousov regs->tf_ds = frame.sf_sc.sc_ds; 6402c66cccaSKonstantin Belousov regs->tf_es = frame.sf_sc.sc_es; 6412c66cccaSKonstantin Belousov regs->tf_fs = frame.sf_sc.sc_fs; 6422c66cccaSKonstantin Belousov regs->tf_gs = frame.sf_sc.sc_gs; 643ea0fabbcSTim J. Robbins regs->tf_rflags = eflags; 644ea0fabbcSTim J. Robbins regs->tf_rsp = frame.sf_sc.sc_esp_at_signal; 645ea0fabbcSTim J. Robbins regs->tf_ss = frame.sf_sc.sc_ss; 646a2622e5dSKonstantin Belousov td->td_pcb->pcb_full_iret = 1; 647ea0fabbcSTim J. Robbins 648ea0fabbcSTim J. Robbins return (EJUSTRETURN); 649ea0fabbcSTim J. Robbins } 650ea0fabbcSTim J. Robbins 651ea0fabbcSTim J. Robbins /* 652ea0fabbcSTim J. Robbins * System call to cleanup state after a signal 653ea0fabbcSTim J. Robbins * has been taken. Reset signal mask and 654ea0fabbcSTim J. Robbins * stack state from context left by rt_sendsig (above). 655ea0fabbcSTim J. Robbins * Return to previous pc and psl as specified by 656ea0fabbcSTim J. Robbins * context left by sendsig. Check carefully to 657ea0fabbcSTim J. Robbins * make sure that the user has not modified the 658ea0fabbcSTim J. Robbins * psl to gain improper privileges or to cause 659ea0fabbcSTim J. Robbins * a machine fault. 660ea0fabbcSTim J. Robbins */ 661ea0fabbcSTim J. Robbins int 662ea0fabbcSTim J. Robbins linux_rt_sigreturn(struct thread *td, struct linux_rt_sigreturn_args *args) 663ea0fabbcSTim J. Robbins { 664ea0fabbcSTim J. Robbins struct l_ucontext uc; 665ea0fabbcSTim J. Robbins struct l_sigcontext *context; 666d6e029adSKonstantin Belousov sigset_t bmask; 667ea0fabbcSTim J. Robbins l_stack_t *lss; 668ea0fabbcSTim J. Robbins stack_t ss; 669ea0fabbcSTim J. Robbins struct trapframe *regs; 670ea0fabbcSTim J. Robbins int eflags; 6719104847fSDavid Xu ksiginfo_t ksi; 672ea0fabbcSTim J. Robbins 673ea0fabbcSTim J. Robbins regs = td->td_frame; 674ea0fabbcSTim J. Robbins 675ea0fabbcSTim J. Robbins #ifdef DEBUG 676ea0fabbcSTim J. Robbins if (ldebug(rt_sigreturn)) 677ea0fabbcSTim J. Robbins printf(ARGS(rt_sigreturn, "%p"), (void *)args->ucp); 678ea0fabbcSTim J. Robbins #endif 679ea0fabbcSTim J. Robbins /* 680ea0fabbcSTim J. Robbins * The trampoline code hands us the ucontext. 681ea0fabbcSTim J. Robbins * It is unsafe to keep track of it ourselves, in the event that a 682ea0fabbcSTim J. Robbins * program jumps out of a signal handler. 683ea0fabbcSTim J. Robbins */ 684ea0fabbcSTim J. Robbins if (copyin(args->ucp, &uc, sizeof(uc)) != 0) 685ea0fabbcSTim J. Robbins return (EFAULT); 686ea0fabbcSTim J. Robbins 687ea0fabbcSTim J. Robbins context = &uc.uc_mcontext; 688ea0fabbcSTim J. Robbins 689ea0fabbcSTim J. Robbins /* 690ea0fabbcSTim J. Robbins * Check for security violations. 691ea0fabbcSTim J. Robbins */ 692ea0fabbcSTim J. Robbins #define EFLAGS_SECURE(ef, oef) ((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0) 693ea0fabbcSTim J. Robbins eflags = context->sc_eflags; 694ea0fabbcSTim J. Robbins /* 695ea0fabbcSTim J. Robbins * XXX do allow users to change the privileged flag PSL_RF. The 696ea0fabbcSTim J. Robbins * cpu sets PSL_RF in tf_eflags for faults. Debuggers should 697ea0fabbcSTim J. Robbins * sometimes set it there too. tf_eflags is kept in the signal 698ea0fabbcSTim J. Robbins * context during signal handling and there is no other place 699ea0fabbcSTim J. Robbins * to remember it, so the PSL_RF bit may be corrupted by the 700ea0fabbcSTim J. Robbins * signal handler without us knowing. Corruption of the PSL_RF 701ea0fabbcSTim J. Robbins * bit at worst causes one more or one less debugger trap, so 702ea0fabbcSTim J. Robbins * allowing it is fairly harmless. 703ea0fabbcSTim J. Robbins */ 704ea0fabbcSTim J. Robbins if (!EFLAGS_SECURE(eflags & ~PSL_RF, regs->tf_rflags & ~PSL_RF)) 705ea0fabbcSTim J. Robbins return(EINVAL); 706ea0fabbcSTim J. Robbins 707ea0fabbcSTim J. Robbins /* 708ea0fabbcSTim J. Robbins * Don't allow users to load a valid privileged %cs. Let the 709ea0fabbcSTim J. Robbins * hardware check for invalid selectors, excess privilege in 710ea0fabbcSTim J. Robbins * other selectors, invalid %eip's and invalid %esp's. 711ea0fabbcSTim J. Robbins */ 712ea0fabbcSTim J. Robbins #define CS_SECURE(cs) (ISPL(cs) == SEL_UPL) 713ea0fabbcSTim J. Robbins if (!CS_SECURE(context->sc_cs)) { 7149104847fSDavid Xu ksiginfo_init_trap(&ksi); 7159104847fSDavid Xu ksi.ksi_signo = SIGBUS; 7169104847fSDavid Xu ksi.ksi_code = BUS_OBJERR; 7179104847fSDavid Xu ksi.ksi_trapno = T_PROTFLT; 7189104847fSDavid Xu ksi.ksi_addr = (void *)regs->tf_rip; 7199104847fSDavid Xu trapsignal(td, &ksi); 720ea0fabbcSTim J. Robbins return(EINVAL); 721ea0fabbcSTim J. Robbins } 722ea0fabbcSTim J. Robbins 723d6e029adSKonstantin Belousov linux_to_bsd_sigset(&uc.uc_sigmask, &bmask); 724d6e029adSKonstantin Belousov kern_sigprocmask(td, SIG_SETMASK, &bmask, NULL, 0); 725ea0fabbcSTim J. Robbins 726ea0fabbcSTim J. Robbins /* 727ea0fabbcSTim J. Robbins * Restore signal context 728ea0fabbcSTim J. Robbins */ 7292c66cccaSKonstantin Belousov regs->tf_gs = context->sc_gs; 7302c66cccaSKonstantin Belousov regs->tf_fs = context->sc_fs; 7312c66cccaSKonstantin Belousov regs->tf_es = context->sc_es; 7322c66cccaSKonstantin Belousov regs->tf_ds = context->sc_ds; 733ea0fabbcSTim J. Robbins regs->tf_rdi = context->sc_edi; 734ea0fabbcSTim J. Robbins regs->tf_rsi = context->sc_esi; 735ea0fabbcSTim J. Robbins regs->tf_rbp = context->sc_ebp; 736ea0fabbcSTim J. Robbins regs->tf_rbx = context->sc_ebx; 737ea0fabbcSTim J. Robbins regs->tf_rdx = context->sc_edx; 738ea0fabbcSTim J. Robbins regs->tf_rcx = context->sc_ecx; 739ea0fabbcSTim J. Robbins regs->tf_rax = context->sc_eax; 740ea0fabbcSTim J. Robbins regs->tf_rip = context->sc_eip; 741ea0fabbcSTim J. Robbins regs->tf_cs = context->sc_cs; 742ea0fabbcSTim J. Robbins regs->tf_rflags = eflags; 743ea0fabbcSTim J. Robbins regs->tf_rsp = context->sc_esp_at_signal; 744ea0fabbcSTim J. Robbins regs->tf_ss = context->sc_ss; 745a2622e5dSKonstantin Belousov td->td_pcb->pcb_full_iret = 1; 746ea0fabbcSTim J. Robbins 747ea0fabbcSTim J. Robbins /* 748ea0fabbcSTim J. Robbins * call sigaltstack & ignore results.. 749ea0fabbcSTim J. Robbins */ 750ea0fabbcSTim J. Robbins lss = &uc.uc_stack; 751ea0fabbcSTim J. Robbins ss.ss_sp = PTRIN(lss->ss_sp); 752ea0fabbcSTim J. Robbins ss.ss_size = lss->ss_size; 753ea0fabbcSTim J. Robbins ss.ss_flags = linux_to_bsd_sigaltstack(lss->ss_flags); 754ea0fabbcSTim J. Robbins 755ea0fabbcSTim J. Robbins #ifdef DEBUG 756ea0fabbcSTim J. Robbins if (ldebug(rt_sigreturn)) 757c680f6b1SDavid E. O'Brien printf(LMSG("rt_sigret flags: 0x%x, sp: %p, ss: 0x%lx, mask: 0x%x"), 758ea0fabbcSTim J. Robbins ss.ss_flags, ss.ss_sp, ss.ss_size, context->sc_mask); 759ea0fabbcSTim J. Robbins #endif 760ea0fabbcSTim J. Robbins (void)kern_sigaltstack(td, &ss, NULL); 761ea0fabbcSTim J. Robbins 762ea0fabbcSTim J. Robbins return (EJUSTRETURN); 763ea0fabbcSTim J. Robbins } 764ea0fabbcSTim J. Robbins 765afe1a688SKonstantin Belousov static int 766afe1a688SKonstantin Belousov linux32_fetch_syscall_args(struct thread *td, struct syscall_args *sa) 767ea0fabbcSTim J. Robbins { 768afe1a688SKonstantin Belousov struct proc *p; 769afe1a688SKonstantin Belousov struct trapframe *frame; 770afe1a688SKonstantin Belousov 771afe1a688SKonstantin Belousov p = td->td_proc; 772afe1a688SKonstantin Belousov frame = td->td_frame; 773afe1a688SKonstantin Belousov 774afe1a688SKonstantin Belousov sa->args[0] = frame->tf_rbx; 775afe1a688SKonstantin Belousov sa->args[1] = frame->tf_rcx; 776afe1a688SKonstantin Belousov sa->args[2] = frame->tf_rdx; 777afe1a688SKonstantin Belousov sa->args[3] = frame->tf_rsi; 778afe1a688SKonstantin Belousov sa->args[4] = frame->tf_rdi; 779afe1a688SKonstantin Belousov sa->args[5] = frame->tf_rbp; /* Unconfirmed */ 780afe1a688SKonstantin Belousov sa->code = frame->tf_rax; 781afe1a688SKonstantin Belousov 782afe1a688SKonstantin Belousov if (sa->code >= p->p_sysent->sv_size) 783afe1a688SKonstantin Belousov sa->callp = &p->p_sysent->sv_table[0]; 784afe1a688SKonstantin Belousov else 785afe1a688SKonstantin Belousov sa->callp = &p->p_sysent->sv_table[sa->code]; 786afe1a688SKonstantin Belousov sa->narg = sa->callp->sy_narg; 787afe1a688SKonstantin Belousov 788afe1a688SKonstantin Belousov td->td_retval[0] = 0; 789afe1a688SKonstantin Belousov td->td_retval[1] = frame->tf_rdx; 790afe1a688SKonstantin Belousov 791afe1a688SKonstantin Belousov return (0); 792ea0fabbcSTim J. Robbins } 793ea0fabbcSTim J. Robbins 794ea0fabbcSTim J. Robbins /* 795ea0fabbcSTim J. Robbins * If a linux binary is exec'ing something, try this image activator 796ea0fabbcSTim J. Robbins * first. We override standard shell script execution in order to 797ea0fabbcSTim J. Robbins * be able to modify the interpreter path. We only do this if a linux 798ea0fabbcSTim J. Robbins * binary is doing the exec, so we do not create an EXEC module for it. 799ea0fabbcSTim J. Robbins */ 800ea0fabbcSTim J. Robbins static int exec_linux_imgact_try(struct image_params *iparams); 801ea0fabbcSTim J. Robbins 802ea0fabbcSTim J. Robbins static int 803ea0fabbcSTim J. Robbins exec_linux_imgact_try(struct image_params *imgp) 804ea0fabbcSTim J. Robbins { 805ea0fabbcSTim J. Robbins const char *head = (const char *)imgp->image_header; 8061d15fdd9SJohn Baldwin char *rpath; 807a14a9498SAlan Cox int error = -1; 808ea0fabbcSTim J. Robbins 809ea0fabbcSTim J. Robbins /* 810ea0fabbcSTim J. Robbins * The interpreter for shell scripts run from a linux binary needs 811ea0fabbcSTim J. Robbins * to be located in /compat/linux if possible in order to recursively 812ea0fabbcSTim J. Robbins * maintain linux path emulation. 813ea0fabbcSTim J. Robbins */ 814ea0fabbcSTim J. Robbins if (((const short *)head)[0] == SHELLMAGIC) { 815ea0fabbcSTim J. Robbins /* 816ea0fabbcSTim J. Robbins * Run our normal shell image activator. If it succeeds attempt 817d065e13dSDavid E. O'Brien * to use the alternate path for the interpreter. If an 818d065e13dSDavid E. O'Brien * alternate * path is found, use our stringspace to store it. 819ea0fabbcSTim J. Robbins */ 820ea0fabbcSTim J. Robbins if ((error = exec_shell_imgact(imgp)) == 0) { 8211d15fdd9SJohn Baldwin linux_emul_convpath(FIRST_THREAD_IN_PROC(imgp->proc), 822d065e13dSDavid E. O'Brien imgp->interpreter_name, UIO_SYSSPACE, &rpath, 0, 823d065e13dSDavid E. O'Brien AT_FDCWD); 824a14a9498SAlan Cox if (rpath != NULL) 825a14a9498SAlan Cox imgp->args->fname_buf = 826a14a9498SAlan Cox imgp->interpreter_name = rpath; 827ea0fabbcSTim J. Robbins } 828ea0fabbcSTim J. Robbins } 829ea0fabbcSTim J. Robbins return (error); 830ea0fabbcSTim J. Robbins } 831ea0fabbcSTim J. Robbins 832ea0fabbcSTim J. Robbins /* 833ea0fabbcSTim J. Robbins * Clear registers on exec 834ea0fabbcSTim J. Robbins * XXX copied from ia32_signal.c. 835ea0fabbcSTim J. Robbins */ 836ea0fabbcSTim J. Robbins static void 837a107d8aaSNathan Whitehorn exec_linux_setregs(struct thread *td, struct image_params *imgp, u_long stack) 838ea0fabbcSTim J. Robbins { 839ea0fabbcSTim J. Robbins struct trapframe *regs = td->td_frame; 840ea0fabbcSTim J. Robbins struct pcb *pcb = td->td_pcb; 841ea0fabbcSTim J. Robbins 8422c66cccaSKonstantin Belousov mtx_lock(&dt_lock); 8432c66cccaSKonstantin Belousov if (td->td_proc->p_md.md_ldt != NULL) 8442c66cccaSKonstantin Belousov user_ldt_free(td); 8452c66cccaSKonstantin Belousov else 8462c66cccaSKonstantin Belousov mtx_unlock(&dt_lock); 8472c66cccaSKonstantin Belousov 8489c5b213eSJung-uk Kim critical_enter(); 849ea0fabbcSTim J. Robbins wrmsr(MSR_FSBASE, 0); 850ea0fabbcSTim J. Robbins wrmsr(MSR_KGSBASE, 0); /* User value while we're in the kernel */ 851ea0fabbcSTim J. Robbins pcb->pcb_fsbase = 0; 852ea0fabbcSTim J. Robbins pcb->pcb_gsbase = 0; 8539c5b213eSJung-uk Kim critical_exit(); 8542ee8325fSJohn Baldwin pcb->pcb_initial_fpucw = __LINUX_NPXCW__; 855ea0fabbcSTim J. Robbins 856ea0fabbcSTim J. Robbins bzero((char *)regs, sizeof(struct trapframe)); 857a107d8aaSNathan Whitehorn regs->tf_rip = imgp->entry_addr; 858ea0fabbcSTim J. Robbins regs->tf_rsp = stack; 859ea0fabbcSTim J. Robbins regs->tf_rflags = PSL_USER | (regs->tf_rflags & PSL_T); 8602c66cccaSKonstantin Belousov regs->tf_gs = _ugssel; 8612c66cccaSKonstantin Belousov regs->tf_fs = _ufssel; 8622c66cccaSKonstantin Belousov regs->tf_es = _udatasel; 8632c66cccaSKonstantin Belousov regs->tf_ds = _udatasel; 864ea0fabbcSTim J. Robbins regs->tf_ss = _udatasel; 8652c66cccaSKonstantin Belousov regs->tf_flags = TF_HASSEGS; 866ea0fabbcSTim J. Robbins regs->tf_cs = _ucode32sel; 867a107d8aaSNathan Whitehorn regs->tf_rbx = imgp->ps_strings; 868ea0fabbcSTim J. Robbins load_cr0(rcr0() | CR0_MP | CR0_TS); 8692a988f7cSStephan Uphoff fpstate_drop(td); 870ea0fabbcSTim J. Robbins 871*1b3c3256SKonstantin Belousov /* Do full restore on return so that we can change to a different %cs */ 8720f0170e6SKonstantin Belousov pcb->pcb_flags |= PCB_32BIT; 873f1f0dd9eSKonstantin Belousov pcb->pcb_flags &= ~PCB_GS32BIT; 874*1b3c3256SKonstantin Belousov pcb->pcb_full_iret = 1; 875ea0fabbcSTim J. Robbins td->td_retval[1] = 0; 876ea0fabbcSTim J. Robbins } 877ea0fabbcSTim J. Robbins 878ea0fabbcSTim J. Robbins /* 879ea0fabbcSTim J. Robbins * XXX copied from ia32_sysvec.c. 880ea0fabbcSTim J. Robbins */ 881ea0fabbcSTim J. Robbins static register_t * 882ea0fabbcSTim J. Robbins linux_copyout_strings(struct image_params *imgp) 883ea0fabbcSTim J. Robbins { 884ea0fabbcSTim J. Robbins int argc, envc; 885ea0fabbcSTim J. Robbins u_int32_t *vectp; 886ea0fabbcSTim J. Robbins char *stringp, *destp; 887ea0fabbcSTim J. Robbins u_int32_t *stack_base; 888ea0fabbcSTim J. Robbins struct linux32_ps_strings *arginfo; 889ea0fabbcSTim J. Robbins 890ea0fabbcSTim J. Robbins /* 891ea0fabbcSTim J. Robbins * Calculate string base and vector table pointers. 892ea0fabbcSTim J. Robbins * Also deal with signal trampoline code for this exec type. 893ea0fabbcSTim J. Robbins */ 894ea0fabbcSTim J. Robbins arginfo = (struct linux32_ps_strings *)LINUX32_PS_STRINGS; 8954d7c2e8aSDmitry Chagin destp = (caddr_t)arginfo - linux_szsigcode - SPARE_USRSPACE - 8964d7c2e8aSDmitry Chagin linux_szplatform - roundup((ARG_MAX - imgp->args->stringspace), 8974d7c2e8aSDmitry Chagin sizeof(char *)); 898ea0fabbcSTim J. Robbins 899ea0fabbcSTim J. Robbins /* 900ea0fabbcSTim J. Robbins * install sigcode 901ea0fabbcSTim J. Robbins */ 902ea0fabbcSTim J. Robbins copyout(imgp->proc->p_sysent->sv_sigcode, 9034d7c2e8aSDmitry Chagin ((caddr_t)arginfo - linux_szsigcode), linux_szsigcode); 9044d7c2e8aSDmitry Chagin 9054d7c2e8aSDmitry Chagin /* 9064d7c2e8aSDmitry Chagin * Install LINUX_PLATFORM 9074d7c2e8aSDmitry Chagin */ 9084d7c2e8aSDmitry Chagin copyout(linux_platform, ((caddr_t)arginfo - linux_szsigcode - 9094d7c2e8aSDmitry Chagin linux_szplatform), linux_szplatform); 910ea0fabbcSTim J. Robbins 911ea0fabbcSTim J. Robbins /* 912ea0fabbcSTim J. Robbins * If we have a valid auxargs ptr, prepare some room 913ea0fabbcSTim J. Robbins * on the stack. 914ea0fabbcSTim J. Robbins */ 915ea0fabbcSTim J. Robbins if (imgp->auxargs) { 916ea0fabbcSTim J. Robbins /* 917ea0fabbcSTim J. Robbins * 'AT_COUNT*2' is size for the ELF Auxargs data. This is for 918ea0fabbcSTim J. Robbins * lower compatibility. 919ea0fabbcSTim J. Robbins */ 920d065e13dSDavid E. O'Brien imgp->auxarg_size = (imgp->auxarg_size) ? imgp->auxarg_size : 9214d7c2e8aSDmitry Chagin (LINUX_AT_COUNT * 2); 922ea0fabbcSTim J. Robbins /* 923ea0fabbcSTim J. Robbins * The '+ 2' is for the null pointers at the end of each of 924ea0fabbcSTim J. Robbins * the arg and env vector sets,and imgp->auxarg_size is room 925ea0fabbcSTim J. Robbins * for argument of Runtime loader. 926ea0fabbcSTim J. Robbins */ 927d065e13dSDavid E. O'Brien vectp = (u_int32_t *) (destp - (imgp->args->argc + 928d065e13dSDavid E. O'Brien imgp->args->envc + 2 + imgp->auxarg_size) * 929d065e13dSDavid E. O'Brien sizeof(u_int32_t)); 930ea0fabbcSTim J. Robbins 931ea0fabbcSTim J. Robbins } else 932ea0fabbcSTim J. Robbins /* 933ea0fabbcSTim J. Robbins * The '+ 2' is for the null pointers at the end of each of 934ea0fabbcSTim J. Robbins * the arg and env vector sets 935ea0fabbcSTim J. Robbins */ 936d065e13dSDavid E. O'Brien vectp = (u_int32_t *)(destp - (imgp->args->argc + 937d065e13dSDavid E. O'Brien imgp->args->envc + 2) * sizeof(u_int32_t)); 938ea0fabbcSTim J. Robbins 939ea0fabbcSTim J. Robbins /* 940ea0fabbcSTim J. Robbins * vectp also becomes our initial stack base 941ea0fabbcSTim J. Robbins */ 942ea0fabbcSTim J. Robbins stack_base = vectp; 943ea0fabbcSTim J. Robbins 944610ecfe0SMaxim Sobolev stringp = imgp->args->begin_argv; 945610ecfe0SMaxim Sobolev argc = imgp->args->argc; 946610ecfe0SMaxim Sobolev envc = imgp->args->envc; 947ea0fabbcSTim J. Robbins /* 948ea0fabbcSTim J. Robbins * Copy out strings - arguments and environment. 949ea0fabbcSTim J. Robbins */ 950610ecfe0SMaxim Sobolev copyout(stringp, destp, ARG_MAX - imgp->args->stringspace); 951ea0fabbcSTim J. Robbins 952ea0fabbcSTim J. Robbins /* 953ea0fabbcSTim J. Robbins * Fill in "ps_strings" struct for ps, w, etc. 954ea0fabbcSTim J. Robbins */ 9554d7c2e8aSDmitry Chagin suword32(&arginfo->ps_argvstr, (uint32_t)(intptr_t)vectp); 956ea0fabbcSTim J. Robbins suword32(&arginfo->ps_nargvstr, argc); 957ea0fabbcSTim J. Robbins 958ea0fabbcSTim J. Robbins /* 959ea0fabbcSTim J. Robbins * Fill in argument portion of vector table. 960ea0fabbcSTim J. Robbins */ 961ea0fabbcSTim J. Robbins for (; argc > 0; --argc) { 9624d7c2e8aSDmitry Chagin suword32(vectp++, (uint32_t)(intptr_t)destp); 963ea0fabbcSTim J. Robbins while (*stringp++ != 0) 964ea0fabbcSTim J. Robbins destp++; 965ea0fabbcSTim J. Robbins destp++; 966ea0fabbcSTim J. Robbins } 967ea0fabbcSTim J. Robbins 968ea0fabbcSTim J. Robbins /* a null vector table pointer separates the argp's from the envp's */ 969ea0fabbcSTim J. Robbins suword32(vectp++, 0); 970ea0fabbcSTim J. Robbins 9714d7c2e8aSDmitry Chagin suword32(&arginfo->ps_envstr, (uint32_t)(intptr_t)vectp); 972ea0fabbcSTim J. Robbins suword32(&arginfo->ps_nenvstr, envc); 973ea0fabbcSTim J. Robbins 974ea0fabbcSTim J. Robbins /* 975ea0fabbcSTim J. Robbins * Fill in environment portion of vector table. 976ea0fabbcSTim J. Robbins */ 977ea0fabbcSTim J. Robbins for (; envc > 0; --envc) { 9784d7c2e8aSDmitry Chagin suword32(vectp++, (uint32_t)(intptr_t)destp); 979ea0fabbcSTim J. Robbins while (*stringp++ != 0) 980ea0fabbcSTim J. Robbins destp++; 981ea0fabbcSTim J. Robbins destp++; 982ea0fabbcSTim J. Robbins } 983ea0fabbcSTim J. Robbins 984ea0fabbcSTim J. Robbins /* end of vector table is a null pointer */ 985ea0fabbcSTim J. Robbins suword32(vectp, 0); 986ea0fabbcSTim J. Robbins 987ea0fabbcSTim J. Robbins return ((register_t *)stack_base); 988ea0fabbcSTim J. Robbins } 989ea0fabbcSTim J. Robbins 990ea0fabbcSTim J. Robbins SYSCTL_NODE(_compat, OID_AUTO, linux32, CTLFLAG_RW, 0, 991ea0fabbcSTim J. Robbins "32-bit Linux emulation"); 992ea0fabbcSTim J. Robbins 993ea0fabbcSTim J. Robbins static u_long linux32_maxdsiz = LINUX32_MAXDSIZ; 994ea0fabbcSTim J. Robbins SYSCTL_ULONG(_compat_linux32, OID_AUTO, maxdsiz, CTLFLAG_RW, 995ea0fabbcSTim J. Robbins &linux32_maxdsiz, 0, ""); 996ea0fabbcSTim J. Robbins static u_long linux32_maxssiz = LINUX32_MAXSSIZ; 997ea0fabbcSTim J. Robbins SYSCTL_ULONG(_compat_linux32, OID_AUTO, maxssiz, CTLFLAG_RW, 998ea0fabbcSTim J. Robbins &linux32_maxssiz, 0, ""); 999ea0fabbcSTim J. Robbins static u_long linux32_maxvmem = LINUX32_MAXVMEM; 1000ea0fabbcSTim J. Robbins SYSCTL_ULONG(_compat_linux32, OID_AUTO, maxvmem, CTLFLAG_RW, 1001ea0fabbcSTim J. Robbins &linux32_maxvmem, 0, ""); 1002ea0fabbcSTim J. Robbins 1003ea0fabbcSTim J. Robbins static void 100419059a13SJohn Baldwin linux32_fixlimit(struct rlimit *rl, int which) 1005ea0fabbcSTim J. Robbins { 1006ea0fabbcSTim J. Robbins 100719059a13SJohn Baldwin switch (which) { 100819059a13SJohn Baldwin case RLIMIT_DATA: 1009ea0fabbcSTim J. Robbins if (linux32_maxdsiz != 0) { 101019059a13SJohn Baldwin if (rl->rlim_cur > linux32_maxdsiz) 101119059a13SJohn Baldwin rl->rlim_cur = linux32_maxdsiz; 101219059a13SJohn Baldwin if (rl->rlim_max > linux32_maxdsiz) 101319059a13SJohn Baldwin rl->rlim_max = linux32_maxdsiz; 1014ea0fabbcSTim J. Robbins } 101519059a13SJohn Baldwin break; 101619059a13SJohn Baldwin case RLIMIT_STACK: 1017ea0fabbcSTim J. Robbins if (linux32_maxssiz != 0) { 101819059a13SJohn Baldwin if (rl->rlim_cur > linux32_maxssiz) 101919059a13SJohn Baldwin rl->rlim_cur = linux32_maxssiz; 102019059a13SJohn Baldwin if (rl->rlim_max > linux32_maxssiz) 102119059a13SJohn Baldwin rl->rlim_max = linux32_maxssiz; 1022ea0fabbcSTim J. Robbins } 102319059a13SJohn Baldwin break; 102419059a13SJohn Baldwin case RLIMIT_VMEM: 1025ea0fabbcSTim J. Robbins if (linux32_maxvmem != 0) { 102619059a13SJohn Baldwin if (rl->rlim_cur > linux32_maxvmem) 102719059a13SJohn Baldwin rl->rlim_cur = linux32_maxvmem; 102819059a13SJohn Baldwin if (rl->rlim_max > linux32_maxvmem) 102919059a13SJohn Baldwin rl->rlim_max = linux32_maxvmem; 1030ea0fabbcSTim J. Robbins } 103119059a13SJohn Baldwin break; 103219059a13SJohn Baldwin } 1033ea0fabbcSTim J. Robbins } 1034ea0fabbcSTim J. Robbins 1035ea0fabbcSTim J. Robbins struct sysentvec elf_linux_sysvec = { 1036a8d403e1SKonstantin Belousov .sv_size = LINUX_SYS_MAXSYSCALL, 1037a8d403e1SKonstantin Belousov .sv_table = linux_sysent, 1038a8d403e1SKonstantin Belousov .sv_mask = 0, 1039a8d403e1SKonstantin Belousov .sv_sigsize = LINUX_SIGTBLSZ, 1040a8d403e1SKonstantin Belousov .sv_sigtbl = bsd_to_linux_signal, 1041a8d403e1SKonstantin Belousov .sv_errsize = ELAST + 1, 1042a8d403e1SKonstantin Belousov .sv_errtbl = bsd_to_linux_errno, 1043a8d403e1SKonstantin Belousov .sv_transtrap = translate_traps, 1044a8d403e1SKonstantin Belousov .sv_fixup = elf_linux_fixup, 1045a8d403e1SKonstantin Belousov .sv_sendsig = linux_sendsig, 1046a8d403e1SKonstantin Belousov .sv_sigcode = linux_sigcode, 1047a8d403e1SKonstantin Belousov .sv_szsigcode = &linux_szsigcode, 1048afe1a688SKonstantin Belousov .sv_prepsyscall = NULL, 1049a8d403e1SKonstantin Belousov .sv_name = "Linux ELF32", 1050a8d403e1SKonstantin Belousov .sv_coredump = elf32_coredump, 1051a8d403e1SKonstantin Belousov .sv_imgact_try = exec_linux_imgact_try, 1052a8d403e1SKonstantin Belousov .sv_minsigstksz = LINUX_MINSIGSTKSZ, 1053a8d403e1SKonstantin Belousov .sv_pagesize = PAGE_SIZE, 1054a8d403e1SKonstantin Belousov .sv_minuser = VM_MIN_ADDRESS, 1055a8d403e1SKonstantin Belousov .sv_maxuser = LINUX32_USRSTACK, 1056a8d403e1SKonstantin Belousov .sv_usrstack = LINUX32_USRSTACK, 1057a8d403e1SKonstantin Belousov .sv_psstrings = LINUX32_PS_STRINGS, 1058a8d403e1SKonstantin Belousov .sv_stackprot = VM_PROT_ALL, 1059a8d403e1SKonstantin Belousov .sv_copyout_strings = linux_copyout_strings, 1060a8d403e1SKonstantin Belousov .sv_setregs = exec_linux_setregs, 1061a8d403e1SKonstantin Belousov .sv_fixlimit = linux32_fixlimit, 1062a8d403e1SKonstantin Belousov .sv_maxssiz = &linux32_maxssiz, 1063afe1a688SKonstantin Belousov .sv_flags = SV_ABI_LINUX | SV_ILP32 | SV_IA32, 1064afe1a688SKonstantin Belousov .sv_set_syscall_retval = cpu_set_syscall_retval, 1065afe1a688SKonstantin Belousov .sv_fetch_syscall_args = linux32_fetch_syscall_args, 1066afe1a688SKonstantin Belousov .sv_syscallnames = NULL, 1067ea0fabbcSTim J. Robbins }; 1068ea0fabbcSTim J. Robbins 106989ffc202SBjoern A. Zeeb static char GNU_ABI_VENDOR[] = "GNU"; 107089ffc202SBjoern A. Zeeb static int GNULINUX_ABI_DESC = 0; 107189ffc202SBjoern A. Zeeb 107289ffc202SBjoern A. Zeeb static boolean_t 107389ffc202SBjoern A. Zeeb linux32_trans_osrel(const Elf_Note *note, int32_t *osrel) 107489ffc202SBjoern A. Zeeb { 107589ffc202SBjoern A. Zeeb const Elf32_Word *desc; 107689ffc202SBjoern A. Zeeb uintptr_t p; 107789ffc202SBjoern A. Zeeb 107889ffc202SBjoern A. Zeeb p = (uintptr_t)(note + 1); 107989ffc202SBjoern A. Zeeb p += roundup2(note->n_namesz, sizeof(Elf32_Addr)); 108089ffc202SBjoern A. Zeeb 108189ffc202SBjoern A. Zeeb desc = (const Elf32_Word *)p; 108289ffc202SBjoern A. Zeeb if (desc[0] != GNULINUX_ABI_DESC) 108389ffc202SBjoern A. Zeeb return (FALSE); 108489ffc202SBjoern A. Zeeb 108589ffc202SBjoern A. Zeeb /* 108689ffc202SBjoern A. Zeeb * For linux we encode osrel as follows (see linux_mib.c): 108789ffc202SBjoern A. Zeeb * VVVMMMIII (version, major, minor), see linux_mib.c. 108889ffc202SBjoern A. Zeeb */ 108989ffc202SBjoern A. Zeeb *osrel = desc[1] * 1000000 + desc[2] * 1000 + desc[3]; 109089ffc202SBjoern A. Zeeb 109189ffc202SBjoern A. Zeeb return (TRUE); 109289ffc202SBjoern A. Zeeb } 109332c01de2SDmitry Chagin 109432c01de2SDmitry Chagin static Elf_Brandnote linux32_brandnote = { 109589ffc202SBjoern A. Zeeb .hdr.n_namesz = sizeof(GNU_ABI_VENDOR), 109689ffc202SBjoern A. Zeeb .hdr.n_descsz = 16, /* XXX at least 16 */ 109732c01de2SDmitry Chagin .hdr.n_type = 1, 109889ffc202SBjoern A. Zeeb .vendor = GNU_ABI_VENDOR, 109989ffc202SBjoern A. Zeeb .flags = BN_TRANSLATE_OSREL, 110089ffc202SBjoern A. Zeeb .trans_osrel = linux32_trans_osrel 110132c01de2SDmitry Chagin }; 110232c01de2SDmitry Chagin 1103ea0fabbcSTim J. Robbins static Elf32_Brandinfo linux_brand = { 1104a8d403e1SKonstantin Belousov .brand = ELFOSABI_LINUX, 1105a8d403e1SKonstantin Belousov .machine = EM_386, 1106a8d403e1SKonstantin Belousov .compat_3_brand = "Linux", 1107a8d403e1SKonstantin Belousov .emul_path = "/compat/linux", 1108a8d403e1SKonstantin Belousov .interp_path = "/lib/ld-linux.so.1", 1109a8d403e1SKonstantin Belousov .sysvec = &elf_linux_sysvec, 1110a8d403e1SKonstantin Belousov .interp_newpath = NULL, 111132c01de2SDmitry Chagin .brand_note = &linux32_brandnote, 1112cd899aadSDmitry Chagin .flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE 1113ea0fabbcSTim J. Robbins }; 1114ea0fabbcSTim J. Robbins 1115ea0fabbcSTim J. Robbins static Elf32_Brandinfo linux_glibc2brand = { 1116a8d403e1SKonstantin Belousov .brand = ELFOSABI_LINUX, 1117a8d403e1SKonstantin Belousov .machine = EM_386, 1118a8d403e1SKonstantin Belousov .compat_3_brand = "Linux", 1119a8d403e1SKonstantin Belousov .emul_path = "/compat/linux", 1120a8d403e1SKonstantin Belousov .interp_path = "/lib/ld-linux.so.2", 1121a8d403e1SKonstantin Belousov .sysvec = &elf_linux_sysvec, 1122a8d403e1SKonstantin Belousov .interp_newpath = NULL, 112332c01de2SDmitry Chagin .brand_note = &linux32_brandnote, 1124cd899aadSDmitry Chagin .flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE 1125ea0fabbcSTim J. Robbins }; 1126ea0fabbcSTim J. Robbins 1127ea0fabbcSTim J. Robbins Elf32_Brandinfo *linux_brandlist[] = { 1128ea0fabbcSTim J. Robbins &linux_brand, 1129ea0fabbcSTim J. Robbins &linux_glibc2brand, 1130ea0fabbcSTim J. Robbins NULL 1131ea0fabbcSTim J. Robbins }; 1132ea0fabbcSTim J. Robbins 1133ea0fabbcSTim J. Robbins static int 1134ea0fabbcSTim J. Robbins linux_elf_modevent(module_t mod, int type, void *data) 1135ea0fabbcSTim J. Robbins { 1136ea0fabbcSTim J. Robbins Elf32_Brandinfo **brandinfo; 1137ea0fabbcSTim J. Robbins int error; 1138ea0fabbcSTim J. Robbins struct linux_ioctl_handler **lihp; 1139387196bfSDoug Ambrisko struct linux_device_handler **ldhp; 1140ea0fabbcSTim J. Robbins 1141ea0fabbcSTim J. Robbins error = 0; 1142ea0fabbcSTim J. Robbins 1143ea0fabbcSTim J. Robbins switch(type) { 1144ea0fabbcSTim J. Robbins case MOD_LOAD: 1145ea0fabbcSTim J. Robbins for (brandinfo = &linux_brandlist[0]; *brandinfo != NULL; 1146ea0fabbcSTim J. Robbins ++brandinfo) 1147ea0fabbcSTim J. Robbins if (elf32_insert_brand_entry(*brandinfo) < 0) 1148ea0fabbcSTim J. Robbins error = EINVAL; 1149ea0fabbcSTim J. Robbins if (error == 0) { 1150ea0fabbcSTim J. Robbins SET_FOREACH(lihp, linux_ioctl_handler_set) 1151ea0fabbcSTim J. Robbins linux_ioctl_register_handler(*lihp); 1152387196bfSDoug Ambrisko SET_FOREACH(ldhp, linux_device_handler_set) 1153387196bfSDoug Ambrisko linux_device_register_handler(*ldhp); 1154357afa71SJung-uk Kim mtx_init(&emul_lock, "emuldata lock", NULL, MTX_DEF); 11557c09e6c0SAlexander Leidinger sx_init(&emul_shared_lock, "emuldata->shared lock"); 11567c09e6c0SAlexander Leidinger LIST_INIT(&futex_list); 115779262bf1SDmitry Chagin mtx_init(&futex_mtx, "ftllk", NULL, MTX_DEF); 1158d065e13dSDavid E. O'Brien linux_exit_tag = EVENTHANDLER_REGISTER(process_exit, 1159d065e13dSDavid E. O'Brien linux_proc_exit, NULL, 1000); 1160d065e13dSDavid E. O'Brien linux_schedtail_tag = EVENTHANDLER_REGISTER(schedtail, 1161d065e13dSDavid E. O'Brien linux_schedtail, NULL, 1000); 1162d065e13dSDavid E. O'Brien linux_exec_tag = EVENTHANDLER_REGISTER(process_exec, 1163d065e13dSDavid E. O'Brien linux_proc_exec, NULL, 1000); 11644d7c2e8aSDmitry Chagin linux_szplatform = roundup(strlen(linux_platform) + 1, 11654d7c2e8aSDmitry Chagin sizeof(char *)); 11667ae27ff4SJamie Gritton linux_osd_jail_register(); 11671ca16454SDmitry Chagin stclohz = (stathz ? stathz : hz); 1168ea0fabbcSTim J. Robbins if (bootverbose) 1169ea0fabbcSTim J. Robbins printf("Linux ELF exec handler installed\n"); 1170ea0fabbcSTim J. Robbins } else 1171ea0fabbcSTim J. Robbins printf("cannot insert Linux ELF brand handler\n"); 1172ea0fabbcSTim J. Robbins break; 1173ea0fabbcSTim J. Robbins case MOD_UNLOAD: 1174ea0fabbcSTim J. Robbins for (brandinfo = &linux_brandlist[0]; *brandinfo != NULL; 1175ea0fabbcSTim J. Robbins ++brandinfo) 1176ea0fabbcSTim J. Robbins if (elf32_brand_inuse(*brandinfo)) 1177ea0fabbcSTim J. Robbins error = EBUSY; 1178ea0fabbcSTim J. Robbins if (error == 0) { 1179ea0fabbcSTim J. Robbins for (brandinfo = &linux_brandlist[0]; 1180ea0fabbcSTim J. Robbins *brandinfo != NULL; ++brandinfo) 1181ea0fabbcSTim J. Robbins if (elf32_remove_brand_entry(*brandinfo) < 0) 1182ea0fabbcSTim J. Robbins error = EINVAL; 1183ea0fabbcSTim J. Robbins } 1184ea0fabbcSTim J. Robbins if (error == 0) { 1185ea0fabbcSTim J. Robbins SET_FOREACH(lihp, linux_ioctl_handler_set) 1186ea0fabbcSTim J. Robbins linux_ioctl_unregister_handler(*lihp); 1187387196bfSDoug Ambrisko SET_FOREACH(ldhp, linux_device_handler_set) 1188387196bfSDoug Ambrisko linux_device_unregister_handler(*ldhp); 1189357afa71SJung-uk Kim mtx_destroy(&emul_lock); 11907c09e6c0SAlexander Leidinger sx_destroy(&emul_shared_lock); 119179262bf1SDmitry Chagin mtx_destroy(&futex_mtx); 11927c09e6c0SAlexander Leidinger EVENTHANDLER_DEREGISTER(process_exit, linux_exit_tag); 11937c09e6c0SAlexander Leidinger EVENTHANDLER_DEREGISTER(schedtail, linux_schedtail_tag); 11947c09e6c0SAlexander Leidinger EVENTHANDLER_DEREGISTER(process_exec, linux_exec_tag); 11957ae27ff4SJamie Gritton linux_osd_jail_deregister(); 1196ea0fabbcSTim J. Robbins if (bootverbose) 1197ea0fabbcSTim J. Robbins printf("Linux ELF exec handler removed\n"); 1198ea0fabbcSTim J. Robbins } else 1199ea0fabbcSTim J. Robbins printf("Could not deinstall ELF interpreter entry\n"); 1200ea0fabbcSTim J. Robbins break; 1201ea0fabbcSTim J. Robbins default: 1202786e4fc4SAlexander Leidinger return EOPNOTSUPP; 1203ea0fabbcSTim J. Robbins } 1204ea0fabbcSTim J. Robbins return error; 1205ea0fabbcSTim J. Robbins } 1206ea0fabbcSTim J. Robbins 1207ea0fabbcSTim J. Robbins static moduledata_t linux_elf_mod = { 1208ea0fabbcSTim J. Robbins "linuxelf", 1209ea0fabbcSTim J. Robbins linux_elf_modevent, 1210ea0fabbcSTim J. Robbins 0 1211ea0fabbcSTim J. Robbins }; 1212ea0fabbcSTim J. Robbins 121378ae4338SKonstantin Belousov DECLARE_MODULE_TIED(linuxelf, linux_elf_mod, SI_SUB_EXEC, SI_ORDER_ANY); 1214