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 32cc1b0f7dSDmitry Chagin #define __ELF_WORD_SIZE 32 33cc1b0f7dSDmitry Chagin 34d66a5066SPeter Wemm #include <sys/param.h> 35ff22c670SBruce Evans #include <sys/exec.h> 3657b4252eSKonstantin Belousov #include <sys/fcntl.h> 37d66a5066SPeter Wemm #include <sys/imgact.h> 3822d4b0fbSJohn Polstra #include <sys/imgact_aout.h> 39e1743d02SSøren Schmidt #include <sys/imgact_elf.h> 40ff22c670SBruce Evans #include <sys/kernel.h> 41*f4a512a5SDmitry Chagin #include <sys/lock.h> 42e1743d02SSøren Schmidt #include <sys/malloc.h> 43ff22c670SBruce Evans #include <sys/module.h> 44*f4a512a5SDmitry Chagin #include <sys/mutex.h> 45fb919e4dSMark Murray #include <sys/proc.h> 469931033bSDmitry Chagin #include <sys/stddef.h> 47206a5d3aSIan Dowse #include <sys/syscallsubr.h> 4867d39748SDmitry Chagin #include <sys/sysctl.h> 49fb919e4dSMark Murray #include <sys/sysent.h> 50fb919e4dSMark Murray #include <sys/sysproto.h> 51fb919e4dSMark Murray 52a9148ab1SPeter Wemm #include <vm/pmap.h> 53*f4a512a5SDmitry Chagin #include <vm/vm.h> 54a9148ab1SPeter Wemm #include <vm/vm_map.h> 55ff22c670SBruce Evans #include <vm/vm_page.h> 56ff22c670SBruce Evans 57ff22c670SBruce Evans #include <machine/cpu.h> 584d7c2e8aSDmitry Chagin #include <machine/cputypes.h> 59ff22c670SBruce Evans #include <machine/md_var.h> 60d3adf769SDavid Schultz #include <machine/pcb.h> 61d41e41f9SJohn Baldwin #include <machine/trap.h> 62a9148ab1SPeter Wemm 639931033bSDmitry Chagin #include <x86/linux/linux_x86.h> 64d66a5066SPeter Wemm #include <i386/linux/linux.h> 65ebea8660SMarcel Moolenaar #include <i386/linux/linux_proto.h> 66cc1b0f7dSDmitry Chagin #include <compat/linux/linux_elf.h> 6794cb2ecfSAlexander Leidinger #include <compat/linux/linux_emul.h> 680a4b664aSDmitry Chagin #include <compat/linux/linux_fork.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 7621f24617SDmitry Chagin #include <x86/linux/linux_x86_sigframe.h> 7721f24617SDmitry Chagin 781d91482dSPeter Wemm MODULE_VERSION(linux, 1); 791d91482dSPeter Wemm 809931033bSDmitry Chagin #define LINUX_VDSOPAGE_SIZE PAGE_SIZE * 2 819931033bSDmitry Chagin #define LINUX_VDSOPAGE (VM_MAXUSER_ADDRESS - LINUX_VDSOPAGE_SIZE) 829931033bSDmitry Chagin #define LINUX_SHAREDPAGE (LINUX_VDSOPAGE - PAGE_SIZE) 839931033bSDmitry Chagin /* 849931033bSDmitry Chagin * PAGE_SIZE - the size 859931033bSDmitry Chagin * of the native SHAREDPAGE 869931033bSDmitry Chagin */ 879931033bSDmitry Chagin #define LINUX_USRSTACK LINUX_SHAREDPAGE 888f1e49a6SDmitry Chagin #define LINUX_PS_STRINGS (LINUX_USRSTACK - sizeof(struct ps_strings)) 898f1e49a6SDmitry Chagin 90bdc37934SDmitry Chagin static int linux_szsigcode; 919931033bSDmitry Chagin static vm_object_t linux_vdso_obj; 929931033bSDmitry Chagin static char *linux_vdso_mapping; 939931033bSDmitry Chagin extern char _binary_linux_vdso_so_o_start; 949931033bSDmitry Chagin extern char _binary_linux_vdso_so_o_end; 959931033bSDmitry Chagin static vm_offset_t linux_vdso_base; 9643bef515SMarcel Moolenaar 9743bef515SMarcel Moolenaar extern struct sysent linux_sysent[LINUX_SYS_MAXSYSCALL]; 981da65dcbSMitchell Horne extern const char *linux_syscallnames[]; 9943bef515SMarcel Moolenaar 100f41325dbSPeter Wemm SET_DECLARE(linux_ioctl_handler_set, struct linux_ioctl_handler); 10143bef515SMarcel Moolenaar 10231174518SJohn Baldwin static int linux_fixup(uintptr_t *stack_base, 10389c9a483SAlfred Perlstein struct image_params *iparams); 1049104847fSDavid Xu static void linux_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask); 105dc858467SEd Maste static void linux_exec_setregs(struct thread *td, 10631174518SJohn Baldwin struct image_params *imgp, uintptr_t stack); 1079931033bSDmitry Chagin static void linux_exec_sysvec_init(void *param); 1085fd9cd53SDmitry Chagin static int linux_on_exec_vmspace(struct proc *p, 1095fd9cd53SDmitry Chagin struct image_params *imgp); 110de8374dfSDmitry Chagin static void linux_set_fork_retval(struct thread *td); 111a543556cSDmitry Chagin static void linux_vdso_install(const void *param); 112a543556cSDmitry Chagin static void linux_vdso_deinstall(const void *param); 1139931033bSDmitry Chagin static void linux_vdso_reloc(char *mapping, Elf_Addr offset); 1144d7c2e8aSDmitry Chagin 115c1da89feSDmitry Chagin LINUX_VDSO_SYM_CHAR(linux_platform); 1169931033bSDmitry Chagin LINUX_VDSO_SYM_INTPTR(__kernel_vsyscall); 1178f9635dcSDmitry Chagin LINUX_VDSO_SYM_INTPTR(linux_vdso_sigcode); 1188f9635dcSDmitry Chagin LINUX_VDSO_SYM_INTPTR(linux_vdso_rt_sigcode); 1199931033bSDmitry Chagin LINUX_VDSO_SYM_INTPTR(kern_timekeep_base); 1209931033bSDmitry Chagin LINUX_VDSO_SYM_INTPTR(kern_tsc_selector); 1215a6a4fb2SDmitry Chagin LINUX_VDSO_SYM_INTPTR(kern_cpu_selector); 122bdc37934SDmitry Chagin 123303b270bSEivind Eklund static int 12431174518SJohn Baldwin linux_fixup(uintptr_t *stack_base, struct image_params *imgp) 125d66a5066SPeter Wemm { 12631174518SJohn Baldwin register_t *base, *argv, *envp; 127d66a5066SPeter Wemm 12831174518SJohn Baldwin base = (register_t *)*stack_base; 12931174518SJohn Baldwin argv = base; 13031174518SJohn Baldwin envp = base + (imgp->args->argc + 1); 13131174518SJohn Baldwin base--; 13231174518SJohn Baldwin suword(base, (intptr_t)envp); 13331174518SJohn Baldwin base--; 13431174518SJohn Baldwin suword(base, (intptr_t)argv); 13531174518SJohn Baldwin base--; 13631174518SJohn Baldwin suword(base, imgp->args->argc); 13731174518SJohn Baldwin *stack_base = (uintptr_t)base; 1384d7c2e8aSDmitry Chagin return (0); 139d66a5066SPeter Wemm } 140d66a5066SPeter Wemm 14103b0d68cSJohn Baldwin static int 142d8010b11SJohn Baldwin linux_copyout_auxargs(struct image_params *imgp, uintptr_t base) 143e1743d02SSøren Schmidt { 14443cf129cSJohn Baldwin Elf32_Auxargs *args; 1455f77b8a8SBrooks Davis Elf32_Auxinfo *argarray, *pos; 14603b0d68cSJohn Baldwin int error, issetugid; 1474d7c2e8aSDmitry Chagin 148669414e4SXin LI issetugid = imgp->proc->p_flag & P_SUGID ? 1 : 0; 14943cf129cSJohn Baldwin args = (Elf32_Auxargs *)imgp->auxargs; 1505f77b8a8SBrooks Davis argarray = pos = malloc(LINUX_AT_COUNT * sizeof(*pos), M_TEMP, 1515f77b8a8SBrooks Davis M_WAITOK | M_ZERO); 152e1743d02SSøren Schmidt 1539931033bSDmitry Chagin AUXARGS_ENTRY(pos, LINUX_AT_SYSINFO_EHDR, linux_vdso_base); 1549931033bSDmitry Chagin AUXARGS_ENTRY(pos, LINUX_AT_SYSINFO, __kernel_vsyscall); 1554d7c2e8aSDmitry Chagin AUXARGS_ENTRY(pos, LINUX_AT_HWCAP, cpu_feature); 1568d30f381SDmitry Chagin 1578d30f381SDmitry Chagin /* 1588d30f381SDmitry Chagin * Do not export AT_CLKTCK when emulating Linux kernel prior to 2.4.0, 1598d30f381SDmitry Chagin * as it has appeared in the 2.4.0-rc7 first time. 1608d30f381SDmitry Chagin * Being exported, AT_CLKTCK is returned by sysconf(_SC_CLK_TCK), 1618d30f381SDmitry Chagin * glibc falls back to the hard-coded CLK_TCK value when aux entry 1628d30f381SDmitry Chagin * is not present. 1638d30f381SDmitry Chagin * Also see linux_times() implementation. 1648d30f381SDmitry Chagin */ 1658d30f381SDmitry Chagin if (linux_kernver(curthread) >= LINUX_KERNVER_2004000) 1661ca16454SDmitry Chagin AUXARGS_ENTRY(pos, LINUX_AT_CLKTCK, stclohz); 167e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_PHDR, args->phdr); 168e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_PHENT, args->phent); 169e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_PHNUM, args->phnum); 170e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_PAGESZ, args->pagesz); 171e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_FLAGS, args->flags); 172e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_ENTRY, args->entry); 173e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_BASE, args->base); 174669414e4SXin LI AUXARGS_ENTRY(pos, LINUX_AT_SECURE, issetugid); 175b1fc0ec1SRobert Watson AUXARGS_ENTRY(pos, AT_UID, imgp->proc->p_ucred->cr_ruid); 176b1fc0ec1SRobert Watson AUXARGS_ENTRY(pos, AT_EUID, imgp->proc->p_ucred->cr_svuid); 177b1fc0ec1SRobert Watson AUXARGS_ENTRY(pos, AT_GID, imgp->proc->p_ucred->cr_rgid); 178b1fc0ec1SRobert Watson AUXARGS_ENTRY(pos, AT_EGID, imgp->proc->p_ucred->cr_svgid); 179c1da89feSDmitry Chagin AUXARGS_ENTRY(pos, LINUX_AT_PLATFORM, PTROUT(linux_platform)); 180b24e6ac8SBrooks Davis AUXARGS_ENTRY_PTR(pos, LINUX_AT_RANDOM, imgp->canary); 1814048f59cSDmitry Chagin if (imgp->execpathp != 0) 182b24e6ac8SBrooks Davis AUXARGS_ENTRY_PTR(pos, LINUX_AT_EXECFN, imgp->execpathp); 1834d7c2e8aSDmitry Chagin if (args->execfd != -1) 1844d7c2e8aSDmitry Chagin AUXARGS_ENTRY(pos, AT_EXECFD, args->execfd); 185e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_NULL, 0); 186e1743d02SSøren Schmidt 187e1743d02SSøren Schmidt free(imgp->auxargs, M_TEMP); 188e1743d02SSøren Schmidt imgp->auxargs = NULL; 189cbf7e0cbSBrooks Davis KASSERT(pos - argarray <= LINUX_AT_COUNT, ("Too many auxargs")); 1905f77b8a8SBrooks Davis 191d8010b11SJohn Baldwin error = copyout(argarray, (void *)base, 192d8010b11SJohn Baldwin sizeof(*argarray) * LINUX_AT_COUNT); 1935f77b8a8SBrooks Davis free(argarray, M_TEMP); 19403b0d68cSJohn Baldwin return (error); 1955caa67faSJohn Baldwin } 1965caa67faSJohn Baldwin 19779363394SAndrew Gallatin static void 1989104847fSDavid Xu linux_rt_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) 19979363394SAndrew Gallatin { 2001d062e2bSDag-Erling Smørgrav struct thread *td = curthread; 2011d062e2bSDag-Erling Smørgrav struct proc *p = td->td_proc; 20290af4afaSJohn Baldwin struct sigacts *psp; 2031d062e2bSDag-Erling Smørgrav struct trapframe *regs; 2045002a60fSMarcel Moolenaar struct l_rt_sigframe *fp, frame; 2059104847fSDavid Xu int sig, code; 20679363394SAndrew Gallatin int oonstack; 20779363394SAndrew Gallatin 208eca368ecSDmitry Chagin sig = linux_translate_traps(ksi->ksi_signo, ksi->ksi_trapno); 2099104847fSDavid Xu code = ksi->ksi_code; 210df53e91cSJohn Baldwin PROC_LOCK_ASSERT(p, MA_OWNED); 21190af4afaSJohn Baldwin psp = p->p_sigacts; 21290af4afaSJohn Baldwin mtx_assert(&psp->ps_mtx, MA_OWNED); 213b40ce416SJulian Elischer regs = td->td_frame; 214d034d459SMarcel Moolenaar oonstack = sigonstack(regs->tf_esp); 21579363394SAndrew Gallatin 2164ba25759SEd Maste /* Allocate space for the signal handler context. */ 217a30ec4b9SDavid Xu if ((td->td_pflags & TDP_ALTSTACK) && !oonstack && 21890af4afaSJohn Baldwin SIGISMEMBER(psp->ps_sigonstack, sig)) { 219aa949be5SJohn Baldwin fp = (struct l_rt_sigframe *)((uintptr_t)td->td_sigstk.ss_sp + 220a30ec4b9SDavid Xu td->td_sigstk.ss_size - sizeof(struct l_rt_sigframe)); 221d034d459SMarcel Moolenaar } else 2225002a60fSMarcel Moolenaar fp = (struct l_rt_sigframe *)regs->tf_esp - 1; 22390af4afaSJohn Baldwin mtx_unlock(&psp->ps_mtx); 22479363394SAndrew Gallatin 2254ba25759SEd Maste /* Build the argument list for the signal handler. */ 2264ab7403bSDmitry Chagin sig = bsd_to_linux_signal(sig); 22779363394SAndrew Gallatin 22899d45c5fSMarcel Moolenaar bzero(&frame, sizeof(frame)); 22999d45c5fSMarcel Moolenaar 23079363394SAndrew Gallatin frame.sf_sig = sig; 23121f24617SDmitry Chagin frame.sf_siginfo = PTROUT(&fp->sf_si); 2326e826d27SDmitry Chagin frame.sf_ucontext = PTROUT(&fp->sf_uc); 233cc6ca9b3SMarcel Moolenaar 2344ba25759SEd Maste /* Fill in POSIX parts. */ 235f4e80108SDmitry Chagin siginfo_to_lsiginfo(&ksi->ksi_info, &frame.sf_si, sig); 236cc6ca9b3SMarcel Moolenaar 2374ba25759SEd Maste /* Build the signal context to be used by sigreturn. */ 2386e826d27SDmitry Chagin frame.sf_uc.uc_stack.ss_sp = PTROUT(td->td_sigstk.ss_sp); 2396e826d27SDmitry Chagin frame.sf_uc.uc_stack.ss_size = td->td_sigstk.ss_size; 2406e826d27SDmitry Chagin frame.sf_uc.uc_stack.ss_flags = (td->td_pflags & TDP_ALTSTACK) 241d034d459SMarcel Moolenaar ? ((oonstack) ? LINUX_SS_ONSTACK : 0) : LINUX_SS_DISABLE; 242611d9407SJohn Baldwin PROC_UNLOCK(p); 243cc6ca9b3SMarcel Moolenaar 2446e826d27SDmitry Chagin bsd_to_linux_sigset(mask, &frame.sf_uc.uc_sigmask); 245cc6ca9b3SMarcel Moolenaar 2466e826d27SDmitry Chagin frame.sf_uc.uc_mcontext.sc_mask = frame.sf_uc.uc_sigmask.__mask; 2476e826d27SDmitry Chagin frame.sf_uc.uc_mcontext.sc_gs = rgs(); 2486e826d27SDmitry Chagin frame.sf_uc.uc_mcontext.sc_fs = regs->tf_fs; 2496e826d27SDmitry Chagin frame.sf_uc.uc_mcontext.sc_es = regs->tf_es; 2506e826d27SDmitry Chagin frame.sf_uc.uc_mcontext.sc_ds = regs->tf_ds; 2516e826d27SDmitry Chagin frame.sf_uc.uc_mcontext.sc_edi = regs->tf_edi; 2526e826d27SDmitry Chagin frame.sf_uc.uc_mcontext.sc_esi = regs->tf_esi; 2536e826d27SDmitry Chagin frame.sf_uc.uc_mcontext.sc_ebp = regs->tf_ebp; 2546e826d27SDmitry Chagin frame.sf_uc.uc_mcontext.sc_ebx = regs->tf_ebx; 2556e826d27SDmitry Chagin frame.sf_uc.uc_mcontext.sc_esp = regs->tf_esp; 2566e826d27SDmitry Chagin frame.sf_uc.uc_mcontext.sc_edx = regs->tf_edx; 2576e826d27SDmitry Chagin frame.sf_uc.uc_mcontext.sc_ecx = regs->tf_ecx; 2586e826d27SDmitry Chagin frame.sf_uc.uc_mcontext.sc_eax = regs->tf_eax; 2596e826d27SDmitry Chagin frame.sf_uc.uc_mcontext.sc_eip = regs->tf_eip; 2606e826d27SDmitry Chagin frame.sf_uc.uc_mcontext.sc_cs = regs->tf_cs; 2616e826d27SDmitry Chagin frame.sf_uc.uc_mcontext.sc_eflags = regs->tf_eflags; 2626e826d27SDmitry Chagin frame.sf_uc.uc_mcontext.sc_esp_at_signal = regs->tf_esp; 2636e826d27SDmitry Chagin frame.sf_uc.uc_mcontext.sc_ss = regs->tf_ss; 2646e826d27SDmitry Chagin frame.sf_uc.uc_mcontext.sc_err = regs->tf_err; 2656e826d27SDmitry Chagin frame.sf_uc.uc_mcontext.sc_cr2 = (register_t)ksi->ksi_addr; 2666e826d27SDmitry Chagin frame.sf_uc.uc_mcontext.sc_trapno = bsd_to_linux_trapcode(code); 26779363394SAndrew Gallatin 26879363394SAndrew Gallatin if (copyout(&frame, fp, sizeof(frame)) != 0) { 26979363394SAndrew Gallatin /* 27079363394SAndrew Gallatin * Process has trashed its stack; give it an illegal 27179363394SAndrew Gallatin * instruction to halt it in its tracks. 27279363394SAndrew Gallatin */ 27319eb87d2SJohn Baldwin PROC_LOCK(p); 274b40ce416SJulian Elischer sigexit(td, SIGILL); 27579363394SAndrew Gallatin } 27679363394SAndrew Gallatin 2774ba25759SEd Maste /* Build context to run handler in. */ 27821f24617SDmitry Chagin regs->tf_esp = PTROUT(fp); 2798f9635dcSDmitry Chagin regs->tf_eip = linux_vdso_rt_sigcode; 28021f24617SDmitry Chagin regs->tf_edi = PTROUT(catcher); 28122eca0bfSKonstantin Belousov regs->tf_eflags &= ~(PSL_T | PSL_VM | PSL_D); 28279363394SAndrew Gallatin regs->tf_cs = _ucodesel; 28379363394SAndrew Gallatin regs->tf_ds = _udatasel; 28479363394SAndrew Gallatin regs->tf_es = _udatasel; 28579363394SAndrew Gallatin regs->tf_fs = _udatasel; 28679363394SAndrew Gallatin regs->tf_ss = _udatasel; 287df53e91cSJohn Baldwin PROC_LOCK(p); 28890af4afaSJohn Baldwin mtx_lock(&psp->ps_mtx); 28979363394SAndrew Gallatin } 29079363394SAndrew Gallatin 291d66a5066SPeter Wemm /* 292d66a5066SPeter Wemm * Send an interrupt to process. 293d66a5066SPeter Wemm * 294d66a5066SPeter Wemm * Stack is set up to allow sigcode stored 295d66a5066SPeter Wemm * in u. to call routine, followed by kcall 296d66a5066SPeter Wemm * to sigreturn routine below. After sigreturn 297d66a5066SPeter Wemm * resets the signal mask, the stack, and the 298d66a5066SPeter Wemm * frame pointer, it returns to the user 299d66a5066SPeter Wemm * specified pc, psl. 300d66a5066SPeter Wemm */ 301303b270bSEivind Eklund static void 3029104847fSDavid Xu linux_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) 303d66a5066SPeter Wemm { 3041d062e2bSDag-Erling Smørgrav struct thread *td = curthread; 3051d062e2bSDag-Erling Smørgrav struct proc *p = td->td_proc; 30690af4afaSJohn Baldwin struct sigacts *psp; 3071d062e2bSDag-Erling Smørgrav struct trapframe *regs; 3085002a60fSMarcel Moolenaar struct l_sigframe *fp, frame; 3095002a60fSMarcel Moolenaar l_sigset_t lmask; 3109e701630SJohn Baldwin int sig; 3114ab7403bSDmitry Chagin int oonstack; 312d66a5066SPeter Wemm 3132509e6c2SJohn Baldwin PROC_LOCK_ASSERT(p, MA_OWNED); 31490af4afaSJohn Baldwin psp = p->p_sigacts; 315eca368ecSDmitry Chagin sig = linux_translate_traps(ksi->ksi_signo, ksi->ksi_trapno); 31690af4afaSJohn Baldwin mtx_assert(&psp->ps_mtx, MA_OWNED); 31790af4afaSJohn Baldwin if (SIGISMEMBER(psp->ps_siginfo, sig)) { 318cc6ca9b3SMarcel Moolenaar /* Signal handler installed with SA_SIGINFO. */ 3199104847fSDavid Xu linux_rt_sendsig(catcher, ksi, mask); 320cc6ca9b3SMarcel Moolenaar return; 321cc6ca9b3SMarcel Moolenaar } 322b40ce416SJulian Elischer regs = td->td_frame; 323d034d459SMarcel Moolenaar oonstack = sigonstack(regs->tf_esp); 324d66a5066SPeter Wemm 3254ba25759SEd Maste /* Allocate space for the signal handler context. */ 326a30ec4b9SDavid Xu if ((td->td_pflags & TDP_ALTSTACK) && !oonstack && 32790af4afaSJohn Baldwin SIGISMEMBER(psp->ps_sigonstack, sig)) { 328aa949be5SJohn Baldwin fp = (struct l_sigframe *)((uintptr_t)td->td_sigstk.ss_sp + 329a30ec4b9SDavid Xu td->td_sigstk.ss_size - sizeof(struct l_sigframe)); 330d034d459SMarcel Moolenaar } else 3315002a60fSMarcel Moolenaar fp = (struct l_sigframe *)regs->tf_esp - 1; 33290af4afaSJohn Baldwin mtx_unlock(&psp->ps_mtx); 333611d9407SJohn Baldwin PROC_UNLOCK(p); 334d66a5066SPeter Wemm 3354ba25759SEd Maste /* Build the argument list for the signal handler. */ 3364ab7403bSDmitry Chagin sig = bsd_to_linux_signal(sig); 337d66a5066SPeter Wemm 33899d45c5fSMarcel Moolenaar bzero(&frame, sizeof(frame)); 33999d45c5fSMarcel Moolenaar 340d66a5066SPeter Wemm frame.sf_sig = sig; 3414a6c2d07SDmitry Chagin frame.sf_sigmask = *mask; 342cc6ca9b3SMarcel Moolenaar bsd_to_linux_sigset(mask, &lmask); 343cc6ca9b3SMarcel Moolenaar 3444ba25759SEd Maste /* Build the signal context to be used by sigreturn. */ 3454ab7403bSDmitry Chagin frame.sf_sc.sc_mask = lmask.__mask; 3465206bca1SLuoqi Chen frame.sf_sc.sc_gs = rgs(); 3475206bca1SLuoqi Chen frame.sf_sc.sc_fs = regs->tf_fs; 348213fdd80SPeter Wemm frame.sf_sc.sc_es = regs->tf_es; 349213fdd80SPeter Wemm frame.sf_sc.sc_ds = regs->tf_ds; 350213fdd80SPeter Wemm frame.sf_sc.sc_edi = regs->tf_edi; 351213fdd80SPeter Wemm frame.sf_sc.sc_esi = regs->tf_esi; 352213fdd80SPeter Wemm frame.sf_sc.sc_ebp = regs->tf_ebp; 353213fdd80SPeter Wemm frame.sf_sc.sc_ebx = regs->tf_ebx; 354bdc37934SDmitry Chagin frame.sf_sc.sc_esp = regs->tf_esp; 355213fdd80SPeter Wemm frame.sf_sc.sc_edx = regs->tf_edx; 356213fdd80SPeter Wemm frame.sf_sc.sc_ecx = regs->tf_ecx; 357213fdd80SPeter Wemm frame.sf_sc.sc_eax = regs->tf_eax; 358213fdd80SPeter Wemm frame.sf_sc.sc_eip = regs->tf_eip; 359213fdd80SPeter Wemm frame.sf_sc.sc_cs = regs->tf_cs; 360213fdd80SPeter Wemm frame.sf_sc.sc_eflags = regs->tf_eflags; 361213fdd80SPeter Wemm frame.sf_sc.sc_esp_at_signal = regs->tf_esp; 362213fdd80SPeter Wemm frame.sf_sc.sc_ss = regs->tf_ss; 363213fdd80SPeter Wemm frame.sf_sc.sc_err = regs->tf_err; 36496a2b635SKonstantin Belousov frame.sf_sc.sc_cr2 = (register_t)ksi->ksi_addr; 3659104847fSDavid Xu frame.sf_sc.sc_trapno = bsd_to_linux_trapcode(ksi->ksi_trapno); 366cc6ca9b3SMarcel Moolenaar 367d66a5066SPeter Wemm if (copyout(&frame, fp, sizeof(frame)) != 0) { 368d66a5066SPeter Wemm /* 369d66a5066SPeter Wemm * Process has trashed its stack; give it an illegal 370d66a5066SPeter Wemm * instruction to halt it in its tracks. 371d66a5066SPeter Wemm */ 37219eb87d2SJohn Baldwin PROC_LOCK(p); 373b40ce416SJulian Elischer sigexit(td, SIGILL); 374d66a5066SPeter Wemm } 375d66a5066SPeter Wemm 3764ba25759SEd Maste /* Build context to run handler in. */ 37721f24617SDmitry Chagin regs->tf_esp = PTROUT(fp); 3788f9635dcSDmitry Chagin regs->tf_eip = linux_vdso_sigcode; 37921f24617SDmitry Chagin regs->tf_edi = PTROUT(catcher); 38022eca0bfSKonstantin Belousov regs->tf_eflags &= ~(PSL_T | PSL_VM | PSL_D); 381213fdd80SPeter Wemm regs->tf_cs = _ucodesel; 382213fdd80SPeter Wemm regs->tf_ds = _udatasel; 383213fdd80SPeter Wemm regs->tf_es = _udatasel; 3845206bca1SLuoqi Chen regs->tf_fs = _udatasel; 385213fdd80SPeter Wemm regs->tf_ss = _udatasel; 3865002a60fSMarcel Moolenaar PROC_LOCK(p); 38790af4afaSJohn Baldwin mtx_lock(&psp->ps_mtx); 388d66a5066SPeter Wemm } 389d66a5066SPeter Wemm 390d66a5066SPeter Wemm /* 391d66a5066SPeter Wemm * System call to cleanup state after a signal 392d66a5066SPeter Wemm * has been taken. Reset signal mask and 393d66a5066SPeter Wemm * stack state from context left by sendsig (above). 394d66a5066SPeter Wemm * Return to previous pc and psl as specified by 395d66a5066SPeter Wemm * context left by sendsig. Check carefully to 396d66a5066SPeter Wemm * make sure that the user has not modified the 397d66a5066SPeter Wemm * psl to gain improper privileges or to cause 398d66a5066SPeter Wemm * a machine fault. 399d66a5066SPeter Wemm */ 400d66a5066SPeter Wemm int 401b07cd97eSMark Murray linux_sigreturn(struct thread *td, struct linux_sigreturn_args *args) 402d66a5066SPeter Wemm { 4035002a60fSMarcel Moolenaar struct l_sigframe frame; 4041d062e2bSDag-Erling Smørgrav struct trapframe *regs; 4054ab7403bSDmitry Chagin int eflags; 4069104847fSDavid Xu ksiginfo_t ksi; 407d66a5066SPeter Wemm 408b40ce416SJulian Elischer regs = td->td_frame; 409d66a5066SPeter Wemm 410d66a5066SPeter Wemm /* 411cc6ca9b3SMarcel Moolenaar * The trampoline code hands us the sigframe. 412d66a5066SPeter Wemm * It is unsafe to keep track of it ourselves, in the event that a 413d66a5066SPeter Wemm * program jumps out of a signal handler. 414d66a5066SPeter Wemm */ 4154b7ef73dSDag-Erling Smørgrav if (copyin(args->sfp, &frame, sizeof(frame)) != 0) 416d66a5066SPeter Wemm return (EFAULT); 417d66a5066SPeter Wemm 4184ba25759SEd Maste /* Check for security violations. */ 419d66a5066SPeter Wemm #define EFLAGS_SECURE(ef, oef) ((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0) 420cc6ca9b3SMarcel Moolenaar eflags = frame.sf_sc.sc_eflags; 4213d271aaaSEd Maste if (!EFLAGS_SECURE(eflags, regs->tf_eflags)) 422d66a5066SPeter Wemm return (EINVAL); 423d66a5066SPeter Wemm 424d66a5066SPeter Wemm /* 425d66a5066SPeter Wemm * Don't allow users to load a valid privileged %cs. Let the 426d66a5066SPeter Wemm * hardware check for invalid selectors, excess privilege in 427d66a5066SPeter Wemm * other selectors, invalid %eip's and invalid %esp's. 428d66a5066SPeter Wemm */ 42940d50994SPhilippe Charnier #define CS_SECURE(cs) (ISPL(cs) == SEL_UPL) 430cc6ca9b3SMarcel Moolenaar if (!CS_SECURE(frame.sf_sc.sc_cs)) { 4319104847fSDavid Xu ksiginfo_init_trap(&ksi); 4329104847fSDavid Xu ksi.ksi_signo = SIGBUS; 4339104847fSDavid Xu ksi.ksi_code = BUS_OBJERR; 4349104847fSDavid Xu ksi.ksi_trapno = T_PROTFLT; 4359104847fSDavid Xu ksi.ksi_addr = (void *)regs->tf_eip; 4369104847fSDavid Xu trapsignal(td, &ksi); 437d66a5066SPeter Wemm return (EINVAL); 438d66a5066SPeter Wemm } 439d66a5066SPeter Wemm 4404a6c2d07SDmitry Chagin kern_sigprocmask(td, SIG_SETMASK, &frame.sf_sigmask, NULL, 0); 441956d3333SMarcel Moolenaar 4424ba25759SEd Maste /* Restore signal context. */ 4435206bca1SLuoqi Chen /* %gs was restored by the trampoline. */ 444cc6ca9b3SMarcel Moolenaar regs->tf_fs = frame.sf_sc.sc_fs; 445cc6ca9b3SMarcel Moolenaar regs->tf_es = frame.sf_sc.sc_es; 446cc6ca9b3SMarcel Moolenaar regs->tf_ds = frame.sf_sc.sc_ds; 447cc6ca9b3SMarcel Moolenaar regs->tf_edi = frame.sf_sc.sc_edi; 448cc6ca9b3SMarcel Moolenaar regs->tf_esi = frame.sf_sc.sc_esi; 449cc6ca9b3SMarcel Moolenaar regs->tf_ebp = frame.sf_sc.sc_ebp; 450cc6ca9b3SMarcel Moolenaar regs->tf_ebx = frame.sf_sc.sc_ebx; 451cc6ca9b3SMarcel Moolenaar regs->tf_edx = frame.sf_sc.sc_edx; 452cc6ca9b3SMarcel Moolenaar regs->tf_ecx = frame.sf_sc.sc_ecx; 453cc6ca9b3SMarcel Moolenaar regs->tf_eax = frame.sf_sc.sc_eax; 454cc6ca9b3SMarcel Moolenaar regs->tf_eip = frame.sf_sc.sc_eip; 455cc6ca9b3SMarcel Moolenaar regs->tf_cs = frame.sf_sc.sc_cs; 456213fdd80SPeter Wemm regs->tf_eflags = eflags; 457cc6ca9b3SMarcel Moolenaar regs->tf_esp = frame.sf_sc.sc_esp_at_signal; 458cc6ca9b3SMarcel Moolenaar regs->tf_ss = frame.sf_sc.sc_ss; 459d66a5066SPeter Wemm 460d66a5066SPeter Wemm return (EJUSTRETURN); 461d66a5066SPeter Wemm } 462d66a5066SPeter Wemm 46379363394SAndrew Gallatin /* 46479363394SAndrew Gallatin * System call to cleanup state after a signal 46579363394SAndrew Gallatin * has been taken. Reset signal mask and 46679363394SAndrew Gallatin * stack state from context left by rt_sendsig (above). 46779363394SAndrew Gallatin * Return to previous pc and psl as specified by 46879363394SAndrew Gallatin * context left by sendsig. Check carefully to 46979363394SAndrew Gallatin * make sure that the user has not modified the 47079363394SAndrew Gallatin * psl to gain improper privileges or to cause 47179363394SAndrew Gallatin * a machine fault. 47279363394SAndrew Gallatin */ 47379363394SAndrew Gallatin int 474b07cd97eSMark Murray linux_rt_sigreturn(struct thread *td, struct linux_rt_sigreturn_args *args) 47579363394SAndrew Gallatin { 4765002a60fSMarcel Moolenaar struct l_ucontext uc; 4775002a60fSMarcel Moolenaar struct l_sigcontext *context; 478d6e029adSKonstantin Belousov sigset_t bmask; 4795002a60fSMarcel Moolenaar l_stack_t *lss; 480206a5d3aSIan Dowse stack_t ss; 4811d062e2bSDag-Erling Smørgrav struct trapframe *regs; 48279363394SAndrew Gallatin int eflags; 4839104847fSDavid Xu ksiginfo_t ksi; 48479363394SAndrew Gallatin 485b40ce416SJulian Elischer regs = td->td_frame; 48679363394SAndrew Gallatin 48779363394SAndrew Gallatin /* 488cc6ca9b3SMarcel Moolenaar * The trampoline code hands us the ucontext. 48979363394SAndrew Gallatin * It is unsafe to keep track of it ourselves, in the event that a 49079363394SAndrew Gallatin * program jumps out of a signal handler. 49179363394SAndrew Gallatin */ 4924b7ef73dSDag-Erling Smørgrav if (copyin(args->ucp, &uc, sizeof(uc)) != 0) 49379363394SAndrew Gallatin return (EFAULT); 49479363394SAndrew Gallatin 49579363394SAndrew Gallatin context = &uc.uc_mcontext; 49679363394SAndrew Gallatin 4974ba25759SEd Maste /* Check for security violations. */ 49879363394SAndrew Gallatin #define EFLAGS_SECURE(ef, oef) ((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0) 49979363394SAndrew Gallatin eflags = context->sc_eflags; 5003d271aaaSEd Maste if (!EFLAGS_SECURE(eflags, regs->tf_eflags)) 50179363394SAndrew Gallatin return (EINVAL); 50279363394SAndrew Gallatin 50379363394SAndrew Gallatin /* 50479363394SAndrew Gallatin * Don't allow users to load a valid privileged %cs. Let the 50579363394SAndrew Gallatin * hardware check for invalid selectors, excess privilege in 50679363394SAndrew Gallatin * other selectors, invalid %eip's and invalid %esp's. 50779363394SAndrew Gallatin */ 50879363394SAndrew Gallatin #define CS_SECURE(cs) (ISPL(cs) == SEL_UPL) 50979363394SAndrew Gallatin if (!CS_SECURE(context->sc_cs)) { 5109104847fSDavid Xu ksiginfo_init_trap(&ksi); 5119104847fSDavid Xu ksi.ksi_signo = SIGBUS; 5129104847fSDavid Xu ksi.ksi_code = BUS_OBJERR; 5139104847fSDavid Xu ksi.ksi_trapno = T_PROTFLT; 5149104847fSDavid Xu ksi.ksi_addr = (void *)regs->tf_eip; 5159104847fSDavid Xu trapsignal(td, &ksi); 51679363394SAndrew Gallatin return (EINVAL); 51779363394SAndrew Gallatin } 51879363394SAndrew Gallatin 519d6e029adSKonstantin Belousov linux_to_bsd_sigset(&uc.uc_sigmask, &bmask); 520d6e029adSKonstantin Belousov kern_sigprocmask(td, SIG_SETMASK, &bmask, NULL, 0); 52179363394SAndrew Gallatin 5224ba25759SEd Maste /* Restore signal context. */ 52379363394SAndrew Gallatin /* %gs was restored by the trampoline. */ 52479363394SAndrew Gallatin regs->tf_fs = context->sc_fs; 52579363394SAndrew Gallatin regs->tf_es = context->sc_es; 52679363394SAndrew Gallatin regs->tf_ds = context->sc_ds; 52779363394SAndrew Gallatin regs->tf_edi = context->sc_edi; 52879363394SAndrew Gallatin regs->tf_esi = context->sc_esi; 52979363394SAndrew Gallatin regs->tf_ebp = context->sc_ebp; 53079363394SAndrew Gallatin regs->tf_ebx = context->sc_ebx; 53179363394SAndrew Gallatin regs->tf_edx = context->sc_edx; 53279363394SAndrew Gallatin regs->tf_ecx = context->sc_ecx; 53379363394SAndrew Gallatin regs->tf_eax = context->sc_eax; 53479363394SAndrew Gallatin regs->tf_eip = context->sc_eip; 53579363394SAndrew Gallatin regs->tf_cs = context->sc_cs; 53679363394SAndrew Gallatin regs->tf_eflags = eflags; 53779363394SAndrew Gallatin regs->tf_esp = context->sc_esp_at_signal; 53879363394SAndrew Gallatin regs->tf_ss = context->sc_ss; 53979363394SAndrew Gallatin 5404ba25759SEd Maste /* Call sigaltstack & ignore results. */ 54179363394SAndrew Gallatin lss = &uc.uc_stack; 54230c6d982SEdward Tomasz Napierala ss.ss_sp = PTRIN(lss->ss_sp); 543206a5d3aSIan Dowse ss.ss_size = lss->ss_size; 544206a5d3aSIan Dowse ss.ss_flags = linux_to_bsd_sigaltstack(lss->ss_flags); 54579363394SAndrew Gallatin 546206a5d3aSIan Dowse (void)kern_sigaltstack(td, &ss, NULL); 54779363394SAndrew Gallatin 54879363394SAndrew Gallatin return (EJUSTRETURN); 54979363394SAndrew Gallatin } 55079363394SAndrew Gallatin 551afe1a688SKonstantin Belousov static int 5522d88da2fSKonstantin Belousov linux_fetch_syscall_args(struct thread *td) 553d66a5066SPeter Wemm { 554afe1a688SKonstantin Belousov struct proc *p; 555afe1a688SKonstantin Belousov struct trapframe *frame; 5562d88da2fSKonstantin Belousov struct syscall_args *sa; 557afe1a688SKonstantin Belousov 558afe1a688SKonstantin Belousov p = td->td_proc; 559afe1a688SKonstantin Belousov frame = td->td_frame; 5602d88da2fSKonstantin Belousov sa = &td->td_sa; 561afe1a688SKonstantin Belousov 562afe1a688SKonstantin Belousov sa->code = frame->tf_eax; 563cf98bc28SDavid Chisnall sa->original_code = sa->code; 564afe1a688SKonstantin Belousov sa->args[0] = frame->tf_ebx; 565afe1a688SKonstantin Belousov sa->args[1] = frame->tf_ecx; 566afe1a688SKonstantin Belousov sa->args[2] = frame->tf_edx; 567afe1a688SKonstantin Belousov sa->args[3] = frame->tf_esi; 568afe1a688SKonstantin Belousov sa->args[4] = frame->tf_edi; 569afe1a688SKonstantin Belousov sa->args[5] = frame->tf_ebp; /* Unconfirmed */ 570afe1a688SKonstantin Belousov 571afe1a688SKonstantin Belousov if (sa->code >= p->p_sysent->sv_size) 572fcdffc03SDmitry Chagin /* nosys */ 5731b8d0393SConrad Meyer sa->callp = &p->p_sysent->sv_table[p->p_sysent->sv_size - 1]; 574afe1a688SKonstantin Belousov else 575afe1a688SKonstantin Belousov sa->callp = &p->p_sysent->sv_table[sa->code]; 576afe1a688SKonstantin Belousov 577afe1a688SKonstantin Belousov td->td_retval[0] = 0; 578afe1a688SKonstantin Belousov td->td_retval[1] = frame->tf_edx; 579afe1a688SKonstantin Belousov 580afe1a688SKonstantin Belousov return (0); 581d66a5066SPeter Wemm } 582d66a5066SPeter Wemm 583c26391f4SEdward Tomasz Napierala static void 584c26391f4SEdward Tomasz Napierala linux_set_syscall_retval(struct thread *td, int error) 585c26391f4SEdward Tomasz Napierala { 586c26391f4SEdward Tomasz Napierala struct trapframe *frame = td->td_frame; 587c26391f4SEdward Tomasz Napierala 588c26391f4SEdward Tomasz Napierala cpu_set_syscall_retval(td, error); 589c26391f4SEdward Tomasz Napierala 590c26391f4SEdward Tomasz Napierala if (__predict_false(error != 0)) { 591c26391f4SEdward Tomasz Napierala if (error != ERESTART && error != EJUSTRETURN) 592866b1f51SEdward Tomasz Napierala frame->tf_eax = bsd_to_linux_errno(error); 593c26391f4SEdward Tomasz Napierala } 594c26391f4SEdward Tomasz Napierala } 595c26391f4SEdward Tomasz Napierala 596de8374dfSDmitry Chagin static void 597de8374dfSDmitry Chagin linux_set_fork_retval(struct thread *td) 598de8374dfSDmitry Chagin { 599de8374dfSDmitry Chagin struct trapframe *frame = td->td_frame; 600de8374dfSDmitry Chagin 601de8374dfSDmitry Chagin frame->tf_eax = 0; 602de8374dfSDmitry Chagin } 603de8374dfSDmitry Chagin 604d323ddf3SMatthew Dillon /* 605598d45beSMatthew N. Dodd * exec_setregs may initialize some registers differently than Linux 606598d45beSMatthew N. Dodd * does, thus potentially confusing Linux binaries. If necessary, we 607598d45beSMatthew N. Dodd * override the exec_setregs default(s) here. 608598d45beSMatthew N. Dodd */ 609598d45beSMatthew N. Dodd static void 61031174518SJohn Baldwin linux_exec_setregs(struct thread *td, struct image_params *imgp, 61131174518SJohn Baldwin uintptr_t stack) 612598d45beSMatthew N. Dodd { 613598d45beSMatthew N. Dodd struct pcb *pcb = td->td_pcb; 614598d45beSMatthew N. Dodd 615a107d8aaSNathan Whitehorn exec_setregs(td, imgp, stack); 616598d45beSMatthew N. Dodd 6174ba25759SEd Maste /* Linux sets %gs to 0, we default to _udatasel. */ 6182ee8325fSJohn Baldwin pcb->pcb_gs = 0; 6192ee8325fSJohn Baldwin load_gs(0); 6202a51b9b0SDavid Schultz 6212ee8325fSJohn Baldwin pcb->pcb_initial_npxcw = __LINUX_NPXCW__; 622598d45beSMatthew N. Dodd } 623598d45beSMatthew N. Dodd 624d66a5066SPeter Wemm struct sysentvec linux_sysvec = { 625a8d403e1SKonstantin Belousov .sv_size = LINUX_SYS_MAXSYSCALL, 626a8d403e1SKonstantin Belousov .sv_table = linux_sysent, 627a8d403e1SKonstantin Belousov .sv_fixup = linux_fixup, 628a8d403e1SKonstantin Belousov .sv_sendsig = linux_sendsig, 6299931033bSDmitry Chagin .sv_sigcode = &_binary_linux_vdso_so_o_start, 630a8d403e1SKonstantin Belousov .sv_szsigcode = &linux_szsigcode, 631a8d403e1SKonstantin Belousov .sv_name = "Linux a.out", 632a8d403e1SKonstantin Belousov .sv_coredump = NULL, 633dc858467SEd Maste .sv_imgact_try = linux_exec_imgact_try, 634a8d403e1SKonstantin Belousov .sv_minsigstksz = LINUX_MINSIGSTKSZ, 635a8d403e1SKonstantin Belousov .sv_minuser = VM_MIN_ADDRESS, 636a8d403e1SKonstantin Belousov .sv_maxuser = VM_MAXUSER_ADDRESS, 6378f1e49a6SDmitry Chagin .sv_usrstack = LINUX_USRSTACK, 638a8d403e1SKonstantin Belousov .sv_psstrings = PS_STRINGS, 6393fc21fddSMark Johnston .sv_psstringssz = sizeof(struct ps_strings), 640a8d403e1SKonstantin Belousov .sv_stackprot = VM_PROT_ALL, 641a8d403e1SKonstantin Belousov .sv_copyout_strings = exec_copyout_strings, 642dc858467SEd Maste .sv_setregs = linux_exec_setregs, 643a8d403e1SKonstantin Belousov .sv_fixlimit = NULL, 644b4cf0e62SKonstantin Belousov .sv_maxssiz = NULL, 645870e197dSKonstantin Belousov .sv_flags = SV_ABI_LINUX | SV_AOUT | SV_IA32 | SV_ILP32 | 646870e197dSKonstantin Belousov SV_SIG_DISCIGN | SV_SIG_WAITNDQ, 647c26391f4SEdward Tomasz Napierala .sv_set_syscall_retval = linux_set_syscall_retval, 648afe1a688SKonstantin Belousov .sv_fetch_syscall_args = linux_fetch_syscall_args, 6491da65dcbSMitchell Horne .sv_syscallnames = linux_syscallnames, 650e5d81ef1SDmitry Chagin .sv_schedtail = linux_schedtail, 65181338031SDmitry Chagin .sv_thread_detach = linux_thread_detach, 652038c7205SDmitry Chagin .sv_trap = NULL, 6535fd9cd53SDmitry Chagin .sv_onexec = linux_on_exec_vmspace, 6544815f175SKonstantin Belousov .sv_onexit = linux_on_exit, 6554815f175SKonstantin Belousov .sv_ontdexit = linux_thread_dtor, 656598f6fb4SKonstantin Belousov .sv_setid_allowed = &linux_setid_allowed_query, 657de8374dfSDmitry Chagin .sv_set_fork_retval = linux_set_fork_retval, 658d66a5066SPeter Wemm }; 6598f1e49a6SDmitry Chagin INIT_SYSENTVEC(aout_sysvec, &linux_sysvec); 660e1743d02SSøren Schmidt 661e1743d02SSøren Schmidt struct sysentvec elf_linux_sysvec = { 662a8d403e1SKonstantin Belousov .sv_size = LINUX_SYS_MAXSYSCALL, 663a8d403e1SKonstantin Belousov .sv_table = linux_sysent, 6649e550625SDmitry Chagin .sv_fixup = __elfN(freebsd_fixup), 665a8d403e1SKonstantin Belousov .sv_sendsig = linux_sendsig, 6669931033bSDmitry Chagin .sv_sigcode = &_binary_linux_vdso_so_o_start, 667a8d403e1SKonstantin Belousov .sv_szsigcode = &linux_szsigcode, 6685faeda90SJessica Clarke .sv_name = "Linux ELF32", 669a8d403e1SKonstantin Belousov .sv_coredump = elf32_coredump, 670cc1b0f7dSDmitry Chagin .sv_elf_core_osabi = ELFOSABI_NONE, 671cc1b0f7dSDmitry Chagin .sv_elf_core_abi_vendor = LINUX_ABI_VENDOR, 672cc1b0f7dSDmitry Chagin .sv_elf_core_prepare_notes = __linuxN(prepare_notes), 673dc858467SEd Maste .sv_imgact_try = linux_exec_imgact_try, 674a8d403e1SKonstantin Belousov .sv_minsigstksz = LINUX_MINSIGSTKSZ, 675a8d403e1SKonstantin Belousov .sv_minuser = VM_MIN_ADDRESS, 676a8d403e1SKonstantin Belousov .sv_maxuser = VM_MAXUSER_ADDRESS, 6778f1e49a6SDmitry Chagin .sv_usrstack = LINUX_USRSTACK, 6788f1e49a6SDmitry Chagin .sv_psstrings = LINUX_PS_STRINGS, 6793fc21fddSMark Johnston .sv_psstringssz = sizeof(struct ps_strings), 680a8d403e1SKonstantin Belousov .sv_stackprot = VM_PROT_ALL, 6815caa67faSJohn Baldwin .sv_copyout_auxargs = linux_copyout_auxargs, 6826039e966SDmitry Chagin .sv_copyout_strings = __linuxN(copyout_strings), 683dc858467SEd Maste .sv_setregs = linux_exec_setregs, 684a8d403e1SKonstantin Belousov .sv_fixlimit = NULL, 685b4cf0e62SKonstantin Belousov .sv_maxssiz = NULL, 686870e197dSKonstantin Belousov .sv_flags = SV_ABI_LINUX | SV_IA32 | SV_ILP32 | SV_SHP | 6879931033bSDmitry Chagin SV_SIG_DISCIGN | SV_SIG_WAITNDQ | SV_TIMEKEEP, 688c26391f4SEdward Tomasz Napierala .sv_set_syscall_retval = linux_set_syscall_retval, 689afe1a688SKonstantin Belousov .sv_fetch_syscall_args = linux_fetch_syscall_args, 690afe1a688SKonstantin Belousov .sv_syscallnames = NULL, 6918f1e49a6SDmitry Chagin .sv_shared_page_base = LINUX_SHAREDPAGE, 6928f1e49a6SDmitry Chagin .sv_shared_page_len = PAGE_SIZE, 693e5d81ef1SDmitry Chagin .sv_schedtail = linux_schedtail, 69481338031SDmitry Chagin .sv_thread_detach = linux_thread_detach, 695038c7205SDmitry Chagin .sv_trap = NULL, 6965fd9cd53SDmitry Chagin .sv_onexec = linux_on_exec_vmspace, 6974815f175SKonstantin Belousov .sv_onexit = linux_on_exit, 6984815f175SKonstantin Belousov .sv_ontdexit = linux_thread_dtor, 699598f6fb4SKonstantin Belousov .sv_setid_allowed = &linux_setid_allowed_query, 700de8374dfSDmitry Chagin .sv_set_fork_retval = linux_set_fork_retval, 701e1743d02SSøren Schmidt }; 702bdc37934SDmitry Chagin 7035fd9cd53SDmitry Chagin static int 7045fd9cd53SDmitry Chagin linux_on_exec_vmspace(struct proc *p, struct image_params *imgp) 7055fd9cd53SDmitry Chagin { 7069931033bSDmitry Chagin int error = 0; 7075fd9cd53SDmitry Chagin 7089931033bSDmitry Chagin if (SV_PROC_FLAG(p, SV_SHP) != 0) 7099931033bSDmitry Chagin error = linux_map_vdso(p, linux_vdso_obj, 7109931033bSDmitry Chagin linux_vdso_base, LINUX_VDSOPAGE_SIZE, imgp); 7119931033bSDmitry Chagin if (error == 0) 7125fd9cd53SDmitry Chagin linux_on_exec(p, imgp); 7139931033bSDmitry Chagin return (error); 7145fd9cd53SDmitry Chagin } 7155fd9cd53SDmitry Chagin 71609cffde9SDmitry Chagin /* 71709cffde9SDmitry Chagin * linux_vdso_install() and linux_exec_sysvec_init() must be called 71809cffde9SDmitry Chagin * after exec_sysvec_init() which is SI_SUB_EXEC (SI_ORDER_ANY). 71909cffde9SDmitry Chagin */ 720bdc37934SDmitry Chagin static void 7219931033bSDmitry Chagin linux_exec_sysvec_init(void *param) 7229931033bSDmitry Chagin { 7239931033bSDmitry Chagin l_uintptr_t *ktimekeep_base, *ktsc_selector; 7249931033bSDmitry Chagin struct sysentvec *sv; 7259931033bSDmitry Chagin ptrdiff_t tkoff; 7269931033bSDmitry Chagin 7279931033bSDmitry Chagin sv = param; 7289931033bSDmitry Chagin /* Fill timekeep_base */ 7299931033bSDmitry Chagin exec_sysvec_init(sv); 7309931033bSDmitry Chagin 7319931033bSDmitry Chagin tkoff = kern_timekeep_base - linux_vdso_base; 7329931033bSDmitry Chagin ktimekeep_base = (l_uintptr_t *)(linux_vdso_mapping + tkoff); 733361971fbSKornel Dulęba *ktimekeep_base = sv->sv_shared_page_base + sv->sv_timekeep_offset; 7349931033bSDmitry Chagin 7359931033bSDmitry Chagin tkoff = kern_tsc_selector - linux_vdso_base; 7369931033bSDmitry Chagin ktsc_selector = (l_uintptr_t *)(linux_vdso_mapping + tkoff); 7379931033bSDmitry Chagin *ktsc_selector = linux_vdso_tsc_selector_idx(); 7389931033bSDmitry Chagin if (bootverbose) 7399931033bSDmitry Chagin printf("Linux i386 vDSO tsc_selector: %u\n", *ktsc_selector); 7405a6a4fb2SDmitry Chagin 7415a6a4fb2SDmitry Chagin tkoff = kern_cpu_selector - linux_vdso_base; 7425a6a4fb2SDmitry Chagin ktsc_selector = (l_uintptr_t *)(linux_vdso_mapping + tkoff); 7435a6a4fb2SDmitry Chagin *ktsc_selector = linux_vdso_cpu_selector_idx(); 7445a6a4fb2SDmitry Chagin if (bootverbose) 7455a6a4fb2SDmitry Chagin printf("Linux i386 vDSO cpu_selector: %u\n", *ktsc_selector); 7469931033bSDmitry Chagin } 74709cffde9SDmitry Chagin SYSINIT(elf_linux_exec_sysvec_init, SI_SUB_EXEC + 1, SI_ORDER_ANY, 7489931033bSDmitry Chagin linux_exec_sysvec_init, &elf_linux_sysvec); 7499931033bSDmitry Chagin 7509931033bSDmitry Chagin static void 751a543556cSDmitry Chagin linux_vdso_install(const void *param) 752bdc37934SDmitry Chagin { 7539931033bSDmitry Chagin char *vdso_start = &_binary_linux_vdso_so_o_start; 7549931033bSDmitry Chagin char *vdso_end = &_binary_linux_vdso_so_o_end; 755bdc37934SDmitry Chagin 7569931033bSDmitry Chagin linux_szsigcode = vdso_end - vdso_start; 7579931033bSDmitry Chagin MPASS(linux_szsigcode <= LINUX_VDSOPAGE_SIZE); 758bdc37934SDmitry Chagin 7599931033bSDmitry Chagin linux_vdso_base = LINUX_VDSOPAGE; 760bdc37934SDmitry Chagin 7619931033bSDmitry Chagin __elfN(linux_vdso_fixup)(vdso_start, linux_vdso_base); 762bdc37934SDmitry Chagin 7639931033bSDmitry Chagin linux_vdso_obj = __elfN(linux_shared_page_init) 7649931033bSDmitry Chagin (&linux_vdso_mapping, LINUX_VDSOPAGE_SIZE); 7659931033bSDmitry Chagin bcopy(vdso_start, linux_vdso_mapping, linux_szsigcode); 766bdc37934SDmitry Chagin 7679931033bSDmitry Chagin linux_vdso_reloc(linux_vdso_mapping, linux_vdso_base); 768bdc37934SDmitry Chagin } 76909cffde9SDmitry Chagin SYSINIT(elf_linux_vdso_init, SI_SUB_EXEC + 1, SI_ORDER_FIRST, 770f8268d4dSEd Maste linux_vdso_install, NULL); 771bdc37934SDmitry Chagin 772bdc37934SDmitry Chagin static void 773a543556cSDmitry Chagin linux_vdso_deinstall(const void *param) 774bdc37934SDmitry Chagin { 775bdc37934SDmitry Chagin 7769931033bSDmitry Chagin __elfN(linux_shared_page_fini)(linux_vdso_obj, 7779931033bSDmitry Chagin linux_vdso_mapping, LINUX_VDSOPAGE_SIZE); 7787b194b3dSEd Maste } 779bdc37934SDmitry Chagin SYSUNINIT(elf_linux_vdso_uninit, SI_SUB_EXEC, SI_ORDER_FIRST, 780f8268d4dSEd Maste linux_vdso_deinstall, NULL); 781e1743d02SSøren Schmidt 7829931033bSDmitry Chagin static void 7839931033bSDmitry Chagin linux_vdso_reloc(char *mapping, Elf_Addr offset) 7849931033bSDmitry Chagin { 7859931033bSDmitry Chagin const Elf_Shdr *shdr; 7869931033bSDmitry Chagin const Elf_Rel *rel; 7879931033bSDmitry Chagin const Elf_Ehdr *ehdr; 7889931033bSDmitry Chagin Elf_Addr *where; 7899931033bSDmitry Chagin Elf_Size rtype, symidx; 7909931033bSDmitry Chagin Elf_Addr addr, addend; 7919931033bSDmitry Chagin int i, relcnt; 7929931033bSDmitry Chagin 7939931033bSDmitry Chagin MPASS(offset != 0); 7949931033bSDmitry Chagin 7959931033bSDmitry Chagin relcnt = 0; 7969931033bSDmitry Chagin ehdr = (const Elf_Ehdr *)mapping; 7979931033bSDmitry Chagin shdr = (const Elf_Shdr *)(mapping + ehdr->e_shoff); 7989931033bSDmitry Chagin for (i = 0; i < ehdr->e_shnum; i++) 7999931033bSDmitry Chagin { 8009931033bSDmitry Chagin switch (shdr[i].sh_type) { 8019931033bSDmitry Chagin case SHT_REL: 8029931033bSDmitry Chagin rel = (const Elf_Rel *)(mapping + shdr[i].sh_offset); 8039931033bSDmitry Chagin relcnt = shdr[i].sh_size / sizeof(*rel); 8049931033bSDmitry Chagin break; 8059931033bSDmitry Chagin case SHT_RELA: 8069931033bSDmitry Chagin printf("Linux i386 vDSO: unexpected Rela section\n"); 8079931033bSDmitry Chagin break; 8089931033bSDmitry Chagin } 8099931033bSDmitry Chagin } 8109931033bSDmitry Chagin 8119931033bSDmitry Chagin for (i = 0; i < relcnt; i++, rel++) { 8129931033bSDmitry Chagin where = (Elf_Addr *)(mapping + rel->r_offset); 8139931033bSDmitry Chagin addend = *where; 8149931033bSDmitry Chagin rtype = ELF_R_TYPE(rel->r_info); 8159931033bSDmitry Chagin symidx = ELF_R_SYM(rel->r_info); 8169931033bSDmitry Chagin 8179931033bSDmitry Chagin switch (rtype) { 8189931033bSDmitry Chagin case R_386_NONE: /* none */ 8199931033bSDmitry Chagin break; 8209931033bSDmitry Chagin 8219931033bSDmitry Chagin case R_386_RELATIVE: /* B + A */ 8229931033bSDmitry Chagin addr = (Elf_Addr)PTROUT(offset + addend); 8239931033bSDmitry Chagin if (*where != addr) 8249931033bSDmitry Chagin *where = addr; 8259931033bSDmitry Chagin break; 8269931033bSDmitry Chagin 8279931033bSDmitry Chagin case R_386_IRELATIVE: 8289931033bSDmitry Chagin printf("Linux i386 vDSO: unexpected ifunc relocation, " 8299931033bSDmitry Chagin "symbol index %d\n", symidx); 8309931033bSDmitry Chagin break; 8319931033bSDmitry Chagin default: 8329931033bSDmitry Chagin printf("Linux i386 vDSO: unexpected relocation type %d, " 8339931033bSDmitry Chagin "symbol index %d\n", rtype, symidx); 8349931033bSDmitry Chagin } 8359931033bSDmitry Chagin } 8369931033bSDmitry Chagin } 8379931033bSDmitry Chagin 83832c01de2SDmitry Chagin static Elf_Brandnote linux_brandnote = { 83989ffc202SBjoern A. Zeeb .hdr.n_namesz = sizeof(GNU_ABI_VENDOR), 84089ffc202SBjoern A. Zeeb .hdr.n_descsz = 16, /* XXX at least 16 */ 84132c01de2SDmitry Chagin .hdr.n_type = 1, 84289ffc202SBjoern A. Zeeb .vendor = GNU_ABI_VENDOR, 84389ffc202SBjoern A. Zeeb .flags = BN_TRANSLATE_OSREL, 84489ffc202SBjoern A. Zeeb .trans_osrel = linux_trans_osrel 84532c01de2SDmitry Chagin }; 84632c01de2SDmitry Chagin 847514058dcSAlexander Langer static Elf32_Brandinfo linux_brand = { 848a8d403e1SKonstantin Belousov .brand = ELFOSABI_LINUX, 849a8d403e1SKonstantin Belousov .machine = EM_386, 850a8d403e1SKonstantin Belousov .compat_3_brand = "Linux", 851b5f20658SEdward Tomasz Napierala .emul_path = linux_emul_path, 852a8d403e1SKonstantin Belousov .interp_path = "/lib/ld-linux.so.1", 853a8d403e1SKonstantin Belousov .sysvec = &elf_linux_sysvec, 854a8d403e1SKonstantin Belousov .interp_newpath = NULL, 85532c01de2SDmitry Chagin .brand_note = &linux_brandnote, 8562dedc128SDmitry Chagin .flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE 8575cf588ebSPeter Wemm }; 8585cf588ebSPeter Wemm 859514058dcSAlexander Langer static Elf32_Brandinfo linux_glibc2brand = { 860a8d403e1SKonstantin Belousov .brand = ELFOSABI_LINUX, 861a8d403e1SKonstantin Belousov .machine = EM_386, 862a8d403e1SKonstantin Belousov .compat_3_brand = "Linux", 863b5f20658SEdward Tomasz Napierala .emul_path = linux_emul_path, 864a8d403e1SKonstantin Belousov .interp_path = "/lib/ld-linux.so.2", 865a8d403e1SKonstantin Belousov .sysvec = &elf_linux_sysvec, 866a8d403e1SKonstantin Belousov .interp_newpath = NULL, 86732c01de2SDmitry Chagin .brand_note = &linux_brandnote, 8682dedc128SDmitry Chagin .flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE 8694e138a28SMike Smith }; 8704e138a28SMike Smith 871a0c59c7aSDmitry Chagin static Elf32_Brandinfo linux_muslbrand = { 872a0c59c7aSDmitry Chagin .brand = ELFOSABI_LINUX, 873a0c59c7aSDmitry Chagin .machine = EM_386, 874a0c59c7aSDmitry Chagin .compat_3_brand = "Linux", 875b5f20658SEdward Tomasz Napierala .emul_path = linux_emul_path, 876a0c59c7aSDmitry Chagin .interp_path = "/lib/ld-musl-i386.so.1", 877a0c59c7aSDmitry Chagin .sysvec = &elf_linux_sysvec, 878a0c59c7aSDmitry Chagin .interp_newpath = NULL, 879a0c59c7aSDmitry Chagin .brand_note = &linux_brandnote, 880cf8d74e3SDmitry Chagin .flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE | 881cf8d74e3SDmitry Chagin LINUX_BI_FUTEX_REQUEUE 882a0c59c7aSDmitry Chagin }; 883a0c59c7aSDmitry Chagin 884514058dcSAlexander Langer Elf32_Brandinfo *linux_brandlist[] = { 885514058dcSAlexander Langer &linux_brand, 886514058dcSAlexander Langer &linux_glibc2brand, 887a0c59c7aSDmitry Chagin &linux_muslbrand, 888514058dcSAlexander Langer NULL 889514058dcSAlexander Langer }; 890514058dcSAlexander Langer 891aa855a59SPeter Wemm static int 892c25ded31SBruce Evans linux_elf_modevent(module_t mod, int type, void *data) 893d30ea4f5SPeter Wemm { 894514058dcSAlexander Langer Elf32_Brandinfo **brandinfo; 895514058dcSAlexander Langer int error; 896f41325dbSPeter Wemm struct linux_ioctl_handler **lihp; 897514058dcSAlexander Langer 898514058dcSAlexander Langer error = 0; 899514058dcSAlexander Langer 900aa855a59SPeter Wemm switch(type) { 901aa855a59SPeter Wemm case MOD_LOAD: 902aa855a59SPeter Wemm for (brandinfo = &linux_brandlist[0]; *brandinfo != NULL; 903aa855a59SPeter Wemm ++brandinfo) 9043ebc1248SPeter Wemm if (elf32_insert_brand_entry(*brandinfo) < 0) 905aa855a59SPeter Wemm error = EINVAL; 906466b14d7SMarcel Moolenaar if (error == 0) { 907f41325dbSPeter Wemm SET_FOREACH(lihp, linux_ioctl_handler_set) 908f41325dbSPeter Wemm linux_ioctl_register_handler(*lihp); 909044ab55eSEdward Tomasz Napierala linux_dev_shm_create(); 9107ae27ff4SJamie Gritton linux_osd_jail_register(); 91107db1f36SDmitry Chagin linux_netlink_register(); 9121ca16454SDmitry Chagin stclohz = (stathz ? stathz : hz); 91343bef515SMarcel Moolenaar if (bootverbose) 914466b14d7SMarcel Moolenaar printf("Linux ELF exec handler installed\n"); 915466b14d7SMarcel Moolenaar } else 916466b14d7SMarcel Moolenaar printf("cannot insert Linux ELF brand handler\n"); 917aa855a59SPeter Wemm break; 918aa855a59SPeter Wemm case MOD_UNLOAD: 919aa855a59SPeter Wemm for (brandinfo = &linux_brandlist[0]; *brandinfo != NULL; 920aa855a59SPeter Wemm ++brandinfo) 9213ebc1248SPeter Wemm if (elf32_brand_inuse(*brandinfo)) 922d2758342SMark Newton error = EBUSY; 923d2758342SMark Newton if (error == 0) { 924d2758342SMark Newton for (brandinfo = &linux_brandlist[0]; 925d2758342SMark Newton *brandinfo != NULL; ++brandinfo) 9263ebc1248SPeter Wemm if (elf32_remove_brand_entry(*brandinfo) < 0) 927aa855a59SPeter Wemm error = EINVAL; 928d2758342SMark Newton } 929466b14d7SMarcel Moolenaar if (error == 0) { 930f41325dbSPeter Wemm SET_FOREACH(lihp, linux_ioctl_handler_set) 931f41325dbSPeter Wemm linux_ioctl_unregister_handler(*lihp); 93207db1f36SDmitry Chagin linux_netlink_deregister(); 933044ab55eSEdward Tomasz Napierala linux_dev_shm_destroy(); 9347ae27ff4SJamie Gritton linux_osd_jail_deregister(); 935466b14d7SMarcel Moolenaar if (bootverbose) 936466b14d7SMarcel Moolenaar printf("Linux ELF exec handler removed\n"); 937466b14d7SMarcel Moolenaar } else 938aa855a59SPeter Wemm printf("Could not deinstall ELF interpreter entry\n"); 939aa855a59SPeter Wemm break; 940aa855a59SPeter Wemm default: 941af682d48SDmitry Chagin return (EOPNOTSUPP); 942d30ea4f5SPeter Wemm } 943af682d48SDmitry Chagin return (error); 944aa855a59SPeter Wemm } 945466b14d7SMarcel Moolenaar 946aa855a59SPeter Wemm static moduledata_t linux_elf_mod = { 947aa855a59SPeter Wemm "linuxelf", 948aa855a59SPeter Wemm linux_elf_modevent, 9499823d527SKevin Lo 0 950aa855a59SPeter Wemm }; 951466b14d7SMarcel Moolenaar 95278ae4338SKonstantin Belousov DECLARE_MODULE_TIED(linuxelf, linux_elf_mod, SI_SUB_EXEC, SI_ORDER_ANY); 95307db1f36SDmitry Chagin MODULE_DEPEND(linuxelf, netlink, 1, 1, 1); 954b6348be7SBaptiste Daroussin FEATURE(linux, "Linux 32bit support"); 955