]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
Handle extended phnum in elflint and elfcmp.
authorRoland McGrath <roland@redhat.com>
Fri, 8 Jan 2010 04:11:42 +0000 (20:11 -0800)
committerRoland McGrath <roland@redhat.com>
Fri, 8 Jan 2010 04:11:42 +0000 (20:11 -0800)
src/ChangeLog
src/elfcmp.c
src/elflint.c

index 91a6450a137f6c863f835f31e7e79814ce7f6522..2a925388702fe9a59c6b8952a8fe07987d00deea 100644 (file)
@@ -1,3 +1,13 @@
+2010-01-07  Roland McGrath  <roland@redhat.com>
+
+       * elfcmp.c (main): Use elf_getshdrnum and elf_getphdrnum.
+
+       * elflint.c (phnum): New static variable.
+       (check_elf_header): Set it, handling PN_XNUM.
+       Use that in place of EHDR->e_phnum throughout.
+       (check_symtab, check_reloc_shdr, check_dynamic): Likewise.
+       (unknown_dependency_p, check_sections, check_program_header): Likewise.
+
 2010-01-05  Roland McGrath  <roland@redhat.com>
 
        * readelf.c (dwarf_attr_string): Match DW_AT_GNU_vector and
index 7f871ecf042c13378ef8b1cb979160bf33a5a7a0..71a80092ae0dfe87de9b4796980f24242fbf9ef4 100644 (file)
@@ -1,5 +1,5 @@
 /* Compare relevant content of two ELF files.
-   Copyright (C) 2005, 2006, 2007, 2008, 2009 Red Hat, Inc.
+   Copyright (C) 2005-2010 Red Hat, Inc.
    This file is part of Red Hat elfutils.
    Written by Ulrich Drepper <drepper@redhat.com>, 2005.
 
@@ -192,6 +192,39 @@ main (int argc, char *argv[])
       goto out;
     }
 
+  size_t shnum1;
+  size_t shnum2;
+  if (unlikely (elf_getshdrnum (elf1, &shnum1) != 0))
+    error (2, 0, gettext ("cannot get section count of '%s': %s"),
+          fname1, elf_errmsg (-1));
+  if (unlikely (elf_getshdrnum (elf2, &shnum2) != 0))
+    error (2, 0, gettext ("cannot get section count of '%s': %s"),
+          fname2, elf_errmsg (-1));
+  if (unlikely (shnum1 != shnum2))
+    {
+      if (! quiet)
+       error (0, 0, gettext ("%s %s diff: section count"), fname1, fname2);
+      result = 1;
+      goto out;
+    }
+
+  size_t phnum1;
+  size_t phnum2;
+  if (unlikely (elf_getphdrnum (elf1, &phnum1) != 0))
+    error (2, 0, gettext ("cannot get program header count of '%s': %s"),
+          fname1, elf_errmsg (-1));
+  if (unlikely (elf_getphdrnum (elf2, &phnum2) != 0))
+    error (2, 0, gettext ("cannot get program header count of '%s': %s"),
+          fname2, elf_errmsg (-1));
+  if (unlikely (phnum1 != phnum2))
+    {
+      if (! quiet)
+       error (0, 0, gettext ("%s %s diff: program header count"),
+              fname1, fname2);
+      result = 1;
+      goto out;
+    }
+
   /* Iterate over all sections.  We expect the sections in the two
      files to match exactly.  */
   Elf_Scn *scn1 = NULL;
@@ -410,7 +443,7 @@ main (int argc, char *argv[])
       ehdr_region.next = &phdr_region;
 
       phdr_region.from = ehdr1->e_phoff;
-      phdr_region.to = ehdr1->e_phoff + ehdr1->e_phnum * ehdr1->e_phentsize;
+      phdr_region.to = ehdr1->e_phoff + phnum1 * ehdr1->e_phentsize;
       phdr_region.next = regions;
 
       regions = &ehdr_region;
@@ -445,7 +478,7 @@ main (int argc, char *argv[])
     }
 
   /* Compare the program header tables.  */
-  for (int ndx = 0; ndx < ehdr1->e_phnum; ++ndx)
+  for (unsigned int ndx = 0; ndx < phnum1; ++ndx)
     {
       GElf_Phdr phdr1_mem;
       GElf_Phdr *phdr1 = gelf_getphdr (elf1, ndx, &phdr1_mem);
index 12e7242f25363eec138f6afb849f9ac1b34e5a85..63d8389ecfb109c755ec3d39898caa37c305ed57 100644 (file)
@@ -1,5 +1,5 @@
 /* Pedantic checking of ELF files compliance with gABI/psABI spec.
-   Copyright (C) 2001,2002,2003,2004,2005,2006,2007,2008,2009 Red Hat, Inc.
+   Copyright (C) 2001-2010 Red Hat, Inc.
    This file is part of Red Hat elfutils.
    Written by Ulrich Drepper <drepper@redhat.com>, 2001.
 
@@ -343,8 +343,9 @@ static const int valid_e_machine[] =
   (sizeof (valid_e_machine) / sizeof (valid_e_machine[0]))
 
 
-/* Number of sections.  */
+/* Numbers of sections and program headers.  */
 static unsigned int shnum;
+static unsigned int phnum;
 
 
 static void
@@ -464,6 +465,24 @@ invalid number of section header table entries\n"));
        ERROR (gettext ("invalid section header index\n"));
     }
 
+  phnum = ehdr->e_phnum;
+  if (ehdr->e_phnum == PN_XNUM)
+    {
+      /* Get the header of the zeroth section.  The sh_info field
+        might contain the phnum count.  */
+      GElf_Shdr shdr_mem;
+      GElf_Shdr *shdr = gelf_getshdr (elf_getscn (ebl->elf, 0), &shdr_mem);
+      if (shdr != NULL)
+       {
+         /* The error will be reported later.  */
+         if (shdr->sh_info < PN_XNUM)
+           ERROR (gettext ("\
+invalid number of program header table entries\n"));
+         else
+           phnum = shdr->sh_info;
+       }
+    }
+
   /* Check the e_flags field.  */
   if (!ebl_machine_flag_check (ebl, ehdr->e_flags))
     ERROR (gettext ("invalid machine flags: %s\n"),
@@ -478,13 +497,13 @@ invalid number of section header table entries\n"));
       if (ehdr->e_phentsize != 0 && ehdr->e_phentsize != sizeof (Elf32_Phdr))
        ERROR (gettext ("invalid program header size: %hd\n"),
               ehdr->e_phentsize);
-      else if (ehdr->e_phoff + ehdr->e_phnum * ehdr->e_phentsize > size)
+      else if (ehdr->e_phoff + phnum * ehdr->e_phentsize > size)
        ERROR (gettext ("invalid program header position or size\n"));
 
       if (ehdr->e_shentsize != 0 && ehdr->e_shentsize != sizeof (Elf32_Shdr))
        ERROR (gettext ("invalid section header size: %hd\n"),
               ehdr->e_shentsize);
-      else if (ehdr->e_shoff + ehdr->e_shnum * ehdr->e_shentsize > size)
+      else if (ehdr->e_shoff + shnum * ehdr->e_shentsize > size)
        ERROR (gettext ("invalid section header position or size\n"));
     }
   else if (gelf_getclass (ebl->elf) == ELFCLASS64)
@@ -495,7 +514,7 @@ invalid number of section header table entries\n"));
       if (ehdr->e_phentsize != 0 && ehdr->e_phentsize != sizeof (Elf64_Phdr))
        ERROR (gettext ("invalid program header size: %hd\n"),
               ehdr->e_phentsize);
-      else if (ehdr->e_phoff + ehdr->e_phnum * ehdr->e_phentsize > size)
+      else if (ehdr->e_phoff + phnum * ehdr->e_phentsize > size)
        ERROR (gettext ("invalid program header position or size\n"));
 
       if (ehdr->e_shentsize != 0 && ehdr->e_shentsize != sizeof (Elf64_Shdr))
@@ -802,16 +821,16 @@ section [%2d] '%s': symbol %zu does not fit completely in referenced section [%2
                    {
                      GElf_Phdr phdr_mem;
                      GElf_Phdr *phdr = NULL;
-                     int pcnt;
+                     unsigned int pcnt;
 
-                     for (pcnt = 0; pcnt < ehdr->e_phnum; ++pcnt)
+                     for (pcnt = 0; pcnt < phnum; ++pcnt)
                        {
                          phdr = gelf_getphdr (ebl->elf, pcnt, &phdr_mem);
                          if (phdr != NULL && phdr->p_type == PT_TLS)
                            break;
                        }
 
-                     if (pcnt == ehdr->e_phnum)
+                     if (pcnt == phnum)
                        {
                          if (no_pt_tls++ == 0)
                            ERROR (gettext ("\
@@ -959,7 +978,7 @@ section [%2d] '%s': _GLOBAL_OFFSET_TABLE_ symbol present, but no .got section\n"
            /* Check that address and size match the dynamic section.
               We locate the dynamic section via the program header
               entry.  */
-           for (int pcnt = 0; pcnt < ehdr->e_phnum; ++pcnt)
+           for (unsigned int pcnt = 0; pcnt < phnum; ++pcnt)
              {
                GElf_Phdr phdr_mem;
                GElf_Phdr *phdr = gelf_getphdr (ebl->elf, pcnt, &phdr_mem);
@@ -1216,7 +1235,7 @@ section [%2d] '%s': section entry size does not match ElfXX_Rel\n"),
      the loaded segments are and b) which are read-only.  This will
      also allow us to determine whether the same reloc section is
      modifying loaded and not loaded segments.  */
-  for (int i = 0; i < ehdr->e_phnum; ++i)
+  for (unsigned int i = 0; i < phnum; ++i)
     {
       GElf_Phdr phdr_mem;
       GElf_Phdr *phdr = gelf_getphdr (ebl->elf, i, &phdr_mem);
@@ -1703,7 +1722,7 @@ section [%2d] '%s': entry %zu: pointer does not match address of section [%2d] '
        case DT_VERNEED:
        case DT_VERSYM:
        check_addr:
-         for (n = 0; n < ehdr->e_phnum; ++n)
+         for (n = 0; n < phnum; ++n)
            {
              GElf_Phdr phdr_mem;
              GElf_Phdr *phdr = gelf_getphdr (ebl->elf, n, &phdr_mem);
@@ -1712,7 +1731,7 @@ section [%2d] '%s': entry %zu: pointer does not match address of section [%2d] '
                  && phdr->p_vaddr + phdr->p_memsz > dyn->d_un.d_ptr)
                break;
            }
-         if (unlikely (n >= ehdr->e_phnum))
+         if (unlikely (n >= phnum))
            {
              char buf[50];
              ERROR (gettext ("\
@@ -2780,18 +2799,18 @@ section [%2d] '%s': symbol %d: version index %d is for requested version\n"),
 
 
 static int
-unknown_dependency_p (Elf *elf, GElf_Ehdr *ehdr, const char *fname)
+unknown_dependency_p (Elf *elf, const char *fname)
 {
   GElf_Phdr phdr_mem;
   GElf_Phdr *phdr = NULL;
 
-  int i;
-  for (i = 0; i < ehdr->e_phnum; ++i)
+  unsigned int i;
+  for (i = 0; i < phnum; ++i)
     if ((phdr = gelf_getphdr (elf, i, &phdr_mem)) != NULL
        && phdr->p_type == PT_DYNAMIC)
       break;
 
-  if (i == ehdr->e_phnum)
+  if (i == phnum)
     return 1;
   assert (phdr != NULL);
   Elf_Scn *scn = gelf_offscn (elf, phdr->p_offset);
@@ -2819,7 +2838,7 @@ unknown_dependency_p (Elf *elf, GElf_Ehdr *ehdr, const char *fname)
 static unsigned int nverneed;
 
 static void
-check_verneed (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, int idx)
+check_verneed (Ebl *ebl, GElf_Shdr *shdr, int idx)
 {
   if (++nverneed == 2)
     ERROR (gettext ("more than one version reference section present\n"));
@@ -2874,7 +2893,7 @@ section [%2d] '%s': entry %d has invalid file reference\n"),
        }
 
       /* Check that there is a DT_NEEDED entry for the referenced library.  */
-      if (unknown_dependency_p (ebl->elf, ehdr, libname))
+      if (unknown_dependency_p (ebl->elf, libname))
        ERROR (gettext ("\
 section [%2d] '%s': entry %d references unknown dependency\n"),
               idx, section_name (ebl, idx), cnt);
@@ -3412,8 +3431,6 @@ check_sections (Ebl *ebl, GElf_Ehdr *ehdr)
        ERROR (gettext ("zeroth section has nonzero address\n"));
       if (shdr->sh_offset != 0)
        ERROR (gettext ("zeroth section has nonzero offset\n"));
-      if (shdr->sh_info != 0)
-       ERROR (gettext ("zeroth section has nonzero info field\n"));
       if (shdr->sh_addralign != 0)
        ERROR (gettext ("zeroth section has nonzero align value\n"));
       if (shdr->sh_entsize != 0)
@@ -3426,9 +3443,13 @@ zeroth section has nonzero size value while ELF header has nonzero shnum value\n
       if (shdr->sh_link != 0 && ehdr->e_shstrndx != SHN_XINDEX)
        ERROR (gettext ("\
 zeroth section has nonzero link value while ELF header does not signal overflow in shstrndx\n"));
+
+      if (shdr->sh_info != 0 && ehdr->e_phnum != PN_XNUM)
+       ERROR (gettext ("\
+zeroth section has nonzero link value while ELF header does not signal overflow in phnum\n"));
     }
 
-  int *segment_flags = xcalloc (ehdr->e_phnum, sizeof segment_flags[0]);
+  int *segment_flags = xcalloc (phnum, sizeof segment_flags[0]);
 
   bool dot_interp_section = false;
 
@@ -3695,11 +3716,11 @@ section [%2zu] '%s' is both executable and writable\n"),
        {
          /* Make sure the section is contained in a loaded segment
             and that the initialization part matches NOBITS sections.  */
-         int pcnt;
+         unsigned int pcnt;
          GElf_Phdr phdr_mem;
          GElf_Phdr *phdr;
 
-         for (pcnt = 0; pcnt < ehdr->e_phnum; ++pcnt)
+         for (pcnt = 0; pcnt < phnum; ++pcnt)
            if ((phdr = gelf_getphdr (ebl->elf, pcnt, &phdr_mem)) != NULL
                && ((phdr->p_type == PT_LOAD
                     && (shdr->sh_flags & SHF_TLS) == 0)
@@ -3760,7 +3781,7 @@ section [%2zu] '%s' is writable in unwritable segment %d\n"),
                break;
              }
 
-         if (pcnt == ehdr->e_phnum)
+         if (pcnt == phnum)
            ERROR (gettext ("\
 section [%2zu] '%s': alloc flag set but section not in any loaded segment\n"),
                   cnt, section_name (ebl, cnt));
@@ -3831,7 +3852,7 @@ section [%2zu] '%s': relocatable files cannot have dynamic symbol tables\n"),
          break;
 
        case SHT_GNU_verneed:
-         check_verneed (ebl, ehdr, shdr, cnt);
+         check_verneed (ebl, shdr, cnt);
          break;
 
        case SHT_GNU_verdef:
@@ -3852,7 +3873,7 @@ section [%2zu] '%s': relocatable files cannot have dynamic symbol tables\n"),
     ERROR (gettext ("INTERP program header entry but no .interp section\n"));
 
   if (!is_debuginfo)
-    for (int pcnt = 0; pcnt < ehdr->e_phnum; ++pcnt)
+    for (unsigned int pcnt = 0; pcnt < phnum; ++pcnt)
       {
        GElf_Phdr phdr_mem;
        GElf_Phdr *phdr = gelf_getphdr (ebl->elf, pcnt, &phdr_mem);
@@ -4079,7 +4100,7 @@ only executables, shared objects, and core files can have program headers\n"));
   int num_pt_tls = 0;
   int num_pt_relro = 0;
 
-  for (int cnt = 0; cnt < ehdr->e_phnum; ++cnt)
+  for (unsigned int cnt = 0; cnt < phnum; ++cnt)
     {
       GElf_Phdr phdr_mem;
       GElf_Phdr *phdr;
@@ -4154,8 +4175,8 @@ more than one GNU_RELRO entry in program header\n"));
          else
            {
              /* Check that the region is in a writable segment.  */
-             int inner;
-             for (inner = 0; inner < ehdr->e_phnum; ++inner)
+             unsigned int inner;
+             for (inner = 0; inner < phnum; ++inner)
                {
                  GElf_Phdr phdr2_mem;
                  GElf_Phdr *phdr2;
@@ -4180,7 +4201,7 @@ loadable segment [%u] flags do not match GNU_RELRO [%u] flags\n"),
                    }
                }
 
-             if (inner >= ehdr->e_phnum)
+             if (inner >= phnum)
                ERROR (gettext ("\
 %s segment not contained in a loaded segment\n"), "GNU_RELRO");
            }
@@ -4188,8 +4209,8 @@ loadable segment [%u] flags do not match GNU_RELRO [%u] flags\n"),
       else if (phdr->p_type == PT_PHDR)
        {
          /* Check that the region is in a writable segment.  */
-         int inner;
-         for (inner = 0; inner < ehdr->e_phnum; ++inner)
+         unsigned int inner;
+         for (inner = 0; inner < phnum; ++inner)
            {
              GElf_Phdr phdr2_mem;
              GElf_Phdr *phdr2;
@@ -4203,7 +4224,7 @@ loadable segment [%u] flags do not match GNU_RELRO [%u] flags\n"),
                break;
            }
 
-         if (inner >= ehdr->e_phnum)
+         if (inner >= phnum)
            ERROR (gettext ("\
 %s segment not contained in a loaded segment\n"), "PHDR");