1d66a5066SPeter Wemm /*- 20ba1b365SEd Maste * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 383ef78beSPedro F. Giffuni * 49a14aa01SUlrich Spörlein * Copyright (c) 1994-1996 Søren Schmidt 5d66a5066SPeter Wemm * All rights reserved. 6d66a5066SPeter Wemm * 7d66a5066SPeter Wemm * Redistribution and use in source and binary forms, with or without 8d66a5066SPeter Wemm * modification, are permitted provided that the following conditions 9d66a5066SPeter Wemm * are met: 10d66a5066SPeter Wemm * 1. Redistributions of source code must retain the above copyright 110ba1b365SEd Maste * notice, this list of conditions and the following disclaimer. 12d66a5066SPeter Wemm * 2. Redistributions in binary form must reproduce the above copyright 13d66a5066SPeter Wemm * notice, this list of conditions and the following disclaimer in the 14d66a5066SPeter Wemm * documentation and/or other materials provided with the distribution. 15d66a5066SPeter Wemm * 160ba1b365SEd Maste * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 170ba1b365SEd Maste * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 180ba1b365SEd Maste * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 190ba1b365SEd Maste * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 200ba1b365SEd Maste * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 210ba1b365SEd Maste * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 220ba1b365SEd Maste * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 230ba1b365SEd Maste * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 240ba1b365SEd Maste * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 250ba1b365SEd Maste * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 260ba1b365SEd Maste * 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> 3557b4252eSKonstantin Belousov #include <sys/fcntl.h> 36d66a5066SPeter Wemm #include <sys/imgact.h> 3722d4b0fbSJohn Polstra #include <sys/imgact_aout.h> 38e1743d02SSøren Schmidt #include <sys/imgact_elf.h> 39ff22c670SBruce Evans #include <sys/kernel.h> 407106ca0dSJohn Baldwin #include <sys/lock.h> 41e1743d02SSøren Schmidt #include <sys/malloc.h> 42ff22c670SBruce Evans #include <sys/module.h> 4323955314SAlfred Perlstein #include <sys/mutex.h> 44fb919e4dSMark Murray #include <sys/proc.h> 45fb919e4dSMark Murray #include <sys/signalvar.h> 46206a5d3aSIan Dowse #include <sys/syscallsubr.h> 4767d39748SDmitry Chagin #include <sys/sysctl.h> 48fb919e4dSMark Murray #include <sys/sysent.h> 49fb919e4dSMark Murray #include <sys/sysproto.h> 50a9148ab1SPeter Wemm #include <sys/vnode.h> 51fb919e4dSMark Murray 52d66a5066SPeter Wemm #include <vm/vm.h> 53a9148ab1SPeter Wemm #include <vm/pmap.h> 54ff22c670SBruce Evans #include <vm/vm_extern.h> 55a9148ab1SPeter Wemm #include <vm/vm_map.h> 56a9148ab1SPeter Wemm #include <vm/vm_object.h> 57ff22c670SBruce Evans #include <vm/vm_page.h> 58ff22c670SBruce Evans #include <vm/vm_param.h> 59ff22c670SBruce Evans 60ff22c670SBruce Evans #include <machine/cpu.h> 614d7c2e8aSDmitry Chagin #include <machine/cputypes.h> 62ff22c670SBruce Evans #include <machine/md_var.h> 63d3adf769SDavid Schultz #include <machine/pcb.h> 64d41e41f9SJohn Baldwin #include <machine/trap.h> 65a9148ab1SPeter Wemm 66d66a5066SPeter Wemm #include <i386/linux/linux.h> 67ebea8660SMarcel Moolenaar #include <i386/linux/linux_proto.h> 6894cb2ecfSAlexander Leidinger #include <compat/linux/linux_emul.h> 69d825ce0aSJohn Baldwin #include <compat/linux/linux_ioctl.h> 700f9d6538SJohn Baldwin #include <compat/linux/linux_mib.h> 714d7c2e8aSDmitry Chagin #include <compat/linux/linux_misc.h> 72b595ab37SAndrew Gallatin #include <compat/linux/linux_signal.h> 73322bfdc3SMarcel Moolenaar #include <compat/linux/linux_util.h> 74bdc37934SDmitry Chagin #include <compat/linux/linux_vdso.h> 75e1743d02SSøren Schmidt 761d91482dSPeter Wemm MODULE_VERSION(linux, 1); 771d91482dSPeter Wemm 788f1e49a6SDmitry Chagin #define LINUX_PS_STRINGS (LINUX_USRSTACK - sizeof(struct ps_strings)) 798f1e49a6SDmitry Chagin 80bdc37934SDmitry Chagin static int linux_szsigcode; 81bdc37934SDmitry Chagin static vm_object_t linux_shared_page_obj; 82bdc37934SDmitry Chagin static char *linux_shared_page_mapping; 83bdc37934SDmitry Chagin extern char _binary_linux_locore_o_start; 84bdc37934SDmitry Chagin extern char _binary_linux_locore_o_end; 8543bef515SMarcel Moolenaar 8643bef515SMarcel Moolenaar extern struct sysent linux_sysent[LINUX_SYS_MAXSYSCALL]; 8743bef515SMarcel Moolenaar 88f41325dbSPeter Wemm SET_DECLARE(linux_ioctl_handler_set, struct linux_ioctl_handler); 8943bef515SMarcel Moolenaar 9031174518SJohn Baldwin static int linux_fixup(uintptr_t *stack_base, 9189c9a483SAlfred Perlstein struct image_params *iparams); 9231174518SJohn Baldwin static int linux_fixup_elf(uintptr_t *stack_base, 9389c9a483SAlfred Perlstein struct image_params *iparams); 949104847fSDavid Xu static void linux_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask); 95dc858467SEd Maste static void linux_exec_setregs(struct thread *td, 9631174518SJohn Baldwin struct image_params *imgp, uintptr_t stack); 97*5fd9cd53SDmitry Chagin static int linux_on_exec_vmspace(struct proc *p, 98*5fd9cd53SDmitry Chagin struct image_params *imgp); 9903b0d68cSJohn Baldwin static int linux_copyout_strings(struct image_params *imgp, 10031174518SJohn Baldwin uintptr_t *stack_base); 101a95659f7SEd Maste static bool linux_trans_osrel(const Elf_Note *note, int32_t *osrel); 102bdc37934SDmitry Chagin static void linux_vdso_install(void *param); 103bdc37934SDmitry Chagin static void linux_vdso_deinstall(void *param); 1044d7c2e8aSDmitry Chagin 10527a828fcSPierre Beyssac #define LINUX_T_UNKNOWN 255 10627a828fcSPierre Beyssac static int _bsd_to_linux_trapcode[] = { 10727a828fcSPierre Beyssac LINUX_T_UNKNOWN, /* 0 */ 10827a828fcSPierre Beyssac 6, /* 1 T_PRIVINFLT */ 10927a828fcSPierre Beyssac LINUX_T_UNKNOWN, /* 2 */ 11027a828fcSPierre Beyssac 3, /* 3 T_BPTFLT */ 11127a828fcSPierre Beyssac LINUX_T_UNKNOWN, /* 4 */ 11227a828fcSPierre Beyssac LINUX_T_UNKNOWN, /* 5 */ 11327a828fcSPierre Beyssac 16, /* 6 T_ARITHTRAP */ 11427a828fcSPierre Beyssac 254, /* 7 T_ASTFLT */ 11527a828fcSPierre Beyssac LINUX_T_UNKNOWN, /* 8 */ 11627a828fcSPierre Beyssac 13, /* 9 T_PROTFLT */ 11727a828fcSPierre Beyssac 1, /* 10 T_TRCTRAP */ 11827a828fcSPierre Beyssac LINUX_T_UNKNOWN, /* 11 */ 11927a828fcSPierre Beyssac 14, /* 12 T_PAGEFLT */ 12027a828fcSPierre Beyssac LINUX_T_UNKNOWN, /* 13 */ 12127a828fcSPierre Beyssac 17, /* 14 T_ALIGNFLT */ 12227a828fcSPierre Beyssac LINUX_T_UNKNOWN, /* 15 */ 12327a828fcSPierre Beyssac LINUX_T_UNKNOWN, /* 16 */ 12427a828fcSPierre Beyssac LINUX_T_UNKNOWN, /* 17 */ 12527a828fcSPierre Beyssac 0, /* 18 T_DIVIDE */ 12627a828fcSPierre Beyssac 2, /* 19 T_NMI */ 12727a828fcSPierre Beyssac 4, /* 20 T_OFLOW */ 12827a828fcSPierre Beyssac 5, /* 21 T_BOUND */ 12927a828fcSPierre Beyssac 7, /* 22 T_DNA */ 13027a828fcSPierre Beyssac 8, /* 23 T_DOUBLEFLT */ 13127a828fcSPierre Beyssac 9, /* 24 T_FPOPFLT */ 13227a828fcSPierre Beyssac 10, /* 25 T_TSSFLT */ 13327a828fcSPierre Beyssac 11, /* 26 T_SEGNPFLT */ 13427a828fcSPierre Beyssac 12, /* 27 T_STKFLT */ 13527a828fcSPierre Beyssac 18, /* 28 T_MCHK */ 13627a828fcSPierre Beyssac 19, /* 29 T_XMMFLT */ 13727a828fcSPierre Beyssac 15 /* 30 T_RESERVED */ 13827a828fcSPierre Beyssac }; 13927a828fcSPierre Beyssac #define bsd_to_linux_trapcode(code) \ 140ea24b056SPedro F. Giffuni ((code)<nitems(_bsd_to_linux_trapcode)? \ 14127a828fcSPierre Beyssac _bsd_to_linux_trapcode[(code)]: \ 14227a828fcSPierre Beyssac LINUX_T_UNKNOWN) 14327a828fcSPierre Beyssac 144c1da89feSDmitry Chagin LINUX_VDSO_SYM_CHAR(linux_platform); 145bdc37934SDmitry Chagin LINUX_VDSO_SYM_INTPTR(linux_sigcode); 146bdc37934SDmitry Chagin LINUX_VDSO_SYM_INTPTR(linux_rt_sigcode); 147bdc37934SDmitry Chagin LINUX_VDSO_SYM_INTPTR(linux_vsyscall); 148bdc37934SDmitry Chagin 149288078beSEivind Eklund /* 150288078beSEivind Eklund * If FreeBSD & Linux have a difference of opinion about what a trap 151288078beSEivind Eklund * means, deal with it here. 152356861dbSMatthew Dillon * 153356861dbSMatthew Dillon * MPSAFE 154288078beSEivind Eklund */ 155288078beSEivind Eklund static int 156dc858467SEd Maste linux_translate_traps(int signal, int trap_code) 157288078beSEivind Eklund { 158d563a53aSEivind Eklund if (signal != SIGBUS) 159af682d48SDmitry Chagin return (signal); 160288078beSEivind Eklund switch (trap_code) { 161288078beSEivind Eklund case T_PROTFLT: 162288078beSEivind Eklund case T_TSSFLT: 163288078beSEivind Eklund case T_DOUBLEFLT: 164288078beSEivind Eklund case T_PAGEFLT: 165af682d48SDmitry Chagin return (SIGSEGV); 166288078beSEivind Eklund default: 167af682d48SDmitry Chagin return (signal); 168288078beSEivind Eklund } 169288078beSEivind Eklund } 170288078beSEivind Eklund 171303b270bSEivind Eklund static int 17231174518SJohn Baldwin linux_fixup(uintptr_t *stack_base, struct image_params *imgp) 173d66a5066SPeter Wemm { 17431174518SJohn Baldwin register_t *base, *argv, *envp; 175d66a5066SPeter Wemm 17631174518SJohn Baldwin base = (register_t *)*stack_base; 17731174518SJohn Baldwin argv = base; 17831174518SJohn Baldwin envp = base + (imgp->args->argc + 1); 17931174518SJohn Baldwin base--; 18031174518SJohn Baldwin suword(base, (intptr_t)envp); 18131174518SJohn Baldwin base--; 18231174518SJohn Baldwin suword(base, (intptr_t)argv); 18331174518SJohn Baldwin base--; 18431174518SJohn Baldwin suword(base, imgp->args->argc); 18531174518SJohn Baldwin *stack_base = (uintptr_t)base; 1864d7c2e8aSDmitry Chagin return (0); 187d66a5066SPeter Wemm } 188d66a5066SPeter Wemm 18903b0d68cSJohn Baldwin static int 190d8010b11SJohn Baldwin linux_copyout_auxargs(struct image_params *imgp, uintptr_t base) 191e1743d02SSøren Schmidt { 1924d7c2e8aSDmitry Chagin struct proc *p; 19343cf129cSJohn Baldwin Elf32_Auxargs *args; 1945f77b8a8SBrooks Davis Elf32_Auxinfo *argarray, *pos; 1954d7c2e8aSDmitry Chagin struct ps_strings *arginfo; 19603b0d68cSJohn Baldwin int error, issetugid; 1974d7c2e8aSDmitry Chagin 1984d7c2e8aSDmitry Chagin p = imgp->proc; 199669414e4SXin LI issetugid = imgp->proc->p_flag & P_SUGID ? 1 : 0; 2004d7c2e8aSDmitry Chagin arginfo = (struct ps_strings *)p->p_sysent->sv_psstrings; 20143cf129cSJohn Baldwin args = (Elf32_Auxargs *)imgp->auxargs; 2025f77b8a8SBrooks Davis argarray = pos = malloc(LINUX_AT_COUNT * sizeof(*pos), M_TEMP, 2035f77b8a8SBrooks Davis M_WAITOK | M_ZERO); 204e1743d02SSøren Schmidt 205bdc37934SDmitry Chagin AUXARGS_ENTRY(pos, LINUX_AT_SYSINFO_EHDR, 206bdc37934SDmitry Chagin imgp->proc->p_sysent->sv_shared_page_base); 207bdc37934SDmitry Chagin AUXARGS_ENTRY(pos, LINUX_AT_SYSINFO, linux_vsyscall); 2084d7c2e8aSDmitry Chagin AUXARGS_ENTRY(pos, LINUX_AT_HWCAP, cpu_feature); 2098d30f381SDmitry Chagin 2108d30f381SDmitry Chagin /* 2118d30f381SDmitry Chagin * Do not export AT_CLKTCK when emulating Linux kernel prior to 2.4.0, 2128d30f381SDmitry Chagin * as it has appeared in the 2.4.0-rc7 first time. 2138d30f381SDmitry Chagin * Being exported, AT_CLKTCK is returned by sysconf(_SC_CLK_TCK), 2148d30f381SDmitry Chagin * glibc falls back to the hard-coded CLK_TCK value when aux entry 2158d30f381SDmitry Chagin * is not present. 2168d30f381SDmitry Chagin * Also see linux_times() implementation. 2178d30f381SDmitry Chagin */ 2188d30f381SDmitry Chagin if (linux_kernver(curthread) >= LINUX_KERNVER_2004000) 2191ca16454SDmitry Chagin AUXARGS_ENTRY(pos, LINUX_AT_CLKTCK, stclohz); 220e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_PHDR, args->phdr); 221e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_PHENT, args->phent); 222e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_PHNUM, args->phnum); 223e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_PAGESZ, args->pagesz); 224e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_FLAGS, args->flags); 225e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_ENTRY, args->entry); 226e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_BASE, args->base); 227669414e4SXin LI AUXARGS_ENTRY(pos, LINUX_AT_SECURE, issetugid); 228b1fc0ec1SRobert Watson AUXARGS_ENTRY(pos, AT_UID, imgp->proc->p_ucred->cr_ruid); 229b1fc0ec1SRobert Watson AUXARGS_ENTRY(pos, AT_EUID, imgp->proc->p_ucred->cr_svuid); 230b1fc0ec1SRobert Watson AUXARGS_ENTRY(pos, AT_GID, imgp->proc->p_ucred->cr_rgid); 231b1fc0ec1SRobert Watson AUXARGS_ENTRY(pos, AT_EGID, imgp->proc->p_ucred->cr_svgid); 232c1da89feSDmitry Chagin AUXARGS_ENTRY(pos, LINUX_AT_PLATFORM, PTROUT(linux_platform)); 233b24e6ac8SBrooks Davis AUXARGS_ENTRY_PTR(pos, LINUX_AT_RANDOM, imgp->canary); 2344048f59cSDmitry Chagin if (imgp->execpathp != 0) 235b24e6ac8SBrooks Davis AUXARGS_ENTRY_PTR(pos, LINUX_AT_EXECFN, imgp->execpathp); 2364d7c2e8aSDmitry Chagin if (args->execfd != -1) 2374d7c2e8aSDmitry Chagin AUXARGS_ENTRY(pos, AT_EXECFD, args->execfd); 238e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_NULL, 0); 239e1743d02SSøren Schmidt 240e1743d02SSøren Schmidt free(imgp->auxargs, M_TEMP); 241e1743d02SSøren Schmidt imgp->auxargs = NULL; 242cbf7e0cbSBrooks Davis KASSERT(pos - argarray <= LINUX_AT_COUNT, ("Too many auxargs")); 2435f77b8a8SBrooks Davis 244d8010b11SJohn Baldwin error = copyout(argarray, (void *)base, 245d8010b11SJohn Baldwin sizeof(*argarray) * LINUX_AT_COUNT); 2465f77b8a8SBrooks Davis free(argarray, M_TEMP); 24703b0d68cSJohn Baldwin return (error); 2485caa67faSJohn Baldwin } 2495caa67faSJohn Baldwin 2505caa67faSJohn Baldwin static int 25131174518SJohn Baldwin linux_fixup_elf(uintptr_t *stack_base, struct image_params *imgp) 2525caa67faSJohn Baldwin { 25331174518SJohn Baldwin register_t *base; 254e1743d02SSøren Schmidt 25531174518SJohn Baldwin base = (register_t *)*stack_base; 25631174518SJohn Baldwin base--; 25731174518SJohn Baldwin if (suword(base, (register_t)imgp->args->argc) == -1) 2585f77b8a8SBrooks Davis return (EFAULT); 25931174518SJohn Baldwin *stack_base = (uintptr_t)base; 2604d7c2e8aSDmitry Chagin return (0); 261e1743d02SSøren Schmidt } 262d66a5066SPeter Wemm 2634d7c2e8aSDmitry Chagin /* 2644d7c2e8aSDmitry Chagin * Copied from kern/kern_exec.c 2654d7c2e8aSDmitry Chagin */ 26603b0d68cSJohn Baldwin static int 26731174518SJohn Baldwin linux_copyout_strings(struct image_params *imgp, uintptr_t *stack_base) 2684d7c2e8aSDmitry Chagin { 26903b0d68cSJohn Baldwin int argc, envc, error; 2704d7c2e8aSDmitry Chagin char **vectp; 27131174518SJohn Baldwin char *stringp; 27231174518SJohn Baldwin uintptr_t destp, ustringp; 2734d7c2e8aSDmitry Chagin struct ps_strings *arginfo; 2744048f59cSDmitry Chagin char canary[LINUX_AT_RANDOM_LEN]; 2754048f59cSDmitry Chagin size_t execpath_len; 2764d7c2e8aSDmitry Chagin struct proc *p; 2774d7c2e8aSDmitry Chagin 2784ba25759SEd Maste /* Calculate string base and vector table pointers. */ 2794d7c2e8aSDmitry Chagin p = imgp->proc; 2804048f59cSDmitry Chagin if (imgp->execpath != NULL && imgp->auxargs != NULL) 2814048f59cSDmitry Chagin execpath_len = strlen(imgp->execpath) + 1; 2824048f59cSDmitry Chagin else 2834048f59cSDmitry Chagin execpath_len = 0; 2844d7c2e8aSDmitry Chagin arginfo = (struct ps_strings *)p->p_sysent->sv_psstrings; 28531174518SJohn Baldwin destp = (uintptr_t)arginfo; 2864d7c2e8aSDmitry Chagin 2874048f59cSDmitry Chagin if (execpath_len != 0) { 28831174518SJohn Baldwin destp -= execpath_len; 28931174518SJohn Baldwin destp = rounddown2(destp, sizeof(void *)); 290b24e6ac8SBrooks Davis imgp->execpathp = (void *)destp; 291b24e6ac8SBrooks Davis error = copyout(imgp->execpath, imgp->execpathp, execpath_len); 29203b0d68cSJohn Baldwin if (error != 0) 29303b0d68cSJohn Baldwin return (error); 2944048f59cSDmitry Chagin } 2954048f59cSDmitry Chagin 2964ba25759SEd Maste /* Prepare the canary for SSP. */ 2974048f59cSDmitry Chagin arc4rand(canary, sizeof(canary), 0); 29831174518SJohn Baldwin destp -= roundup(sizeof(canary), sizeof(void *)); 299b24e6ac8SBrooks Davis imgp->canary = (void *)destp; 300b24e6ac8SBrooks Davis error = copyout(canary, imgp->canary, sizeof(canary)); 30103b0d68cSJohn Baldwin if (error != 0) 30203b0d68cSJohn Baldwin return (error); 3034048f59cSDmitry Chagin 30431174518SJohn Baldwin /* Allocate room for the argument and environment strings. */ 30531174518SJohn Baldwin destp -= ARG_MAX - imgp->args->stringspace; 30631174518SJohn Baldwin destp = rounddown2(destp, sizeof(void *)); 30731174518SJohn Baldwin ustringp = destp; 30831174518SJohn Baldwin 30903b0d68cSJohn Baldwin if (imgp->auxargs) { 310d8010b11SJohn Baldwin /* 311d8010b11SJohn Baldwin * Allocate room on the stack for the ELF auxargs 312d8010b11SJohn Baldwin * array. It has LINUX_AT_COUNT entries. 313d8010b11SJohn Baldwin */ 314d8010b11SJohn Baldwin destp -= LINUX_AT_COUNT * sizeof(Elf32_Auxinfo); 315d8010b11SJohn Baldwin destp = rounddown2(destp, sizeof(void *)); 31603b0d68cSJohn Baldwin } 3174d7c2e8aSDmitry Chagin 31831174518SJohn Baldwin vectp = (char **)destp; 31931174518SJohn Baldwin 32073c8686eSJohn Baldwin /* 32173c8686eSJohn Baldwin * Allocate room for the argv[] and env vectors including the 32273c8686eSJohn Baldwin * terminating NULL pointers. 32373c8686eSJohn Baldwin */ 32473c8686eSJohn Baldwin vectp -= imgp->args->argc + 1 + imgp->args->envc + 1; 32573c8686eSJohn Baldwin 3264ba25759SEd Maste /* vectp also becomes our initial stack base. */ 32731174518SJohn Baldwin *stack_base = (uintptr_t)vectp; 3284d7c2e8aSDmitry Chagin 3294d7c2e8aSDmitry Chagin stringp = imgp->args->begin_argv; 3304d7c2e8aSDmitry Chagin argc = imgp->args->argc; 3314d7c2e8aSDmitry Chagin envc = imgp->args->envc; 3324d7c2e8aSDmitry Chagin 3334ba25759SEd Maste /* Copy out strings - arguments and environment. */ 33431174518SJohn Baldwin error = copyout(stringp, (void *)ustringp, 33531174518SJohn Baldwin ARG_MAX - imgp->args->stringspace); 33603b0d68cSJohn Baldwin if (error != 0) 33703b0d68cSJohn Baldwin return (error); 3384d7c2e8aSDmitry Chagin 3394ba25759SEd Maste /* Fill in "ps_strings" struct for ps, w, etc. */ 34003b0d68cSJohn Baldwin if (suword(&arginfo->ps_argvstr, (long)(intptr_t)vectp) != 0 || 34103b0d68cSJohn Baldwin suword(&arginfo->ps_nargvstr, argc) != 0) 34203b0d68cSJohn Baldwin return (EFAULT); 3434d7c2e8aSDmitry Chagin 3444ba25759SEd Maste /* Fill in argument portion of vector table. */ 3454d7c2e8aSDmitry Chagin for (; argc > 0; --argc) { 34631174518SJohn Baldwin if (suword(vectp++, ustringp) != 0) 34703b0d68cSJohn Baldwin return (EFAULT); 3484d7c2e8aSDmitry Chagin while (*stringp++ != 0) 34931174518SJohn Baldwin ustringp++; 35031174518SJohn Baldwin ustringp++; 3514d7c2e8aSDmitry Chagin } 3524d7c2e8aSDmitry Chagin 3534ba25759SEd Maste /* A null vector table pointer separates the argp's from the envp's. */ 35403b0d68cSJohn Baldwin if (suword(vectp++, 0) != 0) 35503b0d68cSJohn Baldwin return (EFAULT); 3564d7c2e8aSDmitry Chagin 35703b0d68cSJohn Baldwin if (suword(&arginfo->ps_envstr, (long)(intptr_t)vectp) != 0 || 35803b0d68cSJohn Baldwin suword(&arginfo->ps_nenvstr, envc) != 0) 35903b0d68cSJohn Baldwin return (EFAULT); 3604d7c2e8aSDmitry Chagin 3614ba25759SEd Maste /* Fill in environment portion of vector table. */ 3624d7c2e8aSDmitry Chagin for (; envc > 0; --envc) { 36331174518SJohn Baldwin if (suword(vectp++, ustringp) != 0) 36403b0d68cSJohn Baldwin return (EFAULT); 3654d7c2e8aSDmitry Chagin while (*stringp++ != 0) 36631174518SJohn Baldwin ustringp++; 36731174518SJohn Baldwin ustringp++; 3684d7c2e8aSDmitry Chagin } 3694d7c2e8aSDmitry Chagin 3704ba25759SEd Maste /* The end of the vector table is a null pointer. */ 37103b0d68cSJohn Baldwin if (suword(vectp, 0) != 0) 37203b0d68cSJohn Baldwin return (EFAULT); 3734d7c2e8aSDmitry Chagin 374d8010b11SJohn Baldwin if (imgp->auxargs) { 375d8010b11SJohn Baldwin vectp++; 376d8010b11SJohn Baldwin error = imgp->sysent->sv_copyout_auxargs(imgp, 377d8010b11SJohn Baldwin (uintptr_t)vectp); 378d8010b11SJohn Baldwin if (error != 0) 379d8010b11SJohn Baldwin return (error); 380d8010b11SJohn Baldwin } 381d8010b11SJohn Baldwin 38203b0d68cSJohn Baldwin return (0); 3834d7c2e8aSDmitry Chagin } 3844d7c2e8aSDmitry Chagin 38579363394SAndrew Gallatin static void 3869104847fSDavid Xu linux_rt_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) 38779363394SAndrew Gallatin { 3881d062e2bSDag-Erling Smørgrav struct thread *td = curthread; 3891d062e2bSDag-Erling Smørgrav struct proc *p = td->td_proc; 39090af4afaSJohn Baldwin struct sigacts *psp; 3911d062e2bSDag-Erling Smørgrav struct trapframe *regs; 3925002a60fSMarcel Moolenaar struct l_rt_sigframe *fp, frame; 3939104847fSDavid Xu int sig, code; 39479363394SAndrew Gallatin int oonstack; 39579363394SAndrew Gallatin 3969104847fSDavid Xu sig = ksi->ksi_signo; 3979104847fSDavid Xu code = ksi->ksi_code; 398df53e91cSJohn Baldwin PROC_LOCK_ASSERT(p, MA_OWNED); 39990af4afaSJohn Baldwin psp = p->p_sigacts; 40090af4afaSJohn Baldwin mtx_assert(&psp->ps_mtx, MA_OWNED); 401b40ce416SJulian Elischer regs = td->td_frame; 402d034d459SMarcel Moolenaar oonstack = sigonstack(regs->tf_esp); 40379363394SAndrew Gallatin 4044ba25759SEd Maste /* Allocate space for the signal handler context. */ 405a30ec4b9SDavid Xu if ((td->td_pflags & TDP_ALTSTACK) && !oonstack && 40690af4afaSJohn Baldwin SIGISMEMBER(psp->ps_sigonstack, sig)) { 407aa949be5SJohn Baldwin fp = (struct l_rt_sigframe *)((uintptr_t)td->td_sigstk.ss_sp + 408a30ec4b9SDavid Xu td->td_sigstk.ss_size - sizeof(struct l_rt_sigframe)); 409d034d459SMarcel Moolenaar } else 4105002a60fSMarcel Moolenaar fp = (struct l_rt_sigframe *)regs->tf_esp - 1; 41190af4afaSJohn Baldwin mtx_unlock(&psp->ps_mtx); 41279363394SAndrew Gallatin 4134ba25759SEd Maste /* Build the argument list for the signal handler. */ 4144ab7403bSDmitry Chagin sig = bsd_to_linux_signal(sig); 41579363394SAndrew Gallatin 41699d45c5fSMarcel Moolenaar bzero(&frame, sizeof(frame)); 41799d45c5fSMarcel Moolenaar 41879363394SAndrew Gallatin frame.sf_handler = catcher; 41979363394SAndrew Gallatin frame.sf_sig = sig; 42079363394SAndrew Gallatin frame.sf_siginfo = &fp->sf_si; 42179363394SAndrew Gallatin frame.sf_ucontext = &fp->sf_sc; 422cc6ca9b3SMarcel Moolenaar 4234ba25759SEd Maste /* Fill in POSIX parts. */ 424f4e80108SDmitry Chagin siginfo_to_lsiginfo(&ksi->ksi_info, &frame.sf_si, sig); 425cc6ca9b3SMarcel Moolenaar 4264ba25759SEd Maste /* Build the signal context to be used by sigreturn. */ 427cc6ca9b3SMarcel Moolenaar frame.sf_sc.uc_flags = 0; /* XXX ??? */ 428cc6ca9b3SMarcel Moolenaar frame.sf_sc.uc_link = NULL; /* XXX ??? */ 429cc6ca9b3SMarcel Moolenaar 430a30ec4b9SDavid Xu frame.sf_sc.uc_stack.ss_sp = td->td_sigstk.ss_sp; 431a30ec4b9SDavid Xu frame.sf_sc.uc_stack.ss_size = td->td_sigstk.ss_size; 432a30ec4b9SDavid Xu frame.sf_sc.uc_stack.ss_flags = (td->td_pflags & TDP_ALTSTACK) 433d034d459SMarcel Moolenaar ? ((oonstack) ? LINUX_SS_ONSTACK : 0) : LINUX_SS_DISABLE; 434611d9407SJohn Baldwin PROC_UNLOCK(p); 435cc6ca9b3SMarcel Moolenaar 436cc6ca9b3SMarcel Moolenaar bsd_to_linux_sigset(mask, &frame.sf_sc.uc_sigmask); 437cc6ca9b3SMarcel Moolenaar 4384ab7403bSDmitry Chagin frame.sf_sc.uc_mcontext.sc_mask = frame.sf_sc.uc_sigmask.__mask; 43979363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_gs = rgs(); 44079363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_fs = regs->tf_fs; 44179363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_es = regs->tf_es; 44279363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_ds = regs->tf_ds; 44379363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_edi = regs->tf_edi; 44479363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_esi = regs->tf_esi; 44579363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_ebp = regs->tf_ebp; 44679363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_ebx = regs->tf_ebx; 447bdc37934SDmitry Chagin frame.sf_sc.uc_mcontext.sc_esp = regs->tf_esp; 44879363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_edx = regs->tf_edx; 44979363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_ecx = regs->tf_ecx; 45079363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_eax = regs->tf_eax; 45179363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_eip = regs->tf_eip; 45279363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_cs = regs->tf_cs; 45379363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_eflags = regs->tf_eflags; 45479363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_esp_at_signal = regs->tf_esp; 45579363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_ss = regs->tf_ss; 45679363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_err = regs->tf_err; 45796a2b635SKonstantin Belousov frame.sf_sc.uc_mcontext.sc_cr2 = (register_t)ksi->ksi_addr; 45827a828fcSPierre Beyssac frame.sf_sc.uc_mcontext.sc_trapno = bsd_to_linux_trapcode(code); 45979363394SAndrew Gallatin 46079363394SAndrew Gallatin if (copyout(&frame, fp, sizeof(frame)) != 0) { 46179363394SAndrew Gallatin /* 46279363394SAndrew Gallatin * Process has trashed its stack; give it an illegal 46379363394SAndrew Gallatin * instruction to halt it in its tracks. 46479363394SAndrew Gallatin */ 46519eb87d2SJohn Baldwin PROC_LOCK(p); 466b40ce416SJulian Elischer sigexit(td, SIGILL); 46779363394SAndrew Gallatin } 46879363394SAndrew Gallatin 4694ba25759SEd Maste /* Build context to run handler in. */ 47079363394SAndrew Gallatin regs->tf_esp = (int)fp; 471bdc37934SDmitry Chagin regs->tf_eip = linux_rt_sigcode; 47222eca0bfSKonstantin Belousov regs->tf_eflags &= ~(PSL_T | PSL_VM | PSL_D); 47379363394SAndrew Gallatin regs->tf_cs = _ucodesel; 47479363394SAndrew Gallatin regs->tf_ds = _udatasel; 47579363394SAndrew Gallatin regs->tf_es = _udatasel; 47679363394SAndrew Gallatin regs->tf_fs = _udatasel; 47779363394SAndrew Gallatin regs->tf_ss = _udatasel; 478df53e91cSJohn Baldwin PROC_LOCK(p); 47990af4afaSJohn Baldwin mtx_lock(&psp->ps_mtx); 48079363394SAndrew Gallatin } 48179363394SAndrew Gallatin 482d66a5066SPeter Wemm /* 483d66a5066SPeter Wemm * Send an interrupt to process. 484d66a5066SPeter Wemm * 485d66a5066SPeter Wemm * Stack is set up to allow sigcode stored 486d66a5066SPeter Wemm * in u. to call routine, followed by kcall 487d66a5066SPeter Wemm * to sigreturn routine below. After sigreturn 488d66a5066SPeter Wemm * resets the signal mask, the stack, and the 489d66a5066SPeter Wemm * frame pointer, it returns to the user 490d66a5066SPeter Wemm * specified pc, psl. 491d66a5066SPeter Wemm */ 492303b270bSEivind Eklund static void 4939104847fSDavid Xu linux_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) 494d66a5066SPeter Wemm { 4951d062e2bSDag-Erling Smørgrav struct thread *td = curthread; 4961d062e2bSDag-Erling Smørgrav struct proc *p = td->td_proc; 49790af4afaSJohn Baldwin struct sigacts *psp; 4981d062e2bSDag-Erling Smørgrav struct trapframe *regs; 4995002a60fSMarcel Moolenaar struct l_sigframe *fp, frame; 5005002a60fSMarcel Moolenaar l_sigset_t lmask; 5019104847fSDavid Xu int sig, code; 5024ab7403bSDmitry Chagin int oonstack; 503d66a5066SPeter Wemm 5042509e6c2SJohn Baldwin PROC_LOCK_ASSERT(p, MA_OWNED); 50590af4afaSJohn Baldwin psp = p->p_sigacts; 5069104847fSDavid Xu sig = ksi->ksi_signo; 5079104847fSDavid Xu code = ksi->ksi_code; 50890af4afaSJohn Baldwin mtx_assert(&psp->ps_mtx, MA_OWNED); 50990af4afaSJohn Baldwin if (SIGISMEMBER(psp->ps_siginfo, sig)) { 510cc6ca9b3SMarcel Moolenaar /* Signal handler installed with SA_SIGINFO. */ 5119104847fSDavid Xu linux_rt_sendsig(catcher, ksi, mask); 512cc6ca9b3SMarcel Moolenaar return; 513cc6ca9b3SMarcel Moolenaar } 514b40ce416SJulian Elischer regs = td->td_frame; 515d034d459SMarcel Moolenaar oonstack = sigonstack(regs->tf_esp); 516d66a5066SPeter Wemm 5174ba25759SEd Maste /* Allocate space for the signal handler context. */ 518a30ec4b9SDavid Xu if ((td->td_pflags & TDP_ALTSTACK) && !oonstack && 51990af4afaSJohn Baldwin SIGISMEMBER(psp->ps_sigonstack, sig)) { 520aa949be5SJohn Baldwin fp = (struct l_sigframe *)((uintptr_t)td->td_sigstk.ss_sp + 521a30ec4b9SDavid Xu td->td_sigstk.ss_size - sizeof(struct l_sigframe)); 522d034d459SMarcel Moolenaar } else 5235002a60fSMarcel Moolenaar fp = (struct l_sigframe *)regs->tf_esp - 1; 52490af4afaSJohn Baldwin mtx_unlock(&psp->ps_mtx); 525611d9407SJohn Baldwin PROC_UNLOCK(p); 526d66a5066SPeter Wemm 5274ba25759SEd Maste /* Build the argument list for the signal handler. */ 5284ab7403bSDmitry Chagin sig = bsd_to_linux_signal(sig); 529d66a5066SPeter Wemm 53099d45c5fSMarcel Moolenaar bzero(&frame, sizeof(frame)); 53199d45c5fSMarcel Moolenaar 532d66a5066SPeter Wemm frame.sf_handler = catcher; 533d66a5066SPeter Wemm frame.sf_sig = sig; 534d66a5066SPeter Wemm 535cc6ca9b3SMarcel Moolenaar bsd_to_linux_sigset(mask, &lmask); 536cc6ca9b3SMarcel Moolenaar 5374ba25759SEd Maste /* Build the signal context to be used by sigreturn. */ 5384ab7403bSDmitry Chagin frame.sf_sc.sc_mask = lmask.__mask; 5395206bca1SLuoqi Chen frame.sf_sc.sc_gs = rgs(); 5405206bca1SLuoqi Chen frame.sf_sc.sc_fs = regs->tf_fs; 541213fdd80SPeter Wemm frame.sf_sc.sc_es = regs->tf_es; 542213fdd80SPeter Wemm frame.sf_sc.sc_ds = regs->tf_ds; 543213fdd80SPeter Wemm frame.sf_sc.sc_edi = regs->tf_edi; 544213fdd80SPeter Wemm frame.sf_sc.sc_esi = regs->tf_esi; 545213fdd80SPeter Wemm frame.sf_sc.sc_ebp = regs->tf_ebp; 546213fdd80SPeter Wemm frame.sf_sc.sc_ebx = regs->tf_ebx; 547bdc37934SDmitry Chagin frame.sf_sc.sc_esp = regs->tf_esp; 548213fdd80SPeter Wemm frame.sf_sc.sc_edx = regs->tf_edx; 549213fdd80SPeter Wemm frame.sf_sc.sc_ecx = regs->tf_ecx; 550213fdd80SPeter Wemm frame.sf_sc.sc_eax = regs->tf_eax; 551213fdd80SPeter Wemm frame.sf_sc.sc_eip = regs->tf_eip; 552213fdd80SPeter Wemm frame.sf_sc.sc_cs = regs->tf_cs; 553213fdd80SPeter Wemm frame.sf_sc.sc_eflags = regs->tf_eflags; 554213fdd80SPeter Wemm frame.sf_sc.sc_esp_at_signal = regs->tf_esp; 555213fdd80SPeter Wemm frame.sf_sc.sc_ss = regs->tf_ss; 556213fdd80SPeter Wemm frame.sf_sc.sc_err = regs->tf_err; 55796a2b635SKonstantin Belousov frame.sf_sc.sc_cr2 = (register_t)ksi->ksi_addr; 5589104847fSDavid Xu frame.sf_sc.sc_trapno = bsd_to_linux_trapcode(ksi->ksi_trapno); 559cc6ca9b3SMarcel Moolenaar 5604ab7403bSDmitry Chagin frame.sf_extramask[0] = lmask.__mask; 561d66a5066SPeter Wemm 562d66a5066SPeter Wemm if (copyout(&frame, fp, sizeof(frame)) != 0) { 563d66a5066SPeter Wemm /* 564d66a5066SPeter Wemm * Process has trashed its stack; give it an illegal 565d66a5066SPeter Wemm * instruction to halt it in its tracks. 566d66a5066SPeter Wemm */ 56719eb87d2SJohn Baldwin PROC_LOCK(p); 568b40ce416SJulian Elischer sigexit(td, SIGILL); 569d66a5066SPeter Wemm } 570d66a5066SPeter Wemm 5714ba25759SEd Maste /* Build context to run handler in. */ 572213fdd80SPeter Wemm regs->tf_esp = (int)fp; 573bdc37934SDmitry Chagin regs->tf_eip = linux_sigcode; 57422eca0bfSKonstantin Belousov regs->tf_eflags &= ~(PSL_T | PSL_VM | PSL_D); 575213fdd80SPeter Wemm regs->tf_cs = _ucodesel; 576213fdd80SPeter Wemm regs->tf_ds = _udatasel; 577213fdd80SPeter Wemm regs->tf_es = _udatasel; 5785206bca1SLuoqi Chen regs->tf_fs = _udatasel; 579213fdd80SPeter Wemm regs->tf_ss = _udatasel; 5805002a60fSMarcel Moolenaar PROC_LOCK(p); 58190af4afaSJohn Baldwin mtx_lock(&psp->ps_mtx); 582d66a5066SPeter Wemm } 583d66a5066SPeter Wemm 584d66a5066SPeter Wemm /* 585d66a5066SPeter Wemm * System call to cleanup state after a signal 586d66a5066SPeter Wemm * has been taken. Reset signal mask and 587d66a5066SPeter Wemm * stack state from context left by sendsig (above). 588d66a5066SPeter Wemm * Return to previous pc and psl as specified by 589d66a5066SPeter Wemm * context left by sendsig. Check carefully to 590d66a5066SPeter Wemm * make sure that the user has not modified the 591d66a5066SPeter Wemm * psl to gain improper privileges or to cause 592d66a5066SPeter Wemm * a machine fault. 593d66a5066SPeter Wemm */ 594d66a5066SPeter Wemm int 595b07cd97eSMark Murray linux_sigreturn(struct thread *td, struct linux_sigreturn_args *args) 596d66a5066SPeter Wemm { 5975002a60fSMarcel Moolenaar struct l_sigframe frame; 5981d062e2bSDag-Erling Smørgrav struct trapframe *regs; 5995002a60fSMarcel Moolenaar l_sigset_t lmask; 600d6e029adSKonstantin Belousov sigset_t bmask; 6014ab7403bSDmitry Chagin int eflags; 6029104847fSDavid Xu ksiginfo_t ksi; 603d66a5066SPeter Wemm 604b40ce416SJulian Elischer regs = td->td_frame; 605d66a5066SPeter Wemm 606d66a5066SPeter Wemm /* 607cc6ca9b3SMarcel Moolenaar * The trampoline code hands us the sigframe. 608d66a5066SPeter Wemm * It is unsafe to keep track of it ourselves, in the event that a 609d66a5066SPeter Wemm * program jumps out of a signal handler. 610d66a5066SPeter Wemm */ 6114b7ef73dSDag-Erling Smørgrav if (copyin(args->sfp, &frame, sizeof(frame)) != 0) 612d66a5066SPeter Wemm return (EFAULT); 613d66a5066SPeter Wemm 6144ba25759SEd Maste /* Check for security violations. */ 615d66a5066SPeter Wemm #define EFLAGS_SECURE(ef, oef) ((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0) 616cc6ca9b3SMarcel Moolenaar eflags = frame.sf_sc.sc_eflags; 6173d271aaaSEd Maste if (!EFLAGS_SECURE(eflags, regs->tf_eflags)) 618d66a5066SPeter Wemm return (EINVAL); 619d66a5066SPeter Wemm 620d66a5066SPeter Wemm /* 621d66a5066SPeter Wemm * Don't allow users to load a valid privileged %cs. Let the 622d66a5066SPeter Wemm * hardware check for invalid selectors, excess privilege in 623d66a5066SPeter Wemm * other selectors, invalid %eip's and invalid %esp's. 624d66a5066SPeter Wemm */ 62540d50994SPhilippe Charnier #define CS_SECURE(cs) (ISPL(cs) == SEL_UPL) 626cc6ca9b3SMarcel Moolenaar if (!CS_SECURE(frame.sf_sc.sc_cs)) { 6279104847fSDavid Xu ksiginfo_init_trap(&ksi); 6289104847fSDavid Xu ksi.ksi_signo = SIGBUS; 6299104847fSDavid Xu ksi.ksi_code = BUS_OBJERR; 6309104847fSDavid Xu ksi.ksi_trapno = T_PROTFLT; 6319104847fSDavid Xu ksi.ksi_addr = (void *)regs->tf_eip; 6329104847fSDavid Xu trapsignal(td, &ksi); 633d66a5066SPeter Wemm return (EINVAL); 634d66a5066SPeter Wemm } 635d66a5066SPeter Wemm 6364ab7403bSDmitry Chagin lmask.__mask = frame.sf_sc.sc_mask; 637d6e029adSKonstantin Belousov linux_to_bsd_sigset(&lmask, &bmask); 638d6e029adSKonstantin Belousov kern_sigprocmask(td, SIG_SETMASK, &bmask, NULL, 0); 639956d3333SMarcel Moolenaar 6404ba25759SEd Maste /* Restore signal context. */ 6415206bca1SLuoqi Chen /* %gs was restored by the trampoline. */ 642cc6ca9b3SMarcel Moolenaar regs->tf_fs = frame.sf_sc.sc_fs; 643cc6ca9b3SMarcel Moolenaar regs->tf_es = frame.sf_sc.sc_es; 644cc6ca9b3SMarcel Moolenaar regs->tf_ds = frame.sf_sc.sc_ds; 645cc6ca9b3SMarcel Moolenaar regs->tf_edi = frame.sf_sc.sc_edi; 646cc6ca9b3SMarcel Moolenaar regs->tf_esi = frame.sf_sc.sc_esi; 647cc6ca9b3SMarcel Moolenaar regs->tf_ebp = frame.sf_sc.sc_ebp; 648cc6ca9b3SMarcel Moolenaar regs->tf_ebx = frame.sf_sc.sc_ebx; 649cc6ca9b3SMarcel Moolenaar regs->tf_edx = frame.sf_sc.sc_edx; 650cc6ca9b3SMarcel Moolenaar regs->tf_ecx = frame.sf_sc.sc_ecx; 651cc6ca9b3SMarcel Moolenaar regs->tf_eax = frame.sf_sc.sc_eax; 652cc6ca9b3SMarcel Moolenaar regs->tf_eip = frame.sf_sc.sc_eip; 653cc6ca9b3SMarcel Moolenaar regs->tf_cs = frame.sf_sc.sc_cs; 654213fdd80SPeter Wemm regs->tf_eflags = eflags; 655cc6ca9b3SMarcel Moolenaar regs->tf_esp = frame.sf_sc.sc_esp_at_signal; 656cc6ca9b3SMarcel Moolenaar regs->tf_ss = frame.sf_sc.sc_ss; 657d66a5066SPeter Wemm 658d66a5066SPeter Wemm return (EJUSTRETURN); 659d66a5066SPeter Wemm } 660d66a5066SPeter Wemm 66179363394SAndrew Gallatin /* 66279363394SAndrew Gallatin * System call to cleanup state after a signal 66379363394SAndrew Gallatin * has been taken. Reset signal mask and 66479363394SAndrew Gallatin * stack state from context left by rt_sendsig (above). 66579363394SAndrew Gallatin * Return to previous pc and psl as specified by 66679363394SAndrew Gallatin * context left by sendsig. Check carefully to 66779363394SAndrew Gallatin * make sure that the user has not modified the 66879363394SAndrew Gallatin * psl to gain improper privileges or to cause 66979363394SAndrew Gallatin * a machine fault. 67079363394SAndrew Gallatin */ 67179363394SAndrew Gallatin int 672b07cd97eSMark Murray linux_rt_sigreturn(struct thread *td, struct linux_rt_sigreturn_args *args) 67379363394SAndrew Gallatin { 6745002a60fSMarcel Moolenaar struct l_ucontext uc; 6755002a60fSMarcel Moolenaar struct l_sigcontext *context; 676d6e029adSKonstantin Belousov sigset_t bmask; 6775002a60fSMarcel Moolenaar l_stack_t *lss; 678206a5d3aSIan Dowse stack_t ss; 6791d062e2bSDag-Erling Smørgrav struct trapframe *regs; 68079363394SAndrew Gallatin int eflags; 6819104847fSDavid Xu ksiginfo_t ksi; 68279363394SAndrew Gallatin 683b40ce416SJulian Elischer regs = td->td_frame; 68479363394SAndrew Gallatin 68579363394SAndrew Gallatin /* 686cc6ca9b3SMarcel Moolenaar * The trampoline code hands us the ucontext. 68779363394SAndrew Gallatin * It is unsafe to keep track of it ourselves, in the event that a 68879363394SAndrew Gallatin * program jumps out of a signal handler. 68979363394SAndrew Gallatin */ 6904b7ef73dSDag-Erling Smørgrav if (copyin(args->ucp, &uc, sizeof(uc)) != 0) 69179363394SAndrew Gallatin return (EFAULT); 69279363394SAndrew Gallatin 69379363394SAndrew Gallatin context = &uc.uc_mcontext; 69479363394SAndrew Gallatin 6954ba25759SEd Maste /* Check for security violations. */ 69679363394SAndrew Gallatin #define EFLAGS_SECURE(ef, oef) ((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0) 69779363394SAndrew Gallatin eflags = context->sc_eflags; 6983d271aaaSEd Maste if (!EFLAGS_SECURE(eflags, regs->tf_eflags)) 69979363394SAndrew Gallatin return (EINVAL); 70079363394SAndrew Gallatin 70179363394SAndrew Gallatin /* 70279363394SAndrew Gallatin * Don't allow users to load a valid privileged %cs. Let the 70379363394SAndrew Gallatin * hardware check for invalid selectors, excess privilege in 70479363394SAndrew Gallatin * other selectors, invalid %eip's and invalid %esp's. 70579363394SAndrew Gallatin */ 70679363394SAndrew Gallatin #define CS_SECURE(cs) (ISPL(cs) == SEL_UPL) 70779363394SAndrew Gallatin if (!CS_SECURE(context->sc_cs)) { 7089104847fSDavid Xu ksiginfo_init_trap(&ksi); 7099104847fSDavid Xu ksi.ksi_signo = SIGBUS; 7109104847fSDavid Xu ksi.ksi_code = BUS_OBJERR; 7119104847fSDavid Xu ksi.ksi_trapno = T_PROTFLT; 7129104847fSDavid Xu ksi.ksi_addr = (void *)regs->tf_eip; 7139104847fSDavid Xu trapsignal(td, &ksi); 71479363394SAndrew Gallatin return (EINVAL); 71579363394SAndrew Gallatin } 71679363394SAndrew Gallatin 717d6e029adSKonstantin Belousov linux_to_bsd_sigset(&uc.uc_sigmask, &bmask); 718d6e029adSKonstantin Belousov kern_sigprocmask(td, SIG_SETMASK, &bmask, NULL, 0); 71979363394SAndrew Gallatin 7204ba25759SEd Maste /* Restore signal context. */ 72179363394SAndrew Gallatin /* %gs was restored by the trampoline. */ 72279363394SAndrew Gallatin regs->tf_fs = context->sc_fs; 72379363394SAndrew Gallatin regs->tf_es = context->sc_es; 72479363394SAndrew Gallatin regs->tf_ds = context->sc_ds; 72579363394SAndrew Gallatin regs->tf_edi = context->sc_edi; 72679363394SAndrew Gallatin regs->tf_esi = context->sc_esi; 72779363394SAndrew Gallatin regs->tf_ebp = context->sc_ebp; 72879363394SAndrew Gallatin regs->tf_ebx = context->sc_ebx; 72979363394SAndrew Gallatin regs->tf_edx = context->sc_edx; 73079363394SAndrew Gallatin regs->tf_ecx = context->sc_ecx; 73179363394SAndrew Gallatin regs->tf_eax = context->sc_eax; 73279363394SAndrew Gallatin regs->tf_eip = context->sc_eip; 73379363394SAndrew Gallatin regs->tf_cs = context->sc_cs; 73479363394SAndrew Gallatin regs->tf_eflags = eflags; 73579363394SAndrew Gallatin regs->tf_esp = context->sc_esp_at_signal; 73679363394SAndrew Gallatin regs->tf_ss = context->sc_ss; 73779363394SAndrew Gallatin 7384ba25759SEd Maste /* Call sigaltstack & ignore results. */ 73979363394SAndrew Gallatin lss = &uc.uc_stack; 740206a5d3aSIan Dowse ss.ss_sp = lss->ss_sp; 741206a5d3aSIan Dowse ss.ss_size = lss->ss_size; 742206a5d3aSIan Dowse ss.ss_flags = linux_to_bsd_sigaltstack(lss->ss_flags); 74379363394SAndrew Gallatin 744206a5d3aSIan Dowse (void)kern_sigaltstack(td, &ss, NULL); 74579363394SAndrew Gallatin 74679363394SAndrew Gallatin return (EJUSTRETURN); 74779363394SAndrew Gallatin } 74879363394SAndrew Gallatin 749afe1a688SKonstantin Belousov static int 7502d88da2fSKonstantin Belousov linux_fetch_syscall_args(struct thread *td) 751d66a5066SPeter Wemm { 752afe1a688SKonstantin Belousov struct proc *p; 753afe1a688SKonstantin Belousov struct trapframe *frame; 7542d88da2fSKonstantin Belousov struct syscall_args *sa; 755afe1a688SKonstantin Belousov 756afe1a688SKonstantin Belousov p = td->td_proc; 757afe1a688SKonstantin Belousov frame = td->td_frame; 7582d88da2fSKonstantin Belousov sa = &td->td_sa; 759afe1a688SKonstantin Belousov 760afe1a688SKonstantin Belousov sa->code = frame->tf_eax; 761cf98bc28SDavid Chisnall sa->original_code = sa->code; 762afe1a688SKonstantin Belousov sa->args[0] = frame->tf_ebx; 763afe1a688SKonstantin Belousov sa->args[1] = frame->tf_ecx; 764afe1a688SKonstantin Belousov sa->args[2] = frame->tf_edx; 765afe1a688SKonstantin Belousov sa->args[3] = frame->tf_esi; 766afe1a688SKonstantin Belousov sa->args[4] = frame->tf_edi; 767afe1a688SKonstantin Belousov sa->args[5] = frame->tf_ebp; /* Unconfirmed */ 768afe1a688SKonstantin Belousov 769afe1a688SKonstantin Belousov if (sa->code >= p->p_sysent->sv_size) 770fcdffc03SDmitry Chagin /* nosys */ 7711b8d0393SConrad Meyer sa->callp = &p->p_sysent->sv_table[p->p_sysent->sv_size - 1]; 772afe1a688SKonstantin Belousov else 773afe1a688SKonstantin Belousov sa->callp = &p->p_sysent->sv_table[sa->code]; 774afe1a688SKonstantin Belousov 775afe1a688SKonstantin Belousov td->td_retval[0] = 0; 776afe1a688SKonstantin Belousov td->td_retval[1] = frame->tf_edx; 777afe1a688SKonstantin Belousov 778afe1a688SKonstantin Belousov return (0); 779d66a5066SPeter Wemm } 780d66a5066SPeter Wemm 781c26391f4SEdward Tomasz Napierala static void 782c26391f4SEdward Tomasz Napierala linux_set_syscall_retval(struct thread *td, int error) 783c26391f4SEdward Tomasz Napierala { 784c26391f4SEdward Tomasz Napierala struct trapframe *frame = td->td_frame; 785c26391f4SEdward Tomasz Napierala 786c26391f4SEdward Tomasz Napierala cpu_set_syscall_retval(td, error); 787c26391f4SEdward Tomasz Napierala 788c26391f4SEdward Tomasz Napierala if (__predict_false(error != 0)) { 789c26391f4SEdward Tomasz Napierala if (error != ERESTART && error != EJUSTRETURN) 790866b1f51SEdward Tomasz Napierala frame->tf_eax = bsd_to_linux_errno(error); 791c26391f4SEdward Tomasz Napierala } 792c26391f4SEdward Tomasz Napierala } 793c26391f4SEdward Tomasz Napierala 794d323ddf3SMatthew Dillon /* 795598d45beSMatthew N. Dodd * exec_setregs may initialize some registers differently than Linux 796598d45beSMatthew N. Dodd * does, thus potentially confusing Linux binaries. If necessary, we 797598d45beSMatthew N. Dodd * override the exec_setregs default(s) here. 798598d45beSMatthew N. Dodd */ 799598d45beSMatthew N. Dodd static void 80031174518SJohn Baldwin linux_exec_setregs(struct thread *td, struct image_params *imgp, 80131174518SJohn Baldwin uintptr_t stack) 802598d45beSMatthew N. Dodd { 803598d45beSMatthew N. Dodd struct pcb *pcb = td->td_pcb; 804598d45beSMatthew N. Dodd 805a107d8aaSNathan Whitehorn exec_setregs(td, imgp, stack); 806598d45beSMatthew N. Dodd 8074ba25759SEd Maste /* Linux sets %gs to 0, we default to _udatasel. */ 8082ee8325fSJohn Baldwin pcb->pcb_gs = 0; 8092ee8325fSJohn Baldwin load_gs(0); 8102a51b9b0SDavid Schultz 8112ee8325fSJohn Baldwin pcb->pcb_initial_npxcw = __LINUX_NPXCW__; 812598d45beSMatthew N. Dodd } 813598d45beSMatthew N. Dodd 814d66a5066SPeter Wemm struct sysentvec linux_sysvec = { 815a8d403e1SKonstantin Belousov .sv_size = LINUX_SYS_MAXSYSCALL, 816a8d403e1SKonstantin Belousov .sv_table = linux_sysent, 817dc858467SEd Maste .sv_transtrap = linux_translate_traps, 818a8d403e1SKonstantin Belousov .sv_fixup = linux_fixup, 819a8d403e1SKonstantin Belousov .sv_sendsig = linux_sendsig, 820bdc37934SDmitry Chagin .sv_sigcode = &_binary_linux_locore_o_start, 821a8d403e1SKonstantin Belousov .sv_szsigcode = &linux_szsigcode, 822a8d403e1SKonstantin Belousov .sv_name = "Linux a.out", 823a8d403e1SKonstantin Belousov .sv_coredump = NULL, 824dc858467SEd Maste .sv_imgact_try = linux_exec_imgact_try, 825a8d403e1SKonstantin Belousov .sv_minsigstksz = LINUX_MINSIGSTKSZ, 826a8d403e1SKonstantin Belousov .sv_minuser = VM_MIN_ADDRESS, 827a8d403e1SKonstantin Belousov .sv_maxuser = VM_MAXUSER_ADDRESS, 8288f1e49a6SDmitry Chagin .sv_usrstack = LINUX_USRSTACK, 829a8d403e1SKonstantin Belousov .sv_psstrings = PS_STRINGS, 830a8d403e1SKonstantin Belousov .sv_stackprot = VM_PROT_ALL, 831a8d403e1SKonstantin Belousov .sv_copyout_strings = exec_copyout_strings, 832dc858467SEd Maste .sv_setregs = linux_exec_setregs, 833a8d403e1SKonstantin Belousov .sv_fixlimit = NULL, 834b4cf0e62SKonstantin Belousov .sv_maxssiz = NULL, 835870e197dSKonstantin Belousov .sv_flags = SV_ABI_LINUX | SV_AOUT | SV_IA32 | SV_ILP32 | 836870e197dSKonstantin Belousov SV_SIG_DISCIGN | SV_SIG_WAITNDQ, 837c26391f4SEdward Tomasz Napierala .sv_set_syscall_retval = linux_set_syscall_retval, 838afe1a688SKonstantin Belousov .sv_fetch_syscall_args = linux_fetch_syscall_args, 839afe1a688SKonstantin Belousov .sv_syscallnames = NULL, 840e5d81ef1SDmitry Chagin .sv_schedtail = linux_schedtail, 84181338031SDmitry Chagin .sv_thread_detach = linux_thread_detach, 842038c7205SDmitry Chagin .sv_trap = NULL, 843*5fd9cd53SDmitry Chagin .sv_onexec = linux_on_exec_vmspace, 8444815f175SKonstantin Belousov .sv_onexit = linux_on_exit, 8454815f175SKonstantin Belousov .sv_ontdexit = linux_thread_dtor, 846598f6fb4SKonstantin Belousov .sv_setid_allowed = &linux_setid_allowed_query, 847d66a5066SPeter Wemm }; 8488f1e49a6SDmitry Chagin INIT_SYSENTVEC(aout_sysvec, &linux_sysvec); 849e1743d02SSøren Schmidt 850e1743d02SSøren Schmidt struct sysentvec elf_linux_sysvec = { 851a8d403e1SKonstantin Belousov .sv_size = LINUX_SYS_MAXSYSCALL, 852a8d403e1SKonstantin Belousov .sv_table = linux_sysent, 853dc858467SEd Maste .sv_transtrap = linux_translate_traps, 854dc858467SEd Maste .sv_fixup = linux_fixup_elf, 855a8d403e1SKonstantin Belousov .sv_sendsig = linux_sendsig, 856bdc37934SDmitry Chagin .sv_sigcode = &_binary_linux_locore_o_start, 857a8d403e1SKonstantin Belousov .sv_szsigcode = &linux_szsigcode, 8585faeda90SJessica Clarke .sv_name = "Linux ELF32", 859a8d403e1SKonstantin Belousov .sv_coredump = elf32_coredump, 860435754a5SEdward Tomasz Napierala .sv_elf_core_osabi = ELFOSABI_FREEBSD, 861435754a5SEdward Tomasz Napierala .sv_elf_core_abi_vendor = FREEBSD_ABI_VENDOR, 862435754a5SEdward Tomasz Napierala .sv_elf_core_prepare_notes = elf32_prepare_notes, 863dc858467SEd Maste .sv_imgact_try = linux_exec_imgact_try, 864a8d403e1SKonstantin Belousov .sv_minsigstksz = LINUX_MINSIGSTKSZ, 865a8d403e1SKonstantin Belousov .sv_minuser = VM_MIN_ADDRESS, 866a8d403e1SKonstantin Belousov .sv_maxuser = VM_MAXUSER_ADDRESS, 8678f1e49a6SDmitry Chagin .sv_usrstack = LINUX_USRSTACK, 8688f1e49a6SDmitry Chagin .sv_psstrings = LINUX_PS_STRINGS, 869a8d403e1SKonstantin Belousov .sv_stackprot = VM_PROT_ALL, 8705caa67faSJohn Baldwin .sv_copyout_auxargs = linux_copyout_auxargs, 8714d7c2e8aSDmitry Chagin .sv_copyout_strings = linux_copyout_strings, 872dc858467SEd Maste .sv_setregs = linux_exec_setregs, 873a8d403e1SKonstantin Belousov .sv_fixlimit = NULL, 874b4cf0e62SKonstantin Belousov .sv_maxssiz = NULL, 875870e197dSKonstantin Belousov .sv_flags = SV_ABI_LINUX | SV_IA32 | SV_ILP32 | SV_SHP | 876870e197dSKonstantin Belousov SV_SIG_DISCIGN | SV_SIG_WAITNDQ, 877c26391f4SEdward Tomasz Napierala .sv_set_syscall_retval = linux_set_syscall_retval, 878afe1a688SKonstantin Belousov .sv_fetch_syscall_args = linux_fetch_syscall_args, 879afe1a688SKonstantin Belousov .sv_syscallnames = NULL, 8808f1e49a6SDmitry Chagin .sv_shared_page_base = LINUX_SHAREDPAGE, 8818f1e49a6SDmitry Chagin .sv_shared_page_len = PAGE_SIZE, 882e5d81ef1SDmitry Chagin .sv_schedtail = linux_schedtail, 88381338031SDmitry Chagin .sv_thread_detach = linux_thread_detach, 884038c7205SDmitry Chagin .sv_trap = NULL, 885*5fd9cd53SDmitry Chagin .sv_onexec = linux_on_exec_vmspace, 8864815f175SKonstantin Belousov .sv_onexit = linux_on_exit, 8874815f175SKonstantin Belousov .sv_ontdexit = linux_thread_dtor, 888598f6fb4SKonstantin Belousov .sv_setid_allowed = &linux_setid_allowed_query, 889e1743d02SSøren Schmidt }; 890bdc37934SDmitry Chagin 891*5fd9cd53SDmitry Chagin static int 892*5fd9cd53SDmitry Chagin linux_on_exec_vmspace(struct proc *p, struct image_params *imgp) 893*5fd9cd53SDmitry Chagin { 894*5fd9cd53SDmitry Chagin 895*5fd9cd53SDmitry Chagin linux_on_exec(p, imgp); 896*5fd9cd53SDmitry Chagin return (0); 897*5fd9cd53SDmitry Chagin } 898*5fd9cd53SDmitry Chagin 899bdc37934SDmitry Chagin static void 900bdc37934SDmitry Chagin linux_vdso_install(void *param) 901bdc37934SDmitry Chagin { 902bdc37934SDmitry Chagin 903bdc37934SDmitry Chagin linux_szsigcode = (&_binary_linux_locore_o_end - 904bdc37934SDmitry Chagin &_binary_linux_locore_o_start); 905bdc37934SDmitry Chagin 906bdc37934SDmitry Chagin if (linux_szsigcode > elf_linux_sysvec.sv_shared_page_len) 907bdc37934SDmitry Chagin panic("Linux invalid vdso size\n"); 908bdc37934SDmitry Chagin 909bdc37934SDmitry Chagin __elfN(linux_vdso_fixup)(&elf_linux_sysvec); 910bdc37934SDmitry Chagin 911bdc37934SDmitry Chagin linux_shared_page_obj = __elfN(linux_shared_page_init) 912bdc37934SDmitry Chagin (&linux_shared_page_mapping); 913bdc37934SDmitry Chagin 914c151945cSDmitry Chagin __elfN(linux_vdso_reloc)(&elf_linux_sysvec); 915bdc37934SDmitry Chagin 916bdc37934SDmitry Chagin bcopy(elf_linux_sysvec.sv_sigcode, linux_shared_page_mapping, 917bdc37934SDmitry Chagin linux_szsigcode); 918bdc37934SDmitry Chagin elf_linux_sysvec.sv_shared_page_obj = linux_shared_page_obj; 919bdc37934SDmitry Chagin } 920bdc37934SDmitry Chagin SYSINIT(elf_linux_vdso_init, SI_SUB_EXEC, SI_ORDER_ANY, 921f8268d4dSEd Maste linux_vdso_install, NULL); 922bdc37934SDmitry Chagin 923bdc37934SDmitry Chagin static void 924bdc37934SDmitry Chagin linux_vdso_deinstall(void *param) 925bdc37934SDmitry Chagin { 926bdc37934SDmitry Chagin 927aa5fef60SMark Johnston __elfN(linux_shared_page_fini)(linux_shared_page_obj, 928aa5fef60SMark Johnston linux_shared_page_mapping); 9297b194b3dSEd Maste } 930bdc37934SDmitry Chagin SYSUNINIT(elf_linux_vdso_uninit, SI_SUB_EXEC, SI_ORDER_FIRST, 931f8268d4dSEd Maste linux_vdso_deinstall, NULL); 932e1743d02SSøren Schmidt 93389ffc202SBjoern A. Zeeb static char GNU_ABI_VENDOR[] = "GNU"; 93489ffc202SBjoern A. Zeeb static int GNULINUX_ABI_DESC = 0; 93589ffc202SBjoern A. Zeeb 936a95659f7SEd Maste static bool 93789ffc202SBjoern A. Zeeb linux_trans_osrel(const Elf_Note *note, int32_t *osrel) 93889ffc202SBjoern A. Zeeb { 93989ffc202SBjoern A. Zeeb const Elf32_Word *desc; 94089ffc202SBjoern A. Zeeb uintptr_t p; 94189ffc202SBjoern A. Zeeb 94289ffc202SBjoern A. Zeeb p = (uintptr_t)(note + 1); 94389ffc202SBjoern A. Zeeb p += roundup2(note->n_namesz, sizeof(Elf32_Addr)); 94489ffc202SBjoern A. Zeeb 94589ffc202SBjoern A. Zeeb desc = (const Elf32_Word *)p; 94689ffc202SBjoern A. Zeeb if (desc[0] != GNULINUX_ABI_DESC) 947a95659f7SEd Maste return (false); 94889ffc202SBjoern A. Zeeb 94989ffc202SBjoern A. Zeeb /* 95035755049SChuck Tuffli * For Linux we encode osrel using the Linux convention of 95135755049SChuck Tuffli * (version << 16) | (major << 8) | (minor) 95235755049SChuck Tuffli * See macro in linux_mib.h 95389ffc202SBjoern A. Zeeb */ 95435755049SChuck Tuffli *osrel = LINUX_KERNVER(desc[1], desc[2], desc[3]); 95589ffc202SBjoern A. Zeeb 956a95659f7SEd Maste return (true); 95789ffc202SBjoern A. Zeeb } 95832c01de2SDmitry Chagin 95932c01de2SDmitry Chagin static Elf_Brandnote linux_brandnote = { 96089ffc202SBjoern A. Zeeb .hdr.n_namesz = sizeof(GNU_ABI_VENDOR), 96189ffc202SBjoern A. Zeeb .hdr.n_descsz = 16, /* XXX at least 16 */ 96232c01de2SDmitry Chagin .hdr.n_type = 1, 96389ffc202SBjoern A. Zeeb .vendor = GNU_ABI_VENDOR, 96489ffc202SBjoern A. Zeeb .flags = BN_TRANSLATE_OSREL, 96589ffc202SBjoern A. Zeeb .trans_osrel = linux_trans_osrel 96632c01de2SDmitry Chagin }; 96732c01de2SDmitry Chagin 968514058dcSAlexander Langer static Elf32_Brandinfo linux_brand = { 969a8d403e1SKonstantin Belousov .brand = ELFOSABI_LINUX, 970a8d403e1SKonstantin Belousov .machine = EM_386, 971a8d403e1SKonstantin Belousov .compat_3_brand = "Linux", 972b5f20658SEdward Tomasz Napierala .emul_path = linux_emul_path, 973a8d403e1SKonstantin Belousov .interp_path = "/lib/ld-linux.so.1", 974a8d403e1SKonstantin Belousov .sysvec = &elf_linux_sysvec, 975a8d403e1SKonstantin Belousov .interp_newpath = NULL, 97632c01de2SDmitry Chagin .brand_note = &linux_brandnote, 9772dedc128SDmitry Chagin .flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE 9785cf588ebSPeter Wemm }; 9795cf588ebSPeter Wemm 980514058dcSAlexander Langer static Elf32_Brandinfo linux_glibc2brand = { 981a8d403e1SKonstantin Belousov .brand = ELFOSABI_LINUX, 982a8d403e1SKonstantin Belousov .machine = EM_386, 983a8d403e1SKonstantin Belousov .compat_3_brand = "Linux", 984b5f20658SEdward Tomasz Napierala .emul_path = linux_emul_path, 985a8d403e1SKonstantin Belousov .interp_path = "/lib/ld-linux.so.2", 986a8d403e1SKonstantin Belousov .sysvec = &elf_linux_sysvec, 987a8d403e1SKonstantin Belousov .interp_newpath = NULL, 98832c01de2SDmitry Chagin .brand_note = &linux_brandnote, 9892dedc128SDmitry Chagin .flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE 9904e138a28SMike Smith }; 9914e138a28SMike Smith 992a0c59c7aSDmitry Chagin static Elf32_Brandinfo linux_muslbrand = { 993a0c59c7aSDmitry Chagin .brand = ELFOSABI_LINUX, 994a0c59c7aSDmitry Chagin .machine = EM_386, 995a0c59c7aSDmitry Chagin .compat_3_brand = "Linux", 996b5f20658SEdward Tomasz Napierala .emul_path = linux_emul_path, 997a0c59c7aSDmitry Chagin .interp_path = "/lib/ld-musl-i386.so.1", 998a0c59c7aSDmitry Chagin .sysvec = &elf_linux_sysvec, 999a0c59c7aSDmitry Chagin .interp_newpath = NULL, 1000a0c59c7aSDmitry Chagin .brand_note = &linux_brandnote, 1001a0c59c7aSDmitry Chagin .flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE 1002a0c59c7aSDmitry Chagin }; 1003a0c59c7aSDmitry Chagin 1004514058dcSAlexander Langer Elf32_Brandinfo *linux_brandlist[] = { 1005514058dcSAlexander Langer &linux_brand, 1006514058dcSAlexander Langer &linux_glibc2brand, 1007a0c59c7aSDmitry Chagin &linux_muslbrand, 1008514058dcSAlexander Langer NULL 1009514058dcSAlexander Langer }; 1010514058dcSAlexander Langer 1011aa855a59SPeter Wemm static int 1012c25ded31SBruce Evans linux_elf_modevent(module_t mod, int type, void *data) 1013d30ea4f5SPeter Wemm { 1014514058dcSAlexander Langer Elf32_Brandinfo **brandinfo; 1015514058dcSAlexander Langer int error; 1016f41325dbSPeter Wemm struct linux_ioctl_handler **lihp; 1017514058dcSAlexander Langer 1018514058dcSAlexander Langer error = 0; 1019514058dcSAlexander Langer 1020aa855a59SPeter Wemm switch(type) { 1021aa855a59SPeter Wemm case MOD_LOAD: 1022aa855a59SPeter Wemm for (brandinfo = &linux_brandlist[0]; *brandinfo != NULL; 1023aa855a59SPeter Wemm ++brandinfo) 10243ebc1248SPeter Wemm if (elf32_insert_brand_entry(*brandinfo) < 0) 1025aa855a59SPeter Wemm error = EINVAL; 1026466b14d7SMarcel Moolenaar if (error == 0) { 1027f41325dbSPeter Wemm SET_FOREACH(lihp, linux_ioctl_handler_set) 1028f41325dbSPeter Wemm linux_ioctl_register_handler(*lihp); 10299b44bfc5SAlexander Leidinger LIST_INIT(&futex_list); 103079262bf1SDmitry Chagin mtx_init(&futex_mtx, "ftllk", NULL, MTX_DEF); 1031044ab55eSEdward Tomasz Napierala linux_dev_shm_create(); 10327ae27ff4SJamie Gritton linux_osd_jail_register(); 10331ca16454SDmitry Chagin stclohz = (stathz ? stathz : hz); 103443bef515SMarcel Moolenaar if (bootverbose) 1035466b14d7SMarcel Moolenaar printf("Linux ELF exec handler installed\n"); 1036466b14d7SMarcel Moolenaar } else 1037466b14d7SMarcel Moolenaar printf("cannot insert Linux ELF brand handler\n"); 1038aa855a59SPeter Wemm break; 1039aa855a59SPeter Wemm case MOD_UNLOAD: 1040aa855a59SPeter Wemm for (brandinfo = &linux_brandlist[0]; *brandinfo != NULL; 1041aa855a59SPeter Wemm ++brandinfo) 10423ebc1248SPeter Wemm if (elf32_brand_inuse(*brandinfo)) 1043d2758342SMark Newton error = EBUSY; 1044d2758342SMark Newton if (error == 0) { 1045d2758342SMark Newton for (brandinfo = &linux_brandlist[0]; 1046d2758342SMark Newton *brandinfo != NULL; ++brandinfo) 10473ebc1248SPeter Wemm if (elf32_remove_brand_entry(*brandinfo) < 0) 1048aa855a59SPeter Wemm error = EINVAL; 1049d2758342SMark Newton } 1050466b14d7SMarcel Moolenaar if (error == 0) { 1051f41325dbSPeter Wemm SET_FOREACH(lihp, linux_ioctl_handler_set) 1052f41325dbSPeter Wemm linux_ioctl_unregister_handler(*lihp); 105379262bf1SDmitry Chagin mtx_destroy(&futex_mtx); 1054044ab55eSEdward Tomasz Napierala linux_dev_shm_destroy(); 10557ae27ff4SJamie Gritton linux_osd_jail_deregister(); 1056466b14d7SMarcel Moolenaar if (bootverbose) 1057466b14d7SMarcel Moolenaar printf("Linux ELF exec handler removed\n"); 1058466b14d7SMarcel Moolenaar } else 1059aa855a59SPeter Wemm printf("Could not deinstall ELF interpreter entry\n"); 1060aa855a59SPeter Wemm break; 1061aa855a59SPeter Wemm default: 1062af682d48SDmitry Chagin return (EOPNOTSUPP); 1063d30ea4f5SPeter Wemm } 1064af682d48SDmitry Chagin return (error); 1065aa855a59SPeter Wemm } 1066466b14d7SMarcel Moolenaar 1067aa855a59SPeter Wemm static moduledata_t linux_elf_mod = { 1068aa855a59SPeter Wemm "linuxelf", 1069aa855a59SPeter Wemm linux_elf_modevent, 10709823d527SKevin Lo 0 1071aa855a59SPeter Wemm }; 1072466b14d7SMarcel Moolenaar 107378ae4338SKonstantin Belousov DECLARE_MODULE_TIED(linuxelf, linux_elf_mod, SI_SUB_EXEC, SI_ORDER_ANY); 1074b6348be7SBaptiste Daroussin FEATURE(linux, "Linux 32bit support"); 1075