Gentoo Websites Logo
Go to: Gentoo Home Documentation Forums Lists Bugs Planet Store Wiki Get Gentoo!

Bug 713082

Summary: sys-devel/binutils-2.32-r1 : generates TEXTRELs on PIE binaries on many arches (was: sys-devel/gdb merge failed: "Aborting due to QA concerns: textrels")
Product: Gentoo Linux Reporter: Skylar <skylar>
Component: Current packagesAssignee: Gentoo Toolchain Maintainers <toolchain>
Status: RESOLVED FIXED    
Severity: normal CC: herrtimson, jstein, matoro_bugzilla_gentoo, riscv, sam
Priority: Normal    
Version: unspecified   
Hardware: riscv   
OS: Linux   
URL: https://sourceware.org/PR25694
See Also: https://sourceware.org/bugzilla/show_bug.cgi?id=22263
Whiteboard: tracking upstream
Package list:
Runtime testing required: ---
Attachments: emerge info
emerge -pqv
build.log
scanelf

Description Skylar 2020-03-17 22:48:20 UTC
While installing it fails with a QA notice referencing textrels.

Reproducible: Always

Steps to Reproduce:
1. Compile sys-devel/gdb-9.1
Actual Results:  
Install fails.

Expected Results:  
Installs correctly.
Comment 1 Skylar 2020-03-17 22:50:57 UTC
Created attachment 621090 [details]
emerge info

emerge --info
Comment 2 Skylar 2020-03-17 22:54:28 UTC
Created attachment 621146 [details]
emerge -pqv
Comment 3 Skylar 2020-03-17 22:57:09 UTC
Created attachment 621148 [details]
build.log
Comment 4 Jonas Stein gentoo-dev 2020-03-17 23:26:59 UTC
>>> Completed installing sys-devel/gdb-9.1 into /var/tmp/portage/sys-devel/gdb-9.1/image

 * Final size of build directory: 297548 KiB (290.5 MiB)
 * Final size of installed tree:   11992 KiB ( 11.7 MiB)


 * QA Notice: The following files contain runtime text relocations
 *  Text relocations force the dynamic linker to perform extra
 *  work at startup, waste system resources, and may pose a security
 *  risk.  On some architectures, the code may not even function
 *  properly, if at all.
 *  For more information, see:
 * 
 *    https://wiki.gentoo.org/wiki/Hardened/HOWTO_locate_and_fix_textrels
 * 
 *  Please include the following list of files in your report:
 * TEXTREL usr/bin/gdb

 * ERROR: sys-devel/gdb-9.1::gentoo failed:
 *   Aborting due to QA concerns:  textrels,
 * 
 * Call stack:
 *     misc-functions.sh, line 586:  Called install_qa_check
 *     misc-functions.sh, line 132:  Called source 'install_symlink_html_docs'
 *   10executable-issues, line 145:  Called elf_check
 *   10executable-issues, line 141:  Called die
 * The specific snippet of code:
 *   		die "Aborting due to QA concerns: ${die_msg}"
Comment 5 Skylar 2020-03-18 04:25:07 UTC
Created attachment 621160 [details]
scanelf
Comment 6 Sergei Trofimovich (RETIRED) gentoo-dev 2020-03-18 07:31:42 UTC
(In reply to Skylar from comment #5)
> Created attachment 621160 [details]
> scanelf

Your output looks bad:

```
scanelf -qT /usr/bin/gdb
  gdb: (memory/data?) [0x0] in (optimized out) [0x0]
  gdb: (memory/data?) [0x0] in (optimized out) [0x0]
  gdb: (memory/data?) [0x0] in (optimized out) [0x0]
  gdb: (memory/data?) [0x0] in (optimized out) [0x0]
  gdb: (memory/data?) [0x0] in (optimized out) [0x0]
  gdb: (memory/data?) [0x0] in (optimized out) [0x0]
  /usr/bin/gdb
```

Can you attach gdb binary itself? Maybe we can fix scanelf to report better information.
Comment 7 Skylar 2020-03-18 20:16:34 UTC
gdb

https://filetransfer.io/data-package/eLMgIIvj
Comment 8 Sergei Trofimovich (RETIRED) gentoo-dev 2020-03-18 21:52:01 UTC
(In reply to Skylar from comment #7)
> gdb
> 
> https://filetransfer.io/data-package/eLMgIIvj

Uploaded as https://dev.gentoo.org/~slyfox/bugs/713082-gdb-TEXTREL/gdb

I'm not sure which relocations binutils is concerned about. scanelf is also clearly unhappy about some of them.

Of then read-only sections are only:

$ readelf gdb (exclude 'W' sections).

Section Headers:
  [ 1] .interp           PROGBITS         0000000000000270  00000270
  [ 2] .note.ABI-tag     NOTE             0000000000000294  00000294
  [ 3] .gnu.hash         GNU_HASH         00000000000002b8  000002b8
  [ 4] .dynsym           DYNSYM           0000000000001cd8  00001cd8
  [ 5] .dynstr           STRTAB           0000000000009868  00009868
  [ 6] .gnu.version      VERSYM           00000000000104aa  000104aa
  [ 7] .gnu.version_r    VERNEED          0000000000010ef8  00010ef8
  [ 8] .rela.dyn         RELA             0000000000011138  00011138
  [ 9] .rela.plt         RELA             00000000000837f8  000837f8
  [10] .plt              PROGBITS         00000000000871d0  000871d0
  [11] .text             PROGBITS         0000000000089880  00089880
  [12] .rodata           PROGBITS         000000000037d3e0  0037d3e0
  [13] .eh_frame_hdr     PROGBITS         0000000000482c00  00482c00
  [14] .eh_frame         PROGBITS         00000000004993c0  004993c0
  [15] .gcc_except_table PROGBITS         000000000051934c  0051934c


$ LANG=C objdump -D -R gdb | egrep 'R_RISC|section ' | egrep -A2 'section '

# removed sections without dynamic relocations manually

Disassembly of section .tbss:
			543308: R_RISCV_RELATIVE	*ABS*+0x92be6
Disassembly of section .preinit_array:
			543308: R_RISCV_RELATIVE	*ABS*+0x92be6
Disassembly of section .init_array:
			543310: R_RISCV_RELATIVE	*ABS*+0x92c80
Disassembly of section .fini_array:
			543608: R_RISCV_RELATIVE	*ABS*+0x92c46
Disassembly of section .data.rel.ro:
			543610: R_RISCV_RELATIVE	*ABS*+0x37dc30
Disassembly of section .data:
			56c010: R_RISCV_RELATIVE	*ABS*+0x93234
Disassembly of section .got:
			57b128: R_RISCV_JUMP_SLOT	PyMemoryView_FromObject

These all are writable sections. I think 'scanelf' is confused, it should see no bad relocs. Worth fixing it.

It's probably a binutils' bug in 'ld'. It should not have flagged this binary as having TEXTRELs.
Comment 9 Sergei Trofimovich (RETIRED) gentoo-dev 2020-03-18 22:06:03 UTC
Slightly patched binutils to provide exact relocation types and places:

--- a/bfd/elfnn-riscv.c
+++ b/bfd/elfnn-riscv.c
@@ -736,6 +736,10 @@ riscv_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
                  p->pc_count = 0;
                }

+             if (strcmp(p->sec->name, ".text") == 0) {
+               fprintf(stderr, "riscv_elf_check_relocs(): ++ suspicious reloc in '%s'/'%s'\n", p->sec->name, p->sec->owner->filename);
+               fprintf(stderr, "riscv_elf_check_relocs(): r_type=%u\n", r_type);
+             }
              p->count += 1;
              p->pc_count += r == NULL ? 0 : r->pc_relative;
            }
@@ -1151,6 +1155,7 @@ maybe_set_textrel (struct elf_link_hash_entry *h, void *info_p)
       struct bfd_link_info *info = (struct bfd_link_info *) info_p;

       info->flags |= DF_TEXTREL;
+      fprintf(stderr, "maybe_set_textrel(): TEEEEEEEEXTEEEEEEEEEL\n");
       info->callbacks->minfo
        (_("%pB: dynamic relocation against `%pT' in read-only section `%pA'\n"),
         sec->owner, h->root.root.string, sec);
@@ -1219,7 +1224,11 @@ riscv_elf_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info)
                  srel = elf_section_data (p->sec)->sreloc;
                  srel->size += p->count * sizeof (ElfNN_External_Rela);
                  if ((p->sec->output_section->flags & SEC_READONLY) != 0)
+                 {
+                   fprintf(stderr, "riscv_elf_size_dynamic_sections(): TEEEEEEEEXTEEEEEEEEEL:"
+                                   " '%s'/'%s'/count=%lu\n", p->sec->owner->filename, p->sec->name, p->count);
                    info->flags |= DF_TEXTREL;
+                 }
                }
            }
        }
@@ -1371,6 +1380,7 @@ riscv_elf_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info)

       if (info->flags & DF_TEXTREL)
        {
+         fprintf(stderr, "riscv_elf_size_dynamic_sections(): TTTEEEEXT / 2\n");
          if (!add_dynamic_entry (DT_TEXTREL, 0))
            return FALSE;
        }

The output is the following:

$ gcc++ ...  -B/home/slyfox/dev/git/binutils-gdb-riscv64/ld -Wl,-z,text
riscv_elf_check_relocs(): ++ suspicious reloc in '.text'/'cp-support.o'
riscv_elf_check_relocs(): r_type=29
riscv_elf_check_relocs(): ++ suspicious reloc in '.text'/'cp-support.o'
riscv_elf_check_relocs(): r_type=29
riscv_elf_check_relocs(): ++ suspicious reloc in '.text'/'cp-support.o'
riscv_elf_check_relocs(): r_type=29
riscv_elf_check_relocs(): ++ suspicious reloc in '.text'/'cp-support.o'
riscv_elf_check_relocs(): r_type=29
riscv_elf_check_relocs(): ++ suspicious reloc in '.text'/'event-top.o'
riscv_elf_check_relocs(): r_type=29
riscv_elf_check_relocs(): ++ suspicious reloc in '.text'/'gdbsupport/safe-strerror.o'
riscv_elf_check_relocs(): r_type=29
riscv_elf_size_dynamic_sections(): TEEEEEEEEXTEEEEEEEEEL: 'cp-support.o'/'.text'/count=4
riscv_elf_size_dynamic_sections(): TEEEEEEEEXTEEEEEEEEEL: 'event-top.o'/'.text'/count=1
riscv_elf_size_dynamic_sections(): TEEEEEEEEXTEEEEEEEEEL: 'gdbsupport/safe-strerror.o'/'.text'/count=1
riscv_elf_size_dynamic_sections(): TTTEEEEXT / 2
/home/slyfox/dev/git/binutils-gdb-riscv64/ld/ld: read-only segment has dynamic relocations
collect2: error: ld returned 1 exit status

r_type=29 is a 'R_RISCV_TPREL_HI20' relocation:

$ egrep R_RISCV.*29 /usr/include/elf.h
#define R_RISCV_TPREL_HI20	29

Example source of the relocation is event-top.o where it is encountered once:

$ objdump -d -S -r event-top.o

00000000000003ea <handle_sigsegv(int)>:
     3ea:       1141                    addi    sp,sp,-16
     3ec:       e022                    sd      s0,0(sp)
     3ee:       e406                    sd      ra,8(sp)
     3f0:       842a                    mv      s0,a0
     3f2:       00000097                auipc   ra,0x0
                        3f2: R_RISCV_CALL       install_handle_sigsegv()
                        3f2: R_RISCV_RELAX      *ABS*
     3f6:       000080e7                jalr    ra # 3f2 <handle_sigsegv(int)+0x8>
     3fa:       000007b7                lui     a5,0x0
                        3fa: R_RISCV_TPREL_HI20 .LANCHOR1
                        3fa: R_RISCV_RELAX      *ABS*
     3fe:       004787b3                add     a5,a5,tp
                        3fe: R_RISCV_TPREL_ADD  .LANCHOR1
                        3fe: R_RISCV_RELAX      *ABS*
     402:       00078793                mv      a5,a5
                        402: R_RISCV_TPREL_LO12_I       .LANCHOR1
                        402: R_RISCV_RELAX      *ABS*
     406:       0007b303                ld      t1,0(a5) # 0 <async_do_nothing(void*)>
     40a:       00030763                beqz    t1,418 <.L89>
                        40a: R_RISCV_BRANCH     .L89
     40e:       8522                    mv      a0,s0
     410:       6402                    ld      s0,0(sp)
     412:       60a2                    ld      ra,8(sp)
     414:       0141                    addi    sp,sp,16
     416:       8302                    jr      t1

That is reference to thread_local variable: https://sourceware.org/git/?p=binutils-gdb.git;a=blob;f=gdb/event-top.c;h=1bfc28ea09965872f438a2e18951f6ba836d62c7;hb=HEAD#l853

Let's see if I can craft minimal example.
Comment 10 Sergei Trofimovich (RETIRED) gentoo-dev 2020-03-18 22:14:36 UTC
This seems to be enough:

$ cat a.cc
static int a () { return 1; }

static thread_local int (*tlf) () = &a;

int main(void) { return tlf(); }

$ x86_64-pc-linux-gnu-g++ a.cc -o a -Wl,-z,text; riscv64-unknown-linux-gnu-g++ a.cc -o b -Wl,-z,text
/usr/libexec/gcc/riscv64-unknown-linux-gnu/ld: read-only segment has dynamic relocations
collect2: error: ld returned 1 exit status
Comment 11 Sergei Trofimovich (RETIRED) gentoo-dev 2020-03-18 22:30:32 UTC
Filed upstream bug as https://sourceware.org/PR25694.

Meanwhile the workaround for you to get gdb is to temporarily drop one of FEATURES='strict stricter'. I don't remember which one.
Comment 12 Larry the Git Cow gentoo-dev 2020-03-18 23:39:13 UTC
The bug has been referenced in the following commit(s):

https://gitweb.gentoo.org/proj/pax-utils.git/commit/?id=33f047637d8bc3c5d3d3faa37a8ad5b3f8825213

commit 33f047637d8bc3c5d3d3faa37a8ad5b3f8825213
Author:     Sergei Trofimovich <slyfox@gentoo.org>
AuthorDate: 2020-03-18 23:37:19 +0000
Commit:     Sergei Trofimovich <slyfox@gentoo.org>
CommitDate: 2020-03-18 23:37:19 +0000

    scanelf.c: don't srash in -v mode on non-functions
    
    Fix crash when running in verbose mode on bad files:
    $ ./scanelf -T -v gdb
    
    The file is taken from bug #713082.
    
    Bug: https://bugs.gentoo.org/713082
    Signed-off-by: Sergei Trofimovich <slyfox@gentoo.org>

 scanelf.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
Comment 13 Larry the Git Cow gentoo-dev 2020-03-19 00:00:00 UTC
The bug has been referenced in the following commit(s):

https://gitweb.gentoo.org/proj/pax-utils.git/commit/?id=79489b3450faac9ffcc0ffc55d57dacdfed897be

commit 79489b3450faac9ffcc0ffc55d57dacdfed897be
Author:     Sergei Trofimovich <slyfox@gentoo.org>
AuthorDate: 2020-03-18 23:57:30 +0000
Commit:     Sergei Trofimovich <slyfox@gentoo.org>
CommitDate: 2020-03-18 23:57:30 +0000

    scanelf.c: be more verbose at saying what all the addresses mean
    
    Print out relocation type and explain addresses:
    
    ```
    $ ./scanelf -T -v gdb
     TYPE   TEXTRELS FILE
      gdb: (memory/data?) [r_offset=0x0] r_type=0 in (optimized out?) [closest_prev_sym=0x0]
      gdb: (memory/data?) [r_offset=0x0] r_type=0 in (optimized out?) [closest_prev_sym=0x0]
      gdb: (memory/data?) [r_offset=0x0] r_type=0 in (optimized out?) [closest_prev_sym=0x0]
      gdb: (memory/data?) [r_offset=0x0] r_type=0 in (optimized out?) [closest_prev_sym=0x0]
      gdb: (memory/data?) [r_offset=0x0] r_type=0 in (optimized out?) [closest_prev_sym=0x0]
      gdb: (memory/data?) [r_offset=0x0] r_type=0 in (optimized out?) [closest_prev_sym=0x0]
    ```
    
    Note: it's now more obvious that suspicious relocations are not real
    and just zero-initialized leftovers of R_*_NONE type.
    
    Bug: https://bugs.gentoo.org/713082
    Signed-off-by: Sergei Trofimovich <slyfox@gentoo.org>

 scanelf.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)
Comment 14 Sergei Trofimovich (RETIRED) gentoo-dev 2020-03-19 00:03:40 UTC
(In reply to Sergei Trofimovich from comment #6)
> (In reply to Skylar from comment #5)
> > Created attachment 621160 [details]
> > scanelf
> 
> Your output looks bad:
> 
> ```
> scanelf -qT /usr/bin/gdb
>   gdb: (memory/data?) [0x0] in (optimized out) [0x0]
>   gdb: (memory/data?) [0x0] in (optimized out) [0x0]
>   gdb: (memory/data?) [0x0] in (optimized out) [0x0]
>   gdb: (memory/data?) [0x0] in (optimized out) [0x0]
>   gdb: (memory/data?) [0x0] in (optimized out) [0x0]
>   gdb: (memory/data?) [0x0] in (optimized out) [0x0]
>   /usr/bin/gdb
> ```

These ended up being R_RISCV_NONE relocs. They are no-op relocs that should never appear in final bianries. They are not affecting TEXTRELs directy but likely a sign of mis-accounting for R_RISCV_TPREL_HI20 that was statically relocated by ld.
Comment 15 Sam James archtester Gentoo Infrastructure gentoo-dev Security 2023-07-30 16:41:33 UTC
AFAIK this is fixed in Binutils 2.41.