@@ -95,12 +95,16 @@ void ParseMachOHeaderImpl(string_view macho_data, RangeSink* overhead_sink,
9595 for (uint32_t i = 0 ; i < ncmds; i++) {
9696 auto command = GetStructPointer<load_command>(header_data);
9797
98- // We test for this because otherwise a large ncmds can make bloaty hang for
99- // a while, even on a small file. Hopefully there are no real cases where a
100- // zero-size loadcmd exists.
98+ // Validate load command size to prevent hangs or buffer overruns
10199 if (command->cmdsize == 0 ) {
102100 THROW (" Mach-O load command had zero size." );
103101 }
102+ if (command->cmdsize < sizeof (load_command)) {
103+ THROW (" Mach-O load command size smaller than minimum." );
104+ }
105+ if (command->cmdsize > header_data.size ()) {
106+ THROW (" Mach-O load command size exceeds remaining header data." );
107+ }
104108
105109 LoadCommand data;
106110 data.is64bit = Is64Bit<Struct>();
@@ -163,6 +167,12 @@ void ParseFatHeader(string_view fat_file, RangeSink* overhead_sink,
163167 fat_file.substr (0 , sizeof (fat_header)));
164168 assert (ByteSwap (header->magic ) == FAT_MAGIC);
165169 uint32_t nfat_arch = ByteSwap (header->nfat_arch );
170+
171+ // Validate that nfat_arch count doesn't exceed header size
172+ if (nfat_arch > header_data.size () / sizeof (fat_arch)) {
173+ THROW (" invalid nfat_arch count in universal binary header" );
174+ }
175+
166176 for (uint32_t i = 0 ; i < nfat_arch; i++) {
167177 auto arch = GetStructPointerAndAdvance<fat_arch>(&header_data);
168178 string_view macho_data = StrictSubstr (
@@ -203,6 +213,12 @@ void AddSegmentAsFallback(string_view command_data, string_view file_data,
203213 string_view segname = ArrayToStr (segment->segname , 16 );
204214
205215 uint32_t nsects = segment->nsects ;
216+
217+ // Validate that nsects count doesn't exceed command data size
218+ if (nsects > command_data.size () / sizeof (Section)) {
219+ THROW (" invalid section count in segment" );
220+ }
221+
206222 for (uint32_t j = 0 ; j < nsects; j++) {
207223 auto section = GetStructPointerAndAdvance<Section>(&command_data);
208224
@@ -257,6 +273,12 @@ void ParseSegment(LoadCommand cmd, RangeSink* sink) {
257273 }
258274 } else if (sink->data_source () == DataSource::kSections ) {
259275 uint32_t nsects = segment->nsects ;
276+
277+ // Validate that nsects count doesn't exceed command data size
278+ if (nsects > cmd.command_data .size () / sizeof (Section)) {
279+ THROW (" invalid section count in segment" );
280+ }
281+
260282 for (uint32_t j = 0 ; j < nsects; j++) {
261283 auto section = GetStructPointerAndAdvance<Section>(&cmd.command_data );
262284
@@ -425,12 +447,17 @@ void ParseSymbolsFromSymbolTable(const LoadCommand& cmd, SymbolTable* table,
425447 RangeSink* sink) {
426448 auto symtab_cmd = GetStructPointer<symtab_command>(cmd.command_data );
427449
450+ // Validate that nsyms count doesn't cause overflow or exceed file size
451+ uint32_t nsyms = symtab_cmd->nsyms ;
452+ if (nsyms > cmd.file_data .size () / sizeof (NList)) {
453+ THROW (" invalid symbol count in symbol table" );
454+ }
455+
428456 string_view symtab = StrictSubstr (cmd.file_data , symtab_cmd->symoff ,
429- symtab_cmd-> nsyms * sizeof (NList));
457+ nsyms * sizeof (NList));
430458 string_view strtab =
431459 StrictSubstr (cmd.file_data , symtab_cmd->stroff , symtab_cmd->strsize );
432460
433- uint32_t nsyms = symtab_cmd->nsyms ;
434461 for (uint32_t i = 0 ; i < nsyms; i++) {
435462 auto sym = GetStructPointerAndAdvance<NList>(&symtab);
436463 string_view sym_range (reinterpret_cast <const char *>(sym), sizeof (NList));
@@ -507,6 +534,12 @@ void ReadDebugSectionsFromSegment(LoadCommand cmd, dwarf::File *dwarf,
507534 }
508535
509536 uint32_t nsects = segment->nsects ;
537+
538+ // Validate that nsects count doesn't exceed command data size
539+ if (nsects > cmd.command_data .size () / sizeof (Section)) {
540+ THROW (" invalid section count in segment" );
541+ }
542+
510543 for (uint32_t j = 0 ; j < nsects; j++) {
511544 auto section = GetStructPointerAndAdvance<Section>(&cmd.command_data );
512545 string_view sectname = ArrayToStr (section->sectname , 16 );
0 commit comments