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 #include <sys/param.h> 3375f83872SPeter Wemm #include <sys/systm.h> 34ff22c670SBruce Evans #include <sys/exec.h> 35d66a5066SPeter Wemm #include <sys/imgact.h> 3622d4b0fbSJohn Polstra #include <sys/imgact_aout.h> 37e1743d02SSøren Schmidt #include <sys/imgact_elf.h> 38ff22c670SBruce Evans #include <sys/kernel.h> 397106ca0dSJohn Baldwin #include <sys/lock.h> 40e1743d02SSøren Schmidt #include <sys/malloc.h> 41ff22c670SBruce Evans #include <sys/module.h> 4223955314SAlfred Perlstein #include <sys/mutex.h> 43fb919e4dSMark Murray #include <sys/proc.h> 44fb919e4dSMark Murray #include <sys/signalvar.h> 45206a5d3aSIan Dowse #include <sys/syscallsubr.h> 46fb919e4dSMark Murray #include <sys/sysent.h> 47fb919e4dSMark Murray #include <sys/sysproto.h> 48a9148ab1SPeter Wemm #include <sys/vnode.h> 499b44bfc5SAlexander Leidinger #include <sys/eventhandler.h> 50fb919e4dSMark Murray 51d66a5066SPeter Wemm #include <vm/vm.h> 52a9148ab1SPeter Wemm #include <vm/pmap.h> 53ff22c670SBruce Evans #include <vm/vm_extern.h> 54a9148ab1SPeter Wemm #include <vm/vm_map.h> 55a9148ab1SPeter Wemm #include <vm/vm_object.h> 56ff22c670SBruce Evans #include <vm/vm_page.h> 57ff22c670SBruce Evans #include <vm/vm_param.h> 58ff22c670SBruce Evans 59ff22c670SBruce Evans #include <machine/cpu.h> 60ff22c670SBruce Evans #include <machine/md_var.h> 61d3adf769SDavid Schultz #include <machine/pcb.h> 62a9148ab1SPeter Wemm 63d66a5066SPeter Wemm #include <i386/linux/linux.h> 64ebea8660SMarcel Moolenaar #include <i386/linux/linux_proto.h> 6594cb2ecfSAlexander Leidinger #include <compat/linux/linux_emul.h> 660f9d6538SJohn Baldwin #include <compat/linux/linux_mib.h> 67b595ab37SAndrew Gallatin #include <compat/linux/linux_signal.h> 68322bfdc3SMarcel Moolenaar #include <compat/linux/linux_util.h> 69e1743d02SSøren Schmidt 701d91482dSPeter Wemm MODULE_VERSION(linux, 1); 711d91482dSPeter Wemm 7243bef515SMarcel Moolenaar MALLOC_DEFINE(M_LINUX, "linux", "Linux mode structures"); 7343bef515SMarcel Moolenaar 74d323ddf3SMatthew Dillon #if BYTE_ORDER == LITTLE_ENDIAN 75d323ddf3SMatthew Dillon #define SHELLMAGIC 0x2123 /* #! */ 76d323ddf3SMatthew Dillon #else 77d323ddf3SMatthew Dillon #define SHELLMAGIC 0x2321 78d323ddf3SMatthew Dillon #endif 79d323ddf3SMatthew Dillon 80e061a6caSMarcel Moolenaar /* 81e061a6caSMarcel Moolenaar * Allow the sendsig functions to use the ldebug() facility 82e061a6caSMarcel Moolenaar * even though they are not syscalls themselves. Map them 83e061a6caSMarcel Moolenaar * to syscall 0. This is slightly less bogus than using 84e061a6caSMarcel Moolenaar * ldebug(sigreturn). 85e061a6caSMarcel Moolenaar */ 86e061a6caSMarcel Moolenaar #define LINUX_SYS_linux_rt_sendsig 0 87e061a6caSMarcel Moolenaar #define LINUX_SYS_linux_sendsig 0 88e061a6caSMarcel Moolenaar 892a51b9b0SDavid Schultz #define fldcw(addr) __asm("fldcw %0" : : "m" (*(addr))) 902a51b9b0SDavid Schultz #define __LINUX_NPXCW__ 0x37f 912a51b9b0SDavid Schultz 9243bef515SMarcel Moolenaar extern char linux_sigcode[]; 9343bef515SMarcel Moolenaar extern int linux_szsigcode; 9443bef515SMarcel Moolenaar 9543bef515SMarcel Moolenaar extern struct sysent linux_sysent[LINUX_SYS_MAXSYSCALL]; 9643bef515SMarcel Moolenaar 97f41325dbSPeter Wemm SET_DECLARE(linux_ioctl_handler_set, struct linux_ioctl_handler); 98060e4882SDoug Ambrisko SET_DECLARE(linux_device_handler_set, struct linux_device_handler); 9943bef515SMarcel Moolenaar 10089c9a483SAlfred Perlstein static int linux_fixup(register_t **stack_base, 10189c9a483SAlfred Perlstein struct image_params *iparams); 10289c9a483SAlfred Perlstein static int elf_linux_fixup(register_t **stack_base, 10389c9a483SAlfred Perlstein struct image_params *iparams); 104bda2a3afSBruce Evans static void linux_prepsyscall(struct trapframe *tf, int *args, u_int *code, 105bda2a3afSBruce Evans caddr_t *params); 1069104847fSDavid Xu static void linux_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask); 107598d45beSMatthew N. Dodd static void exec_linux_setregs(struct thread *td, u_long entry, 108598d45beSMatthew N. Dodd u_long stack, u_long ps_strings); 109d66a5066SPeter Wemm 1109b44bfc5SAlexander Leidinger extern LIST_HEAD(futex_list, futex) futex_list; 111bb59e63fSAlexander Leidinger extern struct sx futex_sx; 1129b44bfc5SAlexander Leidinger 1139b44bfc5SAlexander Leidinger static eventhandler_tag linux_exit_tag; 1149b44bfc5SAlexander Leidinger static eventhandler_tag linux_schedtail_tag; 1159b44bfc5SAlexander Leidinger static eventhandler_tag linux_exec_tag; 1169b44bfc5SAlexander Leidinger 117d66a5066SPeter Wemm /* 118d66a5066SPeter Wemm * Linux syscalls return negative errno's, we do positive and map them 11950e422f0SAlexander Leidinger * Reference: 12050e422f0SAlexander Leidinger * FreeBSD: src/sys/sys/errno.h 12150e422f0SAlexander Leidinger * Linux: linux-2.6.17.8/include/asm-generic/errno-base.h 12250e422f0SAlexander Leidinger * linux-2.6.17.8/include/asm-generic/errno.h 123d66a5066SPeter Wemm */ 12485f118c8SDmitrij Tejblum static int bsd_to_linux_errno[ELAST + 1] = { 125d66a5066SPeter Wemm -0, -1, -2, -3, -4, -5, -6, -7, -8, -9, 126d66a5066SPeter Wemm -10, -35, -12, -13, -14, -15, -16, -17, -18, -19, 127d66a5066SPeter Wemm -20, -21, -22, -23, -24, -25, -26, -27, -28, -29, 128d66a5066SPeter Wemm -30, -31, -32, -33, -34, -11,-115,-114, -88, -89, 129d66a5066SPeter Wemm -90, -91, -92, -93, -94, -95, -96, -97, -98, -99, 130d66a5066SPeter Wemm -100,-101,-102,-103,-104,-105,-106,-107,-108,-109, 131d66a5066SPeter Wemm -110,-111, -40, -36,-112,-113, -39, -11, -87,-122, 132d66a5066SPeter Wemm -116, -66, -6, -6, -6, -6, -6, -37, -38, -9, 13350e422f0SAlexander Leidinger -6, -6, -43, -42, -75,-125, -84, -95, -16, -74, 13450e422f0SAlexander Leidinger -72, -67, -71 135d66a5066SPeter Wemm }; 136d66a5066SPeter Wemm 137956d3333SMarcel Moolenaar int bsd_to_linux_signal[LINUX_SIGTBLSZ] = { 138956d3333SMarcel Moolenaar LINUX_SIGHUP, LINUX_SIGINT, LINUX_SIGQUIT, LINUX_SIGILL, 139956d3333SMarcel Moolenaar LINUX_SIGTRAP, LINUX_SIGABRT, 0, LINUX_SIGFPE, 140ba873f4cSAlexander Kabaev LINUX_SIGKILL, LINUX_SIGBUS, LINUX_SIGSEGV, LINUX_SIGSYS, 141956d3333SMarcel Moolenaar LINUX_SIGPIPE, LINUX_SIGALRM, LINUX_SIGTERM, LINUX_SIGURG, 142956d3333SMarcel Moolenaar LINUX_SIGSTOP, LINUX_SIGTSTP, LINUX_SIGCONT, LINUX_SIGCHLD, 143956d3333SMarcel Moolenaar LINUX_SIGTTIN, LINUX_SIGTTOU, LINUX_SIGIO, LINUX_SIGXCPU, 144956d3333SMarcel Moolenaar LINUX_SIGXFSZ, LINUX_SIGVTALRM, LINUX_SIGPROF, LINUX_SIGWINCH, 145956d3333SMarcel Moolenaar 0, LINUX_SIGUSR1, LINUX_SIGUSR2 146d66a5066SPeter Wemm }; 147d66a5066SPeter Wemm 148956d3333SMarcel Moolenaar int linux_to_bsd_signal[LINUX_SIGTBLSZ] = { 149956d3333SMarcel Moolenaar SIGHUP, SIGINT, SIGQUIT, SIGILL, 150956d3333SMarcel Moolenaar SIGTRAP, SIGABRT, SIGBUS, SIGFPE, 151956d3333SMarcel Moolenaar SIGKILL, SIGUSR1, SIGSEGV, SIGUSR2, 152956d3333SMarcel Moolenaar SIGPIPE, SIGALRM, SIGTERM, SIGBUS, 153956d3333SMarcel Moolenaar SIGCHLD, SIGCONT, SIGSTOP, SIGTSTP, 154956d3333SMarcel Moolenaar SIGTTIN, SIGTTOU, SIGURG, SIGXCPU, 155956d3333SMarcel Moolenaar SIGXFSZ, SIGVTALRM, SIGPROF, SIGWINCH, 156ba873f4cSAlexander Kabaev SIGIO, SIGURG, SIGSYS 157d66a5066SPeter Wemm }; 158d66a5066SPeter Wemm 15927a828fcSPierre Beyssac #define LINUX_T_UNKNOWN 255 16027a828fcSPierre Beyssac static int _bsd_to_linux_trapcode[] = { 16127a828fcSPierre Beyssac LINUX_T_UNKNOWN, /* 0 */ 16227a828fcSPierre Beyssac 6, /* 1 T_PRIVINFLT */ 16327a828fcSPierre Beyssac LINUX_T_UNKNOWN, /* 2 */ 16427a828fcSPierre Beyssac 3, /* 3 T_BPTFLT */ 16527a828fcSPierre Beyssac LINUX_T_UNKNOWN, /* 4 */ 16627a828fcSPierre Beyssac LINUX_T_UNKNOWN, /* 5 */ 16727a828fcSPierre Beyssac 16, /* 6 T_ARITHTRAP */ 16827a828fcSPierre Beyssac 254, /* 7 T_ASTFLT */ 16927a828fcSPierre Beyssac LINUX_T_UNKNOWN, /* 8 */ 17027a828fcSPierre Beyssac 13, /* 9 T_PROTFLT */ 17127a828fcSPierre Beyssac 1, /* 10 T_TRCTRAP */ 17227a828fcSPierre Beyssac LINUX_T_UNKNOWN, /* 11 */ 17327a828fcSPierre Beyssac 14, /* 12 T_PAGEFLT */ 17427a828fcSPierre Beyssac LINUX_T_UNKNOWN, /* 13 */ 17527a828fcSPierre Beyssac 17, /* 14 T_ALIGNFLT */ 17627a828fcSPierre Beyssac LINUX_T_UNKNOWN, /* 15 */ 17727a828fcSPierre Beyssac LINUX_T_UNKNOWN, /* 16 */ 17827a828fcSPierre Beyssac LINUX_T_UNKNOWN, /* 17 */ 17927a828fcSPierre Beyssac 0, /* 18 T_DIVIDE */ 18027a828fcSPierre Beyssac 2, /* 19 T_NMI */ 18127a828fcSPierre Beyssac 4, /* 20 T_OFLOW */ 18227a828fcSPierre Beyssac 5, /* 21 T_BOUND */ 18327a828fcSPierre Beyssac 7, /* 22 T_DNA */ 18427a828fcSPierre Beyssac 8, /* 23 T_DOUBLEFLT */ 18527a828fcSPierre Beyssac 9, /* 24 T_FPOPFLT */ 18627a828fcSPierre Beyssac 10, /* 25 T_TSSFLT */ 18727a828fcSPierre Beyssac 11, /* 26 T_SEGNPFLT */ 18827a828fcSPierre Beyssac 12, /* 27 T_STKFLT */ 18927a828fcSPierre Beyssac 18, /* 28 T_MCHK */ 19027a828fcSPierre Beyssac 19, /* 29 T_XMMFLT */ 19127a828fcSPierre Beyssac 15 /* 30 T_RESERVED */ 19227a828fcSPierre Beyssac }; 19327a828fcSPierre Beyssac #define bsd_to_linux_trapcode(code) \ 19427a828fcSPierre Beyssac ((code)<sizeof(_bsd_to_linux_trapcode)/sizeof(*_bsd_to_linux_trapcode)? \ 19527a828fcSPierre Beyssac _bsd_to_linux_trapcode[(code)]: \ 19627a828fcSPierre Beyssac LINUX_T_UNKNOWN) 19727a828fcSPierre Beyssac 198288078beSEivind Eklund /* 199288078beSEivind Eklund * If FreeBSD & Linux have a difference of opinion about what a trap 200288078beSEivind Eklund * means, deal with it here. 201356861dbSMatthew Dillon * 202356861dbSMatthew Dillon * MPSAFE 203288078beSEivind Eklund */ 204288078beSEivind Eklund static int 205288078beSEivind Eklund translate_traps(int signal, int trap_code) 206288078beSEivind Eklund { 207d563a53aSEivind Eklund if (signal != SIGBUS) 208d563a53aSEivind Eklund return signal; 209288078beSEivind Eklund switch (trap_code) { 210288078beSEivind Eklund case T_PROTFLT: 211288078beSEivind Eklund case T_TSSFLT: 212288078beSEivind Eklund case T_DOUBLEFLT: 213288078beSEivind Eklund case T_PAGEFLT: 214288078beSEivind Eklund return SIGSEGV; 215288078beSEivind Eklund default: 216288078beSEivind Eklund return signal; 217288078beSEivind Eklund } 218288078beSEivind Eklund } 219288078beSEivind Eklund 220303b270bSEivind Eklund static int 221654f6be1SBruce Evans linux_fixup(register_t **stack_base, struct image_params *imgp) 222d66a5066SPeter Wemm { 223654f6be1SBruce Evans register_t *argv, *envp; 224d66a5066SPeter Wemm 225d66a5066SPeter Wemm argv = *stack_base; 226610ecfe0SMaxim Sobolev envp = *stack_base + (imgp->args->argc + 1); 227d66a5066SPeter Wemm (*stack_base)--; 22886a14a7aSBruce Evans **stack_base = (intptr_t)(void *)envp; 229d66a5066SPeter Wemm (*stack_base)--; 23086a14a7aSBruce Evans **stack_base = (intptr_t)(void *)argv; 231d66a5066SPeter Wemm (*stack_base)--; 232610ecfe0SMaxim Sobolev **stack_base = imgp->args->argc; 233e1743d02SSøren Schmidt return 0; 234d66a5066SPeter Wemm } 235d66a5066SPeter Wemm 236303b270bSEivind Eklund static int 237654f6be1SBruce Evans elf_linux_fixup(register_t **stack_base, struct image_params *imgp) 238e1743d02SSøren Schmidt { 23943cf129cSJohn Baldwin Elf32_Auxargs *args; 240654f6be1SBruce Evans register_t *pos; 241d66a5066SPeter Wemm 24243cf129cSJohn Baldwin KASSERT(curthread->td_proc == imgp->proc && 2430e2a4d3aSDavid Xu (curthread->td_proc->p_flag & P_SA) == 0, 24443cf129cSJohn Baldwin ("unsafe elf_linux_fixup(), should be curproc")); 24543cf129cSJohn Baldwin args = (Elf32_Auxargs *)imgp->auxargs; 246610ecfe0SMaxim Sobolev pos = *stack_base + (imgp->args->argc + imgp->args->envc + 2); 247e1743d02SSøren Schmidt 248b07cd97eSMark Murray if (args->trace) 249e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_DEBUG, 1); 250b07cd97eSMark Murray if (args->execfd != -1) 251e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_EXECFD, args->execfd); 252e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_PHDR, args->phdr); 253e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_PHENT, args->phent); 254e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_PHNUM, args->phnum); 255e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_PAGESZ, args->pagesz); 256e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_FLAGS, args->flags); 257e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_ENTRY, args->entry); 258e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_BASE, args->base); 259b1fc0ec1SRobert Watson AUXARGS_ENTRY(pos, AT_UID, imgp->proc->p_ucred->cr_ruid); 260b1fc0ec1SRobert Watson AUXARGS_ENTRY(pos, AT_EUID, imgp->proc->p_ucred->cr_svuid); 261b1fc0ec1SRobert Watson AUXARGS_ENTRY(pos, AT_GID, imgp->proc->p_ucred->cr_rgid); 262b1fc0ec1SRobert Watson AUXARGS_ENTRY(pos, AT_EGID, imgp->proc->p_ucred->cr_svgid); 263e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_NULL, 0); 264e1743d02SSøren Schmidt 265e1743d02SSøren Schmidt free(imgp->auxargs, M_TEMP); 266e1743d02SSøren Schmidt imgp->auxargs = NULL; 267e1743d02SSøren Schmidt 268e1743d02SSøren Schmidt (*stack_base)--; 269610ecfe0SMaxim Sobolev **stack_base = (register_t)imgp->args->argc; 270e1743d02SSøren Schmidt return 0; 271e1743d02SSøren Schmidt } 272d66a5066SPeter Wemm 273d66a5066SPeter Wemm extern int _ucodesel, _udatasel; 27402318dacSJake Burkholder extern unsigned long linux_sznonrtsigcode; 27579363394SAndrew Gallatin 27679363394SAndrew Gallatin static void 2779104847fSDavid Xu linux_rt_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) 27879363394SAndrew Gallatin { 2791d062e2bSDag-Erling Smørgrav struct thread *td = curthread; 2801d062e2bSDag-Erling Smørgrav struct proc *p = td->td_proc; 28190af4afaSJohn Baldwin struct sigacts *psp; 2821d062e2bSDag-Erling Smørgrav struct trapframe *regs; 2835002a60fSMarcel Moolenaar struct l_rt_sigframe *fp, frame; 2849104847fSDavid Xu int sig, code; 28579363394SAndrew Gallatin int oonstack; 28679363394SAndrew Gallatin 2879104847fSDavid Xu sig = ksi->ksi_signo; 2889104847fSDavid Xu code = ksi->ksi_code; 289df53e91cSJohn Baldwin PROC_LOCK_ASSERT(p, MA_OWNED); 29090af4afaSJohn Baldwin psp = p->p_sigacts; 29190af4afaSJohn Baldwin mtx_assert(&psp->ps_mtx, MA_OWNED); 292b40ce416SJulian Elischer regs = td->td_frame; 293d034d459SMarcel Moolenaar oonstack = sigonstack(regs->tf_esp); 29479363394SAndrew Gallatin 29579363394SAndrew Gallatin #ifdef DEBUG 2965002a60fSMarcel Moolenaar if (ldebug(rt_sendsig)) 297728ef954SJohn Baldwin printf(ARGS(rt_sendsig, "%p, %d, %p, %u"), 29824593369SJonathan Lemon catcher, sig, (void*)mask, code); 29979363394SAndrew Gallatin #endif 30079363394SAndrew Gallatin /* 30179363394SAndrew Gallatin * Allocate space for the signal handler context. 30279363394SAndrew Gallatin */ 303a30ec4b9SDavid Xu if ((td->td_pflags & TDP_ALTSTACK) && !oonstack && 30490af4afaSJohn Baldwin SIGISMEMBER(psp->ps_sigonstack, sig)) { 305a30ec4b9SDavid Xu fp = (struct l_rt_sigframe *)(td->td_sigstk.ss_sp + 306a30ec4b9SDavid Xu td->td_sigstk.ss_size - sizeof(struct l_rt_sigframe)); 307d034d459SMarcel Moolenaar } else 3085002a60fSMarcel Moolenaar fp = (struct l_rt_sigframe *)regs->tf_esp - 1; 30990af4afaSJohn Baldwin mtx_unlock(&psp->ps_mtx); 31079363394SAndrew Gallatin 31179363394SAndrew Gallatin /* 31279363394SAndrew Gallatin * Build the argument list for the signal handler. 31379363394SAndrew Gallatin */ 31479363394SAndrew Gallatin if (p->p_sysent->sv_sigtbl) 31579363394SAndrew Gallatin if (sig <= p->p_sysent->sv_sigsize) 31679363394SAndrew Gallatin sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)]; 31779363394SAndrew Gallatin 31899d45c5fSMarcel Moolenaar bzero(&frame, sizeof(frame)); 31999d45c5fSMarcel Moolenaar 32079363394SAndrew Gallatin frame.sf_handler = catcher; 32179363394SAndrew Gallatin frame.sf_sig = sig; 32279363394SAndrew Gallatin frame.sf_siginfo = &fp->sf_si; 32379363394SAndrew Gallatin frame.sf_ucontext = &fp->sf_sc; 324cc6ca9b3SMarcel Moolenaar 3259d05b77dSJuli Mallett /* Fill in POSIX parts */ 32679363394SAndrew Gallatin frame.sf_si.lsi_signo = sig; 32779363394SAndrew Gallatin frame.sf_si.lsi_code = code; 3289104847fSDavid Xu frame.sf_si.lsi_addr = ksi->ksi_addr; 329cc6ca9b3SMarcel Moolenaar 33079363394SAndrew Gallatin /* 33179363394SAndrew Gallatin * Build the signal context to be used by sigreturn. 33279363394SAndrew Gallatin */ 333cc6ca9b3SMarcel Moolenaar frame.sf_sc.uc_flags = 0; /* XXX ??? */ 334cc6ca9b3SMarcel Moolenaar frame.sf_sc.uc_link = NULL; /* XXX ??? */ 335cc6ca9b3SMarcel Moolenaar 336a30ec4b9SDavid Xu frame.sf_sc.uc_stack.ss_sp = td->td_sigstk.ss_sp; 337a30ec4b9SDavid Xu frame.sf_sc.uc_stack.ss_size = td->td_sigstk.ss_size; 338a30ec4b9SDavid Xu frame.sf_sc.uc_stack.ss_flags = (td->td_pflags & TDP_ALTSTACK) 339d034d459SMarcel Moolenaar ? ((oonstack) ? LINUX_SS_ONSTACK : 0) : LINUX_SS_DISABLE; 340611d9407SJohn Baldwin PROC_UNLOCK(p); 341cc6ca9b3SMarcel Moolenaar 342cc6ca9b3SMarcel Moolenaar bsd_to_linux_sigset(mask, &frame.sf_sc.uc_sigmask); 343cc6ca9b3SMarcel Moolenaar 344cc6ca9b3SMarcel Moolenaar frame.sf_sc.uc_mcontext.sc_mask = frame.sf_sc.uc_sigmask.__bits[0]; 34579363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_gs = rgs(); 34679363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_fs = regs->tf_fs; 34779363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_es = regs->tf_es; 34879363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_ds = regs->tf_ds; 34979363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_edi = regs->tf_edi; 35079363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_esi = regs->tf_esi; 35179363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_ebp = regs->tf_ebp; 35279363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_ebx = regs->tf_ebx; 35379363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_edx = regs->tf_edx; 35479363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_ecx = regs->tf_ecx; 35579363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_eax = regs->tf_eax; 35679363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_eip = regs->tf_eip; 35779363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_cs = regs->tf_cs; 35879363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_eflags = regs->tf_eflags; 35979363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_esp_at_signal = regs->tf_esp; 36079363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_ss = regs->tf_ss; 36179363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_err = regs->tf_err; 36227a828fcSPierre Beyssac frame.sf_sc.uc_mcontext.sc_trapno = bsd_to_linux_trapcode(code); 36379363394SAndrew Gallatin 36479363394SAndrew Gallatin #ifdef DEBUG 3655002a60fSMarcel Moolenaar if (ldebug(rt_sendsig)) 36624593369SJonathan Lemon printf(LMSG("rt_sendsig flags: 0x%x, sp: %p, ss: 0x%x, mask: 0x%x"), 3679b778a16SDavid Xu frame.sf_sc.uc_stack.ss_flags, td->td_sigstk.ss_sp, 3689b778a16SDavid Xu td->td_sigstk.ss_size, frame.sf_sc.uc_mcontext.sc_mask); 36979363394SAndrew Gallatin #endif 37079363394SAndrew Gallatin 37179363394SAndrew Gallatin if (copyout(&frame, fp, sizeof(frame)) != 0) { 37279363394SAndrew Gallatin /* 37379363394SAndrew Gallatin * Process has trashed its stack; give it an illegal 37479363394SAndrew Gallatin * instruction to halt it in its tracks. 37579363394SAndrew Gallatin */ 37689734883SAlan Cox #ifdef DEBUG 37789734883SAlan Cox if (ldebug(rt_sendsig)) 37889734883SAlan Cox printf(LMSG("rt_sendsig: bad stack %p, oonstack=%x"), 37989734883SAlan Cox fp, oonstack); 38089734883SAlan Cox #endif 38119eb87d2SJohn Baldwin PROC_LOCK(p); 382b40ce416SJulian Elischer sigexit(td, SIGILL); 38379363394SAndrew Gallatin } 38479363394SAndrew Gallatin 38579363394SAndrew Gallatin /* 38679363394SAndrew Gallatin * Build context to run handler in. 38779363394SAndrew Gallatin */ 38879363394SAndrew Gallatin regs->tf_esp = (int)fp; 38979363394SAndrew Gallatin regs->tf_eip = PS_STRINGS - *(p->p_sysent->sv_szsigcode) + 39002318dacSJake Burkholder linux_sznonrtsigcode; 391846ac226SBruce Evans regs->tf_eflags &= ~(PSL_T | PSL_VM); 39279363394SAndrew Gallatin regs->tf_cs = _ucodesel; 39379363394SAndrew Gallatin regs->tf_ds = _udatasel; 39479363394SAndrew Gallatin regs->tf_es = _udatasel; 39579363394SAndrew Gallatin regs->tf_fs = _udatasel; 39679363394SAndrew Gallatin regs->tf_ss = _udatasel; 397df53e91cSJohn Baldwin PROC_LOCK(p); 39890af4afaSJohn Baldwin mtx_lock(&psp->ps_mtx); 39979363394SAndrew Gallatin } 40079363394SAndrew Gallatin 401d66a5066SPeter Wemm 402d66a5066SPeter Wemm /* 403d66a5066SPeter Wemm * Send an interrupt to process. 404d66a5066SPeter Wemm * 405d66a5066SPeter Wemm * Stack is set up to allow sigcode stored 406d66a5066SPeter Wemm * in u. to call routine, followed by kcall 407d66a5066SPeter Wemm * to sigreturn routine below. After sigreturn 408d66a5066SPeter Wemm * resets the signal mask, the stack, and the 409d66a5066SPeter Wemm * frame pointer, it returns to the user 410d66a5066SPeter Wemm * specified pc, psl. 411d66a5066SPeter Wemm */ 412303b270bSEivind Eklund static void 4139104847fSDavid Xu linux_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) 414d66a5066SPeter Wemm { 4151d062e2bSDag-Erling Smørgrav struct thread *td = curthread; 4161d062e2bSDag-Erling Smørgrav struct proc *p = td->td_proc; 41790af4afaSJohn Baldwin struct sigacts *psp; 4181d062e2bSDag-Erling Smørgrav struct trapframe *regs; 4195002a60fSMarcel Moolenaar struct l_sigframe *fp, frame; 4205002a60fSMarcel Moolenaar l_sigset_t lmask; 4219104847fSDavid Xu int sig, code; 4222c4ab9ddSAndrew Gallatin int oonstack, i; 423d66a5066SPeter Wemm 4242509e6c2SJohn Baldwin PROC_LOCK_ASSERT(p, MA_OWNED); 42590af4afaSJohn Baldwin psp = p->p_sigacts; 4269104847fSDavid Xu sig = ksi->ksi_signo; 4279104847fSDavid Xu code = ksi->ksi_code; 42890af4afaSJohn Baldwin mtx_assert(&psp->ps_mtx, MA_OWNED); 42990af4afaSJohn Baldwin if (SIGISMEMBER(psp->ps_siginfo, sig)) { 430cc6ca9b3SMarcel Moolenaar /* Signal handler installed with SA_SIGINFO. */ 4319104847fSDavid Xu linux_rt_sendsig(catcher, ksi, mask); 432cc6ca9b3SMarcel Moolenaar return; 433cc6ca9b3SMarcel Moolenaar } 434b40ce416SJulian Elischer regs = td->td_frame; 435d034d459SMarcel Moolenaar oonstack = sigonstack(regs->tf_esp); 436d66a5066SPeter Wemm 437d66a5066SPeter Wemm #ifdef DEBUG 4385002a60fSMarcel Moolenaar if (ldebug(sendsig)) 439728ef954SJohn Baldwin printf(ARGS(sendsig, "%p, %d, %p, %u"), 44024593369SJonathan Lemon catcher, sig, (void*)mask, code); 441d66a5066SPeter Wemm #endif 44279363394SAndrew Gallatin 443d66a5066SPeter Wemm /* 444d66a5066SPeter Wemm * Allocate space for the signal handler context. 445d66a5066SPeter Wemm */ 446a30ec4b9SDavid Xu if ((td->td_pflags & TDP_ALTSTACK) && !oonstack && 44790af4afaSJohn Baldwin SIGISMEMBER(psp->ps_sigonstack, sig)) { 448a30ec4b9SDavid Xu fp = (struct l_sigframe *)(td->td_sigstk.ss_sp + 449a30ec4b9SDavid Xu td->td_sigstk.ss_size - sizeof(struct l_sigframe)); 450d034d459SMarcel Moolenaar } else 4515002a60fSMarcel Moolenaar fp = (struct l_sigframe *)regs->tf_esp - 1; 45290af4afaSJohn Baldwin mtx_unlock(&psp->ps_mtx); 453611d9407SJohn Baldwin PROC_UNLOCK(p); 454d66a5066SPeter Wemm 455d66a5066SPeter Wemm /* 456d66a5066SPeter Wemm * Build the argument list for the signal handler. 457d66a5066SPeter Wemm */ 458956d3333SMarcel Moolenaar if (p->p_sysent->sv_sigtbl) 459956d3333SMarcel Moolenaar if (sig <= p->p_sysent->sv_sigsize) 460956d3333SMarcel Moolenaar sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)]; 461d66a5066SPeter Wemm 46299d45c5fSMarcel Moolenaar bzero(&frame, sizeof(frame)); 46399d45c5fSMarcel Moolenaar 464d66a5066SPeter Wemm frame.sf_handler = catcher; 465d66a5066SPeter Wemm frame.sf_sig = sig; 466d66a5066SPeter Wemm 467cc6ca9b3SMarcel Moolenaar bsd_to_linux_sigset(mask, &lmask); 468cc6ca9b3SMarcel Moolenaar 469d66a5066SPeter Wemm /* 470d66a5066SPeter Wemm * Build the signal context to be used by sigreturn. 471d66a5066SPeter Wemm */ 472cc6ca9b3SMarcel Moolenaar frame.sf_sc.sc_mask = lmask.__bits[0]; 4735206bca1SLuoqi Chen frame.sf_sc.sc_gs = rgs(); 4745206bca1SLuoqi Chen frame.sf_sc.sc_fs = regs->tf_fs; 475213fdd80SPeter Wemm frame.sf_sc.sc_es = regs->tf_es; 476213fdd80SPeter Wemm frame.sf_sc.sc_ds = regs->tf_ds; 477213fdd80SPeter Wemm frame.sf_sc.sc_edi = regs->tf_edi; 478213fdd80SPeter Wemm frame.sf_sc.sc_esi = regs->tf_esi; 479213fdd80SPeter Wemm frame.sf_sc.sc_ebp = regs->tf_ebp; 480213fdd80SPeter Wemm frame.sf_sc.sc_ebx = regs->tf_ebx; 481213fdd80SPeter Wemm frame.sf_sc.sc_edx = regs->tf_edx; 482213fdd80SPeter Wemm frame.sf_sc.sc_ecx = regs->tf_ecx; 483213fdd80SPeter Wemm frame.sf_sc.sc_eax = regs->tf_eax; 484213fdd80SPeter Wemm frame.sf_sc.sc_eip = regs->tf_eip; 485213fdd80SPeter Wemm frame.sf_sc.sc_cs = regs->tf_cs; 486213fdd80SPeter Wemm frame.sf_sc.sc_eflags = regs->tf_eflags; 487213fdd80SPeter Wemm frame.sf_sc.sc_esp_at_signal = regs->tf_esp; 488213fdd80SPeter Wemm frame.sf_sc.sc_ss = regs->tf_ss; 489213fdd80SPeter Wemm frame.sf_sc.sc_err = regs->tf_err; 4909104847fSDavid Xu frame.sf_sc.sc_trapno = bsd_to_linux_trapcode(ksi->ksi_trapno); 491cc6ca9b3SMarcel Moolenaar 4922c4ab9ddSAndrew Gallatin for (i = 0; i < (LINUX_NSIG_WORDS-1); i++) 493cc6ca9b3SMarcel Moolenaar frame.sf_extramask[i] = lmask.__bits[i+1]; 494d66a5066SPeter Wemm 495d66a5066SPeter Wemm if (copyout(&frame, fp, sizeof(frame)) != 0) { 496d66a5066SPeter Wemm /* 497d66a5066SPeter Wemm * Process has trashed its stack; give it an illegal 498d66a5066SPeter Wemm * instruction to halt it in its tracks. 499d66a5066SPeter Wemm */ 50019eb87d2SJohn Baldwin PROC_LOCK(p); 501b40ce416SJulian Elischer sigexit(td, SIGILL); 502d66a5066SPeter Wemm } 503d66a5066SPeter Wemm 504d66a5066SPeter Wemm /* 505d66a5066SPeter Wemm * Build context to run handler in. 506d66a5066SPeter Wemm */ 507213fdd80SPeter Wemm regs->tf_esp = (int)fp; 5084c56fcdeSBruce Evans regs->tf_eip = PS_STRINGS - *(p->p_sysent->sv_szsigcode); 509846ac226SBruce Evans regs->tf_eflags &= ~(PSL_T | PSL_VM); 510213fdd80SPeter Wemm regs->tf_cs = _ucodesel; 511213fdd80SPeter Wemm regs->tf_ds = _udatasel; 512213fdd80SPeter Wemm regs->tf_es = _udatasel; 5135206bca1SLuoqi Chen regs->tf_fs = _udatasel; 514213fdd80SPeter Wemm regs->tf_ss = _udatasel; 5155002a60fSMarcel Moolenaar PROC_LOCK(p); 51690af4afaSJohn Baldwin mtx_lock(&psp->ps_mtx); 517d66a5066SPeter Wemm } 518d66a5066SPeter Wemm 519d66a5066SPeter Wemm /* 520d66a5066SPeter Wemm * System call to cleanup state after a signal 521d66a5066SPeter Wemm * has been taken. Reset signal mask and 522d66a5066SPeter Wemm * stack state from context left by sendsig (above). 523d66a5066SPeter Wemm * Return to previous pc and psl as specified by 524d66a5066SPeter Wemm * context left by sendsig. Check carefully to 525d66a5066SPeter Wemm * make sure that the user has not modified the 526d66a5066SPeter Wemm * psl to gain improper privileges or to cause 527d66a5066SPeter Wemm * a machine fault. 528d66a5066SPeter Wemm */ 529d66a5066SPeter Wemm int 530b07cd97eSMark Murray linux_sigreturn(struct thread *td, struct linux_sigreturn_args *args) 531d66a5066SPeter Wemm { 532b40ce416SJulian Elischer struct proc *p = td->td_proc; 5335002a60fSMarcel Moolenaar struct l_sigframe frame; 5341d062e2bSDag-Erling Smørgrav struct trapframe *regs; 5355002a60fSMarcel Moolenaar l_sigset_t lmask; 5362c4ab9ddSAndrew Gallatin int eflags, i; 5379104847fSDavid Xu ksiginfo_t ksi; 538d66a5066SPeter Wemm 539b40ce416SJulian Elischer regs = td->td_frame; 540d66a5066SPeter Wemm 541d66a5066SPeter Wemm #ifdef DEBUG 54224593369SJonathan Lemon if (ldebug(sigreturn)) 54324593369SJonathan Lemon printf(ARGS(sigreturn, "%p"), (void *)args->sfp); 544d66a5066SPeter Wemm #endif 545d66a5066SPeter Wemm /* 546cc6ca9b3SMarcel Moolenaar * The trampoline code hands us the sigframe. 547d66a5066SPeter Wemm * It is unsafe to keep track of it ourselves, in the event that a 548d66a5066SPeter Wemm * program jumps out of a signal handler. 549d66a5066SPeter Wemm */ 5504b7ef73dSDag-Erling Smørgrav if (copyin(args->sfp, &frame, sizeof(frame)) != 0) 551d66a5066SPeter Wemm return (EFAULT); 552d66a5066SPeter Wemm 553d66a5066SPeter Wemm /* 554d66a5066SPeter Wemm * Check for security violations. 555d66a5066SPeter Wemm */ 556d66a5066SPeter Wemm #define EFLAGS_SECURE(ef, oef) ((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0) 557cc6ca9b3SMarcel Moolenaar eflags = frame.sf_sc.sc_eflags; 558d66a5066SPeter Wemm /* 559d66a5066SPeter Wemm * XXX do allow users to change the privileged flag PSL_RF. The 560d66a5066SPeter Wemm * cpu sets PSL_RF in tf_eflags for faults. Debuggers should 561d66a5066SPeter Wemm * sometimes set it there too. tf_eflags is kept in the signal 562d66a5066SPeter Wemm * context during signal handling and there is no other place 563d66a5066SPeter Wemm * to remember it, so the PSL_RF bit may be corrupted by the 564d66a5066SPeter Wemm * signal handler without us knowing. Corruption of the PSL_RF 565d66a5066SPeter Wemm * bit at worst causes one more or one less debugger trap, so 566d66a5066SPeter Wemm * allowing it is fairly harmless. 567d66a5066SPeter Wemm */ 568b07cd97eSMark Murray if (!EFLAGS_SECURE(eflags & ~PSL_RF, regs->tf_eflags & ~PSL_RF)) 569d66a5066SPeter Wemm return(EINVAL); 570d66a5066SPeter Wemm 571d66a5066SPeter Wemm /* 572d66a5066SPeter Wemm * Don't allow users to load a valid privileged %cs. Let the 573d66a5066SPeter Wemm * hardware check for invalid selectors, excess privilege in 574d66a5066SPeter Wemm * other selectors, invalid %eip's and invalid %esp's. 575d66a5066SPeter Wemm */ 57640d50994SPhilippe Charnier #define CS_SECURE(cs) (ISPL(cs) == SEL_UPL) 577cc6ca9b3SMarcel Moolenaar if (!CS_SECURE(frame.sf_sc.sc_cs)) { 5789104847fSDavid Xu ksiginfo_init_trap(&ksi); 5799104847fSDavid Xu ksi.ksi_signo = SIGBUS; 5809104847fSDavid Xu ksi.ksi_code = BUS_OBJERR; 5819104847fSDavid Xu ksi.ksi_trapno = T_PROTFLT; 5829104847fSDavid Xu ksi.ksi_addr = (void *)regs->tf_eip; 5839104847fSDavid Xu trapsignal(td, &ksi); 584d66a5066SPeter Wemm return(EINVAL); 585d66a5066SPeter Wemm } 586d66a5066SPeter Wemm 587cc6ca9b3SMarcel Moolenaar lmask.__bits[0] = frame.sf_sc.sc_mask; 5882c4ab9ddSAndrew Gallatin for (i = 0; i < (LINUX_NSIG_WORDS-1); i++) 589cc6ca9b3SMarcel Moolenaar lmask.__bits[i+1] = frame.sf_extramask[i]; 590611d9407SJohn Baldwin PROC_LOCK(p); 5914093529dSJeff Roberson linux_to_bsd_sigset(&lmask, &td->td_sigmask); 5924093529dSJeff Roberson SIG_CANTMASK(td->td_sigmask); 5934093529dSJeff Roberson signotify(td); 594611d9407SJohn Baldwin PROC_UNLOCK(p); 595956d3333SMarcel Moolenaar 596d66a5066SPeter Wemm /* 597d66a5066SPeter Wemm * Restore signal context. 598d66a5066SPeter Wemm */ 5995206bca1SLuoqi Chen /* %gs was restored by the trampoline. */ 600cc6ca9b3SMarcel Moolenaar regs->tf_fs = frame.sf_sc.sc_fs; 601cc6ca9b3SMarcel Moolenaar regs->tf_es = frame.sf_sc.sc_es; 602cc6ca9b3SMarcel Moolenaar regs->tf_ds = frame.sf_sc.sc_ds; 603cc6ca9b3SMarcel Moolenaar regs->tf_edi = frame.sf_sc.sc_edi; 604cc6ca9b3SMarcel Moolenaar regs->tf_esi = frame.sf_sc.sc_esi; 605cc6ca9b3SMarcel Moolenaar regs->tf_ebp = frame.sf_sc.sc_ebp; 606cc6ca9b3SMarcel Moolenaar regs->tf_ebx = frame.sf_sc.sc_ebx; 607cc6ca9b3SMarcel Moolenaar regs->tf_edx = frame.sf_sc.sc_edx; 608cc6ca9b3SMarcel Moolenaar regs->tf_ecx = frame.sf_sc.sc_ecx; 609cc6ca9b3SMarcel Moolenaar regs->tf_eax = frame.sf_sc.sc_eax; 610cc6ca9b3SMarcel Moolenaar regs->tf_eip = frame.sf_sc.sc_eip; 611cc6ca9b3SMarcel Moolenaar regs->tf_cs = frame.sf_sc.sc_cs; 612213fdd80SPeter Wemm regs->tf_eflags = eflags; 613cc6ca9b3SMarcel Moolenaar regs->tf_esp = frame.sf_sc.sc_esp_at_signal; 614cc6ca9b3SMarcel Moolenaar regs->tf_ss = frame.sf_sc.sc_ss; 615d66a5066SPeter Wemm 616d66a5066SPeter Wemm return (EJUSTRETURN); 617d66a5066SPeter Wemm } 618d66a5066SPeter Wemm 61979363394SAndrew Gallatin /* 62079363394SAndrew Gallatin * System call to cleanup state after a signal 62179363394SAndrew Gallatin * has been taken. Reset signal mask and 62279363394SAndrew Gallatin * stack state from context left by rt_sendsig (above). 62379363394SAndrew Gallatin * Return to previous pc and psl as specified by 62479363394SAndrew Gallatin * context left by sendsig. Check carefully to 62579363394SAndrew Gallatin * make sure that the user has not modified the 62679363394SAndrew Gallatin * psl to gain improper privileges or to cause 62779363394SAndrew Gallatin * a machine fault. 62879363394SAndrew Gallatin */ 62979363394SAndrew Gallatin int 630b07cd97eSMark Murray linux_rt_sigreturn(struct thread *td, struct linux_rt_sigreturn_args *args) 63179363394SAndrew Gallatin { 632b40ce416SJulian Elischer struct proc *p = td->td_proc; 6335002a60fSMarcel Moolenaar struct l_ucontext uc; 6345002a60fSMarcel Moolenaar struct l_sigcontext *context; 6355002a60fSMarcel Moolenaar l_stack_t *lss; 636206a5d3aSIan Dowse stack_t ss; 6371d062e2bSDag-Erling Smørgrav struct trapframe *regs; 63879363394SAndrew Gallatin int eflags; 6399104847fSDavid Xu ksiginfo_t ksi; 64079363394SAndrew Gallatin 641b40ce416SJulian Elischer regs = td->td_frame; 64279363394SAndrew Gallatin 64379363394SAndrew Gallatin #ifdef DEBUG 64424593369SJonathan Lemon if (ldebug(rt_sigreturn)) 64524593369SJonathan Lemon printf(ARGS(rt_sigreturn, "%p"), (void *)args->ucp); 64679363394SAndrew Gallatin #endif 64779363394SAndrew Gallatin /* 648cc6ca9b3SMarcel Moolenaar * The trampoline code hands us the ucontext. 64979363394SAndrew Gallatin * It is unsafe to keep track of it ourselves, in the event that a 65079363394SAndrew Gallatin * program jumps out of a signal handler. 65179363394SAndrew Gallatin */ 6524b7ef73dSDag-Erling Smørgrav if (copyin(args->ucp, &uc, sizeof(uc)) != 0) 65379363394SAndrew Gallatin return (EFAULT); 65479363394SAndrew Gallatin 65579363394SAndrew Gallatin context = &uc.uc_mcontext; 65679363394SAndrew Gallatin 65779363394SAndrew Gallatin /* 65879363394SAndrew Gallatin * Check for security violations. 65979363394SAndrew Gallatin */ 66079363394SAndrew Gallatin #define EFLAGS_SECURE(ef, oef) ((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0) 66179363394SAndrew Gallatin eflags = context->sc_eflags; 66279363394SAndrew Gallatin /* 66379363394SAndrew Gallatin * XXX do allow users to change the privileged flag PSL_RF. The 66479363394SAndrew Gallatin * cpu sets PSL_RF in tf_eflags for faults. Debuggers should 66579363394SAndrew Gallatin * sometimes set it there too. tf_eflags is kept in the signal 66679363394SAndrew Gallatin * context during signal handling and there is no other place 66779363394SAndrew Gallatin * to remember it, so the PSL_RF bit may be corrupted by the 66879363394SAndrew Gallatin * signal handler without us knowing. Corruption of the PSL_RF 66979363394SAndrew Gallatin * bit at worst causes one more or one less debugger trap, so 67079363394SAndrew Gallatin * allowing it is fairly harmless. 67179363394SAndrew Gallatin */ 672b07cd97eSMark Murray if (!EFLAGS_SECURE(eflags & ~PSL_RF, regs->tf_eflags & ~PSL_RF)) 67379363394SAndrew Gallatin return(EINVAL); 67479363394SAndrew Gallatin 67579363394SAndrew Gallatin /* 67679363394SAndrew Gallatin * Don't allow users to load a valid privileged %cs. Let the 67779363394SAndrew Gallatin * hardware check for invalid selectors, excess privilege in 67879363394SAndrew Gallatin * other selectors, invalid %eip's and invalid %esp's. 67979363394SAndrew Gallatin */ 68079363394SAndrew Gallatin #define CS_SECURE(cs) (ISPL(cs) == SEL_UPL) 68179363394SAndrew Gallatin if (!CS_SECURE(context->sc_cs)) { 6829104847fSDavid Xu ksiginfo_init_trap(&ksi); 6839104847fSDavid Xu ksi.ksi_signo = SIGBUS; 6849104847fSDavid Xu ksi.ksi_code = BUS_OBJERR; 6859104847fSDavid Xu ksi.ksi_trapno = T_PROTFLT; 6869104847fSDavid Xu ksi.ksi_addr = (void *)regs->tf_eip; 6879104847fSDavid Xu trapsignal(td, &ksi); 68879363394SAndrew Gallatin return(EINVAL); 68979363394SAndrew Gallatin } 69079363394SAndrew Gallatin 691611d9407SJohn Baldwin PROC_LOCK(p); 6924093529dSJeff Roberson linux_to_bsd_sigset(&uc.uc_sigmask, &td->td_sigmask); 6934093529dSJeff Roberson SIG_CANTMASK(td->td_sigmask); 6944093529dSJeff Roberson signotify(td); 695611d9407SJohn Baldwin PROC_UNLOCK(p); 69679363394SAndrew Gallatin 69779363394SAndrew Gallatin /* 698cc6ca9b3SMarcel Moolenaar * Restore signal context 69979363394SAndrew Gallatin */ 70079363394SAndrew Gallatin /* %gs was restored by the trampoline. */ 70179363394SAndrew Gallatin regs->tf_fs = context->sc_fs; 70279363394SAndrew Gallatin regs->tf_es = context->sc_es; 70379363394SAndrew Gallatin regs->tf_ds = context->sc_ds; 70479363394SAndrew Gallatin regs->tf_edi = context->sc_edi; 70579363394SAndrew Gallatin regs->tf_esi = context->sc_esi; 70679363394SAndrew Gallatin regs->tf_ebp = context->sc_ebp; 70779363394SAndrew Gallatin regs->tf_ebx = context->sc_ebx; 70879363394SAndrew Gallatin regs->tf_edx = context->sc_edx; 70979363394SAndrew Gallatin regs->tf_ecx = context->sc_ecx; 71079363394SAndrew Gallatin regs->tf_eax = context->sc_eax; 71179363394SAndrew Gallatin regs->tf_eip = context->sc_eip; 71279363394SAndrew Gallatin regs->tf_cs = context->sc_cs; 71379363394SAndrew Gallatin regs->tf_eflags = eflags; 71479363394SAndrew Gallatin regs->tf_esp = context->sc_esp_at_signal; 71579363394SAndrew Gallatin regs->tf_ss = context->sc_ss; 71679363394SAndrew Gallatin 71779363394SAndrew Gallatin /* 71879363394SAndrew Gallatin * call sigaltstack & ignore results.. 71979363394SAndrew Gallatin */ 72079363394SAndrew Gallatin lss = &uc.uc_stack; 721206a5d3aSIan Dowse ss.ss_sp = lss->ss_sp; 722206a5d3aSIan Dowse ss.ss_size = lss->ss_size; 723206a5d3aSIan Dowse ss.ss_flags = linux_to_bsd_sigaltstack(lss->ss_flags); 72479363394SAndrew Gallatin 72579363394SAndrew Gallatin #ifdef DEBUG 72624593369SJonathan Lemon if (ldebug(rt_sigreturn)) 72724593369SJonathan Lemon printf(LMSG("rt_sigret flags: 0x%x, sp: %p, ss: 0x%x, mask: 0x%x"), 728206a5d3aSIan Dowse ss.ss_flags, ss.ss_sp, ss.ss_size, context->sc_mask); 72979363394SAndrew Gallatin #endif 730206a5d3aSIan Dowse (void)kern_sigaltstack(td, &ss, NULL); 73179363394SAndrew Gallatin 73279363394SAndrew Gallatin return (EJUSTRETURN); 73379363394SAndrew Gallatin } 73479363394SAndrew Gallatin 735356861dbSMatthew Dillon /* 736356861dbSMatthew Dillon * MPSAFE 737356861dbSMatthew Dillon */ 738303b270bSEivind Eklund static void 739d66a5066SPeter Wemm linux_prepsyscall(struct trapframe *tf, int *args, u_int *code, caddr_t *params) 740d66a5066SPeter Wemm { 741d66a5066SPeter Wemm args[0] = tf->tf_ebx; 742d66a5066SPeter Wemm args[1] = tf->tf_ecx; 743d66a5066SPeter Wemm args[2] = tf->tf_edx; 744d66a5066SPeter Wemm args[3] = tf->tf_esi; 745d66a5066SPeter Wemm args[4] = tf->tf_edi; 7467646aefcSPeter Wemm args[5] = tf->tf_ebp; /* Unconfirmed */ 747d66a5066SPeter Wemm *params = NULL; /* no copyin */ 748d66a5066SPeter Wemm } 749d66a5066SPeter Wemm 750d323ddf3SMatthew Dillon /* 751d323ddf3SMatthew Dillon * If a linux binary is exec'ing something, try this image activator 752d323ddf3SMatthew Dillon * first. We override standard shell script execution in order to 753d323ddf3SMatthew Dillon * be able to modify the interpreter path. We only do this if a linux 754d323ddf3SMatthew Dillon * binary is doing the exec, so we do not create an EXEC module for it. 755d323ddf3SMatthew Dillon */ 75689c9a483SAlfred Perlstein static int exec_linux_imgact_try(struct image_params *iparams); 757d323ddf3SMatthew Dillon 758d323ddf3SMatthew Dillon static int 759b07cd97eSMark Murray exec_linux_imgact_try(struct image_params *imgp) 760d323ddf3SMatthew Dillon { 761d323ddf3SMatthew Dillon const char *head = (const char *)imgp->image_header; 7620311233eSJohn Baldwin char *rpath; 7630311233eSJohn Baldwin int error = -1, len; 764d323ddf3SMatthew Dillon 765d323ddf3SMatthew Dillon /* 766d323ddf3SMatthew Dillon * The interpreter for shell scripts run from a linux binary needs 767d323ddf3SMatthew Dillon * to be located in /compat/linux if possible in order to recursively 768d323ddf3SMatthew Dillon * maintain linux path emulation. 769d323ddf3SMatthew Dillon */ 770d323ddf3SMatthew Dillon if (((const short *)head)[0] == SHELLMAGIC) { 771d323ddf3SMatthew Dillon /* 772d323ddf3SMatthew Dillon * Run our normal shell image activator. If it succeeds attempt 773d323ddf3SMatthew Dillon * to use the alternate path for the interpreter. If an alternate 774d323ddf3SMatthew Dillon * path is found, use our stringspace to store it. 775d323ddf3SMatthew Dillon */ 776d323ddf3SMatthew Dillon if ((error = exec_shell_imgact(imgp)) == 0) { 7770311233eSJohn Baldwin linux_emul_convpath(FIRST_THREAD_IN_PROC(imgp->proc), 7780311233eSJohn Baldwin imgp->interpreter_name, UIO_SYSSPACE, &rpath, 0); 7790311233eSJohn Baldwin if (rpath != NULL) { 7800311233eSJohn Baldwin len = strlen(rpath) + 1; 781d323ddf3SMatthew Dillon 782d323ddf3SMatthew Dillon if (len <= MAXSHELLCMDLEN) { 783d323ddf3SMatthew Dillon memcpy(imgp->interpreter_name, rpath, len); 784d323ddf3SMatthew Dillon } 785d323ddf3SMatthew Dillon free(rpath, M_TEMP); 786d323ddf3SMatthew Dillon } 787d323ddf3SMatthew Dillon } 788d323ddf3SMatthew Dillon } 789d323ddf3SMatthew Dillon return(error); 790d323ddf3SMatthew Dillon } 791d323ddf3SMatthew Dillon 792598d45beSMatthew N. Dodd /* 793598d45beSMatthew N. Dodd * exec_setregs may initialize some registers differently than Linux 794598d45beSMatthew N. Dodd * does, thus potentially confusing Linux binaries. If necessary, we 795598d45beSMatthew N. Dodd * override the exec_setregs default(s) here. 796598d45beSMatthew N. Dodd */ 797598d45beSMatthew N. Dodd static void 798598d45beSMatthew N. Dodd exec_linux_setregs(struct thread *td, u_long entry, 799598d45beSMatthew N. Dodd u_long stack, u_long ps_strings) 800598d45beSMatthew N. Dodd { 8012a51b9b0SDavid Schultz static const u_short control = __LINUX_NPXCW__; 802598d45beSMatthew N. Dodd struct pcb *pcb = td->td_pcb; 803598d45beSMatthew N. Dodd 804598d45beSMatthew N. Dodd exec_setregs(td, entry, stack, ps_strings); 805598d45beSMatthew N. Dodd 806598d45beSMatthew N. Dodd /* Linux sets %gs to 0, we default to _udatasel */ 807598d45beSMatthew N. Dodd pcb->pcb_gs = 0; load_gs(0); 8082a51b9b0SDavid Schultz 8092a51b9b0SDavid Schultz /* Linux sets the i387 to extended precision. */ 8102a51b9b0SDavid Schultz fldcw(&control); 811598d45beSMatthew N. Dodd } 812598d45beSMatthew N. Dodd 813d66a5066SPeter Wemm struct sysentvec linux_sysvec = { 814e1743d02SSøren Schmidt LINUX_SYS_MAXSYSCALL, 815d66a5066SPeter Wemm linux_sysent, 8169b44bfc5SAlexander Leidinger 0, 817956d3333SMarcel Moolenaar LINUX_SIGTBLSZ, 818d66a5066SPeter Wemm bsd_to_linux_signal, 81985f118c8SDmitrij Tejblum ELAST + 1, 820d66a5066SPeter Wemm bsd_to_linux_errno, 821288078beSEivind Eklund translate_traps, 822d66a5066SPeter Wemm linux_fixup, 823d66a5066SPeter Wemm linux_sendsig, 824d66a5066SPeter Wemm linux_sigcode, 825d66a5066SPeter Wemm &linux_szsigcode, 826d66a5066SPeter Wemm linux_prepsyscall, 82722d4b0fbSJohn Polstra "Linux a.out", 828d3adf769SDavid Schultz NULL, 829806d7daaSMarcel Moolenaar exec_linux_imgact_try, 830f36ba452SJake Burkholder LINUX_MINSIGSTKSZ, 831f36ba452SJake Burkholder PAGE_SIZE, 832f36ba452SJake Burkholder VM_MIN_ADDRESS, 833f36ba452SJake Burkholder VM_MAXUSER_ADDRESS, 834f36ba452SJake Burkholder USRSTACK, 835f36ba452SJake Burkholder PS_STRINGS, 836f36ba452SJake Burkholder VM_PROT_ALL, 837f36ba452SJake Burkholder exec_copyout_strings, 838c460ac3aSPeter Wemm exec_linux_setregs, 839c460ac3aSPeter Wemm NULL 840d66a5066SPeter Wemm }; 841e1743d02SSøren Schmidt 842e1743d02SSøren Schmidt struct sysentvec elf_linux_sysvec = { 843e1743d02SSøren Schmidt LINUX_SYS_MAXSYSCALL, 844e1743d02SSøren Schmidt linux_sysent, 8459b44bfc5SAlexander Leidinger 0, 846956d3333SMarcel Moolenaar LINUX_SIGTBLSZ, 847e1743d02SSøren Schmidt bsd_to_linux_signal, 84885f118c8SDmitrij Tejblum ELAST + 1, 849e1743d02SSøren Schmidt bsd_to_linux_errno, 850288078beSEivind Eklund translate_traps, 851e1743d02SSøren Schmidt elf_linux_fixup, 852e1743d02SSøren Schmidt linux_sendsig, 853e1743d02SSøren Schmidt linux_sigcode, 854e1743d02SSøren Schmidt &linux_szsigcode, 855e1743d02SSøren Schmidt linux_prepsyscall, 85622d4b0fbSJohn Polstra "Linux ELF", 8573ebc1248SPeter Wemm elf32_coredump, 858806d7daaSMarcel Moolenaar exec_linux_imgact_try, 859f36ba452SJake Burkholder LINUX_MINSIGSTKSZ, 860f36ba452SJake Burkholder PAGE_SIZE, 861f36ba452SJake Burkholder VM_MIN_ADDRESS, 862f36ba452SJake Burkholder VM_MAXUSER_ADDRESS, 863f36ba452SJake Burkholder USRSTACK, 864f36ba452SJake Burkholder PS_STRINGS, 865f36ba452SJake Burkholder VM_PROT_ALL, 866f36ba452SJake Burkholder exec_copyout_strings, 867c460ac3aSPeter Wemm exec_linux_setregs, 868c460ac3aSPeter Wemm NULL 869e1743d02SSøren Schmidt }; 870e1743d02SSøren Schmidt 871514058dcSAlexander Langer static Elf32_Brandinfo linux_brand = { 872c815a20cSDavid E. O'Brien ELFOSABI_LINUX, 8733ebc1248SPeter Wemm EM_386, 87421a3ee0eSDavid E. O'Brien "Linux", 875ea5a2b2eSSøren Schmidt "/compat/linux", 8765cf588ebSPeter Wemm "/lib/ld-linux.so.1", 8779b68618dSPeter Wemm &elf_linux_sysvec, 8789b68618dSPeter Wemm NULL, 879900b28f9SMaxim Sobolev BI_CAN_EXEC_DYN, 8805cf588ebSPeter Wemm }; 8815cf588ebSPeter Wemm 882514058dcSAlexander Langer static Elf32_Brandinfo linux_glibc2brand = { 883c815a20cSDavid E. O'Brien ELFOSABI_LINUX, 8843ebc1248SPeter Wemm EM_386, 88521a3ee0eSDavid E. O'Brien "Linux", 8864e138a28SMike Smith "/compat/linux", 8874e138a28SMike Smith "/lib/ld-linux.so.2", 8889b68618dSPeter Wemm &elf_linux_sysvec, 8899b68618dSPeter Wemm NULL, 890900b28f9SMaxim Sobolev BI_CAN_EXEC_DYN, 8914e138a28SMike Smith }; 8924e138a28SMike Smith 893514058dcSAlexander Langer Elf32_Brandinfo *linux_brandlist[] = { 894514058dcSAlexander Langer &linux_brand, 895514058dcSAlexander Langer &linux_glibc2brand, 896514058dcSAlexander Langer NULL 897514058dcSAlexander Langer }; 898514058dcSAlexander Langer 899aa855a59SPeter Wemm static int 900c25ded31SBruce Evans linux_elf_modevent(module_t mod, int type, void *data) 901d30ea4f5SPeter Wemm { 902514058dcSAlexander Langer Elf32_Brandinfo **brandinfo; 903514058dcSAlexander Langer int error; 904f41325dbSPeter Wemm struct linux_ioctl_handler **lihp; 905060e4882SDoug Ambrisko struct linux_device_handler **ldhp; 906514058dcSAlexander Langer 907514058dcSAlexander Langer error = 0; 908514058dcSAlexander Langer 909aa855a59SPeter Wemm switch(type) { 910aa855a59SPeter Wemm case MOD_LOAD: 911aa855a59SPeter Wemm for (brandinfo = &linux_brandlist[0]; *brandinfo != NULL; 912aa855a59SPeter Wemm ++brandinfo) 9133ebc1248SPeter Wemm if (elf32_insert_brand_entry(*brandinfo) < 0) 914aa855a59SPeter Wemm error = EINVAL; 915466b14d7SMarcel Moolenaar if (error == 0) { 916f41325dbSPeter Wemm SET_FOREACH(lihp, linux_ioctl_handler_set) 917f41325dbSPeter Wemm linux_ioctl_register_handler(*lihp); 918060e4882SDoug Ambrisko SET_FOREACH(ldhp, linux_device_handler_set) 919060e4882SDoug Ambrisko linux_device_register_handler(*ldhp); 9209b44bfc5SAlexander Leidinger sx_init(&emul_lock, "emuldata lock"); 9219b44bfc5SAlexander Leidinger sx_init(&emul_shared_lock, "emuldata->shared lock"); 9229b44bfc5SAlexander Leidinger LIST_INIT(&futex_list); 923bb59e63fSAlexander Leidinger sx_init(&futex_sx, "futex protection lock"); 9249b44bfc5SAlexander Leidinger linux_exit_tag = EVENTHANDLER_REGISTER(process_exit, linux_proc_exit, 9259b44bfc5SAlexander Leidinger NULL, 1000); 9269b44bfc5SAlexander Leidinger linux_schedtail_tag = EVENTHANDLER_REGISTER(schedtail, linux_schedtail, 9279b44bfc5SAlexander Leidinger NULL, 1000); 9289b44bfc5SAlexander Leidinger linux_exec_tag = EVENTHANDLER_REGISTER(process_exec, linux_proc_exec, 9299b44bfc5SAlexander Leidinger NULL, 1000); 93043bef515SMarcel Moolenaar if (bootverbose) 931466b14d7SMarcel Moolenaar printf("Linux ELF exec handler installed\n"); 932466b14d7SMarcel Moolenaar } else 933466b14d7SMarcel Moolenaar printf("cannot insert Linux ELF brand handler\n"); 934aa855a59SPeter Wemm break; 935aa855a59SPeter Wemm case MOD_UNLOAD: 936aa855a59SPeter Wemm for (brandinfo = &linux_brandlist[0]; *brandinfo != NULL; 937aa855a59SPeter Wemm ++brandinfo) 9383ebc1248SPeter Wemm if (elf32_brand_inuse(*brandinfo)) 939d2758342SMark Newton error = EBUSY; 940d2758342SMark Newton if (error == 0) { 941d2758342SMark Newton for (brandinfo = &linux_brandlist[0]; 942d2758342SMark Newton *brandinfo != NULL; ++brandinfo) 9433ebc1248SPeter Wemm if (elf32_remove_brand_entry(*brandinfo) < 0) 944aa855a59SPeter Wemm error = EINVAL; 945d2758342SMark Newton } 946466b14d7SMarcel Moolenaar if (error == 0) { 947f41325dbSPeter Wemm SET_FOREACH(lihp, linux_ioctl_handler_set) 948f41325dbSPeter Wemm linux_ioctl_unregister_handler(*lihp); 949060e4882SDoug Ambrisko SET_FOREACH(ldhp, linux_device_handler_set) 950060e4882SDoug Ambrisko linux_device_unregister_handler(*ldhp); 9519b44bfc5SAlexander Leidinger sx_destroy(&emul_lock); 9529b44bfc5SAlexander Leidinger sx_destroy(&emul_shared_lock); 953bb59e63fSAlexander Leidinger sx_destroy(&futex_sx); 9549b44bfc5SAlexander Leidinger EVENTHANDLER_DEREGISTER(process_exit, linux_exit_tag); 9559b44bfc5SAlexander Leidinger EVENTHANDLER_DEREGISTER(schedtail, linux_schedtail_tag); 9569b44bfc5SAlexander Leidinger EVENTHANDLER_DEREGISTER(process_exec, linux_exec_tag); 957466b14d7SMarcel Moolenaar if (bootverbose) 958466b14d7SMarcel Moolenaar printf("Linux ELF exec handler removed\n"); 959466b14d7SMarcel Moolenaar } else 960aa855a59SPeter Wemm printf("Could not deinstall ELF interpreter entry\n"); 961aa855a59SPeter Wemm break; 962aa855a59SPeter Wemm default: 9633e019deaSPoul-Henning Kamp return EOPNOTSUPP; 964d30ea4f5SPeter Wemm } 965aa855a59SPeter Wemm return error; 966aa855a59SPeter Wemm } 967466b14d7SMarcel Moolenaar 968aa855a59SPeter Wemm static moduledata_t linux_elf_mod = { 969aa855a59SPeter Wemm "linuxelf", 970aa855a59SPeter Wemm linux_elf_modevent, 971aa855a59SPeter Wemm 0 972aa855a59SPeter Wemm }; 973466b14d7SMarcel Moolenaar 974aa855a59SPeter Wemm DECLARE_MODULE(linuxelf, linux_elf_mod, SI_SUB_EXEC, SI_ORDER_ANY); 975