diff --git a/src/patchelf.cc b/src/patchelf.cc index b42111dd..e8827bd0 100644 --- a/src/patchelf.cc +++ b/src/patchelf.cc @@ -322,6 +322,8 @@ ElfFile::ElfFile(FileContents fContents) if (rdi(phdrs[i].p_type) == PT_INTERP) isExecutable = true; } + trailingNullPhdrs = 0; + for (int i = 0; i < rdi(hdr()->e_shnum); ++i) { Elf_Shdr *shdr = (Elf_Shdr *) (fileContents->data() + rdi(hdr()->e_shoff)) + i; @@ -1162,7 +1164,7 @@ void ElfFile::rewriteHeaders(Elf_Addr phdrAddress) if (rdi(phdr.p_type) == PT_PHDR) { phdr.p_offset = hdr()->e_phoff; wri(phdr.p_vaddr, wri(phdr.p_paddr, phdrAddress)); - wri(phdr.p_filesz, wri(phdr.p_memsz, phdrs.size() * sizeof(Elf_Phdr))); + wri(phdr.p_filesz, wri(phdr.p_memsz, (phdrs.size() + trailingNullPhdrs) * sizeof(Elf_Phdr))); break; } } @@ -1171,6 +1173,17 @@ void ElfFile::rewriteHeaders(Elf_Addr phdrAddress) sortPhdrs(); } + if (trailingNullPhdrs) { + Elf_Phdr nullPhdr = {}; + nullPhdr.p_type = PT_NULL; + + for (int i = 0; i < trailingNullPhdrs; ++i) { + phdrs.push_back(nullPhdr); + } + + wri(hdr()->e_phnum, rdi(hdr()->e_phnum) + trailingNullPhdrs); + } + for (unsigned int i = 0; i < phdrs.size(); ++i) * ((Elf_Phdr *) (fileContents->data() + rdi(hdr()->e_phoff)) + i) = phdrs.at(i); @@ -1298,7 +1311,13 @@ void ElfFile::rewriteHeaders(Elf_Addr phdrAddress) } } - +template +void ElfFile::appendNullPhdrs(int count) +{ + trailingNullPhdrs += count; + rewriteHeaders(rdi(hdr()->e_phoff)); + changed = true; +} static void setSubstr(std::string & s, unsigned int pos, const std::string & t) { @@ -2376,6 +2395,7 @@ static bool addDebugTag = false; static bool renameDynamicSymbols = false; static bool printRPath = false; static std::string newRPath; +static int nullPhdrsToAppend; static std::set neededLibsToRemove; static std::map neededLibsToReplace; static std::set neededLibsToAdd; @@ -2444,6 +2464,9 @@ static void patchElf2(ElfFile && elfFile, const FileContents & fileContents, con if (renameDynamicSymbols) elfFile.renameDynamicSymbols(symbolsToRename); + if (nullPhdrsToAppend) + elfFile.appendNullPhdrs(nullPhdrsToAppend); + if (elfFile.isChanged()){ writeFile(fileName, elfFile.fileContents); } else if (alwaysWrite) { @@ -2496,6 +2519,8 @@ static void showHelp(const std::string & progName) [--allowed-rpath-prefixes PREFIXES]\t\tWith '--shrink-rpath', reject rpath entries not starting with the allowed prefix\n\ [--print-rpath]\n\ [--force-rpath]\n\ + [--append-null-phdr]\t\tAppends a PT_NULL program header to the end of the table; may be used multiple times\n\ + [--append-null-phdrs N]\t\tAppends N PT_NULL program headers to the end of the table; may be used multiple times\n\ [--add-needed LIBRARY]\n\ [--remove-needed LIBRARY]\n\ [--replace-needed LIBRARY NEW_LIBRARY]\n\ @@ -2600,6 +2625,13 @@ static int mainWrapped(int argc, char * * argv) else if (arg == "--no-sort") { noSort = true; } + else if (arg == "--append-null-phdr") { + ++nullPhdrsToAppend; + } + else if (arg == "--append-null-phdrs") { + if (++i == argc) error("missing argument"); + nullPhdrsToAppend += std::stoi(argv[i]); + } else if (arg == "--add-needed") { if (++i == argc) error("missing argument"); neededLibsToAdd.insert(resolveArgument(argv[i])); diff --git a/src/patchelf.h b/src/patchelf.h index 4e229d67..10e2866b 100644 --- a/src/patchelf.h +++ b/src/patchelf.h @@ -45,6 +45,8 @@ class ElfFile std::vector phdrs; std::vector shdrs; + int trailingNullPhdrs; + bool littleEndian; bool changed = false; @@ -167,6 +169,8 @@ class ElfFile void addDebugTag(); + void appendNullPhdrs(int count); + void renameDynamicSymbols(const std::unordered_map&); void clearSymbolVersions(const std::set & syms); diff --git a/tests/Makefile.am b/tests/Makefile.am index 8bbded7a..dd37d72e 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -40,6 +40,7 @@ src_TESTS = \ basic-flags.sh \ set-empty-rpath.sh \ phdr-corruption.sh \ + append-null-phdr.sh \ replace-needed.sh \ replace-add-needed.sh \ add-debug-tag.sh \ @@ -123,7 +124,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 many-syms-main libmany-syms.so liboveralign.so libshared-rpath.so + phdr-corruption.so append-null-phdr.so many-syms-main libmany-syms.so liboveralign.so libshared-rpath.so libbuildid_so_SOURCES = simple.c libbuildid_so_LDFLAGS = $(LDFLAGS_sharedlib) -Wl,--build-id @@ -180,6 +181,10 @@ 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 = +append_null_phdr_so_SOURCES = void.c +append_null_phdr_so_LDFLAGS = -nostdlib -shared +append_null_phdr_so_CFLAGS = + many-syms.c: i=1; while [ $$i -le 2000 ]; do echo "void f$$i() {};"; i=$$(($$i + 1)); done > $@ diff --git a/tests/append-null-phdr.sh b/tests/append-null-phdr.sh new file mode 100755 index 00000000..b087f2a1 --- /dev/null +++ b/tests/append-null-phdr.sh @@ -0,0 +1,22 @@ +#! /bin/sh -e + +PATCHELF="../src/patchelf" +SONAME="phdr-corruption.so" +SCRATCH="scratch/$(basename "$0" .sh)" +SCRATCH_SO="${SCRATCH}/${SONAME}" +READELF=${READELF:-readelf} + +rm -rf "${SCRATCH}" +mkdir -p "${SCRATCH}" +cp "${SONAME}" "${SCRATCH}" + +"${PATCHELF}" --append-null-phdr --append-null-phdrs 2 "${SCRATCH_SO}" + +# Check for PT_NULL entries +readelfData=$(${READELF} -l "${SCRATCH_SO}" 2>&1) + +if [ "$(echo "$readelfData" | grep -c "NULL")" != 3 ]; then + # Triggered if patchelf doesn't append two PT_NULL entries + echo "ERROR: PT_NULL segments were not appended to the program header table!" + exit 1 +fi