summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2023-02-21 20:01:16 +0000
committerGitHub <noreply@github.com>2023-02-21 20:01:16 +0000
commite37f892b12ff900ab5e733f688548c87cd14ef02 (patch)
tree3d469e631dba265b9f2058fc6451e468468162fd
parent8d3188daa7fbefb93e8d967d2967ca45934c30aa (diff)
parentff7a5beb000a06842fc046c81388e0e103255f3a (diff)
downloadpatchelf-e37f892b12ff900ab5e733f688548c87cd14ef02.tar.gz
Merge #464
464: Modernizations and strictness improvements r=Mic92 a=cgzones Co-authored-by: Christian Göttsche <cgzones@googlemail.com>
-rw-r--r--src/Makefile.am2
-rw-r--r--src/patchelf.cc139
-rw-r--r--src/patchelf.h63
3 files changed, 131 insertions, 73 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index fa0a9cc..93e92d8 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 -Wextra -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 e91e2ab..126cada 100644
--- a/src/patchelf.cc
+++ b/src/patchelf.cc
@@ -24,6 +24,7 @@
#include <sstream>
#include <stdexcept>
#include <string>
+#include <string_view>
#include <unordered_map>
#include <vector>
#include <optional>
@@ -69,14 +70,18 @@ static int forcedPageSize = -1;
#define EM_LOONGARCH 258
#endif
-
-static std::vector<std::string> splitColonDelimitedString(const char * s)
+[[nodiscard]] static std::vector<std::string> splitColonDelimitedString(std::string_view s)
{
- std::string item;
std::vector<std::string> 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;
}
@@ -104,7 +109,7 @@ static std::string downcase(std::string s)
why... */
template<ElfFileParams>
template<class I>
-I ElfFile<ElfFileParamNames>::rdi(I i) const
+constexpr I ElfFile<ElfFileParamNames>::rdi(I i) const noexcept
{
I r = 0;
if (littleEndian) {
@@ -131,7 +136,7 @@ static void debug(const char * format, ...)
}
-void fmt2(std::ostringstream & out)
+static void fmt2([[maybe_unused]] std::ostringstream & out)
{
}
@@ -162,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);
@@ -191,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;
}
@@ -207,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<off_t>(sizeof(Elf32_Ehdr)))
+ if (fileContents->size() < sizeof(Elf32_Ehdr))
error("missing ELF header");
auto contents = fileContents->data();
@@ -231,14 +236,32 @@ ElfType getElfType(const FileContents & fileContents)
}
-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<unsigned char *>(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");
}
+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<const char *>(contents->data()) + offset, size };
+}
+
+
template<ElfFileParams>
ElfFile<ElfFileParamNames>::ElfFile(FileContents fContents)
: fileContents(fContents)
@@ -255,14 +278,34 @@ ElfFile<ElfFileParamNames>::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");
@@ -286,12 +329,15 @@ ElfFile<ElfFileParamNames>::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);
- char * shstrtab = (char * ) fileContents->data() + rdi(shdrs[shstrtabIndex].sh_offset);
+ auto shstrtabSize = rdi(shdrs[shstrtabIndex].sh_size);
+ size_t shstrtabptr;
+ if (__builtin_add_overflow(reinterpret_cast<size_t>(fileContents->data()), rdi(shdrs[shstrtabIndex].sh_offset), &shstrtabptr))
+ error("string table overflow");
+ const char *shstrtab = reinterpret_cast<const char *>(shstrtabptr);
checkPointer(fileContents, shstrtab, shstrtabSize);
if (shstrtabSize == 0)
@@ -309,7 +355,7 @@ ElfFile<ElfFileParamNames>::ElfFile(FileContents fContents)
template<ElfFileParams>
-unsigned int ElfFile<ElfFileParamNames>::getPageSize() const
+unsigned int ElfFile<ElfFileParamNames>::getPageSize() const noexcept
{
if (forcedPageSize > 0)
return forcedPageSize;
@@ -531,7 +577,7 @@ std::string ElfFile<ElfFileParamNames>::getSectionName(const Elf_Shdr & shdr) co
template<ElfFileParams>
-Elf_Shdr & ElfFile<ElfFileParamNames>::findSectionHeader(const SectionName & sectionName)
+const Elf_Shdr & ElfFile<ElfFileParamNames>::findSectionHeader(const SectionName & sectionName) const
{
auto shdr = tryFindSectionHeader(sectionName);
if (!shdr) {
@@ -545,7 +591,7 @@ Elf_Shdr & ElfFile<ElfFileParamNames>::findSectionHeader(const SectionName & sec
template<ElfFileParams>
-std::optional<std::reference_wrapper<Elf_Shdr>> ElfFile<ElfFileParamNames>::tryFindSectionHeader(const SectionName & sectionName)
+std::optional<std::reference_wrapper<const Elf_Shdr>> ElfFile<ElfFileParamNames>::tryFindSectionHeader(const SectionName & sectionName) const
{
auto i = getSectionIndex(sectionName);
if (i)
@@ -555,7 +601,7 @@ std::optional<std::reference_wrapper<Elf_Shdr>> ElfFile<ElfFileParamNames>::tryF
template<ElfFileParams>
-unsigned int ElfFile<ElfFileParamNames>::getSectionIndex(const SectionName & sectionName)
+unsigned int ElfFile<ElfFileParamNames>::getSectionIndex(const SectionName & sectionName) const
{
for (unsigned int i = 1; i < rdi(hdr()->e_shnum); ++i)
if (getSectionName(shdrs.at(i)) == sectionName) return i;
@@ -579,7 +625,7 @@ std::string & ElfFile<ElfFileParamNames>::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);
@@ -598,7 +644,7 @@ void ElfFile<ElfFileParamNames>::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));
}
@@ -617,7 +663,7 @@ void ElfFile<ElfFileParamNames>::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. */
@@ -1186,10 +1232,13 @@ static void setSubstr(std::string & s, unsigned int pos, const std::string & t)
template<ElfFileParams>
-std::string ElfFile<ElfFileParamNames>::getInterpreter()
+std::string ElfFile<ElfFileParamNames>::getInterpreter() const
{
auto shdr = findSectionHeader(".interp");
- return std::string((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<ElfFileParams>
@@ -1312,7 +1361,7 @@ void ElfFile<ElfFileParamNames>::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<const Elf_Dyn *>(newDynamic.c_str())[idx].d_tag) != DT_NULL; idx++);
debug("DT_NULL index is %d\n", idx);
/* Shift all entries down by one. */
@@ -1468,7 +1517,7 @@ void ElfFile<ElfFileParamNames>::modifyRPath(RPathOp op,
case rpPrint: {
printf("%s\n", rpath ? rpath : "");
return;
- };
+ }
case rpRemove: {
if (!rpath) {
debug("no RPATH to delete\n");
@@ -1481,7 +1530,7 @@ void ElfFile<ElfFileParamNames>::modifyRPath(RPathOp op,
if (!rpath) {
debug("no RPATH to shrink\n");
return;
- ;}
+ }
newRPath = shrinkRPath(rpath, neededLibs, allowedRpathPrefixes);
break;
}
@@ -1547,7 +1596,7 @@ void ElfFile<ElfFileParamNames>::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<const Elf_Dyn *>(newDynamic.c_str())[idx].d_tag) != DT_NULL; idx++) ;
debug("DT_NULL index is %d\n", idx);
/* Shift all entries down by one. */
@@ -1749,7 +1798,7 @@ void ElfFile<ElfFileParamNames>::addNeeded(const std::set<std::string> & 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<const Elf_Dyn *>(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. */
@@ -1772,13 +1821,13 @@ void ElfFile<ElfFileParamNames>::addNeeded(const std::set<std::string> & libs)
}
template<ElfFileParams>
-void ElfFile<ElfFileParamNames>::printNeededLibs() // const
+void ElfFile<ElfFileParamNames>::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) {
@@ -1811,7 +1860,7 @@ void ElfFile<ElfFileParamNames>::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<const Elf_Dyn *>(newDynamic.c_str())[idx].d_tag) != DT_NULL; idx++) ;
debug("DT_NULL index is %d\n", idx);
/* Shift all entries down by one. */
@@ -1844,7 +1893,7 @@ void ElfFile<ElfFileParamNames>::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<const Elf_Dyn *>(newDynamic.c_str())[idx].d_tag) != DT_NULL; idx++) ;
debug("DT_NULL index is %d\n", idx);
/* Shift all entries down by one. */
@@ -2073,7 +2122,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());
@@ -2083,7 +2132,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\
@@ -2118,7 +2167,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]);
diff --git a/src/patchelf.h b/src/patchelf.h
index c3096ff..677462d 100644
--- a/src/patchelf.h
+++ b/src/patchelf.h
@@ -1,3 +1,13 @@
+#include <map>
+#include <memory>
+#include <optional>
+#include <set>
+#include <stdexcept>
+#include <string>
+#include <vector>
+
+#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
@@ -30,14 +40,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<SectionName> sectionsByOldIndex;
public:
explicit ElfFile(FileContents fileContents);
- bool isChanged()
+ [[nodiscard]] bool isChanged() const noexcept
{
return changed;
}
@@ -46,8 +56,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;
@@ -58,39 +68,35 @@ private:
}
};
- friend struct CompPhdr;
-
void sortPhdrs();
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);
}
};
- 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);
+ const Elf_Shdr & findSectionHeader(const SectionName & sectionName) const;
- std::optional<std::reference_wrapper<Elf_Shdr>> tryFindSectionHeader(const SectionName & sectionName);
+ [[nodiscard]] std::optional<std::reference_wrapper<const Elf_Shdr>> tryFindSectionHeader(const SectionName & sectionName) const;
- 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);
@@ -107,7 +113,7 @@ public:
void rewriteSections(bool force = false);
- std::string getInterpreter();
+ [[nodiscard]] std::string getInterpreter() const;
typedef enum { printOsAbi, replaceOsAbi } osAbiMode;
@@ -131,7 +137,7 @@ public:
void replaceNeeded(const std::map<std::string, std::string> & libs);
- void printNeededLibs() /* should be const */;
+ void printNeededLibs() const;
void noDefaultLib();
@@ -149,21 +155,24 @@ private:
specified by the ELF header) to this platform's integer
representation. */
template<class I>
- I rdi(I i) const;
+ constexpr I rdi(I i) const noexcept;
/* Convert back to the ELF representation. */
- template<class I>
- I wri(I & t, unsigned long long i) const
+ template<class I, class U>
+ constexpr inline I wri(I & t, U i) const
{
- t = rdi((I) i);
- return i;
+ I val = static_cast<I>(i);
+ if (static_cast<U>(val) != i)
+ throw std::runtime_error { "value truncation" };
+ t = rdi(val);
+ return val;
}
- Elf_Ehdr *hdr() {
- return (Elf_Ehdr *)fileContents->data();
+ [[nodiscard]] Elf_Ehdr *hdr() noexcept {
+ return reinterpret_cast<Elf_Ehdr *>(fileContents->data());
}
- const Elf_Ehdr *hdr() const {
- return (const Elf_Ehdr *)fileContents->data();
+ [[nodiscard]] const Elf_Ehdr *hdr() const noexcept {
+ return reinterpret_cast<const Elf_Ehdr *>(fileContents->data());
}
};