1 /*-
2 * Copyright (c) 1994-1996 Søren Schmidt
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer
10 * in this position and unchanged.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software withough specific prior written permission
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * $FreeBSD: src/sys/i386/linux/linux_sysvec.c,v 1.9.2.4 1999/09/05 08:14:19 peter Exp $
29 */
30
31 /* XXX we use functions that might not exist. */
32 #define COMPAT_43 1
33
34 #include <sys/param.h>
35 #include <sys/buf.h>
36 #include <sys/proc.h>
37 #include <sys/systm.h>
38 #include <sys/sysproto.h>
39 #include <sys/sysent.h>
40 #include <sys/imgact.h>
41 #include <sys/imgact_elf.h>
42 #include <sys/signalvar.h>
43 #include <sys/malloc.h>
44 #include <vm/vm.h>
45 #include <vm/vm_param.h>
46 #include <vm/vm_prot.h>
47 #include <vm/lock.h>
48 #include <vm/vm_kern.h>
49 #include <vm/vm_object.h>
50 #include <vm/vm_page.h>
51 #include <vm/vm_map.h>
52 #include <vm/vm_pager.h>
53 #include <vm/vm_extern.h>
54 #include <sys/user.h>
55 #include <sys/exec.h>
56 #include <sys/kernel.h>
57 #include <machine/cpu.h>
58 #include <machine/frame.h>
59 #include <machine/reg.h>
60 #include <machine/specialreg.h>
61 #include <machine/psl.h>
62 #include <machine/sysarch.h>
63 #include <machine/md_var.h>
64
65 #include <i386/linux/linux.h>
66 #include <i386/linux/linux_proto.h>
67
68 static int linux_fixup __P((int **stack_base,
69 struct image_params *iparams));
70 static int elf_linux_fixup __P((int **stack_base,
71 struct image_params *iparams));
72 static void linux_prepsyscall __P((struct trapframe *tf, int *args,
73 u_int *code, caddr_t *params));
74 static void linux_sendsig __P((sig_t catcher, int sig, int mask,
75 u_long code));
76
77 /*
78 * Linux syscalls return negative errno's, we do positive and map them
79 */
80 static int bsd_to_linux_errno[ELAST] = {
81 -0, -1, -2, -3, -4, -5, -6, -7, -8, -9,
82 -10, -35, -12, -13, -14, -15, -16, -17, -18, -19,
83 -20, -21, -22, -23, -24, -25, -26, -27, -28, -29,
84 -30, -31, -32, -33, -34, -11,-115,-114, -88, -89,
85 -90, -91, -92, -93, -94, -95, -96, -97, -98, -99,
86 -100,-101,-102,-103,-104,-105,-106,-107,-108,-109,
87 -110,-111, -40, -36,-112,-113, -39, -11, -87,-122,
88 -116, -66, -6, -6, -6, -6, -6, -37, -38, -9,
89 -6
90 };
91
92 int bsd_to_linux_signal[NSIG] = {
93 0, LINUX_SIGHUP, LINUX_SIGINT, LINUX_SIGQUIT,
94 LINUX_SIGILL, LINUX_SIGTRAP, LINUX_SIGABRT, 0,
95 LINUX_SIGFPE, LINUX_SIGKILL, LINUX_SIGBUS, LINUX_SIGSEGV,
96 0, LINUX_SIGPIPE, LINUX_SIGALRM, LINUX_SIGTERM,
97 LINUX_SIGURG, LINUX_SIGSTOP, LINUX_SIGTSTP, LINUX_SIGCONT,
98 LINUX_SIGCHLD, LINUX_SIGTTIN, LINUX_SIGTTOU, LINUX_SIGIO,
99 LINUX_SIGXCPU, LINUX_SIGXFSZ, LINUX_SIGVTALRM, LINUX_SIGPROF,
100 LINUX_SIGWINCH, 0, LINUX_SIGUSR1, LINUX_SIGUSR2
101 };
102
103 int linux_to_bsd_signal[LINUX_NSIG] = {
104 0, SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGEMT,
105 SIGFPE, SIGKILL, SIGUSR1, SIGSEGV, SIGUSR2, SIGPIPE, SIGALRM, SIGTERM,
106 SIGBUS, SIGCHLD, SIGCONT, SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGIO,
107 SIGXCPU, SIGXFSZ, SIGVTALRM, SIGPROF, SIGWINCH, SIGURG, SIGURG, 0
108 };
109
110 /*
111 * If FreeBSD & Linux have a difference of opinion about what a trap
112 * means, deal with it here.
113 */
114 static int
115 translate_traps(int signal, int trap_code)
116 {
117 if (signal != SIGBUS)
118 return signal;
119 switch (trap_code) {
120 case T_PROTFLT:
121 case T_TSSFLT:
122 case T_DOUBLEFLT:
123 case T_PAGEFLT:
124 return SIGSEGV;
125 default:
126 return signal;
127 }
128 }
129
130 static int
131 linux_fixup(int **stack_base, struct image_params *imgp)
132 {
133 int *argv, *envp;
134
135 argv = *stack_base;
136 envp = *stack_base + (imgp->argc + 1);
137 (*stack_base)--;
138 **stack_base = (int)envp;
139 (*stack_base)--;
140 **stack_base = (int)argv;
141 (*stack_base)--;
142 **stack_base = (int)imgp->argc;
143 return 0;
144 }
145
146 static int
147 elf_linux_fixup(int **stack_base, struct image_params *imgp)
148 {
149 Elf32_Auxargs *args = (Elf32_Auxargs *)imgp->auxargs;
150 int *pos;
151
152 pos = *stack_base + (imgp->argc + imgp->envc + 2);
153
154 if (args->trace) {
155 AUXARGS_ENTRY(pos, AT_DEBUG, 1);
156 }
157 if (args->execfd != -1) {
158 AUXARGS_ENTRY(pos, AT_EXECFD, args->execfd);
159 }
160 AUXARGS_ENTRY(pos, AT_PHDR, args->phdr);
161 AUXARGS_ENTRY(pos, AT_PHENT, args->phent);
162 AUXARGS_ENTRY(pos, AT_PHNUM, args->phnum);
163 AUXARGS_ENTRY(pos, AT_PAGESZ, args->pagesz);
164 AUXARGS_ENTRY(pos, AT_FLAGS, args->flags);
165 AUXARGS_ENTRY(pos, AT_ENTRY, args->entry);
166 AUXARGS_ENTRY(pos, AT_BASE, args->base);
167 AUXARGS_ENTRY(pos, AT_UID, imgp->proc->p_cred->p_ruid);
168 AUXARGS_ENTRY(pos, AT_EUID, imgp->proc->p_cred->p_svuid);
169 AUXARGS_ENTRY(pos, AT_GID, imgp->proc->p_cred->p_rgid);
170 AUXARGS_ENTRY(pos, AT_EGID, imgp->proc->p_cred->p_svgid);
171 AUXARGS_ENTRY(pos, AT_NULL, 0);
172
173 free(imgp->auxargs, M_TEMP);
174 imgp->auxargs = NULL;
175
176 (*stack_base)--;
177 **stack_base = (int)imgp->argc;
178 return 0;
179 }
180
181 extern int _ucodesel, _udatasel;
182
183 /*
184 * Send an interrupt to process.
185 *
186 * Stack is set up to allow sigcode stored
187 * in u. to call routine, followed by kcall
188 * to sigreturn routine below. After sigreturn
189 * resets the signal mask, the stack, and the
190 * frame pointer, it returns to the user
191 * specified pc, psl.
192 */
193
194 static void
195 linux_sendsig(sig_t catcher, int sig, int mask, u_long code)
196 {
197 register struct proc *p = curproc;
198 register int *regs;
199 struct linux_sigframe *fp, frame;
200 struct sigacts *psp = p->p_sigacts;
201 int oonstack;
202
203 regs = p->p_md.md_regs;
204 oonstack = psp->ps_sigstk.ss_flags & SS_ONSTACK;
205
206 #ifdef DEBUG
207 printf("Linux-emul(%d): linux_sendsig(%8x, %d, %d, %ld)\n",
208 p->p_pid, catcher, sig, mask, code);
209 #endif
210 /*
211 * Allocate space for the signal handler context.
212 */
213 if ((psp->ps_flags & SAS_ALTSTACK) && !oonstack &&
214 (psp->ps_sigonstack & sigmask(sig))) {
215 fp = (struct linux_sigframe *)(psp->ps_sigstk.ss_sp +
216 psp->ps_sigstk.ss_size - sizeof(struct linux_sigframe));
217 psp->ps_sigstk.ss_flags |= SS_ONSTACK;
218 } else {
219 fp = (struct linux_sigframe *)regs[tESP] - 1;
220 }
221
222 /*
223 * grow() will return FALSE if the fp will not fit inside the stack
224 * and the stack can not be grown. useracc will return FALSE
225 * if access is denied.
226 */
227 if ((grow(p, (int)fp) == FALSE) ||
228 (useracc((caddr_t)fp, sizeof (struct linux_sigframe), B_WRITE) == FALSE)) {
229 /*
230 * Process has trashed its stack; give it an illegal
231 * instruction to halt it in its tracks.
232 */
233 SIGACTION(p, SIGILL) = SIG_DFL;
234 sig = sigmask(SIGILL);
235 p->p_sigignore &= ~sig;
236 p->p_sigcatch &= ~sig;
237 p->p_sigmask &= ~sig;
238 psignal(p, SIGILL);
239 return;
240 }
241
242 /*
243 * Build the argument list for the signal handler.
244 */
245 if (p->p_sysent->sv_sigtbl) {
246 if (sig < p->p_sysent->sv_sigsize)
247 sig = p->p_sysent->sv_sigtbl[sig];
248 else
249 sig = p->p_sysent->sv_sigsize + 1;
250 }
251
252 frame.sf_handler = catcher;
253 frame.sf_sig = sig;
254
255 /*
256 * Build the signal context to be used by sigreturn.
257 */
258 frame.sf_sc.sc_mask = mask;
259 __asm("movl %%gs,%w0" : "=r" (frame.sf_sc.sc_gs));
260 __asm("movl %%fs,%w0" : "=r" (frame.sf_sc.sc_fs));
261 frame.sf_sc.sc_es = regs[tES];
262 frame.sf_sc.sc_ds = regs[tDS];
263 frame.sf_sc.sc_edi = regs[tEDI];
264 frame.sf_sc.sc_esi = regs[tESI];
265 frame.sf_sc.sc_ebp = regs[tEBP];
266 frame.sf_sc.sc_ebx = regs[tEBX];
267 frame.sf_sc.sc_edx = regs[tEDX];
268 frame.sf_sc.sc_ecx = regs[tECX];
269 frame.sf_sc.sc_eax = regs[tEAX];
270 frame.sf_sc.sc_eip = regs[tEIP];
271 frame.sf_sc.sc_cs = regs[tCS];
272 frame.sf_sc.sc_eflags = regs[tEFLAGS];
273 frame.sf_sc.sc_esp_at_signal = regs[tESP];
274 frame.sf_sc.sc_ss = regs[tSS];
275 frame.sf_sc.sc_err = regs[tERR];
276 frame.sf_sc.sc_trapno = code; /* XXX ???? */
277
278 if (copyout(&frame, fp, sizeof(frame)) != 0) {
279 /*
280 * Process has trashed its stack; give it an illegal
281 * instruction to halt it in its tracks.
282 */
283 sigexit(p, SIGILL);
284 /* NOTREACHED */
285 }
286
287 /*
288 * Build context to run handler in.
289 */
290 regs[tESP] = (int)fp;
291 regs[tEIP] = (int)(((char *)PS_STRINGS) - *(p->p_sysent->sv_szsigcode));
292 regs[tEFLAGS] &= ~PSL_VM;
293 regs[tCS] = _ucodesel;
294 regs[tDS] = _udatasel;
295 regs[tES] = _udatasel;
296 regs[tSS] = _udatasel;
297 }
298
299 /*
300 * System call to cleanup state after a signal
301 * has been taken. Reset signal mask and
302 * stack state from context left by sendsig (above).
303 * Return to previous pc and psl as specified by
304 * context left by sendsig. Check carefully to
305 * make sure that the user has not modified the
306 * psl to gain improper privileges or to cause
307 * a machine fault.
308 */
309 int
310 linux_sigreturn(p, args, retval)
311 struct proc *p;
312 struct linux_sigreturn_args *args;
313 int *retval;
314 {
315 struct linux_sigcontext *scp, context;
316 register int *regs;
317 int eflags;
318
319 regs = p->p_md.md_regs;
320
321 #ifdef DEBUG
322 printf("Linux-emul(%d): linux_sigreturn(%8x)\n", p->p_pid, args->scp);
323 #endif
324 /*
325 * The trampoline code hands us the context.
326 * It is unsafe to keep track of it ourselves, in the event that a
327 * program jumps out of a signal handler.
328 */
329 scp = args->scp;
330 if (copyin((caddr_t)scp, &context, sizeof(*scp)) != 0)
331 return (EFAULT);
332
333 /*
334 * Check for security violations.
335 */
336 #define EFLAGS_SECURE(ef, oef) ((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0)
337 eflags = context.sc_eflags;
338 /*
339 * XXX do allow users to change the privileged flag PSL_RF. The
340 * cpu sets PSL_RF in tf_eflags for faults. Debuggers should
341 * sometimes set it there too. tf_eflags is kept in the signal
342 * context during signal handling and there is no other place
343 * to remember it, so the PSL_RF bit may be corrupted by the
344 * signal handler without us knowing. Corruption of the PSL_RF
345 * bit at worst causes one more or one less debugger trap, so
346 * allowing it is fairly harmless.
347 */
348 if (!EFLAGS_SECURE(eflags & ~PSL_RF, regs[tEFLAGS] & ~PSL_RF)) {
349 return(EINVAL);
350 }
351
352 /*
353 * Don't allow users to load a valid privileged %cs. Let the
354 * hardware check for invalid selectors, excess privilege in
355 * other selectors, invalid %eip's and invalid %esp's.
356 */
357 #define CS_SECURE(cs) (ISPL(cs) == SEL_UPL)
358 if (!CS_SECURE(context.sc_cs)) {
359 trapsignal(p, SIGBUS, T_PROTFLT);
360 return(EINVAL);
361 }
362
363 p->p_sigacts->ps_sigstk.ss_flags &= ~SS_ONSTACK;
364 p->p_sigmask = context.sc_mask &~
365 (sigmask(SIGKILL)|sigmask(SIGCONT)|sigmask(SIGSTOP));
366 /*
367 * Restore signal context.
368 */
369 /* %fs and %gs were restored by the trampoline. */
370 regs[tES] = context.sc_es;
371 regs[tDS] = context.sc_ds;
372 regs[tEDI] = context.sc_edi;
373 regs[tESI] = context.sc_esi;
374 regs[tEBP] = context.sc_ebp;
375 regs[tEBX] = context.sc_ebx;
376 regs[tEDX] = context.sc_edx;
377 regs[tECX] = context.sc_ecx;
378 regs[tEAX] = context.sc_eax;
379 regs[tEIP] = context.sc_eip;
380 regs[tCS] = context.sc_cs;
381 regs[tEFLAGS] = eflags;
382 regs[tESP] = context.sc_esp_at_signal;
383 regs[tSS] = context.sc_ss;
384
385 return (EJUSTRETURN);
386 }
387
388 void
389 linux_prepsyscall(struct trapframe *tf, int *args, u_int *code, caddr_t *params)
390 {
391 args[0] = tf->tf_ebx;
392 args[1] = tf->tf_ecx;
393 args[2] = tf->tf_edx;
394 args[3] = tf->tf_esi;
395 args[4] = tf->tf_edi;
396 *params = NULL; /* no copyin */
397 }
398
399 struct sysentvec linux_sysvec = {
400 LINUX_SYS_MAXSYSCALL,
401 linux_sysent,
402 0xff,
403 NSIG,
404 bsd_to_linux_signal,
405 ELAST,
406 bsd_to_linux_errno,
407 translate_traps,
408 linux_fixup,
409 linux_sendsig,
410 linux_sigcode,
411 &linux_szsigcode,
412 linux_prepsyscall,
413 "Linux a.out"
414 };
415
416 struct sysentvec elf_linux_sysvec = {
417 LINUX_SYS_MAXSYSCALL,
418 linux_sysent,
419 0xff,
420 NSIG,
421 bsd_to_linux_signal,
422 ELAST,
423 bsd_to_linux_errno,
424 translate_traps,
425 elf_linux_fixup,
426 linux_sendsig,
427 linux_sigcode,
428 &linux_szsigcode,
429 linux_prepsyscall,
430 "Linux ELF"
431 };
432
433 /*
434 * Installed either via SYSINIT() or via LKM stubs.
435 */
436 static Elf32_Brandinfo linux_brand = {
437 "Linux",
438 "/compat/linux",
439 "/lib/ld-linux.so.1",
440 &elf_linux_sysvec
441 };
442
443 static Elf32_Brandinfo linux_glibc2brand = {
444 "Linux",
445 "/compat/linux",
446 "/lib/ld-linux.so.2",
447 &elf_linux_sysvec
448 };
449
450 Elf32_Brandinfo *linux_brandlist[] = {
451 &linux_brand,
452 &linux_glibc2brand,
453 NULL
454 };
455
456 #ifndef LKM
457 /*
458 * XXX: this is WRONG, it needs to be SI_SUB_EXEC, but this is just at the
459 * "proof of concept" stage and will be fixed shortly
460 */
461 static void linux_elf_init __P((void *dummy));
462
463 static void
464 linux_elf_init(dummy)
465 void *dummy;
466 {
467 Elf32_Brandinfo **brandinfo;
468 int error;
469
470 error = 0;
471
472 for (brandinfo = &linux_brandlist[0]; *brandinfo != NULL; ++brandinfo)
473 if (elf_insert_brand_entry(*brandinfo) < 0)
474 error = 1;
475
476 if (error)
477 printf("cannot insert Linux elf brand handler\n");
478 else if (bootverbose)
479 printf("Linux-ELF exec handler installed\n");
480 }
481
482 SYSINIT(linuxelf, SI_SUB_VFS, SI_ORDER_ANY, linux_elf_init, NULL);
483 #endif
Cache object: 400dc2faf0ee3a05865ab56d9fbfb02e
|