tech-toolchain archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Fixing $ORGIN RPATHs - at least some of them



Hey folks,

an increasing amount of software nowadays does side-by-side shared
objects (the rust compiler being the one that triggered this for
me recently), that is for example a tree structure like:

  $arbitrary-install-directory/bin/mybinary
  $arbitrary-install-directory/lib/liba.so
  $arbitrary-install-directory/lib/libb.so
  $arbitrary-install-directory/lib/libc.so

and they embed an RPATH like $ORIGIN/../lib inside mybinary.
This looks like:

Dynamic section at offset 0xaa8 contains 21 entries:
  Tag        Type                         Name/Value
 0x0000000000000001 (NEEDED)             Shared library: [libtest.so.1]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.12]
 0x000000000000000f (RPATH)              Library rpath: [$ORIGIN/../lib]
 0x000000000000000c (INIT)               0x690
 0x000000000000000d (FINI)               0x940

and it usually just works fine on NetBSD.

The way we do this now is pretty cheap: if the path used to exec the binary
is an absolute path, we copy it to the AUX vector and ld.elf_so retrieves
it from there.

For relative paths we have code that might work depending on the vnode
name cache, but it is racy/not always successfull and so has been
disabled for now.

Since none of our base binaries nor most pkgs from pkgsrc need $ORIGIN,
it is good to avoid expensive operations in the exec path before we even
know if $ORIGIN might be used.

We have a second method to query that path, and that is with /proc
being mounted on procfs. The code in procfs is a bit expensive, and might
fail in some environments (directory has been removed or is unaccessible),
but I guess for many programs using $ORIGIN it will not matter at all.

The patch below makes ld.elf_so try to fall back to /proc/current/exe
if the kernel did not pass an execname in AUX and $ORIGIN needs to
be expanded.

I tested it, it works, and size difference in ld.elf_so is minimal.

Any objections?

One detail I'm always unsure about: is PATH_MAX inclusive the terminating 0?

Martin
Index: expand.c
===================================================================
RCS file: /cvsroot/src/libexec/ld.elf_so/expand.c,v
retrieving revision 1.6
diff -u -p -r1.6 expand.c
--- expand.c	6 May 2013 08:02:20 -0000	1.6
+++ expand.c	5 Nov 2017 13:47:32 -0000
@@ -35,6 +35,7 @@ __RCSID("$NetBSD: expand.c,v 1.6 2013/05
 
 #include <ctype.h>
 #include <string.h>
+#include <unistd.h>
 #include <sys/sysctl.h>
 
 #ifdef DEBUG_EXPAND
@@ -75,6 +76,8 @@ expand(char *buf, const char *execname, 
 	char *bp = buf;
 	size_t len;
 	char name[32];
+	char path[PATH_MAX];
+	ssize_t l;
 
 	switch (what) {
 	case 0:	/* HWCAP XXX: Not yet */
@@ -82,8 +85,20 @@ expand(char *buf, const char *execname, 
 		return 0;
 
 	case 2:	/* ORIGIN */
+		if (execname == NULL) {
+			/*
+			 * The kernel did not pass execname in AUX, but
+			 * maybe we have /proc mounted and can get
+			 * it from there?
+			 */
+			l = readlink("/proc/curproc/exe", path, PATH_MAX);
+			if (l > 0) {
+				path[l] = '\0';
+				execname = path;
+			}
+		}
 		if (execname == NULL)
-			xerr(1, "execname not specified in AUX vector");
+			xerr(1, "execname not available");
 		if ((ep = strrchr(p = execname, '/')) == NULL)
 			xerr(1, "bad execname `%s' in AUX vector", execname);
 		break;


Home | Main Index | Thread Index | Old Index