ld.so: Add --rpath-prefix option Scratchbox2 uses the --rpath-prefix option to make the linker search for required libraries under the target rootfs. Packages that run their own binaries as a build step may use RPATH to resolve dependencies located under the build tree - such RPATHs must not be redirected under the target rootfs. It is a common assumption in Scratchbox2 that builds happen under user's home directory. Therefore, RPATHs under /home are excluded from this manipulation. diff --git a/elf/dl-load.c b/elf/dl-load.c index c51e4b37..57a357ea 100644 --- a/elf/dl-load.c +++ b/elf/dl-load.c @@ -443,7 +443,8 @@ static size_t max_dirnamelen; static struct r_search_path_elem ** fillin_rpath (char *rpath, struct r_search_path_elem **result, const char *sep, - const char *what, const char *where, struct link_map *l) + const char *what, const char *where, struct link_map *l, + const char *rpath_prefix) { char *cp; size_t nelems = 0; @@ -483,9 +484,24 @@ fillin_rpath (char *rpath, struct r_search_path_elem **result, const char *sep, } /* See if this directory is already known. */ - for (dirp = GL(dl_all_dirs); dirp != NULL; dirp = dirp->next) - if (dirp->dirnamelen == len && memcmp (cp, dirp->dirname, len) == 0) - break; + if (__builtin_expect (rpath_prefix != NULL, 0) + && (memcmp (cp, "/home/", 6) != 0)) + { + /* has rpath_prefix */ + size_t rpath_prefix_len = strlen (rpath_prefix); + + for (dirp = GL(dl_all_dirs); dirp != NULL; dirp = dirp->next) + if (dirp->dirnamelen == (rpath_prefix_len+len) && + (memcmp (cp, rpath_prefix, rpath_prefix_len) == 0) && + (memcmp (cp+rpath_prefix_len, dirp->dirname, len) == 0)) + break; + } + else + { + for (dirp = GL(dl_all_dirs); dirp != NULL; dirp = dirp->next) + if (dirp->dirnamelen == len && memcmp (cp, dirp->dirname, len) == 0) + break; + } if (dirp != NULL) { @@ -503,22 +519,44 @@ fillin_rpath (char *rpath, struct r_search_path_elem **result, const char *sep, size_t cnt; enum r_dir_status init_val; size_t where_len = where ? strlen (where) + 1 : 0; + size_t rpath_prefix_len = 0; + + if (__builtin_expect (rpath_prefix != NULL, 0) + && (memcmp (cp, "/home/", 6) != 0) + && !__libc_enable_secure) + { + rpath_prefix_len = strlen (rpath_prefix); + if (*cp != '/') rpath_prefix_len++; /* need to add a '/' */ + } /* It's a new directory. Create an entry and add it. */ dirp = (struct r_search_path_elem *) malloc (sizeof (*dirp) + ncapstr * sizeof (enum r_dir_status) - + where_len + len + 1); + + where_len + rpath_prefix_len + len + 1); if (dirp == NULL) _dl_signal_error (ENOMEM, NULL, NULL, N_("cannot create cache for search path")); dirp->dirname = ((char *) dirp + sizeof (*dirp) + ncapstr * sizeof (enum r_dir_status)); - *((char *) __mempcpy ((char *) dirp->dirname, cp, len)) = '\0'; - dirp->dirnamelen = len; + if (rpath_prefix_len == 0) + { + *((char *) __mempcpy ((char *) dirp->dirname, cp, len)) = '\0'; + } + else + { + char *prefixend; + + prefixend = (char *) __mempcpy ((char *) dirp->dirname, + rpath_prefix, rpath_prefix_len); + if (*cp != '/') + prefixend[-1] = '/'; /* replace \0 */ + *((char *) __mempcpy (prefixend, cp, len)) = '\0'; + } + dirp->dirnamelen = len + rpath_prefix_len; - if (len > max_dirnamelen) - max_dirnamelen = len; + if ((len + rpath_prefix_len) > max_dirnamelen) + max_dirnamelen = len + rpath_prefix_len; /* We have to make sure all the relative directories are never ignored. The current directory might change and @@ -529,7 +567,8 @@ fillin_rpath (char *rpath, struct r_search_path_elem **result, const char *sep, dirp->what = what; if (__glibc_likely (where != NULL)) - dirp->where = memcpy ((char *) dirp + sizeof (*dirp) + len + 1 + dirp->where = memcpy ((char *) dirp + sizeof (*dirp) + + rpath_prefix_len + len + 1 + (ncapstr * sizeof (enum r_dir_status)), where, where_len); else @@ -628,7 +667,7 @@ decompose_rpath (struct r_search_path_struct *sps, _dl_signal_error (ENOMEM, NULL, NULL, errstring); } - fillin_rpath (copy, result, ":", what, where, l); + fillin_rpath (copy, result, ":", what, where, l, GLRO(dl_rpath_prefix)); /* Free the copied RPATH string. `fillin_rpath' make own copies if necessary. */ @@ -813,7 +852,7 @@ _dl_init_paths (const char *llp) } (void) fillin_rpath (llp_tmp, env_path_list.dirs, ":;", - "LD_LIBRARY_PATH", NULL, l); + "LD_LIBRARY_PATH", NULL, l, NULL/*no prefix*/); if (env_path_list.dirs[0] == NULL) { diff --git a/elf/dl-support.c b/elf/dl-support.c index b5f10d5a..cdf189b7 100644 --- a/elf/dl-support.c +++ b/elf/dl-support.c @@ -58,6 +58,9 @@ const char *_dl_profile_output; ignored. */ const char *_dl_inhibit_rpath; +/* prefix to be added to all RUNPATHs and RPATHs */ +const char *_dl_rpath_prefix = NULL; + /* The map for the object we will profile. */ struct link_map *_dl_profile_map; diff --git a/elf/rtld.c b/elf/rtld.c index 385b5f88..9bc6d162 100644 --- a/elf/rtld.c +++ b/elf/rtld.c @@ -967,6 +967,15 @@ dl_main (const ElfW(Phdr) *phdr, { GLRO(dl_inhibit_rpath) = _dl_argv[2]; + _dl_skip_args += 2; + _dl_argc -= 2; + _dl_argv += 2; + } + else if (! strcmp (_dl_argv[1], "--rpath-prefix") + && _dl_argc > 2) + { + GLRO(dl_rpath_prefix) = _dl_argv[2]; + _dl_skip_args += 2; _dl_argc -= 2; _dl_argv += 2; @@ -1013,6 +1022,8 @@ of this helper program; chances are you did not intend to run this program.\n\ --inhibit-cache Do not use " LD_SO_CACHE "\n\ --library-path PATH use given PATH instead of content of the environment\n\ variable LD_LIBRARY_PATH\n\ + --rpath-prefix PREFIX add PREFIX to every RUNPATH and RPATH component\n\ + unless it is a path under the /home tree\n\ --inhibit-rpath LIST ignore RUNPATH and RPATH information in object names\n\ in LIST\n\ --argv0 STRING use STRING as argv[0]\n\ diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h index 95dc8751..83b6ae2f 100644 --- a/sysdeps/generic/ldsodefs.h +++ b/sysdeps/generic/ldsodefs.h @@ -617,6 +617,12 @@ struct rtld_global_ro /* List of auditing interfaces. */ struct audit_ifaces *_dl_audit; unsigned int _dl_naudit; +#endif + + /* prefix for RPATH + RUNPATH components. */ + EXTERN const char *_dl_rpath_prefix; + +#ifdef SHARED }; # define __rtld_global_attribute__ # if IS_IN (rtld)