treewide: Add SPDX license identifier for more missed files
[linux-block.git] / arch / x86 / ia32 / ia32_aout.c
CommitLineData
09c434b8 1// SPDX-License-Identifier: GPL-2.0-only
1da177e4
LT
2/*
3 * a.out loader for x86-64
4 *
5 * Copyright (C) 1991, 1992, 1996 Linus Torvalds
6 * Hacked together by Andi Kleen
7 */
8
9#include <linux/module.h>
10
11#include <linux/time.h>
12#include <linux/kernel.h>
13#include <linux/mm.h>
14#include <linux/mman.h>
15#include <linux/a.out.h>
16#include <linux/errno.h>
17#include <linux/signal.h>
18#include <linux/string.h>
19#include <linux/fs.h>
20#include <linux/file.h>
21#include <linux/stat.h>
22#include <linux/fcntl.h>
23#include <linux/ptrace.h>
24#include <linux/user.h>
1da177e4
LT
25#include <linux/binfmts.h>
26#include <linux/personality.h>
27#include <linux/init.h>
e5fc3161 28#include <linux/jiffies.h>
7d2f551f 29#include <linux/perf_event.h>
68db0cf1 30#include <linux/sched/task_stack.h>
1da177e4 31
7c0f6ba6 32#include <linux/uaccess.h>
1da177e4
LT
33#include <asm/pgalloc.h>
34#include <asm/cacheflush.h>
35#include <asm/user32.h>
36#include <asm/ia32.h>
37
38#undef WARN_OLD
1da177e4 39
71613c3b 40static int load_aout_binary(struct linux_binprm *);
8edf8bee 41static int load_aout_library(struct file *);
1da177e4 42
1da177e4
LT
43static struct linux_binfmt aout_format = {
44 .module = THIS_MODULE,
45 .load_binary = load_aout_binary,
46 .load_shlib = load_aout_library,
1da177e4
LT
47};
48
5d22fc25 49static int set_brk(unsigned long start, unsigned long end)
1da177e4
LT
50{
51 start = PAGE_ALIGN(start);
52 end = PAGE_ALIGN(end);
53 if (end <= start)
5d22fc25 54 return 0;
864778b1 55 return vm_brk(start, end - start);
1da177e4
LT
56}
57
1da177e4
LT
58
59/*
60 * create_aout_tables() parses the env- and arg-strings in new user
61 * memory and creates the pointer tables from them, and puts their
62 * addresses on the "stack", returning the new stack pointer value.
63 */
64static u32 __user *create_aout_tables(char __user *p, struct linux_binprm *bprm)
65{
8edf8bee
TG
66 u32 __user *argv, *envp, *sp;
67 int argc = bprm->argc, envc = bprm->envc;
1da177e4
LT
68
69 sp = (u32 __user *) ((-(unsigned long)sizeof(u32)) & (unsigned long) p);
70 sp -= envc+1;
71 envp = sp;
72 sp -= argc+1;
73 argv = sp;
8edf8bee
TG
74 put_user((unsigned long) envp, --sp);
75 put_user((unsigned long) argv, --sp);
76 put_user(argc, --sp);
1da177e4 77 current->mm->arg_start = (unsigned long) p;
8edf8bee 78 while (argc-- > 0) {
1da177e4 79 char c;
8edf8bee
TG
80
81 put_user((u32)(unsigned long)p, argv++);
1da177e4 82 do {
8edf8bee 83 get_user(c, p++);
1da177e4
LT
84 } while (c);
85 }
74019699 86 put_user(0, argv);
1da177e4 87 current->mm->arg_end = current->mm->env_start = (unsigned long) p;
8edf8bee 88 while (envc-- > 0) {
1da177e4 89 char c;
8edf8bee
TG
90
91 put_user((u32)(unsigned long)p, envp++);
1da177e4 92 do {
8edf8bee 93 get_user(c, p++);
1da177e4
LT
94 } while (c);
95 }
74019699 96 put_user(0, envp);
1da177e4
LT
97 current->mm->env_end = (unsigned long) p;
98 return sp;
99}
100
101/*
102 * These are the functions used to load a.out style executables and shared
103 * libraries. There is no binary dependent code anywhere else.
104 */
71613c3b 105static int load_aout_binary(struct linux_binprm *bprm)
1da177e4 106{
8edf8bee 107 unsigned long error, fd_offset, rlim;
71613c3b 108 struct pt_regs *regs = current_pt_regs();
1da177e4 109 struct exec ex;
1da177e4
LT
110 int retval;
111
112 ex = *((struct exec *) bprm->buf); /* exec-header */
113 if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != OMAGIC &&
114 N_MAGIC(ex) != QMAGIC && N_MAGIC(ex) != NMAGIC) ||
115 N_TRSIZE(ex) || N_DRSIZE(ex) ||
496ad9aa 116 i_size_read(file_inode(bprm->file)) <
8edf8bee 117 ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) {
1da177e4
LT
118 return -ENOEXEC;
119 }
120
121 fd_offset = N_TXTOFF(ex);
122
123 /* Check initial limits. This avoids letting people circumvent
124 * size limits imposed on them by creating programs with large
125 * arrays in the data or bss.
126 */
2854e72b 127 rlim = rlimit(RLIMIT_DATA);
1da177e4
LT
128 if (rlim >= RLIM_INFINITY)
129 rlim = ~0;
130 if (ex.a_data + ex.a_bss > rlim)
131 return -ENOMEM;
132
133 /* Flush all traces of the currently running executable */
134 retval = flush_old_exec(bprm);
135 if (retval)
136 return retval;
137
1da177e4
LT
138 /* OK, This is the point of no return */
139 set_personality(PER_LINUX);
ce7e5d2d 140 set_personality_ia32(false);
1da177e4 141
221af7f8
LT
142 setup_new_exec(bprm);
143
144 regs->cs = __USER32_CS;
145 regs->r8 = regs->r9 = regs->r10 = regs->r11 = regs->r12 =
146 regs->r13 = regs->r14 = regs->r15 = 0;
147
1da177e4
LT
148 current->mm->end_code = ex.a_text +
149 (current->mm->start_code = N_TXTADDR(ex));
150 current->mm->end_data = ex.a_data +
151 (current->mm->start_data = N_DATADDR(ex));
152 current->mm->brk = ex.a_bss +
153 (current->mm->start_brk = N_BSSADDR(ex));
1da177e4 154
6414fa6a 155 retval = setup_arg_pages(bprm, IA32_STACK_TOP, EXSTACK_DEFAULT);
19d860a1 156 if (retval < 0)
6414fa6a 157 return retval;
6414fa6a 158
a6f76f23 159 install_exec_creds(bprm);
1da177e4
LT
160
161 if (N_MAGIC(ex) == OMAGIC) {
162 unsigned long text_addr, map_size;
1da177e4
LT
163
164 text_addr = N_TXTADDR(ex);
1da177e4
LT
165 map_size = ex.a_text+ex.a_data;
166
e4eb1ff6 167 error = vm_brk(text_addr & PAGE_MASK, map_size);
1da177e4 168
5d22fc25 169 if (error)
1da177e4 170 return error;
1da177e4 171
3dc20cb2
AV
172 error = read_code(bprm->file, text_addr, 32,
173 ex.a_text + ex.a_data);
19d860a1 174 if ((signed long)error < 0)
1da177e4 175 return error;
1da177e4
LT
176 } else {
177#ifdef WARN_OLD
178 static unsigned long error_time, error_time2;
179 if ((ex.a_text & 0xfff || ex.a_data & 0xfff) &&
e5fc3161
JL
180 (N_MAGIC(ex) != NMAGIC) &&
181 time_after(jiffies, error_time2 + 5*HZ)) {
1da177e4
LT
182 printk(KERN_NOTICE "executable not page aligned\n");
183 error_time2 = jiffies;
184 }
185
186 if ((fd_offset & ~PAGE_MASK) != 0 &&
e5fc3161 187 time_after(jiffies, error_time + 5*HZ)) {
8edf8bee
TG
188 printk(KERN_WARNING
189 "fd_offset is not page aligned. Please convert "
a455589f
AV
190 "program: %pD\n",
191 bprm->file);
1da177e4
LT
192 error_time = jiffies;
193 }
194#endif
195
8edf8bee 196 if (!bprm->file->f_op->mmap || (fd_offset & ~PAGE_MASK) != 0) {
864778b1 197 error = vm_brk(N_TXTADDR(ex), ex.a_text+ex.a_data);
5d22fc25 198 if (error)
864778b1
MH
199 return error;
200
3dc20cb2
AV
201 read_code(bprm->file, N_TXTADDR(ex), fd_offset,
202 ex.a_text+ex.a_data);
1da177e4
LT
203 goto beyond_if;
204 }
205
6be5ceb0 206 error = vm_mmap(bprm->file, N_TXTADDR(ex), ex.a_text,
8edf8bee
TG
207 PROT_READ | PROT_EXEC,
208 MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE |
209 MAP_EXECUTABLE | MAP_32BIT,
210 fd_offset);
1da177e4 211
19d860a1 212 if (error != N_TXTADDR(ex))
1da177e4 213 return error;
1da177e4 214
6be5ceb0 215 error = vm_mmap(bprm->file, N_DATADDR(ex), ex.a_data,
1da177e4 216 PROT_READ | PROT_WRITE | PROT_EXEC,
8edf8bee
TG
217 MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE |
218 MAP_EXECUTABLE | MAP_32BIT,
1da177e4 219 fd_offset + ex.a_text);
19d860a1 220 if (error != N_DATADDR(ex))
1da177e4 221 return error;
1da177e4 222 }
864778b1 223
1da177e4 224beyond_if:
864778b1 225 error = set_brk(current->mm->start_brk, current->mm->brk);
5d22fc25 226 if (error)
864778b1 227 return error;
1da177e4 228
864778b1 229 set_binfmt(&aout_format);
1da177e4 230
1da177e4
LT
231 current->mm->start_stack =
232 (unsigned long)create_aout_tables((char __user *)bprm->p, bprm);
233 /* start thread */
b6edbb1e
JF
234 loadsegment(fs, 0);
235 loadsegment(ds, __USER32_DS);
236 loadsegment(es, __USER32_DS);
8edf8bee 237 load_gs_index(0);
65ea5b03
PA
238 (regs)->ip = ex.a_entry;
239 (regs)->sp = current->mm->start_stack;
240 (regs)->flags = 0x200;
1da177e4
LT
241 (regs)->cs = __USER32_CS;
242 (regs)->ss = __USER32_DS;
f891dd18
AK
243 regs->r8 = regs->r9 = regs->r10 = regs->r11 =
244 regs->r12 = regs->r13 = regs->r14 = regs->r15 = 0;
1da177e4 245 set_fs(USER_DS);
1da177e4
LT
246 return 0;
247}
248
249static int load_aout_library(struct file *file)
250{
8edf8bee 251 unsigned long bss, start_addr, len, error;
1da177e4
LT
252 int retval;
253 struct exec ex;
bdd1d2d3 254 loff_t pos = 0;
1da177e4
LT
255
256 retval = -ENOEXEC;
bdd1d2d3 257 error = kernel_read(file, &ex, sizeof(ex), &pos);
1da177e4
LT
258 if (error != sizeof(ex))
259 goto out;
260
261 /* We come in here for the regular a.out style of shared libraries */
262 if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != QMAGIC) || N_TRSIZE(ex) ||
263 N_DRSIZE(ex) || ((ex.a_entry & 0xfff) && N_MAGIC(ex) == ZMAGIC) ||
496ad9aa 264 i_size_read(file_inode(file)) <
8edf8bee 265 ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) {
1da177e4
LT
266 goto out;
267 }
268
269 if (N_FLAGS(ex))
270 goto out;
271
272 /* For QMAGIC, the starting address is 0x20 into the page. We mask
273 this off to get the starting address for the page */
274
275 start_addr = ex.a_entry & 0xfffff000;
276
277 if ((N_TXTOFF(ex) & ~PAGE_MASK) != 0) {
1da177e4
LT
278#ifdef WARN_OLD
279 static unsigned long error_time;
e5fc3161 280 if (time_after(jiffies, error_time + 5*HZ)) {
8edf8bee
TG
281 printk(KERN_WARNING
282 "N_TXTOFF is not page aligned. Please convert "
a455589f
AV
283 "library: %pD\n",
284 file);
1da177e4
LT
285 error_time = jiffies;
286 }
287#endif
864778b1 288 retval = vm_brk(start_addr, ex.a_text + ex.a_data + ex.a_bss);
5d22fc25 289 if (retval)
864778b1 290 goto out;
8edf8bee 291
3dc20cb2
AV
292 read_code(file, start_addr, N_TXTOFF(ex),
293 ex.a_text + ex.a_data);
1da177e4
LT
294 retval = 0;
295 goto out;
296 }
297 /* Now use mmap to map the library into memory. */
6be5ceb0 298 error = vm_mmap(file, start_addr, ex.a_text + ex.a_data,
1da177e4
LT
299 PROT_READ | PROT_WRITE | PROT_EXEC,
300 MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_32BIT,
301 N_TXTOFF(ex));
1da177e4
LT
302 retval = error;
303 if (error != start_addr)
304 goto out;
305
306 len = PAGE_ALIGN(ex.a_text + ex.a_data);
307 bss = ex.a_text + ex.a_data + ex.a_bss;
308 if (bss > len) {
5d22fc25
LT
309 retval = vm_brk(start_addr + len, bss - len);
310 if (retval)
1da177e4
LT
311 goto out;
312 }
313 retval = 0;
314out:
315 return retval;
316}
317
318static int __init init_aout_binfmt(void)
319{
8fc3dc5a
AV
320 register_binfmt(&aout_format);
321 return 0;
1da177e4
LT
322}
323
324static void __exit exit_aout_binfmt(void)
325{
326 unregister_binfmt(&aout_format);
327}
328
329module_init(init_aout_binfmt);
330module_exit(exit_aout_binfmt);
331MODULE_LICENSE("GPL");