summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoland McGrath <roland@redhat.com>2010-01-07 20:11:42 -0800
committerRoland McGrath <roland@redhat.com>2010-01-07 20:11:42 -0800
commitbd733cae5159e3a3c4c05f7685559fa3ae8b58c6 (patch)
treed6ed85f1594d56f70f6ee1b5af04e2fed0b380ac
parent6fd3cd104adf4107aa64e1c1e84028b4ea0b3296 (diff)
downloadelfutils-bd733cae5159e3a3c4c05f7685559fa3ae8b58c6.tar.gz
Handle extended phnum in elflint and elfcmp.
-rw-r--r--src/ChangeLog10
-rw-r--r--src/elfcmp.c39
-rw-r--r--src/elflint.c87
3 files changed, 100 insertions, 36 deletions
diff --git a/src/ChangeLog b/src/ChangeLog
index 91a6450a..2a925388 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -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
diff --git a/src/elfcmp.c b/src/elfcmp.c
index 7f871ecf..71a80092 100644
--- a/src/elfcmp.c
+++ b/src/elfcmp.c
@@ -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);
diff --git a/src/elflint.c b/src/elflint.c
index 12e7242f..63d8389e 100644
--- a/src/elflint.c
+++ b/src/elflint.c
@@ -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");