Bug 28875 - ld should warn or error out about creating copy relocs & direct external references for protected symbols
Summary: ld should warn or error out about creating copy relocs & direct external refe...
Status: RESOLVED FIXED
Alias: None
Product: binutils
Classification: Unclassified
Component: ld (show other bugs)
Version: 2.38
: P2 normal
Target Milestone: 2.39
Assignee: H.J. Lu
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2022-02-09 19:59 UTC by Thiago Macieira
Modified: 2022-02-11 18:34 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Last reconfirmed: 2022-02-10 00:00:00


Attachments
A patch (2.30 KB, patch)
2022-02-10 00:01 UTC, H.J. Lu
Details | Diff
The v2 patch (2.98 KB, patch)
2022-02-11 00:04 UTC, H.J. Lu
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Thiago Macieira 2022-02-09 19:59:02 UTC
Related: #15228, #17711, #27973.

For a library that has protected symbols:

$ cat libb2.cpp           
__attribute__((visibility("protected"))) long internal_i = 0;
__attribute__((visibility("protected"))) long internal_f()
{
    return 2;
}
$ gcc -shared -fPIC -o libb.so libb2.cpp
$ eu-readelf --dyn-syms libb.so| grep internal
    5: 0000000000004028      8 OBJECT  GLOBAL PROTECTED     22 internal_i
    6: 00000000000010f9     11 FUNC    GLOBAL PROTECTED     11 _Z10internal_fv

The linker should produce a warning when creating copy relocations or position-dependent moves:

$ cat main.cpp 
extern __attribute__((visibility("default"))) long internal_i;
extern __attribute__((visibility("default"))) long internal_f();

int main()
{
    internal_i = (long) &internal_f;
}
$ gcc main.cpp libb.so 
[no error]

gold already does:
$ gcc -fuse-ld=gold main.cpp libb.so
/usr/bin/ld.gold: error: /tmp/ccg0cNpy.o: cannot make copy relocation for protected symbol 'internal_i', defined in libb.so
collect2: error: ld returned 1 exit status
Comment 1 H.J. Lu 2022-02-10 00:01:37 UTC
Created attachment 13964 [details]
A patch

Try this.
Comment 2 Thiago Macieira 2022-02-10 20:06:17 UTC
(In reply to H.J. Lu from comment #1)
> Created attachment 13964 [details]
> A patch
> 
> Try this.

Confirmed for copy relocations:

$ cat main.cpp
extern __attribute__((visibility("default"))) long internal_i;
extern __attribute__((visibility("default"))) long internal_f();

int main()
{
    internal_i = (long) &internal_f;
    return (long) &internal_f;
}
$ gcc main.cpp libb.so
/home/tjmaciei/dev/gcc/lib/gcc/x86_64-pc-linux-gnu/12.0.1/../../../../x86_64-pc-linux-gnu/bin/ld: /tmp/ccwnIS4o.o: copy relocation against non-copyable protected symbol `internal_i' in libb.so
collect2: error: ld returned 1 exit status

But not for PLT entries:

$ cat main2.cpp
extern __attribute__((visibility("default"))) long internal_f();

int main()
{
    return (long) &internal_f;
}
$ gcc main2.cpp libb.so
[no error]
$ objdump --no-show -Cdr a.out| sed -n '/<main>:/,/^$/p'
0000000000401126 <main>:
  401126:       push   %rbp
  401127:       mov    %rsp,%rbp
  40112a:       mov    $0x401030,%eax
  40112f:       pop    %rbp
  401130:       ret    

glibc 2.35 does not complain about this binary by default:

$ LD_LIBRARY_PATH=. ./a.out; printf %x\\n $? 
30

Only if the PLT is processed:

$ LD_BIND_NOW=1 LD_LIBRARY_PATH=. ./a.out                 
./a.out: _Z10internal_fv: ./libb.so: non-canonical reference to canonical protected function
Comment 3 Thiago Macieira 2022-02-10 20:07:18 UTC
That is, this patch brings BFD ld on par with Gold. The remaining issue for Gold is #28876.
Comment 4 H.J. Lu 2022-02-11 00:04:12 UTC
Created attachment 13971 [details]
The v2 patch

I got

/usr/gcc-12.0.1-x32/bin/gcc -B./ -o x main.o libfoo.so -Wl,-R,.
./ld: main.o: non-canonical reference to canonical protected function `internal_f' in libfoo.so
./ld: failed to set dynamic section sizes: bad value
collect2: error: ld returned 1 exit status
Comment 5 Thiago Macieira 2022-02-11 16:44:33 UTC
(In reply to H.J. Lu from comment #4)
> Created attachment 13971 [details]
> The v2 patch
> 
> I got
> 
> /usr/gcc-12.0.1-x32/bin/gcc -B./ -o x main.o libfoo.so -Wl,-R,.
> ./ld: main.o: non-canonical reference to canonical protected function
> `internal_f' in libfoo.so
> ./ld: failed to set dynamic section sizes: bad value
> collect2: error: ld returned 1 exit status

Confirmed:

$ gcc main.cpp libb.so               
/home/tjmaciei/dev/gcc/lib/gcc/x86_64-pc-linux-gnu/12.0.1/../../../../x86_64-pc-linux-gnu/bin/ld: /tmp/ccTtYFXS.o: non-canonical reference to canonical protected function `_Z10internal_fv' in libb.so
collect2: error: ld returned 1 exit status

Uploading my Qt patch to make use of this.
Comment 6 Sourceware Commits 2022-02-11 18:28:52 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=ebb191adac4ab45498dec0bfaac62f0a33537ba4

commit ebb191adac4ab45498dec0bfaac62f0a33537ba4
Author: H.J. Lu <hjl.tools@gmail.com>
Date:   Wed Feb 9 15:51:22 2022 -0800

    x86: Disallow invalid relocation against protected symbol
    
    I am checking this into master and will backport it to 2.38 branch.
    
    H.J
    ----
    On x86, GCC 12 supports -mno-direct-extern-access to enable canonical
    reference to protected function and disable copy relocation.  With
    -mno-direct-extern-access, the canonical protected function symbols must
    be accessed via canonical reference and the protected data symbols in
    shared libraries are non-copyable. Under glibc 2.35, non-canonical
    reference to the canonical protected function will get the run-time error:
    
    ./y: internal_f: ./libfoo.so: non-canonical reference to canonical protected function
    
    and copy relocations against the non-copyable protected symbols will get
    the run-time error:
    
    ./x: internal_i: ./libfoo.so: copy relocation against non-copyable protected symbol
    
    Update x86 linker to disallow non-canonical reference to the canonical
    protected function:
    
    ld: plt.o: non-canonical reference to canonical protected function `internal_f' in libfoo.so
    ld: failed to set dynamic section sizes: bad value
    
    and copy relocation against the non-copyable protected symbol:
    
    ld: main.o: copy relocation against non-copyable protected symbol `internal_i' in libfoo.so
    
    at link-time.
    
    bfd/
    
            PR ld/28875
            * elf-properties.c (_bfd_elf_parse_gnu_properties): Don't skip
            shared libraries for GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS.
            * elf32-i386.c (elf_i386_scan_relocs): Disallow non-canonical
            reference to canonical protected function.
            * elf64-x86-64.c (elf_x86_64_scan_relocs): Likewise.
            * elfxx-x86.c (elf_x86_allocate_dynrelocs): Don't allow copy
            relocation against non-copyable protected symbol.
    
    ld/
    
            PR ld/28875
            * testsuite/ld-i386/i386.exp: Check non-canonical reference to
            canonical protected function and check copy relocation against
            non-copyable protected symbol.
            * testsuite/ld-i386/pr21997-1.err: New file.
            * testsuite/ld-i386/pr28875.err: Likewise.
            * testsuite/ld-i386/pr28875a.c: Likewise.
            * testsuite/ld-i386/pr28875b.c: Likewise.
            * testsuite/ld-x86-64/pr21997-1a.err: Updated.
            * testsuite/ld-x86-64/pr21997-1b.err: Likewise.
            * testsuite/ld-x86-64/pr28875-data.err: New file.
            * testsuite/ld-x86-64/pr28875-func.err: Likewise.
            * testsuite/ld-x86-64/x86-64.exp: Check non-canonical reference
            to canonical protected function and check copy relocation against
            non-copyable protected symbol.
Comment 7 Sourceware Commits 2022-02-11 18:33:18 UTC
The binutils-2_38-branch branch has been updated by H.J. Lu <hjl@sourceware.org>:

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

commit caa6172de4b5100c9b45fd03eae714167a6085c1
Author: H.J. Lu <hjl.tools@gmail.com>
Date:   Wed Feb 9 15:51:22 2022 -0800

    x86: Disallow invalid relocation against protected symbol
    
    I am checking this into master and will backport it to 2.38 branch.
    
    H.J
    ----
    On x86, GCC 12 supports -mno-direct-extern-access to enable canonical
    reference to protected function and disable copy relocation.  With
    -mno-direct-extern-access, the canonical protected function symbols must
    be accessed via canonical reference and the protected data symbols in
    shared libraries are non-copyable. Under glibc 2.35, non-canonical
    reference to the canonical protected function will get the run-time error:
    
    ./y: internal_f: ./libfoo.so: non-canonical reference to canonical protected function
    
    and copy relocations against the non-copyable protected symbols will get
    the run-time error:
    
    ./x: internal_i: ./libfoo.so: copy relocation against non-copyable protected symbol
    
    Update x86 linker to disallow non-canonical reference to the canonical
    protected function:
    
    ld: plt.o: non-canonical reference to canonical protected function `internal_f' in libfoo.so
    ld: failed to set dynamic section sizes: bad value
    
    and copy relocation against the non-copyable protected symbol:
    
    ld: main.o: copy relocation against non-copyable protected symbol `internal_i' in libfoo.so
    
    at link-time.
    
    bfd/
    
            PR ld/28875
            * elf-properties.c (_bfd_elf_parse_gnu_properties): Don't skip
            shared libraries for GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS.
            * elf32-i386.c (elf_i386_scan_relocs): Disallow non-canonical
            reference to canonical protected function.
            * elf64-x86-64.c (elf_x86_64_scan_relocs): Likewise.
            * elfxx-x86.c (elf_x86_allocate_dynrelocs): Don't allow copy
            relocation against non-copyable protected symbol.
    
    ld/
    
            PR ld/28875
            * testsuite/ld-i386/i386.exp: Check non-canonical reference to
            canonical protected function and check copy relocation against
            non-copyable protected symbol.
            * testsuite/ld-i386/pr21997-1.err: New file.
            * testsuite/ld-i386/pr28875.err: Likewise.
            * testsuite/ld-i386/pr28875a.c: Likewise.
            * testsuite/ld-i386/pr28875b.c: Likewise.
            * testsuite/ld-x86-64/pr21997-1a.err: Updated.
            * testsuite/ld-x86-64/pr21997-1b.err: Likewise.
            * testsuite/ld-x86-64/pr28875-data.err: New file.
            * testsuite/ld-x86-64/pr28875-func.err: Likewise.
            * testsuite/ld-x86-64/x86-64.exp: Check non-canonical reference
            to canonical protected function and check copy relocation against
            non-copyable protected symbol.
    
    (cherry picked from commit ebb191adac4ab45498dec0bfaac62f0a33537ba4)
Comment 8 H.J. Lu 2022-02-11 18:34:19 UTC
Fixed for 2.39 and 2.38 branch.