This is the mail archive of the libc-help@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]

Re: sigsegv dereferencing l_addr in link_map



On 11/06/2016 19:12, Carlo Kok wrote:
> On some (ubuntu 14.04.4, libc 2.19-0ubuntu6.9) systems I'm getting a sigsegv when casting the link_map's l_addr to Elf64_Ehdr. This is something libgc does and works fine on most linux systems, but not all.
> 
> What am I missing here, and if this isn't guaranteed to work, how else can I get all the loaded data segments.

Because _DYNAMIC is not an Elf64_Ehdr on all architectures.  It is defined as:

elf/link.h

 28 /* We use this macro to refer to ELF types independent of the native wordsize.
 29    `ElfW(TYPE)' is used in place of `Elf32_TYPE' or `Elf64_TYPE'.  */
 30 #define ElfW(type)      _ElfW (Elf, __ELF_NATIVE_CLASS, type)
 31 #define _ElfW(e,w,t)    _ElfW_1 (e, w, _##t)
 32 #define _ElfW_1(e,w,t)  e##w##t
 [...]
 76 extern ElfW(Dyn) _DYNAMIC[];

bits/elfclass.h

 11 #define __ELF_NATIVE_CLASS __WORDSIZE

So you need to use:

# pragma weak _DYNAMIC
extern ElfW(Dyn) _Dynamic[]

Such as:

--
#include <link.h>
#include <stdio.h>

#pragma weak _DYNAMIC
extern ElfW(Dyn) _DYNAMIC[];

int
main ()
{
  int tag;
  ElfW(Dyn) *dp;
  struct link_map *cachedResult;
  for (dp = _DYNAMIC; (tag = dp->d_tag) != 0; dp++)
    {
      if (tag == DT_DEBUG)
        {
          struct link_map *lm = ((struct r_debug *) (dp->d_un.d_ptr))->r_map;
          if (lm != 0)
            cachedResult = lm->l_next;  /* might be NULL */
          break;
        }
    }
  printf ("%p cached result; %p dyn \n", (void*)cachedResult, (void*)dp->d_un.d_ptr);
  while (cachedResult)
    {
      printf ("%p %p %s\n", (void*)cachedResult->l_addr, cachedResult->l_ld,
              cachedResult->l_name);
      ElfW(Ehdr) *e = (ElfW(Ehdr)*) cachedResult->l_addr;
      printf ("machine: %d\n", e->e_machine);   // CRASH here, first iteration.

      cachedResult = cachedResult->l_next;
    }
  return 0;
}
--

$ gcc -Wall test.c -m32 -o test-m32
$ ./test-m32 
0xf77a0c08 cached result; 0xf77a0904 dyn 
0xf777b000 0xf777b2bc 
machine: 3
0xf759c000 0xf774ddb0 /lib/i386-linux-gnu/libc.so.6
machine: 3
0xf777c000 0xf779ff3c /lib/ld-linux.so.2
machine: 3
$ gcc -Wall test.c -m64 -o test-m64
$ ./test-m64
0x7fc40653e700 cached result; 0x7fc40653e140 dyn 
0x7ffd2409c000 0x7ffd2409c360 
machine: 62
0x7fc405f4e000 0x7fc406310ba0 /lib/x86_64-linux-gnu/libc.so.6
machine: 62
0x7fc406317000 0x7fc40653ce70 /lib64/ld-linux-x86-64.so.2
machine: 62

> Code like this shows it:
> 
> #include <link.h>
> #include <stdio.h>
> 
> # pragma weak _DYNAMIC
> extern Elf64_Dyn _DYNAMIC[];
> 
> int main() {
>   int tag;
>   Elf64_Dyn* dp;
>   struct link_map* cachedResult;
>   for( dp = _DYNAMIC; (tag = dp->d_tag) != 0; dp++ ) {
>     if( tag == DT_DEBUG ) {
>        struct link_map *lm = ((struct r_debug *)(dp->d_un.d_ptr))->r_map;
>        if( lm != 0 ) cachedResult = lm->l_next; /* might be NULL */
>           break;
>      }
>   }
>   printf("%p cached result; %p dyn \n", cachedResult, dp->d_un.d_ptr);
>   while(cachedResult) {
>     printf("%p %p %s\n", cachedResult->l_addr, cachedResult->l_ld, cachedResult->l_name);
>         Elf64_Ehdr* e = (Elf64_Ehdr *)cachedResult->l_addr;
>         printf("machine: %d\n", e->e_machine); // CRASH here, first iteration.
> 
>     cachedResult = cachedResult->l_next;
>   }
>   return 0;
> }
> 


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