Merge git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf
[linux-2.6-block.git] / fs / binfmt_elf.c
index bdb201230bae93c408cf1972b6f9bb92ad37e478..41e04183e4ce84a38e18a3997eb6708c3e8234f6 100644 (file)
@@ -377,6 +377,11 @@ static unsigned long elf_map(struct file *filep, unsigned long addr,
        } else
                map_addr = vm_mmap(filep, addr, size, prot, type, off);
 
+       if ((type & MAP_FIXED_NOREPLACE) && BAD_ADDR(map_addr))
+               pr_info("%d (%s): Uhuuh, elf segment at %p requested but the memory is mapped already\n",
+                               task_pid_nr(current), current->comm,
+                               (void *)addr);
+
        return(map_addr);
 }
 
@@ -575,7 +580,7 @@ static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex,
                                elf_prot |= PROT_EXEC;
                        vaddr = eppnt->p_vaddr;
                        if (interp_elf_ex->e_type == ET_EXEC || load_addr_set)
-                               elf_type |= MAP_FIXED;
+                               elf_type |= MAP_FIXED_NOREPLACE;
                        else if (no_base && interp_elf_ex->e_type == ET_DYN)
                                load_addr = -vaddr;
 
@@ -890,7 +895,7 @@ static int load_elf_binary(struct linux_binprm *bprm)
           the correct location in memory. */
        for(i = 0, elf_ppnt = elf_phdata;
            i < loc->elf_ex.e_phnum; i++, elf_ppnt++) {
-               int elf_prot = 0, elf_flags;
+               int elf_prot = 0, elf_flags, elf_fixed = MAP_FIXED_NOREPLACE;
                unsigned long k, vaddr;
                unsigned long total_size = 0;
 
@@ -922,6 +927,13 @@ static int load_elf_binary(struct linux_binprm *bprm)
                                         */
                                }
                        }
+
+                       /*
+                        * Some binaries have overlapping elf segments and then
+                        * we have to forcefully map over an existing mapping
+                        * e.g. over this newly established brk mapping.
+                        */
+                       elf_fixed = MAP_FIXED;
                }
 
                if (elf_ppnt->p_flags & PF_R)
@@ -939,7 +951,7 @@ static int load_elf_binary(struct linux_binprm *bprm)
                 * the ET_DYN load_addr calculations, proceed normally.
                 */
                if (loc->elf_ex.e_type == ET_EXEC || load_addr_set) {
-                       elf_flags |= MAP_FIXED;
+                       elf_flags |= elf_fixed;
                } else if (loc->elf_ex.e_type == ET_DYN) {
                        /*
                         * This logic is run once for the first LOAD Program
@@ -975,7 +987,7 @@ static int load_elf_binary(struct linux_binprm *bprm)
                                load_bias = ELF_ET_DYN_BASE;
                                if (current->flags & PF_RANDOMIZE)
                                        load_bias += arch_mmap_rnd();
-                               elf_flags |= MAP_FIXED;
+                               elf_flags |= elf_fixed;
                        } else
                                load_bias = 0;
 
@@ -1155,6 +1167,7 @@ static int load_elf_binary(struct linux_binprm *bprm)
        ELF_PLAT_INIT(regs, reloc_func_desc);
 #endif
 
+       finalize_exec(bprm);
        start_thread(regs, elf_entry, bprm->p);
        retval = 0;
 out:
@@ -1234,7 +1247,7 @@ static int load_elf_library(struct file *file)
                        (eppnt->p_filesz +
                         ELF_PAGEOFFSET(eppnt->p_vaddr)),
                        PROT_READ | PROT_WRITE | PROT_EXEC,
-                       MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE,
+                       MAP_FIXED_NOREPLACE | MAP_PRIVATE | MAP_DENYWRITE,
                        (eppnt->p_offset -
                         ELF_PAGEOFFSET(eppnt->p_vaddr)));
        if (error != ELF_PAGESTART(eppnt->p_vaddr))