~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/fs/binfmt_aout.c

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  *  linux/fs/binfmt_aout.c
  3  *
  4  *  Copyright (C) 1991, 1992, 1996  Linus Torvalds
  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/pgalloc.h>
 31 
 32 static int load_aout_binary(struct linux_binprm *, struct pt_regs * regs);
 33 static int load_aout_library(struct file*);
 34 static int aout_core_dump(long signr, struct pt_regs * regs, struct file *file);
 35 
 36 extern void dump_thread(struct pt_regs *, struct user *);
 37 
 38 static struct linux_binfmt aout_format = {
 39         NULL, THIS_MODULE, load_aout_binary, load_aout_library, aout_core_dump, PAGE_SIZE
 40 };
 41 
 42 static void set_brk(unsigned long start, unsigned long end)
 43 {
 44         start = PAGE_ALIGN(start);
 45         end = PAGE_ALIGN(end);
 46         if (end <= start)
 47                 return;
 48         do_brk(start, end - start);
 49 }
 50 
 51 /*
 52  * These are the only things you should do on a core-file: use only these
 53  * macros to write out all the necessary info.
 54  */
 55 
 56 static int dump_write(struct file *file, const void *addr, int nr)
 57 {
 58         return file->f_op->write(file, addr, nr, &file->f_pos) == nr;
 59 }
 60 
 61 #define DUMP_WRITE(addr, nr)    \
 62         if (!dump_write(file, (void *)(addr), (nr))) \
 63                 goto end_coredump;
 64 
 65 #define DUMP_SEEK(offset) \
 66 if (file->f_op->llseek) { \
 67         if (file->f_op->llseek(file,(offset),0) != (offset)) \
 68                 goto end_coredump; \
 69 } else file->f_pos = (offset)
 70 
 71 /*
 72  * Routine writes a core dump image in the current directory.
 73  * Currently only a stub-function.
 74  *
 75  * Note that setuid/setgid files won't make a core-dump if the uid/gid
 76  * changed due to the set[u|g]id. It's enforced by the "current->dumpable"
 77  * field, which also makes sure the core-dumps won't be recursive if the
 78  * dumping of the process results in another error..
 79  */
 80 
 81 static int aout_core_dump(long signr, struct pt_regs * regs, struct file *file)
 82 {
 83         mm_segment_t fs;
 84         int has_dumped = 0;
 85         unsigned long dump_start, dump_size;
 86         struct user dump;
 87 #if defined(__alpha__)
 88 #       define START_DATA(u)    (u.start_data)
 89 #elif defined(__arm__)
 90 #       define START_DATA(u)    ((u.u_tsize << PAGE_SHIFT) + u.start_code)
 91 #elif defined(__sparc__)
 92 #       define START_DATA(u)    (u.u_tsize)
 93 #elif defined(__i386__) || defined(__mc68000__)
 94 #       define START_DATA(u)    (u.u_tsize << PAGE_SHIFT)
 95 #endif
 96 #ifdef __sparc__
 97 #       define START_STACK(u)   ((regs->u_regs[UREG_FP]) & ~(PAGE_SIZE - 1))
 98 #else
 99 #       define START_STACK(u)   (u.start_stack)
100 #endif
101 
102         fs = get_fs();
103         set_fs(KERNEL_DS);
104         has_dumped = 1;
105         current->flags |= PF_DUMPCORE;
106         strncpy(dump.u_comm, current->comm, sizeof(current->comm));
107 #ifndef __sparc__
108         dump.u_ar0 = (void *)(((unsigned long)(&dump.regs)) - ((unsigned long)(&dump)));
109 #endif
110         dump.signal = signr;
111         dump_thread(regs, &dump);
112 
113 /* If the size of the dump file exceeds the rlimit, then see what would happen
114    if we wrote the stack, but not the data area.  */
115 #ifdef __sparc__
116         if ((dump.u_dsize+dump.u_ssize) >
117             current->rlim[RLIMIT_CORE].rlim_cur)
118                 dump.u_dsize = 0;
119 #else
120         if ((dump.u_dsize+dump.u_ssize+1) * PAGE_SIZE >
121             current->rlim[RLIMIT_CORE].rlim_cur)
122                 dump.u_dsize = 0;
123 #endif
124 
125 /* Make sure we have enough room to write the stack and data areas. */
126 #ifdef __sparc__
127         if ((dump.u_ssize) >
128             current->rlim[RLIMIT_CORE].rlim_cur)
129                 dump.u_ssize = 0;
130 #else
131         if ((dump.u_ssize+1) * PAGE_SIZE >
132             current->rlim[RLIMIT_CORE].rlim_cur)
133                 dump.u_ssize = 0;
134 #endif
135 
136 /* make sure we actually have a data and stack area to dump */
137         set_fs(USER_DS);
138 #ifdef __sparc__
139         if (verify_area(VERIFY_READ, (void *) START_DATA(dump), dump.u_dsize))
140                 dump.u_dsize = 0;
141         if (verify_area(VERIFY_READ, (void *) START_STACK(dump), dump.u_ssize))
142                 dump.u_ssize = 0;
143 #else
144         if (verify_area(VERIFY_READ, (void *) START_DATA(dump), dump.u_dsize << PAGE_SHIFT))
145                 dump.u_dsize = 0;
146         if (verify_area(VERIFY_READ, (void *) START_STACK(dump), dump.u_ssize << PAGE_SHIFT))
147                 dump.u_ssize = 0;
148 #endif
149 
150         set_fs(KERNEL_DS);
151 /* struct user */
152         DUMP_WRITE(&dump,sizeof(dump));
153 /* Now dump all of the user data.  Include malloced stuff as well */
154 #ifndef __sparc__
155         DUMP_SEEK(PAGE_SIZE);
156 #endif
157 /* now we start writing out the user space info */
158         set_fs(USER_DS);
159 /* Dump the data area */
160         if (dump.u_dsize != 0) {
161                 dump_start = START_DATA(dump);
162 #ifdef __sparc__
163                 dump_size = dump.u_dsize;
164 #else
165                 dump_size = dump.u_dsize << PAGE_SHIFT;
166 #endif
167                 DUMP_WRITE(dump_start,dump_size);
168         }
169 /* Now prepare to dump the stack area */
170         if (dump.u_ssize != 0) {
171                 dump_start = START_STACK(dump);
172 #ifdef __sparc__
173                 dump_size = dump.u_ssize;
174 #else
175                 dump_size = dump.u_ssize << PAGE_SHIFT;
176 #endif
177                 DUMP_WRITE(dump_start,dump_size);
178         }
179 /* Finally dump the task struct.  Not be used by gdb, but could be useful */
180         set_fs(KERNEL_DS);
181         DUMP_WRITE(current,sizeof(*current));
182 end_coredump:
183         set_fs(fs);
184         return has_dumped;
185 }
186 
187 /*
188  * create_aout_tables() parses the env- and arg-strings in new user
189  * memory and creates the pointer tables from them, and puts their
190  * addresses on the "stack", returning the new stack pointer value.
191  */
192 static unsigned long * create_aout_tables(char * p, struct linux_binprm * bprm)
193 {
194         char **argv, **envp;
195         unsigned long * sp;
196         int argc = bprm->argc;
197         int envc = bprm->envc;
198 
199         sp = (unsigned long *) ((-(unsigned long)sizeof(char *)) & (unsigned long) p);
200 #ifdef __sparc__
201         /* This imposes the proper stack alignment for a new process. */
202         sp = (unsigned long *) (((unsigned long) sp) & ~7);
203         if ((envc+argc+3)&1) --sp;
204 #endif
205 #ifdef __alpha__
206 /* whee.. test-programs are so much fun. */
207         put_user(0, --sp);
208         put_user(0, --sp);
209         if (bprm->loader) {
210                 put_user(0, --sp);
211                 put_user(0x3eb, --sp);
212                 put_user(bprm->loader, --sp);
213                 put_user(0x3ea, --sp);
214         }
215         put_user(bprm->exec, --sp);
216         put_user(0x3e9, --sp);
217 #endif
218         sp -= envc+1;
219         envp = (char **) sp;
220         sp -= argc+1;
221         argv = (char **) sp;
222 #if defined(__i386__) || defined(__mc68000__) || defined(__arm__)
223         put_user((unsigned long) envp,--sp);
224         put_user((unsigned long) argv,--sp);
225 #endif
226         put_user(argc,--sp);
227         current->mm->arg_start = (unsigned long) p;
228         while (argc-->0) {
229                 char c;
230                 put_user(p,argv++);
231                 do {
232                         get_user(c,p++);
233                 } while (c);
234         }
235         put_user(NULL,argv);
236         current->mm->arg_end = current->mm->env_start = (unsigned long) p;
237         while (envc-->0) {
238                 char c;
239                 put_user(p,envp++);
240                 do {
241                         get_user(c,p++);
242                 } while (c);
243         }
244         put_user(NULL,envp);
245         current->mm->env_end = (unsigned long) p;
246         return sp;
247 }
248 
249 /*
250  * These are the functions used to load a.out style executables and shared
251  * libraries.  There is no binary dependent code anywhere else.
252  */
253 
254 static int load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs)
255 {
256         struct exec ex;
257         unsigned long error;
258         unsigned long fd_offset;
259         unsigned long rlim;
260         int retval;
261 
262         ex = *((struct exec *) bprm->buf);              /* exec-header */
263         if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != OMAGIC &&
264              N_MAGIC(ex) != QMAGIC && N_MAGIC(ex) != NMAGIC) ||
265             N_TRSIZE(ex) || N_DRSIZE(ex) ||
266             bprm->file->f_dentry->d_inode->i_size < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) {
267                 return -ENOEXEC;
268         }
269 
270         fd_offset = N_TXTOFF(ex);
271 
272         /* Check initial limits. This avoids letting people circumvent
273          * size limits imposed on them by creating programs with large
274          * arrays in the data or bss.
275          */
276         rlim = current->rlim[RLIMIT_DATA].rlim_cur;
277         if (rlim >= RLIM_INFINITY)
278                 rlim = ~0;
279         if (ex.a_data + ex.a_bss > rlim)
280                 return -ENOMEM;
281 
282         /* Flush all traces of the currently running executable */
283         retval = flush_old_exec(bprm);
284         if (retval)
285                 return retval;
286 
287         /* OK, This is the point of no return */
288 #if !defined(__sparc__)
289         set_personality(PER_LINUX);
290 #else
291         set_personality(PER_SUNOS);
292 #if !defined(__sparc_v9__)
293         memcpy(&current->thread.core_exec, &ex, sizeof(struct exec));
294 #endif
295 #endif
296 
297         current->mm->end_code = ex.a_text +
298                 (current->mm->start_code = N_TXTADDR(ex));
299         current->mm->end_data = ex.a_data +
300                 (current->mm->start_data = N_DATADDR(ex));
301         current->mm->brk = ex.a_bss +
302                 (current->mm->start_brk = N_BSSADDR(ex));
303 
304         current->mm->rss = 0;
305         current->mm->mmap = NULL;
306         compute_creds(bprm);
307         current->flags &= ~PF_FORKNOEXEC;
308 #ifdef __sparc__
309         if (N_MAGIC(ex) == NMAGIC) {
310                 loff_t pos = fd_offset;
311                 /* Fuck me plenty... */
312                 /* <AOL></AOL> */
313                 error = do_brk(N_TXTADDR(ex), ex.a_text);
314                 bprm->file->f_op->read(bprm->file, (char *) N_TXTADDR(ex),
315                           ex.a_text, &pos);
316                 error = do_brk(N_DATADDR(ex), ex.a_data);
317                 bprm->file->f_op->read(bprm->file, (char *) N_DATADDR(ex),
318                           ex.a_data, &pos);
319                 goto beyond_if;
320         }
321 #endif
322 
323         if (N_MAGIC(ex) == OMAGIC) {
324                 unsigned long text_addr, map_size;
325                 loff_t pos;
326 
327                 text_addr = N_TXTADDR(ex);
328 
329 #if defined(__alpha__) || defined(__sparc__)
330                 pos = fd_offset;
331                 map_size = ex.a_text+ex.a_data + PAGE_SIZE - 1;
332 #else
333                 pos = 32;
334                 map_size = ex.a_text+ex.a_data;
335 #endif
336 
337                 error = do_brk(text_addr & PAGE_MASK, map_size);
338                 if (error != (text_addr & PAGE_MASK)) {
339                         send_sig(SIGKILL, current, 0);
340                         return error;
341                 }
342 
343                 error = bprm->file->f_op->read(bprm->file, (char *)text_addr,
344                           ex.a_text+ex.a_data, &pos);
345                 if (error < 0) {
346                         send_sig(SIGKILL, current, 0);
347                         return error;
348                 }
349                          
350                 flush_icache_range(text_addr, text_addr+ex.a_text+ex.a_data);
351         } else {
352                 static unsigned long error_time, error_time2;
353                 if ((ex.a_text & 0xfff || ex.a_data & 0xfff) &&
354                     (N_MAGIC(ex) != NMAGIC) && (jiffies-error_time2) > 5*HZ)
355                 {
356                         printk(KERN_NOTICE "executable not page aligned\n");
357                         error_time2 = jiffies;
358                 }
359 
360                 if ((fd_offset & ~PAGE_MASK) != 0 &&
361                     (jiffies-error_time) > 5*HZ)
362                 {
363                         printk(KERN_WARNING 
364                                "fd_offset is not page aligned. Please convert program: %s\n",
365                                bprm->file->f_dentry->d_name.name);
366                         error_time = jiffies;
367                 }
368 
369                 if (!bprm->file->f_op->mmap||((fd_offset & ~PAGE_MASK) != 0)) {
370                         loff_t pos = fd_offset;
371                         do_brk(N_TXTADDR(ex), ex.a_text+ex.a_data);
372                         bprm->file->f_op->read(bprm->file,(char *)N_TXTADDR(ex),
373                                         ex.a_text+ex.a_data, &pos);
374                         flush_icache_range((unsigned long) N_TXTADDR(ex),
375                                            (unsigned long) N_TXTADDR(ex) +
376                                            ex.a_text+ex.a_data);
377                         goto beyond_if;
378                 }
379 
380                 down(&current->mm->mmap_sem);
381                 error = do_mmap(bprm->file, N_TXTADDR(ex), ex.a_text,
382                         PROT_READ | PROT_EXEC,
383                         MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE,
384                         fd_offset);
385                 up(&current->mm->mmap_sem);
386 
387                 if (error != N_TXTADDR(ex)) {
388                         send_sig(SIGKILL, current, 0);
389                         return error;
390                 }
391 
392                 down(&current->mm->mmap_sem);
393                 error = do_mmap(bprm->file, N_DATADDR(ex), ex.a_data,
394                                 PROT_READ | PROT_WRITE | PROT_EXEC,
395                                 MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE,
396                                 fd_offset + ex.a_text);
397                 up(&current->mm->mmap_sem);
398                 if (error != N_DATADDR(ex)) {
399                         send_sig(SIGKILL, current, 0);
400                         return error;
401                 }
402         }
403 beyond_if:
404         set_binfmt(&aout_format);
405 
406         set_brk(current->mm->start_brk, current->mm->brk);
407 
408         retval = setup_arg_pages(bprm); 
409         if (retval < 0) { 
410                 /* Someone check-me: is this error path enough? */ 
411                 send_sig(SIGKILL, current, 0); 
412                 return retval;
413         }
414 
415         current->mm->start_stack =
416                 (unsigned long) create_aout_tables((char *) bprm->p, bprm);
417 #ifdef __alpha__
418         regs->gp = ex.a_gpvalue;
419 #endif
420         start_thread(regs, ex.a_entry, current->mm->start_stack);
421         if (current->ptrace & PT_PTRACED)
422                 send_sig(SIGTRAP, current, 0);
423         return 0;
424 }
425 
426 static int load_aout_library(struct file *file)
427 {
428         struct inode * inode;
429         unsigned long bss, start_addr, len;
430         unsigned long error;
431         int retval;
432         struct exec ex;
433 
434         inode = file->f_dentry->d_inode;
435 
436         retval = -ENOEXEC;
437         error = kernel_read(file, 0, (char *) &ex, sizeof(ex));
438         if (error != sizeof(ex))
439                 goto out;
440 
441         /* We come in here for the regular a.out style of shared libraries */
442         if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != QMAGIC) || N_TRSIZE(ex) ||
443             N_DRSIZE(ex) || ((ex.a_entry & 0xfff) && N_MAGIC(ex) == ZMAGIC) ||
444             inode->i_size < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) {
445                 goto out;
446         }
447 
448         if (N_FLAGS(ex))
449                 goto out;
450 
451         /* For  QMAGIC, the starting address is 0x20 into the page.  We mask
452            this off to get the starting address for the page */
453 
454         start_addr =  ex.a_entry & 0xfffff000;
455 
456         if ((N_TXTOFF(ex) & ~PAGE_MASK) != 0) {
457                 static unsigned long error_time;
458                 loff_t pos = N_TXTOFF(ex);
459 
460                 if ((jiffies-error_time) > 5*HZ)
461                 {
462                         printk(KERN_WARNING 
463                                "N_TXTOFF is not page aligned. Please convert library: %s\n",
464                                file->f_dentry->d_name.name);
465                         error_time = jiffies;
466                 }
467 
468                 do_brk(start_addr, ex.a_text + ex.a_data + ex.a_bss);
469                 
470                 file->f_op->read(file, (char *)start_addr,
471                         ex.a_text + ex.a_data, &pos);
472                 flush_icache_range((unsigned long) start_addr,
473                                    (unsigned long) start_addr + ex.a_text + ex.a_data);
474 
475                 retval = 0;
476                 goto out;
477         }
478         /* Now use mmap to map the library into memory. */
479         down(&current->mm->mmap_sem);
480         error = do_mmap(file, start_addr, ex.a_text + ex.a_data,
481                         PROT_READ | PROT_WRITE | PROT_EXEC,
482                         MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE,
483                         N_TXTOFF(ex));
484         up(&current->mm->mmap_sem);
485         retval = error;
486         if (error != start_addr)
487                 goto out;
488 
489         len = PAGE_ALIGN(ex.a_text + ex.a_data);
490         bss = ex.a_text + ex.a_data + ex.a_bss;
491         if (bss > len) {
492                 error = do_brk(start_addr + len, bss - len);
493                 retval = error;
494                 if (error != start_addr + len)
495                         goto out;
496         }
497         retval = 0;
498 out:
499         return retval;
500 }
501 
502 static int __init init_aout_binfmt(void)
503 {
504         return register_binfmt(&aout_format);
505 }
506 
507 static void __exit exit_aout_binfmt(void)
508 {
509         unregister_binfmt(&aout_format);
510 }
511 
512 EXPORT_NO_SYMBOLS;
513 
514 module_init(init_aout_binfmt);
515 module_exit(exit_aout_binfmt);
516 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.