Skip to content

Commit e37f892

Browse files
bors[bot]cgzones
andauthored
Merge #464
464: Modernizations and strictness improvements r=Mic92 a=cgzones Co-authored-by: Christian Göttsche <[email protected]>
2 parents 8d3188d + ff7a5be commit e37f892

File tree

3 files changed

+131
-73
lines changed

3 files changed

+131
-73
lines changed

src/Makefile.am

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
AM_CXXFLAGS = -Wall -std=c++17 -D_FILE_OFFSET_BITS=64
1+
AM_CXXFLAGS = -Wall -Wextra -Wcast-qual -std=c++17 -D_FILE_OFFSET_BITS=64
22

33
if WITH_ASAN
44
AM_CXXFLAGS += -fsanitize=address -fsanitize-address-use-after-scope

src/patchelf.cc

+94-45
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include <sstream>
2525
#include <stdexcept>
2626
#include <string>
27+
#include <string_view>
2728
#include <unordered_map>
2829
#include <vector>
2930
#include <optional>
@@ -69,14 +70,18 @@ static int forcedPageSize = -1;
6970
#define EM_LOONGARCH 258
7071
#endif
7172

72-
73-
static std::vector<std::string> splitColonDelimitedString(const char * s)
73+
[[nodiscard]] static std::vector<std::string> splitColonDelimitedString(std::string_view s)
7474
{
75-
std::string item;
7675
std::vector<std::string> parts;
77-
std::stringstream ss(s);
78-
while (std::getline(ss, item, ':'))
79-
parts.push_back(item);
76+
77+
size_t pos;
78+
while ((pos = s.find(':')) != std::string_view::npos) {
79+
parts.emplace_back(s.substr(0, pos));
80+
s = s.substr(pos + 1);
81+
}
82+
83+
if (!s.empty())
84+
parts.emplace_back(s);
8085

8186
return parts;
8287
}
@@ -104,7 +109,7 @@ static std::string downcase(std::string s)
104109
why... */
105110
template<ElfFileParams>
106111
template<class I>
107-
I ElfFile<ElfFileParamNames>::rdi(I i) const
112+
constexpr I ElfFile<ElfFileParamNames>::rdi(I i) const noexcept
108113
{
109114
I r = 0;
110115
if (littleEndian) {
@@ -131,7 +136,7 @@ static void debug(const char * format, ...)
131136
}
132137

133138

134-
void fmt2(std::ostringstream & out)
139+
static void fmt2([[maybe_unused]] std::ostringstream & out)
135140
{
136141
}
137142

@@ -162,7 +167,7 @@ struct SysError : std::runtime_error
162167
{ }
163168
};
164169

165-
__attribute__((noreturn)) static void error(const std::string & msg)
170+
[[noreturn]] static void error(const std::string & msg)
166171
{
167172
if (errno)
168173
throw SysError(msg);
@@ -191,11 +196,11 @@ static FileContents readFile(const std::string & fileName,
191196
while ((portion = read(fd, contents->data() + bytesRead, size - bytesRead)) > 0)
192197
bytesRead += portion;
193198

199+
close(fd);
200+
194201
if (bytesRead != size)
195202
throw SysError(fmt("reading '", fileName, "'"));
196203

197-
close(fd);
198-
199204
return contents;
200205
}
201206

@@ -207,10 +212,10 @@ struct ElfType
207212
};
208213

209214

210-
ElfType getElfType(const FileContents & fileContents)
215+
[[nodiscard]] static ElfType getElfType(const FileContents & fileContents)
211216
{
212217
/* Check the ELF header for basic validity. */
213-
if (fileContents->size() < static_cast<off_t>(sizeof(Elf32_Ehdr)))
218+
if (fileContents->size() < sizeof(Elf32_Ehdr))
214219
error("missing ELF header");
215220

216221
auto contents = fileContents->data();
@@ -231,14 +236,32 @@ ElfType getElfType(const FileContents & fileContents)
231236
}
232237

233238

234-
static void checkPointer(const FileContents & contents, void * p, unsigned int size)
239+
static void checkPointer(const FileContents & contents, const void * p, size_t size)
235240
{
236-
auto q = static_cast<unsigned char *>(p);
237-
if (!(q >= contents->data() && q + size <= contents->data() + contents->size()))
241+
if (p < contents->data() || size > contents->size() || p > contents->data() + contents->size() - size)
238242
error("data region extends past file end");
239243
}
240244

241245

246+
static void checkOffset(const FileContents & contents, size_t offset, size_t size)
247+
{
248+
size_t end;
249+
250+
if (offset > contents->size()
251+
|| size > contents->size()
252+
|| __builtin_add_overflow(offset, size, &end)
253+
|| end > contents->size())
254+
error("data offset extends past file end");
255+
}
256+
257+
258+
static std::string extractString(const FileContents & contents, size_t offset, size_t size)
259+
{
260+
checkOffset(contents, offset, size);
261+
return { reinterpret_cast<const char *>(contents->data()) + offset, size };
262+
}
263+
264+
242265
template<ElfFileParams>
243266
ElfFile<ElfFileParamNames>::ElfFile(FileContents fContents)
244267
: fileContents(fContents)
@@ -255,14 +278,34 @@ ElfFile<ElfFileParamNames>::ElfFile(FileContents fContents)
255278
if (rdi(hdr()->e_type) != ET_EXEC && rdi(hdr()->e_type) != ET_DYN)
256279
error("wrong ELF type");
257280

258-
if (rdi(hdr()->e_phoff) + rdi(hdr()->e_phnum) * rdi(hdr()->e_phentsize) > fileContents->size())
259-
error("program header table out of bounds");
281+
{
282+
auto ph_offset = rdi(hdr()->e_phoff);
283+
auto ph_num = rdi(hdr()->e_phnum);
284+
auto ph_entsize = rdi(hdr()->e_phentsize);
285+
size_t ph_size, ph_end;
286+
287+
if (__builtin_mul_overflow(ph_num, ph_entsize, &ph_size)
288+
|| __builtin_add_overflow(ph_offset, ph_size, &ph_end)
289+
|| ph_end > fileContents->size()) {
290+
error("program header table out of bounds");
291+
}
292+
}
260293

261294
if (rdi(hdr()->e_shnum) == 0)
262295
error("no section headers. The input file is probably a statically linked, self-decompressing binary");
263296

264-
if (rdi(hdr()->e_shoff) + rdi(hdr()->e_shnum) * rdi(hdr()->e_shentsize) > fileContents->size())
265-
error("section header table out of bounds");
297+
{
298+
auto sh_offset = rdi(hdr()->e_shoff);
299+
auto sh_num = rdi(hdr()->e_shnum);
300+
auto sh_entsize = rdi(hdr()->e_shentsize);
301+
size_t sh_size, sh_end;
302+
303+
if (__builtin_mul_overflow(sh_num, sh_entsize, &sh_size)
304+
|| __builtin_add_overflow(sh_offset, sh_size, &sh_end)
305+
|| sh_end > fileContents->size()) {
306+
error("section header table out of bounds");
307+
}
308+
}
266309

267310
if (rdi(hdr()->e_phentsize) != sizeof(Elf_Phdr))
268311
error("program headers have wrong size");
@@ -286,12 +329,15 @@ ElfFile<ElfFileParamNames>::ElfFile(FileContents fContents)
286329
/* Get the section header string table section (".shstrtab"). Its
287330
index in the section header table is given by e_shstrndx field
288331
of the ELF header. */
289-
unsigned int shstrtabIndex = rdi(hdr()->e_shstrndx);
332+
auto shstrtabIndex = rdi(hdr()->e_shstrndx);
290333
if (shstrtabIndex >= shdrs.size())
291334
error("string table index out of bounds");
292335

293-
unsigned int shstrtabSize = rdi(shdrs[shstrtabIndex].sh_size);
294-
char * shstrtab = (char * ) fileContents->data() + rdi(shdrs[shstrtabIndex].sh_offset);
336+
auto shstrtabSize = rdi(shdrs[shstrtabIndex].sh_size);
337+
size_t shstrtabptr;
338+
if (__builtin_add_overflow(reinterpret_cast<size_t>(fileContents->data()), rdi(shdrs[shstrtabIndex].sh_offset), &shstrtabptr))
339+
error("string table overflow");
340+
const char *shstrtab = reinterpret_cast<const char *>(shstrtabptr);
295341
checkPointer(fileContents, shstrtab, shstrtabSize);
296342

297343
if (shstrtabSize == 0)
@@ -309,7 +355,7 @@ ElfFile<ElfFileParamNames>::ElfFile(FileContents fContents)
309355

310356

311357
template<ElfFileParams>
312-
unsigned int ElfFile<ElfFileParamNames>::getPageSize() const
358+
unsigned int ElfFile<ElfFileParamNames>::getPageSize() const noexcept
313359
{
314360
if (forcedPageSize > 0)
315361
return forcedPageSize;
@@ -531,7 +577,7 @@ std::string ElfFile<ElfFileParamNames>::getSectionName(const Elf_Shdr & shdr) co
531577

532578

533579
template<ElfFileParams>
534-
Elf_Shdr & ElfFile<ElfFileParamNames>::findSectionHeader(const SectionName & sectionName)
580+
const Elf_Shdr & ElfFile<ElfFileParamNames>::findSectionHeader(const SectionName & sectionName) const
535581
{
536582
auto shdr = tryFindSectionHeader(sectionName);
537583
if (!shdr) {
@@ -545,7 +591,7 @@ Elf_Shdr & ElfFile<ElfFileParamNames>::findSectionHeader(const SectionName & sec
545591

546592

547593
template<ElfFileParams>
548-
std::optional<std::reference_wrapper<Elf_Shdr>> ElfFile<ElfFileParamNames>::tryFindSectionHeader(const SectionName & sectionName)
594+
std::optional<std::reference_wrapper<const Elf_Shdr>> ElfFile<ElfFileParamNames>::tryFindSectionHeader(const SectionName & sectionName) const
549595
{
550596
auto i = getSectionIndex(sectionName);
551597
if (i)
@@ -555,7 +601,7 @@ std::optional<std::reference_wrapper<Elf_Shdr>> ElfFile<ElfFileParamNames>::tryF
555601

556602

557603
template<ElfFileParams>
558-
unsigned int ElfFile<ElfFileParamNames>::getSectionIndex(const SectionName & sectionName)
604+
unsigned int ElfFile<ElfFileParamNames>::getSectionIndex(const SectionName & sectionName) const
559605
{
560606
for (unsigned int i = 1; i < rdi(hdr()->e_shnum); ++i)
561607
if (getSectionName(shdrs.at(i)) == sectionName) return i;
@@ -579,7 +625,7 @@ std::string & ElfFile<ElfFileParamNames>::replaceSection(const SectionName & sec
579625
s = std::string(i->second);
580626
} else {
581627
auto shdr = findSectionHeader(sectionName);
582-
s = std::string((char *) fileContents->data() + rdi(shdr.sh_offset), rdi(shdr.sh_size));
628+
s = extractString(fileContents, rdi(shdr.sh_offset), rdi(shdr.sh_size));
583629
}
584630

585631
s.resize(size);
@@ -598,7 +644,7 @@ void ElfFile<ElfFileParamNames>::writeReplacedSections(Elf_Off & curOff,
598644
clobbering previously written new section contents. */
599645
for (auto & i : replacedSections) {
600646
const std::string & sectionName = i.first;
601-
Elf_Shdr & shdr = findSectionHeader(sectionName);
647+
const Elf_Shdr & shdr = findSectionHeader(sectionName);
602648
if (rdi(shdr.sh_type) != SHT_NOBITS)
603649
memset(fileContents->data() + rdi(shdr.sh_offset), 'X', rdi(shdr.sh_size));
604650
}
@@ -617,7 +663,7 @@ void ElfFile<ElfFileParamNames>::writeReplacedSections(Elf_Off & curOff,
617663
debug("rewriting section '%s' from offset 0x%x (size %d) to offset 0x%x (size %d)\n",
618664
sectionName.c_str(), rdi(shdr.sh_offset), rdi(shdr.sh_size), curOff, i->second.size());
619665

620-
memcpy(fileContents->data() + curOff, (unsigned char *) i->second.c_str(),
666+
memcpy(fileContents->data() + curOff, i->second.c_str(),
621667
i->second.size());
622668

623669
/* Update the section header for this section. */
@@ -1186,10 +1232,13 @@ static void setSubstr(std::string & s, unsigned int pos, const std::string & t)
11861232

11871233

11881234
template<ElfFileParams>
1189-
std::string ElfFile<ElfFileParamNames>::getInterpreter()
1235+
std::string ElfFile<ElfFileParamNames>::getInterpreter() const
11901236
{
11911237
auto shdr = findSectionHeader(".interp");
1192-
return std::string((char *) fileContents->data() + rdi(shdr.sh_offset), rdi(shdr.sh_size) - 1);
1238+
auto size = rdi(shdr.sh_size);
1239+
if (size > 0)
1240+
size--;
1241+
return extractString(fileContents, rdi(shdr.sh_offset), size);
11931242
}
11941243

11951244
template<ElfFileParams>
@@ -1312,7 +1361,7 @@ void ElfFile<ElfFileParamNames>::modifySoname(sonameMode op, const std::string &
13121361
std::string & newDynamic = replaceSection(".dynamic", rdi(shdrDynamic.sh_size) + sizeof(Elf_Dyn));
13131362

13141363
unsigned int idx = 0;
1315-
for (; rdi(((Elf_Dyn *) newDynamic.c_str())[idx].d_tag) != DT_NULL; idx++);
1364+
for (; rdi(reinterpret_cast<const Elf_Dyn *>(newDynamic.c_str())[idx].d_tag) != DT_NULL; idx++);
13161365
debug("DT_NULL index is %d\n", idx);
13171366

13181367
/* Shift all entries down by one. */
@@ -1468,7 +1517,7 @@ void ElfFile<ElfFileParamNames>::modifyRPath(RPathOp op,
14681517
case rpPrint: {
14691518
printf("%s\n", rpath ? rpath : "");
14701519
return;
1471-
};
1520+
}
14721521
case rpRemove: {
14731522
if (!rpath) {
14741523
debug("no RPATH to delete\n");
@@ -1481,7 +1530,7 @@ void ElfFile<ElfFileParamNames>::modifyRPath(RPathOp op,
14811530
if (!rpath) {
14821531
debug("no RPATH to shrink\n");
14831532
return;
1484-
;}
1533+
}
14851534
newRPath = shrinkRPath(rpath, neededLibs, allowedRpathPrefixes);
14861535
break;
14871536
}
@@ -1547,7 +1596,7 @@ void ElfFile<ElfFileParamNames>::modifyRPath(RPathOp op,
15471596
rdi(shdrDynamic.sh_size) + sizeof(Elf_Dyn));
15481597

15491598
unsigned int idx = 0;
1550-
for ( ; rdi(((Elf_Dyn *) newDynamic.c_str())[idx].d_tag) != DT_NULL; idx++) ;
1599+
for ( ; rdi(reinterpret_cast<const Elf_Dyn *>(newDynamic.c_str())[idx].d_tag) != DT_NULL; idx++) ;
15511600
debug("DT_NULL index is %d\n", idx);
15521601

15531602
/* Shift all entries down by one. */
@@ -1749,7 +1798,7 @@ void ElfFile<ElfFileParamNames>::addNeeded(const std::set<std::string> & libs)
17491798
rdi(shdrDynamic.sh_size) + sizeof(Elf_Dyn) * libs.size());
17501799

17511800
unsigned int idx = 0;
1752-
for ( ; rdi(((Elf_Dyn *) newDynamic.c_str())[idx].d_tag) != DT_NULL; idx++) ;
1801+
for ( ; rdi(reinterpret_cast<const Elf_Dyn *>(newDynamic.c_str())[idx].d_tag) != DT_NULL; idx++) ;
17531802
debug("DT_NULL index is %d\n", idx);
17541803

17551804
/* Shift all entries down by the number of new entries. */
@@ -1772,13 +1821,13 @@ void ElfFile<ElfFileParamNames>::addNeeded(const std::set<std::string> & libs)
17721821
}
17731822

17741823
template<ElfFileParams>
1775-
void ElfFile<ElfFileParamNames>::printNeededLibs() // const
1824+
void ElfFile<ElfFileParamNames>::printNeededLibs() const
17761825
{
17771826
const auto shdrDynamic = findSectionHeader(".dynamic");
17781827
const auto shdrDynStr = findSectionHeader(".dynstr");
1779-
const char *strTab = (char *)fileContents->data() + rdi(shdrDynStr.sh_offset);
1828+
const char *strTab = (const char *)fileContents->data() + rdi(shdrDynStr.sh_offset);
17801829

1781-
const Elf_Dyn *dyn = (Elf_Dyn *) (fileContents->data() + rdi(shdrDynamic.sh_offset));
1830+
const Elf_Dyn *dyn = (const Elf_Dyn *) (fileContents->data() + rdi(shdrDynamic.sh_offset));
17821831

17831832
for (; rdi(dyn->d_tag) != DT_NULL; dyn++) {
17841833
if (rdi(dyn->d_tag) == DT_NEEDED) {
@@ -1811,7 +1860,7 @@ void ElfFile<ElfFileParamNames>::noDefaultLib()
18111860
rdi(shdrDynamic.sh_size) + sizeof(Elf_Dyn));
18121861

18131862
unsigned int idx = 0;
1814-
for ( ; rdi(((Elf_Dyn *) newDynamic.c_str())[idx].d_tag) != DT_NULL; idx++) ;
1863+
for ( ; rdi(reinterpret_cast<const Elf_Dyn *>(newDynamic.c_str())[idx].d_tag) != DT_NULL; idx++) ;
18151864
debug("DT_NULL index is %d\n", idx);
18161865

18171866
/* Shift all entries down by one. */
@@ -1844,7 +1893,7 @@ void ElfFile<ElfFileParamNames>::addDebugTag()
18441893
rdi(shdrDynamic.sh_size) + sizeof(Elf_Dyn));
18451894

18461895
unsigned int idx = 0;
1847-
for ( ; rdi(((Elf_Dyn *) newDynamic.c_str())[idx].d_tag) != DT_NULL; idx++) ;
1896+
for ( ; rdi(reinterpret_cast<const Elf_Dyn *>(newDynamic.c_str())[idx].d_tag) != DT_NULL; idx++) ;
18481897
debug("DT_NULL index is %d\n", idx);
18491898

18501899
/* Shift all entries down by one. */
@@ -2073,7 +2122,7 @@ static void patchElf()
20732122
}
20742123
}
20752124

2076-
std::string resolveArgument(const char *arg) {
2125+
[[nodiscard]] static std::string resolveArgument(const char *arg) {
20772126
if (strlen(arg) > 0 && arg[0] == '@') {
20782127
FileContents cnts = readFile(arg + 1);
20792128
return std::string((char *)cnts->data(), cnts->size());
@@ -2083,7 +2132,7 @@ std::string resolveArgument(const char *arg) {
20832132
}
20842133

20852134

2086-
void showHelp(const std::string & progName)
2135+
static void showHelp(const std::string & progName)
20872136
{
20882137
fprintf(stderr, "syntax: %s\n\
20892138
[--set-interpreter FILENAME]\n\
@@ -2118,7 +2167,7 @@ void showHelp(const std::string & progName)
21182167
}
21192168

21202169

2121-
int mainWrapped(int argc, char * * argv)
2170+
static int mainWrapped(int argc, char * * argv)
21222171
{
21232172
if (argc <= 1) {
21242173
showHelp(argv[0]);

0 commit comments

Comments
 (0)