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 without 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: releng/5.0/sys/alpha/linux/linux_sysvec.c 102808 2002-09-01 21:41:24Z jake $
29 */
30
31 /* XXX we use functions that might not exist. */
32 #include "opt_compat.h"
33
34 #ifndef COMPAT_43
35 #error "Unable to compile Linux-emulator due to missing COMPAT_43 option!"
36 #endif
37
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/exec.h>
41 #include <sys/imgact.h>
42 #include <sys/imgact_aout.h>
43 #include <sys/imgact_elf.h>
44 #include <sys/kernel.h>
45 #include <sys/lock.h>
46 #include <sys/malloc.h>
47 #include <sys/module.h>
48 #include <sys/mutex.h>
49 #include <sys/proc.h>
50 #include <sys/signalvar.h>
51 #include <sys/sysent.h>
52
53 #include <vm/vm.h>
54 #include <vm/vm_param.h>
55 #include <vm/vm_page.h>
56 #include <vm/vm_extern.h>
57
58 #include <machine/cpu.h>
59 #include <machine/md_var.h>
60
61 #include <alpha/linux/linux.h>
62 #include <alpha/linux/linux_proto.h>
63 #include <compat/linux/linux_util.h>
64 #undef szsigcode
65
66 MODULE_VERSION(linux, 1);
67 MODULE_DEPEND(linux, osf1, 1, 1, 1);
68 MODULE_DEPEND(linux, sysvmsg, 1, 1, 1);
69 MODULE_DEPEND(linux, sysvsem, 1, 1, 1);
70 MODULE_DEPEND(linux, sysvshm, 1, 1, 1);
71
72 MALLOC_DEFINE(M_LINUX, "linux", "Linux mode structures");
73
74 #if BYTE_ORDER == LITTLE_ENDIAN
75 #define SHELLMAGIC 0x2123 /* #! */
76 #else
77 #define SHELLMAGIC 0x2321
78 #endif
79
80 SET_DECLARE(linux_ioctl_handler_set, struct linux_ioctl_handler);
81
82 void osendsig(sig_t catcher, int sig, sigset_t *mask, u_long code);
83
84 static int elf_linux_fixup(long **stack_base,
85 struct image_params *iparams);
86 static int exec_linux_imgact_try(struct image_params *iparams);
87
88 static int
89 elf_linux_fixup(long **stack_base, struct image_params *imgp)
90 {
91 long *pos;
92 Elf64_Auxargs *args;
93
94 args = (Elf64_Auxargs *)imgp->auxargs;
95 pos = *stack_base + (imgp->argc + imgp->envc + 2);
96
97 if (args->trace) {
98 AUXARGS_ENTRY(pos, AT_DEBUG, 1);
99 }
100 if (args->execfd != -1) {
101 AUXARGS_ENTRY(pos, AT_EXECFD, args->execfd);
102 }
103 AUXARGS_ENTRY(pos, AT_PHDR, args->phdr);
104 AUXARGS_ENTRY(pos, AT_PHENT, args->phent);
105 AUXARGS_ENTRY(pos, AT_PHNUM, args->phnum);
106 AUXARGS_ENTRY(pos, AT_PAGESZ, args->pagesz);
107 AUXARGS_ENTRY(pos, AT_FLAGS, args->flags);
108 AUXARGS_ENTRY(pos, AT_ENTRY, args->entry);
109 AUXARGS_ENTRY(pos, AT_BASE, args->base);
110 PROC_LOCK(imgp->proc);
111 AUXARGS_ENTRY(pos, AT_UID, imgp->proc->p_ucred->cr_ruid);
112 AUXARGS_ENTRY(pos, AT_EUID, imgp->proc->p_ucred->cr_svuid);
113 AUXARGS_ENTRY(pos, AT_GID, imgp->proc->p_ucred->cr_rgid);
114 AUXARGS_ENTRY(pos, AT_EGID, imgp->proc->p_ucred->cr_svgid);
115 PROC_UNLOCK(imgp->proc);
116 AUXARGS_ENTRY(pos, AT_NULL, 0);
117
118 free(imgp->auxargs, M_TEMP);
119 imgp->auxargs = NULL;
120
121 (*stack_base)--;
122 **stack_base = (long)imgp->argc;
123 return 0;
124 }
125
126 /*
127 * If a linux binary is exec'ing something, try this image activator
128 * first. We override standard shell script execution in order to
129 * be able to modify the interpreter path. We only do this if a linux
130 * binary is doing the exec, so we do not create an EXEC module for it.
131 */
132 static int
133 exec_linux_imgact_try(imgp)
134 struct image_params *imgp;
135 {
136 const char *head;
137 int error;
138
139 head = (const char *)imgp->image_header;
140 error = -1;
141
142 /*
143 * The interpreter for shell scripts run from a linux binary needs
144 * to be located in /compat/linux if possible in order to recursively
145 * maintain linux path emulation.
146 */
147 if (((const short *)head)[0] == SHELLMAGIC) {
148 /*
149 * Run our normal shell image activator. If it succeeds
150 * attempt to use the alternate path for the interpreter. If
151 * an alternate path is found, use our stringspace to store it.
152 */
153 if ((error = exec_shell_imgact(imgp)) == 0) {
154 char *rpath = NULL;
155
156 linux_emul_find(FIRST_THREAD_IN_PROC(imgp->proc), NULL,
157 imgp->interpreter_name, &rpath, 0);
158 if (rpath != imgp->interpreter_name) {
159 int len = strlen(rpath) + 1;
160
161 if (len <= MAXSHELLCMDLEN) {
162 memcpy(imgp->interpreter_name, rpath,
163 len);
164 }
165 free(rpath, M_TEMP);
166 }
167 }
168 }
169 return(error);
170 }
171
172 /*
173 * To maintain OSF/1 compat, linux uses BSD signals & errnos on their
174 * alpha port. This greatly simplfies things for us.
175 */
176
177 struct sysentvec elf_linux_sysvec = {
178 LINUX_SYS_MAXSYSCALL,
179 linux_sysent,
180 0,
181 0,
182 NULL,
183 0,
184 NULL,
185 NULL,
186 elf_linux_fixup,
187 osendsig,
188 linux_sigcode,
189 &linux_szsigcode,
190 NULL,
191 "Linux ELF",
192 elf64_coredump,
193 exec_linux_imgact_try,
194 LINUX_MINSIGSTKSZ,
195 PAGE_SIZE,
196 VM_MIN_ADDRESS,
197 VM_MAXUSER_ADDRESS,
198 USRSTACK,
199 PS_STRINGS,
200 VM_PROT_ALL,
201 exec_copyout_strings,
202 exec_setregs
203 };
204
205 static Elf64_Brandinfo linux_brand = {
206 ELFOSABI_LINUX,
207 EM_ALPHA,
208 "Linux",
209 "/compat/linux",
210 "/lib/ld-linux.so.1",
211 &elf_linux_sysvec
212 };
213
214 static Elf64_Brandinfo linux_glibc2brand = {
215 ELFOSABI_LINUX,
216 EM_ALPHA,
217 "Linux",
218 "/compat/linux",
219 "/lib/ld-linux.so.2",
220 &elf_linux_sysvec
221 };
222
223 Elf64_Brandinfo *linux_brandlist[] = {
224 &linux_brand,
225 &linux_glibc2brand,
226 NULL
227 };
228
229 static int
230 linux_elf_modevent(module_t mod, int type, void *data)
231 {
232 Elf64_Brandinfo **brandinfo;
233 int error;
234 struct linux_ioctl_handler **lihp;
235
236 error = 0;
237
238 switch(type) {
239 case MOD_LOAD:
240 for (brandinfo = &linux_brandlist[0]; *brandinfo != NULL;
241 ++brandinfo)
242 if (elf64_insert_brand_entry(*brandinfo) < 0)
243 error = EINVAL;
244 if (error == 0) {
245 SET_FOREACH(lihp, linux_ioctl_handler_set)
246 linux_ioctl_register_handler(*lihp);
247 if (bootverbose)
248 printf("Linux ELF exec handler installed\n");
249 } else
250 printf("cannot insert Linux ELF brand handler\n");
251 break;
252 case MOD_UNLOAD:
253 for (brandinfo = &linux_brandlist[0]; *brandinfo != NULL;
254 ++brandinfo)
255 if (elf64_brand_inuse(*brandinfo))
256 error = EBUSY;
257 if (error == 0) {
258 for (brandinfo = &linux_brandlist[0];
259 *brandinfo != NULL; ++brandinfo)
260 if (elf64_remove_brand_entry(*brandinfo) < 0)
261 error = EINVAL;
262 }
263 if (error == 0) {
264 SET_FOREACH(lihp, linux_ioctl_handler_set)
265 linux_ioctl_unregister_handler(*lihp);
266 if (bootverbose)
267 printf("Linux ELF exec handler removed\n");
268 } else
269 printf("Could not deinstall ELF interpreter entry\n");
270 break;
271 default:
272 break;
273 }
274 return error;
275 }
276
277 static moduledata_t linux_elf_mod = {
278 "linuxelf",
279 linux_elf_modevent,
280 0
281 };
282
283 DUMMY(rt_sigreturn);
284
285 DECLARE_MODULE(linuxelf, linux_elf_mod, SI_SUB_EXEC, SI_ORDER_ANY);
Cache object: 428af42abb551d55d3a46c22018fa88b
|