Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 15 Jul 2012 10:53:49 +0000 (UTC)
From:      Konstantin Belousov <kib@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r238471 - head/libexec/rtld-elf
Message-ID:  <201207151053.q6FArnqO042991@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: kib
Date: Sun Jul 15 10:53:48 2012
New Revision: 238471
URL: http://svn.freebsd.org/changeset/base/238471

Log:
  Import the DragonFly BSD commit 4f0bc915b65fcf5a23214f6d221d65c80be68ad4
  by John Marino <draco@marino.st>, with the following (edited) commit
  message
  Date: Sat, 24 Mar 2012 06:40:50 +0100
  Subject: [PATCH 1/1] rtld: Implement DT_RUNPATH and -z nodefaultlib
  
  DT_RUNPATH is incorrectly being considered as an alias of DT_RPATH.  The
  purpose of DT_RUNPATH is to have two different types of rpath: one that
  can be overridden by the environment variable LD_LIBRARY_PATH and one that
  can't.  With the currently implementation, LD_LIBRARY_PATH will always
  trump any embedded rpath or runpath tags.
  
  Current path search order by rtld:
  ==================================
  LD_LIBRARY_PATH
  DT_RPATH / DT_RUNPATH (always the same)
  ldconfig hints file (default: /var/run/ld-elf.so.hints)
  /usr/lib
  
  New path search order by rtld:
  ==============================
  DT_RPATH of the calling object if no DT_RUNPATH
  DT_RPATH of the main binary if no DT_RUNPATH and binary isn't calling obj
  LD_LIBRARY_PATH
  DT_RUNPATH
  ldconfig hints file
  /usr/lib
  
  The new path search matches how the linux runtime loader works.  The other
  major added feature is support for linker flag "-z nodefaultlib".  When
  this flag is passed to the linker, rtld will skip all references to the
  standard library search path ("/usr/lib" in this case but it could handle
  more color delimited paths) except in DT_RPATH and DT_RUNPATH.
  
  New path search order by rtld with -z nodefaultlib flag set:
  ============================================================
  DT_RPATH of the calling object if no DT_RUNPATH
  DT_RPATH of the main binary if no DT_RUNPATH and binary isn't calling obj
  LD_LIBRARY_PATH
  DT_RUNPATH
  ldconfig hints file (skips all references to /usr/lib)
  
  FreeBSD notes:
  - we fixed some bugs which were submitted to DragonFly and merged there
    as commit 1ff8a2bd3eb6e5587174c6a983303ea3a79e0002;
  - we added LD_LIBRARY_PATH_RPATH environment variable to switch to
    the previous behaviour of considering DT_RPATH a synonym for DT_RUNPATH;
  - the FreeBSD default search path is /lib:/usr/lib and not /usr/lib.
  
  Reviewed by:   kan
  MFC after:     1 month
  MFC note:      flip the ld_library_path_rpath default value for stable/9

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

Modified: head/libexec/rtld-elf/rtld.1
==============================================================================
--- head/libexec/rtld-elf/rtld.1	Sun Jul 15 10:49:16 2012	(r238470)
+++ head/libexec/rtld-elf/rtld.1	Sun Jul 15 10:53:48 2012	(r238471)
@@ -28,7 +28,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd April 1, 2009
+.Dd June 28, 2012
 .Dt RTLD 1
 .Os
 .Sh NAME
@@ -86,14 +86,39 @@ dynamic linker.
 After the dynamic linker has finished loading,
 relocating, and initializing the program and its required shared
 objects, it transfers control to the entry point of the program.
+The following search order is used to locate required shared objects:
 .Pp
-To locate the required shared objects in the file system,
-.Nm
-may use a
-.Dq hints
-file prepared by the
+.Bl -enum -offset indent -compact
+.It
+.Dv DT_RPATH
+of the referencing object unless that object also contains a
+.Dv DT_RUNPATH
+tag
+.It
+.Dv DT_RPATH
+of the program unless the referencing object contains a
+.Dv DT_RUNPATH
+tag
+.It
+Path indicated by
+.Ev LD_LIBRARY_PATH
+environment variable
+.It
+.Dv DT_RUNPATH
+of the referencing object
+.It
+Hints file produced by the
 .Xr ldconfig 8
-utility.
+utility
+.It
+The
+.Pa /lib
+and
+.Pa /usr/lib
+directories, unless the referencing object was linked using the
+.Dq Fl z Ar nodefaultlib
+option
+.El
 .Pp
 The
 .Nm
@@ -143,6 +168,20 @@ This variable is unset for set-user-ID a
 A colon separated list of directories, overriding the default search path
 for shared libraries.
 This variable is unset for set-user-ID and set-group-ID programs.
+.It Ev LD_LIBRARY_PATH_RPATH
+If the variable is specified and has a value starting with
+any of \'y\', \'Y\' or \'1\' symbols, the path specified by
+.Ev LD_LIBRARY_PATH
+variable is allowed to override the path from
+.Dv DT_RPATH
+for binaries which does not contain
+.Dv DT_RUNPATH
+tag.
+For such binaries, when the variable
+.Ev LD_LIBRARY_PATH_RPATH
+is set,
+.Dq Fl z Ar nodefaultlib
+link-time option is ignored as well.
 .It Ev LD_PRELOAD
 A list of shared libraries, separated by colons and/or white space,
 to be linked in before any

Modified: head/libexec/rtld-elf/rtld.c
==============================================================================
--- head/libexec/rtld-elf/rtld.c	Sun Jul 15 10:49:16 2012	(r238470)
+++ head/libexec/rtld-elf/rtld.c	Sun Jul 15 10:53:48 2012	(r238471)
@@ -80,8 +80,9 @@ typedef void * (*path_enum_proc) (const 
 static const char *basename(const char *);
 static void die(void) __dead2;
 static void digest_dynamic1(Obj_Entry *, int, const Elf_Dyn **,
-    const Elf_Dyn **);
-static void digest_dynamic2(Obj_Entry *, const Elf_Dyn *, const Elf_Dyn *);
+    const Elf_Dyn **, const Elf_Dyn **);
+static void digest_dynamic2(Obj_Entry *, const Elf_Dyn *, const Elf_Dyn *,
+    const Elf_Dyn *);
 static void digest_dynamic(Obj_Entry *, int);
 static Obj_Entry *digest_phdr(const Elf_Phdr *, int, caddr_t, const char *);
 static Obj_Entry *dlcheck(void *);
@@ -94,7 +95,7 @@ static void errmsg_restore(char *);
 static char *errmsg_save(void);
 static void *fill_search_info(const char *, size_t, void *);
 static char *find_library(const char *, const Obj_Entry *);
-static const char *gethints(void);
+static const char *gethints(bool);
 static void init_dag(Obj_Entry *);
 static void init_rtld(caddr_t, Elf_Auxinfo **);
 static void initlist_add_neededs(Needed_Entry *, Objlist *);
@@ -233,6 +234,8 @@ size_t tls_static_space;	/* Static TLS s
 int tls_dtv_generation = 1;	/* Used to detect when dtv size changes  */
 int tls_max_index = 1;		/* Largest module index allocated */
 
+bool ld_library_path_rpath = false;
+
 /*
  * Fill in a DoneList with an allocation large enough to hold all of
  * the currently-loaded objects.  Keep this as a macro since it calls
@@ -323,6 +326,7 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_
     Obj_Entry **preload_tail;
     Objlist initlist;
     RtldLockState lockstate;
+    char *library_path_rpath;
     int mib[2];
     size_t len;
 
@@ -394,7 +398,7 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_
         if (unsetenv(LD_ "PRELOAD") || unsetenv(LD_ "LIBMAP") ||
 	    unsetenv(LD_ "LIBRARY_PATH") || unsetenv(LD_ "LIBMAP_DISABLE") ||
 	    unsetenv(LD_ "DEBUG") || unsetenv(LD_ "ELF_HINTS_PATH") ||
-	    unsetenv(LD_ "LOADFLTR")) {
+	    unsetenv(LD_ "LOADFLTR") || unsetenv(LD_ "LIBRARY_PATH_RPATH")) {
 		_rtld_error("environment corrupt; aborting");
 		die();
 	}
@@ -406,6 +410,15 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_
     ld_preload = getenv(LD_ "PRELOAD");
     ld_elf_hints_path = getenv(LD_ "ELF_HINTS_PATH");
     ld_loadfltr = getenv(LD_ "LOADFLTR") != NULL;
+    library_path_rpath = getenv(LD_ "LIBRARY_PATH_RPATH");
+    if (library_path_rpath != NULL) {
+	    if (library_path_rpath[0] == 'y' ||
+		library_path_rpath[0] == 'Y' ||
+		library_path_rpath[0] == '1')
+		    ld_library_path_rpath = true;
+	    else
+		    ld_library_path_rpath = false;
+    }
     dangerous_ld_env = libmap_disable || (libmap_override != NULL) ||
 	(ld_library_path != NULL) || (ld_preload != NULL) ||
 	(ld_elf_hints_path != NULL) || ld_loadfltr;
@@ -828,7 +841,7 @@ die(void)
  */
 static void
 digest_dynamic1(Obj_Entry *obj, int early, const Elf_Dyn **dyn_rpath,
-    const Elf_Dyn **dyn_soname)
+    const Elf_Dyn **dyn_soname, const Elf_Dyn **dyn_runpath)
 {
     const Elf_Dyn *dynp;
     Needed_Entry **needed_tail = &obj->needed;
@@ -843,6 +856,7 @@ digest_dynamic1(Obj_Entry *obj, int earl
 
     *dyn_rpath = NULL;
     *dyn_soname = NULL;
+    *dyn_runpath = NULL;
 
     obj->bind_now = false;
     for (dynp = obj->dynamic;  dynp->d_tag != DT_NULL;  dynp++) {
@@ -1009,7 +1023,6 @@ digest_dynamic1(Obj_Entry *obj, int earl
 	    break;
 
 	case DT_RPATH:
-	case DT_RUNPATH:	/* XXX: process separately */
 	    /*
 	     * We have to wait until later to process this, because we
 	     * might not have gotten the address of the string table yet.
@@ -1021,6 +1034,10 @@ digest_dynamic1(Obj_Entry *obj, int earl
 	    *dyn_soname = dynp;
 	    break;
 
+	case DT_RUNPATH:
+	    *dyn_runpath = dynp;
+	    break;
+
 	case DT_INIT:
 	    obj->init = (Elf_Addr) (obj->relocbase + dynp->d_un.d_ptr);
 	    break;
@@ -1114,6 +1131,8 @@ digest_dynamic1(Obj_Entry *obj, int earl
 		    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_NODEFLIB)
+		    obj->z_nodeflib = true;
 	    break;
 
 	default:
@@ -1153,7 +1172,7 @@ digest_dynamic1(Obj_Entry *obj, int earl
 
 static void
 digest_dynamic2(Obj_Entry *obj, const Elf_Dyn *dyn_rpath,
-    const Elf_Dyn *dyn_soname)
+    const Elf_Dyn *dyn_soname, const Elf_Dyn *dyn_runpath)
 {
 
     if (obj->z_origin && obj->origin_path == NULL) {
@@ -1162,7 +1181,12 @@ digest_dynamic2(Obj_Entry *obj, const El
 	    die();
     }
 
-    if (dyn_rpath != NULL) {
+    if (dyn_runpath != NULL) {
+	obj->runpath = (char *)obj->strtab + dyn_runpath->d_un.d_val;
+	if (obj->z_origin)
+	    obj->runpath = origin_subst(obj->runpath, obj->origin_path);
+    }
+    else if (dyn_rpath != NULL) {
 	obj->rpath = (char *)obj->strtab + dyn_rpath->d_un.d_val;
 	if (obj->z_origin)
 	    obj->rpath = origin_subst(obj->rpath, obj->origin_path);
@@ -1177,9 +1201,10 @@ digest_dynamic(Obj_Entry *obj, int early
 {
 	const Elf_Dyn *dyn_rpath;
 	const Elf_Dyn *dyn_soname;
+	const Elf_Dyn *dyn_runpath;
 
-	digest_dynamic1(obj, early, &dyn_rpath, &dyn_soname);
-	digest_dynamic2(obj, dyn_rpath, dyn_soname);
+	digest_dynamic1(obj, early, &dyn_rpath, &dyn_soname, &dyn_runpath);
+	digest_dynamic2(obj, dyn_rpath, dyn_soname, dyn_runpath);
 }
 
 /*
@@ -1389,43 +1414,71 @@ gnu_hash(const char *s)
  * loaded shared object, whose library search path will be searched.
  *
  * The search order is:
+ *   DT_RPATH in the referencing file _unless_ DT_RUNPATH is present (1)
+ *   DT_RPATH of the main object if DSO without defined DT_RUNPATH (1)
  *   LD_LIBRARY_PATH
- *   rpath in the referencing file
- *   ldconfig hints
- *   /lib:/usr/lib
+ *   DT_RUNPATH in the referencing file
+ *   ldconfig hints (if -z nodefaultlib, filter out default library directories
+ *	 from list)
+ *   /lib:/usr/lib _unless_ the referencing file is linked with -z nodefaultlib
+ *
+ * (1) Handled in digest_dynamic2 - rpath left NULL if runpath defined.
  */
 static char *
 find_library(const char *xname, const Obj_Entry *refobj)
 {
     char *pathname;
     char *name;
+    bool objgiven;
 
+    objgiven = refobj != NULL;
     if (strchr(xname, '/') != NULL) {	/* Hard coded pathname */
 	if (xname[0] != '/' && !trust) {
 	    _rtld_error("Absolute pathname required for shared object \"%s\"",
 	      xname);
 	    return NULL;
 	}
-	if (refobj != NULL && refobj->z_origin)
+	if (objgiven && refobj->z_origin)
 	    return origin_subst(xname, refobj->origin_path);
 	else
 	    return xstrdup(xname);
     }
 
-    if (libmap_disable || (refobj == NULL) ||
+    if (libmap_disable || !objgiven ||
 	(name = lm_find(refobj->path, xname)) == NULL)
 	name = (char *)xname;
 
     dbg(" Searching for \"%s\"", name);
 
-    if ((pathname = search_library_path(name, ld_library_path)) != NULL ||
-      (refobj != NULL &&
-      (pathname = search_library_path(name, refobj->rpath)) != NULL) ||
-      (pathname = search_library_path(name, gethints())) != NULL ||
-      (pathname = search_library_path(name, STANDARD_LIBRARY_PATH)) != NULL)
-	return pathname;
+    /*
+     * If refobj->rpath != NULL, then refobj->runpath is NULL.  Fall
+     * back to pre-conforming behaviour if user requested so with
+     * LD_LIBRARY_PATH_RPATH environment variable and ignore -z
+     * nodeflib.
+     */
+    if (objgiven && refobj->rpath != NULL && ld_library_path_rpath) {
+	if ((pathname = search_library_path(name, ld_library_path)) != NULL ||
+	  (refobj != NULL &&
+	  (pathname = search_library_path(name, refobj->rpath)) != NULL) ||
+          (pathname = search_library_path(name, gethints(false))) != NULL ||
+	  (pathname = search_library_path(name, STANDARD_LIBRARY_PATH)) != NULL)
+	    return (pathname);
+    } else {
+	if ((objgiven &&
+	  (pathname = search_library_path(name, refobj->rpath)) != NULL) ||
+	  (objgiven && refobj->runpath == NULL && refobj != obj_main &&
+	  (pathname = search_library_path(name, obj_main->rpath)) != NULL) ||
+	  (pathname = search_library_path(name, ld_library_path)) != NULL ||
+	  (objgiven &&
+	  (pathname = search_library_path(name, refobj->runpath)) != NULL) ||
+	  (pathname = search_library_path(name, gethints(refobj->z_nodeflib)))
+	  != NULL ||
+	  (objgiven && !refobj->z_nodeflib &&
+	  (pathname = search_library_path(name, STANDARD_LIBRARY_PATH)) != NULL))
+	    return (pathname);
+    }
 
-    if(refobj != NULL && refobj->path != NULL) {
+    if (objgiven && refobj->path != NULL) {
 	_rtld_error("Shared object \"%s\" not found, required by \"%s\"",
 	  name, basename(refobj->path));
     } else {
@@ -1520,41 +1573,142 @@ find_symdef(unsigned long symnum, const 
 
 /*
  * Return the search path from the ldconfig hints file, reading it if
- * necessary.  Returns NULL if there are problems with the hints file,
+ * necessary.  If nostdlib is true, then the default search paths are
+ * not added to result.
+ *
+ * Returns NULL if there are problems with the hints file,
  * or if the search path there is empty.
  */
 static const char *
-gethints(void)
+gethints(bool nostdlib)
 {
-    static char *hints;
-
-    if (hints == NULL) {
-	int fd;
+	static char *hints, *filtered_path;
 	struct elfhints_hdr hdr;
+	struct fill_search_info_args sargs, hargs;
+	struct dl_serinfo smeta, hmeta, *SLPinfo, *hintinfo;
+	struct dl_serpath *SLPpath, *hintpath;
 	char *p;
+	unsigned int SLPndx, hintndx, fndx, fcount;
+	int fd;
+	size_t flen;
+	bool skip;
 
-	/* Keep from trying again in case the hints file is bad. */
-	hints = "";
-
-	if ((fd = open(ld_elf_hints_path, O_RDONLY)) == -1)
-	    return NULL;
-	if (read(fd, &hdr, sizeof hdr) != sizeof hdr ||
-	  hdr.magic != ELFHINTS_MAGIC ||
-	  hdr.version != 1) {
-	    close(fd);
-	    return NULL;
+	/* First call, read the hints file */
+	if (hints == NULL) {
+		/* Keep from trying again in case the hints file is bad. */
+		hints = "";
+
+		if ((fd = open(ld_elf_hints_path, O_RDONLY)) == -1)
+			return (NULL);
+		if (read(fd, &hdr, sizeof hdr) != sizeof hdr ||
+		    hdr.magic != ELFHINTS_MAGIC ||
+		    hdr.version != 1) {
+			close(fd);
+			return (NULL);
+		}
+		p = xmalloc(hdr.dirlistlen + 1);
+		if (lseek(fd, hdr.strtab + hdr.dirlist, SEEK_SET) == -1 ||
+		    read(fd, p, hdr.dirlistlen + 1) !=
+		    (ssize_t)hdr.dirlistlen + 1) {
+			free(p);
+			close(fd);
+			return (NULL);
+		}
+		hints = p;
+		close(fd);
 	}
-	p = xmalloc(hdr.dirlistlen + 1);
-	if (lseek(fd, hdr.strtab + hdr.dirlist, SEEK_SET) == -1 ||
-	  read(fd, p, hdr.dirlistlen + 1) != (ssize_t)hdr.dirlistlen + 1) {
-	    free(p);
-	    close(fd);
-	    return NULL;
+
+	/*
+	 * If caller agreed to receive list which includes the default
+	 * paths, we are done. Otherwise, if we still did not
+	 * calculated filtered result, do it now.
+	 */
+	if (!nostdlib)
+		return (hints[0] != '\0' ? hints : NULL);
+	if (filtered_path != NULL)
+		goto filt_ret;
+
+	/*
+	 * Obtain the list of all configured search paths, and the
+	 * list of the default paths.
+	 *
+	 * First estimate the size of the results.
+	 */
+	smeta.dls_size = __offsetof(struct dl_serinfo, dls_serpath);
+	smeta.dls_cnt = 0;
+	hmeta.dls_size = __offsetof(struct dl_serinfo, dls_serpath);
+	hmeta.dls_cnt = 0;
+
+	sargs.request = RTLD_DI_SERINFOSIZE;
+	sargs.serinfo = &smeta;
+	hargs.request = RTLD_DI_SERINFOSIZE;
+	hargs.serinfo = &hmeta;
+
+	path_enumerate(STANDARD_LIBRARY_PATH, fill_search_info, &sargs);
+	path_enumerate(p, fill_search_info, &hargs);
+
+	SLPinfo = xmalloc(smeta.dls_size);
+	hintinfo = xmalloc(hmeta.dls_size);
+
+	/*
+	 * Next fetch both sets of paths.
+	 */
+	sargs.request = RTLD_DI_SERINFO;
+	sargs.serinfo = SLPinfo;
+	sargs.serpath = &SLPinfo->dls_serpath[0];
+	sargs.strspace = (char *)&SLPinfo->dls_serpath[smeta.dls_cnt];
+
+	hargs.request = RTLD_DI_SERINFO;
+	hargs.serinfo = hintinfo;
+	hargs.serpath = &hintinfo->dls_serpath[0];
+	hargs.strspace = (char *)&hintinfo->dls_serpath[hmeta.dls_cnt];
+
+	path_enumerate(STANDARD_LIBRARY_PATH, fill_search_info, &sargs);
+	path_enumerate(p, fill_search_info, &hargs);
+
+	/*
+	 * Now calculate the difference between two sets, by excluding
+	 * standard paths from the full set.
+	 */
+	fndx = 0;
+	fcount = 0;
+	filtered_path = xmalloc(hdr.dirlistlen + 1);
+	hintpath = &hintinfo->dls_serpath[0];
+	for (hintndx = 0; hintndx < hmeta.dls_cnt; hintndx++, hintpath++) {
+		skip = false;
+		SLPpath = &SLPinfo->dls_serpath[0];
+		/*
+		 * Check each standard path against current.
+		 */
+		for (SLPndx = 0; SLPndx < smeta.dls_cnt; SLPndx++, SLPpath++) {
+			/* matched, skip the path */
+			if (!strcmp(hintpath->dls_name, SLPpath->dls_name)) {
+				skip = true;
+				break;
+			}
+		}
+		if (skip)
+			continue;
+		/*
+		 * Not matched against any standard path, add the path
+		 * to result. Separate consequtive paths with ':'.
+		 */
+		if (fcount > 0) {
+			filtered_path[fndx] = ':';
+			fndx++;
+		}
+		fcount++;
+		flen = strlen(hintpath->dls_name);
+		strncpy((filtered_path + fndx),	hintpath->dls_name, flen);
+		fndx += flen;
 	}
-	hints = p;
-	close(fd);
-    }
-    return hints[0] != '\0' ? hints : NULL;
+	filtered_path[fndx] = '\0';
+
+	free(SLPinfo);
+	free(hintinfo);
+
+filt_ret:
+	return (filtered_path[0] != '\0' ? filtered_path : NULL);
 }
 
 static void
@@ -1600,6 +1754,7 @@ init_rtld(caddr_t mapbase, Elf_Auxinfo *
     Obj_Entry objtmp;	/* Temporary rtld object */
     const Elf_Dyn *dyn_rpath;
     const Elf_Dyn *dyn_soname;
+    const Elf_Dyn *dyn_runpath;
 
     /*
      * Conjure up an Obj_Entry structure for the dynamic linker.
@@ -1616,7 +1771,7 @@ init_rtld(caddr_t mapbase, Elf_Auxinfo *
 #endif
     if (RTLD_IS_DYNAMIC()) {
 	objtmp.dynamic = rtld_dynamic(&objtmp);
-	digest_dynamic1(&objtmp, 1, &dyn_rpath, &dyn_soname);
+	digest_dynamic1(&objtmp, 1, &dyn_rpath, &dyn_soname, &dyn_runpath);
 	assert(objtmp.needed == NULL);
 #if !defined(__mips__)
 	/* MIPS has a bogus DT_TEXTREL. */
@@ -1642,7 +1797,7 @@ init_rtld(caddr_t mapbase, Elf_Auxinfo *
     if (aux_info[AT_OSRELDATE] != NULL)
 	    osreldate = aux_info[AT_OSRELDATE]->a_un.a_val;
 
-    digest_dynamic2(&obj_rtld, dyn_rpath, dyn_soname);
+    digest_dynamic2(&obj_rtld, dyn_rpath, dyn_soname, dyn_runpath);
 
     /* Replace the path with a dynamically allocated copy. */
     obj_rtld.path = xstrdup(PATH_RTLD);
@@ -3070,14 +3225,6 @@ dl_iterate_phdr(__dl_iterate_hdr_callbac
     return (error);
 }
 
-struct fill_search_info_args {
-    int		 request;
-    unsigned int flags;
-    Dl_serinfo  *serinfo;
-    Dl_serpath  *serpath;
-    char	*strspace;
-};
-
 static void *
 fill_search_info(const char *dir, size_t dirlen, void *param)
 {
@@ -3087,7 +3234,7 @@ fill_search_info(const char *dir, size_t
 
     if (arg->request == RTLD_DI_SERINFOSIZE) {
 	arg->serinfo->dls_cnt ++;
-	arg->serinfo->dls_size += sizeof(Dl_serpath) + dirlen + 1;
+	arg->serinfo->dls_size += sizeof(struct dl_serpath) + dirlen + 1;
     } else {
 	struct dl_serpath *s_entry;
 
@@ -3117,10 +3264,12 @@ do_search_info(const Obj_Entry *obj, int
     _info.dls_size = __offsetof(struct dl_serinfo, dls_serpath);
     _info.dls_cnt  = 0;
 
-    path_enumerate(ld_library_path, fill_search_info, &args);
     path_enumerate(obj->rpath, fill_search_info, &args);
-    path_enumerate(gethints(), fill_search_info, &args);
-    path_enumerate(STANDARD_LIBRARY_PATH, fill_search_info, &args);
+    path_enumerate(ld_library_path, fill_search_info, &args);
+    path_enumerate(obj->runpath, fill_search_info, &args);
+    path_enumerate(gethints(obj->z_nodeflib), fill_search_info, &args);
+    if (!obj->z_nodeflib)
+      path_enumerate(STANDARD_LIBRARY_PATH, fill_search_info, &args);
 
 
     if (request == RTLD_DI_SERINFOSIZE) {
@@ -3139,20 +3288,26 @@ do_search_info(const Obj_Entry *obj, int
     args.serpath  = &info->dls_serpath[0];
     args.strspace = (char *)&info->dls_serpath[_info.dls_cnt];
 
+    args.flags = LA_SER_RUNPATH;
+    if (path_enumerate(obj->rpath, fill_search_info, &args) != NULL)
+	return (-1);
+
     args.flags = LA_SER_LIBPATH;
     if (path_enumerate(ld_library_path, fill_search_info, &args) != NULL)
 	return (-1);
 
     args.flags = LA_SER_RUNPATH;
-    if (path_enumerate(obj->rpath, fill_search_info, &args) != NULL)
+    if (path_enumerate(obj->runpath, fill_search_info, &args) != NULL)
 	return (-1);
 
     args.flags = LA_SER_CONFIG;
-    if (path_enumerate(gethints(), fill_search_info, &args) != NULL)
+    if (path_enumerate(gethints(obj->z_nodeflib), fill_search_info, &args)
+      != NULL)
 	return (-1);
 
     args.flags = LA_SER_DEFAULT;
-    if (path_enumerate(STANDARD_LIBRARY_PATH, fill_search_info, &args) != NULL)
+    if (!obj->z_nodeflib &&
+      path_enumerate(STANDARD_LIBRARY_PATH, fill_search_info, &args) != NULL)
 	return (-1);
     return (0);
 }

Modified: head/libexec/rtld-elf/rtld.h
==============================================================================
--- head/libexec/rtld-elf/rtld.h	Sun Jul 15 10:49:16 2012	(r238470)
+++ head/libexec/rtld-elf/rtld.h	Sun Jul 15 10:53:48 2012	(r238471)
@@ -222,6 +222,7 @@ typedef struct Struct_Obj_Entry {
     const Elf_Hashelt *chain_zero_gnu;	/* GNU hash table value array (Zeroed) */
 
     char *rpath;		/* Search path specified in object */
+    char *runpath;		/* Search path with different priority */
     Needed_Entry *needed;	/* Shared objects needed by this one (%) */
     Needed_Entry *needed_filtees;
     Needed_Entry *needed_aux_filtees;
@@ -258,6 +259,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_nodeflib : 1;	/* Don't search default library path */
     bool ref_nodel : 1;		/* Refcount increased to prevent dlclose */
     bool init_scanned: 1;	/* Object is already on init list. */
     bool on_fini_list: 1;	/* Object is already on fini list. */
@@ -321,6 +323,14 @@ struct Struct_RtldLockState {
 	sigjmp_buf env;
 };
 
+struct fill_search_info_args {
+	int request;
+	unsigned int flags;
+	struct dl_serinfo *serinfo;
+	struct dl_serpath *serpath;
+	char *strspace;
+};
+
 /*
  * The pack of arguments and results for the symbol lookup functions.
  */



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201207151053.q6FArnqO042991>