From d306abeb3549a574408fe8de490415f67f2a486e Mon Sep 17 00:00:00 2001 From: Farid Zakaria Date: Mon, 20 Dec 2021 16:01:18 -0800 Subject: [PATCH 1/5] Allow multiple modifications in same call `patchelf` previously would incorrectly patch the ELF header if it was called with multiple changes at once such as _add_ & _replace_. In order to support that, rewrite the sections in between each section modification. Fix #359 --- src/patchelf.cc | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/patchelf.cc b/src/patchelf.cc index eaf2a42f..0923ec0b 100644 --- a/src/patchelf.cc +++ b/src/patchelf.cc @@ -1878,10 +1878,22 @@ static void patchElf2(ElfFile && elfFile, const FileContents & fileContents, con if (printNeeded) elfFile.printNeededLibs(); - elfFile.removeNeeded(neededLibsToRemove); - elfFile.replaceNeeded(neededLibsToReplace); - elfFile.addNeeded(neededLibsToAdd); - elfFile.clearSymbolVersions(symbolsToClearVersion); + if (!neededLibsToRemove.empty()) { + elfFile.removeNeeded(neededLibsToRemove); + elfFile.rewriteSections(); + } + if (!neededLibsToReplace.empty()) { + elfFile.replaceNeeded(neededLibsToReplace); + elfFile.rewriteSections(); + } + if (!neededLibsToAdd.empty()) { + elfFile.addNeeded(neededLibsToAdd); + elfFile.rewriteSections(); + } + if (!symbolsToClearVersion.empty()) { + elfFile.clearSymbolVersions(symbolsToClearVersion); + elfFile.rewriteSections(); + } if (noDefaultLib) elfFile.noDefaultLib(); From e268662c32464f3a09d3aecf069f906a562ab350 Mon Sep 17 00:00:00 2001 From: Farid Zakaria Date: Mon, 20 Dec 2021 17:28:34 -0800 Subject: [PATCH 2/5] Add a unit test --- result | 1 + tests/Makefile.am | 3 ++- tests/replace-add-needed.sh | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 37 insertions(+), 1 deletion(-) create mode 120000 result create mode 100755 tests/replace-add-needed.sh diff --git a/result b/result new file mode 120000 index 00000000..8e5a9ed8 --- /dev/null +++ b/result @@ -0,0 +1 @@ +/nix/store/p5zbzmcvkgbqldf8g5zsla0xhdf8w2yg-patchelf-0.14.3 \ No newline at end of file diff --git a/tests/Makefile.am b/tests/Makefile.am index 404f159d..b280e62d 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -39,7 +39,8 @@ src_TESTS = \ basic-flags.sh \ set-empty-rpath.sh \ phdr-corruption.sh \ - replace-needed.sh + replace-needed.sh \ + replace-add-needed.sh build_TESTS = \ $(no_rpath_arch_TESTS) diff --git a/tests/replace-add-needed.sh b/tests/replace-add-needed.sh new file mode 100755 index 00000000..b4868978 --- /dev/null +++ b/tests/replace-add-needed.sh @@ -0,0 +1,34 @@ +#! /bin/sh -e +SCRATCH=scratch/$(basename $0 .sh) +PATCHELF=$(readlink -f "../src/patchelf") + +rm -rf ${SCRATCH} +mkdir -p ${SCRATCH} + +cp simple ${SCRATCH}/ +cp libfoo.so ${SCRATCH}/ +cp libbar.so ${SCRATCH}/ + + +cd ${SCRATCH} + +libcldd=$(ldd ./simple | grep -oP "(?<=libc.so.6 => )[^ ]+") + +# We have to set the soname on these libraries +${PATCHELF} --set-soname libbar.so ./libbar.so + +# Add a libbar.so so we can rewrite it later +${PATCHELF} --add-needed libbar.so ./simple + +${PATCHELF} --replace-needed libc.so.6 ${libcldd} \ + --replace-needed libbar.so $(readlink -f ./libbar.so) \ + --add-needed $(readlink -f ./libfoo.so) \ + ./simple + +exitCode=0 +./simple || exitCode=$? + +if test "$exitCode" != 0; then + ldd ./simple + exit 1 +fi From dc375bc7cd94218208387e749a1c552a947e6a72 Mon Sep 17 00:00:00 2001 From: Farid Zakaria Date: Mon, 20 Dec 2021 17:36:06 -0800 Subject: [PATCH 3/5] Remove result and add it to gitignore --- .gitignore | 1 + result | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) delete mode 120000 result diff --git a/.gitignore b/.gitignore index 921b9f85..c3f60a5d 100644 --- a/.gitignore +++ b/.gitignore @@ -36,3 +36,4 @@ Makefile .direnv/ .vscode/ .idea/ +result diff --git a/result b/result deleted file mode 120000 index 8e5a9ed8..00000000 --- a/result +++ /dev/null @@ -1 +0,0 @@ -/nix/store/p5zbzmcvkgbqldf8g5zsla0xhdf8w2yg-patchelf-0.14.3 \ No newline at end of file From d02a3ecdd7b811683d319efa9d24bdae09a3036d Mon Sep 17 00:00:00 2001 From: Farid Zakaria Date: Tue, 21 Dec 2021 05:51:04 -0800 Subject: [PATCH 4/5] Code clarity and test working with musl Made changes according to feedback from @Mic92 such as moving the `rewriteSections` inline into every method. Improved `replace-add-needed.sh` to work with musl libc --- src/patchelf.cc | 33 ++++++++++++++++----------------- tests/replace-add-needed.sh | 2 +- 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/src/patchelf.cc b/src/patchelf.cc index 0923ec0b..70390f45 100644 --- a/src/patchelf.cc +++ b/src/patchelf.cc @@ -1311,6 +1311,7 @@ void ElfFile::modifySoname(sonameMode op, const std::string & } changed = true; + this->rewriteSections(); } template @@ -1319,6 +1320,7 @@ void ElfFile::setInterpreter(const std::string & newInterpret std::string & section = replaceSection(".interp", newInterpreter.size() + 1); setSubstr(section, 0, newInterpreter + '\0'); changed = true; + this->rewriteSections(); } @@ -1395,6 +1397,7 @@ void ElfFile::removeRPath(Elf_Shdr & shdrDynamic) { } } memset(last, 0, sizeof(Elf_Dyn) * (dyn - last)); + this->rewriteSections(); } template @@ -1541,6 +1544,7 @@ void ElfFile::modifyRPath(RPathOp op, newDyn.d_un.d_val = shdrDynStr.sh_size; setSubstr(newDynamic, 0, std::string((char *) &newDyn, sizeof(Elf_Dyn))); } + this->rewriteSections(); } @@ -1570,6 +1574,8 @@ void ElfFile::removeNeeded(const std::set & libs } memset(last, 0, sizeof(Elf_Dyn) * (dyn - last)); + + this->rewriteSections(); } template @@ -1693,6 +1699,8 @@ void ElfFile::replaceNeeded(const std::maprewriteSections(); } template @@ -1743,6 +1751,8 @@ void ElfFile::addNeeded(const std::set & libs) } changed = true; + + this->rewriteSections(); } template @@ -1799,6 +1809,7 @@ void ElfFile::noDefaultLib() setSubstr(newDynamic, 0, std::string((char *) &newDyn, sizeof(Elf_Dyn))); } + this->rewriteSections(); changed = true; } @@ -1828,6 +1839,7 @@ void ElfFile::clearSymbolVersions(const std::set } } changed = true; + this->rewriteSections(); } static bool printInterpreter = false; @@ -1878,28 +1890,15 @@ static void patchElf2(ElfFile && elfFile, const FileContents & fileContents, con if (printNeeded) elfFile.printNeededLibs(); - if (!neededLibsToRemove.empty()) { - elfFile.removeNeeded(neededLibsToRemove); - elfFile.rewriteSections(); - } - if (!neededLibsToReplace.empty()) { - elfFile.replaceNeeded(neededLibsToReplace); - elfFile.rewriteSections(); - } - if (!neededLibsToAdd.empty()) { - elfFile.addNeeded(neededLibsToAdd); - elfFile.rewriteSections(); - } - if (!symbolsToClearVersion.empty()) { - elfFile.clearSymbolVersions(symbolsToClearVersion); - elfFile.rewriteSections(); - } + elfFile.removeNeeded(neededLibsToRemove); + elfFile.replaceNeeded(neededLibsToReplace); + elfFile.addNeeded(neededLibsToAdd); + elfFile.clearSymbolVersions(symbolsToClearVersion); if (noDefaultLib) elfFile.noDefaultLib(); if (elfFile.isChanged()){ - elfFile.rewriteSections(); writeFile(fileName, elfFile.fileContents); } else if (alwaysWrite) { debug("not modified, but alwaysWrite=true\n"); diff --git a/tests/replace-add-needed.sh b/tests/replace-add-needed.sh index b4868978..4c88fd9c 100755 --- a/tests/replace-add-needed.sh +++ b/tests/replace-add-needed.sh @@ -12,7 +12,7 @@ cp libbar.so ${SCRATCH}/ cd ${SCRATCH} -libcldd=$(ldd ./simple | grep -oP "(?<=libc.so.6 => )[^ ]+") +libcldd=$(ldd ./simple | awk '/ => / { print $3 }' | grep .so | head -n 1) # We have to set the soname on these libraries ${PATCHELF} --set-soname libbar.so ./libbar.so From b92a6e895140c41535edb813f366d0fe00fba4fa Mon Sep 17 00:00:00 2001 From: Farid Zakaria Date: Tue, 21 Dec 2021 14:30:45 -0800 Subject: [PATCH 5/5] Fix replace-add-needed.sh test for musl --- tests/replace-add-needed.sh | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/tests/replace-add-needed.sh b/tests/replace-add-needed.sh index 4c88fd9c..ab0d3532 100755 --- a/tests/replace-add-needed.sh +++ b/tests/replace-add-needed.sh @@ -9,10 +9,9 @@ cp simple ${SCRATCH}/ cp libfoo.so ${SCRATCH}/ cp libbar.so ${SCRATCH}/ - cd ${SCRATCH} -libcldd=$(ldd ./simple | awk '/ => / { print $3 }' | grep .so | head -n 1) +libcldd=$(ldd ./simple | awk '/ => / { print $3 }' | grep -E "(libc.so|ld-musl)") # We have to set the soname on these libraries ${PATCHELF} --set-soname libbar.so ./libbar.so @@ -20,6 +19,11 @@ ${PATCHELF} --set-soname libbar.so ./libbar.so # Add a libbar.so so we can rewrite it later ${PATCHELF} --add-needed libbar.so ./simple +# Make the NEEDED in libfoo the same as simple +# This is a current "bug" in musl +# https://www.openwall.com/lists/musl/2021/12/21/1 +${PATCHELF} --replace-needed libbar.so $(readlink -f ./libbar.so) ./libfoo.so + ${PATCHELF} --replace-needed libc.so.6 ${libcldd} \ --replace-needed libbar.so $(readlink -f ./libbar.so) \ --add-needed $(readlink -f ./libfoo.so) \ @@ -31,4 +35,4 @@ exitCode=0 if test "$exitCode" != 0; then ldd ./simple exit 1 -fi +fi \ No newline at end of file