xref: /freebsd/sys/i386/linux/linux_sysvec.c (revision f36ba45234e29c86aa1d00093022d2f6c49f9c38)
1d66a5066SPeter Wemm /*-
2e1743d02SSøren Schmidt  * Copyright (c) 1994-1996 S�ren Schmidt
3d66a5066SPeter Wemm  * All rights reserved.
4d66a5066SPeter Wemm  *
5d66a5066SPeter Wemm  * Redistribution and use in source and binary forms, with or without
6d66a5066SPeter Wemm  * modification, are permitted provided that the following conditions
7d66a5066SPeter Wemm  * are met:
8d66a5066SPeter Wemm  * 1. Redistributions of source code must retain the above copyright
9d66a5066SPeter Wemm  *    notice, this list of conditions and the following disclaimer
10d66a5066SPeter Wemm  *    in this position and unchanged.
11d66a5066SPeter Wemm  * 2. Redistributions in binary form must reproduce the above copyright
12d66a5066SPeter Wemm  *    notice, this list of conditions and the following disclaimer in the
13d66a5066SPeter Wemm  *    documentation and/or other materials provided with the distribution.
14d66a5066SPeter Wemm  * 3. The name of the author may not be used to endorse or promote products
1521dc7d4fSJens Schweikhardt  *    derived from this software without specific prior written permission
16d66a5066SPeter Wemm  *
17d66a5066SPeter Wemm  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18d66a5066SPeter Wemm  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19d66a5066SPeter Wemm  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20d66a5066SPeter Wemm  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21d66a5066SPeter Wemm  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22d66a5066SPeter Wemm  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23d66a5066SPeter Wemm  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24d66a5066SPeter Wemm  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25d66a5066SPeter Wemm  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26d66a5066SPeter Wemm  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27d66a5066SPeter Wemm  *
28c3aac50fSPeter Wemm  * $FreeBSD$
29d66a5066SPeter Wemm  */
30d66a5066SPeter Wemm 
31d66a5066SPeter Wemm /* XXX we use functions that might not exist. */
325591b823SEivind Eklund #include "opt_compat.h"
335591b823SEivind Eklund 
345591b823SEivind Eklund #ifndef COMPAT_43
355591b823SEivind Eklund #error "Unable to compile Linux-emulator due to missing COMPAT_43 option!"
365591b823SEivind Eklund #endif
37d66a5066SPeter Wemm 
38d66a5066SPeter Wemm #include <sys/param.h>
3975f83872SPeter Wemm #include <sys/systm.h>
40d66a5066SPeter Wemm #include <sys/imgact.h>
4122d4b0fbSJohn Polstra #include <sys/imgact_aout.h>
42e1743d02SSøren Schmidt #include <sys/imgact_elf.h>
437106ca0dSJohn Baldwin #include <sys/lock.h>
44e1743d02SSøren Schmidt #include <sys/malloc.h>
4523955314SAlfred Perlstein #include <sys/mutex.h>
46fb919e4dSMark Murray #include <sys/proc.h>
47fb919e4dSMark Murray #include <sys/signalvar.h>
48fb919e4dSMark Murray #include <sys/sysent.h>
49fb919e4dSMark Murray #include <sys/sysproto.h>
50fb919e4dSMark Murray 
51d66a5066SPeter Wemm #include <vm/vm.h>
52d66a5066SPeter Wemm #include <vm/vm_param.h>
53d66a5066SPeter Wemm #include <vm/vm_page.h>
54d66a5066SPeter Wemm #include <vm/vm_extern.h>
55d66a5066SPeter Wemm #include <sys/exec.h>
565cf588ebSPeter Wemm #include <sys/kernel.h>
57aa855a59SPeter Wemm #include <sys/module.h>
58d66a5066SPeter Wemm #include <machine/cpu.h>
59fb919e4dSMark Murray #include <sys/mutex.h>
60d66a5066SPeter Wemm 
61d66a5066SPeter Wemm #include <i386/linux/linux.h>
62ebea8660SMarcel Moolenaar #include <i386/linux/linux_proto.h>
63b595ab37SAndrew Gallatin #include <compat/linux/linux_signal.h>
64322bfdc3SMarcel Moolenaar #include <compat/linux/linux_util.h>
65e1743d02SSøren Schmidt 
661d91482dSPeter Wemm MODULE_VERSION(linux, 1);
67158eb277SDag-Erling Smørgrav MODULE_DEPEND(linux, sysvmsg, 1, 1, 1);
68158eb277SDag-Erling Smørgrav MODULE_DEPEND(linux, sysvsem, 1, 1, 1);
69158eb277SDag-Erling Smørgrav MODULE_DEPEND(linux, sysvshm, 1, 1, 1);
701d91482dSPeter Wemm 
7143bef515SMarcel Moolenaar MALLOC_DEFINE(M_LINUX, "linux", "Linux mode structures");
7243bef515SMarcel Moolenaar 
73d323ddf3SMatthew Dillon #if BYTE_ORDER == LITTLE_ENDIAN
74d323ddf3SMatthew Dillon #define SHELLMAGIC      0x2123 /* #! */
75d323ddf3SMatthew Dillon #else
76d323ddf3SMatthew Dillon #define SHELLMAGIC      0x2321
77d323ddf3SMatthew Dillon #endif
78d323ddf3SMatthew Dillon 
79e061a6caSMarcel Moolenaar /*
80e061a6caSMarcel Moolenaar  * Allow the sendsig functions to use the ldebug() facility
81e061a6caSMarcel Moolenaar  * even though they are not syscalls themselves. Map them
82e061a6caSMarcel Moolenaar  * to syscall 0. This is slightly less bogus than using
83e061a6caSMarcel Moolenaar  * ldebug(sigreturn).
84e061a6caSMarcel Moolenaar  */
85e061a6caSMarcel Moolenaar #define	LINUX_SYS_linux_rt_sendsig	0
86e061a6caSMarcel Moolenaar #define	LINUX_SYS_linux_sendsig		0
87e061a6caSMarcel Moolenaar 
8843bef515SMarcel Moolenaar extern char linux_sigcode[];
8943bef515SMarcel Moolenaar extern int linux_szsigcode;
9043bef515SMarcel Moolenaar 
9143bef515SMarcel Moolenaar extern struct sysent linux_sysent[LINUX_SYS_MAXSYSCALL];
9243bef515SMarcel Moolenaar 
93f41325dbSPeter Wemm SET_DECLARE(linux_ioctl_handler_set, struct linux_ioctl_handler);
9443bef515SMarcel Moolenaar 
9589c9a483SAlfred Perlstein static int	linux_fixup(register_t **stack_base,
9689c9a483SAlfred Perlstein 		    struct image_params *iparams);
9789c9a483SAlfred Perlstein static int	elf_linux_fixup(register_t **stack_base,
9889c9a483SAlfred Perlstein 		    struct image_params *iparams);
99bda2a3afSBruce Evans static void	linux_prepsyscall(struct trapframe *tf, int *args, u_int *code,
100bda2a3afSBruce Evans 		    caddr_t *params);
10189c9a483SAlfred Perlstein static void     linux_sendsig(sig_t catcher, int sig, sigset_t *mask,
10289c9a483SAlfred Perlstein 		    u_long code);
103d66a5066SPeter Wemm 
104d66a5066SPeter Wemm /*
105d66a5066SPeter Wemm  * Linux syscalls return negative errno's, we do positive and map them
106d66a5066SPeter Wemm  */
10785f118c8SDmitrij Tejblum static int bsd_to_linux_errno[ELAST + 1] = {
108d66a5066SPeter Wemm   	-0,  -1,  -2,  -3,  -4,  -5,  -6,  -7,  -8,  -9,
109d66a5066SPeter Wemm  	-10, -35, -12, -13, -14, -15, -16, -17, -18, -19,
110d66a5066SPeter Wemm  	-20, -21, -22, -23, -24, -25, -26, -27, -28, -29,
111d66a5066SPeter Wemm  	-30, -31, -32, -33, -34, -11,-115,-114, -88, -89,
112d66a5066SPeter Wemm  	-90, -91, -92, -93, -94, -95, -96, -97, -98, -99,
113d66a5066SPeter Wemm 	-100,-101,-102,-103,-104,-105,-106,-107,-108,-109,
114d66a5066SPeter Wemm 	-110,-111, -40, -36,-112,-113, -39, -11, -87,-122,
115d66a5066SPeter Wemm 	-116, -66,  -6,  -6,  -6,  -6,  -6, -37, -38,  -9,
11685f118c8SDmitrij Tejblum   	-6, -6, -43, -42, -75, -6, -84
117d66a5066SPeter Wemm };
118d66a5066SPeter Wemm 
119956d3333SMarcel Moolenaar int bsd_to_linux_signal[LINUX_SIGTBLSZ] = {
120956d3333SMarcel Moolenaar 	LINUX_SIGHUP, LINUX_SIGINT, LINUX_SIGQUIT, LINUX_SIGILL,
121956d3333SMarcel Moolenaar 	LINUX_SIGTRAP, LINUX_SIGABRT, 0, LINUX_SIGFPE,
122956d3333SMarcel Moolenaar 	LINUX_SIGKILL, LINUX_SIGBUS, LINUX_SIGSEGV, 0,
123956d3333SMarcel Moolenaar 	LINUX_SIGPIPE, LINUX_SIGALRM, LINUX_SIGTERM, LINUX_SIGURG,
124956d3333SMarcel Moolenaar 	LINUX_SIGSTOP, LINUX_SIGTSTP, LINUX_SIGCONT, LINUX_SIGCHLD,
125956d3333SMarcel Moolenaar 	LINUX_SIGTTIN, LINUX_SIGTTOU, LINUX_SIGIO, LINUX_SIGXCPU,
126956d3333SMarcel Moolenaar 	LINUX_SIGXFSZ, LINUX_SIGVTALRM, LINUX_SIGPROF, LINUX_SIGWINCH,
127956d3333SMarcel Moolenaar 	0, LINUX_SIGUSR1, LINUX_SIGUSR2
128d66a5066SPeter Wemm };
129d66a5066SPeter Wemm 
130956d3333SMarcel Moolenaar int linux_to_bsd_signal[LINUX_SIGTBLSZ] = {
131956d3333SMarcel Moolenaar 	SIGHUP, SIGINT, SIGQUIT, SIGILL,
132956d3333SMarcel Moolenaar 	SIGTRAP, SIGABRT, SIGBUS, SIGFPE,
133956d3333SMarcel Moolenaar 	SIGKILL, SIGUSR1, SIGSEGV, SIGUSR2,
134956d3333SMarcel Moolenaar 	SIGPIPE, SIGALRM, SIGTERM, SIGBUS,
135956d3333SMarcel Moolenaar 	SIGCHLD, SIGCONT, SIGSTOP, SIGTSTP,
136956d3333SMarcel Moolenaar 	SIGTTIN, SIGTTOU, SIGURG, SIGXCPU,
137956d3333SMarcel Moolenaar 	SIGXFSZ, SIGVTALRM, SIGPROF, SIGWINCH,
138956d3333SMarcel Moolenaar 	SIGIO, SIGURG, 0
139d66a5066SPeter Wemm };
140d66a5066SPeter Wemm 
14127a828fcSPierre Beyssac #define LINUX_T_UNKNOWN  255
14227a828fcSPierre Beyssac static int _bsd_to_linux_trapcode[] = {
14327a828fcSPierre Beyssac 	LINUX_T_UNKNOWN,	/* 0 */
14427a828fcSPierre Beyssac 	6,			/* 1  T_PRIVINFLT */
14527a828fcSPierre Beyssac 	LINUX_T_UNKNOWN,	/* 2 */
14627a828fcSPierre Beyssac 	3,			/* 3  T_BPTFLT */
14727a828fcSPierre Beyssac 	LINUX_T_UNKNOWN,	/* 4 */
14827a828fcSPierre Beyssac 	LINUX_T_UNKNOWN,	/* 5 */
14927a828fcSPierre Beyssac 	16,			/* 6  T_ARITHTRAP */
15027a828fcSPierre Beyssac 	254,			/* 7  T_ASTFLT */
15127a828fcSPierre Beyssac 	LINUX_T_UNKNOWN,	/* 8 */
15227a828fcSPierre Beyssac 	13,			/* 9  T_PROTFLT */
15327a828fcSPierre Beyssac 	1,			/* 10 T_TRCTRAP */
15427a828fcSPierre Beyssac 	LINUX_T_UNKNOWN,	/* 11 */
15527a828fcSPierre Beyssac 	14,			/* 12 T_PAGEFLT */
15627a828fcSPierre Beyssac 	LINUX_T_UNKNOWN,	/* 13 */
15727a828fcSPierre Beyssac 	17,			/* 14 T_ALIGNFLT */
15827a828fcSPierre Beyssac 	LINUX_T_UNKNOWN,	/* 15 */
15927a828fcSPierre Beyssac 	LINUX_T_UNKNOWN,	/* 16 */
16027a828fcSPierre Beyssac 	LINUX_T_UNKNOWN,	/* 17 */
16127a828fcSPierre Beyssac 	0,			/* 18 T_DIVIDE */
16227a828fcSPierre Beyssac 	2,			/* 19 T_NMI */
16327a828fcSPierre Beyssac 	4,			/* 20 T_OFLOW */
16427a828fcSPierre Beyssac 	5,			/* 21 T_BOUND */
16527a828fcSPierre Beyssac 	7,			/* 22 T_DNA */
16627a828fcSPierre Beyssac 	8,			/* 23 T_DOUBLEFLT */
16727a828fcSPierre Beyssac 	9,			/* 24 T_FPOPFLT */
16827a828fcSPierre Beyssac 	10,			/* 25 T_TSSFLT */
16927a828fcSPierre Beyssac 	11,			/* 26 T_SEGNPFLT */
17027a828fcSPierre Beyssac 	12,			/* 27 T_STKFLT */
17127a828fcSPierre Beyssac 	18,			/* 28 T_MCHK */
17227a828fcSPierre Beyssac 	19,			/* 29 T_XMMFLT */
17327a828fcSPierre Beyssac 	15			/* 30 T_RESERVED */
17427a828fcSPierre Beyssac };
17527a828fcSPierre Beyssac #define bsd_to_linux_trapcode(code) \
17627a828fcSPierre Beyssac     ((code)<sizeof(_bsd_to_linux_trapcode)/sizeof(*_bsd_to_linux_trapcode)? \
17727a828fcSPierre Beyssac      _bsd_to_linux_trapcode[(code)]: \
17827a828fcSPierre Beyssac      LINUX_T_UNKNOWN)
17927a828fcSPierre Beyssac 
180288078beSEivind Eklund /*
181288078beSEivind Eklund  * If FreeBSD & Linux have a difference of opinion about what a trap
182288078beSEivind Eklund  * means, deal with it here.
183356861dbSMatthew Dillon  *
184356861dbSMatthew Dillon  * MPSAFE
185288078beSEivind Eklund  */
186288078beSEivind Eklund static int
187288078beSEivind Eklund translate_traps(int signal, int trap_code)
188288078beSEivind Eklund {
189d563a53aSEivind Eklund 	if (signal != SIGBUS)
190d563a53aSEivind Eklund 		return signal;
191288078beSEivind Eklund 	switch (trap_code) {
192288078beSEivind Eklund 	case T_PROTFLT:
193288078beSEivind Eklund 	case T_TSSFLT:
194288078beSEivind Eklund 	case T_DOUBLEFLT:
195288078beSEivind Eklund 	case T_PAGEFLT:
196288078beSEivind Eklund 		return SIGSEGV;
197288078beSEivind Eklund 	default:
198288078beSEivind Eklund 		return signal;
199288078beSEivind Eklund 	}
200288078beSEivind Eklund }
201288078beSEivind Eklund 
202303b270bSEivind Eklund static int
203654f6be1SBruce Evans linux_fixup(register_t **stack_base, struct image_params *imgp)
204d66a5066SPeter Wemm {
205654f6be1SBruce Evans 	register_t *argv, *envp;
206d66a5066SPeter Wemm 
207d66a5066SPeter Wemm 	argv = *stack_base;
208d66a5066SPeter Wemm 	envp = *stack_base + (imgp->argc + 1);
209d66a5066SPeter Wemm 	(*stack_base)--;
21086a14a7aSBruce Evans 	**stack_base = (intptr_t)(void *)envp;
211d66a5066SPeter Wemm 	(*stack_base)--;
21286a14a7aSBruce Evans 	**stack_base = (intptr_t)(void *)argv;
213d66a5066SPeter Wemm 	(*stack_base)--;
21486a14a7aSBruce Evans 	**stack_base = imgp->argc;
215e1743d02SSøren Schmidt 	return 0;
216d66a5066SPeter Wemm }
217d66a5066SPeter Wemm 
218303b270bSEivind Eklund static int
219654f6be1SBruce Evans elf_linux_fixup(register_t **stack_base, struct image_params *imgp)
220e1743d02SSøren Schmidt {
221e1743d02SSøren Schmidt 	Elf32_Auxargs *args = (Elf32_Auxargs *)imgp->auxargs;
222654f6be1SBruce Evans 	register_t *pos;
223d66a5066SPeter Wemm 
224e1743d02SSøren Schmidt 	pos = *stack_base + (imgp->argc + imgp->envc + 2);
225e1743d02SSøren Schmidt 
226e1743d02SSøren Schmidt 	if (args->trace) {
227e1743d02SSøren Schmidt 		AUXARGS_ENTRY(pos, AT_DEBUG, 1);
228e1743d02SSøren Schmidt 	}
229e1743d02SSøren Schmidt 	if (args->execfd != -1) {
230e1743d02SSøren Schmidt 		AUXARGS_ENTRY(pos, AT_EXECFD, args->execfd);
231e1743d02SSøren Schmidt 	}
232e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_PHDR, args->phdr);
233e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_PHENT, args->phent);
234e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_PHNUM, args->phnum);
235e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_PAGESZ, args->pagesz);
236e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_FLAGS, args->flags);
237e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_ENTRY, args->entry);
238e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_BASE, args->base);
239611d9407SJohn Baldwin 	PROC_LOCK(imgp->proc);
240b1fc0ec1SRobert Watson 	AUXARGS_ENTRY(pos, AT_UID, imgp->proc->p_ucred->cr_ruid);
241b1fc0ec1SRobert Watson 	AUXARGS_ENTRY(pos, AT_EUID, imgp->proc->p_ucred->cr_svuid);
242b1fc0ec1SRobert Watson 	AUXARGS_ENTRY(pos, AT_GID, imgp->proc->p_ucred->cr_rgid);
243b1fc0ec1SRobert Watson 	AUXARGS_ENTRY(pos, AT_EGID, imgp->proc->p_ucred->cr_svgid);
244611d9407SJohn Baldwin 	PROC_UNLOCK(imgp->proc);
245e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_NULL, 0);
246e1743d02SSøren Schmidt 
247e1743d02SSøren Schmidt 	free(imgp->auxargs, M_TEMP);
248e1743d02SSøren Schmidt 	imgp->auxargs = NULL;
249e1743d02SSøren Schmidt 
250e1743d02SSøren Schmidt 	(*stack_base)--;
251ecbb00a2SDoug Rabson 	**stack_base = (long)imgp->argc;
252e1743d02SSøren Schmidt 	return 0;
253e1743d02SSøren Schmidt }
254d66a5066SPeter Wemm 
255d66a5066SPeter Wemm extern int _ucodesel, _udatasel;
25602318dacSJake Burkholder extern unsigned long linux_sznonrtsigcode;
25779363394SAndrew Gallatin 
25879363394SAndrew Gallatin static void
25979363394SAndrew Gallatin linux_rt_sendsig(sig_t catcher, int sig, sigset_t *mask, u_long code)
26079363394SAndrew Gallatin {
261b40ce416SJulian Elischer 	register struct thread *td = curthread;
262b40ce416SJulian Elischer 	register struct proc *p = td->td_proc;
26379363394SAndrew Gallatin 	register struct trapframe *regs;
2645002a60fSMarcel Moolenaar 	struct l_rt_sigframe *fp, frame;
26579363394SAndrew Gallatin 	int oonstack;
26679363394SAndrew Gallatin 
267df53e91cSJohn Baldwin 	PROC_LOCK_ASSERT(p, MA_OWNED);
268b40ce416SJulian Elischer 	regs = td->td_frame;
269d034d459SMarcel Moolenaar 	oonstack = sigonstack(regs->tf_esp);
27079363394SAndrew Gallatin 
27179363394SAndrew Gallatin #ifdef DEBUG
2725002a60fSMarcel Moolenaar 	if (ldebug(rt_sendsig))
27324593369SJonathan Lemon 		printf(ARGS(rt_sendsig, "%p, %d, %p, %lu"),
27424593369SJonathan Lemon 		    catcher, sig, (void*)mask, code);
27579363394SAndrew Gallatin #endif
27679363394SAndrew Gallatin 	/*
27779363394SAndrew Gallatin 	 * Allocate space for the signal handler context.
27879363394SAndrew Gallatin 	 */
27979363394SAndrew Gallatin 	if ((p->p_flag & P_ALTSTACK) && !oonstack &&
280cc6ca9b3SMarcel Moolenaar 	    SIGISMEMBER(p->p_sigacts->ps_sigonstack, sig)) {
2815002a60fSMarcel Moolenaar 		fp = (struct l_rt_sigframe *)(p->p_sigstk.ss_sp +
2825002a60fSMarcel Moolenaar 		    p->p_sigstk.ss_size - sizeof(struct l_rt_sigframe));
283d034d459SMarcel Moolenaar 	} else
2845002a60fSMarcel Moolenaar 		fp = (struct l_rt_sigframe *)regs->tf_esp - 1;
285611d9407SJohn Baldwin 	PROC_UNLOCK(p);
28679363394SAndrew Gallatin 
28779363394SAndrew Gallatin 	/*
28879363394SAndrew Gallatin 	 * Build the argument list for the signal handler.
28979363394SAndrew Gallatin 	 */
29079363394SAndrew Gallatin 	if (p->p_sysent->sv_sigtbl)
29179363394SAndrew Gallatin 		if (sig <= p->p_sysent->sv_sigsize)
29279363394SAndrew Gallatin 			sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)];
29379363394SAndrew Gallatin 
29479363394SAndrew Gallatin 	frame.sf_handler = catcher;
29579363394SAndrew Gallatin 	frame.sf_sig = sig;
29679363394SAndrew Gallatin 	frame.sf_siginfo = &fp->sf_si;
29779363394SAndrew Gallatin 	frame.sf_ucontext = &fp->sf_sc;
298cc6ca9b3SMarcel Moolenaar 
29979363394SAndrew Gallatin 	/* Fill siginfo structure. */
30079363394SAndrew Gallatin 	frame.sf_si.lsi_signo = sig;
30179363394SAndrew Gallatin 	frame.sf_si.lsi_code = code;
30279363394SAndrew Gallatin 	frame.sf_si.lsi_addr = (void *)regs->tf_err;
303cc6ca9b3SMarcel Moolenaar 
30479363394SAndrew Gallatin 	/*
30579363394SAndrew Gallatin 	 * Build the signal context to be used by sigreturn.
30679363394SAndrew Gallatin 	 */
307cc6ca9b3SMarcel Moolenaar 	frame.sf_sc.uc_flags = 0;		/* XXX ??? */
308cc6ca9b3SMarcel Moolenaar 	frame.sf_sc.uc_link = NULL;		/* XXX ??? */
309cc6ca9b3SMarcel Moolenaar 
310611d9407SJohn Baldwin 	PROC_LOCK(p);
311cc6ca9b3SMarcel Moolenaar 	frame.sf_sc.uc_stack.ss_sp = p->p_sigstk.ss_sp;
312cc6ca9b3SMarcel Moolenaar 	frame.sf_sc.uc_stack.ss_size = p->p_sigstk.ss_size;
313d034d459SMarcel Moolenaar 	frame.sf_sc.uc_stack.ss_flags = (p->p_flag & P_ALTSTACK)
314d034d459SMarcel Moolenaar 	    ? ((oonstack) ? LINUX_SS_ONSTACK : 0) : LINUX_SS_DISABLE;
315611d9407SJohn Baldwin 	PROC_UNLOCK(p);
316cc6ca9b3SMarcel Moolenaar 
317cc6ca9b3SMarcel Moolenaar 	bsd_to_linux_sigset(mask, &frame.sf_sc.uc_sigmask);
318cc6ca9b3SMarcel Moolenaar 
319cc6ca9b3SMarcel Moolenaar 	frame.sf_sc.uc_mcontext.sc_mask   = frame.sf_sc.uc_sigmask.__bits[0];
32079363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_gs     = rgs();
32179363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_fs     = regs->tf_fs;
32279363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_es     = regs->tf_es;
32379363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_ds     = regs->tf_ds;
32479363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_edi    = regs->tf_edi;
32579363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_esi    = regs->tf_esi;
32679363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_ebp    = regs->tf_ebp;
32779363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_ebx    = regs->tf_ebx;
32879363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_edx    = regs->tf_edx;
32979363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_ecx    = regs->tf_ecx;
33079363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_eax    = regs->tf_eax;
33179363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_eip    = regs->tf_eip;
33279363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_cs     = regs->tf_cs;
33379363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_eflags = regs->tf_eflags;
33479363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_esp_at_signal = regs->tf_esp;
33579363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_ss     = regs->tf_ss;
33679363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_err    = regs->tf_err;
33727a828fcSPierre Beyssac 	frame.sf_sc.uc_mcontext.sc_trapno = bsd_to_linux_trapcode(code);
33879363394SAndrew Gallatin 
33979363394SAndrew Gallatin #ifdef DEBUG
3405002a60fSMarcel Moolenaar 	if (ldebug(rt_sendsig))
34124593369SJonathan Lemon 		printf(LMSG("rt_sendsig flags: 0x%x, sp: %p, ss: 0x%x, mask: 0x%x"),
34224593369SJonathan Lemon 		    frame.sf_sc.uc_stack.ss_flags, p->p_sigstk.ss_sp,
34324593369SJonathan Lemon 		    p->p_sigstk.ss_size, frame.sf_sc.uc_mcontext.sc_mask);
34479363394SAndrew Gallatin #endif
34579363394SAndrew Gallatin 
34679363394SAndrew Gallatin 	if (copyout(&frame, fp, sizeof(frame)) != 0) {
34779363394SAndrew Gallatin 		/*
34879363394SAndrew Gallatin 		 * Process has trashed its stack; give it an illegal
34979363394SAndrew Gallatin 		 * instruction to halt it in its tracks.
35079363394SAndrew Gallatin 		 */
35189734883SAlan Cox #ifdef DEBUG
35289734883SAlan Cox 		if (ldebug(rt_sendsig))
35389734883SAlan Cox 			printf(LMSG("rt_sendsig: bad stack %p, oonstack=%x"),
35489734883SAlan Cox 			    fp, oonstack);
35589734883SAlan Cox #endif
35619eb87d2SJohn Baldwin 		PROC_LOCK(p);
357b40ce416SJulian Elischer 		sigexit(td, SIGILL);
35879363394SAndrew Gallatin 	}
35979363394SAndrew Gallatin 
36079363394SAndrew Gallatin 	/*
36179363394SAndrew Gallatin 	 * Build context to run handler in.
36279363394SAndrew Gallatin 	 */
36379363394SAndrew Gallatin 	regs->tf_esp = (int)fp;
36479363394SAndrew Gallatin 	regs->tf_eip = PS_STRINGS - *(p->p_sysent->sv_szsigcode) +
36502318dacSJake Burkholder 	    linux_sznonrtsigcode;
366846ac226SBruce Evans 	regs->tf_eflags &= ~(PSL_T | PSL_VM);
36779363394SAndrew Gallatin 	regs->tf_cs = _ucodesel;
36879363394SAndrew Gallatin 	regs->tf_ds = _udatasel;
36979363394SAndrew Gallatin 	regs->tf_es = _udatasel;
37079363394SAndrew Gallatin 	regs->tf_fs = _udatasel;
37179363394SAndrew Gallatin 	regs->tf_ss = _udatasel;
372df53e91cSJohn Baldwin 	PROC_LOCK(p);
37379363394SAndrew Gallatin }
37479363394SAndrew Gallatin 
375d66a5066SPeter Wemm 
376d66a5066SPeter Wemm /*
377d66a5066SPeter Wemm  * Send an interrupt to process.
378d66a5066SPeter Wemm  *
379d66a5066SPeter Wemm  * Stack is set up to allow sigcode stored
380d66a5066SPeter Wemm  * in u. to call routine, followed by kcall
381d66a5066SPeter Wemm  * to sigreturn routine below.  After sigreturn
382d66a5066SPeter Wemm  * resets the signal mask, the stack, and the
383d66a5066SPeter Wemm  * frame pointer, it returns to the user
384d66a5066SPeter Wemm  * specified pc, psl.
385d66a5066SPeter Wemm  */
386d66a5066SPeter Wemm 
387303b270bSEivind Eklund static void
388956d3333SMarcel Moolenaar linux_sendsig(sig_t catcher, int sig, sigset_t *mask, u_long code)
389d66a5066SPeter Wemm {
390b40ce416SJulian Elischer 	register struct thread *td = curthread;
391b40ce416SJulian Elischer 	register struct proc *p = td->td_proc;
392213fdd80SPeter Wemm 	register struct trapframe *regs;
3935002a60fSMarcel Moolenaar 	struct l_sigframe *fp, frame;
3945002a60fSMarcel Moolenaar 	l_sigset_t lmask;
3952c4ab9ddSAndrew Gallatin 	int oonstack, i;
396d66a5066SPeter Wemm 
3972509e6c2SJohn Baldwin 	PROC_LOCK_ASSERT(p, MA_OWNED);
398cc6ca9b3SMarcel Moolenaar 	if (SIGISMEMBER(p->p_sigacts->ps_siginfo, sig)) {
399cc6ca9b3SMarcel Moolenaar 		/* Signal handler installed with SA_SIGINFO. */
400cc6ca9b3SMarcel Moolenaar 		linux_rt_sendsig(catcher, sig, mask, code);
401cc6ca9b3SMarcel Moolenaar 		return;
402cc6ca9b3SMarcel Moolenaar 	}
403cc6ca9b3SMarcel Moolenaar 
404b40ce416SJulian Elischer 	regs = td->td_frame;
405d034d459SMarcel Moolenaar 	oonstack = sigonstack(regs->tf_esp);
406d66a5066SPeter Wemm 
407d66a5066SPeter Wemm #ifdef DEBUG
4085002a60fSMarcel Moolenaar 	if (ldebug(sendsig))
40924593369SJonathan Lemon 		printf(ARGS(sendsig, "%p, %d, %p, %lu"),
41024593369SJonathan Lemon 		    catcher, sig, (void*)mask, code);
411d66a5066SPeter Wemm #endif
41279363394SAndrew Gallatin 
413d66a5066SPeter Wemm 	/*
414d66a5066SPeter Wemm 	 * Allocate space for the signal handler context.
415d66a5066SPeter Wemm 	 */
416645682fdSLuoqi Chen 	if ((p->p_flag & P_ALTSTACK) && !oonstack &&
417cc6ca9b3SMarcel Moolenaar 	    SIGISMEMBER(p->p_sigacts->ps_sigonstack, sig)) {
4185002a60fSMarcel Moolenaar 		fp = (struct l_sigframe *)(p->p_sigstk.ss_sp +
4195002a60fSMarcel Moolenaar 		    p->p_sigstk.ss_size - sizeof(struct l_sigframe));
420d034d459SMarcel Moolenaar 	} else
4215002a60fSMarcel Moolenaar 		fp = (struct l_sigframe *)regs->tf_esp - 1;
422611d9407SJohn Baldwin 	PROC_UNLOCK(p);
423d66a5066SPeter Wemm 
424d66a5066SPeter Wemm 	/*
425d66a5066SPeter Wemm 	 * Build the argument list for the signal handler.
426d66a5066SPeter Wemm 	 */
427956d3333SMarcel Moolenaar 	if (p->p_sysent->sv_sigtbl)
428956d3333SMarcel Moolenaar 		if (sig <= p->p_sysent->sv_sigsize)
429956d3333SMarcel Moolenaar 			sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)];
430d66a5066SPeter Wemm 
431d66a5066SPeter Wemm 	frame.sf_handler = catcher;
432d66a5066SPeter Wemm 	frame.sf_sig = sig;
433d66a5066SPeter Wemm 
434cc6ca9b3SMarcel Moolenaar 	bsd_to_linux_sigset(mask, &lmask);
435cc6ca9b3SMarcel Moolenaar 
436d66a5066SPeter Wemm 	/*
437d66a5066SPeter Wemm 	 * Build the signal context to be used by sigreturn.
438d66a5066SPeter Wemm 	 */
439cc6ca9b3SMarcel Moolenaar 	frame.sf_sc.sc_mask   = lmask.__bits[0];
4405206bca1SLuoqi Chen 	frame.sf_sc.sc_gs     = rgs();
4415206bca1SLuoqi Chen 	frame.sf_sc.sc_fs     = regs->tf_fs;
442213fdd80SPeter Wemm 	frame.sf_sc.sc_es     = regs->tf_es;
443213fdd80SPeter Wemm 	frame.sf_sc.sc_ds     = regs->tf_ds;
444213fdd80SPeter Wemm 	frame.sf_sc.sc_edi    = regs->tf_edi;
445213fdd80SPeter Wemm 	frame.sf_sc.sc_esi    = regs->tf_esi;
446213fdd80SPeter Wemm 	frame.sf_sc.sc_ebp    = regs->tf_ebp;
447213fdd80SPeter Wemm 	frame.sf_sc.sc_ebx    = regs->tf_ebx;
448213fdd80SPeter Wemm 	frame.sf_sc.sc_edx    = regs->tf_edx;
449213fdd80SPeter Wemm 	frame.sf_sc.sc_ecx    = regs->tf_ecx;
450213fdd80SPeter Wemm 	frame.sf_sc.sc_eax    = regs->tf_eax;
451213fdd80SPeter Wemm 	frame.sf_sc.sc_eip    = regs->tf_eip;
452213fdd80SPeter Wemm 	frame.sf_sc.sc_cs     = regs->tf_cs;
453213fdd80SPeter Wemm 	frame.sf_sc.sc_eflags = regs->tf_eflags;
454213fdd80SPeter Wemm 	frame.sf_sc.sc_esp_at_signal = regs->tf_esp;
455213fdd80SPeter Wemm 	frame.sf_sc.sc_ss     = regs->tf_ss;
456213fdd80SPeter Wemm 	frame.sf_sc.sc_err    = regs->tf_err;
45727a828fcSPierre Beyssac 	frame.sf_sc.sc_trapno = bsd_to_linux_trapcode(code);
458cc6ca9b3SMarcel Moolenaar 
4595002a60fSMarcel Moolenaar 	bzero(&frame.sf_fpstate, sizeof(struct l_fpstate));
460cc6ca9b3SMarcel Moolenaar 
4612c4ab9ddSAndrew Gallatin 	for (i = 0; i < (LINUX_NSIG_WORDS-1); i++)
462cc6ca9b3SMarcel Moolenaar 		frame.sf_extramask[i] = lmask.__bits[i+1];
463d66a5066SPeter Wemm 
464d66a5066SPeter Wemm 	if (copyout(&frame, fp, sizeof(frame)) != 0) {
465d66a5066SPeter Wemm 		/*
466d66a5066SPeter Wemm 		 * Process has trashed its stack; give it an illegal
467d66a5066SPeter Wemm 		 * instruction to halt it in its tracks.
468d66a5066SPeter Wemm 		 */
46919eb87d2SJohn Baldwin 		PROC_LOCK(p);
470b40ce416SJulian Elischer 		sigexit(td, SIGILL);
471d66a5066SPeter Wemm 	}
472d66a5066SPeter Wemm 
473d66a5066SPeter Wemm 	/*
474d66a5066SPeter Wemm 	 * Build context to run handler in.
475d66a5066SPeter Wemm 	 */
476213fdd80SPeter Wemm 	regs->tf_esp = (int)fp;
4774c56fcdeSBruce Evans 	regs->tf_eip = PS_STRINGS - *(p->p_sysent->sv_szsigcode);
478846ac226SBruce Evans 	regs->tf_eflags &= ~(PSL_T | PSL_VM);
479213fdd80SPeter Wemm 	regs->tf_cs = _ucodesel;
480213fdd80SPeter Wemm 	regs->tf_ds = _udatasel;
481213fdd80SPeter Wemm 	regs->tf_es = _udatasel;
4825206bca1SLuoqi Chen 	regs->tf_fs = _udatasel;
483213fdd80SPeter Wemm 	regs->tf_ss = _udatasel;
4845002a60fSMarcel Moolenaar 	PROC_LOCK(p);
485d66a5066SPeter Wemm }
486d66a5066SPeter Wemm 
487d66a5066SPeter Wemm /*
488d66a5066SPeter Wemm  * System call to cleanup state after a signal
489d66a5066SPeter Wemm  * has been taken.  Reset signal mask and
490d66a5066SPeter Wemm  * stack state from context left by sendsig (above).
491d66a5066SPeter Wemm  * Return to previous pc and psl as specified by
492d66a5066SPeter Wemm  * context left by sendsig. Check carefully to
493d66a5066SPeter Wemm  * make sure that the user has not modified the
494d66a5066SPeter Wemm  * psl to gain improper privileges or to cause
495d66a5066SPeter Wemm  * a machine fault.
496d66a5066SPeter Wemm  */
497d66a5066SPeter Wemm int
498b40ce416SJulian Elischer linux_sigreturn(td, args)
499b40ce416SJulian Elischer 	struct thread *td;
500d66a5066SPeter Wemm 	struct linux_sigreturn_args *args;
501d66a5066SPeter Wemm {
502b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
5035002a60fSMarcel Moolenaar 	struct l_sigframe frame;
504213fdd80SPeter Wemm 	register struct trapframe *regs;
5055002a60fSMarcel Moolenaar 	l_sigset_t lmask;
5062c4ab9ddSAndrew Gallatin 	int eflags, i;
507d66a5066SPeter Wemm 
508b40ce416SJulian Elischer 	regs = td->td_frame;
509d66a5066SPeter Wemm 
510d66a5066SPeter Wemm #ifdef DEBUG
51124593369SJonathan Lemon 	if (ldebug(sigreturn))
51224593369SJonathan Lemon 		printf(ARGS(sigreturn, "%p"), (void *)args->sfp);
513d66a5066SPeter Wemm #endif
514d66a5066SPeter Wemm 	/*
515cc6ca9b3SMarcel Moolenaar 	 * The trampoline code hands us the sigframe.
516d66a5066SPeter Wemm 	 * It is unsafe to keep track of it ourselves, in the event that a
517d66a5066SPeter Wemm 	 * program jumps out of a signal handler.
518d66a5066SPeter Wemm 	 */
519cc6ca9b3SMarcel Moolenaar 	if (copyin((caddr_t)args->sfp, &frame, sizeof(frame)) != 0)
520d66a5066SPeter Wemm 		return (EFAULT);
521d66a5066SPeter Wemm 
522d66a5066SPeter Wemm 	/*
523d66a5066SPeter Wemm 	 * Check for security violations.
524d66a5066SPeter Wemm 	 */
525d66a5066SPeter Wemm #define	EFLAGS_SECURE(ef, oef)	((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0)
526cc6ca9b3SMarcel Moolenaar 	eflags = frame.sf_sc.sc_eflags;
527d66a5066SPeter Wemm 	/*
528d66a5066SPeter Wemm 	 * XXX do allow users to change the privileged flag PSL_RF.  The
529d66a5066SPeter Wemm 	 * cpu sets PSL_RF in tf_eflags for faults.  Debuggers should
530d66a5066SPeter Wemm 	 * sometimes set it there too.  tf_eflags is kept in the signal
531d66a5066SPeter Wemm 	 * context during signal handling and there is no other place
532d66a5066SPeter Wemm 	 * to remember it, so the PSL_RF bit may be corrupted by the
533d66a5066SPeter Wemm 	 * signal handler without us knowing.  Corruption of the PSL_RF
534d66a5066SPeter Wemm 	 * bit at worst causes one more or one less debugger trap, so
535d66a5066SPeter Wemm 	 * allowing it is fairly harmless.
536d66a5066SPeter Wemm 	 */
537213fdd80SPeter Wemm 	if (!EFLAGS_SECURE(eflags & ~PSL_RF, regs->tf_eflags & ~PSL_RF)) {
538d66a5066SPeter Wemm     		return(EINVAL);
539d66a5066SPeter Wemm 	}
540d66a5066SPeter Wemm 
541d66a5066SPeter Wemm 	/*
542d66a5066SPeter Wemm 	 * Don't allow users to load a valid privileged %cs.  Let the
543d66a5066SPeter Wemm 	 * hardware check for invalid selectors, excess privilege in
544d66a5066SPeter Wemm 	 * other selectors, invalid %eip's and invalid %esp's.
545d66a5066SPeter Wemm 	 */
54640d50994SPhilippe Charnier #define	CS_SECURE(cs)	(ISPL(cs) == SEL_UPL)
547cc6ca9b3SMarcel Moolenaar 	if (!CS_SECURE(frame.sf_sc.sc_cs)) {
548d66a5066SPeter Wemm 		trapsignal(p, SIGBUS, T_PROTFLT);
549d66a5066SPeter Wemm 		return(EINVAL);
550d66a5066SPeter Wemm 	}
551d66a5066SPeter Wemm 
552cc6ca9b3SMarcel Moolenaar 	lmask.__bits[0] = frame.sf_sc.sc_mask;
5532c4ab9ddSAndrew Gallatin 	for (i = 0; i < (LINUX_NSIG_WORDS-1); i++)
554cc6ca9b3SMarcel Moolenaar 		lmask.__bits[i+1] = frame.sf_extramask[i];
555611d9407SJohn Baldwin 	PROC_LOCK(p);
556cc6ca9b3SMarcel Moolenaar 	linux_to_bsd_sigset(&lmask, &p->p_sigmask);
557645682fdSLuoqi Chen 	SIG_CANTMASK(p->p_sigmask);
55879065dbaSBruce Evans 	signotify(p);
559611d9407SJohn Baldwin 	PROC_UNLOCK(p);
560956d3333SMarcel Moolenaar 
561d66a5066SPeter Wemm 	/*
562d66a5066SPeter Wemm 	 * Restore signal context.
563d66a5066SPeter Wemm 	 */
5645206bca1SLuoqi Chen 	/* %gs was restored by the trampoline. */
565cc6ca9b3SMarcel Moolenaar 	regs->tf_fs     = frame.sf_sc.sc_fs;
566cc6ca9b3SMarcel Moolenaar 	regs->tf_es     = frame.sf_sc.sc_es;
567cc6ca9b3SMarcel Moolenaar 	regs->tf_ds     = frame.sf_sc.sc_ds;
568cc6ca9b3SMarcel Moolenaar 	regs->tf_edi    = frame.sf_sc.sc_edi;
569cc6ca9b3SMarcel Moolenaar 	regs->tf_esi    = frame.sf_sc.sc_esi;
570cc6ca9b3SMarcel Moolenaar 	regs->tf_ebp    = frame.sf_sc.sc_ebp;
571cc6ca9b3SMarcel Moolenaar 	regs->tf_ebx    = frame.sf_sc.sc_ebx;
572cc6ca9b3SMarcel Moolenaar 	regs->tf_edx    = frame.sf_sc.sc_edx;
573cc6ca9b3SMarcel Moolenaar 	regs->tf_ecx    = frame.sf_sc.sc_ecx;
574cc6ca9b3SMarcel Moolenaar 	regs->tf_eax    = frame.sf_sc.sc_eax;
575cc6ca9b3SMarcel Moolenaar 	regs->tf_eip    = frame.sf_sc.sc_eip;
576cc6ca9b3SMarcel Moolenaar 	regs->tf_cs     = frame.sf_sc.sc_cs;
577213fdd80SPeter Wemm 	regs->tf_eflags = eflags;
578cc6ca9b3SMarcel Moolenaar 	regs->tf_esp    = frame.sf_sc.sc_esp_at_signal;
579cc6ca9b3SMarcel Moolenaar 	regs->tf_ss     = frame.sf_sc.sc_ss;
580d66a5066SPeter Wemm 
581d66a5066SPeter Wemm 	return (EJUSTRETURN);
582d66a5066SPeter Wemm }
583d66a5066SPeter Wemm 
58479363394SAndrew Gallatin /*
58579363394SAndrew Gallatin  * System call to cleanup state after a signal
58679363394SAndrew Gallatin  * has been taken.  Reset signal mask and
58779363394SAndrew Gallatin  * stack state from context left by rt_sendsig (above).
58879363394SAndrew Gallatin  * Return to previous pc and psl as specified by
58979363394SAndrew Gallatin  * context left by sendsig. Check carefully to
59079363394SAndrew Gallatin  * make sure that the user has not modified the
59179363394SAndrew Gallatin  * psl to gain improper privileges or to cause
59279363394SAndrew Gallatin  * a machine fault.
59379363394SAndrew Gallatin  */
59479363394SAndrew Gallatin int
595b40ce416SJulian Elischer linux_rt_sigreturn(td, args)
596b40ce416SJulian Elischer 	struct thread *td;
59779363394SAndrew Gallatin 	struct linux_rt_sigreturn_args *args;
59879363394SAndrew Gallatin {
599b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
60079363394SAndrew Gallatin 	struct sigaltstack_args sasargs;
6015002a60fSMarcel Moolenaar 	struct l_ucontext uc;
6025002a60fSMarcel Moolenaar 	struct l_sigcontext *context;
6035002a60fSMarcel Moolenaar 	l_stack_t *lss;
60479363394SAndrew Gallatin 	stack_t *ss;
60579363394SAndrew Gallatin 	register struct trapframe *regs;
60679363394SAndrew Gallatin 	int eflags;
60779363394SAndrew Gallatin 	caddr_t sg = stackgap_init();
60879363394SAndrew Gallatin 
609b40ce416SJulian Elischer 	regs = td->td_frame;
61079363394SAndrew Gallatin 
61179363394SAndrew Gallatin #ifdef DEBUG
61224593369SJonathan Lemon 	if (ldebug(rt_sigreturn))
61324593369SJonathan Lemon 		printf(ARGS(rt_sigreturn, "%p"), (void *)args->ucp);
61479363394SAndrew Gallatin #endif
61579363394SAndrew Gallatin 	/*
616cc6ca9b3SMarcel Moolenaar 	 * The trampoline code hands us the ucontext.
61779363394SAndrew Gallatin 	 * It is unsafe to keep track of it ourselves, in the event that a
61879363394SAndrew Gallatin 	 * program jumps out of a signal handler.
61979363394SAndrew Gallatin 	 */
62079363394SAndrew Gallatin 	if (copyin((caddr_t)args->ucp, &uc, sizeof(uc)) != 0)
62179363394SAndrew Gallatin 		return (EFAULT);
62279363394SAndrew Gallatin 
62379363394SAndrew Gallatin 	context = &uc.uc_mcontext;
62479363394SAndrew Gallatin 
62579363394SAndrew Gallatin 	/*
62679363394SAndrew Gallatin 	 * Check for security violations.
62779363394SAndrew Gallatin 	 */
62879363394SAndrew Gallatin #define	EFLAGS_SECURE(ef, oef)	((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0)
62979363394SAndrew Gallatin 	eflags = context->sc_eflags;
63079363394SAndrew Gallatin 	/*
63179363394SAndrew Gallatin 	 * XXX do allow users to change the privileged flag PSL_RF.  The
63279363394SAndrew Gallatin 	 * cpu sets PSL_RF in tf_eflags for faults.  Debuggers should
63379363394SAndrew Gallatin 	 * sometimes set it there too.  tf_eflags is kept in the signal
63479363394SAndrew Gallatin 	 * context during signal handling and there is no other place
63579363394SAndrew Gallatin 	 * to remember it, so the PSL_RF bit may be corrupted by the
63679363394SAndrew Gallatin 	 * signal handler without us knowing.  Corruption of the PSL_RF
63779363394SAndrew Gallatin 	 * bit at worst causes one more or one less debugger trap, so
63879363394SAndrew Gallatin 	 * allowing it is fairly harmless.
63979363394SAndrew Gallatin 	 */
64079363394SAndrew Gallatin 	if (!EFLAGS_SECURE(eflags & ~PSL_RF, regs->tf_eflags & ~PSL_RF)) {
64179363394SAndrew Gallatin     		return(EINVAL);
64279363394SAndrew Gallatin 	}
64379363394SAndrew Gallatin 
64479363394SAndrew Gallatin 	/*
64579363394SAndrew Gallatin 	 * Don't allow users to load a valid privileged %cs.  Let the
64679363394SAndrew Gallatin 	 * hardware check for invalid selectors, excess privilege in
64779363394SAndrew Gallatin 	 * other selectors, invalid %eip's and invalid %esp's.
64879363394SAndrew Gallatin 	 */
64979363394SAndrew Gallatin #define	CS_SECURE(cs)	(ISPL(cs) == SEL_UPL)
65079363394SAndrew Gallatin 	if (!CS_SECURE(context->sc_cs)) {
65179363394SAndrew Gallatin 		trapsignal(p, SIGBUS, T_PROTFLT);
65279363394SAndrew Gallatin 		return(EINVAL);
65379363394SAndrew Gallatin 	}
65479363394SAndrew Gallatin 
655611d9407SJohn Baldwin 	PROC_LOCK(p);
656b595ab37SAndrew Gallatin 	linux_to_bsd_sigset(&uc.uc_sigmask, &p->p_sigmask);
65779363394SAndrew Gallatin 	SIG_CANTMASK(p->p_sigmask);
65879065dbaSBruce Evans 	signotify(p);
659611d9407SJohn Baldwin 	PROC_UNLOCK(p);
66079363394SAndrew Gallatin 
66179363394SAndrew Gallatin 	/*
662cc6ca9b3SMarcel Moolenaar 	 * Restore signal context
66379363394SAndrew Gallatin 	 */
66479363394SAndrew Gallatin 	/* %gs was restored by the trampoline. */
66579363394SAndrew Gallatin 	regs->tf_fs     = context->sc_fs;
66679363394SAndrew Gallatin 	regs->tf_es     = context->sc_es;
66779363394SAndrew Gallatin 	regs->tf_ds     = context->sc_ds;
66879363394SAndrew Gallatin 	regs->tf_edi    = context->sc_edi;
66979363394SAndrew Gallatin 	regs->tf_esi    = context->sc_esi;
67079363394SAndrew Gallatin 	regs->tf_ebp    = context->sc_ebp;
67179363394SAndrew Gallatin 	regs->tf_ebx    = context->sc_ebx;
67279363394SAndrew Gallatin 	regs->tf_edx    = context->sc_edx;
67379363394SAndrew Gallatin 	regs->tf_ecx    = context->sc_ecx;
67479363394SAndrew Gallatin 	regs->tf_eax    = context->sc_eax;
67579363394SAndrew Gallatin 	regs->tf_eip    = context->sc_eip;
67679363394SAndrew Gallatin 	regs->tf_cs     = context->sc_cs;
67779363394SAndrew Gallatin 	regs->tf_eflags = eflags;
67879363394SAndrew Gallatin 	regs->tf_esp    = context->sc_esp_at_signal;
67979363394SAndrew Gallatin 	regs->tf_ss     = context->sc_ss;
68079363394SAndrew Gallatin 
68179363394SAndrew Gallatin 	/*
68279363394SAndrew Gallatin 	 * call sigaltstack & ignore results..
68379363394SAndrew Gallatin 	 */
68479363394SAndrew Gallatin 	ss = stackgap_alloc(&sg, sizeof(stack_t));
68579363394SAndrew Gallatin 	lss = &uc.uc_stack;
68679363394SAndrew Gallatin 	ss->ss_sp = lss->ss_sp;
687806d7daaSMarcel Moolenaar 	ss->ss_size = lss->ss_size;
68879363394SAndrew Gallatin 	ss->ss_flags = linux_to_bsd_sigaltstack(lss->ss_flags);
68979363394SAndrew Gallatin 
69079363394SAndrew Gallatin #ifdef DEBUG
69124593369SJonathan Lemon 	if (ldebug(rt_sigreturn))
69224593369SJonathan Lemon 		printf(LMSG("rt_sigret flags: 0x%x, sp: %p, ss: 0x%x, mask: 0x%x"),
69324593369SJonathan Lemon 		    ss->ss_flags, ss->ss_sp, ss->ss_size, context->sc_mask);
69479363394SAndrew Gallatin #endif
69579363394SAndrew Gallatin 	sasargs.ss = ss;
69679363394SAndrew Gallatin 	sasargs.oss = NULL;
697b40ce416SJulian Elischer 	(void) sigaltstack(td, &sasargs);
69879363394SAndrew Gallatin 
69979363394SAndrew Gallatin 	return (EJUSTRETURN);
70079363394SAndrew Gallatin }
70179363394SAndrew Gallatin 
702356861dbSMatthew Dillon /*
703356861dbSMatthew Dillon  * MPSAFE
704356861dbSMatthew Dillon  */
705303b270bSEivind Eklund static void
706d66a5066SPeter Wemm linux_prepsyscall(struct trapframe *tf, int *args, u_int *code, caddr_t *params)
707d66a5066SPeter Wemm {
708d66a5066SPeter Wemm 	args[0] = tf->tf_ebx;
709d66a5066SPeter Wemm 	args[1] = tf->tf_ecx;
710d66a5066SPeter Wemm 	args[2] = tf->tf_edx;
711d66a5066SPeter Wemm 	args[3] = tf->tf_esi;
712d66a5066SPeter Wemm 	args[4] = tf->tf_edi;
713d66a5066SPeter Wemm 	*params = NULL;		/* no copyin */
714d66a5066SPeter Wemm }
715d66a5066SPeter Wemm 
716d323ddf3SMatthew Dillon /*
717d323ddf3SMatthew Dillon  * If a linux binary is exec'ing something, try this image activator
718d323ddf3SMatthew Dillon  * first.  We override standard shell script execution in order to
719d323ddf3SMatthew Dillon  * be able to modify the interpreter path.  We only do this if a linux
720d323ddf3SMatthew Dillon  * binary is doing the exec, so we do not create an EXEC module for it.
721d323ddf3SMatthew Dillon  */
72289c9a483SAlfred Perlstein static int	exec_linux_imgact_try(struct image_params *iparams);
723d323ddf3SMatthew Dillon 
724d323ddf3SMatthew Dillon static int
725d323ddf3SMatthew Dillon exec_linux_imgact_try(imgp)
726d323ddf3SMatthew Dillon     struct image_params *imgp;
727d323ddf3SMatthew Dillon {
728d323ddf3SMatthew Dillon     const char *head = (const char *)imgp->image_header;
729d323ddf3SMatthew Dillon     int error = -1;
730d323ddf3SMatthew Dillon 
731d323ddf3SMatthew Dillon     /*
732d323ddf3SMatthew Dillon      * The interpreter for shell scripts run from a linux binary needs
733d323ddf3SMatthew Dillon      * to be located in /compat/linux if possible in order to recursively
734d323ddf3SMatthew Dillon      * maintain linux path emulation.
735d323ddf3SMatthew Dillon      */
736d323ddf3SMatthew Dillon     if (((const short *)head)[0] == SHELLMAGIC) {
737d323ddf3SMatthew Dillon 	    /*
738d323ddf3SMatthew Dillon 	     * Run our normal shell image activator.  If it succeeds attempt
739d323ddf3SMatthew Dillon 	     * to use the alternate path for the interpreter.  If an alternate
740d323ddf3SMatthew Dillon 	     * path is found, use our stringspace to store it.
741d323ddf3SMatthew Dillon 	     */
742d323ddf3SMatthew Dillon 	    if ((error = exec_shell_imgact(imgp)) == 0) {
743d323ddf3SMatthew Dillon 		    char *rpath = NULL;
744d323ddf3SMatthew Dillon 
745079b7badSJulian Elischer 		    linux_emul_find(FIRST_THREAD_IN_PROC(imgp->proc), NULL,
746d323ddf3SMatthew Dillon 			imgp->interpreter_name, &rpath, 0);
747d323ddf3SMatthew Dillon 		    if (rpath != imgp->interpreter_name) {
748d323ddf3SMatthew Dillon 			    int len = strlen(rpath) + 1;
749d323ddf3SMatthew Dillon 
750d323ddf3SMatthew Dillon 			    if (len <= MAXSHELLCMDLEN) {
751d323ddf3SMatthew Dillon 				    memcpy(imgp->interpreter_name, rpath, len);
752d323ddf3SMatthew Dillon 			    }
753d323ddf3SMatthew Dillon 			    free(rpath, M_TEMP);
754d323ddf3SMatthew Dillon 		    }
755d323ddf3SMatthew Dillon 	    }
756d323ddf3SMatthew Dillon     }
757d323ddf3SMatthew Dillon     return(error);
758d323ddf3SMatthew Dillon }
759d323ddf3SMatthew Dillon 
760d66a5066SPeter Wemm struct sysentvec linux_sysvec = {
761e1743d02SSøren Schmidt 	LINUX_SYS_MAXSYSCALL,
762d66a5066SPeter Wemm 	linux_sysent,
763d66a5066SPeter Wemm 	0xff,
764956d3333SMarcel Moolenaar 	LINUX_SIGTBLSZ,
765d66a5066SPeter Wemm 	bsd_to_linux_signal,
76685f118c8SDmitrij Tejblum 	ELAST + 1,
767d66a5066SPeter Wemm 	bsd_to_linux_errno,
768288078beSEivind Eklund 	translate_traps,
769d66a5066SPeter Wemm 	linux_fixup,
770d66a5066SPeter Wemm 	linux_sendsig,
771d66a5066SPeter Wemm 	linux_sigcode,
772d66a5066SPeter Wemm 	&linux_szsigcode,
773d66a5066SPeter Wemm 	linux_prepsyscall,
77422d4b0fbSJohn Polstra 	"Linux a.out",
775d323ddf3SMatthew Dillon 	aout_coredump,
776806d7daaSMarcel Moolenaar 	exec_linux_imgact_try,
777f36ba452SJake Burkholder 	LINUX_MINSIGSTKSZ,
778f36ba452SJake Burkholder 	PAGE_SIZE,
779f36ba452SJake Burkholder 	VM_MIN_ADDRESS,
780f36ba452SJake Burkholder 	VM_MAXUSER_ADDRESS,
781f36ba452SJake Burkholder 	USRSTACK,
782f36ba452SJake Burkholder 	PS_STRINGS,
783f36ba452SJake Burkholder 	VM_PROT_ALL,
784f36ba452SJake Burkholder 	exec_copyout_strings,
785f36ba452SJake Burkholder 	exec_setregs
786d66a5066SPeter Wemm };
787e1743d02SSøren Schmidt 
788e1743d02SSøren Schmidt struct sysentvec elf_linux_sysvec = {
789e1743d02SSøren Schmidt 	LINUX_SYS_MAXSYSCALL,
790e1743d02SSøren Schmidt 	linux_sysent,
791e1743d02SSøren Schmidt 	0xff,
792956d3333SMarcel Moolenaar 	LINUX_SIGTBLSZ,
793e1743d02SSøren Schmidt 	bsd_to_linux_signal,
79485f118c8SDmitrij Tejblum 	ELAST + 1,
795e1743d02SSøren Schmidt 	bsd_to_linux_errno,
796288078beSEivind Eklund 	translate_traps,
797e1743d02SSøren Schmidt 	elf_linux_fixup,
798e1743d02SSøren Schmidt 	linux_sendsig,
799e1743d02SSøren Schmidt 	linux_sigcode,
800e1743d02SSøren Schmidt 	&linux_szsigcode,
801e1743d02SSøren Schmidt 	linux_prepsyscall,
80222d4b0fbSJohn Polstra 	"Linux ELF",
8033ebc1248SPeter Wemm 	elf32_coredump,
804806d7daaSMarcel Moolenaar 	exec_linux_imgact_try,
805f36ba452SJake Burkholder 	LINUX_MINSIGSTKSZ,
806f36ba452SJake Burkholder 	PAGE_SIZE,
807f36ba452SJake Burkholder 	VM_MIN_ADDRESS,
808f36ba452SJake Burkholder 	VM_MAXUSER_ADDRESS,
809f36ba452SJake Burkholder 	USRSTACK,
810f36ba452SJake Burkholder 	PS_STRINGS,
811f36ba452SJake Burkholder 	VM_PROT_ALL,
812f36ba452SJake Burkholder 	exec_copyout_strings,
813f36ba452SJake Burkholder 	exec_setregs
814e1743d02SSøren Schmidt };
815e1743d02SSøren Schmidt 
816514058dcSAlexander Langer static Elf32_Brandinfo linux_brand = {
817c815a20cSDavid E. O'Brien 					ELFOSABI_LINUX,
8183ebc1248SPeter Wemm 					EM_386,
81921a3ee0eSDavid E. O'Brien 					"Linux",
820ea5a2b2eSSøren Schmidt 					"/compat/linux",
8215cf588ebSPeter Wemm 					"/lib/ld-linux.so.1",
822ea5a2b2eSSøren Schmidt 					&elf_linux_sysvec
8235cf588ebSPeter Wemm 				 };
8245cf588ebSPeter Wemm 
825514058dcSAlexander Langer static Elf32_Brandinfo linux_glibc2brand = {
826c815a20cSDavid E. O'Brien 					ELFOSABI_LINUX,
8273ebc1248SPeter Wemm 					EM_386,
82821a3ee0eSDavid E. O'Brien 					"Linux",
8294e138a28SMike Smith 					"/compat/linux",
8304e138a28SMike Smith 					"/lib/ld-linux.so.2",
8314e138a28SMike Smith 					&elf_linux_sysvec
8324e138a28SMike Smith 				 };
8334e138a28SMike Smith 
834514058dcSAlexander Langer Elf32_Brandinfo *linux_brandlist[] = {
835514058dcSAlexander Langer 					&linux_brand,
836514058dcSAlexander Langer 					&linux_glibc2brand,
837514058dcSAlexander Langer 					NULL
838514058dcSAlexander Langer 				};
839514058dcSAlexander Langer 
840aa855a59SPeter Wemm static int
841c25ded31SBruce Evans linux_elf_modevent(module_t mod, int type, void *data)
842d30ea4f5SPeter Wemm {
843514058dcSAlexander Langer 	Elf32_Brandinfo **brandinfo;
844514058dcSAlexander Langer 	int error;
845f41325dbSPeter Wemm 	struct linux_ioctl_handler **lihp;
846514058dcSAlexander Langer 
847514058dcSAlexander Langer 	error = 0;
848514058dcSAlexander Langer 
849aa855a59SPeter Wemm 	switch(type) {
850aa855a59SPeter Wemm 	case MOD_LOAD:
851aa855a59SPeter Wemm 		for (brandinfo = &linux_brandlist[0]; *brandinfo != NULL;
852aa855a59SPeter Wemm 		     ++brandinfo)
8533ebc1248SPeter Wemm 			if (elf32_insert_brand_entry(*brandinfo) < 0)
854aa855a59SPeter Wemm 				error = EINVAL;
855466b14d7SMarcel Moolenaar 		if (error == 0) {
856f41325dbSPeter Wemm 			SET_FOREACH(lihp, linux_ioctl_handler_set)
857f41325dbSPeter Wemm 				linux_ioctl_register_handler(*lihp);
85843bef515SMarcel Moolenaar 			if (bootverbose)
859466b14d7SMarcel Moolenaar 				printf("Linux ELF exec handler installed\n");
860466b14d7SMarcel Moolenaar 		} else
861466b14d7SMarcel Moolenaar 			printf("cannot insert Linux ELF brand handler\n");
862aa855a59SPeter Wemm 		break;
863aa855a59SPeter Wemm 	case MOD_UNLOAD:
864aa855a59SPeter Wemm 		for (brandinfo = &linux_brandlist[0]; *brandinfo != NULL;
865aa855a59SPeter Wemm 		     ++brandinfo)
8663ebc1248SPeter Wemm 			if (elf32_brand_inuse(*brandinfo))
867d2758342SMark Newton 				error = EBUSY;
868d2758342SMark Newton 		if (error == 0) {
869d2758342SMark Newton 			for (brandinfo = &linux_brandlist[0];
870d2758342SMark Newton 			     *brandinfo != NULL; ++brandinfo)
8713ebc1248SPeter Wemm 				if (elf32_remove_brand_entry(*brandinfo) < 0)
872aa855a59SPeter Wemm 					error = EINVAL;
873d2758342SMark Newton 		}
874466b14d7SMarcel Moolenaar 		if (error == 0) {
875f41325dbSPeter Wemm 			SET_FOREACH(lihp, linux_ioctl_handler_set)
876f41325dbSPeter Wemm 				linux_ioctl_unregister_handler(*lihp);
877466b14d7SMarcel Moolenaar 			if (bootverbose)
878466b14d7SMarcel Moolenaar 				printf("Linux ELF exec handler removed\n");
879466b14d7SMarcel Moolenaar 		} else
880aa855a59SPeter Wemm 			printf("Could not deinstall ELF interpreter entry\n");
881aa855a59SPeter Wemm 		break;
882aa855a59SPeter Wemm 	default:
883aa855a59SPeter Wemm 		break;
884d30ea4f5SPeter Wemm 	}
885aa855a59SPeter Wemm 	return error;
886aa855a59SPeter Wemm }
887466b14d7SMarcel Moolenaar 
888aa855a59SPeter Wemm static moduledata_t linux_elf_mod = {
889aa855a59SPeter Wemm 	"linuxelf",
890aa855a59SPeter Wemm 	linux_elf_modevent,
891aa855a59SPeter Wemm 	0
892aa855a59SPeter Wemm };
893466b14d7SMarcel Moolenaar 
894aa855a59SPeter Wemm DECLARE_MODULE(linuxelf, linux_elf_mod, SI_SUB_EXEC, SI_ORDER_ANY);
895