Bug 18841 - Data relocations with IFUNC symbols can lead to segfault
Summary: Data relocations with IFUNC symbols can lead to segfault
Status: RESOLVED FIXED
Alias: None
Product: binutils
Classification: Unclassified
Component: ld (show other bugs)
Version: unspecified
: P2 normal
Target Milestone: 2.26
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2015-08-17 22:22 UTC by Alexander Monakov
Modified: 2020-07-13 14:26 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Alexander Monakov 2015-08-17 22:22:29 UTC
In the following testcase, libfoo.so is compiled so that it has GLOB_DAT relocations against 'foo' and 'zoo', in that order (with BFD linker), which leads to failure at dynamic linking time.  Renaming 'zoo' to 'z' with the preprocessor avoids the segfault (the relocations happen to be emitted in the opposite order).  Gold linker appears to always sort the relocations "properly".

cat <<EOF >foo.c
void foo() __attribute__((ifunc("resolve_foo")));

static void foo_impl() {}

void test()
{
  void (*pg)(void) = foo;
  pg();
}

static void* resolve_foo()
{
  extern void zoo(void);

  void (*pz)(void) = zoo;
  pz();
  return foo_impl;
}
EOF

cat <<EOF >main.c
void zoo(){}

void test(void);

int main()
{
  test();
  return 0;
}
EOF

cat <<'EOF' >Makefile
test: main; ./main

main: libfoo.so

lib%.so: %.c; $(CC) $(CFLAGS) -fPIC -shared -o $@ $<

main: LDLIBS=-L. -lfoo

main: LDFLAGS=-Wl,-rpath,.
EOF

$ make -B CFLAGS=-fuse-ld=gold
cc -fuse-ld=gold -fPIC -shared -o libfoo.so foo.c
cc -fuse-ld=gold  -Wl,-rpath,.  main.c libfoo.so  -L. -lfoo -o main
./main
$ make -B CFLAGS=-fuse-ld=bfd
cc -fuse-ld=bfd -fPIC -shared -o libfoo.so foo.c
cc -fuse-ld=bfd  -Wl,-rpath,.  main.c libfoo.so  -L. -lfoo -o main
./main
Makefile:2: recipe for target 'test' failed
make: *** [test] Segmentation fault
$ make -B CFLAGS=-fuse-ld=bfd\ -Dzoo=z
cc -fuse-ld=bfd -Dzoo=z -fPIC -shared -o libfoo.so foo.c
cc -fuse-ld=bfd -Dzoo=z  -Wl,-rpath,.  main.c libfoo.so  -L. -lfoo -o main
./main
$
Comment 1 H.J. Lu 2015-08-17 23:28:31 UTC
This usage is ill defined. Small changes change the run-time
behavior:

1. Use -O2 causes it to pass with ld:

[hjl@gnu-6 pr18841]$ make 
gcc -B./ -O2 -g   -c -o main.o main.c
gcc -B./ -O2 -g -fpic   -c -o foo.o foo.c
gcc -B./  -shared -o libfoo.so foo.o
gcc -B./  -o main main.o libfoo.so -Wl,-R.
./main
[hjl@gnu-6 pr18841]$ 

2. Make pz file scope causes it to fail with gold and ld:

[hjl@gnu-6 pr18841-bad]$ cat foo.c
void foo() __attribute__((ifunc("resolve_foo")));

static void foo_impl() {}

extern void zoo(void);
void (*pz)(void) = zoo;

void test()
{
  void (*pg)(void) = foo;
  pg();
}

static void* resolve_foo()
{
  pz();
  return foo_impl;
}
[hjl@gnu-6 pr18841-bad]$ make
gcc -B./ -fuse-ld=gold -g -fpic   -c -o foo.o foo.c
gcc -B./ -fuse-ld=gold  -shared -o libfoo.so foo.o
gcc -B./ -fuse-ld=gold  -o main main.o libfoo.so -Wl,-R.
./main
Makefile:17: recipe for target 'all' failed
make: *** [all] Segmentation fault
[hjl@gnu-6 pr18841-bad]$
Comment 2 Alan Modra 2015-08-18 06:37:26 UTC
The problem here is that x86_64 doesn't properly sort ifunc relocs last.  elf_x86_64_reloc_type_class needs to return reloc_class_ifunc for relocs against ifunc symbols.
Comment 3 cvs-commit@gcc.gnu.org 2015-08-18 16:52:08 UTC
The master branch has been updated by H.J. Lu <hjl@sourceware.org>:

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=cae1fbbb7e3d770702a0d7a5027b46835e6adc13

commit cae1fbbb7e3d770702a0d7a5027b46835e6adc13
Author: H.J. Lu <hjl.tools@gmail.com>
Date:   Tue Aug 18 09:47:59 2015 -0700

    Return reloc_class_ifunc for reloc against IFUNC
    
    elf_XXX_reloc_type_class should return reloc_class_ifunc for relocation
    against STT_GNU_IFUNC symbol.
    
    bfd/
    
    	PR ld/18841
    	* elf-bfd.h (elf_link_hash_table): Add dynsym.
    	* elf32-i386.c (elf_i386_reloc_type_class): Return
    	reloc_class_ifunc for relocation against STT_GNU_IFUNC symbol.
    	* elf64-x86-64.c (elf_x86_64_reloc_type_class): Likewise.
    	* elflink.c (_bfd_elf_link_create_dynamic_sections): Set dynsym.
    	(bfd_elf_size_dynsym_hash_dynstr): Use dynsym.
    	(elf_final_link_info): Remove dynsym_sec.
    	(elf_link_output_extsym): Replace dynsym_sec with dynsym.
    	(bfd_elf_final_link): Remove reference to dynsym_sec.  Replace
    	dynsym_sec with dynsym.
    
    ld/testsuite/
    
    	PR ld/18841
    	* ld-ifunc/ifunc.exp: Add a test for PR ld/18841.
    	* ld-ifunc/pr18841.out: New file.
    	* ld-ifunc/pr18841a.c: Likewise.
    	* ld-ifunc/pr18841b.c: Likewise.
Comment 4 H.J. Lu 2015-08-18 16:53:15 UTC
Fixed.
Comment 5 Alexander Monakov 2015-08-18 17:26:43 UTC
Does it still fail with the change you mentioned in comment #2?

> 2. Make pz file scope causes it to fail with gold and ld
Comment 6 H.J. Lu 2015-08-18 17:28:35 UTC
(In reply to Alexander Monakov from comment #5)
> Does it still fail with the change you mentioned in comment #2?
> 
> > 2. Make pz file scope causes it to fail with gold and ld

Yes.
Comment 7 H.J. Lu 2015-08-18 17:33:21 UTC
(In reply to H.J. Lu from comment #6)
> (In reply to Alexander Monakov from comment #5)
> > Does it still fail with the change you mentioned in comment #2?
> > 
> > > 2. Make pz file scope causes it to fail with gold and ld
> 
> Yes.

I was wrong.  It works with ld.
Comment 8 cvs-commit@gcc.gnu.org 2015-08-18 17:44:41 UTC
The master branch has been updated by H.J. Lu <hjl@sourceware.org>:

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=4e1626f5a8d73573d6cf593fabe5bc80f7b3e04e

commit 4e1626f5a8d73573d6cf593fabe5bc80f7b3e04e
Author: H.J. Lu <hjl.tools@gmail.com>
Date:   Tue Aug 18 10:43:19 2015 -0700

    Add another test for PR ld/18841
    
    	PR ld/18841
    	* ld-ifunc/ifunc.exp: Add another test for PR ld/18841.
    	* ld-ifunc/pr18841c.c: New file.
Comment 9 cvs-commit@gcc.gnu.org 2015-10-22 08:16:37 UTC
The master branch has been updated by Andreas Krebbel <krebbel@sourceware.org>:

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=0f042c67a04d5d0c8f879c27d651a7ed5aa6566f

commit 0f042c67a04d5d0c8f879c27d651a7ed5aa6566f
Author: Andreas Krebbel <krebbel@linux.vnet.ibm.com>
Date:   Thu Oct 22 10:11:07 2015 +0200

    S/390: ifunc: Fix PR18841.
    
    In order to get the ifunc relocs properly sorted the correct class
    needs to be returned.  The code mimics what has been done for x86.
    
    bfd/ChangeLog:
    
    	PR ld/18841
    	* elf32-s390.c (elf_s390_reloc_type_class): Return
    	reloc_class_ifunc for ifunc symbols.
    	* elf64-s390.c (elf_s390_reloc_type_class): Likewise.
Comment 10 cvs-commit@gcc.gnu.org 2017-07-19 17:49:27 UTC
The master branch has been updated by Szabolcs Nagy <nsz@sourceware.org>:

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=f2e6a8430e72d58e70aaaaefbb32dc3953d5cf33

commit f2e6a8430e72d58e70aaaaefbb32dc3953d5cf33
Author: Szabolcs Nagy <szabolcs.nagy@arm.com>
Date:   Tue Jul 4 15:43:59 2017 +0100

    [AArch64] Fix PR18841 ifunc relocation ordering
    
    In order to get the ifunc relocs properly sorted the correct class
    needs to be returned.  The code mimics what has been done for x86.
    
    Fixes
    FAIL: Run pr18841 with libpr18841c.so
    
    bfd/
    	PR ld/18841
    	* elfnn-aarch64.c (elfNN_aarch64_reloc_type_class): Return
    	reloc_class_ifunc for ifunc symbols.
Comment 11 cvs-commit@gcc.gnu.org 2017-08-17 14:20:15 UTC
The binutils-2_29-branch branch has been updated by Szabolcs Nagy <nsz@sourceware.org>:

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=6f0f222468cd8cf23cbe2458be233c553842a568

commit 6f0f222468cd8cf23cbe2458be233c553842a568
Author: Szabolcs Nagy <szabolcs.nagy@arm.com>
Date:   Tue Jul 4 15:43:59 2017 +0100

    [AArch64] Fix PR18841 ifunc relocation ordering
    
    In order to get the ifunc relocs properly sorted the correct class
    needs to be returned.  The code mimics what has been done for x86.
    
    Fixes
    FAIL: Run pr18841 with libpr18841c.so
    
    bfd/
    	PR ld/18841
    	* elfnn-aarch64.c (elfNN_aarch64_reloc_type_class): Return
    	reloc_class_ifunc for ifunc symbols.
Comment 12 cvs-commit@gcc.gnu.org 2019-02-07 16:06:12 UTC
The master branch has been updated by Eric Botcazou <ebotcazou@sourceware.org>:

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=b2abe1bd8149dd9ad64432f620c3a034bf23a5fe

commit b2abe1bd8149dd9ad64432f620c3a034bf23a5fe
Author: Eric Botcazou <ebotcazou@gcc.gnu.org>
Date:   Thu Feb 7 17:04:31 2019 +0100

    SPARC: fix PR ld/18841
    
    This fixes the last ld failures on SPARC64/Linux:
    
    FAIL: Run pr18841 with libpr18841b.so
    FAIL: Run pr18841 with libpr18841c.so
    FAIL: Run pr18841 with libpr18841bn.so (-z now)
    FAIL: Run pr18841 with libpr18841cn.so (-z now)
    
    by mimicing what has been done on x86-64 and Aarch64 to fix the PR.
    
    bfd/
    	PR ld/18841
            * elf32-sparc.c (elf32_sparc_reloc_type_class): Return
            reloc_class_ifunc for ifunc symbols.
            * elf64-sparc.c (elf64_sparc_reloc_type_class): Likewise.
Comment 13 cvs-commit@gcc.gnu.org 2019-02-07 16:12:02 UTC
The binutils-2_32-branch branch has been updated by Eric Botcazou <ebotcazou@sourceware.org>:

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=afbdeb58468604ede2d51fb00c4ea9850fcf2617

commit afbdeb58468604ede2d51fb00c4ea9850fcf2617
Author: Eric Botcazou <ebotcazou@gcc.gnu.org>
Date:   Thu Feb 7 17:04:31 2019 +0100

    SPARC: fix PR ld/18841
    
    This fixes the last ld failures on SPARC64/Linux:
    
    FAIL: Run pr18841 with libpr18841b.so
    FAIL: Run pr18841 with libpr18841c.so
    FAIL: Run pr18841 with libpr18841bn.so (-z now)
    FAIL: Run pr18841 with libpr18841cn.so (-z now)
    
    by mimicing what has been done on x86-64 and Aarch64 to fix the PR.
    
    bfd/
    	PR ld/18841
            * elf32-sparc.c (elf32_sparc_reloc_type_class): Return
            reloc_class_ifunc for ifunc symbols.
            * elf64-sparc.c (elf64_sparc_reloc_type_class): Likewise.
Comment 14 cvs-commit@gcc.gnu.org 2019-02-07 16:15:22 UTC
The binutils-2_31-branch branch has been updated by Eric Botcazou <ebotcazou@sourceware.org>:

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=1532a937c64105681d74055389f0e846244fb830

commit 1532a937c64105681d74055389f0e846244fb830
Author: Eric Botcazou <ebotcazou@gcc.gnu.org>
Date:   Thu Feb 7 17:04:31 2019 +0100

    SPARC: fix PR ld/18841
    
    This fixes the last ld failures on SPARC64/Linux:
    
    FAIL: Run pr18841 with libpr18841b.so
    FAIL: Run pr18841 with libpr18841c.so
    FAIL: Run pr18841 with libpr18841bn.so (-z now)
    FAIL: Run pr18841 with libpr18841cn.so (-z now)
    
    by mimicing what has been done on x86-64 and Aarch64 to fix the PR.
    
    bfd/
    	PR ld/18841
            * elf32-sparc.c (elf32_sparc_reloc_type_class): Return
            reloc_class_ifunc for ifunc symbols.
            * elf64-sparc.c (elf64_sparc_reloc_type_class): Likewise.
Comment 15 cvs-commit@gcc.gnu.org 2020-07-09 13:28:42 UTC
The master branch has been updated by Alan Modra <amodra@sourceware.org>:

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=470cd0faa7f433b47944683eee4fc3dad6ef7cdf

commit 470cd0faa7f433b47944683eee4fc3dad6ef7cdf
Author: Alan Modra <amodra@gmail.com>
Date:   Thu Jul 9 16:35:27 2020 +0930

    pr18841 tests on powerpc64
    
    The PR18841 test does cross-module calls from within an ifunc
    resolver, which is nasty, and not supported in general since the
    called function may not be relocated.  In this case the called
    function (zoo) is just a stub so doesn't need relocating, but on ppc64
    the function descriptor for zoo in the executable won't be relocated
    at the time the shared library ifunc resolver runs.  That means the
    test will fail if your compiler generates PIEs by default.
    
            PR 18841
            * testsuite/ld-ifunc/ifunc.exp: Run pr18841 tests non-pie.
Comment 16 cvs-commit@gcc.gnu.org 2020-07-13 14:26:13 UTC
The binutils-2_35-branch branch has been updated by Alan Modra <amodra@sourceware.org>:

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=3d186ccca35dfd7e9e5ae1eaba3015d0ae17e247

commit 3d186ccca35dfd7e9e5ae1eaba3015d0ae17e247
Author: Alan Modra <amodra@gmail.com>
Date:   Thu Jul 9 16:35:27 2020 +0930

    pr18841 tests on powerpc64
    
    The PR18841 test does cross-module calls from within an ifunc
    resolver, which is nasty, and not supported in general since the
    called function may not be relocated.  In this case the called
    function (zoo) is just a stub so doesn't need relocating, but on ppc64
    the function descriptor for zoo in the executable won't be relocated
    at the time the shared library ifunc resolver runs.  That means the
    test will fail if your compiler generates PIEs by default.
    
            PR 18841
            * testsuite/ld-ifunc/ifunc.exp: Run pr18841 tests non-pie.
    
    (cherry picked from commit 470cd0faa7f433b47944683eee4fc3dad6ef7cdf)