1 /* $NetBSD: pecoff_exec.c,v 1.34 2006/11/16 01:32:44 christos 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.34 2006/11/16 01:32:44 christos 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 lwp *l, struct vnode *vp,
64 struct pecoff_dos_filehdr *dp);
65 int pecoff_load_file (struct lwp *l, 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 lwp *l, struct exec_package *epp);
72 int exec_pecoff_coff_makecmds (struct lwp *l, 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 lwp *l, struct exec_package *epp,
81 struct coff_filehdr *fp,
82 struct coff_aouthdr *ap, int peofs);
83
84
85 int
86 pecoff_copyargs(l, pack, arginfo, stackp, argp)
87 struct lwp *l;
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(l, 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(l, vp, dp)
121 struct lwp *l;
122 struct vnode *vp;
123 struct pecoff_dos_filehdr *dp;
124 {
125 int error;
126 char tbuf[sizeof(signature) - 1];
127
128 if (DOS_BADMAG(dp)) {
129 return ENOEXEC;
130 }
131 error = exec_read_from(l, vp, dp->d_peofs, tbuf, sizeof(tbuf));
132 if (error) {
133 return error;
134 }
135 if (memcmp(tbuf, 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(l, epp, path, vcset, entry, argp)
146 struct lwp *l;
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(l, 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, l);
183 if ((error = namei(&nd)) != 0) {
184 /*XXXUNCONST*/
185 free(__UNCONST(bp), M_TEMP);
186 return error;
187 }
188 vp = nd.ni_vp;
189
190 /*
191 * Similarly, if it's not marked as executable, or it's not a regular
192 * file, we don't allow it to be used.
193 */
194 if (vp->v_type != VREG) {
195 error = EACCES;
196 goto badunlock;
197 }
198 if ((error = VOP_ACCESS(vp, VEXEC, l->l_cred, l)) != 0)
199 goto badunlock;
200
201 /* get attributes */
202 if ((error = VOP_GETATTR(vp, &attr, l->l_cred, l)) != 0)
203 goto badunlock;
204
205 /*
206 * Check mount point. Though we're not trying to exec this binary,
207 * we will be executing code from it, so if the mount point
208 * disallows execution or set-id-ness, we punt or kill the set-id.
209 */
210 if (vp->v_mount->mnt_flag & MNT_NOEXEC) {
211 error = EACCES;
212 goto badunlock;
213 }
214 if (vp->v_mount->mnt_flag & MNT_NOSUID)
215 epp->ep_vap->va_mode &= ~(S_ISUID | S_ISGID);
216
217 if ((error = vn_marktext(vp)))
218 goto badunlock;
219
220 VOP_UNLOCK(vp, 0);
221 /*
222 * Read header.
223 */
224 error = exec_read_from(l, vp, 0, &dh, sizeof(dh));
225 if (error != 0)
226 goto bad;
227 if ((error = pecoff_signature(l, vp, &dh)) != 0)
228 goto bad;
229 fp = malloc(PECOFF_HDR_SIZE, M_TEMP, M_WAITOK);
230 peofs = dh.d_peofs + sizeof(signature) - 1;
231 error = exec_read_from(l, vp, peofs, fp, PECOFF_HDR_SIZE);
232 if (error != 0)
233 goto bad;
234 if (COFF_BADMAG(fp)) {
235 error = ENOEXEC;
236 goto bad;
237 }
238 ap = (void *)((char *)fp + sizeof(struct coff_filehdr));
239 wp = (void *)((char *)ap + sizeof(struct coff_aouthdr));
240 /* read section header */
241 scnsiz = sizeof(struct coff_scnhdr) * fp->f_nscns;
242 sh = malloc(scnsiz, M_TEMP, M_WAITOK);
243 if ((error = exec_read_from(l, vp, peofs + PECOFF_HDR_SIZE, sh,
244 scnsiz)) != 0)
245 goto bad;
246
247 /*
248 * Read section header, and mmap.
249 */
250 for (i = 0; i < fp->f_nscns; i++) {
251 int prot = 0;
252 long addr;
253 u_long size;
254
255 if (sh[i].s_flags & COFF_STYP_DISCARD)
256 continue;
257 /* XXX ? */
258 if ((sh[i].s_flags & COFF_STYP_TEXT) &&
259 (sh[i].s_flags & COFF_STYP_EXEC) == 0)
260 continue;
261 if ((sh[i].s_flags & (COFF_STYP_TEXT|COFF_STYP_DATA|
262 COFF_STYP_BSS|COFF_STYP_READ)) == 0)
263 continue;
264 sh[i].s_vaddr += wp->w_base; /* RVA --> VA */
265 pecoff_load_section(vcset, vp, &sh[i], &addr, &size, &prot);
266 }
267 *entry = wp->w_base + ap->a_entry;
268 argp->a_ldbase = wp->w_base;
269 argp->a_ldexport = wp->w_imghdr[0].i_vaddr + wp->w_base;
270
271 free(fp, M_TEMP);
272 free(sh, M_TEMP);
273 /*XXXUNCONST*/
274 free(__UNCONST(bp), M_TEMP);
275 vrele(vp);
276 return 0;
277
278 badunlock:
279 VOP_UNLOCK(vp, 0);
280
281 bad:
282 if (fp != 0)
283 free(fp, M_TEMP);
284 if (sh != 0)
285 free(sh, M_TEMP);
286 /*XXXUNCONST*/
287 free(__UNCONST(bp), M_TEMP);
288 vrele(vp);
289 return error;
290 }
291
292 /*
293 * mmap one section.
294 */
295 void
296 pecoff_load_section(vcset, vp, sh, addr, size, prot)
297 struct exec_vmcmd_set *vcset;
298 struct vnode *vp;
299 struct coff_scnhdr *sh;
300 long *addr;
301 u_long *size;
302 int *prot;
303 {
304 u_long diff, offset;
305
306 *addr = COFF_ALIGN(sh->s_vaddr);
307 diff = (sh->s_vaddr - *addr);
308 offset = sh->s_scnptr - diff;
309 *size = COFF_ROUND(sh->s_size + diff, COFF_LDPGSZ);
310
311 *prot |= (sh->s_flags & COFF_STYP_EXEC) ? VM_PROT_EXECUTE : 0;
312 *prot |= (sh->s_flags & COFF_STYP_READ) ? VM_PROT_READ : 0;
313 *prot |= (sh->s_flags & COFF_STYP_WRITE) ? VM_PROT_WRITE : 0;
314
315 if (diff == 0 && offset == COFF_ALIGN(offset))
316 NEW_VMCMD(vcset, vmcmd_map_pagedvn, *size, *addr, vp,
317 offset, *prot);
318 else
319 NEW_VMCMD(vcset, vmcmd_map_readvn, sh->s_size, sh->s_vaddr, vp,
320 sh->s_scnptr, *prot);
321
322 if (*size < sh->s_paddr) {
323 u_long baddr, bsize;
324
325 baddr = *addr + COFF_ROUND(*size, COFF_LDPGSZ);
326 bsize = sh->s_paddr - COFF_ROUND(*size, COFF_LDPGSZ);
327 DPRINTF(("additional zero space (addr %lx size %ld)\n",
328 baddr, bsize));
329 NEW_VMCMD(vcset, vmcmd_map_zero, bsize, baddr,
330 NULLVP, 0, *prot);
331 *size = COFF_ROUND(sh->s_paddr, COFF_LDPGSZ);
332 }
333 DPRINTF(("section %s loaded. (addr %lx size %ld prot %d)\n",
334 sh->s_name, sh->s_vaddr, sh->s_size, *prot));
335 }
336
337 /*
338 */
339 int
340 exec_pecoff_makecmds(l, epp)
341 struct lwp *l;
342 struct exec_package *epp;
343 {
344 int error, peofs;
345 struct pecoff_dos_filehdr *dp = epp->ep_hdr;
346 struct coff_filehdr *fp;
347 struct proc *p;
348
349 p = l->l_proc;
350 /*
351 * mmap EXE file (PE format)
352 * 1. read header (DOS,PE)
353 * 2. mmap code section (READ|EXEC)
354 * 3. mmap other section, such as data (READ|WRITE|EXEC)
355 */
356 if (epp->ep_hdrvalid < PECOFF_DOS_HDR_SIZE) {
357 return ENOEXEC;
358 }
359 if ((error = pecoff_signature(l, epp->ep_vp, dp)) != 0)
360 return error;
361
362 if ((error = vn_marktext(epp->ep_vp)) != 0)
363 return error;
364
365 peofs = dp->d_peofs + sizeof(signature) - 1;
366 fp = malloc(PECOFF_HDR_SIZE, M_TEMP, M_WAITOK);
367 error = exec_read_from(l, epp->ep_vp, peofs, fp, PECOFF_HDR_SIZE);
368 if (error) {
369 free(fp, M_TEMP);
370 return error;
371 }
372 error = exec_pecoff_coff_makecmds(l, epp, fp, peofs);
373
374 if (error != 0)
375 kill_vmcmds(&epp->ep_vmcmds);
376
377 free(fp, M_TEMP);
378 return error;
379 }
380
381 /*
382 */
383 int
384 exec_pecoff_coff_makecmds(l, epp, fp, peofs)
385 struct lwp *l;
386 struct exec_package *epp;
387 struct coff_filehdr *fp;
388 int peofs;
389 {
390 struct coff_aouthdr *ap;
391 struct proc *p;
392 int error;
393
394 if (COFF_BADMAG(fp)) {
395 return ENOEXEC;
396 }
397 p = l->l_proc;
398 ap = (void *)((char *)fp + sizeof(struct coff_filehdr));
399 switch (ap->a_magic) {
400 case COFF_OMAGIC:
401 error = exec_pecoff_prep_omagic(p, epp, fp, ap, peofs);
402 break;
403 case COFF_NMAGIC:
404 error = exec_pecoff_prep_nmagic(p, epp, fp, ap, peofs);
405 break;
406 case COFF_ZMAGIC:
407 error = exec_pecoff_prep_zmagic(l, epp, fp, ap, peofs);
408 break;
409 default:
410 return ENOEXEC;
411 }
412
413 return error;
414 }
415
416 /*
417 */
418 int
419 exec_pecoff_prep_omagic(struct proc *p,
420 struct exec_package *epp, struct coff_filehdr *fp,
421 struct coff_aouthdr *ap, int peofs)
422 {
423 return ENOEXEC;
424 }
425
426 /*
427 */
428 int
429 exec_pecoff_prep_nmagic(struct proc *p,
430 struct exec_package *epp, struct coff_filehdr *fp,
431 struct coff_aouthdr *ap, int peofs)
432 {
433 return ENOEXEC;
434 }
435
436 /*
437 */
438 int
439 exec_pecoff_prep_zmagic(l, epp, fp, ap, peofs)
440 struct lwp *l;
441 struct exec_package *epp;
442 struct coff_filehdr *fp;
443 struct coff_aouthdr *ap;
444 int peofs;
445 {
446 int error, i;
447 struct pecoff_opthdr *wp;
448 long daddr, baddr, bsize;
449 u_long tsize, dsize;
450 struct coff_scnhdr *sh;
451 struct pecoff_args *argp;
452 int scnsiz = sizeof(struct coff_scnhdr) * fp->f_nscns;
453
454 wp = (void *)((char *)ap + sizeof(struct coff_aouthdr));
455
456 epp->ep_tsize = ap->a_tsize;
457 epp->ep_daddr = VM_MAXUSER_ADDRESS;
458 epp->ep_dsize = 0;
459 /* read section header */
460 sh = malloc(scnsiz, M_TEMP, M_WAITOK);
461 error = exec_read_from(l, epp->ep_vp, peofs + PECOFF_HDR_SIZE, sh,
462 scnsiz);
463 if (error) {
464 free(sh, M_TEMP);
465 return error;
466 }
467 /*
468 * map section
469 */
470 for (i = 0; i < fp->f_nscns; i++) {
471 int prot = /**/VM_PROT_WRITE;
472 long s_flags = sh[i].s_flags;
473
474 if ((s_flags & COFF_STYP_DISCARD) != 0)
475 continue;
476 sh[i].s_vaddr += wp->w_base; /* RVA --> VA */
477
478 if ((s_flags & COFF_STYP_TEXT) != 0) {
479 /* set up command for text segment */
480 /* DPRINTF(("COFF text addr %lx size %ld offset %ld\n",
481 sh[i].s_vaddr, sh[i].s_size, sh[i].s_scnptr));
482 */ pecoff_load_section(&epp->ep_vmcmds, epp->ep_vp,
483 &sh[i], (long *)&epp->ep_taddr,
484 &tsize, &prot);
485 } else if ((s_flags & COFF_STYP_BSS) != 0) {
486 /* set up command for bss segment */
487 baddr = sh[i].s_vaddr;
488 bsize = sh[i].s_paddr;
489 if (bsize)
490 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero,
491 bsize, baddr, NULLVP, 0,
492 VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
493 epp->ep_daddr = min(epp->ep_daddr, baddr);
494 bsize = baddr + bsize - epp->ep_daddr;
495 epp->ep_dsize = max(epp->ep_dsize, bsize);
496 } else if ((s_flags & (COFF_STYP_DATA|COFF_STYP_READ)) != 0) {
497 /* set up command for data segment */
498 /* DPRINTF(("COFF data addr %lx size %ld offset %ld\n",
499 sh[i].s_vaddr, sh[i].s_size, sh[i].s_scnptr));*/
500 pecoff_load_section(&epp->ep_vmcmds, epp->ep_vp,
501 &sh[i], &daddr, &dsize, &prot);
502 epp->ep_daddr = min(epp->ep_daddr, daddr);
503 dsize = daddr + dsize - epp->ep_daddr;
504 epp->ep_dsize = max(epp->ep_dsize, dsize);
505 }
506 }
507 /* set up ep_emul_arg */
508 argp = malloc(sizeof(struct pecoff_args), M_TEMP, M_WAITOK);
509 epp->ep_emul_arg = argp;
510 argp->a_abiversion = NETBSDPE_ABI_VERSION;
511 argp->a_zero = 0;
512 argp->a_entry = wp->w_base + ap->a_entry;
513 argp->a_end = epp->ep_daddr + epp->ep_dsize;
514 argp->a_opthdr = *wp;
515
516 /*
517 * load dynamic linker
518 */
519 error = pecoff_load_file(l, epp, "/usr/libexec/ld.so.dll",
520 &epp->ep_vmcmds, &epp->ep_entry, argp);
521 if (error) {
522 free(sh, M_TEMP);
523 return error;
524 }
525
526 #if 0
527 DPRINTF(("text addr: %lx size: %ld data addr: %lx size: %ld entry: %lx\n",
528 epp->ep_taddr, epp->ep_tsize,
529 epp->ep_daddr, epp->ep_dsize,
530 epp->ep_entry));
531 #endif
532
533 free(sh, M_TEMP);
534 return (*epp->ep_esch->es_setup_stack)(l, epp);
535 }
Cache object: 37f64d121517b746dcee40a5dc95c3a1
|