Bug 20515

Summary: i686 ifunc and non-default symbol visibility
Product: binutils Reporter: Alan Modra <amodra>
Component: ldAssignee: H.J. Lu <hjl.tools>
Status: RESOLVED FIXED    
Severity: normal CC: fweimer, hjl.tools
Priority: P2 Flags: fweimer: security-
Version: 2.28   
Target Milestone: 2.28   
Host: Target: x86_64-linux
Build: Last reconfirmed:

Description Alan Modra 2016-08-25 14:02:51 UTC
An adaptation of the existing pr19784 testcase.
cat > pr19784a.c <<\EOF
#include <stdio.h>
int bar(void);
int main(void)
{
  if (bar())
    printf ("PASS\n");
  else
    __builtin_abort ();
  return 0;
}
EOF
cat > pr19784b.c <<\EOF
int foo (int x) __attribute__ ((ifunc ("resolve_foo")));

static int foo_impl(int x)
{
  return x;
}

void *resolve_foo (void)
{
  return (void *) foo_impl;
}
EOF
cat > pr19784c.c <<\EOF
extern int foo (int) __attribute__ ((visibility("hidden")));

int bar()
{
  return foo (5) == 5;
}
EOF
gcc -m32 -c -g -O2 -fPIC pr19784a.c
gcc -m32 -c -g -O2 -fPIC pr19784b.c
gcc -m32 -c -g -O2 -fPIC pr19784c.c
gcc -m32 -shared -o libpr19784a.so pr19784b.o pr19784c.o
gcc -m32 -shared -o libpr19784b.so pr19784c.o pr19784b.o
gcc -m32 -o pr19784a pr19784a.o -Wl,--rpath=. libpr19784a.so
gcc -m32 -o pr19784b pr19784a.o -Wl,--rpath=. libpr19784b.so
./pr19784a
./pr19784b

The linker ought to issue an error rather than building invalid shared libraries that segfault at runtime.  Ditto for the pr14961 testcase.
Comment 1 H.J. Lu 2016-08-26 16:56:45 UTC
diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c
index 4179572..aa6b8d0 100644
--- a/bfd/elf32-i386.c
+++ b/bfd/elf32-i386.c
@@ -2178,6 +2178,20 @@ do_relocation:
 		     a function defined in a shared library.  */
 		  if ((sec->flags & SEC_CODE) == 0)
 		    h->pointer_equality_needed = 1;
+		  else if (h->type == STT_GNU_IFUNC
+			   && bfd_link_pic (info))
+		    {
+		    if (isym == NULL)
+		      name = h->root.root.string;
+		    else
+		      name = bfd_elf_sym_name (abfd, symtab_hdr, isym,
+					       NULL);
+		    (*_bfd_error_handler)
+		      (_("%B: unspported local call to IFUNC `%s'"),
+		       abfd, name);
+		      bfd_set_error (bfd_error_bad_value);
+		      goto error_return;
+		    }
 		}
 	      else
 		{
Comment 2 H.J. Lu 2016-08-26 18:13:02 UTC
*** Bug 14961 has been marked as a duplicate of this bug. ***
Comment 3 Sourceware Commits 2016-08-29 15:16:00 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=74437ea28fb611d4c88077b486fd7c0a8b4c2a25

commit 74437ea28fb611d4c88077b486fd7c0a8b4c2a25
Author: H.J. Lu <hjl.tools@gmail.com>
Date:   Mon Aug 29 08:12:59 2016 -0700

    i386: Issue an error on non-PIC call to IFUNC in PIC object
    
    On i386, IFUNC function must be called via PLT.  Since PLT in PIC
    object uses EBX register, R_386_PLT32 relocation must be used to
    call IFUNC function even when IFUNC function is defined locally.
    Linker should issue an error when R_386_PC32 relocation is used
    to call IFUNC function.
    
    Since PR ld/19784 tests doesn't use PLT relocation to local IFUNC
    function, they are moved to the x86-64 test directory.
    
    bfd/
    
    	PR ld/14961
    	PR ld/20515
    	* elf32-i386.c (elf_i386_check_relocs): Issue an error when
    	R_386_PC32 relocation is used to call IFUNC function in PIC
    	object.
    
    ld/
    
    	PR ld/14961
    	PR ld/20515
    	* testsuite/ld-i386/i386.exp: Run pr20515.
    	* testsuite/ld-i386/pr20515.d: New file.
    	* testsuite/ld-i386/pr20515.s: Likewise.
    	* testsuite/ld-ifunc/ifunc-14a.s: Use R_386_PLT32 to call IFUNC
    	function.
    	* testsuite/ld-ifunc/ifunc-14c.s: Likewise.
    	* testsuite/ld-ifunc/ifunc-2-i386.s: Likewise.
    	* testsuite/ld-ifunc/ifunc-2-local-i386.s: Likewise.
    	* testsuite/ld-ifunc/ifunc.exp: Move PR ld/19784 tests to ...
    	* testsuite/ld-x86-64/x86-64.exp: Here.
    	* testsuite/ld-ifunc/pr19784a.c: Moved to ...
    	* testsuite/ld-x86-64/pr19784a.c: Here.
    	* testsuite/ld-ifunc/pr19784b.c: Moved to ...
    	* testsuite/ld-x86-64/pr19784b.c: Here.
    	* testsuite/ld-ifunc/pr19784c.c: Moved to ...
    	* testsuite/ld-x86-64/pr19784c.c: Here.
Comment 4 H.J. Lu 2016-08-29 15:18:34 UTC
Fixed.