Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add '--allowed-rpath-prefixes' option to '--shrink-rpath' … #98

Merged
merged 2 commits into from
Sep 1, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions README
Original file line number Diff line number Diff line change
Expand Up @@ -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):

Expand Down
6 changes: 6 additions & 0 deletions patchelf.1
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
60 changes: 45 additions & 15 deletions src/patchelf.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

=> for (auto & it : allowedPrefixes).

if (!s.compare(0, it->size(), *it)) return true;
}
return false;
}


static unsigned int getPageSize(){
return pageSize;
}
Expand Down Expand Up @@ -169,7 +192,7 @@ class ElfFile

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);

Expand Down Expand Up @@ -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");

Expand Down Expand Up @@ -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). */
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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();

Expand Down Expand Up @@ -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\
Expand Down Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion tests/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
47 changes: 47 additions & 0 deletions tests/shrink-rpath-with-allowed-prefixes.sh
Original file line number Diff line number Diff line change
@@ -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