Deleted Added
full compact
imgact_aout.c (102808) imgact_aout.c (103047)
1/*
2 * Copyright (c) 1993, David Greenman
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 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
1/*
2 * Copyright (c) 1993, David Greenman
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 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD: head/sys/kern/imgact_aout.c 102808 2002-09-01 21:41:24Z jake $
26 * $FreeBSD: head/sys/kern/imgact_aout.c 103047 2002-09-07 01:23:51Z peter $
27 */
28
29#include "opt_kstack_pages.h"
30
31#include <sys/param.h>
32#include <sys/exec.h>
33#include <sys/fcntl.h>
34#include <sys/imgact.h>
35#include <sys/imgact_aout.h>
36#include <sys/kernel.h>
37#include <sys/lock.h>
38#include <sys/mutex.h>
39#include <sys/namei.h>
40#include <sys/pioctl.h>
41#include <sys/proc.h>
42#include <sys/resourcevar.h>
43#include <sys/systm.h>
44#include <sys/signalvar.h>
45#include <sys/stat.h>
46#include <sys/sysent.h>
47#include <sys/syscall.h>
48#include <sys/vnode.h>
49#include <sys/user.h>
50
51#include <machine/md_var.h>
27 */
28
29#include "opt_kstack_pages.h"
30
31#include <sys/param.h>
32#include <sys/exec.h>
33#include <sys/fcntl.h>
34#include <sys/imgact.h>
35#include <sys/imgact_aout.h>
36#include <sys/kernel.h>
37#include <sys/lock.h>
38#include <sys/mutex.h>
39#include <sys/namei.h>
40#include <sys/pioctl.h>
41#include <sys/proc.h>
42#include <sys/resourcevar.h>
43#include <sys/systm.h>
44#include <sys/signalvar.h>
45#include <sys/stat.h>
46#include <sys/sysent.h>
47#include <sys/syscall.h>
48#include <sys/vnode.h>
49#include <sys/user.h>
50
51#include <machine/md_var.h>
52#include <machine/frame.h>
52
53#include <vm/vm.h>
54#include <vm/vm_param.h>
55#include <vm/pmap.h>
56#include <vm/vm_map.h>
57#include <vm/vm_object.h>
58
59static int exec_aout_imgact(struct image_params *imgp);
60static int aout_fixup(register_t **stack_base, struct image_params *imgp);
61
62struct sysentvec aout_sysvec = {
63 SYS_MAXSYSCALL,
64 sysent,
65 0,
66 0,
67 NULL,
68 0,
69 NULL,
70 NULL,
71 aout_fixup,
72 sendsig,
73 sigcode,
74 &szsigcode,
75 NULL,
76 "FreeBSD a.out",
77 aout_coredump,
78 NULL,
79 MINSIGSTKSZ,
80 PAGE_SIZE,
81 VM_MIN_ADDRESS,
82 VM_MAXUSER_ADDRESS,
83 USRSTACK,
84 PS_STRINGS,
85 VM_PROT_ALL,
86 exec_copyout_strings,
87 exec_setregs
88};
89
90static int
91aout_fixup(stack_base, imgp)
92 register_t **stack_base;
93 struct image_params *imgp;
94{
95
96 return (suword(--(*stack_base), imgp->argc));
97}
98
99static int
100exec_aout_imgact(imgp)
101 struct image_params *imgp;
102{
103 const struct exec *a_out = (const struct exec *) imgp->image_header;
104 struct vmspace *vmspace;
105 struct vnode *vp;
106 vm_map_t map;
107 vm_object_t object;
108 vm_offset_t text_end, data_end;
109 unsigned long virtual_offset;
110 unsigned long file_offset;
111 unsigned long bss_size;
112 int error;
113
114 GIANT_REQUIRED;
115
116 /*
117 * Linux and *BSD binaries look very much alike,
118 * only the machine id is different:
119 * 0x64 for Linux, 0x86 for *BSD, 0x00 for BSDI.
120 * NetBSD is in network byte order.. ugh.
121 */
122 if (((a_out->a_magic >> 16) & 0xff) != 0x86 &&
123 ((a_out->a_magic >> 16) & 0xff) != 0 &&
124 ((((int)ntohl(a_out->a_magic)) >> 16) & 0xff) != 0x86)
125 return -1;
126
127 /*
128 * Set file/virtual offset based on a.out variant.
129 * We do two cases: host byte order and network byte order
130 * (for NetBSD compatibility)
131 */
132 switch ((int)(a_out->a_magic & 0xffff)) {
133 case ZMAGIC:
134 virtual_offset = 0;
135 if (a_out->a_text) {
136 file_offset = PAGE_SIZE;
137 } else {
138 /* Bill's "screwball mode" */
139 file_offset = 0;
140 }
141 break;
142 case QMAGIC:
143 virtual_offset = PAGE_SIZE;
144 file_offset = 0;
145 /* Pass PS_STRINGS for BSD/OS binaries only. */
146 if (N_GETMID(*a_out) == MID_ZERO)
147 imgp->ps_strings = PS_STRINGS;
148 break;
149 default:
150 /* NetBSD compatibility */
151 switch ((int)(ntohl(a_out->a_magic) & 0xffff)) {
152 case ZMAGIC:
153 case QMAGIC:
154 virtual_offset = PAGE_SIZE;
155 file_offset = 0;
156 break;
157 default:
158 return (-1);
159 }
160 }
161
162 bss_size = roundup(a_out->a_bss, PAGE_SIZE);
163
164 /*
165 * Check various fields in header for validity/bounds.
166 */
167 if (/* entry point must lay with text region */
168 a_out->a_entry < virtual_offset ||
169 a_out->a_entry >= virtual_offset + a_out->a_text ||
170
171 /* text and data size must each be page rounded */
172 a_out->a_text & PAGE_MASK || a_out->a_data & PAGE_MASK)
173 return (-1);
174
175 /* text + data can't exceed file size */
176 if (a_out->a_data + a_out->a_text > imgp->attr->va_size)
177 return (EFAULT);
178
179 /*
180 * text/data/bss must not exceed limits
181 */
182 mtx_assert(&Giant, MA_OWNED);
183 if (/* text can't exceed maximum text size */
184 a_out->a_text > maxtsiz ||
185
186 /* data + bss can't exceed rlimit */
187 a_out->a_data + bss_size >
188 imgp->proc->p_rlimit[RLIMIT_DATA].rlim_cur)
189 return (ENOMEM);
190
191 /* copy in arguments and/or environment from old process */
192 error = exec_extract_strings(imgp);
193 if (error)
194 return (error);
195
196 /*
197 * Destroy old process VM and create a new one (with a new stack)
198 */
199 exec_new_vmspace(imgp, VM_MIN_ADDRESS, VM_MAXUSER_ADDRESS, USRSTACK);
200
201 /*
202 * The vm space can be changed by exec_new_vmspace
203 */
204 vmspace = imgp->proc->p_vmspace;
205
206 vp = imgp->vp;
207 object = imgp->object;
208 map = &vmspace->vm_map;
209 vm_map_lock(map);
210 vm_object_reference(object);
211
212 text_end = virtual_offset + a_out->a_text;
213 error = vm_map_insert(map, object,
214 file_offset,
215 virtual_offset, text_end,
216 VM_PROT_READ | VM_PROT_EXECUTE, VM_PROT_ALL,
217 MAP_COPY_ON_WRITE | MAP_PREFAULT);
218 if (error) {
219 vm_map_unlock(map);
220 return (error);
221 }
222 data_end = text_end + a_out->a_data;
223 if (a_out->a_data) {
224 vm_object_reference(object);
225 error = vm_map_insert(map, object,
226 file_offset + a_out->a_text,
227 text_end, data_end,
228 VM_PROT_ALL, VM_PROT_ALL,
229 MAP_COPY_ON_WRITE | MAP_PREFAULT);
230 if (error) {
231 vm_map_unlock(map);
232 return (error);
233 }
234 }
235
236 if (bss_size) {
237 error = vm_map_insert(map, NULL, 0,
238 data_end, data_end + bss_size,
239 VM_PROT_ALL, VM_PROT_ALL, 0);
240 if (error) {
241 vm_map_unlock(map);
242 return (error);
243 }
244 }
245 vm_map_unlock(map);
246
247 /* Fill in process VM information */
248 vmspace->vm_tsize = a_out->a_text >> PAGE_SHIFT;
249 vmspace->vm_dsize = (a_out->a_data + bss_size) >> PAGE_SHIFT;
250 vmspace->vm_taddr = (caddr_t) (uintptr_t) virtual_offset;
251 vmspace->vm_daddr = (caddr_t) (uintptr_t)
252 (virtual_offset + a_out->a_text);
253
254 /* Fill in image_params */
255 imgp->interpreted = 0;
256 imgp->entry_addr = a_out->a_entry;
257
258 imgp->proc->p_sysent = &aout_sysvec;
259
260 return (0);
261}
262
263/*
264 * Dump core, into a file named as described in the comments for
265 * expand_name(), unless the process was setuid/setgid.
266 */
267int
268aout_coredump(td, vp, limit)
269 register struct thread *td;
270 register struct vnode *vp;
271 off_t limit;
272{
273 struct proc *p = td->td_proc;
274 register struct ucred *cred = td->td_ucred;
275 register struct vmspace *vm = p->p_vmspace;
53
54#include <vm/vm.h>
55#include <vm/vm_param.h>
56#include <vm/pmap.h>
57#include <vm/vm_map.h>
58#include <vm/vm_object.h>
59
60static int exec_aout_imgact(struct image_params *imgp);
61static int aout_fixup(register_t **stack_base, struct image_params *imgp);
62
63struct sysentvec aout_sysvec = {
64 SYS_MAXSYSCALL,
65 sysent,
66 0,
67 0,
68 NULL,
69 0,
70 NULL,
71 NULL,
72 aout_fixup,
73 sendsig,
74 sigcode,
75 &szsigcode,
76 NULL,
77 "FreeBSD a.out",
78 aout_coredump,
79 NULL,
80 MINSIGSTKSZ,
81 PAGE_SIZE,
82 VM_MIN_ADDRESS,
83 VM_MAXUSER_ADDRESS,
84 USRSTACK,
85 PS_STRINGS,
86 VM_PROT_ALL,
87 exec_copyout_strings,
88 exec_setregs
89};
90
91static int
92aout_fixup(stack_base, imgp)
93 register_t **stack_base;
94 struct image_params *imgp;
95{
96
97 return (suword(--(*stack_base), imgp->argc));
98}
99
100static int
101exec_aout_imgact(imgp)
102 struct image_params *imgp;
103{
104 const struct exec *a_out = (const struct exec *) imgp->image_header;
105 struct vmspace *vmspace;
106 struct vnode *vp;
107 vm_map_t map;
108 vm_object_t object;
109 vm_offset_t text_end, data_end;
110 unsigned long virtual_offset;
111 unsigned long file_offset;
112 unsigned long bss_size;
113 int error;
114
115 GIANT_REQUIRED;
116
117 /*
118 * Linux and *BSD binaries look very much alike,
119 * only the machine id is different:
120 * 0x64 for Linux, 0x86 for *BSD, 0x00 for BSDI.
121 * NetBSD is in network byte order.. ugh.
122 */
123 if (((a_out->a_magic >> 16) & 0xff) != 0x86 &&
124 ((a_out->a_magic >> 16) & 0xff) != 0 &&
125 ((((int)ntohl(a_out->a_magic)) >> 16) & 0xff) != 0x86)
126 return -1;
127
128 /*
129 * Set file/virtual offset based on a.out variant.
130 * We do two cases: host byte order and network byte order
131 * (for NetBSD compatibility)
132 */
133 switch ((int)(a_out->a_magic & 0xffff)) {
134 case ZMAGIC:
135 virtual_offset = 0;
136 if (a_out->a_text) {
137 file_offset = PAGE_SIZE;
138 } else {
139 /* Bill's "screwball mode" */
140 file_offset = 0;
141 }
142 break;
143 case QMAGIC:
144 virtual_offset = PAGE_SIZE;
145 file_offset = 0;
146 /* Pass PS_STRINGS for BSD/OS binaries only. */
147 if (N_GETMID(*a_out) == MID_ZERO)
148 imgp->ps_strings = PS_STRINGS;
149 break;
150 default:
151 /* NetBSD compatibility */
152 switch ((int)(ntohl(a_out->a_magic) & 0xffff)) {
153 case ZMAGIC:
154 case QMAGIC:
155 virtual_offset = PAGE_SIZE;
156 file_offset = 0;
157 break;
158 default:
159 return (-1);
160 }
161 }
162
163 bss_size = roundup(a_out->a_bss, PAGE_SIZE);
164
165 /*
166 * Check various fields in header for validity/bounds.
167 */
168 if (/* entry point must lay with text region */
169 a_out->a_entry < virtual_offset ||
170 a_out->a_entry >= virtual_offset + a_out->a_text ||
171
172 /* text and data size must each be page rounded */
173 a_out->a_text & PAGE_MASK || a_out->a_data & PAGE_MASK)
174 return (-1);
175
176 /* text + data can't exceed file size */
177 if (a_out->a_data + a_out->a_text > imgp->attr->va_size)
178 return (EFAULT);
179
180 /*
181 * text/data/bss must not exceed limits
182 */
183 mtx_assert(&Giant, MA_OWNED);
184 if (/* text can't exceed maximum text size */
185 a_out->a_text > maxtsiz ||
186
187 /* data + bss can't exceed rlimit */
188 a_out->a_data + bss_size >
189 imgp->proc->p_rlimit[RLIMIT_DATA].rlim_cur)
190 return (ENOMEM);
191
192 /* copy in arguments and/or environment from old process */
193 error = exec_extract_strings(imgp);
194 if (error)
195 return (error);
196
197 /*
198 * Destroy old process VM and create a new one (with a new stack)
199 */
200 exec_new_vmspace(imgp, VM_MIN_ADDRESS, VM_MAXUSER_ADDRESS, USRSTACK);
201
202 /*
203 * The vm space can be changed by exec_new_vmspace
204 */
205 vmspace = imgp->proc->p_vmspace;
206
207 vp = imgp->vp;
208 object = imgp->object;
209 map = &vmspace->vm_map;
210 vm_map_lock(map);
211 vm_object_reference(object);
212
213 text_end = virtual_offset + a_out->a_text;
214 error = vm_map_insert(map, object,
215 file_offset,
216 virtual_offset, text_end,
217 VM_PROT_READ | VM_PROT_EXECUTE, VM_PROT_ALL,
218 MAP_COPY_ON_WRITE | MAP_PREFAULT);
219 if (error) {
220 vm_map_unlock(map);
221 return (error);
222 }
223 data_end = text_end + a_out->a_data;
224 if (a_out->a_data) {
225 vm_object_reference(object);
226 error = vm_map_insert(map, object,
227 file_offset + a_out->a_text,
228 text_end, data_end,
229 VM_PROT_ALL, VM_PROT_ALL,
230 MAP_COPY_ON_WRITE | MAP_PREFAULT);
231 if (error) {
232 vm_map_unlock(map);
233 return (error);
234 }
235 }
236
237 if (bss_size) {
238 error = vm_map_insert(map, NULL, 0,
239 data_end, data_end + bss_size,
240 VM_PROT_ALL, VM_PROT_ALL, 0);
241 if (error) {
242 vm_map_unlock(map);
243 return (error);
244 }
245 }
246 vm_map_unlock(map);
247
248 /* Fill in process VM information */
249 vmspace->vm_tsize = a_out->a_text >> PAGE_SHIFT;
250 vmspace->vm_dsize = (a_out->a_data + bss_size) >> PAGE_SHIFT;
251 vmspace->vm_taddr = (caddr_t) (uintptr_t) virtual_offset;
252 vmspace->vm_daddr = (caddr_t) (uintptr_t)
253 (virtual_offset + a_out->a_text);
254
255 /* Fill in image_params */
256 imgp->interpreted = 0;
257 imgp->entry_addr = a_out->a_entry;
258
259 imgp->proc->p_sysent = &aout_sysvec;
260
261 return (0);
262}
263
264/*
265 * Dump core, into a file named as described in the comments for
266 * expand_name(), unless the process was setuid/setgid.
267 */
268int
269aout_coredump(td, vp, limit)
270 register struct thread *td;
271 register struct vnode *vp;
272 off_t limit;
273{
274 struct proc *p = td->td_proc;
275 register struct ucred *cred = td->td_ucred;
276 register struct vmspace *vm = p->p_vmspace;
277 caddr_t tempuser;
276 int error;
277
278 if (ctob((UAREA_PAGES + KSTACK_PAGES)
279 + vm->vm_dsize + vm->vm_ssize) >= limit)
280 return (EFAULT);
278 int error;
279
280 if (ctob((UAREA_PAGES + KSTACK_PAGES)
281 + vm->vm_dsize + vm->vm_ssize) >= limit)
282 return (EFAULT);
283 tempuser = malloc(ctob(UAREA_PAGES + KSTACK_PAGES), M_TEMP,
284 M_WAITOK | M_ZERO);
285 if (tempuser == NULL)
286 return (ENOMEM);
287 bcopy(p->p_uarea, tempuser, sizeof(struct user));
288 bcopy(td->td_frame,
289 tempuser + ctob(UAREA_PAGES) +
290 ((caddr_t) td->td_frame - (caddr_t) td->td_kstack),
291 sizeof(struct trapframe));
281 PROC_LOCK(p);
282 fill_kinfo_proc(p, &p->p_uarea->u_kproc);
283 PROC_UNLOCK(p);
292 PROC_LOCK(p);
293 fill_kinfo_proc(p, &p->p_uarea->u_kproc);
294 PROC_UNLOCK(p);
284 error = cpu_coredump(td, vp, cred);
295 error = vn_rdwr(UIO_WRITE, vp, (caddr_t) tempuser,
296 ctob(UAREA_PAGES + KSTACK_PAGES),
297 (off_t)0, UIO_SYSSPACE, IO_UNIT, cred, NOCRED,
298 (int *)NULL, td);
299 free(tempuser, M_TEMP);
285 if (error == 0)
286 error = vn_rdwr(UIO_WRITE, vp, vm->vm_daddr,
287 (int)ctob(vm->vm_dsize),
288 (off_t)ctob(UAREA_PAGES + KSTACK_PAGES), UIO_USERSPACE,
289 IO_UNIT | IO_DIRECT, cred, NOCRED, (int *) NULL, td);
290 if (error == 0)
291 error = vn_rdwr_inchunks(UIO_WRITE, vp,
292 (caddr_t) trunc_page(USRSTACK - ctob(vm->vm_ssize)),
293 round_page(ctob(vm->vm_ssize)),
294 (off_t)ctob(UAREA_PAGES + KSTACK_PAGES) +
295 ctob(vm->vm_dsize), UIO_USERSPACE,
296 IO_UNIT | IO_DIRECT, cred, NOCRED, (int *) NULL, td);
297 return (error);
298}
299
300/*
301 * Tell kern_execve.c about it, with a little help from the linker.
302 */
303static struct execsw aout_execsw = { exec_aout_imgact, "a.out" };
304EXEC_SET(aout, aout_execsw);
300 if (error == 0)
301 error = vn_rdwr(UIO_WRITE, vp, vm->vm_daddr,
302 (int)ctob(vm->vm_dsize),
303 (off_t)ctob(UAREA_PAGES + KSTACK_PAGES), UIO_USERSPACE,
304 IO_UNIT | IO_DIRECT, cred, NOCRED, (int *) NULL, td);
305 if (error == 0)
306 error = vn_rdwr_inchunks(UIO_WRITE, vp,
307 (caddr_t) trunc_page(USRSTACK - ctob(vm->vm_ssize)),
308 round_page(ctob(vm->vm_ssize)),
309 (off_t)ctob(UAREA_PAGES + KSTACK_PAGES) +
310 ctob(vm->vm_dsize), UIO_USERSPACE,
311 IO_UNIT | IO_DIRECT, cred, NOCRED, (int *) NULL, td);
312 return (error);
313}
314
315/*
316 * Tell kern_execve.c about it, with a little help from the linker.
317 */
318static struct execsw aout_execsw = { exec_aout_imgact, "a.out" };
319EXEC_SET(aout, aout_execsw);