avoid spurious dso matches by dladdr outside bounds of load segments
authorRich Felker <dalias@aerifal.cx>
Thu, 28 Jun 2018 16:20:58 +0000 (12:20 -0400)
committerRich Felker <dalias@aerifal.cx>
Thu, 28 Jun 2018 16:27:01 +0000 (12:27 -0400)
since slack space at the beginning and/or end of writable load maps is
donated to malloc, the application could obtain valid pointers in
these ranges which dladdr would erroneously identify as part of the
shared object whose mapping they came from.

instead of checking the queried address against the mapping base and
length, check it against the load segments from the program headers,
and only match the dso if it lies within the bounds of one of them.

as a shortcut, if the address does match the range of the mapping but
not any of the load segments, we know it cannot match any other dso
and can immediately return failure.

ldso/dynlink.c

index a773b7825eb6266d943f516b3dedb4b4ee40c823..41534e90e4680b88e7d6a623c1632b014600e547 100644 (file)
@@ -1878,8 +1878,17 @@ static void *addr2dso(size_t a)
                                        return p;
                        }
                } else {
+                       Phdr *ph = p->phdr;
+                       size_t phcnt = p->phnum;
+                       size_t entsz = p->phentsize;
+                       size_t base = (size_t)p->base;
+                       for (; phcnt--; ph=(void *)((char *)ph+entsz)) {
+                               if (ph->p_type != PT_LOAD) continue;
+                               if (a-base-ph->p_vaddr < ph->p_memsz)
+                                       return p;
+                       }
                        if (a-(size_t)p->map < p->map_len)
-                               return p;
+                               return 0;
                }
        }
        return 0;