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