From 0b6b66687370f2ae97310edbdbd61e7a81ac3019 Mon Sep 17 00:00:00 2001 From: Breno Rodrigues Guimaraes Date: Thu, 16 Feb 2023 13:58:36 -0300 Subject: Add support for symbol name remapping --- src/patchelf.cc | 272 +++++++++++++++++++++++++++++++++++++++- src/patchelf.h | 72 ++++++++++- tests/Makefile.am | 23 +++- tests/rename-dynamic-symbols.sh | 84 +++++++++++++ 4 files changed, 444 insertions(+), 7 deletions(-) create mode 100755 tests/rename-dynamic-symbols.sh diff --git a/src/patchelf.cc b/src/patchelf.cc index e91e2ab..847d4dc 100644 --- a/src/patchelf.cc +++ b/src/patchelf.cc @@ -17,16 +17,18 @@ */ #include +#include #include #include #include +#include #include #include #include #include #include +#include #include -#include #include #include @@ -553,6 +555,27 @@ std::optional> ElfFile::tryF return {}; } +template +template +span ElfFile::getSectionSpan(const Elf_Shdr & shdr) const +{ + return span((T*)(fileContents->data() + rdi(shdr.sh_offset)), rdi(shdr.sh_size)/sizeof(T)); +} + +template +template +span ElfFile::getSectionSpan(const SectionName & sectionName) +{ + return getSectionSpan(findSectionHeader(sectionName)); +} + +template +template +span ElfFile::tryGetSectionSpan(const SectionName & sectionName) +{ + auto shdrOpt = tryFindSectionHeader(sectionName); + return shdrOpt ? getSectionSpan(*shdrOpt) : span(); +} template unsigned int ElfFile::getSectionIndex(const SectionName & sectionName) @@ -1861,6 +1884,223 @@ void ElfFile::addDebugTag() changed = true; } +static uint32_t gnuHash(std::string_view name) { + uint32_t h = 5381; + for (uint8_t c : name) + h = ((h << 5) + h) + c; + return h; +} + +template +auto ElfFile::parseGnuHashTable(span sectionData) -> GnuHashTable +{ + auto hdr = (typename GnuHashTable::Header*)sectionData.begin(); + auto bloomFilters = span((typename GnuHashTable::BloomWord*)(hdr+1), rdi(hdr->maskwords)); + auto buckets = span((uint32_t*)bloomFilters.end(), rdi(hdr->numBuckets)); + auto table = span(buckets.end(), ((uint32_t*)sectionData.end()) - buckets.end()); + return GnuHashTable{*hdr, bloomFilters, buckets, table}; +} + +template +void ElfFile::rebuildGnuHashTable(const char* strTab, span dynsyms) +{ + auto sectionData = tryGetSectionSpan(".gnu.hash"); + if (!sectionData) + return; + + auto ght = parseGnuHashTable(sectionData); + + // We can't trust the value of symndx when the hash table is empty + if (ght.m_table.size() == 0) + return; + + // The hash table includes only a subset of dynsyms + auto firstSymIdx = rdi(ght.m_hdr.symndx); + dynsyms = span(dynsyms.begin() + firstSymIdx, dynsyms.end()); + + // Only use the range of symbol versions that will be changed + auto versyms = tryGetSectionSpan(".gnu.version"); + if (versyms) + versyms = span(versyms.begin() + firstSymIdx, versyms.end()); + + struct Entry + { + uint32_t hash, bucketIdx, originalPos; + }; + + std::vector entries; + entries.reserve(dynsyms.size()); + + uint32_t pos = 0; // Track the original position of the symbol in the table + for (auto& sym : dynsyms) + { + Entry e; + e.hash = gnuHash(strTab + rdi(sym.st_name)); + e.bucketIdx = e.hash % ght.m_buckets.size(); + e.originalPos = pos++; + entries.push_back(e); + } + + // Sort the entries based on the buckets. This is a requirement for gnu hash table to work + std::sort(entries.begin(), entries.end(), [&] (auto& l, auto& r) { + return l.bucketIdx < r.bucketIdx; + }); + + // Create a map of old positions to new positions after sorting + std::vector old2new(entries.size()); + for (size_t i = 0; i < entries.size(); ++i) + old2new[entries[i].originalPos] = i; + + // Update the symbol table with the new order and + // all tables that refer to symbols through indexes in the symbol table + auto reorderSpan = [] (auto dst, auto& old2new) + { + std::vector tmp(dst.begin(), dst.end()); + for (size_t i = 0; i < tmp.size(); ++i) + dst[old2new[i]] = tmp[i]; + }; + + reorderSpan(dynsyms, old2new); + if (versyms) + reorderSpan(versyms, old2new); + + auto fixRelocationTable = [&old2new, firstSymIdx, this] (auto& hdr) + { + auto rela = getSectionSpan(hdr); + for (auto& r : rela) + { + auto info = rdi(r.r_info); + auto oldSymIdx = rel_getSymId(info); + if (oldSymIdx >= firstSymIdx) + { + auto newSymIdx = old2new[oldSymIdx - firstSymIdx] + firstSymIdx; + if (newSymIdx != oldSymIdx) + wri(r.r_info, rel_setSymId(info, newSymIdx)); + } + } + }; + + for (unsigned int i = 1; i < rdi(hdr()->e_shnum); ++i) + { + auto& shdr = shdrs.at(i); + auto shtype = rdi(shdr.sh_type); + if (shtype == SHT_REL) + fixRelocationTable.template operator()(shdr); + else if (shtype == SHT_RELA) + fixRelocationTable.template operator()(shdr); + } + + // Update bloom filters + std::fill(ght.m_bloomFilters.begin(), ght.m_bloomFilters.end(), 0); + for (size_t i = 0; i < entries.size(); ++i) + { + auto h = entries[i].hash; + size_t idx = (h / ElfClass) % ght.m_bloomFilters.size(); + auto val = rdi(ght.m_bloomFilters[idx]); + val |= uint64_t(1) << (h % ElfClass); + val |= uint64_t(1) << ((h >> rdi(ght.m_hdr.shift2)) % ElfClass); + wri(ght.m_bloomFilters[idx], val); + } + + // Fill buckets + std::fill(ght.m_buckets.begin(), ght.m_buckets.end(), 0); + for (size_t i = 0; i < entries.size(); ++i) + { + auto symBucketIdx = entries[i].bucketIdx; + if (!ght.m_buckets[symBucketIdx]) + wri(ght.m_buckets[symBucketIdx], i + firstSymIdx); + } + + // Fill hash table + for (size_t i = 0; i < entries.size(); ++i) + { + auto& n = entries[i]; + bool isLast = (i == entries.size() - 1) || (n.bucketIdx != entries[i+1].bucketIdx); + // Add hash with first bit indicating end of chain + wri(ght.m_table[i], isLast ? (n.hash | 1) : (n.hash & ~1)); + } +} + +static uint32_t sysvHash(std::string_view name) { + uint32_t h = 0; + for (uint8_t c : name) + { + h = (h << 4) + c; + uint32_t g = h & 0xf0000000; + if (g != 0) + h ^= g >> 24; + h &= ~g; + } + return h; +} + +template +auto ElfFile::parseHashTable(span sectionData) -> HashTable +{ + auto hdr = (typename HashTable::Header*)sectionData.begin(); + auto buckets = span((uint32_t*)(hdr+1), rdi(hdr->numBuckets)); + auto table = span(buckets.end(), ((uint32_t*)sectionData.end()) - buckets.end()); + return HashTable{*hdr, buckets, table}; +} + +template +void ElfFile::rebuildHashTable(const char* strTab, span dynsyms) +{ + auto sectionData = tryGetSectionSpan(".hash"); + if (!sectionData) + return; + + auto ht = parseHashTable(sectionData); + + std::fill(ht.m_buckets.begin(), ht.m_buckets.end(), 0); + std::fill(ht.m_chain.begin(), ht.m_chain.end(), 0); + + auto symsToInsert = span(dynsyms.end() - ht.m_chain.size(), dynsyms.end()); + + for (auto& sym : symsToInsert) + { + auto name = strTab + rdi(sym.st_name); + uint32_t i = &sym - dynsyms.begin(); + uint32_t hash = sysvHash(name) % ht.m_buckets.size(); + wri(ht.m_chain[i], rdi(ht.m_buckets[hash])); + wri(ht.m_buckets[hash], i); + } +} + +template +void ElfFile::renameDynamicSymbols(const std::unordered_map& remap) +{ + auto dynsyms = getSectionSpan(".dynsym"); + auto strTab = getSectionSpan(".dynstr"); + + std::vector extraStrings; + extraStrings.reserve(remap.size() * 30); // Just an estimate + for (size_t i = 0; i < dynsyms.size(); i++) + { + auto& dynsym = dynsyms[i]; + std::string_view name = &strTab[rdi(dynsym.st_name)]; + auto it = remap.find(name); + if (it != remap.end()) + { + wri(dynsym.st_name, strTab.size() + extraStrings.size()); + auto& newName = it->second; + extraStrings.insert(extraStrings.end(), newName.data(), newName.data() + newName.size() + 1); + changed = true; + } + } + + if (changed) + { + auto& newSec = replaceSection(".dynstr", strTab.size() + extraStrings.size()); + std::copy(extraStrings.begin(), extraStrings.end(), newSec.begin() + strTab.size()); + + rebuildGnuHashTable(newSec.data(), dynsyms); + rebuildHashTable(newSec.data(), dynsyms); + } + + this->rewriteSections(); +} + template void ElfFile::clearSymbolVersions(const std::set & syms) { @@ -1983,12 +2223,15 @@ static bool removeRPath = false; static bool setRPath = false; static bool addRPath = false; static bool addDebugTag = false; +static bool renameDynamicSymbols = false; static bool printRPath = false; static std::string newRPath; static std::set neededLibsToRemove; static std::map neededLibsToReplace; static std::set neededLibsToAdd; static std::set symbolsToClearVersion; +static std::unordered_map symbolsToRename; +static std::unordered_set symbolsToRenameKeys; static bool printNeeded = false; static bool noDefaultLib = false; static bool printExecstack = false; @@ -2048,6 +2291,9 @@ static void patchElf2(ElfFile && elfFile, const FileContents & fileContents, con if (addDebugTag) elfFile.addDebugTag(); + if (renameDynamicSymbols) + elfFile.renameDynamicSymbols(symbolsToRename); + if (elfFile.isChanged()){ writeFile(fileName, elfFile.fileContents); } else if (alwaysWrite) { @@ -2067,9 +2313,9 @@ static void patchElf() const std::string & outputFileName2 = outputFileName.empty() ? fileName : outputFileName; if (getElfType(fileContents).is32Bit) - patchElf2(ElfFile(fileContents), fileContents, outputFileName2); + patchElf2(ElfFile(fileContents), fileContents, outputFileName2); else - patchElf2(ElfFile(fileContents), fileContents, outputFileName2); + patchElf2(ElfFile(fileContents), fileContents, outputFileName2); } } @@ -2111,6 +2357,7 @@ void showHelp(const std::string & progName) [--print-execstack]\t\tPrints whether the object requests an executable stack\n\ [--clear-execstack]\n\ [--set-execstack]\n\ + [--rename-dynamic-symbols NAME_MAP_FILE]\tRenames dynamic symbols. The name map file should contain two symbols (old_name new_name) per line\n\ [--output FILE]\n\ [--debug]\n\ [--version]\n\ @@ -2242,6 +2489,25 @@ int mainWrapped(int argc, char * * argv) else if (arg == "--add-debug-tag") { addDebugTag = true; } + else if (arg == "--rename-dynamic-symbols") { + renameDynamicSymbols = true; + if (++i == argc) error("missing argument"); + + std::ifstream infile(argv[i]); + if (!infile) error(fmt("Cannot open map file ", argv[i])); + + std::string from, to; + while (true) + { + if (!(infile >> from)) + break; + if (!(infile >> to)) + error("Odd number of symbols in map file"); + if (symbolsToRenameKeys.count(from)) + error(fmt("Symbol appears twice in the map file: ", from.c_str())); + symbolsToRename[*symbolsToRenameKeys.insert(from).first] = to; + } + } else if (arg == "--help" || arg == "-h" ) { showHelp(argv[0]); return 0; diff --git a/src/patchelf.h b/src/patchelf.h index c3096ff..1914d96 100644 --- a/src/patchelf.h +++ b/src/patchelf.h @@ -1,7 +1,22 @@ using FileContents = std::shared_ptr>; -#define ElfFileParams class Elf_Ehdr, class Elf_Phdr, class Elf_Shdr, class Elf_Addr, class Elf_Off, class Elf_Dyn, class Elf_Sym, class Elf_Verneed, class Elf_Versym -#define ElfFileParamNames Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Addr, Elf_Off, Elf_Dyn, Elf_Sym, Elf_Verneed, Elf_Versym +#define ElfFileParams class Elf_Ehdr, class Elf_Phdr, class Elf_Shdr, class Elf_Addr, class Elf_Off, class Elf_Dyn, class Elf_Sym, class Elf_Verneed, class Elf_Versym, class Elf_Rel, class Elf_Rela, unsigned ElfClass +#define ElfFileParamNames Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Addr, Elf_Off, Elf_Dyn, Elf_Sym, Elf_Verneed, Elf_Versym, Elf_Rel, Elf_Rela, ElfClass + +template +struct span +{ + span(T* d = {}, size_t l = {}) : data(d), len(l) {} + span(T* from, T* to) : data(from), len(to-from) {} + T& operator[](std::size_t i) { return data[i]; } + T* begin() { return data; } + T* end() { return data + len; } + auto size() { return len; } + explicit operator bool() { return size() > 0; } + + T* data; + size_t len; +}; template class ElfFile @@ -85,6 +100,10 @@ private: std::optional> tryFindSectionHeader(const SectionName & sectionName); + template span getSectionSpan(const Elf_Shdr & shdr) const; + template span getSectionSpan(const SectionName & sectionName); + template span tryGetSectionSpan(const SectionName & sectionName); + unsigned int getSectionIndex(const SectionName & sectionName); std::string & replaceSection(const SectionName & sectionName, @@ -137,6 +156,55 @@ public: void addDebugTag(); + void renameDynamicSymbols(const std::unordered_map&); + + struct GnuHashTable { + using BloomWord = Elf_Addr; + struct Header { + uint32_t numBuckets, symndx, maskwords, shift2; + } m_hdr; + span m_bloomFilters; + span m_buckets, m_table; + }; + GnuHashTable parseGnuHashTable(span gh); + + struct HashTable { + struct Header { + uint32_t numBuckets, nchain; + } m_hdr; + span m_buckets, m_chain; + }; + HashTable parseHashTable(span gh); + + void rebuildGnuHashTable(const char* strTab, span dynsyms); + void rebuildHashTable(const char* strTab, span dynsyms); + + using Elf_Rel_Info = decltype(Elf_Rel::r_info); + + uint32_t rel_getSymId(const Elf_Rel_Info& info) const + { + if constexpr (std::is_same_v) + return ELF64_R_SYM(info); + else + return ELF32_R_SYM(info); + } + + Elf_Rel_Info rel_setSymId(Elf_Rel_Info info, uint32_t id) const + { + if constexpr (std::is_same_v) + { + constexpr Elf_Rel_Info idmask = (~Elf_Rel_Info()) << 32; + info = (info & ~idmask) | (Elf_Rel_Info(id) << 32); + } + else + { + constexpr Elf_Rel_Info idmask = (~Elf_Rel_Info()) << 8; + info = (info & ~idmask) | (Elf_Rel_Info(id) << 8); + } + return info; + } + + void clearSymbolVersions(const std::set & syms); enum class ExecstackMode { print, set, clear }; diff --git a/tests/Makefile.am b/tests/Makefile.am index 9d36645..4a08c14 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -45,7 +45,9 @@ src_TESTS = \ add-debug-tag.sh \ empty-note.sh \ print-execstack.sh \ - modify-execstack.sh + modify-execstack.sh \ + rename-dynamic-symbols.sh \ + empty-note.sh build_TESTS = \ $(no_rpath_arch_TESTS) @@ -116,7 +118,7 @@ check_DATA = libbig-dynstr.debug # - with libtool, it is difficult to control options # - with libtool, it is not possible to compile convenience *dynamic* libraries :-( check_PROGRAMS += libfoo.so libfoo-scoped.so libbar.so libbar-scoped.so libsimple.so libsimple-execstack.so libbuildid.so libtoomanystrtab.so \ - phdr-corruption.so + phdr-corruption.so many-syms-main libmany-syms.so libbuildid_so_SOURCES = simple.c libbuildid_so_LDFLAGS = $(LDFLAGS_sharedlib) -Wl,--build-id @@ -147,6 +149,14 @@ too_many_strtab_SOURCES = too-many-strtab.c too-many-strtab2.s libtoomanystrtab_so_SOURCES = too-many-strtab.c too-many-strtab2.s libtoomanystrtab_so_LDFLAGS = $(LDFLAGS_sharedlib) +many_syms_main_SOURCES = many-syms-main.c +many_syms_main_LDFLAGS = $(LDFLAGS_local) +many_syms_main_LDADD = -lmany-syms $(AM_LDADD) +many_syms_main_DEPENDENCIES = libmany-syms.so +many_syms_main_CFLAGS = -pie +libmany_syms_so_SOURCES = many-syms.c +libmany_syms_so_LDFLAGS = $(LDFLAGS_sharedlib) + no_rpath_SOURCES = no-rpath.c # no -fpic for no-rpath.o no_rpath_CFLAGS = @@ -158,3 +168,12 @@ contiguous_note_sections_CFLAGS = -pie phdr_corruption_so_SOURCES = void.c phdr-corruption.ld phdr_corruption_so_LDFLAGS = -nostdlib -shared -Wl,-T$(srcdir)/phdr-corruption.ld phdr_corruption_so_CFLAGS = + +many-syms.c: + i=1; while [ $$i -le 2000 ]; do echo "void f$$i() {};"; i=$$(($$i + 1)); done > $@ + +many-syms-main.c: + echo "int main() {" > $@ + i=1; while [ $$i -le 2000 ]; do echo "void f$$i(); f$$i();"; i=$$(($$i + 1)); done >> $@ + echo "}" >> $@ + diff --git a/tests/rename-dynamic-symbols.sh b/tests/rename-dynamic-symbols.sh new file mode 100755 index 0000000..6fabb33 --- /dev/null +++ b/tests/rename-dynamic-symbols.sh @@ -0,0 +1,84 @@ +#!/bin/sh -e +SCRATCH=scratch/$(basename $0 .sh) +PATCHELF=$(readlink -f "../src/patchelf") + +rm -rf ${SCRATCH} +mkdir -p ${SCRATCH} + +full_main_name="${PWD}/many-syms-main" +full_lib_name="${PWD}/libmany-syms.so" +chmod -w $full_lib_name $full_main_name + +suffix="_special_suffix" + +cd ${SCRATCH} + +############################################################################### +# Test that all symbols in the dynamic symbol table will have the expected +# names after renaming. +# Also test that if we rename all symbols back, the symbols are as expected +############################################################################### + +list_symbols() { + nm -D $@ | awk '{ print $NF }' | sed '/^ *$/d' +} + +list_symbols $full_lib_name | cut -d@ -f1 | sort -u | awk "{printf \"%s %s${suffix}\n\",\$1,\$1}" > map +list_symbols $full_lib_name | cut -d@ -f1 | sort -u | awk "{printf \"%s${suffix} %s\n\",\$1,\$1}" > rmap + +${PATCHELF} --rename-dynamic-symbols map --output libmapped.so $full_lib_name +${PATCHELF} --rename-dynamic-symbols rmap --output libreversed.so libmapped.so + +list_symbols $full_lib_name | sort > orig_syms +list_symbols libmapped.so | sort > map_syms +list_symbols libreversed.so | sort > rev_syms + +diff orig_syms rev_syms > diff_orig_syms_rev_syms || exit 1 + +# Renamed symbols that match version numbers will be printed with version instead of them being ommited +# CXXABI10 is printed as CXXABI10 +# but CXXABI10_renamed is printed as CXXABI10_renamed@@CXXABI10 +# awk is used to remove these cases so that we can match the "mapped" symbols to original symbols +sed "s/${suffix}//" map_syms | awk -F @ '{ if ($1 == $2 || $1 == $3) { print $1; } else { print $0; }}' | sort > map_syms_r +diff orig_syms map_syms_r > diff_orig_syms_map_syms_r || exit 1 + +############################################################################### +# Check the relocation tables after renaming +############################################################################### + +print_relocation_table() { + readelf -W -r $1 | awk '{ printf "%s\n",$5 }' | cut -f1 -d@ +} + +print_relocation_table $full_lib_name > orig_rel +print_relocation_table libmapped.so > map_rel +print_relocation_table libreversed.so > rev_rel + +diff orig_rel rev_rel > diff_orig_rel_rev_rel || exit 1 +sed "s/${suffix}//" map_rel > map_rel_r +diff orig_rel map_rel_r > diff_orig_rel_map_rel_r || exit 1 + +############################################################################### +# Test that the hash table is correctly updated. +# For this to work, we need to rename symbols and actually use the library +# Here we: +# 1. Create a map from all symbols in libstdc++.so as "sym sym_special_suffix" +# 2. Copy Patchelf and all of its transitive library dependencies into a new directory +# 3. Rename symbols in Patchelf and all dependencies according to the map +# 4. Run patchelf with the modified dependencies +############################################################################### + +echo "# Create the map" +list_symbols --defined-only $full_lib_name | cut -d@ -f1 | sort -u | awk "{printf \"%s %s${suffix}\n\",\$1,\$1}" > map + +echo "# Copy all dependencies" +mkdir env +cd env +cp $full_lib_name $full_main_name . + +echo "# Apply renaming" +chmod +w * +${PATCHELF} --rename-dynamic-symbols ../map * + +echo "# Run the patched tool and libraries" +env LD_BIND_NOW=1 LD_LIBRARY_PATH=${PWD} ./many-syms-main -- cgit v1.2.1 From be4b84635f806998853825e23d94b14723e37b55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Thalheim?= Date: Sun, 19 Feb 2023 08:55:11 +0100 Subject: tests: apply suggestions from shellcheck --- tests/add-debug-tag.sh | 14 ++++----- tests/add-rpath.sh | 25 ++++++++-------- tests/args-from-file.sh | 20 ++++++------- tests/big-dynstr.sh | 25 ++++++++-------- tests/build-id.sh | 2 +- tests/change-abi.sh | 45 ++++++++++------------------- tests/contiguous-note-sections.sh | 4 +-- tests/empty-note.sh | 10 +++---- tests/endianness.sh | 14 ++++----- tests/force-rpath.sh | 28 ++++++++++-------- tests/grow-file.sh | 14 ++++----- tests/invalid-elf.sh | 4 +-- tests/no-gnu-hash.sh | 12 ++++---- tests/no-rpath-pie-powerpc.sh | 2 +- tests/no-rpath-prebuild.sh | 22 +++++++------- tests/no-rpath.sh | 16 +++++----- tests/output-flag.sh | 29 ++++++++++--------- tests/phdr-corruption.sh | 4 +-- tests/plain-needed.sh | 8 ++--- tests/replace-add-needed.sh | 24 +++++++-------- tests/replace-needed.sh | 17 +++++------ tests/set-empty-rpath.sh | 12 ++++---- tests/set-interpreter-long.sh | 18 ++++++------ tests/set-interpreter-short.sh | 12 ++++---- tests/set-rpath-library.sh | 34 +++++++++++----------- tests/set-rpath-rel-map.sh | 27 ++++++++--------- tests/set-rpath.sh | 25 ++++++++-------- tests/shrink-rpath-with-allowed-prefixes.sh | 42 +++++++++++++-------------- tests/shrink-rpath.sh | 16 +++++----- tests/soname.sh | 18 ++++++------ tests/too-many-strtab.sh | 12 ++++---- 31 files changed, 274 insertions(+), 281 deletions(-) diff --git a/tests/add-debug-tag.sh b/tests/add-debug-tag.sh index 4fbbfa4..37bf957 100755 --- a/tests/add-debug-tag.sh +++ b/tests/add-debug-tag.sh @@ -1,14 +1,14 @@ #! /bin/sh -e -SCRATCH=scratch/$(basename $0 .sh) +SCRATCH=scratch/$(basename "$0" .sh) READELF=${READELF:-readelf} -rm -rf ${SCRATCH} -mkdir -p ${SCRATCH} +rm -rf "${SCRATCH}" +mkdir -p "${SCRATCH}" -cp libsimple.so ${SCRATCH}/ +cp libsimple.so "${SCRATCH}"/ # check there is no DT_DEBUG tag -debugTag=$($READELF -d ${SCRATCH}/libsimple.so) +debugTag=$($READELF -d "${SCRATCH}/libsimple.so") echo ".dynamic before: $debugTag" if echo "$debugTag" | grep -q DEBUG; then echo "failed --add-debug-tag test. Expected no line with (DEBUG), got: $debugTag" @@ -16,10 +16,10 @@ if echo "$debugTag" | grep -q DEBUG; then fi # set DT_DEBUG -../src/patchelf --add-debug-tag ${SCRATCH}/libsimple.so +../src/patchelf --add-debug-tag "${SCRATCH}/libsimple.so" # check there is DT_DEBUG tag -debugTag=$($READELF -d ${SCRATCH}/libsimple.so) +debugTag=$($READELF -d "${SCRATCH}/libsimple.so") echo ".dynamic before: $debugTag" if ! echo "$debugTag" | grep -q DEBUG; then echo "failed --add-debug-tag test. Expected line with (DEBUG), got: $debugTag" diff --git a/tests/add-rpath.sh b/tests/add-rpath.sh index 3368708..1f9f7f9 100755 --- a/tests/add-rpath.sh +++ b/tests/add-rpath.sh @@ -1,24 +1,25 @@ #! /bin/sh -e -SCRATCH=scratch/$(basename $0 .sh) +SCRATCH=scratch/$(basename "$0" .sh) -rm -rf ${SCRATCH} -mkdir -p ${SCRATCH} -mkdir -p ${SCRATCH}/libsA -mkdir -p ${SCRATCH}/libsB +rm -rf "${SCRATCH}" +mkdir -p "${SCRATCH}" +mkdir -p "${SCRATCH}/libsA" +mkdir -p "${SCRATCH}/libsB" -cp main ${SCRATCH}/ -cp libfoo.so ${SCRATCH}/libsA/ -cp libbar.so ${SCRATCH}/libsB/ +cp main "${SCRATCH}"/ +cp libfoo.so "${SCRATCH}/libsA/" +cp libbar.so "${SCRATCH}/libsB/" -../src/patchelf --force-rpath --add-rpath $(pwd)/${SCRATCH}/libsA ${SCRATCH}/main -../src/patchelf --force-rpath --add-rpath $(pwd)/${SCRATCH}/libsB ${SCRATCH}/main +../src/patchelf --force-rpath --add-rpath "$(pwd)/${SCRATCH}/libsA" "${SCRATCH}/main" +../src/patchelf --force-rpath --add-rpath "$(pwd)/${SCRATCH}/libsB" "${SCRATCH}/main" if test "$(uname)" = FreeBSD; then - export LD_LIBRARY_PATH=$(pwd)/${SCRATCH}/libsB + LD_LIBRARY_PATH="$(pwd)/${SCRATCH}/libsB" + export LD_LIBRARY_PATH fi exitCode=0 -(cd ${SCRATCH} && ./main) || exitCode=$? +(cd "${SCRATCH}" && ./main) || exitCode=$? if test "$exitCode" != 46; then echo "bad exit code!" diff --git a/tests/args-from-file.sh b/tests/args-from-file.sh index c0d1a54..107031e 100755 --- a/tests/args-from-file.sh +++ b/tests/args-from-file.sh @@ -1,16 +1,16 @@ #! /bin/sh -e -SCRATCH=scratch/$(basename $0 .sh) +SCRATCH=scratch/$(basename "$0" .sh) -rm -rf ${SCRATCH} -mkdir -p ${SCRATCH} +rm -rf "${SCRATCH}" +mkdir -p "${SCRATCH}" -cp main ${SCRATCH}/ -RANDOM_PATH=$(pwd)/${SCRATCH}/$RANDOM -echo -n ${RANDOM_PATH} >> ${SCRATCH}/add-rpath +cp main "${SCRATCH}"/ +SOME_PATH=$(pwd)/${SCRATCH}/some-path +printf "%s" "$SOME_PATH" >> "${SCRATCH}"/add-rpath -! ../src/patchelf --print-rpath ${SCRATCH}/main | grep $RANDOM_PATH -../src/patchelf --add-rpath @${SCRATCH}/add-rpath ${SCRATCH}/main -../src/patchelf --print-rpath ${SCRATCH}/main | grep $RANDOM_PATH + ../src/patchelf --print-rpath "${SCRATCH}"/main | grep "$SOME_PATH" && exit 1 +../src/patchelf --add-rpath @"${SCRATCH}"/add-rpath "${SCRATCH}"/main +../src/patchelf --print-rpath "${SCRATCH}"/main | grep "$SOME_PATH" # should print error message and fail -../src/patchelf --set-rpath @${SCRATCH}/does-not-exist ${SCRATCH}/main 2>&1 | grep "getting info about" +../src/patchelf --set-rpath @"${SCRATCH}"/does-not-exist "${SCRATCH}"/main 2>&1 | grep "getting info about" diff --git a/tests/big-dynstr.sh b/tests/big-dynstr.sh index 19adad1..89c5355 100755 --- a/tests/big-dynstr.sh +++ b/tests/big-dynstr.sh @@ -1,25 +1,26 @@ #! /bin/sh -e -SCRATCH=scratch/$(basename $0 .sh) +SCRATCH=scratch/$(basename "$0" .sh) -rm -rf ${SCRATCH} -mkdir -p ${SCRATCH} -mkdir -p ${SCRATCH}/libsA -mkdir -p ${SCRATCH}/libsB +rm -rf "${SCRATCH}" +mkdir -p "${SCRATCH}" +mkdir -p "${SCRATCH}/libsA" +mkdir -p "${SCRATCH}/libsB" -cp big-dynstr ${SCRATCH}/ -cp libfoo.so ${SCRATCH}/libsA/ -cp libbar.so ${SCRATCH}/libsB/ +cp big-dynstr "${SCRATCH}/" +cp libfoo.so "${SCRATCH}/libsA/" +cp libbar.so "${SCRATCH}/libsB/" -oldRPath=$(../src/patchelf --print-rpath ${SCRATCH}/big-dynstr) +oldRPath=$(../src/patchelf --print-rpath "${SCRATCH}/big-dynstr") if test -z "$oldRPath"; then oldRPath="/oops"; fi -../src/patchelf --force-rpath --set-rpath $oldRPath:$(pwd)/${SCRATCH}/libsA:$(pwd)/${SCRATCH}/libsB ${SCRATCH}/big-dynstr +../src/patchelf --force-rpath --set-rpath "$oldRPath:$(pwd)/${SCRATCH}/libsA:$(pwd)/${SCRATCH}/libsB" "${SCRATCH}/big-dynstr" if test "$(uname)" = FreeBSD; then - export LD_LIBRARY_PATH=$(pwd)/${SCRATCH}/libsB + LD_LIBRARY_PATH="$(pwd)/${SCRATCH}/libsB" + export LD_LIBRARY_PATH fi exitCode=0 -cd ${SCRATCH} && ./big-dynstr || exitCode=$? +cd "${SCRATCH}" && ./big-dynstr || exitCode=$? if test "$exitCode" != 46; then echo "bad exit code!" diff --git a/tests/build-id.sh b/tests/build-id.sh index dc44a7a..c9bf712 100755 --- a/tests/build-id.sh +++ b/tests/build-id.sh @@ -1,5 +1,5 @@ #! /bin/sh -e -SCRATCH=scratch/$(basename $0 .sh) +SCRATCH=scratch/$(basename "$0" .sh) READELF=${READELF:-readelf} rm -rf "${SCRATCH}" diff --git a/tests/change-abi.sh b/tests/change-abi.sh index 26a151d..03c5f9b 100755 --- a/tests/change-abi.sh +++ b/tests/change-abi.sh @@ -1,44 +1,29 @@ #! /bin/sh -e -SCRATCH=scratch/$(basename $0 .sh) +SCRATCH=scratch/$(basename "$0" .sh) -rm -rf ${SCRATCH} -mkdir -p ${SCRATCH} +rm -rf "${SCRATCH}" +mkdir -p "${SCRATCH}" -cp simple-pie ${SCRATCH}/simple-pie +cp simple-pie "${SCRATCH}/simple-pie" # Save the old OS ABI -OLDABI=`../src/patchelf --print-os-abi ${SCRATCH}/simple-pie` +OLDABI=$(../src/patchelf --print-os-abi "${SCRATCH}/simple-pie") # Ensure it's not empty test -n "$OLDABI" # Change OS ABI and verify it has been changed -{ - echo "System V" - echo "HP-UX" - echo "NetBSD" - echo "Linux" - echo "GNU Hurd" - echo "Solaris" - echo "AIX" - echo "IRIX" - echo "FreeBSD" - echo "Tru64" - echo "OpenBSD" - echo "OpenVMS" -} | { - while IFS="\n" read ABI; do - echo "Set OS ABI to '$ABI'..." - ../src/patchelf --set-os-abi "$ABI" ${SCRATCH}/simple-pie - - echo "Check is OS ABI is '$ABI'..." - NEWABI=`../src/patchelf --print-os-abi ${SCRATCH}/simple-pie` - test "$NEWABI" = "$ABI" - done -} +for ABI in "System V" "HP-UX" "NetBSD" "Linux" "GNU Hurd" "Solaris" "AIX" "IRIX" "FreeBSD" "Tru64" "OpenBSD" "OpenVMS"; do + echo "Set OS ABI to '$ABI'..." + ../src/patchelf --set-os-abi "$ABI" "${SCRATCH}/simple-pie" + + echo "Check is OS ABI is '$ABI'..." + NEWABI=$(../src/patchelf --print-os-abi "${SCRATCH}/simple-pie") + test "$NEWABI" = "$ABI" +done # Reset OS ABI to the saved one -../src/patchelf --set-os-abi "$OLDABI" ${SCRATCH}/simple-pie +../src/patchelf --set-os-abi "$OLDABI" "${SCRATCH}/simple-pie" # Verify we still can run the executable -${SCRATCH}/simple-pie +"${SCRATCH}/simple-pie" diff --git a/tests/contiguous-note-sections.sh b/tests/contiguous-note-sections.sh index 65abf0c..aa1f84a 100755 --- a/tests/contiguous-note-sections.sh +++ b/tests/contiguous-note-sections.sh @@ -1,6 +1,6 @@ #! /bin/sh -e -SCRATCH=scratch/$(basename $0 .sh) +SCRATCH=scratch/$(basename "$0" .sh) rm -rf "${SCRATCH}" mkdir -p "${SCRATCH}" @@ -10,4 +10,4 @@ cp contiguous-note-sections "${SCRATCH}/" # Running --set-interpreter on this binary should not produce the following # error: # patchelf: cannot normalize PT_NOTE segment: non-contiguous SHT_NOTE sections -../src/patchelf --set-interpreter ld-linux-x86-64.so.2 ${SCRATCH}/contiguous-note-sections +../src/patchelf --set-interpreter ld-linux-x86-64.so.2 "${SCRATCH}/contiguous-note-sections" diff --git a/tests/empty-note.sh b/tests/empty-note.sh index c127d8c..57656fb 100755 --- a/tests/empty-note.sh +++ b/tests/empty-note.sh @@ -1,12 +1,12 @@ #! /bin/sh -e -SCRATCH=scratch/$(basename $0 .sh) +SCRATCH=scratch/$(basename "$0" .sh) -rm -rf ${SCRATCH} -mkdir -p ${SCRATCH} -cp $(dirname $(readlink -f $0))/empty-note ${SCRATCH}/ +rm -rf "${SCRATCH}" +mkdir -p "${SCRATCH}" +cp "$(dirname "$(readlink -f "$0")")/empty-note" "${SCRATCH}/" # Running --set-interpreter on this binary should not produce the following # error: # patchelf: cannot normalize PT_NOTE segment: non-contiguous SHT_NOTE sections -../src/patchelf --set-interpreter ld-linux-x86-64.so.2 ${SCRATCH}/empty-note +../src/patchelf --set-interpreter ld-linux-x86-64.so.2 "${SCRATCH}/empty-note" diff --git a/tests/endianness.sh b/tests/endianness.sh index 4f84a08..fc2994b 100755 --- a/tests/endianness.sh +++ b/tests/endianness.sh @@ -1,23 +1,23 @@ #! /bin/sh -e -SCRATCH=scratch/$(basename $0 .sh) +SCRATCH=scratch/$(basename "$0" .sh) PATCHELF="../src/patchelf" for arch in ppc64 ppc64le; do - rm -rf ${SCRATCH} - mkdir -p ${SCRATCH} + rm -rf "${SCRATCH}" + mkdir -p "${SCRATCH}" - cp ${srcdir}/endianness/${arch}/main ${srcdir}/endianness/${arch}/libtest.so ${SCRATCH}/ + cp "${srcdir}/endianness/${arch}/main" "${srcdir}/endianness/${arch}/libtest.so" "${SCRATCH}/" rpath="${PWD}/${SCRATCH}" # set rpath to scratch dir - ${PATCHELF} --output ${SCRATCH}/main-rpath --set-rpath $rpath ${SCRATCH}/main + ${PATCHELF} --output "${SCRATCH}/main-rpath" --set-rpath "$rpath" "${SCRATCH}/main" # attempt to shrink rpath, should not result in empty rpath - ${PATCHELF} --output ${SCRATCH}/main-shrunk --shrink-rpath --debug ${SCRATCH}/main-rpath + ${PATCHELF} --output "${SCRATCH}/main-shrunk" --shrink-rpath --debug "${SCRATCH}/main-rpath" # check whether rpath is still present - if ! ${PATCHELF} --print-rpath ${SCRATCH}/main-shrunk | grep -q "$rpath"; then + if ! ${PATCHELF} --print-rpath "${SCRATCH}/main-shrunk" | grep -q "$rpath"; then echo "rpath was removed for ${arch}" exit 1 fi diff --git a/tests/force-rpath.sh b/tests/force-rpath.sh index c9b9a5d..a673f20 100755 --- a/tests/force-rpath.sh +++ b/tests/force-rpath.sh @@ -1,29 +1,33 @@ #! /bin/sh -e -SCRATCH=scratch/$(basename $0 .sh) +SCRATCH=scratch/$(basename "$0" .sh) OBJDUMP=${OBJDUMP:-objdump} -rm -rf ${SCRATCH} -mkdir -p ${SCRATCH} +rm -rf "${SCRATCH}" +mkdir -p "${SCRATCH}" SCRATCHFILE=${SCRATCH}/libfoo.so -cp libfoo.so $SCRATCHFILE +cp libfoo.so "$SCRATCHFILE" doit() { - echo patchelf $* - ../src/patchelf $* $SCRATCHFILE + set +x + ../src/patchelf "$@" "$SCRATCHFILE" + set -x } expect() { - out=$(echo $($OBJDUMP -x $SCRATCHFILE | grep PATH)) + out=$("$OBJDUMP" -x "$SCRATCHFILE" | grep PATH || true) - if [ "$out" != "$*" ]; then - echo "Expected '$*' but got '$out'" - exit 1 - fi + for i in $out; do + if [ "$i" != "$1" ]; then + echo "Expected '$*' but got '$out'" + exit 1 + fi + shift + done } doit --remove-rpath -expect +expect "" doit --set-rpath foo expect RUNPATH foo doit --force-rpath --set-rpath foo diff --git a/tests/grow-file.sh b/tests/grow-file.sh index 4c405df..ec5957d 100755 --- a/tests/grow-file.sh +++ b/tests/grow-file.sh @@ -1,16 +1,16 @@ #! /bin/sh -e -SCRATCH=scratch/$(basename $0 .sh) +SCRATCH=scratch/$(basename "$0" .sh) -rm -rf ${SCRATCH} -mkdir -p ${SCRATCH} +rm -rf "${SCRATCH}" +mkdir -p "${SCRATCH}" -cp simple-pie ${SCRATCH}/simple-pie +cp simple-pie "${SCRATCH}/simple-pie" # Add a 40MB rpath -tr -cd 'a-z0-9' < /dev/urandom | dd count=40 bs=1000000 > ${SCRATCH}/foo.bin +tr -cd 'a-z0-9' < /dev/urandom | dd count=40 bs=1000000 > "${SCRATCH}/foo.bin" # Grow the file -../src/patchelf --add-rpath @${SCRATCH}/foo.bin ${SCRATCH}/simple-pie +../src/patchelf --add-rpath @"${SCRATCH}/foo.bin" "${SCRATCH}/simple-pie" # Make sure we can still run it -${SCRATCH}/simple-pie +"${SCRATCH}/simple-pie" diff --git a/tests/invalid-elf.sh b/tests/invalid-elf.sh index 0f020e8..c124501 100755 --- a/tests/invalid-elf.sh +++ b/tests/invalid-elf.sh @@ -6,12 +6,12 @@ # by a signal. This works because the exit code of processes that were # killed by a signal is 128 plus the signal number. killed_by_signal() { - [ $1 -ge 128 ] + [ "$1" -ge 128 ] } # The directory containing all our input files. -TEST_DIR=$(dirname $(readlink -f $0))/invalid-elf +TEST_DIR=$(dirname "$(readlink -f "$0")")/invalid-elf # Each test case is listed here. The names should roughly indicate # what makes the given ELF file invalid. diff --git a/tests/no-gnu-hash.sh b/tests/no-gnu-hash.sh index 0ce93f4..b12542e 100755 --- a/tests/no-gnu-hash.sh +++ b/tests/no-gnu-hash.sh @@ -1,14 +1,14 @@ #! /bin/sh -e -SCRATCH=scratch/$(basename $0 .sh) +SCRATCH=scratch/$(basename "$0" .sh) STRIP=${STRIP:-strip} -rm -rf ${SCRATCH} -mkdir -p ${SCRATCH} +rm -rf "${SCRATCH}" +mkdir -p "${SCRATCH}" -cp simple ${SCRATCH}/ +cp simple "${SCRATCH}/" -${STRIP} --remove-section=.gnu.hash ${SCRATCH}/simple +${STRIP} --remove-section=.gnu.hash "${SCRATCH}/simple" # Check if patchelf handles binaries with GNU_HASH in dynamic section but # without .gnu.hash section -../src/patchelf --set-interpreter /oops ${SCRATCH}/simple +../src/patchelf --set-interpreter /oops "${SCRATCH}/simple" diff --git a/tests/no-rpath-pie-powerpc.sh b/tests/no-rpath-pie-powerpc.sh index b469f9b..963797c 100755 --- a/tests/no-rpath-pie-powerpc.sh +++ b/tests/no-rpath-pie-powerpc.sh @@ -30,7 +30,7 @@ fi # Tests for powerpc PIE endianness regressions readelfData=$(${READELF} -l ${SCRATCH}/no-rpath 2>&1) -if [ $(echo "$readelfData" | grep --count "PHDR") != 1 ]; then +if [ $(echo "$readelfData" | grep "PHDR" | wc -l) != 1 ]; then # Triggered if PHDR errors appear on stderr echo "Unexpected number of occurences of PHDR in readelf results" exit 1 diff --git a/tests/no-rpath-prebuild.sh b/tests/no-rpath-prebuild.sh index c58cf8e..143c55c 100755 --- a/tests/no-rpath-prebuild.sh +++ b/tests/no-rpath-prebuild.sh @@ -4,35 +4,35 @@ ARCH="$1" PAGESIZE=4096 if [ -z "$ARCH" ]; then - ARCH=$(basename $0 .sh | sed -e 's/^no-rpath-//') + ARCH=$(basename "$0" .sh | sed -e 's/^no-rpath-//') fi SCRATCH=scratch/no-rpath-$ARCH -if [ -z "$ARCH" ] || [ $ARCH = prebuild ] ; then +if [ -z "$ARCH" ] || [ "$ARCH" = prebuild ] ; then echo "Architecture required" exit 1 fi no_rpath_bin="${srcdir}/no-rpath-prebuild/no-rpath-$ARCH" -if [ ! -f $no_rpath_bin ]; then +if [ ! -f "$no_rpath_bin" ]; then echo "no 'no-rpath' binary for '$ARCH' in '${srcdir}/no-rpath-prebuild'" exit 1 fi -rm -rf ${SCRATCH} -mkdir -p ${SCRATCH} +rm -rf "${SCRATCH}" +mkdir -p "${SCRATCH}" -cp $no_rpath_bin ${SCRATCH}/no-rpath +cp "$no_rpath_bin" "${SCRATCH}"/no-rpath -oldRPath=$(../src/patchelf --page-size ${PAGESIZE} --print-rpath ${SCRATCH}/no-rpath) +oldRPath=$(../src/patchelf --page-size "${PAGESIZE}" --print-rpath "${SCRATCH}/no-rpath") if test -n "$oldRPath"; then exit 1; fi -../src/patchelf --page-size ${PAGESIZE} \ - --set-interpreter "$(../src/patchelf --page-size ${PAGESIZE} --print-interpreter ../src/patchelf)" \ - --set-rpath /foo:/bar:/xxxxxxxxxxxxxxx ${SCRATCH}/no-rpath +../src/patchelf --page-size "${PAGESIZE}" \ + --set-interpreter "$(../src/patchelf --page-size "${PAGESIZE}" --print-interpreter ../src/patchelf)" \ + --set-rpath /foo:/bar:/xxxxxxxxxxxxxxx "${SCRATCH}"/no-rpath -newRPath=$(../src/patchelf --page-size ${PAGESIZE} --print-rpath ${SCRATCH}/no-rpath) +newRPath=$(../src/patchelf --page-size "${PAGESIZE}" --print-rpath "${SCRATCH}/no-rpath") if ! echo "$newRPath" | grep -q '/foo:/bar'; then echo "incomplete RPATH" exit 1 diff --git a/tests/no-rpath.sh b/tests/no-rpath.sh index 3efa7f1..7fe0372 100755 --- a/tests/no-rpath.sh +++ b/tests/no-rpath.sh @@ -1,21 +1,21 @@ #! /bin/sh -e -SCRATCH=scratch/$(basename $0 .sh) +SCRATCH=scratch/$(basename "$0" .sh) -rm -rf ${SCRATCH} -mkdir -p ${SCRATCH} +rm -rf "${SCRATCH}" +mkdir -p "${SCRATCH}" -cp no-rpath ${SCRATCH}/ +cp no-rpath "${SCRATCH}/" -oldRPath=$(../src/patchelf --print-rpath ${SCRATCH}/no-rpath) +oldRPath=$(../src/patchelf --print-rpath "${SCRATCH}/no-rpath") if test -n "$oldRPath"; then exit 1; fi ../src/patchelf \ --set-interpreter "$(../src/patchelf --print-interpreter ../src/patchelf)" \ - --set-rpath /foo:/bar:/xxxxxxxxxxxxxxx ${SCRATCH}/no-rpath + --set-rpath /foo:/bar:/xxxxxxxxxxxxxxx "${SCRATCH}/no-rpath" -newRPath=$(../src/patchelf --print-rpath ${SCRATCH}/no-rpath) +newRPath=$(../src/patchelf --print-rpath "${SCRATCH}/no-rpath") if ! echo "$newRPath" | grep -q '/foo:/bar'; then echo "incomplete RPATH" exit 1 fi -cd ${SCRATCH} && ./no-rpath +cd "${SCRATCH}" && ./no-rpath diff --git a/tests/output-flag.sh b/tests/output-flag.sh index 5da26b5..26e8782 100755 --- a/tests/output-flag.sh +++ b/tests/output-flag.sh @@ -1,28 +1,29 @@ #! /bin/sh -e -SCRATCH=scratch/$(basename $0 .sh) +SCRATCH=scratch/$(basename "$0" .sh) -rm -rf ${SCRATCH} -mkdir -p ${SCRATCH} -mkdir -p ${SCRATCH}/libsA -mkdir -p ${SCRATCH}/libsB +rm -rf "${SCRATCH}" +mkdir -p "${SCRATCH}" +mkdir -p "${SCRATCH}/libsA" +mkdir -p "${SCRATCH}/libsB" -cp main ${SCRATCH}/ -cp libfoo.so ${SCRATCH}/libsA/ -cp libbar.so ${SCRATCH}/libsB/ +cp main "${SCRATCH}"/ +cp libfoo.so "${SCRATCH}/libsA/" +cp libbar.so "${SCRATCH}/libsB/" -oldRPath=$(../src/patchelf --print-rpath ${SCRATCH}/main) +oldRPath=$(../src/patchelf --print-rpath "${SCRATCH}/main") if test -z "$oldRPath"; then oldRPath="/oops"; fi -../src/patchelf --force-rpath --set-rpath $oldRPath:$(pwd)/${SCRATCH}/libsA:$(pwd)/${SCRATCH}/libsB ${SCRATCH}/main --output ${SCRATCH}/main2 +../src/patchelf --force-rpath --set-rpath "$oldRPath:$(pwd)/${SCRATCH}/libsA:$(pwd)/${SCRATCH}/libsB" "${SCRATCH}/main" --output "${SCRATCH}/main2" # make sure it copies even when there is nothing to do (because rpath is already set) -../src/patchelf --force-rpath --set-rpath $oldRPath:$(pwd)/${SCRATCH}/libsA:$(pwd)/${SCRATCH}/libsB ${SCRATCH}/main2 --output ${SCRATCH}/main3 +../src/patchelf --force-rpath --set-rpath "$oldRPath:$(pwd)/${SCRATCH}/libsA:$(pwd)/${SCRATCH}/libsB" "${SCRATCH}/main2" --output "${SCRATCH}/main3" if test "$(uname)" = FreeBSD; then - export LD_LIBRARY_PATH=$(pwd)/${SCRATCH}/libsB + LD_LIBRARY_PATH="$(pwd)/${SCRATCH}/libsB" + export LD_LIBRARY_PATH fi exitCode=0 -(cd ${SCRATCH} && ./main2) || exitCode=$? +(cd "${SCRATCH}" && ./main2) || exitCode=$? if test "$exitCode" != 46; then echo "bad exit code!" @@ -30,7 +31,7 @@ if test "$exitCode" != 46; then fi exitCode=0 -(cd ${SCRATCH} && ./main3) || exitCode=$? +(cd "${SCRATCH}" && ./main3) || exitCode=$? if test "$exitCode" != 46; then echo "bad exit code!" diff --git a/tests/phdr-corruption.sh b/tests/phdr-corruption.sh index 1e62101..4f6e901 100755 --- a/tests/phdr-corruption.sh +++ b/tests/phdr-corruption.sh @@ -2,7 +2,7 @@ PATCHELF="../src/patchelf" SONAME="phdr-corruption.so" -SCRATCH="scratch/$(basename $0 .sh)" +SCRATCH="scratch/$(basename "$0" .sh)" SCRATCH_SO="${SCRATCH}/${SONAME}" READELF=${READELF:-readelf} @@ -15,7 +15,7 @@ cp "${SONAME}" "${SCRATCH}" # Check for PT_PHDR entry VirtAddr corruption readelfData=$(${READELF} -l "${SCRATCH_SO}" 2>&1) -if [ $(echo "$readelfData" | grep --count "PHDR") != 1 ]; then +if [ "$(echo "$readelfData" | grep "PHDR" | wc -l)" != 1 ]; then # Triggered if PHDR errors appear on stderr echo "ERROR: Unexpected number of occurences of PHDR in readelf results!" exit 1 diff --git a/tests/plain-needed.sh b/tests/plain-needed.sh index 8967303..e44293b 100755 --- a/tests/plain-needed.sh +++ b/tests/plain-needed.sh @@ -1,14 +1,14 @@ #! /bin/sh set -e -SCRATCH=scratch/$(basename $0 .sh) +SCRATCH=scratch/$(basename "$0" .sh) MAIN_ELF="${SCRATCH}/main" PATCHELF="../src/patchelf" -rm -rf ${SCRATCH} -mkdir -p ${SCRATCH} -cp main ${SCRATCH}/ +rm -rf "${SCRATCH}" +mkdir -p "${SCRATCH}" +cp main "${SCRATCH}"/ echo "Confirming main requires libfoo" ${PATCHELF} --print-needed "${MAIN_ELF}" | grep -q libfoo.so diff --git a/tests/replace-add-needed.sh b/tests/replace-add-needed.sh index e2cb255..701cb95 100755 --- a/tests/replace-add-needed.sh +++ b/tests/replace-add-needed.sh @@ -1,15 +1,15 @@ #! /bin/sh -e -SCRATCH=scratch/$(basename $0 .sh) +SCRATCH=scratch/$(basename "$0" .sh) PATCHELF=$(readlink -f "../src/patchelf") -rm -rf ${SCRATCH} -mkdir -p ${SCRATCH} +rm -rf "${SCRATCH}" +mkdir -p "${SCRATCH}" -cp simple ${SCRATCH}/ -cp libfoo.so ${SCRATCH}/ -cp libbar.so ${SCRATCH}/ +cp simple "${SCRATCH}"/ +cp libfoo.so "${SCRATCH}"/ +cp libbar.so "${SCRATCH}"/ -cd ${SCRATCH} +cd "${SCRATCH}" libcldd=$(ldd ./simple | awk '/ => / { print $3 }' | grep -E "(libc(-[0-9.]*)*.so|ld-musl)") @@ -22,11 +22,11 @@ ${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 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) \ +${PATCHELF} --replace-needed libc.so.6 "${libcldd}" \ + --replace-needed libbar.so "$(readlink -f ./libbar.so)" \ + --add-needed "$(readlink -f ./libfoo.so)" \ ./simple exitCode=0 @@ -35,4 +35,4 @@ exitCode=0 if test "$exitCode" != 0; then ldd ./simple exit 1 -fi \ No newline at end of file +fi diff --git a/tests/replace-needed.sh b/tests/replace-needed.sh index 0a5581c..6099d93 100755 --- a/tests/replace-needed.sh +++ b/tests/replace-needed.sh @@ -1,21 +1,20 @@ #! /bin/sh -e -SCRATCH=scratch/$(basename $0 .sh) +SCRATCH=scratch/$(basename "$0" .sh) -rm -rf ${SCRATCH} -mkdir -p ${SCRATCH} +rm -rf "${SCRATCH}" +mkdir -p "${SCRATCH}" -oldNeeded=$(../src/patchelf --print-needed big-dynstr) oldLibc=$(../src/patchelf --print-needed big-dynstr | grep -v 'foo\.so') -../src/patchelf --output ${SCRATCH}/big-needed --replace-needed ${oldLibc} long_long_very_long_libc.so.6 --replace-needed libfoo.so lf.so big-dynstr +../src/patchelf --output "${SCRATCH}/big-needed" --replace-needed "${oldLibc}" long_long_very_long_libc.so.6 --replace-needed libfoo.so lf.so big-dynstr -if [ -z "$(../src/patchelf --print-needed ${SCRATCH}/big-needed | grep -Fx "long_long_very_long_libc.so.6")" ]; then +if ! ../src/patchelf --print-needed "${SCRATCH}/big-needed" | grep -Fxq "long_long_very_long_libc.so.6"; then echo "library long_long_very_long_libc.so.6 not found as NEEDED" - ../src/patchelf --print-needed ${SCRATCH}/big-needed + ../src/patchelf --print-needed "${SCRATCH}/big-needed" exit 1 fi -if [ -z "$(../src/patchelf --print-needed ${SCRATCH}/big-needed | grep -Fx "lf.so")" ]; then +if ! ../src/patchelf --print-needed "${SCRATCH}/big-needed" | grep -Fxq "lf.so"; then echo "library lf.so not found as NEEDED" - ../src/patchelf --print-needed ${SCRATCH}/big-needed + ../src/patchelf --print-needed "${SCRATCH}/big-needed" exit 1 fi diff --git a/tests/set-empty-rpath.sh b/tests/set-empty-rpath.sh index de846a2..b640822 100755 --- a/tests/set-empty-rpath.sh +++ b/tests/set-empty-rpath.sh @@ -1,11 +1,11 @@ #! /bin/sh -e -SCRATCH=scratch/$(basename $0 .sh) +SCRATCH=scratch/$(basename "$0" .sh) -rm -rf ${SCRATCH} -mkdir -p ${SCRATCH} +rm -rf "${SCRATCH}" +mkdir -p "${SCRATCH}" -cp simple ${SCRATCH}/simple +cp simple "${SCRATCH}"/simple -../src/patchelf --force-rpath --set-rpath "" ${SCRATCH}/simple +../src/patchelf --force-rpath --set-rpath "" "${SCRATCH}/simple" -${SCRATCH}/simple +"${SCRATCH}"/simple diff --git a/tests/set-interpreter-long.sh b/tests/set-interpreter-long.sh index 058ccd2..f1e0d2f 100755 --- a/tests/set-interpreter-long.sh +++ b/tests/set-interpreter-long.sh @@ -1,5 +1,5 @@ #! /bin/sh -e -SCRATCH=scratch/$(basename $0 .sh) +SCRATCH=scratch/$(basename "$0" .sh) ./simple @@ -11,24 +11,24 @@ if test "$(uname)" = Linux; then "$oldInterpreter" ./simple fi -rm -rf ${SCRATCH} -mkdir -p ${SCRATCH} +rm -rf "${SCRATCH}" +mkdir -p "${SCRATCH}" -newInterpreter=$(pwd)/${SCRATCH}/iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii -cp simple ${SCRATCH}/ -../src/patchelf --set-interpreter "$newInterpreter" ${SCRATCH}/simple +newInterpreter="$(pwd)/${SCRATCH}/iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii" +cp simple "${SCRATCH}/" +../src/patchelf --set-interpreter "$newInterpreter" "${SCRATCH}/simple" echo "running with missing interpreter..." -if ${SCRATCH}/simple; then +if "${SCRATCH}"/simple; then echo "simple works, but it shouldn't" exit 1 fi echo "running with new interpreter..." ln -s "$oldInterpreter" "$newInterpreter" -${SCRATCH}/simple +"${SCRATCH}"/simple if test "$(uname)" = Linux; then echo "running with explicit interpreter..." - "$oldInterpreter" ${SCRATCH}/simple + "$oldInterpreter" "${SCRATCH}/simple" fi diff --git a/tests/set-interpreter-short.sh b/tests/set-interpreter-short.sh index 2c9f4eb..69746da 100755 --- a/tests/set-interpreter-short.sh +++ b/tests/set-interpreter-short.sh @@ -1,19 +1,19 @@ #! /bin/sh -e -SCRATCH=scratch/$(basename $0 .sh) +SCRATCH=scratch/$(basename "$0" .sh) ./simple oldInterpreter=$(../src/patchelf --print-interpreter ./simple) echo "current interpreter is $oldInterpreter" -rm -rf ${SCRATCH} -mkdir -p ${SCRATCH} +rm -rf "${SCRATCH}" +mkdir -p "${SCRATCH}" -cp simple ${SCRATCH}/ -../src/patchelf --set-interpreter /oops ${SCRATCH}/simple +cp simple "${SCRATCH}"/ +../src/patchelf --set-interpreter /oops "${SCRATCH}/simple" echo "running with missing interpreter..." -if ${SCRATCH}/simple; then +if "${SCRATCH}/simple"; then echo "simple works, but it shouldn't" exit 1 fi diff --git a/tests/set-rpath-library.sh b/tests/set-rpath-library.sh index a5c8ca7..55661a1 100755 --- a/tests/set-rpath-library.sh +++ b/tests/set-rpath-library.sh @@ -1,40 +1,40 @@ #! /bin/sh -e -SCRATCH=scratch/$(basename $0 .sh) +SCRATCH=scratch/$(basename "$0" .sh) if test "$(uname)" = FreeBSD; then echo "skipping on FreeBSD" exit 0 fi -rm -rf ${SCRATCH} -mkdir -p ${SCRATCH} -mkdir -p ${SCRATCH}/libsA -mkdir -p ${SCRATCH}/libsB +rm -rf "${SCRATCH}" +mkdir -p "${SCRATCH}" +mkdir -p "${SCRATCH}/libsA" +mkdir -p "${SCRATCH}/libsB" -cp main-scoped ${SCRATCH}/ -cp libfoo-scoped.so ${SCRATCH}/libsA/ -cp libbar-scoped.so ${SCRATCH}/libsB/ +cp main-scoped "${SCRATCH}/" +cp libfoo-scoped.so "${SCRATCH}/libsA/" +cp libbar-scoped.so "${SCRATCH}/libsB/" -oldRPath=$(../src/patchelf --print-rpath ${SCRATCH}/main-scoped) +oldRPath=$(../src/patchelf --print-rpath "${SCRATCH}"/main-scoped) if test -z "$oldRPath"; then oldRPath="/oops"; fi -../src/patchelf --set-rpath $oldRPath:$(pwd)/${SCRATCH}/libsA:$(pwd)/${SCRATCH}/libsB ${SCRATCH}/main-scoped +../src/patchelf --set-rpath "$oldRPath:$(pwd)/${SCRATCH}/libsA:$(pwd)/${SCRATCH}/libsB" "${SCRATCH}/main-scoped" # "main" contains libbar in its RUNPATH, but that's ignored when # resolving libfoo. So libfoo won't find libbar and this will fail. exitCode=0 -(cd ${SCRATCH} && ./main-scoped) || exitCode=$? +(cd "${SCRATCH}" && ./main-scoped) || exitCode=$? if test "$exitCode" = 46; then echo "expected failure" fi # So set an RUNPATH on libfoo as well. -oldRPath=$(../src/patchelf --print-rpath ${SCRATCH}/libsA/libfoo-scoped.so) +oldRPath=$(../src/patchelf --print-rpath "${SCRATCH}/libsA/libfoo-scoped.so") if test -z "$oldRPath"; then oldRPath="/oops"; fi -../src/patchelf --set-rpath $oldRPath:$(pwd)/${SCRATCH}/libsB ${SCRATCH}/libsA/libfoo-scoped.so +../src/patchelf --set-rpath "$oldRPath:$(pwd)/${SCRATCH}/libsB" "${SCRATCH}/libsA/libfoo-scoped.so" exitCode=0 -(cd ${SCRATCH} && ./main-scoped) || exitCode=$? +(cd "${SCRATCH}" && ./main-scoped) || exitCode=$? if test "$exitCode" != 46; then echo "bad exit code!" @@ -42,15 +42,15 @@ if test "$exitCode" != 46; then fi # Remove the libbar PATH from main using --shrink-rpath. -../src/patchelf --shrink-rpath ${SCRATCH}/main-scoped -if ../src/patchelf --print-rpath ${SCRATCH}/main-scoped | grep /libsB; then +../src/patchelf --shrink-rpath "${SCRATCH}/main-scoped" +if ../src/patchelf --print-rpath "${SCRATCH}/main-scoped" | grep /libsB; then echo "shrink failed" exit 1 fi # And it should still run. exitCode=0 -(cd ${SCRATCH} && ./main-scoped) || exitCode=$? +(cd "${SCRATCH}" && ./main-scoped) || exitCode=$? if test "$exitCode" != 46; then echo "bad exit code!" diff --git a/tests/set-rpath-rel-map.sh b/tests/set-rpath-rel-map.sh index 48bc361..2f890f2 100755 --- a/tests/set-rpath-rel-map.sh +++ b/tests/set-rpath-rel-map.sh @@ -1,6 +1,6 @@ #! /bin/sh -e -SCRATCH=scratch/$(basename $0 .sh) +SCRATCH=scratch/$(basename "$0" .sh) OBJDUMP=${OBJDUMP:-objdump} OBJCOPY=${OBJCOPY:-objcopy} @@ -9,29 +9,30 @@ if ! $OBJDUMP -p main | grep -q MIPS_RLD_MAP_REL; then exit 0 fi -rm -rf ${SCRATCH} -mkdir -p ${SCRATCH} -mkdir -p ${SCRATCH}/libsA -mkdir -p ${SCRATCH}/libsB +rm -rf "${SCRATCH}" +mkdir -p "${SCRATCH}" +mkdir -p "${SCRATCH}/libsA" +mkdir -p "${SCRATCH}/libsB" -cp main ${SCRATCH}/ -cp libfoo.so ${SCRATCH}/libsA/ -cp libbar.so ${SCRATCH}/libsB/ +cp main "${SCRATCH}/" +cp libfoo.so "${SCRATCH}/libsA/" +cp libbar.so "${SCRATCH}/libsB/" # break the main executable by removing .rld_map section -${OBJCOPY} --remove-section .rld_map ${SCRATCH}/main +${OBJCOPY} --remove-section .rld_map "${SCRATCH}/main" -oldRPath=$(../src/patchelf --print-rpath ${SCRATCH}/main) +oldRPath=$(../src/patchelf --print-rpath "${SCRATCH}/main") if test -z "$oldRPath"; then oldRPath="/oops"; fi -../src/patchelf --force-rpath --set-rpath $oldRPath:$(pwd)/${SCRATCH}/libsA:$(pwd)/${SCRATCH}/libsB ${SCRATCH}/main +../src/patchelf --force-rpath --set-rpath "$oldRPath:$(pwd)/${SCRATCH}/libsA:$(pwd)/${SCRATCH}/libsB" "${SCRATCH}/main" if test "$(uname)" = FreeBSD; then - export LD_LIBRARY_PATH=$(pwd)/${SCRATCH}/libsB + LD_LIBRARY_PATH=$(pwd)/"${SCRATCH}"/libsB + export LD_LIBRARY_PATH fi exitCode=0 -(cd ${SCRATCH} && ./main) || exitCode=$? +(cd "${SCRATCH}" && ./main) || exitCode=$? if test "$exitCode" != 46; then echo "bad exit code!" diff --git a/tests/set-rpath.sh b/tests/set-rpath.sh index 90452f9..565582a 100755 --- a/tests/set-rpath.sh +++ b/tests/set-rpath.sh @@ -1,25 +1,26 @@ #! /bin/sh -e -SCRATCH=scratch/$(basename $0 .sh) +SCRATCH=scratch/$(basename "$0" .sh) -rm -rf ${SCRATCH} -mkdir -p ${SCRATCH} -mkdir -p ${SCRATCH}/libsA -mkdir -p ${SCRATCH}/libsB +rm -rf "${SCRATCH}" +mkdir -p "${SCRATCH}" +mkdir -p "${SCRATCH}"/libsA +mkdir -p "${SCRATCH}"/libsB -cp main ${SCRATCH}/ -cp libfoo.so ${SCRATCH}/libsA/ -cp libbar.so ${SCRATCH}/libsB/ +cp main "${SCRATCH}"/ +cp libfoo.so "${SCRATCH}/libsA/" +cp libbar.so "${SCRATCH}/libsB/" -oldRPath=$(../src/patchelf --print-rpath ${SCRATCH}/main) +oldRPath=$(../src/patchelf --print-rpath "${SCRATCH}/main") if test -z "$oldRPath"; then oldRPath="/oops"; fi -../src/patchelf --force-rpath --set-rpath $oldRPath:$(pwd)/${SCRATCH}/libsA:$(pwd)/${SCRATCH}/libsB ${SCRATCH}/main +../src/patchelf --force-rpath --set-rpath "$oldRPath:$(pwd)/${SCRATCH}/libsA:$(pwd)/${SCRATCH}/libsB" "${SCRATCH}/main" if test "$(uname)" = FreeBSD; then - export LD_LIBRARY_PATH=$(pwd)/${SCRATCH}/libsB + LD_LIBRARY_PATH="$(pwd)/${SCRATCH}/libsB" + export LD_LIBRARY_PATH fi exitCode=0 -(cd ${SCRATCH} && ./main) || exitCode=$? +(cd "${SCRATCH}" && ./main) || exitCode=$? if test "$exitCode" != 46; then echo "bad exit code!" diff --git a/tests/shrink-rpath-with-allowed-prefixes.sh b/tests/shrink-rpath-with-allowed-prefixes.sh index db24da2..aca8d06 100755 --- a/tests/shrink-rpath-with-allowed-prefixes.sh +++ b/tests/shrink-rpath-with-allowed-prefixes.sh @@ -1,47 +1,47 @@ #! /bin/sh -e -SCRATCH=scratch/$(basename $0 .sh) +SCRATCH=scratch/$(basename "$0" .sh) -rm -rf ${SCRATCH} -mkdir -p ${SCRATCH} -mkdir -p ${SCRATCH}/libsA -mkdir -p ${SCRATCH}/libsB +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/ +cp main "${SCRATCH}"/ +cp libfoo.so libbar.so "${SCRATCH}/libsA/" +cp libfoo.so libbar.so "${SCRATCH}/libsB/" -oldRPath=$(../src/patchelf --print-rpath ${SCRATCH}/main) +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 +../src/patchelf --force-rpath --set-rpath "$oldRPath:$pathA:$pathB" "${SCRATCH}/main" -cp ${SCRATCH}/main ${SCRATCH}/mainA -cp ${SCRATCH}/main ${SCRATCH}/mainB +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 +../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) + rpath=$(../src/patchelf --print-rpath "$exe") echo "RPATH of $exe after: $rpath" - if ! echo "$rpath" | grep -q $mustContain; then + 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 + 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 +check "${SCRATCH}/main" "$pathA" "$pathB" +check "${SCRATCH}/mainA" "$pathA" "$pathB" +check "${SCRATCH}/mainB" "$pathB" "$pathA" diff --git a/tests/shrink-rpath.sh b/tests/shrink-rpath.sh index 3adc846..6944a44 100755 --- a/tests/shrink-rpath.sh +++ b/tests/shrink-rpath.sh @@ -1,5 +1,5 @@ #! /bin/sh -e -SCRATCH=scratch/$(basename $0 .sh) +SCRATCH=scratch/$(basename "$0" .sh) rpath=$(../src/patchelf --print-rpath ./libbar.so) echo "RPATH before: $rpath" @@ -8,22 +8,22 @@ if ! echo "$rpath" | grep -q /no-such-path; then exit 1 fi -rm -rf ${SCRATCH} -mkdir -p ${SCRATCH} -cp libbar.so ${SCRATCH}/ -../src/patchelf --shrink-rpath ${SCRATCH}/libbar.so +rm -rf "${SCRATCH}" +mkdir -p "${SCRATCH}" +cp libbar.so "${SCRATCH}"/ +../src/patchelf --shrink-rpath "${SCRATCH}/libbar.so" -rpath=$(../src/patchelf --print-rpath ${SCRATCH}/libbar.so) +rpath=$(../src/patchelf --print-rpath "${SCRATCH}/libbar.so") echo "RPATH after: $rpath" if echo "$rpath" | grep -q /no-such-path; then echo "RPATH not shrunk" exit 1 fi -cp libfoo.so ${SCRATCH}/ +cp libfoo.so "${SCRATCH}/" exitCode=0 -cd ${SCRATCH} && LD_LIBRARY_PATH=. ../../main || exitCode=$? +cd "${SCRATCH}" && LD_LIBRARY_PATH=. ../../main || exitCode=$? if test "$exitCode" != 46; then echo "bad exit code!" diff --git a/tests/soname.sh b/tests/soname.sh index 4a8fb96..683e481 100755 --- a/tests/soname.sh +++ b/tests/soname.sh @@ -1,29 +1,29 @@ #! /bin/sh -e -SCRATCH=scratch/$(basename $0 .sh) +SCRATCH=scratch/$(basename "$0" .sh) -rm -rf ${SCRATCH} -mkdir -p ${SCRATCH} +rm -rf "${SCRATCH}" +mkdir -p "${SCRATCH}" -cp libsimple.so ${SCRATCH}/ +cp libsimple.so "${SCRATCH}/" # set an initial DT_SONAME entry -../src/patchelf --set-soname libsimple.so.1.0 ${SCRATCH}/libsimple.so -newSoname=$(../src/patchelf --print-soname ${SCRATCH}/libsimple.so) +../src/patchelf --set-soname libsimple.so.1.0 "${SCRATCH}/libsimple.so" +newSoname=$(../src/patchelf --print-soname "${SCRATCH}/libsimple.so") if test "$newSoname" != libsimple.so.1.0; then echo "failed --set-soname test. Expected newSoname: libsimple.so.1.0, got: $newSoname" exit 1 fi # print DT_SONAME -soname=$(../src/patchelf --print-soname ${SCRATCH}/libsimple.so) +soname=$(../src/patchelf --print-soname "${SCRATCH}/libsimple.so") if test "$soname" != libsimple.so.1.0; then echo "failed --print-soname test. Expected soname: libsimple.so.1.0, got: $soname" exit 1 fi # replace DT_SONAME entry -../src/patchelf --set-soname libsimple.so.1.1 ${SCRATCH}/libsimple.so -newSoname=$(../src/patchelf --print-soname ${SCRATCH}/libsimple.so) +../src/patchelf --set-soname libsimple.so.1.1 "${SCRATCH}/libsimple.so" +newSoname=$(../src/patchelf --print-soname "${SCRATCH}/libsimple.so") if test "$newSoname" != libsimple.so.1.1; then echo "failed --set-soname test. Expected newSoname: libsimple.so.1.1, got: $newSoname" exit 1 diff --git a/tests/too-many-strtab.sh b/tests/too-many-strtab.sh index 3ef158f..96006a4 100755 --- a/tests/too-many-strtab.sh +++ b/tests/too-many-strtab.sh @@ -1,19 +1,19 @@ #! /bin/sh -e -SCRATCH=scratch/$(basename $0 .sh) +SCRATCH=scratch/$(basename "$0" .sh) -rm -rf ${SCRATCH} -mkdir -p ${SCRATCH} +rm -rf "${SCRATCH}" +mkdir -p "${SCRATCH}" -cp libtoomanystrtab.so ${SCRATCH}/ +cp libtoomanystrtab.so "${SCRATCH}"/ # Set a RUNPATH on the library -../src/patchelf --set-rpath '$ORIGIN' ${SCRATCH}/libtoomanystrtab.so +../src/patchelf --set-rpath "\$ORIGIN" "${SCRATCH}/libtoomanystrtab.so" # Check that patchelf is able to patch it again without crashing. Previously, # it will wrongly identify the lib as a static object because there was no # .dynamic section exitCode=0 -(../src/patchelf --set-rpath '$ORIGIN' ${SCRATCH}/libtoomanystrtab.so) || exitCode=$? +(../src/patchelf --set-rpath "\$ORIGIN" "${SCRATCH}/libtoomanystrtab.so") || exitCode=$? if test "$exitCode" != 0; then echo "bad exit code!" exit 1 -- cgit v1.2.1 From a187790b47381a84fadcb3aa55acc06f48f598b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Thalheim?= Date: Mon, 20 Feb 2023 22:42:14 +0100 Subject: bump github actions version --- .github/workflows/publish.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index c180417..f330171 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -47,7 +47,7 @@ jobs: needs: [build_windows] runs-on: windows-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: actions/download-artifact@v3 with: name: patchelf -- cgit v1.2.1 From cd0926c73f09394a57089c5b8b5fe09a5341f3ce Mon Sep 17 00:00:00 2001 From: Breno Rodrigues Guimaraes Date: Mon, 20 Feb 2023 19:32:47 -0300 Subject: Add description to patchelf.1 --- patchelf.1 | 4 ++++ src/patchelf.cc | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/patchelf.1 b/patchelf.1 index 3d46f1f..ec9d995 100644 --- a/patchelf.1 +++ b/patchelf.1 @@ -123,6 +123,10 @@ Clears the executable flag of the GNU_STACK program header, or adds a new header .IP "--set-execstack" Sets the executable flag of the GNU_STACK program header, or adds a new header. +.IP "--rename-dynamic-symbols NAME_MAP_FILE" +Renames dynamic symbols. The name map file should contain two space separated +names (old name and new name) per line. + .IP "--output FILE" Set the output file name. If not specified, the input will be modified in place. diff --git a/src/patchelf.cc b/src/patchelf.cc index 847d4dc..afb97f7 100644 --- a/src/patchelf.cc +++ b/src/patchelf.cc @@ -2357,7 +2357,7 @@ void showHelp(const std::string & progName) [--print-execstack]\t\tPrints whether the object requests an executable stack\n\ [--clear-execstack]\n\ [--set-execstack]\n\ - [--rename-dynamic-symbols NAME_MAP_FILE]\tRenames dynamic symbols. The name map file should contain two symbols (old_name new_name) per line\n\ + [--rename-dynamic-symbols NAME_MAP_FILE]\tRenames dynamic symbols. The map file should contain two symbols (old_name new_name) per line\n\ [--output FILE]\n\ [--debug]\n\ [--version]\n\ -- cgit v1.2.1 From 5380f3b3a6d94def10fb5af7ef58666fa77efb48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Breno=20Rodrigues=20Guimar=C3=A3es?= Date: Tue, 21 Feb 2023 06:12:44 -0300 Subject: Update patchelf.1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jörg Thalheim --- patchelf.1 | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/patchelf.1 b/patchelf.1 index ec9d995..2112c73 100644 --- a/patchelf.1 +++ b/patchelf.1 @@ -124,8 +124,10 @@ Clears the executable flag of the GNU_STACK program header, or adds a new header Sets the executable flag of the GNU_STACK program header, or adds a new header. .IP "--rename-dynamic-symbols NAME_MAP_FILE" -Renames dynamic symbols. The name map file should contain two space separated -names (old name and new name) per line. +Renames dynamic symbols. The name map file should contain lines +with the old and the new name separated by spaces like this: + +old_name new_name .IP "--output FILE" Set the output file name. If not specified, the input will be modified in place. -- cgit v1.2.1 From b09b28f3c732ce25354511b7b2165dd3e4ecf31c Mon Sep 17 00:00:00 2001 From: Breno Rodrigues Guimaraes Date: Tue, 21 Feb 2023 06:37:47 -0300 Subject: Add out-of-range check for span --- src/patchelf.h | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/patchelf.h b/src/patchelf.h index 1914d96..faa6e1a 100644 --- a/src/patchelf.h +++ b/src/patchelf.h @@ -6,14 +6,21 @@ using FileContents = std::shared_ptr>; template struct span { - span(T* d = {}, size_t l = {}) : data(d), len(l) {} - span(T* from, T* to) : data(from), len(to-from) {} - T& operator[](std::size_t i) { return data[i]; } + explicit span(T* d = {}, size_t l = {}) : data(d), len(l) {} + span(T* from, T* to) : data(from), len(to-from) { assert(from <= to); } + T& operator[](std::size_t i) { checkRange(i); return data[i]; } T* begin() { return data; } T* end() { return data + len; } - auto size() { return len; } - explicit operator bool() { return size() > 0; } + auto size() const { return len; } + explicit operator bool() const { return size() > 0; } +private: + void checkRange(std::size_t i) + { + bool oor = i >= size(); + assert(!oor); + if (oor) throw std::out_of_range("error: Access out of range."); + } T* data; size_t len; }; -- cgit v1.2.1 From 6de67423cab3b95b1f83667dd5624904f520eef6 Mon Sep 17 00:00:00 2001 From: Breno Rodrigues Guimaraes Date: Tue, 21 Feb 2023 06:49:20 -0300 Subject: Code polishing to use more spans --- src/patchelf.cc | 34 +++++++++++++++++++--------------- src/patchelf.h | 4 ++-- 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/src/patchelf.cc b/src/patchelf.cc index afb97f7..829d817 100644 --- a/src/patchelf.cc +++ b/src/patchelf.cc @@ -1902,7 +1902,7 @@ auto ElfFile::parseGnuHashTable(span sectionData) -> Gn } template -void ElfFile::rebuildGnuHashTable(const char* strTab, span dynsyms) +void ElfFile::rebuildGnuHashTable(span strTab, span dynsyms) { auto sectionData = tryGetSectionSpan(".gnu.hash"); if (!sectionData) @@ -1916,12 +1916,12 @@ void ElfFile::rebuildGnuHashTable(const char* strTab, span(".gnu.version"); if (versyms) - versyms = span(versyms.begin() + firstSymIdx, versyms.end()); + versyms = span(&versyms[firstSymIdx], versyms.end()); struct Entry { @@ -1935,7 +1935,7 @@ void ElfFile::rebuildGnuHashTable(const char* strTab, span::parseHashTable(span sectionData) -> HashT } template -void ElfFile::rebuildHashTable(const char* strTab, span dynsyms) +void ElfFile::rebuildHashTable(span strTab, span dynsyms) { auto sectionData = tryGetSectionSpan(".hash"); if (!sectionData) @@ -2055,11 +2055,13 @@ void ElfFile::rebuildHashTable(const char* strTab, span::renameDynamicSymbols(const std::unordered_map extraStrings; extraStrings.reserve(remap.size() * 30); // Just an estimate - for (size_t i = 0; i < dynsyms.size(); i++) + for (auto& dynsym : dynsyms) { - auto& dynsym = dynsyms[i]; std::string_view name = &strTab[rdi(dynsym.st_name)]; auto it = remap.find(name); if (it != remap.end()) { wri(dynsym.st_name, strTab.size() + extraStrings.size()); auto& newName = it->second; - extraStrings.insert(extraStrings.end(), newName.data(), newName.data() + newName.size() + 1); + extraStrings.insert(extraStrings.end(), newName.begin(), newName.end() + 1); changed = true; } } if (changed) { - auto& newSec = replaceSection(".dynstr", strTab.size() + extraStrings.size()); - std::copy(extraStrings.begin(), extraStrings.end(), newSec.begin() + strTab.size()); + auto newStrTabSize = strTab.size() + extraStrings.size(); + auto& newSec = replaceSection(".dynstr", newStrTabSize); + auto newStrTabSpan = span(newSec.data(), newStrTabSize); + + std::copy(extraStrings.begin(), extraStrings.end(), &newStrTabSpan[strTab.size()]); - rebuildGnuHashTable(newSec.data(), dynsyms); - rebuildHashTable(newSec.data(), dynsyms); + rebuildGnuHashTable(newStrTabSpan, dynsyms); + rebuildHashTable(newStrTabSpan, dynsyms); } this->rewriteSections(); diff --git a/src/patchelf.h b/src/patchelf.h index faa6e1a..29c11c2 100644 --- a/src/patchelf.h +++ b/src/patchelf.h @@ -183,8 +183,8 @@ public: }; HashTable parseHashTable(span gh); - void rebuildGnuHashTable(const char* strTab, span dynsyms); - void rebuildHashTable(const char* strTab, span dynsyms); + void rebuildGnuHashTable(span strTab, span dynsyms); + void rebuildHashTable(span strTab, span dynsyms); using Elf_Rel_Info = decltype(Elf_Rel::r_info); -- cgit v1.2.1 From 107ebb65ba346c54c09c349a018d4b36e4b9921e Mon Sep 17 00:00:00 2001 From: Breno Rodrigues Guimaraes Date: Tue, 21 Feb 2023 06:51:57 -0300 Subject: No need for both assert and exception --- src/patchelf.h | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/patchelf.h b/src/patchelf.h index 29c11c2..6c640d5 100644 --- a/src/patchelf.h +++ b/src/patchelf.h @@ -15,12 +15,10 @@ struct span explicit operator bool() const { return size() > 0; } private: - void checkRange(std::size_t i) - { - bool oor = i >= size(); - assert(!oor); - if (oor) throw std::out_of_range("error: Access out of range."); + void checkRange(std::size_t i) { + if (i >= size()) throw std::out_of_range("error: Span access out of range."); } + T* data; size_t len; }; -- cgit v1.2.1 From ce5907fc40d5e355872a4288fde3de7586e6e766 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= Date: Tue, 21 Feb 2023 19:40:44 +0100 Subject: Add required includes in header file Enable to parse the header file on its own, e.g. for language servers (clangd). --- src/patchelf.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/patchelf.h b/src/patchelf.h index c3096ff..1308815 100644 --- a/src/patchelf.h +++ b/src/patchelf.h @@ -1,3 +1,12 @@ +#include +#include +#include +#include +#include +#include + +#include "elf.h" + using FileContents = std::shared_ptr>; #define ElfFileParams class Elf_Ehdr, class Elf_Phdr, class Elf_Shdr, class Elf_Addr, class Elf_Off, class Elf_Dyn, class Elf_Sym, class Elf_Verneed, class Elf_Versym -- cgit v1.2.1 From fbb12a72ad1a98c079597b820364196fcfc512af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= Date: Tue, 21 Feb 2023 19:40:52 +0100 Subject: Add misc functions annotations Make the behavior of functions more explicit. --- src/patchelf.cc | 8 ++++---- src/patchelf.h | 32 ++++++++++++++++---------------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/patchelf.cc b/src/patchelf.cc index e91e2ab..1a67158 100644 --- a/src/patchelf.cc +++ b/src/patchelf.cc @@ -104,7 +104,7 @@ static std::string downcase(std::string s) why... */ template template -I ElfFile::rdi(I i) const +constexpr I ElfFile::rdi(I i) const noexcept { I r = 0; if (littleEndian) { @@ -131,7 +131,7 @@ static void debug(const char * format, ...) } -void fmt2(std::ostringstream & out) +static void fmt2([[maybe_unused]] std::ostringstream & out) { } @@ -309,7 +309,7 @@ ElfFile::ElfFile(FileContents fContents) template -unsigned int ElfFile::getPageSize() const +unsigned int ElfFile::getPageSize() const noexcept { if (forcedPageSize > 0) return forcedPageSize; @@ -555,7 +555,7 @@ std::optional> ElfFile::tryF template -unsigned int ElfFile::getSectionIndex(const SectionName & sectionName) +unsigned int ElfFile::getSectionIndex(const SectionName & sectionName) const { for (unsigned int i = 1; i < rdi(hdr()->e_shnum); ++i) if (getSectionName(shdrs.at(i)) == sectionName) return i; diff --git a/src/patchelf.h b/src/patchelf.h index 1308815..4857ab6 100644 --- a/src/patchelf.h +++ b/src/patchelf.h @@ -39,14 +39,14 @@ private: /* Align on 4 or 8 bytes boundaries on 32- or 64-bit platforms respectively. */ - size_t sectionAlignment = sizeof(Elf_Off); + static constexpr size_t sectionAlignment = sizeof(Elf_Off); std::vector sectionsByOldIndex; public: explicit ElfFile(FileContents fileContents); - bool isChanged() + [[nodiscard]] bool isChanged() const noexcept { return changed; } @@ -55,8 +55,8 @@ private: struct CompPhdr { - ElfFile * elfFile; - bool operator ()(const Elf_Phdr & x, const Elf_Phdr & y) + const ElfFile * elfFile; + bool operator ()(const Elf_Phdr & x, const Elf_Phdr & y) const noexcept { // A PHDR comes before everything else. if (elfFile->rdi(y.p_type) == PT_PHDR) return false; @@ -73,8 +73,8 @@ private: struct CompShdr { - ElfFile * elfFile; - bool operator ()(const Elf_Shdr & x, const Elf_Shdr & y) + const ElfFile * elfFile; + bool operator ()(const Elf_Shdr & x, const Elf_Shdr & y) const noexcept { return elfFile->rdi(x.sh_offset) < elfFile->rdi(y.sh_offset); } @@ -82,24 +82,24 @@ private: friend struct CompShdr; - unsigned int getPageSize() const; + [[nodiscard]] unsigned int getPageSize() const noexcept; void sortShdrs(); void shiftFile(unsigned int extraPages, size_t sizeOffset, size_t extraBytes); - std::string getSectionName(const Elf_Shdr & shdr) const; + [[nodiscard]] std::string getSectionName(const Elf_Shdr & shdr) const; Elf_Shdr & findSectionHeader(const SectionName & sectionName); - std::optional> tryFindSectionHeader(const SectionName & sectionName); + [[nodiscard]] std::optional> tryFindSectionHeader(const SectionName & sectionName); - unsigned int getSectionIndex(const SectionName & sectionName); + [[nodiscard]] unsigned int getSectionIndex(const SectionName & sectionName) const; std::string & replaceSection(const SectionName & sectionName, unsigned int size); - bool haveReplacedSection(const SectionName & sectionName) const; + [[nodiscard]] bool haveReplacedSection(const SectionName & sectionName) const; void writeReplacedSections(Elf_Off & curOff, Elf_Addr startAddr, Elf_Off startOffset); @@ -116,7 +116,7 @@ public: void rewriteSections(bool force = false); - std::string getInterpreter(); + [[nodiscard]] std::string getInterpreter(); typedef enum { printOsAbi, replaceOsAbi } osAbiMode; @@ -158,21 +158,21 @@ private: specified by the ELF header) to this platform's integer representation. */ template - I rdi(I i) const; + constexpr I rdi(I i) const noexcept; /* Convert back to the ELF representation. */ template - I wri(I & t, unsigned long long i) const + constexpr I wri(I & t, unsigned long long i) const { t = rdi((I) i); return i; } - Elf_Ehdr *hdr() { + [[nodiscard]] Elf_Ehdr *hdr() noexcept { return (Elf_Ehdr *)fileContents->data(); } - const Elf_Ehdr *hdr() const { + [[nodiscard]] const Elf_Ehdr *hdr() const noexcept { return (const Elf_Ehdr *)fileContents->data(); } }; -- cgit v1.2.1 From 09673eb553b3dc7c67627b51c34a8b9cc2f8d0f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= Date: Tue, 21 Feb 2023 19:40:54 +0100 Subject: Drop unnecessary friend declarations --- src/patchelf.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/patchelf.h b/src/patchelf.h index 4857ab6..79e7a17 100644 --- a/src/patchelf.h +++ b/src/patchelf.h @@ -67,8 +67,6 @@ private: } }; - friend struct CompPhdr; - void sortPhdrs(); struct CompShdr @@ -80,8 +78,6 @@ private: } }; - friend struct CompShdr; - [[nodiscard]] unsigned int getPageSize() const noexcept; void sortShdrs(); -- cgit v1.2.1 From 404761cf4df321580b40baacd50cd3d3e5cb643f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= Date: Tue, 21 Feb 2023 19:40:55 +0100 Subject: Use C++ casts instead of raw C ones in hdr() --- src/patchelf.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/patchelf.h b/src/patchelf.h index 79e7a17..7c1165b 100644 --- a/src/patchelf.h +++ b/src/patchelf.h @@ -165,10 +165,10 @@ private: } [[nodiscard]] Elf_Ehdr *hdr() noexcept { - return (Elf_Ehdr *)fileContents->data(); + return reinterpret_cast(fileContents->data()); } [[nodiscard]] const Elf_Ehdr *hdr() const noexcept { - return (const Elf_Ehdr *)fileContents->data(); + return reinterpret_cast(fileContents->data()); } }; -- cgit v1.2.1 From a3934549633550ea625604c03e25724664048f40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= Date: Tue, 21 Feb 2023 19:40:56 +0100 Subject: Avoid unnecessary copies in splitColonDelimitedString() Avoid creating a stringstream by using find(). --- src/patchelf.cc | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/patchelf.cc b/src/patchelf.cc index 1a67158..946e81c 100644 --- a/src/patchelf.cc +++ b/src/patchelf.cc @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -69,14 +70,18 @@ static int forcedPageSize = -1; #define EM_LOONGARCH 258 #endif - -static std::vector splitColonDelimitedString(const char * s) +[[nodiscard]] static std::vector splitColonDelimitedString(std::string_view s) { - std::string item; std::vector parts; - std::stringstream ss(s); - while (std::getline(ss, item, ':')) - parts.push_back(item); + + size_t pos; + while ((pos = s.find(':')) != std::string_view::npos) { + parts.emplace_back(s.substr(0, pos)); + s = s.substr(pos + 1); + } + + if (!s.empty()) + parts.emplace_back(s); return parts; } -- cgit v1.2.1 From c00676a28af82f4c73c19916b803d7058f02d104 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= Date: Tue, 21 Feb 2023 19:40:57 +0100 Subject: Close file before potentially throwing --- src/patchelf.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/patchelf.cc b/src/patchelf.cc index 946e81c..8240361 100644 --- a/src/patchelf.cc +++ b/src/patchelf.cc @@ -196,11 +196,11 @@ static FileContents readFile(const std::string & fileName, while ((portion = read(fd, contents->data() + bytesRead, size - bytesRead)) > 0) bytesRead += portion; + close(fd); + if (bytesRead != size) throw SysError(fmt("reading '", fileName, "'")); - close(fd); - return contents; } -- cgit v1.2.1 From 98d1813f2516aa4c771dd8824e7cada98393049f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= Date: Tue, 21 Feb 2023 19:40:58 +0100 Subject: Drop unnecessary casts in getElfType() Also declare the function static and warn if return value not used. --- src/patchelf.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/patchelf.cc b/src/patchelf.cc index 8240361..4c94175 100644 --- a/src/patchelf.cc +++ b/src/patchelf.cc @@ -212,10 +212,10 @@ struct ElfType }; -ElfType getElfType(const FileContents & fileContents) +[[nodiscard]] static ElfType getElfType(const FileContents & fileContents) { /* Check the ELF header for basic validity. */ - if (fileContents->size() < static_cast(sizeof(Elf32_Ehdr))) + if (fileContents->size() < sizeof(Elf32_Ehdr)) error("missing ELF header"); auto contents = fileContents->data(); -- cgit v1.2.1 From e8832294372f0e7c69948d701f3613183a4f78a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= Date: Tue, 21 Feb 2023 19:40:59 +0100 Subject: Avoid potential overflows in checkPointer() Prevent overflows in the addtion of q and size, and avoid truncations in callers by using size_t as type for size. --- src/patchelf.cc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/patchelf.cc b/src/patchelf.cc index 4c94175..6ea238e 100644 --- a/src/patchelf.cc +++ b/src/patchelf.cc @@ -236,10 +236,9 @@ struct ElfType } -static void checkPointer(const FileContents & contents, void * p, unsigned int size) +static void checkPointer(const FileContents & contents, const void * p, size_t size) { - auto q = static_cast(p); - if (!(q >= contents->data() && q + size <= contents->data() + contents->size())) + if (p < contents->data() || size > contents->size() || p > contents->data() + contents->size() - size) error("data region extends past file end"); } -- cgit v1.2.1 From b2897ab819812060c43ebc9fafa1483b1843536b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= Date: Tue, 21 Feb 2023 19:41:01 +0100 Subject: Use C++11 [[noreturn]] --- src/patchelf.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/patchelf.cc b/src/patchelf.cc index 6ea238e..0b7c249 100644 --- a/src/patchelf.cc +++ b/src/patchelf.cc @@ -167,7 +167,7 @@ struct SysError : std::runtime_error { } }; -__attribute__((noreturn)) static void error(const std::string & msg) +[[noreturn]] static void error(const std::string & msg) { if (errno) throw SysError(msg); -- cgit v1.2.1 From 1c2d1fffaffb1cd97b49d48c503d8dde03f56696 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= Date: Tue, 21 Feb 2023 19:41:02 +0100 Subject: Drop superfluous semicolons --- src/patchelf.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/patchelf.cc b/src/patchelf.cc index 0b7c249..c33379f 100644 --- a/src/patchelf.cc +++ b/src/patchelf.cc @@ -1472,7 +1472,7 @@ void ElfFile::modifyRPath(RPathOp op, case rpPrint: { printf("%s\n", rpath ? rpath : ""); return; - }; + } case rpRemove: { if (!rpath) { debug("no RPATH to delete\n"); @@ -1485,7 +1485,7 @@ void ElfFile::modifyRPath(RPathOp op, if (!rpath) { debug("no RPATH to shrink\n"); return; - ;} + } newRPath = shrinkRPath(rpath, neededLibs, allowedRpathPrefixes); break; } -- cgit v1.2.1 From 889350de509de7d5d6724b66c18ef1e09c92cbb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= Date: Tue, 21 Feb 2023 19:41:03 +0100 Subject: Declare file local functions static --- src/patchelf.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/patchelf.cc b/src/patchelf.cc index c33379f..80c2d93 100644 --- a/src/patchelf.cc +++ b/src/patchelf.cc @@ -2077,7 +2077,7 @@ static void patchElf() } } -std::string resolveArgument(const char *arg) { +[[nodiscard]] static std::string resolveArgument(const char *arg) { if (strlen(arg) > 0 && arg[0] == '@') { FileContents cnts = readFile(arg + 1); return std::string((char *)cnts->data(), cnts->size()); @@ -2087,7 +2087,7 @@ std::string resolveArgument(const char *arg) { } -void showHelp(const std::string & progName) +static void showHelp(const std::string & progName) { fprintf(stderr, "syntax: %s\n\ [--set-interpreter FILENAME]\n\ @@ -2122,7 +2122,7 @@ void showHelp(const std::string & progName) } -int mainWrapped(int argc, char * * argv) +static int mainWrapped(int argc, char * * argv) { if (argc <= 1) { showHelp(argv[0]); -- cgit v1.2.1 From b5b59ca4cbdc7bc9ba30c46fb6307edfdfe90c94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= Date: Tue, 21 Feb 2023 19:41:04 +0100 Subject: Avoid dropping const qualifier --- src/Makefile.am | 2 +- src/patchelf.cc | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index fa0a9cc..a85204e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,4 +1,4 @@ -AM_CXXFLAGS = -Wall -std=c++17 -D_FILE_OFFSET_BITS=64 +AM_CXXFLAGS = -Wall -Wcast-qual -std=c++17 -D_FILE_OFFSET_BITS=64 if WITH_ASAN AM_CXXFLAGS += -fsanitize=address -fsanitize-address-use-after-scope diff --git a/src/patchelf.cc b/src/patchelf.cc index 80c2d93..08f0882 100644 --- a/src/patchelf.cc +++ b/src/patchelf.cc @@ -621,7 +621,7 @@ void ElfFile::writeReplacedSections(Elf_Off & curOff, debug("rewriting section '%s' from offset 0x%x (size %d) to offset 0x%x (size %d)\n", sectionName.c_str(), rdi(shdr.sh_offset), rdi(shdr.sh_size), curOff, i->second.size()); - memcpy(fileContents->data() + curOff, (unsigned char *) i->second.c_str(), + memcpy(fileContents->data() + curOff, i->second.c_str(), i->second.size()); /* Update the section header for this section. */ @@ -1316,7 +1316,7 @@ void ElfFile::modifySoname(sonameMode op, const std::string & std::string & newDynamic = replaceSection(".dynamic", rdi(shdrDynamic.sh_size) + sizeof(Elf_Dyn)); unsigned int idx = 0; - for (; rdi(((Elf_Dyn *) newDynamic.c_str())[idx].d_tag) != DT_NULL; idx++); + for (; rdi(reinterpret_cast(newDynamic.c_str())[idx].d_tag) != DT_NULL; idx++); debug("DT_NULL index is %d\n", idx); /* Shift all entries down by one. */ @@ -1551,7 +1551,7 @@ void ElfFile::modifyRPath(RPathOp op, rdi(shdrDynamic.sh_size) + sizeof(Elf_Dyn)); unsigned int idx = 0; - for ( ; rdi(((Elf_Dyn *) newDynamic.c_str())[idx].d_tag) != DT_NULL; idx++) ; + for ( ; rdi(reinterpret_cast(newDynamic.c_str())[idx].d_tag) != DT_NULL; idx++) ; debug("DT_NULL index is %d\n", idx); /* Shift all entries down by one. */ @@ -1753,7 +1753,7 @@ void ElfFile::addNeeded(const std::set & libs) rdi(shdrDynamic.sh_size) + sizeof(Elf_Dyn) * libs.size()); unsigned int idx = 0; - for ( ; rdi(((Elf_Dyn *) newDynamic.c_str())[idx].d_tag) != DT_NULL; idx++) ; + for ( ; rdi(reinterpret_cast(newDynamic.c_str())[idx].d_tag) != DT_NULL; idx++) ; debug("DT_NULL index is %d\n", idx); /* Shift all entries down by the number of new entries. */ @@ -1815,7 +1815,7 @@ void ElfFile::noDefaultLib() rdi(shdrDynamic.sh_size) + sizeof(Elf_Dyn)); unsigned int idx = 0; - for ( ; rdi(((Elf_Dyn *) newDynamic.c_str())[idx].d_tag) != DT_NULL; idx++) ; + for ( ; rdi(reinterpret_cast(newDynamic.c_str())[idx].d_tag) != DT_NULL; idx++) ; debug("DT_NULL index is %d\n", idx); /* Shift all entries down by one. */ @@ -1848,7 +1848,7 @@ void ElfFile::addDebugTag() rdi(shdrDynamic.sh_size) + sizeof(Elf_Dyn)); unsigned int idx = 0; - for ( ; rdi(((Elf_Dyn *) newDynamic.c_str())[idx].d_tag) != DT_NULL; idx++) ; + for ( ; rdi(reinterpret_cast(newDynamic.c_str())[idx].d_tag) != DT_NULL; idx++) ; debug("DT_NULL index is %d\n", idx); /* Shift all entries down by one. */ -- cgit v1.2.1 From 959cd168db3860af6d63892d5cf6836d55bf2ced Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= Date: Tue, 21 Feb 2023 19:41:05 +0100 Subject: Enable Wextra Enable common additional compiler warnings. --- src/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Makefile.am b/src/Makefile.am index a85204e..93e92d8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,4 +1,4 @@ -AM_CXXFLAGS = -Wall -Wcast-qual -std=c++17 -D_FILE_OFFSET_BITS=64 +AM_CXXFLAGS = -Wall -Wextra -Wcast-qual -std=c++17 -D_FILE_OFFSET_BITS=64 if WITH_ASAN AM_CXXFLAGS += -fsanitize=address -fsanitize-address-use-after-scope -- cgit v1.2.1 From 28e95b30f3e7f1920a51a43ae275ec6f3508b495 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= Date: Tue, 21 Feb 2023 19:41:06 +0100 Subject: Avoid implicit value truncations in wri() Abort on truncation of values being written to the ELF data, to prevent silent behavior mismatch. --- src/patchelf.h | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/patchelf.h b/src/patchelf.h index 7c1165b..101b1c9 100644 --- a/src/patchelf.h +++ b/src/patchelf.h @@ -2,6 +2,7 @@ #include #include #include +#include #include #include @@ -157,11 +158,14 @@ private: constexpr I rdi(I i) const noexcept; /* Convert back to the ELF representation. */ - template - constexpr I wri(I & t, unsigned long long i) const + template + constexpr inline I wri(I & t, U i) const { - t = rdi((I) i); - return i; + I val = static_cast(i); + if (static_cast(val) != i) + throw std::runtime_error { "value truncation" }; + t = rdi(val); + return val; } [[nodiscard]] Elf_Ehdr *hdr() noexcept { -- cgit v1.2.1 From 00d1e82f2b1e415ec66d9aacb7e760d3ff617f02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= Date: Tue, 21 Feb 2023 19:41:07 +0100 Subject: Avoid implicit conversion Use auto to avoid implicit type conversion, hiding possible value truncation. --- src/patchelf.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/patchelf.cc b/src/patchelf.cc index 08f0882..c10e369 100644 --- a/src/patchelf.cc +++ b/src/patchelf.cc @@ -290,11 +290,11 @@ ElfFile::ElfFile(FileContents fContents) /* Get the section header string table section (".shstrtab"). Its index in the section header table is given by e_shstrndx field of the ELF header. */ - unsigned int shstrtabIndex = rdi(hdr()->e_shstrndx); + auto shstrtabIndex = rdi(hdr()->e_shstrndx); if (shstrtabIndex >= shdrs.size()) error("string table index out of bounds"); - unsigned int shstrtabSize = rdi(shdrs[shstrtabIndex].sh_size); + auto shstrtabSize = rdi(shdrs[shstrtabIndex].sh_size); char * shstrtab = (char * ) fileContents->data() + rdi(shdrs[shstrtabIndex].sh_offset); checkPointer(fileContents, shstrtab, shstrtabSize); -- cgit v1.2.1 From 81c64ddc99ad448408689bea0de2f1d22dd10762 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= Date: Tue, 21 Feb 2023 19:41:08 +0100 Subject: Declare more read-only functions const --- src/patchelf.cc | 16 ++++++++-------- src/patchelf.h | 8 ++++---- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/patchelf.cc b/src/patchelf.cc index c10e369..7bfabb4 100644 --- a/src/patchelf.cc +++ b/src/patchelf.cc @@ -535,7 +535,7 @@ std::string ElfFile::getSectionName(const Elf_Shdr & shdr) co template -Elf_Shdr & ElfFile::findSectionHeader(const SectionName & sectionName) +const Elf_Shdr & ElfFile::findSectionHeader(const SectionName & sectionName) const { auto shdr = tryFindSectionHeader(sectionName); if (!shdr) { @@ -549,7 +549,7 @@ Elf_Shdr & ElfFile::findSectionHeader(const SectionName & sec template -std::optional> ElfFile::tryFindSectionHeader(const SectionName & sectionName) +std::optional> ElfFile::tryFindSectionHeader(const SectionName & sectionName) const { auto i = getSectionIndex(sectionName); if (i) @@ -602,7 +602,7 @@ void ElfFile::writeReplacedSections(Elf_Off & curOff, clobbering previously written new section contents. */ for (auto & i : replacedSections) { const std::string & sectionName = i.first; - Elf_Shdr & shdr = findSectionHeader(sectionName); + const Elf_Shdr & shdr = findSectionHeader(sectionName); if (rdi(shdr.sh_type) != SHT_NOBITS) memset(fileContents->data() + rdi(shdr.sh_offset), 'X', rdi(shdr.sh_size)); } @@ -1190,10 +1190,10 @@ static void setSubstr(std::string & s, unsigned int pos, const std::string & t) template -std::string ElfFile::getInterpreter() +std::string ElfFile::getInterpreter() const { auto shdr = findSectionHeader(".interp"); - return std::string((char *) fileContents->data() + rdi(shdr.sh_offset), rdi(shdr.sh_size) - 1); + return std::string((const char *) fileContents->data() + rdi(shdr.sh_offset), rdi(shdr.sh_size) - 1); } template @@ -1776,13 +1776,13 @@ void ElfFile::addNeeded(const std::set & libs) } template -void ElfFile::printNeededLibs() // const +void ElfFile::printNeededLibs() const { const auto shdrDynamic = findSectionHeader(".dynamic"); const auto shdrDynStr = findSectionHeader(".dynstr"); - const char *strTab = (char *)fileContents->data() + rdi(shdrDynStr.sh_offset); + const char *strTab = (const char *)fileContents->data() + rdi(shdrDynStr.sh_offset); - const Elf_Dyn *dyn = (Elf_Dyn *) (fileContents->data() + rdi(shdrDynamic.sh_offset)); + const Elf_Dyn *dyn = (const Elf_Dyn *) (fileContents->data() + rdi(shdrDynamic.sh_offset)); for (; rdi(dyn->d_tag) != DT_NULL; dyn++) { if (rdi(dyn->d_tag) == DT_NEEDED) { diff --git a/src/patchelf.h b/src/patchelf.h index 101b1c9..677462d 100644 --- a/src/patchelf.h +++ b/src/patchelf.h @@ -87,9 +87,9 @@ private: [[nodiscard]] std::string getSectionName(const Elf_Shdr & shdr) const; - Elf_Shdr & findSectionHeader(const SectionName & sectionName); + const Elf_Shdr & findSectionHeader(const SectionName & sectionName) const; - [[nodiscard]] std::optional> tryFindSectionHeader(const SectionName & sectionName); + [[nodiscard]] std::optional> tryFindSectionHeader(const SectionName & sectionName) const; [[nodiscard]] unsigned int getSectionIndex(const SectionName & sectionName) const; @@ -113,7 +113,7 @@ public: void rewriteSections(bool force = false); - [[nodiscard]] std::string getInterpreter(); + [[nodiscard]] std::string getInterpreter() const; typedef enum { printOsAbi, replaceOsAbi } osAbiMode; @@ -137,7 +137,7 @@ public: void replaceNeeded(const std::map & libs); - void printNeededLibs() /* should be const */; + void printNeededLibs() const; void noDefaultLib(); -- cgit v1.2.1 From ff7a5beb000a06842fc046c81388e0e103255f3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= Date: Tue, 21 Feb 2023 19:41:11 +0100 Subject: Avoid memory corruption on invalid ELF input Reject ELF data that would lead to invalid memory access or integer overflows. --- src/patchelf.cc | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 52 insertions(+), 7 deletions(-) diff --git a/src/patchelf.cc b/src/patchelf.cc index 7bfabb4..126cada 100644 --- a/src/patchelf.cc +++ b/src/patchelf.cc @@ -243,6 +243,25 @@ static void checkPointer(const FileContents & contents, const void * p, size_t s } +static void checkOffset(const FileContents & contents, size_t offset, size_t size) +{ + size_t end; + + if (offset > contents->size() + || size > contents->size() + || __builtin_add_overflow(offset, size, &end) + || end > contents->size()) + error("data offset extends past file end"); +} + + +static std::string extractString(const FileContents & contents, size_t offset, size_t size) +{ + checkOffset(contents, offset, size); + return { reinterpret_cast(contents->data()) + offset, size }; +} + + template ElfFile::ElfFile(FileContents fContents) : fileContents(fContents) @@ -259,14 +278,34 @@ ElfFile::ElfFile(FileContents fContents) if (rdi(hdr()->e_type) != ET_EXEC && rdi(hdr()->e_type) != ET_DYN) error("wrong ELF type"); - if (rdi(hdr()->e_phoff) + rdi(hdr()->e_phnum) * rdi(hdr()->e_phentsize) > fileContents->size()) - error("program header table out of bounds"); + { + auto ph_offset = rdi(hdr()->e_phoff); + auto ph_num = rdi(hdr()->e_phnum); + auto ph_entsize = rdi(hdr()->e_phentsize); + size_t ph_size, ph_end; + + if (__builtin_mul_overflow(ph_num, ph_entsize, &ph_size) + || __builtin_add_overflow(ph_offset, ph_size, &ph_end) + || ph_end > fileContents->size()) { + error("program header table out of bounds"); + } + } if (rdi(hdr()->e_shnum) == 0) error("no section headers. The input file is probably a statically linked, self-decompressing binary"); - if (rdi(hdr()->e_shoff) + rdi(hdr()->e_shnum) * rdi(hdr()->e_shentsize) > fileContents->size()) - error("section header table out of bounds"); + { + auto sh_offset = rdi(hdr()->e_shoff); + auto sh_num = rdi(hdr()->e_shnum); + auto sh_entsize = rdi(hdr()->e_shentsize); + size_t sh_size, sh_end; + + if (__builtin_mul_overflow(sh_num, sh_entsize, &sh_size) + || __builtin_add_overflow(sh_offset, sh_size, &sh_end) + || sh_end > fileContents->size()) { + error("section header table out of bounds"); + } + } if (rdi(hdr()->e_phentsize) != sizeof(Elf_Phdr)) error("program headers have wrong size"); @@ -295,7 +334,10 @@ ElfFile::ElfFile(FileContents fContents) error("string table index out of bounds"); auto shstrtabSize = rdi(shdrs[shstrtabIndex].sh_size); - char * shstrtab = (char * ) fileContents->data() + rdi(shdrs[shstrtabIndex].sh_offset); + size_t shstrtabptr; + if (__builtin_add_overflow(reinterpret_cast(fileContents->data()), rdi(shdrs[shstrtabIndex].sh_offset), &shstrtabptr)) + error("string table overflow"); + const char *shstrtab = reinterpret_cast(shstrtabptr); checkPointer(fileContents, shstrtab, shstrtabSize); if (shstrtabSize == 0) @@ -583,7 +625,7 @@ std::string & ElfFile::replaceSection(const SectionName & sec s = std::string(i->second); } else { auto shdr = findSectionHeader(sectionName); - s = std::string((char *) fileContents->data() + rdi(shdr.sh_offset), rdi(shdr.sh_size)); + s = extractString(fileContents, rdi(shdr.sh_offset), rdi(shdr.sh_size)); } s.resize(size); @@ -1193,7 +1235,10 @@ template std::string ElfFile::getInterpreter() const { auto shdr = findSectionHeader(".interp"); - return std::string((const char *) fileContents->data() + rdi(shdr.sh_offset), rdi(shdr.sh_size) - 1); + auto size = rdi(shdr.sh_size); + if (size > 0) + size--; + return extractString(fileContents, rdi(shdr.sh_offset), size); } template -- cgit v1.2.1 From fadce0a95b9b7925ecfaab4ea4177ec17501ae5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Breno=20Rodrigues=20Guimar=C3=A3es?= Date: Wed, 22 Feb 2023 06:10:01 -0300 Subject: Update src/patchelf.cc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jörg Thalheim --- src/patchelf.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/patchelf.cc b/src/patchelf.cc index 97f40cb..2a03da7 100644 --- a/src/patchelf.cc +++ b/src/patchelf.cc @@ -2134,6 +2134,7 @@ void ElfFile::renameDynamicSymbols(const std::unordered_mapsecond; + debug("renaming dynamic symbol %s to %s\n", name.data(), it->second.c_str()); extraStrings.insert(extraStrings.end(), newName.begin(), newName.end() + 1); changed = true; } -- cgit v1.2.1 From 4a50d12e22fa958b733111bf38c878519afc1a5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Breno=20Rodrigues=20Guimar=C3=A3es?= Date: Wed, 22 Feb 2023 06:10:19 -0300 Subject: Update src/patchelf.cc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jörg Thalheim --- src/patchelf.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/patchelf.cc b/src/patchelf.cc index 2a03da7..19994c5 100644 --- a/src/patchelf.cc +++ b/src/patchelf.cc @@ -2137,6 +2137,8 @@ void ElfFile::renameDynamicSymbols(const std::unordered_mapsecond.c_str()); extraStrings.insert(extraStrings.end(), newName.begin(), newName.end() + 1); changed = true; + } else { + debug("skip renaming dynamic symbol %sn", name.data()); } } -- cgit v1.2.1 From 16f13b4194d75ad2dbb9f48ce75268b4cc9e7e6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Breno=20Rodrigues=20Guimar=C3=A3es?= Date: Wed, 22 Feb 2023 06:10:33 -0300 Subject: Update patchelf.1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jörg Thalheim --- patchelf.1 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/patchelf.1 b/patchelf.1 index 2112c73..6a8a94e 100644 --- a/patchelf.1 +++ b/patchelf.1 @@ -129,6 +129,8 @@ with the old and the new name separated by spaces like this: old_name new_name +Symbol names do not contain version specifier that are also shown in the output of the nm -D command from binutils. So instead of the name write@GLIBC_2.2.5 it is just write. + .IP "--output FILE" Set the output file name. If not specified, the input will be modified in place. -- cgit v1.2.1 From 0611392aaae61da0c4fb0b41b4fb98a19d4b910f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Breno=20Rodrigues=20Guimar=C3=A3es?= Date: Wed, 22 Feb 2023 06:42:46 -0300 Subject: Update patchelf.cc Untested. Coding from github while my VM is acting up. --- src/patchelf.cc | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/patchelf.cc b/src/patchelf.cc index 19994c5..924c4cf 100644 --- a/src/patchelf.cc +++ b/src/patchelf.cc @@ -2549,18 +2549,24 @@ static int mainWrapped(int argc, char * * argv) renameDynamicSymbols = true; if (++i == argc) error("missing argument"); - std::ifstream infile(argv[i]); - if (!infile) error(fmt("Cannot open map file ", argv[i])); + const char* fname = argv[i]; + std::ifstream infile(fname); + if (!infile) error(fmt("Cannot open map file ", fname)); - std::string from, to; - while (true) + std::string line, from, to; + size_t lineCount = 1; + while (std::getline(infile, line)) { - if (!(infile >> from)) + std::istringstream iss(line); + if (!(iss >> from)) break; - if (!(infile >> to)) - error("Odd number of symbols in map file"); + if (!(iss >> to)) + error(fmt(fname, ":", lineCount, ": Map file line is missing the second element")); if (symbolsToRenameKeys.count(from)) - error(fmt("Symbol appears twice in the map file: ", from.c_str())); + error(fmt(fname, ":", lineCount, ": Name ", from, " appears twice in the map file")); + if (from.find('@') != std::string_view::npos || to.find('@') != std::string_view::npos) + error(fmt(fname, ":", lineCount, ": Name pair contains version tag: ", from, " ", to)); + lineCount++; symbolsToRename[*symbolsToRenameKeys.insert(from).first] = to; } } -- cgit v1.2.1 From 991bf3a4ff094e4d09b9bf72f058393ae44e4a94 Mon Sep 17 00:00:00 2001 From: Breno Rodrigues Guimaraes Date: Wed, 22 Feb 2023 06:51:28 -0300 Subject: Fixup --- src/patchelf.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/patchelf.cc b/src/patchelf.cc index 924c4cf..a4388f9 100644 --- a/src/patchelf.cc +++ b/src/patchelf.cc @@ -2563,7 +2563,7 @@ static int mainWrapped(int argc, char * * argv) if (!(iss >> to)) error(fmt(fname, ":", lineCount, ": Map file line is missing the second element")); if (symbolsToRenameKeys.count(from)) - error(fmt(fname, ":", lineCount, ": Name ", from, " appears twice in the map file")); + error(fmt(fname, ":", lineCount, ": Name '", from, "' appears twice in the map file")); if (from.find('@') != std::string_view::npos || to.find('@') != std::string_view::npos) error(fmt(fname, ":", lineCount, ": Name pair contains version tag: ", from, " ", to)); lineCount++; -- cgit v1.2.1 From aeb34c2cc9d473319f320db49cd20e7e9ea4bff8 Mon Sep 17 00:00:00 2001 From: Breno Rodrigues Guimaraes Date: Wed, 22 Feb 2023 07:18:28 -0300 Subject: Avoid syntax in lambdas. Thats C++20 --- src/patchelf.cc | 20 +++++--------------- src/patchelf.h | 27 ++++++++++++++++++++------- 2 files changed, 25 insertions(+), 22 deletions(-) diff --git a/src/patchelf.cc b/src/patchelf.cc index a4388f9..db18837 100644 --- a/src/patchelf.cc +++ b/src/patchelf.cc @@ -2013,20 +2013,10 @@ void ElfFile::rebuildGnuHashTable(span strTab, span (auto& hdr) + auto remapSymbolId = [&old2new, firstSymIdx] (auto& oldSymIdx) { - auto rela = getSectionSpan(hdr); - for (auto& r : rela) - { - auto info = rdi(r.r_info); - auto oldSymIdx = rel_getSymId(info); - if (oldSymIdx >= firstSymIdx) - { - auto newSymIdx = old2new[oldSymIdx - firstSymIdx] + firstSymIdx; - if (newSymIdx != oldSymIdx) - wri(r.r_info, rel_setSymId(info, newSymIdx)); - } - } + return oldSymIdx >= firstSymIdx ? old2new[oldSymIdx - firstSymIdx] + firstSymIdx + : oldSymIdx; }; for (unsigned int i = 1; i < rdi(hdr()->e_shnum); ++i) @@ -2034,9 +2024,9 @@ void ElfFile::rebuildGnuHashTable(span strTab, span(shdr); + changeRelocTableSymIds(shdr, remapSymbolId); else if (shtype == SHT_RELA) - fixRelocationTable.template operator()(shdr); + changeRelocTableSymIds(shdr, remapSymbolId); } // Update bloom filters diff --git a/src/patchelf.h b/src/patchelf.h index 8f96ec6..9fab18c 100644 --- a/src/patchelf.h +++ b/src/patchelf.h @@ -169,6 +169,13 @@ public: void renameDynamicSymbols(const std::unordered_map&); + void clearSymbolVersions(const std::set & syms); + + enum class ExecstackMode { print, set, clear }; + + void modifyExecstack(ExecstackMode op); + +private: struct GnuHashTable { using BloomWord = Elf_Addr; struct Header { @@ -215,14 +222,20 @@ public: return info; } + template + void changeRelocTableSymIds(const Elf_Shdr& shdr, RemapFn&& old2newSymId) + { + static_assert(std::is_same_v || std::is_same_v); - void clearSymbolVersions(const std::set & syms); - - enum class ExecstackMode { print, set, clear }; - - void modifyExecstack(ExecstackMode op); - -private: + for (auto& r : getSectionSpan(shdr)) + { + auto info = rdi(r.r_info); + auto oldSymIdx = rel_getSymId(info); + auto newSymIdx = old2newSymId(oldSymIdx); + if (newSymIdx != oldSymIdx) + wri(r.r_info, rel_setSymId(info, newSymIdx)); + } + } /* Convert an integer in big or little endian representation (as specified by the ELF header) to this platform's integer -- cgit v1.2.1 From 5b88266ce8a381c496d031cd46cc2f2fdf7ec8f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= Date: Wed, 22 Feb 2023 20:14:12 +0100 Subject: Adjust roundUp for 0 as input Round up 0 to m instead of wrapping around and return an unexpected result, which is not a multiple of m. --- src/patchelf.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/patchelf.cc b/src/patchelf.cc index 126cada..859fe92 100644 --- a/src/patchelf.cc +++ b/src/patchelf.cc @@ -477,6 +477,8 @@ static void writeFile(const std::string & fileName, const FileContents & content static uint64_t roundUp(uint64_t n, uint64_t m) { + if (n == 0) + return m; return ((n - 1) / m + 1) * m; } -- cgit v1.2.1