Index: eglibc-2.19/elf/dl-load.c =================================================================== --- eglibc-2.19.orig/elf/dl-load.c +++ eglibc-2.19/elf/dl-load.c @@ -482,7 +482,7 @@ static size_t max_dirnamelen; static struct r_search_path_elem ** fillin_rpath (char *rpath, struct r_search_path_elem **result, const char *sep, int check_trusted, const char *what, const char *where, - struct link_map *l) + struct link_map *l, const char *rpath_prefix) { char *cp; size_t nelems = 0; @@ -520,9 +520,23 @@ fillin_rpath (char *rpath, struct r_sear } /* 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)) + { + /* 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) { @@ -540,22 +554,43 @@ fillin_rpath (char *rpath, struct r_sear 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) + && !INTUSE(__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 @@ -566,7 +601,8 @@ fillin_rpath (char *rpath, struct r_sear dirp->what = what; if (__builtin_expect (where != NULL, 1)) - 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 @@ -668,7 +704,7 @@ decompose_rpath (struct r_search_path_st _dl_signal_error (ENOMEM, NULL, NULL, errstring); } - fillin_rpath (copy, result, ":", 0, what, where, l); + fillin_rpath (copy, result, ":", 0, what, where, l, GLRO(dl_rpath_prefix)); /* Free the copied RPATH string. `fillin_rpath' make own copies if necessary. */ @@ -871,7 +907,7 @@ _dl_init_paths (const char *llp) (void) fillin_rpath (llp_tmp, env_path_list.dirs, ":;", INTUSE(__libc_enable_secure), "LD_LIBRARY_PATH", - NULL, l); + NULL, l, NULL/*no prefix*/); if (env_path_list.dirs[0] == NULL) { Index: eglibc-2.19/elf/dl-support.c =================================================================== --- eglibc-2.19.orig/elf/dl-support.c +++ eglibc-2.19/elf/dl-support.c @@ -61,6 +61,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; Index: eglibc-2.19/elf/rtld.c =================================================================== --- eglibc-2.19.orig/elf/rtld.c +++ eglibc-2.19/elf/rtld.c @@ -991,6 +991,15 @@ dl_main (const ElfW(Phdr) *phdr, _dl_argc -= 2; INTUSE(_dl_argv) += 2; } + else if (! strcmp (INTUSE(_dl_argv)[1], "--rpath-prefix") + && _dl_argc > 2) + { + GLRO(dl_rpath_prefix) = INTUSE(_dl_argv)[2]; + + _dl_skip_args += 2; + _dl_argc -= 2; + INTUSE(_dl_argv) += 2; + } else if (! strcmp (INTUSE(_dl_argv)[1], "--audit") && _dl_argc > 2) { process_dl_audit (INTUSE(_dl_argv)[2]); @@ -1025,6 +1034,7 @@ of this helper program; chances are you --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\ --inhibit-rpath LIST ignore RUNPATH and RPATH information in object names\n\ in LIST\n\ --audit LIST use objects named in LIST as auditors\n"); Index: eglibc-2.19/sysdeps/generic/ldsodefs.h =================================================================== --- eglibc-2.19.orig/sysdeps/generic/ldsodefs.h +++ eglibc-2.19/sysdeps/generic/ldsodefs.h @@ -600,6 +600,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__ # ifdef IS_IN_rtld