Loading...
--- dyld/dyld-1284.13/mach_o/Header.cpp
+++ dyld/dyld-1330/mach_o/Header.cpp
@@ -286,9 +286,10 @@
if ( content.size() < sizeof(mach_header) )
return nullptr;
- const Header* mh = (const Header*)content.data();
- if ( mh->hasMachOMagic() )
- return mh;
+ if ( const Header* mh = (const Header*)content.data() ) {
+ if ( mh->hasMachOMagic() )
+ return mh;
+ }
return nullptr;
}
@@ -323,6 +324,12 @@
return (this->mh.flags & MH_SIM_SUPPORT) != 0;
}
+bool Header::noDynamicAccess() const
+{
+ return (this->mh.flags & MH_NO_DYNAMIC_ACCESS) != 0;
+}
+
+
//
// MARK: --- methods for validating mach-o content ---
//
@@ -333,7 +340,7 @@
__block PlatformAndVersions pvs;
forEachPlatformLoadCommand(^(Platform platform, Version32 minOS, Version32 sdk) {
Error err = pvs.zip({ platform, minOS, sdk });
- assert(err.noError());
+ // .zip() will not combine platforms if it is an invalid combo
});
return pvs;
}
@@ -423,7 +430,7 @@
const char* str = (char*)cmd + strOffset;
const char* end = (char*)cmd + cmd->cmdsize;
- for ( const char* s = str; s < end; ++s ) {
+ for ( const char* s = end-1; s >= str; --s ) {
if ( *s == '\0' ) {
return Error::none();
}
@@ -439,7 +446,7 @@
return Error("load commands length (%llu) exceeds length of file (%llu)", headerAndLCSize, fileSize);
}
- // check for reconized filetype
+ // check for recognized filetype
switch ( mh.filetype ) {
case MH_EXECUTE:
case MH_DYLIB:
@@ -627,11 +634,12 @@
});
if ( uuidCount > 1 )
return Error("too many LC_UUID load commands");
- if ( (uuidCount == 0) && policy.enforceHasUUID() )
- return Error("missing LC_UUID load command");
-
+ if ( (uuidCount == 0) && policy.enforceHasUUID() ) {
+ return Error("missing LC_UUID load command");
+ }
return Error::none();
}
+
Error Header::validSemanticsInstallName(const Policy& policy) const
{
@@ -854,7 +862,7 @@
{
Interval vm;
Interval file;
- const char* name;
+ CString name;
};
STACK_ALLOC_OVERFLOW_SAFE_ARRAY(SegRange, ranges, 12);
__block Error lcError;
@@ -913,15 +921,18 @@
}
// check for overlapping segments, by looking at every possible pair of segments
+ const bool checkNames = isDyldManaged() && policy.enforceUniqueSegmentNames();
for ( const SegRange& r1 : ranges ) {
for ( const SegRange& r2 : ranges ) {
if ( &r1 == &r2 )
continue;
if ( r1.vm.overlaps(r2.vm) )
- return Error("vm range of segment '%s' overlaps segment '%s'", r1.name, r2.name);
+ return Error("vm range of segment '%s' overlaps segment '%s'", r1.name.c_str(), r2.name.c_str());
// can't compare file offsets for segments in dyld cache because they may be offsets into different files
if ( !this->inDyldCache() && r1.file.overlaps(r2.file) )
- return Error("file range of segment '%s' overlaps segment '%s'", r1.name, r2.name);
+ return Error("file range of segment '%s' overlaps segment '%s'", r1.name.c_str(), r2.name.c_str());
+ if ( checkNames && (r1.name == r2.name) )
+ return Error("duplicate segment name '%s'", r1.name.c_str());
}
}
@@ -932,13 +943,14 @@
const SegRange& a = ranges[i-1];
const SegRange& b = ranges[i];
if ( (b.file.start < a.file.start) && (b.file.start != b.file.end) )
- return Error("segment '%s' file offset out of order", a.name);
+ return Error("segment '%s' file offset out of order", a.name.c_str());
if ( b.vm.start < a.vm.start ) {
- if ( isFileSet() && (strcmp(b.name, "__PRELINK_INFO") == 0) ) {
+ if ( isFileSet() && (b.name == "__PRELINK_INFO") ) {
// __PRELINK_INFO may have no vmaddr set
- }
- else {
- return Error("segment '%s' vm address out of order", b.name);
+ } else if ( arch().usesx86_64Instructions() && isDynamicExecutable() && !isPIE() ) {
+ // rdar://149897776 (allow out of VM address order segments on legacy x86 binaries)
+ } else {
+ return Error("segment '%s' vm address out of order", b.name.c_str());
}
}
}
@@ -1154,7 +1166,7 @@
// old binary with no explicit platform
#if TARGET_OS_OSX
- if ( (mh.cputype == CPU_TYPE_X86_64) | (mh.cputype == CPU_TYPE_I386) )
+ if ( (mh.cputype == CPU_TYPE_X86_64) || (mh.cputype == CPU_TYPE_I386) )
handler(Platform::macOS, Version32(10, 5), Version32(10, 5)); // guess it is a macOS 10.5 binary
// <rdar://problem/75343399>
// The Go linker emits non-standard binaries without a platform and we have to live with it.
@@ -1338,6 +1350,9 @@
Version32 compatVersion, Version32 curVersion,
bool synthesizedLink, bool& stop)) const
{
+ if ( this->isDylinker() )
+ return;
+
__block unsigned count = 0;
__block bool stopped = false;
forEachLoadCommandSafe(^(const load_command* cmd, bool& stop) {
@@ -1419,7 +1434,7 @@
case CPU_TYPE_ARM64:
case CPU_TYPE_ARM64_32:
if ( flavor == 6 ) { // ARM_THREAD_STATE64
- addr = regs64[32]; // arm_thread_state64_t.__pc
+ memcpy((uint32_t*)&addr, (uint32_t*)®s64[32], sizeof(uint64_t)); // arm_thread_state64_t.__pc
return true;
}
break;
@@ -1464,7 +1479,14 @@
stop = true;
}
});
- // FIXME: may need to ignore codesigs from pre 10.9 macOS binaries
+
+ // <rdar://problem/13622786> ignore code signatures in macOS binaries built with pre-10.9 tools
+ if ( mh.cputype == CPU_TYPE_X86_64 ) {
+ PlatformAndVersions pvs = platformAndVersions();
+ if ( (pvs.platform == Platform::macOS) && (pvs.sdk < Version32(10,9)) )
+ return false;
+ }
+
return result;
}
@@ -1492,6 +1514,23 @@
fileOffset = dySymCmd->indirectsymoff;
count = dySymCmd->nindirectsyms;
result = true;
+ stop = true;
+ }
+ });
+ return result;
+}
+
+bool Header::hasClassicRelocations(uint32_t& nLocRel, uint32_t& nExtRel) const
+{
+ __block bool result = false;
+ nLocRel = 0;
+ nExtRel = 0;
+ forEachLoadCommandSafe(^(const load_command* cmd, bool& stop) {
+ if ( cmd->cmd == LC_DYSYMTAB) {
+ dysymtab_command* dySymCmd = (dysymtab_command*)cmd;
+ nLocRel = dySymCmd->nlocrel;
+ nExtRel = dySymCmd->nextrel;
+ result = (nLocRel != 0 || nExtRel != 0);
stop = true;
}
});
@@ -2331,6 +2370,21 @@
return result;
}
+bool Header::hasDiscontiguousSegments() const
+{
+ uint64_t loadAddr = preferredLoadAddress();
+ __block bool res = false;
+ this->forEachSegment(^(const SegmentInfo& info, bool& stop) {
+ if ( info.maxProt == 0 )
+ return;
+ if ( info.vmaddr < loadAddr ) {
+ res = true;
+ stop = true;
+ }
+ });
+ return res;
+}
+
std::string_view Header::segmentName(uint32_t segIndex) const
{
__block std::string_view result;
@@ -2477,10 +2531,12 @@
const segment_command_64* segCmd = (segment_command_64*)cmd;
const section_64* const sectionsStart = (section_64*)((char*)segCmd + sizeof(struct segment_command_64));
const section_64* const sectionsEnd = §ionsStart[segCmd->nsects];
+ std::string_view segName = name16(segCmd->segname);
for ( const section_64* sect = sectionsStart; !stop && (sect < sectionsEnd); ++sect ) {
+ std::string_view segNameFromSectLC = name16(sect->segname);
SectionInfo info = {
// Note: use of segCmd->segname is for bin compat for copy protection in rdar://146096183
- .sectionName=name16(sect->sectname), .segmentName=name16(segCmd->segname), .segIndex=segmentIndex,
+ .sectionName=name16(sect->sectname), .segmentName=segNameFromSectLC.empty() ? segName : segNameFromSectLC, .segIndex=segmentIndex,
.segMaxProt=(uint32_t)segCmd->maxprot, .segInitProt=(uint32_t)segCmd->initprot,
.flags=sect->flags, .alignment=sect->align, .address=sect->addr, .size=sect->size, .fileOffset=sect->offset,
.relocsOffset=sect->reloff, .relocsCount=sect->nreloc, .reserved1=sect->reserved1, .reserved2=sect->reserved2
@@ -2639,16 +2695,25 @@
return result;
}
-bool Header::isRestricted() const
+// checks if a section exists.
+// use `segNamePrefix` to just match segment name prefix (e.g. "__DATA" matches "__DATA_CONST")
+bool Header::hasSection(CString segName, CString sectName, bool segNamePrefix) const
{
__block bool result = false;
this->forEachSection(^(const SectionInfo& info, bool& stop) {
- if ( (info.segmentName == "__RESTRICT") && (info.sectionName == "__restrict") ) {
- result = true;
- stop = true;
+ if ( info.sectionName == sectName ) {
+ if ( (segNamePrefix && info.segmentName.starts_with(segName)) || (info.segmentName == segName)) {
+ result = true;
+ stop = true;
+ }
}
});
return result;
+}
+
+bool Header::isRestricted() const
+{
+ return this->hasSection("__RESTRICT", "__restrict");
}
bool Header::hasInterposingTuples() const
@@ -2796,7 +2861,7 @@
cmdSize = Header::pointerAligned(false, 16 + 34 * 8); // base size + ARM_EXCEPTION_STATE64_COUNT * 8
else if ( arch.sameCpu(Architecture::x86_64) )
cmdSize = Header::pointerAligned(true, 16 + 42 * 4); // base size + x86_THREAD_STATE64_COUNT * 4
- else if ( arch.usesThumbInstructions() || arch.usesArm32Instructions() )
+ else if ( arch.usesArmOrThumbInstructions() )
cmdSize = Header::pointerAligned(false, 16 + 17 * 4); // base size + ARM_THREAD_STATE_COUNT * 4
else
assert(0 && "unsupported arch for thread load command");