summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEelco Dolstra <eelco.dolstra@logicblox.com>2016-09-01 09:39:06 (GMT)
committerGitHub <noreply@github.com>2016-09-01 09:39:06 (GMT)
commit9d2f4a174710b37bf6bacdce3716bcb664e02990 (patch)
treeb1348f8591c5f723404811adfdceba8df12c3616
parentc66b2deb6089d29cbb7261c28282da32ea65c384 (diff)
parent48143414941d91016efca2b0ef6f32475d6eaa75 (diff)
downloadpatchelf-9d2f4a174710b37bf6bacdce3716bcb664e02990.zip
patchelf-9d2f4a174710b37bf6bacdce3716bcb664e02990.tar.gz
patchelf-9d2f4a174710b37bf6bacdce3716bcb664e02990.tar.bz2
Merge pull request #98 from dezgeg/shrink-prefix
Add '--allowed-rpath-prefixes' option to '--shrink-rpath' …
-rw-r--r--README8
-rw-r--r--patchelf.16
-rw-r--r--src/patchelf.cc60
-rw-r--r--tests/Makefile.am2
-rwxr-xr-xtests/shrink-rpath-with-allowed-prefixes.sh47
5 files changed, 107 insertions, 16 deletions
diff --git a/README b/README
index eb291ba..406cefd 100644
--- a/README
+++ b/README
@@ -19,6 +19,14 @@ libraries. In particular, it can do the following:
an RPATH "/lib:/usr/lib:/foo/lib", and libfoo.so can only be found
in /foo/lib, then the new RPATH will be "/foo/lib".
+ In addition, the '--allowed-rpath-prefixes' option can be used for
+ further rpath tuning. For instance, if an executable has an RPATH
+ "/tmp/build-foo/.libs:/foo/lib", it is probably desirable to keep
+ the "/foo/lib" reference instead of the "/tmp" entry. To accomplish
+ that, use:
+
+ $ patchelf --shrink-rpath --allowed-rpath-prefixes /usr/lib:/foo/lib my-program
+
* Remove declared dependencies on dynamic libraries (DT_NEEDED
entries):
diff --git a/patchelf.1 b/patchelf.1
index 8067dff..ecf4217 100644
--- a/patchelf.1
+++ b/patchelf.1
@@ -53,6 +53,12 @@ For instance, if an executable references one library libfoo.so, has
an RPATH "/lib:/usr/lib:/foo/lib", and libfoo.so can only be found
in /foo/lib, then the new RPATH will be "/foo/lib".
+.IP "--allowed-rpath-prefixes PREFIXES"
+Combined with the "--shrink-rpath" option, this can be used for
+further rpath tuning. For instance, if an executable has an RPATH
+"/tmp/build-foo/.libs:/foo/lib", it is probably desirable to keep
+the "/foo/lib" reference instead of the "/tmp" entry.
+
.IP --print-rpath
Prints the RPATH for an executable or library.
diff --git a/src/patchelf.cc b/src/patchelf.cc
index ca8fb49..a59c12d 100644
--- a/src/patchelf.cc
+++ b/src/patchelf.cc
@@ -57,6 +57,29 @@ unsigned char * contents = 0;
#define ElfFileParamNames Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Addr, Elf_Off, Elf_Dyn, Elf_Sym, Elf_Verneed
+static vector<string> splitColonDelimitedString(const char * s){
+ vector<string> parts;
+ const char * pos = s;
+ while (*pos) {
+ const char * end = strchr(pos, ':');
+ if (!end) end = strchr(pos, 0);
+
+ parts.push_back(string(pos, end - pos));
+ if (*end == ':') ++end;
+ pos = end;
+ }
+
+ return parts;
+}
+
+static bool hasAllowedPrefix(const string & s, const vector<string> & allowedPrefixes){
+ for (vector<string>::const_iterator it = allowedPrefixes.begin(); it != allowedPrefixes.end(); ++it) {
+ if (!s.compare(0, it->size(), *it)) return true;
+ }
+ return false;
+}
+
+
static unsigned int getPageSize(){
return pageSize;
}
@@ -169,7 +192,7 @@ public:
typedef enum { rpPrint, rpShrink, rpSet, rpRemove } RPathOp;
- void modifyRPath(RPathOp op, string newRPath);
+ void modifyRPath(RPathOp op, vector<string> allowedRpathPrefixes, string newRPath);
void addNeeded(set<string> libs);
@@ -1027,7 +1050,7 @@ static void concatToRPath(string & rpath, const string & path)
template<ElfFileParams>
-void ElfFile<ElfFileParamNames>::modifyRPath(RPathOp op, string newRPath)
+void ElfFile<ElfFileParamNames>::modifyRPath(RPathOp op, vector<string> allowedRpathPrefixes, string newRPath)
{
Elf_Shdr & shdrDynamic = findSection(".dynamic");
@@ -1095,15 +1118,9 @@ void ElfFile<ElfFileParamNames>::modifyRPath(RPathOp op, string newRPath)
newRPath = "";
- char * pos = rpath;
- while (*pos) {
- char * end = strchr(pos, ':');
- if (!end) end = strchr(pos, 0);
-
- /* Get the name of the directory. */
- string dirName(pos, end - pos);
- if (*end == ':') ++end;
- pos = end;
+ vector<string> rpathDirs = splitColonDelimitedString(rpath);
+ for (vector<string>::iterator it = rpathDirs.begin(); it != rpathDirs.end(); ++it) {
+ const string & dirName = *it;
/* Non-absolute entries are allowed (e.g., the special
"$ORIGIN" hack). */
@@ -1112,6 +1129,13 @@ void ElfFile<ElfFileParamNames>::modifyRPath(RPathOp op, string newRPath)
continue;
}
+ /* If --allowed-rpath-prefixes was given, reject directories
+ not starting with any of the (colon-delimited) prefixes. */
+ if (!allowedRpathPrefixes.empty() && !hasAllowedPrefix(dirName, allowedRpathPrefixes)) {
+ debug("removing directory '%s' from RPATH because of non-allowed prefix\n", dirName.c_str());
+ continue;
+ }
+
/* For each library that we haven't found yet, see if it
exists in this directory. */
bool libFound = false;
@@ -1455,6 +1479,7 @@ static bool setSoname = false;
static string newSoname;
static string newInterpreter;
static bool shrinkRPath = false;
+static vector<string> allowedRpathPrefixes;
static bool removeRPath = false;
static bool setRPath = false;
static bool printRPath = false;
@@ -1483,14 +1508,14 @@ static void patchElf2(ElfFile & elfFile)
elfFile.setInterpreter(newInterpreter);
if (printRPath)
- elfFile.modifyRPath(elfFile.rpPrint, "");
+ elfFile.modifyRPath(elfFile.rpPrint, vector<string>(), "");
if (shrinkRPath)
- elfFile.modifyRPath(elfFile.rpShrink, "");
+ elfFile.modifyRPath(elfFile.rpShrink, allowedRpathPrefixes, "");
else if (removeRPath)
- elfFile.modifyRPath(elfFile.rpRemove, "");
+ elfFile.modifyRPath(elfFile.rpRemove, vector<string>(), "");
else if (setRPath)
- elfFile.modifyRPath(elfFile.rpSet, newRPath);
+ elfFile.modifyRPath(elfFile.rpSet, vector<string>(), newRPath);
if (printNeeded) elfFile.printNeededLibs();
@@ -1553,6 +1578,7 @@ void showHelp(const string & progName)
[--set-rpath RPATH]\n\
[--remove-rpath]\n\
[--shrink-rpath]\n\
+ [--allowed-rpath-prefixes PREFIXES]\t\tWith '--shrink-rpath', reject rpath entries not starting with the allowed prefix\n\
[--print-rpath]\n\
[--force-rpath]\n\
[--add-needed LIBRARY]\n\
@@ -1604,6 +1630,10 @@ int main(int argc, char * * argv)
else if (arg == "--shrink-rpath") {
shrinkRPath = true;
}
+ else if (arg == "--allowed-rpath-prefixes") {
+ if (++i == argc) error("missing argument");
+ allowedRpathPrefixes = splitColonDelimitedString(argv[i]);
+ }
else if (arg == "--set-rpath") {
if (++i == argc) error("missing argument");
setRPath = true;
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 4290fe3..32218e8 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -21,7 +21,7 @@ no_rpath_arch_TESTS = \
src_TESTS = \
plain-fail.sh plain-run.sh shrink-rpath.sh set-interpreter-short.sh \
set-interpreter-long.sh set-rpath.sh no-rpath.sh big-dynstr.sh \
- set-rpath-library.sh soname.sh
+ set-rpath-library.sh soname.sh shrink-rpath-with-allowed-prefixes.sh
build_TESTS = \
$(no_rpath_arch_TESTS)
diff --git a/tests/shrink-rpath-with-allowed-prefixes.sh b/tests/shrink-rpath-with-allowed-prefixes.sh
new file mode 100755
index 0000000..db24da2
--- /dev/null
+++ b/tests/shrink-rpath-with-allowed-prefixes.sh
@@ -0,0 +1,47 @@
+#! /bin/sh -e
+SCRATCH=scratch/$(basename $0 .sh)
+
+rm -rf ${SCRATCH}
+mkdir -p ${SCRATCH}
+mkdir -p ${SCRATCH}/libsA
+mkdir -p ${SCRATCH}/libsB
+
+cp main ${SCRATCH}/
+cp libfoo.so libbar.so ${SCRATCH}/libsA/
+cp libfoo.so libbar.so ${SCRATCH}/libsB/
+
+oldRPath=$(../src/patchelf --print-rpath ${SCRATCH}/main)
+if test -z "$oldRPath"; then oldRPath="/oops"; fi
+pathA="$(pwd)/${SCRATCH}/libsA"
+pathB="$(pwd)/${SCRATCH}/libsB"
+../src/patchelf --force-rpath --set-rpath $oldRPath:$pathA:$pathB ${SCRATCH}/main
+
+cp ${SCRATCH}/main ${SCRATCH}/mainA
+cp ${SCRATCH}/main ${SCRATCH}/mainB
+
+../src/patchelf --shrink-rpath ${SCRATCH}/main
+../src/patchelf --shrink-rpath --allowed-rpath-prefixes $oldRPath:$pathA ${SCRATCH}/mainA
+../src/patchelf --shrink-rpath --allowed-rpath-prefixes $oldRPath:$pathB ${SCRATCH}/mainB
+
+check() {
+ exe=$1
+ mustContain=$2
+ mustNotContain=$3
+
+ rpath=$(../src/patchelf --print-rpath $exe)
+ echo "RPATH of $exe after: $rpath"
+
+ if ! echo "$rpath" | grep -q $mustContain; then
+ echo "RPATH didn't contain '$mustContain' when it should have"
+ exit 1
+ fi
+
+ if echo "$rpath" | grep -q $mustNotContain; then
+ echo "RPATH contained '$mustNotContain' when it shouldn't have"
+ exit 1
+ fi
+}
+
+check ${SCRATCH}/main $pathA $pathB
+check ${SCRATCH}/mainA $pathA $pathB
+check ${SCRATCH}/mainB $pathB $pathA