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 * 28c3aac50fSPeter Wemm * $FreeBSD$ 29d66a5066SPeter Wemm */ 30d66a5066SPeter Wemm 31d66a5066SPeter Wemm /* XXX we use functions that might not exist. */ 325591b823SEivind Eklund #include "opt_compat.h" 33a9148ab1SPeter Wemm #include "opt_kstack_pages.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> 41d66a5066SPeter Wemm #include <sys/imgact.h> 4222d4b0fbSJohn Polstra #include <sys/imgact_aout.h> 43e1743d02SSøren Schmidt #include <sys/imgact_elf.h> 447106ca0dSJohn Baldwin #include <sys/lock.h> 45e1743d02SSøren Schmidt #include <sys/malloc.h> 4623955314SAlfred Perlstein #include <sys/mutex.h> 47fb919e4dSMark Murray #include <sys/proc.h> 48fb919e4dSMark Murray #include <sys/signalvar.h> 49206a5d3aSIan Dowse #include <sys/syscallsubr.h> 50fb919e4dSMark Murray #include <sys/sysent.h> 51fb919e4dSMark Murray #include <sys/sysproto.h> 52a9148ab1SPeter Wemm #include <sys/user.h> 53a9148ab1SPeter Wemm #include <sys/vnode.h> 54fb919e4dSMark Murray 55d66a5066SPeter Wemm #include <vm/vm.h> 56d66a5066SPeter Wemm #include <vm/vm_param.h> 57d66a5066SPeter Wemm #include <vm/vm_page.h> 58d66a5066SPeter Wemm #include <vm/vm_extern.h> 59d66a5066SPeter Wemm #include <sys/exec.h> 605cf588ebSPeter Wemm #include <sys/kernel.h> 61aa855a59SPeter Wemm #include <sys/module.h> 62d66a5066SPeter Wemm #include <machine/cpu.h> 63a9148ab1SPeter Wemm #include <machine/md_var.h> 64fb919e4dSMark Murray #include <sys/mutex.h> 65d66a5066SPeter Wemm 66a9148ab1SPeter Wemm #include <vm/vm.h> 67a9148ab1SPeter Wemm #include <vm/vm_param.h> 68a9148ab1SPeter Wemm #include <vm/pmap.h> 69a9148ab1SPeter Wemm #include <vm/vm_map.h> 70a9148ab1SPeter Wemm #include <vm/vm_object.h> 71a9148ab1SPeter Wemm 72d66a5066SPeter Wemm #include <i386/linux/linux.h> 73ebea8660SMarcel Moolenaar #include <i386/linux/linux_proto.h> 74b595ab37SAndrew Gallatin #include <compat/linux/linux_signal.h> 75322bfdc3SMarcel Moolenaar #include <compat/linux/linux_util.h> 76e1743d02SSøren Schmidt 771d91482dSPeter Wemm MODULE_VERSION(linux, 1); 78158eb277SDag-Erling Smørgrav MODULE_DEPEND(linux, sysvmsg, 1, 1, 1); 79158eb277SDag-Erling Smørgrav MODULE_DEPEND(linux, sysvsem, 1, 1, 1); 80158eb277SDag-Erling Smørgrav MODULE_DEPEND(linux, sysvshm, 1, 1, 1); 811d91482dSPeter Wemm 8243bef515SMarcel Moolenaar MALLOC_DEFINE(M_LINUX, "linux", "Linux mode structures"); 8343bef515SMarcel Moolenaar 84d323ddf3SMatthew Dillon #if BYTE_ORDER == LITTLE_ENDIAN 85d323ddf3SMatthew Dillon #define SHELLMAGIC 0x2123 /* #! */ 86d323ddf3SMatthew Dillon #else 87d323ddf3SMatthew Dillon #define SHELLMAGIC 0x2321 88d323ddf3SMatthew Dillon #endif 89d323ddf3SMatthew Dillon 90e061a6caSMarcel Moolenaar /* 91e061a6caSMarcel Moolenaar * Allow the sendsig functions to use the ldebug() facility 92e061a6caSMarcel Moolenaar * even though they are not syscalls themselves. Map them 93e061a6caSMarcel Moolenaar * to syscall 0. This is slightly less bogus than using 94e061a6caSMarcel Moolenaar * ldebug(sigreturn). 95e061a6caSMarcel Moolenaar */ 96e061a6caSMarcel Moolenaar #define LINUX_SYS_linux_rt_sendsig 0 97e061a6caSMarcel Moolenaar #define LINUX_SYS_linux_sendsig 0 98e061a6caSMarcel Moolenaar 9943bef515SMarcel Moolenaar extern char linux_sigcode[]; 10043bef515SMarcel Moolenaar extern int linux_szsigcode; 10143bef515SMarcel Moolenaar 10243bef515SMarcel Moolenaar extern struct sysent linux_sysent[LINUX_SYS_MAXSYSCALL]; 10343bef515SMarcel Moolenaar 104f41325dbSPeter Wemm SET_DECLARE(linux_ioctl_handler_set, struct linux_ioctl_handler); 10543bef515SMarcel Moolenaar 10689c9a483SAlfred Perlstein static int linux_fixup(register_t **stack_base, 10789c9a483SAlfred Perlstein struct image_params *iparams); 10889c9a483SAlfred Perlstein static int elf_linux_fixup(register_t **stack_base, 10989c9a483SAlfred Perlstein struct image_params *iparams); 110bda2a3afSBruce Evans static void linux_prepsyscall(struct trapframe *tf, int *args, u_int *code, 111bda2a3afSBruce Evans caddr_t *params); 11289c9a483SAlfred Perlstein static void linux_sendsig(sig_t catcher, int sig, sigset_t *mask, 11389c9a483SAlfred Perlstein u_long code); 114d66a5066SPeter Wemm 115d66a5066SPeter Wemm /* 116d66a5066SPeter Wemm * Linux syscalls return negative errno's, we do positive and map them 117d66a5066SPeter Wemm */ 11885f118c8SDmitrij Tejblum static int bsd_to_linux_errno[ELAST + 1] = { 119d66a5066SPeter Wemm -0, -1, -2, -3, -4, -5, -6, -7, -8, -9, 120d66a5066SPeter Wemm -10, -35, -12, -13, -14, -15, -16, -17, -18, -19, 121d66a5066SPeter Wemm -20, -21, -22, -23, -24, -25, -26, -27, -28, -29, 122d66a5066SPeter Wemm -30, -31, -32, -33, -34, -11,-115,-114, -88, -89, 123d66a5066SPeter Wemm -90, -91, -92, -93, -94, -95, -96, -97, -98, -99, 124d66a5066SPeter Wemm -100,-101,-102,-103,-104,-105,-106,-107,-108,-109, 125d66a5066SPeter Wemm -110,-111, -40, -36,-112,-113, -39, -11, -87,-122, 126d66a5066SPeter Wemm -116, -66, -6, -6, -6, -6, -6, -37, -38, -9, 12785f118c8SDmitrij Tejblum -6, -6, -43, -42, -75, -6, -84 128d66a5066SPeter Wemm }; 129d66a5066SPeter Wemm 130956d3333SMarcel Moolenaar int bsd_to_linux_signal[LINUX_SIGTBLSZ] = { 131956d3333SMarcel Moolenaar LINUX_SIGHUP, LINUX_SIGINT, LINUX_SIGQUIT, LINUX_SIGILL, 132956d3333SMarcel Moolenaar LINUX_SIGTRAP, LINUX_SIGABRT, 0, LINUX_SIGFPE, 133956d3333SMarcel Moolenaar LINUX_SIGKILL, LINUX_SIGBUS, LINUX_SIGSEGV, 0, 134956d3333SMarcel Moolenaar LINUX_SIGPIPE, LINUX_SIGALRM, LINUX_SIGTERM, LINUX_SIGURG, 135956d3333SMarcel Moolenaar LINUX_SIGSTOP, LINUX_SIGTSTP, LINUX_SIGCONT, LINUX_SIGCHLD, 136956d3333SMarcel Moolenaar LINUX_SIGTTIN, LINUX_SIGTTOU, LINUX_SIGIO, LINUX_SIGXCPU, 137956d3333SMarcel Moolenaar LINUX_SIGXFSZ, LINUX_SIGVTALRM, LINUX_SIGPROF, LINUX_SIGWINCH, 138956d3333SMarcel Moolenaar 0, LINUX_SIGUSR1, LINUX_SIGUSR2 139d66a5066SPeter Wemm }; 140d66a5066SPeter Wemm 141956d3333SMarcel Moolenaar int linux_to_bsd_signal[LINUX_SIGTBLSZ] = { 142956d3333SMarcel Moolenaar SIGHUP, SIGINT, SIGQUIT, SIGILL, 143956d3333SMarcel Moolenaar SIGTRAP, SIGABRT, SIGBUS, SIGFPE, 144956d3333SMarcel Moolenaar SIGKILL, SIGUSR1, SIGSEGV, SIGUSR2, 145956d3333SMarcel Moolenaar SIGPIPE, SIGALRM, SIGTERM, SIGBUS, 146956d3333SMarcel Moolenaar SIGCHLD, SIGCONT, SIGSTOP, SIGTSTP, 147956d3333SMarcel Moolenaar SIGTTIN, SIGTTOU, SIGURG, SIGXCPU, 148956d3333SMarcel Moolenaar SIGXFSZ, SIGVTALRM, SIGPROF, SIGWINCH, 149956d3333SMarcel Moolenaar SIGIO, SIGURG, 0 150d66a5066SPeter Wemm }; 151d66a5066SPeter Wemm 15227a828fcSPierre Beyssac #define LINUX_T_UNKNOWN 255 15327a828fcSPierre Beyssac static int _bsd_to_linux_trapcode[] = { 15427a828fcSPierre Beyssac LINUX_T_UNKNOWN, /* 0 */ 15527a828fcSPierre Beyssac 6, /* 1 T_PRIVINFLT */ 15627a828fcSPierre Beyssac LINUX_T_UNKNOWN, /* 2 */ 15727a828fcSPierre Beyssac 3, /* 3 T_BPTFLT */ 15827a828fcSPierre Beyssac LINUX_T_UNKNOWN, /* 4 */ 15927a828fcSPierre Beyssac LINUX_T_UNKNOWN, /* 5 */ 16027a828fcSPierre Beyssac 16, /* 6 T_ARITHTRAP */ 16127a828fcSPierre Beyssac 254, /* 7 T_ASTFLT */ 16227a828fcSPierre Beyssac LINUX_T_UNKNOWN, /* 8 */ 16327a828fcSPierre Beyssac 13, /* 9 T_PROTFLT */ 16427a828fcSPierre Beyssac 1, /* 10 T_TRCTRAP */ 16527a828fcSPierre Beyssac LINUX_T_UNKNOWN, /* 11 */ 16627a828fcSPierre Beyssac 14, /* 12 T_PAGEFLT */ 16727a828fcSPierre Beyssac LINUX_T_UNKNOWN, /* 13 */ 16827a828fcSPierre Beyssac 17, /* 14 T_ALIGNFLT */ 16927a828fcSPierre Beyssac LINUX_T_UNKNOWN, /* 15 */ 17027a828fcSPierre Beyssac LINUX_T_UNKNOWN, /* 16 */ 17127a828fcSPierre Beyssac LINUX_T_UNKNOWN, /* 17 */ 17227a828fcSPierre Beyssac 0, /* 18 T_DIVIDE */ 17327a828fcSPierre Beyssac 2, /* 19 T_NMI */ 17427a828fcSPierre Beyssac 4, /* 20 T_OFLOW */ 17527a828fcSPierre Beyssac 5, /* 21 T_BOUND */ 17627a828fcSPierre Beyssac 7, /* 22 T_DNA */ 17727a828fcSPierre Beyssac 8, /* 23 T_DOUBLEFLT */ 17827a828fcSPierre Beyssac 9, /* 24 T_FPOPFLT */ 17927a828fcSPierre Beyssac 10, /* 25 T_TSSFLT */ 18027a828fcSPierre Beyssac 11, /* 26 T_SEGNPFLT */ 18127a828fcSPierre Beyssac 12, /* 27 T_STKFLT */ 18227a828fcSPierre Beyssac 18, /* 28 T_MCHK */ 18327a828fcSPierre Beyssac 19, /* 29 T_XMMFLT */ 18427a828fcSPierre Beyssac 15 /* 30 T_RESERVED */ 18527a828fcSPierre Beyssac }; 18627a828fcSPierre Beyssac #define bsd_to_linux_trapcode(code) \ 18727a828fcSPierre Beyssac ((code)<sizeof(_bsd_to_linux_trapcode)/sizeof(*_bsd_to_linux_trapcode)? \ 18827a828fcSPierre Beyssac _bsd_to_linux_trapcode[(code)]: \ 18927a828fcSPierre Beyssac LINUX_T_UNKNOWN) 19027a828fcSPierre Beyssac 191288078beSEivind Eklund /* 192288078beSEivind Eklund * If FreeBSD & Linux have a difference of opinion about what a trap 193288078beSEivind Eklund * means, deal with it here. 194356861dbSMatthew Dillon * 195356861dbSMatthew Dillon * MPSAFE 196288078beSEivind Eklund */ 197288078beSEivind Eklund static int 198288078beSEivind Eklund translate_traps(int signal, int trap_code) 199288078beSEivind Eklund { 200d563a53aSEivind Eklund if (signal != SIGBUS) 201d563a53aSEivind Eklund return signal; 202288078beSEivind Eklund switch (trap_code) { 203288078beSEivind Eklund case T_PROTFLT: 204288078beSEivind Eklund case T_TSSFLT: 205288078beSEivind Eklund case T_DOUBLEFLT: 206288078beSEivind Eklund case T_PAGEFLT: 207288078beSEivind Eklund return SIGSEGV; 208288078beSEivind Eklund default: 209288078beSEivind Eklund return signal; 210288078beSEivind Eklund } 211288078beSEivind Eklund } 212288078beSEivind Eklund 213303b270bSEivind Eklund static int 214654f6be1SBruce Evans linux_fixup(register_t **stack_base, struct image_params *imgp) 215d66a5066SPeter Wemm { 216654f6be1SBruce Evans register_t *argv, *envp; 217d66a5066SPeter Wemm 218d66a5066SPeter Wemm argv = *stack_base; 219d66a5066SPeter Wemm envp = *stack_base + (imgp->argc + 1); 220d66a5066SPeter Wemm (*stack_base)--; 22186a14a7aSBruce Evans **stack_base = (intptr_t)(void *)envp; 222d66a5066SPeter Wemm (*stack_base)--; 22386a14a7aSBruce Evans **stack_base = (intptr_t)(void *)argv; 224d66a5066SPeter Wemm (*stack_base)--; 22586a14a7aSBruce Evans **stack_base = imgp->argc; 226e1743d02SSøren Schmidt return 0; 227d66a5066SPeter Wemm } 228d66a5066SPeter Wemm 229303b270bSEivind Eklund static int 230654f6be1SBruce Evans elf_linux_fixup(register_t **stack_base, struct image_params *imgp) 231e1743d02SSøren Schmidt { 232e1743d02SSøren Schmidt Elf32_Auxargs *args = (Elf32_Auxargs *)imgp->auxargs; 233654f6be1SBruce Evans register_t *pos; 234d66a5066SPeter Wemm 235e1743d02SSøren Schmidt pos = *stack_base + (imgp->argc + imgp->envc + 2); 236e1743d02SSøren Schmidt 237e1743d02SSøren Schmidt if (args->trace) { 238e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_DEBUG, 1); 239e1743d02SSøren Schmidt } 240e1743d02SSøren Schmidt if (args->execfd != -1) { 241e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_EXECFD, args->execfd); 242e1743d02SSøren Schmidt } 243e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_PHDR, args->phdr); 244e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_PHENT, args->phent); 245e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_PHNUM, args->phnum); 246e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_PAGESZ, args->pagesz); 247e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_FLAGS, args->flags); 248e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_ENTRY, args->entry); 249e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_BASE, args->base); 250611d9407SJohn Baldwin PROC_LOCK(imgp->proc); 251b1fc0ec1SRobert Watson AUXARGS_ENTRY(pos, AT_UID, imgp->proc->p_ucred->cr_ruid); 252b1fc0ec1SRobert Watson AUXARGS_ENTRY(pos, AT_EUID, imgp->proc->p_ucred->cr_svuid); 253b1fc0ec1SRobert Watson AUXARGS_ENTRY(pos, AT_GID, imgp->proc->p_ucred->cr_rgid); 254b1fc0ec1SRobert Watson AUXARGS_ENTRY(pos, AT_EGID, imgp->proc->p_ucred->cr_svgid); 255611d9407SJohn Baldwin PROC_UNLOCK(imgp->proc); 256e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_NULL, 0); 257e1743d02SSøren Schmidt 258e1743d02SSøren Schmidt free(imgp->auxargs, M_TEMP); 259e1743d02SSøren Schmidt imgp->auxargs = NULL; 260e1743d02SSøren Schmidt 261e1743d02SSøren Schmidt (*stack_base)--; 262ecbb00a2SDoug Rabson **stack_base = (long)imgp->argc; 263e1743d02SSøren Schmidt return 0; 264e1743d02SSøren Schmidt } 265d66a5066SPeter Wemm 266d66a5066SPeter Wemm extern int _ucodesel, _udatasel; 26702318dacSJake Burkholder extern unsigned long linux_sznonrtsigcode; 26879363394SAndrew Gallatin 26979363394SAndrew Gallatin static void 27079363394SAndrew Gallatin linux_rt_sendsig(sig_t catcher, int sig, sigset_t *mask, u_long code) 27179363394SAndrew Gallatin { 272b40ce416SJulian Elischer register struct thread *td = curthread; 273b40ce416SJulian Elischer register struct proc *p = td->td_proc; 27479363394SAndrew Gallatin register struct trapframe *regs; 2755002a60fSMarcel Moolenaar struct l_rt_sigframe *fp, frame; 27679363394SAndrew Gallatin int oonstack; 27779363394SAndrew Gallatin 278df53e91cSJohn Baldwin PROC_LOCK_ASSERT(p, MA_OWNED); 279b40ce416SJulian Elischer regs = td->td_frame; 280d034d459SMarcel Moolenaar oonstack = sigonstack(regs->tf_esp); 28179363394SAndrew Gallatin 28279363394SAndrew Gallatin #ifdef DEBUG 2835002a60fSMarcel Moolenaar if (ldebug(rt_sendsig)) 28424593369SJonathan Lemon printf(ARGS(rt_sendsig, "%p, %d, %p, %lu"), 28524593369SJonathan Lemon catcher, sig, (void*)mask, code); 28679363394SAndrew Gallatin #endif 28779363394SAndrew Gallatin /* 28879363394SAndrew Gallatin * Allocate space for the signal handler context. 28979363394SAndrew Gallatin */ 29079363394SAndrew Gallatin if ((p->p_flag & P_ALTSTACK) && !oonstack && 291cc6ca9b3SMarcel Moolenaar SIGISMEMBER(p->p_sigacts->ps_sigonstack, sig)) { 2925002a60fSMarcel Moolenaar fp = (struct l_rt_sigframe *)(p->p_sigstk.ss_sp + 2935002a60fSMarcel Moolenaar p->p_sigstk.ss_size - sizeof(struct l_rt_sigframe)); 294d034d459SMarcel Moolenaar } else 2955002a60fSMarcel Moolenaar fp = (struct l_rt_sigframe *)regs->tf_esp - 1; 296611d9407SJohn Baldwin PROC_UNLOCK(p); 29779363394SAndrew Gallatin 29879363394SAndrew Gallatin /* 29979363394SAndrew Gallatin * Build the argument list for the signal handler. 30079363394SAndrew Gallatin */ 30179363394SAndrew Gallatin if (p->p_sysent->sv_sigtbl) 30279363394SAndrew Gallatin if (sig <= p->p_sysent->sv_sigsize) 30379363394SAndrew Gallatin sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)]; 30479363394SAndrew Gallatin 30579363394SAndrew Gallatin frame.sf_handler = catcher; 30679363394SAndrew Gallatin frame.sf_sig = sig; 30779363394SAndrew Gallatin frame.sf_siginfo = &fp->sf_si; 30879363394SAndrew Gallatin frame.sf_ucontext = &fp->sf_sc; 309cc6ca9b3SMarcel Moolenaar 31079363394SAndrew Gallatin /* Fill siginfo structure. */ 31179363394SAndrew Gallatin frame.sf_si.lsi_signo = sig; 31279363394SAndrew Gallatin frame.sf_si.lsi_code = code; 31379363394SAndrew Gallatin frame.sf_si.lsi_addr = (void *)regs->tf_err; 314cc6ca9b3SMarcel Moolenaar 31579363394SAndrew Gallatin /* 31679363394SAndrew Gallatin * Build the signal context to be used by sigreturn. 31779363394SAndrew Gallatin */ 318cc6ca9b3SMarcel Moolenaar frame.sf_sc.uc_flags = 0; /* XXX ??? */ 319cc6ca9b3SMarcel Moolenaar frame.sf_sc.uc_link = NULL; /* XXX ??? */ 320cc6ca9b3SMarcel Moolenaar 321611d9407SJohn Baldwin PROC_LOCK(p); 322cc6ca9b3SMarcel Moolenaar frame.sf_sc.uc_stack.ss_sp = p->p_sigstk.ss_sp; 323cc6ca9b3SMarcel Moolenaar frame.sf_sc.uc_stack.ss_size = p->p_sigstk.ss_size; 324d034d459SMarcel Moolenaar frame.sf_sc.uc_stack.ss_flags = (p->p_flag & P_ALTSTACK) 325d034d459SMarcel Moolenaar ? ((oonstack) ? LINUX_SS_ONSTACK : 0) : LINUX_SS_DISABLE; 326611d9407SJohn Baldwin PROC_UNLOCK(p); 327cc6ca9b3SMarcel Moolenaar 328cc6ca9b3SMarcel Moolenaar bsd_to_linux_sigset(mask, &frame.sf_sc.uc_sigmask); 329cc6ca9b3SMarcel Moolenaar 330cc6ca9b3SMarcel Moolenaar frame.sf_sc.uc_mcontext.sc_mask = frame.sf_sc.uc_sigmask.__bits[0]; 33179363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_gs = rgs(); 33279363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_fs = regs->tf_fs; 33379363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_es = regs->tf_es; 33479363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_ds = regs->tf_ds; 33579363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_edi = regs->tf_edi; 33679363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_esi = regs->tf_esi; 33779363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_ebp = regs->tf_ebp; 33879363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_ebx = regs->tf_ebx; 33979363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_edx = regs->tf_edx; 34079363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_ecx = regs->tf_ecx; 34179363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_eax = regs->tf_eax; 34279363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_eip = regs->tf_eip; 34379363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_cs = regs->tf_cs; 34479363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_eflags = regs->tf_eflags; 34579363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_esp_at_signal = regs->tf_esp; 34679363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_ss = regs->tf_ss; 34779363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_err = regs->tf_err; 34827a828fcSPierre Beyssac frame.sf_sc.uc_mcontext.sc_trapno = bsd_to_linux_trapcode(code); 34979363394SAndrew Gallatin 35079363394SAndrew Gallatin #ifdef DEBUG 3515002a60fSMarcel Moolenaar if (ldebug(rt_sendsig)) 35224593369SJonathan Lemon printf(LMSG("rt_sendsig flags: 0x%x, sp: %p, ss: 0x%x, mask: 0x%x"), 35324593369SJonathan Lemon frame.sf_sc.uc_stack.ss_flags, p->p_sigstk.ss_sp, 35424593369SJonathan Lemon p->p_sigstk.ss_size, frame.sf_sc.uc_mcontext.sc_mask); 35579363394SAndrew Gallatin #endif 35679363394SAndrew Gallatin 35779363394SAndrew Gallatin if (copyout(&frame, fp, sizeof(frame)) != 0) { 35879363394SAndrew Gallatin /* 35979363394SAndrew Gallatin * Process has trashed its stack; give it an illegal 36079363394SAndrew Gallatin * instruction to halt it in its tracks. 36179363394SAndrew Gallatin */ 36289734883SAlan Cox #ifdef DEBUG 36389734883SAlan Cox if (ldebug(rt_sendsig)) 36489734883SAlan Cox printf(LMSG("rt_sendsig: bad stack %p, oonstack=%x"), 36589734883SAlan Cox fp, oonstack); 36689734883SAlan Cox #endif 36719eb87d2SJohn Baldwin PROC_LOCK(p); 368b40ce416SJulian Elischer sigexit(td, SIGILL); 36979363394SAndrew Gallatin } 37079363394SAndrew Gallatin 37179363394SAndrew Gallatin /* 37279363394SAndrew Gallatin * Build context to run handler in. 37379363394SAndrew Gallatin */ 37479363394SAndrew Gallatin regs->tf_esp = (int)fp; 37579363394SAndrew Gallatin regs->tf_eip = PS_STRINGS - *(p->p_sysent->sv_szsigcode) + 37602318dacSJake Burkholder linux_sznonrtsigcode; 377846ac226SBruce Evans regs->tf_eflags &= ~(PSL_T | PSL_VM); 37879363394SAndrew Gallatin regs->tf_cs = _ucodesel; 37979363394SAndrew Gallatin regs->tf_ds = _udatasel; 38079363394SAndrew Gallatin regs->tf_es = _udatasel; 38179363394SAndrew Gallatin regs->tf_fs = _udatasel; 38279363394SAndrew Gallatin regs->tf_ss = _udatasel; 383df53e91cSJohn Baldwin PROC_LOCK(p); 38479363394SAndrew Gallatin } 38579363394SAndrew Gallatin 386d66a5066SPeter Wemm 387d66a5066SPeter Wemm /* 388d66a5066SPeter Wemm * Send an interrupt to process. 389d66a5066SPeter Wemm * 390d66a5066SPeter Wemm * Stack is set up to allow sigcode stored 391d66a5066SPeter Wemm * in u. to call routine, followed by kcall 392d66a5066SPeter Wemm * to sigreturn routine below. After sigreturn 393d66a5066SPeter Wemm * resets the signal mask, the stack, and the 394d66a5066SPeter Wemm * frame pointer, it returns to the user 395d66a5066SPeter Wemm * specified pc, psl. 396d66a5066SPeter Wemm */ 397d66a5066SPeter Wemm 398303b270bSEivind Eklund static void 399956d3333SMarcel Moolenaar linux_sendsig(sig_t catcher, int sig, sigset_t *mask, u_long code) 400d66a5066SPeter Wemm { 401b40ce416SJulian Elischer register struct thread *td = curthread; 402b40ce416SJulian Elischer register struct proc *p = td->td_proc; 403213fdd80SPeter Wemm register struct trapframe *regs; 4045002a60fSMarcel Moolenaar struct l_sigframe *fp, frame; 4055002a60fSMarcel Moolenaar l_sigset_t lmask; 4062c4ab9ddSAndrew Gallatin int oonstack, i; 407d66a5066SPeter Wemm 4082509e6c2SJohn Baldwin PROC_LOCK_ASSERT(p, MA_OWNED); 409cc6ca9b3SMarcel Moolenaar if (SIGISMEMBER(p->p_sigacts->ps_siginfo, sig)) { 410cc6ca9b3SMarcel Moolenaar /* Signal handler installed with SA_SIGINFO. */ 411cc6ca9b3SMarcel Moolenaar linux_rt_sendsig(catcher, sig, mask, code); 412cc6ca9b3SMarcel Moolenaar return; 413cc6ca9b3SMarcel Moolenaar } 414cc6ca9b3SMarcel Moolenaar 415b40ce416SJulian Elischer regs = td->td_frame; 416d034d459SMarcel Moolenaar oonstack = sigonstack(regs->tf_esp); 417d66a5066SPeter Wemm 418d66a5066SPeter Wemm #ifdef DEBUG 4195002a60fSMarcel Moolenaar if (ldebug(sendsig)) 42024593369SJonathan Lemon printf(ARGS(sendsig, "%p, %d, %p, %lu"), 42124593369SJonathan Lemon catcher, sig, (void*)mask, code); 422d66a5066SPeter Wemm #endif 42379363394SAndrew Gallatin 424d66a5066SPeter Wemm /* 425d66a5066SPeter Wemm * Allocate space for the signal handler context. 426d66a5066SPeter Wemm */ 427645682fdSLuoqi Chen if ((p->p_flag & P_ALTSTACK) && !oonstack && 428cc6ca9b3SMarcel Moolenaar SIGISMEMBER(p->p_sigacts->ps_sigonstack, sig)) { 4295002a60fSMarcel Moolenaar fp = (struct l_sigframe *)(p->p_sigstk.ss_sp + 4305002a60fSMarcel Moolenaar p->p_sigstk.ss_size - sizeof(struct l_sigframe)); 431d034d459SMarcel Moolenaar } else 4325002a60fSMarcel Moolenaar fp = (struct l_sigframe *)regs->tf_esp - 1; 433611d9407SJohn Baldwin PROC_UNLOCK(p); 434d66a5066SPeter Wemm 435d66a5066SPeter Wemm /* 436d66a5066SPeter Wemm * Build the argument list for the signal handler. 437d66a5066SPeter Wemm */ 438956d3333SMarcel Moolenaar if (p->p_sysent->sv_sigtbl) 439956d3333SMarcel Moolenaar if (sig <= p->p_sysent->sv_sigsize) 440956d3333SMarcel Moolenaar sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)]; 441d66a5066SPeter Wemm 442d66a5066SPeter Wemm frame.sf_handler = catcher; 443d66a5066SPeter Wemm frame.sf_sig = sig; 444d66a5066SPeter Wemm 445cc6ca9b3SMarcel Moolenaar bsd_to_linux_sigset(mask, &lmask); 446cc6ca9b3SMarcel Moolenaar 447d66a5066SPeter Wemm /* 448d66a5066SPeter Wemm * Build the signal context to be used by sigreturn. 449d66a5066SPeter Wemm */ 450cc6ca9b3SMarcel Moolenaar frame.sf_sc.sc_mask = lmask.__bits[0]; 4515206bca1SLuoqi Chen frame.sf_sc.sc_gs = rgs(); 4525206bca1SLuoqi Chen frame.sf_sc.sc_fs = regs->tf_fs; 453213fdd80SPeter Wemm frame.sf_sc.sc_es = regs->tf_es; 454213fdd80SPeter Wemm frame.sf_sc.sc_ds = regs->tf_ds; 455213fdd80SPeter Wemm frame.sf_sc.sc_edi = regs->tf_edi; 456213fdd80SPeter Wemm frame.sf_sc.sc_esi = regs->tf_esi; 457213fdd80SPeter Wemm frame.sf_sc.sc_ebp = regs->tf_ebp; 458213fdd80SPeter Wemm frame.sf_sc.sc_ebx = regs->tf_ebx; 459213fdd80SPeter Wemm frame.sf_sc.sc_edx = regs->tf_edx; 460213fdd80SPeter Wemm frame.sf_sc.sc_ecx = regs->tf_ecx; 461213fdd80SPeter Wemm frame.sf_sc.sc_eax = regs->tf_eax; 462213fdd80SPeter Wemm frame.sf_sc.sc_eip = regs->tf_eip; 463213fdd80SPeter Wemm frame.sf_sc.sc_cs = regs->tf_cs; 464213fdd80SPeter Wemm frame.sf_sc.sc_eflags = regs->tf_eflags; 465213fdd80SPeter Wemm frame.sf_sc.sc_esp_at_signal = regs->tf_esp; 466213fdd80SPeter Wemm frame.sf_sc.sc_ss = regs->tf_ss; 467213fdd80SPeter Wemm frame.sf_sc.sc_err = regs->tf_err; 46827a828fcSPierre Beyssac frame.sf_sc.sc_trapno = bsd_to_linux_trapcode(code); 469cc6ca9b3SMarcel Moolenaar 4705002a60fSMarcel Moolenaar bzero(&frame.sf_fpstate, sizeof(struct l_fpstate)); 471cc6ca9b3SMarcel Moolenaar 4722c4ab9ddSAndrew Gallatin for (i = 0; i < (LINUX_NSIG_WORDS-1); i++) 473cc6ca9b3SMarcel Moolenaar frame.sf_extramask[i] = lmask.__bits[i+1]; 474d66a5066SPeter Wemm 475d66a5066SPeter Wemm if (copyout(&frame, fp, sizeof(frame)) != 0) { 476d66a5066SPeter Wemm /* 477d66a5066SPeter Wemm * Process has trashed its stack; give it an illegal 478d66a5066SPeter Wemm * instruction to halt it in its tracks. 479d66a5066SPeter Wemm */ 48019eb87d2SJohn Baldwin PROC_LOCK(p); 481b40ce416SJulian Elischer sigexit(td, SIGILL); 482d66a5066SPeter Wemm } 483d66a5066SPeter Wemm 484d66a5066SPeter Wemm /* 485d66a5066SPeter Wemm * Build context to run handler in. 486d66a5066SPeter Wemm */ 487213fdd80SPeter Wemm regs->tf_esp = (int)fp; 4884c56fcdeSBruce Evans regs->tf_eip = PS_STRINGS - *(p->p_sysent->sv_szsigcode); 489846ac226SBruce Evans regs->tf_eflags &= ~(PSL_T | PSL_VM); 490213fdd80SPeter Wemm regs->tf_cs = _ucodesel; 491213fdd80SPeter Wemm regs->tf_ds = _udatasel; 492213fdd80SPeter Wemm regs->tf_es = _udatasel; 4935206bca1SLuoqi Chen regs->tf_fs = _udatasel; 494213fdd80SPeter Wemm regs->tf_ss = _udatasel; 4955002a60fSMarcel Moolenaar PROC_LOCK(p); 496d66a5066SPeter Wemm } 497d66a5066SPeter Wemm 498d66a5066SPeter Wemm /* 499d66a5066SPeter Wemm * System call to cleanup state after a signal 500d66a5066SPeter Wemm * has been taken. Reset signal mask and 501d66a5066SPeter Wemm * stack state from context left by sendsig (above). 502d66a5066SPeter Wemm * Return to previous pc and psl as specified by 503d66a5066SPeter Wemm * context left by sendsig. Check carefully to 504d66a5066SPeter Wemm * make sure that the user has not modified the 505d66a5066SPeter Wemm * psl to gain improper privileges or to cause 506d66a5066SPeter Wemm * a machine fault. 507d66a5066SPeter Wemm */ 508d66a5066SPeter Wemm int 509b40ce416SJulian Elischer linux_sigreturn(td, args) 510b40ce416SJulian Elischer struct thread *td; 511d66a5066SPeter Wemm struct linux_sigreturn_args *args; 512d66a5066SPeter Wemm { 513b40ce416SJulian Elischer struct proc *p = td->td_proc; 5145002a60fSMarcel Moolenaar struct l_sigframe frame; 515213fdd80SPeter Wemm register struct trapframe *regs; 5165002a60fSMarcel Moolenaar l_sigset_t lmask; 5172c4ab9ddSAndrew Gallatin int eflags, i; 518d66a5066SPeter Wemm 519b40ce416SJulian Elischer regs = td->td_frame; 520d66a5066SPeter Wemm 521d66a5066SPeter Wemm #ifdef DEBUG 52224593369SJonathan Lemon if (ldebug(sigreturn)) 52324593369SJonathan Lemon printf(ARGS(sigreturn, "%p"), (void *)args->sfp); 524d66a5066SPeter Wemm #endif 525d66a5066SPeter Wemm /* 526cc6ca9b3SMarcel Moolenaar * The trampoline code hands us the sigframe. 527d66a5066SPeter Wemm * It is unsafe to keep track of it ourselves, in the event that a 528d66a5066SPeter Wemm * program jumps out of a signal handler. 529d66a5066SPeter Wemm */ 530cc6ca9b3SMarcel Moolenaar if (copyin((caddr_t)args->sfp, &frame, sizeof(frame)) != 0) 531d66a5066SPeter Wemm return (EFAULT); 532d66a5066SPeter Wemm 533d66a5066SPeter Wemm /* 534d66a5066SPeter Wemm * Check for security violations. 535d66a5066SPeter Wemm */ 536d66a5066SPeter Wemm #define EFLAGS_SECURE(ef, oef) ((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0) 537cc6ca9b3SMarcel Moolenaar eflags = frame.sf_sc.sc_eflags; 538d66a5066SPeter Wemm /* 539d66a5066SPeter Wemm * XXX do allow users to change the privileged flag PSL_RF. The 540d66a5066SPeter Wemm * cpu sets PSL_RF in tf_eflags for faults. Debuggers should 541d66a5066SPeter Wemm * sometimes set it there too. tf_eflags is kept in the signal 542d66a5066SPeter Wemm * context during signal handling and there is no other place 543d66a5066SPeter Wemm * to remember it, so the PSL_RF bit may be corrupted by the 544d66a5066SPeter Wemm * signal handler without us knowing. Corruption of the PSL_RF 545d66a5066SPeter Wemm * bit at worst causes one more or one less debugger trap, so 546d66a5066SPeter Wemm * allowing it is fairly harmless. 547d66a5066SPeter Wemm */ 548213fdd80SPeter Wemm if (!EFLAGS_SECURE(eflags & ~PSL_RF, regs->tf_eflags & ~PSL_RF)) { 549d66a5066SPeter Wemm return(EINVAL); 550d66a5066SPeter Wemm } 551d66a5066SPeter Wemm 552d66a5066SPeter Wemm /* 553d66a5066SPeter Wemm * Don't allow users to load a valid privileged %cs. Let the 554d66a5066SPeter Wemm * hardware check for invalid selectors, excess privilege in 555d66a5066SPeter Wemm * other selectors, invalid %eip's and invalid %esp's. 556d66a5066SPeter Wemm */ 55740d50994SPhilippe Charnier #define CS_SECURE(cs) (ISPL(cs) == SEL_UPL) 558cc6ca9b3SMarcel Moolenaar if (!CS_SECURE(frame.sf_sc.sc_cs)) { 559d66a5066SPeter Wemm trapsignal(p, SIGBUS, T_PROTFLT); 560d66a5066SPeter Wemm return(EINVAL); 561d66a5066SPeter Wemm } 562d66a5066SPeter Wemm 563cc6ca9b3SMarcel Moolenaar lmask.__bits[0] = frame.sf_sc.sc_mask; 5642c4ab9ddSAndrew Gallatin for (i = 0; i < (LINUX_NSIG_WORDS-1); i++) 565cc6ca9b3SMarcel Moolenaar lmask.__bits[i+1] = frame.sf_extramask[i]; 566611d9407SJohn Baldwin PROC_LOCK(p); 567cc6ca9b3SMarcel Moolenaar linux_to_bsd_sigset(&lmask, &p->p_sigmask); 568645682fdSLuoqi Chen SIG_CANTMASK(p->p_sigmask); 56979065dbaSBruce Evans signotify(p); 570611d9407SJohn Baldwin PROC_UNLOCK(p); 571956d3333SMarcel Moolenaar 572d66a5066SPeter Wemm /* 573d66a5066SPeter Wemm * Restore signal context. 574d66a5066SPeter Wemm */ 5755206bca1SLuoqi Chen /* %gs was restored by the trampoline. */ 576cc6ca9b3SMarcel Moolenaar regs->tf_fs = frame.sf_sc.sc_fs; 577cc6ca9b3SMarcel Moolenaar regs->tf_es = frame.sf_sc.sc_es; 578cc6ca9b3SMarcel Moolenaar regs->tf_ds = frame.sf_sc.sc_ds; 579cc6ca9b3SMarcel Moolenaar regs->tf_edi = frame.sf_sc.sc_edi; 580cc6ca9b3SMarcel Moolenaar regs->tf_esi = frame.sf_sc.sc_esi; 581cc6ca9b3SMarcel Moolenaar regs->tf_ebp = frame.sf_sc.sc_ebp; 582cc6ca9b3SMarcel Moolenaar regs->tf_ebx = frame.sf_sc.sc_ebx; 583cc6ca9b3SMarcel Moolenaar regs->tf_edx = frame.sf_sc.sc_edx; 584cc6ca9b3SMarcel Moolenaar regs->tf_ecx = frame.sf_sc.sc_ecx; 585cc6ca9b3SMarcel Moolenaar regs->tf_eax = frame.sf_sc.sc_eax; 586cc6ca9b3SMarcel Moolenaar regs->tf_eip = frame.sf_sc.sc_eip; 587cc6ca9b3SMarcel Moolenaar regs->tf_cs = frame.sf_sc.sc_cs; 588213fdd80SPeter Wemm regs->tf_eflags = eflags; 589cc6ca9b3SMarcel Moolenaar regs->tf_esp = frame.sf_sc.sc_esp_at_signal; 590cc6ca9b3SMarcel Moolenaar regs->tf_ss = frame.sf_sc.sc_ss; 591d66a5066SPeter Wemm 592d66a5066SPeter Wemm return (EJUSTRETURN); 593d66a5066SPeter Wemm } 594d66a5066SPeter Wemm 59579363394SAndrew Gallatin /* 59679363394SAndrew Gallatin * System call to cleanup state after a signal 59779363394SAndrew Gallatin * has been taken. Reset signal mask and 59879363394SAndrew Gallatin * stack state from context left by rt_sendsig (above). 59979363394SAndrew Gallatin * Return to previous pc and psl as specified by 60079363394SAndrew Gallatin * context left by sendsig. Check carefully to 60179363394SAndrew Gallatin * make sure that the user has not modified the 60279363394SAndrew Gallatin * psl to gain improper privileges or to cause 60379363394SAndrew Gallatin * a machine fault. 60479363394SAndrew Gallatin */ 60579363394SAndrew Gallatin int 606b40ce416SJulian Elischer linux_rt_sigreturn(td, args) 607b40ce416SJulian Elischer struct thread *td; 60879363394SAndrew Gallatin struct linux_rt_sigreturn_args *args; 60979363394SAndrew Gallatin { 610b40ce416SJulian Elischer struct proc *p = td->td_proc; 6115002a60fSMarcel Moolenaar struct l_ucontext uc; 6125002a60fSMarcel Moolenaar struct l_sigcontext *context; 6135002a60fSMarcel Moolenaar l_stack_t *lss; 614206a5d3aSIan Dowse stack_t ss; 61579363394SAndrew Gallatin register struct trapframe *regs; 61679363394SAndrew Gallatin int eflags; 61779363394SAndrew Gallatin 618b40ce416SJulian Elischer regs = td->td_frame; 61979363394SAndrew Gallatin 62079363394SAndrew Gallatin #ifdef DEBUG 62124593369SJonathan Lemon if (ldebug(rt_sigreturn)) 62224593369SJonathan Lemon printf(ARGS(rt_sigreturn, "%p"), (void *)args->ucp); 62379363394SAndrew Gallatin #endif 62479363394SAndrew Gallatin /* 625cc6ca9b3SMarcel Moolenaar * The trampoline code hands us the ucontext. 62679363394SAndrew Gallatin * It is unsafe to keep track of it ourselves, in the event that a 62779363394SAndrew Gallatin * program jumps out of a signal handler. 62879363394SAndrew Gallatin */ 62979363394SAndrew Gallatin if (copyin((caddr_t)args->ucp, &uc, sizeof(uc)) != 0) 63079363394SAndrew Gallatin return (EFAULT); 63179363394SAndrew Gallatin 63279363394SAndrew Gallatin context = &uc.uc_mcontext; 63379363394SAndrew Gallatin 63479363394SAndrew Gallatin /* 63579363394SAndrew Gallatin * Check for security violations. 63679363394SAndrew Gallatin */ 63779363394SAndrew Gallatin #define EFLAGS_SECURE(ef, oef) ((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0) 63879363394SAndrew Gallatin eflags = context->sc_eflags; 63979363394SAndrew Gallatin /* 64079363394SAndrew Gallatin * XXX do allow users to change the privileged flag PSL_RF. The 64179363394SAndrew Gallatin * cpu sets PSL_RF in tf_eflags for faults. Debuggers should 64279363394SAndrew Gallatin * sometimes set it there too. tf_eflags is kept in the signal 64379363394SAndrew Gallatin * context during signal handling and there is no other place 64479363394SAndrew Gallatin * to remember it, so the PSL_RF bit may be corrupted by the 64579363394SAndrew Gallatin * signal handler without us knowing. Corruption of the PSL_RF 64679363394SAndrew Gallatin * bit at worst causes one more or one less debugger trap, so 64779363394SAndrew Gallatin * allowing it is fairly harmless. 64879363394SAndrew Gallatin */ 64979363394SAndrew Gallatin if (!EFLAGS_SECURE(eflags & ~PSL_RF, regs->tf_eflags & ~PSL_RF)) { 65079363394SAndrew Gallatin return(EINVAL); 65179363394SAndrew Gallatin } 65279363394SAndrew Gallatin 65379363394SAndrew Gallatin /* 65479363394SAndrew Gallatin * Don't allow users to load a valid privileged %cs. Let the 65579363394SAndrew Gallatin * hardware check for invalid selectors, excess privilege in 65679363394SAndrew Gallatin * other selectors, invalid %eip's and invalid %esp's. 65779363394SAndrew Gallatin */ 65879363394SAndrew Gallatin #define CS_SECURE(cs) (ISPL(cs) == SEL_UPL) 65979363394SAndrew Gallatin if (!CS_SECURE(context->sc_cs)) { 66079363394SAndrew Gallatin trapsignal(p, SIGBUS, T_PROTFLT); 66179363394SAndrew Gallatin return(EINVAL); 66279363394SAndrew Gallatin } 66379363394SAndrew Gallatin 664611d9407SJohn Baldwin PROC_LOCK(p); 665b595ab37SAndrew Gallatin linux_to_bsd_sigset(&uc.uc_sigmask, &p->p_sigmask); 66679363394SAndrew Gallatin SIG_CANTMASK(p->p_sigmask); 66779065dbaSBruce Evans signotify(p); 668611d9407SJohn Baldwin PROC_UNLOCK(p); 66979363394SAndrew Gallatin 67079363394SAndrew Gallatin /* 671cc6ca9b3SMarcel Moolenaar * Restore signal context 67279363394SAndrew Gallatin */ 67379363394SAndrew Gallatin /* %gs was restored by the trampoline. */ 67479363394SAndrew Gallatin regs->tf_fs = context->sc_fs; 67579363394SAndrew Gallatin regs->tf_es = context->sc_es; 67679363394SAndrew Gallatin regs->tf_ds = context->sc_ds; 67779363394SAndrew Gallatin regs->tf_edi = context->sc_edi; 67879363394SAndrew Gallatin regs->tf_esi = context->sc_esi; 67979363394SAndrew Gallatin regs->tf_ebp = context->sc_ebp; 68079363394SAndrew Gallatin regs->tf_ebx = context->sc_ebx; 68179363394SAndrew Gallatin regs->tf_edx = context->sc_edx; 68279363394SAndrew Gallatin regs->tf_ecx = context->sc_ecx; 68379363394SAndrew Gallatin regs->tf_eax = context->sc_eax; 68479363394SAndrew Gallatin regs->tf_eip = context->sc_eip; 68579363394SAndrew Gallatin regs->tf_cs = context->sc_cs; 68679363394SAndrew Gallatin regs->tf_eflags = eflags; 68779363394SAndrew Gallatin regs->tf_esp = context->sc_esp_at_signal; 68879363394SAndrew Gallatin regs->tf_ss = context->sc_ss; 68979363394SAndrew Gallatin 69079363394SAndrew Gallatin /* 69179363394SAndrew Gallatin * call sigaltstack & ignore results.. 69279363394SAndrew Gallatin */ 69379363394SAndrew Gallatin lss = &uc.uc_stack; 694206a5d3aSIan Dowse ss.ss_sp = lss->ss_sp; 695206a5d3aSIan Dowse ss.ss_size = lss->ss_size; 696206a5d3aSIan Dowse ss.ss_flags = linux_to_bsd_sigaltstack(lss->ss_flags); 69779363394SAndrew Gallatin 69879363394SAndrew Gallatin #ifdef DEBUG 69924593369SJonathan Lemon if (ldebug(rt_sigreturn)) 70024593369SJonathan Lemon printf(LMSG("rt_sigret flags: 0x%x, sp: %p, ss: 0x%x, mask: 0x%x"), 701206a5d3aSIan Dowse ss.ss_flags, ss.ss_sp, ss.ss_size, context->sc_mask); 70279363394SAndrew Gallatin #endif 703206a5d3aSIan Dowse (void)kern_sigaltstack(td, &ss, NULL); 70479363394SAndrew Gallatin 70579363394SAndrew Gallatin return (EJUSTRETURN); 70679363394SAndrew Gallatin } 70779363394SAndrew Gallatin 708356861dbSMatthew Dillon /* 709356861dbSMatthew Dillon * MPSAFE 710356861dbSMatthew Dillon */ 711303b270bSEivind Eklund static void 712d66a5066SPeter Wemm linux_prepsyscall(struct trapframe *tf, int *args, u_int *code, caddr_t *params) 713d66a5066SPeter Wemm { 714d66a5066SPeter Wemm args[0] = tf->tf_ebx; 715d66a5066SPeter Wemm args[1] = tf->tf_ecx; 716d66a5066SPeter Wemm args[2] = tf->tf_edx; 717d66a5066SPeter Wemm args[3] = tf->tf_esi; 718d66a5066SPeter Wemm args[4] = tf->tf_edi; 7197646aefcSPeter Wemm args[5] = tf->tf_ebp; /* Unconfirmed */ 720d66a5066SPeter Wemm *params = NULL; /* no copyin */ 721d66a5066SPeter Wemm } 722d66a5066SPeter Wemm 723a9148ab1SPeter Wemm 724a9148ab1SPeter Wemm 725a9148ab1SPeter Wemm /* 726a9148ab1SPeter Wemm * Dump core, into a file named as described in the comments for 727a9148ab1SPeter Wemm * expand_name(), unless the process was setuid/setgid. 728a9148ab1SPeter Wemm */ 729a9148ab1SPeter Wemm static int 730a9148ab1SPeter Wemm linux_aout_coredump(struct thread *td, struct vnode *vp, off_t limit) 731a9148ab1SPeter Wemm { 732a9148ab1SPeter Wemm struct proc *p = td->td_proc; 733a9148ab1SPeter Wemm struct ucred *cred = td->td_ucred; 734a9148ab1SPeter Wemm struct vmspace *vm = p->p_vmspace; 735a9148ab1SPeter Wemm caddr_t tempuser; 736a9148ab1SPeter Wemm int error; 737a9148ab1SPeter Wemm 738a9148ab1SPeter Wemm if (ctob((UAREA_PAGES + KSTACK_PAGES) + 739a9148ab1SPeter Wemm vm->vm_dsize + vm->vm_ssize) >= limit) 740a9148ab1SPeter Wemm return (EFAULT); 741a9148ab1SPeter Wemm tempuser = malloc(ctob(UAREA_PAGES + KSTACK_PAGES), M_TEMP, 742a9148ab1SPeter Wemm M_WAITOK | M_ZERO); 743a9148ab1SPeter Wemm if (tempuser == NULL) 744a9148ab1SPeter Wemm return (ENOMEM); 745a9148ab1SPeter Wemm bcopy(p->p_uarea, tempuser, sizeof(struct user)); 746a9148ab1SPeter Wemm bcopy(td->td_frame, 747a9148ab1SPeter Wemm tempuser + ctob(UAREA_PAGES) + 748a9148ab1SPeter Wemm ((caddr_t) td->td_frame - (caddr_t) td->td_kstack), 749a9148ab1SPeter Wemm sizeof(struct trapframe)); 750a9148ab1SPeter Wemm PROC_LOCK(p); 751a9148ab1SPeter Wemm fill_kinfo_proc(p, &p->p_uarea->u_kproc); 752a9148ab1SPeter Wemm PROC_UNLOCK(p); 753a9148ab1SPeter Wemm error = vn_rdwr(UIO_WRITE, vp, (caddr_t) tempuser, 754a9148ab1SPeter Wemm ctob(UAREA_PAGES + KSTACK_PAGES), 755a9148ab1SPeter Wemm (off_t)0, UIO_SYSSPACE, IO_UNIT, cred, NOCRED, 756a9148ab1SPeter Wemm (int *)NULL, td); 757a9148ab1SPeter Wemm free(tempuser, M_TEMP); 758a9148ab1SPeter Wemm if (error == 0) 759a9148ab1SPeter Wemm error = vn_rdwr(UIO_WRITE, vp, vm->vm_daddr, 760a9148ab1SPeter Wemm (int)ctob(vm->vm_dsize), 761a9148ab1SPeter Wemm (off_t)ctob(UAREA_PAGES + KSTACK_PAGES), UIO_USERSPACE, 762a9148ab1SPeter Wemm IO_UNIT | IO_DIRECT, cred, NOCRED, (int *) NULL, td); 763a9148ab1SPeter Wemm if (error == 0) 764a9148ab1SPeter Wemm error = vn_rdwr_inchunks(UIO_WRITE, vp, 765a9148ab1SPeter Wemm (caddr_t) trunc_page(USRSTACK - ctob(vm->vm_ssize)), 766a9148ab1SPeter Wemm round_page(ctob(vm->vm_ssize)), 767a9148ab1SPeter Wemm (off_t)ctob(UAREA_PAGES + KSTACK_PAGES) + 768a9148ab1SPeter Wemm ctob(vm->vm_dsize), UIO_USERSPACE, 769a9148ab1SPeter Wemm IO_UNIT | IO_DIRECT, cred, NOCRED, (int *) NULL, td); 770a9148ab1SPeter Wemm return (error); 771a9148ab1SPeter Wemm } 772d323ddf3SMatthew Dillon /* 773d323ddf3SMatthew Dillon * If a linux binary is exec'ing something, try this image activator 774d323ddf3SMatthew Dillon * first. We override standard shell script execution in order to 775d323ddf3SMatthew Dillon * be able to modify the interpreter path. We only do this if a linux 776d323ddf3SMatthew Dillon * binary is doing the exec, so we do not create an EXEC module for it. 777d323ddf3SMatthew Dillon */ 77889c9a483SAlfred Perlstein static int exec_linux_imgact_try(struct image_params *iparams); 779d323ddf3SMatthew Dillon 780d323ddf3SMatthew Dillon static int 781d323ddf3SMatthew Dillon exec_linux_imgact_try(imgp) 782d323ddf3SMatthew Dillon struct image_params *imgp; 783d323ddf3SMatthew Dillon { 784d323ddf3SMatthew Dillon const char *head = (const char *)imgp->image_header; 785d323ddf3SMatthew Dillon int error = -1; 786d323ddf3SMatthew Dillon 787d323ddf3SMatthew Dillon /* 788d323ddf3SMatthew Dillon * The interpreter for shell scripts run from a linux binary needs 789d323ddf3SMatthew Dillon * to be located in /compat/linux if possible in order to recursively 790d323ddf3SMatthew Dillon * maintain linux path emulation. 791d323ddf3SMatthew Dillon */ 792d323ddf3SMatthew Dillon if (((const short *)head)[0] == SHELLMAGIC) { 793d323ddf3SMatthew Dillon /* 794d323ddf3SMatthew Dillon * Run our normal shell image activator. If it succeeds attempt 795d323ddf3SMatthew Dillon * to use the alternate path for the interpreter. If an alternate 796d323ddf3SMatthew Dillon * path is found, use our stringspace to store it. 797d323ddf3SMatthew Dillon */ 798d323ddf3SMatthew Dillon if ((error = exec_shell_imgact(imgp)) == 0) { 799d323ddf3SMatthew Dillon char *rpath = NULL; 800d323ddf3SMatthew Dillon 801079b7badSJulian Elischer linux_emul_find(FIRST_THREAD_IN_PROC(imgp->proc), NULL, 802d323ddf3SMatthew Dillon imgp->interpreter_name, &rpath, 0); 803d323ddf3SMatthew Dillon if (rpath != imgp->interpreter_name) { 804d323ddf3SMatthew Dillon int len = strlen(rpath) + 1; 805d323ddf3SMatthew Dillon 806d323ddf3SMatthew Dillon if (len <= MAXSHELLCMDLEN) { 807d323ddf3SMatthew Dillon memcpy(imgp->interpreter_name, rpath, len); 808d323ddf3SMatthew Dillon } 809d323ddf3SMatthew Dillon free(rpath, M_TEMP); 810d323ddf3SMatthew Dillon } 811d323ddf3SMatthew Dillon } 812d323ddf3SMatthew Dillon } 813d323ddf3SMatthew Dillon return(error); 814d323ddf3SMatthew Dillon } 815d323ddf3SMatthew Dillon 816d66a5066SPeter Wemm struct sysentvec linux_sysvec = { 817e1743d02SSøren Schmidt LINUX_SYS_MAXSYSCALL, 818d66a5066SPeter Wemm linux_sysent, 819d66a5066SPeter Wemm 0xff, 820956d3333SMarcel Moolenaar LINUX_SIGTBLSZ, 821d66a5066SPeter Wemm bsd_to_linux_signal, 82285f118c8SDmitrij Tejblum ELAST + 1, 823d66a5066SPeter Wemm bsd_to_linux_errno, 824288078beSEivind Eklund translate_traps, 825d66a5066SPeter Wemm linux_fixup, 826d66a5066SPeter Wemm linux_sendsig, 827d66a5066SPeter Wemm linux_sigcode, 828d66a5066SPeter Wemm &linux_szsigcode, 829d66a5066SPeter Wemm linux_prepsyscall, 83022d4b0fbSJohn Polstra "Linux a.out", 831a9148ab1SPeter Wemm linux_aout_coredump, 832806d7daaSMarcel Moolenaar exec_linux_imgact_try, 833f36ba452SJake Burkholder LINUX_MINSIGSTKSZ, 834f36ba452SJake Burkholder PAGE_SIZE, 835f36ba452SJake Burkholder VM_MIN_ADDRESS, 836f36ba452SJake Burkholder VM_MAXUSER_ADDRESS, 837f36ba452SJake Burkholder USRSTACK, 838f36ba452SJake Burkholder PS_STRINGS, 839f36ba452SJake Burkholder VM_PROT_ALL, 840f36ba452SJake Burkholder exec_copyout_strings, 841f36ba452SJake Burkholder exec_setregs 842d66a5066SPeter Wemm }; 843e1743d02SSøren Schmidt 844e1743d02SSøren Schmidt struct sysentvec elf_linux_sysvec = { 845e1743d02SSøren Schmidt LINUX_SYS_MAXSYSCALL, 846e1743d02SSøren Schmidt linux_sysent, 847e1743d02SSøren Schmidt 0xff, 848956d3333SMarcel Moolenaar LINUX_SIGTBLSZ, 849e1743d02SSøren Schmidt bsd_to_linux_signal, 85085f118c8SDmitrij Tejblum ELAST + 1, 851e1743d02SSøren Schmidt bsd_to_linux_errno, 852288078beSEivind Eklund translate_traps, 853e1743d02SSøren Schmidt elf_linux_fixup, 854e1743d02SSøren Schmidt linux_sendsig, 855e1743d02SSøren Schmidt linux_sigcode, 856e1743d02SSøren Schmidt &linux_szsigcode, 857e1743d02SSøren Schmidt linux_prepsyscall, 85822d4b0fbSJohn Polstra "Linux ELF", 8593ebc1248SPeter Wemm elf32_coredump, 860806d7daaSMarcel Moolenaar exec_linux_imgact_try, 861f36ba452SJake Burkholder LINUX_MINSIGSTKSZ, 862f36ba452SJake Burkholder PAGE_SIZE, 863f36ba452SJake Burkholder VM_MIN_ADDRESS, 864f36ba452SJake Burkholder VM_MAXUSER_ADDRESS, 865f36ba452SJake Burkholder USRSTACK, 866f36ba452SJake Burkholder PS_STRINGS, 867f36ba452SJake Burkholder VM_PROT_ALL, 868f36ba452SJake Burkholder exec_copyout_strings, 869f36ba452SJake Burkholder exec_setregs 870e1743d02SSøren Schmidt }; 871e1743d02SSøren Schmidt 872514058dcSAlexander Langer static Elf32_Brandinfo linux_brand = { 873c815a20cSDavid E. O'Brien ELFOSABI_LINUX, 8743ebc1248SPeter Wemm EM_386, 87521a3ee0eSDavid E. O'Brien "Linux", 876ea5a2b2eSSøren Schmidt "/compat/linux", 8775cf588ebSPeter Wemm "/lib/ld-linux.so.1", 878ea5a2b2eSSøren Schmidt &elf_linux_sysvec 8795cf588ebSPeter Wemm }; 8805cf588ebSPeter Wemm 881514058dcSAlexander Langer static Elf32_Brandinfo linux_glibc2brand = { 882c815a20cSDavid E. O'Brien ELFOSABI_LINUX, 8833ebc1248SPeter Wemm EM_386, 88421a3ee0eSDavid E. O'Brien "Linux", 8854e138a28SMike Smith "/compat/linux", 8864e138a28SMike Smith "/lib/ld-linux.so.2", 8874e138a28SMike Smith &elf_linux_sysvec 8884e138a28SMike Smith }; 8894e138a28SMike Smith 890514058dcSAlexander Langer Elf32_Brandinfo *linux_brandlist[] = { 891514058dcSAlexander Langer &linux_brand, 892514058dcSAlexander Langer &linux_glibc2brand, 893514058dcSAlexander Langer NULL 894514058dcSAlexander Langer }; 895514058dcSAlexander Langer 896aa855a59SPeter Wemm static int 897c25ded31SBruce Evans linux_elf_modevent(module_t mod, int type, void *data) 898d30ea4f5SPeter Wemm { 899514058dcSAlexander Langer Elf32_Brandinfo **brandinfo; 900514058dcSAlexander Langer int error; 901f41325dbSPeter Wemm struct linux_ioctl_handler **lihp; 902514058dcSAlexander Langer 903514058dcSAlexander Langer error = 0; 904514058dcSAlexander Langer 905aa855a59SPeter Wemm switch(type) { 906aa855a59SPeter Wemm case MOD_LOAD: 907aa855a59SPeter Wemm for (brandinfo = &linux_brandlist[0]; *brandinfo != NULL; 908aa855a59SPeter Wemm ++brandinfo) 9093ebc1248SPeter Wemm if (elf32_insert_brand_entry(*brandinfo) < 0) 910aa855a59SPeter Wemm error = EINVAL; 911466b14d7SMarcel Moolenaar if (error == 0) { 912f41325dbSPeter Wemm SET_FOREACH(lihp, linux_ioctl_handler_set) 913f41325dbSPeter Wemm linux_ioctl_register_handler(*lihp); 91443bef515SMarcel Moolenaar if (bootverbose) 915466b14d7SMarcel Moolenaar printf("Linux ELF exec handler installed\n"); 916466b14d7SMarcel Moolenaar } else 917466b14d7SMarcel Moolenaar printf("cannot insert Linux ELF brand handler\n"); 918aa855a59SPeter Wemm break; 919aa855a59SPeter Wemm case MOD_UNLOAD: 920aa855a59SPeter Wemm for (brandinfo = &linux_brandlist[0]; *brandinfo != NULL; 921aa855a59SPeter Wemm ++brandinfo) 9223ebc1248SPeter Wemm if (elf32_brand_inuse(*brandinfo)) 923d2758342SMark Newton error = EBUSY; 924d2758342SMark Newton if (error == 0) { 925d2758342SMark Newton for (brandinfo = &linux_brandlist[0]; 926d2758342SMark Newton *brandinfo != NULL; ++brandinfo) 9273ebc1248SPeter Wemm if (elf32_remove_brand_entry(*brandinfo) < 0) 928aa855a59SPeter Wemm error = EINVAL; 929d2758342SMark Newton } 930466b14d7SMarcel Moolenaar if (error == 0) { 931f41325dbSPeter Wemm SET_FOREACH(lihp, linux_ioctl_handler_set) 932f41325dbSPeter Wemm linux_ioctl_unregister_handler(*lihp); 933466b14d7SMarcel Moolenaar if (bootverbose) 934466b14d7SMarcel Moolenaar printf("Linux ELF exec handler removed\n"); 935466b14d7SMarcel Moolenaar } else 936aa855a59SPeter Wemm printf("Could not deinstall ELF interpreter entry\n"); 937aa855a59SPeter Wemm break; 938aa855a59SPeter Wemm default: 939aa855a59SPeter Wemm break; 940d30ea4f5SPeter Wemm } 941aa855a59SPeter Wemm return error; 942aa855a59SPeter Wemm } 943466b14d7SMarcel Moolenaar 944aa855a59SPeter Wemm static moduledata_t linux_elf_mod = { 945aa855a59SPeter Wemm "linuxelf", 946aa855a59SPeter Wemm linux_elf_modevent, 947aa855a59SPeter Wemm 0 948aa855a59SPeter Wemm }; 949466b14d7SMarcel Moolenaar 950aa855a59SPeter Wemm DECLARE_MODULE(linuxelf, linux_elf_mod, SI_SUB_EXEC, SI_ORDER_ANY); 951