This is the mail archive of the glibc-bugs@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[Bug dynamic-link/20105] New: bad version variable in elf_dynamic_do_Rel() elf/do-rel.h (2.23) causes coredump in dl-machine.h elf_machine_rela()


https://sourceware.org/bugzilla/show_bug.cgi?id=20105

            Bug ID: 20105
           Summary: bad version variable in elf_dynamic_do_Rel()
                    elf/do-rel.h (2.23) causes coredump in dl-machine.h
                    elf_machine_rela()
           Product: glibc
           Version: 2.23
            Status: UNCONFIRMED
          Severity: normal
          Priority: P2
         Component: dynamic-link
          Assignee: unassigned at sourceware dot org
          Reporter: jason.vas.dias at gmail dot com
  Target Milestone: ---

Having built the latest publicly available git tag of the glibc GIT:
git://sourceware.org/git/glibc.git
( latest tag as of writing (2016-05-18) is 'glibc-2.23' )
on a Linux (LFS 7.9+) x86_64 (4-core 4th. gen Intel i7) machine,
both for -m64 (/usr/lib64) and -m32 (/usr/lib32), 
running linux kernel 4.5.0, with binutils-2.26.20160125 ,
I generally experienced no problems for a month or so, 
but now I tried to run some freeware (OpenOffice-4.1.2) 
and it is having problems dynamically loading its copy
of 'libfwk.so*' with dlopen() - glibc suffers a core dump 
during dlopen() because it gets an incorrect address for the 
'version' variable in do-rel.h :
elf/do-rel.h line 121:

          const ElfW(Half) *const version =
            (const void *) D_PTR (map, l_info[VERSYMIDX (DT_VERSYM)]);

Now, during the load initiated by the command:
 $ LD_LIBRARY_PATH=${OOO_HOME} ${OOO_HOME}/soffice.bin
this core dump occurs:
 $ echo 'run
info reg
disass/sr
' > /tmp/gdb.cmds
 $ LD_LIBRARY_PATH=${OOO_HOME} gdb \
   -x /tmp/gdb.cmds--args \
   ${OOO_HOME}/soffice.bin -writer
 ... # ( here is selected output showing core dump info :
[New Thread 0x7fffeba9b700 (LWP 8471)]
[New Thread 0x7fffe6d1c700 (LWP 8472)]
[New Thread 0x7fffe651b700 (LWP 8473)]

Thread 1 "soffice.bin" received signal SIGSEGV, Segmentation fault.
0x00007ffff7de5812 in elf_machine_rela (skip_ifunc=0,
reloc_addr_arg=0x7fffea23a460, version=0x48, sym=0x7fffe9f31a98,
reloc=0x7fffe9f45fb0, map=0x61b660) at ../sysdeps/x86_64/dl-machine.h:301
301           struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
...
# important registers:
r8             0x48     72
rip            0x00007ffff7de5812
# Dissassmbly of coredump point :
301           struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
   0x00007ffff7de5789 <+1113>:  41 0f b6 46 04  movzbl 0x4(%r14),%eax
   0x00007ffff7de578e <+1118>:  c0 e8 04        shr    $0x4,%al
   0x00007ffff7de5791 <+1121>:  0f 84 a9 03 00 00       je     0x7ffff7de5b40
<_dl_relocate_object+2064>
   0x00007ffff7de5797 <+1127>:  4d 3b b4 24 f8 03 00 00 cmp    0x3f8(%r12),%r14
   0x00007ffff7de579f <+1135>:  0f 84 ab 06 00 00       je     0x7ffff7de5e50
<_dl_relocate_object+2848>
   0x00007ffff7de57a5 <+1141>:  49 83 fd 07     cmp    $0x7,%r13
   0x00007ffff7de57a9 <+1145>:  0f 84 b1 03 00 00       je     0x7ffff7de5b60
<_dl_relocate_object+2096>
   0x00007ffff7de57af <+1151>:  49 83 fd 10     cmp    $0x10,%r13
   0x00007ffff7de57b3 <+1155>:  0f 84 a7 03 00 00       je     0x7ffff7de5b60
<_dl_relocate_object+2096>
   0x00007ffff7de57b9 <+1161>:  49 8d 45 ef     lea    -0x11(%r13),%rax
   0x00007ffff7de57bd <+1165>:  48 83 f8 01     cmp    $0x1,%rax
   0x00007ffff7de57c1 <+1169>:  41 0f 96 c1     setbe  %r9b
   0x00007ffff7de57c5 <+1173>:  49 83 fd 24     cmp    $0x24,%r13
   0x00007ffff7de57c9 <+1177>:  0f 94 c0        sete   %al
   0x00007ffff7de57cc <+1180>:  41 09 c1        or     %eax,%r9d
   0x00007ffff7de57cf <+1183>:  41 0f b6 c1     movzbl %r9b,%eax
   0x00007ffff7de57d3 <+1187>:  49 83 fd 05     cmp    $0x5,%r13
   0x00007ffff7de57d7 <+1191>:  0f 84 92 03 00 00       je     0x7ffff7de5b6f
<_dl_relocate_object+2111>
   0x00007ffff7de57dd <+1197>:  45 31 c9        xor    %r9d,%r9d
   0x00007ffff7de57e0 <+1200>:  49 83 fd 06     cmp    $0x6,%r13
   0x00007ffff7de57e4 <+1204>:  41 0f 94 c1     sete   %r9b
   0x00007ffff7de57e8 <+1208>:  41 c1 e1 02     shl    $0x2,%r9d

do-rel.h:
137                   elf_machine_rel (map, r, &symtab[ELFW(R_SYM)
(r->r_info)],
   0x00007ffff7de57ec <+1212>:  81 e2 ff 7f 00 00       and    $0x7fff,%edx

../sysdeps/x86_64/dl-machine.h:
301           struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
   0x00007ffff7de57f2 <+1218>:  41 09 c1        or     %eax,%r9d
   0x00007ffff7de57f5 <+1221>:  4d 89 b4 24 f8 03 00 00 mov    %r14,0x3f8(%r12)

do-rel.h:
137                   elf_machine_rel (map, r, &symtab[ELFW(R_SYM)
(r->r_info)],
   0x00007ffff7de57fd <+1229>:  48 8d 14 52     lea    (%rdx,%rdx,2),%rdx

../sysdeps/x86_64/dl-machine.h:
301           struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
   0x00007ffff7de5801 <+1233>:  45 89 8c 24 00 04 00 00 mov    %r9d,0x400(%r12)

do-rel.h:
137                   elf_machine_rel (map, r, &symtab[ELFW(R_SYM)
(r->r_info)],
   0x00007ffff7de5809 <+1241>:  4c 8d 04 d6     lea    (%rsi,%rdx,8),%r8

../sysdeps/x86_64/dl-machine.h:
301           struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
   0x00007ffff7de580d <+1245>:  4d 85 c0        test   %r8,%r8
   0x00007ffff7de5810 <+1248>:  74 0f   je     0x7ffff7de5821
<_dl_relocate_object+1265>
=> 0x00007ffff7de5812 <+1250>:  41 8b 40 08     mov    0x8(%r8),%eax
# info scope 0x00007ffff7de5812 showing variable in %r8 (whose address has
# value 0x48) :
Symbol v is multi-location:
  Range 0x7ffff7de57fd-0x7ffff7de584e: the constant 0
  Range 0x7ffff7de584e-0x7ffff7de5852: a variable in $r8
, length 8.

'v' is the value of the version value parameter set in do-rel.h , as 
shown in the pre-processed dl-reloc.c output :
# 283 "../sysdeps/x86_64/dl-machine.h"
 *reloc_addr = map->l_addr + reloc->r_addend;
    }
  else
  if (__builtin_expect ((r_type == 38), 0))
    *(Elf64_Addr *) reloc_addr = (Elf64_Addr) map->l_addr + reloc->r_addend;
  else

  if (__builtin_expect ((r_type == 0), 0))
    return;
  else
    {

      const Elf64_Sym *const refsym = sym;

      struct link_map *sym_map = ((((unsigned char) ((*&sym)->st_info)) >> 4)
!= 0 ? ((__builtin_expect ((*&sym) == l->l_lookup_cache.sym, 0) && ((((r_type)
== 7 || (r_type) == 16 || (r_type) == 17 || (r_type) == 18 || (r_type) == 36) *
1) | (((r_type) == 5) * 2) | (((r_type) == 6) * 4)) ==
l->l_lookup_cache.type_class) ? (++_rtld_global._dl_num_cache_relocations,
(*&sym) = l->l_lookup_cache.ret, l->l_lookup_cache.value) : ({ lookup_t _lr;
int _tc = ((((r_type) == 7 || (r_type) == 16 || (r_type) == 17 || (r_type) ==
18 || (r_type) == 36) * 1) | (((r_type) == 5) * 2) | (((r_type) == 6) * 4));
l->l_lookup_cache.type_class = _tc; l->l_lookup_cache.sym = (*&sym); const
struct r_found_version *v = 
# 301 "../sysdeps/x86_64/dl-machine.h" 3 4
# 301 "../sysdeps/x86_64/dl-machine.h"
                                ; if ((version) != 
# 301 "../sysdeps/x86_64/dl-machine.h" 3 4
                                ((void *)0) 
# 301 "../sysdeps/x86_64/dl-machine.h"
                                && (version)->hash != 0) v = (version);

Now 'version' is the parameter to the elf_machine_rela call made by
do-rel.h:

#ifdef RTLD_BOOTSTRAP
      /* The dynamic linker always uses versioning.  */
      assert (map->l_info[VERSYMIDX (DT_VERSYM)] != NULL);
#else
      if (map->l_info[VERSYMIDX (DT_VERSYM)])
#endif
        {
          const ElfW(Half) *const version =
            (const void *) D_PTR (map, l_info[VERSYMIDX (DT_VERSYM)]);

          for (; r < end; ++r)
            {
#if defined ELF_MACHINE_IRELATIVE && !defined RTLD_BOOTSTRAP
              if (ELFW(R_TYPE) (r->r_info) == ELF_MACHINE_IRELATIVE)
                {
                  if (r2 == NULL)
                    r2 = r;
                  end2 = r;
                  continue;
                }
#endif

              ElfW(Half) ndx = version[ELFW(R_SYM) (r->r_info)] & 0x7fff;
              elf_machine_rel (map, r, &symtab[ELFW(R_SYM) (r->r_info)],
                               &map->l_versions[ndx],
                               (void *) (l_addr + r->r_offset), skip_ifunc);
            }


So the expression &map->l_versions[ndx] has value 0x48 but is dereferenced
as a pointer by elf_machine_rela() .

Please can we modify the expression above so that is
it something like :

              elf_machine_rel (map, r, &symtab[ELFW(R_SYM) (r->r_info)],
                               is_sane_version_pointer(&map->l_versions[ndx])
                               ? (void *) &map->l_versions[ndx] : ((void*)0UL)
                               , (void *) (l_addr + r->r_offset), skip_ifunc); 

What should 'is_sane_version_pointer(p,map)' test for ?  
(p >= (&map)->l_versions[0]) perhaps? 

This problem does not occur when running the same freeware binaries in a RHEL7 
(glibc 2.17) binary distribution system - I believe glibc-2.23 would 
eventually complain about library version mismatches when those same 
binaries are loaded, but coredumps before getting to that point .
It would be nice if glibc could help debug the problem rather than 
coredump in this case - I'll try implementing the above patch with :

#define is_sane_version_pointer(p,map) \
  ( ((map)->l_version != (void*)0)
  && ((p) >= &((map)->l_version[0])
  )

re-building, and see what happens.

-- 
You are receiving this mail because:
You are on the CC list for the bug.

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]