xref: /freebsd/sys/i386/linux/linux_sysvec.c (revision 2a51b9b0aa5e759bd93651f5b7d18171e04b3500)
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  */
28d66a5066SPeter Wemm 
2927e0099cSDavid E. O'Brien #include <sys/cdefs.h>
3027e0099cSDavid E. O'Brien __FBSDID("$FreeBSD$");
3127e0099cSDavid E. O'Brien 
32d66a5066SPeter Wemm /* XXX we use functions that might not exist. */
335591b823SEivind Eklund #include "opt_compat.h"
345591b823SEivind Eklund 
355591b823SEivind Eklund #ifndef COMPAT_43
365591b823SEivind Eklund #error "Unable to compile Linux-emulator due to missing COMPAT_43 option!"
375591b823SEivind Eklund #endif
38d66a5066SPeter Wemm 
39d66a5066SPeter Wemm #include <sys/param.h>
4075f83872SPeter Wemm #include <sys/systm.h>
41ff22c670SBruce Evans #include <sys/exec.h>
42d66a5066SPeter Wemm #include <sys/imgact.h>
4322d4b0fbSJohn Polstra #include <sys/imgact_aout.h>
44e1743d02SSøren Schmidt #include <sys/imgact_elf.h>
45ff22c670SBruce Evans #include <sys/kernel.h>
467106ca0dSJohn Baldwin #include <sys/lock.h>
47e1743d02SSøren Schmidt #include <sys/malloc.h>
48ff22c670SBruce Evans #include <sys/module.h>
4923955314SAlfred Perlstein #include <sys/mutex.h>
50fb919e4dSMark Murray #include <sys/proc.h>
51fb919e4dSMark Murray #include <sys/signalvar.h>
52206a5d3aSIan Dowse #include <sys/syscallsubr.h>
53fb919e4dSMark Murray #include <sys/sysent.h>
54fb919e4dSMark Murray #include <sys/sysproto.h>
55a9148ab1SPeter Wemm #include <sys/vnode.h>
56fb919e4dSMark Murray 
57d66a5066SPeter Wemm #include <vm/vm.h>
58a9148ab1SPeter Wemm #include <vm/pmap.h>
59ff22c670SBruce Evans #include <vm/vm_extern.h>
60a9148ab1SPeter Wemm #include <vm/vm_map.h>
61a9148ab1SPeter Wemm #include <vm/vm_object.h>
62ff22c670SBruce Evans #include <vm/vm_page.h>
63ff22c670SBruce Evans #include <vm/vm_param.h>
64ff22c670SBruce Evans 
65ff22c670SBruce Evans #include <machine/cpu.h>
66ff22c670SBruce Evans #include <machine/md_var.h>
67d3adf769SDavid Schultz #include <machine/pcb.h>
68a9148ab1SPeter Wemm 
69d66a5066SPeter Wemm #include <i386/linux/linux.h>
70ebea8660SMarcel Moolenaar #include <i386/linux/linux_proto.h>
710f9d6538SJohn Baldwin #include <compat/linux/linux_mib.h>
72b595ab37SAndrew Gallatin #include <compat/linux/linux_signal.h>
73322bfdc3SMarcel Moolenaar #include <compat/linux/linux_util.h>
74e1743d02SSøren Schmidt 
751d91482dSPeter Wemm MODULE_VERSION(linux, 1);
76158eb277SDag-Erling Smørgrav MODULE_DEPEND(linux, sysvmsg, 1, 1, 1);
77158eb277SDag-Erling Smørgrav MODULE_DEPEND(linux, sysvsem, 1, 1, 1);
78158eb277SDag-Erling Smørgrav MODULE_DEPEND(linux, sysvshm, 1, 1, 1);
791d91482dSPeter Wemm 
8043bef515SMarcel Moolenaar MALLOC_DEFINE(M_LINUX, "linux", "Linux mode structures");
8143bef515SMarcel Moolenaar 
82d323ddf3SMatthew Dillon #if BYTE_ORDER == LITTLE_ENDIAN
83d323ddf3SMatthew Dillon #define SHELLMAGIC      0x2123 /* #! */
84d323ddf3SMatthew Dillon #else
85d323ddf3SMatthew Dillon #define SHELLMAGIC      0x2321
86d323ddf3SMatthew Dillon #endif
87d323ddf3SMatthew Dillon 
88e061a6caSMarcel Moolenaar /*
89e061a6caSMarcel Moolenaar  * Allow the sendsig functions to use the ldebug() facility
90e061a6caSMarcel Moolenaar  * even though they are not syscalls themselves. Map them
91e061a6caSMarcel Moolenaar  * to syscall 0. This is slightly less bogus than using
92e061a6caSMarcel Moolenaar  * ldebug(sigreturn).
93e061a6caSMarcel Moolenaar  */
94e061a6caSMarcel Moolenaar #define	LINUX_SYS_linux_rt_sendsig	0
95e061a6caSMarcel Moolenaar #define	LINUX_SYS_linux_sendsig		0
96e061a6caSMarcel Moolenaar 
972a51b9b0SDavid Schultz #define	fldcw(addr)		__asm("fldcw %0" : : "m" (*(addr)))
982a51b9b0SDavid Schultz #define	__LINUX_NPXCW__		0x37f
992a51b9b0SDavid Schultz 
10043bef515SMarcel Moolenaar extern char linux_sigcode[];
10143bef515SMarcel Moolenaar extern int linux_szsigcode;
10243bef515SMarcel Moolenaar 
10343bef515SMarcel Moolenaar extern struct sysent linux_sysent[LINUX_SYS_MAXSYSCALL];
10443bef515SMarcel Moolenaar 
105f41325dbSPeter Wemm SET_DECLARE(linux_ioctl_handler_set, struct linux_ioctl_handler);
10643bef515SMarcel Moolenaar 
10789c9a483SAlfred Perlstein static int	linux_fixup(register_t **stack_base,
10889c9a483SAlfred Perlstein 		    struct image_params *iparams);
10989c9a483SAlfred Perlstein static int	elf_linux_fixup(register_t **stack_base,
11089c9a483SAlfred Perlstein 		    struct image_params *iparams);
111bda2a3afSBruce Evans static void	linux_prepsyscall(struct trapframe *tf, int *args, u_int *code,
112bda2a3afSBruce Evans 		    caddr_t *params);
11389c9a483SAlfred Perlstein static void     linux_sendsig(sig_t catcher, int sig, sigset_t *mask,
11489c9a483SAlfred Perlstein 		    u_long code);
115598d45beSMatthew N. Dodd static void	exec_linux_setregs(struct thread *td, u_long entry,
116598d45beSMatthew N. Dodd 				   u_long stack, u_long ps_strings);
117d66a5066SPeter Wemm 
118d66a5066SPeter Wemm /*
119d66a5066SPeter Wemm  * Linux syscalls return negative errno's, we do positive and map them
120d66a5066SPeter Wemm  */
12185f118c8SDmitrij Tejblum static int bsd_to_linux_errno[ELAST + 1] = {
122d66a5066SPeter Wemm 	-0,  -1,  -2,  -3,  -4,  -5,  -6,  -7,  -8,  -9,
123d66a5066SPeter Wemm 	-10, -35, -12, -13, -14, -15, -16, -17, -18, -19,
124d66a5066SPeter Wemm 	-20, -21, -22, -23, -24, -25, -26, -27, -28, -29,
125d66a5066SPeter Wemm 	-30, -31, -32, -33, -34, -11,-115,-114, -88, -89,
126d66a5066SPeter Wemm 	-90, -91, -92, -93, -94, -95, -96, -97, -98, -99,
127d66a5066SPeter Wemm 	-100,-101,-102,-103,-104,-105,-106,-107,-108,-109,
128d66a5066SPeter Wemm 	-110,-111, -40, -36,-112,-113, -39, -11, -87,-122,
129d66a5066SPeter Wemm 	-116, -66,  -6,  -6,  -6,  -6,  -6, -37, -38,  -9,
13085f118c8SDmitrij Tejblum 	-6, -6, -43, -42, -75, -6, -84
131d66a5066SPeter Wemm };
132d66a5066SPeter Wemm 
133956d3333SMarcel Moolenaar int bsd_to_linux_signal[LINUX_SIGTBLSZ] = {
134956d3333SMarcel Moolenaar 	LINUX_SIGHUP, LINUX_SIGINT, LINUX_SIGQUIT, LINUX_SIGILL,
135956d3333SMarcel Moolenaar 	LINUX_SIGTRAP, LINUX_SIGABRT, 0, LINUX_SIGFPE,
136ba873f4cSAlexander Kabaev 	LINUX_SIGKILL, LINUX_SIGBUS, LINUX_SIGSEGV, LINUX_SIGSYS,
137956d3333SMarcel Moolenaar 	LINUX_SIGPIPE, LINUX_SIGALRM, LINUX_SIGTERM, LINUX_SIGURG,
138956d3333SMarcel Moolenaar 	LINUX_SIGSTOP, LINUX_SIGTSTP, LINUX_SIGCONT, LINUX_SIGCHLD,
139956d3333SMarcel Moolenaar 	LINUX_SIGTTIN, LINUX_SIGTTOU, LINUX_SIGIO, LINUX_SIGXCPU,
140956d3333SMarcel Moolenaar 	LINUX_SIGXFSZ, LINUX_SIGVTALRM, LINUX_SIGPROF, LINUX_SIGWINCH,
141956d3333SMarcel Moolenaar 	0, LINUX_SIGUSR1, LINUX_SIGUSR2
142d66a5066SPeter Wemm };
143d66a5066SPeter Wemm 
144956d3333SMarcel Moolenaar int linux_to_bsd_signal[LINUX_SIGTBLSZ] = {
145956d3333SMarcel Moolenaar 	SIGHUP, SIGINT, SIGQUIT, SIGILL,
146956d3333SMarcel Moolenaar 	SIGTRAP, SIGABRT, SIGBUS, SIGFPE,
147956d3333SMarcel Moolenaar 	SIGKILL, SIGUSR1, SIGSEGV, SIGUSR2,
148956d3333SMarcel Moolenaar 	SIGPIPE, SIGALRM, SIGTERM, SIGBUS,
149956d3333SMarcel Moolenaar 	SIGCHLD, SIGCONT, SIGSTOP, SIGTSTP,
150956d3333SMarcel Moolenaar 	SIGTTIN, SIGTTOU, SIGURG, SIGXCPU,
151956d3333SMarcel Moolenaar 	SIGXFSZ, SIGVTALRM, SIGPROF, SIGWINCH,
152ba873f4cSAlexander Kabaev 	SIGIO, SIGURG, SIGSYS
153d66a5066SPeter Wemm };
154d66a5066SPeter Wemm 
15527a828fcSPierre Beyssac #define LINUX_T_UNKNOWN  255
15627a828fcSPierre Beyssac static int _bsd_to_linux_trapcode[] = {
15727a828fcSPierre Beyssac 	LINUX_T_UNKNOWN,	/* 0 */
15827a828fcSPierre Beyssac 	6,			/* 1  T_PRIVINFLT */
15927a828fcSPierre Beyssac 	LINUX_T_UNKNOWN,	/* 2 */
16027a828fcSPierre Beyssac 	3,			/* 3  T_BPTFLT */
16127a828fcSPierre Beyssac 	LINUX_T_UNKNOWN,	/* 4 */
16227a828fcSPierre Beyssac 	LINUX_T_UNKNOWN,	/* 5 */
16327a828fcSPierre Beyssac 	16,			/* 6  T_ARITHTRAP */
16427a828fcSPierre Beyssac 	254,			/* 7  T_ASTFLT */
16527a828fcSPierre Beyssac 	LINUX_T_UNKNOWN,	/* 8 */
16627a828fcSPierre Beyssac 	13,			/* 9  T_PROTFLT */
16727a828fcSPierre Beyssac 	1,			/* 10 T_TRCTRAP */
16827a828fcSPierre Beyssac 	LINUX_T_UNKNOWN,	/* 11 */
16927a828fcSPierre Beyssac 	14,			/* 12 T_PAGEFLT */
17027a828fcSPierre Beyssac 	LINUX_T_UNKNOWN,	/* 13 */
17127a828fcSPierre Beyssac 	17,			/* 14 T_ALIGNFLT */
17227a828fcSPierre Beyssac 	LINUX_T_UNKNOWN,	/* 15 */
17327a828fcSPierre Beyssac 	LINUX_T_UNKNOWN,	/* 16 */
17427a828fcSPierre Beyssac 	LINUX_T_UNKNOWN,	/* 17 */
17527a828fcSPierre Beyssac 	0,			/* 18 T_DIVIDE */
17627a828fcSPierre Beyssac 	2,			/* 19 T_NMI */
17727a828fcSPierre Beyssac 	4,			/* 20 T_OFLOW */
17827a828fcSPierre Beyssac 	5,			/* 21 T_BOUND */
17927a828fcSPierre Beyssac 	7,			/* 22 T_DNA */
18027a828fcSPierre Beyssac 	8,			/* 23 T_DOUBLEFLT */
18127a828fcSPierre Beyssac 	9,			/* 24 T_FPOPFLT */
18227a828fcSPierre Beyssac 	10,			/* 25 T_TSSFLT */
18327a828fcSPierre Beyssac 	11,			/* 26 T_SEGNPFLT */
18427a828fcSPierre Beyssac 	12,			/* 27 T_STKFLT */
18527a828fcSPierre Beyssac 	18,			/* 28 T_MCHK */
18627a828fcSPierre Beyssac 	19,			/* 29 T_XMMFLT */
18727a828fcSPierre Beyssac 	15			/* 30 T_RESERVED */
18827a828fcSPierre Beyssac };
18927a828fcSPierre Beyssac #define bsd_to_linux_trapcode(code) \
19027a828fcSPierre Beyssac     ((code)<sizeof(_bsd_to_linux_trapcode)/sizeof(*_bsd_to_linux_trapcode)? \
19127a828fcSPierre Beyssac      _bsd_to_linux_trapcode[(code)]: \
19227a828fcSPierre Beyssac      LINUX_T_UNKNOWN)
19327a828fcSPierre Beyssac 
194288078beSEivind Eklund /*
195288078beSEivind Eklund  * If FreeBSD & Linux have a difference of opinion about what a trap
196288078beSEivind Eklund  * means, deal with it here.
197356861dbSMatthew Dillon  *
198356861dbSMatthew Dillon  * MPSAFE
199288078beSEivind Eklund  */
200288078beSEivind Eklund static int
201288078beSEivind Eklund translate_traps(int signal, int trap_code)
202288078beSEivind Eklund {
203d563a53aSEivind Eklund 	if (signal != SIGBUS)
204d563a53aSEivind Eklund 		return signal;
205288078beSEivind Eklund 	switch (trap_code) {
206288078beSEivind Eklund 	case T_PROTFLT:
207288078beSEivind Eklund 	case T_TSSFLT:
208288078beSEivind Eklund 	case T_DOUBLEFLT:
209288078beSEivind Eklund 	case T_PAGEFLT:
210288078beSEivind Eklund 		return SIGSEGV;
211288078beSEivind Eklund 	default:
212288078beSEivind Eklund 		return signal;
213288078beSEivind Eklund 	}
214288078beSEivind Eklund }
215288078beSEivind Eklund 
216303b270bSEivind Eklund static int
217654f6be1SBruce Evans linux_fixup(register_t **stack_base, struct image_params *imgp)
218d66a5066SPeter Wemm {
219654f6be1SBruce Evans 	register_t *argv, *envp;
220d66a5066SPeter Wemm 
221d66a5066SPeter Wemm 	argv = *stack_base;
222610ecfe0SMaxim Sobolev 	envp = *stack_base + (imgp->args->argc + 1);
223d66a5066SPeter Wemm 	(*stack_base)--;
22486a14a7aSBruce Evans 	**stack_base = (intptr_t)(void *)envp;
225d66a5066SPeter Wemm 	(*stack_base)--;
22686a14a7aSBruce Evans 	**stack_base = (intptr_t)(void *)argv;
227d66a5066SPeter Wemm 	(*stack_base)--;
228610ecfe0SMaxim Sobolev 	**stack_base = imgp->args->argc;
229e1743d02SSøren Schmidt 	return 0;
230d66a5066SPeter Wemm }
231d66a5066SPeter Wemm 
232303b270bSEivind Eklund static int
233654f6be1SBruce Evans elf_linux_fixup(register_t **stack_base, struct image_params *imgp)
234e1743d02SSøren Schmidt {
23543cf129cSJohn Baldwin 	Elf32_Auxargs *args;
236654f6be1SBruce Evans 	register_t *pos;
237d66a5066SPeter Wemm 
23843cf129cSJohn Baldwin 	KASSERT(curthread->td_proc == imgp->proc &&
2390e2a4d3aSDavid Xu 	    (curthread->td_proc->p_flag & P_SA) == 0,
24043cf129cSJohn Baldwin 	    ("unsafe elf_linux_fixup(), should be curproc"));
24143cf129cSJohn Baldwin 	args = (Elf32_Auxargs *)imgp->auxargs;
242610ecfe0SMaxim Sobolev 	pos = *stack_base + (imgp->args->argc + imgp->args->envc + 2);
243e1743d02SSøren Schmidt 
244b07cd97eSMark Murray 	if (args->trace)
245e1743d02SSøren Schmidt 		AUXARGS_ENTRY(pos, AT_DEBUG, 1);
246b07cd97eSMark Murray 	if (args->execfd != -1)
247e1743d02SSøren Schmidt 		AUXARGS_ENTRY(pos, AT_EXECFD, args->execfd);
248e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_PHDR, args->phdr);
249e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_PHENT, args->phent);
250e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_PHNUM, args->phnum);
251e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_PAGESZ, args->pagesz);
252e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_FLAGS, args->flags);
253e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_ENTRY, args->entry);
254e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_BASE, args->base);
255b1fc0ec1SRobert Watson 	AUXARGS_ENTRY(pos, AT_UID, imgp->proc->p_ucred->cr_ruid);
256b1fc0ec1SRobert Watson 	AUXARGS_ENTRY(pos, AT_EUID, imgp->proc->p_ucred->cr_svuid);
257b1fc0ec1SRobert Watson 	AUXARGS_ENTRY(pos, AT_GID, imgp->proc->p_ucred->cr_rgid);
258b1fc0ec1SRobert Watson 	AUXARGS_ENTRY(pos, AT_EGID, imgp->proc->p_ucred->cr_svgid);
259e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_NULL, 0);
260e1743d02SSøren Schmidt 
261e1743d02SSøren Schmidt 	free(imgp->auxargs, M_TEMP);
262e1743d02SSøren Schmidt 	imgp->auxargs = NULL;
263e1743d02SSøren Schmidt 
264e1743d02SSøren Schmidt 	(*stack_base)--;
265610ecfe0SMaxim Sobolev 	**stack_base = (register_t)imgp->args->argc;
266e1743d02SSøren Schmidt 	return 0;
267e1743d02SSøren Schmidt }
268d66a5066SPeter Wemm 
269d66a5066SPeter Wemm extern int _ucodesel, _udatasel;
27002318dacSJake Burkholder extern unsigned long linux_sznonrtsigcode;
27179363394SAndrew Gallatin 
27279363394SAndrew Gallatin static void
27379363394SAndrew Gallatin linux_rt_sendsig(sig_t catcher, int sig, sigset_t *mask, u_long code)
27479363394SAndrew Gallatin {
2751d062e2bSDag-Erling Smørgrav 	struct thread *td = curthread;
2761d062e2bSDag-Erling Smørgrav 	struct proc *p = td->td_proc;
27790af4afaSJohn Baldwin 	struct sigacts *psp;
2781d062e2bSDag-Erling Smørgrav 	struct trapframe *regs;
2795002a60fSMarcel Moolenaar 	struct l_rt_sigframe *fp, frame;
28079363394SAndrew Gallatin 	int oonstack;
28179363394SAndrew Gallatin 
282df53e91cSJohn Baldwin 	PROC_LOCK_ASSERT(p, MA_OWNED);
28390af4afaSJohn Baldwin 	psp = p->p_sigacts;
28490af4afaSJohn Baldwin 	mtx_assert(&psp->ps_mtx, MA_OWNED);
285b40ce416SJulian Elischer 	regs = td->td_frame;
286d034d459SMarcel Moolenaar 	oonstack = sigonstack(regs->tf_esp);
28779363394SAndrew Gallatin 
28879363394SAndrew Gallatin #ifdef DEBUG
2895002a60fSMarcel Moolenaar 	if (ldebug(rt_sendsig))
29024593369SJonathan Lemon 		printf(ARGS(rt_sendsig, "%p, %d, %p, %lu"),
29124593369SJonathan Lemon 		    catcher, sig, (void*)mask, code);
29279363394SAndrew Gallatin #endif
29379363394SAndrew Gallatin 	/*
29479363394SAndrew Gallatin 	 * Allocate space for the signal handler context.
29579363394SAndrew Gallatin 	 */
296a30ec4b9SDavid Xu 	if ((td->td_pflags & TDP_ALTSTACK) && !oonstack &&
29790af4afaSJohn Baldwin 	    SIGISMEMBER(psp->ps_sigonstack, sig)) {
298a30ec4b9SDavid Xu 		fp = (struct l_rt_sigframe *)(td->td_sigstk.ss_sp +
299a30ec4b9SDavid Xu 		    td->td_sigstk.ss_size - sizeof(struct l_rt_sigframe));
300d034d459SMarcel Moolenaar 	} else
3015002a60fSMarcel Moolenaar 		fp = (struct l_rt_sigframe *)regs->tf_esp - 1;
30290af4afaSJohn Baldwin 	mtx_unlock(&psp->ps_mtx);
30379363394SAndrew Gallatin 
30479363394SAndrew Gallatin 	/*
30579363394SAndrew Gallatin 	 * Build the argument list for the signal handler.
30679363394SAndrew Gallatin 	 */
30779363394SAndrew Gallatin 	if (p->p_sysent->sv_sigtbl)
30879363394SAndrew Gallatin 		if (sig <= p->p_sysent->sv_sigsize)
30979363394SAndrew Gallatin 			sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)];
31079363394SAndrew Gallatin 
31199d45c5fSMarcel Moolenaar 	bzero(&frame, sizeof(frame));
31299d45c5fSMarcel Moolenaar 
31379363394SAndrew Gallatin 	frame.sf_handler = catcher;
31479363394SAndrew Gallatin 	frame.sf_sig = sig;
31579363394SAndrew Gallatin 	frame.sf_siginfo = &fp->sf_si;
31679363394SAndrew Gallatin 	frame.sf_ucontext = &fp->sf_sc;
317cc6ca9b3SMarcel Moolenaar 
3189d05b77dSJuli Mallett 	/* Fill in POSIX parts */
31979363394SAndrew Gallatin 	frame.sf_si.lsi_signo = sig;
32079363394SAndrew Gallatin 	frame.sf_si.lsi_code = code;
32179363394SAndrew Gallatin 	frame.sf_si.lsi_addr = (void *)regs->tf_err;
322cc6ca9b3SMarcel Moolenaar 
32379363394SAndrew Gallatin 	/*
32479363394SAndrew Gallatin 	 * Build the signal context to be used by sigreturn.
32579363394SAndrew Gallatin 	 */
326cc6ca9b3SMarcel Moolenaar 	frame.sf_sc.uc_flags = 0;		/* XXX ??? */
327cc6ca9b3SMarcel Moolenaar 	frame.sf_sc.uc_link = NULL;		/* XXX ??? */
328cc6ca9b3SMarcel Moolenaar 
329a30ec4b9SDavid Xu 	frame.sf_sc.uc_stack.ss_sp = td->td_sigstk.ss_sp;
330a30ec4b9SDavid Xu 	frame.sf_sc.uc_stack.ss_size = td->td_sigstk.ss_size;
331a30ec4b9SDavid Xu 	frame.sf_sc.uc_stack.ss_flags = (td->td_pflags & TDP_ALTSTACK)
332d034d459SMarcel Moolenaar 	    ? ((oonstack) ? LINUX_SS_ONSTACK : 0) : LINUX_SS_DISABLE;
333611d9407SJohn Baldwin 	PROC_UNLOCK(p);
334cc6ca9b3SMarcel Moolenaar 
335cc6ca9b3SMarcel Moolenaar 	bsd_to_linux_sigset(mask, &frame.sf_sc.uc_sigmask);
336cc6ca9b3SMarcel Moolenaar 
337cc6ca9b3SMarcel Moolenaar 	frame.sf_sc.uc_mcontext.sc_mask   = frame.sf_sc.uc_sigmask.__bits[0];
33879363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_gs     = rgs();
33979363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_fs     = regs->tf_fs;
34079363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_es     = regs->tf_es;
34179363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_ds     = regs->tf_ds;
34279363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_edi    = regs->tf_edi;
34379363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_esi    = regs->tf_esi;
34479363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_ebp    = regs->tf_ebp;
34579363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_ebx    = regs->tf_ebx;
34679363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_edx    = regs->tf_edx;
34779363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_ecx    = regs->tf_ecx;
34879363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_eax    = regs->tf_eax;
34979363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_eip    = regs->tf_eip;
35079363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_cs     = regs->tf_cs;
35179363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_eflags = regs->tf_eflags;
35279363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_esp_at_signal = regs->tf_esp;
35379363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_ss     = regs->tf_ss;
35479363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_err    = regs->tf_err;
35527a828fcSPierre Beyssac 	frame.sf_sc.uc_mcontext.sc_trapno = bsd_to_linux_trapcode(code);
35679363394SAndrew Gallatin 
35779363394SAndrew Gallatin #ifdef DEBUG
3585002a60fSMarcel Moolenaar 	if (ldebug(rt_sendsig))
35924593369SJonathan Lemon 		printf(LMSG("rt_sendsig flags: 0x%x, sp: %p, ss: 0x%x, mask: 0x%x"),
3609b778a16SDavid Xu 		    frame.sf_sc.uc_stack.ss_flags, td->td_sigstk.ss_sp,
3619b778a16SDavid Xu 		    td->td_sigstk.ss_size, frame.sf_sc.uc_mcontext.sc_mask);
36279363394SAndrew Gallatin #endif
36379363394SAndrew Gallatin 
36479363394SAndrew Gallatin 	if (copyout(&frame, fp, sizeof(frame)) != 0) {
36579363394SAndrew Gallatin 		/*
36679363394SAndrew Gallatin 		 * Process has trashed its stack; give it an illegal
36779363394SAndrew Gallatin 		 * instruction to halt it in its tracks.
36879363394SAndrew Gallatin 		 */
36989734883SAlan Cox #ifdef DEBUG
37089734883SAlan Cox 		if (ldebug(rt_sendsig))
37189734883SAlan Cox 			printf(LMSG("rt_sendsig: bad stack %p, oonstack=%x"),
37289734883SAlan Cox 			    fp, oonstack);
37389734883SAlan Cox #endif
37419eb87d2SJohn Baldwin 		PROC_LOCK(p);
375b40ce416SJulian Elischer 		sigexit(td, SIGILL);
37679363394SAndrew Gallatin 	}
37779363394SAndrew Gallatin 
37879363394SAndrew Gallatin 	/*
37979363394SAndrew Gallatin 	 * Build context to run handler in.
38079363394SAndrew Gallatin 	 */
38179363394SAndrew Gallatin 	regs->tf_esp = (int)fp;
38279363394SAndrew Gallatin 	regs->tf_eip = PS_STRINGS - *(p->p_sysent->sv_szsigcode) +
38302318dacSJake Burkholder 	    linux_sznonrtsigcode;
384846ac226SBruce Evans 	regs->tf_eflags &= ~(PSL_T | PSL_VM);
38579363394SAndrew Gallatin 	regs->tf_cs = _ucodesel;
38679363394SAndrew Gallatin 	regs->tf_ds = _udatasel;
38779363394SAndrew Gallatin 	regs->tf_es = _udatasel;
38879363394SAndrew Gallatin 	regs->tf_fs = _udatasel;
38979363394SAndrew Gallatin 	regs->tf_ss = _udatasel;
390df53e91cSJohn Baldwin 	PROC_LOCK(p);
39190af4afaSJohn Baldwin 	mtx_lock(&psp->ps_mtx);
39279363394SAndrew Gallatin }
39379363394SAndrew Gallatin 
394d66a5066SPeter Wemm 
395d66a5066SPeter Wemm /*
396d66a5066SPeter Wemm  * Send an interrupt to process.
397d66a5066SPeter Wemm  *
398d66a5066SPeter Wemm  * Stack is set up to allow sigcode stored
399d66a5066SPeter Wemm  * in u. to call routine, followed by kcall
400d66a5066SPeter Wemm  * to sigreturn routine below.  After sigreturn
401d66a5066SPeter Wemm  * resets the signal mask, the stack, and the
402d66a5066SPeter Wemm  * frame pointer, it returns to the user
403d66a5066SPeter Wemm  * specified pc, psl.
404d66a5066SPeter Wemm  */
405303b270bSEivind Eklund static void
406956d3333SMarcel Moolenaar linux_sendsig(sig_t catcher, int sig, sigset_t *mask, u_long code)
407d66a5066SPeter Wemm {
4081d062e2bSDag-Erling Smørgrav 	struct thread *td = curthread;
4091d062e2bSDag-Erling Smørgrav 	struct proc *p = td->td_proc;
41090af4afaSJohn Baldwin 	struct sigacts *psp;
4111d062e2bSDag-Erling Smørgrav 	struct trapframe *regs;
4125002a60fSMarcel Moolenaar 	struct l_sigframe *fp, frame;
4135002a60fSMarcel Moolenaar 	l_sigset_t lmask;
4142c4ab9ddSAndrew Gallatin 	int oonstack, i;
415d66a5066SPeter Wemm 
4162509e6c2SJohn Baldwin 	PROC_LOCK_ASSERT(p, MA_OWNED);
41790af4afaSJohn Baldwin 	psp = p->p_sigacts;
41890af4afaSJohn Baldwin 	mtx_assert(&psp->ps_mtx, MA_OWNED);
41990af4afaSJohn Baldwin 	if (SIGISMEMBER(psp->ps_siginfo, sig)) {
420cc6ca9b3SMarcel Moolenaar 		/* Signal handler installed with SA_SIGINFO. */
421cc6ca9b3SMarcel Moolenaar 		linux_rt_sendsig(catcher, sig, mask, code);
422cc6ca9b3SMarcel Moolenaar 		return;
423cc6ca9b3SMarcel Moolenaar 	}
424cc6ca9b3SMarcel Moolenaar 
425b40ce416SJulian Elischer 	regs = td->td_frame;
426d034d459SMarcel Moolenaar 	oonstack = sigonstack(regs->tf_esp);
427d66a5066SPeter Wemm 
428d66a5066SPeter Wemm #ifdef DEBUG
4295002a60fSMarcel Moolenaar 	if (ldebug(sendsig))
43024593369SJonathan Lemon 		printf(ARGS(sendsig, "%p, %d, %p, %lu"),
43124593369SJonathan Lemon 		    catcher, sig, (void*)mask, code);
432d66a5066SPeter Wemm #endif
43379363394SAndrew Gallatin 
434d66a5066SPeter Wemm 	/*
435d66a5066SPeter Wemm 	 * Allocate space for the signal handler context.
436d66a5066SPeter Wemm 	 */
437a30ec4b9SDavid Xu 	if ((td->td_pflags & TDP_ALTSTACK) && !oonstack &&
43890af4afaSJohn Baldwin 	    SIGISMEMBER(psp->ps_sigonstack, sig)) {
439a30ec4b9SDavid Xu 		fp = (struct l_sigframe *)(td->td_sigstk.ss_sp +
440a30ec4b9SDavid Xu 		    td->td_sigstk.ss_size - sizeof(struct l_sigframe));
441d034d459SMarcel Moolenaar 	} else
4425002a60fSMarcel Moolenaar 		fp = (struct l_sigframe *)regs->tf_esp - 1;
44390af4afaSJohn Baldwin 	mtx_unlock(&psp->ps_mtx);
444611d9407SJohn Baldwin 	PROC_UNLOCK(p);
445d66a5066SPeter Wemm 
446d66a5066SPeter Wemm 	/*
447d66a5066SPeter Wemm 	 * Build the argument list for the signal handler.
448d66a5066SPeter Wemm 	 */
449956d3333SMarcel Moolenaar 	if (p->p_sysent->sv_sigtbl)
450956d3333SMarcel Moolenaar 		if (sig <= p->p_sysent->sv_sigsize)
451956d3333SMarcel Moolenaar 			sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)];
452d66a5066SPeter Wemm 
45399d45c5fSMarcel Moolenaar 	bzero(&frame, sizeof(frame));
45499d45c5fSMarcel Moolenaar 
455d66a5066SPeter Wemm 	frame.sf_handler = catcher;
456d66a5066SPeter Wemm 	frame.sf_sig = sig;
457d66a5066SPeter Wemm 
458cc6ca9b3SMarcel Moolenaar 	bsd_to_linux_sigset(mask, &lmask);
459cc6ca9b3SMarcel Moolenaar 
460d66a5066SPeter Wemm 	/*
461d66a5066SPeter Wemm 	 * Build the signal context to be used by sigreturn.
462d66a5066SPeter Wemm 	 */
463cc6ca9b3SMarcel Moolenaar 	frame.sf_sc.sc_mask   = lmask.__bits[0];
4645206bca1SLuoqi Chen 	frame.sf_sc.sc_gs     = rgs();
4655206bca1SLuoqi Chen 	frame.sf_sc.sc_fs     = regs->tf_fs;
466213fdd80SPeter Wemm 	frame.sf_sc.sc_es     = regs->tf_es;
467213fdd80SPeter Wemm 	frame.sf_sc.sc_ds     = regs->tf_ds;
468213fdd80SPeter Wemm 	frame.sf_sc.sc_edi    = regs->tf_edi;
469213fdd80SPeter Wemm 	frame.sf_sc.sc_esi    = regs->tf_esi;
470213fdd80SPeter Wemm 	frame.sf_sc.sc_ebp    = regs->tf_ebp;
471213fdd80SPeter Wemm 	frame.sf_sc.sc_ebx    = regs->tf_ebx;
472213fdd80SPeter Wemm 	frame.sf_sc.sc_edx    = regs->tf_edx;
473213fdd80SPeter Wemm 	frame.sf_sc.sc_ecx    = regs->tf_ecx;
474213fdd80SPeter Wemm 	frame.sf_sc.sc_eax    = regs->tf_eax;
475213fdd80SPeter Wemm 	frame.sf_sc.sc_eip    = regs->tf_eip;
476213fdd80SPeter Wemm 	frame.sf_sc.sc_cs     = regs->tf_cs;
477213fdd80SPeter Wemm 	frame.sf_sc.sc_eflags = regs->tf_eflags;
478213fdd80SPeter Wemm 	frame.sf_sc.sc_esp_at_signal = regs->tf_esp;
479213fdd80SPeter Wemm 	frame.sf_sc.sc_ss     = regs->tf_ss;
480213fdd80SPeter Wemm 	frame.sf_sc.sc_err    = regs->tf_err;
48127a828fcSPierre Beyssac 	frame.sf_sc.sc_trapno = bsd_to_linux_trapcode(code);
482cc6ca9b3SMarcel Moolenaar 
4832c4ab9ddSAndrew Gallatin 	for (i = 0; i < (LINUX_NSIG_WORDS-1); i++)
484cc6ca9b3SMarcel Moolenaar 		frame.sf_extramask[i] = lmask.__bits[i+1];
485d66a5066SPeter Wemm 
486d66a5066SPeter Wemm 	if (copyout(&frame, fp, sizeof(frame)) != 0) {
487d66a5066SPeter Wemm 		/*
488d66a5066SPeter Wemm 		 * Process has trashed its stack; give it an illegal
489d66a5066SPeter Wemm 		 * instruction to halt it in its tracks.
490d66a5066SPeter Wemm 		 */
49119eb87d2SJohn Baldwin 		PROC_LOCK(p);
492b40ce416SJulian Elischer 		sigexit(td, SIGILL);
493d66a5066SPeter Wemm 	}
494d66a5066SPeter Wemm 
495d66a5066SPeter Wemm 	/*
496d66a5066SPeter Wemm 	 * Build context to run handler in.
497d66a5066SPeter Wemm 	 */
498213fdd80SPeter Wemm 	regs->tf_esp = (int)fp;
4994c56fcdeSBruce Evans 	regs->tf_eip = PS_STRINGS - *(p->p_sysent->sv_szsigcode);
500846ac226SBruce Evans 	regs->tf_eflags &= ~(PSL_T | PSL_VM);
501213fdd80SPeter Wemm 	regs->tf_cs = _ucodesel;
502213fdd80SPeter Wemm 	regs->tf_ds = _udatasel;
503213fdd80SPeter Wemm 	regs->tf_es = _udatasel;
5045206bca1SLuoqi Chen 	regs->tf_fs = _udatasel;
505213fdd80SPeter Wemm 	regs->tf_ss = _udatasel;
5065002a60fSMarcel Moolenaar 	PROC_LOCK(p);
50790af4afaSJohn Baldwin 	mtx_lock(&psp->ps_mtx);
508d66a5066SPeter Wemm }
509d66a5066SPeter Wemm 
510d66a5066SPeter Wemm /*
511d66a5066SPeter Wemm  * System call to cleanup state after a signal
512d66a5066SPeter Wemm  * has been taken.  Reset signal mask and
513d66a5066SPeter Wemm  * stack state from context left by sendsig (above).
514d66a5066SPeter Wemm  * Return to previous pc and psl as specified by
515d66a5066SPeter Wemm  * context left by sendsig. Check carefully to
516d66a5066SPeter Wemm  * make sure that the user has not modified the
517d66a5066SPeter Wemm  * psl to gain improper privileges or to cause
518d66a5066SPeter Wemm  * a machine fault.
519d66a5066SPeter Wemm  */
520d66a5066SPeter Wemm int
521b07cd97eSMark Murray linux_sigreturn(struct thread *td, struct linux_sigreturn_args *args)
522d66a5066SPeter Wemm {
523b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
5245002a60fSMarcel Moolenaar 	struct l_sigframe frame;
5251d062e2bSDag-Erling Smørgrav 	struct trapframe *regs;
5265002a60fSMarcel Moolenaar 	l_sigset_t lmask;
5272c4ab9ddSAndrew Gallatin 	int eflags, i;
528d66a5066SPeter Wemm 
529b40ce416SJulian Elischer 	regs = td->td_frame;
530d66a5066SPeter Wemm 
531d66a5066SPeter Wemm #ifdef DEBUG
53224593369SJonathan Lemon 	if (ldebug(sigreturn))
53324593369SJonathan Lemon 		printf(ARGS(sigreturn, "%p"), (void *)args->sfp);
534d66a5066SPeter Wemm #endif
535d66a5066SPeter Wemm 	/*
536cc6ca9b3SMarcel Moolenaar 	 * The trampoline code hands us the sigframe.
537d66a5066SPeter Wemm 	 * It is unsafe to keep track of it ourselves, in the event that a
538d66a5066SPeter Wemm 	 * program jumps out of a signal handler.
539d66a5066SPeter Wemm 	 */
5404b7ef73dSDag-Erling Smørgrav 	if (copyin(args->sfp, &frame, sizeof(frame)) != 0)
541d66a5066SPeter Wemm 		return (EFAULT);
542d66a5066SPeter Wemm 
543d66a5066SPeter Wemm 	/*
544d66a5066SPeter Wemm 	 * Check for security violations.
545d66a5066SPeter Wemm 	 */
546d66a5066SPeter Wemm #define	EFLAGS_SECURE(ef, oef)	((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0)
547cc6ca9b3SMarcel Moolenaar 	eflags = frame.sf_sc.sc_eflags;
548d66a5066SPeter Wemm 	/*
549d66a5066SPeter Wemm 	 * XXX do allow users to change the privileged flag PSL_RF.  The
550d66a5066SPeter Wemm 	 * cpu sets PSL_RF in tf_eflags for faults.  Debuggers should
551d66a5066SPeter Wemm 	 * sometimes set it there too.  tf_eflags is kept in the signal
552d66a5066SPeter Wemm 	 * context during signal handling and there is no other place
553d66a5066SPeter Wemm 	 * to remember it, so the PSL_RF bit may be corrupted by the
554d66a5066SPeter Wemm 	 * signal handler without us knowing.  Corruption of the PSL_RF
555d66a5066SPeter Wemm 	 * bit at worst causes one more or one less debugger trap, so
556d66a5066SPeter Wemm 	 * allowing it is fairly harmless.
557d66a5066SPeter Wemm 	 */
558b07cd97eSMark Murray 	if (!EFLAGS_SECURE(eflags & ~PSL_RF, regs->tf_eflags & ~PSL_RF))
559d66a5066SPeter Wemm 		return(EINVAL);
560d66a5066SPeter Wemm 
561d66a5066SPeter Wemm 	/*
562d66a5066SPeter Wemm 	 * Don't allow users to load a valid privileged %cs.  Let the
563d66a5066SPeter Wemm 	 * hardware check for invalid selectors, excess privilege in
564d66a5066SPeter Wemm 	 * other selectors, invalid %eip's and invalid %esp's.
565d66a5066SPeter Wemm 	 */
56640d50994SPhilippe Charnier #define	CS_SECURE(cs)	(ISPL(cs) == SEL_UPL)
567cc6ca9b3SMarcel Moolenaar 	if (!CS_SECURE(frame.sf_sc.sc_cs)) {
5681bf4700bSJeff Roberson 		trapsignal(td, SIGBUS, T_PROTFLT);
569d66a5066SPeter Wemm 		return(EINVAL);
570d66a5066SPeter Wemm 	}
571d66a5066SPeter Wemm 
572cc6ca9b3SMarcel Moolenaar 	lmask.__bits[0] = frame.sf_sc.sc_mask;
5732c4ab9ddSAndrew Gallatin 	for (i = 0; i < (LINUX_NSIG_WORDS-1); i++)
574cc6ca9b3SMarcel Moolenaar 		lmask.__bits[i+1] = frame.sf_extramask[i];
575611d9407SJohn Baldwin 	PROC_LOCK(p);
5764093529dSJeff Roberson 	linux_to_bsd_sigset(&lmask, &td->td_sigmask);
5774093529dSJeff Roberson 	SIG_CANTMASK(td->td_sigmask);
5784093529dSJeff Roberson 	signotify(td);
579611d9407SJohn Baldwin 	PROC_UNLOCK(p);
580956d3333SMarcel Moolenaar 
581d66a5066SPeter Wemm 	/*
582d66a5066SPeter Wemm 	 * Restore signal context.
583d66a5066SPeter Wemm 	 */
5845206bca1SLuoqi Chen 	/* %gs was restored by the trampoline. */
585cc6ca9b3SMarcel Moolenaar 	regs->tf_fs     = frame.sf_sc.sc_fs;
586cc6ca9b3SMarcel Moolenaar 	regs->tf_es     = frame.sf_sc.sc_es;
587cc6ca9b3SMarcel Moolenaar 	regs->tf_ds     = frame.sf_sc.sc_ds;
588cc6ca9b3SMarcel Moolenaar 	regs->tf_edi    = frame.sf_sc.sc_edi;
589cc6ca9b3SMarcel Moolenaar 	regs->tf_esi    = frame.sf_sc.sc_esi;
590cc6ca9b3SMarcel Moolenaar 	regs->tf_ebp    = frame.sf_sc.sc_ebp;
591cc6ca9b3SMarcel Moolenaar 	regs->tf_ebx    = frame.sf_sc.sc_ebx;
592cc6ca9b3SMarcel Moolenaar 	regs->tf_edx    = frame.sf_sc.sc_edx;
593cc6ca9b3SMarcel Moolenaar 	regs->tf_ecx    = frame.sf_sc.sc_ecx;
594cc6ca9b3SMarcel Moolenaar 	regs->tf_eax    = frame.sf_sc.sc_eax;
595cc6ca9b3SMarcel Moolenaar 	regs->tf_eip    = frame.sf_sc.sc_eip;
596cc6ca9b3SMarcel Moolenaar 	regs->tf_cs     = frame.sf_sc.sc_cs;
597213fdd80SPeter Wemm 	regs->tf_eflags = eflags;
598cc6ca9b3SMarcel Moolenaar 	regs->tf_esp    = frame.sf_sc.sc_esp_at_signal;
599cc6ca9b3SMarcel Moolenaar 	regs->tf_ss     = frame.sf_sc.sc_ss;
600d66a5066SPeter Wemm 
601d66a5066SPeter Wemm 	return (EJUSTRETURN);
602d66a5066SPeter Wemm }
603d66a5066SPeter Wemm 
60479363394SAndrew Gallatin /*
60579363394SAndrew Gallatin  * System call to cleanup state after a signal
60679363394SAndrew Gallatin  * has been taken.  Reset signal mask and
60779363394SAndrew Gallatin  * stack state from context left by rt_sendsig (above).
60879363394SAndrew Gallatin  * Return to previous pc and psl as specified by
60979363394SAndrew Gallatin  * context left by sendsig. Check carefully to
61079363394SAndrew Gallatin  * make sure that the user has not modified the
61179363394SAndrew Gallatin  * psl to gain improper privileges or to cause
61279363394SAndrew Gallatin  * a machine fault.
61379363394SAndrew Gallatin  */
61479363394SAndrew Gallatin int
615b07cd97eSMark Murray linux_rt_sigreturn(struct thread *td, struct linux_rt_sigreturn_args *args)
61679363394SAndrew Gallatin {
617b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
6185002a60fSMarcel Moolenaar 	struct l_ucontext uc;
6195002a60fSMarcel Moolenaar 	struct l_sigcontext *context;
6205002a60fSMarcel Moolenaar 	l_stack_t *lss;
621206a5d3aSIan Dowse 	stack_t ss;
6221d062e2bSDag-Erling Smørgrav 	struct trapframe *regs;
62379363394SAndrew Gallatin 	int eflags;
62479363394SAndrew Gallatin 
625b40ce416SJulian Elischer 	regs = td->td_frame;
62679363394SAndrew Gallatin 
62779363394SAndrew Gallatin #ifdef DEBUG
62824593369SJonathan Lemon 	if (ldebug(rt_sigreturn))
62924593369SJonathan Lemon 		printf(ARGS(rt_sigreturn, "%p"), (void *)args->ucp);
63079363394SAndrew Gallatin #endif
63179363394SAndrew Gallatin 	/*
632cc6ca9b3SMarcel Moolenaar 	 * The trampoline code hands us the ucontext.
63379363394SAndrew Gallatin 	 * It is unsafe to keep track of it ourselves, in the event that a
63479363394SAndrew Gallatin 	 * program jumps out of a signal handler.
63579363394SAndrew Gallatin 	 */
6364b7ef73dSDag-Erling Smørgrav 	if (copyin(args->ucp, &uc, sizeof(uc)) != 0)
63779363394SAndrew Gallatin 		return (EFAULT);
63879363394SAndrew Gallatin 
63979363394SAndrew Gallatin 	context = &uc.uc_mcontext;
64079363394SAndrew Gallatin 
64179363394SAndrew Gallatin 	/*
64279363394SAndrew Gallatin 	 * Check for security violations.
64379363394SAndrew Gallatin 	 */
64479363394SAndrew Gallatin #define	EFLAGS_SECURE(ef, oef)	((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0)
64579363394SAndrew Gallatin 	eflags = context->sc_eflags;
64679363394SAndrew Gallatin 	/*
64779363394SAndrew Gallatin 	 * XXX do allow users to change the privileged flag PSL_RF.  The
64879363394SAndrew Gallatin 	 * cpu sets PSL_RF in tf_eflags for faults.  Debuggers should
64979363394SAndrew Gallatin 	 * sometimes set it there too.  tf_eflags is kept in the signal
65079363394SAndrew Gallatin 	 * context during signal handling and there is no other place
65179363394SAndrew Gallatin 	 * to remember it, so the PSL_RF bit may be corrupted by the
65279363394SAndrew Gallatin 	 * signal handler without us knowing.  Corruption of the PSL_RF
65379363394SAndrew Gallatin 	 * bit at worst causes one more or one less debugger trap, so
65479363394SAndrew Gallatin 	 * allowing it is fairly harmless.
65579363394SAndrew Gallatin 	 */
656b07cd97eSMark Murray 	if (!EFLAGS_SECURE(eflags & ~PSL_RF, regs->tf_eflags & ~PSL_RF))
65779363394SAndrew Gallatin 		return(EINVAL);
65879363394SAndrew Gallatin 
65979363394SAndrew Gallatin 	/*
66079363394SAndrew Gallatin 	 * Don't allow users to load a valid privileged %cs.  Let the
66179363394SAndrew Gallatin 	 * hardware check for invalid selectors, excess privilege in
66279363394SAndrew Gallatin 	 * other selectors, invalid %eip's and invalid %esp's.
66379363394SAndrew Gallatin 	 */
66479363394SAndrew Gallatin #define	CS_SECURE(cs)	(ISPL(cs) == SEL_UPL)
66579363394SAndrew Gallatin 	if (!CS_SECURE(context->sc_cs)) {
6661bf4700bSJeff Roberson 		trapsignal(td, SIGBUS, T_PROTFLT);
66779363394SAndrew Gallatin 		return(EINVAL);
66879363394SAndrew Gallatin 	}
66979363394SAndrew Gallatin 
670611d9407SJohn Baldwin 	PROC_LOCK(p);
6714093529dSJeff Roberson 	linux_to_bsd_sigset(&uc.uc_sigmask, &td->td_sigmask);
6724093529dSJeff Roberson 	SIG_CANTMASK(td->td_sigmask);
6734093529dSJeff Roberson 	signotify(td);
674611d9407SJohn Baldwin 	PROC_UNLOCK(p);
67579363394SAndrew Gallatin 
67679363394SAndrew Gallatin 	/*
677cc6ca9b3SMarcel Moolenaar 	 * Restore signal context
67879363394SAndrew Gallatin 	 */
67979363394SAndrew Gallatin 	/* %gs was restored by the trampoline. */
68079363394SAndrew Gallatin 	regs->tf_fs     = context->sc_fs;
68179363394SAndrew Gallatin 	regs->tf_es     = context->sc_es;
68279363394SAndrew Gallatin 	regs->tf_ds     = context->sc_ds;
68379363394SAndrew Gallatin 	regs->tf_edi    = context->sc_edi;
68479363394SAndrew Gallatin 	regs->tf_esi    = context->sc_esi;
68579363394SAndrew Gallatin 	regs->tf_ebp    = context->sc_ebp;
68679363394SAndrew Gallatin 	regs->tf_ebx    = context->sc_ebx;
68779363394SAndrew Gallatin 	regs->tf_edx    = context->sc_edx;
68879363394SAndrew Gallatin 	regs->tf_ecx    = context->sc_ecx;
68979363394SAndrew Gallatin 	regs->tf_eax    = context->sc_eax;
69079363394SAndrew Gallatin 	regs->tf_eip    = context->sc_eip;
69179363394SAndrew Gallatin 	regs->tf_cs     = context->sc_cs;
69279363394SAndrew Gallatin 	regs->tf_eflags = eflags;
69379363394SAndrew Gallatin 	regs->tf_esp    = context->sc_esp_at_signal;
69479363394SAndrew Gallatin 	regs->tf_ss     = context->sc_ss;
69579363394SAndrew Gallatin 
69679363394SAndrew Gallatin 	/*
69779363394SAndrew Gallatin 	 * call sigaltstack & ignore results..
69879363394SAndrew Gallatin 	 */
69979363394SAndrew Gallatin 	lss = &uc.uc_stack;
700206a5d3aSIan Dowse 	ss.ss_sp = lss->ss_sp;
701206a5d3aSIan Dowse 	ss.ss_size = lss->ss_size;
702206a5d3aSIan Dowse 	ss.ss_flags = linux_to_bsd_sigaltstack(lss->ss_flags);
70379363394SAndrew Gallatin 
70479363394SAndrew Gallatin #ifdef DEBUG
70524593369SJonathan Lemon 	if (ldebug(rt_sigreturn))
70624593369SJonathan Lemon 		printf(LMSG("rt_sigret flags: 0x%x, sp: %p, ss: 0x%x, mask: 0x%x"),
707206a5d3aSIan Dowse 		    ss.ss_flags, ss.ss_sp, ss.ss_size, context->sc_mask);
70879363394SAndrew Gallatin #endif
709206a5d3aSIan Dowse 	(void)kern_sigaltstack(td, &ss, NULL);
71079363394SAndrew Gallatin 
71179363394SAndrew Gallatin 	return (EJUSTRETURN);
71279363394SAndrew Gallatin }
71379363394SAndrew Gallatin 
714356861dbSMatthew Dillon /*
715356861dbSMatthew Dillon  * MPSAFE
716356861dbSMatthew Dillon  */
717303b270bSEivind Eklund static void
718d66a5066SPeter Wemm linux_prepsyscall(struct trapframe *tf, int *args, u_int *code, caddr_t *params)
719d66a5066SPeter Wemm {
720d66a5066SPeter Wemm 	args[0] = tf->tf_ebx;
721d66a5066SPeter Wemm 	args[1] = tf->tf_ecx;
722d66a5066SPeter Wemm 	args[2] = tf->tf_edx;
723d66a5066SPeter Wemm 	args[3] = tf->tf_esi;
724d66a5066SPeter Wemm 	args[4] = tf->tf_edi;
7257646aefcSPeter Wemm 	args[5] = tf->tf_ebp;	/* Unconfirmed */
726d66a5066SPeter Wemm 	*params = NULL;		/* no copyin */
727d66a5066SPeter Wemm }
728d66a5066SPeter Wemm 
729d323ddf3SMatthew Dillon /*
730d323ddf3SMatthew Dillon  * If a linux binary is exec'ing something, try this image activator
731d323ddf3SMatthew Dillon  * first.  We override standard shell script execution in order to
732d323ddf3SMatthew Dillon  * be able to modify the interpreter path.  We only do this if a linux
733d323ddf3SMatthew Dillon  * binary is doing the exec, so we do not create an EXEC module for it.
734d323ddf3SMatthew Dillon  */
73589c9a483SAlfred Perlstein static int	exec_linux_imgact_try(struct image_params *iparams);
736d323ddf3SMatthew Dillon 
737d323ddf3SMatthew Dillon static int
738b07cd97eSMark Murray exec_linux_imgact_try(struct image_params *imgp)
739d323ddf3SMatthew Dillon {
740d323ddf3SMatthew Dillon     const char *head = (const char *)imgp->image_header;
741d323ddf3SMatthew Dillon     int error = -1;
742d323ddf3SMatthew Dillon 
743d323ddf3SMatthew Dillon     /*
744d323ddf3SMatthew Dillon      * The interpreter for shell scripts run from a linux binary needs
745d323ddf3SMatthew Dillon      * to be located in /compat/linux if possible in order to recursively
746d323ddf3SMatthew Dillon      * maintain linux path emulation.
747d323ddf3SMatthew Dillon      */
748d323ddf3SMatthew Dillon     if (((const short *)head)[0] == SHELLMAGIC) {
749d323ddf3SMatthew Dillon 	    /*
750d323ddf3SMatthew Dillon 	     * Run our normal shell image activator.  If it succeeds attempt
751d323ddf3SMatthew Dillon 	     * to use the alternate path for the interpreter.  If an alternate
752d323ddf3SMatthew Dillon 	     * path is found, use our stringspace to store it.
753d323ddf3SMatthew Dillon 	     */
754d323ddf3SMatthew Dillon 	    if ((error = exec_shell_imgact(imgp)) == 0) {
755d323ddf3SMatthew Dillon 		    char *rpath = NULL;
756d323ddf3SMatthew Dillon 
757079b7badSJulian Elischer 		    linux_emul_find(FIRST_THREAD_IN_PROC(imgp->proc), NULL,
758d323ddf3SMatthew Dillon 			imgp->interpreter_name, &rpath, 0);
759d323ddf3SMatthew Dillon 		    if (rpath != imgp->interpreter_name) {
760d323ddf3SMatthew Dillon 			    int len = strlen(rpath) + 1;
761d323ddf3SMatthew Dillon 
762d323ddf3SMatthew Dillon 			    if (len <= MAXSHELLCMDLEN) {
763d323ddf3SMatthew Dillon 				    memcpy(imgp->interpreter_name, rpath, len);
764d323ddf3SMatthew Dillon 			    }
765d323ddf3SMatthew Dillon 			    free(rpath, M_TEMP);
766d323ddf3SMatthew Dillon 		    }
767d323ddf3SMatthew Dillon 	    }
768d323ddf3SMatthew Dillon     }
769d323ddf3SMatthew Dillon     return(error);
770d323ddf3SMatthew Dillon }
771d323ddf3SMatthew Dillon 
772598d45beSMatthew N. Dodd /*
773598d45beSMatthew N. Dodd  * exec_setregs may initialize some registers differently than Linux
774598d45beSMatthew N. Dodd  * does, thus potentially confusing Linux binaries. If necessary, we
775598d45beSMatthew N. Dodd  * override the exec_setregs default(s) here.
776598d45beSMatthew N. Dodd  */
777598d45beSMatthew N. Dodd static void
778598d45beSMatthew N. Dodd exec_linux_setregs(struct thread *td, u_long entry,
779598d45beSMatthew N. Dodd 		   u_long stack, u_long ps_strings)
780598d45beSMatthew N. Dodd {
7812a51b9b0SDavid Schultz 	static const u_short control = __LINUX_NPXCW__;
782598d45beSMatthew N. Dodd 	struct pcb *pcb = td->td_pcb;
783598d45beSMatthew N. Dodd 
784598d45beSMatthew N. Dodd 	exec_setregs(td, entry, stack, ps_strings);
785598d45beSMatthew N. Dodd 
786598d45beSMatthew N. Dodd 	/* Linux sets %gs to 0, we default to _udatasel */
787598d45beSMatthew N. Dodd 	pcb->pcb_gs = 0; load_gs(0);
7882a51b9b0SDavid Schultz 
7892a51b9b0SDavid Schultz 	/* Linux sets the i387 to extended precision. */
7902a51b9b0SDavid Schultz 	fldcw(&control);
791598d45beSMatthew N. Dodd }
792598d45beSMatthew N. Dodd 
793d66a5066SPeter Wemm struct sysentvec linux_sysvec = {
794e1743d02SSøren Schmidt 	LINUX_SYS_MAXSYSCALL,
795d66a5066SPeter Wemm 	linux_sysent,
796d66a5066SPeter Wemm 	0xff,
797956d3333SMarcel Moolenaar 	LINUX_SIGTBLSZ,
798d66a5066SPeter Wemm 	bsd_to_linux_signal,
79985f118c8SDmitrij Tejblum 	ELAST + 1,
800d66a5066SPeter Wemm 	bsd_to_linux_errno,
801288078beSEivind Eklund 	translate_traps,
802d66a5066SPeter Wemm 	linux_fixup,
803d66a5066SPeter Wemm 	linux_sendsig,
804d66a5066SPeter Wemm 	linux_sigcode,
805d66a5066SPeter Wemm 	&linux_szsigcode,
806d66a5066SPeter Wemm 	linux_prepsyscall,
80722d4b0fbSJohn Polstra 	"Linux a.out",
808d3adf769SDavid Schultz 	NULL,
809806d7daaSMarcel Moolenaar 	exec_linux_imgact_try,
810f36ba452SJake Burkholder 	LINUX_MINSIGSTKSZ,
811f36ba452SJake Burkholder 	PAGE_SIZE,
812f36ba452SJake Burkholder 	VM_MIN_ADDRESS,
813f36ba452SJake Burkholder 	VM_MAXUSER_ADDRESS,
814f36ba452SJake Burkholder 	USRSTACK,
815f36ba452SJake Burkholder 	PS_STRINGS,
816f36ba452SJake Burkholder 	VM_PROT_ALL,
817f36ba452SJake Burkholder 	exec_copyout_strings,
818c460ac3aSPeter Wemm 	exec_linux_setregs,
819c460ac3aSPeter Wemm 	NULL
820d66a5066SPeter Wemm };
821e1743d02SSøren Schmidt 
822e1743d02SSøren Schmidt struct sysentvec elf_linux_sysvec = {
823e1743d02SSøren Schmidt 	LINUX_SYS_MAXSYSCALL,
824e1743d02SSøren Schmidt 	linux_sysent,
825e1743d02SSøren Schmidt 	0xff,
826956d3333SMarcel Moolenaar 	LINUX_SIGTBLSZ,
827e1743d02SSøren Schmidt 	bsd_to_linux_signal,
82885f118c8SDmitrij Tejblum 	ELAST + 1,
829e1743d02SSøren Schmidt 	bsd_to_linux_errno,
830288078beSEivind Eklund 	translate_traps,
831e1743d02SSøren Schmidt 	elf_linux_fixup,
832e1743d02SSøren Schmidt 	linux_sendsig,
833e1743d02SSøren Schmidt 	linux_sigcode,
834e1743d02SSøren Schmidt 	&linux_szsigcode,
835e1743d02SSøren Schmidt 	linux_prepsyscall,
83622d4b0fbSJohn Polstra 	"Linux ELF",
8373ebc1248SPeter Wemm 	elf32_coredump,
838806d7daaSMarcel Moolenaar 	exec_linux_imgact_try,
839f36ba452SJake Burkholder 	LINUX_MINSIGSTKSZ,
840f36ba452SJake Burkholder 	PAGE_SIZE,
841f36ba452SJake Burkholder 	VM_MIN_ADDRESS,
842f36ba452SJake Burkholder 	VM_MAXUSER_ADDRESS,
843f36ba452SJake Burkholder 	USRSTACK,
844f36ba452SJake Burkholder 	PS_STRINGS,
845f36ba452SJake Burkholder 	VM_PROT_ALL,
846f36ba452SJake Burkholder 	exec_copyout_strings,
847c460ac3aSPeter Wemm 	exec_linux_setregs,
848c460ac3aSPeter Wemm 	NULL
849e1743d02SSøren Schmidt };
850e1743d02SSøren Schmidt 
851514058dcSAlexander Langer static Elf32_Brandinfo linux_brand = {
852c815a20cSDavid E. O'Brien 					ELFOSABI_LINUX,
8533ebc1248SPeter Wemm 					EM_386,
85421a3ee0eSDavid E. O'Brien 					"Linux",
855ea5a2b2eSSøren Schmidt 					"/compat/linux",
8565cf588ebSPeter Wemm 					"/lib/ld-linux.so.1",
8579b68618dSPeter Wemm 					&elf_linux_sysvec,
8589b68618dSPeter Wemm 					NULL,
8595cf588ebSPeter Wemm 				 };
8605cf588ebSPeter Wemm 
861514058dcSAlexander Langer static Elf32_Brandinfo linux_glibc2brand = {
862c815a20cSDavid E. O'Brien 					ELFOSABI_LINUX,
8633ebc1248SPeter Wemm 					EM_386,
86421a3ee0eSDavid E. O'Brien 					"Linux",
8654e138a28SMike Smith 					"/compat/linux",
8664e138a28SMike Smith 					"/lib/ld-linux.so.2",
8679b68618dSPeter Wemm 					&elf_linux_sysvec,
8689b68618dSPeter Wemm 					NULL,
8694e138a28SMike Smith 				 };
8704e138a28SMike Smith 
871514058dcSAlexander Langer Elf32_Brandinfo *linux_brandlist[] = {
872514058dcSAlexander Langer 					&linux_brand,
873514058dcSAlexander Langer 					&linux_glibc2brand,
874514058dcSAlexander Langer 					NULL
875514058dcSAlexander Langer 				};
876514058dcSAlexander Langer 
877aa855a59SPeter Wemm static int
878c25ded31SBruce Evans linux_elf_modevent(module_t mod, int type, void *data)
879d30ea4f5SPeter Wemm {
880514058dcSAlexander Langer 	Elf32_Brandinfo **brandinfo;
881514058dcSAlexander Langer 	int error;
882f41325dbSPeter Wemm 	struct linux_ioctl_handler **lihp;
883514058dcSAlexander Langer 
884514058dcSAlexander Langer 	error = 0;
885514058dcSAlexander Langer 
886aa855a59SPeter Wemm 	switch(type) {
887aa855a59SPeter Wemm 	case MOD_LOAD:
888aa855a59SPeter Wemm 		for (brandinfo = &linux_brandlist[0]; *brandinfo != NULL;
889aa855a59SPeter Wemm 		     ++brandinfo)
8903ebc1248SPeter Wemm 			if (elf32_insert_brand_entry(*brandinfo) < 0)
891aa855a59SPeter Wemm 				error = EINVAL;
892466b14d7SMarcel Moolenaar 		if (error == 0) {
893f41325dbSPeter Wemm 			SET_FOREACH(lihp, linux_ioctl_handler_set)
894f41325dbSPeter Wemm 				linux_ioctl_register_handler(*lihp);
89543bef515SMarcel Moolenaar 			if (bootverbose)
896466b14d7SMarcel Moolenaar 				printf("Linux ELF exec handler installed\n");
897466b14d7SMarcel Moolenaar 		} else
898466b14d7SMarcel Moolenaar 			printf("cannot insert Linux ELF brand handler\n");
899aa855a59SPeter Wemm 		break;
900aa855a59SPeter Wemm 	case MOD_UNLOAD:
901aa855a59SPeter Wemm 		for (brandinfo = &linux_brandlist[0]; *brandinfo != NULL;
902aa855a59SPeter Wemm 		     ++brandinfo)
9033ebc1248SPeter Wemm 			if (elf32_brand_inuse(*brandinfo))
904d2758342SMark Newton 				error = EBUSY;
905d2758342SMark Newton 		if (error == 0) {
906d2758342SMark Newton 			for (brandinfo = &linux_brandlist[0];
907d2758342SMark Newton 			     *brandinfo != NULL; ++brandinfo)
9083ebc1248SPeter Wemm 				if (elf32_remove_brand_entry(*brandinfo) < 0)
909aa855a59SPeter Wemm 					error = EINVAL;
910d2758342SMark Newton 		}
911466b14d7SMarcel Moolenaar 		if (error == 0) {
912f41325dbSPeter Wemm 			SET_FOREACH(lihp, linux_ioctl_handler_set)
913f41325dbSPeter Wemm 				linux_ioctl_unregister_handler(*lihp);
914466b14d7SMarcel Moolenaar 			if (bootverbose)
915466b14d7SMarcel Moolenaar 				printf("Linux ELF exec handler removed\n");
91635eb8c5aSJohn Baldwin 			linux_mib_destroy();
917466b14d7SMarcel Moolenaar 		} else
918aa855a59SPeter Wemm 			printf("Could not deinstall ELF interpreter entry\n");
919aa855a59SPeter Wemm 		break;
920aa855a59SPeter Wemm 	default:
9213e019deaSPoul-Henning Kamp 		return EOPNOTSUPP;
922d30ea4f5SPeter Wemm 	}
923aa855a59SPeter Wemm 	return error;
924aa855a59SPeter Wemm }
925466b14d7SMarcel Moolenaar 
926aa855a59SPeter Wemm static moduledata_t linux_elf_mod = {
927aa855a59SPeter Wemm 	"linuxelf",
928aa855a59SPeter Wemm 	linux_elf_modevent,
929aa855a59SPeter Wemm 	0
930aa855a59SPeter Wemm };
931466b14d7SMarcel Moolenaar 
932aa855a59SPeter Wemm DECLARE_MODULE(linuxelf, linux_elf_mod, SI_SUB_EXEC, SI_ORDER_ANY);
933