1/*	$NetBSD: netbsd32_exec_aout.c,v 1.31 2021/01/19 03:20:13 simonb Exp $	*/
2/*	from: NetBSD: exec_aout.c,v 1.15 1996/09/26 23:34:46 cgd Exp */
3
4/*
5 * Copyright (c) 1998, 2001 Matthew R. Green.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
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
29/*
30 * Copyright (c) 1993, 1994 Christopher G. Demetriou
31 * All rights reserved.
32 *
33 * Redistribution and use in source and binary forms, with or without
34 * modification, are permitted provided that the following conditions
35 * are met:
36 * 1. Redistributions of source code must retain the above copyright
37 *    notice, this list of conditions and the following disclaimer.
38 * 2. Redistributions in binary form must reproduce the above copyright
39 *    notice, this list of conditions and the following disclaimer in the
40 *    documentation and/or other materials provided with the distribution.
41 * 3. All advertising materials mentioning features or use of this software
42 *    must display the following acknowledgement:
43 *      This product includes software developed by Christopher G. Demetriou.
44 * 4. The name of the author may not be used to endorse or promote products
45 *    derived from this software without specific prior written permission
46 *
47 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
48 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
49 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
50 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
51 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
52 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
53 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
54 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
55 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
56 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
57 */
58
59#include <sys/cdefs.h>
60__KERNEL_RCSID(0, "$NetBSD: netbsd32_exec_aout.c,v 1.31 2021/01/19 03:20:13 simonb Exp $");
61
62#include <sys/param.h>
63#include <sys/systm.h>
64#include <sys/proc.h>
65#include <sys/vnode.h>
66#include <sys/exec.h>
67#include <sys/exec_aout.h>
68#include <sys/resourcevar.h>
69#include <sys/signal.h>
70#include <sys/signalvar.h>
71
72#include <compat/netbsd32/netbsd32.h>
73#ifndef EXEC_AOUT
74#define EXEC_AOUT
75#endif
76#include <compat/netbsd32/netbsd32_exec.h>
77
78#include <machine/frame.h>
79#include <machine/netbsd32_machdep.h>
80
81#ifdef COMPAT_NOMID
82static int netbsd32_exec_aout_nomid(struct lwp *, struct exec_package *);
83#endif
84
85/*
86 * exec_netbsd32_makecmds(): Check if it's an netbsd32 a.out format
87 * executable.
88 *
89 * Given a lwp pointer and an exec package pointer, see if the referent
90 * of the epp is in netbsd32 a.out format.  Check 'standard' magic
91 * numbers for this architecture.
92 *
93 * This function, in the former case, or the hook, in the latter, is
94 * responsible for creating a set of vmcmds which can be used to build
95 * the process's vm space and inserting them into the exec package.
96 */
97
98int
99exec_netbsd32_makecmds(struct lwp *l, struct exec_package *epp)
100{
101	netbsd32_u_long midmag, magic;
102	u_short mid;
103	int error;
104	struct netbsd32_exec *execp = epp->ep_hdr;
105
106	if (epp->ep_hdrvalid < sizeof(struct netbsd32_exec))
107		return ENOEXEC;
108
109	midmag = (netbsd32_u_long)ntohl(execp->a_midmag);
110	mid = (midmag >> 16) & 0x3ff;
111	magic = midmag & 0xffff;
112
113	midmag = mid << 16 | magic;
114
115	/* this is already needed by setup_stack() */
116	epp->ep_flags |= EXEC_32;
117
118	switch (midmag) {
119	case (NETBSD32_MID_MACHINE << 16) | ZMAGIC:
120		error = netbsd32_exec_aout_prep_zmagic(l, epp);
121		break;
122	case (NETBSD32_MID_MACHINE << 16) | NMAGIC:
123		error = netbsd32_exec_aout_prep_nmagic(l, epp);
124		break;
125	case (NETBSD32_MID_MACHINE << 16) | OMAGIC:
126		error = netbsd32_exec_aout_prep_omagic(l, epp);
127		break;
128	default:
129#ifdef COMPAT_NOMID
130		error = netbsd32_exec_aout_nomid(l,  epp);
131#else
132		error = ENOEXEC;
133#endif
134		break;
135	}
136
137	if (error) {
138		kill_vmcmds(&epp->ep_vmcmds);
139		epp->ep_flags &= ~EXEC_32;
140	} else
141		epp->ep_flags &= ~EXEC_TOPDOWN_VM;
142	return error;
143}
144
145/*
146 * netbsd32_exec_aout_prep_zmagic(): Prepare a 'native' ZMAGIC binary's
147 * exec package
148 *
149 * First, set of the various offsets/lengths in the exec package.
150 *
151 * Then, mark the text image busy (so it can be demand paged) or error
152 * out if this is not possible.  Finally, set up vmcmds for the
153 * text, data, bss, and stack segments.
154 */
155
156int
157netbsd32_exec_aout_prep_zmagic(struct lwp *l, struct exec_package *epp)
158{
159	struct netbsd32_exec *execp = epp->ep_hdr;
160	int error;
161
162	epp->ep_taddr = AOUT_LDPGSZ;
163	epp->ep_tsize = execp->a_text;
164	epp->ep_daddr = epp->ep_taddr + execp->a_text;
165	epp->ep_dsize = execp->a_data + execp->a_bss;
166	epp->ep_entry = execp->a_entry;
167	epp->ep_vm_minaddr = exec_vm_minaddr(VM_MIN_ADDRESS);
168	epp->ep_vm_maxaddr = VM_MAXUSER_ADDRESS32;
169
170	error = vn_marktext(epp->ep_vp);
171	if (error)
172		return error;
173
174	/* set up command for text segment */
175	NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_pagedvn, execp->a_text,
176	    epp->ep_taddr, epp->ep_vp, 0, VM_PROT_READ|VM_PROT_EXECUTE);
177
178	/* set up command for data segment */
179	NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_pagedvn, execp->a_data,
180	    epp->ep_daddr, epp->ep_vp, execp->a_text,
181	    VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
182
183	/* set up command for bss segment */
184	if (execp->a_bss > 0)
185		NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, execp->a_bss,
186		    epp->ep_daddr + execp->a_data, NULLVP, 0,
187		    VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
188
189	return (*epp->ep_esch->es_setup_stack)(l, epp);
190}
191
192/*
193 * netbsd32_exec_aout_prep_nmagic(): Prepare a 'native' NMAGIC binary's
194 * exec package
195 */
196
197int
198netbsd32_exec_aout_prep_nmagic(struct lwp *l, struct exec_package *epp)
199{
200	struct netbsd32_exec *execp = epp->ep_hdr;
201	long bsize, baddr;
202
203	epp->ep_taddr = AOUT_LDPGSZ;
204	epp->ep_tsize = execp->a_text;
205	epp->ep_daddr = roundup(epp->ep_taddr + execp->a_text, AOUT_LDPGSZ);
206	epp->ep_dsize = execp->a_data + execp->a_bss;
207	epp->ep_entry = execp->a_entry;
208	epp->ep_vm_minaddr = exec_vm_minaddr(VM_MIN_ADDRESS);
209	epp->ep_vm_maxaddr = VM_MAXUSER_ADDRESS32;
210
211	/* set up command for text segment */
212	NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, execp->a_text,
213	    epp->ep_taddr, epp->ep_vp, sizeof(struct netbsd32_exec),
214	    VM_PROT_READ|VM_PROT_EXECUTE);
215
216	/* set up command for data segment */
217	NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, execp->a_data,
218	    epp->ep_daddr, epp->ep_vp, execp->a_text + sizeof(struct netbsd32_exec),
219	    VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
220
221	/* set up command for bss segment */
222	baddr = roundup(epp->ep_daddr + execp->a_data, PAGE_SIZE);
223	bsize = epp->ep_daddr + epp->ep_dsize - baddr;
224	if (bsize > 0)
225		NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, bsize, baddr,
226		    NULLVP, 0, VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
227
228	return (*epp->ep_esch->es_setup_stack)(l, epp);
229}
230
231/*
232 * netbsd32_exec_aout_prep_omagic(): Prepare a 'native' OMAGIC binary's
233 * exec package
234 */
235
236int
237netbsd32_exec_aout_prep_omagic(struct lwp *l, struct exec_package *epp)
238{
239	struct netbsd32_exec *execp = epp->ep_hdr;
240	long dsize, bsize, baddr;
241
242	epp->ep_taddr = AOUT_LDPGSZ;
243	epp->ep_tsize = execp->a_text;
244	epp->ep_daddr = epp->ep_taddr + execp->a_text;
245	epp->ep_dsize = execp->a_data + execp->a_bss;
246	epp->ep_entry = execp->a_entry;
247	epp->ep_vm_minaddr = exec_vm_minaddr(VM_MIN_ADDRESS);
248	epp->ep_vm_maxaddr = VM_MAXUSER_ADDRESS32;
249
250	/* set up command for text and data segments */
251	NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn,
252	    execp->a_text + execp->a_data, epp->ep_taddr, epp->ep_vp,
253	    sizeof(struct netbsd32_exec), VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
254
255	/* set up command for bss segment */
256	baddr = roundup(epp->ep_daddr + execp->a_data, PAGE_SIZE);
257	bsize = epp->ep_daddr + epp->ep_dsize - baddr;
258	if (bsize > 0)
259		NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, bsize, baddr,
260		    NULLVP, 0, VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
261
262	/*
263	 * Make sure (# of pages) mapped above equals (vm_tsize + vm_dsize);
264	 * obreak(2) relies on this fact. Both `vm_tsize' and `vm_dsize' are
265	 * computed (in execve(2)) by rounding *up* `ep_tsize' and `ep_dsize'
266	 * respectively to page boundaries.
267	 * Compensate `ep_dsize' for the amount of data covered by the last
268	 * text page.
269	 */
270	dsize = epp->ep_dsize + execp->a_text - roundup(execp->a_text,
271							PAGE_SIZE);
272	epp->ep_dsize = (dsize > 0) ? dsize : 0;
273	return (*epp->ep_esch->es_setup_stack)(l, epp);
274}
275
276#ifdef COMPAT_NOMID
277/*
278 * netbsd32_exec_aout_prep_oldzmagic():
279 *	Prepare the vmcmds to build a vmspace for an old ZMAGIC
280 *	binary. [386BSD/BSDI/4.4BSD/NetBSD0.8]
281 *
282 * Cloned from exec_aout_prep_zmagic() in kern/exec_aout.c; a more verbose
283 * description of operation is there.
284 * There were copies of this in the mac68k, hp300, and i386 ports.
285 */
286static int
287netbsd32_exec_aout_prep_oldzmagic(struct lwp *l, struct exec_package *epp)
288{
289	struct netbsd32_exec *execp = epp->ep_hdr;
290	int error;
291
292	epp->ep_taddr = 0;
293	epp->ep_tsize = execp->a_text;
294	epp->ep_daddr = epp->ep_taddr + execp->a_text;
295	epp->ep_dsize = execp->a_data + execp->a_bss;
296	epp->ep_entry = execp->a_entry;
297	epp->ep_vm_minaddr = exec_vm_minaddr(VM_MIN_ADDRESS);
298	epp->ep_vm_maxaddr = VM_MAXUSER_ADDRESS32;
299
300	error = vn_marktext(epp->ep_vp);
301	if (error)
302		return error;
303
304	/* set up command for text segment */
305	NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_pagedvn, execp->a_text,
306	    epp->ep_taddr, epp->ep_vp, PAGE_SIZE, /* XXX CLBYTES? */
307	    VM_PROT_READ|VM_PROT_EXECUTE);
308
309	/* set up command for data segment */
310	NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_pagedvn, execp->a_data,
311	    epp->ep_daddr, epp->ep_vp,
312	    execp->a_text + PAGE_SIZE, /* XXX CLBYTES? */
313	    VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
314
315	/* set up command for bss segment */
316	if (execp->a_bss)
317	    NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, execp->a_bss,
318		epp->ep_daddr + execp->a_data, NULLVP, 0,
319		VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
320
321	return (*epp->ep_esch->es_setup_stack)(l, epp);
322}
323
324
325/*
326 * netbsd32_exec_aout_prep_oldnmagic():
327 *	Prepare the vmcmds to build a vmspace for an old NMAGIC
328 *	binary. [BSDI]
329 *
330 * Cloned from exec_aout_prep_nmagic() in kern/exec_aout.c; with text starting
331 * at 0.
332 * XXX: There must be a better way to share this code.
333 */
334static int
335netbsd32_exec_aout_prep_oldnmagic(struct lwp *l, struct exec_package *epp)
336{
337	struct netbsd32_exec *execp = epp->ep_hdr;
338	long bsize, baddr;
339
340	epp->ep_taddr = 0;
341	epp->ep_tsize = execp->a_text;
342	epp->ep_daddr = roundup(epp->ep_taddr + execp->a_text, AOUT_LDPGSZ);
343	epp->ep_dsize = execp->a_data + execp->a_bss;
344	epp->ep_entry = execp->a_entry;
345	epp->ep_vm_minaddr = exec_vm_minaddr(VM_MIN_ADDRESS);
346	epp->ep_vm_maxaddr = VM_MAXUSER_ADDRESS32;
347
348	/* set up command for text segment */
349	NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, execp->a_text,
350	    epp->ep_taddr, epp->ep_vp, sizeof(struct netbsd32_exec),
351	    VM_PROT_READ|VM_PROT_EXECUTE);
352
353	/* set up command for data segment */
354	NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, execp->a_data,
355	    epp->ep_daddr, epp->ep_vp, execp->a_text + sizeof(struct netbsd32_exec),
356	    VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
357
358	/* set up command for bss segment */
359	baddr = roundup(epp->ep_daddr + execp->a_data, PAGE_SIZE);
360	bsize = epp->ep_daddr + epp->ep_dsize - baddr;
361	if (bsize > 0)
362		NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, bsize, baddr,
363		    NULLVP, 0, VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
364
365	return (*epp->ep_esch->es_setup_stack)(l, epp);
366}
367
368
369/*
370 * netbsd32_exec_aout_prep_oldomagic():
371 *	Prepare the vmcmds to build a vmspace for an old OMAGIC
372 *	binary. [BSDI]
373 *
374 * Cloned from exec_aout_prep_omagic() in kern/exec_aout.c; with text starting
375 * at 0.
376 * XXX: There must be a better way to share this code.
377 */
378static int
379netbsd32_exec_aout_prep_oldomagic(struct lwp *l, struct exec_package *epp)
380{
381	struct netbsd32_exec *execp = epp->ep_hdr;
382	long dsize, bsize, baddr;
383
384	epp->ep_taddr = 0;
385	epp->ep_tsize = execp->a_text;
386	epp->ep_daddr = epp->ep_taddr + execp->a_text;
387	epp->ep_dsize = execp->a_data + execp->a_bss;
388	epp->ep_entry = execp->a_entry;
389
390	/* set up command for text and data segments */
391	NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn,
392	    execp->a_text + execp->a_data, epp->ep_taddr, epp->ep_vp,
393	    sizeof(struct netbsd32_exec), VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
394
395	/* set up command for bss segment */
396	baddr = roundup(epp->ep_daddr + execp->a_data, PAGE_SIZE);
397	bsize = epp->ep_daddr + epp->ep_dsize - baddr;
398	if (bsize > 0)
399		NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, bsize, baddr,
400		    NULLVP, 0, VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
401
402	/*
403	 * Make sure (# of pages) mapped above equals (vm_tsize + vm_dsize);
404	 * obreak(2) relies on this fact. Both `vm_tsize' and `vm_dsize' are
405	 * computed (in execve(2)) by rounding *up* `ep_tsize' and `ep_dsize'
406	 * respectively to page boundaries.
407	 * Compensate `ep_dsize' for the amount of data covered by the last
408	 * text page.
409	 */
410	dsize = epp->ep_dsize + execp->a_text - roundup(execp->a_text,
411							PAGE_SIZE);
412	epp->ep_dsize = (dsize > 0) ? dsize : 0;
413	return (*epp->ep_esch->es_setup_stack)(l, epp);
414}
415
416static int
417netbsd32_exec_aout_nomid(struct lwp *l, struct exec_package *epp)
418{
419	int error;
420	u_long midmag, magic;
421	u_short mid;
422	struct exec *execp = epp->ep_hdr;
423
424	/* check on validity of epp->ep_hdr performed by exec_out_makecmds */
425
426	midmag = ntohl(execp->a_midmag);
427	mid = (midmag >> 16) & 0xffff;
428	magic = midmag & 0xffff;
429
430	if (magic == 0) {
431		magic = (execp->a_midmag & 0xffff);
432		mid = MID_ZERO;
433	}
434
435	midmag = mid << 16 | magic;
436
437	switch (midmag) {
438	case (MID_ZERO << 16) | ZMAGIC:
439		/*
440		 * 386BSD's ZMAGIC format:
441		 */
442		return netbsd32_exec_aout_prep_oldzmagic(l, epp);
443		break;
444
445	case (MID_ZERO << 16) | QMAGIC:
446		/*
447		 * BSDI's QMAGIC format:
448		 * same as new ZMAGIC format, but with different magic number
449		 */
450		return netbsd32_exec_aout_prep_zmagic(l, epp);
451		break;
452
453	case (MID_ZERO << 16) | NMAGIC:
454		/*
455		 * BSDI's NMAGIC format:
456		 * same as NMAGIC format, but with different magic number
457		 * and with text starting at 0.
458		 */
459		return netbsd32_exec_aout_prep_oldnmagic(l, epp);
460
461	case (MID_ZERO << 16) | OMAGIC:
462		/*
463		 * BSDI's OMAGIC format:
464		 * same as OMAGIC format, but with different magic number
465		 * and with text starting at 0.
466		 */
467		return netbsd32_exec_aout_prep_oldomagic(l, epp);
468
469	default:
470		return ENOEXEC;
471	}
472
473	return error;
474}
475#endif
476