diff options
author | Michal Hocko <mhocko@suse.com> | 2018-04-10 19:36:05 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-04-11 13:28:38 -0400 |
commit | ad55eac74f2016c6dc132b9502f794156858a3d1 (patch) | |
tree | b1d69288fc42ebf5192495b95a47afcb76a3e7a5 /fs | |
parent | 4ed28639519c7bad5f518e70b3284c6e0763e650 (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.c | 13 |
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 | ||