Re: readelf reporting of e_shstrndx is slightly wrong

2018-08-21 Thread Alan Modra
On Tue, Aug 21, 2018 at 11:09:04PM +, Mike Murphy wrote:
> I think an example would help explain this.  Below is part of the
> output from readelf -h on an elf object I have which has 210016
> sections, but puts the section header string table at section 1.  So
> e_shstrndx is 1, but e_shnum is 0.  My reading of the elf standard
> is that this is legal,

I agree.

> but readelf complains due to the check
> header->e_shstrndx >= header->e_shnum: 

Oh, right, header->e_shnum hasn't been updated to the actual number of
sections at that point.  It's still zero.

>   Size of this header:   64 (bytes)
>   Size of program headers:   56 (bytes)
>   Number of program headers: 0
>   Size of section headers:   64 (bytes)
>   Number of section headers: 0 (210016)
>   Section header string table index: 1 
> 
> The code in readelf seems to assume that if there are > 0xff00
> sections then shstrndx will be one of those sections that are
> > 0xff00.

Yes, the range checking is wrong too, even if header->e_shnum had been
updated to the value retrieved from section_header[0].sh_size.  It
doesn't range check a value from section_header[0].sh_link.

* readelf.c (process_file_header): Assign updated values from
section_header[0] fields to e_phnum, e_shnum and e_shstrndx
during printing of header.  Correct e_shstrndx range check.
Remove unnecessary casts and use %u rather than %ld for
unsigned int header fields.  Don't print a random %lx when
reporting an unknown EI_VERSION.

diff --git a/binutils/readelf.c b/binutils/readelf.c
index d330484663..4627da20ab 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -4765,12 +4765,12 @@ process_file_header (Filedata * filedata)
  get_elf_class (header->e_ident[EI_CLASS]));
   printf (_("  Data:  %s\n"),
  get_data_encoding (header->e_ident[EI_DATA]));
-  printf (_("  Version:   %d %s\n"),
+  printf (_("  Version:   %d%s\n"),
  header->e_ident[EI_VERSION],
  (header->e_ident[EI_VERSION] == EV_CURRENT
-  ? "(current)"
+  ? _(" (current)")
   : (header->e_ident[EI_VERSION] != EV_NONE
- ? _("")
+ ? _(" ")
  : "")));
   printf (_("  OS/ABI:%s\n"),
  get_osabi_name (filedata, header->e_ident[EI_OSABI]));
@@ -4781,45 +4781,57 @@ process_file_header (Filedata * filedata)
   printf (_("  Machine:   %s\n"),
  get_machine_name (header->e_machine));
   printf (_("  Version:   0x%lx\n"),
- (unsigned long) header->e_version);
+ header->e_version);
 
   printf (_("  Entry point address:   "));
-  print_vma ((bfd_vma) header->e_entry, PREFIX_HEX);
+  print_vma (header->e_entry, PREFIX_HEX);
   printf (_("\n  Start of program headers:  "));
-  print_vma ((bfd_vma) header->e_phoff, DEC);
+  print_vma (header->e_phoff, DEC);
   printf (_(" (bytes into file)\n  Start of section headers:  "));
-  print_vma ((bfd_vma) header->e_shoff, DEC);
+  print_vma (header->e_shoff, DEC);
   printf (_(" (bytes into file)\n"));
 
   printf (_("  Flags: 0x%lx%s\n"),
- (unsigned long) header->e_flags,
+ header->e_flags,
  get_machine_flags (filedata, header->e_flags, header->e_machine));
-  printf (_("  Size of this header:   %ld (bytes)\n"),
- (long) header->e_ehsize);
-  printf (_("  Size of program headers:   %ld (bytes)\n"),
- (long) header->e_phentsize);
-  printf (_("  Number of program headers: %ld"),
- (long) header->e_phnum);
+  printf (_("  Size of this header:   %u (bytes)\n"),
+ header->e_ehsize);
+  printf (_("  Size of program headers:   %u (bytes)\n"),
+ header->e_phentsize);
+  printf (_("  Number of program headers: %u"),
+ header->e_phnum);
   if (filedata->section_headers != NULL
  && header->e_phnum == PN_XNUM
  && filedata->section_headers[0].sh_info != 0)
-   printf (" (%ld)", (long) filedata->section_headers[0].sh_info);
+   {
+ header->e_phnum = filedata->section_headers[0].sh_info;
+ printf (" (%u)", header->e_phnum);
+   }
   putc ('\n', stdout);
-  printf (_("  Size of section headers:   %ld (bytes)\n"),
- (long) header->e_shentsize);
-  printf (_("  Number of section headers: %ld"),
- (long) header->e_shnum);
+  printf (_("  Size of section headers:   %u (bytes)\n"),
+ header->e_shentsize);
+  printf (_("  Number of section headers:

RE: readelf reporting of e_shstrndx is slightly wrong

2018-08-21 Thread Mike Murphy
I think an example would help explain this.  Below is part of the output from 
readelf -h on an elf object I have which has 210016 sections, but puts the 
section header string table at section 1.  So e_shstrndx is 1, but e_shnum is 
0.  My reading of the elf standard is that this is legal, but readelf complains 
due to the check header->e_shstrndx >= header->e_shnum:
  Size of this header:   64 (bytes)
  Size of program headers:   56 (bytes)
  Number of program headers: 0
  Size of section headers:   64 (bytes)
  Number of section headers: 0 (210016)
  Section header string table index: 1 

The code in readelf seems to assume that if there are > 0xff00 sections then 
shstrndx will be one of those sections that are > 0xff00.

-Original Message-
From: Nick Clifton  
Sent: Tuesday, August 21, 2018 8:32 AM
To: Mike Murphy ; bug-binutils@gnu.org
Subject: Re: readelf reporting of e_shstrndx is slightly wrong

Hi Mike,

> If the file has no section name string table, this member holds the value 
> |SHN_UNDEF|. 
> If the section name string table section index is greater than or 
> equal to |SHN_LORESERVE| (|0xff00|), this member has the value 
> |SHN_XINDEX| (|0x|)

> The current readelf -h seems to assume that if there are more than 0xff00 
> sections, then the shstrndx will also be past that.  But there is nothing to 
> prevent the section name string table from being section 1, in which case 
> e_shstrndx should just be 1.  But the readelf implementation has:
> 
>    else if (elf_header.e_shstrndx != SHN_UNDEF && 
> elf_header.e_shstrndx >= elf_header.e_shnum)
> 
>        printf(_(""));

I disagree.  The readelf code actually looks like this:

 if (filedata->section_headers != NULL
  && header->e_shstrndx == (SHN_XINDEX & 0x))
printf (" (%u)", filedata->section_headers[0].sh_link);
  else if (header->e_shstrndx != SHN_UNDEF
   && header->e_shstrndx >= header->e_shnum)
printf (_(" "));
   
There is no check that the file itself has more than 0xff00 sections.
Instead it checks to see if the e_shstrndx field is SHN_XINDEX and if so it 
follows the link.  Otherwise it checks that the index is either SHN_UNDEF or a 
valid section number.

Note - the use if "& 0x" in the above code is confusing, and looks surplus 
to me, but I do not think that it makes any difference to the behaviour.

Cheers
  Nick

___
bug-binutils mailing list
bug-binutils@gnu.org
https://lists.gnu.org/mailman/listinfo/bug-binutils


Re: readelf reporting of e_shstrndx is slightly wrong

2018-08-21 Thread Egeyar Bagcioglu

Hi,


On 08/21/2018 05:31 PM, Nick Clifton wrote:


  if (filedata->section_headers != NULL
  && header->e_shstrndx == (SHN_XINDEX & 0x))
printf (" (%u)", filedata->section_headers[0].sh_link);
   else if (header->e_shstrndx != SHN_UNDEF
   && header->e_shstrndx >= header->e_shnum)
printf (_(" "));

[...]


Note - the use if "& 0x" in the above code is confusing, and looks
surplus to me, but I do not think that it makes any difference to the
behaviour.


I haven't checked the location of this quoted code; however, the use of 
"& 0x" is probably due to a clever hack made internally:


Elf[32|64]_External_Ehdr in include/elf/external.h declares e_shstrndx 
as 2 bytes,
while Elf_Internal_Ehdr in include/elf/internal.h  declares it as 4 
bytes because we would like to be able to keep the overflowing values 
within the same variable without extra checks.


We would like to be able to store values that are reserved or higher 
than 0x as valid indices internally in the 4-byte e_shstrndx. 
Therefore, some constants including SHN_XINDEX are re-defined in 
elf/internal.h as 4 byte values. These redefinitions hold the new bounds 
on such indices. Because of this internal simplification, though, we 
need to use "& 0x" to get the 2-byte value that's used when reading 
values in or outputting them.


Regards,
Egeyar

___
bug-binutils mailing list
bug-binutils@gnu.org
https://lists.gnu.org/mailman/listinfo/bug-binutils


Re: readelf reporting of e_shstrndx is slightly wrong

2018-08-21 Thread Nick Clifton
Hi Mike,

> If the file has no section name string table, this member holds the value 
> |SHN_UNDEF|. 
> If the section name string table section index is greater than or equal to 
> |SHN_LORESERVE| (|0xff00|), this member has the value |SHN_XINDEX| (|0x|) 

> The current readelf -h seems to assume that if there are more than 0xff00 
> sections, then the shstrndx will also be past that.  But there is nothing to 
> prevent the section name string table from being section 1, in which case 
> e_shstrndx should just be 1.  But the readelf implementation has:
> 
>    else if (elf_header.e_shstrndx != SHN_UNDEF && 
> elf_header.e_shstrndx >= elf_header.e_shnum)
> 
>        printf(_(“”));

I disagree.  The readelf code actually looks like this:

 if (filedata->section_headers != NULL
  && header->e_shstrndx == (SHN_XINDEX & 0x))
printf (" (%u)", filedata->section_headers[0].sh_link);
  else if (header->e_shstrndx != SHN_UNDEF
   && header->e_shstrndx >= header->e_shnum)
printf (_(" "));
   
There is no check that the file itself has more than 0xff00 sections.
Instead it checks to see if the e_shstrndx field is SHN_XINDEX and if
so it follows the link.  Otherwise it checks that the index is either
SHN_UNDEF or a valid section number.

Note - the use if "& 0x" in the above code is confusing, and looks
surplus to me, but I do not think that it makes any difference to the
behaviour.

Cheers
  Nick

___
bug-binutils mailing list
bug-binutils@gnu.org
https://lists.gnu.org/mailman/listinfo/bug-binutils