diff options
author | Christian Göttsche <cgzones@googlemail.com> | 2023-01-27 17:15:02 +0100 |
---|---|---|
committer | Christian Göttsche <cgzones@googlemail.com> | 2023-01-28 23:27:34 +0100 |
commit | f7d304eeb1f46a15d8fb6564459ed003edbf9bb3 (patch) | |
tree | 06c541da9cf09d6d92ac8f2510b02316348db6b9 /src | |
parent | 5908e16cd562bcb1909be4de0409c4912a8afc52 (diff) | |
download | patchelf-f7d304eeb1f46a15d8fb6564459ed003edbf9bb3.tar.gz |
Add options to print, clear and set executable stack state
Add options the modify the state of the executable flag of the GNU_STACK
program header. That header indicates whether the object is requiring an
executable stack.
Diffstat (limited to 'src')
-rw-r--r-- | src/patchelf.cc | 105 | ||||
-rw-r--r-- | src/patchelf.h | 6 |
2 files changed, 108 insertions, 3 deletions
diff --git a/src/patchelf.cc b/src/patchelf.cc index 2bb84eb..e91e2ab 100644 --- a/src/patchelf.cc +++ b/src/patchelf.cc @@ -1010,10 +1010,10 @@ void ElfFile<ElfFileParamNames>::normalizeNoteSegments() template<ElfFileParams> -void ElfFile<ElfFileParamNames>::rewriteSections() +void ElfFile<ElfFileParamNames>::rewriteSections(bool force) { - if (replacedSections.empty()) return; + if (!force && replacedSections.empty()) return; for (auto & i : replacedSections) debug("replacing section '%s' with size %d\n", @@ -1890,6 +1890,85 @@ void ElfFile<ElfFileParamNames>::clearSymbolVersions(const std::set<std::string> this->rewriteSections(); } +template<ElfFileParams> +void ElfFile<ElfFileParamNames>::modifyExecstack(ExecstackMode op) +{ + if (op == ExecstackMode::clear || op == ExecstackMode::set) { + size_t nullhdr = (size_t)-1; + + for (size_t i = 0; i < phdrs.size(); i++) { + auto & header = phdrs[i]; + const auto type = rdi(header.p_type); + if (type != PT_GNU_STACK) { + if (!nullhdr && type == PT_NULL) + nullhdr = i; + continue; + } + + if (op == ExecstackMode::clear && (rdi(header.p_flags) & PF_X) == PF_X) { + debug("simple execstack clear of header %zu\n", i); + + wri(header.p_flags, rdi(header.p_flags) & ~PF_X); + * ((Elf_Phdr *) (fileContents->data() + rdi(hdr()->e_phoff)) + i) = header; + changed = true; + } else if (op == ExecstackMode::set && (rdi(header.p_flags) & PF_X) != PF_X) { + debug("simple execstack set of header %zu\n", i); + + wri(header.p_flags, rdi(header.p_flags) | PF_X); + * ((Elf_Phdr *) (fileContents->data() + rdi(hdr()->e_phoff)) + i) = header; + changed = true; + } else { + debug("execstack already in requested state\n"); + } + + return; + } + + if (nullhdr != (size_t)-1) { + debug("replacement execstack of header %zu\n", nullhdr); + + auto & header = phdrs[nullhdr]; + header = {}; + wri(header.p_type, PT_GNU_STACK); + wri(header.p_flags, PF_R | PF_W | (op == ExecstackMode::set ? PF_X : 0)); + wri(header.p_align, 0x1); + + * ((Elf_Phdr *) (fileContents->data() + rdi(hdr()->e_phoff)) + nullhdr) = header; + changed = true; + return; + } + + debug("header addition for execstack\n"); + + Elf_Phdr new_phdr = {}; + wri(new_phdr.p_type, PT_GNU_STACK); + wri(new_phdr.p_flags, PF_R | PF_W | (op == ExecstackMode::set ? PF_X : 0)); + wri(new_phdr.p_align, 0x1); + phdrs.push_back(new_phdr); + + wri(hdr()->e_phnum, rdi(hdr()->e_phnum) + 1); + + changed = true; + rewriteSections(true); + return; + } + + char result = '?'; + + for (const auto & header : phdrs) { + if (rdi(header.p_type) != PT_GNU_STACK) + continue; + + if ((rdi(header.p_flags) & PF_X) == PF_X) + result = 'X'; + else + result = '-'; + break; + } + + printf("execstack: %c\n", result); +} + static bool printInterpreter = false; static bool printOsAbi = false; static bool setOsAbi = false; @@ -1912,6 +1991,9 @@ static std::set<std::string> neededLibsToAdd; static std::set<std::string> symbolsToClearVersion; static bool printNeeded = false; static bool noDefaultLib = false; +static bool printExecstack = false; +static bool clearExecstack = false; +static bool setExecstack = false; template<class ElfFile> static void patchElf2(ElfFile && elfFile, const FileContents & fileContents, const std::string & fileName) @@ -1937,6 +2019,13 @@ static void patchElf2(ElfFile && elfFile, const FileContents & fileContents, con if (printRPath) elfFile.modifyRPath(elfFile.rpPrint, {}, ""); + if (printExecstack) + elfFile.modifyExecstack(ElfFile::ExecstackMode::print); + else if (clearExecstack) + elfFile.modifyExecstack(ElfFile::ExecstackMode::clear); + else if (setExecstack) + elfFile.modifyExecstack(ElfFile::ExecstackMode::set); + if (shrinkRPath) elfFile.modifyRPath(elfFile.rpShrink, allowedRpathPrefixes, ""); else if (removeRPath) @@ -2019,6 +2108,9 @@ void showHelp(const std::string & progName) [--no-sort]\t\tDo not sort program+section headers; useful for debugging patchelf.\n\ [--clear-symbol-version SYMBOL]\n\ [--add-debug-tag]\n\ + [--print-execstack]\t\tPrints whether the object requests an executable stack\n\ + [--clear-execstack]\n\ + [--set-execstack]\n\ [--output FILE]\n\ [--debug]\n\ [--version]\n\ @@ -2127,6 +2219,15 @@ int mainWrapped(int argc, char * * argv) if (++i == argc) error("missing argument"); symbolsToClearVersion.insert(resolveArgument(argv[i])); } + else if (arg == "--print-execstack") { + printExecstack = true; + } + else if (arg == "--clear-execstack") { + clearExecstack = true; + } + else if (arg == "--set-execstack") { + setExecstack = true; + } else if (arg == "--output") { if (++i == argc) error("missing argument"); outputFileName = resolveArgument(argv[i]); diff --git a/src/patchelf.h b/src/patchelf.h index f4eec6f..c3096ff 100644 --- a/src/patchelf.h +++ b/src/patchelf.h @@ -105,7 +105,7 @@ private: public: - void rewriteSections(); + void rewriteSections(bool force = false); std::string getInterpreter(); @@ -139,6 +139,10 @@ public: void clearSymbolVersions(const std::set<std::string> & syms); + enum class ExecstackMode { print, set, clear }; + + void modifyExecstack(ExecstackMode op); + private: /* Convert an integer in big or little endian representation (as |