-
-
Notifications
You must be signed in to change notification settings - Fork 490
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Introduce Finally to help track section rewrites #363
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,29 +18,20 @@ | |
|
||
#include <algorithm> | ||
#include <limits> | ||
#include <map> | ||
#include <memory> | ||
#include <set> | ||
#include <sstream> | ||
#include <stdexcept> | ||
#include <string> | ||
#include <unordered_map> | ||
#include <vector> | ||
#include <optional> | ||
|
||
#include <cassert> | ||
#include <cerrno> | ||
#include <cstdarg> | ||
#include <cstdio> | ||
#include <cstdlib> | ||
#include <cstring> | ||
|
||
#include <fcntl.h> | ||
#include <sys/stat.h> | ||
#include <sys/types.h> | ||
#include <unistd.h> | ||
|
||
#include "elf.h" | ||
#include "patchelf.h" | ||
|
||
#ifndef PACKAGE_STRING | ||
|
@@ -1082,6 +1073,16 @@ std::string ElfFile<ElfFileParamNames>::getInterpreter() | |
template<ElfFileParams> | ||
void ElfFile<ElfFileParamNames>::modifySoname(sonameMode op, const std::string & newSoname) | ||
{ | ||
|
||
bool soNameModified = false; | ||
|
||
Finally finally([&]() { | ||
if (soNameModified) { | ||
this->rewriteSections(); | ||
changed = true; | ||
} | ||
}); | ||
|
||
if (rdi(hdr()->e_type) != ET_DYN) { | ||
debug("this is not a dynamic library\n"); | ||
return; | ||
|
@@ -1149,17 +1150,24 @@ void ElfFile<ElfFileParamNames>::modifySoname(sonameMode op, const std::string & | |
setSubstr(newDynamic, 0, std::string((char *)&newDyn, sizeof(Elf_Dyn))); | ||
} | ||
|
||
changed = true; | ||
this->rewriteSections(); | ||
soNameModified = true; | ||
} | ||
|
||
template<ElfFileParams> | ||
void ElfFile<ElfFileParamNames>::setInterpreter(const std::string & newInterpreter) | ||
{ | ||
bool interpreterChanged = false; | ||
|
||
Finally finally([&]() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This one as well. |
||
if (interpreterChanged) { | ||
this->rewriteSections(); | ||
changed = true; | ||
} | ||
}); | ||
|
||
std::string & section = replaceSection(".interp", newInterpreter.size() + 1); | ||
setSubstr(section, 0, newInterpreter + '\0'); | ||
changed = true; | ||
this->rewriteSections(); | ||
interpreterChanged = true; | ||
} | ||
|
||
|
||
|
@@ -1222,27 +1230,42 @@ std::string ElfFile<ElfFileParamNames>::shrinkRPath(char* rpath, std::vector<std | |
|
||
template<ElfFileParams> | ||
void ElfFile<ElfFileParamNames>::removeRPath(Elf_Shdr & shdrDynamic) { | ||
bool rpathChanged = false; | ||
Finally finally([&]() { | ||
if (rpathChanged) { | ||
this->rewriteSections(); | ||
changed = true; | ||
} | ||
}); | ||
|
||
auto dyn = (Elf_Dyn *)(fileContents->data() + rdi(shdrDynamic.sh_offset)); | ||
Elf_Dyn * last = dyn; | ||
for ( ; rdi(dyn->d_tag) != DT_NULL; dyn++) { | ||
if (rdi(dyn->d_tag) == DT_RPATH) { | ||
debug("removing DT_RPATH entry\n"); | ||
changed = true; | ||
rpathChanged = true; | ||
} else if (rdi(dyn->d_tag) == DT_RUNPATH) { | ||
debug("removing DT_RUNPATH entry\n"); | ||
changed = true; | ||
rpathChanged = true; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This one seems fine. |
||
} else { | ||
*last++ = *dyn; | ||
} | ||
} | ||
memset(last, 0, sizeof(Elf_Dyn) * (dyn - last)); | ||
this->rewriteSections(); | ||
} | ||
|
||
template<ElfFileParams> | ||
void ElfFile<ElfFileParamNames>::modifyRPath(RPathOp op, | ||
const std::vector<std::string> & allowedRpathPrefixes, std::string newRPath) | ||
{ | ||
bool rpathChanged = false; | ||
Finally finally([&]() { | ||
if (rpathChanged) { | ||
this->rewriteSections(); | ||
changed = true; | ||
} | ||
}); | ||
|
||
auto shdrDynamic = findSectionHeader(".dynamic"); | ||
|
||
if (rdi(shdrDynamic.sh_type) == SHT_NOBITS) { | ||
|
@@ -1321,18 +1344,18 @@ void ElfFile<ElfFileParamNames>::modifyRPath(RPathOp op, | |
wri(dynRPath->d_tag, DT_RUNPATH); | ||
dynRunPath = dynRPath; | ||
dynRPath = nullptr; | ||
changed = true; | ||
rpathChanged = true; | ||
} else if (forceRPath && dynRunPath) { /* convert DT_RUNPATH to DT_RPATH */ | ||
wri(dynRunPath->d_tag, DT_RPATH); | ||
dynRPath = dynRunPath; | ||
dynRunPath = nullptr; | ||
changed = true; | ||
rpathChanged = true; | ||
} | ||
|
||
if (rpath && rpath == newRPath) { | ||
return; | ||
} | ||
changed = true; | ||
rpathChanged = true; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This one seems fine. |
||
|
||
/* Zero out the previous rpath to prevent retained dependencies in | ||
Nix. */ | ||
|
@@ -1383,7 +1406,6 @@ void ElfFile<ElfFileParamNames>::modifyRPath(RPathOp op, | |
newDyn.d_un.d_val = shdrDynStr.sh_size; | ||
setSubstr(newDynamic, 0, std::string((char *) &newDyn, sizeof(Elf_Dyn))); | ||
} | ||
this->rewriteSections(); | ||
} | ||
|
||
|
||
|
@@ -1392,6 +1414,14 @@ void ElfFile<ElfFileParamNames>::removeNeeded(const std::set<std::string> & libs | |
{ | ||
if (libs.empty()) return; | ||
|
||
bool neededChanged = false; | ||
Finally finally([&]() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This one seems fine, but there should be no |
||
if (neededChanged) { | ||
this->rewriteSections(); | ||
changed = true; | ||
} | ||
}); | ||
|
||
auto shdrDynamic = findSectionHeader(".dynamic"); | ||
auto shdrDynStr = findSectionHeader(".dynstr"); | ||
char * strTab = (char *) fileContents->data() + rdi(shdrDynStr.sh_offset); | ||
|
@@ -1403,7 +1433,7 @@ void ElfFile<ElfFileParamNames>::removeNeeded(const std::set<std::string> & libs | |
char * name = strTab + rdi(dyn->d_un.d_val); | ||
if (libs.count(name)) { | ||
debug("removing DT_NEEDED entry '%s'\n", name); | ||
changed = true; | ||
neededChanged = true; | ||
} else { | ||
debug("keeping DT_NEEDED entry '%s'\n", name); | ||
*last++ = *dyn; | ||
|
@@ -1422,6 +1452,14 @@ void ElfFile<ElfFileParamNames>::replaceNeeded(const std::map<std::string, std:: | |
{ | ||
if (libs.empty()) return; | ||
|
||
bool neededChanged = false; | ||
Finally finally([&]() { | ||
if (neededChanged) { | ||
this->rewriteSections(); | ||
changed = true; | ||
} | ||
}); | ||
|
||
auto shdrDynamic = findSectionHeader(".dynamic"); | ||
auto shdrDynStr = findSectionHeader(".dynstr"); | ||
char * strTab = (char *) fileContents->data() + rdi(shdrDynStr.sh_offset); | ||
|
@@ -1464,7 +1502,7 @@ void ElfFile<ElfFileParamNames>::replaceNeeded(const std::map<std::string, std:: | |
|
||
dynStrAddedBytes += replacement.size() + 1; | ||
|
||
changed = true; | ||
neededChanged = true; | ||
} else { | ||
debug("keeping DT_NEEDED entry '%s'\n", name); | ||
} | ||
|
@@ -1529,7 +1567,7 @@ void ElfFile<ElfFileParamNames>::replaceNeeded(const std::map<std::string, std:: | |
verStrAddedBytes += replacement.size() + 1; | ||
} | ||
|
||
changed = true; | ||
neededChanged = true; | ||
} else { | ||
debug("keeping .gnu.version_r entry '%s'\n", file); | ||
} | ||
|
@@ -1538,15 +1576,21 @@ void ElfFile<ElfFileParamNames>::replaceNeeded(const std::map<std::string, std:: | |
--verNeedNum; | ||
} | ||
} | ||
|
||
this->rewriteSections(); | ||
} | ||
|
||
template<ElfFileParams> | ||
void ElfFile<ElfFileParamNames>::addNeeded(const std::set<std::string> & libs) | ||
{ | ||
if (libs.empty()) return; | ||
|
||
bool neededChanged = false; | ||
Finally finally([&]() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can be dropped here. |
||
if (neededChanged) { | ||
this->rewriteSections(); | ||
changed = true; | ||
} | ||
}); | ||
|
||
auto shdrDynamic = findSectionHeader(".dynamic"); | ||
auto shdrDynStr = findSectionHeader(".dynstr"); | ||
|
||
|
@@ -1589,9 +1633,7 @@ void ElfFile<ElfFileParamNames>::addNeeded(const std::set<std::string> & libs) | |
i++; | ||
} | ||
|
||
changed = true; | ||
|
||
this->rewriteSections(); | ||
neededChanged = true; | ||
} | ||
|
||
template<ElfFileParams> | ||
|
@@ -1615,6 +1657,14 @@ void ElfFile<ElfFileParamNames>::printNeededLibs() // const | |
template<ElfFileParams> | ||
void ElfFile<ElfFileParamNames>::noDefaultLib() | ||
{ | ||
bool defaultLibChanged = false; | ||
Finally finally([&]() { | ||
if (defaultLibChanged) { | ||
this->rewriteSections(); | ||
changed = true; | ||
} | ||
}); | ||
|
||
auto shdrDynamic = findSectionHeader(".dynamic"); | ||
|
||
auto dyn = (Elf_Dyn *)(fileContents->data() + rdi(shdrDynamic.sh_offset)); | ||
|
@@ -1648,15 +1698,22 @@ void ElfFile<ElfFileParamNames>::noDefaultLib() | |
setSubstr(newDynamic, 0, std::string((char *) &newDyn, sizeof(Elf_Dyn))); | ||
} | ||
|
||
this->rewriteSections(); | ||
changed = true; | ||
defaultLibChanged = true; | ||
} | ||
|
||
template<ElfFileParams> | ||
void ElfFile<ElfFileParamNames>::clearSymbolVersions(const std::set<std::string> & syms) | ||
{ | ||
if (syms.empty()) return; | ||
|
||
bool symbolVersionsChanged = false; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can be dropped here. |
||
Finally finally([&]() { | ||
if (symbolVersionsChanged) { | ||
this->rewriteSections(); | ||
changed = true; | ||
} | ||
}); | ||
|
||
auto shdrDynStr = findSectionHeader(".dynstr"); | ||
auto shdrDynsym = findSectionHeader(".dynsym"); | ||
auto shdrVersym = findSectionHeader(".gnu.version"); | ||
|
@@ -1677,8 +1734,7 @@ void ElfFile<ElfFileParamNames>::clearSymbolVersions(const std::set<std::string> | |
wri(versyms[i], 1); | ||
} | ||
} | ||
changed = true; | ||
this->rewriteSections(); | ||
symbolVersionsChanged = true; | ||
} | ||
|
||
static bool printInterpreter = false; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,15 @@ | ||
#pragma once | ||
|
||
#include <string> | ||
#include <functional> | ||
#include <vector> | ||
#include <optional> | ||
#include <map> | ||
#include <set> | ||
#include <memory> | ||
Comment on lines
+3
to
+9
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Tried to make this header file more "correct". |
||
|
||
#include "elf.h" | ||
|
||
using FileContents = std::shared_ptr<std::vector<unsigned char>>; | ||
|
||
#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 | ||
|
@@ -157,3 +169,15 @@ class ElfFile | |
return (const Elf_Ehdr *)fileContents->data(); | ||
} | ||
}; | ||
|
||
/* A trivial class to run a function at the end of a scope. */ | ||
class Finally | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
{ | ||
private: | ||
std::function<void()> fun; | ||
|
||
public: | ||
Finally(std::function<void()> fun) : fun(fun) { } | ||
~Finally() { fun(); } | ||
}; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would actually prefer the old code in cases where we don't need to handle early returns
to avoid hidden control flow. This one is such a case.