public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
* Re: [binutils-gdb] Fix the linker so that it will not silently generate ELF binaries with invalid program headers. Fix
       [not found] <20161123111226.62132.qmail@sourceware.org>
@ 2016-12-08  9:30 ` Maciej W. Rozycki
  2016-12-08 11:32   ` Alan Modra
  2016-12-08 12:09   ` Nick Clifton
  0 siblings, 2 replies; 9+ messages in thread
From: Maciej W. Rozycki @ 2016-12-08  9:30 UTC (permalink / raw)
  To: Nick Clifton; +Cc: binutils

Hi Nick,

On Wed, 23 Nov 2016, Nick Clifton wrote:

> commit 1a9ccd70f9a75dc6b48d340059f28ef3550c107b
> Author: Nick Clifton <nickc@redhat.com>
> Date:   Wed Nov 23 11:10:39 2016 +0000
> 
>     Fix the linker so that it will not silently generate ELF binaries with invalid program headers.  Fix readelf to report such invalid binaries.

 This change has caused a `mips-vxworks' and `mipsel-vxworks' target 
regression:

FAIL: VxWorks executable test 2 (dynamic)

and I cannot figure out either from the commit description or the lengthy 
Bugzilla discussion whether it is an actual functional VxWorks regression 
or whether we can just adjust the regexps in the test case and consider it 
handled.

 Your commit changed output from this test case from:

Elf file type is EXEC (Executable file)
Entry point 0x80400
There are 5 program headers, starting at offset 52

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  PHDR           0x000034 0x00001034 0x00000000 0x000a0 0x000a0 R E 0x4
  INTERP         0x001000 0x00080000 0x00080000 0x00013 0x00013 R   0x1
      [Requesting program interpreter: /usr/lib/libc.so.1]
  LOAD           0x001000 0x00080000 0x00080000 0x00408 0x00408 R E 0x1000
  LOAD           0x002000 0x00081000 0x00081000 0x00804 0x00c00 RW  0x1000
  DYNAMIC        0x002000 0x00081000 0x00081000 0x00078 0x00078 RW  0x4

 Section to Segment mapping:
  Segment Sections...
   00
   01     .interp
   02     .interp .hash .dynsym .dynstr .text
   03     .dynamic .got .data .rld_map
   04     .dynamic

to:

Elf file type is EXEC (Executable file)
Entry point 0x80400
There are 5 program headers, starting at offset 52

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  PHDR           0x000034 0x0007f034 0x0007f034 0x000a0 0x000a0 R E 0x4
  INTERP         0x001000 0x00080000 0x00080000 0x00013 0x00013 R   0x1
      [Requesting program interpreter: /usr/lib/libc.so.1]
  LOAD           0x000000 0x0007f000 0x0007f000 0x01408 0x01408 R E 0x1000
  LOAD           0x002000 0x00081000 0x00081000 0x00804 0x00c00 RW  0x1000
  DYNAMIC        0x002000 0x00081000 0x00081000 0x00078 0x00078 RW  0x4

 Section to Segment mapping:
  Segment Sections...
   00
   01     .interp
   02     .interp .hash .dynsym .dynstr .text
   03     .dynamic .got .data .rld_map
   04     .dynamic

This places the first LOAD segment below the location set with the linker 
script, which I fear may affect run-time interpretation.  The test case 
has the addresses expected spelled out in full for a reason I suppose.

 Please help with resolving this problem.

  Maciej

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [binutils-gdb] Fix the linker so that it will not silently generate ELF binaries with invalid program headers. Fix
  2016-12-08  9:30 ` [binutils-gdb] Fix the linker so that it will not silently generate ELF binaries with invalid program headers. Fix Maciej W. Rozycki
@ 2016-12-08 11:32   ` Alan Modra
  2016-12-08 12:14     ` Nick Clifton
  2016-12-09  0:17     ` Maciej W. Rozycki
  2016-12-08 12:09   ` Nick Clifton
  1 sibling, 2 replies; 9+ messages in thread
From: Alan Modra @ 2016-12-08 11:32 UTC (permalink / raw)
  To: Maciej W. Rozycki; +Cc: Nick Clifton, binutils

On Thu, Dec 08, 2016 at 09:30:04AM +0000, Maciej W. Rozycki wrote:
> Program Headers:
>   Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
>   PHDR           0x000034 0x00001034 0x00000000 0x000a0 0x000a0 R E 0x4
>   INTERP         0x001000 0x00080000 0x00080000 0x00013 0x00013 R   0x1
>       [Requesting program interpreter: /usr/lib/libc.so.1]
>   LOAD           0x001000 0x00080000 0x00080000 0x00408 0x00408 R E 0x1000
>   LOAD           0x002000 0x00081000 0x00081000 0x00804 0x00c00 RW  0x1000
>   DYNAMIC        0x002000 0x00081000 0x00081000 0x00078 0x00078 RW  0x4

The gABI says:

PT_PHDR
    The array element, if present, specifies the location and size of
    the program header table itself, both in the file and in the
    memory image of the program. This segment type may not occur more
    than once in a file. Moreover, it may occur only if the program
    header table is part of the memory image of the program. If it is
    present, it must precede any loadable segment entry.

The above clearly violates this part of the spec because PT_PHDR is
present yet is not part of the memory image.

Nick's patch forced the first PT_LOAD to cover the program headers.  I
think an equally valid and somewhat better fix would have been to not
emit PT_PHDR when no PT_LOAD header covers the program headers.  The
reason I say that is because PT_PHDR is optional.  A loader can read
the program headers itself from file using info in the ELF header.

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [binutils-gdb] Fix the linker so that it will not silently generate ELF binaries with invalid program headers. Fix
  2016-12-08  9:30 ` [binutils-gdb] Fix the linker so that it will not silently generate ELF binaries with invalid program headers. Fix Maciej W. Rozycki
  2016-12-08 11:32   ` Alan Modra
@ 2016-12-08 12:09   ` Nick Clifton
  1 sibling, 0 replies; 9+ messages in thread
From: Nick Clifton @ 2016-12-08 12:09 UTC (permalink / raw)
  To: Maciej W. Rozycki, Nick Clifton; +Cc: binutils

[-- Attachment #1: Type: text/plain, Size: 3574 bytes --]

Hi Maciej,

> Program Headers:
>   Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
>   PHDR           0x000034 0x00001034 0x00000000 0x000a0 0x000a0 R E 0x4
>   INTERP         0x001000 0x00080000 0x00080000 0x00013 0x00013 R   0x1
>       [Requesting program interpreter: /usr/lib/libc.so.1]
>   LOAD           0x001000 0x00080000 0x00080000 0x00408 0x00408 R E 0x1000
>   LOAD           0x002000 0x00081000 0x00081000 0x00804 0x00c00 RW  0x1000
>   DYNAMIC        0x002000 0x00081000 0x00081000 0x00078 0x00078 RW  0x4

The problem with this layout is that the ELF specification says in its description
of the program header types:

  PT_PHDR  The array element, if present, specifies the location 
           and size of the program header table itself, both in 
           the file and in the memory image of the program. This 
           segment type may not occur more than once in a file.
           Moreover, it may occur only if the program header table 
           is part of the memory image of the program. If it is
           present, it must precede any loadable segment entry.

Hence, if a PT_PHDR segment is present in a binary it must also be part of
a PT_LOAD segment, so that it gets loaded into the runtime memory image of
the executable.

The layout above breaks this requirement by placing the PT_PHDR segment at
0x1034 but starting the first load segment at 0x80000.

> Program Headers:
>   Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
>   PHDR           0x000034 0x0007f034 0x0007f034 0x000a0 0x000a0 R E 0x4
>   INTERP         0x001000 0x00080000 0x00080000 0x00013 0x00013 R   0x1
>       [Requesting program interpreter: /usr/lib/libc.so.1]
>   LOAD           0x000000 0x0007f000 0x0007f000 0x01408 0x01408 R E 0x1000
>   LOAD           0x002000 0x00081000 0x00081000 0x00804 0x00c00 RW  0x1000
>   DYNAMIC        0x002000 0x00081000 0x00081000 0x00078 0x00078 RW  0x4

This is the linker's attempt to resolve the problem, by moving the start
address of the first LOAD segment down to 0x7f0000.  (The linker cannot just
create another LOAD segment just for the program headers as there is code
inside the linker that will discard any LOAD segments that do not have any
sections mapped into them).


> This places the first LOAD segment below the location set with the linker 
> script, which I fear may affect run-time interpretation.  The test case 
> has the addresses expected spelled out in full for a reason I suppose.

True.  You could fix the problem by adding --no-dynamic-linker to the test's
linker command line, since then the linker will not create PHDR or INTERP
segments, and so the LOAD segments will have the expected addresses.  I doubt
if you want this solution however as I assume that the whole point of this
test is to create a working dynamic executable.

The correct solution, I think, is to define the program headers in the linker
script, so that their placement can be specifically controlled by the user.
See the vxworks1.ld script attached, which does this.

But...this causes a problem for the "VxWorks executable test 2 (static)" test
as now there is a DYNAMIC segment in the program headers but no .dynamic
section in the section headers, and readelf complains.  *sigh*  So you need
a second linker script, just for static executables.

So the result is the attached patch, which I think resolves the problem.  (For
MIPS based vxworks targets anyway.  It looks like similar changes may be needed
for other vxworks architectures).  What do you think ?

Cheers
  Nick

[-- Attachment #2: vxworks1.ld --]
[-- Type: text/plain, Size: 815 bytes --]

PHDRS
{
  headers      PT_PHDR PHDRS;
  header_load  PT_LOAD PHDRS;
  interp       PT_INTERP;
  code         PT_LOAD;
  data         PT_LOAD;
  dynamic      PT_DYNAMIC;
}

SECTIONS
{
  . = 0x80000;
  . = . + SIZEOF_HEADERS;
  .interp : { *(.interp) } :interp :headers :header_load
  .hash : { *(.hash) } :code
  .dynsym : { *(.dynsym) }
  .dynstr : { *(.dynstr) }

  . = ALIGN (0x400);
  .rela.dyn : { *(.rela.dyn) }
  .rela.plt : { *(.rela.plt) }

  . = ALIGN (0x400);
  .plt : { *(.plt) }

  . = ALIGN (0x400);
  .text : { *(.text) }

  . = ALIGN (0x1000);
  .dynamic : { *(.dynamic) } :data :dynamic

  . = ALIGN (0x400);
  .got : { *(.got.plt) *(.got) } :data

  . = ALIGN (0x400);
  .data : { *(.data) }

  . = ALIGN (0x400);
  .bss : { *(.bss) *(.dynbss) }


  /DISCARD/ : { *(.reginfo) *(.MIPS.abiflags) }
}

[-- Attachment #3: mips.vxworks.ld-tests.patch --]
[-- Type: text/x-patch, Size: 2635 bytes --]

diff --git a/ld/testsuite/ld-mips-elf/mips-elf.exp b/ld/testsuite/ld-mips-elf/mips-elf.exp
index fd79e80..b12d1b7 100644
--- a/ld/testsuite/ld-mips-elf/mips-elf.exp
+++ b/ld/testsuite/ld-mips-elf/mips-elf.exp
@@ -37,7 +37,7 @@ if {[istarget "mips*-*-vxworks"]} {
 	 {{readelf --segments vxworks2.sd}}
 	 "vxworks2"}
 	{"VxWorks executable test 2 (static)"
-	 "-Tvxworks1.ld" ""
+	 "-Tvxworks2-static.ld" ""
 	 "-mips2" {vxworks2.s}
 	 {{readelf --segments vxworks2-static.sd}}
 	 "vxworks2"}
diff --git a/ld/testsuite/ld-mips-elf/vxworks1.ld b/ld/testsuite/ld-mips-elf/vxworks1.ld
index d9f8621..428564c 100644
--- a/ld/testsuite/ld-mips-elf/vxworks1.ld
+++ b/ld/testsuite/ld-mips-elf/vxworks1.ld
@@ -1,8 +1,19 @@
+PHDRS
+{
+  headers      PT_PHDR PHDRS;
+  header_load  PT_LOAD PHDRS;
+  interp       PT_INTERP;
+  code         PT_LOAD;
+  data         PT_LOAD;
+  dynamic      PT_DYNAMIC;
+}
+
 SECTIONS
 {
   . = 0x80000;
-  .interp : { *(.interp) }
-  .hash : { *(.hash) }
+  . = . + SIZEOF_HEADERS;
+  .interp : { *(.interp) } :interp :headers :header_load
+  .hash : { *(.hash) } :code
   .dynsym : { *(.dynsym) }
   .dynstr : { *(.dynstr) }
 
@@ -17,10 +28,10 @@ SECTIONS
   .text : { *(.text) }
 
   . = ALIGN (0x1000);
-  .dynamic : { *(.dynamic) }
+  .dynamic : { *(.dynamic) } :data :dynamic
 
   . = ALIGN (0x400);
-  .got : { *(.got.plt) *(.got) }
+  .got : { *(.got.plt) *(.got) } :data
 
   . = ALIGN (0x400);
   .data : { *(.data) }
@@ -28,5 +39,6 @@ SECTIONS
   . = ALIGN (0x400);
   .bss : { *(.bss) *(.dynbss) }
 
+
   /DISCARD/ : { *(.reginfo) *(.MIPS.abiflags) }
 }
diff --git a/ld/testsuite/ld-mips-elf/vxworks2.sd b/ld/testsuite/ld-mips-elf/vxworks2.sd
index 5ff87d3..01301ba 100644
--- a/ld/testsuite/ld-mips-elf/vxworks2.sd
+++ b/ld/testsuite/ld-mips-elf/vxworks2.sd
@@ -6,8 +6,8 @@ Program Headers:
   Type .*
   PHDR .*
 #...
-  LOAD .* 0x00080000 0x00080000 .* R E 0x1000
-  LOAD .* 0x00081000 0x00081000 .* RW  0x1000
+  LOAD .* 0x00080... 0x00080... .* R E 0x1000
+  LOAD .* 0x00081... 0x00081... .* RW  0x1000
   DYNAMIC .*
 
 #...
--- /dev/null	2016-12-08 07:35:33.885870158 +0000
+++ ld/testsuite/ld-mips-elf/vxworks2-static.ld	2016-12-08 12:04:17.091239541 +0000
@@ -0,0 +1,25 @@
+SECTIONS
+{
+  . = 0x80000;
+  .hash : { *(.hash) }
+
+  . = ALIGN (0x400);
+  .rela.plt : { *(.rela.plt) }
+
+  . = ALIGN (0x400);
+  .plt : { *(.plt) }
+
+  . = ALIGN (0x400);
+  .text : { *(.text) }
+
+  . = ALIGN (0x1000);
+  .got : { *(.got.plt) *(.got) }
+
+  . = ALIGN (0x400);
+  .data : { *(.data) }
+
+  . = ALIGN (0x400);
+  .bss : { *(.bss) *(.dynbss) }
+
+  /DISCARD/ : { *(.reginfo) *(.MIPS.abiflags) }
+}

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [binutils-gdb] Fix the linker so that it will not silently generate ELF binaries with invalid program headers. Fix
  2016-12-08 11:32   ` Alan Modra
@ 2016-12-08 12:14     ` Nick Clifton
  2016-12-08 13:27       ` Alan Modra
  2016-12-09  0:17     ` Maciej W. Rozycki
  1 sibling, 1 reply; 9+ messages in thread
From: Nick Clifton @ 2016-12-08 12:14 UTC (permalink / raw)
  To: Alan Modra, Maciej W. Rozycki; +Cc: Nick Clifton, binutils

Hi Alan,

> I think an equally valid and somewhat better fix would have been to not
> emit PT_PHDR when no PT_LOAD header covers the program headers.  The
> reason I say that is because PT_PHDR is optional.  A loader can read
> the program headers itself from file using info in the ELF header.

That would be nicer, but there is explicit code in _bfd_elf_map_sections_to_segments()
to create a PHDR segment whenever we create an INTERP segment.  I assumed
that this was a requirement and hence could not be dropped.  (I did not
explore why this was needed, I just assumed that I would break something,
probably the kernel, if I dropped the requirement).

Cheers
  Nick

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [binutils-gdb] Fix the linker so that it will not silently generate ELF binaries with invalid program headers. Fix
  2016-12-08 12:14     ` Nick Clifton
@ 2016-12-08 13:27       ` Alan Modra
  0 siblings, 0 replies; 9+ messages in thread
From: Alan Modra @ 2016-12-08 13:27 UTC (permalink / raw)
  To: Nick Clifton; +Cc: Maciej W. Rozycki, Nick Clifton, binutils

On Thu, Dec 08, 2016 at 12:14:49PM +0000, Nick Clifton wrote:
> Hi Alan,
> 
> > I think an equally valid and somewhat better fix would have been to not
> > emit PT_PHDR when no PT_LOAD header covers the program headers.  The
> > reason I say that is because PT_PHDR is optional.  A loader can read
> > the program headers itself from file using info in the ELF header.
> 
> That would be nicer, but there is explicit code in _bfd_elf_map_sections_to_segments()
> to create a PHDR segment whenever we create an INTERP segment.  I assumed
> that this was a requirement and hence could not be dropped.  (I did not
> explore why this was needed, I just assumed that I would break something,
> probably the kernel, if I dropped the requirement).

OK, so I experimented with a patch that omits PHDR when a script
doesn't leave enough room, and "hello world" no longer runs on Ubuntu
16.04.  Segfault in dl_main.  So it seems INTERP really does need
PHDR, at least with current glibc ld.so.

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [binutils-gdb] Fix the linker so that it will not silently generate ELF binaries with invalid program headers. Fix
  2016-12-08 11:32   ` Alan Modra
  2016-12-08 12:14     ` Nick Clifton
@ 2016-12-09  0:17     ` Maciej W. Rozycki
  2016-12-09  3:39       ` Alan Modra
  1 sibling, 1 reply; 9+ messages in thread
From: Maciej W. Rozycki @ 2016-12-09  0:17 UTC (permalink / raw)
  To: Alan Modra; +Cc: Nick Clifton, binutils

On Thu, 8 Dec 2016, Alan Modra wrote:

> > Program Headers:
> >   Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
> >   PHDR           0x000034 0x00001034 0x00000000 0x000a0 0x000a0 R E 0x4
> >   INTERP         0x001000 0x00080000 0x00080000 0x00013 0x00013 R   0x1
> >       [Requesting program interpreter: /usr/lib/libc.so.1]
> >   LOAD           0x001000 0x00080000 0x00080000 0x00408 0x00408 R E 0x1000
> >   LOAD           0x002000 0x00081000 0x00081000 0x00804 0x00c00 RW  0x1000
> >   DYNAMIC        0x002000 0x00081000 0x00081000 0x00078 0x00078 RW  0x4
> 
> The gABI says:
> 
> PT_PHDR
>     The array element, if present, specifies the location and size of
>     the program header table itself, both in the file and in the
>     memory image of the program. This segment type may not occur more
>     than once in a file. Moreover, it may occur only if the program
>     header table is part of the memory image of the program. If it is
>     present, it must precede any loadable segment entry.
> 
> The above clearly violates this part of the spec because PT_PHDR is
> present yet is not part of the memory image.

 Well, TBH I think it's all but clear, given that nowhere in the ELF gABI 
that I can find there is an actual definition of what "the memory image" 
is.

 It might be possible to prove it by contradiction from the "Base Address" 
section, where it is specified that it is `p_vaddr' of the lowest PT_LOAD 
segment that is used to calculate the base address or the relocation 
amount for the whole image, that no other segment type is a part of the 
memory image without a corresponding PT_LOAD shadow.  But I wouldn't be 
that convinced about it as arguably the definition does not actually 
*require* that there is no mapped area below the lowest PT_LOAD segment -- 
it merely specifies the calculation algorithm which needs a point of 
reference, and which may well apply to any other segment types, even if 
mapped below the lowest PT_LOAD segment.

 It may also be important to note that based on the change bars in the 
latest 4.1 PDF version of the gABI it can be inferred that the "Base 
Address" section was updated relatively late in the course of the 
document's processing and it cannot be completely ruled out that parts 
elsewhere were missed out and not revised accordingly.

 Contrariwise, it is specified that `p_memsz' gives "the number of bytes 
in the memory image of the segment" without limiting it to PT_LOAD 
segments, so one could argue all segments whose this value is non-zero 
comprise the memory image, regardless of whether they are shadowed by a 
PT_LOAD segment or not.

 Intuitively I think that you are correct in that it was the intent of the 
gABI authors that only PT_LOAD segments comprise the memory image, but I 
also think that intuition and guessing the intent is not the right way of 
interpreting a technical specification, as intuition varies among people 
and some implementers may have understood the document differently and 
still be formally right in their interpretation.

> Nick's patch forced the first PT_LOAD to cover the program headers.  I
> think an equally valid and somewhat better fix would have been to not
> emit PT_PHDR when no PT_LOAD header covers the program headers.  The
> reason I say that is because PT_PHDR is optional.  A loader can read
> the program headers itself from file using info in the ELF header.

 There may be no loader available to load the program headers or the ELF 
file header if a bare-metal ELF image has been externally loaded according 
to some interpretation of the headers, and the binary wants to access its 
own structures at run time.  Existing environments may rely on our current 
semantics even if it is not strictly compliant.

 I think my inability to actually decide which way is correct for MIPS 
VxWorks (for which I have no environment available to verify) just shows 
that changing semantics which we had since forever just to match a piece 
of (virtual) paper from 20 years ago may not be the greatest idea, and 
certainly needs a lot of care and consideration if it is given a go-ahead.  
There may well be environments out there which have relied on our 
technically broken semantics for an equally long period of time and we may 
well have thus established the de-facto standard.  There may be parts of 
the environments we have no control over and which may be difficult to 
correct to match the written standard.

 I mean if there is a case of actual breakage that our implementation 
causes, as it has been in this case, then we certainly do ought to address 
it, one way or another.  So we found a way to fix Linux, but are we 
confident it didn't break anything else?  Maybe we need a different fix.  
Or at least a linker script or command-line option to chicken out and 
resort to the old semantics?

 But perhaps I'm just being overly cautious.  So is anyone out there who 
could actually regression-test say GCC with current binutils on MIPS 
VxWorks, or run whatever is usually done for toolchain validation with 
that target?  After all what matters is whether the environment continues 
operating correctly and not whether a cryptic test case from 10 years ago 
passes unchanged or not.  It might be that the test case is too strict or 
genuinely wrong in some way.

  Maciej

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [binutils-gdb] Fix the linker so that it will not silently generate ELF binaries with invalid program headers. Fix
  2016-12-09  0:17     ` Maciej W. Rozycki
@ 2016-12-09  3:39       ` Alan Modra
  2016-12-10  0:13         ` Maciej W. Rozycki
  0 siblings, 1 reply; 9+ messages in thread
From: Alan Modra @ 2016-12-09  3:39 UTC (permalink / raw)
  To: Maciej W. Rozycki; +Cc: Nick Clifton, binutils

[-- Attachment #1: Type: text/plain, Size: 3100 bytes --]

On Fri, Dec 09, 2016 at 12:17:31AM +0000, Maciej W. Rozycki wrote:
> On Thu, 8 Dec 2016, Alan Modra wrote:
> 
> > > Program Headers:
> > >   Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
> > >   PHDR           0x000034 0x00001034 0x00000000 0x000a0 0x000a0 R E 0x4
> > >   INTERP         0x001000 0x00080000 0x00080000 0x00013 0x00013 R   0x1
> > >       [Requesting program interpreter: /usr/lib/libc.so.1]
> > >   LOAD           0x001000 0x00080000 0x00080000 0x00408 0x00408 R E 0x1000
> > >   LOAD           0x002000 0x00081000 0x00081000 0x00804 0x00c00 RW  0x1000
> > >   DYNAMIC        0x002000 0x00081000 0x00081000 0x00078 0x00078 RW  0x4
> > 
> > The gABI says:
> > 
> > PT_PHDR
> >     The array element, if present, specifies the location and size of
> >     the program header table itself, both in the file and in the
> >     memory image of the program. This segment type may not occur more
> >     than once in a file. Moreover, it may occur only if the program
> >     header table is part of the memory image of the program. If it is
> >     present, it must precede any loadable segment entry.
> > 
> > The above clearly violates this part of the spec because PT_PHDR is
> > present yet is not part of the memory image.
> 
>  Well, TBH I think it's all but clear, given that nowhere in the ELF gABI 
> that I can find there is an actual definition of what "the memory image" 
> is.

I'm not going to argue this point except to note that all specs I've
ever read rely on some background knowledge and require
interpretation.  Those that try to specify endless detail might
satisfy lawyers, but often become so unwieldy that they aren't as
useful as they should be to engineers.

> > Nick's patch forced the first PT_LOAD to cover the program headers.  I
> > think an equally valid and somewhat better fix would have been to not
> > emit PT_PHDR when no PT_LOAD header covers the program headers.  The
> > reason I say that is because PT_PHDR is optional.  A loader can read
> > the program headers itself from file using info in the ELF header.
> 
>  There may be no loader available to load the program headers or the ELF 
> file header if a bare-metal ELF image has been externally loaded according 
> to some interpretation of the headers, and the binary wants to access its 
> own structures at run time.  Existing environments may rely on our current 
> semantics even if it is not strictly compliant.

This is true but I was arguing about the validity of the ELF file.  I
mentioned a loader only to say what might be done.

We do know that on reasonably up to date Linux with glibc, that
linking a simple program with a script that leaves no room for headers
results in a segfault before Nick's patch, but runs after Nick's
patch.  My suggestion to remove PHDR (patch attached) results in the
same ld.so segfault.  It would certainly be useful to know how vxworks
behaves with similar tests.

We've also found that Nick's patch broke linux kernel builds, which is
why I was exploring alternative fixes.

-- 
Alan Modra
Australia Development Lab, IBM

[-- Attachment #2: dropphdr.diff --]
[-- Type: text/x-diff, Size: 1572 bytes --]

diff --git a/bfd/elf.c b/bfd/elf.c
index 678c043..d7fbca1 100644
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -4507,7 +4507,6 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info)
       asection *dynsec, *eh_frame_hdr;
       bfd_size_type amt;
       bfd_vma addr_mask, wrap_to = 0;
-      bfd_boolean linker_created_pt_phdr_segment = FALSE;
 
       /* Select the allocated sections, and sort them.  */
 
@@ -4560,7 +4559,6 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info)
 	  m->p_flags = PF_R | PF_X;
 	  m->p_flags_valid = 1;
 	  m->includes_phdrs = 1;
-	  linker_created_pt_phdr_segment = TRUE;
 	  *pm = m;
 	  pm = &m->next;
 
@@ -4612,17 +4610,13 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info)
 		  < phdr_size % maxpagesize)
 	      || (sections[0]->lma & addr_mask & -maxpagesize) < wrap_to)
 	    {
+	      phdr_in_segment = FALSE;
 	      /* PR 20815: The ELF standard says that a PT_PHDR segment, if
 		 present, must be included as part of the memory image of the
 		 program.  Ie it must be part of a PT_LOAD segment as well.
-		 If we have had to create our own PT_PHDR segment, but it is
-		 not going to be covered by the first PT_LOAD segment, then
-		 force the inclusion if we can...  */
-	      if ((abfd->flags & D_PAGED) != 0
-		  && linker_created_pt_phdr_segment)
-		phdr_in_segment = TRUE;
-	      else
-		phdr_in_segment = FALSE;
+		 If PHDR won't be part of the memory image, remove it.  */
+	      if (mfirst->p_type == PT_PHDR)
+		mfirst = mfirst->next;
 	    }
 	}
 

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [binutils-gdb] Fix the linker so that it will not silently generate ELF binaries with invalid program headers. Fix
  2016-12-09  3:39       ` Alan Modra
@ 2016-12-10  0:13         ` Maciej W. Rozycki
  2016-12-11  4:17           ` Alan Modra
  0 siblings, 1 reply; 9+ messages in thread
From: Maciej W. Rozycki @ 2016-12-10  0:13 UTC (permalink / raw)
  To: Alan Modra; +Cc: Nick Clifton, binutils

On Fri, 9 Dec 2016, Alan Modra wrote:

> >  Well, TBH I think it's all but clear, given that nowhere in the ELF gABI 
> > that I can find there is an actual definition of what "the memory image" 
> > is.
> 
> I'm not going to argue this point except to note that all specs I've
> ever read rely on some background knowledge and require
> interpretation.  Those that try to specify endless detail might
> satisfy lawyers, but often become so unwieldy that they aren't as
> useful as they should be to engineers.

 True, we've been applying common sense over the years to the original 
MIPS SVR psABI as well, which has areas which are grey to say the least 
if not outright broken.  All I have written is that I think we need to 
be careful stating that something is clear where indeed I think we can 
have serious doubts about it.

 There is this also this note in the "Program Header" section:

"Some entries describe process segments; others give supplementary 
information and do not contribute to the process image."

-- if that said say:

"Loadable entries describe process segments..."

or something similar to the same effect, then it would make things 
clear about PT_LOAD segments being *the* process image, at least to me.

 Otherwise we can of course make a *decision* to interpret a 
specification one way or another, or declare that our (or someone 
else's) implementation has become the de-facto standard, and then follow 
that choice.  I think it would also be great to have such decisions and 
any backing analysis recorded with commits themselves as well, now that 
we've departed from the "ChangeLog entry only for commit logs" rule.

 NB I'm not arguing about the actual decision made here, it does seem 
reasonable to me.

> >  There may be no loader available to load the program headers or the ELF 
> > file header if a bare-metal ELF image has been externally loaded according 
> > to some interpretation of the headers, and the binary wants to access its 
> > own structures at run time.  Existing environments may rely on our current 
> > semantics even if it is not strictly compliant.
> 
> This is true but I was arguing about the validity of the ELF file.  I
> mentioned a loader only to say what might be done.
> 
> We do know that on reasonably up to date Linux with glibc, that
> linking a simple program with a script that leaves no room for headers
> results in a segfault before Nick's patch, but runs after Nick's
> patch.  My suggestion to remove PHDR (patch attached) results in the
> same ld.so segfault.  It would certainly be useful to know how vxworks
> behaves with similar tests.
> 
> We've also found that Nick's patch broke linux kernel builds, which is
> why I was exploring alternative fixes.

 Thanks for your and Nick's effort; I'll be looking into these patches 
once I have offloaded my immediately pending queue, which has to take 
precedence over any VxWorks cleanups.  As I say, what would really help 
is if someone who has a suitable test environment available verified the 
recent PHDR changes, and if they are indeed fine, then we can then deal 
with test suite adjustments ourselves.

  Maciej

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [binutils-gdb] Fix the linker so that it will not silently generate ELF binaries with invalid program headers. Fix
  2016-12-10  0:13         ` Maciej W. Rozycki
@ 2016-12-11  4:17           ` Alan Modra
  0 siblings, 0 replies; 9+ messages in thread
From: Alan Modra @ 2016-12-11  4:17 UTC (permalink / raw)
  To: Maciej W. Rozycki; +Cc: Nick Clifton, binutils

On Sat, Dec 10, 2016 at 12:13:46AM +0000, Maciej W. Rozycki wrote:
>  Thanks for your and Nick's effort; I'll be looking into these patches 
> once I have offloaded my immediately pending queue, which has to take 

I should note that the patch I posted was just a quick hack to
experiment with removing the PT_PHDR header.  A proper patch minus
testsuite tweaking is more like the following, due to elf-nacl.c
fiddling with segments.

diff --git a/bfd/elf.c b/bfd/elf.c
index 678c043..9c8a167 100644
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -4483,6 +4483,7 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info)
   asection **sections = NULL;
   const struct elf_backend_data *bed = get_elf_backend_data (abfd);
   bfd_boolean no_user_phdrs;
+  bfd_boolean phdr_in_segment = TRUE;
 
   no_user_phdrs = elf_seg_map (abfd) == NULL;
 
@@ -4500,14 +4501,12 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info)
       unsigned int phdr_index;
       bfd_vma maxpagesize;
       asection **hdrpp;
-      bfd_boolean phdr_in_segment = TRUE;
       bfd_boolean writable;
       int tls_count = 0;
       asection *first_tls = NULL;
       asection *dynsec, *eh_frame_hdr;
       bfd_size_type amt;
       bfd_vma addr_mask, wrap_to = 0;
-      bfd_boolean linker_created_pt_phdr_segment = FALSE;
 
       /* Select the allocated sections, and sort them.  */
 
@@ -4560,7 +4559,6 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info)
 	  m->p_flags = PF_R | PF_X;
 	  m->p_flags_valid = 1;
 	  m->includes_phdrs = 1;
-	  linker_created_pt_phdr_segment = TRUE;
 	  *pm = m;
 	  pm = &m->next;
 
@@ -4611,19 +4609,7 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info)
 	      || ((sections[0]->lma & addr_mask) % maxpagesize
 		  < phdr_size % maxpagesize)
 	      || (sections[0]->lma & addr_mask & -maxpagesize) < wrap_to)
-	    {
-	      /* PR 20815: The ELF standard says that a PT_PHDR segment, if
-		 present, must be included as part of the memory image of the
-		 program.  Ie it must be part of a PT_LOAD segment as well.
-		 If we have had to create our own PT_PHDR segment, but it is
-		 not going to be covered by the first PT_LOAD segment, then
-		 force the inclusion if we can...  */
-	      if ((abfd->flags & D_PAGED) != 0
-		  && linker_created_pt_phdr_segment)
-		phdr_in_segment = TRUE;
-	      else
-		phdr_in_segment = FALSE;
-	    }
+	    phdr_in_segment = FALSE;
 	}
 
       for (i = 0, hdrpp = sections; i < count; i++, hdrpp++)
@@ -4965,8 +4951,26 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info)
   if (!elf_modify_segment_map (abfd, info, no_user_phdrs))
     return FALSE;
 
+  phdr_in_segment = FALSE;
   for (count = 0, m = elf_seg_map (abfd); m != NULL; m = m->next)
-    ++count;
+    {
+      if (m->p_type == PT_LOAD && m->includes_phdrs)
+	phdr_in_segment = TRUE;
+      ++count;
+    }
+  if (no_user_phdrs && !phdr_in_segment && count != 0)
+    {
+      /* PR 20815: The ELF standard says that a PT_PHDR segment, if
+	 present, must be included as part of the memory image of the
+	 program.  Ie it must be part of a PT_LOAD segment as well.
+	 If PHDR won't be part of the memory image, remove it.  */
+      m = elf_seg_map (abfd);
+      if (m->p_type == PT_PHDR)
+	{
+	  elf_seg_map (abfd) = m->next;
+	  --count;
+	}
+    }
   elf_program_header_size (abfd) = count * bed->s->sizeof_phdr;
 
   return TRUE;

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2016-12-11  4:17 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <20161123111226.62132.qmail@sourceware.org>
2016-12-08  9:30 ` [binutils-gdb] Fix the linker so that it will not silently generate ELF binaries with invalid program headers. Fix Maciej W. Rozycki
2016-12-08 11:32   ` Alan Modra
2016-12-08 12:14     ` Nick Clifton
2016-12-08 13:27       ` Alan Modra
2016-12-09  0:17     ` Maciej W. Rozycki
2016-12-09  3:39       ` Alan Modra
2016-12-10  0:13         ` Maciej W. Rozycki
2016-12-11  4:17           ` Alan Modra
2016-12-08 12:09   ` Nick Clifton

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).