[PATCH] BZ #14831: Segfault in _dl_profile_fixup with IRELATIVE and LD_AUDIT

H.J. Lu hjl.tools@gmail.com
Wed Nov 14 17:40:00 GMT 2012


On Tue, Nov 13, 2012 at 6:37 PM, H.J. Lu <hjl.tools@gmail.com> wrote:
> On Tue, Nov 13, 2012 at 4:50 PM, H.J. Lu <hjl.tools@gmail.com> wrote:
>> On Tue, Nov 13, 2012 at 4:26 PM, Roland McGrath <roland@hack.frob.com> wrote:
>>>> +  if (l->l_reloc_result == NULL)
>>>> +    {
>>>> +      /* Skip audit if l_reloc_result is NULL which happens with
>>>> +      IRELATIVE relocations in other DSOs, like libm.so.  */
>>>> +      *framesizep = -1;
>>>
>>> This needs a more extensive comment about how it arises that we get here
>>> with l_reloc_result NULL and why it is OK to short-circuit this way.
>>
>> R_X86_IRELATIVE lazy relocation in libm.so leads to:
>>
>> 00042010  00000507 R_386_JUMP_SLOT   00000000   __get_cpu_features
>>
>> But __get_cpu_features isn't set up yet and requires a lazy relocation.
>> That is why  l_reloc_result is NULL.  We don't want audit in R_X86_IRELATIVE
>> relocations.  What is what my patch does.
>>
>>>> +      return _dl_fixup (l, reloc_arg);
>>>
>>> How can this be right when ELF_MACHINE_RUNTIME_FIXUP_ARGS is nonempty?
>>>
>>
>> My post has
>>
>> ---
>> Targets which define ELF_MACHINE_RUNTIME_FIXUP_ARGS must find a way
>> to pass ELF_MACHINE_RUNTIME_FIXUP_ARGS from _dl_fixup/_dl_profile_fixup
>> to _dl_runtime_fixup.
>> ---
>>
>> Only
>>
>> ports/sysdeps/m68k/dl-machine.h:#define ELF_MACHINE_RUNTIME_FIXUP_ARGS
>> long int save_a0, long int save_a1
>> sysdeps/sh/dl-machine.h:#define ELF_MACHINE_RUNTIME_FIXUP_ARGS int plt_type
>>
>> I can work with sh and m68k maintainers on a solution. It shouldn't be
>> too hard.
>
> Here is the updated patch.
>
>

Here is what happened:


(gdb) bt
#0  _dl_profile_fixup (l=0x7ffff7ff6908, reloc_arg=4, retaddr=140737342864537,
    regs=0x7fffffffd8b0, framesizep=0x7fffffffdc08) at ../elf/dl-runtime.c:191
#1  0x00007ffff7df01e6 in _dl_runtime_profile ()
    at ../sysdeps/x86_64/dl-trampoline.h:48
#2  0x00007ffff753fc99 in ?? ()
#3  0x00007fffffffdd50 in ?? ()
#4  0x00007ffff7de6f41 in elf_machine_lazy_rel (skip_ifunc=<optimized out>,
    reloc=0x7ffff7535110, l_addr=140737342799872, map=0x7ffff7ff6908)
    at ../sysdeps/x86_64/dl-machine.h:511
#5  elf_dynamic_do_Rela (skip_ifunc=<optimized out>, lazy=<optimized out>,
    nrelative=<optimized out>, relsize=<optimized out>,
    reladdr=<optimized out>, map=0x7ffff7ff6908) at do-rel.h:77
#6  _dl_relocate_object (scope=0x7ffff7ff6c60, reloc_mode=<optimized out>,
    consider_profiling=1, consider_profiling@entry=0) at dl-reloc.c:265
#7  0x00007ffff7ddfaa2 in dl_main (phdr=<optimized out>, phnum=4160718464,
    user_entry=<optimized out>, auxv=0x7ffff7ffe101 <cache_new+1>)
    at rtld.c:2203
#8  0x00007ffff7df0f7e in _dl_sysdep_start (
    start_argptr=start_argptr@entry=0x7fffffffdf50,
    dl_main=dl_main@entry=0x7ffff7ddda40 <dl_main>) at ../elf/dl-sysdep.c:241
#9  0x00007ffff7de0ce6 in _dl_start_final (arg=0x7fffffffdf50) at rtld.c:331
#10 _dl_start (arg=0x7fffffffdf50) at rtld.c:557
#11 0x00007ffff7ddd508 in _start ()
---Type <return> to continue, or q <return> to quit---
   from /export/build/gnu/glibc-test/build-x86_64-linux/elf/ld.so
#12 0x0000000000000001 in ?? ()
#13 0x00007fffffffe262 in ?? ()
#14 0x0000000000000000 in ?? ()
(gdb) f 6
#6  _dl_relocate_object (scope=0x7ffff7ff6c60, reloc_mode=<optimized out>,
    consider_profiling=1, consider_profiling@entry=0) at dl-reloc.c:265
265	    ELF_DYNAMIC_RELOCATE (l, lazy, consider_profiling, skip_ifunc);
(gdb) f 4
#4  0x00007ffff7de6f41 in elf_machine_lazy_rel (skip_ifunc=<optimized out>,
    reloc=0x7ffff7535110, l_addr=140737342799872, map=0x7ffff7ff6908)
    at ../sysdeps/x86_64/dl-machine.h:511
511		value = ((ElfW(Addr) (*) (void)) value) ();
(gdb)

We have

    ELF_DYNAMIC_RELOCATE (l, lazy, consider_profiling, skip_ifunc);

#ifndef PROF
    if (__builtin_expect (consider_profiling, 0))
      {
        /* Allocate the array which will contain the already found
           relocations.  If the shared object lacks a PLT (for example
           if it only contains lead function) the l_info[DT_PLTRELSZ]
           will be NULL.  */
        if (l->l_info[DT_PLTRELSZ] == NULL)
          {
            errstring = N_("%s: no PLTREL found in object %s\n");
          fatal:
            _dl_fatal_printf (errstring,
                              rtld_progname ?: "<program name unknown>",
                              l->l_name);
          }

        l->l_reloc_result = calloc (sizeof (l->l_reloc_result[0]),
                                    l->l_info[DT_PLTRELSZ]->d_un.d_val);
        if (l->l_reloc_result == NULL)
          {
            errstring = N_("\
%s: out of memory to store relocation results for %s\n");
            goto fatal;
          }
      }
#endif
  }

ld.so crashes because IRELATIVE relocation invokes another relocation
before l_reloc_result is allocated. My patch simply avoids it.  Here is
the patch with updated comments.  OK to install?

Thanks.


-- 
H.J.
---
2012-11-13  H.J. Lu  <hongjiu.lu@intel.com>

	[BZ #14831]
	* elf/Makefile (tests): Add tst-audit8.
	($(objpfx)tst-audit8): Also depend on $(common-objpfx)math/libm.so.
	($(objpfx)tst-audit8.out): New target.
	(tst-audit8-ENV): New variable.
	* elf/dl-runtime.c (_dl_profile_fixup): Call _dl_fixup to skip
	audit if l_reloc_result is NULL.
	(ELF_MACHINE_RUNTIME_FIXUP_PARAMS): Issue an error if it isn't
	defined and ELF_MACHINE_RUNTIME_FIXUP_ARGS is defined.
	* elf/tst-audit8.c: New file.

diff --git a/elf/Makefile b/elf/Makefile
index dc00f9b..369a3f6 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -142,7 +142,7 @@ tests += loadtest restest1 preloadtest loadfail
multiload origtest resolvfail \
 	 tst-dlmodcount tst-dlopenrpath tst-deep1 \
 	 tst-dlmopen1 tst-dlmopen2 tst-dlmopen3 \
 	 unload3 unload4 unload5 unload6 unload7 unload8 tst-global1 order2 \
-	 tst-audit1 tst-audit2 \
+	 tst-audit1 tst-audit2 tst-audit8 \
 	 tst-stackguard1 tst-addr1 tst-thrlock \
 	 tst-unique1 tst-unique2 tst-unique3 tst-unique4 \
 	 tst-initorder tst-initorder2 tst-relsort1
@@ -1019,6 +1019,10 @@ $(objpfx)tst-audit7: $(objpfx)tst-auditmod7a.so
 $(objpfx)tst-audit7.out: $(objpfx)tst-auditmod7b.so
 tst-audit7-ENV = LD_AUDIT=$(objpfx)tst-auditmod7b.so

+$(objpfx)tst-audit8: $(common-objpfx)math/libm.so
+$(objpfx)tst-audit8.out: $(objpfx)tst-auditmod1.so
+tst-audit8-ENV = LD_AUDIT=$(objpfx)tst-auditmod1.so
+
 $(objpfx)tst-global1: $(libdl)
 $(objpfx)tst-global1.out: $(objpfx)testobj6.so $(objpfx)testobj2.so

diff --git a/elf/dl-runtime.c b/elf/dl-runtime.c
index 2e02a21..c4c57c2 100644
--- a/elf/dl-runtime.c
+++ b/elf/dl-runtime.c
@@ -164,6 +164,25 @@ _dl_profile_fixup (
 {
   void (*mcount_fct) (ElfW(Addr), ElfW(Addr)) = INTUSE(_dl_mcount);

+  if (l->l_reloc_result == NULL)
+    {
+      /* Resolve an IRELATIVE relocation in another DSO may reference a
+	 function defined in libc.so before l_reloc_result is allocated.
+	 For example, __get_cpu_features in libc.so is called to resolve
+	 R_X86_64_IRELATIVE relocations in x86-64 libm.so.  Skip audit and
+	 resolve the function in this case.  It is OK since we aren't
+	 supposed to audit IRELATIVE relocations.  */
+      *framesizep = -1;
+      return _dl_fixup (
+# ifdef ELF_MACHINE_RUNTIME_FIXUP_ARGS
+#  ifndef ELF_MACHINE_RUNTIME_FIXUP_PARAMS
+#   error Please define ELF_MACHINE_RUNTIME_FIXUP_PARAMS.
+#  endif
+			ELF_MACHINE_RUNTIME_FIXUP_PARAMS,
+# endif
+			l, reloc_arg);
+    }
+
   /* This is the address in the array where we store the result of previous
      relocations.  */
   struct reloc_result *reloc_result = &l->l_reloc_result[reloc_index];



More information about the Libc-alpha mailing list