static binary, dlopen, and ifunc

Samuel Thibault samuel.thibault@gnu.org
Fri Nov 13 00:00:51 GMT 2020


Hello,

I'm having an issue on GNU/Hurd with ifunc when a static binary dlopens
modules (in the inet/tst-idna_name_classify test, more precisely). The
backtrace is as the following:

Program terminated with signal SIGSEGV, Segmentation fault.
    27      static inline void *
    28      IFUNC_SELECTOR (void)
    29      {
    30        const struct cpu_features* cpu_features = __get_cpu_features ();
    31
>>> 32        if (CPU_FEATURE_USABLE_P (cpu_features, SSE2)
    33            && CPU_FEATURES_ARCH_P (cpu_features, Fast_Rep_String))
    34          return OPTIMIZE (sse2);
    35
    36        if (CPU_FEATURE_USABLE_P (cpu_features, SSSE3))

#0  0x0111f610 in stpncpy_ifunc_selector () at ../sysdeps/i386/i686/multiarch/ifunc-sse2-ssse3.h:32
#1  __stpncpy_ifunc () at ../sysdeps/i386/i686/multiarch/stpncpy.c:31
#2  0x080c7fd5 in elf_machine_rel (skip_ifunc=<optimized out>, reloc_addr_arg=<optimized out>, version=<optimized out>, sym=0x132418c, reloc=0x1326898, map=<optimized out>) at ../sysdeps/i386/dl-machine.h:352
#3  elf_dynamic_do_Rel (skip_ifunc=<optimized out>, lazy=<optimized out>, nrelative=<optimized out>, relsize=<optimized out>, reladdr=<optimized out>, map=<optimized out>) at do-rel.h:137
#4  _dl_relocate_object (l=<optimized out>, scope=<optimized out>, reloc_mode=<optimized out>, consider_profiling=<optimized out>) at dl-reloc.c:274
#5  0x080e607e in dl_open_worker (a=0x1001808) at dl-open.c:700
#6  0x0808c8f5 in _dl_catch_exception (exception=0x10017fc, operate=0x80e5e30 <dl_open_worker>, args=0x1001808) at dl-error-skeleton.c:208
#7  0x080e5a95 in _dl_open (file=0x1001f878 "/usr/src/glibc-upstream/build/iconvdata/ISO8859-1.so", mode=-2147483646, caller_dlopen=0x80a6f75 <__gconv_find_shlib+101>, nsid=-2, argc=2, argv=0x1001dd4, env=0x1001de0) at dl-open.c:864
#8  0x080cb885 in do_dlopen (ptr=0x1001960) at dl-libc.c:96
#9  0x0808c8f5 in _dl_catch_exception (exception=0x10018f4, operate=0x80cb850 <do_dlopen>, args=0x1001960) at dl-error-skeleton.c:208
#10 0x0808c985 in _dl_catch_error (objname=0x1001948, errstring=0x100194c, mallocedp=0x1001947, operate=0x80cb850 <do_dlopen>, args=0x1001960) at dl-error-skeleton.c:227
#11 0x080cb8bd in dlerror_run (operate=<optimized out>, args=<optimized out>) at dl-libc.c:46
#12 0x080cbc64 in __libc_dlopen_mode (name=0x1001f878 "/usr/src/glibc-upstream/build/iconvdata/ISO8859-1.so", mode=-2147483646) at dl-libc.c:197
#13 0x080a6f75 in __gconv_find_shlib (name=<optimized out>) at gconv_dl.c:115
#14 0x0809e29c in gen_steps (toset=0x8121930 "INTERNAL", nsteps=0x1001b58, handle=0x1001b5c, fromset=<optimized out>, best=<optimized out>) at gconv_db.c:287
#15 find_derivation (toset=toset@entry=0x8121930 "INTERNAL", toset_expand=0x0, fromset=fromset@entry=0x1001b10 "ISO-8859-1//", fromset_expand=<optimized out>, handle=0x1001b5c, nsteps=0x1001b58) at gconv_db.c:672
#16 0x0809e89c in __gconv_find_transform (toset=0x8121930 "INTERNAL", fromset=0x1001b10 "ISO-8859-1//", handle=0x1001b5c, nsteps=0x1001b58, flags=0) at gconv_db.c:767
#17 0x0807b8a4 in __wcsmbs_getfct (nstepsp=0x10003134, from=0x1001b10 "ISO-8859-1//", to=0x8121930 "INTERNAL") at wcsmbsload.c:186
#18 __wcsmbs_load_conv (new_category=<optimized out>) at wcsmbsload.c:186
#19 0x080bc817 in get_gconv_fcts (data=0x10001570) at ./wcsmbsload.h:74
#20 __mbrtowc (pwc=0x1001c14 L"", s=<optimized out>, n=<optimized out>, ps=0x1001c18) at mbrtowc.c:70
#21 0x0808a052 in __idna_name_classify (name=0x813038d <support_install_prefix> "") at idna_name_classify.c:37
#22 0x080488bb in locale_insensitive_tests () at tst-idna_name_classify.c:27
#23 0x08048b85 in do_test () at tst-idna_name_classify.c:49
#24 0x08049a9a in support_test_main (argc=1, argv=0x1001dd8, config=0x1001ce4) at support_test_main.c:402
#25 0x080486b2 in main (argc=2, argv=0x1001dd4) at ../support/test-driver.c:168

and more precisely:

(gdb) disassemble
Dump of assembler code for function __stpncpy_ifunc:
   0x0111f600 <+0>:       call   0x1218dab <__x86.get_pc_thunk.ax>
   0x0111f605 <+5>:       add    $0x1bb9fb,%eax
   				(R_386_GOTPC  _GLOBAL_OFFSET_TABLE_)
   0x0111f60a <+10>:      mov    -0x148(%eax),%ecx
                                (R_386_GOT32X _rtld_global_ro)
=> 0x0111f610 <+16>:      testb  $0x4,0x7b(%ecx)
[...]
(gdb) p/x $ecx
$3 = 0x0

i.e. _rtld_global_ro is NULL (!?)

Also,
(gdb) info sharedlibrary
From        To          Syms Read   Shared Object Library
0x0105d430  0x0105e254  Yes         /usr/src/glibc-upstream/build/iconvdata/ISO8859-1.so
0x010812c0  0x012421e6  Yes         /usr/src/glibc-upstream/build/libc.so.0.3
0x012e20f0  0x01304753  Yes         /usr/src/glibc-upstream/build/elf/ld.so.1
0x01318990  0x01324a74  Yes         /usr/src/glibc-upstream/build/mach/libmachuser.so.1
0x013356a0  0x01352684  Yes         /usr/src/glibc-upstream/build/hurd/libhurduser.so.0.3

So we have the static binary loaded around 0x080486b2 with its
own static libc, and the dynamic libraries getting loaded around
0x01[0-3]00000. AIUI it's supposed to be supported, but it seems somehow
_rtld_global_ro is not getting relocated, or relocated too late (?)
compared to the elf_machine_rel call that calls the ifunc selectors for
stpncpy? Is there something somewhere that makes sure that symbols are
getting relocated in the proper order or is it working on Linux just by
luck?  Perhaps a missing flag in the GNU/Hurd target host?


It happens that the output of the program is

info: C locale tests
info: en_US.ISO-8859-1 locale tests
tst-idna_name_classify: Relink `/usr/src/glibc-upstream/build/mach/libmachuser.so.1' with `/usr/src/glibc-upstream/build/libc.so.0.3' for IFUNC symbol `__stpncpy'
Segmentation fault

Is that perhaps what triggers the ifunc selection unexpectedly early?
I'm not sure what should be done about this warning actually, since
libmachuser.so was really linked after libc.so:

-rwxr-xr-x 1 samy samy 14511352 2020-11-12 00:59:09.000000000 +0000 libc.so
-rwxr-xr-x 1 samy samy   514352 2020-11-12 00:59:36.000000000 +0000 mach/libmachuser.so
lrwxr-xr-x 1 samy samy       14 2020-11-12 00:59:36.000000000 +0000 mach/libmachuser.so.1 -> libmachuser.so

And yes it has "NEEDED libc.so.0.3", and the link command does explicit
that libc.so, not the system's:

gcc   -shared -static-libgcc -Wl,-O1  -Wl,-z,defs -Wl,-dynamic-linker=/lib/i386-gnu/ld.so.1  -B/usr/src/glibc-upstream/build/csu/   -Wl,-soname=libmachuser.so.1 -Wl,-z,combreloc -Wl,-z,relro -Wl,--hash-style=both   -L/usr/src/glibc-upstream/build -L/usr/src/glibc-upstream/build/math -L/usr/src/glibc-upstream/build/elf -L/usr/src/glibc-upstream/build/dlfcn -L/usr/src/glibc-upstream/build/nss -L/usr/src/glibc-upstream/build/nis -L/usr/src/glibc-upstream/build/rt -L/usr/src/glibc-upstream/build/resolv -L/usr/src/glibc-upstream/build/mathvec -L/usr/src/glibc-upstream/build/support -L/usr/src/glibc-upstream/build/crypt -L/usr/src/glibc-upstream/build/htl -L/usr/src/glibc-upstream/build/mach -L/usr/src/glibc-upstream/build/hurd -Wl,-rpath-link=/usr/src/glibc-upstream/build:/usr/src/glibc-upstream/build/math:/usr/src/glibc-upstream/build/elf:/usr/src/glibc-upstream/build/dlfcn:/usr/src/glibc-upstream/build/nss:/usr/src/glibc-upstream/build/nis:/usr/src/glibc-upstream/build/rt:/usr/src/glibc-upstream/build/resolv:/usr/src/glibc-upstream/build/mathvec:/usr/src/glibc-upstream/build/support:/usr/src/glibc-upstream/build/crypt:/usr/src/glibc-upstream/build/htl:/usr/src/glibc-upstream/build/mach:/usr/src/glibc-upstream/build/hurd -o /usr/src/glibc-upstream/build/mach/libmachuser.so  /usr/src/glibc-upstream/build/csu/abi-note.o -Wl,--whole-archive /usr/src/glibc-upstream/build/mach/libmachuser_pic.a -Wl,--no-whole-archive   -Wl,--start-group /usr/src/glibc-upstream/build/libc.so /usr/src/glibc-upstream/build/libc_nonshared.a -Wl,--as-needed /usr/src/glibc-upstream/build/elf/ld.so -Wl,--no-as-needed -Wl,--end-group


The binaries show

€ objdump -T -R mach/libmachuser.so | grep stpncpy
00000000       F *UND*  00000000              __stpncpy@@GLIBC_2.2.6
00000000      DF *UND*  00000000  GLIBC_2.2.6 __stpncpy
00017020 R_386_JUMP_SLOT   __stpncpy@GLIBC_2.2.6

€ objdump -x -T -R libc.so | grep stpncpy
00000000 l    df *ABS*  00000000              stpncpy.c
000be600 l     F .text  0000003b              __stpncpy_ifunc
00000000 l    df *ABS*  00000000              stpncpy_chk.c
000ceec0 l     F .text  000010e6              __stpncpy_sse2
000d78e0 l     F .text  00000091              __GI___stpncpy
000ca620 l     F .text  00002c6f              __stpncpy_ssse3
000d78e0 l     F .text  00000091              __stpncpy_ia32
000be600 g   i   .text  0000003b              __stpncpy
000be600  w  i   .text  0000003b              stpncpy
0018cf40 g     F .text  00000035              __stpncpy_chk
000be600  w  iD  .text  0000003b  GLIBC_2.2.6 stpncpy
000be600 g   iD  .text  0000003b  GLIBC_2.2.6 __stpncpy
0018cf40 g    DF .text  00000035  GLIBC_2.4   __stpncpy_chk


Any further idea what oddity I should look for?

Samuel


More information about the Libc-alpha mailing list