This commit was manufactured by cvs2svn to create tag
[linux-2.6.git] / fs / binfmt_elf.c
index a67e6f5..9086615 100644 (file)
@@ -46,7 +46,7 @@
 
 static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs);
 static int load_elf_library(struct file*);
-static unsigned long elf_map (struct file *, unsigned long, struct elf_phdr *, int, int);
+static unsigned long elf_map (struct file *, unsigned long, struct elf_phdr *, int, int, unsigned long);
 extern int dump_fpu (struct pt_regs *, elf_fpregset_t *);
 
 #ifndef elf_addr_t
@@ -110,18 +110,18 @@ static void padzero(unsigned long elf_bss)
        nbyte = ELF_PAGEOFFSET(elf_bss);
        if (nbyte) {
                nbyte = ELF_MIN_ALIGN - nbyte;
-               clear_user((void *) elf_bss, nbyte);
+               clear_user((void __user *) elf_bss, nbyte);
        }
 }
 
 /* Let's use some macros to make this stack manipulation a litle clearer */
 #ifdef CONFIG_STACK_GROWSUP
-#define STACK_ADD(sp, items) ((elf_addr_t *)(sp) + (items))
+#define STACK_ADD(sp, items) ((elf_addr_t __user *)(sp) + (items))
 #define STACK_ROUND(sp, items) \
        ((15 + (unsigned long) ((sp) + (items))) &~ 15UL)
-#define STACK_ALLOC(sp, len) ({ elf_addr_t *old_sp = (elf_addr_t *)sp; sp += len; old_sp; })
+#define STACK_ALLOC(sp, len) ({ elf_addr_t __user *old_sp = (elf_addr_t __user *)sp; sp += len; old_sp; })
 #else
-#define STACK_ADD(sp, items) ((elf_addr_t *)(sp) - (items))
+#define STACK_ADD(sp, items) ((elf_addr_t __user *)(sp) - (items))
 #define STACK_ROUND(sp, items) \
        (((unsigned long) (sp - items)) &~ 15UL)
 #define STACK_ALLOC(sp, len) ({ sp -= len ; sp; })
@@ -135,8 +135,10 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr * exec,
        unsigned long p = bprm->p;
        int argc = bprm->argc;
        int envc = bprm->envc;
-       elf_addr_t *argv, *envp;
-       elf_addr_t *sp, *u_platform;
+       elf_addr_t __user *argv;
+       elf_addr_t __user *envp;
+       elf_addr_t __user *sp;
+       elf_addr_t __user *u_platform;
        const char *k_platform = ELF_PLATFORM;
        int items;
        elf_addr_t *elf_info;
@@ -154,22 +156,10 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr * exec,
        if (k_platform) {
                size_t len = strlen(k_platform) + 1;
 
-#ifdef CONFIG_X86_HT
-               /*
-                * In some cases (e.g. Hyper-Threading), we want to avoid L1
-                * evictions by the processes running on the same package. One
-                * thing we can do is to shuffle the initial stack for them.
-                *
-                * The conditionals here are unneeded, but kept in to make the
-                * code behaviour the same as pre change unless we have
-                * hyperthreaded processors. This should be cleaned up
-                * before 2.6
-                */
-        
-               if (smp_num_siblings > 1)
-                       STACK_ALLOC(p, ((current->pid % 64) << 7));
+#ifdef __HAVE_ARCH_ALIGN_STACK
+               p = (unsigned long)arch_align_stack((unsigned long)p);
 #endif
-               u_platform = (elf_addr_t *)STACK_ALLOC(p, len);
+               u_platform = (elf_addr_t __user *)STACK_ALLOC(p, len);
                __copy_to_user(u_platform, k_platform, len);
        }
 
@@ -222,10 +212,10 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr * exec,
 
        /* Point sp at the lowest address on the stack */
 #ifdef CONFIG_STACK_GROWSUP
-       sp = (elf_addr_t *)bprm->p - items - ei_index;
+       sp = (elf_addr_t __user *)bprm->p - items - ei_index;
        bprm->exec = (unsigned long) sp; /* XXX: PARISC HACK */
 #else
-       sp = (elf_addr_t *)bprm->p;
+       sp = (elf_addr_t __user *)bprm->p;
 #endif
 
        /* Now, let's put argc (and argv, envp if appropriate) on the stack */
@@ -245,7 +235,7 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr * exec,
        while (argc-- > 0) {
                size_t len;
                __put_user((elf_addr_t)p, argv++);
-               len = strnlen_user((void *)p, PAGE_SIZE*MAX_ARG_PAGES);
+               len = strnlen_user((void __user *)p, PAGE_SIZE*MAX_ARG_PAGES);
                if (!len || len > PAGE_SIZE*MAX_ARG_PAGES)
                        return;
                p += len;
@@ -255,7 +245,7 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr * exec,
        while (envc-- > 0) {
                size_t len;
                __put_user((elf_addr_t)p, envp++);
-               len = strnlen_user((void *)p, PAGE_SIZE*MAX_ARG_PAGES);
+               len = strnlen_user((void __user *)p, PAGE_SIZE*MAX_ARG_PAGES);
                if (!len || len > PAGE_SIZE*MAX_ARG_PAGES)
                        return;
                p += len;
@@ -264,27 +254,66 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr * exec,
        current->mm->env_end = p;
 
        /* Put the elf_info on the stack in the right place.  */
-       sp = (elf_addr_t *)envp + 1;
+       sp = (elf_addr_t __user *)envp + 1;
        copy_to_user(sp, elf_info, ei_index * sizeof(elf_addr_t));
 }
 
 #ifndef elf_map
 
 static unsigned long elf_map(struct file *filep, unsigned long addr,
-                       struct elf_phdr *eppnt, int prot, int type)
+                            struct elf_phdr *eppnt, int prot, int type,
+                            unsigned long total_size)
 {
        unsigned long map_addr;
+       unsigned long size = eppnt->p_filesz + ELF_PAGEOFFSET(eppnt->p_vaddr);
+       unsigned long off = eppnt->p_offset - ELF_PAGEOFFSET(eppnt->p_vaddr);
+
+       addr = ELF_PAGESTART(addr);
+       size = ELF_PAGEALIGN(size);
 
        down_write(&current->mm->mmap_sem);
-       map_addr = do_mmap(filep, ELF_PAGESTART(addr),
-                          eppnt->p_filesz + ELF_PAGEOFFSET(eppnt->p_vaddr), prot, type,
-                          eppnt->p_offset - ELF_PAGEOFFSET(eppnt->p_vaddr));
+
+       /*
+        * total_size is the size of the ELF (interpreter) image.
+        * The _first_ mmap needs to know the full size, otherwise
+        * randomization might put this image into an overlapping
+        * position with the ELF binary image. (since size < total_size)
+        * So we first map the 'big' image - and unmap the remainder at
+        * the end. (which unmap is needed for ELF images with holes.)
+        */
+       if (total_size) {
+               total_size = ELF_PAGEALIGN(total_size);
+               map_addr = do_mmap(filep, addr, total_size, prot, type, off);
+               if (!BAD_ADDR(map_addr))
+                       do_munmap(current->mm, map_addr+size, total_size-size);
+       } else
+               map_addr = do_mmap(filep, addr, size, prot, type, off);
+               
        up_write(&current->mm->mmap_sem);
-       return(map_addr);
+
+       return map_addr;
 }
 
 #endif /* !elf_map */
 
+static inline unsigned long total_mapping_size(struct elf_phdr *cmds, int nr)
+{
+       int i, first_idx = -1, last_idx = -1;
+
+       for (i = 0; i < nr; i++)
+               if (cmds[i].p_type == PT_LOAD) {
+                       last_idx = i;
+                       if (first_idx == -1)
+                               first_idx = i;
+               }
+
+       if (first_idx == -1)
+               return 0;
+
+       return cmds[last_idx].p_vaddr + cmds[last_idx].p_memsz -
+                               ELF_PAGESTART(cmds[first_idx].p_vaddr);
+}
+
 /* This is much more generalized than the library routine read function,
    so we keep this separate.  Technically the library read function
    is only provided so that we can read a.out libraries that have
@@ -292,7 +321,8 @@ static unsigned long elf_map(struct file *filep, unsigned long addr,
 
 static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
                                     struct file * interpreter,
-                                    unsigned long *interp_load_addr)
+                                    unsigned long *interp_load_addr,
+                                    unsigned long no_base)
 {
        struct elf_phdr *elf_phdata;
        struct elf_phdr *eppnt;
@@ -300,6 +330,7 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
        int load_addr_set = 0;
        unsigned long last_bss = 0, elf_bss = 0;
        unsigned long error = ~0UL;
+       unsigned long total_size;
        int retval, i, size;
 
        /* First of all, some simple consistency checks */
@@ -334,6 +365,10 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
        if (retval < 0)
                goto out_close;
 
+       total_size = total_mapping_size(elf_phdata, interp_elf_ex->e_phnum);
+       if (!total_size)
+               goto out_close;
+
        eppnt = elf_phdata;
        for (i=0; i<interp_elf_ex->e_phnum; i++, eppnt++) {
          if (eppnt->p_type == PT_LOAD) {
@@ -348,8 +383,11 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
            vaddr = eppnt->p_vaddr;
            if (interp_elf_ex->e_type == ET_EXEC || load_addr_set)
                elf_type |= MAP_FIXED;
+           else if (no_base && interp_elf_ex->e_type == ET_DYN)
+               load_addr = -vaddr;
 
-           map_addr = elf_map(interpreter, load_addr + vaddr, eppnt, elf_prot, elf_type);
+           map_addr = elf_map(interpreter, load_addr + vaddr, eppnt, elf_prot, elf_type, total_size);
+           total_size = 0;
            error = map_addr;
            if (BAD_ADDR(map_addr))
                goto out_close;
@@ -418,7 +456,7 @@ static unsigned long load_aout_interp(struct exec * interp_ex,
                             struct file * interpreter)
 {
        unsigned long text_data, elf_entry = ~0UL;
-       char * addr;
+       char __user * addr;
        loff_t offset;
 
        current->mm->end_code = interp_ex->a_text;
@@ -429,12 +467,12 @@ static unsigned long load_aout_interp(struct exec * interp_ex,
        switch (N_MAGIC(*interp_ex)) {
        case OMAGIC:
                offset = 32;
-               addr = (char *) 0;
+               addr = (char __user *)0;
                break;
        case ZMAGIC:
        case QMAGIC:
                offset = N_TXTOFF(*interp_ex);
-               addr = (char *) N_TXTADDR(*interp_ex);
+               addr = (char __user *) N_TXTADDR(*interp_ex);
                break;
        default:
                goto out;
@@ -488,7 +526,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
        struct exec interp_ex;
        char passed_fileno[6];
        struct files_struct *files;
-       int executable_stack = EXSTACK_DEFAULT;
+       int executable_stack, relocexec, old_relocexec = current->flags & PF_RELOCEXEC;
        
        /* Get the exec-header */
        elf_ex = *((struct elfhdr *) bprm->buf);
@@ -614,14 +652,35 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
        }
 
        elf_ppnt = elf_phdata;
+       executable_stack = EXSTACK_DEFAULT;
+
        for (i = 0; i < elf_ex.e_phnum; i++, elf_ppnt++)
                if (elf_ppnt->p_type == PT_GNU_STACK) {
                        if (elf_ppnt->p_flags & PF_X)
                                executable_stack = EXSTACK_ENABLE_X;
                        else
                                executable_stack = EXSTACK_DISABLE_X;
+                       break;
                }
 
+       relocexec = 0;
+
+       if (current->personality == PER_LINUX)
+       switch (exec_shield) {
+       case 1:
+               if (executable_stack != EXSTACK_DEFAULT) {
+                       current->flags |= PF_RELOCEXEC;
+                       relocexec = PF_RELOCEXEC;
+               }
+               break;
+
+       case 2:
+               executable_stack = EXSTACK_DISABLE_X;
+               current->flags |= PF_RELOCEXEC;
+               relocexec = PF_RELOCEXEC;
+               break;
+       }
+
        /* Some simple consistency checks for the interpreter */
        if (elf_interpreter) {
                interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT;
@@ -674,6 +733,16 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
        retval = flush_old_exec(bprm);
        if (retval)
                goto out_free_dentry;
+       current->flags |= relocexec;
+
+#ifdef __i386__
+       /*
+        * In the exec-shield-disabled case turn off the CS limit
+        * completely:
+        */
+       if (!exec_shield)
+               arch_add_exec_range(current->mm, -1);
+#endif
 
        /* Discard our unneeded old files struct */
        if (files) {
@@ -687,6 +756,9 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
        current->mm->end_data = 0;
        current->mm->end_code = 0;
        current->mm->mmap = NULL;
+#ifdef __HAVE_ARCH_MMAP_TOP
+       current->mm->mmap_top = mmap_top();
+#endif
        current->flags &= ~PF_FORKNOEXEC;
 
        /* Do this immediately, since STACK_TOP as used in setup_arg_pages
@@ -697,6 +769,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
           change some of these later */
        current->mm->rss = 0;
        current->mm->free_area_cache = TASK_UNMAPPED_BASE;
+       current->mm->non_executable_cache = current->mm->mmap_top;
        retval = setup_arg_pages(bprm, executable_stack);
        if (retval < 0) {
                send_sig(SIGKILL, current, 0);
@@ -705,10 +778,10 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
        
        current->mm->start_stack = bprm->p;
 
+
        /* Now we do a little grungy work by mmaping the ELF image into
-          the correct location in memory.  At this point, we assume that
-          the image should be loaded at fixed address, not at a variable
-          address. */
+          the correct location in memory.
+        */
 
        for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) {
                int elf_prot = 0, elf_flags;
@@ -734,7 +807,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
                                nbyte = ELF_MIN_ALIGN - nbyte;
                                if (nbyte > elf_brk - elf_bss)
                                        nbyte = elf_brk - elf_bss;
-                               clear_user((void *) elf_bss + load_bias, nbyte);
+                               clear_user((void __user *) elf_bss + load_bias, nbyte);
                        }
                }
 
@@ -745,16 +818,16 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
                elf_flags = MAP_PRIVATE|MAP_DENYWRITE|MAP_EXECUTABLE;
 
                vaddr = elf_ppnt->p_vaddr;
-               if (elf_ex.e_type == ET_EXEC || load_addr_set) {
+               if (elf_ex.e_type == ET_EXEC || load_addr_set)
                        elf_flags |= MAP_FIXED;
-               } else if (elf_ex.e_type == ET_DYN) {
-                       /* Try and get dynamic programs out of the way of the default mmap
-                          base, as well as whatever program they might try to exec.  This
-                          is because the brk will follow the loader, and is not movable.  */
+               else if (elf_ex.e_type == ET_DYN)
+#ifdef __i386__
+                       load_bias = 0;
+#else
                        load_bias = ELF_PAGESTART(ELF_ET_DYN_BASE - vaddr);
-               }
+#endif
 
-               error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt, elf_prot, elf_flags);
+               error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt, elf_prot, elf_flags, 0);
                if (BAD_ADDR(error))
                        continue;
 
@@ -825,7 +898,8 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
                else
                        elf_entry = load_elf_interp(&interp_elf_ex,
                                                    interpreter,
-                                                   &interp_load_addr);
+                                                   &interp_load_addr,
+                                                   load_bias);
                if (BAD_ADDR(elf_entry)) {
                        printk(KERN_ERR "Unable to load interpreter\n");
                        send_sig(SIGSEGV, current, 0);
@@ -848,6 +922,14 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
 
        set_binfmt(&elf_format);
 
+       /*
+        * Map the vsyscall trampoline. This address is then passed via
+        * AT_SYSINFO.
+        */
+#ifdef __HAVE_ARCH_VSYSCALL
+       map_vsyscall();
+#endif
+
        compute_creds(bprm);
        current->flags &= ~PF_FORKNOEXEC;
        create_elf_tables(bprm, &elf_ex, (interpreter_type == INTERPRETER_AOUT),
@@ -861,6 +943,10 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
        current->mm->end_data = end_data;
        current->mm->start_stack = bprm->p;
 
+#ifdef __HAVE_ARCH_RANDOMIZE_BRK
+       if (current->flags & PF_RELOCEXEC)
+               randomize_brk(elf_brk);
+#endif
        if (current->personality & MMAP_PAGE_ZERO) {
                /* Why this, you ask???  Well SVr4 maps page 0 as read-only,
                   and some applications "depend" upon this behavior.
@@ -914,6 +1000,8 @@ out_free_fh:
        }
 out_free_ph:
        kfree(elf_phdata);
+       current->flags &= ~PF_RELOCEXEC;
+       current->flags |= old_relocexec;
        goto out;
 }
 
@@ -1184,7 +1272,7 @@ static void fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p,
        if (len >= ELF_PRARGSZ)
                len = ELF_PRARGSZ-1;
        copy_from_user(&psinfo->pr_psargs,
-                      (const char *)mm->arg_start, len);
+                      (const char __user *)mm->arg_start, len);
        for(i = 0; i < len; i++)
                if (psinfo->pr_psargs[i] == 0)
                        psinfo->pr_psargs[i] = ' ';
@@ -1543,6 +1631,6 @@ static void __exit exit_elf_binfmt(void)
        unregister_binfmt(&elf_format);
 }
 
-module_init(init_elf_binfmt)
-module_exit(exit_elf_binfmt)
+core_initcall(init_elf_binfmt);
+module_exit(exit_elf_binfmt);
 MODULE_LICENSE("GPL");