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... */
105110template <ElfFileParams>
106111template <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+
242265template <ElfFileParams>
243266ElfFile<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
311357template <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
533579template <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
547593template <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
557603template <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
11881234template <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
11951244template <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
17741823template <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