xref: /freebsd/sys/i386/linux/linux_sysvec.c (revision f41325db5f16640212574a03b9a34e5ed4a884ca)
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
15d66a5066SPeter Wemm  *    derived from this software withough 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>
43e1743d02SSøren Schmidt #include <sys/malloc.h>
4423955314SAlfred Perlstein #include <sys/mutex.h>
45fb919e4dSMark Murray #include <sys/proc.h>
46fb919e4dSMark Murray #include <sys/signalvar.h>
47fb919e4dSMark Murray #include <sys/sysent.h>
48fb919e4dSMark Murray #include <sys/sysproto.h>
49fb919e4dSMark Murray 
50d66a5066SPeter Wemm #include <vm/vm.h>
51d66a5066SPeter Wemm #include <vm/vm_param.h>
52d66a5066SPeter Wemm #include <vm/vm_page.h>
53d66a5066SPeter Wemm #include <vm/vm_extern.h>
54d66a5066SPeter Wemm #include <sys/exec.h>
555cf588ebSPeter Wemm #include <sys/kernel.h>
56aa855a59SPeter Wemm #include <sys/module.h>
57d66a5066SPeter Wemm #include <machine/cpu.h>
58fb919e4dSMark Murray #include <sys/lock.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 
7943bef515SMarcel Moolenaar extern char linux_sigcode[];
8043bef515SMarcel Moolenaar extern int linux_szsigcode;
8143bef515SMarcel Moolenaar 
8243bef515SMarcel Moolenaar extern struct sysent linux_sysent[LINUX_SYS_MAXSYSCALL];
8343bef515SMarcel Moolenaar 
84f41325dbSPeter Wemm SET_DECLARE(linux_ioctl_handler_set, struct linux_ioctl_handler);
8543bef515SMarcel Moolenaar 
86654f6be1SBruce Evans static int	linux_fixup __P((register_t **stack_base,
87303b270bSEivind Eklund 				 struct image_params *iparams));
88654f6be1SBruce Evans static int	elf_linux_fixup __P((register_t **stack_base,
89303b270bSEivind Eklund 				     struct image_params *iparams));
90303b270bSEivind Eklund static void	linux_prepsyscall __P((struct trapframe *tf, int *args,
91303b270bSEivind Eklund 				       u_int *code, caddr_t *params));
92956d3333SMarcel Moolenaar static void     linux_sendsig __P((sig_t catcher, int sig, sigset_t *mask,
93303b270bSEivind Eklund 				   u_long code));
94d66a5066SPeter Wemm 
95d66a5066SPeter Wemm /*
96d66a5066SPeter Wemm  * Linux syscalls return negative errno's, we do positive and map them
97d66a5066SPeter Wemm  */
9885f118c8SDmitrij Tejblum static int bsd_to_linux_errno[ELAST + 1] = {
99d66a5066SPeter Wemm   	-0,  -1,  -2,  -3,  -4,  -5,  -6,  -7,  -8,  -9,
100d66a5066SPeter Wemm  	-10, -35, -12, -13, -14, -15, -16, -17, -18, -19,
101d66a5066SPeter Wemm  	-20, -21, -22, -23, -24, -25, -26, -27, -28, -29,
102d66a5066SPeter Wemm  	-30, -31, -32, -33, -34, -11,-115,-114, -88, -89,
103d66a5066SPeter Wemm  	-90, -91, -92, -93, -94, -95, -96, -97, -98, -99,
104d66a5066SPeter Wemm 	-100,-101,-102,-103,-104,-105,-106,-107,-108,-109,
105d66a5066SPeter Wemm 	-110,-111, -40, -36,-112,-113, -39, -11, -87,-122,
106d66a5066SPeter Wemm 	-116, -66,  -6,  -6,  -6,  -6,  -6, -37, -38,  -9,
10785f118c8SDmitrij Tejblum   	-6, -6, -43, -42, -75, -6, -84
108d66a5066SPeter Wemm };
109d66a5066SPeter Wemm 
110956d3333SMarcel Moolenaar int bsd_to_linux_signal[LINUX_SIGTBLSZ] = {
111956d3333SMarcel Moolenaar 	LINUX_SIGHUP, LINUX_SIGINT, LINUX_SIGQUIT, LINUX_SIGILL,
112956d3333SMarcel Moolenaar 	LINUX_SIGTRAP, LINUX_SIGABRT, 0, LINUX_SIGFPE,
113956d3333SMarcel Moolenaar 	LINUX_SIGKILL, LINUX_SIGBUS, LINUX_SIGSEGV, 0,
114956d3333SMarcel Moolenaar 	LINUX_SIGPIPE, LINUX_SIGALRM, LINUX_SIGTERM, LINUX_SIGURG,
115956d3333SMarcel Moolenaar 	LINUX_SIGSTOP, LINUX_SIGTSTP, LINUX_SIGCONT, LINUX_SIGCHLD,
116956d3333SMarcel Moolenaar 	LINUX_SIGTTIN, LINUX_SIGTTOU, LINUX_SIGIO, LINUX_SIGXCPU,
117956d3333SMarcel Moolenaar 	LINUX_SIGXFSZ, LINUX_SIGVTALRM, LINUX_SIGPROF, LINUX_SIGWINCH,
118956d3333SMarcel Moolenaar 	0, LINUX_SIGUSR1, LINUX_SIGUSR2
119d66a5066SPeter Wemm };
120d66a5066SPeter Wemm 
121956d3333SMarcel Moolenaar int linux_to_bsd_signal[LINUX_SIGTBLSZ] = {
122956d3333SMarcel Moolenaar 	SIGHUP, SIGINT, SIGQUIT, SIGILL,
123956d3333SMarcel Moolenaar 	SIGTRAP, SIGABRT, SIGBUS, SIGFPE,
124956d3333SMarcel Moolenaar 	SIGKILL, SIGUSR1, SIGSEGV, SIGUSR2,
125956d3333SMarcel Moolenaar 	SIGPIPE, SIGALRM, SIGTERM, SIGBUS,
126956d3333SMarcel Moolenaar 	SIGCHLD, SIGCONT, SIGSTOP, SIGTSTP,
127956d3333SMarcel Moolenaar 	SIGTTIN, SIGTTOU, SIGURG, SIGXCPU,
128956d3333SMarcel Moolenaar 	SIGXFSZ, SIGVTALRM, SIGPROF, SIGWINCH,
129956d3333SMarcel Moolenaar 	SIGIO, SIGURG, 0
130d66a5066SPeter Wemm };
131d66a5066SPeter Wemm 
132288078beSEivind Eklund /*
133288078beSEivind Eklund  * If FreeBSD & Linux have a difference of opinion about what a trap
134288078beSEivind Eklund  * means, deal with it here.
135288078beSEivind Eklund  */
136288078beSEivind Eklund static int
137288078beSEivind Eklund translate_traps(int signal, int trap_code)
138288078beSEivind Eklund {
139d563a53aSEivind Eklund 	if (signal != SIGBUS)
140d563a53aSEivind Eklund 		return signal;
141288078beSEivind Eklund 	switch (trap_code) {
142288078beSEivind Eklund 	case T_PROTFLT:
143288078beSEivind Eklund 	case T_TSSFLT:
144288078beSEivind Eklund 	case T_DOUBLEFLT:
145288078beSEivind Eklund 	case T_PAGEFLT:
146288078beSEivind Eklund 		return SIGSEGV;
147288078beSEivind Eklund 	default:
148288078beSEivind Eklund 		return signal;
149288078beSEivind Eklund 	}
150288078beSEivind Eklund }
151288078beSEivind Eklund 
152303b270bSEivind Eklund static int
153654f6be1SBruce Evans linux_fixup(register_t **stack_base, struct image_params *imgp)
154d66a5066SPeter Wemm {
155654f6be1SBruce Evans 	register_t *argv, *envp;
156d66a5066SPeter Wemm 
157d66a5066SPeter Wemm 	argv = *stack_base;
158d66a5066SPeter Wemm 	envp = *stack_base + (imgp->argc + 1);
159d66a5066SPeter Wemm 	(*stack_base)--;
16086a14a7aSBruce Evans 	**stack_base = (intptr_t)(void *)envp;
161d66a5066SPeter Wemm 	(*stack_base)--;
16286a14a7aSBruce Evans 	**stack_base = (intptr_t)(void *)argv;
163d66a5066SPeter Wemm 	(*stack_base)--;
16486a14a7aSBruce Evans 	**stack_base = imgp->argc;
165e1743d02SSøren Schmidt 	return 0;
166d66a5066SPeter Wemm }
167d66a5066SPeter Wemm 
168303b270bSEivind Eklund static int
169654f6be1SBruce Evans elf_linux_fixup(register_t **stack_base, struct image_params *imgp)
170e1743d02SSøren Schmidt {
171e1743d02SSøren Schmidt 	Elf32_Auxargs *args = (Elf32_Auxargs *)imgp->auxargs;
172654f6be1SBruce Evans 	register_t *pos;
173d66a5066SPeter Wemm 
174e1743d02SSøren Schmidt 	pos = *stack_base + (imgp->argc + imgp->envc + 2);
175e1743d02SSøren Schmidt 
176e1743d02SSøren Schmidt 	if (args->trace) {
177e1743d02SSøren Schmidt 		AUXARGS_ENTRY(pos, AT_DEBUG, 1);
178e1743d02SSøren Schmidt 	}
179e1743d02SSøren Schmidt 	if (args->execfd != -1) {
180e1743d02SSøren Schmidt 		AUXARGS_ENTRY(pos, AT_EXECFD, args->execfd);
181e1743d02SSøren Schmidt 	}
182e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_PHDR, args->phdr);
183e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_PHENT, args->phent);
184e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_PHNUM, args->phnum);
185e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_PAGESZ, args->pagesz);
186e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_FLAGS, args->flags);
187e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_ENTRY, args->entry);
188e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_BASE, args->base);
189611d9407SJohn Baldwin 	PROC_LOCK(imgp->proc);
190b1fc0ec1SRobert Watson 	AUXARGS_ENTRY(pos, AT_UID, imgp->proc->p_ucred->cr_ruid);
191b1fc0ec1SRobert Watson 	AUXARGS_ENTRY(pos, AT_EUID, imgp->proc->p_ucred->cr_svuid);
192b1fc0ec1SRobert Watson 	AUXARGS_ENTRY(pos, AT_GID, imgp->proc->p_ucred->cr_rgid);
193b1fc0ec1SRobert Watson 	AUXARGS_ENTRY(pos, AT_EGID, imgp->proc->p_ucred->cr_svgid);
194611d9407SJohn Baldwin 	PROC_UNLOCK(imgp->proc);
195e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_NULL, 0);
196e1743d02SSøren Schmidt 
197e1743d02SSøren Schmidt 	free(imgp->auxargs, M_TEMP);
198e1743d02SSøren Schmidt 	imgp->auxargs = NULL;
199e1743d02SSøren Schmidt 
200e1743d02SSøren Schmidt 	(*stack_base)--;
201ecbb00a2SDoug Rabson 	**stack_base = (long)imgp->argc;
202e1743d02SSøren Schmidt 	return 0;
203e1743d02SSøren Schmidt }
204d66a5066SPeter Wemm 
205d66a5066SPeter Wemm extern int _ucodesel, _udatasel;
20602318dacSJake Burkholder extern unsigned long linux_sznonrtsigcode;
20779363394SAndrew Gallatin 
20879363394SAndrew Gallatin static void
20979363394SAndrew Gallatin linux_rt_sendsig(sig_t catcher, int sig, sigset_t *mask, u_long code)
21079363394SAndrew Gallatin {
21179363394SAndrew Gallatin 	register struct proc *p = curproc;
21279363394SAndrew Gallatin 	register struct trapframe *regs;
21379363394SAndrew Gallatin 	struct linux_rt_sigframe *fp, frame;
21479363394SAndrew Gallatin 	int oonstack;
21579363394SAndrew Gallatin 
21679363394SAndrew Gallatin 	regs = p->p_md.md_regs;
217d034d459SMarcel Moolenaar 	oonstack = sigonstack(regs->tf_esp);
21879363394SAndrew Gallatin 
21979363394SAndrew Gallatin #ifdef DEBUG
22024593369SJonathan Lemon 	if (ldebug(sigreturn))
22124593369SJonathan Lemon 		printf(ARGS(rt_sendsig, "%p, %d, %p, %lu"),
22224593369SJonathan Lemon 		    catcher, sig, (void*)mask, code);
22379363394SAndrew Gallatin #endif
22479363394SAndrew Gallatin 	/*
22579363394SAndrew Gallatin 	 * Allocate space for the signal handler context.
22679363394SAndrew Gallatin 	 */
227611d9407SJohn Baldwin 	PROC_LOCK(p);
22879363394SAndrew Gallatin 	if ((p->p_flag & P_ALTSTACK) && !oonstack &&
229cc6ca9b3SMarcel Moolenaar 	    SIGISMEMBER(p->p_sigacts->ps_sigonstack, sig)) {
23079363394SAndrew Gallatin 		fp = (struct linux_rt_sigframe *)(p->p_sigstk.ss_sp +
23179363394SAndrew Gallatin 		    p->p_sigstk.ss_size - sizeof(struct linux_rt_sigframe));
232d034d459SMarcel Moolenaar 	} else
23379363394SAndrew Gallatin 		fp = (struct linux_rt_sigframe *)regs->tf_esp - 1;
234611d9407SJohn Baldwin 	PROC_UNLOCK(p);
23579363394SAndrew Gallatin 
23679363394SAndrew Gallatin 	/*
23779363394SAndrew Gallatin 	 * grow() will return FALSE if the fp will not fit inside the stack
23879363394SAndrew Gallatin 	 *	and the stack can not be grown. useracc will return FALSE
23979363394SAndrew Gallatin 	 *	if access is denied.
24079363394SAndrew Gallatin 	 */
24179363394SAndrew Gallatin 	if ((grow_stack (p, (int)fp) == FALSE) ||
24279363394SAndrew Gallatin 	    !useracc((caddr_t)fp, sizeof (struct linux_rt_sigframe),
24379363394SAndrew Gallatin 	    VM_PROT_WRITE)) {
24479363394SAndrew Gallatin 		/*
24579363394SAndrew Gallatin 		 * Process has trashed its stack; give it an illegal
24679363394SAndrew Gallatin 		 * instruction to halt it in its tracks.
24779363394SAndrew Gallatin 		 */
248611d9407SJohn Baldwin 		PROC_LOCK(p);
24979363394SAndrew Gallatin 		SIGACTION(p, SIGILL) = SIG_DFL;
25079363394SAndrew Gallatin 		SIGDELSET(p->p_sigignore, SIGILL);
25179363394SAndrew Gallatin 		SIGDELSET(p->p_sigcatch, SIGILL);
25279363394SAndrew Gallatin 		SIGDELSET(p->p_sigmask, SIGILL);
25379363394SAndrew Gallatin #ifdef DEBUG
25424593369SJonathan Lemon 		if (ldebug(sigreturn))
25524593369SJonathan Lemon 			printf(LMSG("rt_sendsig: bad stack %p, oonstack=%x"),
25624593369SJonathan Lemon 			    fp, oonstack);
25779363394SAndrew Gallatin #endif
25879363394SAndrew Gallatin 		psignal(p, SIGILL);
25919eb87d2SJohn Baldwin 		PROC_UNLOCK(p);
26079363394SAndrew Gallatin 		return;
26179363394SAndrew Gallatin 	}
26279363394SAndrew Gallatin 
26379363394SAndrew Gallatin 	/*
26479363394SAndrew Gallatin 	 * Build the argument list for the signal handler.
26579363394SAndrew Gallatin 	 */
26679363394SAndrew Gallatin 	if (p->p_sysent->sv_sigtbl)
26779363394SAndrew Gallatin 		if (sig <= p->p_sysent->sv_sigsize)
26879363394SAndrew Gallatin 			sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)];
26979363394SAndrew Gallatin 
27079363394SAndrew Gallatin 	frame.sf_handler = catcher;
27179363394SAndrew Gallatin 	frame.sf_sig = sig;
27279363394SAndrew Gallatin 	frame.sf_siginfo = &fp->sf_si;
27379363394SAndrew Gallatin 	frame.sf_ucontext = &fp->sf_sc;
274cc6ca9b3SMarcel Moolenaar 
27579363394SAndrew Gallatin 	/* Fill siginfo structure. */
27679363394SAndrew Gallatin 	frame.sf_si.lsi_signo = sig;
27779363394SAndrew Gallatin 	frame.sf_si.lsi_code = code;
27879363394SAndrew Gallatin 	frame.sf_si.lsi_addr = (void *)regs->tf_err;
279cc6ca9b3SMarcel Moolenaar 
28079363394SAndrew Gallatin 	/*
28179363394SAndrew Gallatin 	 * Build the signal context to be used by sigreturn.
28279363394SAndrew Gallatin 	 */
283cc6ca9b3SMarcel Moolenaar 	frame.sf_sc.uc_flags = 0;		/* XXX ??? */
284cc6ca9b3SMarcel Moolenaar 	frame.sf_sc.uc_link = NULL;		/* XXX ??? */
285cc6ca9b3SMarcel Moolenaar 
286611d9407SJohn Baldwin 	PROC_LOCK(p);
287cc6ca9b3SMarcel Moolenaar 	frame.sf_sc.uc_stack.ss_sp = p->p_sigstk.ss_sp;
288cc6ca9b3SMarcel Moolenaar 	frame.sf_sc.uc_stack.ss_size = p->p_sigstk.ss_size;
289d034d459SMarcel Moolenaar 	frame.sf_sc.uc_stack.ss_flags = (p->p_flag & P_ALTSTACK)
290d034d459SMarcel Moolenaar 	    ? ((oonstack) ? LINUX_SS_ONSTACK : 0) : LINUX_SS_DISABLE;
291611d9407SJohn Baldwin 	PROC_UNLOCK(p);
292cc6ca9b3SMarcel Moolenaar 
293cc6ca9b3SMarcel Moolenaar 	bsd_to_linux_sigset(mask, &frame.sf_sc.uc_sigmask);
294cc6ca9b3SMarcel Moolenaar 
295cc6ca9b3SMarcel Moolenaar 	frame.sf_sc.uc_mcontext.sc_mask   = frame.sf_sc.uc_sigmask.__bits[0];
29679363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_gs     = rgs();
29779363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_fs     = regs->tf_fs;
29879363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_es     = regs->tf_es;
29979363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_ds     = regs->tf_ds;
30079363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_edi    = regs->tf_edi;
30179363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_esi    = regs->tf_esi;
30279363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_ebp    = regs->tf_ebp;
30379363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_ebx    = regs->tf_ebx;
30479363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_edx    = regs->tf_edx;
30579363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_ecx    = regs->tf_ecx;
30679363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_eax    = regs->tf_eax;
30779363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_eip    = regs->tf_eip;
30879363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_cs     = regs->tf_cs;
30979363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_eflags = regs->tf_eflags;
31079363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_esp_at_signal = regs->tf_esp;
31179363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_ss     = regs->tf_ss;
31279363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_err    = regs->tf_err;
31379363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_trapno = code;	/* XXX ???? */
31479363394SAndrew Gallatin 
31579363394SAndrew Gallatin #ifdef DEBUG
31624593369SJonathan Lemon 	if (ldebug(sigreturn))
31724593369SJonathan Lemon 		printf(LMSG("rt_sendsig flags: 0x%x, sp: %p, ss: 0x%x, mask: 0x%x"),
31824593369SJonathan Lemon 		    frame.sf_sc.uc_stack.ss_flags, p->p_sigstk.ss_sp,
31924593369SJonathan Lemon 		    p->p_sigstk.ss_size, frame.sf_sc.uc_mcontext.sc_mask);
32079363394SAndrew Gallatin #endif
32179363394SAndrew Gallatin 
32279363394SAndrew Gallatin 	if (copyout(&frame, fp, sizeof(frame)) != 0) {
32379363394SAndrew Gallatin 		/*
32479363394SAndrew Gallatin 		 * Process has trashed its stack; give it an illegal
32579363394SAndrew Gallatin 		 * instruction to halt it in its tracks.
32679363394SAndrew Gallatin 		 */
32719eb87d2SJohn Baldwin 		PROC_LOCK(p);
32879363394SAndrew Gallatin 		sigexit(p, SIGILL);
32979363394SAndrew Gallatin 		/* NOTREACHED */
33079363394SAndrew Gallatin 	}
33179363394SAndrew Gallatin 
33279363394SAndrew Gallatin 	/*
33379363394SAndrew Gallatin 	 * Build context to run handler in.
33479363394SAndrew Gallatin 	 */
33579363394SAndrew Gallatin 	regs->tf_esp = (int)fp;
33679363394SAndrew Gallatin 	regs->tf_eip = PS_STRINGS - *(p->p_sysent->sv_szsigcode) +
33702318dacSJake Burkholder 	    linux_sznonrtsigcode;
33879363394SAndrew Gallatin 	regs->tf_eflags &= ~PSL_VM;
33979363394SAndrew Gallatin 	regs->tf_cs = _ucodesel;
34079363394SAndrew Gallatin 	regs->tf_ds = _udatasel;
34179363394SAndrew Gallatin 	regs->tf_es = _udatasel;
34279363394SAndrew Gallatin 	regs->tf_fs = _udatasel;
34379363394SAndrew Gallatin 	regs->tf_ss = _udatasel;
34479363394SAndrew Gallatin }
34579363394SAndrew Gallatin 
346d66a5066SPeter Wemm 
347d66a5066SPeter Wemm /*
348d66a5066SPeter Wemm  * Send an interrupt to process.
349d66a5066SPeter Wemm  *
350d66a5066SPeter Wemm  * Stack is set up to allow sigcode stored
351d66a5066SPeter Wemm  * in u. to call routine, followed by kcall
352d66a5066SPeter Wemm  * to sigreturn routine below.  After sigreturn
353d66a5066SPeter Wemm  * resets the signal mask, the stack, and the
354d66a5066SPeter Wemm  * frame pointer, it returns to the user
355d66a5066SPeter Wemm  * specified pc, psl.
356d66a5066SPeter Wemm  */
357d66a5066SPeter Wemm 
358303b270bSEivind Eklund static void
359956d3333SMarcel Moolenaar linux_sendsig(sig_t catcher, int sig, sigset_t *mask, u_long code)
360d66a5066SPeter Wemm {
361d66a5066SPeter Wemm 	register struct proc *p = curproc;
362213fdd80SPeter Wemm 	register struct trapframe *regs;
363d66a5066SPeter Wemm 	struct linux_sigframe *fp, frame;
364cc6ca9b3SMarcel Moolenaar 	linux_sigset_t lmask;
3652c4ab9ddSAndrew Gallatin 	int oonstack, i;
366d66a5066SPeter Wemm 
367cc6ca9b3SMarcel Moolenaar 	if (SIGISMEMBER(p->p_sigacts->ps_siginfo, sig)) {
368cc6ca9b3SMarcel Moolenaar 		/* Signal handler installed with SA_SIGINFO. */
369cc6ca9b3SMarcel Moolenaar 		linux_rt_sendsig(catcher, sig, mask, code);
370cc6ca9b3SMarcel Moolenaar 		return;
371cc6ca9b3SMarcel Moolenaar 	}
372cc6ca9b3SMarcel Moolenaar 
373d66a5066SPeter Wemm 	regs = p->p_md.md_regs;
374d034d459SMarcel Moolenaar 	oonstack = sigonstack(regs->tf_esp);
375d66a5066SPeter Wemm 
376d66a5066SPeter Wemm #ifdef DEBUG
37724593369SJonathan Lemon 	if (ldebug(sigreturn))
37824593369SJonathan Lemon 		printf(ARGS(sendsig, "%p, %d, %p, %lu"),
37924593369SJonathan Lemon 		    catcher, sig, (void*)mask, code);
380d66a5066SPeter Wemm #endif
38179363394SAndrew Gallatin 
382d66a5066SPeter Wemm 	/*
383d66a5066SPeter Wemm 	 * Allocate space for the signal handler context.
384d66a5066SPeter Wemm 	 */
385611d9407SJohn Baldwin 	PROC_LOCK(p);
386645682fdSLuoqi Chen 	if ((p->p_flag & P_ALTSTACK) && !oonstack &&
387cc6ca9b3SMarcel Moolenaar 	    SIGISMEMBER(p->p_sigacts->ps_sigonstack, sig)) {
388645682fdSLuoqi Chen 		fp = (struct linux_sigframe *)(p->p_sigstk.ss_sp +
389645682fdSLuoqi Chen 		    p->p_sigstk.ss_size - sizeof(struct linux_sigframe));
390d034d459SMarcel Moolenaar 	} else
391213fdd80SPeter Wemm 		fp = (struct linux_sigframe *)regs->tf_esp - 1;
392611d9407SJohn Baldwin 	PROC_UNLOCK(p);
393d66a5066SPeter Wemm 
394d66a5066SPeter Wemm 	/*
395d66a5066SPeter Wemm 	 * grow() will return FALSE if the fp will not fit inside the stack
396d66a5066SPeter Wemm 	 *	and the stack can not be grown. useracc will return FALSE
397d66a5066SPeter Wemm 	 *	if access is denied.
398d66a5066SPeter Wemm 	 */
3996626c604SJulian Elischer 	if ((grow_stack (p, (int)fp) == FALSE) ||
40002c58685SPoul-Henning Kamp 	    !useracc((caddr_t)fp, sizeof (struct linux_sigframe),
40102c58685SPoul-Henning Kamp 	    VM_PROT_WRITE)) {
402d66a5066SPeter Wemm 		/*
403d66a5066SPeter Wemm 		 * Process has trashed its stack; give it an illegal
404d66a5066SPeter Wemm 		 * instruction to halt it in its tracks.
405d66a5066SPeter Wemm 		 */
406611d9407SJohn Baldwin 		PROC_LOCK(p);
407d66a5066SPeter Wemm 		SIGACTION(p, SIGILL) = SIG_DFL;
408956d3333SMarcel Moolenaar 		SIGDELSET(p->p_sigignore, SIGILL);
409956d3333SMarcel Moolenaar 		SIGDELSET(p->p_sigcatch, SIGILL);
410956d3333SMarcel Moolenaar 		SIGDELSET(p->p_sigmask, SIGILL);
411d66a5066SPeter Wemm 		psignal(p, SIGILL);
41219eb87d2SJohn Baldwin 		PROC_UNLOCK(p);
413d66a5066SPeter Wemm 		return;
414d66a5066SPeter Wemm 	}
415d66a5066SPeter Wemm 
416d66a5066SPeter Wemm 	/*
417d66a5066SPeter Wemm 	 * Build the argument list for the signal handler.
418d66a5066SPeter Wemm 	 */
419956d3333SMarcel Moolenaar 	if (p->p_sysent->sv_sigtbl)
420956d3333SMarcel Moolenaar 		if (sig <= p->p_sysent->sv_sigsize)
421956d3333SMarcel Moolenaar 			sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)];
422d66a5066SPeter Wemm 
423d66a5066SPeter Wemm 	frame.sf_handler = catcher;
424d66a5066SPeter Wemm 	frame.sf_sig = sig;
425d66a5066SPeter Wemm 
426cc6ca9b3SMarcel Moolenaar 	bsd_to_linux_sigset(mask, &lmask);
427cc6ca9b3SMarcel Moolenaar 
428d66a5066SPeter Wemm 	/*
429d66a5066SPeter Wemm 	 * Build the signal context to be used by sigreturn.
430d66a5066SPeter Wemm 	 */
431cc6ca9b3SMarcel Moolenaar 	frame.sf_sc.sc_mask   = lmask.__bits[0];
4325206bca1SLuoqi Chen 	frame.sf_sc.sc_gs     = rgs();
4335206bca1SLuoqi Chen 	frame.sf_sc.sc_fs     = regs->tf_fs;
434213fdd80SPeter Wemm 	frame.sf_sc.sc_es     = regs->tf_es;
435213fdd80SPeter Wemm 	frame.sf_sc.sc_ds     = regs->tf_ds;
436213fdd80SPeter Wemm 	frame.sf_sc.sc_edi    = regs->tf_edi;
437213fdd80SPeter Wemm 	frame.sf_sc.sc_esi    = regs->tf_esi;
438213fdd80SPeter Wemm 	frame.sf_sc.sc_ebp    = regs->tf_ebp;
439213fdd80SPeter Wemm 	frame.sf_sc.sc_ebx    = regs->tf_ebx;
440213fdd80SPeter Wemm 	frame.sf_sc.sc_edx    = regs->tf_edx;
441213fdd80SPeter Wemm 	frame.sf_sc.sc_ecx    = regs->tf_ecx;
442213fdd80SPeter Wemm 	frame.sf_sc.sc_eax    = regs->tf_eax;
443213fdd80SPeter Wemm 	frame.sf_sc.sc_eip    = regs->tf_eip;
444213fdd80SPeter Wemm 	frame.sf_sc.sc_cs     = regs->tf_cs;
445213fdd80SPeter Wemm 	frame.sf_sc.sc_eflags = regs->tf_eflags;
446213fdd80SPeter Wemm 	frame.sf_sc.sc_esp_at_signal = regs->tf_esp;
447213fdd80SPeter Wemm 	frame.sf_sc.sc_ss     = regs->tf_ss;
448213fdd80SPeter Wemm 	frame.sf_sc.sc_err    = regs->tf_err;
449d66a5066SPeter Wemm 	frame.sf_sc.sc_trapno = code;	/* XXX ???? */
450cc6ca9b3SMarcel Moolenaar 
451cc6ca9b3SMarcel Moolenaar 	bzero(&frame.sf_fpstate, sizeof(struct linux_fpstate));
452cc6ca9b3SMarcel Moolenaar 
4532c4ab9ddSAndrew Gallatin 	for (i = 0; i < (LINUX_NSIG_WORDS-1); i++)
454cc6ca9b3SMarcel Moolenaar 		frame.sf_extramask[i] = lmask.__bits[i+1];
455d66a5066SPeter Wemm 
456d66a5066SPeter Wemm 	if (copyout(&frame, fp, sizeof(frame)) != 0) {
457d66a5066SPeter Wemm 		/*
458d66a5066SPeter Wemm 		 * Process has trashed its stack; give it an illegal
459d66a5066SPeter Wemm 		 * instruction to halt it in its tracks.
460d66a5066SPeter Wemm 		 */
46119eb87d2SJohn Baldwin 		PROC_LOCK(p);
462d66a5066SPeter Wemm 		sigexit(p, SIGILL);
463d66a5066SPeter Wemm 		/* NOTREACHED */
464d66a5066SPeter Wemm 	}
465d66a5066SPeter Wemm 
466d66a5066SPeter Wemm 	/*
467d66a5066SPeter Wemm 	 * Build context to run handler in.
468d66a5066SPeter Wemm 	 */
469213fdd80SPeter Wemm 	regs->tf_esp = (int)fp;
4704c56fcdeSBruce Evans 	regs->tf_eip = PS_STRINGS - *(p->p_sysent->sv_szsigcode);
471213fdd80SPeter Wemm 	regs->tf_eflags &= ~PSL_VM;
472213fdd80SPeter Wemm 	regs->tf_cs = _ucodesel;
473213fdd80SPeter Wemm 	regs->tf_ds = _udatasel;
474213fdd80SPeter Wemm 	regs->tf_es = _udatasel;
4755206bca1SLuoqi Chen 	regs->tf_fs = _udatasel;
476213fdd80SPeter Wemm 	regs->tf_ss = _udatasel;
477d66a5066SPeter Wemm }
478d66a5066SPeter Wemm 
479d66a5066SPeter Wemm /*
480d66a5066SPeter Wemm  * System call to cleanup state after a signal
481d66a5066SPeter Wemm  * has been taken.  Reset signal mask and
482d66a5066SPeter Wemm  * stack state from context left by sendsig (above).
483d66a5066SPeter Wemm  * Return to previous pc and psl as specified by
484d66a5066SPeter Wemm  * context left by sendsig. Check carefully to
485d66a5066SPeter Wemm  * make sure that the user has not modified the
486d66a5066SPeter Wemm  * psl to gain improper privileges or to cause
487d66a5066SPeter Wemm  * a machine fault.
488d66a5066SPeter Wemm  */
489d66a5066SPeter Wemm int
490cb226aaaSPoul-Henning Kamp linux_sigreturn(p, args)
491d66a5066SPeter Wemm 	struct proc *p;
492d66a5066SPeter Wemm 	struct linux_sigreturn_args *args;
493d66a5066SPeter Wemm {
494cc6ca9b3SMarcel Moolenaar 	struct linux_sigframe frame;
495213fdd80SPeter Wemm 	register struct trapframe *regs;
496cc6ca9b3SMarcel Moolenaar 	linux_sigset_t lmask;
4972c4ab9ddSAndrew Gallatin 	int eflags, i;
498d66a5066SPeter Wemm 
499d66a5066SPeter Wemm 	regs = p->p_md.md_regs;
500d66a5066SPeter Wemm 
501d66a5066SPeter Wemm #ifdef DEBUG
50224593369SJonathan Lemon 	if (ldebug(sigreturn))
50324593369SJonathan Lemon 		printf(ARGS(sigreturn, "%p"), (void *)args->sfp);
504d66a5066SPeter Wemm #endif
505d66a5066SPeter Wemm 	/*
506cc6ca9b3SMarcel Moolenaar 	 * The trampoline code hands us the sigframe.
507d66a5066SPeter Wemm 	 * It is unsafe to keep track of it ourselves, in the event that a
508d66a5066SPeter Wemm 	 * program jumps out of a signal handler.
509d66a5066SPeter Wemm 	 */
510cc6ca9b3SMarcel Moolenaar 	if (copyin((caddr_t)args->sfp, &frame, sizeof(frame)) != 0)
511d66a5066SPeter Wemm 		return (EFAULT);
512d66a5066SPeter Wemm 
513d66a5066SPeter Wemm 	/*
514d66a5066SPeter Wemm 	 * Check for security violations.
515d66a5066SPeter Wemm 	 */
516d66a5066SPeter Wemm #define	EFLAGS_SECURE(ef, oef)	((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0)
517cc6ca9b3SMarcel Moolenaar 	eflags = frame.sf_sc.sc_eflags;
518d66a5066SPeter Wemm 	/*
519d66a5066SPeter Wemm 	 * XXX do allow users to change the privileged flag PSL_RF.  The
520d66a5066SPeter Wemm 	 * cpu sets PSL_RF in tf_eflags for faults.  Debuggers should
521d66a5066SPeter Wemm 	 * sometimes set it there too.  tf_eflags is kept in the signal
522d66a5066SPeter Wemm 	 * context during signal handling and there is no other place
523d66a5066SPeter Wemm 	 * to remember it, so the PSL_RF bit may be corrupted by the
524d66a5066SPeter Wemm 	 * signal handler without us knowing.  Corruption of the PSL_RF
525d66a5066SPeter Wemm 	 * bit at worst causes one more or one less debugger trap, so
526d66a5066SPeter Wemm 	 * allowing it is fairly harmless.
527d66a5066SPeter Wemm 	 */
528213fdd80SPeter Wemm 	if (!EFLAGS_SECURE(eflags & ~PSL_RF, regs->tf_eflags & ~PSL_RF)) {
529d66a5066SPeter Wemm     		return(EINVAL);
530d66a5066SPeter Wemm 	}
531d66a5066SPeter Wemm 
532d66a5066SPeter Wemm 	/*
533d66a5066SPeter Wemm 	 * Don't allow users to load a valid privileged %cs.  Let the
534d66a5066SPeter Wemm 	 * hardware check for invalid selectors, excess privilege in
535d66a5066SPeter Wemm 	 * other selectors, invalid %eip's and invalid %esp's.
536d66a5066SPeter Wemm 	 */
53740d50994SPhilippe Charnier #define	CS_SECURE(cs)	(ISPL(cs) == SEL_UPL)
538cc6ca9b3SMarcel Moolenaar 	if (!CS_SECURE(frame.sf_sc.sc_cs)) {
539d66a5066SPeter Wemm 		trapsignal(p, SIGBUS, T_PROTFLT);
540d66a5066SPeter Wemm 		return(EINVAL);
541d66a5066SPeter Wemm 	}
542d66a5066SPeter Wemm 
543cc6ca9b3SMarcel Moolenaar 	lmask.__bits[0] = frame.sf_sc.sc_mask;
5442c4ab9ddSAndrew Gallatin 	for (i = 0; i < (LINUX_NSIG_WORDS-1); i++)
545cc6ca9b3SMarcel Moolenaar 		lmask.__bits[i+1] = frame.sf_extramask[i];
546611d9407SJohn Baldwin 	PROC_LOCK(p);
547cc6ca9b3SMarcel Moolenaar 	linux_to_bsd_sigset(&lmask, &p->p_sigmask);
548645682fdSLuoqi Chen 	SIG_CANTMASK(p->p_sigmask);
549611d9407SJohn Baldwin 	PROC_UNLOCK(p);
550956d3333SMarcel Moolenaar 
551d66a5066SPeter Wemm 	/*
552d66a5066SPeter Wemm 	 * Restore signal context.
553d66a5066SPeter Wemm 	 */
5545206bca1SLuoqi Chen 	/* %gs was restored by the trampoline. */
555cc6ca9b3SMarcel Moolenaar 	regs->tf_fs     = frame.sf_sc.sc_fs;
556cc6ca9b3SMarcel Moolenaar 	regs->tf_es     = frame.sf_sc.sc_es;
557cc6ca9b3SMarcel Moolenaar 	regs->tf_ds     = frame.sf_sc.sc_ds;
558cc6ca9b3SMarcel Moolenaar 	regs->tf_edi    = frame.sf_sc.sc_edi;
559cc6ca9b3SMarcel Moolenaar 	regs->tf_esi    = frame.sf_sc.sc_esi;
560cc6ca9b3SMarcel Moolenaar 	regs->tf_ebp    = frame.sf_sc.sc_ebp;
561cc6ca9b3SMarcel Moolenaar 	regs->tf_ebx    = frame.sf_sc.sc_ebx;
562cc6ca9b3SMarcel Moolenaar 	regs->tf_edx    = frame.sf_sc.sc_edx;
563cc6ca9b3SMarcel Moolenaar 	regs->tf_ecx    = frame.sf_sc.sc_ecx;
564cc6ca9b3SMarcel Moolenaar 	regs->tf_eax    = frame.sf_sc.sc_eax;
565cc6ca9b3SMarcel Moolenaar 	regs->tf_eip    = frame.sf_sc.sc_eip;
566cc6ca9b3SMarcel Moolenaar 	regs->tf_cs     = frame.sf_sc.sc_cs;
567213fdd80SPeter Wemm 	regs->tf_eflags = eflags;
568cc6ca9b3SMarcel Moolenaar 	regs->tf_esp    = frame.sf_sc.sc_esp_at_signal;
569cc6ca9b3SMarcel Moolenaar 	regs->tf_ss     = frame.sf_sc.sc_ss;
570d66a5066SPeter Wemm 
571d66a5066SPeter Wemm 	return (EJUSTRETURN);
572d66a5066SPeter Wemm }
573d66a5066SPeter Wemm 
57479363394SAndrew Gallatin /*
57579363394SAndrew Gallatin  * System call to cleanup state after a signal
57679363394SAndrew Gallatin  * has been taken.  Reset signal mask and
57779363394SAndrew Gallatin  * stack state from context left by rt_sendsig (above).
57879363394SAndrew Gallatin  * Return to previous pc and psl as specified by
57979363394SAndrew Gallatin  * context left by sendsig. Check carefully to
58079363394SAndrew Gallatin  * make sure that the user has not modified the
58179363394SAndrew Gallatin  * psl to gain improper privileges or to cause
58279363394SAndrew Gallatin  * a machine fault.
58379363394SAndrew Gallatin  */
58479363394SAndrew Gallatin int
58579363394SAndrew Gallatin linux_rt_sigreturn(p, args)
58679363394SAndrew Gallatin 	struct proc *p;
58779363394SAndrew Gallatin 	struct linux_rt_sigreturn_args *args;
58879363394SAndrew Gallatin {
58979363394SAndrew Gallatin 	struct sigaltstack_args sasargs;
59079363394SAndrew Gallatin 	struct linux_ucontext 	 uc;
59179363394SAndrew Gallatin 	struct linux_sigcontext *context;
59279363394SAndrew Gallatin 	linux_stack_t *lss;
59379363394SAndrew Gallatin 	stack_t *ss;
59479363394SAndrew Gallatin 	register struct trapframe *regs;
59579363394SAndrew Gallatin 	int eflags;
59679363394SAndrew Gallatin 	caddr_t sg = stackgap_init();
59779363394SAndrew Gallatin 
59879363394SAndrew Gallatin 	regs = p->p_md.md_regs;
59979363394SAndrew Gallatin 
60079363394SAndrew Gallatin #ifdef DEBUG
60124593369SJonathan Lemon 	if (ldebug(rt_sigreturn))
60224593369SJonathan Lemon 		printf(ARGS(rt_sigreturn, "%p"), (void *)args->ucp);
60379363394SAndrew Gallatin #endif
60479363394SAndrew Gallatin 	/*
605cc6ca9b3SMarcel Moolenaar 	 * The trampoline code hands us the ucontext.
60679363394SAndrew Gallatin 	 * It is unsafe to keep track of it ourselves, in the event that a
60779363394SAndrew Gallatin 	 * program jumps out of a signal handler.
60879363394SAndrew Gallatin 	 */
60979363394SAndrew Gallatin 	if (copyin((caddr_t)args->ucp, &uc, sizeof(uc)) != 0)
61079363394SAndrew Gallatin 		return (EFAULT);
61179363394SAndrew Gallatin 
61279363394SAndrew Gallatin 	context = &uc.uc_mcontext;
61379363394SAndrew Gallatin 
61479363394SAndrew Gallatin 	/*
61579363394SAndrew Gallatin 	 * Check for security violations.
61679363394SAndrew Gallatin 	 */
61779363394SAndrew Gallatin #define	EFLAGS_SECURE(ef, oef)	((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0)
61879363394SAndrew Gallatin 	eflags = context->sc_eflags;
61979363394SAndrew Gallatin 	/*
62079363394SAndrew Gallatin 	 * XXX do allow users to change the privileged flag PSL_RF.  The
62179363394SAndrew Gallatin 	 * cpu sets PSL_RF in tf_eflags for faults.  Debuggers should
62279363394SAndrew Gallatin 	 * sometimes set it there too.  tf_eflags is kept in the signal
62379363394SAndrew Gallatin 	 * context during signal handling and there is no other place
62479363394SAndrew Gallatin 	 * to remember it, so the PSL_RF bit may be corrupted by the
62579363394SAndrew Gallatin 	 * signal handler without us knowing.  Corruption of the PSL_RF
62679363394SAndrew Gallatin 	 * bit at worst causes one more or one less debugger trap, so
62779363394SAndrew Gallatin 	 * allowing it is fairly harmless.
62879363394SAndrew Gallatin 	 */
62979363394SAndrew Gallatin 	if (!EFLAGS_SECURE(eflags & ~PSL_RF, regs->tf_eflags & ~PSL_RF)) {
63079363394SAndrew Gallatin     		return(EINVAL);
63179363394SAndrew Gallatin 	}
63279363394SAndrew Gallatin 
63379363394SAndrew Gallatin 	/*
63479363394SAndrew Gallatin 	 * Don't allow users to load a valid privileged %cs.  Let the
63579363394SAndrew Gallatin 	 * hardware check for invalid selectors, excess privilege in
63679363394SAndrew Gallatin 	 * other selectors, invalid %eip's and invalid %esp's.
63779363394SAndrew Gallatin 	 */
63879363394SAndrew Gallatin #define	CS_SECURE(cs)	(ISPL(cs) == SEL_UPL)
63979363394SAndrew Gallatin 	if (!CS_SECURE(context->sc_cs)) {
64079363394SAndrew Gallatin 		trapsignal(p, SIGBUS, T_PROTFLT);
64179363394SAndrew Gallatin 		return(EINVAL);
64279363394SAndrew Gallatin 	}
64379363394SAndrew Gallatin 
644611d9407SJohn Baldwin 	PROC_LOCK(p);
645b595ab37SAndrew Gallatin 	linux_to_bsd_sigset(&uc.uc_sigmask, &p->p_sigmask);
64679363394SAndrew Gallatin 	SIG_CANTMASK(p->p_sigmask);
647611d9407SJohn Baldwin 	PROC_UNLOCK(p);
64879363394SAndrew Gallatin 
64979363394SAndrew Gallatin 	/*
650cc6ca9b3SMarcel Moolenaar 	 * Restore signal context
65179363394SAndrew Gallatin 	 */
65279363394SAndrew Gallatin 	/* %gs was restored by the trampoline. */
65379363394SAndrew Gallatin 	regs->tf_fs     = context->sc_fs;
65479363394SAndrew Gallatin 	regs->tf_es     = context->sc_es;
65579363394SAndrew Gallatin 	regs->tf_ds     = context->sc_ds;
65679363394SAndrew Gallatin 	regs->tf_edi    = context->sc_edi;
65779363394SAndrew Gallatin 	regs->tf_esi    = context->sc_esi;
65879363394SAndrew Gallatin 	regs->tf_ebp    = context->sc_ebp;
65979363394SAndrew Gallatin 	regs->tf_ebx    = context->sc_ebx;
66079363394SAndrew Gallatin 	regs->tf_edx    = context->sc_edx;
66179363394SAndrew Gallatin 	regs->tf_ecx    = context->sc_ecx;
66279363394SAndrew Gallatin 	regs->tf_eax    = context->sc_eax;
66379363394SAndrew Gallatin 	regs->tf_eip    = context->sc_eip;
66479363394SAndrew Gallatin 	regs->tf_cs     = context->sc_cs;
66579363394SAndrew Gallatin 	regs->tf_eflags = eflags;
66679363394SAndrew Gallatin 	regs->tf_esp    = context->sc_esp_at_signal;
66779363394SAndrew Gallatin 	regs->tf_ss     = context->sc_ss;
66879363394SAndrew Gallatin 
66979363394SAndrew Gallatin 	/*
67079363394SAndrew Gallatin 	 * call sigaltstack & ignore results..
67179363394SAndrew Gallatin 	 */
67279363394SAndrew Gallatin 	ss = stackgap_alloc(&sg, sizeof(stack_t));
67379363394SAndrew Gallatin 	lss = &uc.uc_stack;
67479363394SAndrew Gallatin 	ss->ss_sp = lss->ss_sp;
675806d7daaSMarcel Moolenaar 	ss->ss_size = lss->ss_size;
67679363394SAndrew Gallatin 	ss->ss_flags = linux_to_bsd_sigaltstack(lss->ss_flags);
67779363394SAndrew Gallatin 
67879363394SAndrew Gallatin #ifdef DEBUG
67924593369SJonathan Lemon 	if (ldebug(rt_sigreturn))
68024593369SJonathan Lemon 		printf(LMSG("rt_sigret flags: 0x%x, sp: %p, ss: 0x%x, mask: 0x%x"),
68124593369SJonathan Lemon 		    ss->ss_flags, ss->ss_sp, ss->ss_size, context->sc_mask);
68279363394SAndrew Gallatin #endif
68379363394SAndrew Gallatin 	sasargs.ss = ss;
68479363394SAndrew Gallatin 	sasargs.oss = NULL;
68579363394SAndrew Gallatin 	(void) sigaltstack(p, &sasargs);
68679363394SAndrew Gallatin 
68779363394SAndrew Gallatin 	return (EJUSTRETURN);
68879363394SAndrew Gallatin }
68979363394SAndrew Gallatin 
690303b270bSEivind Eklund static void
691d66a5066SPeter Wemm linux_prepsyscall(struct trapframe *tf, int *args, u_int *code, caddr_t *params)
692d66a5066SPeter Wemm {
693d66a5066SPeter Wemm 	args[0] = tf->tf_ebx;
694d66a5066SPeter Wemm 	args[1] = tf->tf_ecx;
695d66a5066SPeter Wemm 	args[2] = tf->tf_edx;
696d66a5066SPeter Wemm 	args[3] = tf->tf_esi;
697d66a5066SPeter Wemm 	args[4] = tf->tf_edi;
698d66a5066SPeter Wemm 	*params = NULL;		/* no copyin */
699d66a5066SPeter Wemm }
700d66a5066SPeter Wemm 
701d323ddf3SMatthew Dillon /*
702d323ddf3SMatthew Dillon  * If a linux binary is exec'ing something, try this image activator
703d323ddf3SMatthew Dillon  * first.  We override standard shell script execution in order to
704d323ddf3SMatthew Dillon  * be able to modify the interpreter path.  We only do this if a linux
705d323ddf3SMatthew Dillon  * binary is doing the exec, so we do not create an EXEC module for it.
706d323ddf3SMatthew Dillon  */
707d323ddf3SMatthew Dillon static int	exec_linux_imgact_try __P((struct image_params *iparams));
708d323ddf3SMatthew Dillon 
709d323ddf3SMatthew Dillon static int
710d323ddf3SMatthew Dillon exec_linux_imgact_try(imgp)
711d323ddf3SMatthew Dillon     struct image_params *imgp;
712d323ddf3SMatthew Dillon {
713d323ddf3SMatthew Dillon     const char *head = (const char *)imgp->image_header;
714d323ddf3SMatthew Dillon     int error = -1;
715d323ddf3SMatthew Dillon 
716d323ddf3SMatthew Dillon     /*
717d323ddf3SMatthew Dillon      * The interpreter for shell scripts run from a linux binary needs
718d323ddf3SMatthew Dillon      * to be located in /compat/linux if possible in order to recursively
719d323ddf3SMatthew Dillon      * maintain linux path emulation.
720d323ddf3SMatthew Dillon      */
721d323ddf3SMatthew Dillon     if (((const short *)head)[0] == SHELLMAGIC) {
722d323ddf3SMatthew Dillon 	    /*
723d323ddf3SMatthew Dillon 	     * Run our normal shell image activator.  If it succeeds attempt
724d323ddf3SMatthew Dillon 	     * to use the alternate path for the interpreter.  If an alternate
725d323ddf3SMatthew Dillon 	     * path is found, use our stringspace to store it.
726d323ddf3SMatthew Dillon 	     */
727d323ddf3SMatthew Dillon 	    if ((error = exec_shell_imgact(imgp)) == 0) {
728d323ddf3SMatthew Dillon 		    char *rpath = NULL;
729d323ddf3SMatthew Dillon 
730d323ddf3SMatthew Dillon 		    linux_emul_find(imgp->proc, NULL, linux_emul_path,
731d323ddf3SMatthew Dillon 			imgp->interpreter_name, &rpath, 0);
732d323ddf3SMatthew Dillon 		    if (rpath != imgp->interpreter_name) {
733d323ddf3SMatthew Dillon 			    int len = strlen(rpath) + 1;
734d323ddf3SMatthew Dillon 
735d323ddf3SMatthew Dillon 			    if (len <= MAXSHELLCMDLEN) {
736d323ddf3SMatthew Dillon 				memcpy(imgp->interpreter_name, rpath, len);
737d323ddf3SMatthew Dillon 			    }
738d323ddf3SMatthew Dillon 			    free(rpath, M_TEMP);
739d323ddf3SMatthew Dillon 		    }
740d323ddf3SMatthew Dillon 	    }
741d323ddf3SMatthew Dillon     }
742d323ddf3SMatthew Dillon     return(error);
743d323ddf3SMatthew Dillon }
744d323ddf3SMatthew Dillon 
745d66a5066SPeter Wemm struct sysentvec linux_sysvec = {
746e1743d02SSøren Schmidt 	LINUX_SYS_MAXSYSCALL,
747d66a5066SPeter Wemm 	linux_sysent,
748d66a5066SPeter Wemm 	0xff,
749956d3333SMarcel Moolenaar 	LINUX_SIGTBLSZ,
750d66a5066SPeter Wemm 	bsd_to_linux_signal,
75185f118c8SDmitrij Tejblum 	ELAST + 1,
752d66a5066SPeter Wemm 	bsd_to_linux_errno,
753288078beSEivind Eklund 	translate_traps,
754d66a5066SPeter Wemm 	linux_fixup,
755d66a5066SPeter Wemm 	linux_sendsig,
756d66a5066SPeter Wemm 	linux_sigcode,
757d66a5066SPeter Wemm 	&linux_szsigcode,
758d66a5066SPeter Wemm 	linux_prepsyscall,
75922d4b0fbSJohn Polstra 	"Linux a.out",
760d323ddf3SMatthew Dillon 	aout_coredump,
761806d7daaSMarcel Moolenaar 	exec_linux_imgact_try,
762806d7daaSMarcel Moolenaar 	LINUX_MINSIGSTKSZ
763d66a5066SPeter Wemm };
764e1743d02SSøren Schmidt 
765e1743d02SSøren Schmidt struct sysentvec elf_linux_sysvec = {
766e1743d02SSøren Schmidt 	LINUX_SYS_MAXSYSCALL,
767e1743d02SSøren Schmidt 	linux_sysent,
768e1743d02SSøren Schmidt 	0xff,
769956d3333SMarcel Moolenaar 	LINUX_SIGTBLSZ,
770e1743d02SSøren Schmidt 	bsd_to_linux_signal,
77185f118c8SDmitrij Tejblum 	ELAST + 1,
772e1743d02SSøren Schmidt 	bsd_to_linux_errno,
773288078beSEivind Eklund 	translate_traps,
774e1743d02SSøren Schmidt 	elf_linux_fixup,
775e1743d02SSøren Schmidt 	linux_sendsig,
776e1743d02SSøren Schmidt 	linux_sigcode,
777e1743d02SSøren Schmidt 	&linux_szsigcode,
778e1743d02SSøren Schmidt 	linux_prepsyscall,
77922d4b0fbSJohn Polstra 	"Linux ELF",
780d323ddf3SMatthew Dillon 	elf_coredump,
781806d7daaSMarcel Moolenaar 	exec_linux_imgact_try,
782806d7daaSMarcel Moolenaar 	LINUX_MINSIGSTKSZ
783e1743d02SSøren Schmidt };
784e1743d02SSøren Schmidt 
785514058dcSAlexander Langer static Elf32_Brandinfo linux_brand = {
786c815a20cSDavid E. O'Brien 					ELFOSABI_LINUX,
78721a3ee0eSDavid E. O'Brien 					"Linux",
788ea5a2b2eSSøren Schmidt 					"/compat/linux",
7895cf588ebSPeter Wemm 					"/lib/ld-linux.so.1",
790ea5a2b2eSSøren Schmidt 					&elf_linux_sysvec
7915cf588ebSPeter Wemm 				 };
7925cf588ebSPeter Wemm 
793514058dcSAlexander Langer static Elf32_Brandinfo linux_glibc2brand = {
794c815a20cSDavid E. O'Brien 					ELFOSABI_LINUX,
79521a3ee0eSDavid E. O'Brien 					"Linux",
7964e138a28SMike Smith 					"/compat/linux",
7974e138a28SMike Smith 					"/lib/ld-linux.so.2",
7984e138a28SMike Smith 					&elf_linux_sysvec
7994e138a28SMike Smith 				 };
8004e138a28SMike Smith 
801514058dcSAlexander Langer Elf32_Brandinfo *linux_brandlist[] = {
802514058dcSAlexander Langer 					&linux_brand,
803514058dcSAlexander Langer 					&linux_glibc2brand,
804514058dcSAlexander Langer 					NULL
805514058dcSAlexander Langer 				};
806514058dcSAlexander Langer 
807aa855a59SPeter Wemm static int
808c25ded31SBruce Evans linux_elf_modevent(module_t mod, int type, void *data)
809d30ea4f5SPeter Wemm {
810514058dcSAlexander Langer 	Elf32_Brandinfo **brandinfo;
811514058dcSAlexander Langer 	int error;
812f41325dbSPeter Wemm 	struct linux_ioctl_handler **lihp;
813514058dcSAlexander Langer 
814514058dcSAlexander Langer 	error = 0;
815514058dcSAlexander Langer 
816aa855a59SPeter Wemm 	switch(type) {
817aa855a59SPeter Wemm 	case MOD_LOAD:
818aa855a59SPeter Wemm 		for (brandinfo = &linux_brandlist[0]; *brandinfo != NULL;
819aa855a59SPeter Wemm 		     ++brandinfo)
820514058dcSAlexander Langer 			if (elf_insert_brand_entry(*brandinfo) < 0)
821aa855a59SPeter Wemm 				error = EINVAL;
822466b14d7SMarcel Moolenaar 		if (error == 0) {
823f41325dbSPeter Wemm 			SET_FOREACH(lihp, linux_ioctl_handler_set)
824f41325dbSPeter Wemm 				linux_ioctl_register_handler(*lihp);
82543bef515SMarcel Moolenaar 			if (bootverbose)
826466b14d7SMarcel Moolenaar 				printf("Linux ELF exec handler installed\n");
827466b14d7SMarcel Moolenaar 		} else
828466b14d7SMarcel Moolenaar 			printf("cannot insert Linux ELF brand handler\n");
829aa855a59SPeter Wemm 		break;
830aa855a59SPeter Wemm 	case MOD_UNLOAD:
831aa855a59SPeter Wemm 		for (brandinfo = &linux_brandlist[0]; *brandinfo != NULL;
832aa855a59SPeter Wemm 		     ++brandinfo)
83343bef515SMarcel Moolenaar 			if (elf_brand_inuse(*brandinfo))
834d2758342SMark Newton 				error = EBUSY;
835d2758342SMark Newton 		if (error == 0) {
836d2758342SMark Newton 			for (brandinfo = &linux_brandlist[0];
837d2758342SMark Newton 			     *brandinfo != NULL; ++brandinfo)
838aa855a59SPeter Wemm 				if (elf_remove_brand_entry(*brandinfo) < 0)
839aa855a59SPeter Wemm 					error = EINVAL;
840d2758342SMark Newton 		}
841466b14d7SMarcel Moolenaar 		if (error == 0) {
842f41325dbSPeter Wemm 			SET_FOREACH(lihp, linux_ioctl_handler_set)
843f41325dbSPeter Wemm 				linux_ioctl_unregister_handler(*lihp);
844466b14d7SMarcel Moolenaar 			if (bootverbose)
845466b14d7SMarcel Moolenaar 				printf("Linux ELF exec handler removed\n");
846466b14d7SMarcel Moolenaar 		} else
847aa855a59SPeter Wemm 			printf("Could not deinstall ELF interpreter entry\n");
848aa855a59SPeter Wemm 		break;
849aa855a59SPeter Wemm 	default:
850aa855a59SPeter Wemm 		break;
851d30ea4f5SPeter Wemm 	}
852aa855a59SPeter Wemm 	return error;
853aa855a59SPeter Wemm }
854466b14d7SMarcel Moolenaar 
855aa855a59SPeter Wemm static moduledata_t linux_elf_mod = {
856aa855a59SPeter Wemm 	"linuxelf",
857aa855a59SPeter Wemm 	linux_elf_modevent,
858aa855a59SPeter Wemm 	0
859aa855a59SPeter Wemm };
860466b14d7SMarcel Moolenaar 
861aa855a59SPeter Wemm DECLARE_MODULE(linuxelf, linux_elf_mod, SI_SUB_EXEC, SI_ORDER_ANY);
862