From: Michal Hocko <mhocko@kernel.org> To: linux-api@vger.kernel.org Cc: Khalid Aziz <khalid.aziz@oracle.com>, Michael Ellerman <mpe@ellerman.id.au>, Andrew Morton <akpm@linux-foundation.org>, Russell King - ARM Linux <linux@armlinux.org.uk>, Andrea Arcangeli <aarcange@redhat.com>, linux-mm@kvack.org, LKML <linux-kernel@vger.kernel.org>, linux-arch@vger.kernel.org, Florian Weimer <fweimer@redhat.com>, John Hubbard <jhubbard@nvidia.com>, Michal Hocko <mhocko@suse.com>, Abdul Haleem <abdhalee@linux.vnet.ibm.com>, Joel Stanley <joel@jms.id.au>, Kees Cook <keescook@chromium.org> Subject: [PATCH 2/2] fs, elf: drop MAP_FIXED usage from elf_map Date: Wed, 29 Nov 2017 15:42:19 +0100 [thread overview] Message-ID: <20171129144219.22867-3-mhocko@kernel.org> (raw) In-Reply-To: <20171129144219.22867-1-mhocko@kernel.org> From: Michal Hocko <mhocko@suse.com> 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_SAFE. This will mean that mmap will fail if there is an existing mapping clashing with the requested one without clobbering it. Cc: Abdul Haleem <abdhalee@linux.vnet.ibm.com> Cc: Joel Stanley <joel@jms.id.au> Acked-by: Kees Cook <keescook@chromium.org> Signed-off-by: Michal Hocko <mhocko@suse.com> --- arch/metag/kernel/process.c | 6 +++++- fs/binfmt_elf.c | 12 ++++++++---- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/arch/metag/kernel/process.c b/arch/metag/kernel/process.c index 0909834c83a7..867c8d0a5fb4 100644 --- a/arch/metag/kernel/process.c +++ b/arch/metag/kernel/process.c @@ -399,7 +399,7 @@ unsigned long __metag_elf_map(struct file *filep, unsigned long addr, tcm_tag = tcm_lookup_tag(addr); if (tcm_tag != TCM_INVALID_TAG) - type &= ~MAP_FIXED; + type &= ~(MAP_FIXED | MAP_FIXED_SAFE); /* * total_size is the size of the ELF (interpreter) image. @@ -417,6 +417,10 @@ unsigned long __metag_elf_map(struct file *filep, unsigned long addr, } else map_addr = vm_mmap(filep, addr, size, prot, type, off); + if ((type & MAP_FIXED_SAFE) && 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 --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 73b01e474fdc..5916d45f64a7 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -372,6 +372,10 @@ 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_SAFE) && 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); } @@ -569,7 +573,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_SAFE; else if (no_base && interp_elf_ex->e_type == ET_DYN) load_addr = -vaddr; @@ -930,7 +934,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 |= MAP_FIXED_SAFE; } else if (loc->elf_ex.e_type == ET_DYN) { /* * This logic is run once for the first LOAD Program @@ -966,7 +970,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 |= MAP_FIXED_SAFE; } else load_bias = 0; @@ -1223,7 +1227,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_SAFE | MAP_PRIVATE | MAP_DENYWRITE, (eppnt->p_offset - ELF_PAGEOFFSET(eppnt->p_vaddr))); if (error != ELF_PAGESTART(eppnt->p_vaddr)) -- 2.15.0 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@kvack.org. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
WARNING: multiple messages have this Message-ID (diff)
From: Michal Hocko <mhocko@kernel.org> To: linux-api@vger.kernel.org Cc: Khalid Aziz <khalid.aziz@oracle.com>, Michael Ellerman <mpe@ellerman.id.au>, Andrew Morton <akpm@linux-foundation.org>, Russell King - ARM Linux <linux@armlinux.org.uk>, Andrea Arcangeli <aarcange@redhat.com>, linux-mm@kvack.org, LKML <linux-kernel@vger.kernel.org>, linux-arch@vger.kernel.org, Florian Weimer <fweimer@redhat.com>, John Hubbard <jhubbard@nvidia.com>, Michal Hocko <mhocko@suse.com>, Abdul Haleem <abdhalee@linux.vnet.ibm.com>, Joel Stanley <joel@jms.id.au>, Kees Cook <keescook@chromium.org> Subject: [PATCH 2/2] fs, elf: drop MAP_FIXED usage from elf_map Date: Wed, 29 Nov 2017 15:42:19 +0100 [thread overview] Message-ID: <20171129144219.22867-3-mhocko@kernel.org> (raw) Message-ID: <20171129144219.YRpLcmTJEj1kyUTEET3WiutFABklwlciIe7LRmEPv3o@z> (raw) In-Reply-To: <20171129144219.22867-1-mhocko@kernel.org> From: Michal Hocko <mhocko@suse.com> 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_SAFE. This will mean that mmap will fail if there is an existing mapping clashing with the requested one without clobbering it. Cc: Abdul Haleem <abdhalee@linux.vnet.ibm.com> Cc: Joel Stanley <joel@jms.id.au> Acked-by: Kees Cook <keescook@chromium.org> Signed-off-by: Michal Hocko <mhocko@suse.com> --- arch/metag/kernel/process.c | 6 +++++- fs/binfmt_elf.c | 12 ++++++++---- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/arch/metag/kernel/process.c b/arch/metag/kernel/process.c index 0909834c83a7..867c8d0a5fb4 100644 --- a/arch/metag/kernel/process.c +++ b/arch/metag/kernel/process.c @@ -399,7 +399,7 @@ unsigned long __metag_elf_map(struct file *filep, unsigned long addr, tcm_tag = tcm_lookup_tag(addr); if (tcm_tag != TCM_INVALID_TAG) - type &= ~MAP_FIXED; + type &= ~(MAP_FIXED | MAP_FIXED_SAFE); /* * total_size is the size of the ELF (interpreter) image. @@ -417,6 +417,10 @@ unsigned long __metag_elf_map(struct file *filep, unsigned long addr, } else map_addr = vm_mmap(filep, addr, size, prot, type, off); + if ((type & MAP_FIXED_SAFE) && 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 --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 73b01e474fdc..5916d45f64a7 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -372,6 +372,10 @@ 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_SAFE) && 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); } @@ -569,7 +573,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_SAFE; else if (no_base && interp_elf_ex->e_type == ET_DYN) load_addr = -vaddr; @@ -930,7 +934,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 |= MAP_FIXED_SAFE; } else if (loc->elf_ex.e_type == ET_DYN) { /* * This logic is run once for the first LOAD Program @@ -966,7 +970,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 |= MAP_FIXED_SAFE; } else load_bias = 0; @@ -1223,7 +1227,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_SAFE | MAP_PRIVATE | MAP_DENYWRITE, (eppnt->p_offset - ELF_PAGEOFFSET(eppnt->p_vaddr))); if (error != ELF_PAGESTART(eppnt->p_vaddr)) -- 2.15.0
next prev parent reply other threads:[~2017-11-29 14:42 UTC|newest] Thread overview: 87+ messages / expand[flat|nested] mbox.gz Atom feed top 2017-11-29 14:42 [PATCH 0/2] mm: introduce MAP_FIXED_SAFE Michal Hocko 2017-11-29 14:42 ` Michal Hocko 2017-11-29 14:42 ` [PATCH 1/2] " Michal Hocko 2017-11-29 14:42 ` Michal Hocko 2017-12-06 5:15 ` Michael Ellerman 2017-12-06 5:15 ` Michael Ellerman 2017-12-06 9:27 ` Michal Hocko 2017-12-06 9:27 ` Michal Hocko 2017-12-06 10:02 ` Michal Hocko 2017-12-06 10:02 ` Michal Hocko 2017-12-07 12:07 ` Pavel Machek 2017-11-29 14:42 ` Michal Hocko [this message] 2017-11-29 14:42 ` [PATCH 2/2] fs, elf: drop MAP_FIXED usage from elf_map Michal Hocko 2017-11-29 17:45 ` Khalid Aziz 2017-11-29 17:45 ` Khalid Aziz 2017-11-29 14:45 ` [PATCH] mmap.2: document new MAP_FIXED_SAFE flag Michal Hocko 2017-11-30 3:16 ` John Hubbard 2017-11-30 3:16 ` John Hubbard 2017-11-30 8:23 ` Michal Hocko 2017-11-30 8:23 ` Michal Hocko 2017-11-30 8:24 ` [PATCH v2] " Michal Hocko 2017-11-30 8:24 ` Michal Hocko 2017-11-30 18:31 ` John Hubbard 2017-11-30 18:39 ` Michal Hocko 2017-11-30 18:39 ` Michal Hocko 2017-11-29 15:13 ` [PATCH 0/2] mm: introduce MAP_FIXED_SAFE Rasmus Villemoes 2017-11-29 15:13 ` Rasmus Villemoes [not found] ` <b154b794-7a8b-995e-0954-9234b9446b31-rjjw5hvvQKZaa/9Udqfwiw@public.gmane.org> 2017-11-29 15:50 ` Michal Hocko 2017-11-29 15:50 ` Michal Hocko 2017-11-29 22:15 ` Kees Cook 2017-11-29 22:12 ` Kees Cook 2017-11-29 22:12 ` Kees Cook 2017-11-29 22:25 ` Kees Cook [not found] ` <CAGXu5jLa=b2HhjWXXTQunaZuz11qUhm5aNXHpS26jVqb=G-gfw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> 2017-11-30 6:58 ` Michal Hocko 2017-11-30 6:58 ` Michal Hocko 2017-12-01 15:26 ` Cyril Hrubis 2017-12-01 15:26 ` Cyril Hrubis 2017-12-06 4:51 ` Michael Ellerman 2017-12-06 4:51 ` Michael Ellerman 2017-12-06 4:54 ` Matthew Wilcox 2017-12-06 4:54 ` Matthew Wilcox 2017-12-06 7:03 ` Matthew Wilcox 2017-12-06 7:03 ` Matthew Wilcox 2017-12-06 7:33 ` John Hubbard 2017-12-06 7:33 ` John Hubbard [not found] ` <5f4fc834-274a-b8f1-bda0-5bcddc5902ed-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org> 2017-12-06 7:35 ` Florian Weimer 2017-12-06 7:35 ` Florian Weimer 2017-12-06 8:06 ` John Hubbard 2017-12-06 8:06 ` John Hubbard [not found] ` <27ee1755-76d8-f086-5760-9c973b31108a-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org> 2017-12-06 8:54 ` Florian Weimer 2017-12-06 8:54 ` Florian Weimer [not found] ` <20171206070355.GA32044-PfSpb0PWhxZc2C7mugBRk2EX/6BAtgUQ@public.gmane.org> 2017-12-07 5:46 ` Michael Ellerman 2017-12-07 5:46 ` Michael Ellerman 2017-12-07 19:14 ` Kees Cook 2017-12-07 19:14 ` Kees Cook [not found] ` <CAGXu5jLWRQn6EaXEEvdvXr+4gbiJawwp1EaLMfYisHVfMiqgSA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> 2017-12-07 19:57 ` Matthew Wilcox 2017-12-07 19:57 ` Matthew Wilcox 2017-12-08 8:33 ` Michal Hocko [not found] ` <20171208083315.GR20234-2MMpYkNvuYDjFM9bn6wA6Q@public.gmane.org> 2017-12-08 20:13 ` Kees Cook 2017-12-08 20:13 ` Kees Cook [not found] ` <CAGXu5j+VupGmKEEHx-uNXw27Xvndu=0ObsBqMwQiaYPyMGD+vw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> 2017-12-08 20:57 ` Matthew Wilcox 2017-12-08 20:57 ` Matthew Wilcox 2017-12-08 11:08 ` Michael Ellerman 2017-12-08 11:08 ` Michael Ellerman 2017-12-08 14:27 ` Pavel Machek 2017-12-08 14:27 ` Pavel Machek 2017-12-08 20:31 ` Cyril Hrubis 2017-12-08 20:31 ` Cyril Hrubis 2017-12-08 20:47 ` Florian Weimer 2017-12-08 20:47 ` Florian Weimer 2017-12-08 14:33 ` David Laight 2017-12-08 14:33 ` David Laight 2017-12-06 4:50 ` Michael Ellerman 2017-12-06 4:50 ` Michael Ellerman [not found] ` <87zi6we9z2.fsf-W0DJWXSxmBNbyGPkN3NxC2scP1bn1w/D@public.gmane.org> 2017-12-06 7:33 ` Rasmus Villemoes 2017-12-06 7:33 ` Rasmus Villemoes [not found] ` <a3b3129a-2626-a65e-59b0-68aada523723-rjjw5hvvQKZaa/9Udqfwiw@public.gmane.org> 2017-12-06 9:08 ` Michal Hocko 2017-12-06 9:08 ` Michal Hocko 2017-12-07 0:19 ` Kees Cook 2017-12-07 0:19 ` Kees Cook 2017-12-07 1:08 ` John Hubbard -- strict thread matches above, loose matches on Subject: below -- 2017-12-13 9:25 [PATCH v2 " Michal Hocko 2017-12-13 9:25 ` [PATCH 2/2] fs, elf: drop MAP_FIXED usage from elf_map Michal Hocko 2017-12-13 9:25 ` Michal Hocko 2017-11-16 10:18 (unknown), Michal Hocko 2017-11-16 10:19 ` [PATCH 2/2] fs, elf: drop MAP_FIXED usage from elf_map Michal Hocko 2017-11-16 10:19 ` Michal Hocko 2017-11-17 0:30 ` Kees Cook 2017-11-17 0:30 ` Kees Cook
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=20171129144219.22867-3-mhocko@kernel.org \ --to=mhocko@kernel.org \ --cc=aarcange@redhat.com \ --cc=abdhalee@linux.vnet.ibm.com \ --cc=akpm@linux-foundation.org \ --cc=fweimer@redhat.com \ --cc=jhubbard@nvidia.com \ --cc=joel@jms.id.au \ --cc=keescook@chromium.org \ --cc=khalid.aziz@oracle.com \ --cc=linux-api@vger.kernel.org \ --cc=linux-arch@vger.kernel.org \ --cc=linux-kernel@vger.kernel.org \ --cc=linux-mm@kvack.org \ --cc=linux@armlinux.org.uk \ --cc=mhocko@suse.com \ --cc=mpe@ellerman.id.au \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: linkBe sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).