Page MenuHomeFreeBSD

Don't allow strong symbols to override weak ones for lookups
Needs ReviewPublic

Authored by i_maskray.me on Sep 7 2020, 5:30 PM.

Details

Summary

The current lookup prefers a strong definition to a STB_WEAK definition (similar to glibc pre-2.2 behavior) which is non-conforming.

The non-compliant behavior provoked https://reviews.llvm.org/D4418 which was intended to fix
-shared-libasan but introduced new problems (and caused some sanitizer tests (e.g. test/asan/TestCases/interception_failure_test.cpp) to fail):
sanitizer interceptors are STB_GLOBAL instead of STB_WEAK, so defining
a second STB_GLOBAL interceptor can lead to a multiple definition linker error.
For example, in a
-fsanitize={address,memory,...} build, libc functions like
malloc/free/strtol/... cannot be provided by user object files.

See https://docs.freebsd.org/cgi/getmsg.cgi?fetch=16483939+0+archive/2014/freebsd-current/20140716.freebsd-current for discussions.

Diff Detail

Lint
Lint Skipped
Unit
Unit Tests Skipped
Build Status
Buildable 33438
Build 30725: arc lint + arc unit

Event Timeline

i_maskray.me edited the summary of this revision. (Show Details)
i_maskray.me edited the summary of this revision. (Show Details)
i_maskray.me edited the summary of this revision. (Show Details)

This breaks FreeBSD. If you look at the deleted block, the deleted comment explains why (and this is only one instance of it, there are more).

In D26352#585872, @kib wrote:

This breaks FreeBSD. If you look at the deleted block, the deleted comment explains why (and this is only one instance of it, there are more).

I can indeed find many instances of Search the dynamic linker itself in the file. Is this unfixable now?

(The special case for the ld-elf.so.1 is strange: in glibc, the dynamic linker needs to be in a DT_NEEDED entry to be searchable, so there is no such special case.)

After make buildworld, how can I rebuild just libexec/rtld-elf? make -C libexec/rtld-elf does not work

% make -C libexec/rtld-elf                                                                                                                       [41/30860]
cc  -O2 -pipe -fno-common   -Wall -DFREEBSD_ELF -DIN_RTLD -ffreestanding -I/usr/home/ray/freebsd/lib/csu/common -I/usr/home/ray/freebsd/libexec/rtld-elf/amd64 
-I/usr/home/ray/freebsd/libexec/rtld-elf -fpic -DPIC  -I/usr/home/ray/freebsd/libexec/rtld-elf/rtld-libc -mno-mmx -mno-sse -mno-avx -mno-avx2 -msoft-float -fvi
sibility=hidden -g -MD  -MF.depend.rtld.o -MTrtld.o -std=gnu99 -Wno-format-zero-length -Wsystem-headers -Werror -Wall -Wno-format-y2k -W -Wno-unused-parameter 
-Wstrict-prototypes -Wmissing-prototypes -Wpointer-arith -Wreturn-type -Wcast-qual -Wwrite-strings -Wswitch -Wshadow -Wunused-parameter -Wchar-subscripts -Winl
ine -Wnested-externs -Wredundant-decls -Wold-style-definition -Wno-pointer-sign -Wformat=2 -Wno-format-extra-args -Werror -Wmissing-variable-declarations -Wthr
ead-safety -Wno-empty-body -Wno-string-plus-int -Wno-unused-const-variable  -Qunused-arguments    -c /usr/home/ray/freebsd/libexec/rtld-elf/rtld.c -o rtld.o   
/usr/home/ray/freebsd/libexec/rtld-elf/rtld.c:450:18: error: use of undeclared identifier 'AT_BSDFLAGS'
    if (aux_info[AT_BSDFLAGS] != NULL &&                                       
                 ^                     
/usr/home/ray/freebsd/libexec/rtld-elf/rtld.c:451:12: error: use of undeclared identifier 'AT_BSDFLAGS'                                                        
        (aux_info[AT_BSDFLAGS]->a_un.a_val & ELF_BSDF_SIGFASTBLK) != 0)        
                  ^                                                            
/usr/home/ray/freebsd/libexec/rtld-elf/rtld.c:451:39: error: use of undeclared identifier 'ELF_BSDF_SIGFASTBLK'                                                
        (aux_info[AT_BSDFLAGS]->a_un.a_val & ELF_BSDF_SIGFASTBLK) != 0)        
                                             ^                                 
/usr/home/ray/freebsd/libexec/rtld-elf/rtld.c:1231:20: error: no member named 'l_refname' in 'struct link_map'; did you mean 'l_name'?                         
                if (obj->linkmap.l_refname == NULL) 
...
In D26352#585872, @kib wrote:

This breaks FreeBSD. If you look at the deleted block, the deleted comment explains why (and this is only one instance of it, there are more).

I can indeed find many instances of Search the dynamic linker itself in the file. Is this unfixable now?

I might have an idea how to handle this, but first I need to evaluate the scope.
Some time ago this quirk was also needed for libc+libthr operations, but I suspect that I fixed all places already while making libthr dlopenable.

(The special case for the ld-elf.so.1 is strange: in glibc, the dynamic linker needs to be in a DT_NEEDED entry to be searchable, so there is no such special case.)

We do not link with ld-elf.so.1, and until recently we do not even have libdl.so.

After make buildworld, how can I rebuild just libexec/rtld-elf? make -C libexec/rtld-elf does not work

% make -C libexec/rtld-elf                                                                                                                       [41/30860]
cc  -O2 -pipe -fno-common   -Wall -DFREEBSD_ELF -DIN_RTLD -ffreestanding -I/usr/home/ray/freebsd/lib/csu/common -I/usr/home/ray/freebsd/libexec/rtld-elf/amd64 
-I/usr/home/ray/freebsd/libexec/rtld-elf -fpic -DPIC  -I/usr/home/ray/freebsd/libexec/rtld-elf/rtld-libc -mno-mmx -mno-sse -mno-avx -mno-avx2 -msoft-float -fvi
sibility=hidden -g -MD  -MF.depend.rtld.o -MTrtld.o -std=gnu99 -Wno-format-zero-length -Wsystem-headers -Werror -Wall -Wno-format-y2k -W -Wno-unused-parameter 
-Wstrict-prototypes -Wmissing-prototypes -Wpointer-arith -Wreturn-type -Wcast-qual -Wwrite-strings -Wswitch -Wshadow -Wunused-parameter -Wchar-subscripts -Winl
ine -Wnested-externs -Wredundant-decls -Wold-style-definition -Wno-pointer-sign -Wformat=2 -Wno-format-extra-args -Werror -Wmissing-variable-declarations -Wthr
ead-safety -Wno-empty-body -Wno-string-plus-int -Wno-unused-const-variable  -Qunused-arguments    -c /usr/home/ray/freebsd/libexec/rtld-elf/rtld.c -o rtld.o   
/usr/home/ray/freebsd/libexec/rtld-elf/rtld.c:450:18: error: use of undeclared identifier 'AT_BSDFLAGS'
    if (aux_info[AT_BSDFLAGS] != NULL &&                                       
                 ^                     
/usr/home/ray/freebsd/libexec/rtld-elf/rtld.c:451:12: error: use of undeclared identifier 'AT_BSDFLAGS'                                                        
        (aux_info[AT_BSDFLAGS]->a_un.a_val & ELF_BSDF_SIGFASTBLK) != 0)        
                  ^                                                            
/usr/home/ray/freebsd/libexec/rtld-elf/rtld.c:451:39: error: use of undeclared identifier 'ELF_BSDF_SIGFASTBLK'                                                
        (aux_info[AT_BSDFLAGS]->a_un.a_val & ELF_BSDF_SIGFASTBLK) != 0)        
                                             ^                                 
/usr/home/ray/freebsd/libexec/rtld-elf/rtld.c:1231:20: error: no member named 'l_refname' in 'struct link_map'; did you mean 'l_name'?                         
                if (obj->linkmap.l_refname == NULL) 
...

You should 'enter the build environment'. Basically you do make buildenv (but care to supply all the same knobs like MAKEOBJDIRPREFIX etc), then you can cd libexec/rtld-elf and do make there. But note the useful hint in the libexec/rtld-elf/Makefile at the beginning.

Fix all STB_WEAK occurrences

Unfortunately this can cause a segfault in a function in libc.so

libexec/rtld-elf/rtld.c
3654

I suggest you to leave this (and all similar 'search the dynamic linker itself') places intact. Basically, the biggest issue I am aware of where FreeBSD depends on the strong override of weak, is rtld export. We provide weak symbols like dlopen exported from libc weak, and rtld links to its own definition of the symbols.

If you leave this chunk as is, rtld export should still work. Then I suspect there is nothing else left that depends on this behavior in the base system.

libexec/rtld-elf/rtld.c
3654

And one more thing. Perhaps, old behavior should not be removed completely. I suggest to add e.g. the variable ${LD}_WEAK_OLD, which if set, restores the old mode of operation where strong overrides weak (feel free to suggest more adequate name).