public inbox for elfutils@sourceware.org
 help / color / mirror / Atom feed
From: Mark Wielaard <mjw@redhat.com>
To: elfutils-devel@lists.fedorahosted.org
Subject: Re: out-of-bounds read / crash in elfutils tools (readelf, nm, ...) with malformed file
Date: Sat, 08 Nov 2014 15:04:16 +0100	[thread overview]
Message-ID: <20141108140416.GB28913@blokker.redhat.com> (raw)
In-Reply-To: 20141107163249.1ded8b70@pc

[-- Attachment #1: Type: text/plain, Size: 992 bytes --]

On Fri, Nov 07, 2014 at 04:32:49PM +0100, Hanno Böck wrote:
> Also see attachmend, output from american fuzzy lop with latest git
> code and your two patches. 9 crashes, 10 hangs.

Thanks. One of those pointed out that my overflow check for hash section
sizes was bogus. Fixed version attached. The others seem to be because
handle_versym didn't initialize its vernames and filenames. Then when
an ELF file didn't set them we did check they were not set (NULL), but
that check failed, because the elements still contained random data.
The second second patch fixes that.

I have pushed all three fuzz-robustify patches to master.

Note that the testcases you say are hanging are just really, realy slow.
Because of very large input values they try to process a lot of elements,
but eventually they will finish. We still might to sanity check some of
those excessively large input values, but they don't lead to hangs or
crashes. Just very long runtimes.

Cheers,

Mark

[-- Attachment #2: 0001-readelf-Sanity-check-hash-section-contents-before-pr.patch --]
[-- Type: text/plain, Size: 4229 bytes --]

>From 6b246e0620bdbaf8240f3bf391ec773eea3f7f48 Mon Sep 17 00:00:00 2001
From: Mark Wielaard <mjw@redhat.com>
Date: Fri, 7 Nov 2014 12:54:02 +0100
Subject: [PATCH 1/2] readelf: Sanity check hash section contents before
 processing.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Reported by: Hanno Böck <hanno@hboeck.de>
Signed-off-by: Mark Wielaard <mjw@redhat.com>
---
 src/ChangeLog |  6 ++++++
 src/readelf.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 54 insertions(+), 1 deletion(-)

diff --git a/src/ChangeLog b/src/ChangeLog
index a252cdc..3ff3e31 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,9 @@
+2014-11-07  Mark Wielaard  <mjw@redhat.com>
+
+	* readelf.c (handle_sysv_hash): Sanity check section contents.
+	(handle_sysv_hash64): Likewise.
+	(handle_gnu_hash): Likewise.
+
 2014-09-14  Petr Machata  <pmachata@redhat.com>
 
 	* readelf.c (handle_relocs_rela): Typo fix, test DESTSHDR properly.
diff --git a/src/readelf.c b/src/readelf.c
index 4d3bb36..e03a771 100644
--- a/src/readelf.c
+++ b/src/readelf.c
@@ -2954,8 +2954,21 @@ handle_sysv_hash (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr, size_t shstrndx)
       return;
     }
 
+  if (unlikely (data->d_size < 2 * sizeof (Elf32_Word)))
+    {
+    invalid_data:
+      error (0, 0, gettext ("invalid data in sysv.hash section %d"),
+	     (int) elf_ndxscn (scn));
+      return;
+    }
+
   Elf32_Word nbucket = ((Elf32_Word *) data->d_buf)[0];
   Elf32_Word nchain = ((Elf32_Word *) data->d_buf)[1];
+
+  uint64_t used_buf = (2ULL + nchain + nbucket) * sizeof (Elf32_Word);
+  if (used_buf > data->d_size)
+    goto invalid_data;
+
   Elf32_Word *bucket = &((Elf32_Word *) data->d_buf)[2];
   Elf32_Word *chain = &((Elf32_Word *) data->d_buf)[2 + nbucket];
 
@@ -2996,8 +3009,21 @@ handle_sysv_hash64 (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr, size_t shstrndx)
       return;
     }
 
+  if (unlikely (data->d_size < 2 * sizeof (Elf64_Xword)))
+    {
+    invalid_data:
+      error (0, 0, gettext ("invalid data in sysv.hash64 section %d"),
+	     (int) elf_ndxscn (scn));
+      return;
+    }
+
   Elf64_Xword nbucket = ((Elf64_Xword *) data->d_buf)[0];
   Elf64_Xword nchain = ((Elf64_Xword *) data->d_buf)[1];
+
+  uint64_t used_buf = (2ULL + nchain + nbucket) * sizeof (Elf64_Xword);
+  if (used_buf > data->d_size)
+    goto invalid_data;
+
   Elf64_Xword *bucket = &((Elf64_Xword *) data->d_buf)[2];
   Elf64_Xword *chain = &((Elf64_Xword *) data->d_buf)[2 + nbucket];
 
@@ -3037,18 +3063,37 @@ handle_gnu_hash (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr, size_t shstrndx)
       return;
     }
 
+  if (unlikely (data->d_size < 4 * sizeof (Elf32_Word)))
+    {
+    invalid_data:
+      error (0, 0, gettext ("invalid data in gnu.hash section %d"),
+	     (int) elf_ndxscn (scn));
+      return;
+    }
+
   Elf32_Word nbucket = ((Elf32_Word *) data->d_buf)[0];
   Elf32_Word symbias = ((Elf32_Word *) data->d_buf)[1];
 
   /* Next comes the size of the bitmap.  It's measured in words for
      the architecture.  It's 32 bits for 32 bit archs, and 64 bits for
-     64 bit archs.  */
+     64 bit archs.  There is always a bloom filter present, so zero is
+     an invalid value.  */
   Elf32_Word bitmask_words = ((Elf32_Word *) data->d_buf)[2];
   if (gelf_getclass (ebl->elf) == ELFCLASS64)
     bitmask_words *= 2;
 
+  if (bitmask_words == 0)
+    goto invalid_data;
+
   Elf32_Word shift = ((Elf32_Word *) data->d_buf)[3];
 
+  /* Is there still room for the sym chain?
+     Use uint64_t calculation to prevent 32bit overlow.  */
+  uint64_t used_buf = (4ULL + bitmask_words + nbucket) * sizeof (Elf32_Word);
+  uint32_t max_nsyms = (data->d_size - used_buf) / sizeof (Elf32_Word);
+  if (used_buf > data->d_size)
+    goto invalid_data;
+
   uint32_t *lengths = (uint32_t *) xcalloc (nbucket, sizeof (uint32_t));
 
   Elf32_Word *bitmask = &((Elf32_Word *) data->d_buf)[4];
@@ -3068,6 +3113,8 @@ handle_gnu_hash (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr, size_t shstrndx)
 	    ++nsyms;
 	    if (maxlength < ++lengths[cnt])
 	      ++maxlength;
+	    if (inner > max_nsyms)
+	      goto invalid_data;
 	  }
 	while ((chain[inner++] & 1) == 0);
       }
-- 
1.9.3


[-- Attachment #3: 0002-readelf.c-handle_versym-Initialize-vername-and-filen.patch --]
[-- Type: text/plain, Size: 1614 bytes --]

>From d8b9682b1a5ff2746f172487eaf19ebd088bb7f4 Mon Sep 17 00:00:00 2001
From: Mark Wielaard <mjw@redhat.com>
Date: Sat, 8 Nov 2014 14:04:27 +0100
Subject: [PATCH 2/2] readelf.c (handle_versym): Initialize vername and
 filename array elements.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

We check whether the elements are set before printing their contents,
but didn't make sure they were initialized.

Reported-by: Hanno Böck <hanno@hboeck.de>
Signed-off-by: Mark Wielaard <mjw@redhat.com>
---
 src/ChangeLog | 5 +++++
 src/readelf.c | 2 ++
 2 files changed, 7 insertions(+)

diff --git a/src/ChangeLog b/src/ChangeLog
index 3ff3e31..6d3e951 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,8 @@
+2014-11-08  Mark Wielaard  <mjw@redhat.com>
+
+	* readelf.c (handle_versym): Initialize vername and filename array
+	elements.
+
 2014-11-07  Mark Wielaard  <mjw@redhat.com>
 
 	* readelf.c (handle_sysv_hash): Sanity check section contents.
diff --git a/src/readelf.c b/src/readelf.c
index e03a771..01c644f 100644
--- a/src/readelf.c
+++ b/src/readelf.c
@@ -2716,7 +2716,9 @@ handle_versym (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
 
       /* Allocate the array.  */
       vername = (const char **) alloca (nvername * sizeof (const char *));
+      memset(vername, 0, nvername * sizeof (const char *));
       filename = (const char **) alloca (nvername * sizeof (const char *));
+      memset(filename, 0, nvername * sizeof (const char *));
 
       /* Run through the data structures again and collect the strings.  */
       if (defscn != NULL)
-- 
1.9.3


             reply	other threads:[~2014-11-08 14:04 UTC|newest]

Thread overview: 28+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-11-08 14:04 Mark Wielaard [this message]
  -- strict thread matches above, loose matches on Subject: below --
2014-11-13 21:55 
2014-11-13 21:51 Mark Wielaard
2014-11-13 19:39 
2014-11-13 14:45 Mark Wielaard
2014-11-11 16:57 Mark Wielaard
2014-11-11 13:57 
2014-11-11 13:53 Mark Wielaard
2014-11-11 13:49 Petr Machata
2014-11-11 13:40 
2014-11-11 13:30 Petr Machata
2014-11-11 13:15 Mark Wielaard
2014-11-11 10:31 
2014-11-10 20:58 Mark Wielaard
2014-11-09 21:59 
2014-11-09 16:57 Mark Wielaard
2014-11-08 16:10 
2014-11-08 15:32 Mark Wielaard
2014-11-07 16:13 
2014-11-07 15:45 Mark Wielaard
2014-11-07 15:32 
2014-11-07 11:58 Mark Wielaard
2014-11-07 11:51 Mark Wielaard
2014-11-07  0:27 
2014-11-06 18:25 Roland McGrath
2014-11-06 16:05 Mark Wielaard
2014-11-06 15:11 Mark Wielaard
2014-10-31 16:13 

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=20141108140416.GB28913@blokker.redhat.com \
    --to=mjw@redhat.com \
    --cc=elfutils-devel@lists.fedorahosted.org \
    /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 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 read-only IMAP folder(s) and NNTP newsgroup(s).