aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKees Cook <keescook@chromium.org>2016-08-02 17:04:51 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2016-08-02 19:35:14 -0400
commit0036d1f7eb95bcc52977f15507f00dd07018e7e2 (patch)
tree7031059870f2cdfdd0076b87c981a67e4e1655b9
parent45107ff6d5265b9786c62b694140d839bc3d2433 (diff)
binfmt_elf: fix calculations for bss padding
A double-bug exists in the bss calculation code, where an overflow can happen in the "last_bss - elf_bss" calculation, but vm_brk internally aligns the argument, underflowing it, wrapping back around safe. We shouldn't depend on these bugs staying in sync, so this cleans up the bss padding handling to avoid the overflow. This moves the bss padzero() before the last_bss > elf_bss case, since the zero-filling of the ELF_PAGE should have nothing to do with the relationship of last_bss and elf_bss: any trailing portion should be zeroed, and a zero size is already handled by padzero(). Then it handles the math on elf_bss vs last_bss correctly. These need to both be ELF_PAGE aligned to get the comparison correct, since that's the expected granularity of the mappings. Since elf_bss already had alignment-based padding happen in padzero(), the "start" of the new vm_brk() should be moved forward as done in the original code. However, since the "end" of the vm_brk() area will already become PAGE_ALIGNed in vm_brk() then last_bss should get aligned here to avoid hiding it as a side-effect. Additionally makes a cosmetic change to the initial last_bss calculation so it's easier to read in comparison to the load_addr calculation above it (i.e. the only difference is p_filesz vs p_memsz). Link: http://lkml.kernel.org/r/1468014494-25291-2-git-send-email-keescook@chromium.org Signed-off-by: Kees Cook <keescook@chromium.org> Reported-by: Hector Marco-Gisbert <hecmargi@upv.es> Cc: Ismael Ripoll Ripoll <iripoll@upv.es> Cc: Alexander Viro <viro@zeniv.linux.org.uk> Cc: "Kirill A. Shutemov" <kirill.shutemov@linux.intel.com> Cc: Oleg Nesterov <oleg@redhat.com> Cc: Chen Gang <gang.chen.5i5j@gmail.com> Cc: Michal Hocko <mhocko@suse.com> Cc: Konstantin Khlebnikov <koct9i@gmail.com> Cc: Andrea Arcangeli <aarcange@redhat.com> Cc: Andrey Ryabinin <aryabinin@virtuozzo.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--fs/binfmt_elf.c34
1 files changed, 18 insertions, 16 deletions
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index a7a28110dc80..7f6aff3f72eb 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -605,28 +605,30 @@ static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex,
605 * Do the same thing for the memory mapping - between 605 * Do the same thing for the memory mapping - between
606 * elf_bss and last_bss is the bss section. 606 * elf_bss and last_bss is the bss section.
607 */ 607 */
608 k = load_addr + eppnt->p_memsz + eppnt->p_vaddr; 608 k = load_addr + eppnt->p_vaddr + eppnt->p_memsz;
609 if (k > last_bss) 609 if (k > last_bss)
610 last_bss = k; 610 last_bss = k;
611 } 611 }
612 } 612 }
613 613
614 /*
615 * Now fill out the bss section: first pad the last page from
616 * the file up to the page boundary, and zero it from elf_bss
617 * up to the end of the page.
618 */
619 if (padzero(elf_bss)) {
620 error = -EFAULT;
621 goto out;
622 }
623 /*
624 * Next, align both the file and mem bss up to the page size,
625 * since this is where elf_bss was just zeroed up to, and where
626 * last_bss will end after the vm_brk() below.
627 */
628 elf_bss = ELF_PAGEALIGN(elf_bss);
629 last_bss = ELF_PAGEALIGN(last_bss);
630 /* Finally, if there is still more bss to allocate, do it. */
614 if (last_bss > elf_bss) { 631 if (last_bss > elf_bss) {
615 /*
616 * Now fill out the bss section. First pad the last page up
617 * to the page boundary, and then perform a mmap to make sure
618 * that there are zero-mapped pages up to and including the
619 * last bss page.
620 */
621 if (padzero(elf_bss)) {
622 error = -EFAULT;
623 goto out;
624 }
625
626 /* What we have mapped so far */
627 elf_bss = ELF_PAGESTART(elf_bss + ELF_MIN_ALIGN - 1);
628
629 /* Map the last of the bss segment */
630 error = vm_brk(elf_bss, last_bss - elf_bss); 632 error = vm_brk(elf_bss, last_bss - elf_bss);
631 if (error) 633 if (error)
632 goto out; 634 goto out;