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 69a14aa01SUlrich Spörlein * 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> 797c09e6c0SAlexander Leidinger #include <compat/linux/linux_emul.h> 80fde63162SDmitry Chagin #include <compat/linux/linux_futex.h> 81d825ce0aSJohn Baldwin #include <compat/linux/linux_ioctl.h> 82ea0fabbcSTim J. Robbins #include <compat/linux/linux_mib.h> 834d7c2e8aSDmitry Chagin #include <compat/linux/linux_misc.h> 84ea0fabbcSTim J. Robbins #include <compat/linux/linux_signal.h> 85ea0fabbcSTim J. Robbins #include <compat/linux/linux_util.h> 86bdc37934SDmitry Chagin #include <compat/linux/linux_vdso.h> 87ea0fabbcSTim J. Robbins 88ea0fabbcSTim J. Robbins MODULE_VERSION(linux, 1); 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 1110020bdf1SDmitry Chagin const char *linux_kplatform; 112bdc37934SDmitry Chagin static int linux_szsigcode; 113bdc37934SDmitry Chagin static vm_object_t linux_shared_page_obj; 114bdc37934SDmitry Chagin static char *linux_shared_page_mapping; 115bdc37934SDmitry Chagin extern char _binary_linux32_locore_o_start; 116bdc37934SDmitry Chagin extern char _binary_linux32_locore_o_end; 117ea0fabbcSTim J. Robbins 118ea0fabbcSTim J. Robbins extern struct sysent linux_sysent[LINUX_SYS_MAXSYSCALL]; 119ea0fabbcSTim J. Robbins 120ea0fabbcSTim J. Robbins SET_DECLARE(linux_ioctl_handler_set, struct linux_ioctl_handler); 121ea0fabbcSTim J. Robbins 122ea0fabbcSTim J. Robbins static int elf_linux_fixup(register_t **stack_base, 123ea0fabbcSTim J. Robbins struct image_params *iparams); 124ea0fabbcSTim J. Robbins static register_t *linux_copyout_strings(struct image_params *imgp); 1259104847fSDavid Xu static void linux_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask); 126a107d8aaSNathan Whitehorn static void exec_linux_setregs(struct thread *td, 127a107d8aaSNathan Whitehorn struct image_params *imgp, u_long stack); 12819059a13SJohn Baldwin static void linux32_fixlimit(struct rlimit *rl, int which); 12989ffc202SBjoern A. Zeeb static boolean_t linux32_trans_osrel(const Elf_Note *note, int32_t *osrel); 130bdc37934SDmitry Chagin static void linux_vdso_install(void *param); 131bdc37934SDmitry Chagin static void linux_vdso_deinstall(void *param); 132ea0fabbcSTim J. Robbins 133ea0fabbcSTim J. Robbins /* 134ea0fabbcSTim J. Robbins * Linux syscalls return negative errno's, we do positive and map them 13550e422f0SAlexander Leidinger * Reference: 13650e422f0SAlexander Leidinger * FreeBSD: src/sys/sys/errno.h 13750e422f0SAlexander Leidinger * Linux: linux-2.6.17.8/include/asm-generic/errno-base.h 13850e422f0SAlexander Leidinger * linux-2.6.17.8/include/asm-generic/errno.h 139ea0fabbcSTim J. Robbins */ 140ea0fabbcSTim J. Robbins static int bsd_to_linux_errno[ELAST + 1] = { 141ea0fabbcSTim J. Robbins -0, -1, -2, -3, -4, -5, -6, -7, -8, -9, 142ea0fabbcSTim J. Robbins -10, -35, -12, -13, -14, -15, -16, -17, -18, -19, 143ea0fabbcSTim J. Robbins -20, -21, -22, -23, -24, -25, -26, -27, -28, -29, 144ea0fabbcSTim J. Robbins -30, -31, -32, -33, -34, -11,-115,-114, -88, -89, 145ea0fabbcSTim J. Robbins -90, -91, -92, -93, -94, -95, -96, -97, -98, -99, 146ea0fabbcSTim J. Robbins -100,-101,-102,-103,-104,-105,-106,-107,-108,-109, 147ea0fabbcSTim J. Robbins -110,-111, -40, -36,-112,-113, -39, -11, -87,-122, 148ea0fabbcSTim J. Robbins -116, -66, -6, -6, -6, -6, -6, -37, -38, -9, 14950e422f0SAlexander Leidinger -6, -6, -43, -42, -75,-125, -84, -95, -16, -74, 15050e422f0SAlexander Leidinger -72, -67, -71 151ea0fabbcSTim J. Robbins }; 152ea0fabbcSTim J. Robbins 153ea0fabbcSTim J. Robbins int bsd_to_linux_signal[LINUX_SIGTBLSZ] = { 154ea0fabbcSTim J. Robbins LINUX_SIGHUP, LINUX_SIGINT, LINUX_SIGQUIT, LINUX_SIGILL, 155ea0fabbcSTim J. Robbins LINUX_SIGTRAP, LINUX_SIGABRT, 0, LINUX_SIGFPE, 156ea0fabbcSTim J. Robbins LINUX_SIGKILL, LINUX_SIGBUS, LINUX_SIGSEGV, LINUX_SIGSYS, 157ea0fabbcSTim J. Robbins LINUX_SIGPIPE, LINUX_SIGALRM, LINUX_SIGTERM, LINUX_SIGURG, 158ea0fabbcSTim J. Robbins LINUX_SIGSTOP, LINUX_SIGTSTP, LINUX_SIGCONT, LINUX_SIGCHLD, 159ea0fabbcSTim J. Robbins LINUX_SIGTTIN, LINUX_SIGTTOU, LINUX_SIGIO, LINUX_SIGXCPU, 160ea0fabbcSTim J. Robbins LINUX_SIGXFSZ, LINUX_SIGVTALRM, LINUX_SIGPROF, LINUX_SIGWINCH, 161ea0fabbcSTim J. Robbins 0, LINUX_SIGUSR1, LINUX_SIGUSR2 162ea0fabbcSTim J. Robbins }; 163ea0fabbcSTim J. Robbins 164ea0fabbcSTim J. Robbins int linux_to_bsd_signal[LINUX_SIGTBLSZ] = { 165ea0fabbcSTim J. Robbins SIGHUP, SIGINT, SIGQUIT, SIGILL, 166ea0fabbcSTim J. Robbins SIGTRAP, SIGABRT, SIGBUS, SIGFPE, 167ea0fabbcSTim J. Robbins SIGKILL, SIGUSR1, SIGSEGV, SIGUSR2, 168ea0fabbcSTim J. Robbins SIGPIPE, SIGALRM, SIGTERM, SIGBUS, 169ea0fabbcSTim J. Robbins SIGCHLD, SIGCONT, SIGSTOP, SIGTSTP, 170ea0fabbcSTim J. Robbins SIGTTIN, SIGTTOU, SIGURG, SIGXCPU, 171ea0fabbcSTim J. Robbins SIGXFSZ, SIGVTALRM, SIGPROF, SIGWINCH, 172ea0fabbcSTim J. Robbins SIGIO, SIGURG, SIGSYS 173ea0fabbcSTim J. Robbins }; 174ea0fabbcSTim J. Robbins 175ea0fabbcSTim J. Robbins #define LINUX_T_UNKNOWN 255 176ea0fabbcSTim J. Robbins static int _bsd_to_linux_trapcode[] = { 177ea0fabbcSTim J. Robbins LINUX_T_UNKNOWN, /* 0 */ 178ea0fabbcSTim J. Robbins 6, /* 1 T_PRIVINFLT */ 179ea0fabbcSTim J. Robbins LINUX_T_UNKNOWN, /* 2 */ 180ea0fabbcSTim J. Robbins 3, /* 3 T_BPTFLT */ 181ea0fabbcSTim J. Robbins LINUX_T_UNKNOWN, /* 4 */ 182ea0fabbcSTim J. Robbins LINUX_T_UNKNOWN, /* 5 */ 183ea0fabbcSTim J. Robbins 16, /* 6 T_ARITHTRAP */ 184ea0fabbcSTim J. Robbins 254, /* 7 T_ASTFLT */ 185ea0fabbcSTim J. Robbins LINUX_T_UNKNOWN, /* 8 */ 186ea0fabbcSTim J. Robbins 13, /* 9 T_PROTFLT */ 187ea0fabbcSTim J. Robbins 1, /* 10 T_TRCTRAP */ 188ea0fabbcSTim J. Robbins LINUX_T_UNKNOWN, /* 11 */ 189ea0fabbcSTim J. Robbins 14, /* 12 T_PAGEFLT */ 190ea0fabbcSTim J. Robbins LINUX_T_UNKNOWN, /* 13 */ 191ea0fabbcSTim J. Robbins 17, /* 14 T_ALIGNFLT */ 192ea0fabbcSTim J. Robbins LINUX_T_UNKNOWN, /* 15 */ 193ea0fabbcSTim J. Robbins LINUX_T_UNKNOWN, /* 16 */ 194ea0fabbcSTim J. Robbins LINUX_T_UNKNOWN, /* 17 */ 195ea0fabbcSTim J. Robbins 0, /* 18 T_DIVIDE */ 196ea0fabbcSTim J. Robbins 2, /* 19 T_NMI */ 197ea0fabbcSTim J. Robbins 4, /* 20 T_OFLOW */ 198ea0fabbcSTim J. Robbins 5, /* 21 T_BOUND */ 199ea0fabbcSTim J. Robbins 7, /* 22 T_DNA */ 200ea0fabbcSTim J. Robbins 8, /* 23 T_DOUBLEFLT */ 201ea0fabbcSTim J. Robbins 9, /* 24 T_FPOPFLT */ 202ea0fabbcSTim J. Robbins 10, /* 25 T_TSSFLT */ 203ea0fabbcSTim J. Robbins 11, /* 26 T_SEGNPFLT */ 204ea0fabbcSTim J. Robbins 12, /* 27 T_STKFLT */ 205ea0fabbcSTim J. Robbins 18, /* 28 T_MCHK */ 206ea0fabbcSTim J. Robbins 19, /* 29 T_XMMFLT */ 207ea0fabbcSTim J. Robbins 15 /* 30 T_RESERVED */ 208ea0fabbcSTim J. Robbins }; 209ea0fabbcSTim J. Robbins #define bsd_to_linux_trapcode(code) \ 210ea0fabbcSTim J. Robbins ((code)<sizeof(_bsd_to_linux_trapcode)/sizeof(*_bsd_to_linux_trapcode)? \ 211ea0fabbcSTim J. Robbins _bsd_to_linux_trapcode[(code)]: \ 212ea0fabbcSTim J. Robbins LINUX_T_UNKNOWN) 213ea0fabbcSTim J. Robbins 214ea0fabbcSTim J. Robbins struct linux32_ps_strings { 215ea0fabbcSTim J. Robbins u_int32_t ps_argvstr; /* first of 0 or more argument strings */ 216f2c7668eSDavid Schultz u_int ps_nargvstr; /* the number of argument strings */ 217ea0fabbcSTim J. Robbins u_int32_t ps_envstr; /* first of 0 or more environment strings */ 218f2c7668eSDavid Schultz u_int ps_nenvstr; /* the number of environment strings */ 219ea0fabbcSTim J. Robbins }; 220ea0fabbcSTim J. Robbins 221bdc37934SDmitry Chagin LINUX_VDSO_SYM_INTPTR(linux32_sigcode); 222bdc37934SDmitry Chagin LINUX_VDSO_SYM_INTPTR(linux32_rt_sigcode); 223bdc37934SDmitry Chagin LINUX_VDSO_SYM_INTPTR(linux32_vsyscall); 2240020bdf1SDmitry Chagin LINUX_VDSO_SYM_CHAR(linux_platform); 225bdc37934SDmitry Chagin 226ea0fabbcSTim J. Robbins /* 227ea0fabbcSTim J. Robbins * If FreeBSD & Linux have a difference of opinion about what a trap 228ea0fabbcSTim J. Robbins * means, deal with it here. 229ea0fabbcSTim J. Robbins * 230ea0fabbcSTim J. Robbins * MPSAFE 231ea0fabbcSTim J. Robbins */ 232ea0fabbcSTim J. Robbins static int 233ea0fabbcSTim J. Robbins translate_traps(int signal, int trap_code) 234ea0fabbcSTim J. Robbins { 235ea0fabbcSTim J. Robbins if (signal != SIGBUS) 236ea0fabbcSTim J. Robbins return signal; 237ea0fabbcSTim J. Robbins switch (trap_code) { 238ea0fabbcSTim J. Robbins case T_PROTFLT: 239ea0fabbcSTim J. Robbins case T_TSSFLT: 240ea0fabbcSTim J. Robbins case T_DOUBLEFLT: 241ea0fabbcSTim J. Robbins case T_PAGEFLT: 242ea0fabbcSTim J. Robbins return SIGSEGV; 243ea0fabbcSTim J. Robbins default: 244ea0fabbcSTim J. Robbins return signal; 245ea0fabbcSTim J. Robbins } 246ea0fabbcSTim J. Robbins } 247ea0fabbcSTim J. Robbins 248ea0fabbcSTim J. Robbins static int 249ea0fabbcSTim J. Robbins elf_linux_fixup(register_t **stack_base, struct image_params *imgp) 250ea0fabbcSTim J. Robbins { 251ea0fabbcSTim J. Robbins Elf32_Auxargs *args; 252ea0fabbcSTim J. Robbins Elf32_Addr *base; 2530020bdf1SDmitry Chagin Elf32_Addr *pos; 2544d7c2e8aSDmitry Chagin struct linux32_ps_strings *arginfo; 2554d7c2e8aSDmitry Chagin 2564d7c2e8aSDmitry Chagin arginfo = (struct linux32_ps_strings *)LINUX32_PS_STRINGS; 257ea0fabbcSTim J. Robbins 2586617724cSJeff Roberson KASSERT(curthread->td_proc == imgp->proc, 259ea0fabbcSTim J. Robbins ("unsafe elf_linux_fixup(), should be curproc")); 260ea0fabbcSTim J. Robbins base = (Elf32_Addr *)*stack_base; 261ea0fabbcSTim J. Robbins args = (Elf32_Auxargs *)imgp->auxargs; 262610ecfe0SMaxim Sobolev pos = base + (imgp->args->argc + imgp->args->envc + 2); 263ea0fabbcSTim J. Robbins 264bdc37934SDmitry Chagin AUXARGS_ENTRY_32(pos, LINUX_AT_SYSINFO_EHDR, 265bdc37934SDmitry Chagin imgp->proc->p_sysent->sv_shared_page_base); 266bdc37934SDmitry Chagin AUXARGS_ENTRY_32(pos, LINUX_AT_SYSINFO, linux32_vsyscall); 2674d7c2e8aSDmitry Chagin AUXARGS_ENTRY_32(pos, LINUX_AT_HWCAP, cpu_feature); 2688d30f381SDmitry Chagin 2698d30f381SDmitry Chagin /* 2708d30f381SDmitry Chagin * Do not export AT_CLKTCK when emulating Linux kernel prior to 2.4.0, 2718d30f381SDmitry Chagin * as it has appeared in the 2.4.0-rc7 first time. 2728d30f381SDmitry Chagin * Being exported, AT_CLKTCK is returned by sysconf(_SC_CLK_TCK), 2738d30f381SDmitry Chagin * glibc falls back to the hard-coded CLK_TCK value when aux entry 2748d30f381SDmitry Chagin * is not present. 2758d30f381SDmitry Chagin * Also see linux_times() implementation. 2768d30f381SDmitry Chagin */ 2778d30f381SDmitry Chagin if (linux_kernver(curthread) >= LINUX_KERNVER_2004000) 2781ca16454SDmitry Chagin AUXARGS_ENTRY_32(pos, LINUX_AT_CLKTCK, stclohz); 279ea0fabbcSTim J. Robbins AUXARGS_ENTRY_32(pos, AT_PHDR, args->phdr); 280ea0fabbcSTim J. Robbins AUXARGS_ENTRY_32(pos, AT_PHENT, args->phent); 281ea0fabbcSTim J. Robbins AUXARGS_ENTRY_32(pos, AT_PHNUM, args->phnum); 282ea0fabbcSTim J. Robbins AUXARGS_ENTRY_32(pos, AT_PAGESZ, args->pagesz); 283ea0fabbcSTim J. Robbins AUXARGS_ENTRY_32(pos, AT_FLAGS, args->flags); 284ea0fabbcSTim J. Robbins AUXARGS_ENTRY_32(pos, AT_ENTRY, args->entry); 285ea0fabbcSTim J. Robbins AUXARGS_ENTRY_32(pos, AT_BASE, args->base); 2864d7c2e8aSDmitry Chagin AUXARGS_ENTRY_32(pos, LINUX_AT_SECURE, 0); 287ea0fabbcSTim J. Robbins AUXARGS_ENTRY_32(pos, AT_UID, imgp->proc->p_ucred->cr_ruid); 288ea0fabbcSTim J. Robbins AUXARGS_ENTRY_32(pos, AT_EUID, imgp->proc->p_ucred->cr_svuid); 289ea0fabbcSTim J. Robbins AUXARGS_ENTRY_32(pos, AT_GID, imgp->proc->p_ucred->cr_rgid); 290ea0fabbcSTim J. Robbins AUXARGS_ENTRY_32(pos, AT_EGID, imgp->proc->p_ucred->cr_svgid); 2910020bdf1SDmitry Chagin AUXARGS_ENTRY_32(pos, LINUX_AT_PLATFORM, PTROUT(linux_platform)); 292*4048f59cSDmitry Chagin AUXARGS_ENTRY(pos, LINUX_AT_RANDOM, PTROUT(imgp->canary)); 293*4048f59cSDmitry Chagin if (imgp->execpathp != 0) 294*4048f59cSDmitry Chagin AUXARGS_ENTRY(pos, LINUX_AT_EXECFN, PTROUT(imgp->execpathp)); 2954d7c2e8aSDmitry Chagin if (args->execfd != -1) 2964d7c2e8aSDmitry Chagin AUXARGS_ENTRY_32(pos, AT_EXECFD, args->execfd); 297ea0fabbcSTim J. Robbins AUXARGS_ENTRY_32(pos, AT_NULL, 0); 298ea0fabbcSTim J. Robbins 299ea0fabbcSTim J. Robbins free(imgp->auxargs, M_TEMP); 300ea0fabbcSTim J. Robbins imgp->auxargs = NULL; 301ea0fabbcSTim J. Robbins 302ea0fabbcSTim J. Robbins base--; 303610ecfe0SMaxim Sobolev suword32(base, (uint32_t)imgp->args->argc); 304ea0fabbcSTim J. Robbins *stack_base = (register_t *)base; 305af682d48SDmitry Chagin return (0); 306ea0fabbcSTim J. Robbins } 307ea0fabbcSTim J. Robbins 308ea0fabbcSTim J. Robbins static void 3099104847fSDavid Xu linux_rt_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) 310ea0fabbcSTim J. Robbins { 311ea0fabbcSTim J. Robbins struct thread *td = curthread; 312ea0fabbcSTim J. Robbins struct proc *p = td->td_proc; 313ea0fabbcSTim J. Robbins struct sigacts *psp; 314ea0fabbcSTim J. Robbins struct trapframe *regs; 315ea0fabbcSTim J. Robbins struct l_rt_sigframe *fp, frame; 316ea0fabbcSTim J. Robbins int oonstack; 3179104847fSDavid Xu int sig; 3189104847fSDavid Xu int code; 319ea0fabbcSTim J. Robbins 3209104847fSDavid Xu sig = ksi->ksi_signo; 3219104847fSDavid Xu code = ksi->ksi_code; 322ea0fabbcSTim J. Robbins PROC_LOCK_ASSERT(p, MA_OWNED); 323ea0fabbcSTim J. Robbins psp = p->p_sigacts; 324ea0fabbcSTim J. Robbins mtx_assert(&psp->ps_mtx, MA_OWNED); 325ea0fabbcSTim J. Robbins regs = td->td_frame; 326ea0fabbcSTim J. Robbins oonstack = sigonstack(regs->tf_rsp); 327ea0fabbcSTim J. Robbins 328ea0fabbcSTim J. Robbins #ifdef DEBUG 329ea0fabbcSTim J. Robbins if (ldebug(rt_sendsig)) 330728ef954SJohn Baldwin printf(ARGS(rt_sendsig, "%p, %d, %p, %u"), 331ea0fabbcSTim J. Robbins catcher, sig, (void*)mask, code); 332ea0fabbcSTim J. Robbins #endif 333ea0fabbcSTim J. Robbins /* 334ea0fabbcSTim J. Robbins * Allocate space for the signal handler context. 335ea0fabbcSTim J. Robbins */ 336ea0fabbcSTim J. Robbins if ((td->td_pflags & TDP_ALTSTACK) && !oonstack && 337ea0fabbcSTim J. Robbins SIGISMEMBER(psp->ps_sigonstack, sig)) { 338ea0fabbcSTim J. Robbins fp = (struct l_rt_sigframe *)(td->td_sigstk.ss_sp + 339ea0fabbcSTim J. Robbins td->td_sigstk.ss_size - sizeof(struct l_rt_sigframe)); 340ea0fabbcSTim J. Robbins } else 341ea0fabbcSTim J. Robbins fp = (struct l_rt_sigframe *)regs->tf_rsp - 1; 342ea0fabbcSTim J. Robbins mtx_unlock(&psp->ps_mtx); 343ea0fabbcSTim J. Robbins 344ea0fabbcSTim J. Robbins /* 345ea0fabbcSTim J. Robbins * Build the argument list for the signal handler. 346ea0fabbcSTim J. Robbins */ 347ea0fabbcSTim J. Robbins if (p->p_sysent->sv_sigtbl) 348ea0fabbcSTim J. Robbins if (sig <= p->p_sysent->sv_sigsize) 349ea0fabbcSTim J. Robbins sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)]; 350ea0fabbcSTim J. Robbins 351ea0fabbcSTim J. Robbins bzero(&frame, sizeof(frame)); 352ea0fabbcSTim J. Robbins 353ea0fabbcSTim J. Robbins frame.sf_handler = PTROUT(catcher); 354ea0fabbcSTim J. Robbins frame.sf_sig = sig; 355ea0fabbcSTim J. Robbins frame.sf_siginfo = PTROUT(&fp->sf_si); 356ea0fabbcSTim J. Robbins frame.sf_ucontext = PTROUT(&fp->sf_sc); 357ea0fabbcSTim J. Robbins 358ea0fabbcSTim J. Robbins /* Fill in POSIX parts */ 359aa8b2011SKonstantin Belousov ksiginfo_to_lsiginfo(ksi, &frame.sf_si, sig); 360ea0fabbcSTim J. Robbins 361ea0fabbcSTim J. Robbins /* 362bdc37934SDmitry Chagin * Build the signal context to be used by sigreturn 363bdc37934SDmitry Chagin * and libgcc unwind. 364ea0fabbcSTim J. Robbins */ 365ea0fabbcSTim J. Robbins frame.sf_sc.uc_flags = 0; /* XXX ??? */ 366ea0fabbcSTim J. Robbins frame.sf_sc.uc_link = 0; /* XXX ??? */ 367ea0fabbcSTim J. Robbins 368ea0fabbcSTim J. Robbins frame.sf_sc.uc_stack.ss_sp = PTROUT(td->td_sigstk.ss_sp); 369ea0fabbcSTim J. Robbins frame.sf_sc.uc_stack.ss_size = td->td_sigstk.ss_size; 370ea0fabbcSTim J. Robbins frame.sf_sc.uc_stack.ss_flags = (td->td_pflags & TDP_ALTSTACK) 371ea0fabbcSTim J. Robbins ? ((oonstack) ? LINUX_SS_ONSTACK : 0) : LINUX_SS_DISABLE; 372ea0fabbcSTim J. Robbins PROC_UNLOCK(p); 373ea0fabbcSTim J. Robbins 374ea0fabbcSTim J. Robbins bsd_to_linux_sigset(mask, &frame.sf_sc.uc_sigmask); 375ea0fabbcSTim J. Robbins 376ea0fabbcSTim J. Robbins frame.sf_sc.uc_mcontext.sc_mask = frame.sf_sc.uc_sigmask.__bits[0]; 377ea0fabbcSTim J. Robbins frame.sf_sc.uc_mcontext.sc_edi = regs->tf_rdi; 378ea0fabbcSTim J. Robbins frame.sf_sc.uc_mcontext.sc_esi = regs->tf_rsi; 379ea0fabbcSTim J. Robbins frame.sf_sc.uc_mcontext.sc_ebp = regs->tf_rbp; 380ea0fabbcSTim J. Robbins frame.sf_sc.uc_mcontext.sc_ebx = regs->tf_rbx; 381bdc37934SDmitry Chagin frame.sf_sc.uc_mcontext.sc_esp = regs->tf_rsp; 382ea0fabbcSTim J. Robbins frame.sf_sc.uc_mcontext.sc_edx = regs->tf_rdx; 383ea0fabbcSTim J. Robbins frame.sf_sc.uc_mcontext.sc_ecx = regs->tf_rcx; 384ea0fabbcSTim J. Robbins frame.sf_sc.uc_mcontext.sc_eax = regs->tf_rax; 385ea0fabbcSTim J. Robbins frame.sf_sc.uc_mcontext.sc_eip = regs->tf_rip; 386ea0fabbcSTim J. Robbins frame.sf_sc.uc_mcontext.sc_cs = regs->tf_cs; 3872c66cccaSKonstantin Belousov frame.sf_sc.uc_mcontext.sc_gs = regs->tf_gs; 3882c66cccaSKonstantin Belousov frame.sf_sc.uc_mcontext.sc_fs = regs->tf_fs; 3892c66cccaSKonstantin Belousov frame.sf_sc.uc_mcontext.sc_es = regs->tf_es; 3902c66cccaSKonstantin Belousov frame.sf_sc.uc_mcontext.sc_ds = regs->tf_ds; 391ea0fabbcSTim J. Robbins frame.sf_sc.uc_mcontext.sc_eflags = regs->tf_rflags; 392ea0fabbcSTim J. Robbins frame.sf_sc.uc_mcontext.sc_esp_at_signal = regs->tf_rsp; 393ea0fabbcSTim J. Robbins frame.sf_sc.uc_mcontext.sc_ss = regs->tf_ss; 394ea0fabbcSTim J. Robbins frame.sf_sc.uc_mcontext.sc_err = regs->tf_err; 39596a2b635SKonstantin Belousov frame.sf_sc.uc_mcontext.sc_cr2 = (u_int32_t)(uintptr_t)ksi->ksi_addr; 396ea0fabbcSTim J. Robbins frame.sf_sc.uc_mcontext.sc_trapno = bsd_to_linux_trapcode(code); 397ea0fabbcSTim J. Robbins 398ea0fabbcSTim J. Robbins #ifdef DEBUG 399ea0fabbcSTim J. Robbins if (ldebug(rt_sendsig)) 400c680f6b1SDavid E. O'Brien printf(LMSG("rt_sendsig flags: 0x%x, sp: %p, ss: 0x%lx, mask: 0x%x"), 401ea0fabbcSTim J. Robbins frame.sf_sc.uc_stack.ss_flags, td->td_sigstk.ss_sp, 402ea0fabbcSTim J. Robbins td->td_sigstk.ss_size, frame.sf_sc.uc_mcontext.sc_mask); 403ea0fabbcSTim J. Robbins #endif 404ea0fabbcSTim J. Robbins 405ea0fabbcSTim J. Robbins if (copyout(&frame, fp, sizeof(frame)) != 0) { 406ea0fabbcSTim J. Robbins /* 407ea0fabbcSTim J. Robbins * Process has trashed its stack; give it an illegal 408ea0fabbcSTim J. Robbins * instruction to halt it in its tracks. 409ea0fabbcSTim J. Robbins */ 410ea0fabbcSTim J. Robbins #ifdef DEBUG 411ea0fabbcSTim J. Robbins if (ldebug(rt_sendsig)) 412ea0fabbcSTim J. Robbins printf(LMSG("rt_sendsig: bad stack %p, oonstack=%x"), 413ea0fabbcSTim J. Robbins fp, oonstack); 414ea0fabbcSTim J. Robbins #endif 415ea0fabbcSTim J. Robbins PROC_LOCK(p); 416ea0fabbcSTim J. Robbins sigexit(td, SIGILL); 417ea0fabbcSTim J. Robbins } 418ea0fabbcSTim J. Robbins 419ea0fabbcSTim J. Robbins /* 420ea0fabbcSTim J. Robbins * Build context to run handler in. 421ea0fabbcSTim J. Robbins */ 422ea0fabbcSTim J. Robbins regs->tf_rsp = PTROUT(fp); 423bdc37934SDmitry Chagin regs->tf_rip = linux32_rt_sigcode; 42422eca0bfSKonstantin Belousov regs->tf_rflags &= ~(PSL_T | PSL_D); 425ea0fabbcSTim J. Robbins regs->tf_cs = _ucode32sel; 426ea0fabbcSTim J. Robbins regs->tf_ss = _udatasel; 4272c66cccaSKonstantin Belousov regs->tf_ds = _udatasel; 4282c66cccaSKonstantin Belousov regs->tf_es = _udatasel; 4292c66cccaSKonstantin Belousov regs->tf_fs = _ufssel; 4302c66cccaSKonstantin Belousov regs->tf_gs = _ugssel; 4312c66cccaSKonstantin Belousov regs->tf_flags = TF_HASSEGS; 432e6c006d9SJung-uk Kim set_pcb_flags(td->td_pcb, PCB_FULL_IRET); 433ea0fabbcSTim J. Robbins PROC_LOCK(p); 434ea0fabbcSTim J. Robbins mtx_lock(&psp->ps_mtx); 435ea0fabbcSTim J. Robbins } 436ea0fabbcSTim J. Robbins 437ea0fabbcSTim J. Robbins 438ea0fabbcSTim J. Robbins /* 439ea0fabbcSTim J. Robbins * Send an interrupt to process. 440ea0fabbcSTim J. Robbins * 441ea0fabbcSTim J. Robbins * Stack is set up to allow sigcode stored 442ea0fabbcSTim J. Robbins * in u. to call routine, followed by kcall 443ea0fabbcSTim J. Robbins * to sigreturn routine below. After sigreturn 444ea0fabbcSTim J. Robbins * resets the signal mask, the stack, and the 445ea0fabbcSTim J. Robbins * frame pointer, it returns to the user 446ea0fabbcSTim J. Robbins * specified pc, psl. 447ea0fabbcSTim J. Robbins */ 448ea0fabbcSTim J. Robbins static void 4499104847fSDavid Xu linux_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) 450ea0fabbcSTim J. Robbins { 451ea0fabbcSTim J. Robbins struct thread *td = curthread; 452ea0fabbcSTim J. Robbins struct proc *p = td->td_proc; 453ea0fabbcSTim J. Robbins struct sigacts *psp; 454ea0fabbcSTim J. Robbins struct trapframe *regs; 455ea0fabbcSTim J. Robbins struct l_sigframe *fp, frame; 456ea0fabbcSTim J. Robbins l_sigset_t lmask; 457ea0fabbcSTim J. Robbins int oonstack, i; 4589104847fSDavid Xu int sig, code; 459ea0fabbcSTim J. Robbins 4609104847fSDavid Xu sig = ksi->ksi_signo; 4619104847fSDavid Xu code = ksi->ksi_code; 462ea0fabbcSTim J. Robbins PROC_LOCK_ASSERT(p, MA_OWNED); 463ea0fabbcSTim J. Robbins psp = p->p_sigacts; 464ea0fabbcSTim J. Robbins mtx_assert(&psp->ps_mtx, MA_OWNED); 465ea0fabbcSTim J. Robbins if (SIGISMEMBER(psp->ps_siginfo, sig)) { 466ea0fabbcSTim J. Robbins /* Signal handler installed with SA_SIGINFO. */ 4679104847fSDavid Xu linux_rt_sendsig(catcher, ksi, mask); 468ea0fabbcSTim J. Robbins return; 469ea0fabbcSTim J. Robbins } 470ea0fabbcSTim J. Robbins 471ea0fabbcSTim J. Robbins regs = td->td_frame; 472ea0fabbcSTim J. Robbins oonstack = sigonstack(regs->tf_rsp); 473ea0fabbcSTim J. Robbins 474ea0fabbcSTim J. Robbins #ifdef DEBUG 475ea0fabbcSTim J. Robbins if (ldebug(sendsig)) 476728ef954SJohn Baldwin printf(ARGS(sendsig, "%p, %d, %p, %u"), 477ea0fabbcSTim J. Robbins catcher, sig, (void*)mask, code); 478ea0fabbcSTim J. Robbins #endif 479ea0fabbcSTim J. Robbins 480ea0fabbcSTim J. Robbins /* 481ea0fabbcSTim J. Robbins * Allocate space for the signal handler context. 482ea0fabbcSTim J. Robbins */ 483ea0fabbcSTim J. Robbins if ((td->td_pflags & TDP_ALTSTACK) && !oonstack && 484ea0fabbcSTim J. Robbins SIGISMEMBER(psp->ps_sigonstack, sig)) { 485ea0fabbcSTim J. Robbins fp = (struct l_sigframe *)(td->td_sigstk.ss_sp + 486ea0fabbcSTim J. Robbins td->td_sigstk.ss_size - sizeof(struct l_sigframe)); 487ea0fabbcSTim J. Robbins } else 488ea0fabbcSTim J. Robbins fp = (struct l_sigframe *)regs->tf_rsp - 1; 489ea0fabbcSTim J. Robbins mtx_unlock(&psp->ps_mtx); 490ea0fabbcSTim J. Robbins PROC_UNLOCK(p); 491ea0fabbcSTim J. Robbins 492ea0fabbcSTim J. Robbins /* 493ea0fabbcSTim J. Robbins * Build the argument list for the signal handler. 494ea0fabbcSTim J. Robbins */ 495ea0fabbcSTim J. Robbins if (p->p_sysent->sv_sigtbl) 496ea0fabbcSTim J. Robbins if (sig <= p->p_sysent->sv_sigsize) 497ea0fabbcSTim J. Robbins sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)]; 498ea0fabbcSTim J. Robbins 499ea0fabbcSTim J. Robbins bzero(&frame, sizeof(frame)); 500ea0fabbcSTim J. Robbins 501ea0fabbcSTim J. Robbins frame.sf_handler = PTROUT(catcher); 502ea0fabbcSTim J. Robbins frame.sf_sig = sig; 503ea0fabbcSTim J. Robbins 504ea0fabbcSTim J. Robbins bsd_to_linux_sigset(mask, &lmask); 505ea0fabbcSTim J. Robbins 506ea0fabbcSTim J. Robbins /* 507ea0fabbcSTim J. Robbins * Build the signal context to be used by sigreturn. 508ea0fabbcSTim J. Robbins */ 509ea0fabbcSTim J. Robbins frame.sf_sc.sc_mask = lmask.__bits[0]; 5102c66cccaSKonstantin Belousov frame.sf_sc.sc_gs = regs->tf_gs; 5112c66cccaSKonstantin Belousov frame.sf_sc.sc_fs = regs->tf_fs; 5122c66cccaSKonstantin Belousov frame.sf_sc.sc_es = regs->tf_es; 5132c66cccaSKonstantin Belousov frame.sf_sc.sc_ds = regs->tf_ds; 514ea0fabbcSTim J. Robbins frame.sf_sc.sc_edi = regs->tf_rdi; 515ea0fabbcSTim J. Robbins frame.sf_sc.sc_esi = regs->tf_rsi; 516ea0fabbcSTim J. Robbins frame.sf_sc.sc_ebp = regs->tf_rbp; 517ea0fabbcSTim J. Robbins frame.sf_sc.sc_ebx = regs->tf_rbx; 518bdc37934SDmitry Chagin frame.sf_sc.sc_esp = regs->tf_rsp; 519ea0fabbcSTim J. Robbins frame.sf_sc.sc_edx = regs->tf_rdx; 520ea0fabbcSTim J. Robbins frame.sf_sc.sc_ecx = regs->tf_rcx; 521ea0fabbcSTim J. Robbins frame.sf_sc.sc_eax = regs->tf_rax; 522ea0fabbcSTim J. Robbins frame.sf_sc.sc_eip = regs->tf_rip; 523ea0fabbcSTim J. Robbins frame.sf_sc.sc_cs = regs->tf_cs; 524ea0fabbcSTim J. Robbins frame.sf_sc.sc_eflags = regs->tf_rflags; 525ea0fabbcSTim J. Robbins frame.sf_sc.sc_esp_at_signal = regs->tf_rsp; 526ea0fabbcSTim J. Robbins frame.sf_sc.sc_ss = regs->tf_ss; 527ea0fabbcSTim J. Robbins frame.sf_sc.sc_err = regs->tf_err; 52896a2b635SKonstantin Belousov frame.sf_sc.sc_cr2 = (u_int32_t)(uintptr_t)ksi->ksi_addr; 529ea0fabbcSTim J. Robbins frame.sf_sc.sc_trapno = bsd_to_linux_trapcode(code); 530ea0fabbcSTim J. Robbins 531ea0fabbcSTim J. Robbins for (i = 0; i < (LINUX_NSIG_WORDS-1); i++) 532ea0fabbcSTim J. Robbins frame.sf_extramask[i] = lmask.__bits[i+1]; 533ea0fabbcSTim J. Robbins 534ea0fabbcSTim J. Robbins if (copyout(&frame, fp, sizeof(frame)) != 0) { 535ea0fabbcSTim J. Robbins /* 536ea0fabbcSTim J. Robbins * Process has trashed its stack; give it an illegal 537ea0fabbcSTim J. Robbins * instruction to halt it in its tracks. 538ea0fabbcSTim J. Robbins */ 539ea0fabbcSTim J. Robbins PROC_LOCK(p); 540ea0fabbcSTim J. Robbins sigexit(td, SIGILL); 541ea0fabbcSTim J. Robbins } 542ea0fabbcSTim J. Robbins 543ea0fabbcSTim J. Robbins /* 544ea0fabbcSTim J. Robbins * Build context to run handler in. 545ea0fabbcSTim J. Robbins */ 546ea0fabbcSTim J. Robbins regs->tf_rsp = PTROUT(fp); 547bdc37934SDmitry Chagin regs->tf_rip = linux32_sigcode; 54822eca0bfSKonstantin Belousov regs->tf_rflags &= ~(PSL_T | PSL_D); 549ea0fabbcSTim J. Robbins regs->tf_cs = _ucode32sel; 550ea0fabbcSTim J. Robbins regs->tf_ss = _udatasel; 5512c66cccaSKonstantin Belousov regs->tf_ds = _udatasel; 5522c66cccaSKonstantin Belousov regs->tf_es = _udatasel; 5532c66cccaSKonstantin Belousov regs->tf_fs = _ufssel; 5542c66cccaSKonstantin Belousov regs->tf_gs = _ugssel; 5552c66cccaSKonstantin Belousov regs->tf_flags = TF_HASSEGS; 556e6c006d9SJung-uk Kim set_pcb_flags(td->td_pcb, PCB_FULL_IRET); 557ea0fabbcSTim J. Robbins PROC_LOCK(p); 558ea0fabbcSTim J. Robbins mtx_lock(&psp->ps_mtx); 559ea0fabbcSTim J. Robbins } 560ea0fabbcSTim J. Robbins 561ea0fabbcSTim J. Robbins /* 562ea0fabbcSTim J. Robbins * System call to cleanup state after a signal 563ea0fabbcSTim J. Robbins * has been taken. Reset signal mask and 564ea0fabbcSTim J. Robbins * stack state from context left by sendsig (above). 565ea0fabbcSTim J. Robbins * Return to previous pc and psl as specified by 566ea0fabbcSTim J. Robbins * context left by sendsig. Check carefully to 567ea0fabbcSTim J. Robbins * make sure that the user has not modified the 568ea0fabbcSTim J. Robbins * psl to gain improper privileges or to cause 569ea0fabbcSTim J. Robbins * a machine fault. 570ea0fabbcSTim J. Robbins */ 571ea0fabbcSTim J. Robbins int 572ea0fabbcSTim J. Robbins linux_sigreturn(struct thread *td, struct linux_sigreturn_args *args) 573ea0fabbcSTim J. Robbins { 574ea0fabbcSTim J. Robbins struct l_sigframe frame; 575ea0fabbcSTim J. Robbins struct trapframe *regs; 576d6e029adSKonstantin Belousov sigset_t bmask; 577ea0fabbcSTim J. Robbins l_sigset_t lmask; 578ea0fabbcSTim J. Robbins int eflags, i; 5799104847fSDavid Xu ksiginfo_t ksi; 580ea0fabbcSTim J. Robbins 581ea0fabbcSTim J. Robbins regs = td->td_frame; 582ea0fabbcSTim J. Robbins 583ea0fabbcSTim J. Robbins #ifdef DEBUG 584ea0fabbcSTim J. Robbins if (ldebug(sigreturn)) 585ea0fabbcSTim J. Robbins printf(ARGS(sigreturn, "%p"), (void *)args->sfp); 586ea0fabbcSTim J. Robbins #endif 587ea0fabbcSTim J. Robbins /* 588ea0fabbcSTim J. Robbins * The trampoline code hands us the sigframe. 589ea0fabbcSTim J. Robbins * It is unsafe to keep track of it ourselves, in the event that a 590ea0fabbcSTim J. Robbins * program jumps out of a signal handler. 591ea0fabbcSTim J. Robbins */ 592ea0fabbcSTim J. Robbins if (copyin(args->sfp, &frame, sizeof(frame)) != 0) 593ea0fabbcSTim J. Robbins return (EFAULT); 594ea0fabbcSTim J. Robbins 595ea0fabbcSTim J. Robbins /* 596ea0fabbcSTim J. Robbins * Check for security violations. 597ea0fabbcSTim J. Robbins */ 598ea0fabbcSTim J. Robbins #define EFLAGS_SECURE(ef, oef) ((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0) 599ea0fabbcSTim J. Robbins eflags = frame.sf_sc.sc_eflags; 6003d271aaaSEd Maste if (!EFLAGS_SECURE(eflags, regs->tf_rflags)) 601ea0fabbcSTim J. Robbins return(EINVAL); 602ea0fabbcSTim J. Robbins 603ea0fabbcSTim J. Robbins /* 604ea0fabbcSTim J. Robbins * Don't allow users to load a valid privileged %cs. Let the 605ea0fabbcSTim J. Robbins * hardware check for invalid selectors, excess privilege in 606ea0fabbcSTim J. Robbins * other selectors, invalid %eip's and invalid %esp's. 607ea0fabbcSTim J. Robbins */ 608ea0fabbcSTim J. Robbins #define CS_SECURE(cs) (ISPL(cs) == SEL_UPL) 609ea0fabbcSTim J. Robbins if (!CS_SECURE(frame.sf_sc.sc_cs)) { 6109104847fSDavid Xu ksiginfo_init_trap(&ksi); 6119104847fSDavid Xu ksi.ksi_signo = SIGBUS; 6129104847fSDavid Xu ksi.ksi_code = BUS_OBJERR; 6139104847fSDavid Xu ksi.ksi_trapno = T_PROTFLT; 6149104847fSDavid Xu ksi.ksi_addr = (void *)regs->tf_rip; 6159104847fSDavid Xu trapsignal(td, &ksi); 616ea0fabbcSTim J. Robbins return(EINVAL); 617ea0fabbcSTim J. Robbins } 618ea0fabbcSTim J. Robbins 619ea0fabbcSTim J. Robbins lmask.__bits[0] = frame.sf_sc.sc_mask; 620ea0fabbcSTim J. Robbins for (i = 0; i < (LINUX_NSIG_WORDS-1); i++) 621ea0fabbcSTim J. Robbins lmask.__bits[i+1] = frame.sf_extramask[i]; 622d6e029adSKonstantin Belousov linux_to_bsd_sigset(&lmask, &bmask); 623d6e029adSKonstantin Belousov kern_sigprocmask(td, SIG_SETMASK, &bmask, NULL, 0); 624ea0fabbcSTim J. Robbins 625ea0fabbcSTim J. Robbins /* 626ea0fabbcSTim J. Robbins * Restore signal context. 627ea0fabbcSTim J. Robbins */ 628ea0fabbcSTim J. Robbins regs->tf_rdi = frame.sf_sc.sc_edi; 629ea0fabbcSTim J. Robbins regs->tf_rsi = frame.sf_sc.sc_esi; 630ea0fabbcSTim J. Robbins regs->tf_rbp = frame.sf_sc.sc_ebp; 631ea0fabbcSTim J. Robbins regs->tf_rbx = frame.sf_sc.sc_ebx; 632ea0fabbcSTim J. Robbins regs->tf_rdx = frame.sf_sc.sc_edx; 633ea0fabbcSTim J. Robbins regs->tf_rcx = frame.sf_sc.sc_ecx; 634ea0fabbcSTim J. Robbins regs->tf_rax = frame.sf_sc.sc_eax; 635ea0fabbcSTim J. Robbins regs->tf_rip = frame.sf_sc.sc_eip; 636ea0fabbcSTim J. Robbins regs->tf_cs = frame.sf_sc.sc_cs; 6372c66cccaSKonstantin Belousov regs->tf_ds = frame.sf_sc.sc_ds; 6382c66cccaSKonstantin Belousov regs->tf_es = frame.sf_sc.sc_es; 6392c66cccaSKonstantin Belousov regs->tf_fs = frame.sf_sc.sc_fs; 6402c66cccaSKonstantin Belousov regs->tf_gs = frame.sf_sc.sc_gs; 641ea0fabbcSTim J. Robbins regs->tf_rflags = eflags; 642ea0fabbcSTim J. Robbins regs->tf_rsp = frame.sf_sc.sc_esp_at_signal; 643ea0fabbcSTim J. Robbins regs->tf_ss = frame.sf_sc.sc_ss; 644e6c006d9SJung-uk Kim set_pcb_flags(td->td_pcb, PCB_FULL_IRET); 645ea0fabbcSTim J. Robbins 646ea0fabbcSTim J. Robbins return (EJUSTRETURN); 647ea0fabbcSTim J. Robbins } 648ea0fabbcSTim J. Robbins 649ea0fabbcSTim J. Robbins /* 650ea0fabbcSTim J. Robbins * System call to cleanup state after a signal 651ea0fabbcSTim J. Robbins * has been taken. Reset signal mask and 652ea0fabbcSTim J. Robbins * stack state from context left by rt_sendsig (above). 653ea0fabbcSTim J. Robbins * Return to previous pc and psl as specified by 654ea0fabbcSTim J. Robbins * context left by sendsig. Check carefully to 655ea0fabbcSTim J. Robbins * make sure that the user has not modified the 656ea0fabbcSTim J. Robbins * psl to gain improper privileges or to cause 657ea0fabbcSTim J. Robbins * a machine fault. 658ea0fabbcSTim J. Robbins */ 659ea0fabbcSTim J. Robbins int 660ea0fabbcSTim J. Robbins linux_rt_sigreturn(struct thread *td, struct linux_rt_sigreturn_args *args) 661ea0fabbcSTim J. Robbins { 662ea0fabbcSTim J. Robbins struct l_ucontext uc; 663ea0fabbcSTim J. Robbins struct l_sigcontext *context; 664d6e029adSKonstantin Belousov sigset_t bmask; 665ea0fabbcSTim J. Robbins l_stack_t *lss; 666ea0fabbcSTim J. Robbins stack_t ss; 667ea0fabbcSTim J. Robbins struct trapframe *regs; 668ea0fabbcSTim J. Robbins int eflags; 6699104847fSDavid Xu ksiginfo_t ksi; 670ea0fabbcSTim J. Robbins 671ea0fabbcSTim J. Robbins regs = td->td_frame; 672ea0fabbcSTim J. Robbins 673ea0fabbcSTim J. Robbins #ifdef DEBUG 674ea0fabbcSTim J. Robbins if (ldebug(rt_sigreturn)) 675ea0fabbcSTim J. Robbins printf(ARGS(rt_sigreturn, "%p"), (void *)args->ucp); 676ea0fabbcSTim J. Robbins #endif 677ea0fabbcSTim J. Robbins /* 678ea0fabbcSTim J. Robbins * The trampoline code hands us the ucontext. 679ea0fabbcSTim J. Robbins * It is unsafe to keep track of it ourselves, in the event that a 680ea0fabbcSTim J. Robbins * program jumps out of a signal handler. 681ea0fabbcSTim J. Robbins */ 682ea0fabbcSTim J. Robbins if (copyin(args->ucp, &uc, sizeof(uc)) != 0) 683ea0fabbcSTim J. Robbins return (EFAULT); 684ea0fabbcSTim J. Robbins 685ea0fabbcSTim J. Robbins context = &uc.uc_mcontext; 686ea0fabbcSTim J. Robbins 687ea0fabbcSTim J. Robbins /* 688ea0fabbcSTim J. Robbins * Check for security violations. 689ea0fabbcSTim J. Robbins */ 690ea0fabbcSTim J. Robbins #define EFLAGS_SECURE(ef, oef) ((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0) 691ea0fabbcSTim J. Robbins eflags = context->sc_eflags; 6923d271aaaSEd Maste if (!EFLAGS_SECURE(eflags, regs->tf_rflags)) 693ea0fabbcSTim J. Robbins return(EINVAL); 694ea0fabbcSTim J. Robbins 695ea0fabbcSTim J. Robbins /* 696ea0fabbcSTim J. Robbins * Don't allow users to load a valid privileged %cs. Let the 697ea0fabbcSTim J. Robbins * hardware check for invalid selectors, excess privilege in 698ea0fabbcSTim J. Robbins * other selectors, invalid %eip's and invalid %esp's. 699ea0fabbcSTim J. Robbins */ 700ea0fabbcSTim J. Robbins #define CS_SECURE(cs) (ISPL(cs) == SEL_UPL) 701ea0fabbcSTim J. Robbins if (!CS_SECURE(context->sc_cs)) { 7029104847fSDavid Xu ksiginfo_init_trap(&ksi); 7039104847fSDavid Xu ksi.ksi_signo = SIGBUS; 7049104847fSDavid Xu ksi.ksi_code = BUS_OBJERR; 7059104847fSDavid Xu ksi.ksi_trapno = T_PROTFLT; 7069104847fSDavid Xu ksi.ksi_addr = (void *)regs->tf_rip; 7079104847fSDavid Xu trapsignal(td, &ksi); 708ea0fabbcSTim J. Robbins return(EINVAL); 709ea0fabbcSTim J. Robbins } 710ea0fabbcSTim J. Robbins 711d6e029adSKonstantin Belousov linux_to_bsd_sigset(&uc.uc_sigmask, &bmask); 712d6e029adSKonstantin Belousov kern_sigprocmask(td, SIG_SETMASK, &bmask, NULL, 0); 713ea0fabbcSTim J. Robbins 714ea0fabbcSTim J. Robbins /* 715ea0fabbcSTim J. Robbins * Restore signal context 716ea0fabbcSTim J. Robbins */ 7172c66cccaSKonstantin Belousov regs->tf_gs = context->sc_gs; 7182c66cccaSKonstantin Belousov regs->tf_fs = context->sc_fs; 7192c66cccaSKonstantin Belousov regs->tf_es = context->sc_es; 7202c66cccaSKonstantin Belousov regs->tf_ds = context->sc_ds; 721ea0fabbcSTim J. Robbins regs->tf_rdi = context->sc_edi; 722ea0fabbcSTim J. Robbins regs->tf_rsi = context->sc_esi; 723ea0fabbcSTim J. Robbins regs->tf_rbp = context->sc_ebp; 724ea0fabbcSTim J. Robbins regs->tf_rbx = context->sc_ebx; 725ea0fabbcSTim J. Robbins regs->tf_rdx = context->sc_edx; 726ea0fabbcSTim J. Robbins regs->tf_rcx = context->sc_ecx; 727ea0fabbcSTim J. Robbins regs->tf_rax = context->sc_eax; 728ea0fabbcSTim J. Robbins regs->tf_rip = context->sc_eip; 729ea0fabbcSTim J. Robbins regs->tf_cs = context->sc_cs; 730ea0fabbcSTim J. Robbins regs->tf_rflags = eflags; 731ea0fabbcSTim J. Robbins regs->tf_rsp = context->sc_esp_at_signal; 732ea0fabbcSTim J. Robbins regs->tf_ss = context->sc_ss; 733e6c006d9SJung-uk Kim set_pcb_flags(td->td_pcb, PCB_FULL_IRET); 734ea0fabbcSTim J. Robbins 735ea0fabbcSTim J. Robbins /* 736ea0fabbcSTim J. Robbins * call sigaltstack & ignore results.. 737ea0fabbcSTim J. Robbins */ 738ea0fabbcSTim J. Robbins lss = &uc.uc_stack; 739ea0fabbcSTim J. Robbins ss.ss_sp = PTRIN(lss->ss_sp); 740ea0fabbcSTim J. Robbins ss.ss_size = lss->ss_size; 741ea0fabbcSTim J. Robbins ss.ss_flags = linux_to_bsd_sigaltstack(lss->ss_flags); 742ea0fabbcSTim J. Robbins 743ea0fabbcSTim J. Robbins #ifdef DEBUG 744ea0fabbcSTim J. Robbins if (ldebug(rt_sigreturn)) 745c680f6b1SDavid E. O'Brien printf(LMSG("rt_sigret flags: 0x%x, sp: %p, ss: 0x%lx, mask: 0x%x"), 746ea0fabbcSTim J. Robbins ss.ss_flags, ss.ss_sp, ss.ss_size, context->sc_mask); 747ea0fabbcSTim J. Robbins #endif 748ea0fabbcSTim J. Robbins (void)kern_sigaltstack(td, &ss, NULL); 749ea0fabbcSTim J. Robbins 750ea0fabbcSTim J. Robbins return (EJUSTRETURN); 751ea0fabbcSTim J. Robbins } 752ea0fabbcSTim J. Robbins 753afe1a688SKonstantin Belousov static int 754afe1a688SKonstantin Belousov linux32_fetch_syscall_args(struct thread *td, struct syscall_args *sa) 755ea0fabbcSTim J. Robbins { 756afe1a688SKonstantin Belousov struct proc *p; 757afe1a688SKonstantin Belousov struct trapframe *frame; 758afe1a688SKonstantin Belousov 759afe1a688SKonstantin Belousov p = td->td_proc; 760afe1a688SKonstantin Belousov frame = td->td_frame; 761afe1a688SKonstantin Belousov 762afe1a688SKonstantin Belousov sa->args[0] = frame->tf_rbx; 763afe1a688SKonstantin Belousov sa->args[1] = frame->tf_rcx; 764afe1a688SKonstantin Belousov sa->args[2] = frame->tf_rdx; 765afe1a688SKonstantin Belousov sa->args[3] = frame->tf_rsi; 766afe1a688SKonstantin Belousov sa->args[4] = frame->tf_rdi; 767afe1a688SKonstantin Belousov sa->args[5] = frame->tf_rbp; /* Unconfirmed */ 768afe1a688SKonstantin Belousov sa->code = frame->tf_rax; 769afe1a688SKonstantin Belousov 770afe1a688SKonstantin Belousov if (sa->code >= p->p_sysent->sv_size) 771afe1a688SKonstantin Belousov sa->callp = &p->p_sysent->sv_table[0]; 772afe1a688SKonstantin Belousov else 773afe1a688SKonstantin Belousov sa->callp = &p->p_sysent->sv_table[sa->code]; 774afe1a688SKonstantin Belousov sa->narg = sa->callp->sy_narg; 775afe1a688SKonstantin Belousov 776afe1a688SKonstantin Belousov td->td_retval[0] = 0; 777afe1a688SKonstantin Belousov td->td_retval[1] = frame->tf_rdx; 778afe1a688SKonstantin Belousov 779afe1a688SKonstantin Belousov return (0); 780ea0fabbcSTim J. Robbins } 781ea0fabbcSTim J. Robbins 782ea0fabbcSTim J. Robbins /* 783ea0fabbcSTim J. Robbins * If a linux binary is exec'ing something, try this image activator 784ea0fabbcSTim J. Robbins * first. We override standard shell script execution in order to 785ea0fabbcSTim J. Robbins * be able to modify the interpreter path. We only do this if a linux 786ea0fabbcSTim J. Robbins * binary is doing the exec, so we do not create an EXEC module for it. 787ea0fabbcSTim J. Robbins */ 788ea0fabbcSTim J. Robbins static int exec_linux_imgact_try(struct image_params *iparams); 789ea0fabbcSTim J. Robbins 790ea0fabbcSTim J. Robbins static int 791ea0fabbcSTim J. Robbins exec_linux_imgact_try(struct image_params *imgp) 792ea0fabbcSTim J. Robbins { 793ea0fabbcSTim J. Robbins const char *head = (const char *)imgp->image_header; 7941d15fdd9SJohn Baldwin char *rpath; 795a14a9498SAlan Cox int error = -1; 796ea0fabbcSTim J. Robbins 797ea0fabbcSTim J. Robbins /* 798ea0fabbcSTim J. Robbins * The interpreter for shell scripts run from a linux binary needs 799ea0fabbcSTim J. Robbins * to be located in /compat/linux if possible in order to recursively 800ea0fabbcSTim J. Robbins * maintain linux path emulation. 801ea0fabbcSTim J. Robbins */ 802ea0fabbcSTim J. Robbins if (((const short *)head)[0] == SHELLMAGIC) { 803ea0fabbcSTim J. Robbins /* 804ea0fabbcSTim J. Robbins * Run our normal shell image activator. If it succeeds attempt 805d065e13dSDavid E. O'Brien * to use the alternate path for the interpreter. If an 806d065e13dSDavid E. O'Brien * alternate * path is found, use our stringspace to store it. 807ea0fabbcSTim J. Robbins */ 808ea0fabbcSTim J. Robbins if ((error = exec_shell_imgact(imgp)) == 0) { 8091d15fdd9SJohn Baldwin linux_emul_convpath(FIRST_THREAD_IN_PROC(imgp->proc), 810d065e13dSDavid E. O'Brien imgp->interpreter_name, UIO_SYSSPACE, &rpath, 0, 811d065e13dSDavid E. O'Brien AT_FDCWD); 812a14a9498SAlan Cox if (rpath != NULL) 813a14a9498SAlan Cox imgp->args->fname_buf = 814a14a9498SAlan Cox imgp->interpreter_name = rpath; 815ea0fabbcSTim J. Robbins } 816ea0fabbcSTim J. Robbins } 817ea0fabbcSTim J. Robbins return (error); 818ea0fabbcSTim J. Robbins } 819ea0fabbcSTim J. Robbins 820ea0fabbcSTim J. Robbins /* 821ea0fabbcSTim J. Robbins * Clear registers on exec 822ea0fabbcSTim J. Robbins * XXX copied from ia32_signal.c. 823ea0fabbcSTim J. Robbins */ 824ea0fabbcSTim J. Robbins static void 825a107d8aaSNathan Whitehorn exec_linux_setregs(struct thread *td, struct image_params *imgp, u_long stack) 826ea0fabbcSTim J. Robbins { 827ea0fabbcSTim J. Robbins struct trapframe *regs = td->td_frame; 828ea0fabbcSTim J. Robbins struct pcb *pcb = td->td_pcb; 829ea0fabbcSTim J. Robbins 8302c66cccaSKonstantin Belousov mtx_lock(&dt_lock); 8312c66cccaSKonstantin Belousov if (td->td_proc->p_md.md_ldt != NULL) 8322c66cccaSKonstantin Belousov user_ldt_free(td); 8332c66cccaSKonstantin Belousov else 8342c66cccaSKonstantin Belousov mtx_unlock(&dt_lock); 8352c66cccaSKonstantin Belousov 8369c5b213eSJung-uk Kim critical_enter(); 837ea0fabbcSTim J. Robbins wrmsr(MSR_FSBASE, 0); 838ea0fabbcSTim J. Robbins wrmsr(MSR_KGSBASE, 0); /* User value while we're in the kernel */ 839ea0fabbcSTim J. Robbins pcb->pcb_fsbase = 0; 840ea0fabbcSTim J. Robbins pcb->pcb_gsbase = 0; 8419c5b213eSJung-uk Kim critical_exit(); 8422ee8325fSJohn Baldwin pcb->pcb_initial_fpucw = __LINUX_NPXCW__; 843ea0fabbcSTim J. Robbins 844ea0fabbcSTim J. Robbins bzero((char *)regs, sizeof(struct trapframe)); 845a107d8aaSNathan Whitehorn regs->tf_rip = imgp->entry_addr; 846ea0fabbcSTim J. Robbins regs->tf_rsp = stack; 847ea0fabbcSTim J. Robbins regs->tf_rflags = PSL_USER | (regs->tf_rflags & PSL_T); 8482c66cccaSKonstantin Belousov regs->tf_gs = _ugssel; 8492c66cccaSKonstantin Belousov regs->tf_fs = _ufssel; 8502c66cccaSKonstantin Belousov regs->tf_es = _udatasel; 8512c66cccaSKonstantin Belousov regs->tf_ds = _udatasel; 852ea0fabbcSTim J. Robbins regs->tf_ss = _udatasel; 8532c66cccaSKonstantin Belousov regs->tf_flags = TF_HASSEGS; 854ea0fabbcSTim J. Robbins regs->tf_cs = _ucode32sel; 855a107d8aaSNathan Whitehorn regs->tf_rbx = imgp->ps_strings; 856bdbf2db5SJung-uk Kim 8572a988f7cSStephan Uphoff fpstate_drop(td); 858ea0fabbcSTim J. Robbins 8591b3c3256SKonstantin Belousov /* Do full restore on return so that we can change to a different %cs */ 860e6c006d9SJung-uk Kim set_pcb_flags(pcb, PCB_32BIT | PCB_FULL_IRET); 861ea0fabbcSTim J. Robbins td->td_retval[1] = 0; 862ea0fabbcSTim J. Robbins } 863ea0fabbcSTim J. Robbins 864ea0fabbcSTim J. Robbins /* 865ea0fabbcSTim J. Robbins * XXX copied from ia32_sysvec.c. 866ea0fabbcSTim J. Robbins */ 867ea0fabbcSTim J. Robbins static register_t * 868ea0fabbcSTim J. Robbins linux_copyout_strings(struct image_params *imgp) 869ea0fabbcSTim J. Robbins { 870ea0fabbcSTim J. Robbins int argc, envc; 871ea0fabbcSTim J. Robbins u_int32_t *vectp; 872ea0fabbcSTim J. Robbins char *stringp, *destp; 873ea0fabbcSTim J. Robbins u_int32_t *stack_base; 874ea0fabbcSTim J. Robbins struct linux32_ps_strings *arginfo; 875*4048f59cSDmitry Chagin char canary[LINUX_AT_RANDOM_LEN]; 876*4048f59cSDmitry Chagin size_t execpath_len; 877ea0fabbcSTim J. Robbins 878ea0fabbcSTim J. Robbins /* 879ea0fabbcSTim J. Robbins * Calculate string base and vector table pointers. 880ea0fabbcSTim J. Robbins */ 881*4048f59cSDmitry Chagin if (imgp->execpath != NULL && imgp->auxargs != NULL) 882*4048f59cSDmitry Chagin execpath_len = strlen(imgp->execpath) + 1; 883*4048f59cSDmitry Chagin else 884*4048f59cSDmitry Chagin execpath_len = 0; 885*4048f59cSDmitry Chagin 886ea0fabbcSTim J. Robbins arginfo = (struct linux32_ps_strings *)LINUX32_PS_STRINGS; 8870020bdf1SDmitry Chagin destp = (caddr_t)arginfo - SPARE_USRSPACE - 888*4048f59cSDmitry Chagin roundup(sizeof(canary), sizeof(char *)) - 889*4048f59cSDmitry Chagin roundup(execpath_len, sizeof(char *)) - 8900020bdf1SDmitry Chagin roundup((ARG_MAX - imgp->args->stringspace), sizeof(char *)); 891ea0fabbcSTim J. Robbins 892*4048f59cSDmitry Chagin if (execpath_len != 0) { 893*4048f59cSDmitry Chagin imgp->execpathp = (uintptr_t)arginfo - execpath_len; 894*4048f59cSDmitry Chagin copyout(imgp->execpath, (void *)imgp->execpathp, execpath_len); 895*4048f59cSDmitry Chagin } 896*4048f59cSDmitry Chagin 897*4048f59cSDmitry Chagin /* 898*4048f59cSDmitry Chagin * Prepare the canary for SSP. 899*4048f59cSDmitry Chagin */ 900*4048f59cSDmitry Chagin arc4rand(canary, sizeof(canary), 0); 901*4048f59cSDmitry Chagin imgp->canary = (uintptr_t)arginfo - 902*4048f59cSDmitry Chagin roundup(execpath_len, sizeof(char *)) - 903*4048f59cSDmitry Chagin roundup(sizeof(canary), sizeof(char *)); 904*4048f59cSDmitry Chagin copyout(canary, (void *)imgp->canary, sizeof(canary)); 905*4048f59cSDmitry Chagin 906ea0fabbcSTim J. Robbins /* 907ea0fabbcSTim J. Robbins * If we have a valid auxargs ptr, prepare some room 908ea0fabbcSTim J. Robbins * on the stack. 909ea0fabbcSTim J. Robbins */ 910ea0fabbcSTim J. Robbins if (imgp->auxargs) { 911ea0fabbcSTim J. Robbins /* 912ea0fabbcSTim J. Robbins * 'AT_COUNT*2' is size for the ELF Auxargs data. This is for 913ea0fabbcSTim J. Robbins * lower compatibility. 914ea0fabbcSTim J. Robbins */ 915d065e13dSDavid E. O'Brien imgp->auxarg_size = (imgp->auxarg_size) ? imgp->auxarg_size : 9164d7c2e8aSDmitry Chagin (LINUX_AT_COUNT * 2); 917ea0fabbcSTim J. Robbins /* 918ea0fabbcSTim J. Robbins * The '+ 2' is for the null pointers at the end of each of 919ea0fabbcSTim J. Robbins * the arg and env vector sets,and imgp->auxarg_size is room 920ea0fabbcSTim J. Robbins * for argument of Runtime loader. 921ea0fabbcSTim J. Robbins */ 922d065e13dSDavid E. O'Brien vectp = (u_int32_t *) (destp - (imgp->args->argc + 923d065e13dSDavid E. O'Brien imgp->args->envc + 2 + imgp->auxarg_size) * 924d065e13dSDavid E. O'Brien sizeof(u_int32_t)); 925ea0fabbcSTim J. Robbins 926ea0fabbcSTim J. Robbins } else 927ea0fabbcSTim J. Robbins /* 928ea0fabbcSTim J. Robbins * The '+ 2' is for the null pointers at the end of each of 929ea0fabbcSTim J. Robbins * the arg and env vector sets 930ea0fabbcSTim J. Robbins */ 931d065e13dSDavid E. O'Brien vectp = (u_int32_t *)(destp - (imgp->args->argc + 932d065e13dSDavid E. O'Brien imgp->args->envc + 2) * sizeof(u_int32_t)); 933ea0fabbcSTim J. Robbins 934ea0fabbcSTim J. Robbins /* 935ea0fabbcSTim J. Robbins * vectp also becomes our initial stack base 936ea0fabbcSTim J. Robbins */ 937ea0fabbcSTim J. Robbins stack_base = vectp; 938ea0fabbcSTim J. Robbins 939610ecfe0SMaxim Sobolev stringp = imgp->args->begin_argv; 940610ecfe0SMaxim Sobolev argc = imgp->args->argc; 941610ecfe0SMaxim Sobolev envc = imgp->args->envc; 942ea0fabbcSTim J. Robbins /* 943ea0fabbcSTim J. Robbins * Copy out strings - arguments and environment. 944ea0fabbcSTim J. Robbins */ 945610ecfe0SMaxim Sobolev copyout(stringp, destp, ARG_MAX - imgp->args->stringspace); 946ea0fabbcSTim J. Robbins 947ea0fabbcSTim J. Robbins /* 948ea0fabbcSTim J. Robbins * Fill in "ps_strings" struct for ps, w, etc. 949ea0fabbcSTim J. Robbins */ 9504d7c2e8aSDmitry Chagin suword32(&arginfo->ps_argvstr, (uint32_t)(intptr_t)vectp); 951ea0fabbcSTim J. Robbins suword32(&arginfo->ps_nargvstr, argc); 952ea0fabbcSTim J. Robbins 953ea0fabbcSTim J. Robbins /* 954ea0fabbcSTim J. Robbins * Fill in argument portion of vector table. 955ea0fabbcSTim J. Robbins */ 956ea0fabbcSTim J. Robbins for (; argc > 0; --argc) { 9574d7c2e8aSDmitry Chagin suword32(vectp++, (uint32_t)(intptr_t)destp); 958ea0fabbcSTim J. Robbins while (*stringp++ != 0) 959ea0fabbcSTim J. Robbins destp++; 960ea0fabbcSTim J. Robbins destp++; 961ea0fabbcSTim J. Robbins } 962ea0fabbcSTim J. Robbins 963ea0fabbcSTim J. Robbins /* a null vector table pointer separates the argp's from the envp's */ 964ea0fabbcSTim J. Robbins suword32(vectp++, 0); 965ea0fabbcSTim J. Robbins 9664d7c2e8aSDmitry Chagin suword32(&arginfo->ps_envstr, (uint32_t)(intptr_t)vectp); 967ea0fabbcSTim J. Robbins suword32(&arginfo->ps_nenvstr, envc); 968ea0fabbcSTim J. Robbins 969ea0fabbcSTim J. Robbins /* 970ea0fabbcSTim J. Robbins * Fill in environment portion of vector table. 971ea0fabbcSTim J. Robbins */ 972ea0fabbcSTim J. Robbins for (; envc > 0; --envc) { 9734d7c2e8aSDmitry Chagin suword32(vectp++, (uint32_t)(intptr_t)destp); 974ea0fabbcSTim J. Robbins while (*stringp++ != 0) 975ea0fabbcSTim J. Robbins destp++; 976ea0fabbcSTim J. Robbins destp++; 977ea0fabbcSTim J. Robbins } 978ea0fabbcSTim J. Robbins 979ea0fabbcSTim J. Robbins /* end of vector table is a null pointer */ 980ea0fabbcSTim J. Robbins suword32(vectp, 0); 981ea0fabbcSTim J. Robbins 982ea0fabbcSTim J. Robbins return ((register_t *)stack_base); 983ea0fabbcSTim J. Robbins } 984ea0fabbcSTim J. Robbins 9856472ac3dSEd Schouten static SYSCTL_NODE(_compat, OID_AUTO, linux32, CTLFLAG_RW, 0, 986ea0fabbcSTim J. Robbins "32-bit Linux emulation"); 987ea0fabbcSTim J. Robbins 988ea0fabbcSTim J. Robbins static u_long linux32_maxdsiz = LINUX32_MAXDSIZ; 989ea0fabbcSTim J. Robbins SYSCTL_ULONG(_compat_linux32, OID_AUTO, maxdsiz, CTLFLAG_RW, 990ea0fabbcSTim J. Robbins &linux32_maxdsiz, 0, ""); 991ea0fabbcSTim J. Robbins static u_long linux32_maxssiz = LINUX32_MAXSSIZ; 992ea0fabbcSTim J. Robbins SYSCTL_ULONG(_compat_linux32, OID_AUTO, maxssiz, CTLFLAG_RW, 993ea0fabbcSTim J. Robbins &linux32_maxssiz, 0, ""); 994ea0fabbcSTim J. Robbins static u_long linux32_maxvmem = LINUX32_MAXVMEM; 995ea0fabbcSTim J. Robbins SYSCTL_ULONG(_compat_linux32, OID_AUTO, maxvmem, CTLFLAG_RW, 996ea0fabbcSTim J. Robbins &linux32_maxvmem, 0, ""); 997ea0fabbcSTim J. Robbins 99867d39748SDmitry Chagin #if defined(DEBUG) 99967d39748SDmitry Chagin SYSCTL_PROC(_compat_linux32, OID_AUTO, debug, 100067d39748SDmitry Chagin CTLTYPE_STRING | CTLFLAG_RW, 100167d39748SDmitry Chagin 0, 0, linux_sysctl_debug, "A", 100267d39748SDmitry Chagin "Linux debugging control"); 100367d39748SDmitry Chagin #endif 100467d39748SDmitry Chagin 1005ea0fabbcSTim J. Robbins static void 100619059a13SJohn Baldwin linux32_fixlimit(struct rlimit *rl, int which) 1007ea0fabbcSTim J. Robbins { 1008ea0fabbcSTim J. Robbins 100919059a13SJohn Baldwin switch (which) { 101019059a13SJohn Baldwin case RLIMIT_DATA: 1011ea0fabbcSTim J. Robbins if (linux32_maxdsiz != 0) { 101219059a13SJohn Baldwin if (rl->rlim_cur > linux32_maxdsiz) 101319059a13SJohn Baldwin rl->rlim_cur = linux32_maxdsiz; 101419059a13SJohn Baldwin if (rl->rlim_max > linux32_maxdsiz) 101519059a13SJohn Baldwin rl->rlim_max = linux32_maxdsiz; 1016ea0fabbcSTim J. Robbins } 101719059a13SJohn Baldwin break; 101819059a13SJohn Baldwin case RLIMIT_STACK: 1019ea0fabbcSTim J. Robbins if (linux32_maxssiz != 0) { 102019059a13SJohn Baldwin if (rl->rlim_cur > linux32_maxssiz) 102119059a13SJohn Baldwin rl->rlim_cur = linux32_maxssiz; 102219059a13SJohn Baldwin if (rl->rlim_max > linux32_maxssiz) 102319059a13SJohn Baldwin rl->rlim_max = linux32_maxssiz; 1024ea0fabbcSTim J. Robbins } 102519059a13SJohn Baldwin break; 102619059a13SJohn Baldwin case RLIMIT_VMEM: 1027ea0fabbcSTim J. Robbins if (linux32_maxvmem != 0) { 102819059a13SJohn Baldwin if (rl->rlim_cur > linux32_maxvmem) 102919059a13SJohn Baldwin rl->rlim_cur = linux32_maxvmem; 103019059a13SJohn Baldwin if (rl->rlim_max > linux32_maxvmem) 103119059a13SJohn Baldwin rl->rlim_max = linux32_maxvmem; 1032ea0fabbcSTim J. Robbins } 103319059a13SJohn Baldwin break; 103419059a13SJohn Baldwin } 1035ea0fabbcSTim J. Robbins } 1036ea0fabbcSTim J. Robbins 1037ea0fabbcSTim J. Robbins struct sysentvec elf_linux_sysvec = { 1038a8d403e1SKonstantin Belousov .sv_size = LINUX_SYS_MAXSYSCALL, 1039a8d403e1SKonstantin Belousov .sv_table = linux_sysent, 1040a8d403e1SKonstantin Belousov .sv_mask = 0, 1041a8d403e1SKonstantin Belousov .sv_sigsize = LINUX_SIGTBLSZ, 1042a8d403e1SKonstantin Belousov .sv_sigtbl = bsd_to_linux_signal, 1043a8d403e1SKonstantin Belousov .sv_errsize = ELAST + 1, 1044a8d403e1SKonstantin Belousov .sv_errtbl = bsd_to_linux_errno, 1045a8d403e1SKonstantin Belousov .sv_transtrap = translate_traps, 1046a8d403e1SKonstantin Belousov .sv_fixup = elf_linux_fixup, 1047a8d403e1SKonstantin Belousov .sv_sendsig = linux_sendsig, 1048bdc37934SDmitry Chagin .sv_sigcode = &_binary_linux32_locore_o_start, 1049a8d403e1SKonstantin Belousov .sv_szsigcode = &linux_szsigcode, 1050afe1a688SKonstantin Belousov .sv_prepsyscall = NULL, 1051a8d403e1SKonstantin Belousov .sv_name = "Linux ELF32", 1052a8d403e1SKonstantin Belousov .sv_coredump = elf32_coredump, 1053a8d403e1SKonstantin Belousov .sv_imgact_try = exec_linux_imgact_try, 1054a8d403e1SKonstantin Belousov .sv_minsigstksz = LINUX_MINSIGSTKSZ, 1055a8d403e1SKonstantin Belousov .sv_pagesize = PAGE_SIZE, 1056a8d403e1SKonstantin Belousov .sv_minuser = VM_MIN_ADDRESS, 10578f1e49a6SDmitry Chagin .sv_maxuser = LINUX32_MAXUSER, 1058a8d403e1SKonstantin Belousov .sv_usrstack = LINUX32_USRSTACK, 1059a8d403e1SKonstantin Belousov .sv_psstrings = LINUX32_PS_STRINGS, 1060a8d403e1SKonstantin Belousov .sv_stackprot = VM_PROT_ALL, 1061a8d403e1SKonstantin Belousov .sv_copyout_strings = linux_copyout_strings, 1062a8d403e1SKonstantin Belousov .sv_setregs = exec_linux_setregs, 1063a8d403e1SKonstantin Belousov .sv_fixlimit = linux32_fixlimit, 1064a8d403e1SKonstantin Belousov .sv_maxssiz = &linux32_maxssiz, 10658f1e49a6SDmitry Chagin .sv_flags = SV_ABI_LINUX | SV_ILP32 | SV_IA32 | SV_SHP, 1066afe1a688SKonstantin Belousov .sv_set_syscall_retval = cpu_set_syscall_retval, 1067afe1a688SKonstantin Belousov .sv_fetch_syscall_args = linux32_fetch_syscall_args, 1068afe1a688SKonstantin Belousov .sv_syscallnames = NULL, 10698f1e49a6SDmitry Chagin .sv_shared_page_base = LINUX32_SHAREDPAGE, 10708f1e49a6SDmitry Chagin .sv_shared_page_len = PAGE_SIZE, 1071e5d81ef1SDmitry Chagin .sv_schedtail = linux_schedtail, 107281338031SDmitry Chagin .sv_thread_detach = linux_thread_detach, 1073ea0fabbcSTim J. Robbins }; 1074bdc37934SDmitry Chagin 1075bdc37934SDmitry Chagin static void 1076bdc37934SDmitry Chagin linux_vdso_install(void *param) 1077bdc37934SDmitry Chagin { 1078bdc37934SDmitry Chagin 1079bdc37934SDmitry Chagin linux_szsigcode = (&_binary_linux32_locore_o_end - 1080bdc37934SDmitry Chagin &_binary_linux32_locore_o_start); 1081bdc37934SDmitry Chagin 1082bdc37934SDmitry Chagin if (linux_szsigcode > elf_linux_sysvec.sv_shared_page_len) 1083bdc37934SDmitry Chagin panic("Linux invalid vdso size\n"); 1084bdc37934SDmitry Chagin 1085bdc37934SDmitry Chagin __elfN(linux_vdso_fixup)(&elf_linux_sysvec); 1086bdc37934SDmitry Chagin 1087bdc37934SDmitry Chagin linux_shared_page_obj = __elfN(linux_shared_page_init) 1088bdc37934SDmitry Chagin (&linux_shared_page_mapping); 1089bdc37934SDmitry Chagin 1090bdc37934SDmitry Chagin __elfN(linux_vdso_reloc)(&elf_linux_sysvec, LINUX32_SHAREDPAGE); 1091bdc37934SDmitry Chagin 1092bdc37934SDmitry Chagin bcopy(elf_linux_sysvec.sv_sigcode, linux_shared_page_mapping, 1093bdc37934SDmitry Chagin linux_szsigcode); 1094bdc37934SDmitry Chagin elf_linux_sysvec.sv_shared_page_obj = linux_shared_page_obj; 10950020bdf1SDmitry Chagin 10960020bdf1SDmitry Chagin linux_kplatform = linux_shared_page_mapping + 10970020bdf1SDmitry Chagin (linux_platform - (caddr_t)LINUX32_SHAREDPAGE); 1098bdc37934SDmitry Chagin } 1099bdc37934SDmitry Chagin SYSINIT(elf_linux_vdso_init, SI_SUB_EXEC, SI_ORDER_ANY, 1100bdc37934SDmitry Chagin (sysinit_cfunc_t)linux_vdso_install, NULL); 1101bdc37934SDmitry Chagin 1102bdc37934SDmitry Chagin static void 1103bdc37934SDmitry Chagin linux_vdso_deinstall(void *param) 1104bdc37934SDmitry Chagin { 1105bdc37934SDmitry Chagin 1106bdc37934SDmitry Chagin __elfN(linux_shared_page_fini)(linux_shared_page_obj); 1107bdc37934SDmitry Chagin }; 1108bdc37934SDmitry Chagin SYSUNINIT(elf_linux_vdso_uninit, SI_SUB_EXEC, SI_ORDER_FIRST, 1109bdc37934SDmitry Chagin (sysinit_cfunc_t)linux_vdso_deinstall, NULL); 1110ea0fabbcSTim J. Robbins 111189ffc202SBjoern A. Zeeb static char GNU_ABI_VENDOR[] = "GNU"; 111289ffc202SBjoern A. Zeeb static int GNULINUX_ABI_DESC = 0; 111389ffc202SBjoern A. Zeeb 111489ffc202SBjoern A. Zeeb static boolean_t 111589ffc202SBjoern A. Zeeb linux32_trans_osrel(const Elf_Note *note, int32_t *osrel) 111689ffc202SBjoern A. Zeeb { 111789ffc202SBjoern A. Zeeb const Elf32_Word *desc; 111889ffc202SBjoern A. Zeeb uintptr_t p; 111989ffc202SBjoern A. Zeeb 112089ffc202SBjoern A. Zeeb p = (uintptr_t)(note + 1); 112189ffc202SBjoern A. Zeeb p += roundup2(note->n_namesz, sizeof(Elf32_Addr)); 112289ffc202SBjoern A. Zeeb 112389ffc202SBjoern A. Zeeb desc = (const Elf32_Word *)p; 112489ffc202SBjoern A. Zeeb if (desc[0] != GNULINUX_ABI_DESC) 112589ffc202SBjoern A. Zeeb return (FALSE); 112689ffc202SBjoern A. Zeeb 112789ffc202SBjoern A. Zeeb /* 112889ffc202SBjoern A. Zeeb * For linux we encode osrel as follows (see linux_mib.c): 112989ffc202SBjoern A. Zeeb * VVVMMMIII (version, major, minor), see linux_mib.c. 113089ffc202SBjoern A. Zeeb */ 113189ffc202SBjoern A. Zeeb *osrel = desc[1] * 1000000 + desc[2] * 1000 + desc[3]; 113289ffc202SBjoern A. Zeeb 113389ffc202SBjoern A. Zeeb return (TRUE); 113489ffc202SBjoern A. Zeeb } 113532c01de2SDmitry Chagin 113632c01de2SDmitry Chagin static Elf_Brandnote linux32_brandnote = { 113789ffc202SBjoern A. Zeeb .hdr.n_namesz = sizeof(GNU_ABI_VENDOR), 113889ffc202SBjoern A. Zeeb .hdr.n_descsz = 16, /* XXX at least 16 */ 113932c01de2SDmitry Chagin .hdr.n_type = 1, 114089ffc202SBjoern A. Zeeb .vendor = GNU_ABI_VENDOR, 114189ffc202SBjoern A. Zeeb .flags = BN_TRANSLATE_OSREL, 114289ffc202SBjoern A. Zeeb .trans_osrel = linux32_trans_osrel 114332c01de2SDmitry Chagin }; 114432c01de2SDmitry Chagin 1145ea0fabbcSTim J. Robbins static Elf32_Brandinfo linux_brand = { 1146a8d403e1SKonstantin Belousov .brand = ELFOSABI_LINUX, 1147a8d403e1SKonstantin Belousov .machine = EM_386, 1148a8d403e1SKonstantin Belousov .compat_3_brand = "Linux", 1149a8d403e1SKonstantin Belousov .emul_path = "/compat/linux", 1150a8d403e1SKonstantin Belousov .interp_path = "/lib/ld-linux.so.1", 1151a8d403e1SKonstantin Belousov .sysvec = &elf_linux_sysvec, 1152a8d403e1SKonstantin Belousov .interp_newpath = NULL, 115332c01de2SDmitry Chagin .brand_note = &linux32_brandnote, 11542dedc128SDmitry Chagin .flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE 1155ea0fabbcSTim J. Robbins }; 1156ea0fabbcSTim J. Robbins 1157ea0fabbcSTim J. Robbins static Elf32_Brandinfo linux_glibc2brand = { 1158a8d403e1SKonstantin Belousov .brand = ELFOSABI_LINUX, 1159a8d403e1SKonstantin Belousov .machine = EM_386, 1160a8d403e1SKonstantin Belousov .compat_3_brand = "Linux", 1161a8d403e1SKonstantin Belousov .emul_path = "/compat/linux", 1162a8d403e1SKonstantin Belousov .interp_path = "/lib/ld-linux.so.2", 1163a8d403e1SKonstantin Belousov .sysvec = &elf_linux_sysvec, 1164a8d403e1SKonstantin Belousov .interp_newpath = NULL, 116532c01de2SDmitry Chagin .brand_note = &linux32_brandnote, 11662dedc128SDmitry Chagin .flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE 1167ea0fabbcSTim J. Robbins }; 1168ea0fabbcSTim J. Robbins 1169ea0fabbcSTim J. Robbins Elf32_Brandinfo *linux_brandlist[] = { 1170ea0fabbcSTim J. Robbins &linux_brand, 1171ea0fabbcSTim J. Robbins &linux_glibc2brand, 1172ea0fabbcSTim J. Robbins NULL 1173ea0fabbcSTim J. Robbins }; 1174ea0fabbcSTim J. Robbins 1175ea0fabbcSTim J. Robbins static int 1176ea0fabbcSTim J. Robbins linux_elf_modevent(module_t mod, int type, void *data) 1177ea0fabbcSTim J. Robbins { 1178ea0fabbcSTim J. Robbins Elf32_Brandinfo **brandinfo; 1179ea0fabbcSTim J. Robbins int error; 1180ea0fabbcSTim J. Robbins struct linux_ioctl_handler **lihp; 1181ea0fabbcSTim J. Robbins 1182ea0fabbcSTim J. Robbins error = 0; 1183ea0fabbcSTim J. Robbins 1184ea0fabbcSTim J. Robbins switch(type) { 1185ea0fabbcSTim J. Robbins case MOD_LOAD: 1186ea0fabbcSTim J. Robbins for (brandinfo = &linux_brandlist[0]; *brandinfo != NULL; 1187ea0fabbcSTim J. Robbins ++brandinfo) 1188ea0fabbcSTim J. Robbins if (elf32_insert_brand_entry(*brandinfo) < 0) 1189ea0fabbcSTim J. Robbins error = EINVAL; 1190ea0fabbcSTim J. Robbins if (error == 0) { 1191ea0fabbcSTim J. Robbins SET_FOREACH(lihp, linux_ioctl_handler_set) 1192ea0fabbcSTim J. Robbins linux_ioctl_register_handler(*lihp); 11937c09e6c0SAlexander Leidinger LIST_INIT(&futex_list); 119479262bf1SDmitry Chagin mtx_init(&futex_mtx, "ftllk", NULL, MTX_DEF); 11951ca16454SDmitry Chagin stclohz = (stathz ? stathz : hz); 1196ea0fabbcSTim J. Robbins if (bootverbose) 1197ea0fabbcSTim J. Robbins printf("Linux ELF exec handler installed\n"); 1198ea0fabbcSTim J. Robbins } else 1199ea0fabbcSTim J. Robbins printf("cannot insert Linux ELF brand handler\n"); 1200ea0fabbcSTim J. Robbins break; 1201ea0fabbcSTim J. Robbins case MOD_UNLOAD: 1202ea0fabbcSTim J. Robbins for (brandinfo = &linux_brandlist[0]; *brandinfo != NULL; 1203ea0fabbcSTim J. Robbins ++brandinfo) 1204ea0fabbcSTim J. Robbins if (elf32_brand_inuse(*brandinfo)) 1205ea0fabbcSTim J. Robbins error = EBUSY; 1206ea0fabbcSTim J. Robbins if (error == 0) { 1207ea0fabbcSTim J. Robbins for (brandinfo = &linux_brandlist[0]; 1208ea0fabbcSTim J. Robbins *brandinfo != NULL; ++brandinfo) 1209ea0fabbcSTim J. Robbins if (elf32_remove_brand_entry(*brandinfo) < 0) 1210ea0fabbcSTim J. Robbins error = EINVAL; 1211ea0fabbcSTim J. Robbins } 1212ea0fabbcSTim J. Robbins if (error == 0) { 1213ea0fabbcSTim J. Robbins SET_FOREACH(lihp, linux_ioctl_handler_set) 1214ea0fabbcSTim J. Robbins linux_ioctl_unregister_handler(*lihp); 121579262bf1SDmitry Chagin mtx_destroy(&futex_mtx); 1216ea0fabbcSTim J. Robbins if (bootverbose) 1217ea0fabbcSTim J. Robbins printf("Linux ELF exec handler removed\n"); 1218ea0fabbcSTim J. Robbins } else 1219ea0fabbcSTim J. Robbins printf("Could not deinstall ELF interpreter entry\n"); 1220ea0fabbcSTim J. Robbins break; 1221ea0fabbcSTim J. Robbins default: 1222af682d48SDmitry Chagin return (EOPNOTSUPP); 1223ea0fabbcSTim J. Robbins } 1224af682d48SDmitry Chagin return (error); 1225ea0fabbcSTim J. Robbins } 1226ea0fabbcSTim J. Robbins 1227ea0fabbcSTim J. Robbins static moduledata_t linux_elf_mod = { 1228ea0fabbcSTim J. Robbins "linuxelf", 1229ea0fabbcSTim J. Robbins linux_elf_modevent, 12309823d527SKevin Lo 0 1231ea0fabbcSTim J. Robbins }; 1232ea0fabbcSTim J. Robbins 123378ae4338SKonstantin Belousov DECLARE_MODULE_TIED(linuxelf, linux_elf_mod, SI_SUB_EXEC, SI_ORDER_ANY); 123467d39748SDmitry Chagin MODULE_DEPEND(linuxelf, linux_common, 1, 1, 1); 1235