1
2
3
4
5
6
7#include <linux/module.h>
8
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>
27
28#include <asm/system.h>
29#include <asm/uaccess.h>
30#include <asm/pgtable.h>
31
32static int load_aout_binary(struct linux_binprm *, struct pt_regs * regs);
33static int load_aout_library(struct file *file);
34static int aout_core_dump(long signr, struct pt_regs * regs, struct file *);
35
36extern void dump_thread(struct pt_regs *, struct user *);
37
38static struct linux_binfmt aout_format = {
39 module: THIS_MODULE,
40 load_binary: load_aout_binary,
41 load_shlib: load_aout_library,
42 core_dump: aout_core_dump,
43 min_coredump: PAGE_SIZE,
44};
45
46static void set_brk(unsigned long start, unsigned long end)
47{
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);
55}
56
57
58
59
60
61
62static int dump_write(struct file *file, const void *addr, int nr)
63{
64 int r;
65 fs_down(&file->f_dentry->d_inode->i_sem);
66 r = file->f_op->write(file, addr, nr, &file->f_pos) == nr;
67 fs_up(&file->f_dentry->d_inode->i_sem);
68 return r;
69}
70
71#define DUMP_WRITE(addr, nr) \
72 if (!dump_write(file, (void *)(addr), (nr))) \
73 goto close_coredump;
74
75#define DUMP_SEEK(offset) \
76if (file->f_op->llseek) { \
77 if (file->f_op->llseek(file,(offset),0) != (offset)) \
78 goto close_coredump; \
79} else file->f_pos = (offset)
80
81
82
83
84
85
86
87
88
89
90
91static int
92aout_core_dump(long signr, struct pt_regs * regs, struct file * file)
93{
94 mm_segment_t fs;
95 int has_dumped = 0;
96 unsigned long dump_start, dump_size;
97 struct user dump;
98#if defined(__alpha__)
99# define START_DATA(u) (u.start_data)
100#elif defined(__sparc__)
101# define START_DATA(u) (u.u_tsize)
102#elif defined(__i386__) || defined(__mc68000__)
103# define START_DATA(u) (u.u_tsize << PAGE_SHIFT)
104#endif
105#ifdef __sparc__
106# define START_STACK(u) ((regs->u_regs[UREG_FP]) & ~(PAGE_SIZE - 1))
107#else
108# define START_STACK(u) (u.start_stack)
109#endif
110
111 fs = get_fs();
112 set_fs(KERNEL_DS);
113 has_dumped = 1;
114 current->flags |= PF_DUMPCORE;
115 strncpy(dump.u_comm, current->comm, sizeof(current->comm));
116#ifndef __sparc__
117 dump.u_ar0 = (void *)(((unsigned long)(&dump.regs)) - ((unsigned long)(&dump)));
118#endif
119 dump.signal = signr;
120 dump_thread(regs, &dump);
121
122
123
124#ifdef __sparc__
125 if ((dump.u_dsize+dump.u_ssize) >
126 current->rlim[RLIMIT_CORE].rlim_cur)
127 dump.u_dsize = 0;
128#else
129 if ((dump.u_dsize+dump.u_ssize+1) * PAGE_SIZE >
130 current->rlim[RLIMIT_CORE].rlim_cur)
131 dump.u_dsize = 0;
132#endif
133
134
135#ifdef __sparc__
136 if ((dump.u_ssize) >
137 current->rlim[RLIMIT_CORE].rlim_cur)
138 dump.u_ssize = 0;
139#else
140 if ((dump.u_ssize+1) * PAGE_SIZE >
141 current->rlim[RLIMIT_CORE].rlim_cur)
142 dump.u_ssize = 0;
143#endif
144
145
146 set_fs(USER_DS);
147#ifdef __sparc__
148 if (verify_area(VERIFY_READ, (void *) START_DATA(dump), dump.u_dsize))
149 dump.u_dsize = 0;
150 if (verify_area(VERIFY_READ, (void *) START_STACK(dump), dump.u_ssize))
151 dump.u_ssize = 0;
152#else
153 if (verify_area(VERIFY_READ, (void *) START_DATA(dump), dump.u_dsize << PAGE_SHIFT))
154 dump.u_dsize = 0;
155 if (verify_area(VERIFY_READ, (void *) START_STACK(dump), dump.u_ssize << PAGE_SHIFT))
156 dump.u_ssize = 0;
157#endif
158
159 set_fs(KERNEL_DS);
160
161 DUMP_WRITE(&dump,sizeof(dump));
162
163#ifndef __sparc__
164 DUMP_SEEK(PAGE_SIZE);
165#endif
166
167 set_fs(USER_DS);
168
169 if (dump.u_dsize != 0) {
170 dump_start = START_DATA(dump);
171#ifdef __sparc__
172 dump_size = dump.u_dsize;
173#else
174 dump_size = dump.u_dsize << PAGE_SHIFT;
175#endif
176 DUMP_WRITE(dump_start,dump_size);
177 }
178
179 if (dump.u_ssize != 0) {
180 dump_start = START_STACK(dump);
181#ifdef __sparc__
182 dump_size = dump.u_ssize;
183#else
184 dump_size = dump.u_ssize << PAGE_SHIFT;
185#endif
186 DUMP_WRITE(dump_start,dump_size);
187 }
188
189 set_fs(KERNEL_DS);
190 DUMP_WRITE(current,sizeof(*current));
191close_coredump:
192 set_fs(fs);
193 return has_dumped;
194}
195
196
197
198
199
200
201static unsigned long * create_aout_tables(char * p, struct linux_binprm * bprm)
202{
203 char **argv, **envp;
204 unsigned long * sp;
205 int argc = bprm->argc;
206 int envc = bprm->envc;
207
208 sp = (unsigned long *) ((-(unsigned long)sizeof(char *)) & (unsigned long) p);
209#ifdef __sparc__
210
211 sp = (unsigned long *) (((unsigned long) sp) & ~7);
212 if ((envc+argc+3)&1) --sp;
213#endif
214#ifdef __alpha__
215
216 put_user(0, --sp);
217 put_user(0, --sp);
218 if (bprm->loader) {
219 put_user(0, --sp);
220 put_user(0x3eb, --sp);
221 put_user(bprm->loader, --sp);
222 put_user(0x3ea, --sp);
223 }
224 put_user(bprm->exec, --sp);
225 put_user(0x3e9, --sp);
226#endif
227 sp -= envc+1;
228 envp = (char **) sp;
229 sp -= argc+1;
230 argv = (char **) sp;
231#if defined(__i386__) || defined(__mc68000__)
232 put_user((unsigned long) envp,--sp);
233 put_user((unsigned long) argv,--sp);
234#endif
235 put_user(argc,--sp);
236 current->mm->arg_start = (unsigned long) p;
237 while (argc-->0) {
238 char c;
239 put_user(p,argv++);
240 do {
241 get_user(c,p++);
242 } while (c);
243 }
244 put_user(NULL,argv);
245 current->mm->arg_end = current->mm->env_start = (unsigned long) p;
246 while (envc-->0) {
247 char c;
248 put_user(p,envp++);
249 do {
250 get_user(c,p++);
251 } while (c);
252 }
253 put_user(NULL,envp);
254 current->mm->env_end = (unsigned long) p;
255 return sp;
256}
257
258static int warnings = 0;
259
260
261
262
263
264
265static int load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs)
266{
267 struct exec ex;
268 struct file * file;
269 int fd;
270 unsigned long error;
271 unsigned long p = bprm->p;
272 unsigned long fd_offset;
273 unsigned long rlim;
274 int retval;
275
276 ex = *((struct exec *) bprm->buf);
277 if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != OMAGIC &&
278 N_MAGIC(ex) != QMAGIC && N_MAGIC(ex) != NMAGIC) ||
279 N_TRSIZE(ex) || N_DRSIZE(ex) ||
280 bprm->dentry->d_inode->i_size < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) {
281 return -ENOEXEC;
282 }
283
284 fd_offset = N_TXTOFF(ex);
285
286#ifdef __i386__
287 if (N_MAGIC(ex) == ZMAGIC && fd_offset != BLOCK_SIZE) {
288 if(warnings++<10)
289 printk(KERN_NOTICE "N_TXTOFF != BLOCK_SIZE. See a.out.h.\n");
290 return -ENOEXEC;
291 }
292#endif
293
294
295
296
297
298 rlim = current->rlim[RLIMIT_DATA].rlim_cur;
299 if (rlim >= RLIM_INFINITY)
300 rlim = ~0;
301 if (ex.a_data + ex.a_bss > rlim)
302 return -ENOMEM;
303
304
305 retval = flush_old_exec(bprm);
306 if (retval)
307 return retval;
308
309
310 current->personality = PER_LINUX;
311
312#if defined(__sparc__) && !defined(__sparc_v9__)
313 memcpy(¤t->tss.core_exec, &ex, sizeof(struct exec));
314#endif
315
316 current->mm->end_code = ex.a_text +
317 (current->mm->start_code = N_TXTADDR(ex));
318 current->mm->end_data = ex.a_data +
319 (current->mm->start_data = N_DATADDR(ex));
320 current->mm->brk = ex.a_bss +
321 (current->mm->start_brk = N_BSSADDR(ex));
322
323 current->mm->rss = 0;
324 current->mm->mmap = NULL;
325 compute_creds(bprm);
326 current->flags &= ~PF_FORKNOEXEC;
327#ifdef __sparc__
328 if (N_MAGIC(ex) == NMAGIC) {
329
330 error = do_mmap(NULL, N_TXTADDR(ex), ex.a_text,
331 PROT_READ|PROT_WRITE|PROT_EXEC,
332 MAP_FIXED|MAP_PRIVATE, 0);
333 read_exec(bprm->dentry, fd_offset, (char *) N_TXTADDR(ex),
334 ex.a_text, 0);
335 error = do_mmap(NULL, N_DATADDR(ex), ex.a_data,
336 PROT_READ|PROT_WRITE|PROT_EXEC,
337 MAP_FIXED|MAP_PRIVATE, 0);
338 read_exec(bprm->dentry, fd_offset + ex.a_text, (char *) N_DATADDR(ex),
339 ex.a_data, 0);
340 goto beyond_if;
341 }
342#endif
343
344 if (N_MAGIC(ex) == OMAGIC) {
345#if defined(__alpha__) || defined(__sparc__)
346 do_mmap(NULL, N_TXTADDR(ex) & PAGE_MASK,
347 ex.a_text+ex.a_data + PAGE_SIZE - 1,
348 PROT_READ|PROT_WRITE|PROT_EXEC,
349 MAP_FIXED|MAP_PRIVATE, 0);
350 read_exec(bprm->dentry, fd_offset, (char *) N_TXTADDR(ex),
351 ex.a_text+ex.a_data, 0);
352#else
353 do_mmap(NULL, 0, ex.a_text+ex.a_data,
354 PROT_READ|PROT_WRITE|PROT_EXEC,
355 MAP_FIXED|MAP_PRIVATE, 0);
356 read_exec(bprm->dentry, 32, (char *) 0, ex.a_text+ex.a_data, 0);
357#endif
358 flush_icache_range((unsigned long) 0,
359 (unsigned long) ex.a_text+ex.a_data);
360 } else {
361 if ((ex.a_text & 0xfff || ex.a_data & 0xfff) &&
362 (N_MAGIC(ex) != NMAGIC))
363 if(warnings++<10)
364 printk(KERN_NOTICE "executable not page aligned\n");
365
366 fd = open_dentry(bprm->dentry, O_RDONLY);
367 if (fd < 0)
368 return fd;
369 file = fget(fd);
370
371 if (!file->f_op || !file->f_op->mmap ||
372 fd_offset & (bprm->dentry->d_inode->i_sb->s_blocksize-1)) {
373 if (warnings++<10)
374 printk(KERN_NOTICE
375 "fd_offset is not blocksize aligned. Loading %s in anonymous memory.\n",
376 file->f_dentry->d_name.name);
377 fput(file);
378 sys_close(fd);
379 do_mmap(NULL, N_TXTADDR(ex), ex.a_text+ex.a_data,
380 PROT_READ|PROT_WRITE|PROT_EXEC,
381 MAP_FIXED|MAP_PRIVATE, 0);
382 read_exec(bprm->dentry, fd_offset,
383 (char *) N_TXTADDR(ex), ex.a_text+ex.a_data, 0);
384 flush_icache_range((unsigned long) N_TXTADDR(ex),
385 (unsigned long) N_TXTADDR(ex) +
386 ex.a_text+ex.a_data);
387 goto beyond_if;
388 }
389
390 error = do_mmap(file, N_TXTADDR(ex), ex.a_text,
391 PROT_READ | PROT_EXEC,
392 MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE,
393 fd_offset);
394
395 if (error != N_TXTADDR(ex)) {
396 fput(file);
397 sys_close(fd);
398 send_sig(SIGKILL, current, 0);
399 return error;
400 }
401
402 error = do_mmap(file, N_DATADDR(ex), ex.a_data,
403 PROT_READ | PROT_WRITE | PROT_EXEC,
404 MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE,
405 fd_offset + ex.a_text);
406 fput(file);
407 sys_close(fd);
408 if (error != N_DATADDR(ex)) {
409 send_sig(SIGKILL, current, 0);
410 return error;
411 }
412 }
413beyond_if:
414 set_binfmt(&aout_format);
415 if (current->exec_domain && current->exec_domain->module)
416 __MOD_DEC_USE_COUNT(current->exec_domain->module);
417 current->exec_domain = lookup_exec_domain(current->personality);
418 if (current->exec_domain && current->exec_domain->module)
419 __MOD_INC_USE_COUNT(current->exec_domain->module);
420
421 set_brk(current->mm->start_brk, current->mm->brk);
422
423 p = setup_arg_pages(p, bprm);
424
425 p = (unsigned long) create_aout_tables((char *)p, bprm);
426 current->mm->start_stack = p;
427#ifdef __alpha__
428 regs->gp = ex.a_gpvalue;
429#endif
430 start_thread(regs, ex.a_entry, p);
431 if (current->ptrace & PT_PTRACED)
432 send_sig(SIGTRAP, current, 0);
433 return 0;
434}
435
436static int load_aout_library(struct file *file)
437{
438 struct inode * inode;
439 unsigned long bss, start_addr, len;
440 unsigned long error;
441 int retval;
442 loff_t offset = 0;
443 struct exec ex;
444
445 inode = file->f_dentry->d_inode;
446
447 retval = -ENOEXEC;
448
449 set_fs(KERNEL_DS);
450 error = file->f_op->read(file, (char *) &ex, sizeof(ex), &offset);
451 set_fs(USER_DS);
452 if (error != sizeof(ex))
453 goto out_putf;
454
455
456 if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != QMAGIC) || N_TRSIZE(ex) ||
457 N_DRSIZE(ex) || ((ex.a_entry & 0xfff) && N_MAGIC(ex) == ZMAGIC) ||
458 inode->i_size < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) {
459 goto out_putf;
460 }
461
462 if (N_FLAGS(ex))
463 goto out_putf;
464
465
466
467
468 start_addr = ex.a_entry & 0xfffff000;
469
470 if (N_TXTOFF(ex) & (inode->i_sb->s_blocksize-1)) {
471 if (warnings++<10)
472 printk(KERN_NOTICE
473 "N_TXTOFF is not blocksize aligned. Loading library %s in anonymous memory.\n",
474 file->f_dentry->d_name.name);
475 do_mmap(NULL, start_addr, ex.a_text + ex.a_data,
476 PROT_READ | PROT_WRITE | PROT_EXEC,
477 MAP_FIXED| MAP_PRIVATE, 0);
478 read_exec(file->f_dentry, N_TXTOFF(ex),
479 (char *)start_addr, ex.a_text + ex.a_data, 0);
480 flush_icache_range((unsigned long) start_addr,
481 (unsigned long) start_addr + ex.a_text + ex.a_data);
482 goto map_bss;
483 }
484
485 error = do_mmap(file, start_addr, ex.a_text + ex.a_data,
486 PROT_READ | PROT_WRITE | PROT_EXEC,
487 MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE,
488 N_TXTOFF(ex));
489 retval = error;
490 if (error != start_addr)
491 goto out_putf;
492
493 map_bss:
494 len = PAGE_ALIGN(ex.a_text + ex.a_data);
495 bss = ex.a_text + ex.a_data + ex.a_bss;
496 if (bss > len) {
497 error = do_mmap(NULL, start_addr + len, bss - len,
498 PROT_READ | PROT_WRITE | PROT_EXEC,
499 MAP_PRIVATE | MAP_FIXED, 0);
500 retval = error;
501 if (error != start_addr + len)
502 goto out_putf;
503 }
504 retval = 0;
505
506out_putf:
507 return retval;
508}
509
510int __init init_aout_binfmt(void)
511{
512 return register_binfmt(&aout_format);
513}
514
515#ifdef MODULE
516int init_module(void) {
517 return init_aout_binfmt();
518}
519
520void cleanup_module( void) {
521 unregister_binfmt(&aout_format);
522}
523#endif
524