Fix the linker so that it will not silently generate ELF binaries with invalid program headers. Fix readelf to report such invalid binaries.

PR ld/20815
bfd	* elf.c (elf_modify_segment_map): Allow empty LOAD segments if
	they contain the program headers.
	(_bfd_elf_map_sections_to_segments): If the linker created the
	PHDR segment then always attempt to include it in a LOAD segment.
	(assign_file_positions_for_non_load_sections): Allow LOAD segments
	to overlap PHDR segments.
	(phdr_sorter): New function.  Sorts program headers.
	(assign_file_positions_except_relocs): Sort the program headers
	before writing them out.  Issue an error if the PHDR segment is
	not covered by a LOAD segment, unless the backend allows it.
	* elf-bfd.h (struct elf_backend_data): Add
	elf_backend_allow_non_load_phdr.
	* elfxx-target.h (elf_backend_allow_non_load_phdr): Provide
	default definition that returns FALSE.
	(elfNN_bed): Initialise the elf_backend_allow_non_load_phdr
	field.
	* elf64-hppa.c (elf64_hppa_allow_non_load_phdr): New function.
	Returns TRUE.
	(elf_backend_allow_non_load_phdr): Define.
	* elf-m10300.c (_bfd_mn10300_elf_size_dynamic_sections): Do not
	place the interpreter string into the .interp section if the
	nointerp flag is set in the link info structure.
	* elf32-arc.c (elf_arc_size_dynamic_sections): Likewise.
	* elf32-score7.c (score_elf_final_link_relocate): Allow for the
	_gp symbol not being part of the output.

binutils* readelf.c (process_program_headers): Check PT_LOAD and PT_PHDR
	segments for validity.

ld	* ld.texinfo: Note that PT_TLS can be used as a segment type.
	* testsuite/ld-discard/discard.ld: Add space for program headers.
	* testsuite/ld-elf/flags1.ld: Likewise.
	* testsuite/ld-elf/maxpage3.t: Likewise.
	* testsuite/ld-elf/noload-1.t: Likewise.
	* testsuite/ld-elf/orphan.ld: Likewise.
	* testsuite/ld-elf/overlay.t: Likewise.
	* testsuite/ld-elf/pr14052.t: Likewise.
	* testsuite/ld-elf/pr19539.t: Likewise.
	* testsuite/ld-elf/provide-hidden-1.ld: Likewise.
	* testsuite/ld-elf/provide-hidden-s.ld: Likewise.
	* testsuite/ld-elf/weak-dyn-1.ld: Likewise.
	* testsuite/ld-i386/pr19539.t: Likewise.
	* testsuite/ld-scripts/defined.t: Likewise.
	* testsuite/ld-scripts/defined6.t: Likewise.
	* testsuite/ld-scripts/dynamic-sections.t: Likewise.
	* testsuite/ld-scripts/empty-aligned.t: Likewise.
	* testsuite/ld-scripts/provide-2.t: Likewise.
	* testsuite/ld-scripts/provide-4.t: Likewise.
	* testsuite/ld-vax-elf/plt-local.ld: Likewise.
	* testsuite/ld-x86-64/pr19539.t: Likewise.
	* testsuite/ld-elf/ehdr_start-missing.d: Do not initialise the
	dynamic linker.
	* testsuite/ld-elf/ehdr_start-weak.d: Likewise.
	* testsuite/ld-elf/elf.exp (pr14170, pr17068): Likewise.
	* testsuite/ld-elf/loadaddr1.d: Update expected readelf output.
	* testsuite/ld-elf/noload-2.d: Likewise.
	* testsuite/ld-powerpc/vxworks2.sd: Likewise.
	* testsuite/ld-scripts/phdrs3a.d: Likewise.
	* testsuite/ld-scripts/size-2.d: Likewise.
	* testsuite/ld-elf/group.ld: Add program headers.
	* testsuite/ld-elf/overlay.d: Skip for SPU.
	* testsuite/ld-elf/flags1.d: Skip for RX.
	* testsuite/ld-elf/pr19162.d: Skip for HPPA64.
	* testsuite/ld-elf/pr19539.d: Skip for ALPHA.
	* testsuite/ld-scripts/empty-orphan.t: Update program headers.
	* testsuite/ld-scripts/size-2.t: Likewise.
This commit is contained in:
Nick Clifton
2016-11-23 11:10:39 +00:00
parent 128e85e3ab
commit 1a9ccd70f9
48 changed files with 324 additions and 40 deletions

125
bfd/elf.c
View File

@ -4254,7 +4254,7 @@ get_program_header_size (bfd *abfd, struct bfd_link_info *info)
PT_INTERP segment. In this case, assume we also need a
PT_PHDR segment, although that may not be true for all
targets. */
segs += 2;
segs += 3;
}
if (bfd_get_section_by_name (abfd, ".dynamic") != NULL)
@ -4438,7 +4438,10 @@ elf_modify_segment_map (bfd *abfd,
}
(*m)->count = new_count;
if (remove_empty_load && (*m)->p_type == PT_LOAD && (*m)->count == 0)
if (remove_empty_load
&& (*m)->p_type == PT_LOAD
&& (*m)->count == 0
&& !(*m)->includes_phdrs)
*m = (*m)->next;
else
m = &(*m)->next;
@ -4488,6 +4491,7 @@ _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. */
@ -4540,7 +4544,7 @@ _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;
@ -4591,7 +4595,19 @@ _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)
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;
}
}
for (i = 0, hdrpp = sections; i < count; i++, hdrpp++)
@ -5773,16 +5789,25 @@ assign_file_positions_for_non_load_sections (bfd *abfd,
else if (m->count != 0)
{
unsigned int i;
if (p->p_type != PT_LOAD
&& (p->p_type != PT_NOTE
|| bfd_get_format (abfd) != bfd_core))
{
/* A user specified segment layout may include a PHDR
segment that overlaps with a LOAD segment... */
if (p->p_type == PT_PHDR)
{
m->count = 0;
continue;
}
if (m->includes_filehdr || m->includes_phdrs)
{
/* PR 17512: file: 2195325e. */
_bfd_error_handler
(_("%B: warning: non-load segment includes file header and/or program header"),
abfd);
(_("%B: error: non-load segment %d includes file header and/or program header"),
abfd, (int)(p - phdrs));
return FALSE;
}
@ -5829,6 +5854,52 @@ find_section_in_list (unsigned int i, elf_section_list * list)
return list;
}
/* Compare function used when sorting the program header table.
The ELF standard requires that a PT_PHDR segment, if present,
must appear before any PT_LOAD segments. It also requires
that all PT_LOAD segments are sorted into order of increasing
p_vaddr. */
static signed int
phdr_sorter (const void * a, const void * b)
{
Elf_Internal_Phdr * ahdr = (Elf_Internal_Phdr *) a;
Elf_Internal_Phdr * bhdr = (Elf_Internal_Phdr *) b;
switch (ahdr->p_type)
{
case PT_LOAD:
switch (bhdr->p_type)
{
case PT_PHDR:
return 1;
case PT_LOAD:
if (ahdr->p_vaddr < bhdr->p_vaddr)
return -1;
if (ahdr->p_vaddr > bhdr->p_vaddr)
return 1;
return 0;
default:
return 0;
}
break;
case PT_PHDR:
switch (bhdr->p_type)
{
case PT_PHDR:
_bfd_error_handler (_("error: multiple PHDR segments detecetd"));
return 0;
case PT_LOAD:
return -1;
default:
return 0;
}
break;
default:
return 0;
}
}
/* Work out the file positions of all the sections. This is called by
_bfd_elf_compute_section_file_positions. All the section sizes and
VMAs must be known before this is called.
@ -5892,6 +5963,7 @@ assign_file_positions_except_relocs (bfd *abfd,
}
else
{
Elf_Internal_Phdr * map;
unsigned int alloc;
/* Assign file positions for the loaded sections based on the
@ -5930,9 +6002,46 @@ assign_file_positions_except_relocs (bfd *abfd,
/* Write out the program headers. */
alloc = elf_program_header_size (abfd) / bed->s->sizeof_phdr;
/* Sort the program headers into the ordering required by the ELF standard. */
if (alloc == 0)
return TRUE;
map = (Elf_Internal_Phdr *) xmalloc (alloc * sizeof (* tdata->phdr));
memcpy (map, tdata->phdr, alloc * sizeof (* tdata->phdr));
qsort (map, alloc, sizeof (* tdata->phdr), phdr_sorter);
/* PR ld/20815 - Check that the program header segment, if present, will
be loaded into memory. FIXME: The check below is not sufficient as
really all PT_LOAD segments should be checked before issuing an error
message. Plus the PHDR segment does not have to be the first segment
in the program header table. But this version of the check should
catch all real world use cases. */
if (alloc > 1
&& map[0].p_type == PT_PHDR
&& ! bed->elf_backend_allow_non_load_phdr (abfd, map, alloc)
&& map[1].p_type == PT_LOAD
&& (map[1].p_vaddr > map[0].p_vaddr
|| (map[1].p_vaddr + map[1].p_memsz) < (map[0].p_vaddr + map[0].p_memsz)))
{
/* The fix for this error is usually to edit the linker script being
used and set up the program headers manually. Either that or
leave room for the headers at the start of the SECTIONS. */
_bfd_error_handler (_("\
%B: error: PHDR segment not covered by LOAD segment"),
abfd);
free (map);
return FALSE;
}
if (bfd_seek (abfd, (bfd_signed_vma) bed->s->sizeof_ehdr, SEEK_SET) != 0
|| bed->s->write_out_phdrs (abfd, tdata->phdr, alloc) != 0)
return FALSE;
|| bed->s->write_out_phdrs (abfd, map, alloc) != 0)
{
free (map);
return FALSE;
}
free (map);
}
return TRUE;