Skip to content

Commit ad55eac

Browse files
Michal Hockotorvalds
authored andcommitted
elf: enforce MAP_FIXED on overlaying elf segments
Anshuman has reported that with "fs, elf: drop MAP_FIXED usage from elf_map" applied, some ELF binaries in his environment fail to start with [ 23.423642] 9148 (sed): Uhuuh, elf segment at 0000000010030000 requested but the memory is mapped already [ 23.423706] requested [10030000, 10040000] mapped [10030000, 10040000] 100073 anon The reason is that the above binary has overlapping elf segments: LOAD 0x0000000000000000 0x0000000010000000 0x0000000010000000 0x0000000000013a8c 0x0000000000013a8c R E 10000 LOAD 0x000000000001fd40 0x000000001002fd40 0x000000001002fd40 0x00000000000002c0 0x00000000000005e8 RW 10000 LOAD 0x0000000000020328 0x0000000010030328 0x0000000010030328 0x0000000000000384 0x00000000000094a0 RW 10000 That binary has two RW LOAD segments, the first crosses a page border into the second 0x1002fd40 (LOAD2-vaddr) + 0x5e8 (LOAD2-memlen) == 0x10030328 (LOAD3-vaddr) Handle this situation by enforcing MAP_FIXED when we establish a temporary brk VMA to handle overlapping segments. All other mappings will still use MAP_FIXED_NOREPLACE. Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Michal Hocko <[email protected]> Reported-by: Anshuman Khandual <[email protected]> Reviewed-by: Khalid Aziz <[email protected]> Cc: Andrei Vagin <[email protected]> Cc: Michael Ellerman <[email protected]> Cc: Kees Cook <[email protected]> Cc: Abdul Haleem <[email protected]> Cc: Joel Stanley <[email protected]> Cc: Stephen Rothwell <[email protected]> Cc: Mark Brown <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent 4ed2863 commit ad55eac

File tree

1 file changed

+10
-3
lines changed

1 file changed

+10
-3
lines changed

fs/binfmt_elf.c

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -895,7 +895,7 @@ static int load_elf_binary(struct linux_binprm *bprm)
895895
the correct location in memory. */
896896
for(i = 0, elf_ppnt = elf_phdata;
897897
i < loc->elf_ex.e_phnum; i++, elf_ppnt++) {
898-
int elf_prot = 0, elf_flags;
898+
int elf_prot = 0, elf_flags, elf_fixed = MAP_FIXED_NOREPLACE;
899899
unsigned long k, vaddr;
900900
unsigned long total_size = 0;
901901

@@ -927,6 +927,13 @@ static int load_elf_binary(struct linux_binprm *bprm)
927927
*/
928928
}
929929
}
930+
931+
/*
932+
* Some binaries have overlapping elf segments and then
933+
* we have to forcefully map over an existing mapping
934+
* e.g. over this newly established brk mapping.
935+
*/
936+
elf_fixed = MAP_FIXED;
930937
}
931938

932939
if (elf_ppnt->p_flags & PF_R)
@@ -944,7 +951,7 @@ static int load_elf_binary(struct linux_binprm *bprm)
944951
* the ET_DYN load_addr calculations, proceed normally.
945952
*/
946953
if (loc->elf_ex.e_type == ET_EXEC || load_addr_set) {
947-
elf_flags |= MAP_FIXED_NOREPLACE;
954+
elf_flags |= elf_fixed;
948955
} else if (loc->elf_ex.e_type == ET_DYN) {
949956
/*
950957
* This logic is run once for the first LOAD Program
@@ -980,7 +987,7 @@ static int load_elf_binary(struct linux_binprm *bprm)
980987
load_bias = ELF_ET_DYN_BASE;
981988
if (current->flags & PF_RANDOMIZE)
982989
load_bias += arch_mmap_rnd();
983-
elf_flags |= MAP_FIXED_NOREPLACE;
990+
elf_flags |= elf_fixed;
984991
} else
985992
load_bias = 0;
986993

0 commit comments

Comments
 (0)