If there is no e_phoff e_phnum cannot be trusted. Extended phnum can only
be gotten if we have an actual section table and a shdr for section zero,
Extended phnum can be too large to fit in the file (or a size_t).

Signed-off-by: Mark Wielaard <[email protected]>
---
 libelf/ChangeLog        |  7 +++++++
 libelf/elf32_getphdr.c  |  6 ++++--
 libelf/elf_getphdrnum.c | 18 +++++++++++++-----
 src/ChangeLog           |  6 ++++++
 src/readelf.c           |  7 ++++++-
 5 files changed, 36 insertions(+), 8 deletions(-)

diff --git a/libelf/ChangeLog b/libelf/ChangeLog
index beb431f..ef5da43 100644
--- a/libelf/ChangeLog
+++ b/libelf/ChangeLog
@@ -1,5 +1,12 @@
 2014-11-16  Mark Wielaard  <[email protected]>
 
+       * elf32_getphdr.c (getphdr_wrlock): Check e_phoff isn't zero.
+       Check for too many pheaders.
+       * elf_getphdrnum.c (__elf_getphdrnum_rdlock): Check section zero
+       actually exists before handling PN_XNUM.
+
+2014-11-16  Mark Wielaard  <[email protected]>
+
        * gelf_getnote.c (gelf_getnote): Check padding overflow.
 
 2014-11-16  Mark Wielaard  <[email protected]>
diff --git a/libelf/elf32_getphdr.c b/libelf/elf32_getphdr.c
index e74e63f..1b82a48 100644
--- a/libelf/elf32_getphdr.c
+++ b/libelf/elf32_getphdr.c
@@ -76,15 +76,17 @@ __elfw2(LIBELFBITS,getphdr_wrlock) (elf)
       size_t phnum;
       if (__elf_getphdrnum_rdlock (elf, &phnum) != 0)
        goto out;
-      if (phnum == 0)
+      if (phnum == 0 || ehdr->e_phoff == 0)
        {
          __libelf_seterrno (ELF_E_NO_PHDR);
          goto out;
        }
 
+      /* Check this doesn't overflow.  */
       size_t size = phnum * sizeof (ElfW2(LIBELFBITS,Phdr));
 
-      if (ehdr->e_phoff > elf->maximum_size
+      if (phnum > SIZE_MAX / sizeof (ElfW2(LIBELFBITS,Phdr))
+         || ehdr->e_phoff > elf->maximum_size
          || elf->maximum_size - ehdr->e_phoff < size)
        {
          __libelf_seterrno (ELF_E_INVALID_DATA);
diff --git a/libelf/elf_getphdrnum.c b/libelf/elf_getphdrnum.c
index 99649be..d8e34d7 100644
--- a/libelf/elf_getphdrnum.c
+++ b/libelf/elf_getphdrnum.c
@@ -1,5 +1,5 @@
 /* Return number of program headers in the ELF file.
-   Copyright (C) 2010 Red Hat, Inc.
+   Copyright (C) 2010, 2014 Red Hat, Inc.
    This file is part of elfutils.
 
    This file is free software; you can redistribute it and/or modify
@@ -62,10 +62,18 @@ __elf_getphdrnum_rdlock (elf, dst)
      /* If there are no section headers, perhaps this is really just 65536
        written without PN_XNUM support.  Either that or it's bad data.  */
 
-     if (likely (scns->cnt > 0))
-       *dst = (elf->class == ELFCLASS32
-              ? scns->data[0].shdr.e32->sh_info
-              : scns->data[0].shdr.e64->sh_info);
+     if (elf->class == ELFCLASS32)
+       {
+        if (likely (scns->cnt > 0
+                    && elf->state.elf32.scns.data[0].shdr.e32 != NULL))
+          *dst = scns->data[0].shdr.e32->sh_info;
+       }
+     else
+       {
+        if (likely (scns->cnt > 0
+                    && elf->state.elf64.scns.data[0].shdr.e64 != NULL))
+          *dst = scns->data[0].shdr.e64->sh_info;
+       }
    }
 
  return 0;
diff --git a/src/ChangeLog b/src/ChangeLog
index fefd6c1..737c674 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,5 +1,11 @@
 2014-11-16  Mark Wielaard  <[email protected]>
 
+       * readelf (process_elf_file): Set phnum to zero if there aren't
+       actually any pheaders.
+       (print_phdr): Check there actually is a phdr.
+
+2014-11-16  Mark Wielaard  <[email protected]>
+
        * readelf.c (print_cfa_program): Check block len before calling
        print_ops.
 
diff --git a/src/readelf.c b/src/readelf.c
index 697a0e5..583b5da 100644
--- a/src/readelf.c
+++ b/src/readelf.c
@@ -835,6 +835,11 @@ process_elf_file (Dwfl_Module *dwflmod, int fd)
           gettext ("cannot determine number of program headers: %s"),
           elf_errmsg (-1));
 
+  /* If there isn't actually a program header then set phnum to zero.
+     Don't do any extra work.  gelf_getphdr will always return NULL.  */
+  if (ehdr->e_phoff == 0)
+    phnum = 0;
+
   /* For an ET_REL file, libdwfl has adjusted the in-core shdrs
      and may have applied relocation to some sections.
      So we need to get a fresh Elf handle on the file to display those.  */
@@ -1157,7 +1162,7 @@ There are %d section headers, starting at offset %#" 
PRIx64 ":\n\
 static void
 print_phdr (Ebl *ebl, GElf_Ehdr *ehdr)
 {
-  if (ehdr->e_phnum == 0)
+  if (ehdr->e_phnum == 0 || ehdr->e_phoff == 0)
     /* No program header, this is OK in relocatable objects.  */
     return;
 
-- 
1.8.3.1

Reply via email to