rtld: Perform reloc before filtree dependency object init
authorJohn Marino <draco@marino.st>
Mon, 20 Aug 2012 19:27:06 +0000 (21:27 +0200)
committerJohn Marino <draco@marino.st>
Mon, 20 Aug 2012 20:24:25 +0000 (22:24 +0200)
Ensure that for the object which is a dependency of some filtree,
relocations are performed before the object's initializer is called.
While dlopen()ing an object, relocate the whole DAG rooted in the
object instead of only relocating the object itself and list of newly
loaded dependencies.

Reversed sequence currently can occur if the same object is a
dependency for both filtree and filter since filtrees are loaded typically
during the relocation processing when some filter dependencies might be
already loaded but not yet relocated.

Taken-from: FreeBSD SVN 237659 (27 June 2012)

libexec/rtld-elf/rtld.c

index 4d4aa29..7cd9fe0 100644 (file)
@@ -119,6 +119,10 @@ static void objlist_push_head(Objlist *, Obj_Entry *);
 static void objlist_push_tail(Objlist *, Obj_Entry *);
 static void objlist_remove(Objlist *, Obj_Entry *);
 static void *path_enumerate(const char *, path_enum_proc, void *);
 static void objlist_push_tail(Objlist *, Obj_Entry *);
 static void objlist_remove(Objlist *, Obj_Entry *);
 static void *path_enumerate(const char *, path_enum_proc, void *);
+static int relocate_object_dag(Obj_Entry *root, bool bind_now,
+    Obj_Entry *rtldobj, int flags, RtldLockState *lockstate);
+static int relocate_object(Obj_Entry *obj, bool bind_now, Obj_Entry *rtldobj,
+    int flags, RtldLockState *lockstate);
 static int relocate_objects(Obj_Entry *, bool, Obj_Entry *, int,
     RtldLockState *);
 static int resolve_objects_ifunc(Obj_Entry *first, bool bind_now,
 static int relocate_objects(Obj_Entry *, bool, Obj_Entry *, int,
     RtldLockState *);
 static int resolve_objects_ifunc(Obj_Entry *first, bool bind_now,
@@ -2468,20 +2472,38 @@ objlist_remove(Objlist *list, Obj_Entry *obj)
 }
 
 /*
 }
 
 /*
- * Relocate newly-loaded shared objects.  The argument is a pointer to
- * the Obj_Entry for the first such object.  All objects from the first
- * to the end of the list of objects are relocated.  Returns 0 on success,
- * or -1 on failure.
+ * Relocate dag rooted in the specified object.
+ * Returns 0 on success, or -1 on failure.
  */
  */
+
 static int
 static int
-relocate_objects(Obj_Entry *first, bool bind_now, Obj_Entry *rtldobj,
+relocate_object_dag(Obj_Entry *root, bool bind_now, Obj_Entry *rtldobj,
     int flags, RtldLockState *lockstate)
 {
     int flags, RtldLockState *lockstate)
 {
-    Obj_Entry *obj;
+       Objlist_Entry *elm;
+       int error;
 
 
-    for (obj = first;  obj != NULL;  obj = obj->next) {
+       error = 0;
+       STAILQ_FOREACH(elm, &root->dagmembers, link) {
+               error = relocate_object(elm->obj, bind_now, rtldobj, flags,
+                   lockstate);
+               if (error == -1)
+                       break;
+       }
+       return (error);
+}
+
+/*
+ * Relocate single object.
+ * Returns 0 on success, or -1 on failure.
+ */
+
+static int
+relocate_object(Obj_Entry *obj, bool bind_now, Obj_Entry *rtldobj,
+    int flags, RtldLockState *lockstate)
+{
        if (obj->relocated)
        if (obj->relocated)
-           continue;
+           return (0);
        obj->relocated = true;
        if (obj != rtldobj)
            dbg("relocating \"%s\"", obj->path);
        obj->relocated = true;
        if (obj != rtldobj)
            dbg("relocating \"%s\"", obj->path);
@@ -2490,7 +2512,7 @@ relocate_objects(Obj_Entry *first, bool bind_now, Obj_Entry *rtldobj,
          !(obj->valid_hash_sysv || obj->valid_hash_gnu)) {
            _rtld_error("%s: Shared object has no run-time symbol table",
              obj->path);
          !(obj->valid_hash_sysv || obj->valid_hash_gnu)) {
            _rtld_error("%s: Shared object has no run-time symbol table",
              obj->path);
-           return -1;
+           return (-1);
        }
 
        if (obj->textrel) {
        }
 
        if (obj->textrel) {
@@ -2499,13 +2521,13 @@ relocate_objects(Obj_Entry *first, bool bind_now, Obj_Entry *rtldobj,
              PROT_READ|PROT_WRITE|PROT_EXEC) == -1) {
                _rtld_error("%s: Cannot write-enable text segment: %s",
                  obj->path, rtld_strerror(errno));
              PROT_READ|PROT_WRITE|PROT_EXEC) == -1) {
                _rtld_error("%s: Cannot write-enable text segment: %s",
                  obj->path, rtld_strerror(errno));
-               return -1;
+               return (-1);
            }
        }
 
        /* Process the non-PLT relocations. */
        if (reloc_non_plt(obj, rtldobj, flags, lockstate))
            }
        }
 
        /* Process the non-PLT relocations. */
        if (reloc_non_plt(obj, rtldobj, flags, lockstate))
-               return -1;
+               return (-1);
 
        /*
         * Reprotect the text segment.  Make sure it is included in the
 
        /*
         * Reprotect the text segment.  Make sure it is included in the
@@ -2526,7 +2548,7 @@ relocate_objects(Obj_Entry *first, bool bind_now, Obj_Entry *rtldobj,
              PROT_READ|PROT_EXEC) == -1) {
                _rtld_error("%s: Cannot write-protect text segment: %s",
                  obj->path, rtld_strerror(errno));
              PROT_READ|PROT_EXEC) == -1) {
                _rtld_error("%s: Cannot write-protect text segment: %s",
                  obj->path, rtld_strerror(errno));
-               return -1;
+               return (-1);
            }
        }
 
            }
        }
 
@@ -2536,11 +2558,11 @@ relocate_objects(Obj_Entry *first, bool bind_now, Obj_Entry *rtldobj,
 
        /* Process the PLT relocations. */
        if (reloc_plt(obj) == -1)
 
        /* Process the PLT relocations. */
        if (reloc_plt(obj) == -1)
-           return -1;
+           return (-1);
        /* Relocate the jump slots if we are doing immediate binding. */
        if (obj->bind_now || bind_now)
            if (reloc_jmpslots(obj, flags, lockstate) == -1)
        /* Relocate the jump slots if we are doing immediate binding. */
        if (obj->bind_now || bind_now)
            if (reloc_jmpslots(obj, flags, lockstate) == -1)
-               return -1;
+               return (-1);
 
        /*
         * Set up the magic number and version in the Obj_Entry.  These
 
        /*
         * Set up the magic number and version in the Obj_Entry.  These
@@ -2558,12 +2580,32 @@ relocate_objects(Obj_Entry *first, bool bind_now, Obj_Entry *rtldobj,
            if (mprotect(obj->relro_page, obj->relro_size, PROT_READ) == -1) {
                _rtld_error("%s: Cannot enforce relro relocation: %s",
                  obj->path, rtld_strerror(errno));
            if (mprotect(obj->relro_page, obj->relro_size, PROT_READ) == -1) {
                _rtld_error("%s: Cannot enforce relro relocation: %s",
                  obj->path, rtld_strerror(errno));
-               return -1;
+               return (-1);
            }
        }
            }
        }
-    }
+       return (0);
+}
 
 
-    return (0);
+/*
+ * Relocate newly-loaded shared objects.  The argument is a pointer to
+ * the Obj_Entry for the first such object.  All objects from the first
+ * to the end of the list of objects are relocated.  Returns 0 on success,
+ * or -1 on failure.
+ */
+static int
+relocate_objects(Obj_Entry *first, bool bind_now, Obj_Entry *rtldobj,
+    int flags, RtldLockState *lockstate)
+{
+       Obj_Entry *obj;
+       int error;
+
+       for (error = 0, obj = first;  obj != NULL;  obj = obj->next) {
+               error = relocate_object(obj, bind_now, rtldobj, flags,
+                   lockstate);
+               if (error == -1)
+                       break;
+       }
+       return (error);
 }
 
 /*
 }
 
 /*
@@ -2852,10 +2894,10 @@ dlopen_object(const char *name, int fd, Obj_Entry *refobj, int lo_flags,
                result = rtld_verify_versions(&obj->dagmembers);
            if (result != -1 && ld_tracing)
                goto trace;
                result = rtld_verify_versions(&obj->dagmembers);
            if (result != -1 && ld_tracing)
                goto trace;
-           if (result == -1 || (relocate_objects(obj,
-            (mode & RTLD_MODEMASK) == RTLD_NOW, &obj_rtld,
+           if (result == -1 || relocate_object_dag(obj,
+             (mode & RTLD_MODEMASK) == RTLD_NOW, &obj_rtld,
              (lo_flags & RTLD_LO_EARLY) ? SYMLOOK_EARLY : 0,
              (lo_flags & RTLD_LO_EARLY) ? SYMLOOK_EARLY : 0,
-             lockstate)) == -1) {
+             lockstate) == -1) {
                dlopen_cleanup(obj);
                obj = NULL;
            } else if (lo_flags & RTLD_LO_EARLY) {
                dlopen_cleanup(obj);
                obj = NULL;
            } else if (lo_flags & RTLD_LO_EARLY) {