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 1521dc7d4fSJens Schweikhardt * derived from this software without 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 */ 28d66a5066SPeter Wemm 2927e0099cSDavid E. O'Brien #include <sys/cdefs.h> 3027e0099cSDavid E. O'Brien __FBSDID("$FreeBSD$"); 3127e0099cSDavid E. O'Brien 32d66a5066SPeter Wemm /* XXX we use functions that might not exist. */ 335591b823SEivind Eklund #include "opt_compat.h" 345591b823SEivind Eklund 355591b823SEivind Eklund #ifndef COMPAT_43 365591b823SEivind Eklund #error "Unable to compile Linux-emulator due to missing COMPAT_43 option!" 375591b823SEivind Eklund #endif 38d66a5066SPeter Wemm 39d66a5066SPeter Wemm #include <sys/param.h> 4075f83872SPeter Wemm #include <sys/systm.h> 41ff22c670SBruce Evans #include <sys/exec.h> 42d66a5066SPeter Wemm #include <sys/imgact.h> 4322d4b0fbSJohn Polstra #include <sys/imgact_aout.h> 44e1743d02SSøren Schmidt #include <sys/imgact_elf.h> 45ff22c670SBruce Evans #include <sys/kernel.h> 467106ca0dSJohn Baldwin #include <sys/lock.h> 47e1743d02SSøren Schmidt #include <sys/malloc.h> 48ff22c670SBruce Evans #include <sys/module.h> 4923955314SAlfred Perlstein #include <sys/mutex.h> 50fb919e4dSMark Murray #include <sys/proc.h> 51fb919e4dSMark Murray #include <sys/signalvar.h> 52206a5d3aSIan Dowse #include <sys/syscallsubr.h> 53fb919e4dSMark Murray #include <sys/sysent.h> 54fb919e4dSMark Murray #include <sys/sysproto.h> 55a9148ab1SPeter Wemm #include <sys/vnode.h> 56fb919e4dSMark Murray 57d66a5066SPeter Wemm #include <vm/vm.h> 58a9148ab1SPeter Wemm #include <vm/pmap.h> 59ff22c670SBruce Evans #include <vm/vm_extern.h> 60a9148ab1SPeter Wemm #include <vm/vm_map.h> 61a9148ab1SPeter Wemm #include <vm/vm_object.h> 62ff22c670SBruce Evans #include <vm/vm_page.h> 63ff22c670SBruce Evans #include <vm/vm_param.h> 64ff22c670SBruce Evans 65ff22c670SBruce Evans #include <machine/cpu.h> 66ff22c670SBruce Evans #include <machine/md_var.h> 67d3adf769SDavid Schultz #include <machine/pcb.h> 68a9148ab1SPeter Wemm 69d66a5066SPeter Wemm #include <i386/linux/linux.h> 70ebea8660SMarcel Moolenaar #include <i386/linux/linux_proto.h> 710f9d6538SJohn Baldwin #include <compat/linux/linux_mib.h> 72b595ab37SAndrew Gallatin #include <compat/linux/linux_signal.h> 73322bfdc3SMarcel Moolenaar #include <compat/linux/linux_util.h> 74e1743d02SSøren Schmidt 751d91482dSPeter Wemm MODULE_VERSION(linux, 1); 76158eb277SDag-Erling Smørgrav MODULE_DEPEND(linux, sysvmsg, 1, 1, 1); 77158eb277SDag-Erling Smørgrav MODULE_DEPEND(linux, sysvsem, 1, 1, 1); 78158eb277SDag-Erling Smørgrav MODULE_DEPEND(linux, sysvshm, 1, 1, 1); 791d91482dSPeter Wemm 8043bef515SMarcel Moolenaar MALLOC_DEFINE(M_LINUX, "linux", "Linux mode structures"); 8143bef515SMarcel Moolenaar 82d323ddf3SMatthew Dillon #if BYTE_ORDER == LITTLE_ENDIAN 83d323ddf3SMatthew Dillon #define SHELLMAGIC 0x2123 /* #! */ 84d323ddf3SMatthew Dillon #else 85d323ddf3SMatthew Dillon #define SHELLMAGIC 0x2321 86d323ddf3SMatthew Dillon #endif 87d323ddf3SMatthew Dillon 88e061a6caSMarcel Moolenaar /* 89e061a6caSMarcel Moolenaar * Allow the sendsig functions to use the ldebug() facility 90e061a6caSMarcel Moolenaar * even though they are not syscalls themselves. Map them 91e061a6caSMarcel Moolenaar * to syscall 0. This is slightly less bogus than using 92e061a6caSMarcel Moolenaar * ldebug(sigreturn). 93e061a6caSMarcel Moolenaar */ 94e061a6caSMarcel Moolenaar #define LINUX_SYS_linux_rt_sendsig 0 95e061a6caSMarcel Moolenaar #define LINUX_SYS_linux_sendsig 0 96e061a6caSMarcel Moolenaar 972a51b9b0SDavid Schultz #define fldcw(addr) __asm("fldcw %0" : : "m" (*(addr))) 982a51b9b0SDavid Schultz #define __LINUX_NPXCW__ 0x37f 992a51b9b0SDavid Schultz 10043bef515SMarcel Moolenaar extern char linux_sigcode[]; 10143bef515SMarcel Moolenaar extern int linux_szsigcode; 10243bef515SMarcel Moolenaar 10343bef515SMarcel Moolenaar extern struct sysent linux_sysent[LINUX_SYS_MAXSYSCALL]; 10443bef515SMarcel Moolenaar 105f41325dbSPeter Wemm SET_DECLARE(linux_ioctl_handler_set, struct linux_ioctl_handler); 10643bef515SMarcel Moolenaar 10789c9a483SAlfred Perlstein static int linux_fixup(register_t **stack_base, 10889c9a483SAlfred Perlstein struct image_params *iparams); 10989c9a483SAlfred Perlstein static int elf_linux_fixup(register_t **stack_base, 11089c9a483SAlfred Perlstein struct image_params *iparams); 111bda2a3afSBruce Evans static void linux_prepsyscall(struct trapframe *tf, int *args, u_int *code, 112bda2a3afSBruce Evans caddr_t *params); 11389c9a483SAlfred Perlstein static void linux_sendsig(sig_t catcher, int sig, sigset_t *mask, 11489c9a483SAlfred Perlstein u_long code); 115598d45beSMatthew N. Dodd static void exec_linux_setregs(struct thread *td, u_long entry, 116598d45beSMatthew N. Dodd u_long stack, u_long ps_strings); 117d66a5066SPeter Wemm 118d66a5066SPeter Wemm /* 119d66a5066SPeter Wemm * Linux syscalls return negative errno's, we do positive and map them 120d66a5066SPeter Wemm */ 12185f118c8SDmitrij Tejblum static int bsd_to_linux_errno[ELAST + 1] = { 122d66a5066SPeter Wemm -0, -1, -2, -3, -4, -5, -6, -7, -8, -9, 123d66a5066SPeter Wemm -10, -35, -12, -13, -14, -15, -16, -17, -18, -19, 124d66a5066SPeter Wemm -20, -21, -22, -23, -24, -25, -26, -27, -28, -29, 125d66a5066SPeter Wemm -30, -31, -32, -33, -34, -11,-115,-114, -88, -89, 126d66a5066SPeter Wemm -90, -91, -92, -93, -94, -95, -96, -97, -98, -99, 127d66a5066SPeter Wemm -100,-101,-102,-103,-104,-105,-106,-107,-108,-109, 128d66a5066SPeter Wemm -110,-111, -40, -36,-112,-113, -39, -11, -87,-122, 129d66a5066SPeter Wemm -116, -66, -6, -6, -6, -6, -6, -37, -38, -9, 13085f118c8SDmitrij Tejblum -6, -6, -43, -42, -75, -6, -84 131d66a5066SPeter Wemm }; 132d66a5066SPeter Wemm 133956d3333SMarcel Moolenaar int bsd_to_linux_signal[LINUX_SIGTBLSZ] = { 134956d3333SMarcel Moolenaar LINUX_SIGHUP, LINUX_SIGINT, LINUX_SIGQUIT, LINUX_SIGILL, 135956d3333SMarcel Moolenaar LINUX_SIGTRAP, LINUX_SIGABRT, 0, LINUX_SIGFPE, 136ba873f4cSAlexander Kabaev LINUX_SIGKILL, LINUX_SIGBUS, LINUX_SIGSEGV, LINUX_SIGSYS, 137956d3333SMarcel Moolenaar LINUX_SIGPIPE, LINUX_SIGALRM, LINUX_SIGTERM, LINUX_SIGURG, 138956d3333SMarcel Moolenaar LINUX_SIGSTOP, LINUX_SIGTSTP, LINUX_SIGCONT, LINUX_SIGCHLD, 139956d3333SMarcel Moolenaar LINUX_SIGTTIN, LINUX_SIGTTOU, LINUX_SIGIO, LINUX_SIGXCPU, 140956d3333SMarcel Moolenaar LINUX_SIGXFSZ, LINUX_SIGVTALRM, LINUX_SIGPROF, LINUX_SIGWINCH, 141956d3333SMarcel Moolenaar 0, LINUX_SIGUSR1, LINUX_SIGUSR2 142d66a5066SPeter Wemm }; 143d66a5066SPeter Wemm 144956d3333SMarcel Moolenaar int linux_to_bsd_signal[LINUX_SIGTBLSZ] = { 145956d3333SMarcel Moolenaar SIGHUP, SIGINT, SIGQUIT, SIGILL, 146956d3333SMarcel Moolenaar SIGTRAP, SIGABRT, SIGBUS, SIGFPE, 147956d3333SMarcel Moolenaar SIGKILL, SIGUSR1, SIGSEGV, SIGUSR2, 148956d3333SMarcel Moolenaar SIGPIPE, SIGALRM, SIGTERM, SIGBUS, 149956d3333SMarcel Moolenaar SIGCHLD, SIGCONT, SIGSTOP, SIGTSTP, 150956d3333SMarcel Moolenaar SIGTTIN, SIGTTOU, SIGURG, SIGXCPU, 151956d3333SMarcel Moolenaar SIGXFSZ, SIGVTALRM, SIGPROF, SIGWINCH, 152ba873f4cSAlexander Kabaev SIGIO, SIGURG, SIGSYS 153d66a5066SPeter Wemm }; 154d66a5066SPeter Wemm 15527a828fcSPierre Beyssac #define LINUX_T_UNKNOWN 255 15627a828fcSPierre Beyssac static int _bsd_to_linux_trapcode[] = { 15727a828fcSPierre Beyssac LINUX_T_UNKNOWN, /* 0 */ 15827a828fcSPierre Beyssac 6, /* 1 T_PRIVINFLT */ 15927a828fcSPierre Beyssac LINUX_T_UNKNOWN, /* 2 */ 16027a828fcSPierre Beyssac 3, /* 3 T_BPTFLT */ 16127a828fcSPierre Beyssac LINUX_T_UNKNOWN, /* 4 */ 16227a828fcSPierre Beyssac LINUX_T_UNKNOWN, /* 5 */ 16327a828fcSPierre Beyssac 16, /* 6 T_ARITHTRAP */ 16427a828fcSPierre Beyssac 254, /* 7 T_ASTFLT */ 16527a828fcSPierre Beyssac LINUX_T_UNKNOWN, /* 8 */ 16627a828fcSPierre Beyssac 13, /* 9 T_PROTFLT */ 16727a828fcSPierre Beyssac 1, /* 10 T_TRCTRAP */ 16827a828fcSPierre Beyssac LINUX_T_UNKNOWN, /* 11 */ 16927a828fcSPierre Beyssac 14, /* 12 T_PAGEFLT */ 17027a828fcSPierre Beyssac LINUX_T_UNKNOWN, /* 13 */ 17127a828fcSPierre Beyssac 17, /* 14 T_ALIGNFLT */ 17227a828fcSPierre Beyssac LINUX_T_UNKNOWN, /* 15 */ 17327a828fcSPierre Beyssac LINUX_T_UNKNOWN, /* 16 */ 17427a828fcSPierre Beyssac LINUX_T_UNKNOWN, /* 17 */ 17527a828fcSPierre Beyssac 0, /* 18 T_DIVIDE */ 17627a828fcSPierre Beyssac 2, /* 19 T_NMI */ 17727a828fcSPierre Beyssac 4, /* 20 T_OFLOW */ 17827a828fcSPierre Beyssac 5, /* 21 T_BOUND */ 17927a828fcSPierre Beyssac 7, /* 22 T_DNA */ 18027a828fcSPierre Beyssac 8, /* 23 T_DOUBLEFLT */ 18127a828fcSPierre Beyssac 9, /* 24 T_FPOPFLT */ 18227a828fcSPierre Beyssac 10, /* 25 T_TSSFLT */ 18327a828fcSPierre Beyssac 11, /* 26 T_SEGNPFLT */ 18427a828fcSPierre Beyssac 12, /* 27 T_STKFLT */ 18527a828fcSPierre Beyssac 18, /* 28 T_MCHK */ 18627a828fcSPierre Beyssac 19, /* 29 T_XMMFLT */ 18727a828fcSPierre Beyssac 15 /* 30 T_RESERVED */ 18827a828fcSPierre Beyssac }; 18927a828fcSPierre Beyssac #define bsd_to_linux_trapcode(code) \ 19027a828fcSPierre Beyssac ((code)<sizeof(_bsd_to_linux_trapcode)/sizeof(*_bsd_to_linux_trapcode)? \ 19127a828fcSPierre Beyssac _bsd_to_linux_trapcode[(code)]: \ 19227a828fcSPierre Beyssac LINUX_T_UNKNOWN) 19327a828fcSPierre Beyssac 194288078beSEivind Eklund /* 195288078beSEivind Eklund * If FreeBSD & Linux have a difference of opinion about what a trap 196288078beSEivind Eklund * means, deal with it here. 197356861dbSMatthew Dillon * 198356861dbSMatthew Dillon * MPSAFE 199288078beSEivind Eklund */ 200288078beSEivind Eklund static int 201288078beSEivind Eklund translate_traps(int signal, int trap_code) 202288078beSEivind Eklund { 203d563a53aSEivind Eklund if (signal != SIGBUS) 204d563a53aSEivind Eklund return signal; 205288078beSEivind Eklund switch (trap_code) { 206288078beSEivind Eklund case T_PROTFLT: 207288078beSEivind Eklund case T_TSSFLT: 208288078beSEivind Eklund case T_DOUBLEFLT: 209288078beSEivind Eklund case T_PAGEFLT: 210288078beSEivind Eklund return SIGSEGV; 211288078beSEivind Eklund default: 212288078beSEivind Eklund return signal; 213288078beSEivind Eklund } 214288078beSEivind Eklund } 215288078beSEivind Eklund 216303b270bSEivind Eklund static int 217654f6be1SBruce Evans linux_fixup(register_t **stack_base, struct image_params *imgp) 218d66a5066SPeter Wemm { 219654f6be1SBruce Evans register_t *argv, *envp; 220d66a5066SPeter Wemm 221d66a5066SPeter Wemm argv = *stack_base; 222610ecfe0SMaxim Sobolev envp = *stack_base + (imgp->args->argc + 1); 223d66a5066SPeter Wemm (*stack_base)--; 22486a14a7aSBruce Evans **stack_base = (intptr_t)(void *)envp; 225d66a5066SPeter Wemm (*stack_base)--; 22686a14a7aSBruce Evans **stack_base = (intptr_t)(void *)argv; 227d66a5066SPeter Wemm (*stack_base)--; 228610ecfe0SMaxim Sobolev **stack_base = imgp->args->argc; 229e1743d02SSøren Schmidt return 0; 230d66a5066SPeter Wemm } 231d66a5066SPeter Wemm 232303b270bSEivind Eklund static int 233654f6be1SBruce Evans elf_linux_fixup(register_t **stack_base, struct image_params *imgp) 234e1743d02SSøren Schmidt { 23543cf129cSJohn Baldwin Elf32_Auxargs *args; 236654f6be1SBruce Evans register_t *pos; 237d66a5066SPeter Wemm 23843cf129cSJohn Baldwin KASSERT(curthread->td_proc == imgp->proc && 2390e2a4d3aSDavid Xu (curthread->td_proc->p_flag & P_SA) == 0, 24043cf129cSJohn Baldwin ("unsafe elf_linux_fixup(), should be curproc")); 24143cf129cSJohn Baldwin args = (Elf32_Auxargs *)imgp->auxargs; 242610ecfe0SMaxim Sobolev pos = *stack_base + (imgp->args->argc + imgp->args->envc + 2); 243e1743d02SSøren Schmidt 244b07cd97eSMark Murray if (args->trace) 245e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_DEBUG, 1); 246b07cd97eSMark Murray if (args->execfd != -1) 247e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_EXECFD, args->execfd); 248e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_PHDR, args->phdr); 249e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_PHENT, args->phent); 250e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_PHNUM, args->phnum); 251e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_PAGESZ, args->pagesz); 252e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_FLAGS, args->flags); 253e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_ENTRY, args->entry); 254e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_BASE, args->base); 255b1fc0ec1SRobert Watson AUXARGS_ENTRY(pos, AT_UID, imgp->proc->p_ucred->cr_ruid); 256b1fc0ec1SRobert Watson AUXARGS_ENTRY(pos, AT_EUID, imgp->proc->p_ucred->cr_svuid); 257b1fc0ec1SRobert Watson AUXARGS_ENTRY(pos, AT_GID, imgp->proc->p_ucred->cr_rgid); 258b1fc0ec1SRobert Watson AUXARGS_ENTRY(pos, AT_EGID, imgp->proc->p_ucred->cr_svgid); 259e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_NULL, 0); 260e1743d02SSøren Schmidt 261e1743d02SSøren Schmidt free(imgp->auxargs, M_TEMP); 262e1743d02SSøren Schmidt imgp->auxargs = NULL; 263e1743d02SSøren Schmidt 264e1743d02SSøren Schmidt (*stack_base)--; 265610ecfe0SMaxim Sobolev **stack_base = (register_t)imgp->args->argc; 266e1743d02SSøren Schmidt return 0; 267e1743d02SSøren Schmidt } 268d66a5066SPeter Wemm 269d66a5066SPeter Wemm extern int _ucodesel, _udatasel; 27002318dacSJake Burkholder extern unsigned long linux_sznonrtsigcode; 27179363394SAndrew Gallatin 27279363394SAndrew Gallatin static void 27379363394SAndrew Gallatin linux_rt_sendsig(sig_t catcher, int sig, sigset_t *mask, u_long code) 27479363394SAndrew Gallatin { 2751d062e2bSDag-Erling Smørgrav struct thread *td = curthread; 2761d062e2bSDag-Erling Smørgrav struct proc *p = td->td_proc; 27790af4afaSJohn Baldwin struct sigacts *psp; 2781d062e2bSDag-Erling Smørgrav struct trapframe *regs; 2795002a60fSMarcel Moolenaar struct l_rt_sigframe *fp, frame; 28079363394SAndrew Gallatin int oonstack; 28179363394SAndrew Gallatin 282df53e91cSJohn Baldwin PROC_LOCK_ASSERT(p, MA_OWNED); 28390af4afaSJohn Baldwin psp = p->p_sigacts; 28490af4afaSJohn Baldwin mtx_assert(&psp->ps_mtx, MA_OWNED); 285b40ce416SJulian Elischer regs = td->td_frame; 286d034d459SMarcel Moolenaar oonstack = sigonstack(regs->tf_esp); 28779363394SAndrew Gallatin 28879363394SAndrew Gallatin #ifdef DEBUG 2895002a60fSMarcel Moolenaar if (ldebug(rt_sendsig)) 29024593369SJonathan Lemon printf(ARGS(rt_sendsig, "%p, %d, %p, %lu"), 29124593369SJonathan Lemon catcher, sig, (void*)mask, code); 29279363394SAndrew Gallatin #endif 29379363394SAndrew Gallatin /* 29479363394SAndrew Gallatin * Allocate space for the signal handler context. 29579363394SAndrew Gallatin */ 296a30ec4b9SDavid Xu if ((td->td_pflags & TDP_ALTSTACK) && !oonstack && 29790af4afaSJohn Baldwin SIGISMEMBER(psp->ps_sigonstack, sig)) { 298a30ec4b9SDavid Xu fp = (struct l_rt_sigframe *)(td->td_sigstk.ss_sp + 299a30ec4b9SDavid Xu td->td_sigstk.ss_size - sizeof(struct l_rt_sigframe)); 300d034d459SMarcel Moolenaar } else 3015002a60fSMarcel Moolenaar fp = (struct l_rt_sigframe *)regs->tf_esp - 1; 30290af4afaSJohn Baldwin mtx_unlock(&psp->ps_mtx); 30379363394SAndrew Gallatin 30479363394SAndrew Gallatin /* 30579363394SAndrew Gallatin * Build the argument list for the signal handler. 30679363394SAndrew Gallatin */ 30779363394SAndrew Gallatin if (p->p_sysent->sv_sigtbl) 30879363394SAndrew Gallatin if (sig <= p->p_sysent->sv_sigsize) 30979363394SAndrew Gallatin sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)]; 31079363394SAndrew Gallatin 31199d45c5fSMarcel Moolenaar bzero(&frame, sizeof(frame)); 31299d45c5fSMarcel Moolenaar 31379363394SAndrew Gallatin frame.sf_handler = catcher; 31479363394SAndrew Gallatin frame.sf_sig = sig; 31579363394SAndrew Gallatin frame.sf_siginfo = &fp->sf_si; 31679363394SAndrew Gallatin frame.sf_ucontext = &fp->sf_sc; 317cc6ca9b3SMarcel Moolenaar 3189d05b77dSJuli Mallett /* Fill in POSIX parts */ 31979363394SAndrew Gallatin frame.sf_si.lsi_signo = sig; 32079363394SAndrew Gallatin frame.sf_si.lsi_code = code; 32179363394SAndrew Gallatin frame.sf_si.lsi_addr = (void *)regs->tf_err; 322cc6ca9b3SMarcel Moolenaar 32379363394SAndrew Gallatin /* 32479363394SAndrew Gallatin * Build the signal context to be used by sigreturn. 32579363394SAndrew Gallatin */ 326cc6ca9b3SMarcel Moolenaar frame.sf_sc.uc_flags = 0; /* XXX ??? */ 327cc6ca9b3SMarcel Moolenaar frame.sf_sc.uc_link = NULL; /* XXX ??? */ 328cc6ca9b3SMarcel Moolenaar 329a30ec4b9SDavid Xu frame.sf_sc.uc_stack.ss_sp = td->td_sigstk.ss_sp; 330a30ec4b9SDavid Xu frame.sf_sc.uc_stack.ss_size = td->td_sigstk.ss_size; 331a30ec4b9SDavid Xu frame.sf_sc.uc_stack.ss_flags = (td->td_pflags & TDP_ALTSTACK) 332d034d459SMarcel Moolenaar ? ((oonstack) ? LINUX_SS_ONSTACK : 0) : LINUX_SS_DISABLE; 333611d9407SJohn Baldwin PROC_UNLOCK(p); 334cc6ca9b3SMarcel Moolenaar 335cc6ca9b3SMarcel Moolenaar bsd_to_linux_sigset(mask, &frame.sf_sc.uc_sigmask); 336cc6ca9b3SMarcel Moolenaar 337cc6ca9b3SMarcel Moolenaar frame.sf_sc.uc_mcontext.sc_mask = frame.sf_sc.uc_sigmask.__bits[0]; 33879363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_gs = rgs(); 33979363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_fs = regs->tf_fs; 34079363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_es = regs->tf_es; 34179363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_ds = regs->tf_ds; 34279363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_edi = regs->tf_edi; 34379363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_esi = regs->tf_esi; 34479363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_ebp = regs->tf_ebp; 34579363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_ebx = regs->tf_ebx; 34679363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_edx = regs->tf_edx; 34779363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_ecx = regs->tf_ecx; 34879363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_eax = regs->tf_eax; 34979363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_eip = regs->tf_eip; 35079363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_cs = regs->tf_cs; 35179363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_eflags = regs->tf_eflags; 35279363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_esp_at_signal = regs->tf_esp; 35379363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_ss = regs->tf_ss; 35479363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_err = regs->tf_err; 35527a828fcSPierre Beyssac frame.sf_sc.uc_mcontext.sc_trapno = bsd_to_linux_trapcode(code); 35679363394SAndrew Gallatin 35779363394SAndrew Gallatin #ifdef DEBUG 3585002a60fSMarcel Moolenaar if (ldebug(rt_sendsig)) 35924593369SJonathan Lemon printf(LMSG("rt_sendsig flags: 0x%x, sp: %p, ss: 0x%x, mask: 0x%x"), 3609b778a16SDavid Xu frame.sf_sc.uc_stack.ss_flags, td->td_sigstk.ss_sp, 3619b778a16SDavid Xu td->td_sigstk.ss_size, frame.sf_sc.uc_mcontext.sc_mask); 36279363394SAndrew Gallatin #endif 36379363394SAndrew Gallatin 36479363394SAndrew Gallatin if (copyout(&frame, fp, sizeof(frame)) != 0) { 36579363394SAndrew Gallatin /* 36679363394SAndrew Gallatin * Process has trashed its stack; give it an illegal 36779363394SAndrew Gallatin * instruction to halt it in its tracks. 36879363394SAndrew Gallatin */ 36989734883SAlan Cox #ifdef DEBUG 37089734883SAlan Cox if (ldebug(rt_sendsig)) 37189734883SAlan Cox printf(LMSG("rt_sendsig: bad stack %p, oonstack=%x"), 37289734883SAlan Cox fp, oonstack); 37389734883SAlan Cox #endif 37419eb87d2SJohn Baldwin PROC_LOCK(p); 375b40ce416SJulian Elischer sigexit(td, SIGILL); 37679363394SAndrew Gallatin } 37779363394SAndrew Gallatin 37879363394SAndrew Gallatin /* 37979363394SAndrew Gallatin * Build context to run handler in. 38079363394SAndrew Gallatin */ 38179363394SAndrew Gallatin regs->tf_esp = (int)fp; 38279363394SAndrew Gallatin regs->tf_eip = PS_STRINGS - *(p->p_sysent->sv_szsigcode) + 38302318dacSJake Burkholder linux_sznonrtsigcode; 384846ac226SBruce Evans regs->tf_eflags &= ~(PSL_T | PSL_VM); 38579363394SAndrew Gallatin regs->tf_cs = _ucodesel; 38679363394SAndrew Gallatin regs->tf_ds = _udatasel; 38779363394SAndrew Gallatin regs->tf_es = _udatasel; 38879363394SAndrew Gallatin regs->tf_fs = _udatasel; 38979363394SAndrew Gallatin regs->tf_ss = _udatasel; 390df53e91cSJohn Baldwin PROC_LOCK(p); 39190af4afaSJohn Baldwin mtx_lock(&psp->ps_mtx); 39279363394SAndrew Gallatin } 39379363394SAndrew Gallatin 394d66a5066SPeter Wemm 395d66a5066SPeter Wemm /* 396d66a5066SPeter Wemm * Send an interrupt to process. 397d66a5066SPeter Wemm * 398d66a5066SPeter Wemm * Stack is set up to allow sigcode stored 399d66a5066SPeter Wemm * in u. to call routine, followed by kcall 400d66a5066SPeter Wemm * to sigreturn routine below. After sigreturn 401d66a5066SPeter Wemm * resets the signal mask, the stack, and the 402d66a5066SPeter Wemm * frame pointer, it returns to the user 403d66a5066SPeter Wemm * specified pc, psl. 404d66a5066SPeter Wemm */ 405303b270bSEivind Eklund static void 406956d3333SMarcel Moolenaar linux_sendsig(sig_t catcher, int sig, sigset_t *mask, u_long code) 407d66a5066SPeter Wemm { 4081d062e2bSDag-Erling Smørgrav struct thread *td = curthread; 4091d062e2bSDag-Erling Smørgrav struct proc *p = td->td_proc; 41090af4afaSJohn Baldwin struct sigacts *psp; 4111d062e2bSDag-Erling Smørgrav struct trapframe *regs; 4125002a60fSMarcel Moolenaar struct l_sigframe *fp, frame; 4135002a60fSMarcel Moolenaar l_sigset_t lmask; 4142c4ab9ddSAndrew Gallatin int oonstack, i; 415d66a5066SPeter Wemm 4162509e6c2SJohn Baldwin PROC_LOCK_ASSERT(p, MA_OWNED); 41790af4afaSJohn Baldwin psp = p->p_sigacts; 41890af4afaSJohn Baldwin mtx_assert(&psp->ps_mtx, MA_OWNED); 41990af4afaSJohn Baldwin if (SIGISMEMBER(psp->ps_siginfo, sig)) { 420cc6ca9b3SMarcel Moolenaar /* Signal handler installed with SA_SIGINFO. */ 421cc6ca9b3SMarcel Moolenaar linux_rt_sendsig(catcher, sig, mask, code); 422cc6ca9b3SMarcel Moolenaar return; 423cc6ca9b3SMarcel Moolenaar } 424cc6ca9b3SMarcel Moolenaar 425b40ce416SJulian Elischer regs = td->td_frame; 426d034d459SMarcel Moolenaar oonstack = sigonstack(regs->tf_esp); 427d66a5066SPeter Wemm 428d66a5066SPeter Wemm #ifdef DEBUG 4295002a60fSMarcel Moolenaar if (ldebug(sendsig)) 43024593369SJonathan Lemon printf(ARGS(sendsig, "%p, %d, %p, %lu"), 43124593369SJonathan Lemon catcher, sig, (void*)mask, code); 432d66a5066SPeter Wemm #endif 43379363394SAndrew Gallatin 434d66a5066SPeter Wemm /* 435d66a5066SPeter Wemm * Allocate space for the signal handler context. 436d66a5066SPeter Wemm */ 437a30ec4b9SDavid Xu if ((td->td_pflags & TDP_ALTSTACK) && !oonstack && 43890af4afaSJohn Baldwin SIGISMEMBER(psp->ps_sigonstack, sig)) { 439a30ec4b9SDavid Xu fp = (struct l_sigframe *)(td->td_sigstk.ss_sp + 440a30ec4b9SDavid Xu td->td_sigstk.ss_size - sizeof(struct l_sigframe)); 441d034d459SMarcel Moolenaar } else 4425002a60fSMarcel Moolenaar fp = (struct l_sigframe *)regs->tf_esp - 1; 44390af4afaSJohn Baldwin mtx_unlock(&psp->ps_mtx); 444611d9407SJohn Baldwin PROC_UNLOCK(p); 445d66a5066SPeter Wemm 446d66a5066SPeter Wemm /* 447d66a5066SPeter Wemm * Build the argument list for the signal handler. 448d66a5066SPeter Wemm */ 449956d3333SMarcel Moolenaar if (p->p_sysent->sv_sigtbl) 450956d3333SMarcel Moolenaar if (sig <= p->p_sysent->sv_sigsize) 451956d3333SMarcel Moolenaar sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)]; 452d66a5066SPeter Wemm 45399d45c5fSMarcel Moolenaar bzero(&frame, sizeof(frame)); 45499d45c5fSMarcel Moolenaar 455d66a5066SPeter Wemm frame.sf_handler = catcher; 456d66a5066SPeter Wemm frame.sf_sig = sig; 457d66a5066SPeter Wemm 458cc6ca9b3SMarcel Moolenaar bsd_to_linux_sigset(mask, &lmask); 459cc6ca9b3SMarcel Moolenaar 460d66a5066SPeter Wemm /* 461d66a5066SPeter Wemm * Build the signal context to be used by sigreturn. 462d66a5066SPeter Wemm */ 463cc6ca9b3SMarcel Moolenaar frame.sf_sc.sc_mask = lmask.__bits[0]; 4645206bca1SLuoqi Chen frame.sf_sc.sc_gs = rgs(); 4655206bca1SLuoqi Chen frame.sf_sc.sc_fs = regs->tf_fs; 466213fdd80SPeter Wemm frame.sf_sc.sc_es = regs->tf_es; 467213fdd80SPeter Wemm frame.sf_sc.sc_ds = regs->tf_ds; 468213fdd80SPeter Wemm frame.sf_sc.sc_edi = regs->tf_edi; 469213fdd80SPeter Wemm frame.sf_sc.sc_esi = regs->tf_esi; 470213fdd80SPeter Wemm frame.sf_sc.sc_ebp = regs->tf_ebp; 471213fdd80SPeter Wemm frame.sf_sc.sc_ebx = regs->tf_ebx; 472213fdd80SPeter Wemm frame.sf_sc.sc_edx = regs->tf_edx; 473213fdd80SPeter Wemm frame.sf_sc.sc_ecx = regs->tf_ecx; 474213fdd80SPeter Wemm frame.sf_sc.sc_eax = regs->tf_eax; 475213fdd80SPeter Wemm frame.sf_sc.sc_eip = regs->tf_eip; 476213fdd80SPeter Wemm frame.sf_sc.sc_cs = regs->tf_cs; 477213fdd80SPeter Wemm frame.sf_sc.sc_eflags = regs->tf_eflags; 478213fdd80SPeter Wemm frame.sf_sc.sc_esp_at_signal = regs->tf_esp; 479213fdd80SPeter Wemm frame.sf_sc.sc_ss = regs->tf_ss; 480213fdd80SPeter Wemm frame.sf_sc.sc_err = regs->tf_err; 48127a828fcSPierre Beyssac frame.sf_sc.sc_trapno = bsd_to_linux_trapcode(code); 482cc6ca9b3SMarcel Moolenaar 4832c4ab9ddSAndrew Gallatin for (i = 0; i < (LINUX_NSIG_WORDS-1); i++) 484cc6ca9b3SMarcel Moolenaar frame.sf_extramask[i] = lmask.__bits[i+1]; 485d66a5066SPeter Wemm 486d66a5066SPeter Wemm if (copyout(&frame, fp, sizeof(frame)) != 0) { 487d66a5066SPeter Wemm /* 488d66a5066SPeter Wemm * Process has trashed its stack; give it an illegal 489d66a5066SPeter Wemm * instruction to halt it in its tracks. 490d66a5066SPeter Wemm */ 49119eb87d2SJohn Baldwin PROC_LOCK(p); 492b40ce416SJulian Elischer sigexit(td, SIGILL); 493d66a5066SPeter Wemm } 494d66a5066SPeter Wemm 495d66a5066SPeter Wemm /* 496d66a5066SPeter Wemm * Build context to run handler in. 497d66a5066SPeter Wemm */ 498213fdd80SPeter Wemm regs->tf_esp = (int)fp; 4994c56fcdeSBruce Evans regs->tf_eip = PS_STRINGS - *(p->p_sysent->sv_szsigcode); 500846ac226SBruce Evans regs->tf_eflags &= ~(PSL_T | PSL_VM); 501213fdd80SPeter Wemm regs->tf_cs = _ucodesel; 502213fdd80SPeter Wemm regs->tf_ds = _udatasel; 503213fdd80SPeter Wemm regs->tf_es = _udatasel; 5045206bca1SLuoqi Chen regs->tf_fs = _udatasel; 505213fdd80SPeter Wemm regs->tf_ss = _udatasel; 5065002a60fSMarcel Moolenaar PROC_LOCK(p); 50790af4afaSJohn Baldwin mtx_lock(&psp->ps_mtx); 508d66a5066SPeter Wemm } 509d66a5066SPeter Wemm 510d66a5066SPeter Wemm /* 511d66a5066SPeter Wemm * System call to cleanup state after a signal 512d66a5066SPeter Wemm * has been taken. Reset signal mask and 513d66a5066SPeter Wemm * stack state from context left by sendsig (above). 514d66a5066SPeter Wemm * Return to previous pc and psl as specified by 515d66a5066SPeter Wemm * context left by sendsig. Check carefully to 516d66a5066SPeter Wemm * make sure that the user has not modified the 517d66a5066SPeter Wemm * psl to gain improper privileges or to cause 518d66a5066SPeter Wemm * a machine fault. 519d66a5066SPeter Wemm */ 520d66a5066SPeter Wemm int 521b07cd97eSMark Murray linux_sigreturn(struct thread *td, struct linux_sigreturn_args *args) 522d66a5066SPeter Wemm { 523b40ce416SJulian Elischer struct proc *p = td->td_proc; 5245002a60fSMarcel Moolenaar struct l_sigframe frame; 5251d062e2bSDag-Erling Smørgrav struct trapframe *regs; 5265002a60fSMarcel Moolenaar l_sigset_t lmask; 5272c4ab9ddSAndrew Gallatin int eflags, i; 528d66a5066SPeter Wemm 529b40ce416SJulian Elischer regs = td->td_frame; 530d66a5066SPeter Wemm 531d66a5066SPeter Wemm #ifdef DEBUG 53224593369SJonathan Lemon if (ldebug(sigreturn)) 53324593369SJonathan Lemon printf(ARGS(sigreturn, "%p"), (void *)args->sfp); 534d66a5066SPeter Wemm #endif 535d66a5066SPeter Wemm /* 536cc6ca9b3SMarcel Moolenaar * The trampoline code hands us the sigframe. 537d66a5066SPeter Wemm * It is unsafe to keep track of it ourselves, in the event that a 538d66a5066SPeter Wemm * program jumps out of a signal handler. 539d66a5066SPeter Wemm */ 5404b7ef73dSDag-Erling Smørgrav if (copyin(args->sfp, &frame, sizeof(frame)) != 0) 541d66a5066SPeter Wemm return (EFAULT); 542d66a5066SPeter Wemm 543d66a5066SPeter Wemm /* 544d66a5066SPeter Wemm * Check for security violations. 545d66a5066SPeter Wemm */ 546d66a5066SPeter Wemm #define EFLAGS_SECURE(ef, oef) ((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0) 547cc6ca9b3SMarcel Moolenaar eflags = frame.sf_sc.sc_eflags; 548d66a5066SPeter Wemm /* 549d66a5066SPeter Wemm * XXX do allow users to change the privileged flag PSL_RF. The 550d66a5066SPeter Wemm * cpu sets PSL_RF in tf_eflags for faults. Debuggers should 551d66a5066SPeter Wemm * sometimes set it there too. tf_eflags is kept in the signal 552d66a5066SPeter Wemm * context during signal handling and there is no other place 553d66a5066SPeter Wemm * to remember it, so the PSL_RF bit may be corrupted by the 554d66a5066SPeter Wemm * signal handler without us knowing. Corruption of the PSL_RF 555d66a5066SPeter Wemm * bit at worst causes one more or one less debugger trap, so 556d66a5066SPeter Wemm * allowing it is fairly harmless. 557d66a5066SPeter Wemm */ 558b07cd97eSMark Murray if (!EFLAGS_SECURE(eflags & ~PSL_RF, regs->tf_eflags & ~PSL_RF)) 559d66a5066SPeter Wemm return(EINVAL); 560d66a5066SPeter Wemm 561d66a5066SPeter Wemm /* 562d66a5066SPeter Wemm * Don't allow users to load a valid privileged %cs. Let the 563d66a5066SPeter Wemm * hardware check for invalid selectors, excess privilege in 564d66a5066SPeter Wemm * other selectors, invalid %eip's and invalid %esp's. 565d66a5066SPeter Wemm */ 56640d50994SPhilippe Charnier #define CS_SECURE(cs) (ISPL(cs) == SEL_UPL) 567cc6ca9b3SMarcel Moolenaar if (!CS_SECURE(frame.sf_sc.sc_cs)) { 5681bf4700bSJeff Roberson trapsignal(td, SIGBUS, T_PROTFLT); 569d66a5066SPeter Wemm return(EINVAL); 570d66a5066SPeter Wemm } 571d66a5066SPeter Wemm 572cc6ca9b3SMarcel Moolenaar lmask.__bits[0] = frame.sf_sc.sc_mask; 5732c4ab9ddSAndrew Gallatin for (i = 0; i < (LINUX_NSIG_WORDS-1); i++) 574cc6ca9b3SMarcel Moolenaar lmask.__bits[i+1] = frame.sf_extramask[i]; 575611d9407SJohn Baldwin PROC_LOCK(p); 5764093529dSJeff Roberson linux_to_bsd_sigset(&lmask, &td->td_sigmask); 5774093529dSJeff Roberson SIG_CANTMASK(td->td_sigmask); 5784093529dSJeff Roberson signotify(td); 579611d9407SJohn Baldwin PROC_UNLOCK(p); 580956d3333SMarcel Moolenaar 581d66a5066SPeter Wemm /* 582d66a5066SPeter Wemm * Restore signal context. 583d66a5066SPeter Wemm */ 5845206bca1SLuoqi Chen /* %gs was restored by the trampoline. */ 585cc6ca9b3SMarcel Moolenaar regs->tf_fs = frame.sf_sc.sc_fs; 586cc6ca9b3SMarcel Moolenaar regs->tf_es = frame.sf_sc.sc_es; 587cc6ca9b3SMarcel Moolenaar regs->tf_ds = frame.sf_sc.sc_ds; 588cc6ca9b3SMarcel Moolenaar regs->tf_edi = frame.sf_sc.sc_edi; 589cc6ca9b3SMarcel Moolenaar regs->tf_esi = frame.sf_sc.sc_esi; 590cc6ca9b3SMarcel Moolenaar regs->tf_ebp = frame.sf_sc.sc_ebp; 591cc6ca9b3SMarcel Moolenaar regs->tf_ebx = frame.sf_sc.sc_ebx; 592cc6ca9b3SMarcel Moolenaar regs->tf_edx = frame.sf_sc.sc_edx; 593cc6ca9b3SMarcel Moolenaar regs->tf_ecx = frame.sf_sc.sc_ecx; 594cc6ca9b3SMarcel Moolenaar regs->tf_eax = frame.sf_sc.sc_eax; 595cc6ca9b3SMarcel Moolenaar regs->tf_eip = frame.sf_sc.sc_eip; 596cc6ca9b3SMarcel Moolenaar regs->tf_cs = frame.sf_sc.sc_cs; 597213fdd80SPeter Wemm regs->tf_eflags = eflags; 598cc6ca9b3SMarcel Moolenaar regs->tf_esp = frame.sf_sc.sc_esp_at_signal; 599cc6ca9b3SMarcel Moolenaar regs->tf_ss = frame.sf_sc.sc_ss; 600d66a5066SPeter Wemm 601d66a5066SPeter Wemm return (EJUSTRETURN); 602d66a5066SPeter Wemm } 603d66a5066SPeter Wemm 60479363394SAndrew Gallatin /* 60579363394SAndrew Gallatin * System call to cleanup state after a signal 60679363394SAndrew Gallatin * has been taken. Reset signal mask and 60779363394SAndrew Gallatin * stack state from context left by rt_sendsig (above). 60879363394SAndrew Gallatin * Return to previous pc and psl as specified by 60979363394SAndrew Gallatin * context left by sendsig. Check carefully to 61079363394SAndrew Gallatin * make sure that the user has not modified the 61179363394SAndrew Gallatin * psl to gain improper privileges or to cause 61279363394SAndrew Gallatin * a machine fault. 61379363394SAndrew Gallatin */ 61479363394SAndrew Gallatin int 615b07cd97eSMark Murray linux_rt_sigreturn(struct thread *td, struct linux_rt_sigreturn_args *args) 61679363394SAndrew Gallatin { 617b40ce416SJulian Elischer struct proc *p = td->td_proc; 6185002a60fSMarcel Moolenaar struct l_ucontext uc; 6195002a60fSMarcel Moolenaar struct l_sigcontext *context; 6205002a60fSMarcel Moolenaar l_stack_t *lss; 621206a5d3aSIan Dowse stack_t ss; 6221d062e2bSDag-Erling Smørgrav struct trapframe *regs; 62379363394SAndrew Gallatin int eflags; 62479363394SAndrew Gallatin 625b40ce416SJulian Elischer regs = td->td_frame; 62679363394SAndrew Gallatin 62779363394SAndrew Gallatin #ifdef DEBUG 62824593369SJonathan Lemon if (ldebug(rt_sigreturn)) 62924593369SJonathan Lemon printf(ARGS(rt_sigreturn, "%p"), (void *)args->ucp); 63079363394SAndrew Gallatin #endif 63179363394SAndrew Gallatin /* 632cc6ca9b3SMarcel Moolenaar * The trampoline code hands us the ucontext. 63379363394SAndrew Gallatin * It is unsafe to keep track of it ourselves, in the event that a 63479363394SAndrew Gallatin * program jumps out of a signal handler. 63579363394SAndrew Gallatin */ 6364b7ef73dSDag-Erling Smørgrav if (copyin(args->ucp, &uc, sizeof(uc)) != 0) 63779363394SAndrew Gallatin return (EFAULT); 63879363394SAndrew Gallatin 63979363394SAndrew Gallatin context = &uc.uc_mcontext; 64079363394SAndrew Gallatin 64179363394SAndrew Gallatin /* 64279363394SAndrew Gallatin * Check for security violations. 64379363394SAndrew Gallatin */ 64479363394SAndrew Gallatin #define EFLAGS_SECURE(ef, oef) ((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0) 64579363394SAndrew Gallatin eflags = context->sc_eflags; 64679363394SAndrew Gallatin /* 64779363394SAndrew Gallatin * XXX do allow users to change the privileged flag PSL_RF. The 64879363394SAndrew Gallatin * cpu sets PSL_RF in tf_eflags for faults. Debuggers should 64979363394SAndrew Gallatin * sometimes set it there too. tf_eflags is kept in the signal 65079363394SAndrew Gallatin * context during signal handling and there is no other place 65179363394SAndrew Gallatin * to remember it, so the PSL_RF bit may be corrupted by the 65279363394SAndrew Gallatin * signal handler without us knowing. Corruption of the PSL_RF 65379363394SAndrew Gallatin * bit at worst causes one more or one less debugger trap, so 65479363394SAndrew Gallatin * allowing it is fairly harmless. 65579363394SAndrew Gallatin */ 656b07cd97eSMark Murray if (!EFLAGS_SECURE(eflags & ~PSL_RF, regs->tf_eflags & ~PSL_RF)) 65779363394SAndrew Gallatin return(EINVAL); 65879363394SAndrew Gallatin 65979363394SAndrew Gallatin /* 66079363394SAndrew Gallatin * Don't allow users to load a valid privileged %cs. Let the 66179363394SAndrew Gallatin * hardware check for invalid selectors, excess privilege in 66279363394SAndrew Gallatin * other selectors, invalid %eip's and invalid %esp's. 66379363394SAndrew Gallatin */ 66479363394SAndrew Gallatin #define CS_SECURE(cs) (ISPL(cs) == SEL_UPL) 66579363394SAndrew Gallatin if (!CS_SECURE(context->sc_cs)) { 6661bf4700bSJeff Roberson trapsignal(td, SIGBUS, T_PROTFLT); 66779363394SAndrew Gallatin return(EINVAL); 66879363394SAndrew Gallatin } 66979363394SAndrew Gallatin 670611d9407SJohn Baldwin PROC_LOCK(p); 6714093529dSJeff Roberson linux_to_bsd_sigset(&uc.uc_sigmask, &td->td_sigmask); 6724093529dSJeff Roberson SIG_CANTMASK(td->td_sigmask); 6734093529dSJeff Roberson signotify(td); 674611d9407SJohn Baldwin PROC_UNLOCK(p); 67579363394SAndrew Gallatin 67679363394SAndrew Gallatin /* 677cc6ca9b3SMarcel Moolenaar * Restore signal context 67879363394SAndrew Gallatin */ 67979363394SAndrew Gallatin /* %gs was restored by the trampoline. */ 68079363394SAndrew Gallatin regs->tf_fs = context->sc_fs; 68179363394SAndrew Gallatin regs->tf_es = context->sc_es; 68279363394SAndrew Gallatin regs->tf_ds = context->sc_ds; 68379363394SAndrew Gallatin regs->tf_edi = context->sc_edi; 68479363394SAndrew Gallatin regs->tf_esi = context->sc_esi; 68579363394SAndrew Gallatin regs->tf_ebp = context->sc_ebp; 68679363394SAndrew Gallatin regs->tf_ebx = context->sc_ebx; 68779363394SAndrew Gallatin regs->tf_edx = context->sc_edx; 68879363394SAndrew Gallatin regs->tf_ecx = context->sc_ecx; 68979363394SAndrew Gallatin regs->tf_eax = context->sc_eax; 69079363394SAndrew Gallatin regs->tf_eip = context->sc_eip; 69179363394SAndrew Gallatin regs->tf_cs = context->sc_cs; 69279363394SAndrew Gallatin regs->tf_eflags = eflags; 69379363394SAndrew Gallatin regs->tf_esp = context->sc_esp_at_signal; 69479363394SAndrew Gallatin regs->tf_ss = context->sc_ss; 69579363394SAndrew Gallatin 69679363394SAndrew Gallatin /* 69779363394SAndrew Gallatin * call sigaltstack & ignore results.. 69879363394SAndrew Gallatin */ 69979363394SAndrew Gallatin lss = &uc.uc_stack; 700206a5d3aSIan Dowse ss.ss_sp = lss->ss_sp; 701206a5d3aSIan Dowse ss.ss_size = lss->ss_size; 702206a5d3aSIan Dowse ss.ss_flags = linux_to_bsd_sigaltstack(lss->ss_flags); 70379363394SAndrew Gallatin 70479363394SAndrew Gallatin #ifdef DEBUG 70524593369SJonathan Lemon if (ldebug(rt_sigreturn)) 70624593369SJonathan Lemon printf(LMSG("rt_sigret flags: 0x%x, sp: %p, ss: 0x%x, mask: 0x%x"), 707206a5d3aSIan Dowse ss.ss_flags, ss.ss_sp, ss.ss_size, context->sc_mask); 70879363394SAndrew Gallatin #endif 709206a5d3aSIan Dowse (void)kern_sigaltstack(td, &ss, NULL); 71079363394SAndrew Gallatin 71179363394SAndrew Gallatin return (EJUSTRETURN); 71279363394SAndrew Gallatin } 71379363394SAndrew Gallatin 714356861dbSMatthew Dillon /* 715356861dbSMatthew Dillon * MPSAFE 716356861dbSMatthew Dillon */ 717303b270bSEivind Eklund static void 718d66a5066SPeter Wemm linux_prepsyscall(struct trapframe *tf, int *args, u_int *code, caddr_t *params) 719d66a5066SPeter Wemm { 720d66a5066SPeter Wemm args[0] = tf->tf_ebx; 721d66a5066SPeter Wemm args[1] = tf->tf_ecx; 722d66a5066SPeter Wemm args[2] = tf->tf_edx; 723d66a5066SPeter Wemm args[3] = tf->tf_esi; 724d66a5066SPeter Wemm args[4] = tf->tf_edi; 7257646aefcSPeter Wemm args[5] = tf->tf_ebp; /* Unconfirmed */ 726d66a5066SPeter Wemm *params = NULL; /* no copyin */ 727d66a5066SPeter Wemm } 728d66a5066SPeter Wemm 729d323ddf3SMatthew Dillon /* 730d323ddf3SMatthew Dillon * If a linux binary is exec'ing something, try this image activator 731d323ddf3SMatthew Dillon * first. We override standard shell script execution in order to 732d323ddf3SMatthew Dillon * be able to modify the interpreter path. We only do this if a linux 733d323ddf3SMatthew Dillon * binary is doing the exec, so we do not create an EXEC module for it. 734d323ddf3SMatthew Dillon */ 73589c9a483SAlfred Perlstein static int exec_linux_imgact_try(struct image_params *iparams); 736d323ddf3SMatthew Dillon 737d323ddf3SMatthew Dillon static int 738b07cd97eSMark Murray exec_linux_imgact_try(struct image_params *imgp) 739d323ddf3SMatthew Dillon { 740d323ddf3SMatthew Dillon const char *head = (const char *)imgp->image_header; 741d323ddf3SMatthew Dillon int error = -1; 742d323ddf3SMatthew Dillon 743d323ddf3SMatthew Dillon /* 744d323ddf3SMatthew Dillon * The interpreter for shell scripts run from a linux binary needs 745d323ddf3SMatthew Dillon * to be located in /compat/linux if possible in order to recursively 746d323ddf3SMatthew Dillon * maintain linux path emulation. 747d323ddf3SMatthew Dillon */ 748d323ddf3SMatthew Dillon if (((const short *)head)[0] == SHELLMAGIC) { 749d323ddf3SMatthew Dillon /* 750d323ddf3SMatthew Dillon * Run our normal shell image activator. If it succeeds attempt 751d323ddf3SMatthew Dillon * to use the alternate path for the interpreter. If an alternate 752d323ddf3SMatthew Dillon * path is found, use our stringspace to store it. 753d323ddf3SMatthew Dillon */ 754d323ddf3SMatthew Dillon if ((error = exec_shell_imgact(imgp)) == 0) { 755d323ddf3SMatthew Dillon char *rpath = NULL; 756d323ddf3SMatthew Dillon 757079b7badSJulian Elischer linux_emul_find(FIRST_THREAD_IN_PROC(imgp->proc), NULL, 758d323ddf3SMatthew Dillon imgp->interpreter_name, &rpath, 0); 759d323ddf3SMatthew Dillon if (rpath != imgp->interpreter_name) { 760d323ddf3SMatthew Dillon int len = strlen(rpath) + 1; 761d323ddf3SMatthew Dillon 762d323ddf3SMatthew Dillon if (len <= MAXSHELLCMDLEN) { 763d323ddf3SMatthew Dillon memcpy(imgp->interpreter_name, rpath, len); 764d323ddf3SMatthew Dillon } 765d323ddf3SMatthew Dillon free(rpath, M_TEMP); 766d323ddf3SMatthew Dillon } 767d323ddf3SMatthew Dillon } 768d323ddf3SMatthew Dillon } 769d323ddf3SMatthew Dillon return(error); 770d323ddf3SMatthew Dillon } 771d323ddf3SMatthew Dillon 772598d45beSMatthew N. Dodd /* 773598d45beSMatthew N. Dodd * exec_setregs may initialize some registers differently than Linux 774598d45beSMatthew N. Dodd * does, thus potentially confusing Linux binaries. If necessary, we 775598d45beSMatthew N. Dodd * override the exec_setregs default(s) here. 776598d45beSMatthew N. Dodd */ 777598d45beSMatthew N. Dodd static void 778598d45beSMatthew N. Dodd exec_linux_setregs(struct thread *td, u_long entry, 779598d45beSMatthew N. Dodd u_long stack, u_long ps_strings) 780598d45beSMatthew N. Dodd { 7812a51b9b0SDavid Schultz static const u_short control = __LINUX_NPXCW__; 782598d45beSMatthew N. Dodd struct pcb *pcb = td->td_pcb; 783598d45beSMatthew N. Dodd 784598d45beSMatthew N. Dodd exec_setregs(td, entry, stack, ps_strings); 785598d45beSMatthew N. Dodd 786598d45beSMatthew N. Dodd /* Linux sets %gs to 0, we default to _udatasel */ 787598d45beSMatthew N. Dodd pcb->pcb_gs = 0; load_gs(0); 7882a51b9b0SDavid Schultz 7892a51b9b0SDavid Schultz /* Linux sets the i387 to extended precision. */ 7902a51b9b0SDavid Schultz fldcw(&control); 791598d45beSMatthew N. Dodd } 792598d45beSMatthew N. Dodd 793d66a5066SPeter Wemm struct sysentvec linux_sysvec = { 794e1743d02SSøren Schmidt LINUX_SYS_MAXSYSCALL, 795d66a5066SPeter Wemm linux_sysent, 796d66a5066SPeter Wemm 0xff, 797956d3333SMarcel Moolenaar LINUX_SIGTBLSZ, 798d66a5066SPeter Wemm bsd_to_linux_signal, 79985f118c8SDmitrij Tejblum ELAST + 1, 800d66a5066SPeter Wemm bsd_to_linux_errno, 801288078beSEivind Eklund translate_traps, 802d66a5066SPeter Wemm linux_fixup, 803d66a5066SPeter Wemm linux_sendsig, 804d66a5066SPeter Wemm linux_sigcode, 805d66a5066SPeter Wemm &linux_szsigcode, 806d66a5066SPeter Wemm linux_prepsyscall, 80722d4b0fbSJohn Polstra "Linux a.out", 808d3adf769SDavid Schultz NULL, 809806d7daaSMarcel Moolenaar exec_linux_imgact_try, 810f36ba452SJake Burkholder LINUX_MINSIGSTKSZ, 811f36ba452SJake Burkholder PAGE_SIZE, 812f36ba452SJake Burkholder VM_MIN_ADDRESS, 813f36ba452SJake Burkholder VM_MAXUSER_ADDRESS, 814f36ba452SJake Burkholder USRSTACK, 815f36ba452SJake Burkholder PS_STRINGS, 816f36ba452SJake Burkholder VM_PROT_ALL, 817f36ba452SJake Burkholder exec_copyout_strings, 818c460ac3aSPeter Wemm exec_linux_setregs, 819c460ac3aSPeter Wemm NULL 820d66a5066SPeter Wemm }; 821e1743d02SSøren Schmidt 822e1743d02SSøren Schmidt struct sysentvec elf_linux_sysvec = { 823e1743d02SSøren Schmidt LINUX_SYS_MAXSYSCALL, 824e1743d02SSøren Schmidt linux_sysent, 825e1743d02SSøren Schmidt 0xff, 826956d3333SMarcel Moolenaar LINUX_SIGTBLSZ, 827e1743d02SSøren Schmidt bsd_to_linux_signal, 82885f118c8SDmitrij Tejblum ELAST + 1, 829e1743d02SSøren Schmidt bsd_to_linux_errno, 830288078beSEivind Eklund translate_traps, 831e1743d02SSøren Schmidt elf_linux_fixup, 832e1743d02SSøren Schmidt linux_sendsig, 833e1743d02SSøren Schmidt linux_sigcode, 834e1743d02SSøren Schmidt &linux_szsigcode, 835e1743d02SSøren Schmidt linux_prepsyscall, 83622d4b0fbSJohn Polstra "Linux ELF", 8373ebc1248SPeter Wemm elf32_coredump, 838806d7daaSMarcel Moolenaar exec_linux_imgact_try, 839f36ba452SJake Burkholder LINUX_MINSIGSTKSZ, 840f36ba452SJake Burkholder PAGE_SIZE, 841f36ba452SJake Burkholder VM_MIN_ADDRESS, 842f36ba452SJake Burkholder VM_MAXUSER_ADDRESS, 843f36ba452SJake Burkholder USRSTACK, 844f36ba452SJake Burkholder PS_STRINGS, 845f36ba452SJake Burkholder VM_PROT_ALL, 846f36ba452SJake Burkholder exec_copyout_strings, 847c460ac3aSPeter Wemm exec_linux_setregs, 848c460ac3aSPeter Wemm NULL 849e1743d02SSøren Schmidt }; 850e1743d02SSøren Schmidt 851514058dcSAlexander Langer static Elf32_Brandinfo linux_brand = { 852c815a20cSDavid E. O'Brien ELFOSABI_LINUX, 8533ebc1248SPeter Wemm EM_386, 85421a3ee0eSDavid E. O'Brien "Linux", 855ea5a2b2eSSøren Schmidt "/compat/linux", 8565cf588ebSPeter Wemm "/lib/ld-linux.so.1", 8579b68618dSPeter Wemm &elf_linux_sysvec, 8589b68618dSPeter Wemm NULL, 8595cf588ebSPeter Wemm }; 8605cf588ebSPeter Wemm 861514058dcSAlexander Langer static Elf32_Brandinfo linux_glibc2brand = { 862c815a20cSDavid E. O'Brien ELFOSABI_LINUX, 8633ebc1248SPeter Wemm EM_386, 86421a3ee0eSDavid E. O'Brien "Linux", 8654e138a28SMike Smith "/compat/linux", 8664e138a28SMike Smith "/lib/ld-linux.so.2", 8679b68618dSPeter Wemm &elf_linux_sysvec, 8689b68618dSPeter Wemm NULL, 8694e138a28SMike Smith }; 8704e138a28SMike Smith 871514058dcSAlexander Langer Elf32_Brandinfo *linux_brandlist[] = { 872514058dcSAlexander Langer &linux_brand, 873514058dcSAlexander Langer &linux_glibc2brand, 874514058dcSAlexander Langer NULL 875514058dcSAlexander Langer }; 876514058dcSAlexander Langer 877aa855a59SPeter Wemm static int 878c25ded31SBruce Evans linux_elf_modevent(module_t mod, int type, void *data) 879d30ea4f5SPeter Wemm { 880514058dcSAlexander Langer Elf32_Brandinfo **brandinfo; 881514058dcSAlexander Langer int error; 882f41325dbSPeter Wemm struct linux_ioctl_handler **lihp; 883514058dcSAlexander Langer 884514058dcSAlexander Langer error = 0; 885514058dcSAlexander Langer 886aa855a59SPeter Wemm switch(type) { 887aa855a59SPeter Wemm case MOD_LOAD: 888aa855a59SPeter Wemm for (brandinfo = &linux_brandlist[0]; *brandinfo != NULL; 889aa855a59SPeter Wemm ++brandinfo) 8903ebc1248SPeter Wemm if (elf32_insert_brand_entry(*brandinfo) < 0) 891aa855a59SPeter Wemm error = EINVAL; 892466b14d7SMarcel Moolenaar if (error == 0) { 893f41325dbSPeter Wemm SET_FOREACH(lihp, linux_ioctl_handler_set) 894f41325dbSPeter Wemm linux_ioctl_register_handler(*lihp); 89543bef515SMarcel Moolenaar if (bootverbose) 896466b14d7SMarcel Moolenaar printf("Linux ELF exec handler installed\n"); 897466b14d7SMarcel Moolenaar } else 898466b14d7SMarcel Moolenaar printf("cannot insert Linux ELF brand handler\n"); 899aa855a59SPeter Wemm break; 900aa855a59SPeter Wemm case MOD_UNLOAD: 901aa855a59SPeter Wemm for (brandinfo = &linux_brandlist[0]; *brandinfo != NULL; 902aa855a59SPeter Wemm ++brandinfo) 9033ebc1248SPeter Wemm if (elf32_brand_inuse(*brandinfo)) 904d2758342SMark Newton error = EBUSY; 905d2758342SMark Newton if (error == 0) { 906d2758342SMark Newton for (brandinfo = &linux_brandlist[0]; 907d2758342SMark Newton *brandinfo != NULL; ++brandinfo) 9083ebc1248SPeter Wemm if (elf32_remove_brand_entry(*brandinfo) < 0) 909aa855a59SPeter Wemm error = EINVAL; 910d2758342SMark Newton } 911466b14d7SMarcel Moolenaar if (error == 0) { 912f41325dbSPeter Wemm SET_FOREACH(lihp, linux_ioctl_handler_set) 913f41325dbSPeter Wemm linux_ioctl_unregister_handler(*lihp); 914466b14d7SMarcel Moolenaar if (bootverbose) 915466b14d7SMarcel Moolenaar printf("Linux ELF exec handler removed\n"); 91635eb8c5aSJohn Baldwin linux_mib_destroy(); 917466b14d7SMarcel Moolenaar } else 918aa855a59SPeter Wemm printf("Could not deinstall ELF interpreter entry\n"); 919aa855a59SPeter Wemm break; 920aa855a59SPeter Wemm default: 9213e019deaSPoul-Henning Kamp return EOPNOTSUPP; 922d30ea4f5SPeter Wemm } 923aa855a59SPeter Wemm return error; 924aa855a59SPeter Wemm } 925466b14d7SMarcel Moolenaar 926aa855a59SPeter Wemm static moduledata_t linux_elf_mod = { 927aa855a59SPeter Wemm "linuxelf", 928aa855a59SPeter Wemm linux_elf_modevent, 929aa855a59SPeter Wemm 0 930aa855a59SPeter Wemm }; 931466b14d7SMarcel Moolenaar 932aa855a59SPeter Wemm DECLARE_MODULE(linuxelf, linux_elf_mod, SI_SUB_EXEC, SI_ORDER_ANY); 933