Bug 2131609 - (0==ElfXX_Ehdr.e_shnum) really does mean "no Section headers"
Summary: (0==ElfXX_Ehdr.e_shnum) really does mean "no Section headers"
Keywords:
Status: CLOSED EOL
Alias: None
Product: Fedora
Classification: Fedora
Component: binutils
Version: 36
Hardware: x86_64
OS: Linux
unspecified
unspecified
Target Milestone: ---
Assignee: Nick Clifton
QA Contact: Fedora Extras Quality Assurance
URL:
Whiteboard:
Depends On:
Blocks:
TreeView+ depends on / blocked
 
Reported: 2022-10-02 21:34 UTC by John Reiser
Modified: 2023-05-25 19:36 UTC (History)
7 users (show)

Fixed In Version: (binutils-2.39-4.fc38
Doc Type: If docs needed, set a value
Doc Text:
Clone Of:
Environment:
Last Closed: 2023-05-25 19:36:35 UTC
Type: Bug
Embargoed:


Attachments (Terms of Use)
Short ET_EXEC with (0 == .e_shnum) (7.42 KB, application/x-executable)
2022-10-02 21:34 UTC, John Reiser
no flags Details

Description John Reiser 2022-10-02 21:34:42 UTC
Created attachment 1915583 [details]
Short ET_EXEC with (0 == .e_shnum)

Description of problem: When ( 0 == ElfXX_Ehdr.e_shnum ) then "readelf --headers" prints 64 items of garbage ElfXX_Shdr Section headers, as if the 0 meant 64 instead.  This is a bug.  It is perfectly reasonable for an ELF executable to have no Section headers at all.  This worked correctly (that is, no Section header info is printed when (0 == .e_shnum)) in Fedora 34.


Version-Release number of selected component (if applicable):
binutils-2.37-36.fc36.x86_64


How reproducible: every time


Steps to Reproduce:
1. "readelf --headers" when (0 == ElfXX_Ehdr.e_shnum)
2.
3.

Actual results:
Prints 64 items of garbage ElfXX_Shdr Secton headers.

Expected results: No Section header info is printed when (0 == .e_shnum).


Additional info: 7KB example ET_EXEC with (0 == .e_shnum) will be attached.

Comment 1 Nick Clifton 2022-10-03 11:59:37 UTC
Hi John,

  Actually readelf is behaving correctly.  There is an extension to the ELF standard 
  that allows for a file to contain more than 0xFF00 sections:

    https://docs.oracle.com/cd/E19120-01/open.solaris/819-0690/chapter6-43405/index.html

  The definition of e_shnum there says:

    The number of entries in the section header table. The product of 
    e_shentsize and e_shnum gives the section header table's size in bytes. 
    If a file has no section header table, e_shnum holds the value zero.

    If the number of sections is greater than or equal to SHN_LORESERVE (0xff00),
    e_shnum has the value zero.  The actual number of section header table entries 
    is contained in the sh_size field of the section header at index 0.  Otherwise, 
    the sh_size member of the initial section header entry contains the value zero. 
    See Table 7–6 and Table 7–7.

  So in theory your test file should have a single section header which contains
  a sh_size value of 0.  Either that or the e_shentsize field in the file header 
  should be set to 0, indicating that there really are no sections in the file.

  There is one thing that readelf can/should do however.  If the e_shoff field in
  the ELF header is zero, then this is a sure sign that there are no sections.  Since
  the file has to start with an ELF file header, that cannot also be the location
  of the section header table.  I will add this test to the upstream binutils
  sources and to rawhide.  I do not see this as a serious issue however, so I am
  not planning to backport the patch to other releases.

Cheers
  Nick

Comment 2 John Reiser 2022-10-03 14:04:00 UTC
Hi Nick,

> ... or the e_shentsize field in the file header should be set to 0, ...

libbfd and other code that checks for "sanity" of ELF, complains if
(.e_shentsize != sizeof(ElfXX_Shdr)), regardless of .e_shnum, .e_shoff, etc.;
and bfd_open() fails.  [The git log for my project shows that I discovered
this 16 years ago in 2006.]  This makes gdb totally useless, which is fatal
for developers and maintenance and support.

So I look forward to the extra check for (0 == .e_shoff) as an overriding
confirmation of "no Section headers at all, not even by any extension"
when (0 == .e_shnum).

[Side rant:  (.e_shentsize > sizeof(ElfXX_Shdr)) should be allowed
so that ElfXX_Shdr can have private extensions!  Of course in plain-C
this means that incrementing a pointer (ElfXX_Shdr *ptr;) must be done
by explicit addition of .shentsize instead of implicitly by increment
operator (++).  It has long been time to use C++ instead of C.]

Comment 3 Nick Clifton 2022-10-03 14:59:29 UTC
(In reply to John Reiser from comment #2)

> libbfd and other code that checks for "sanity" of ELF, complains if
> (.e_shentsize != sizeof(ElfXX_Shdr)), regardless of .e_shnum, .e_shoff, etc.;
> and bfd_open() fails.

Hmm, well that is a bug.  I should probably fix it.  I don't suppose you would 
care to file an upstream bug report for it ?


> So I look forward to the extra check for (0 == .e_shoff) as an overriding
> confirmation of "no Section headers at all, not even by any extension"
> when (0 == .e_shnum).

Please try out: binutils-2.39-4.fc38.

> [Side rant:  (.e_shentsize > sizeof(ElfXX_Shdr)) should be allowed
> so that ElfXX_Shdr can have private extensions!

Weeelll - private extensions to the ELF format could be a dangerous 
thing to pursue.  But yes, technically you are correct.

> Of course in plain-C
> this means that incrementing a pointer (ElfXX_Shdr *ptr;) must be done
> by explicit addition of .shentsize instead of implicitly by increment
> operator (++).

True - and several other changes as well.

> It has long been time to use C++ instead of C.]

Well I will politely agree to disagree with you here.  But then I am
old and crumbly...

Cheers
  Nick

Comment 4 John Reiser 2022-10-04 18:24:34 UTC
(In reply to Nick Clifton from comment #3)

Looking at commit aef1974a66ba9644b239f761c4b8b586f4763e4b (origin/master/HEAD on Oct.3)
of  git://sourceware.org/git/binutils-gdb.git  in directory bfd:
===== git blame $(grep -srl e_shentsize .)
elfcode.h:dc810e3900d4 (Alan Modra        2001-09-18 09:57:26 +0000  254)   dst->e_shentsize = H_GET_16 (abfd, src->e_shentsize);
elfcode.h:dc810e3900d4 (Alan Modra        2001-09-18 09:57:26 +0000  287)   H_PUT_16 (abfd, src->e_shentsize, dst->e_shentsize);
elfcode.h:0c35f01ab36d (Alan Modra        2001-09-22 03:16:01 +0000  581)   if (i_ehdrp->e_shentsize != sizeof (x_shdr) && i_ehdrp->e_shnum != 0)
elfcode.h:^252b5132c75 (Richard Henderson 1999-05-03 07:29:11 +0000 1682)   fprintf (stderr, "e_shentsize  = %ld\n", (long) ehdrp->e_shentsize);
elfcode.h:5979d6b69b20 (Alan Modra        2014-04-02 12:07:33 +1030 1846)   if (i_ehdr.e_shoff != 0 && i_ehdr.e_shnum != 0 && i_ehdr.e_shentsize != 0)
elfcode.h:5979d6b69b20 (Alan Modra        2014-04-02 12:07:33 +1030 1848)       shdr_end = i_ehdr.e_shoff + i_ehdr.e_shnum * i_ehdr.e_shentsize;
=====
it looks like line 1846) took care of _some_ of this 8.5 years ago in 2014;
my problem dates to 2006, 8 years before that.

> Please try out: binutils-2.39-4.fc38.

Where is version 2.39-4?  I tried
   sudo dnf install fedora-repos-rawhide
   dnf download --enablerepo rawhide binutils
and got version 2.39-3 which still has the problem.
I also got version 2.39-3 from
   Fedora-Workstation-Live-x86_64-Rawhide-20221004.n.0.iso
which is today's rawhide compose.
(My fedora 36 system has "GNU readelf version 2.37-36.fc36".)

Comment 5 Nick Clifton 2022-10-05 10:50:03 UTC
(In reply to John Reiser from comment #4)
 
> it looks like line 1846) took care of _some_ of this 8.5 years ago in 2014;

My own tests seem to confirm this.  If you do come across a case when an sh_entsize of 0 is causing a problem, please let me know - or file a bug report.


> Where is version 2.39-4?

Stuck in gating.  But you can find the rpms here:

  https://koji.fedoraproject.org/koji/buildinfo?buildID=2070126

Comment 6 Ben Cotton 2023-04-25 18:27:56 UTC
This message is a reminder that Fedora Linux 36 is nearing its end of life.
Fedora will stop maintaining and issuing updates for Fedora Linux 36 on 2023-05-16.
It is Fedora's policy to close all bug reports from releases that are no longer
maintained. At that time this bug will be closed as EOL if it remains open with a
'version' of '36'.

Package Maintainer: If you wish for this bug to remain open because you
plan to fix it in a currently maintained version, change the 'version' 
to a later Fedora Linux version. Note that the version field may be hidden.
Click the "Show advanced fields" button if you do not see it.

Thank you for reporting this issue and we are sorry that we were not 
able to fix it before Fedora Linux 36 is end of life. If you would still like 
to see this bug fixed and are able to reproduce it against a later version 
of Fedora Linux, you are encouraged to change the 'version' to a later version
prior to this bug being closed.

Comment 7 Ludek Smid 2023-05-25 19:36:35 UTC
Fedora Linux 36 entered end-of-life (EOL) status on 2023-05-16.

Fedora Linux 36 is no longer maintained, which means that it
will not receive any further security or bug fix updates. As a result we
are closing this bug.

If you can reproduce this bug against a currently maintained version of Fedora Linux
please feel free to reopen this bug against that version. Note that the version
field may be hidden. Click the "Show advanced fields" button if you do not see
the version field.

If you are unable to reopen this bug, please file a new report against an
active release.

Thank you for reporting this bug and we are sorry it could not be fixed.


Note You need to log in before you can comment on or make changes to this bug.