The patch titled Subject: fs, elf: drop MAP_FIXED usage from elf_map has been added to the -mm tree. Its filename is fs-elf-drop-map_fixed-usage-from-elf_map.patch This patch should soon appear at http://ozlabs.org/~akpm/mmots/broken-out/fs-elf-drop-map_fixed-usage-from-elf_map.patch and later at http://ozlabs.org/~akpm/mmotm/broken-out/fs-elf-drop-map_fixed-usage-from-elf_map.patch Before you just go and hit "reply", please: a) Consider who else should be cc'ed b) Prefer to cc a suitable mailing list as well c) Ideally: find the original patch on the mailing list and do a reply-to-all to that, adding suitable additional cc's *** Remember to use Documentation/SubmitChecklist when testing your code *** The -mm tree is included into linux-next and is updated there every 3-4 working days ------------------------------------------------------ From: Michal Hocko <mhocko@xxxxxxxx> Subject: fs, elf: drop MAP_FIXED usage from elf_map Both load_elf_interp and load_elf_binary rely on elf_map to map segments on a controlled address and they use MAP_FIXED to enforce that. This is however dangerous thing prone to silent data corruption which can be even exploitable. Let's take CVE-2017-1000253 as an example. At the time (before eab09532d400 ("binfmt_elf: use ELF_ET_DYN_BASE only for PIE")) ELF_ET_DYN_BASE was at TASK_SIZE / 3 * 2 which is not that far away from the stack top on 32b (legacy) memory layout (only 1GB away). Therefore we could end up mapping over the existing stack with some luck. The issue has been fixed since then (a87938b2e246 ("fs/binfmt_elf.c: fix bug in loading of PIE binaries")), ELF_ET_DYN_BASE moved moved much further from the stack (eab09532d400 and later by c715b72c1ba4 ("mm: revert x86_64 and arm64 ELF_ET_DYN_BASE base changes")) and excessive stack consumption early during execve fully stopped by da029c11e6b1 ("exec: Limit arg stack to at most 75% of _STK_LIM"). So we should be safe and any attack should be impractical. On the other hand this is just too subtle assumption so it can break quite easily and hard to spot. I believe that the MAP_FIXED usage in load_elf_binary (et. al) is still fundamentally dangerous. Moreover it shouldn't be even needed. We are at the early process stage and so there shouldn't be unrelated mappings (except for stack and loader) existing so mmap for a given address should succeed even without MAP_FIXED. Something is terribly wrong if this is not the case and we should rather fail than silently corrupt the underlying mapping. Address this issue by changing MAP_FIXED to the newly added MAP_FIXED_NOREPLACE. This will mean that mmap will fail if there is an existing mapping clashing with the requested one without clobbering it. Link: http://lkml.kernel.org/r/20171213092550.2774-3-mhocko@xxxxxxxxxx Signed-off-by: Michal Hocko <mhocko@xxxxxxxx> Reviewed-by: Khalid Aziz <khalid.aziz@xxxxxxxxxx> Acked-by: Michael Ellerman <mpe@xxxxxxxxxxxxxx> Acked-by: Kees Cook <keescook@xxxxxxxxxxxx> Cc: Abdul Haleem <abdhalee@xxxxxxxxxxxxxxxxxx> Cc: Joel Stanley <joel@xxxxxxxxx> Cc: Anshuman Khandual <khandual@xxxxxxxxxxxxxxxxxx> Signed-off-by: Andrew Morton <akpm@xxxxxxxxxxxxxxxxxxxx> --- arch/metag/kernel/process.c | 6 +++++- fs/binfmt_elf.c | 12 ++++++++---- 2 files changed, 13 insertions(+), 5 deletions(-) diff -puN arch/metag/kernel/process.c~fs-elf-drop-map_fixed-usage-from-elf_map arch/metag/kernel/process.c --- a/arch/metag/kernel/process.c~fs-elf-drop-map_fixed-usage-from-elf_map +++ a/arch/metag/kernel/process.c @@ -399,7 +399,7 @@ unsigned long __metag_elf_map(struct fil tcm_tag = tcm_lookup_tag(addr); if (tcm_tag != TCM_INVALID_TAG) - type &= ~MAP_FIXED; + type &= ~(MAP_FIXED | MAP_FIXED_NOREPLACE); /* * total_size is the size of the ELF (interpreter) image. @@ -417,6 +417,10 @@ unsigned long __metag_elf_map(struct fil } 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 segement at %p requested but the memory is mapped already\n", + task_pid_nr(current), tsk->comm, (void*)addr); + if (!BAD_ADDR(map_addr) && tcm_tag != TCM_INVALID_TAG) { struct tcm_allocation *tcm; unsigned long tcm_addr; diff -puN fs/binfmt_elf.c~fs-elf-drop-map_fixed-usage-from-elf_map fs/binfmt_elf.c --- a/fs/binfmt_elf.c~fs-elf-drop-map_fixed-usage-from-elf_map +++ a/fs/binfmt_elf.c @@ -377,6 +377,10 @@ static unsigned long elf_map(struct file } 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 segement at %p requested but the memory is mapped already\n", + task_pid_nr(current), current->comm, (void*)addr); + return(map_addr); } @@ -575,7 +579,7 @@ static unsigned long load_elf_interp(str 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; @@ -939,7 +943,7 @@ static int load_elf_binary(struct linux_ * 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 |= MAP_FIXED_NOREPLACE; } else if (loc->elf_ex.e_type == ET_DYN) { /* * This logic is run once for the first LOAD Program @@ -975,7 +979,7 @@ static int load_elf_binary(struct linux_ load_bias = ELF_ET_DYN_BASE; if (current->flags & PF_RANDOMIZE) load_bias += arch_mmap_rnd(); - elf_flags |= MAP_FIXED; + elf_flags |= MAP_FIXED_NOREPLACE; } else load_bias = 0; @@ -1234,7 +1238,7 @@ static int load_elf_library(struct 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)) _ Patches currently in -mm which might be from mhocko@xxxxxxxx are mm-oom-docs-describe-the-cgroup-aware-oom-killer-fix-2.patch mm-introduce-map_fixed_safe.patch fs-elf-drop-map_fixed-usage-from-elf_map.patch fs-elf-drop-map_fixed-usage-from-elf_map-fix-fix.patch mm-numa-rework-do_pages_move.patch mm-migrate-remove-reason-argument-from-new_page_t.patch mm-migrate-remove-reason-argument-from-new_page_t-fix-3.patch mm-unclutter-thp-migration.patch net-netfilter-x_tablesc-remove-size-check.patch -- To unsubscribe from this list: send the line "unsubscribe mm-commits" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html