All of lore.kernel.org
 help / color / mirror / Atom feed
From: Hector Marco-Gisbert <hecmargi@upv.es>
To: linux-kernel@vger.kernel.org
Cc: linux-fsdevel@vger.kernel.org,
	Alexander Viro <viro@zeniv.linux.org.uk>,
	kees Cook <keescook@chromium.org>,
	Ismael Ripoll Ripoll <iripoll@upv.es>,
	Hector Marco-Gisbert <hecmargi@upv.es>
Subject: [PATCH] Fix bss mapping for the interpreter in binfmt_elf
Date: Wed, 11 May 2016 12:37:00 +0200	[thread overview]
Message-ID: <1462963020-11097-1-git-send-email-hecmargi@upv.es> (raw)

While working on a new ASLR for userspace we detected an error in the
interpret loader.

The size of the bss section for some interpreters is not correctly
calculated resulting in unnecessary calls to vm_brk() with enormous size
values.

The bug appears when loading some interpreters with a small bss size. Once
the last loadable segment has been loaded, the bss section is zeroed up to
the page boundary and the elf_bss variable is updated to this new page
boundary.  Because of this update (alignment), the last_bss could be less
than elf_bss and the subtraction "last_bss - elf_bss" value could overflow.

Although it is quite easy to check this error, it has not been manifested
because some peculiarities of the bug. Following is a brief description:


$ size /lib32/ld-2.19.so 
   text    data     bss     dec     hex filename
 128456    2964     192  131612   2021c /lib32/ld-2.19.so


An execution example with:
  - last_bss: 0xb7794938
  - elf_bss:  0xb7794878

        
>From fs/binfmt_elf.c:
---------------------------------------------------------------------------
     if (last_bss > elf_bss) { 
             /*
              * Now fill out the bss section.  First pad the last page up
              * to the page boundary, and then perform a mmap to make sure
              * that there are zero-mapped pages up to and including the
              * last bss page.
              */
             if (padzero(elf_bss)) {
                     error = -EFAULT;
                     goto out;
             }

             /* What we have mapped so far */
             elf_bss = ELF_PAGESTART(elf_bss + ELF_MIN_ALIGN - 1);

             <---------- elf_bss here is 0xb7795000

             /* Map the last of the bss segment */
             error = vm_brk(elf_bss, last_bss - elf_bss); <-- overflow!
             if (BAD_ADDR(error))
                     goto out;
     }

     error = load_addr;
out:
     return error;
}
---------------------------------------------------------------------------


The size value requested to the vm_brk() call (last_bss - elf_bss) is
0xfffffffffffff938 and internally this size is page aligned in the do_brk()
function resulting in a 0 length request.

static unsigned long do_brk(unsigned long addr, unsigned long len)
{
        ...
        len = PAGE_ALIGN(len);
        if (!len)
                return addr;


Since a segment of 0 bytes is perfectly valid, it returns the requested
address to vm_brk() and because it is page aligned (done by the previous
line to the vm_brk() call the "error" is not detected by
"BAD_ADDR(error)" and the "load_elf_interp()" functions does not
returns any error. Note that vm_brk() is not necessary at all.

In brief, if the end of the bss is in the same page than the last segment
loaded then the size of the last of bss segment is incorrectly calculated.


This patch set up to the page boundary of the last_bss variable and only do
the vm_brk() call when necessary.


Signed-off-by: Hector Marco-Gisbert <hecmargi@upv.es>
Acked-by: Ismael Ripoll Ripoll <iripoll@upv.es>
---
 fs/binfmt_elf.c | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index 81381cc..acfbdc2 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -526,7 +526,7 @@ static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex,
 	int load_addr_set = 0;
 	unsigned long last_bss = 0, elf_bss = 0;
 	unsigned long error = ~0UL;
-	unsigned long total_size;
+	unsigned long total_size, size;
 	int i;
 
 	/* First of all, some simple consistency checks */
@@ -626,11 +626,15 @@ static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex,
 
 		/* What we have mapped so far */
 		elf_bss = ELF_PAGESTART(elf_bss + ELF_MIN_ALIGN - 1);
+		last_bss = ELF_PAGESTART(last_bss + ELF_MIN_ALIGN - 1);
 
 		/* Map the last of the bss segment */
-		error = vm_brk(elf_bss, last_bss - elf_bss);
-		if (BAD_ADDR(error))
-			goto out;
+		size = last_bss - elf_bss;
+		if (size) {
+			error = vm_brk(elf_bss, size);
+			if (BAD_ADDR(error))
+				goto out;
+		}
 	}
 
 	error = load_addr;
-- 
1.9.1

             reply	other threads:[~2016-05-11 10:37 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-05-11 10:37 Hector Marco-Gisbert [this message]
2016-06-22 16:28 ` [PATCH] Fix bss mapping for the interpreter in binfmt_elf Hector Marco-Gisbert
2016-06-22 16:28   ` Hector Marco-Gisbert
2016-06-22 22:31 ` Kees Cook
2016-07-04 17:01   ` Hector Marco-Gisbert
2016-07-08 21:10     ` 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=1462963020-11097-1-git-send-email-hecmargi@upv.es \
    --to=hecmargi@upv.es \
    --cc=iripoll@upv.es \
    --cc=keescook@chromium.org \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=viro@zeniv.linux.org.uk \
    /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: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.