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 37c680f6b1SDavid E. O'Brien #ifndef COMPAT_IA32 38ce55a234SDavid E. O'Brien #error "Unable to compile Linux-emulator due to missing COMPAT_IA32 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); 124ea0fabbcSTim J. Robbins static void linux_prepsyscall(struct trapframe *tf, int *args, u_int *code, 125ea0fabbcSTim J. Robbins caddr_t *params); 1269104847fSDavid Xu static void linux_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask); 127ea0fabbcSTim J. Robbins static void exec_linux_setregs(struct thread *td, u_long entry, 128ea0fabbcSTim J. Robbins u_long stack, u_long ps_strings); 12919059a13SJohn Baldwin static void linux32_fixlimit(struct rlimit *rl, int which); 130ea0fabbcSTim J. Robbins 1317c09e6c0SAlexander Leidinger static eventhandler_tag linux_exit_tag; 1327c09e6c0SAlexander Leidinger static eventhandler_tag linux_schedtail_tag; 1337c09e6c0SAlexander Leidinger static eventhandler_tag linux_exec_tag; 1347c09e6c0SAlexander Leidinger 135ea0fabbcSTim J. Robbins /* 136ea0fabbcSTim J. Robbins * Linux syscalls return negative errno's, we do positive and map them 13750e422f0SAlexander Leidinger * Reference: 13850e422f0SAlexander Leidinger * FreeBSD: src/sys/sys/errno.h 13950e422f0SAlexander Leidinger * Linux: linux-2.6.17.8/include/asm-generic/errno-base.h 14050e422f0SAlexander Leidinger * linux-2.6.17.8/include/asm-generic/errno.h 141ea0fabbcSTim J. Robbins */ 142ea0fabbcSTim J. Robbins static int bsd_to_linux_errno[ELAST + 1] = { 143ea0fabbcSTim J. Robbins -0, -1, -2, -3, -4, -5, -6, -7, -8, -9, 144ea0fabbcSTim J. Robbins -10, -35, -12, -13, -14, -15, -16, -17, -18, -19, 145ea0fabbcSTim J. Robbins -20, -21, -22, -23, -24, -25, -26, -27, -28, -29, 146ea0fabbcSTim J. Robbins -30, -31, -32, -33, -34, -11,-115,-114, -88, -89, 147ea0fabbcSTim J. Robbins -90, -91, -92, -93, -94, -95, -96, -97, -98, -99, 148ea0fabbcSTim J. Robbins -100,-101,-102,-103,-104,-105,-106,-107,-108,-109, 149ea0fabbcSTim J. Robbins -110,-111, -40, -36,-112,-113, -39, -11, -87,-122, 150ea0fabbcSTim J. Robbins -116, -66, -6, -6, -6, -6, -6, -37, -38, -9, 15150e422f0SAlexander Leidinger -6, -6, -43, -42, -75,-125, -84, -95, -16, -74, 15250e422f0SAlexander Leidinger -72, -67, -71 153ea0fabbcSTim J. Robbins }; 154ea0fabbcSTim J. Robbins 155ea0fabbcSTim J. Robbins int bsd_to_linux_signal[LINUX_SIGTBLSZ] = { 156ea0fabbcSTim J. Robbins LINUX_SIGHUP, LINUX_SIGINT, LINUX_SIGQUIT, LINUX_SIGILL, 157ea0fabbcSTim J. Robbins LINUX_SIGTRAP, LINUX_SIGABRT, 0, LINUX_SIGFPE, 158ea0fabbcSTim J. Robbins LINUX_SIGKILL, LINUX_SIGBUS, LINUX_SIGSEGV, LINUX_SIGSYS, 159ea0fabbcSTim J. Robbins LINUX_SIGPIPE, LINUX_SIGALRM, LINUX_SIGTERM, LINUX_SIGURG, 160ea0fabbcSTim J. Robbins LINUX_SIGSTOP, LINUX_SIGTSTP, LINUX_SIGCONT, LINUX_SIGCHLD, 161ea0fabbcSTim J. Robbins LINUX_SIGTTIN, LINUX_SIGTTOU, LINUX_SIGIO, LINUX_SIGXCPU, 162ea0fabbcSTim J. Robbins LINUX_SIGXFSZ, LINUX_SIGVTALRM, LINUX_SIGPROF, LINUX_SIGWINCH, 163ea0fabbcSTim J. Robbins 0, LINUX_SIGUSR1, LINUX_SIGUSR2 164ea0fabbcSTim J. Robbins }; 165ea0fabbcSTim J. Robbins 166ea0fabbcSTim J. Robbins int linux_to_bsd_signal[LINUX_SIGTBLSZ] = { 167ea0fabbcSTim J. Robbins SIGHUP, SIGINT, SIGQUIT, SIGILL, 168ea0fabbcSTim J. Robbins SIGTRAP, SIGABRT, SIGBUS, SIGFPE, 169ea0fabbcSTim J. Robbins SIGKILL, SIGUSR1, SIGSEGV, SIGUSR2, 170ea0fabbcSTim J. Robbins SIGPIPE, SIGALRM, SIGTERM, SIGBUS, 171ea0fabbcSTim J. Robbins SIGCHLD, SIGCONT, SIGSTOP, SIGTSTP, 172ea0fabbcSTim J. Robbins SIGTTIN, SIGTTOU, SIGURG, SIGXCPU, 173ea0fabbcSTim J. Robbins SIGXFSZ, SIGVTALRM, SIGPROF, SIGWINCH, 174ea0fabbcSTim J. Robbins SIGIO, SIGURG, SIGSYS 175ea0fabbcSTim J. Robbins }; 176ea0fabbcSTim J. Robbins 177ea0fabbcSTim J. Robbins #define LINUX_T_UNKNOWN 255 178ea0fabbcSTim J. Robbins static int _bsd_to_linux_trapcode[] = { 179ea0fabbcSTim J. Robbins LINUX_T_UNKNOWN, /* 0 */ 180ea0fabbcSTim J. Robbins 6, /* 1 T_PRIVINFLT */ 181ea0fabbcSTim J. Robbins LINUX_T_UNKNOWN, /* 2 */ 182ea0fabbcSTim J. Robbins 3, /* 3 T_BPTFLT */ 183ea0fabbcSTim J. Robbins LINUX_T_UNKNOWN, /* 4 */ 184ea0fabbcSTim J. Robbins LINUX_T_UNKNOWN, /* 5 */ 185ea0fabbcSTim J. Robbins 16, /* 6 T_ARITHTRAP */ 186ea0fabbcSTim J. Robbins 254, /* 7 T_ASTFLT */ 187ea0fabbcSTim J. Robbins LINUX_T_UNKNOWN, /* 8 */ 188ea0fabbcSTim J. Robbins 13, /* 9 T_PROTFLT */ 189ea0fabbcSTim J. Robbins 1, /* 10 T_TRCTRAP */ 190ea0fabbcSTim J. Robbins LINUX_T_UNKNOWN, /* 11 */ 191ea0fabbcSTim J. Robbins 14, /* 12 T_PAGEFLT */ 192ea0fabbcSTim J. Robbins LINUX_T_UNKNOWN, /* 13 */ 193ea0fabbcSTim J. Robbins 17, /* 14 T_ALIGNFLT */ 194ea0fabbcSTim J. Robbins LINUX_T_UNKNOWN, /* 15 */ 195ea0fabbcSTim J. Robbins LINUX_T_UNKNOWN, /* 16 */ 196ea0fabbcSTim J. Robbins LINUX_T_UNKNOWN, /* 17 */ 197ea0fabbcSTim J. Robbins 0, /* 18 T_DIVIDE */ 198ea0fabbcSTim J. Robbins 2, /* 19 T_NMI */ 199ea0fabbcSTim J. Robbins 4, /* 20 T_OFLOW */ 200ea0fabbcSTim J. Robbins 5, /* 21 T_BOUND */ 201ea0fabbcSTim J. Robbins 7, /* 22 T_DNA */ 202ea0fabbcSTim J. Robbins 8, /* 23 T_DOUBLEFLT */ 203ea0fabbcSTim J. Robbins 9, /* 24 T_FPOPFLT */ 204ea0fabbcSTim J. Robbins 10, /* 25 T_TSSFLT */ 205ea0fabbcSTim J. Robbins 11, /* 26 T_SEGNPFLT */ 206ea0fabbcSTim J. Robbins 12, /* 27 T_STKFLT */ 207ea0fabbcSTim J. Robbins 18, /* 28 T_MCHK */ 208ea0fabbcSTim J. Robbins 19, /* 29 T_XMMFLT */ 209ea0fabbcSTim J. Robbins 15 /* 30 T_RESERVED */ 210ea0fabbcSTim J. Robbins }; 211ea0fabbcSTim J. Robbins #define bsd_to_linux_trapcode(code) \ 212ea0fabbcSTim J. Robbins ((code)<sizeof(_bsd_to_linux_trapcode)/sizeof(*_bsd_to_linux_trapcode)? \ 213ea0fabbcSTim J. Robbins _bsd_to_linux_trapcode[(code)]: \ 214ea0fabbcSTim J. Robbins LINUX_T_UNKNOWN) 215ea0fabbcSTim J. Robbins 216ea0fabbcSTim J. Robbins struct linux32_ps_strings { 217ea0fabbcSTim J. Robbins u_int32_t ps_argvstr; /* first of 0 or more argument strings */ 218f2c7668eSDavid Schultz u_int ps_nargvstr; /* the number of argument strings */ 219ea0fabbcSTim J. Robbins u_int32_t ps_envstr; /* first of 0 or more environment strings */ 220f2c7668eSDavid Schultz u_int ps_nenvstr; /* the number of environment strings */ 221ea0fabbcSTim J. Robbins }; 222ea0fabbcSTim J. Robbins 223ea0fabbcSTim J. Robbins /* 224ea0fabbcSTim J. Robbins * If FreeBSD & Linux have a difference of opinion about what a trap 225ea0fabbcSTim J. Robbins * means, deal with it here. 226ea0fabbcSTim J. Robbins * 227ea0fabbcSTim J. Robbins * MPSAFE 228ea0fabbcSTim J. Robbins */ 229ea0fabbcSTim J. Robbins static int 230ea0fabbcSTim J. Robbins translate_traps(int signal, int trap_code) 231ea0fabbcSTim J. Robbins { 232ea0fabbcSTim J. Robbins if (signal != SIGBUS) 233ea0fabbcSTim J. Robbins return signal; 234ea0fabbcSTim J. Robbins switch (trap_code) { 235ea0fabbcSTim J. Robbins case T_PROTFLT: 236ea0fabbcSTim J. Robbins case T_TSSFLT: 237ea0fabbcSTim J. Robbins case T_DOUBLEFLT: 238ea0fabbcSTim J. Robbins case T_PAGEFLT: 239ea0fabbcSTim J. Robbins return SIGSEGV; 240ea0fabbcSTim J. Robbins default: 241ea0fabbcSTim J. Robbins return signal; 242ea0fabbcSTim J. Robbins } 243ea0fabbcSTim J. Robbins } 244ea0fabbcSTim J. Robbins 245ea0fabbcSTim J. Robbins static int 246ea0fabbcSTim J. Robbins elf_linux_fixup(register_t **stack_base, struct image_params *imgp) 247ea0fabbcSTim J. Robbins { 248ea0fabbcSTim J. Robbins Elf32_Auxargs *args; 249ea0fabbcSTim J. Robbins Elf32_Addr *base; 2504d7c2e8aSDmitry Chagin Elf32_Addr *pos, *uplatform; 2514d7c2e8aSDmitry Chagin struct linux32_ps_strings *arginfo; 2524d7c2e8aSDmitry Chagin 2534d7c2e8aSDmitry Chagin arginfo = (struct linux32_ps_strings *)LINUX32_PS_STRINGS; 2544d7c2e8aSDmitry Chagin uplatform = (Elf32_Addr *)((caddr_t)arginfo - linux_szsigcode - 2554d7c2e8aSDmitry Chagin linux_szplatform); 256ea0fabbcSTim J. Robbins 2576617724cSJeff Roberson KASSERT(curthread->td_proc == imgp->proc, 258ea0fabbcSTim J. Robbins ("unsafe elf_linux_fixup(), should be curproc")); 259ea0fabbcSTim J. Robbins base = (Elf32_Addr *)*stack_base; 260ea0fabbcSTim J. Robbins args = (Elf32_Auxargs *)imgp->auxargs; 261610ecfe0SMaxim Sobolev pos = base + (imgp->args->argc + imgp->args->envc + 2); 262ea0fabbcSTim J. Robbins 2634d7c2e8aSDmitry Chagin AUXARGS_ENTRY_32(pos, LINUX_AT_HWCAP, cpu_feature); 2641ca16454SDmitry Chagin AUXARGS_ENTRY_32(pos, LINUX_AT_CLKTCK, stclohz); 265ea0fabbcSTim J. Robbins AUXARGS_ENTRY_32(pos, AT_PHDR, args->phdr); 266ea0fabbcSTim J. Robbins AUXARGS_ENTRY_32(pos, AT_PHENT, args->phent); 267ea0fabbcSTim J. Robbins AUXARGS_ENTRY_32(pos, AT_PHNUM, args->phnum); 268ea0fabbcSTim J. Robbins AUXARGS_ENTRY_32(pos, AT_PAGESZ, args->pagesz); 269ea0fabbcSTim J. Robbins AUXARGS_ENTRY_32(pos, AT_FLAGS, args->flags); 270ea0fabbcSTim J. Robbins AUXARGS_ENTRY_32(pos, AT_ENTRY, args->entry); 271ea0fabbcSTim J. Robbins AUXARGS_ENTRY_32(pos, AT_BASE, args->base); 2724d7c2e8aSDmitry Chagin AUXARGS_ENTRY_32(pos, LINUX_AT_SECURE, 0); 273ea0fabbcSTim J. Robbins AUXARGS_ENTRY_32(pos, AT_UID, imgp->proc->p_ucred->cr_ruid); 274ea0fabbcSTim J. Robbins AUXARGS_ENTRY_32(pos, AT_EUID, imgp->proc->p_ucred->cr_svuid); 275ea0fabbcSTim J. Robbins AUXARGS_ENTRY_32(pos, AT_GID, imgp->proc->p_ucred->cr_rgid); 276ea0fabbcSTim J. Robbins AUXARGS_ENTRY_32(pos, AT_EGID, imgp->proc->p_ucred->cr_svgid); 2774d7c2e8aSDmitry Chagin AUXARGS_ENTRY_32(pos, LINUX_AT_PLATFORM, PTROUT(uplatform)); 2784d7c2e8aSDmitry Chagin if (args->execfd != -1) 2794d7c2e8aSDmitry Chagin AUXARGS_ENTRY_32(pos, AT_EXECFD, args->execfd); 280ea0fabbcSTim J. Robbins AUXARGS_ENTRY_32(pos, AT_NULL, 0); 281ea0fabbcSTim J. Robbins 282ea0fabbcSTim J. Robbins free(imgp->auxargs, M_TEMP); 283ea0fabbcSTim J. Robbins imgp->auxargs = NULL; 284ea0fabbcSTim J. Robbins 285ea0fabbcSTim J. Robbins base--; 286610ecfe0SMaxim Sobolev suword32(base, (uint32_t)imgp->args->argc); 287ea0fabbcSTim J. Robbins *stack_base = (register_t *)base; 288ea0fabbcSTim J. Robbins return 0; 289ea0fabbcSTim J. Robbins } 290ea0fabbcSTim J. Robbins 291ea0fabbcSTim J. Robbins extern unsigned long linux_sznonrtsigcode; 292ea0fabbcSTim J. Robbins 293ea0fabbcSTim J. Robbins static void 2949104847fSDavid Xu linux_rt_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) 295ea0fabbcSTim J. Robbins { 296ea0fabbcSTim J. Robbins struct thread *td = curthread; 297ea0fabbcSTim J. Robbins struct proc *p = td->td_proc; 298ea0fabbcSTim J. Robbins struct sigacts *psp; 299ea0fabbcSTim J. Robbins struct trapframe *regs; 300ea0fabbcSTim J. Robbins struct l_rt_sigframe *fp, frame; 301ea0fabbcSTim J. Robbins int oonstack; 3029104847fSDavid Xu int sig; 3039104847fSDavid Xu int code; 304ea0fabbcSTim J. Robbins 3059104847fSDavid Xu sig = ksi->ksi_signo; 3069104847fSDavid Xu code = ksi->ksi_code; 307ea0fabbcSTim J. Robbins PROC_LOCK_ASSERT(p, MA_OWNED); 308ea0fabbcSTim J. Robbins psp = p->p_sigacts; 309ea0fabbcSTim J. Robbins mtx_assert(&psp->ps_mtx, MA_OWNED); 310ea0fabbcSTim J. Robbins regs = td->td_frame; 311ea0fabbcSTim J. Robbins oonstack = sigonstack(regs->tf_rsp); 312ea0fabbcSTim J. Robbins 313ea0fabbcSTim J. Robbins #ifdef DEBUG 314ea0fabbcSTim J. Robbins if (ldebug(rt_sendsig)) 315728ef954SJohn Baldwin printf(ARGS(rt_sendsig, "%p, %d, %p, %u"), 316ea0fabbcSTim J. Robbins catcher, sig, (void*)mask, code); 317ea0fabbcSTim J. Robbins #endif 318ea0fabbcSTim J. Robbins /* 319ea0fabbcSTim J. Robbins * Allocate space for the signal handler context. 320ea0fabbcSTim J. Robbins */ 321ea0fabbcSTim J. Robbins if ((td->td_pflags & TDP_ALTSTACK) && !oonstack && 322ea0fabbcSTim J. Robbins SIGISMEMBER(psp->ps_sigonstack, sig)) { 323ea0fabbcSTim J. Robbins fp = (struct l_rt_sigframe *)(td->td_sigstk.ss_sp + 324ea0fabbcSTim J. Robbins td->td_sigstk.ss_size - sizeof(struct l_rt_sigframe)); 325ea0fabbcSTim J. Robbins } else 326ea0fabbcSTim J. Robbins fp = (struct l_rt_sigframe *)regs->tf_rsp - 1; 327ea0fabbcSTim J. Robbins mtx_unlock(&psp->ps_mtx); 328ea0fabbcSTim J. Robbins 329ea0fabbcSTim J. Robbins /* 330ea0fabbcSTim J. Robbins * Build the argument list for the signal handler. 331ea0fabbcSTim J. Robbins */ 332ea0fabbcSTim J. Robbins if (p->p_sysent->sv_sigtbl) 333ea0fabbcSTim J. Robbins if (sig <= p->p_sysent->sv_sigsize) 334ea0fabbcSTim J. Robbins sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)]; 335ea0fabbcSTim J. Robbins 336ea0fabbcSTim J. Robbins bzero(&frame, sizeof(frame)); 337ea0fabbcSTim J. Robbins 338ea0fabbcSTim J. Robbins frame.sf_handler = PTROUT(catcher); 339ea0fabbcSTim J. Robbins frame.sf_sig = sig; 340ea0fabbcSTim J. Robbins frame.sf_siginfo = PTROUT(&fp->sf_si); 341ea0fabbcSTim J. Robbins frame.sf_ucontext = PTROUT(&fp->sf_sc); 342ea0fabbcSTim J. Robbins 343ea0fabbcSTim J. Robbins /* Fill in POSIX parts */ 344aa8b2011SKonstantin Belousov ksiginfo_to_lsiginfo(ksi, &frame.sf_si, sig); 345ea0fabbcSTim J. Robbins 346ea0fabbcSTim J. Robbins /* 347ea0fabbcSTim J. Robbins * Build the signal context to be used by sigreturn. 348ea0fabbcSTim J. Robbins */ 349ea0fabbcSTim J. Robbins frame.sf_sc.uc_flags = 0; /* XXX ??? */ 350ea0fabbcSTim J. Robbins frame.sf_sc.uc_link = 0; /* XXX ??? */ 351ea0fabbcSTim J. Robbins 352ea0fabbcSTim J. Robbins frame.sf_sc.uc_stack.ss_sp = PTROUT(td->td_sigstk.ss_sp); 353ea0fabbcSTim J. Robbins frame.sf_sc.uc_stack.ss_size = td->td_sigstk.ss_size; 354ea0fabbcSTim J. Robbins frame.sf_sc.uc_stack.ss_flags = (td->td_pflags & TDP_ALTSTACK) 355ea0fabbcSTim J. Robbins ? ((oonstack) ? LINUX_SS_ONSTACK : 0) : LINUX_SS_DISABLE; 356ea0fabbcSTim J. Robbins PROC_UNLOCK(p); 357ea0fabbcSTim J. Robbins 358ea0fabbcSTim J. Robbins bsd_to_linux_sigset(mask, &frame.sf_sc.uc_sigmask); 359ea0fabbcSTim J. Robbins 360ea0fabbcSTim J. Robbins frame.sf_sc.uc_mcontext.sc_mask = frame.sf_sc.uc_sigmask.__bits[0]; 361ea0fabbcSTim J. Robbins frame.sf_sc.uc_mcontext.sc_edi = regs->tf_rdi; 362ea0fabbcSTim J. Robbins frame.sf_sc.uc_mcontext.sc_esi = regs->tf_rsi; 363ea0fabbcSTim J. Robbins frame.sf_sc.uc_mcontext.sc_ebp = regs->tf_rbp; 364ea0fabbcSTim J. Robbins frame.sf_sc.uc_mcontext.sc_ebx = regs->tf_rbx; 365ea0fabbcSTim J. Robbins frame.sf_sc.uc_mcontext.sc_edx = regs->tf_rdx; 366ea0fabbcSTim J. Robbins frame.sf_sc.uc_mcontext.sc_ecx = regs->tf_rcx; 367ea0fabbcSTim J. Robbins frame.sf_sc.uc_mcontext.sc_eax = regs->tf_rax; 368ea0fabbcSTim J. Robbins frame.sf_sc.uc_mcontext.sc_eip = regs->tf_rip; 369ea0fabbcSTim J. Robbins frame.sf_sc.uc_mcontext.sc_cs = regs->tf_cs; 3702c66cccaSKonstantin Belousov frame.sf_sc.uc_mcontext.sc_gs = regs->tf_gs; 3712c66cccaSKonstantin Belousov frame.sf_sc.uc_mcontext.sc_fs = regs->tf_fs; 3722c66cccaSKonstantin Belousov frame.sf_sc.uc_mcontext.sc_es = regs->tf_es; 3732c66cccaSKonstantin Belousov frame.sf_sc.uc_mcontext.sc_ds = regs->tf_ds; 374ea0fabbcSTim J. Robbins frame.sf_sc.uc_mcontext.sc_eflags = regs->tf_rflags; 375ea0fabbcSTim J. Robbins frame.sf_sc.uc_mcontext.sc_esp_at_signal = regs->tf_rsp; 376ea0fabbcSTim J. Robbins frame.sf_sc.uc_mcontext.sc_ss = regs->tf_ss; 377ea0fabbcSTim J. Robbins frame.sf_sc.uc_mcontext.sc_err = regs->tf_err; 37896a2b635SKonstantin Belousov frame.sf_sc.uc_mcontext.sc_cr2 = (u_int32_t)(uintptr_t)ksi->ksi_addr; 379ea0fabbcSTim J. Robbins frame.sf_sc.uc_mcontext.sc_trapno = bsd_to_linux_trapcode(code); 380ea0fabbcSTim J. Robbins 381ea0fabbcSTim J. Robbins #ifdef DEBUG 382ea0fabbcSTim J. Robbins if (ldebug(rt_sendsig)) 383c680f6b1SDavid E. O'Brien printf(LMSG("rt_sendsig flags: 0x%x, sp: %p, ss: 0x%lx, mask: 0x%x"), 384ea0fabbcSTim J. Robbins frame.sf_sc.uc_stack.ss_flags, td->td_sigstk.ss_sp, 385ea0fabbcSTim J. Robbins td->td_sigstk.ss_size, frame.sf_sc.uc_mcontext.sc_mask); 386ea0fabbcSTim J. Robbins #endif 387ea0fabbcSTim J. Robbins 388ea0fabbcSTim J. Robbins if (copyout(&frame, fp, sizeof(frame)) != 0) { 389ea0fabbcSTim J. Robbins /* 390ea0fabbcSTim J. Robbins * Process has trashed its stack; give it an illegal 391ea0fabbcSTim J. Robbins * instruction to halt it in its tracks. 392ea0fabbcSTim J. Robbins */ 393ea0fabbcSTim J. Robbins #ifdef DEBUG 394ea0fabbcSTim J. Robbins if (ldebug(rt_sendsig)) 395ea0fabbcSTim J. Robbins printf(LMSG("rt_sendsig: bad stack %p, oonstack=%x"), 396ea0fabbcSTim J. Robbins fp, oonstack); 397ea0fabbcSTim J. Robbins #endif 398ea0fabbcSTim J. Robbins PROC_LOCK(p); 399ea0fabbcSTim J. Robbins sigexit(td, SIGILL); 400ea0fabbcSTim J. Robbins } 401ea0fabbcSTim J. Robbins 402ea0fabbcSTim J. Robbins /* 403ea0fabbcSTim J. Robbins * Build context to run handler in. 404ea0fabbcSTim J. Robbins */ 405ea0fabbcSTim J. Robbins regs->tf_rsp = PTROUT(fp); 406ea0fabbcSTim J. Robbins regs->tf_rip = LINUX32_PS_STRINGS - *(p->p_sysent->sv_szsigcode) + 407ea0fabbcSTim J. Robbins linux_sznonrtsigcode; 40822eca0bfSKonstantin Belousov regs->tf_rflags &= ~(PSL_T | PSL_D); 409ea0fabbcSTim J. Robbins regs->tf_cs = _ucode32sel; 410ea0fabbcSTim J. Robbins regs->tf_ss = _udatasel; 4112c66cccaSKonstantin Belousov regs->tf_ds = _udatasel; 4122c66cccaSKonstantin Belousov regs->tf_es = _udatasel; 4132c66cccaSKonstantin Belousov regs->tf_fs = _ufssel; 4142c66cccaSKonstantin Belousov regs->tf_gs = _ugssel; 4152c66cccaSKonstantin Belousov regs->tf_flags = TF_HASSEGS; 416ea0fabbcSTim J. Robbins PROC_LOCK(p); 417ea0fabbcSTim J. Robbins mtx_lock(&psp->ps_mtx); 418ea0fabbcSTim J. Robbins } 419ea0fabbcSTim J. Robbins 420ea0fabbcSTim J. Robbins 421ea0fabbcSTim J. Robbins /* 422ea0fabbcSTim J. Robbins * Send an interrupt to process. 423ea0fabbcSTim J. Robbins * 424ea0fabbcSTim J. Robbins * Stack is set up to allow sigcode stored 425ea0fabbcSTim J. Robbins * in u. to call routine, followed by kcall 426ea0fabbcSTim J. Robbins * to sigreturn routine below. After sigreturn 427ea0fabbcSTim J. Robbins * resets the signal mask, the stack, and the 428ea0fabbcSTim J. Robbins * frame pointer, it returns to the user 429ea0fabbcSTim J. Robbins * specified pc, psl. 430ea0fabbcSTim J. Robbins */ 431ea0fabbcSTim J. Robbins static void 4329104847fSDavid Xu linux_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) 433ea0fabbcSTim J. Robbins { 434ea0fabbcSTim J. Robbins struct thread *td = curthread; 435ea0fabbcSTim J. Robbins struct proc *p = td->td_proc; 436ea0fabbcSTim J. Robbins struct sigacts *psp; 437ea0fabbcSTim J. Robbins struct trapframe *regs; 438ea0fabbcSTim J. Robbins struct l_sigframe *fp, frame; 439ea0fabbcSTim J. Robbins l_sigset_t lmask; 440ea0fabbcSTim J. Robbins int oonstack, i; 4419104847fSDavid Xu int sig, code; 442ea0fabbcSTim J. Robbins 4439104847fSDavid Xu sig = ksi->ksi_signo; 4449104847fSDavid Xu code = ksi->ksi_code; 445ea0fabbcSTim J. Robbins PROC_LOCK_ASSERT(p, MA_OWNED); 446ea0fabbcSTim J. Robbins psp = p->p_sigacts; 447ea0fabbcSTim J. Robbins mtx_assert(&psp->ps_mtx, MA_OWNED); 448ea0fabbcSTim J. Robbins if (SIGISMEMBER(psp->ps_siginfo, sig)) { 449ea0fabbcSTim J. Robbins /* Signal handler installed with SA_SIGINFO. */ 4509104847fSDavid Xu linux_rt_sendsig(catcher, ksi, mask); 451ea0fabbcSTim J. Robbins return; 452ea0fabbcSTim J. Robbins } 453ea0fabbcSTim J. Robbins 454ea0fabbcSTim J. Robbins regs = td->td_frame; 455ea0fabbcSTim J. Robbins oonstack = sigonstack(regs->tf_rsp); 456ea0fabbcSTim J. Robbins 457ea0fabbcSTim J. Robbins #ifdef DEBUG 458ea0fabbcSTim J. Robbins if (ldebug(sendsig)) 459728ef954SJohn Baldwin printf(ARGS(sendsig, "%p, %d, %p, %u"), 460ea0fabbcSTim J. Robbins catcher, sig, (void*)mask, code); 461ea0fabbcSTim J. Robbins #endif 462ea0fabbcSTim J. Robbins 463ea0fabbcSTim J. Robbins /* 464ea0fabbcSTim J. Robbins * Allocate space for the signal handler context. 465ea0fabbcSTim J. Robbins */ 466ea0fabbcSTim J. Robbins if ((td->td_pflags & TDP_ALTSTACK) && !oonstack && 467ea0fabbcSTim J. Robbins SIGISMEMBER(psp->ps_sigonstack, sig)) { 468ea0fabbcSTim J. Robbins fp = (struct l_sigframe *)(td->td_sigstk.ss_sp + 469ea0fabbcSTim J. Robbins td->td_sigstk.ss_size - sizeof(struct l_sigframe)); 470ea0fabbcSTim J. Robbins } else 471ea0fabbcSTim J. Robbins fp = (struct l_sigframe *)regs->tf_rsp - 1; 472ea0fabbcSTim J. Robbins mtx_unlock(&psp->ps_mtx); 473ea0fabbcSTim J. Robbins PROC_UNLOCK(p); 474ea0fabbcSTim J. Robbins 475ea0fabbcSTim J. Robbins /* 476ea0fabbcSTim J. Robbins * Build the argument list for the signal handler. 477ea0fabbcSTim J. Robbins */ 478ea0fabbcSTim J. Robbins if (p->p_sysent->sv_sigtbl) 479ea0fabbcSTim J. Robbins if (sig <= p->p_sysent->sv_sigsize) 480ea0fabbcSTim J. Robbins sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)]; 481ea0fabbcSTim J. Robbins 482ea0fabbcSTim J. Robbins bzero(&frame, sizeof(frame)); 483ea0fabbcSTim J. Robbins 484ea0fabbcSTim J. Robbins frame.sf_handler = PTROUT(catcher); 485ea0fabbcSTim J. Robbins frame.sf_sig = sig; 486ea0fabbcSTim J. Robbins 487ea0fabbcSTim J. Robbins bsd_to_linux_sigset(mask, &lmask); 488ea0fabbcSTim J. Robbins 489ea0fabbcSTim J. Robbins /* 490ea0fabbcSTim J. Robbins * Build the signal context to be used by sigreturn. 491ea0fabbcSTim J. Robbins */ 492ea0fabbcSTim J. Robbins frame.sf_sc.sc_mask = lmask.__bits[0]; 4932c66cccaSKonstantin Belousov frame.sf_sc.sc_gs = regs->tf_gs; 4942c66cccaSKonstantin Belousov frame.sf_sc.sc_fs = regs->tf_fs; 4952c66cccaSKonstantin Belousov frame.sf_sc.sc_es = regs->tf_es; 4962c66cccaSKonstantin Belousov frame.sf_sc.sc_ds = regs->tf_ds; 497ea0fabbcSTim J. Robbins frame.sf_sc.sc_edi = regs->tf_rdi; 498ea0fabbcSTim J. Robbins frame.sf_sc.sc_esi = regs->tf_rsi; 499ea0fabbcSTim J. Robbins frame.sf_sc.sc_ebp = regs->tf_rbp; 500ea0fabbcSTim J. Robbins frame.sf_sc.sc_ebx = regs->tf_rbx; 501ea0fabbcSTim J. Robbins frame.sf_sc.sc_edx = regs->tf_rdx; 502ea0fabbcSTim J. Robbins frame.sf_sc.sc_ecx = regs->tf_rcx; 503ea0fabbcSTim J. Robbins frame.sf_sc.sc_eax = regs->tf_rax; 504ea0fabbcSTim J. Robbins frame.sf_sc.sc_eip = regs->tf_rip; 505ea0fabbcSTim J. Robbins frame.sf_sc.sc_cs = regs->tf_cs; 506ea0fabbcSTim J. Robbins frame.sf_sc.sc_eflags = regs->tf_rflags; 507ea0fabbcSTim J. Robbins frame.sf_sc.sc_esp_at_signal = regs->tf_rsp; 508ea0fabbcSTim J. Robbins frame.sf_sc.sc_ss = regs->tf_ss; 509ea0fabbcSTim J. Robbins frame.sf_sc.sc_err = regs->tf_err; 51096a2b635SKonstantin Belousov frame.sf_sc.sc_cr2 = (u_int32_t)(uintptr_t)ksi->ksi_addr; 511ea0fabbcSTim J. Robbins frame.sf_sc.sc_trapno = bsd_to_linux_trapcode(code); 512ea0fabbcSTim J. Robbins 513ea0fabbcSTim J. Robbins for (i = 0; i < (LINUX_NSIG_WORDS-1); i++) 514ea0fabbcSTim J. Robbins frame.sf_extramask[i] = lmask.__bits[i+1]; 515ea0fabbcSTim J. Robbins 516ea0fabbcSTim J. Robbins if (copyout(&frame, fp, sizeof(frame)) != 0) { 517ea0fabbcSTim J. Robbins /* 518ea0fabbcSTim J. Robbins * Process has trashed its stack; give it an illegal 519ea0fabbcSTim J. Robbins * instruction to halt it in its tracks. 520ea0fabbcSTim J. Robbins */ 521ea0fabbcSTim J. Robbins PROC_LOCK(p); 522ea0fabbcSTim J. Robbins sigexit(td, SIGILL); 523ea0fabbcSTim J. Robbins } 524ea0fabbcSTim J. Robbins 525ea0fabbcSTim J. Robbins /* 526ea0fabbcSTim J. Robbins * Build context to run handler in. 527ea0fabbcSTim J. Robbins */ 528ea0fabbcSTim J. Robbins regs->tf_rsp = PTROUT(fp); 529ea0fabbcSTim J. Robbins regs->tf_rip = LINUX32_PS_STRINGS - *(p->p_sysent->sv_szsigcode); 53022eca0bfSKonstantin Belousov regs->tf_rflags &= ~(PSL_T | PSL_D); 531ea0fabbcSTim J. Robbins regs->tf_cs = _ucode32sel; 532ea0fabbcSTim J. Robbins regs->tf_ss = _udatasel; 5332c66cccaSKonstantin Belousov regs->tf_ds = _udatasel; 5342c66cccaSKonstantin Belousov regs->tf_es = _udatasel; 5352c66cccaSKonstantin Belousov regs->tf_fs = _ufssel; 5362c66cccaSKonstantin Belousov regs->tf_gs = _ugssel; 5372c66cccaSKonstantin Belousov regs->tf_flags = TF_HASSEGS; 538ea0fabbcSTim J. Robbins PROC_LOCK(p); 539ea0fabbcSTim J. Robbins mtx_lock(&psp->ps_mtx); 540ea0fabbcSTim J. Robbins } 541ea0fabbcSTim J. Robbins 542ea0fabbcSTim J. Robbins /* 543ea0fabbcSTim J. Robbins * System call to cleanup state after a signal 544ea0fabbcSTim J. Robbins * has been taken. Reset signal mask and 545ea0fabbcSTim J. Robbins * stack state from context left by sendsig (above). 546ea0fabbcSTim J. Robbins * Return to previous pc and psl as specified by 547ea0fabbcSTim J. Robbins * context left by sendsig. Check carefully to 548ea0fabbcSTim J. Robbins * make sure that the user has not modified the 549ea0fabbcSTim J. Robbins * psl to gain improper privileges or to cause 550ea0fabbcSTim J. Robbins * a machine fault. 551ea0fabbcSTim J. Robbins */ 552ea0fabbcSTim J. Robbins int 553ea0fabbcSTim J. Robbins linux_sigreturn(struct thread *td, struct linux_sigreturn_args *args) 554ea0fabbcSTim J. Robbins { 555ea0fabbcSTim J. Robbins struct proc *p = td->td_proc; 556ea0fabbcSTim J. Robbins struct l_sigframe frame; 557ea0fabbcSTim J. Robbins struct trapframe *regs; 558ea0fabbcSTim J. Robbins l_sigset_t lmask; 559ea0fabbcSTim J. Robbins int eflags, i; 5609104847fSDavid Xu ksiginfo_t ksi; 561ea0fabbcSTim J. Robbins 562ea0fabbcSTim J. Robbins regs = td->td_frame; 563ea0fabbcSTim J. Robbins 564ea0fabbcSTim J. Robbins #ifdef DEBUG 565ea0fabbcSTim J. Robbins if (ldebug(sigreturn)) 566ea0fabbcSTim J. Robbins printf(ARGS(sigreturn, "%p"), (void *)args->sfp); 567ea0fabbcSTim J. Robbins #endif 568ea0fabbcSTim J. Robbins /* 569ea0fabbcSTim J. Robbins * The trampoline code hands us the sigframe. 570ea0fabbcSTim J. Robbins * It is unsafe to keep track of it ourselves, in the event that a 571ea0fabbcSTim J. Robbins * program jumps out of a signal handler. 572ea0fabbcSTim J. Robbins */ 573ea0fabbcSTim J. Robbins if (copyin(args->sfp, &frame, sizeof(frame)) != 0) 574ea0fabbcSTim J. Robbins return (EFAULT); 575ea0fabbcSTim J. Robbins 576ea0fabbcSTim J. Robbins /* 577ea0fabbcSTim J. Robbins * Check for security violations. 578ea0fabbcSTim J. Robbins */ 579ea0fabbcSTim J. Robbins #define EFLAGS_SECURE(ef, oef) ((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0) 580ea0fabbcSTim J. Robbins eflags = frame.sf_sc.sc_eflags; 581ea0fabbcSTim J. Robbins /* 582ea0fabbcSTim J. Robbins * XXX do allow users to change the privileged flag PSL_RF. The 583ea0fabbcSTim J. Robbins * cpu sets PSL_RF in tf_eflags for faults. Debuggers should 584ea0fabbcSTim J. Robbins * sometimes set it there too. tf_eflags is kept in the signal 585ea0fabbcSTim J. Robbins * context during signal handling and there is no other place 586ea0fabbcSTim J. Robbins * to remember it, so the PSL_RF bit may be corrupted by the 587ea0fabbcSTim J. Robbins * signal handler without us knowing. Corruption of the PSL_RF 588ea0fabbcSTim J. Robbins * bit at worst causes one more or one less debugger trap, so 589ea0fabbcSTim J. Robbins * allowing it is fairly harmless. 590ea0fabbcSTim J. Robbins */ 591ea0fabbcSTim J. Robbins if (!EFLAGS_SECURE(eflags & ~PSL_RF, regs->tf_rflags & ~PSL_RF)) 592ea0fabbcSTim J. Robbins return(EINVAL); 593ea0fabbcSTim J. Robbins 594ea0fabbcSTim J. Robbins /* 595ea0fabbcSTim J. Robbins * Don't allow users to load a valid privileged %cs. Let the 596ea0fabbcSTim J. Robbins * hardware check for invalid selectors, excess privilege in 597ea0fabbcSTim J. Robbins * other selectors, invalid %eip's and invalid %esp's. 598ea0fabbcSTim J. Robbins */ 599ea0fabbcSTim J. Robbins #define CS_SECURE(cs) (ISPL(cs) == SEL_UPL) 600ea0fabbcSTim J. Robbins if (!CS_SECURE(frame.sf_sc.sc_cs)) { 6019104847fSDavid Xu ksiginfo_init_trap(&ksi); 6029104847fSDavid Xu ksi.ksi_signo = SIGBUS; 6039104847fSDavid Xu ksi.ksi_code = BUS_OBJERR; 6049104847fSDavid Xu ksi.ksi_trapno = T_PROTFLT; 6059104847fSDavid Xu ksi.ksi_addr = (void *)regs->tf_rip; 6069104847fSDavid Xu trapsignal(td, &ksi); 607ea0fabbcSTim J. Robbins return(EINVAL); 608ea0fabbcSTim J. Robbins } 609ea0fabbcSTim J. Robbins 610ea0fabbcSTim J. Robbins lmask.__bits[0] = frame.sf_sc.sc_mask; 611ea0fabbcSTim J. Robbins for (i = 0; i < (LINUX_NSIG_WORDS-1); i++) 612ea0fabbcSTim J. Robbins lmask.__bits[i+1] = frame.sf_extramask[i]; 613ea0fabbcSTim J. Robbins PROC_LOCK(p); 614ea0fabbcSTim J. Robbins linux_to_bsd_sigset(&lmask, &td->td_sigmask); 615ea0fabbcSTim J. Robbins SIG_CANTMASK(td->td_sigmask); 616ea0fabbcSTim J. Robbins signotify(td); 617ea0fabbcSTim J. Robbins PROC_UNLOCK(p); 618ea0fabbcSTim J. Robbins 619ea0fabbcSTim J. Robbins /* 620ea0fabbcSTim J. Robbins * Restore signal context. 621ea0fabbcSTim J. Robbins */ 622ea0fabbcSTim J. Robbins regs->tf_rdi = frame.sf_sc.sc_edi; 623ea0fabbcSTim J. Robbins regs->tf_rsi = frame.sf_sc.sc_esi; 624ea0fabbcSTim J. Robbins regs->tf_rbp = frame.sf_sc.sc_ebp; 625ea0fabbcSTim J. Robbins regs->tf_rbx = frame.sf_sc.sc_ebx; 626ea0fabbcSTim J. Robbins regs->tf_rdx = frame.sf_sc.sc_edx; 627ea0fabbcSTim J. Robbins regs->tf_rcx = frame.sf_sc.sc_ecx; 628ea0fabbcSTim J. Robbins regs->tf_rax = frame.sf_sc.sc_eax; 629ea0fabbcSTim J. Robbins regs->tf_rip = frame.sf_sc.sc_eip; 630ea0fabbcSTim J. Robbins regs->tf_cs = frame.sf_sc.sc_cs; 6312c66cccaSKonstantin Belousov regs->tf_ds = frame.sf_sc.sc_ds; 6322c66cccaSKonstantin Belousov regs->tf_es = frame.sf_sc.sc_es; 6332c66cccaSKonstantin Belousov regs->tf_fs = frame.sf_sc.sc_fs; 6342c66cccaSKonstantin Belousov regs->tf_gs = frame.sf_sc.sc_gs; 635ea0fabbcSTim J. Robbins regs->tf_rflags = eflags; 636ea0fabbcSTim J. Robbins regs->tf_rsp = frame.sf_sc.sc_esp_at_signal; 637ea0fabbcSTim J. Robbins regs->tf_ss = frame.sf_sc.sc_ss; 638ea0fabbcSTim J. Robbins 639ea0fabbcSTim J. Robbins return (EJUSTRETURN); 640ea0fabbcSTim J. Robbins } 641ea0fabbcSTim J. Robbins 642ea0fabbcSTim J. Robbins /* 643ea0fabbcSTim J. Robbins * System call to cleanup state after a signal 644ea0fabbcSTim J. Robbins * has been taken. Reset signal mask and 645ea0fabbcSTim J. Robbins * stack state from context left by rt_sendsig (above). 646ea0fabbcSTim J. Robbins * Return to previous pc and psl as specified by 647ea0fabbcSTim J. Robbins * context left by sendsig. Check carefully to 648ea0fabbcSTim J. Robbins * make sure that the user has not modified the 649ea0fabbcSTim J. Robbins * psl to gain improper privileges or to cause 650ea0fabbcSTim J. Robbins * a machine fault. 651ea0fabbcSTim J. Robbins */ 652ea0fabbcSTim J. Robbins int 653ea0fabbcSTim J. Robbins linux_rt_sigreturn(struct thread *td, struct linux_rt_sigreturn_args *args) 654ea0fabbcSTim J. Robbins { 655ea0fabbcSTim J. Robbins struct proc *p = td->td_proc; 656ea0fabbcSTim J. Robbins struct l_ucontext uc; 657ea0fabbcSTim J. Robbins struct l_sigcontext *context; 658ea0fabbcSTim J. Robbins l_stack_t *lss; 659ea0fabbcSTim J. Robbins stack_t ss; 660ea0fabbcSTim J. Robbins struct trapframe *regs; 661ea0fabbcSTim J. Robbins int eflags; 6629104847fSDavid Xu ksiginfo_t ksi; 663ea0fabbcSTim J. Robbins 664ea0fabbcSTim J. Robbins regs = td->td_frame; 665ea0fabbcSTim J. Robbins 666ea0fabbcSTim J. Robbins #ifdef DEBUG 667ea0fabbcSTim J. Robbins if (ldebug(rt_sigreturn)) 668ea0fabbcSTim J. Robbins printf(ARGS(rt_sigreturn, "%p"), (void *)args->ucp); 669ea0fabbcSTim J. Robbins #endif 670ea0fabbcSTim J. Robbins /* 671ea0fabbcSTim J. Robbins * The trampoline code hands us the ucontext. 672ea0fabbcSTim J. Robbins * It is unsafe to keep track of it ourselves, in the event that a 673ea0fabbcSTim J. Robbins * program jumps out of a signal handler. 674ea0fabbcSTim J. Robbins */ 675ea0fabbcSTim J. Robbins if (copyin(args->ucp, &uc, sizeof(uc)) != 0) 676ea0fabbcSTim J. Robbins return (EFAULT); 677ea0fabbcSTim J. Robbins 678ea0fabbcSTim J. Robbins context = &uc.uc_mcontext; 679ea0fabbcSTim J. Robbins 680ea0fabbcSTim J. Robbins /* 681ea0fabbcSTim J. Robbins * Check for security violations. 682ea0fabbcSTim J. Robbins */ 683ea0fabbcSTim J. Robbins #define EFLAGS_SECURE(ef, oef) ((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0) 684ea0fabbcSTim J. Robbins eflags = context->sc_eflags; 685ea0fabbcSTim J. Robbins /* 686ea0fabbcSTim J. Robbins * XXX do allow users to change the privileged flag PSL_RF. The 687ea0fabbcSTim J. Robbins * cpu sets PSL_RF in tf_eflags for faults. Debuggers should 688ea0fabbcSTim J. Robbins * sometimes set it there too. tf_eflags is kept in the signal 689ea0fabbcSTim J. Robbins * context during signal handling and there is no other place 690ea0fabbcSTim J. Robbins * to remember it, so the PSL_RF bit may be corrupted by the 691ea0fabbcSTim J. Robbins * signal handler without us knowing. Corruption of the PSL_RF 692ea0fabbcSTim J. Robbins * bit at worst causes one more or one less debugger trap, so 693ea0fabbcSTim J. Robbins * allowing it is fairly harmless. 694ea0fabbcSTim J. Robbins */ 695ea0fabbcSTim J. Robbins if (!EFLAGS_SECURE(eflags & ~PSL_RF, regs->tf_rflags & ~PSL_RF)) 696ea0fabbcSTim J. Robbins return(EINVAL); 697ea0fabbcSTim J. Robbins 698ea0fabbcSTim J. Robbins /* 699ea0fabbcSTim J. Robbins * Don't allow users to load a valid privileged %cs. Let the 700ea0fabbcSTim J. Robbins * hardware check for invalid selectors, excess privilege in 701ea0fabbcSTim J. Robbins * other selectors, invalid %eip's and invalid %esp's. 702ea0fabbcSTim J. Robbins */ 703ea0fabbcSTim J. Robbins #define CS_SECURE(cs) (ISPL(cs) == SEL_UPL) 704ea0fabbcSTim J. Robbins if (!CS_SECURE(context->sc_cs)) { 7059104847fSDavid Xu ksiginfo_init_trap(&ksi); 7069104847fSDavid Xu ksi.ksi_signo = SIGBUS; 7079104847fSDavid Xu ksi.ksi_code = BUS_OBJERR; 7089104847fSDavid Xu ksi.ksi_trapno = T_PROTFLT; 7099104847fSDavid Xu ksi.ksi_addr = (void *)regs->tf_rip; 7109104847fSDavid Xu trapsignal(td, &ksi); 711ea0fabbcSTim J. Robbins return(EINVAL); 712ea0fabbcSTim J. Robbins } 713ea0fabbcSTim J. Robbins 714ea0fabbcSTim J. Robbins PROC_LOCK(p); 715ea0fabbcSTim J. Robbins linux_to_bsd_sigset(&uc.uc_sigmask, &td->td_sigmask); 716ea0fabbcSTim J. Robbins SIG_CANTMASK(td->td_sigmask); 717ea0fabbcSTim J. Robbins signotify(td); 718ea0fabbcSTim J. Robbins PROC_UNLOCK(p); 719ea0fabbcSTim J. Robbins 720ea0fabbcSTim J. Robbins /* 721ea0fabbcSTim J. Robbins * Restore signal context 722ea0fabbcSTim J. Robbins */ 7232c66cccaSKonstantin Belousov regs->tf_gs = context->sc_gs; 7242c66cccaSKonstantin Belousov regs->tf_fs = context->sc_fs; 7252c66cccaSKonstantin Belousov regs->tf_es = context->sc_es; 7262c66cccaSKonstantin Belousov regs->tf_ds = context->sc_ds; 727ea0fabbcSTim J. Robbins regs->tf_rdi = context->sc_edi; 728ea0fabbcSTim J. Robbins regs->tf_rsi = context->sc_esi; 729ea0fabbcSTim J. Robbins regs->tf_rbp = context->sc_ebp; 730ea0fabbcSTim J. Robbins regs->tf_rbx = context->sc_ebx; 731ea0fabbcSTim J. Robbins regs->tf_rdx = context->sc_edx; 732ea0fabbcSTim J. Robbins regs->tf_rcx = context->sc_ecx; 733ea0fabbcSTim J. Robbins regs->tf_rax = context->sc_eax; 734ea0fabbcSTim J. Robbins regs->tf_rip = context->sc_eip; 735ea0fabbcSTim J. Robbins regs->tf_cs = context->sc_cs; 736ea0fabbcSTim J. Robbins regs->tf_rflags = eflags; 737ea0fabbcSTim J. Robbins regs->tf_rsp = context->sc_esp_at_signal; 738ea0fabbcSTim J. Robbins regs->tf_ss = context->sc_ss; 739ea0fabbcSTim J. Robbins 740ea0fabbcSTim J. Robbins /* 741ea0fabbcSTim J. Robbins * call sigaltstack & ignore results.. 742ea0fabbcSTim J. Robbins */ 743ea0fabbcSTim J. Robbins lss = &uc.uc_stack; 744ea0fabbcSTim J. Robbins ss.ss_sp = PTRIN(lss->ss_sp); 745ea0fabbcSTim J. Robbins ss.ss_size = lss->ss_size; 746ea0fabbcSTim J. Robbins ss.ss_flags = linux_to_bsd_sigaltstack(lss->ss_flags); 747ea0fabbcSTim J. Robbins 748ea0fabbcSTim J. Robbins #ifdef DEBUG 749ea0fabbcSTim J. Robbins if (ldebug(rt_sigreturn)) 750c680f6b1SDavid E. O'Brien printf(LMSG("rt_sigret flags: 0x%x, sp: %p, ss: 0x%lx, mask: 0x%x"), 751ea0fabbcSTim J. Robbins ss.ss_flags, ss.ss_sp, ss.ss_size, context->sc_mask); 752ea0fabbcSTim J. Robbins #endif 753ea0fabbcSTim J. Robbins (void)kern_sigaltstack(td, &ss, NULL); 754ea0fabbcSTim J. Robbins 755ea0fabbcSTim J. Robbins return (EJUSTRETURN); 756ea0fabbcSTim J. Robbins } 757ea0fabbcSTim J. Robbins 758ea0fabbcSTim J. Robbins /* 759ea0fabbcSTim J. Robbins * MPSAFE 760ea0fabbcSTim J. Robbins */ 761ea0fabbcSTim J. Robbins static void 762ea0fabbcSTim J. Robbins linux_prepsyscall(struct trapframe *tf, int *args, u_int *code, caddr_t *params) 763ea0fabbcSTim J. Robbins { 764ea0fabbcSTim J. Robbins args[0] = tf->tf_rbx; 765ea0fabbcSTim J. Robbins args[1] = tf->tf_rcx; 766ea0fabbcSTim J. Robbins args[2] = tf->tf_rdx; 767ea0fabbcSTim J. Robbins args[3] = tf->tf_rsi; 768ea0fabbcSTim J. Robbins args[4] = tf->tf_rdi; 769ea0fabbcSTim J. Robbins args[5] = tf->tf_rbp; /* Unconfirmed */ 770ea0fabbcSTim J. Robbins *params = NULL; /* no copyin */ 771ea0fabbcSTim J. Robbins } 772ea0fabbcSTim J. Robbins 773ea0fabbcSTim J. Robbins /* 774ea0fabbcSTim J. Robbins * If a linux binary is exec'ing something, try this image activator 775ea0fabbcSTim J. Robbins * first. We override standard shell script execution in order to 776ea0fabbcSTim J. Robbins * be able to modify the interpreter path. We only do this if a linux 777ea0fabbcSTim J. Robbins * binary is doing the exec, so we do not create an EXEC module for it. 778ea0fabbcSTim J. Robbins */ 779ea0fabbcSTim J. Robbins static int exec_linux_imgact_try(struct image_params *iparams); 780ea0fabbcSTim J. Robbins 781ea0fabbcSTim J. Robbins static int 782ea0fabbcSTim J. Robbins exec_linux_imgact_try(struct image_params *imgp) 783ea0fabbcSTim J. Robbins { 784ea0fabbcSTim J. Robbins const char *head = (const char *)imgp->image_header; 7851d15fdd9SJohn Baldwin char *rpath; 7861d15fdd9SJohn Baldwin int error = -1, len; 787ea0fabbcSTim J. Robbins 788ea0fabbcSTim J. Robbins /* 789ea0fabbcSTim J. Robbins * The interpreter for shell scripts run from a linux binary needs 790ea0fabbcSTim J. Robbins * to be located in /compat/linux if possible in order to recursively 791ea0fabbcSTim J. Robbins * maintain linux path emulation. 792ea0fabbcSTim J. Robbins */ 793ea0fabbcSTim J. Robbins if (((const short *)head)[0] == SHELLMAGIC) { 794ea0fabbcSTim J. Robbins /* 795ea0fabbcSTim J. Robbins * Run our normal shell image activator. If it succeeds attempt 796d065e13dSDavid E. O'Brien * to use the alternate path for the interpreter. If an 797d065e13dSDavid E. O'Brien * alternate * path is found, use our stringspace to store it. 798ea0fabbcSTim J. Robbins */ 799ea0fabbcSTim J. Robbins if ((error = exec_shell_imgact(imgp)) == 0) { 8001d15fdd9SJohn Baldwin linux_emul_convpath(FIRST_THREAD_IN_PROC(imgp->proc), 801d065e13dSDavid E. O'Brien imgp->interpreter_name, UIO_SYSSPACE, &rpath, 0, 802d065e13dSDavid E. O'Brien AT_FDCWD); 8031d15fdd9SJohn Baldwin if (rpath != NULL) { 8041d15fdd9SJohn Baldwin len = strlen(rpath) + 1; 805ea0fabbcSTim J. Robbins 806ea0fabbcSTim J. Robbins if (len <= MAXSHELLCMDLEN) { 807d065e13dSDavid E. O'Brien memcpy(imgp->interpreter_name, rpath, 808d065e13dSDavid E. O'Brien len); 809ea0fabbcSTim J. Robbins } 810ea0fabbcSTim J. Robbins free(rpath, M_TEMP); 811ea0fabbcSTim J. Robbins } 812ea0fabbcSTim J. Robbins } 813ea0fabbcSTim J. Robbins } 814ea0fabbcSTim J. Robbins return(error); 815ea0fabbcSTim J. Robbins } 816ea0fabbcSTim J. Robbins 817ea0fabbcSTim J. Robbins /* 818ea0fabbcSTim J. Robbins * Clear registers on exec 819ea0fabbcSTim J. Robbins * XXX copied from ia32_signal.c. 820ea0fabbcSTim J. Robbins */ 821ea0fabbcSTim J. Robbins static void 822ea0fabbcSTim J. Robbins exec_linux_setregs(td, entry, stack, ps_strings) 823ea0fabbcSTim J. Robbins struct thread *td; 824ea0fabbcSTim J. Robbins u_long entry; 825ea0fabbcSTim J. Robbins u_long stack; 826ea0fabbcSTim J. Robbins u_long ps_strings; 827ea0fabbcSTim J. Robbins { 828ea0fabbcSTim J. Robbins struct trapframe *regs = td->td_frame; 829ea0fabbcSTim J. Robbins struct pcb *pcb = td->td_pcb; 830ea0fabbcSTim J. Robbins 8312c66cccaSKonstantin Belousov mtx_lock(&dt_lock); 8322c66cccaSKonstantin Belousov if (td->td_proc->p_md.md_ldt != NULL) 8332c66cccaSKonstantin Belousov user_ldt_free(td); 8342c66cccaSKonstantin Belousov else 8352c66cccaSKonstantin Belousov mtx_unlock(&dt_lock); 8362c66cccaSKonstantin Belousov 8379c5b213eSJung-uk Kim critical_enter(); 838ea0fabbcSTim J. Robbins wrmsr(MSR_FSBASE, 0); 839ea0fabbcSTim J. Robbins wrmsr(MSR_KGSBASE, 0); /* User value while we're in the kernel */ 840ea0fabbcSTim J. Robbins pcb->pcb_fsbase = 0; 841ea0fabbcSTim J. Robbins pcb->pcb_gsbase = 0; 8429c5b213eSJung-uk Kim critical_exit(); 8432ee8325fSJohn Baldwin pcb->pcb_initial_fpucw = __LINUX_NPXCW__; 844ea0fabbcSTim J. Robbins 845ea0fabbcSTim J. Robbins bzero((char *)regs, sizeof(struct trapframe)); 846ea0fabbcSTim J. Robbins regs->tf_rip = entry; 847ea0fabbcSTim J. Robbins regs->tf_rsp = stack; 848ea0fabbcSTim J. Robbins regs->tf_rflags = PSL_USER | (regs->tf_rflags & PSL_T); 8492c66cccaSKonstantin Belousov regs->tf_gs = _ugssel; 8502c66cccaSKonstantin Belousov regs->tf_fs = _ufssel; 8512c66cccaSKonstantin Belousov regs->tf_es = _udatasel; 8522c66cccaSKonstantin Belousov regs->tf_ds = _udatasel; 853ea0fabbcSTim J. Robbins regs->tf_ss = _udatasel; 8542c66cccaSKonstantin Belousov regs->tf_flags = TF_HASSEGS; 855ea0fabbcSTim J. Robbins regs->tf_cs = _ucode32sel; 856ea0fabbcSTim J. Robbins regs->tf_rbx = ps_strings; 857ea0fabbcSTim J. Robbins load_cr0(rcr0() | CR0_MP | CR0_TS); 8582a988f7cSStephan Uphoff fpstate_drop(td); 859ea0fabbcSTim J. Robbins 860ea0fabbcSTim J. Robbins /* Return via doreti so that we can change to a different %cs */ 861f1f0dd9eSKonstantin Belousov pcb->pcb_flags |= PCB_FULLCTX | PCB_32BIT; 862f1f0dd9eSKonstantin Belousov pcb->pcb_flags &= ~PCB_GS32BIT; 863ea0fabbcSTim J. Robbins td->td_retval[1] = 0; 864ea0fabbcSTim J. Robbins } 865ea0fabbcSTim J. Robbins 866ea0fabbcSTim J. Robbins /* 867ea0fabbcSTim J. Robbins * XXX copied from ia32_sysvec.c. 868ea0fabbcSTim J. Robbins */ 869ea0fabbcSTim J. Robbins static register_t * 870ea0fabbcSTim J. Robbins linux_copyout_strings(struct image_params *imgp) 871ea0fabbcSTim J. Robbins { 872ea0fabbcSTim J. Robbins int argc, envc; 873ea0fabbcSTim J. Robbins u_int32_t *vectp; 874ea0fabbcSTim J. Robbins char *stringp, *destp; 875ea0fabbcSTim J. Robbins u_int32_t *stack_base; 876ea0fabbcSTim J. Robbins struct linux32_ps_strings *arginfo; 877ea0fabbcSTim J. Robbins 878ea0fabbcSTim J. Robbins /* 879ea0fabbcSTim J. Robbins * Calculate string base and vector table pointers. 880ea0fabbcSTim J. Robbins * Also deal with signal trampoline code for this exec type. 881ea0fabbcSTim J. Robbins */ 882ea0fabbcSTim J. Robbins arginfo = (struct linux32_ps_strings *)LINUX32_PS_STRINGS; 8834d7c2e8aSDmitry Chagin destp = (caddr_t)arginfo - linux_szsigcode - SPARE_USRSPACE - 8844d7c2e8aSDmitry Chagin linux_szplatform - roundup((ARG_MAX - imgp->args->stringspace), 8854d7c2e8aSDmitry Chagin sizeof(char *)); 886ea0fabbcSTim J. Robbins 887ea0fabbcSTim J. Robbins /* 888ea0fabbcSTim J. Robbins * install sigcode 889ea0fabbcSTim J. Robbins */ 890ea0fabbcSTim J. Robbins copyout(imgp->proc->p_sysent->sv_sigcode, 8914d7c2e8aSDmitry Chagin ((caddr_t)arginfo - linux_szsigcode), linux_szsigcode); 8924d7c2e8aSDmitry Chagin 8934d7c2e8aSDmitry Chagin /* 8944d7c2e8aSDmitry Chagin * Install LINUX_PLATFORM 8954d7c2e8aSDmitry Chagin */ 8964d7c2e8aSDmitry Chagin copyout(linux_platform, ((caddr_t)arginfo - linux_szsigcode - 8974d7c2e8aSDmitry Chagin linux_szplatform), linux_szplatform); 898ea0fabbcSTim J. Robbins 899ea0fabbcSTim J. Robbins /* 900ea0fabbcSTim J. Robbins * If we have a valid auxargs ptr, prepare some room 901ea0fabbcSTim J. Robbins * on the stack. 902ea0fabbcSTim J. Robbins */ 903ea0fabbcSTim J. Robbins if (imgp->auxargs) { 904ea0fabbcSTim J. Robbins /* 905ea0fabbcSTim J. Robbins * 'AT_COUNT*2' is size for the ELF Auxargs data. This is for 906ea0fabbcSTim J. Robbins * lower compatibility. 907ea0fabbcSTim J. Robbins */ 908d065e13dSDavid E. O'Brien imgp->auxarg_size = (imgp->auxarg_size) ? imgp->auxarg_size : 9094d7c2e8aSDmitry Chagin (LINUX_AT_COUNT * 2); 910ea0fabbcSTim J. Robbins /* 911ea0fabbcSTim J. Robbins * The '+ 2' is for the null pointers at the end of each of 912ea0fabbcSTim J. Robbins * the arg and env vector sets,and imgp->auxarg_size is room 913ea0fabbcSTim J. Robbins * for argument of Runtime loader. 914ea0fabbcSTim J. Robbins */ 915d065e13dSDavid E. O'Brien vectp = (u_int32_t *) (destp - (imgp->args->argc + 916d065e13dSDavid E. O'Brien imgp->args->envc + 2 + imgp->auxarg_size) * 917d065e13dSDavid E. O'Brien sizeof(u_int32_t)); 918ea0fabbcSTim J. Robbins 919ea0fabbcSTim J. Robbins } else 920ea0fabbcSTim J. Robbins /* 921ea0fabbcSTim J. Robbins * The '+ 2' is for the null pointers at the end of each of 922ea0fabbcSTim J. Robbins * the arg and env vector sets 923ea0fabbcSTim J. Robbins */ 924d065e13dSDavid E. O'Brien vectp = (u_int32_t *)(destp - (imgp->args->argc + 925d065e13dSDavid E. O'Brien imgp->args->envc + 2) * sizeof(u_int32_t)); 926ea0fabbcSTim J. Robbins 927ea0fabbcSTim J. Robbins /* 928ea0fabbcSTim J. Robbins * vectp also becomes our initial stack base 929ea0fabbcSTim J. Robbins */ 930ea0fabbcSTim J. Robbins stack_base = vectp; 931ea0fabbcSTim J. Robbins 932610ecfe0SMaxim Sobolev stringp = imgp->args->begin_argv; 933610ecfe0SMaxim Sobolev argc = imgp->args->argc; 934610ecfe0SMaxim Sobolev envc = imgp->args->envc; 935ea0fabbcSTim J. Robbins /* 936ea0fabbcSTim J. Robbins * Copy out strings - arguments and environment. 937ea0fabbcSTim J. Robbins */ 938610ecfe0SMaxim Sobolev copyout(stringp, destp, ARG_MAX - imgp->args->stringspace); 939ea0fabbcSTim J. Robbins 940ea0fabbcSTim J. Robbins /* 941ea0fabbcSTim J. Robbins * Fill in "ps_strings" struct for ps, w, etc. 942ea0fabbcSTim J. Robbins */ 9434d7c2e8aSDmitry Chagin suword32(&arginfo->ps_argvstr, (uint32_t)(intptr_t)vectp); 944ea0fabbcSTim J. Robbins suword32(&arginfo->ps_nargvstr, argc); 945ea0fabbcSTim J. Robbins 946ea0fabbcSTim J. Robbins /* 947ea0fabbcSTim J. Robbins * Fill in argument portion of vector table. 948ea0fabbcSTim J. Robbins */ 949ea0fabbcSTim J. Robbins for (; argc > 0; --argc) { 9504d7c2e8aSDmitry Chagin suword32(vectp++, (uint32_t)(intptr_t)destp); 951ea0fabbcSTim J. Robbins while (*stringp++ != 0) 952ea0fabbcSTim J. Robbins destp++; 953ea0fabbcSTim J. Robbins destp++; 954ea0fabbcSTim J. Robbins } 955ea0fabbcSTim J. Robbins 956ea0fabbcSTim J. Robbins /* a null vector table pointer separates the argp's from the envp's */ 957ea0fabbcSTim J. Robbins suword32(vectp++, 0); 958ea0fabbcSTim J. Robbins 9594d7c2e8aSDmitry Chagin suword32(&arginfo->ps_envstr, (uint32_t)(intptr_t)vectp); 960ea0fabbcSTim J. Robbins suword32(&arginfo->ps_nenvstr, envc); 961ea0fabbcSTim J. Robbins 962ea0fabbcSTim J. Robbins /* 963ea0fabbcSTim J. Robbins * Fill in environment portion of vector table. 964ea0fabbcSTim J. Robbins */ 965ea0fabbcSTim J. Robbins for (; envc > 0; --envc) { 9664d7c2e8aSDmitry Chagin suword32(vectp++, (uint32_t)(intptr_t)destp); 967ea0fabbcSTim J. Robbins while (*stringp++ != 0) 968ea0fabbcSTim J. Robbins destp++; 969ea0fabbcSTim J. Robbins destp++; 970ea0fabbcSTim J. Robbins } 971ea0fabbcSTim J. Robbins 972ea0fabbcSTim J. Robbins /* end of vector table is a null pointer */ 973ea0fabbcSTim J. Robbins suword32(vectp, 0); 974ea0fabbcSTim J. Robbins 975ea0fabbcSTim J. Robbins return ((register_t *)stack_base); 976ea0fabbcSTim J. Robbins } 977ea0fabbcSTim J. Robbins 978ea0fabbcSTim J. Robbins SYSCTL_NODE(_compat, OID_AUTO, linux32, CTLFLAG_RW, 0, 979ea0fabbcSTim J. Robbins "32-bit Linux emulation"); 980ea0fabbcSTim J. Robbins 981ea0fabbcSTim J. Robbins static u_long linux32_maxdsiz = LINUX32_MAXDSIZ; 982ea0fabbcSTim J. Robbins SYSCTL_ULONG(_compat_linux32, OID_AUTO, maxdsiz, CTLFLAG_RW, 983ea0fabbcSTim J. Robbins &linux32_maxdsiz, 0, ""); 984ea0fabbcSTim J. Robbins static u_long linux32_maxssiz = LINUX32_MAXSSIZ; 985ea0fabbcSTim J. Robbins SYSCTL_ULONG(_compat_linux32, OID_AUTO, maxssiz, CTLFLAG_RW, 986ea0fabbcSTim J. Robbins &linux32_maxssiz, 0, ""); 987ea0fabbcSTim J. Robbins static u_long linux32_maxvmem = LINUX32_MAXVMEM; 988ea0fabbcSTim J. Robbins SYSCTL_ULONG(_compat_linux32, OID_AUTO, maxvmem, CTLFLAG_RW, 989ea0fabbcSTim J. Robbins &linux32_maxvmem, 0, ""); 990ea0fabbcSTim J. Robbins 991ea0fabbcSTim J. Robbins static void 99219059a13SJohn Baldwin linux32_fixlimit(struct rlimit *rl, int which) 993ea0fabbcSTim J. Robbins { 994ea0fabbcSTim J. Robbins 99519059a13SJohn Baldwin switch (which) { 99619059a13SJohn Baldwin case RLIMIT_DATA: 997ea0fabbcSTim J. Robbins if (linux32_maxdsiz != 0) { 99819059a13SJohn Baldwin if (rl->rlim_cur > linux32_maxdsiz) 99919059a13SJohn Baldwin rl->rlim_cur = linux32_maxdsiz; 100019059a13SJohn Baldwin if (rl->rlim_max > linux32_maxdsiz) 100119059a13SJohn Baldwin rl->rlim_max = linux32_maxdsiz; 1002ea0fabbcSTim J. Robbins } 100319059a13SJohn Baldwin break; 100419059a13SJohn Baldwin case RLIMIT_STACK: 1005ea0fabbcSTim J. Robbins if (linux32_maxssiz != 0) { 100619059a13SJohn Baldwin if (rl->rlim_cur > linux32_maxssiz) 100719059a13SJohn Baldwin rl->rlim_cur = linux32_maxssiz; 100819059a13SJohn Baldwin if (rl->rlim_max > linux32_maxssiz) 100919059a13SJohn Baldwin rl->rlim_max = linux32_maxssiz; 1010ea0fabbcSTim J. Robbins } 101119059a13SJohn Baldwin break; 101219059a13SJohn Baldwin case RLIMIT_VMEM: 1013ea0fabbcSTim J. Robbins if (linux32_maxvmem != 0) { 101419059a13SJohn Baldwin if (rl->rlim_cur > linux32_maxvmem) 101519059a13SJohn Baldwin rl->rlim_cur = linux32_maxvmem; 101619059a13SJohn Baldwin if (rl->rlim_max > linux32_maxvmem) 101719059a13SJohn Baldwin rl->rlim_max = linux32_maxvmem; 1018ea0fabbcSTim J. Robbins } 101919059a13SJohn Baldwin break; 102019059a13SJohn Baldwin } 1021ea0fabbcSTim J. Robbins } 1022ea0fabbcSTim J. Robbins 1023ea0fabbcSTim J. Robbins struct sysentvec elf_linux_sysvec = { 1024a8d403e1SKonstantin Belousov .sv_size = LINUX_SYS_MAXSYSCALL, 1025a8d403e1SKonstantin Belousov .sv_table = linux_sysent, 1026a8d403e1SKonstantin Belousov .sv_mask = 0, 1027a8d403e1SKonstantin Belousov .sv_sigsize = LINUX_SIGTBLSZ, 1028a8d403e1SKonstantin Belousov .sv_sigtbl = bsd_to_linux_signal, 1029a8d403e1SKonstantin Belousov .sv_errsize = ELAST + 1, 1030a8d403e1SKonstantin Belousov .sv_errtbl = bsd_to_linux_errno, 1031a8d403e1SKonstantin Belousov .sv_transtrap = translate_traps, 1032a8d403e1SKonstantin Belousov .sv_fixup = elf_linux_fixup, 1033a8d403e1SKonstantin Belousov .sv_sendsig = linux_sendsig, 1034a8d403e1SKonstantin Belousov .sv_sigcode = linux_sigcode, 1035a8d403e1SKonstantin Belousov .sv_szsigcode = &linux_szsigcode, 1036a8d403e1SKonstantin Belousov .sv_prepsyscall = linux_prepsyscall, 1037a8d403e1SKonstantin Belousov .sv_name = "Linux ELF32", 1038a8d403e1SKonstantin Belousov .sv_coredump = elf32_coredump, 1039a8d403e1SKonstantin Belousov .sv_imgact_try = exec_linux_imgact_try, 1040a8d403e1SKonstantin Belousov .sv_minsigstksz = LINUX_MINSIGSTKSZ, 1041a8d403e1SKonstantin Belousov .sv_pagesize = PAGE_SIZE, 1042a8d403e1SKonstantin Belousov .sv_minuser = VM_MIN_ADDRESS, 1043a8d403e1SKonstantin Belousov .sv_maxuser = LINUX32_USRSTACK, 1044a8d403e1SKonstantin Belousov .sv_usrstack = LINUX32_USRSTACK, 1045a8d403e1SKonstantin Belousov .sv_psstrings = LINUX32_PS_STRINGS, 1046a8d403e1SKonstantin Belousov .sv_stackprot = VM_PROT_ALL, 1047a8d403e1SKonstantin Belousov .sv_copyout_strings = linux_copyout_strings, 1048a8d403e1SKonstantin Belousov .sv_setregs = exec_linux_setregs, 1049a8d403e1SKonstantin Belousov .sv_fixlimit = linux32_fixlimit, 1050a8d403e1SKonstantin Belousov .sv_maxssiz = &linux32_maxssiz, 1051b4cf0e62SKonstantin Belousov .sv_flags = SV_ABI_LINUX | SV_ILP32 | SV_IA32 1052ea0fabbcSTim J. Robbins }; 1053ea0fabbcSTim J. Robbins 105432c01de2SDmitry Chagin static char GNULINUX_ABI_VENDOR[] = "GNU"; 105532c01de2SDmitry Chagin 105632c01de2SDmitry Chagin static Elf_Brandnote linux32_brandnote = { 105732c01de2SDmitry Chagin .hdr.n_namesz = sizeof(GNULINUX_ABI_VENDOR), 105832c01de2SDmitry Chagin .hdr.n_descsz = 16, 105932c01de2SDmitry Chagin .hdr.n_type = 1, 106032c01de2SDmitry Chagin .vendor = GNULINUX_ABI_VENDOR, 106132c01de2SDmitry Chagin .flags = 0 106232c01de2SDmitry Chagin }; 106332c01de2SDmitry Chagin 1064ea0fabbcSTim J. Robbins static Elf32_Brandinfo linux_brand = { 1065a8d403e1SKonstantin Belousov .brand = ELFOSABI_LINUX, 1066a8d403e1SKonstantin Belousov .machine = EM_386, 1067a8d403e1SKonstantin Belousov .compat_3_brand = "Linux", 1068a8d403e1SKonstantin Belousov .emul_path = "/compat/linux", 1069a8d403e1SKonstantin Belousov .interp_path = "/lib/ld-linux.so.1", 1070a8d403e1SKonstantin Belousov .sysvec = &elf_linux_sysvec, 1071a8d403e1SKonstantin Belousov .interp_newpath = NULL, 107232c01de2SDmitry Chagin .brand_note = &linux32_brandnote, 1073cd899aadSDmitry Chagin .flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE 1074ea0fabbcSTim J. Robbins }; 1075ea0fabbcSTim J. Robbins 1076ea0fabbcSTim J. Robbins static Elf32_Brandinfo linux_glibc2brand = { 1077a8d403e1SKonstantin Belousov .brand = ELFOSABI_LINUX, 1078a8d403e1SKonstantin Belousov .machine = EM_386, 1079a8d403e1SKonstantin Belousov .compat_3_brand = "Linux", 1080a8d403e1SKonstantin Belousov .emul_path = "/compat/linux", 1081a8d403e1SKonstantin Belousov .interp_path = "/lib/ld-linux.so.2", 1082a8d403e1SKonstantin Belousov .sysvec = &elf_linux_sysvec, 1083a8d403e1SKonstantin Belousov .interp_newpath = NULL, 108432c01de2SDmitry Chagin .brand_note = &linux32_brandnote, 1085cd899aadSDmitry Chagin .flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE 1086ea0fabbcSTim J. Robbins }; 1087ea0fabbcSTim J. Robbins 1088ea0fabbcSTim J. Robbins Elf32_Brandinfo *linux_brandlist[] = { 1089ea0fabbcSTim J. Robbins &linux_brand, 1090ea0fabbcSTim J. Robbins &linux_glibc2brand, 1091ea0fabbcSTim J. Robbins NULL 1092ea0fabbcSTim J. Robbins }; 1093ea0fabbcSTim J. Robbins 1094ea0fabbcSTim J. Robbins static int 1095ea0fabbcSTim J. Robbins linux_elf_modevent(module_t mod, int type, void *data) 1096ea0fabbcSTim J. Robbins { 1097ea0fabbcSTim J. Robbins Elf32_Brandinfo **brandinfo; 1098ea0fabbcSTim J. Robbins int error; 1099ea0fabbcSTim J. Robbins struct linux_ioctl_handler **lihp; 1100387196bfSDoug Ambrisko struct linux_device_handler **ldhp; 1101ea0fabbcSTim J. Robbins 1102ea0fabbcSTim J. Robbins error = 0; 1103ea0fabbcSTim J. Robbins 1104ea0fabbcSTim J. Robbins switch(type) { 1105ea0fabbcSTim J. Robbins case MOD_LOAD: 1106ea0fabbcSTim J. Robbins for (brandinfo = &linux_brandlist[0]; *brandinfo != NULL; 1107ea0fabbcSTim J. Robbins ++brandinfo) 1108ea0fabbcSTim J. Robbins if (elf32_insert_brand_entry(*brandinfo) < 0) 1109ea0fabbcSTim J. Robbins error = EINVAL; 1110ea0fabbcSTim J. Robbins if (error == 0) { 1111ea0fabbcSTim J. Robbins SET_FOREACH(lihp, linux_ioctl_handler_set) 1112ea0fabbcSTim J. Robbins linux_ioctl_register_handler(*lihp); 1113387196bfSDoug Ambrisko SET_FOREACH(ldhp, linux_device_handler_set) 1114387196bfSDoug Ambrisko linux_device_register_handler(*ldhp); 1115357afa71SJung-uk Kim mtx_init(&emul_lock, "emuldata lock", NULL, MTX_DEF); 11167c09e6c0SAlexander Leidinger sx_init(&emul_shared_lock, "emuldata->shared lock"); 11177c09e6c0SAlexander Leidinger LIST_INIT(&futex_list); 111879262bf1SDmitry Chagin mtx_init(&futex_mtx, "ftllk", NULL, MTX_DEF); 1119d065e13dSDavid E. O'Brien linux_exit_tag = EVENTHANDLER_REGISTER(process_exit, 1120d065e13dSDavid E. O'Brien linux_proc_exit, NULL, 1000); 1121d065e13dSDavid E. O'Brien linux_schedtail_tag = EVENTHANDLER_REGISTER(schedtail, 1122d065e13dSDavid E. O'Brien linux_schedtail, NULL, 1000); 1123d065e13dSDavid E. O'Brien linux_exec_tag = EVENTHANDLER_REGISTER(process_exec, 1124d065e13dSDavid E. O'Brien linux_proc_exec, NULL, 1000); 11254d7c2e8aSDmitry Chagin linux_szplatform = roundup(strlen(linux_platform) + 1, 11264d7c2e8aSDmitry Chagin sizeof(char *)); 11277ae27ff4SJamie Gritton linux_osd_jail_register(); 11281ca16454SDmitry Chagin stclohz = (stathz ? stathz : hz); 1129ea0fabbcSTim J. Robbins if (bootverbose) 1130ea0fabbcSTim J. Robbins printf("Linux ELF exec handler installed\n"); 1131ea0fabbcSTim J. Robbins } else 1132ea0fabbcSTim J. Robbins printf("cannot insert Linux ELF brand handler\n"); 1133ea0fabbcSTim J. Robbins break; 1134ea0fabbcSTim J. Robbins case MOD_UNLOAD: 1135ea0fabbcSTim J. Robbins for (brandinfo = &linux_brandlist[0]; *brandinfo != NULL; 1136ea0fabbcSTim J. Robbins ++brandinfo) 1137ea0fabbcSTim J. Robbins if (elf32_brand_inuse(*brandinfo)) 1138ea0fabbcSTim J. Robbins error = EBUSY; 1139ea0fabbcSTim J. Robbins if (error == 0) { 1140ea0fabbcSTim J. Robbins for (brandinfo = &linux_brandlist[0]; 1141ea0fabbcSTim J. Robbins *brandinfo != NULL; ++brandinfo) 1142ea0fabbcSTim J. Robbins if (elf32_remove_brand_entry(*brandinfo) < 0) 1143ea0fabbcSTim J. Robbins error = EINVAL; 1144ea0fabbcSTim J. Robbins } 1145ea0fabbcSTim J. Robbins if (error == 0) { 1146ea0fabbcSTim J. Robbins SET_FOREACH(lihp, linux_ioctl_handler_set) 1147ea0fabbcSTim J. Robbins linux_ioctl_unregister_handler(*lihp); 1148387196bfSDoug Ambrisko SET_FOREACH(ldhp, linux_device_handler_set) 1149387196bfSDoug Ambrisko linux_device_unregister_handler(*ldhp); 1150357afa71SJung-uk Kim mtx_destroy(&emul_lock); 11517c09e6c0SAlexander Leidinger sx_destroy(&emul_shared_lock); 115279262bf1SDmitry Chagin mtx_destroy(&futex_mtx); 11537c09e6c0SAlexander Leidinger EVENTHANDLER_DEREGISTER(process_exit, linux_exit_tag); 11547c09e6c0SAlexander Leidinger EVENTHANDLER_DEREGISTER(schedtail, linux_schedtail_tag); 11557c09e6c0SAlexander Leidinger EVENTHANDLER_DEREGISTER(process_exec, linux_exec_tag); 11567ae27ff4SJamie Gritton linux_osd_jail_deregister(); 1157ea0fabbcSTim J. Robbins if (bootverbose) 1158ea0fabbcSTim J. Robbins printf("Linux ELF exec handler removed\n"); 1159ea0fabbcSTim J. Robbins } else 1160ea0fabbcSTim J. Robbins printf("Could not deinstall ELF interpreter entry\n"); 1161ea0fabbcSTim J. Robbins break; 1162ea0fabbcSTim J. Robbins default: 1163786e4fc4SAlexander Leidinger return EOPNOTSUPP; 1164ea0fabbcSTim J. Robbins } 1165ea0fabbcSTim J. Robbins return error; 1166ea0fabbcSTim J. Robbins } 1167ea0fabbcSTim J. Robbins 1168ea0fabbcSTim J. Robbins static moduledata_t linux_elf_mod = { 1169ea0fabbcSTim J. Robbins "linuxelf", 1170ea0fabbcSTim J. Robbins linux_elf_modevent, 1171ea0fabbcSTim J. Robbins 0 1172ea0fabbcSTim J. Robbins }; 1173ea0fabbcSTim J. Robbins 1174ea0fabbcSTim J. Robbins DECLARE_MODULE(linuxelf, linux_elf_mod, SI_SUB_EXEC, SI_ORDER_ANY); 1175