24
24
#include < sstream>
25
25
#include < stdexcept>
26
26
#include < string>
27
+ #include < string_view>
27
28
#include < unordered_map>
28
29
#include < vector>
29
30
#include < optional>
@@ -69,14 +70,18 @@ static int forcedPageSize = -1;
69
70
#define EM_LOONGARCH 258
70
71
#endif
71
72
72
-
73
- static std::vector<std::string> splitColonDelimitedString (const char * s)
73
+ [[nodiscard]] static std::vector<std::string> splitColonDelimitedString (std::string_view s)
74
74
{
75
- std::string item;
76
75
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);
80
85
81
86
return parts;
82
87
}
@@ -104,7 +109,7 @@ static std::string downcase(std::string s)
104
109
why... */
105
110
template <ElfFileParams>
106
111
template <class I >
107
- I ElfFile<ElfFileParamNames>::rdi(I i) const
112
+ constexpr I ElfFile<ElfFileParamNames>::rdi(I i) const noexcept
108
113
{
109
114
I r = 0 ;
110
115
if (littleEndian) {
@@ -131,7 +136,7 @@ static void debug(const char * format, ...)
131
136
}
132
137
133
138
134
- void fmt2 (std::ostringstream & out)
139
+ static void fmt2 ([[maybe_unused]] std::ostringstream & out)
135
140
{
136
141
}
137
142
@@ -162,7 +167,7 @@ struct SysError : std::runtime_error
162
167
{ }
163
168
};
164
169
165
- __attribute__ (( noreturn)) static void error(const std::string & msg)
170
+ [[ noreturn]] static void error (const std::string & msg)
166
171
{
167
172
if (errno)
168
173
throw SysError (msg);
@@ -191,11 +196,11 @@ static FileContents readFile(const std::string & fileName,
191
196
while ((portion = read (fd, contents->data () + bytesRead, size - bytesRead)) > 0 )
192
197
bytesRead += portion;
193
198
199
+ close (fd);
200
+
194
201
if (bytesRead != size)
195
202
throw SysError (fmt (" reading '" , fileName, " '" ));
196
203
197
- close (fd);
198
-
199
204
return contents;
200
205
}
201
206
@@ -207,10 +212,10 @@ struct ElfType
207
212
};
208
213
209
214
210
- ElfType getElfType (const FileContents & fileContents)
215
+ [[nodiscard]] static ElfType getElfType (const FileContents & fileContents)
211
216
{
212
217
/* 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))
214
219
error (" missing ELF header" );
215
220
216
221
auto contents = fileContents->data ();
@@ -231,14 +236,32 @@ ElfType getElfType(const FileContents & fileContents)
231
236
}
232
237
233
238
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)
235
240
{
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)
238
242
error (" data region extends past file end" );
239
243
}
240
244
241
245
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
+
242
265
template <ElfFileParams>
243
266
ElfFile<ElfFileParamNames>::ElfFile(FileContents fContents )
244
267
: fileContents(fContents )
@@ -255,14 +278,34 @@ ElfFile<ElfFileParamNames>::ElfFile(FileContents fContents)
255
278
if (rdi (hdr ()->e_type ) != ET_EXEC && rdi (hdr ()->e_type ) != ET_DYN)
256
279
error (" wrong ELF type" );
257
280
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
+ }
260
293
261
294
if (rdi (hdr ()->e_shnum ) == 0 )
262
295
error (" no section headers. The input file is probably a statically linked, self-decompressing binary" );
263
296
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
+ }
266
309
267
310
if (rdi (hdr ()->e_phentsize ) != sizeof (Elf_Phdr))
268
311
error (" program headers have wrong size" );
@@ -286,12 +329,15 @@ ElfFile<ElfFileParamNames>::ElfFile(FileContents fContents)
286
329
/* Get the section header string table section (".shstrtab"). Its
287
330
index in the section header table is given by e_shstrndx field
288
331
of the ELF header. */
289
- unsigned int shstrtabIndex = rdi (hdr ()->e_shstrndx );
332
+ auto shstrtabIndex = rdi (hdr ()->e_shstrndx );
290
333
if (shstrtabIndex >= shdrs.size ())
291
334
error (" string table index out of bounds" );
292
335
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);
295
341
checkPointer (fileContents, shstrtab, shstrtabSize);
296
342
297
343
if (shstrtabSize == 0 )
@@ -309,7 +355,7 @@ ElfFile<ElfFileParamNames>::ElfFile(FileContents fContents)
309
355
310
356
311
357
template <ElfFileParams>
312
- unsigned int ElfFile<ElfFileParamNames>::getPageSize() const
358
+ unsigned int ElfFile<ElfFileParamNames>::getPageSize() const noexcept
313
359
{
314
360
if (forcedPageSize > 0 )
315
361
return forcedPageSize;
@@ -531,7 +577,7 @@ std::string ElfFile<ElfFileParamNames>::getSectionName(const Elf_Shdr & shdr) co
531
577
532
578
533
579
template <ElfFileParams>
534
- Elf_Shdr & ElfFile<ElfFileParamNames>::findSectionHeader(const SectionName & sectionName)
580
+ const Elf_Shdr & ElfFile<ElfFileParamNames>::findSectionHeader(const SectionName & sectionName) const
535
581
{
536
582
auto shdr = tryFindSectionHeader (sectionName);
537
583
if (!shdr) {
@@ -545,7 +591,7 @@ Elf_Shdr & ElfFile<ElfFileParamNames>::findSectionHeader(const SectionName & sec
545
591
546
592
547
593
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
549
595
{
550
596
auto i = getSectionIndex (sectionName);
551
597
if (i)
@@ -555,7 +601,7 @@ std::optional<std::reference_wrapper<Elf_Shdr>> ElfFile<ElfFileParamNames>::tryF
555
601
556
602
557
603
template <ElfFileParams>
558
- unsigned int ElfFile<ElfFileParamNames>::getSectionIndex(const SectionName & sectionName)
604
+ unsigned int ElfFile<ElfFileParamNames>::getSectionIndex(const SectionName & sectionName) const
559
605
{
560
606
for (unsigned int i = 1 ; i < rdi (hdr ()->e_shnum ); ++i)
561
607
if (getSectionName (shdrs.at (i)) == sectionName) return i;
@@ -579,7 +625,7 @@ std::string & ElfFile<ElfFileParamNames>::replaceSection(const SectionName & sec
579
625
s = std::string (i->second );
580
626
} else {
581
627
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 ));
583
629
}
584
630
585
631
s.resize (size);
@@ -598,7 +644,7 @@ void ElfFile<ElfFileParamNames>::writeReplacedSections(Elf_Off & curOff,
598
644
clobbering previously written new section contents. */
599
645
for (auto & i : replacedSections) {
600
646
const std::string & sectionName = i.first ;
601
- Elf_Shdr & shdr = findSectionHeader (sectionName);
647
+ const Elf_Shdr & shdr = findSectionHeader (sectionName);
602
648
if (rdi (shdr.sh_type ) != SHT_NOBITS)
603
649
memset (fileContents->data () + rdi (shdr.sh_offset ), ' X' , rdi (shdr.sh_size ));
604
650
}
@@ -617,7 +663,7 @@ void ElfFile<ElfFileParamNames>::writeReplacedSections(Elf_Off & curOff,
617
663
debug (" rewriting section '%s' from offset 0x%x (size %d) to offset 0x%x (size %d)\n " ,
618
664
sectionName.c_str (), rdi (shdr.sh_offset ), rdi (shdr.sh_size ), curOff, i->second .size ());
619
665
620
- memcpy (fileContents->data () + curOff, ( unsigned char *) i->second .c_str (),
666
+ memcpy (fileContents->data () + curOff, i->second .c_str (),
621
667
i->second .size ());
622
668
623
669
/* Update the section header for this section. */
@@ -1186,10 +1232,13 @@ static void setSubstr(std::string & s, unsigned int pos, const std::string & t)
1186
1232
1187
1233
1188
1234
template <ElfFileParams>
1189
- std::string ElfFile<ElfFileParamNames>::getInterpreter()
1235
+ std::string ElfFile<ElfFileParamNames>::getInterpreter() const
1190
1236
{
1191
1237
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);
1193
1242
}
1194
1243
1195
1244
template <ElfFileParams>
@@ -1312,7 +1361,7 @@ void ElfFile<ElfFileParamNames>::modifySoname(sonameMode op, const std::string &
1312
1361
std::string & newDynamic = replaceSection (" .dynamic" , rdi (shdrDynamic.sh_size ) + sizeof (Elf_Dyn));
1313
1362
1314
1363
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++);
1316
1365
debug (" DT_NULL index is %d\n " , idx);
1317
1366
1318
1367
/* Shift all entries down by one. */
@@ -1468,7 +1517,7 @@ void ElfFile<ElfFileParamNames>::modifyRPath(RPathOp op,
1468
1517
case rpPrint: {
1469
1518
printf (" %s\n " , rpath ? rpath : " " );
1470
1519
return ;
1471
- };
1520
+ }
1472
1521
case rpRemove: {
1473
1522
if (!rpath) {
1474
1523
debug (" no RPATH to delete\n " );
@@ -1481,7 +1530,7 @@ void ElfFile<ElfFileParamNames>::modifyRPath(RPathOp op,
1481
1530
if (!rpath) {
1482
1531
debug (" no RPATH to shrink\n " );
1483
1532
return ;
1484
- ; }
1533
+ }
1485
1534
newRPath = shrinkRPath (rpath, neededLibs, allowedRpathPrefixes);
1486
1535
break ;
1487
1536
}
@@ -1547,7 +1596,7 @@ void ElfFile<ElfFileParamNames>::modifyRPath(RPathOp op,
1547
1596
rdi (shdrDynamic.sh_size ) + sizeof (Elf_Dyn));
1548
1597
1549
1598
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++) ;
1551
1600
debug (" DT_NULL index is %d\n " , idx);
1552
1601
1553
1602
/* Shift all entries down by one. */
@@ -1749,7 +1798,7 @@ void ElfFile<ElfFileParamNames>::addNeeded(const std::set<std::string> & libs)
1749
1798
rdi (shdrDynamic.sh_size ) + sizeof (Elf_Dyn) * libs.size ());
1750
1799
1751
1800
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++) ;
1753
1802
debug (" DT_NULL index is %d\n " , idx);
1754
1803
1755
1804
/* Shift all entries down by the number of new entries. */
@@ -1772,13 +1821,13 @@ void ElfFile<ElfFileParamNames>::addNeeded(const std::set<std::string> & libs)
1772
1821
}
1773
1822
1774
1823
template <ElfFileParams>
1775
- void ElfFile<ElfFileParamNames>::printNeededLibs() // const
1824
+ void ElfFile<ElfFileParamNames>::printNeededLibs() const
1776
1825
{
1777
1826
const auto shdrDynamic = findSectionHeader (" .dynamic" );
1778
1827
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 );
1780
1829
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 ));
1782
1831
1783
1832
for (; rdi (dyn->d_tag ) != DT_NULL; dyn++) {
1784
1833
if (rdi (dyn->d_tag ) == DT_NEEDED) {
@@ -1811,7 +1860,7 @@ void ElfFile<ElfFileParamNames>::noDefaultLib()
1811
1860
rdi (shdrDynamic.sh_size ) + sizeof (Elf_Dyn));
1812
1861
1813
1862
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++) ;
1815
1864
debug (" DT_NULL index is %d\n " , idx);
1816
1865
1817
1866
/* Shift all entries down by one. */
@@ -1844,7 +1893,7 @@ void ElfFile<ElfFileParamNames>::addDebugTag()
1844
1893
rdi (shdrDynamic.sh_size ) + sizeof (Elf_Dyn));
1845
1894
1846
1895
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++) ;
1848
1897
debug (" DT_NULL index is %d\n " , idx);
1849
1898
1850
1899
/* Shift all entries down by one. */
@@ -2073,7 +2122,7 @@ static void patchElf()
2073
2122
}
2074
2123
}
2075
2124
2076
- std::string resolveArgument (const char *arg) {
2125
+ [[nodiscard]] static std::string resolveArgument (const char *arg) {
2077
2126
if (strlen (arg) > 0 && arg[0 ] == ' @' ) {
2078
2127
FileContents cnts = readFile (arg + 1 );
2079
2128
return std::string ((char *)cnts->data (), cnts->size ());
@@ -2083,7 +2132,7 @@ std::string resolveArgument(const char *arg) {
2083
2132
}
2084
2133
2085
2134
2086
- void showHelp (const std::string & progName)
2135
+ static void showHelp (const std::string & progName)
2087
2136
{
2088
2137
fprintf (stderr, " syntax: %s\n \
2089
2138
[--set-interpreter FILENAME]\n \
@@ -2118,7 +2167,7 @@ void showHelp(const std::string & progName)
2118
2167
}
2119
2168
2120
2169
2121
- int mainWrapped (int argc, char * * argv)
2170
+ static int mainWrapped (int argc, char * * argv)
2122
2171
{
2123
2172
if (argc <= 1 ) {
2124
2173
showHelp (argv[0 ]);
0 commit comments