Fix dl-addr to ensure the address falls in one of the loaded segments

classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

Fix dl-addr to ensure the address falls in one of the loaded segments

Suzuki Poulose
Hi,


We encountered a problem with dl-addr which would return incorrect
results for an address lookup.

The problem occurs when a library (say libA) is mapped (by glibc) in the
space between two loaded segments of an already mapped library ( we have
seen this library is most of the time ld-linux.so). In this case we have,

LD.SO.l_map_start < LIBA.l_map_start < LIBA.l_map_end < LD.SO.l_map_end


So while looking up an address in LIBA, we get the result as LD.SO which
confuses the caller.

This is due to the following bug in the dl-addr logic:

1) We find a link_map whose [l_map_start,l_map_end) encloses the address.

2) We consult only the *LAST* loaded segment of the lib to check if the
address lies beyond the segment's end address.

So, if the ld.so is consulted before libA, we end up in returning ld.so
as the result.

The proper fix here would be to make sure that the address *falls in*
_any_ of the segments of the library.

Attached here is a patch which we have tested and verified to work.

Please let us know your thoughts about the patch.

If it looks good, please apply.


Thanks

Suzuki K P
Linux Technology Center
IBM









elf/dl-addr.c : _dl_addr() : Fix dl-addr to ensure the address falls in one of the loaded segments of the library.

        If a library gets mapped in the space between the segments of an already loaded lib (mostly, ld.so ), dl-addr will not return the proper results for address lookups, in our library. We check each segment of the library to make sure the address falls in the library.


Index: libc/elf/dl-addr.c
===================================================================
--- libc.orig/elf/dl-addr.c 2006-10-27 16:11:41.000000000 -0700
+++ libc/elf/dl-addr.c 2007-03-01 10:39:10.000000000 -0800
@@ -28,6 +28,7 @@
   struct link_map **mapp, const ElfW(Sym) **symbolp)
 {
   const ElfW(Addr) addr = DL_LOOKUP_ADDRESS (address);
+  int result = 0;
 
   /* Protect against concurrent loads and unloads.  */
   __rtld_lock_lock_recursive (GL(dl_load_lock));
@@ -39,24 +40,26 @@
       if (addr >= l->l_map_start && addr < l->l_map_end)
  {
   /* We know ADDRESS lies within L if in any shared object.
-     Make sure it isn't past the end of L's segments.  */
-  size_t n = l->l_phnum;
-  if (n > 0)
+     Make sure it lies within one of L's segments.  */
+  int n = l->l_phnum;
+  while (--n >= 0)
     {
-      do
- --n;
-      while (l->l_phdr[n].p_type != PT_LOAD);
-      if (addr >= (l->l_addr +
-   l->l_phdr[n].p_vaddr + l->l_phdr[n].p_memsz))
- /* Off the end of the highest-addressed shared object.  */
+      if (l->l_phdr[n].p_type != PT_LOAD)
  continue;
+      if ((addr >= l->l_addr +
+   l->l_phdr[n].p_vaddr) &&
+  (addr < l->l_addr +
+  l->l_phdr[n].p_vaddr + l->l_phdr[n].p_memsz))
+ {
+  match = l;
+  goto found_match;
+ }
     }
 
-  match = l;
-  break;
  }
 
-  int result = 0;
+found_match:
+
   if (match != NULL)
     {
       /* Now we know what object the address lies in.  */
Reply | Threaded
Open this post in threaded view
|

Re: Fix dl-addr to ensure the address falls in one of the loaded segments

Ulrich Drepper
suzuki wrote:
> Hi,
> The problem occurs when a library (say libA) is mapped (by glibc) in the
> space between two loaded segments of an already mapped library ( we have
> seen this library is most of the time ld-linux.so).

There are only two objects which have that problem: ld.so and the
application binary itself.

The problem is that kernel which does not fill the gap when loading
ld.so.  I've complained about this many times but nothing happens.

Your proposed change does not address the fact that other code could
also depend on the address space range being used for one purpose.  It's
only dladdr which is changed.

An alternative fix would be to fill in the gaps in ld.so after startup.
   This means two extra syscalls for all processes and only for the odd
chance that somebody requests addresses.

I have to think about it.

--
➧ Ulrich Drepper ➧ Red Hat, Inc. ➧ 444 Castro St ➧ Mountain View, CA ❖


signature.asc (259 bytes) Download Attachment