1d66a5066SPeter Wemm /*- 2e1743d02SSøren Schmidt * Copyright (c) 1994-1996 S�ren Schmidt 3d66a5066SPeter Wemm * All rights reserved. 4d66a5066SPeter Wemm * 5d66a5066SPeter Wemm * Redistribution and use in source and binary forms, with or without 6d66a5066SPeter Wemm * modification, are permitted provided that the following conditions 7d66a5066SPeter Wemm * are met: 8d66a5066SPeter Wemm * 1. Redistributions of source code must retain the above copyright 9d66a5066SPeter Wemm * notice, this list of conditions and the following disclaimer 10d66a5066SPeter Wemm * in this position and unchanged. 11d66a5066SPeter Wemm * 2. Redistributions in binary form must reproduce the above copyright 12d66a5066SPeter Wemm * notice, this list of conditions and the following disclaimer in the 13d66a5066SPeter Wemm * documentation and/or other materials provided with the distribution. 14d66a5066SPeter Wemm * 3. The name of the author may not be used to endorse or promote products 15d66a5066SPeter Wemm * derived from this software withough specific prior written permission 16d66a5066SPeter Wemm * 17d66a5066SPeter Wemm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18d66a5066SPeter Wemm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19d66a5066SPeter Wemm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20d66a5066SPeter Wemm * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21d66a5066SPeter Wemm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22d66a5066SPeter Wemm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23d66a5066SPeter Wemm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24d66a5066SPeter Wemm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25d66a5066SPeter Wemm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26d66a5066SPeter Wemm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27d66a5066SPeter Wemm * 286626c604SJulian Elischer * $Id: linux_sysvec.c,v 1.40 1998/12/16 16:28:57 bde Exp $ 29d66a5066SPeter Wemm */ 30d66a5066SPeter Wemm 31d66a5066SPeter Wemm /* XXX we use functions that might not exist. */ 325591b823SEivind Eklund #include "opt_compat.h" 335591b823SEivind Eklund 345591b823SEivind Eklund #ifndef COMPAT_43 355591b823SEivind Eklund #error "Unable to compile Linux-emulator due to missing COMPAT_43 option!" 365591b823SEivind Eklund #endif 37d66a5066SPeter Wemm 38d66a5066SPeter Wemm #include <sys/param.h> 395e26fb6fSJordan K. Hubbard #include <sys/buf.h> 40aad9af2bSBruce Evans #include <sys/proc.h> 41d66a5066SPeter Wemm #include <sys/systm.h> 42d66a5066SPeter Wemm #include <sys/sysent.h> 43d66a5066SPeter Wemm #include <sys/imgact.h> 4422d4b0fbSJohn Polstra #include <sys/imgact_aout.h> 45e1743d02SSøren Schmidt #include <sys/imgact_elf.h> 46d66a5066SPeter Wemm #include <sys/signalvar.h> 47e1743d02SSøren Schmidt #include <sys/malloc.h> 48d66a5066SPeter Wemm #include <vm/vm.h> 49d66a5066SPeter Wemm #include <vm/vm_param.h> 50d66a5066SPeter Wemm #include <vm/vm_prot.h> 51d66a5066SPeter Wemm #include <vm/vm_page.h> 52d66a5066SPeter Wemm #include <vm/vm_extern.h> 536626c604SJulian Elischer #ifdef COMPAT_LINUX_THREADS 546626c604SJulian Elischer #include <sys/lock.h> /* needed, for now, by vm_map.h */ 556626c604SJulian Elischer #include <vm/vm_map.h> /* needed, for now, for VM_STACK defines */ 566626c604SJulian Elischer #endif /* COMPAT_LINUX_THREADS */ 57d66a5066SPeter Wemm #include <sys/exec.h> 585cf588ebSPeter Wemm #include <sys/kernel.h> 59aa855a59SPeter Wemm #include <sys/module.h> 60d66a5066SPeter Wemm #include <machine/cpu.h> 61d66a5066SPeter Wemm 62d66a5066SPeter Wemm #include <i386/linux/linux.h> 63d66a5066SPeter Wemm #include <i386/linux/linux_proto.h> 64e1743d02SSøren Schmidt 65ecbb00a2SDoug Rabson static int linux_fixup __P((long **stack_base, 66303b270bSEivind Eklund struct image_params *iparams)); 67ecbb00a2SDoug Rabson static int elf_linux_fixup __P((long **stack_base, 68303b270bSEivind Eklund struct image_params *iparams)); 69303b270bSEivind Eklund static void linux_prepsyscall __P((struct trapframe *tf, int *args, 70303b270bSEivind Eklund u_int *code, caddr_t *params)); 71303b270bSEivind Eklund static void linux_sendsig __P((sig_t catcher, int sig, int mask, 72303b270bSEivind Eklund u_long code)); 73d66a5066SPeter Wemm 74d66a5066SPeter Wemm /* 75d66a5066SPeter Wemm * Linux syscalls return negative errno's, we do positive and map them 76d66a5066SPeter Wemm */ 7785f118c8SDmitrij Tejblum static int bsd_to_linux_errno[ELAST + 1] = { 78d66a5066SPeter Wemm -0, -1, -2, -3, -4, -5, -6, -7, -8, -9, 79d66a5066SPeter Wemm -10, -35, -12, -13, -14, -15, -16, -17, -18, -19, 80d66a5066SPeter Wemm -20, -21, -22, -23, -24, -25, -26, -27, -28, -29, 81d66a5066SPeter Wemm -30, -31, -32, -33, -34, -11,-115,-114, -88, -89, 82d66a5066SPeter Wemm -90, -91, -92, -93, -94, -95, -96, -97, -98, -99, 83d66a5066SPeter Wemm -100,-101,-102,-103,-104,-105,-106,-107,-108,-109, 84d66a5066SPeter Wemm -110,-111, -40, -36,-112,-113, -39, -11, -87,-122, 85d66a5066SPeter Wemm -116, -66, -6, -6, -6, -6, -6, -37, -38, -9, 8685f118c8SDmitrij Tejblum -6, -6, -43, -42, -75, -6, -84 87d66a5066SPeter Wemm }; 88d66a5066SPeter Wemm 89d66a5066SPeter Wemm int bsd_to_linux_signal[NSIG] = { 90d66a5066SPeter Wemm 0, LINUX_SIGHUP, LINUX_SIGINT, LINUX_SIGQUIT, 91d66a5066SPeter Wemm LINUX_SIGILL, LINUX_SIGTRAP, LINUX_SIGABRT, 0, 92d66a5066SPeter Wemm LINUX_SIGFPE, LINUX_SIGKILL, LINUX_SIGBUS, LINUX_SIGSEGV, 93d66a5066SPeter Wemm 0, LINUX_SIGPIPE, LINUX_SIGALRM, LINUX_SIGTERM, 94d66a5066SPeter Wemm LINUX_SIGURG, LINUX_SIGSTOP, LINUX_SIGTSTP, LINUX_SIGCONT, 95d66a5066SPeter Wemm LINUX_SIGCHLD, LINUX_SIGTTIN, LINUX_SIGTTOU, LINUX_SIGIO, 96d66a5066SPeter Wemm LINUX_SIGXCPU, LINUX_SIGXFSZ, LINUX_SIGVTALRM, LINUX_SIGPROF, 97d66a5066SPeter Wemm LINUX_SIGWINCH, 0, LINUX_SIGUSR1, LINUX_SIGUSR2 98d66a5066SPeter Wemm }; 99d66a5066SPeter Wemm 100d66a5066SPeter Wemm int linux_to_bsd_signal[LINUX_NSIG] = { 10198fd9ce8SJohn Fieber 0, SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGBUS, 102d66a5066SPeter Wemm SIGFPE, SIGKILL, SIGUSR1, SIGSEGV, SIGUSR2, SIGPIPE, SIGALRM, SIGTERM, 10398fd9ce8SJohn Fieber SIGBUS, SIGCHLD, SIGCONT, SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, 10498fd9ce8SJohn Fieber SIGXCPU, SIGXFSZ, SIGVTALRM, SIGPROF, SIGWINCH, SIGIO, SIGURG, 0 105d66a5066SPeter Wemm }; 106d66a5066SPeter Wemm 107288078beSEivind Eklund /* 108288078beSEivind Eklund * If FreeBSD & Linux have a difference of opinion about what a trap 109288078beSEivind Eklund * means, deal with it here. 110288078beSEivind Eklund */ 111288078beSEivind Eklund static int 112288078beSEivind Eklund translate_traps(int signal, int trap_code) 113288078beSEivind Eklund { 114d563a53aSEivind Eklund if (signal != SIGBUS) 115d563a53aSEivind Eklund return signal; 116288078beSEivind Eklund switch (trap_code) { 117288078beSEivind Eklund case T_PROTFLT: 118288078beSEivind Eklund case T_TSSFLT: 119288078beSEivind Eklund case T_DOUBLEFLT: 120288078beSEivind Eklund case T_PAGEFLT: 121288078beSEivind Eklund return SIGSEGV; 122288078beSEivind Eklund default: 123288078beSEivind Eklund return signal; 124288078beSEivind Eklund } 125288078beSEivind Eklund } 126288078beSEivind Eklund 127303b270bSEivind Eklund static int 128ecbb00a2SDoug Rabson linux_fixup(long **stack_base, struct image_params *imgp) 129d66a5066SPeter Wemm { 130ecbb00a2SDoug Rabson long *argv, *envp; 131d66a5066SPeter Wemm 132d66a5066SPeter Wemm argv = *stack_base; 133d66a5066SPeter Wemm envp = *stack_base + (imgp->argc + 1); 134d66a5066SPeter Wemm (*stack_base)--; 13586a14a7aSBruce Evans **stack_base = (intptr_t)(void *)envp; 136d66a5066SPeter Wemm (*stack_base)--; 13786a14a7aSBruce Evans **stack_base = (intptr_t)(void *)argv; 138d66a5066SPeter Wemm (*stack_base)--; 13986a14a7aSBruce Evans **stack_base = imgp->argc; 140e1743d02SSøren Schmidt return 0; 141d66a5066SPeter Wemm } 142d66a5066SPeter Wemm 143303b270bSEivind Eklund static int 144ecbb00a2SDoug Rabson elf_linux_fixup(long **stack_base, struct image_params *imgp) 145e1743d02SSøren Schmidt { 146e1743d02SSøren Schmidt Elf32_Auxargs *args = (Elf32_Auxargs *)imgp->auxargs; 147ecbb00a2SDoug Rabson long *pos; 148d66a5066SPeter Wemm 149e1743d02SSøren Schmidt pos = *stack_base + (imgp->argc + imgp->envc + 2); 150e1743d02SSøren Schmidt 151e1743d02SSøren Schmidt if (args->trace) { 152e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_DEBUG, 1); 153e1743d02SSøren Schmidt } 154e1743d02SSøren Schmidt if (args->execfd != -1) { 155e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_EXECFD, args->execfd); 156e1743d02SSøren Schmidt } 157e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_PHDR, args->phdr); 158e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_PHENT, args->phent); 159e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_PHNUM, args->phnum); 160e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_PAGESZ, args->pagesz); 161e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_FLAGS, args->flags); 162e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_ENTRY, args->entry); 163e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_BASE, args->base); 164e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_UID, imgp->proc->p_cred->p_ruid); 165e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_EUID, imgp->proc->p_cred->p_svuid); 166e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_GID, imgp->proc->p_cred->p_rgid); 167e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_EGID, imgp->proc->p_cred->p_svgid); 168e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_NULL, 0); 169e1743d02SSøren Schmidt 170e1743d02SSøren Schmidt free(imgp->auxargs, M_TEMP); 171e1743d02SSøren Schmidt imgp->auxargs = NULL; 172e1743d02SSøren Schmidt 173e1743d02SSøren Schmidt (*stack_base)--; 174ecbb00a2SDoug Rabson **stack_base = (long)imgp->argc; 175e1743d02SSøren Schmidt return 0; 176e1743d02SSøren Schmidt } 177d66a5066SPeter Wemm 178d66a5066SPeter Wemm extern int _ucodesel, _udatasel; 179d66a5066SPeter Wemm 180d66a5066SPeter Wemm /* 181d66a5066SPeter Wemm * Send an interrupt to process. 182d66a5066SPeter Wemm * 183d66a5066SPeter Wemm * Stack is set up to allow sigcode stored 184d66a5066SPeter Wemm * in u. to call routine, followed by kcall 185d66a5066SPeter Wemm * to sigreturn routine below. After sigreturn 186d66a5066SPeter Wemm * resets the signal mask, the stack, and the 187d66a5066SPeter Wemm * frame pointer, it returns to the user 188d66a5066SPeter Wemm * specified pc, psl. 189d66a5066SPeter Wemm */ 190d66a5066SPeter Wemm 191303b270bSEivind Eklund static void 192b36546f6SPeter Wemm linux_sendsig(sig_t catcher, int sig, int mask, u_long code) 193d66a5066SPeter Wemm { 194d66a5066SPeter Wemm register struct proc *p = curproc; 195213fdd80SPeter Wemm register struct trapframe *regs; 196d66a5066SPeter Wemm struct linux_sigframe *fp, frame; 197d66a5066SPeter Wemm struct sigacts *psp = p->p_sigacts; 198d66a5066SPeter Wemm int oonstack; 199d66a5066SPeter Wemm 200d66a5066SPeter Wemm regs = p->p_md.md_regs; 201d66a5066SPeter Wemm oonstack = psp->ps_sigstk.ss_flags & SS_ONSTACK; 202d66a5066SPeter Wemm 203d66a5066SPeter Wemm #ifdef DEBUG 204e4e6ae13SBruce Evans printf("Linux-emul(%ld): linux_sendsig(%p, %d, %d, %lu)\n", 205e4e6ae13SBruce Evans (long)p->p_pid, catcher, sig, mask, code); 206d66a5066SPeter Wemm #endif 207d66a5066SPeter Wemm /* 208d66a5066SPeter Wemm * Allocate space for the signal handler context. 209d66a5066SPeter Wemm */ 210d66a5066SPeter Wemm if ((psp->ps_flags & SAS_ALTSTACK) && !oonstack && 211d66a5066SPeter Wemm (psp->ps_sigonstack & sigmask(sig))) { 212d66a5066SPeter Wemm fp = (struct linux_sigframe *)(psp->ps_sigstk.ss_sp + 213d66a5066SPeter Wemm psp->ps_sigstk.ss_size - sizeof(struct linux_sigframe)); 214d66a5066SPeter Wemm psp->ps_sigstk.ss_flags |= SS_ONSTACK; 215d66a5066SPeter Wemm } else { 216213fdd80SPeter Wemm fp = (struct linux_sigframe *)regs->tf_esp - 1; 217d66a5066SPeter Wemm } 218d66a5066SPeter Wemm 219d66a5066SPeter Wemm /* 220d66a5066SPeter Wemm * grow() will return FALSE if the fp will not fit inside the stack 221d66a5066SPeter Wemm * and the stack can not be grown. useracc will return FALSE 222d66a5066SPeter Wemm * if access is denied. 223d66a5066SPeter Wemm */ 2246626c604SJulian Elischer #ifdef COMPAT_LINUX_THREADS 2256626c604SJulian Elischer #ifdef USE_VM_STACK 2266626c604SJulian Elischer #ifndef USE_VM_STACK_FOR_EXEC 2276626c604SJulian Elischer if ((((caddr_t)fp > p->p_vmspace->vm_maxsaddr && 2286626c604SJulian Elischer (caddr_t)fp < (caddr_t)USRSTACK && 2296626c604SJulian Elischer grow(p, (int)fp) == FALSE) || 2306626c604SJulian Elischer (((caddr_t)fp <= p->p_vmspace->vm_maxsaddr || 2316626c604SJulian Elischer (caddr_t)fp >= (caddr_t)USRSTACK) && 2326626c604SJulian Elischer grow_stack (p, (int)fp) == FALSE)) || 2336626c604SJulian Elischer #else 2346626c604SJulian Elischer if ((grow_stack (p, (int)fp) == FALSE) || 2356626c604SJulian Elischer #endif 2366626c604SJulian Elischer #else 2376626c604SJulian Elischer #endif /* COMPAT_LINUX_THREADS */ 238d66a5066SPeter Wemm if ((grow(p, (int)fp) == FALSE) || 2396626c604SJulian Elischer #ifdef COMPAT_LINUX_THREADS 2406626c604SJulian Elischer #endif 2416626c604SJulian Elischer #endif /* COMPAT_LINUX_THREADS */ 242d66a5066SPeter Wemm (useracc((caddr_t)fp, sizeof (struct linux_sigframe), B_WRITE) == FALSE)) { 243d66a5066SPeter Wemm /* 244d66a5066SPeter Wemm * Process has trashed its stack; give it an illegal 245d66a5066SPeter Wemm * instruction to halt it in its tracks. 246d66a5066SPeter Wemm */ 247d66a5066SPeter Wemm SIGACTION(p, SIGILL) = SIG_DFL; 248d66a5066SPeter Wemm sig = sigmask(SIGILL); 249d66a5066SPeter Wemm p->p_sigignore &= ~sig; 250d66a5066SPeter Wemm p->p_sigcatch &= ~sig; 251d66a5066SPeter Wemm p->p_sigmask &= ~sig; 252d66a5066SPeter Wemm psignal(p, SIGILL); 253d66a5066SPeter Wemm return; 254d66a5066SPeter Wemm } 255d66a5066SPeter Wemm 256d66a5066SPeter Wemm /* 257d66a5066SPeter Wemm * Build the argument list for the signal handler. 258d66a5066SPeter Wemm */ 259d66a5066SPeter Wemm if (p->p_sysent->sv_sigtbl) { 260d66a5066SPeter Wemm if (sig < p->p_sysent->sv_sigsize) 261d66a5066SPeter Wemm sig = p->p_sysent->sv_sigtbl[sig]; 262d66a5066SPeter Wemm else 263d66a5066SPeter Wemm sig = p->p_sysent->sv_sigsize + 1; 264d66a5066SPeter Wemm } 265d66a5066SPeter Wemm 266d66a5066SPeter Wemm frame.sf_handler = catcher; 267d66a5066SPeter Wemm frame.sf_sig = sig; 268d66a5066SPeter Wemm 269d66a5066SPeter Wemm /* 270d66a5066SPeter Wemm * Build the signal context to be used by sigreturn. 271d66a5066SPeter Wemm */ 272d66a5066SPeter Wemm frame.sf_sc.sc_mask = mask; 273d66a5066SPeter Wemm __asm("movl %%gs,%w0" : "=r" (frame.sf_sc.sc_gs)); 274d66a5066SPeter Wemm __asm("movl %%fs,%w0" : "=r" (frame.sf_sc.sc_fs)); 275213fdd80SPeter Wemm frame.sf_sc.sc_es = regs->tf_es; 276213fdd80SPeter Wemm frame.sf_sc.sc_ds = regs->tf_ds; 277213fdd80SPeter Wemm frame.sf_sc.sc_edi = regs->tf_edi; 278213fdd80SPeter Wemm frame.sf_sc.sc_esi = regs->tf_esi; 279213fdd80SPeter Wemm frame.sf_sc.sc_ebp = regs->tf_ebp; 280213fdd80SPeter Wemm frame.sf_sc.sc_ebx = regs->tf_ebx; 281213fdd80SPeter Wemm frame.sf_sc.sc_edx = regs->tf_edx; 282213fdd80SPeter Wemm frame.sf_sc.sc_ecx = regs->tf_ecx; 283213fdd80SPeter Wemm frame.sf_sc.sc_eax = regs->tf_eax; 284213fdd80SPeter Wemm frame.sf_sc.sc_eip = regs->tf_eip; 285213fdd80SPeter Wemm frame.sf_sc.sc_cs = regs->tf_cs; 286213fdd80SPeter Wemm frame.sf_sc.sc_eflags = regs->tf_eflags; 287213fdd80SPeter Wemm frame.sf_sc.sc_esp_at_signal = regs->tf_esp; 288213fdd80SPeter Wemm frame.sf_sc.sc_ss = regs->tf_ss; 289213fdd80SPeter Wemm frame.sf_sc.sc_err = regs->tf_err; 290d66a5066SPeter Wemm frame.sf_sc.sc_trapno = code; /* XXX ???? */ 291d66a5066SPeter Wemm 292d66a5066SPeter Wemm if (copyout(&frame, fp, sizeof(frame)) != 0) { 293d66a5066SPeter Wemm /* 294d66a5066SPeter Wemm * Process has trashed its stack; give it an illegal 295d66a5066SPeter Wemm * instruction to halt it in its tracks. 296d66a5066SPeter Wemm */ 297d66a5066SPeter Wemm sigexit(p, SIGILL); 298d66a5066SPeter Wemm /* NOTREACHED */ 299d66a5066SPeter Wemm } 300d66a5066SPeter Wemm 301d66a5066SPeter Wemm /* 302d66a5066SPeter Wemm * Build context to run handler in. 303d66a5066SPeter Wemm */ 304213fdd80SPeter Wemm regs->tf_esp = (int)fp; 3054c56fcdeSBruce Evans regs->tf_eip = PS_STRINGS - *(p->p_sysent->sv_szsigcode); 306213fdd80SPeter Wemm regs->tf_eflags &= ~PSL_VM; 307213fdd80SPeter Wemm regs->tf_cs = _ucodesel; 308213fdd80SPeter Wemm regs->tf_ds = _udatasel; 309213fdd80SPeter Wemm regs->tf_es = _udatasel; 310213fdd80SPeter Wemm regs->tf_ss = _udatasel; 311d66a5066SPeter Wemm } 312d66a5066SPeter Wemm 313d66a5066SPeter Wemm /* 314d66a5066SPeter Wemm * System call to cleanup state after a signal 315d66a5066SPeter Wemm * has been taken. Reset signal mask and 316d66a5066SPeter Wemm * stack state from context left by sendsig (above). 317d66a5066SPeter Wemm * Return to previous pc and psl as specified by 318d66a5066SPeter Wemm * context left by sendsig. Check carefully to 319d66a5066SPeter Wemm * make sure that the user has not modified the 320d66a5066SPeter Wemm * psl to gain improper privileges or to cause 321d66a5066SPeter Wemm * a machine fault. 322d66a5066SPeter Wemm */ 323d66a5066SPeter Wemm int 324cb226aaaSPoul-Henning Kamp linux_sigreturn(p, args) 325d66a5066SPeter Wemm struct proc *p; 326d66a5066SPeter Wemm struct linux_sigreturn_args *args; 327d66a5066SPeter Wemm { 328d66a5066SPeter Wemm struct linux_sigcontext *scp, context; 329213fdd80SPeter Wemm register struct trapframe *regs; 330d66a5066SPeter Wemm int eflags; 331d66a5066SPeter Wemm 332d66a5066SPeter Wemm regs = p->p_md.md_regs; 333d66a5066SPeter Wemm 334d66a5066SPeter Wemm #ifdef DEBUG 335e4e6ae13SBruce Evans printf("Linux-emul(%ld): linux_sigreturn(%p)\n", 336e4e6ae13SBruce Evans (long)p->p_pid, (void *)args->scp); 337d66a5066SPeter Wemm #endif 338d66a5066SPeter Wemm /* 339d66a5066SPeter Wemm * The trampoline code hands us the context. 340d66a5066SPeter Wemm * It is unsafe to keep track of it ourselves, in the event that a 341d66a5066SPeter Wemm * program jumps out of a signal handler. 342d66a5066SPeter Wemm */ 343ecbb00a2SDoug Rabson scp = SCARG(args,scp); 344d66a5066SPeter Wemm if (copyin((caddr_t)scp, &context, sizeof(*scp)) != 0) 345d66a5066SPeter Wemm return (EFAULT); 346d66a5066SPeter Wemm 347d66a5066SPeter Wemm /* 348d66a5066SPeter Wemm * Check for security violations. 349d66a5066SPeter Wemm */ 350d66a5066SPeter Wemm #define EFLAGS_SECURE(ef, oef) ((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0) 351d66a5066SPeter Wemm eflags = context.sc_eflags; 352d66a5066SPeter Wemm /* 353d66a5066SPeter Wemm * XXX do allow users to change the privileged flag PSL_RF. The 354d66a5066SPeter Wemm * cpu sets PSL_RF in tf_eflags for faults. Debuggers should 355d66a5066SPeter Wemm * sometimes set it there too. tf_eflags is kept in the signal 356d66a5066SPeter Wemm * context during signal handling and there is no other place 357d66a5066SPeter Wemm * to remember it, so the PSL_RF bit may be corrupted by the 358d66a5066SPeter Wemm * signal handler without us knowing. Corruption of the PSL_RF 359d66a5066SPeter Wemm * bit at worst causes one more or one less debugger trap, so 360d66a5066SPeter Wemm * allowing it is fairly harmless. 361d66a5066SPeter Wemm */ 362213fdd80SPeter Wemm if (!EFLAGS_SECURE(eflags & ~PSL_RF, regs->tf_eflags & ~PSL_RF)) { 363d66a5066SPeter Wemm return(EINVAL); 364d66a5066SPeter Wemm } 365d66a5066SPeter Wemm 366d66a5066SPeter Wemm /* 367d66a5066SPeter Wemm * Don't allow users to load a valid privileged %cs. Let the 368d66a5066SPeter Wemm * hardware check for invalid selectors, excess privilege in 369d66a5066SPeter Wemm * other selectors, invalid %eip's and invalid %esp's. 370d66a5066SPeter Wemm */ 37140d50994SPhilippe Charnier #define CS_SECURE(cs) (ISPL(cs) == SEL_UPL) 372d66a5066SPeter Wemm if (!CS_SECURE(context.sc_cs)) { 373d66a5066SPeter Wemm trapsignal(p, SIGBUS, T_PROTFLT); 374d66a5066SPeter Wemm return(EINVAL); 375d66a5066SPeter Wemm } 376d66a5066SPeter Wemm 377d66a5066SPeter Wemm p->p_sigacts->ps_sigstk.ss_flags &= ~SS_ONSTACK; 378d66a5066SPeter Wemm p->p_sigmask = context.sc_mask &~ 379d66a5066SPeter Wemm (sigmask(SIGKILL)|sigmask(SIGCONT)|sigmask(SIGSTOP)); 380d66a5066SPeter Wemm /* 381d66a5066SPeter Wemm * Restore signal context. 382d66a5066SPeter Wemm */ 383d66a5066SPeter Wemm /* %fs and %gs were restored by the trampoline. */ 384213fdd80SPeter Wemm regs->tf_es = context.sc_es; 385213fdd80SPeter Wemm regs->tf_ds = context.sc_ds; 386213fdd80SPeter Wemm regs->tf_edi = context.sc_edi; 387213fdd80SPeter Wemm regs->tf_esi = context.sc_esi; 388213fdd80SPeter Wemm regs->tf_ebp = context.sc_ebp; 389213fdd80SPeter Wemm regs->tf_ebx = context.sc_ebx; 390213fdd80SPeter Wemm regs->tf_edx = context.sc_edx; 391213fdd80SPeter Wemm regs->tf_ecx = context.sc_ecx; 392213fdd80SPeter Wemm regs->tf_eax = context.sc_eax; 393213fdd80SPeter Wemm regs->tf_eip = context.sc_eip; 394213fdd80SPeter Wemm regs->tf_cs = context.sc_cs; 395213fdd80SPeter Wemm regs->tf_eflags = eflags; 396213fdd80SPeter Wemm regs->tf_esp = context.sc_esp_at_signal; 397213fdd80SPeter Wemm regs->tf_ss = context.sc_ss; 398d66a5066SPeter Wemm 399d66a5066SPeter Wemm return (EJUSTRETURN); 400d66a5066SPeter Wemm } 401d66a5066SPeter Wemm 402303b270bSEivind Eklund static void 403d66a5066SPeter Wemm linux_prepsyscall(struct trapframe *tf, int *args, u_int *code, caddr_t *params) 404d66a5066SPeter Wemm { 405d66a5066SPeter Wemm args[0] = tf->tf_ebx; 406d66a5066SPeter Wemm args[1] = tf->tf_ecx; 407d66a5066SPeter Wemm args[2] = tf->tf_edx; 408d66a5066SPeter Wemm args[3] = tf->tf_esi; 409d66a5066SPeter Wemm args[4] = tf->tf_edi; 410d66a5066SPeter Wemm *params = NULL; /* no copyin */ 411d66a5066SPeter Wemm } 412d66a5066SPeter Wemm 413d66a5066SPeter Wemm struct sysentvec linux_sysvec = { 414e1743d02SSøren Schmidt LINUX_SYS_MAXSYSCALL, 415d66a5066SPeter Wemm linux_sysent, 416d66a5066SPeter Wemm 0xff, 417d66a5066SPeter Wemm NSIG, 418d66a5066SPeter Wemm bsd_to_linux_signal, 41985f118c8SDmitrij Tejblum ELAST + 1, 420d66a5066SPeter Wemm bsd_to_linux_errno, 421288078beSEivind Eklund translate_traps, 422d66a5066SPeter Wemm linux_fixup, 423d66a5066SPeter Wemm linux_sendsig, 424d66a5066SPeter Wemm linux_sigcode, 425d66a5066SPeter Wemm &linux_szsigcode, 426d66a5066SPeter Wemm linux_prepsyscall, 42722d4b0fbSJohn Polstra "Linux a.out", 42822d4b0fbSJohn Polstra aout_coredump 429d66a5066SPeter Wemm }; 430e1743d02SSøren Schmidt 431e1743d02SSøren Schmidt struct sysentvec elf_linux_sysvec = { 432e1743d02SSøren Schmidt LINUX_SYS_MAXSYSCALL, 433e1743d02SSøren Schmidt linux_sysent, 434e1743d02SSøren Schmidt 0xff, 435e1743d02SSøren Schmidt NSIG, 436e1743d02SSøren Schmidt bsd_to_linux_signal, 43785f118c8SDmitrij Tejblum ELAST + 1, 438e1743d02SSøren Schmidt bsd_to_linux_errno, 439288078beSEivind Eklund translate_traps, 440e1743d02SSøren Schmidt elf_linux_fixup, 441e1743d02SSøren Schmidt linux_sendsig, 442e1743d02SSøren Schmidt linux_sigcode, 443e1743d02SSøren Schmidt &linux_szsigcode, 444e1743d02SSøren Schmidt linux_prepsyscall, 44522d4b0fbSJohn Polstra "Linux ELF", 44622d4b0fbSJohn Polstra elf_coredump 447e1743d02SSøren Schmidt }; 448e1743d02SSøren Schmidt 4495cf588ebSPeter Wemm /* 4505cf588ebSPeter Wemm * Installed either via SYSINIT() or via LKM stubs. 4515cf588ebSPeter Wemm */ 452514058dcSAlexander Langer static Elf32_Brandinfo linux_brand = { 453ea5a2b2eSSøren Schmidt "Linux", 454ea5a2b2eSSøren Schmidt "/compat/linux", 4555cf588ebSPeter Wemm "/lib/ld-linux.so.1", 456ea5a2b2eSSøren Schmidt &elf_linux_sysvec 4575cf588ebSPeter Wemm }; 4585cf588ebSPeter Wemm 459514058dcSAlexander Langer static Elf32_Brandinfo linux_glibc2brand = { 4604e138a28SMike Smith "Linux", 4614e138a28SMike Smith "/compat/linux", 4624e138a28SMike Smith "/lib/ld-linux.so.2", 4634e138a28SMike Smith &elf_linux_sysvec 4644e138a28SMike Smith }; 4654e138a28SMike Smith 466514058dcSAlexander Langer Elf32_Brandinfo *linux_brandlist[] = { 467514058dcSAlexander Langer &linux_brand, 468514058dcSAlexander Langer &linux_glibc2brand, 469514058dcSAlexander Langer NULL 470514058dcSAlexander Langer }; 471514058dcSAlexander Langer 472aa855a59SPeter Wemm static int 473c25ded31SBruce Evans linux_elf_modevent(module_t mod, int type, void *data) 474d30ea4f5SPeter Wemm { 475514058dcSAlexander Langer Elf32_Brandinfo **brandinfo; 476514058dcSAlexander Langer int error; 477514058dcSAlexander Langer 478514058dcSAlexander Langer error = 0; 479514058dcSAlexander Langer 480aa855a59SPeter Wemm switch(type) { 481aa855a59SPeter Wemm case MOD_LOAD: 482aa855a59SPeter Wemm for (brandinfo = &linux_brandlist[0]; *brandinfo != NULL; 483aa855a59SPeter Wemm ++brandinfo) 484514058dcSAlexander Langer if (elf_insert_brand_entry(*brandinfo) < 0) 485aa855a59SPeter Wemm error = EINVAL; 486514058dcSAlexander Langer if (error) 487d30ea4f5SPeter Wemm printf("cannot insert Linux elf brand handler\n"); 488d30ea4f5SPeter Wemm else if (bootverbose) 489d30ea4f5SPeter Wemm printf("Linux-ELF exec handler installed\n"); 490aa855a59SPeter Wemm break; 491aa855a59SPeter Wemm case MOD_UNLOAD: 492aa855a59SPeter Wemm for (brandinfo = &linux_brandlist[0]; *brandinfo != NULL; 493aa855a59SPeter Wemm ++brandinfo) 494aa855a59SPeter Wemm if (elf_remove_brand_entry(*brandinfo) < 0) 495aa855a59SPeter Wemm error = EINVAL; 496aa855a59SPeter Wemm if (error) 497aa855a59SPeter Wemm printf("Could not deinstall ELF interpreter entry\n"); 498aa855a59SPeter Wemm else if (bootverbose) 499aa855a59SPeter Wemm printf("Linux-elf exec handler removed\n"); 500aa855a59SPeter Wemm break; 501aa855a59SPeter Wemm default: 502aa855a59SPeter Wemm break; 503d30ea4f5SPeter Wemm } 504aa855a59SPeter Wemm return error; 505aa855a59SPeter Wemm } 506aa855a59SPeter Wemm static moduledata_t linux_elf_mod = { 507aa855a59SPeter Wemm "linuxelf", 508aa855a59SPeter Wemm linux_elf_modevent, 509aa855a59SPeter Wemm 0 510aa855a59SPeter Wemm }; 511aa855a59SPeter Wemm DECLARE_MODULE(linuxelf, linux_elf_mod, SI_SUB_EXEC, SI_ORDER_ANY); 512