svn commit: r341441 - head/libexec/rtld-elf

Konstantin Belousov kib at FreeBSD.org
Mon Dec 3 20:03:44 UTC 2018


Author: kib
Date: Mon Dec  3 20:03:43 2018
New Revision: 341441
URL: https://svnweb.freebsd.org/changeset/base/341441

Log:
  Some fixes for LD_BIND_NOW + ifuncs.
  
  - Do not perform ifunc relocations together with other PLT relocations
    in PLT.  Instead, do it during an additional pass over the init
    list, so that ifuncs are resolved in the order of dso
    dependencies. This allows the ifuncs resolvers to call into depended
    libs.  Init list now includes all objects instead of only objects
    with init/fini callables.
  - Disable relro protection around bind_now ifunc relocations.
  
  I considered calling ifunc resolvers of dso after initializers of all
  dependencies are processed, and decided that this is wrong/should not
  be supported. The order now is normal relocations for all
  objects->ifunc resolution in init order->initializers, where each step
  does complete pass over all loaded objects before moving to the next
  step.
  
  Reported, tested and reviewed by:	emaste
  Sponsored by:	The FreeBSD Foundation
  MFC after:	1 week
  Differential revision:	https://reviews.freebsd.org/D18400

Modified:
  head/libexec/rtld-elf/rtld.c
  head/libexec/rtld-elf/rtld.h

Modified: head/libexec/rtld-elf/rtld.c
==============================================================================
--- head/libexec/rtld-elf/rtld.c	Mon Dec  3 20:01:51 2018	(r341440)
+++ head/libexec/rtld-elf/rtld.c	Mon Dec  3 20:03:43 2018	(r341441)
@@ -111,6 +111,7 @@ static void init_pagesizes(Elf_Auxinfo **aux_info);
 static void init_rtld(caddr_t, Elf_Auxinfo **);
 static void initlist_add_neededs(Needed_Entry *, Objlist *);
 static void initlist_add_objects(Obj_Entry *, Obj_Entry *, Objlist *);
+static int initlist_objects_ifunc(Objlist *, bool, int, RtldLockState *);
 static void linkmap_add(Obj_Entry *);
 static void linkmap_delete(Obj_Entry *);
 static void load_filtees(Obj_Entry *, int flags, RtldLockState *);
@@ -119,6 +120,7 @@ static int load_needed_objects(Obj_Entry *, int);
 static int load_preload_objects(void);
 static Obj_Entry *load_object(const char *, int fd, const Obj_Entry *, int);
 static void map_stacks_exec(RtldLockState *);
+static int obj_disable_relro(Obj_Entry *);
 static int obj_enforce_relro(Obj_Entry *);
 static Obj_Entry *obj_from_addr(const void *);
 static void objlist_call_fini(Objlist *, Obj_Entry *, RtldLockState *);
@@ -143,8 +145,6 @@ static int relocate_object(Obj_Entry *obj, bool bind_n
 static int relocate_objects(Obj_Entry *, bool, Obj_Entry *, int,
     RtldLockState *);
 static int resolve_object_ifunc(Obj_Entry *, bool, int, RtldLockState *);
-static int resolve_objects_ifunc(Obj_Entry *first, bool bind_now,
-    int flags, RtldLockState *lockstate);
 static int rtld_dirname(const char *, char *);
 static int rtld_dirname_abs(const char *, char *);
 static void *rtld_dlopen(const char *name, int fd, int mode);
@@ -730,16 +730,6 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entr
 
     map_stacks_exec(NULL);
 
-    dbg("resolving ifuncs");
-    if (resolve_objects_ifunc(obj_main,
-      ld_bind_now != NULL && *ld_bind_now != '\0', SYMLOOK_EARLY,
-      NULL) == -1)
-	rtld_die();
-
-    dbg("enforcing main obj relro");
-    if (obj_enforce_relro(obj_main) == -1)
-	rtld_die();
-
     if (!obj_main->crt_no_init) {
 	/*
 	 * Make sure we don't call the main program's init and fini
@@ -758,6 +748,12 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entr
     pre_init();
 
     wlock_acquire(rtld_bind_lock, &lockstate);
+
+    dbg("resolving ifuncs");
+    if (initlist_objects_ifunc(&initlist, ld_bind_now != NULL &&
+      *ld_bind_now != '\0', SYMLOOK_EARLY, &lockstate) == -1)
+	rtld_die();
+
     if (obj_main->crt_no_init)
 	preinit_main();
     objlist_call_init(&initlist, &lockstate);
@@ -770,6 +766,11 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entr
 	if (ld_loadfltr || obj->z_loadfltr)
 	    load_filtees(obj, 0, &lockstate);
     }
+
+    dbg("enforcing main obj relro");
+    if (obj_enforce_relro(obj_main) == -1)
+	rtld_die();
+
     lock_release(rtld_bind_lock, &lockstate);
 
     dbg("transferring control to program entry point = %p", obj_main->entry);
@@ -2243,9 +2244,7 @@ initlist_add_objects(Obj_Entry *obj, Obj_Entry *tail, 
 	initlist_add_neededs(obj->needed_aux_filtees, list);
 
     /* Add the object to the init list. */
-    if (obj->preinit_array != (Elf_Addr)NULL || obj->init != (Elf_Addr)NULL ||
-      obj->init_array != (Elf_Addr)NULL)
-	objlist_push_tail(list, obj);
+    objlist_push_tail(list, obj);
 
     /* Add the object to the global fini list in the reverse order. */
     if ((obj->fini != (Elf_Addr)NULL || obj->fini_array != (Elf_Addr)NULL)
@@ -2894,11 +2893,9 @@ relocate_object(Obj_Entry *obj, bool bind_now, Obj_Ent
 	if (reloc_plt(obj) == -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 ||
-		    resolve_object_ifunc(obj, true, flags, lockstate) == -1)
-			return (-1);
-	}
+	if ((obj->bind_now || bind_now) && reloc_jmpslots(obj, flags,
+	    lockstate) == -1)
+		return (-1);
 
 	/*
 	 * Process the non-PLT IFUNC relocations.  The relocations are
@@ -2964,24 +2961,16 @@ static int
 resolve_object_ifunc(Obj_Entry *obj, bool bind_now, int flags,
     RtldLockState *lockstate)
 {
+
+	if (obj->ifuncs_resolved)
+		return (0);
+	obj->ifuncs_resolved = true;
 	if (obj->irelative && reloc_iresolve(obj, lockstate) == -1)
 		return (-1);
-	if ((obj->bind_now || bind_now) && obj->gnu_ifunc &&
-	    reloc_gnu_ifunc(obj, flags, lockstate) == -1)
-		return (-1);
-	return (0);
-}
-
-static int
-resolve_objects_ifunc(Obj_Entry *first, bool bind_now, int flags,
-    RtldLockState *lockstate)
-{
-	Obj_Entry *obj;
-
-	for (obj = first; obj != NULL; obj = TAILQ_NEXT(obj, next)) {
-		if (obj->marker)
-			continue;
-		if (resolve_object_ifunc(obj, bind_now, flags, lockstate) == -1)
+	if ((obj->bind_now || bind_now) && obj->gnu_ifunc) {
+		if (obj_disable_relro(obj) ||
+		    reloc_gnu_ifunc(obj, flags, lockstate) == -1 ||
+		    obj_enforce_relro(obj))
 			return (-1);
 	}
 	return (0);
@@ -2992,9 +2981,13 @@ initlist_objects_ifunc(Objlist *list, bool bind_now, i
     RtldLockState *lockstate)
 {
 	Objlist_Entry *elm;
+	Obj_Entry *obj;
 
 	STAILQ_FOREACH(elm, list, link) {
-		if (resolve_object_ifunc(elm->obj, bind_now, flags,
+		obj = elm->obj;
+		if (obj->marker)
+			continue;
+		if (resolve_object_ifunc(obj, bind_now, flags,
 		    lockstate) == -1)
 			return (-1);
 	}
@@ -5354,17 +5347,31 @@ _rtld_is_dlopened(void *arg)
 	return (res);
 }
 
-int
-obj_enforce_relro(Obj_Entry *obj)
+static int
+obj_remap_relro(Obj_Entry *obj, int prot)
 {
 
 	if (obj->relro_size > 0 && mprotect(obj->relro_page, obj->relro_size,
-	    PROT_READ) == -1) {
-		_rtld_error("%s: Cannot enforce relro protection: %s",
-		    obj->path, rtld_strerror(errno));
+	    prot) == -1) {
+		_rtld_error("%s: Cannot set relro protection to %#x: %s",
+		    obj->path, prot, rtld_strerror(errno));
 		return (-1);
 	}
 	return (0);
+}
+
+static int
+obj_disable_relro(Obj_Entry *obj)
+{
+
+	return (obj_remap_relro(obj, PROT_READ | PROT_WRITE));
+}
+
+static int
+obj_enforce_relro(Obj_Entry *obj)
+{
+
+	return (obj_remap_relro(obj, PROT_READ));
 }
 
 static void

Modified: head/libexec/rtld-elf/rtld.h
==============================================================================
--- head/libexec/rtld-elf/rtld.h	Mon Dec  3 20:01:51 2018	(r341440)
+++ head/libexec/rtld-elf/rtld.h	Mon Dec  3 20:03:43 2018	(r341441)
@@ -264,6 +264,7 @@ typedef struct Struct_Obj_Entry {
     bool irelative : 1;		/* Object has R_MACHDEP_IRELATIVE relocs */
     bool gnu_ifunc : 1;		/* Object has references to STT_GNU_IFUNC */
     bool non_plt_gnu_ifunc : 1;	/* Object has non-plt IFUNC references */
+    bool ifuncs_resolved : 1;	/* Object ifuncs were already resolved */
     bool crt_no_init : 1;	/* Object' crt does not call _init/_fini */
     bool valid_hash_sysv : 1;	/* A valid System V hash hash tag is available */
     bool valid_hash_gnu : 1;	/* A valid GNU hash tag is available */


More information about the svn-src-head mailing list