1 /* $NetBSD: pecoff_exec.c,v 1.27 2005/02/26 23:10:21 perry Exp $ */
2
3 /*
4 * Copyright (c) 2000 Masaru OKI
5 * Copyright (c) 1994, 1995, 1998 Scott Bartram
6 * Copyright (c) 1994 Adam Glass
7 * Copyright (c) 1993, 1994 Christopher G. Demetriou
8 * All rights reserved.
9 *
10 * from compat/ibcs2/ibcs2_exec.c
11 * originally from kern/exec_ecoff.c
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 * 3. All advertising materials mentioning features or use of this software
22 * must display the following acknowledgement:
23 * This product includes software developed by Scott Bartram.
24 * 4. The name of the author may not be used to endorse or promote products
25 * derived from this software without specific prior written permission
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
28 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
29 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
30 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
31 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
32 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
33 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
34 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
35 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
36 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 #include <sys/cdefs.h>
40 __KERNEL_RCSID(0, "$NetBSD: pecoff_exec.c,v 1.27 2005/02/26 23:10:21 perry Exp $");
41
42 /*#define DEBUG_PECOFF*/
43
44 #include <sys/param.h>
45 #include <sys/proc.h>
46 #include <sys/malloc.h>
47 #include <sys/namei.h>
48 #include <sys/vnode.h>
49 #include <sys/mount.h>
50 #include <sys/exec.h>
51 #include <sys/syscall.h>
52 #include <sys/signalvar.h>
53 #include <sys/resourcevar.h>
54 #include <sys/stat.h>
55
56 #include <sys/exec_coff.h>
57 #include <machine/coff_machdep.h>
58
59 #include <compat/pecoff/pecoff_exec.h>
60 #include <compat/pecoff/pecoff_util.h>
61 #include <compat/pecoff/pecoff_syscall.h>
62
63 int pecoff_signature (struct proc *p, struct vnode *vp,
64 struct pecoff_dos_filehdr *dp);
65 int pecoff_load_file (struct proc *p, struct exec_package *epp,
66 const char *path, struct exec_vmcmd_set *vcset,
67 u_long *entry, struct pecoff_args *argp);
68 void pecoff_load_section (struct exec_vmcmd_set *vcset, struct vnode *vp,
69 struct coff_scnhdr *sh, long *addr,
70 u_long *size, int *prot);
71 int exec_pecoff_makecmds (struct proc *p, struct exec_package *epp);
72 int exec_pecoff_coff_makecmds (struct proc *p, struct exec_package *epp,
73 struct coff_filehdr *fp, int peofs);
74 int exec_pecoff_prep_omagic (struct proc *p, struct exec_package *epp,
75 struct coff_filehdr *fp,
76 struct coff_aouthdr *ap, int peofs);
77 int exec_pecoff_prep_nmagic (struct proc *p, struct exec_package *epp,
78 struct coff_filehdr *fp,
79 struct coff_aouthdr *ap, int peofs);
80 int exec_pecoff_prep_zmagic (struct proc *p, struct exec_package *epp,
81 struct coff_filehdr *fp,
82 struct coff_aouthdr *ap, int peofs);
83
84
85 int
86 pecoff_copyargs(p, pack, arginfo, stackp, argp)
87 struct proc *p;
88 struct exec_package *pack;
89 struct ps_strings *arginfo;
90 char **stackp;
91 void *argp;
92 {
93 int len = sizeof(struct pecoff_args);
94 struct pecoff_args *ap;
95 int error;
96
97 if ((error = copyargs(p, pack, arginfo, stackp, argp)) != 0)
98 return error;
99
100 ap = (struct pecoff_args *)pack->ep_emul_arg;
101 if ((error = copyout(ap, *stackp, len)) != 0)
102 return error;
103
104 #if 0 /* kern_exec.c? */
105 free(ap, M_TEMP);
106 pack->ep_emul_arg = 0;
107 #endif
108
109 *stackp += len;
110 return error;
111 }
112
113 #define PECOFF_SIGNATURE "PE\0\0"
114 static const char signature[] = PECOFF_SIGNATURE;
115
116 /*
117 * Check PE signature.
118 */
119 int
120 pecoff_signature(p, vp, dp)
121 struct proc *p;
122 struct vnode *vp;
123 struct pecoff_dos_filehdr *dp;
124 {
125 int error;
126 char buf[sizeof(signature) - 1];
127
128 if (DOS_BADMAG(dp)) {
129 return ENOEXEC;
130 }
131 error = exec_read_from(p, vp, dp->d_peofs, buf, sizeof(buf));
132 if (error) {
133 return error;
134 }
135 if (memcmp(buf, signature, sizeof(signature) - 1) == 0) {
136 return 0;
137 }
138 return EFTYPE;
139 }
140
141 /*
142 * load(mmap) file. for dynamic linker (ld.so.dll)
143 */
144 int
145 pecoff_load_file(p, epp, path, vcset, entry, argp)
146 struct proc *p;
147 struct exec_package *epp;
148 const char *path;
149 struct exec_vmcmd_set *vcset;
150 u_long *entry;
151 struct pecoff_args *argp;
152 {
153 int error, peofs, scnsiz, i;
154 struct nameidata nd;
155 struct vnode *vp;
156 struct vattr attr;
157 struct pecoff_dos_filehdr dh;
158 struct coff_filehdr *fp = 0;
159 struct coff_aouthdr *ap;
160 struct pecoff_opthdr *wp;
161 struct coff_scnhdr *sh = 0;
162 const char *bp;
163
164 /*
165 * Following has ~same effect as emul_find_interp(), but the code
166 * needs to do some more checks while having the vnode open.
167 * emul_find_interp() wouldn't really simplify handling here.
168 */
169 if ((error = emul_find(p, NULL, epp->ep_esch->es_emul->e_path,
170 path, &bp, 0))) {
171 char *ptr;
172 int len;
173
174 len = strlen(path) + 1;
175 if (len > MAXPATHLEN)
176 return error;
177 ptr = malloc(len, M_TEMP, M_WAITOK);
178 copystr(path, ptr, len, 0);
179 bp = ptr;
180 }
181
182 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, bp, p);
183 if ((error = namei(&nd)) != 0) {
184 free((void *)bp, M_TEMP);
185 return error;
186 }
187 vp = nd.ni_vp;
188
189 /*
190 * Similarly, if it's not marked as executable, or it's not a regular
191 * file, we don't allow it to be used.
192 */
193 if (vp->v_type != VREG) {
194 error = EACCES;
195 goto badunlock;
196 }
197 if ((error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p)) != 0)
198 goto badunlock;
199
200 /* get attributes */
201 if ((error = VOP_GETATTR(vp, &attr, p->p_ucred, p)) != 0)
202 goto badunlock;
203
204 /*
205 * Check mount point. Though we're not trying to exec this binary,
206 * we will be executing code from it, so if the mount point
207 * disallows execution or set-id-ness, we punt or kill the set-id.
208 */
209 if (vp->v_mount->mnt_flag & MNT_NOEXEC) {
210 error = EACCES;
211 goto badunlock;
212 }
213 if (vp->v_mount->mnt_flag & MNT_NOSUID)
214 epp->ep_vap->va_mode &= ~(S_ISUID | S_ISGID);
215
216 if ((error = vn_marktext(vp)))
217 goto badunlock;
218
219 VOP_UNLOCK(vp, 0);
220 /*
221 * Read header.
222 */
223 error = exec_read_from(p, vp, 0, &dh, sizeof(dh));
224 if (error != 0)
225 goto bad;
226 if ((error = pecoff_signature(p, vp, &dh)) != 0)
227 goto bad;
228 fp = malloc(PECOFF_HDR_SIZE, M_TEMP, M_WAITOK);
229 peofs = dh.d_peofs + sizeof(signature) - 1;
230 error = exec_read_from(p, vp, peofs, fp, PECOFF_HDR_SIZE);
231 if (error != 0)
232 goto bad;
233 if (COFF_BADMAG(fp)) {
234 error = ENOEXEC;
235 goto bad;
236 }
237 ap = (void *)((char *)fp + sizeof(struct coff_filehdr));
238 wp = (void *)((char *)ap + sizeof(struct coff_aouthdr));
239 /* read section header */
240 scnsiz = sizeof(struct coff_scnhdr) * fp->f_nscns;
241 sh = malloc(scnsiz, M_TEMP, M_WAITOK);
242 if ((error = exec_read_from(p, vp, peofs + PECOFF_HDR_SIZE, sh,
243 scnsiz)) != 0)
244 goto bad;
245
246 /*
247 * Read section header, and mmap.
248 */
249 for (i = 0; i < fp->f_nscns; i++) {
250 int prot = 0;
251 long addr, size;
252
253 if (sh[i].s_flags & COFF_STYP_DISCARD)
254 continue;
255 /* XXX ? */
256 if ((sh[i].s_flags & COFF_STYP_TEXT) &&
257 (sh[i].s_flags & COFF_STYP_EXEC) == 0)
258 continue;
259 if ((sh[i].s_flags & (COFF_STYP_TEXT|COFF_STYP_DATA|
260 COFF_STYP_BSS|COFF_STYP_READ)) == 0)
261 continue;
262 sh[i].s_vaddr += wp->w_base; /* RVA --> VA */
263 pecoff_load_section(vcset, vp, &sh[i], &addr, &size, &prot);
264 }
265 *entry = wp->w_base + ap->a_entry;
266 argp->a_ldbase = wp->w_base;
267 argp->a_ldexport = wp->w_imghdr[0].i_vaddr + wp->w_base;
268
269 free(fp, M_TEMP);
270 free(sh, M_TEMP);
271 free((void *)bp, M_TEMP);
272 vrele(vp);
273 return 0;
274
275 badunlock:
276 VOP_UNLOCK(vp, 0);
277
278 bad:
279 if (fp != 0)
280 free(fp, M_TEMP);
281 if (sh != 0)
282 free(sh, M_TEMP);
283 free((void *)bp, M_TEMP);
284 vrele(vp);
285 return error;
286 }
287
288 /*
289 * mmap one section.
290 */
291 void
292 pecoff_load_section(vcset, vp, sh, addr, size, prot)
293 struct exec_vmcmd_set *vcset;
294 struct vnode *vp;
295 struct coff_scnhdr *sh;
296 long *addr;
297 u_long *size;
298 int *prot;
299 {
300 u_long diff, offset;
301
302 *addr = COFF_ALIGN(sh->s_vaddr);
303 diff = (sh->s_vaddr - *addr);
304 offset = sh->s_scnptr - diff;
305 *size = COFF_ROUND(sh->s_size + diff, COFF_LDPGSZ);
306
307 *prot |= (sh->s_flags & COFF_STYP_EXEC) ? VM_PROT_EXECUTE : 0;
308 *prot |= (sh->s_flags & COFF_STYP_READ) ? VM_PROT_READ : 0;
309 *prot |= (sh->s_flags & COFF_STYP_WRITE) ? VM_PROT_WRITE : 0;
310
311 if (diff == 0 && offset == COFF_ALIGN(offset))
312 NEW_VMCMD(vcset, vmcmd_map_pagedvn, *size, *addr, vp,
313 offset, *prot);
314 else
315 NEW_VMCMD(vcset, vmcmd_map_readvn, sh->s_size, sh->s_vaddr, vp,
316 sh->s_scnptr, *prot);
317
318 if (*size < sh->s_paddr) {
319 u_long baddr, bsize;
320
321 baddr = *addr + COFF_ROUND(*size, COFF_LDPGSZ);
322 bsize = sh->s_paddr - COFF_ROUND(*size, COFF_LDPGSZ);
323 DPRINTF(("additional zero space (addr %lx size %ld)\n",
324 baddr, bsize));
325 NEW_VMCMD(vcset, vmcmd_map_zero, bsize, baddr,
326 NULLVP, 0, *prot);
327 *size = COFF_ROUND(sh->s_paddr, COFF_LDPGSZ);
328 }
329 DPRINTF(("section %s loaded. (addr %lx size %ld prot %d)\n",
330 sh->s_name, sh->s_vaddr, sh->s_size, *prot));
331 }
332
333 /*
334 */
335 int
336 exec_pecoff_makecmds(p, epp)
337 struct proc *p;
338 struct exec_package *epp;
339 {
340 int error, peofs;
341 struct pecoff_dos_filehdr *dp = epp->ep_hdr;
342 struct coff_filehdr *fp;
343
344 /*
345 * mmap EXE file (PE format)
346 * 1. read header (DOS,PE)
347 * 2. mmap code section (READ|EXEC)
348 * 3. mmap other section, such as data (READ|WRITE|EXEC)
349 */
350 if (epp->ep_hdrvalid < PECOFF_DOS_HDR_SIZE) {
351 return ENOEXEC;
352 }
353 if ((error = pecoff_signature(p, epp->ep_vp, dp)) != 0)
354 return error;
355
356 if ((error = vn_marktext(epp->ep_vp)) != 0)
357 return error;
358
359 peofs = dp->d_peofs + sizeof(signature) - 1;
360 fp = malloc(PECOFF_HDR_SIZE, M_TEMP, M_WAITOK);
361 error = exec_read_from(p, epp->ep_vp, peofs, fp, PECOFF_HDR_SIZE);
362 if (error) {
363 free(fp, M_TEMP);
364 return error;
365 }
366 error = exec_pecoff_coff_makecmds(p, epp, fp, peofs);
367
368 if (error != 0)
369 kill_vmcmds(&epp->ep_vmcmds);
370
371 free(fp, M_TEMP);
372 return error;
373 }
374
375 /*
376 */
377 int
378 exec_pecoff_coff_makecmds(p, epp, fp, peofs)
379 struct proc *p;
380 struct exec_package *epp;
381 struct coff_filehdr *fp;
382 int peofs;
383 {
384 struct coff_aouthdr *ap;
385 int error;
386
387 if (COFF_BADMAG(fp)) {
388 return ENOEXEC;
389 }
390 ap = (void *)((char *)fp + sizeof(struct coff_filehdr));
391 switch (ap->a_magic) {
392 case COFF_OMAGIC:
393 error = exec_pecoff_prep_omagic(p, epp, fp, ap, peofs);
394 break;
395 case COFF_NMAGIC:
396 error = exec_pecoff_prep_nmagic(p, epp, fp, ap, peofs);
397 break;
398 case COFF_ZMAGIC:
399 error = exec_pecoff_prep_zmagic(p, epp, fp, ap, peofs);
400 break;
401 default:
402 return ENOEXEC;
403 }
404
405 return error;
406 }
407
408 /*
409 */
410 int
411 exec_pecoff_prep_omagic(p, epp, fp, ap, peofs)
412 struct proc *p;
413 struct exec_package *epp;
414 struct coff_filehdr *fp;
415 struct coff_aouthdr *ap;
416 int peofs;
417 {
418 return ENOEXEC;
419 }
420
421 /*
422 */
423 int
424 exec_pecoff_prep_nmagic(p, epp, fp, ap, peofs)
425 struct proc *p;
426 struct exec_package *epp;
427 struct coff_filehdr *fp;
428 struct coff_aouthdr *ap;
429 int peofs;
430 {
431 return ENOEXEC;
432 }
433
434 /*
435 */
436 int
437 exec_pecoff_prep_zmagic(p, epp, fp, ap, peofs)
438 struct proc *p;
439 struct exec_package *epp;
440 struct coff_filehdr *fp;
441 struct coff_aouthdr *ap;
442 int peofs;
443 {
444 int error, i;
445 struct pecoff_opthdr *wp;
446 long tsize, daddr, dsize, baddr, bsize;
447 struct coff_scnhdr *sh;
448 struct pecoff_args *argp;
449 int scnsiz = sizeof(struct coff_scnhdr) * fp->f_nscns;
450
451 wp = (void *)((char *)ap + sizeof(struct coff_aouthdr));
452
453 epp->ep_tsize = ap->a_tsize;
454 epp->ep_daddr = VM_MAXUSER_ADDRESS;
455 epp->ep_dsize = 0;
456 /* read section header */
457 sh = malloc(scnsiz, M_TEMP, M_WAITOK);
458 error = exec_read_from(p, epp->ep_vp, peofs + PECOFF_HDR_SIZE, sh,
459 scnsiz);
460 if (error) {
461 free(sh, M_TEMP);
462 return error;
463 }
464 /*
465 * map section
466 */
467 for (i = 0; i < fp->f_nscns; i++) {
468 int prot = /**/VM_PROT_WRITE;
469 long s_flags = sh[i].s_flags;
470
471 if ((s_flags & COFF_STYP_DISCARD) != 0)
472 continue;
473 sh[i].s_vaddr += wp->w_base; /* RVA --> VA */
474
475 if ((s_flags & COFF_STYP_TEXT) != 0) {
476 /* set up command for text segment */
477 /* DPRINTF(("COFF text addr %lx size %ld offset %ld\n",
478 sh[i].s_vaddr, sh[i].s_size, sh[i].s_scnptr));
479 */ pecoff_load_section(&epp->ep_vmcmds, epp->ep_vp,
480 &sh[i], &epp->ep_taddr,
481 &tsize, &prot);
482 } else if ((s_flags & COFF_STYP_BSS) != 0) {
483 /* set up command for bss segment */
484 baddr = sh[i].s_vaddr;
485 bsize = sh[i].s_paddr;
486 if (bsize)
487 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero,
488 bsize, baddr, NULLVP, 0,
489 VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
490 epp->ep_daddr = min(epp->ep_daddr, baddr);
491 bsize = baddr + bsize - epp->ep_daddr;
492 epp->ep_dsize = max(epp->ep_dsize, bsize);
493 } else if ((s_flags & (COFF_STYP_DATA|COFF_STYP_READ)) != 0) {
494 /* set up command for data segment */
495 /* DPRINTF(("COFF data addr %lx size %ld offset %ld\n",
496 sh[i].s_vaddr, sh[i].s_size, sh[i].s_scnptr));*/
497 pecoff_load_section(&epp->ep_vmcmds, epp->ep_vp,
498 &sh[i], &daddr, &dsize, &prot);
499 epp->ep_daddr = min(epp->ep_daddr, daddr);
500 dsize = daddr + dsize - epp->ep_daddr;
501 epp->ep_dsize = max(epp->ep_dsize, dsize);
502 }
503 }
504 /* set up ep_emul_arg */
505 argp = malloc(sizeof(struct pecoff_args), M_TEMP, M_WAITOK);
506 epp->ep_emul_arg = argp;
507 argp->a_abiversion = NETBSDPE_ABI_VERSION;
508 argp->a_zero = 0;
509 argp->a_entry = wp->w_base + ap->a_entry;
510 argp->a_end = epp->ep_daddr + epp->ep_dsize;
511 argp->a_opthdr = *wp;
512
513 /*
514 * load dynamic linker
515 */
516 error = pecoff_load_file(p, epp, "/usr/libexec/ld.so.dll",
517 &epp->ep_vmcmds, &epp->ep_entry, argp);
518 if (error) {
519 free(sh, M_TEMP);
520 return error;
521 }
522
523 #if 0
524 DPRINTF(("text addr: %lx size: %ld data addr: %lx size: %ld entry: %lx\n",
525 epp->ep_taddr, epp->ep_tsize,
526 epp->ep_daddr, epp->ep_dsize,
527 epp->ep_entry));
528 #endif
529
530 free(sh, M_TEMP);
531 return (*epp->ep_esch->es_setup_stack)(p, epp);
532 }
Cache object: 42dfa838fa230e033e580960395beb95
|