Back to home page

LXR

 
 

    


0001 /*
0002  *  linux/fs/binfmt_aout.c
0003  *
0004  *  Copyright (C) 1991, 1992, 1996  Linus Torvalds
0005  */
0006 
0007 #include <linux/module.h>
0008 
0009 #include <linux/time.h>
0010 #include <linux/kernel.h>
0011 #include <linux/mm.h>
0012 #include <linux/mman.h>
0013 #include <linux/a.out.h>
0014 #include <linux/errno.h>
0015 #include <linux/signal.h>
0016 #include <linux/string.h>
0017 #include <linux/fs.h>
0018 #include <linux/file.h>
0019 #include <linux/stat.h>
0020 #include <linux/fcntl.h>
0021 #include <linux/ptrace.h>
0022 #include <linux/user.h>
0023 #include <linux/binfmts.h>
0024 #include <linux/personality.h>
0025 #include <linux/init.h>
0026 #include <linux/coredump.h>
0027 #include <linux/slab.h>
0028 
0029 #include <linux/uaccess.h>
0030 #include <asm/cacheflush.h>
0031 #include <asm/a.out-core.h>
0032 
0033 static int load_aout_binary(struct linux_binprm *);
0034 static int load_aout_library(struct file*);
0035 
0036 #ifdef CONFIG_COREDUMP
0037 /*
0038  * Routine writes a core dump image in the current directory.
0039  * Currently only a stub-function.
0040  *
0041  * Note that setuid/setgid files won't make a core-dump if the uid/gid
0042  * changed due to the set[u|g]id. It's enforced by the "current->mm->dumpable"
0043  * field, which also makes sure the core-dumps won't be recursive if the
0044  * dumping of the process results in another error..
0045  */
0046 static int aout_core_dump(struct coredump_params *cprm)
0047 {
0048     mm_segment_t fs;
0049     int has_dumped = 0;
0050     void __user *dump_start;
0051     int dump_size;
0052     struct user dump;
0053 #ifdef __alpha__
0054 #       define START_DATA(u)    ((void __user *)u.start_data)
0055 #else
0056 #   define START_DATA(u)    ((void __user *)((u.u_tsize << PAGE_SHIFT) + \
0057                  u.start_code))
0058 #endif
0059 #       define START_STACK(u)   ((void __user *)u.start_stack)
0060 
0061     fs = get_fs();
0062     set_fs(KERNEL_DS);
0063     has_dumped = 1;
0064         strncpy(dump.u_comm, current->comm, sizeof(dump.u_comm));
0065     dump.u_ar0 = offsetof(struct user, regs);
0066     dump.signal = cprm->siginfo->si_signo;
0067     aout_dump_thread(cprm->regs, &dump);
0068 
0069 /* If the size of the dump file exceeds the rlimit, then see what would happen
0070    if we wrote the stack, but not the data area.  */
0071     if ((dump.u_dsize + dump.u_ssize+1) * PAGE_SIZE > cprm->limit)
0072         dump.u_dsize = 0;
0073 
0074 /* Make sure we have enough room to write the stack and data areas. */
0075     if ((dump.u_ssize + 1) * PAGE_SIZE > cprm->limit)
0076         dump.u_ssize = 0;
0077 
0078 /* make sure we actually have a data and stack area to dump */
0079     set_fs(USER_DS);
0080     if (!access_ok(VERIFY_READ, START_DATA(dump), dump.u_dsize << PAGE_SHIFT))
0081         dump.u_dsize = 0;
0082     if (!access_ok(VERIFY_READ, START_STACK(dump), dump.u_ssize << PAGE_SHIFT))
0083         dump.u_ssize = 0;
0084 
0085     set_fs(KERNEL_DS);
0086 /* struct user */
0087     if (!dump_emit(cprm, &dump, sizeof(dump)))
0088         goto end_coredump;
0089 /* Now dump all of the user data.  Include malloced stuff as well */
0090     if (!dump_skip(cprm, PAGE_SIZE - sizeof(dump)))
0091         goto end_coredump;
0092 /* now we start writing out the user space info */
0093     set_fs(USER_DS);
0094 /* Dump the data area */
0095     if (dump.u_dsize != 0) {
0096         dump_start = START_DATA(dump);
0097         dump_size = dump.u_dsize << PAGE_SHIFT;
0098         if (!dump_emit(cprm, dump_start, dump_size))
0099             goto end_coredump;
0100     }
0101 /* Now prepare to dump the stack area */
0102     if (dump.u_ssize != 0) {
0103         dump_start = START_STACK(dump);
0104         dump_size = dump.u_ssize << PAGE_SHIFT;
0105         if (!dump_emit(cprm, dump_start, dump_size))
0106             goto end_coredump;
0107     }
0108 end_coredump:
0109     set_fs(fs);
0110     return has_dumped;
0111 }
0112 #else
0113 #define aout_core_dump NULL
0114 #endif
0115 
0116 static struct linux_binfmt aout_format = {
0117     .module     = THIS_MODULE,
0118     .load_binary    = load_aout_binary,
0119     .load_shlib = load_aout_library,
0120     .core_dump  = aout_core_dump,
0121     .min_coredump   = PAGE_SIZE
0122 };
0123 
0124 #define BAD_ADDR(x) ((unsigned long)(x) >= TASK_SIZE)
0125 
0126 static int set_brk(unsigned long start, unsigned long end)
0127 {
0128     start = PAGE_ALIGN(start);
0129     end = PAGE_ALIGN(end);
0130     if (end > start)
0131         return vm_brk(start, end - start);
0132     return 0;
0133 }
0134 
0135 /*
0136  * create_aout_tables() parses the env- and arg-strings in new user
0137  * memory and creates the pointer tables from them, and puts their
0138  * addresses on the "stack", returning the new stack pointer value.
0139  */
0140 static unsigned long __user *create_aout_tables(char __user *p, struct linux_binprm * bprm)
0141 {
0142     char __user * __user *argv;
0143     char __user * __user *envp;
0144     unsigned long __user *sp;
0145     int argc = bprm->argc;
0146     int envc = bprm->envc;
0147 
0148     sp = (void __user *)((-(unsigned long)sizeof(char *)) & (unsigned long) p);
0149 #ifdef __alpha__
0150 /* whee.. test-programs are so much fun. */
0151     put_user(0, --sp);
0152     put_user(0, --sp);
0153     if (bprm->loader) {
0154         put_user(0, --sp);
0155         put_user(1003, --sp);
0156         put_user(bprm->loader, --sp);
0157         put_user(1002, --sp);
0158     }
0159     put_user(bprm->exec, --sp);
0160     put_user(1001, --sp);
0161 #endif
0162     sp -= envc+1;
0163     envp = (char __user * __user *) sp;
0164     sp -= argc+1;
0165     argv = (char __user * __user *) sp;
0166 #ifndef __alpha__
0167     put_user((unsigned long) envp,--sp);
0168     put_user((unsigned long) argv,--sp);
0169 #endif
0170     put_user(argc,--sp);
0171     current->mm->arg_start = (unsigned long) p;
0172     while (argc-->0) {
0173         char c;
0174         put_user(p,argv++);
0175         do {
0176             get_user(c,p++);
0177         } while (c);
0178     }
0179     put_user(NULL,argv);
0180     current->mm->arg_end = current->mm->env_start = (unsigned long) p;
0181     while (envc-->0) {
0182         char c;
0183         put_user(p,envp++);
0184         do {
0185             get_user(c,p++);
0186         } while (c);
0187     }
0188     put_user(NULL,envp);
0189     current->mm->env_end = (unsigned long) p;
0190     return sp;
0191 }
0192 
0193 /*
0194  * These are the functions used to load a.out style executables and shared
0195  * libraries.  There is no binary dependent code anywhere else.
0196  */
0197 
0198 static int load_aout_binary(struct linux_binprm * bprm)
0199 {
0200     struct pt_regs *regs = current_pt_regs();
0201     struct exec ex;
0202     unsigned long error;
0203     unsigned long fd_offset;
0204     unsigned long rlim;
0205     int retval;
0206 
0207     ex = *((struct exec *) bprm->buf);      /* exec-header */
0208     if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != OMAGIC &&
0209          N_MAGIC(ex) != QMAGIC && N_MAGIC(ex) != NMAGIC) ||
0210         N_TRSIZE(ex) || N_DRSIZE(ex) ||
0211         i_size_read(file_inode(bprm->file)) < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) {
0212         return -ENOEXEC;
0213     }
0214 
0215     /*
0216      * Requires a mmap handler. This prevents people from using a.out
0217      * as part of an exploit attack against /proc-related vulnerabilities.
0218      */
0219     if (!bprm->file->f_op->mmap)
0220         return -ENOEXEC;
0221 
0222     fd_offset = N_TXTOFF(ex);
0223 
0224     /* Check initial limits. This avoids letting people circumvent
0225      * size limits imposed on them by creating programs with large
0226      * arrays in the data or bss.
0227      */
0228     rlim = rlimit(RLIMIT_DATA);
0229     if (rlim >= RLIM_INFINITY)
0230         rlim = ~0;
0231     if (ex.a_data + ex.a_bss > rlim)
0232         return -ENOMEM;
0233 
0234     /* Flush all traces of the currently running executable */
0235     retval = flush_old_exec(bprm);
0236     if (retval)
0237         return retval;
0238 
0239     /* OK, This is the point of no return */
0240 #ifdef __alpha__
0241     SET_AOUT_PERSONALITY(bprm, ex);
0242 #else
0243     set_personality(PER_LINUX);
0244 #endif
0245     setup_new_exec(bprm);
0246 
0247     current->mm->end_code = ex.a_text +
0248         (current->mm->start_code = N_TXTADDR(ex));
0249     current->mm->end_data = ex.a_data +
0250         (current->mm->start_data = N_DATADDR(ex));
0251     current->mm->brk = ex.a_bss +
0252         (current->mm->start_brk = N_BSSADDR(ex));
0253 
0254     retval = setup_arg_pages(bprm, STACK_TOP, EXSTACK_DEFAULT);
0255     if (retval < 0)
0256         return retval;
0257 
0258     install_exec_creds(bprm);
0259 
0260     if (N_MAGIC(ex) == OMAGIC) {
0261         unsigned long text_addr, map_size;
0262         loff_t pos;
0263 
0264         text_addr = N_TXTADDR(ex);
0265 
0266 #ifdef __alpha__
0267         pos = fd_offset;
0268         map_size = ex.a_text+ex.a_data + PAGE_SIZE - 1;
0269 #else
0270         pos = 32;
0271         map_size = ex.a_text+ex.a_data;
0272 #endif
0273         error = vm_brk(text_addr & PAGE_MASK, map_size);
0274         if (error)
0275             return error;
0276 
0277         error = read_code(bprm->file, text_addr, pos,
0278                   ex.a_text+ex.a_data);
0279         if ((signed long)error < 0)
0280             return error;
0281     } else {
0282         if ((ex.a_text & 0xfff || ex.a_data & 0xfff) &&
0283             (N_MAGIC(ex) != NMAGIC) && printk_ratelimit())
0284         {
0285             printk(KERN_NOTICE "executable not page aligned\n");
0286         }
0287 
0288         if ((fd_offset & ~PAGE_MASK) != 0 && printk_ratelimit())
0289         {
0290             printk(KERN_WARNING 
0291                    "fd_offset is not page aligned. Please convert program: %pD\n",
0292                    bprm->file);
0293         }
0294 
0295         if (!bprm->file->f_op->mmap||((fd_offset & ~PAGE_MASK) != 0)) {
0296             error = vm_brk(N_TXTADDR(ex), ex.a_text+ex.a_data);
0297             if (error)
0298                 return error;
0299 
0300             read_code(bprm->file, N_TXTADDR(ex), fd_offset,
0301                   ex.a_text + ex.a_data);
0302             goto beyond_if;
0303         }
0304 
0305         error = vm_mmap(bprm->file, N_TXTADDR(ex), ex.a_text,
0306             PROT_READ | PROT_EXEC,
0307             MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE,
0308             fd_offset);
0309 
0310         if (error != N_TXTADDR(ex))
0311             return error;
0312 
0313         error = vm_mmap(bprm->file, N_DATADDR(ex), ex.a_data,
0314                 PROT_READ | PROT_WRITE | PROT_EXEC,
0315                 MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE,
0316                 fd_offset + ex.a_text);
0317         if (error != N_DATADDR(ex))
0318             return error;
0319     }
0320 beyond_if:
0321     set_binfmt(&aout_format);
0322 
0323     retval = set_brk(current->mm->start_brk, current->mm->brk);
0324     if (retval < 0)
0325         return retval;
0326 
0327     current->mm->start_stack =
0328         (unsigned long) create_aout_tables((char __user *) bprm->p, bprm);
0329 #ifdef __alpha__
0330     regs->gp = ex.a_gpvalue;
0331 #endif
0332     start_thread(regs, ex.a_entry, current->mm->start_stack);
0333     return 0;
0334 }
0335 
0336 static int load_aout_library(struct file *file)
0337 {
0338     struct inode * inode;
0339     unsigned long bss, start_addr, len;
0340     unsigned long error;
0341     int retval;
0342     struct exec ex;
0343 
0344     inode = file_inode(file);
0345 
0346     retval = -ENOEXEC;
0347     error = kernel_read(file, 0, (char *) &ex, sizeof(ex));
0348     if (error != sizeof(ex))
0349         goto out;
0350 
0351     /* We come in here for the regular a.out style of shared libraries */
0352     if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != QMAGIC) || N_TRSIZE(ex) ||
0353         N_DRSIZE(ex) || ((ex.a_entry & 0xfff) && N_MAGIC(ex) == ZMAGIC) ||
0354         i_size_read(inode) < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) {
0355         goto out;
0356     }
0357 
0358     /*
0359      * Requires a mmap handler. This prevents people from using a.out
0360      * as part of an exploit attack against /proc-related vulnerabilities.
0361      */
0362     if (!file->f_op->mmap)
0363         goto out;
0364 
0365     if (N_FLAGS(ex))
0366         goto out;
0367 
0368     /* For  QMAGIC, the starting address is 0x20 into the page.  We mask
0369        this off to get the starting address for the page */
0370 
0371     start_addr =  ex.a_entry & 0xfffff000;
0372 
0373     if ((N_TXTOFF(ex) & ~PAGE_MASK) != 0) {
0374         if (printk_ratelimit())
0375         {
0376             printk(KERN_WARNING 
0377                    "N_TXTOFF is not page aligned. Please convert library: %pD\n",
0378                    file);
0379         }
0380         retval = vm_brk(start_addr, ex.a_text + ex.a_data + ex.a_bss);
0381         if (retval)
0382             goto out;
0383 
0384         read_code(file, start_addr, N_TXTOFF(ex),
0385               ex.a_text + ex.a_data);
0386         retval = 0;
0387         goto out;
0388     }
0389     /* Now use mmap to map the library into memory. */
0390     error = vm_mmap(file, start_addr, ex.a_text + ex.a_data,
0391             PROT_READ | PROT_WRITE | PROT_EXEC,
0392             MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE,
0393             N_TXTOFF(ex));
0394     retval = error;
0395     if (error != start_addr)
0396         goto out;
0397 
0398     len = PAGE_ALIGN(ex.a_text + ex.a_data);
0399     bss = ex.a_text + ex.a_data + ex.a_bss;
0400     if (bss > len) {
0401         retval = vm_brk(start_addr + len, bss - len);
0402         if (retval)
0403             goto out;
0404     }
0405     retval = 0;
0406 out:
0407     return retval;
0408 }
0409 
0410 static int __init init_aout_binfmt(void)
0411 {
0412     register_binfmt(&aout_format);
0413     return 0;
0414 }
0415 
0416 static void __exit exit_aout_binfmt(void)
0417 {
0418     unregister_binfmt(&aout_format);
0419 }
0420 
0421 core_initcall(init_aout_binfmt);
0422 module_exit(exit_aout_binfmt);
0423 MODULE_LICENSE("GPL");