Import 2.2.8pre2
[davej-history.git] / fs / binfmt_aout.c
blob8eb3b6e5fba1fa9af533dcc90f614a767c6616f4
1 /*
2 * linux/fs/binfmt_aout.c
4 * Copyright (C) 1991, 1992, 1996 Linus Torvalds
5 */
7 #include <linux/module.h>
9 #include <linux/sched.h>
10 #include <linux/kernel.h>
11 #include <linux/mm.h>
12 #include <linux/mman.h>
13 #include <linux/a.out.h>
14 #include <linux/errno.h>
15 #include <linux/signal.h>
16 #include <linux/string.h>
17 #include <linux/fs.h>
18 #include <linux/file.h>
19 #include <linux/stat.h>
20 #include <linux/fcntl.h>
21 #include <linux/ptrace.h>
22 #include <linux/user.h>
23 #include <linux/malloc.h>
24 #include <linux/binfmts.h>
25 #include <linux/personality.h>
26 #include <linux/init.h>
28 #include <asm/system.h>
29 #include <asm/uaccess.h>
30 #include <asm/pgtable.h>
32 static int load_aout_binary(struct linux_binprm *, struct pt_regs * regs);
33 static int load_aout_library(int fd);
34 static int aout_core_dump(long signr, struct pt_regs * regs);
36 extern void dump_thread(struct pt_regs *, struct user *);
38 static struct linux_binfmt aout_format = {
39 #ifndef MODULE
40 NULL, NULL, load_aout_binary, load_aout_library, aout_core_dump
41 #else
42 NULL, &__this_module, load_aout_binary, load_aout_library, aout_core_dump
43 #endif
46 static void set_brk(unsigned long start, unsigned long end)
48 start = PAGE_ALIGN(start);
49 end = PAGE_ALIGN(end);
50 if (end <= start)
51 return;
52 do_mmap(NULL, start, end - start,
53 PROT_READ | PROT_WRITE | PROT_EXEC,
54 MAP_FIXED | MAP_PRIVATE, 0);
58 * These are the only things you should do on a core-file: use only these
59 * macros to write out all the necessary info.
61 #define DUMP_WRITE(addr,nr) \
62 while (file->f_op->write(file,(char *)(addr),(nr),&file->f_pos) != (nr)) goto close_coredump
64 #define DUMP_SEEK(offset) \
65 if (file->f_op->llseek) { \
66 if (file->f_op->llseek(file,(offset),0) != (offset)) \
67 goto close_coredump; \
68 } else file->f_pos = (offset)
71 * Routine writes a core dump image in the current directory.
72 * Currently only a stub-function.
74 * Note that setuid/setgid files won't make a core-dump if the uid/gid
75 * changed due to the set[u|g]id. It's enforced by the "current->dumpable"
76 * field, which also makes sure the core-dumps won't be recursive if the
77 * dumping of the process results in another error..
80 static inline int
81 do_aout_core_dump(long signr, struct pt_regs * regs)
83 struct dentry * dentry = NULL;
84 struct inode * inode = NULL;
85 struct file * file;
86 mm_segment_t fs;
87 int has_dumped = 0;
88 char corefile[6+sizeof(current->comm)];
89 unsigned long dump_start, dump_size;
90 struct user dump;
91 #if defined(__alpha__)
92 # define START_DATA(u) (u.start_data)
93 #elif defined(__sparc__)
94 # define START_DATA(u) (u.u_tsize)
95 #elif defined(__i386__) || defined(__mc68000__)
96 # define START_DATA(u) (u.u_tsize << PAGE_SHIFT)
97 #endif
98 #ifdef __sparc__
99 # define START_STACK(u) ((regs->u_regs[UREG_FP]) & ~(PAGE_SIZE - 1))
100 #else
101 # define START_STACK(u) (u.start_stack)
102 #endif
104 if (!current->dumpable || atomic_read(&current->mm->count) != 1)
105 return 0;
106 current->dumpable = 0;
108 /* See if we have enough room to write the upage. */
109 if (current->rlim[RLIMIT_CORE].rlim_cur < PAGE_SIZE)
110 return 0;
111 fs = get_fs();
112 set_fs(KERNEL_DS);
113 memcpy(corefile,"core.",5);
114 #if 0
115 memcpy(corefile+5,current->comm,sizeof(current->comm));
116 #else
117 corefile[4] = '\0';
118 #endif
119 file = filp_open(corefile,O_CREAT | 2 | O_TRUNC | O_NOFOLLOW, 0600);
120 if (IS_ERR(file))
121 goto end_coredump;
122 dentry = file->f_dentry;
123 inode = dentry->d_inode;
124 if (!S_ISREG(inode->i_mode))
125 goto close_coredump;
126 if (!inode->i_op || !inode->i_op->default_file_ops)
127 goto close_coredump;
128 if (!file->f_op->write)
129 goto close_coredump;
130 has_dumped = 1;
131 current->flags |= PF_DUMPCORE;
132 strncpy(dump.u_comm, current->comm, sizeof(current->comm));
133 #ifndef __sparc__
134 dump.u_ar0 = (void *)(((unsigned long)(&dump.regs)) - ((unsigned long)(&dump)));
135 #endif
136 dump.signal = signr;
137 dump_thread(regs, &dump);
139 /* If the size of the dump file exceeds the rlimit, then see what would happen
140 if we wrote the stack, but not the data area. */
141 #ifdef __sparc__
142 if ((dump.u_dsize+dump.u_ssize) >
143 current->rlim[RLIMIT_CORE].rlim_cur)
144 dump.u_dsize = 0;
145 #else
146 if ((dump.u_dsize+dump.u_ssize+1) * PAGE_SIZE >
147 current->rlim[RLIMIT_CORE].rlim_cur)
148 dump.u_dsize = 0;
149 #endif
151 /* Make sure we have enough room to write the stack and data areas. */
152 #ifdef __sparc__
153 if ((dump.u_ssize) >
154 current->rlim[RLIMIT_CORE].rlim_cur)
155 dump.u_ssize = 0;
156 #else
157 if ((dump.u_ssize+1) * PAGE_SIZE >
158 current->rlim[RLIMIT_CORE].rlim_cur)
159 dump.u_ssize = 0;
160 #endif
162 /* make sure we actually have a data and stack area to dump */
163 set_fs(USER_DS);
164 #ifdef __sparc__
165 if (verify_area(VERIFY_READ, (void *) START_DATA(dump), dump.u_dsize))
166 dump.u_dsize = 0;
167 if (verify_area(VERIFY_READ, (void *) START_STACK(dump), dump.u_ssize))
168 dump.u_ssize = 0;
169 #else
170 if (verify_area(VERIFY_READ, (void *) START_DATA(dump), dump.u_dsize << PAGE_SHIFT))
171 dump.u_dsize = 0;
172 if (verify_area(VERIFY_READ, (void *) START_STACK(dump), dump.u_ssize << PAGE_SHIFT))
173 dump.u_ssize = 0;
174 #endif
176 set_fs(KERNEL_DS);
177 /* struct user */
178 DUMP_WRITE(&dump,sizeof(dump));
179 /* Now dump all of the user data. Include malloced stuff as well */
180 #ifndef __sparc__
181 DUMP_SEEK(PAGE_SIZE);
182 #endif
183 /* now we start writing out the user space info */
184 set_fs(USER_DS);
185 /* Dump the data area */
186 if (dump.u_dsize != 0) {
187 dump_start = START_DATA(dump);
188 #ifdef __sparc__
189 dump_size = dump.u_dsize;
190 #else
191 dump_size = dump.u_dsize << PAGE_SHIFT;
192 #endif
193 DUMP_WRITE(dump_start,dump_size);
195 /* Now prepare to dump the stack area */
196 if (dump.u_ssize != 0) {
197 dump_start = START_STACK(dump);
198 #ifdef __sparc__
199 dump_size = dump.u_ssize;
200 #else
201 dump_size = dump.u_ssize << PAGE_SHIFT;
202 #endif
203 DUMP_WRITE(dump_start,dump_size);
205 /* Finally dump the task struct. Not be used by gdb, but could be useful */
206 set_fs(KERNEL_DS);
207 DUMP_WRITE(current,sizeof(*current));
208 close_coredump:
209 filp_close(file, NULL);
210 end_coredump:
211 set_fs(fs);
212 return has_dumped;
215 static int
216 aout_core_dump(long signr, struct pt_regs * regs)
218 int retval;
220 MOD_INC_USE_COUNT;
221 retval = do_aout_core_dump(signr, regs);
222 MOD_DEC_USE_COUNT;
223 return retval;
227 * create_aout_tables() parses the env- and arg-strings in new user
228 * memory and creates the pointer tables from them, and puts their
229 * addresses on the "stack", returning the new stack pointer value.
231 static unsigned long * create_aout_tables(char * p, struct linux_binprm * bprm)
233 char **argv, **envp;
234 unsigned long * sp;
235 int argc = bprm->argc;
236 int envc = bprm->envc;
238 sp = (unsigned long *) ((-(unsigned long)sizeof(char *)) & (unsigned long) p);
239 #ifdef __sparc__
240 /* This imposes the proper stack alignment for a new process. */
241 sp = (unsigned long *) (((unsigned long) sp) & ~7);
242 if ((envc+argc+3)&1) --sp;
243 #endif
244 #ifdef __alpha__
245 /* whee.. test-programs are so much fun. */
246 put_user(0, --sp);
247 put_user(0, --sp);
248 if (bprm->loader) {
249 put_user(0, --sp);
250 put_user(0x3eb, --sp);
251 put_user(bprm->loader, --sp);
252 put_user(0x3ea, --sp);
254 put_user(bprm->exec, --sp);
255 put_user(0x3e9, --sp);
256 #endif
257 sp -= envc+1;
258 envp = (char **) sp;
259 sp -= argc+1;
260 argv = (char **) sp;
261 #if defined(__i386__) || defined(__mc68000__)
262 put_user((unsigned long) envp,--sp);
263 put_user((unsigned long) argv,--sp);
264 #endif
265 put_user(argc,--sp);
266 current->mm->arg_start = (unsigned long) p;
267 while (argc-->0) {
268 char c;
269 put_user(p,argv++);
270 do {
271 get_user(c,p++);
272 } while (c);
274 put_user(NULL,argv);
275 current->mm->arg_end = current->mm->env_start = (unsigned long) p;
276 while (envc-->0) {
277 char c;
278 put_user(p,envp++);
279 do {
280 get_user(c,p++);
281 } while (c);
283 put_user(NULL,envp);
284 current->mm->env_end = (unsigned long) p;
285 return sp;
289 * These are the functions used to load a.out style executables and shared
290 * libraries. There is no binary dependent code anywhere else.
293 static inline int do_load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs)
295 struct exec ex;
296 struct file * file;
297 int fd;
298 unsigned long error;
299 unsigned long p = bprm->p;
300 unsigned long fd_offset;
301 unsigned long rlim;
302 int retval;
304 ex = *((struct exec *) bprm->buf); /* exec-header */
305 if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != OMAGIC &&
306 N_MAGIC(ex) != QMAGIC && N_MAGIC(ex) != NMAGIC) ||
307 N_TRSIZE(ex) || N_DRSIZE(ex) ||
308 bprm->dentry->d_inode->i_size < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) {
309 return -ENOEXEC;
312 fd_offset = N_TXTOFF(ex);
314 #ifdef __i386__
315 if (N_MAGIC(ex) == ZMAGIC && fd_offset != BLOCK_SIZE) {
316 printk(KERN_NOTICE "N_TXTOFF != BLOCK_SIZE. See a.out.h.\n");
317 return -ENOEXEC;
320 if (N_MAGIC(ex) == ZMAGIC && ex.a_text &&
321 bprm->dentry->d_inode->i_op &&
322 bprm->dentry->d_inode->i_op->bmap &&
323 (fd_offset < bprm->dentry->d_inode->i_sb->s_blocksize)) {
324 printk(KERN_NOTICE "N_TXTOFF < BLOCK_SIZE. Please convert binary.\n");
325 return -ENOEXEC;
327 #endif
329 /* Check initial limits. This avoids letting people circumvent
330 * size limits imposed on them by creating programs with large
331 * arrays in the data or bss.
333 rlim = current->rlim[RLIMIT_DATA].rlim_cur;
334 if (rlim >= RLIM_INFINITY)
335 rlim = ~0;
336 if (ex.a_data + ex.a_bss > rlim)
337 return -ENOMEM;
339 /* Flush all traces of the currently running executable */
340 retval = flush_old_exec(bprm);
341 if (retval)
342 return retval;
344 /* OK, This is the point of no return */
345 current->personality = PER_LINUX;
347 #if defined(__sparc__) && !defined(__sparc_v9__)
348 memcpy(&current->tss.core_exec, &ex, sizeof(struct exec));
349 #endif
351 current->mm->end_code = ex.a_text +
352 (current->mm->start_code = N_TXTADDR(ex));
353 current->mm->end_data = ex.a_data +
354 (current->mm->start_data = N_DATADDR(ex));
355 current->mm->brk = ex.a_bss +
356 (current->mm->start_brk = N_BSSADDR(ex));
358 current->mm->rss = 0;
359 current->mm->mmap = NULL;
360 compute_creds(bprm);
361 current->flags &= ~PF_FORKNOEXEC;
362 #ifdef __sparc__
363 if (N_MAGIC(ex) == NMAGIC) {
364 /* Fuck me plenty... */
365 error = do_mmap(NULL, N_TXTADDR(ex), ex.a_text,
366 PROT_READ|PROT_WRITE|PROT_EXEC,
367 MAP_FIXED|MAP_PRIVATE, 0);
368 read_exec(bprm->dentry, fd_offset, (char *) N_TXTADDR(ex),
369 ex.a_text, 0);
370 error = do_mmap(NULL, N_DATADDR(ex), ex.a_data,
371 PROT_READ|PROT_WRITE|PROT_EXEC,
372 MAP_FIXED|MAP_PRIVATE, 0);
373 read_exec(bprm->dentry, fd_offset + ex.a_text, (char *) N_DATADDR(ex),
374 ex.a_data, 0);
375 goto beyond_if;
377 #endif
379 if (N_MAGIC(ex) == OMAGIC) {
380 #if defined(__alpha__) || defined(__sparc__)
381 do_mmap(NULL, N_TXTADDR(ex) & PAGE_MASK,
382 ex.a_text+ex.a_data + PAGE_SIZE - 1,
383 PROT_READ|PROT_WRITE|PROT_EXEC,
384 MAP_FIXED|MAP_PRIVATE, 0);
385 read_exec(bprm->dentry, fd_offset, (char *) N_TXTADDR(ex),
386 ex.a_text+ex.a_data, 0);
387 #else
388 do_mmap(NULL, 0, ex.a_text+ex.a_data,
389 PROT_READ|PROT_WRITE|PROT_EXEC,
390 MAP_FIXED|MAP_PRIVATE, 0);
391 read_exec(bprm->dentry, 32, (char *) 0, ex.a_text+ex.a_data, 0);
392 #endif
393 flush_icache_range((unsigned long) 0,
394 (unsigned long) ex.a_text+ex.a_data);
395 } else {
396 if ((ex.a_text & 0xfff || ex.a_data & 0xfff) &&
397 (N_MAGIC(ex) != NMAGIC))
398 printk(KERN_NOTICE "executable not page aligned\n");
400 fd = open_dentry(bprm->dentry, O_RDONLY);
401 if (fd < 0)
402 return fd;
403 file = fcheck(fd);
405 if (!file->f_op || !file->f_op->mmap) {
406 sys_close(fd);
407 do_mmap(NULL, 0, ex.a_text+ex.a_data,
408 PROT_READ|PROT_WRITE|PROT_EXEC,
409 MAP_FIXED|MAP_PRIVATE, 0);
410 read_exec(bprm->dentry, fd_offset,
411 (char *) N_TXTADDR(ex), ex.a_text+ex.a_data, 0);
412 flush_icache_range((unsigned long) N_TXTADDR(ex),
413 (unsigned long) N_TXTADDR(ex) +
414 ex.a_text+ex.a_data);
415 goto beyond_if;
418 error = do_mmap(file, N_TXTADDR(ex), ex.a_text,
419 PROT_READ | PROT_EXEC,
420 MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE,
421 fd_offset);
423 if (error != N_TXTADDR(ex)) {
424 sys_close(fd);
425 send_sig(SIGKILL, current, 0);
426 return error;
429 error = do_mmap(file, N_DATADDR(ex), ex.a_data,
430 PROT_READ | PROT_WRITE | PROT_EXEC,
431 MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE,
432 fd_offset + ex.a_text);
433 sys_close(fd);
434 if (error != N_DATADDR(ex)) {
435 send_sig(SIGKILL, current, 0);
436 return error;
439 beyond_if:
440 if (current->exec_domain && current->exec_domain->module)
441 __MOD_DEC_USE_COUNT(current->exec_domain->module);
442 if (current->binfmt && current->binfmt->module)
443 __MOD_DEC_USE_COUNT(current->binfmt->module);
444 current->exec_domain = lookup_exec_domain(current->personality);
445 current->binfmt = &aout_format;
446 if (current->exec_domain && current->exec_domain->module)
447 __MOD_INC_USE_COUNT(current->exec_domain->module);
448 if (current->binfmt && current->binfmt->module)
449 __MOD_INC_USE_COUNT(current->binfmt->module);
451 set_brk(current->mm->start_brk, current->mm->brk);
453 p = setup_arg_pages(p, bprm);
455 p = (unsigned long) create_aout_tables((char *)p, bprm);
456 current->mm->start_stack = p;
457 #ifdef __alpha__
458 regs->gp = ex.a_gpvalue;
459 #endif
460 start_thread(regs, ex.a_entry, p);
461 if (current->flags & PF_PTRACED)
462 send_sig(SIGTRAP, current, 0);
463 return 0;
467 static int
468 load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs)
470 int retval;
472 MOD_INC_USE_COUNT;
473 retval = do_load_aout_binary(bprm, regs);
474 MOD_DEC_USE_COUNT;
475 return retval;
478 static inline int
479 do_load_aout_library(int fd)
481 struct file * file;
482 struct inode * inode;
483 unsigned long bss, start_addr, len;
484 unsigned long error;
485 int retval;
486 loff_t offset = 0;
487 struct exec ex;
489 retval = -EACCES;
490 file = fget(fd);
491 if (!file)
492 goto out;
493 if (!file->f_op)
494 goto out_putf;
495 inode = file->f_dentry->d_inode;
497 retval = -ENOEXEC;
498 /* N.B. Save current fs? */
499 set_fs(KERNEL_DS);
500 error = file->f_op->read(file, (char *) &ex, sizeof(ex), &offset);
501 set_fs(USER_DS);
502 if (error != sizeof(ex))
503 goto out_putf;
505 /* We come in here for the regular a.out style of shared libraries */
506 if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != QMAGIC) || N_TRSIZE(ex) ||
507 N_DRSIZE(ex) || ((ex.a_entry & 0xfff) && N_MAGIC(ex) == ZMAGIC) ||
508 inode->i_size < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) {
509 goto out_putf;
512 if (N_MAGIC(ex) == ZMAGIC && N_TXTOFF(ex) &&
513 (N_TXTOFF(ex) < inode->i_sb->s_blocksize)) {
514 printk("N_TXTOFF < BLOCK_SIZE. Please convert library\n");
515 goto out_putf;
518 if (N_FLAGS(ex))
519 goto out_putf;
521 /* For QMAGIC, the starting address is 0x20 into the page. We mask
522 this off to get the starting address for the page */
524 start_addr = ex.a_entry & 0xfffff000;
526 /* Now use mmap to map the library into memory. */
527 error = do_mmap(file, start_addr, ex.a_text + ex.a_data,
528 PROT_READ | PROT_WRITE | PROT_EXEC,
529 MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE,
530 N_TXTOFF(ex));
531 retval = error;
532 if (error != start_addr)
533 goto out_putf;
535 len = PAGE_ALIGN(ex.a_text + ex.a_data);
536 bss = ex.a_text + ex.a_data + ex.a_bss;
537 if (bss > len) {
538 error = do_mmap(NULL, start_addr + len, bss - len,
539 PROT_READ | PROT_WRITE | PROT_EXEC,
540 MAP_PRIVATE | MAP_FIXED, 0);
541 retval = error;
542 if (error != start_addr + len)
543 goto out_putf;
545 retval = 0;
547 out_putf:
548 fput(file);
549 out:
550 return retval;
553 static int
554 load_aout_library(int fd)
556 int retval;
558 MOD_INC_USE_COUNT;
559 retval = do_load_aout_library(fd);
560 MOD_DEC_USE_COUNT;
561 return retval;
565 int __init init_aout_binfmt(void)
567 return register_binfmt(&aout_format);
570 #ifdef MODULE
571 int init_module(void) {
572 return init_aout_binfmt();
575 void cleanup_module( void) {
576 unregister_binfmt(&aout_format);
578 #endif