Bug 20972 - Running libc.so.6 as an executable triggers IFUNC relocation ordering issues
Summary: Running libc.so.6 as an executable triggers IFUNC relocation ordering issues
Status: UNCONFIRMED
Alias: None
Product: glibc
Classification: Unclassified
Component: dynamic-link (show other bugs)
Version: 2.24
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2016-12-15 14:35 UTC by Matej Krizan
Modified: 2019-04-14 11:03 UTC (History)
4 users (show)

See Also:
Host:
Target:
Build:
Last reconfirmed:
fweimer: security-


Attachments
libc output (1.07 KB, text/plain)
2016-12-15 14:35 UTC, Matej Krizan
Details
gdb output (2.43 KB, text/plain)
2016-12-15 14:36 UTC, Matej Krizan
Details
uname output (5.55 KB, text/plain)
2016-12-15 14:36 UTC, Matej Krizan
Details
64bit preload library (108.63 KB, application/x-sharedlib)
2016-12-15 18:26 UTC, Matej Krizan
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Matej Krizan 2016-12-15 14:35:22 UTC
Created attachment 9700 [details]
libc output

I have a problem with latest glibc 2.24 and our on-access preload library on 64bit Fedora 25 (the same also with glibc 2.17 on CentOS 7 and on 32bit archs). It seems, that the dynamic linker is crashing with SIGSEGV while preloading libesets_pac.so when libc.so is started as a normal program:

LD_DEBUG=all LD_PRELOAD=./libesets_pac.so /lib64/libc-2.24.so > libc.txt 2>&1

I got a populated backtrace only when attaching gdb to the shell and following forked child:

#0  0x00005623257aa717 in _dl_vdso_vsym (
    name=name@entry=0x5623257efce1 "__vdso_gettimeofday", 
    vers=vers@entry=0x7ffe43447760) at ../sysdeps/unix/sysv/linux/dl-vdso.c:27
#1  0x0000562325720ec7 in __gettimeofday ()
    at ../sysdeps/unix/sysv/linux/x86/gettimeofday.c:40
#2  0x00007fdb915f8f50 in elf_machine_rela (skip_ifunc=<optimized out>, 
    reloc_addr_arg=<optimized out>, version=<optimized out>, 
    sym=<optimized out>, reloc=0x7fdb913d2de8, map=0x7fdb9180fbb0)
    at ../sysdeps/x86_64/dl-machine.h:314
#3  elf_dynamic_do_Rela (skip_ifunc=<optimized out>, lazy=<optimized out>, 
    nrelative=<optimized out>, relsize=<optimized out>, 
    reladdr=<optimized out>, map=0x7fdb9180fbb0) at do-rel.h:137
#4  _dl_relocate_object (scope=<optimized out>, reloc_mode=<optimized out>, 
    consider_profiling=<optimized out>, consider_profiling@entry=0)
    at dl-reloc.c:259
#5  0x00007fdb915f0051 in dl_main (phdr=<optimized out>, 
    phnum=<optimized out>, user_entry=<optimized out>, auxv=<optimized out>)
    at rtld.c:2066
#6  0x00007fdb9160591f in _dl_sysdep_start (
    start_argptr=start_argptr@entry=0x7ffe43447b20, 
    dl_main=dl_main@entry=0x7fdb915ed9a0 <dl_main>) at ../elf/dl-sysdep.c:249
#7  0x00007fdb915f0f68 in _dl_start_final (arg=0x7ffe43447b20) at rtld.c:305
#8  _dl_start (arg=0x7ffe43447b20) at rtld.c:411
#9  0x00007fdb915eccd8 in _start () from /lib64/ld-linux-x86-64.so.2
#10 0x0000000000000001 in ?? ()
#11 0x00007ffe434493a3 in ?? ()
#12 0x0000000000000000 in ?? ()

However, no crash when running any other dynamically linked program (you have to create an empty file /opt/eset/esets/sbin/esets_daemon first), e.g.:

LD_DEBUG=all LD_PRELOAD=./libesets_pac.so /bin/uname -r > uname.txt 2>&1

Full details and outputs attached. Our preload library is built on Debian 4.0 for compatibility reasons.

Does someone know what's going on there?
Comment 1 Matej Krizan 2016-12-15 14:36:06 UTC
Created attachment 9701 [details]
gdb output
Comment 2 Matej Krizan 2016-12-15 14:36:31 UTC
Created attachment 9702 [details]
uname output
Comment 3 Matej Krizan 2016-12-15 18:26:58 UTC
Created attachment 9704 [details]
64bit preload library

From the 4.0.82.0 package https://download.eset.com/com/eset/apps/home/eav/linux/latest/eset_nod32av_64bit_en.linux
Comment 4 Florian Weimer 2017-01-26 16:35:08 UTC
Dependency sorting always puts the main executable first, under the assumption that nothing can have a DT_NEEDED dependency on it.

When libc.so.6 is executed as an executable, it takes that position, rather than its usual position in the dependency order.

Relocation of objects precedes in a depth-first order.  This means that libpthread.so.0 is relocated before the main executable (libc.so.6 in this case).

Relocation processing for the __gettimeofday symbol reference in libpthread.so.0 calls the IFUNC resolver for this symbol in libc.so.6.

However, libc.so.6 has not been relocated at this point, and the reference to _rtld_global_ro (behind the GLRO macro) is undefined.

So in short, this is another IFUNC ordering issue.  The good news is that this particular one can only happen if libc.so.6 is the main executable.  Otherwise, libc.so.6 is relocated before libpthread.so.0.

Shorter reproducer:

LD_PRELOAD=/lib64/libpthread.so.0 /lib64/libc.so.6
Comment 5 Carlos O'Donell 2017-01-26 16:57:48 UTC
(In reply to Florian Weimer from comment #4)
> Dependency sorting always puts the main executable first, under the
> assumption that nothing can have a DT_NEEDED dependency on it.
> 
> When libc.so.6 is executed as an executable, it takes that position, rather
> than its usual position in the dependency order.
> 
> Relocation of objects precedes in a depth-first order.  This means that
> libpthread.so.0 is relocated before the main executable (libc.so.6 in this
> case).
> 
> Relocation processing for the __gettimeofday symbol reference in
> libpthread.so.0 calls the IFUNC resolver for this symbol in libc.so.6.
> 
> However, libc.so.6 has not been relocated at this point, and the reference
> to _rtld_global_ro (behind the GLRO macro) is undefined.
> 
> So in short, this is another IFUNC ordering issue.  The good news is that
> this particular one can only happen if libc.so.6 is the main executable. 
> Otherwise, libc.so.6 is relocated before libpthread.so.0.
> 
> Shorter reproducer:
> 
> LD_PRELOAD=/lib64/libpthread.so.0 /lib64/libc.so.6

The libesets_pac.so is preloaded and needs to have all of it's dependencies initialized first. I think it's a dynamic loader bug that all the DT_NEEDED of the preloaded DSO are not initialized first.

Though I agree this is a corner case, but one which we could fix with proper dependency handling.
Comment 6 Matej Krizan 2017-02-08 07:16:21 UTC
Ok, thank you very much for the investigation.