rtld: Implement Interpose DSO flag
authorJohn Marino <draco@marino.st>
Sat, 30 Nov 2013 09:47:20 +0000 (10:47 +0100)
committerJohn Marino <draco@marino.st>
Sat, 30 Nov 2013 11:55:32 +0000 (12:55 +0100)
This implementation was sponsored by FreeBSD Foundation.

Taken from:
SVN 256101 (07 OCT 2013)

libexec/rtld-elf/rtld.c
libexec/rtld-elf/rtld.h

index 1a9a47f..968a526 100644 (file)
@@ -116,6 +116,7 @@ static Objlist_Entry *objlist_find(Objlist *, const Obj_Entry *);
 static void objlist_init(Objlist *);
 static void objlist_push_head(Objlist *, Obj_Entry *);
 static void objlist_push_tail(Objlist *, Obj_Entry *);
+static void objlist_put_after(Objlist *, Obj_Entry *, 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,
@@ -323,6 +324,7 @@ ld_utrace_log(int event, void *handle, void *mapbase, size_t mapsize,
 func_ptr_type
 _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp)
 {
+    Obj_Entry *last_interposer;
     Elf_Auxinfo *aux_info[AT_COUNT];
     int i;
     int argc;
@@ -566,8 +568,14 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp)
        die();
 
     /* Make a list of all objects loaded at startup. */
+    last_interposer = obj_main;
     for (obj = obj_list;  obj != NULL;  obj = obj->next) {
-       objlist_push_tail(&list_main, obj);
+       if (obj->z_interpose && obj != obj_main) {
+          objlist_put_after(&list_main, last_interposer, obj);
+          last_interposer = obj;
+       } else {
+          objlist_push_tail(&list_main, obj);
+       }
        obj->refcount++;
     }
 
@@ -1199,6 +1207,8 @@ digest_dynamic1(Obj_Entry *obj, int early, const Elf_Dyn **dyn_rpath,
                    obj->z_nodelete = true;
                if (dynp->d_un.d_val & DF_1_LOADFLTR)
                    obj->z_loadfltr = true;
+               if (dynp->d_un.d_val & DF_1_INTERPOSE)
+                   obj->z_interpose = true;
                if (dynp->d_un.d_val & DF_1_NODEFLIB)
                    obj->z_nodeflib = true;
            break;
@@ -2031,6 +2041,7 @@ static int
 load_preload_objects(void)
 {
     char *p = ld_preload;
+    Obj_Entry *obj;
     static const char delim[] = " \t:;";
 
     if (p == NULL)
@@ -2040,7 +2051,6 @@ load_preload_objects(void)
     while (*p != '\0') {
        size_t len = strcspn(p, delim);
        char savech;
-       Obj_Entry *obj;
        SymLook req;
        int res;
 
@@ -2049,6 +2059,7 @@ load_preload_objects(void)
        obj = load_object(p, -1, NULL, 0);
        if (obj == NULL)
            return -1;  /* XXX - cleanup */
+       obj->z_interpose = true;
        p[len] = savech;
        p += len;
        p += strspn(p, delim);
@@ -2463,6 +2474,23 @@ objlist_push_tail(Objlist *list, Obj_Entry *obj)
     STAILQ_INSERT_TAIL(list, elm, link);
 }
 
+static void
+objlist_put_after(Objlist *list, Obj_Entry *listobj, Obj_Entry *obj)
+{
+       Objlist_Entry *elm, *listelm;
+
+       STAILQ_FOREACH(listelm, list, link) {
+               if (listelm->obj == listobj)
+                       break;
+       }
+       elm = NEW(Objlist_Entry);
+       elm->obj = obj;
+       if (listelm != NULL)
+               STAILQ_INSERT_AFTER(list, listelm, elm, link);
+       else
+               STAILQ_INSERT_TAIL(list, elm, link);
+}
+
 static void
 objlist_remove(Objlist *list, Obj_Entry *obj)
 {
index e5e9cb0..58e7aef 100644 (file)
@@ -242,6 +242,7 @@ typedef struct Struct_Obj_Entry {
     bool z_nodelete : 1;       /* Do not unload the object and dependencies */
     bool z_noopen : 1;         /* Do not load on dlopen */
     bool z_loadfltr : 1;       /* Immediately load filtees */
+    bool z_interpose : 1;      /* Interpose all objects but main */
     bool z_nodeflib : 1;       /* Don't search default /usr/lib path */
     bool ref_nodel : 1;                /* Refcount increased to prevent dlclose */
     bool init_scanned: 1;      /* Object is already on init list. */