+ if ( linkeditSegCmd == NULL )
+ throw "malformed mach-o image: missing __LINKEDIT segment";
+ if ( !inCache && (startOfFileSegCmd == NULL) )
+ throw "malformed mach-o image: missing __TEXT segment that maps start of file";
+ // <rdar://problem/13145644> verify every segment does not overlap another segment
+ if ( context.strictMachORequired ) {
+ uintptr_t lastFileStart = 0;
+ uintptr_t linkeditFileStart = 0;
+ const struct load_command* cmd1 = startCmds;
+ for (uint32_t i = 0; i < cmd_count; ++i) {
+ if ( cmd1->cmd == LC_SEGMENT_COMMAND ) {
+ struct macho_segment_command* segCmd1 = (struct macho_segment_command*)cmd1;
+ uintptr_t vmStart1 = segCmd1->vmaddr;
+ uintptr_t vmEnd1 = segCmd1->vmaddr + segCmd1->vmsize;
+ uintptr_t fileStart1 = segCmd1->fileoff;
+ uintptr_t fileEnd1 = segCmd1->fileoff + segCmd1->filesize;
+
+ if (fileStart1 > lastFileStart)
+ lastFileStart = fileStart1;
+
+ if ( strcmp(&segCmd1->segname[0], "__LINKEDIT") == 0 ) {
+ linkeditFileStart = fileStart1;
+ }
+
+ const struct load_command* cmd2 = startCmds;
+ for (uint32_t j = 0; j < cmd_count; ++j) {
+ if ( cmd2 == cmd1 )
+ continue;
+ if ( cmd2->cmd == LC_SEGMENT_COMMAND ) {
+ struct macho_segment_command* segCmd2 = (struct macho_segment_command*)cmd2;
+ uintptr_t vmStart2 = segCmd2->vmaddr;
+ uintptr_t vmEnd2 = segCmd2->vmaddr + segCmd2->vmsize;
+ uintptr_t fileStart2 = segCmd2->fileoff;
+ uintptr_t fileEnd2 = segCmd2->fileoff + segCmd2->filesize;
+ if ( ((vmStart2 <= vmStart1) && (vmEnd2 > vmStart1) && (vmEnd1 > vmStart1))
+ || ((vmStart2 >= vmStart1) && (vmStart2 < vmEnd1) && (vmEnd2 > vmStart2)) )
+ dyld::throwf("malformed mach-o image: segment %s vm overlaps segment %s", segCmd1->segname, segCmd2->segname);
+ if ( ((fileStart2 <= fileStart1) && (fileEnd2 > fileStart1) && (fileEnd1 > fileStart1))
+ || ((fileStart2 >= fileStart1) && (fileStart2 < fileEnd1) && (fileEnd2 > fileStart2)) )
+ dyld::throwf("malformed mach-o image: segment %s file content overlaps segment %s", segCmd1->segname, segCmd2->segname);
+ }
+ cmd2 = (const struct load_command*)(((char*)cmd2)+cmd2->cmdsize);
+ }
+ }
+ cmd1 = (const struct load_command*)(((char*)cmd1)+cmd1->cmdsize);
+ }
+
+ if (lastFileStart != linkeditFileStart)
+ dyld::throwf("malformed mach-o image: __LINKEDIT must be last segment");
+ }
+
+ // validate linkedit content
+ if ( (dyldInfoCmd == NULL) && (symTabCmd == NULL) )
+ throw "malformed mach-o image: missing LC_SYMTAB or LC_DYLD_INFO";
+ if ( dynSymbTabCmd == NULL )
+ throw "malformed mach-o image: missing LC_DYSYMTAB";
+
+ uint32_t linkeditFileOffsetStart = (uint32_t)linkeditSegCmd->fileoff;
+ uint32_t linkeditFileOffsetEnd = (uint32_t)linkeditSegCmd->fileoff + (uint32_t)linkeditSegCmd->filesize;
+
+ if ( !inCache && (dyldInfoCmd != NULL) && context.strictMachORequired ) {
+ // validate all LC_DYLD_INFO chunks fit in LINKEDIT and don't overlap
+ uint32_t offset = linkeditFileOffsetStart;
+ if ( dyldInfoCmd->rebase_size != 0 ) {
+ if ( dyldInfoCmd->rebase_size & 0x80000000 )
+ throw "malformed mach-o image: dyld rebase info size overflow";
+ if ( dyldInfoCmd->rebase_off < offset )
+ throw "malformed mach-o image: dyld rebase info underruns __LINKEDIT";
+ offset = dyldInfoCmd->rebase_off + dyldInfoCmd->rebase_size;
+ if ( offset > linkeditFileOffsetEnd )
+ throw "malformed mach-o image: dyld rebase info overruns __LINKEDIT";
+ }
+ if ( dyldInfoCmd->bind_size != 0 ) {
+ if ( dyldInfoCmd->bind_size & 0x80000000 )
+ throw "malformed mach-o image: dyld bind info size overflow";
+ if ( dyldInfoCmd->bind_off < offset )
+ throw "malformed mach-o image: dyld bind info overlaps rebase info";
+ offset = dyldInfoCmd->bind_off + dyldInfoCmd->bind_size;
+ if ( offset > linkeditFileOffsetEnd )
+ throw "malformed mach-o image: dyld bind info overruns __LINKEDIT";
+ }
+ if ( dyldInfoCmd->weak_bind_size != 0 ) {
+ if ( dyldInfoCmd->weak_bind_size & 0x80000000 )
+ throw "malformed mach-o image: dyld weak bind info size overflow";
+ if ( dyldInfoCmd->weak_bind_off < offset )
+ throw "malformed mach-o image: dyld weak bind info overlaps bind info";
+ offset = dyldInfoCmd->weak_bind_off + dyldInfoCmd->weak_bind_size;
+ if ( offset > linkeditFileOffsetEnd )
+ throw "malformed mach-o image: dyld weak bind info overruns __LINKEDIT";
+ }
+ if ( dyldInfoCmd->lazy_bind_size != 0 ) {
+ if ( dyldInfoCmd->lazy_bind_size & 0x80000000 )
+ throw "malformed mach-o image: dyld lazy bind info size overflow";
+ if ( dyldInfoCmd->lazy_bind_off < offset )
+ throw "malformed mach-o image: dyld lazy bind info overlaps weak bind info";
+ offset = dyldInfoCmd->lazy_bind_off + dyldInfoCmd->lazy_bind_size;
+ if ( offset > linkeditFileOffsetEnd )
+ throw "malformed mach-o image: dyld lazy bind info overruns __LINKEDIT";
+ }
+ if ( dyldInfoCmd->export_size != 0 ) {
+ if ( dyldInfoCmd->export_size & 0x80000000 )
+ throw "malformed mach-o image: dyld export info size overflow";
+ if ( dyldInfoCmd->export_off < offset )
+ throw "malformed mach-o image: dyld export info overlaps lazy bind info";
+ offset = dyldInfoCmd->export_off + dyldInfoCmd->export_size;
+ if ( offset > linkeditFileOffsetEnd )
+ throw "malformed mach-o image: dyld export info overruns __LINKEDIT";
+ }
+ }
+
+ if ( symTabCmd != NULL ) {
+ // validate symbol table fits in LINKEDIT
+ if ( (symTabCmd->nsyms > 0) && (symTabCmd->symoff < linkeditFileOffsetStart) )
+ throw "malformed mach-o image: symbol table underruns __LINKEDIT";
+ if ( symTabCmd->nsyms > 0x10000000 )
+ throw "malformed mach-o image: symbol table too large";
+ uint32_t symbolsSize = symTabCmd->nsyms * sizeof(macho_nlist);
+ if ( symbolsSize > linkeditSegCmd->filesize )
+ throw "malformed mach-o image: symbol table overruns __LINKEDIT";
+ if ( symTabCmd->symoff + symbolsSize < symTabCmd->symoff )
+ throw "malformed mach-o image: symbol table size wraps";
+ if ( symTabCmd->symoff + symbolsSize > symTabCmd->stroff )
+ throw "malformed mach-o image: symbol table overlaps symbol strings";
+ if ( symTabCmd->stroff + symTabCmd->strsize < symTabCmd->stroff )
+ throw "malformed mach-o image: symbol string size wraps";
+ if ( symTabCmd->stroff + symTabCmd->strsize > linkeditFileOffsetEnd ) {
+ // <rdar://problem/24220313> let old apps overflow as long as it stays within mapped page
+ if ( context.strictMachORequired || (symTabCmd->stroff + symTabCmd->strsize > ((linkeditFileOffsetEnd + 4095) & (-4096))) )
+ throw "malformed mach-o image: symbol strings overrun __LINKEDIT";
+ }
+ // validate indirect symbol table
+ if ( dynSymbTabCmd->nindirectsyms != 0 ) {
+ if ( dynSymbTabCmd->indirectsymoff < linkeditFileOffsetStart )
+ throw "malformed mach-o image: indirect symbol table underruns __LINKEDIT";
+ if ( dynSymbTabCmd->nindirectsyms > 0x10000000 )
+ throw "malformed mach-o image: indirect symbol table too large";
+ uint32_t indirectTableSize = dynSymbTabCmd->nindirectsyms * sizeof(uint32_t);
+ if ( indirectTableSize > linkeditSegCmd->filesize )
+ throw "malformed mach-o image: indirect symbol table overruns __LINKEDIT";
+ if ( dynSymbTabCmd->indirectsymoff + indirectTableSize < dynSymbTabCmd->indirectsymoff )
+ throw "malformed mach-o image: indirect symbol table size wraps";
+ if ( context.strictMachORequired && (dynSymbTabCmd->indirectsymoff + indirectTableSize > symTabCmd->stroff) )
+ throw "malformed mach-o image: indirect symbol table overruns string pool";
+ }
+ if ( (dynSymbTabCmd->nlocalsym > symTabCmd->nsyms) || (dynSymbTabCmd->ilocalsym > symTabCmd->nsyms) )
+ throw "malformed mach-o image: indirect symbol table local symbol count exceeds total symbols";
+ if ( dynSymbTabCmd->ilocalsym + dynSymbTabCmd->nlocalsym < dynSymbTabCmd->ilocalsym )
+ throw "malformed mach-o image: indirect symbol table local symbol count wraps";
+ if ( (dynSymbTabCmd->nextdefsym > symTabCmd->nsyms) || (dynSymbTabCmd->iextdefsym > symTabCmd->nsyms) )
+ throw "malformed mach-o image: indirect symbol table extern symbol count exceeds total symbols";
+ if ( dynSymbTabCmd->iextdefsym + dynSymbTabCmd->nextdefsym < dynSymbTabCmd->iextdefsym )
+ throw "malformed mach-o image: indirect symbol table extern symbol count wraps";
+ if ( (dynSymbTabCmd->nundefsym > symTabCmd->nsyms) || (dynSymbTabCmd->iundefsym > symTabCmd->nsyms) )
+ throw "malformed mach-o image: indirect symbol table undefined symbol count exceeds total symbols";
+ if ( dynSymbTabCmd->iundefsym + dynSymbTabCmd->nundefsym < dynSymbTabCmd->iundefsym )
+ throw "malformed mach-o image: indirect symbol table undefined symbol count wraps";
+ }
+
+