1 /* $NetBSD: pecoff_exec.c,v 1.37 2007/11/26 19:01:33 pooka Exp $ */
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
10 * from compat/ibcs2/ibcs2_exec.c
11 * originally from kern/exec_ecoff.c
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
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
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.
39 #include <sys/cdefs.h>
40 __KERNEL_RCSID(0, "$NetBSD: pecoff_exec.c,v 1.37 2007/11/26 19:01:33 pooka Exp $");
42 /*#define DEBUG_PECOFF*/
44 #include <sys/param.h>
46 #include <sys/malloc.h>
47 #include <sys/namei.h>
48 #include <sys/vnode.h>
49 #include <sys/mount.h>
51 #include <sys/syscall.h>
52 #include <sys/signalvar.h>
53 #include <sys/resourcevar.h>
56 #include <sys/exec_coff.h>
57 #include <machine/coff_machdep.h>
59 #include <compat/pecoff/pecoff_exec.h>
60 #include <compat/pecoff/pecoff_util.h>
62 int pecoff_signature (struct lwp
*l
, struct vnode
*vp
,
63 struct pecoff_dos_filehdr
*dp
);
64 int pecoff_load_file (struct lwp
*l
, struct exec_package
*epp
,
65 const char *path
, struct exec_vmcmd_set
*vcset
,
66 u_long
*entry
, struct pecoff_args
*argp
);
67 void pecoff_load_section (struct exec_vmcmd_set
*vcset
, struct vnode
*vp
,
68 struct coff_scnhdr
*sh
, long *addr
,
69 u_long
*size
, int *prot
);
70 int exec_pecoff_makecmds (struct lwp
*l
, struct exec_package
*epp
);
71 int exec_pecoff_coff_makecmds (struct lwp
*l
, struct exec_package
*epp
,
72 struct coff_filehdr
*fp
, int peofs
);
73 int exec_pecoff_prep_omagic (struct proc
*p
, struct exec_package
*epp
,
74 struct coff_filehdr
*fp
,
75 struct coff_aouthdr
*ap
, int peofs
);
76 int exec_pecoff_prep_nmagic (struct proc
*p
, struct exec_package
*epp
,
77 struct coff_filehdr
*fp
,
78 struct coff_aouthdr
*ap
, int peofs
);
79 int exec_pecoff_prep_zmagic (struct lwp
*l
, struct exec_package
*epp
,
80 struct coff_filehdr
*fp
,
81 struct coff_aouthdr
*ap
, int peofs
);
85 pecoff_copyargs(struct lwp
*l
, struct exec_package
*pack
, struct ps_strings
*arginfo
, char **stackp
, void *argp
)
87 int len
= sizeof(struct pecoff_args
);
88 struct pecoff_args
*ap
;
91 if ((error
= copyargs(l
, pack
, arginfo
, stackp
, argp
)) != 0)
94 ap
= (struct pecoff_args
*)pack
->ep_emul_arg
;
95 if ((error
= copyout(ap
, *stackp
, len
)) != 0)
98 #if 0 /* kern_exec.c? */
100 pack
->ep_emul_arg
= 0;
107 #define PECOFF_SIGNATURE "PE\0\0"
108 static const char signature
[] = PECOFF_SIGNATURE
;
111 * Check PE signature.
114 pecoff_signature(struct lwp
*l
, struct vnode
*vp
, struct pecoff_dos_filehdr
*dp
)
117 char tbuf
[sizeof(signature
) - 1];
119 if (DOS_BADMAG(dp
)) {
122 error
= exec_read_from(l
, vp
, dp
->d_peofs
, tbuf
, sizeof(tbuf
));
126 if (memcmp(tbuf
, signature
, sizeof(signature
) - 1) == 0) {
133 * load(mmap) file. for dynamic linker (ld.so.dll)
136 pecoff_load_file(struct lwp
*l
, struct exec_package
*epp
, const char *path
, struct exec_vmcmd_set
*vcset
, u_long
*entry
, struct pecoff_args
*argp
)
138 int error
, peofs
, scnsiz
, i
;
141 struct pecoff_dos_filehdr dh
;
142 struct coff_filehdr
*fp
= 0;
143 struct coff_aouthdr
*ap
;
144 struct pecoff_opthdr
*wp
;
145 struct coff_scnhdr
*sh
= 0;
147 error
= emul_find_interp(l
, epp
, path
);
152 epp
->ep_interp
= NULL
;
153 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
);
156 * If it's not marked as executable, or it's not a regular
157 * file, we don't allow it to be used.
159 if (vp
->v_type
!= VREG
) {
163 if ((error
= VOP_ACCESS(vp
, VEXEC
, l
->l_cred
)) != 0)
167 if ((error
= VOP_GETATTR(vp
, &attr
, l
->l_cred
)) != 0)
171 * Check mount point. Though we're not trying to exec this binary,
172 * we will be executing code from it, so if the mount point
173 * disallows execution or set-id-ness, we punt or kill the set-id.
175 if (vp
->v_mount
->mnt_flag
& MNT_NOEXEC
) {
179 if (vp
->v_mount
->mnt_flag
& MNT_NOSUID
)
180 epp
->ep_vap
->va_mode
&= ~(S_ISUID
| S_ISGID
);
182 if ((error
= vn_marktext(vp
)))
189 error
= exec_read_from(l
, vp
, 0, &dh
, sizeof(dh
));
192 if ((error
= pecoff_signature(l
, vp
, &dh
)) != 0)
194 fp
= malloc(PECOFF_HDR_SIZE
, M_TEMP
, M_WAITOK
);
195 peofs
= dh
.d_peofs
+ sizeof(signature
) - 1;
196 error
= exec_read_from(l
, vp
, peofs
, fp
, PECOFF_HDR_SIZE
);
199 if (COFF_BADMAG(fp
)) {
203 ap
= (void *)((char *)fp
+ sizeof(struct coff_filehdr
));
204 wp
= (void *)((char *)ap
+ sizeof(struct coff_aouthdr
));
205 /* read section header */
206 scnsiz
= sizeof(struct coff_scnhdr
) * fp
->f_nscns
;
207 sh
= malloc(scnsiz
, M_TEMP
, M_WAITOK
);
208 if ((error
= exec_read_from(l
, vp
, peofs
+ PECOFF_HDR_SIZE
, sh
,
213 * Read section header, and mmap.
215 for (i
= 0; i
< fp
->f_nscns
; i
++) {
220 if (sh
[i
].s_flags
& COFF_STYP_DISCARD
)
223 if ((sh
[i
].s_flags
& COFF_STYP_TEXT
) &&
224 (sh
[i
].s_flags
& COFF_STYP_EXEC
) == 0)
226 if ((sh
[i
].s_flags
& (COFF_STYP_TEXT
|COFF_STYP_DATA
|
227 COFF_STYP_BSS
|COFF_STYP_READ
)) == 0)
229 sh
[i
].s_vaddr
+= wp
->w_base
; /* RVA --> VA */
230 pecoff_load_section(vcset
, vp
, &sh
[i
], &addr
, &size
, &prot
);
232 *entry
= wp
->w_base
+ ap
->a_entry
;
233 argp
->a_ldbase
= wp
->w_base
;
234 argp
->a_ldexport
= wp
->w_imghdr
[0].i_vaddr
+ wp
->w_base
;
259 pecoff_load_section(struct exec_vmcmd_set
*vcset
, struct vnode
*vp
, struct coff_scnhdr
*sh
, long *addr
, u_long
*size
, int *prot
)
263 *addr
= COFF_ALIGN(sh
->s_vaddr
);
264 diff
= (sh
->s_vaddr
- *addr
);
265 offset
= sh
->s_scnptr
- diff
;
266 *size
= COFF_ROUND(sh
->s_size
+ diff
, COFF_LDPGSZ
);
268 *prot
|= (sh
->s_flags
& COFF_STYP_EXEC
) ? VM_PROT_EXECUTE
: 0;
269 *prot
|= (sh
->s_flags
& COFF_STYP_READ
) ? VM_PROT_READ
: 0;
270 *prot
|= (sh
->s_flags
& COFF_STYP_WRITE
) ? VM_PROT_WRITE
: 0;
272 if (diff
== 0 && offset
== COFF_ALIGN(offset
))
273 NEW_VMCMD(vcset
, vmcmd_map_pagedvn
, *size
, *addr
, vp
,
276 NEW_VMCMD(vcset
, vmcmd_map_readvn
, sh
->s_size
, sh
->s_vaddr
, vp
,
277 sh
->s_scnptr
, *prot
);
279 if (*size
< sh
->s_paddr
) {
282 baddr
= *addr
+ COFF_ROUND(*size
, COFF_LDPGSZ
);
283 bsize
= sh
->s_paddr
- COFF_ROUND(*size
, COFF_LDPGSZ
);
284 DPRINTF(("additional zero space (addr %lx size %ld)\n",
286 NEW_VMCMD(vcset
, vmcmd_map_zero
, bsize
, baddr
,
288 *size
= COFF_ROUND(sh
->s_paddr
, COFF_LDPGSZ
);
290 DPRINTF(("section %s loaded. (addr %lx size %ld prot %d)\n",
291 sh
->s_name
, sh
->s_vaddr
, sh
->s_size
, *prot
));
297 exec_pecoff_makecmds(struct lwp
*l
, struct exec_package
*epp
)
300 struct pecoff_dos_filehdr
*dp
= epp
->ep_hdr
;
301 struct coff_filehdr
*fp
;
306 * mmap EXE file (PE format)
307 * 1. read header (DOS,PE)
308 * 2. mmap code section (READ|EXEC)
309 * 3. mmap other section, such as data (READ|WRITE|EXEC)
311 if (epp
->ep_hdrvalid
< PECOFF_DOS_HDR_SIZE
) {
314 if ((error
= pecoff_signature(l
, epp
->ep_vp
, dp
)) != 0)
317 if ((error
= vn_marktext(epp
->ep_vp
)) != 0)
320 peofs
= dp
->d_peofs
+ sizeof(signature
) - 1;
321 fp
= malloc(PECOFF_HDR_SIZE
, M_TEMP
, M_WAITOK
);
322 error
= exec_read_from(l
, epp
->ep_vp
, peofs
, fp
, PECOFF_HDR_SIZE
);
327 error
= exec_pecoff_coff_makecmds(l
, epp
, fp
, peofs
);
330 kill_vmcmds(&epp
->ep_vmcmds
);
339 exec_pecoff_coff_makecmds(struct lwp
*l
, struct exec_package
*epp
, struct coff_filehdr
*fp
, int peofs
)
341 struct coff_aouthdr
*ap
;
345 if (COFF_BADMAG(fp
)) {
349 ap
= (void *)((char *)fp
+ sizeof(struct coff_filehdr
));
350 switch (ap
->a_magic
) {
352 error
= exec_pecoff_prep_omagic(p
, epp
, fp
, ap
, peofs
);
355 error
= exec_pecoff_prep_nmagic(p
, epp
, fp
, ap
, peofs
);
358 error
= exec_pecoff_prep_zmagic(l
, epp
, fp
, ap
, peofs
);
370 exec_pecoff_prep_omagic(struct proc
*p
,
371 struct exec_package
*epp
, struct coff_filehdr
*fp
,
372 struct coff_aouthdr
*ap
, int peofs
)
380 exec_pecoff_prep_nmagic(struct proc
*p
,
381 struct exec_package
*epp
, struct coff_filehdr
*fp
,
382 struct coff_aouthdr
*ap
, int peofs
)
390 exec_pecoff_prep_zmagic(struct lwp
*l
, struct exec_package
*epp
, struct coff_filehdr
*fp
, struct coff_aouthdr
*ap
, int peofs
)
393 struct pecoff_opthdr
*wp
;
394 long daddr
, baddr
, bsize
;
396 struct coff_scnhdr
*sh
;
397 struct pecoff_args
*argp
;
398 int scnsiz
= sizeof(struct coff_scnhdr
) * fp
->f_nscns
;
400 wp
= (void *)((char *)ap
+ sizeof(struct coff_aouthdr
));
402 epp
->ep_tsize
= ap
->a_tsize
;
403 epp
->ep_daddr
= VM_MAXUSER_ADDRESS
;
405 /* read section header */
406 sh
= malloc(scnsiz
, M_TEMP
, M_WAITOK
);
407 error
= exec_read_from(l
, epp
->ep_vp
, peofs
+ PECOFF_HDR_SIZE
, sh
,
416 for (i
= 0; i
< fp
->f_nscns
; i
++) {
417 int prot
= /*0*/VM_PROT_WRITE
;
418 long s_flags
= sh
[i
].s_flags
;
420 if ((s_flags
& COFF_STYP_DISCARD
) != 0)
422 sh
[i
].s_vaddr
+= wp
->w_base
; /* RVA --> VA */
424 if ((s_flags
& COFF_STYP_TEXT
) != 0) {
425 /* set up command for text segment */
426 /* DPRINTF(("COFF text addr %lx size %ld offset %ld\n",
427 sh[i].s_vaddr, sh[i].s_size, sh[i].s_scnptr));
428 */ pecoff_load_section(&epp
->ep_vmcmds
, epp
->ep_vp
,
429 &sh
[i
], (long *)&epp
->ep_taddr
,
431 } else if ((s_flags
& COFF_STYP_BSS
) != 0) {
432 /* set up command for bss segment */
433 baddr
= sh
[i
].s_vaddr
;
434 bsize
= sh
[i
].s_paddr
;
436 NEW_VMCMD(&epp
->ep_vmcmds
, vmcmd_map_zero
,
437 bsize
, baddr
, NULLVP
, 0,
438 VM_PROT_READ
|VM_PROT_WRITE
|VM_PROT_EXECUTE
);
439 epp
->ep_daddr
= min(epp
->ep_daddr
, baddr
);
440 bsize
= baddr
+ bsize
- epp
->ep_daddr
;
441 epp
->ep_dsize
= max(epp
->ep_dsize
, bsize
);
442 } else if ((s_flags
& (COFF_STYP_DATA
|COFF_STYP_READ
)) != 0) {
443 /* set up command for data segment */
444 /* DPRINTF(("COFF data addr %lx size %ld offset %ld\n",
445 sh[i].s_vaddr, sh[i].s_size, sh[i].s_scnptr));*/
446 pecoff_load_section(&epp
->ep_vmcmds
, epp
->ep_vp
,
447 &sh
[i
], &daddr
, &dsize
, &prot
);
448 epp
->ep_daddr
= min(epp
->ep_daddr
, daddr
);
449 dsize
= daddr
+ dsize
- epp
->ep_daddr
;
450 epp
->ep_dsize
= max(epp
->ep_dsize
, dsize
);
453 /* set up ep_emul_arg */
454 argp
= malloc(sizeof(struct pecoff_args
), M_TEMP
, M_WAITOK
);
455 epp
->ep_emul_arg
= argp
;
456 argp
->a_abiversion
= NETBSDPE_ABI_VERSION
;
458 argp
->a_entry
= wp
->w_base
+ ap
->a_entry
;
459 argp
->a_end
= epp
->ep_daddr
+ epp
->ep_dsize
;
460 argp
->a_opthdr
= *wp
;
463 * load dynamic linker
465 error
= pecoff_load_file(l
, epp
, "/usr/libexec/ld.so.dll",
466 &epp
->ep_vmcmds
, &epp
->ep_entry
, argp
);
473 DPRINTF(("text addr: %lx size: %ld data addr: %lx size: %ld entry: %lx\n",
474 epp
->ep_taddr
, epp
->ep_tsize
,
475 epp
->ep_daddr
, epp
->ep_dsize
,
480 return (*epp
->ep_esch
->es_setup_stack
)(l
, epp
);