https://sourceware.org/bugzilla/show_bug.cgi?id=34998
Bug ID: 34998
Summary: ld aborts with an internal error when a section
without SHF_ALLOC holds a relocation against an
STT_GNU_IFUNC symbol, and that section is not a note
or debug section. There are two abort sites in the
same function, one for global and one for local IFUNC
s
Product: binutils
Version: 2.48 (HEAD)
Status: UNCONFIRMED
Severity: normal
Priority: P2
Component: ld
Assignee: unassigned at sourceware dot org
Reporter: emily.west286 at gmail dot com
Target Milestone: ---
Created attachment 17272
--> https://sourceware.org/bugzilla/attachment.cgi?id=17272&action=edit
Suggested patch
Binutils ld: internal error (abort) in elf_x86_64_relocate_section on IFUNC
relocation in non-SHF_ALLOC section
Component: ld
Version: binutils-gdb master, found on commit
c79376a262328164cdf81eddfcc5518314b1856a
Target: x86_64-pc-linux-gnu
Summary:
ld aborts with an internal error when a section without SHF_ALLOC holds a
relocation against an STT_GNU_IFUNC symbol, and that section is not a note or
debug section. There are two abort sites in the same function, one for global
and one for local IFUNC symbols:
ld-new: BFD (GNU Binutils) ... internal error, aborting at elf64-x86-64.c:3349
in elf_x86_64_relocate_section
ld-new: BFD (GNU Binutils) ... internal error, aborting at elf64-x86-64.c:3261
in elf_x86_64_relocate_section
ld-new: Please report this bug.
Reproducers:
id001441 (attached): aborts at 3349
/src/build/ld/ld-new: BFD (GNU Binutils) 2.47.50.20261112 internal
error, aborting at /src/binutils-gdb/bfd/elf64-x86-64.c:3349 in
elf_x86_64_relocate_section
Please report this bug.
id002053 (attached): aborts at 3261
/src/build/ld/ld-new: warning: cannot find entry symbol _start;
defaulting to 0000000000401000
/src/build/ld/ld-new: BFD (GNU Binutils) 2.47.50.20261112 internal
error, aborting at /src/binutils-gdb/bfd/elf64-x86-64.c:3261 in
elf_x86_64_relocate_section
Please report this bug.
ld -o /tmp/out id001441
ld -o /tmp/out id002053
Backtrace for id001441
#0 _bfd_abort bfd/bfd.c:2315
#1 elf_x86_64_relocate_section bfd/elf64-x86-64.c:3349
#2 elf_link_input_bfd bfd/elflink.c:11978
#3 _bfd_elf_final_link bfd/elflink.c:13241
#4 ldwrite ld/ldwrite.c:548
#5 main ld/ldmain.c:1001
Root cause:
Line 3349 (global IFUNC). For a regular-defined STT_GNU_IFUNC symbol, the code
only handles two kinds of non-SEC_ALLOC input sections:
c
if ((input_section->flags & SEC_ALLOC) == 0)
{
if (elf_section_type (input_section) == SHT_NOTE)
goto skip_ifunc;
if ((input_section->flags & SEC_DEBUGGING) != 0)
continue;
abort ();
}
Any other non-alloc section reaches abort(). SEC_DEBUGGING is set from the
section name (.debug* and similar), so a custom non-alloc section, or one with
an empty or corrupted name, is not covered. The note and debug cases were added
as separate fixes (PR ld/18808, and a 2018 fix for annobin notes). The general
case was never handled.
>From gdb, for id001441:
input_section->name = "", flags = 0x10c (SEC_HAS_CONTENTS | SEC_READONLY |
SEC_RELOC). It has no SEC_ALLOC, and SEC_DEBUGGING isn’t set because of the
empty name. Its type isn’t SHT_NOTE.
h->root.root.string = "_start", h->type = STT_GNU_IFUNC, regular-defined.
This input fails both exceptions in the (input_section->flags & SEC_ALLOC) == 0
branch and falls through to abort().
Impact:
Low. ld exits instead of reporting an error. It needs a crafted or unusual
object file. No memory corruption was observed when run with Address Sanitizer.
Suggested fix:
Replace both abort() calls with a normal error, so ld reports bad input and
fails cleanly. e.g.,
@@ -3258,7 +3258,15 @@
h = _bfd_elf_x86_get_local_sym_hash (htab, input_bfd,
rel, false);
if (h == NULL)
- abort ();
+ {
+ _bfd_error_handler
+ (_("%pB(%pA+%#" PRIx64 "): relocation against local "
+ "STT_GNU_IFUNC symbol in non-SHF_ALLOC section is not "
+ "supported"),
+ input_bfd, input_section, (uint64_t) rel->r_offset);
+ bfd_set_error (bfd_error_bad_value);
+ return false;
+ }
/* Set STT_GNU_IFUNC symbol value. */
h->root.u.def.value = sym->st_value;
@@ -3346,7 +3354,13 @@
thus ld.so will not process them. */
if ((input_section->flags & SEC_DEBUGGING) != 0)
continue;
- abort ();
+ _bfd_error_handler
+ (_("%pB(%pA+%#" PRIx64 "): relocation against STT_GNU_IFUNC "
+ "symbol `%s' in non-SHF_ALLOC section is not supported"),
+ input_bfd, input_section, (uint64_t) rel->r_offset,
+ h->root.root.string);
+ bfd_set_error (bfd_error_bad_value);
+ return false;
}
switch (r_type)
Alternatively, move the SEC_ALLOC check before the local-symbol lookup, so both
cases share one error path. elf32-i386.c has similar IFUNC handling and is
worth checking for the same pattern.
Fix verification:
The attached patch.Dockerfile builds ld at commit
c79376a262328164cdf81eddfcc5518314b1856a with ifunc-nonalloc.patch applied (the
suggested fix above). With the patch, both inputs fail with a normal error
instead of aborting:
docker build -f patch.Dockerfile -t ld-fix .
docker run --rm -v "$PWD":/work ld-fix id001441
docker run --rm -v "$PWD":/work ld-fix id002053
/src/build/ld/ld-new: split-inputs/id001441/part0(+0x1): relocation against
STT_GNU_IFUNC symbol `_start' in non-SHF_ALLOC section is not supported
/src/build/ld/ld-new: final link failed: bad value
/src/build/ld/ld-new: warning: cannot find entry symbol _start; defaulting to
0000000000401000
/src/build/ld/ld-new: split-inputs/id002053/part0(.text+0x1): relocation
against local STT_GNU_IFUNC symbol in non-SHF_ALLOC section is not supported
/src/build/ld/ld-new: final link failed: bad value
Attachments:
id001441 and id002053 finding
ifunc-nonalloc.patch suggested fix
patch.Dockerfile builds ld with the patch for the suggested fix applied
--
You are receiving this mail because:
You are on the CC list for the bug.