Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/kern/imgact_aout.c
39475 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 1993, David Greenman
5
* All rights reserved.
6
*
7
* Redistribution and use in source and binary forms, with or without
8
* modification, are permitted provided that the following conditions
9
* are met:
10
* 1. Redistributions of source code must retain the above copyright
11
* notice, this list of conditions and the following disclaimer.
12
* 2. Redistributions in binary form must reproduce the above copyright
13
* notice, this list of conditions and the following disclaimer in the
14
* documentation and/or other materials provided with the distribution.
15
*
16
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26
* SUCH DAMAGE.
27
*/
28
29
#include <sys/param.h>
30
#include <sys/exec.h>
31
#include <sys/imgact.h>
32
#include <sys/imgact_aout.h>
33
#include <sys/kernel.h>
34
#include <sys/limits.h>
35
#include <sys/lock.h>
36
#include <sys/malloc.h>
37
#include <sys/mutex.h>
38
#include <sys/proc.h>
39
#include <sys/racct.h>
40
#include <sys/resourcevar.h>
41
#include <sys/signalvar.h>
42
#include <sys/syscall.h>
43
#include <sys/sysent.h>
44
#include <sys/systm.h>
45
#include <sys/vnode.h>
46
47
#include <machine/frame.h>
48
#include <machine/md_var.h>
49
50
#include <vm/vm.h>
51
#include <vm/pmap.h>
52
#include <vm/vm_map.h>
53
#include <vm/vm_object.h>
54
#include <vm/vm_param.h>
55
56
#ifdef __amd64__
57
#include <compat/freebsd32/freebsd32_signal.h>
58
#include <compat/freebsd32/freebsd32_util.h>
59
#include <compat/freebsd32/freebsd32_proto.h>
60
#include <compat/freebsd32/freebsd32_syscall.h>
61
#include <compat/ia32/ia32_signal.h>
62
#endif
63
64
static int exec_aout_imgact(struct image_params *imgp);
65
static int aout_fixup(uintptr_t *stack_base, struct image_params *imgp);
66
67
#define AOUT32_USRSTACK 0xbfc00000
68
69
#if defined(__i386__)
70
71
#define AOUT32_PS_STRINGS (AOUT32_USRSTACK - sizeof(struct ps_strings))
72
73
struct sysentvec aout_sysvec = {
74
.sv_size = SYS_MAXSYSCALL,
75
.sv_table = sysent,
76
.sv_fixup = aout_fixup,
77
.sv_sendsig = sendsig,
78
.sv_sigcode = sigcode,
79
.sv_szsigcode = &szsigcode,
80
.sv_name = "FreeBSD a.out",
81
.sv_coredump = NULL,
82
.sv_minsigstksz = MINSIGSTKSZ,
83
.sv_minuser = VM_MIN_ADDRESS,
84
.sv_maxuser = AOUT32_USRSTACK,
85
.sv_usrstack = AOUT32_USRSTACK,
86
.sv_psstrings = AOUT32_PS_STRINGS,
87
.sv_psstringssz = sizeof(struct ps_strings),
88
.sv_stackprot = VM_PROT_ALL,
89
.sv_copyout_strings = exec_copyout_strings,
90
.sv_setregs = exec_setregs,
91
.sv_fixlimit = NULL,
92
.sv_maxssiz = NULL,
93
.sv_flags = SV_ABI_FREEBSD | SV_AOUT | SV_ILP32 | SV_SIGSYS,
94
.sv_set_syscall_retval = cpu_set_syscall_retval,
95
.sv_fetch_syscall_args = cpu_fetch_syscall_args,
96
.sv_syscallnames = syscallnames,
97
.sv_schedtail = NULL,
98
.sv_thread_detach = NULL,
99
.sv_trap = NULL,
100
.sv_onexec_old = exec_onexec_old,
101
.sv_onexit = exit_onexit,
102
.sv_set_fork_retval = x86_set_fork_retval,
103
};
104
105
#elif defined(__amd64__)
106
107
#include "vdso_ia32_offsets.h"
108
109
extern const char _binary_elf_vdso32_so_1_start[];
110
extern const char _binary_elf_vdso32_so_1_end[];
111
extern char _binary_elf_vdso32_so_1_size;
112
113
#define AOUT32_PS_STRINGS \
114
(AOUT32_USRSTACK - sizeof(struct freebsd32_ps_strings))
115
#define AOUT32_MINUSER FREEBSD32_MINUSER
116
117
extern const char *freebsd32_syscallnames[];
118
extern u_long ia32_maxssiz;
119
120
static int aout_szsigcode;
121
122
struct sysentvec aout_sysvec = {
123
.sv_size = FREEBSD32_SYS_MAXSYSCALL,
124
.sv_table = freebsd32_sysent,
125
.sv_fixup = aout_fixup,
126
.sv_sendsig = ia32_sendsig,
127
.sv_sigcode = _binary_elf_vdso32_so_1_start,
128
.sv_szsigcode = &aout_szsigcode,
129
.sv_name = "FreeBSD a.out",
130
.sv_coredump = NULL,
131
.sv_minsigstksz = MINSIGSTKSZ,
132
.sv_minuser = AOUT32_MINUSER,
133
.sv_maxuser = AOUT32_USRSTACK,
134
.sv_usrstack = AOUT32_USRSTACK,
135
.sv_psstrings = AOUT32_PS_STRINGS,
136
.sv_psstringssz = sizeof(struct freebsd32_ps_strings),
137
.sv_stackprot = VM_PROT_ALL,
138
.sv_copyout_strings = freebsd32_copyout_strings,
139
.sv_setregs = ia32_setregs,
140
.sv_fixlimit = ia32_fixlimit,
141
.sv_maxssiz = &ia32_maxssiz,
142
.sv_flags = SV_ABI_FREEBSD | SV_AOUT | SV_ILP32 | SV_SIGSYS,
143
.sv_set_syscall_retval = ia32_set_syscall_retval,
144
.sv_fetch_syscall_args = ia32_fetch_syscall_args,
145
.sv_syscallnames = freebsd32_syscallnames,
146
.sv_onexec_old = exec_onexec_old,
147
.sv_onexit = exit_onexit,
148
.sv_set_fork_retval = x86_set_fork_retval,
149
};
150
151
static void
152
aout_sysent(void *arg __unused)
153
{
154
aout_szsigcode = (int)(uintptr_t)&_binary_elf_vdso32_so_1_size;
155
}
156
SYSINIT(aout_sysent, SI_SUB_EXEC, SI_ORDER_ANY, aout_sysent, NULL);
157
#else
158
#error "Only ia32 arch is supported"
159
#endif
160
161
static int
162
aout_fixup(uintptr_t *stack_base, struct image_params *imgp)
163
{
164
165
*stack_base -= sizeof(uint32_t);
166
if (suword32((void *)*stack_base, imgp->args->argc) != 0)
167
return (EFAULT);
168
return (0);
169
}
170
171
static int
172
exec_aout_imgact(struct image_params *imgp)
173
{
174
const struct exec *a_out;
175
struct vmspace *vmspace;
176
vm_map_t map;
177
vm_object_t object;
178
vm_offset_t text_end, data_end;
179
unsigned long virtual_offset;
180
unsigned long file_offset;
181
unsigned long bss_size;
182
int error;
183
184
a_out = (const struct exec *)imgp->image_header;
185
186
/*
187
* Linux and *BSD binaries look very much alike,
188
* only the machine id is different:
189
* 0x64 for Linux, 0x86 for *BSD, 0x00 for BSDI.
190
* NetBSD is in network byte order.. ugh.
191
*/
192
if (((a_out->a_midmag >> 16) & 0xff) != 0x86 &&
193
((a_out->a_midmag >> 16) & 0xff) != 0 &&
194
((((int)ntohl(a_out->a_midmag)) >> 16) & 0xff) != 0x86)
195
return (-1);
196
197
/*
198
* Set file/virtual offset based on a.out variant.
199
* We do two cases: host byte order and network byte order
200
* (for NetBSD compatibility)
201
*/
202
switch ((int)(a_out->a_midmag & 0xffff)) {
203
case ZMAGIC:
204
virtual_offset = 0;
205
if (a_out->a_text) {
206
file_offset = PAGE_SIZE;
207
} else {
208
/* Bill's "screwball mode" */
209
file_offset = 0;
210
}
211
break;
212
case QMAGIC:
213
virtual_offset = PAGE_SIZE;
214
file_offset = 0;
215
/* Pass PS_STRINGS for BSD/OS binaries only. */
216
if (N_GETMID(*a_out) == MID_ZERO)
217
imgp->ps_strings = (void *)aout_sysvec.sv_psstrings;
218
break;
219
default:
220
/* NetBSD compatibility */
221
switch ((int)(ntohl(a_out->a_midmag) & 0xffff)) {
222
case ZMAGIC:
223
case QMAGIC:
224
virtual_offset = PAGE_SIZE;
225
file_offset = 0;
226
break;
227
default:
228
return (-1);
229
}
230
}
231
232
bss_size = roundup(a_out->a_bss, PAGE_SIZE);
233
234
/*
235
* Check various fields in header for validity/bounds.
236
*/
237
if (/* entry point must lay with text region */
238
a_out->a_entry < virtual_offset ||
239
a_out->a_entry >= virtual_offset + a_out->a_text ||
240
241
/* text and data size must each be page rounded */
242
a_out->a_text & PAGE_MASK || a_out->a_data & PAGE_MASK
243
244
#ifdef __amd64__
245
||
246
/* overflows */
247
virtual_offset + a_out->a_text + a_out->a_data + bss_size > UINT_MAX
248
#endif
249
)
250
return (-1);
251
252
/* text + data can't exceed file size */
253
if (a_out->a_data + a_out->a_text > imgp->attr->va_size)
254
return (EFAULT);
255
256
/*
257
* text/data/bss must not exceed limits
258
*/
259
PROC_LOCK(imgp->proc);
260
if (/* text can't exceed maximum text size */
261
a_out->a_text > maxtsiz ||
262
263
/* data + bss can't exceed rlimit */
264
a_out->a_data + bss_size > lim_cur_proc(imgp->proc, RLIMIT_DATA) ||
265
racct_set(imgp->proc, RACCT_DATA, a_out->a_data + bss_size) != 0) {
266
PROC_UNLOCK(imgp->proc);
267
return (ENOMEM);
268
}
269
PROC_UNLOCK(imgp->proc);
270
271
/*
272
* Avoid a possible deadlock if the current address space is destroyed
273
* and that address space maps the locked vnode. In the common case,
274
* the locked vnode's v_usecount is decremented but remains greater
275
* than zero. Consequently, the vnode lock is not needed by vrele().
276
* However, in cases where the vnode lock is external, such as nullfs,
277
* v_usecount may become zero.
278
*/
279
VOP_UNLOCK(imgp->vp);
280
281
/*
282
* Destroy old process VM and create a new one (with a new stack)
283
*/
284
error = exec_new_vmspace(imgp, &aout_sysvec);
285
286
vn_lock(imgp->vp, LK_SHARED | LK_RETRY);
287
if (error)
288
return (error);
289
290
/*
291
* The vm space can be changed by exec_new_vmspace
292
*/
293
vmspace = imgp->proc->p_vmspace;
294
295
object = imgp->object;
296
map = &vmspace->vm_map;
297
vm_map_lock(map);
298
vm_object_reference(object);
299
300
text_end = virtual_offset + a_out->a_text;
301
error = vm_map_insert(map, object,
302
file_offset,
303
virtual_offset, text_end,
304
VM_PROT_READ | VM_PROT_EXECUTE, VM_PROT_ALL,
305
MAP_COPY_ON_WRITE | MAP_PREFAULT | MAP_VN_EXEC);
306
if (error) {
307
vm_map_unlock(map);
308
vm_object_deallocate(object);
309
return (error);
310
}
311
VOP_SET_TEXT_CHECKED(imgp->vp);
312
data_end = text_end + a_out->a_data;
313
if (a_out->a_data) {
314
vm_object_reference(object);
315
error = vm_map_insert(map, object,
316
file_offset + a_out->a_text,
317
text_end, data_end,
318
VM_PROT_ALL, VM_PROT_ALL,
319
MAP_COPY_ON_WRITE | MAP_PREFAULT | MAP_VN_EXEC);
320
if (error) {
321
vm_map_unlock(map);
322
vm_object_deallocate(object);
323
return (error);
324
}
325
VOP_SET_TEXT_CHECKED(imgp->vp);
326
}
327
328
if (bss_size) {
329
error = vm_map_insert(map, NULL, 0,
330
data_end, data_end + bss_size,
331
VM_PROT_ALL, VM_PROT_ALL, 0);
332
if (error) {
333
vm_map_unlock(map);
334
return (error);
335
}
336
}
337
vm_map_unlock(map);
338
339
/* Fill in process VM information */
340
vmspace->vm_tsize = a_out->a_text >> PAGE_SHIFT;
341
vmspace->vm_dsize = (a_out->a_data + bss_size) >> PAGE_SHIFT;
342
vmspace->vm_taddr = (caddr_t) (uintptr_t) virtual_offset;
343
vmspace->vm_daddr = (caddr_t) (uintptr_t)
344
(virtual_offset + a_out->a_text);
345
346
error = exec_map_stack(imgp);
347
if (error != 0)
348
return (error);
349
350
/* Fill in image_params */
351
imgp->interpreted = 0;
352
imgp->entry_addr = a_out->a_entry;
353
354
imgp->proc->p_sysent = &aout_sysvec;
355
356
return (0);
357
}
358
359
/*
360
* Tell kern_execve.c about it, with a little help from the linker.
361
*/
362
static struct execsw aout_execsw = {
363
.ex_imgact = exec_aout_imgact,
364
.ex_name = "a.out"
365
};
366
EXEC_SET(aout, aout_execsw);
367
368