summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorMichal Hocko <mhocko@suse.com>2018-04-10 19:36:05 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2018-04-11 13:28:38 -0400
commitad55eac74f2016c6dc132b9502f794156858a3d1 (patch)
treeb1d69288fc42ebf5192495b95a47afcb76a3e7a5 /fs
parent4ed28639519c7bad5f518e70b3284c6e0763e650 (diff)
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/20180213100440.GM3443@dhcp22.suse.cz Signed-off-by: Michal Hocko <mhocko@suse.com> Reported-by: Anshuman Khandual <khandual@linux.vnet.ibm.com> Reviewed-by: Khalid Aziz <khalid.aziz@oracle.com> Cc: Andrei Vagin <avagin@openvz.org> Cc: Michael Ellerman <mpe@ellerman.id.au> Cc: Kees Cook <keescook@chromium.org> Cc: Abdul Haleem <abdhalee@linux.vnet.ibm.com> Cc: Joel Stanley <joel@jms.id.au> Cc: Stephen Rothwell <sfr@canb.auug.org.au> Cc: Mark Brown <broonie@kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs')
-rw-r--r--fs/binfmt_elf.c13
1 files changed, 10 insertions, 3 deletions
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index 46f0438088d3..41e04183e4ce 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -895,7 +895,7 @@ static int load_elf_binary(struct linux_binprm *bprm)
895 the correct location in memory. */ 895 the correct location in memory. */
896 for(i = 0, elf_ppnt = elf_phdata; 896 for(i = 0, elf_ppnt = elf_phdata;
897 i < loc->elf_ex.e_phnum; i++, elf_ppnt++) { 897 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;
899 unsigned long k, vaddr; 899 unsigned long k, vaddr;
900 unsigned long total_size = 0; 900 unsigned long total_size = 0;
901 901
@@ -927,6 +927,13 @@ static int load_elf_binary(struct linux_binprm *bprm)
927 */ 927 */
928 } 928 }
929 } 929 }
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;
930 } 937 }
931 938
932 if (elf_ppnt->p_flags & PF_R) 939 if (elf_ppnt->p_flags & PF_R)
@@ -944,7 +951,7 @@ static int load_elf_binary(struct linux_binprm *bprm)
944 * the ET_DYN load_addr calculations, proceed normally. 951 * the ET_DYN load_addr calculations, proceed normally.
945 */ 952 */
946 if (loc->elf_ex.e_type == ET_EXEC || load_addr_set) { 953 if (loc->elf_ex.e_type == ET_EXEC || load_addr_set) {
947 elf_flags |= MAP_FIXED_NOREPLACE; 954 elf_flags |= elf_fixed;
948 } else if (loc->elf_ex.e_type == ET_DYN) { 955 } else if (loc->elf_ex.e_type == ET_DYN) {
949 /* 956 /*
950 * This logic is run once for the first LOAD Program 957 * This logic is run once for the first LOAD Program
@@ -980,7 +987,7 @@ static int load_elf_binary(struct linux_binprm *bprm)
980 load_bias = ELF_ET_DYN_BASE; 987 load_bias = ELF_ET_DYN_BASE;
981 if (current->flags & PF_RANDOMIZE) 988 if (current->flags & PF_RANDOMIZE)
982 load_bias += arch_mmap_rnd(); 989 load_bias += arch_mmap_rnd();
983 elf_flags |= MAP_FIXED_NOREPLACE; 990 elf_flags |= elf_fixed;
984 } else 991 } else
985 load_bias = 0; 992 load_bias = 0;
986 993