Commit 90af5c4f authored by Kees Cook's avatar Kees Cook Committed by Kleber Sacilotto de Souza

binfmt_elf: fix calculations for bss padding

BugLink: https://bugs.launchpad.net/bugs/1810947

commit 0036d1f7 upstream.

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.orgSigned-off-by: default avatarKees Cook <keescook@chromium.org>
Reported-by: default avatarHector 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: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: default avatarBen Hutchings <ben.hutchings@codethink.co.uk>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
Signed-off-by: default avatarJuerg Haefliger <juergh@canonical.com>
Signed-off-by: default avatarKleber Sacilotto de Souza <kleber.souza@canonical.com>
parent 3a42023c
...@@ -604,28 +604,30 @@ static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex, ...@@ -604,28 +604,30 @@ static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex,
* Do the same thing for the memory mapping - between * Do the same thing for the memory mapping - between
* elf_bss and last_bss is the bss section. * elf_bss and last_bss is the bss section.
*/ */
k = load_addr + eppnt->p_memsz + eppnt->p_vaddr; k = load_addr + eppnt->p_vaddr + eppnt->p_memsz;
if (k > last_bss) if (k > last_bss)
last_bss = k; last_bss = k;
} }
} }
if (last_bss > elf_bss) {
/* /*
* Now fill out the bss section. First pad the last page up * Now fill out the bss section: first pad the last page from
* to the page boundary, and then perform a mmap to make sure * the file up to the page boundary, and zero it from elf_bss
* that there are zero-mapped pages up to and including the * up to the end of the page.
* last bss page.
*/ */
if (padzero(elf_bss)) { if (padzero(elf_bss)) {
error = -EFAULT; error = -EFAULT;
goto out; goto out;
} }
/*
/* What we have mapped so far */ * Next, align both the file and mem bss up to the page size,
elf_bss = ELF_PAGESTART(elf_bss + ELF_MIN_ALIGN - 1); * since this is where elf_bss was just zeroed up to, and where
* last_bss will end after the vm_brk() below.
/* Map the last of the bss segment */ */
elf_bss = ELF_PAGEALIGN(elf_bss);
last_bss = ELF_PAGEALIGN(last_bss);
/* Finally, if there is still more bss to allocate, do it. */
if (last_bss > elf_bss) {
error = vm_brk(elf_bss, last_bss - elf_bss); error = vm_brk(elf_bss, last_bss - elf_bss);
if (BAD_ADDR(error)) if (BAD_ADDR(error))
goto out; goto out;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment