Loading...
src/dyld2.cpp dyld-732.8 dyld-750.6
--- dyld/dyld-732.8/src/dyld2.cpp
+++ dyld/dyld-750.6/src/dyld2.cpp
@@ -62,6 +62,7 @@
 #include <kern/kcdata.h>
 #include <sys/attr.h>
 #include <sys/fsgetpath.h>
+#include <System/sys/content_protection.h>
 
 #if TARGET_OS_SIMULATOR
 	enum {
@@ -74,11 +75,13 @@
 		AMFI_DYLD_OUTPUT_ALLOW_FALLBACK_PATHS = (1 << 3),
 		AMFI_DYLD_OUTPUT_ALLOW_PRINT_VARS = (1 << 4),
 		AMFI_DYLD_OUTPUT_ALLOW_FAILED_LIBRARY_INSERTION = (1 << 5),
+		AMFI_DYLD_OUTPUT_ALLOW_LIBRARY_INTERPOSING = (1 << 6),
 	};
 	extern "C" int amfi_check_dyld_policy_self(uint64_t input_flags, uint64_t* output_flags);
 #else
 	#include <libamfi.h>
 #endif
+
 #include <sandbox.h>
 #include <sandbox/private.h>
 #if __has_feature(ptrauth_calls)
@@ -1468,6 +1471,25 @@
 			sImageRoots.erase(it);
 			break;
 		}
+	}
+
+	// If this image is the potential canonical definition of any weak defs, then set them to a tombstone value
+	if ( gLinkContext.weakDefMapInitialized && image->hasCoalescedExports() && (image->getState() >= dyld_image_state_bound) ) {
+		Diagnostics diag;
+		const dyld3::MachOAnalyzer* ma = (const dyld3::MachOAnalyzer*)image->machHeader();
+		ma->forEachWeakDef(diag, ^(const char *symbolName, uintptr_t imageOffset, bool isFromExportTrie) {
+			auto it = gLinkContext.weakDefMap.find(symbolName);
+			assert(it != gLinkContext.weakDefMap.end());
+			it->second = { nullptr, 0 };
+			if ( !isFromExportTrie ) {
+				// The string was already duplicated if we are an export trie
+				// so only strdup as we are the nlist
+				size_t hash1 = ImageLoader::HashCString::hash(it->first);
+				it->first = strdup(it->first);
+				size_t hash2 = ImageLoader::HashCString::hash(it->first);
+				assert(hash1 == hash2);
+			}
+		});
 	}
 
 	// log if requested
@@ -3352,19 +3374,36 @@
 			return sAllCacheImagesProxy;
 	}
 #endif
-#if TARGET_OS_SIMULATOR
-	// in simulators, 'path' has DYLD_ROOT_PATH prepended, but cache index does not have the prefix, so use orgPath
-	const char* pathToFindInCache = orgPath;
-#else
-	const char* pathToFindInCache = path;
-#endif
 	uint statErrNo;
 	struct stat statBuf;
 	bool didStat = false;
 	bool existsOnDisk;
-	dyld3::SharedCacheFindDylibResults shareCacheResults;
+	__block dyld3::SharedCacheFindDylibResults shareCacheResults;
 	shareCacheResults.image = nullptr;
-	if ( dyld3::findInSharedCacheImage(sSharedCacheLoadInfo, pathToFindInCache, &shareCacheResults) ) {
+
+#if TARGET_OS_SIMULATOR
+
+	auto findSharedCacheImage = ^() {
+		// in simulators, 'path' has DYLD_ROOT_PATH prepended, but cache index does not have the prefix, so use orgPath
+		return dyld3::findInSharedCacheImage(sSharedCacheLoadInfo, orgPath, &shareCacheResults);
+	};
+
+#else
+
+	auto findSharedCacheImage = ^() {
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
+		if ( gLinkContext.iOSonMac ) {
+			// On iOSMac, we are also running with DYLD_ROOT_PATH set, but want to look up the orgPath
+			if ( dyld3::findInSharedCacheImage(sSharedCacheLoadInfo, orgPath, &shareCacheResults) )
+				return true;
+		}
+#endif
+		return dyld3::findInSharedCacheImage(sSharedCacheLoadInfo, path, &shareCacheResults);
+	};
+
+#endif
+
+	if ( findSharedCacheImage() ) {
 		// see if this image in the cache was already loaded via a different path
 		for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); ++it) {
 			ImageLoader* anImage = *it;
@@ -3794,6 +3833,16 @@
 			return image;
 	}
 
+#if SUPPORT_VERSIONED_PATHS
+    // <rdar://problem/53215116> DYLD_VERSIONED_FRAMEWORK_PATH fails to load a framework if it does not also exist at the system install path
+    // Scan to see if the dylib appears in a versioned path. Don't worry if we find the newest, that will handled later
+    if ( !context.dontLoad  && (exceptions != NULL) && ((sEnv.DYLD_VERSIONED_FRAMEWORK_PATH != NULL) || (sEnv.DYLD_VERSIONED_LIBRARY_PATH != NULL)) ) {
+        image = loadPhase2(path, orgPath, context, sEnv.DYLD_VERSIONED_FRAMEWORK_PATH, sEnv.DYLD_VERSIONED_LIBRARY_PATH, cacheIndex, exceptions);
+        if ( image != NULL )
+            return image;
+    }
+#endif
+
 	return NULL;
 }
 
@@ -5064,6 +5113,11 @@
 		gLinkContext.allowEnvVarsSharedCache	= (amfiOutputFlags & AMFI_DYLD_OUTPUT_ALLOW_CUSTOM_SHARED_CACHE);
 		gLinkContext.allowClassicFallbackPaths	= (amfiOutputFlags & AMFI_DYLD_OUTPUT_ALLOW_FALLBACK_PATHS);
 		gLinkContext.allowInsertFailures    	= (amfiOutputFlags & AMFI_DYLD_OUTPUT_ALLOW_FAILED_LIBRARY_INSERTION);
+#ifdef AMFI_RETURNS_INTERPOSING_FLAG
+		gLinkContext.allowInterposing	    	= (amfiOutputFlags & AMFI_DYLD_OUTPUT_ALLOW_LIBRARY_INTERPOSING);
+#else
+		gLinkContext.allowInterposing	    	= true;
+#endif
 	}
 	else {
 #if __MAC_OS_X_VERSION_MIN_REQUIRED
@@ -5093,6 +5147,7 @@
 		gLinkContext.allowEnvVarsSharedCache     = !libraryValidation || !usingSIP;
 		gLinkContext.allowClassicFallbackPaths   = !isRestricted;
 		gLinkContext.allowInsertFailures         = false;
+		gLinkContext.allowInterposing         	 = true;
 #else
 		halt("amfi_check_dyld_policy_self() failed\n");
 #endif
@@ -5172,14 +5227,11 @@
 }
 
 #if __MAC_OS_X_VERSION_MIN_REQUIRED
-typedef int (*open_proc_t)(const char*, int, int);
-typedef int (*fcntl_proc_t)(int, int, void*);
-typedef int (*ioctl_proc_t)(int, unsigned long, void*);
 static void* getProcessInfo() { return dyld::gProcessInfo; }
 static const SyscallHelpers sSysCalls = {
 		12,
 		// added in version 1
-		(open_proc_t)&open, 
+		&open,
 		&close, 
 		&pread, 
 		&write, 
@@ -5187,8 +5239,8 @@
 		&munmap, 
 		&madvise,
 		&stat, 
-		(fcntl_proc_t)&fcntl, 
-		(ioctl_proc_t)&ioctl, 
+		&fcntl,
+		&ioctl, 
 		&issetugid, 
 		&getcwd, 
 		&realpath, 
@@ -5774,7 +5826,11 @@
 			dyld::log("dyld: closure %p not used because is used default fallback paths, but process does not allow that\n", mainClosure);
 		return false;
 	}
-
+	if ( mainClosure->usedInterposing() && !gLinkContext.allowInterposing ) {
+		if ( gLinkContext.verboseWarnings )
+			dyld::log("dyld: closure %p not used because is uses interposing, but process does not allow that\n", mainClosure);
+		return false;
+	}
 	return !foundFileThatInvalidatesClosure;
 }
 
@@ -5862,6 +5918,21 @@
 
 	// send info on all images to libdyld.dylb
 	libDyldEntry->setVars(mainExecutableMH, argc, argv, envp, apple);
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
+	uint32_t progVarsOffset;
+	if ( mainClosure->hasProgramVars(progVarsOffset) ) {
+		if ( libDyldEntry->vectorVersion >= 8 ) {
+			// main executable contains globals to hold argc, argv, envp, and progname, but they need to be filled in
+			ProgramVars* vars = (ProgramVars*)((uint8_t*)mainExecutableMH + progVarsOffset);
+			*vars->NXArgcPtr 	= argc;
+			*vars->NXArgvPtr 	= argv;
+			*vars->environPtr 	= envp;
+			*vars->__prognamePtr = (argv[0] != NULL) ? basename(argv[0]) : "";
+			// set up so libSystem gets ProgramVars struct embedded in main executable
+			libDyldEntry->setProgramVars(vars);
+		}
+	}
+#endif
 	if ( libDyldEntry->vectorVersion > 4 )
 		libDyldEntry->setRestrictions(gLinkContext.allowAtPaths, gLinkContext.allowEnvVarsPath, gLinkContext.allowClassicFallbackPaths);
 	libDyldEntry->setHaltFunction(&halt);
@@ -5990,6 +6061,8 @@
 										   archs, pathOverrides, atPathHanding, gLinkContext.allowEnvVarsPath, errorInfo);
 	if (sForceInvalidSharedCacheClosureFormat)
 		builder.setDyldCacheInvalidFormatVersion();
+	if ( !gLinkContext.allowInterposing )
+		builder.disableInterposing();
 	const dyld3::closure::LaunchClosure* result = builder.makeLaunchClosure(mainFileInfo, gLinkContext.allowInsertFailures);
 	if ( builder.diagnostics().hasError() ) {
 		const char* errMsg = builder.diagnostics().errorMessage();
@@ -6038,7 +6111,11 @@
 		putHexByte(mypid, s);
 		*s = '\0';
 		strlcat(closurePathTemp, pidBuf, PATH_MAX);
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
 		int fd = ::open(closurePathTemp, O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR);
+#else
+		int fd = ::open_dprotected_np(closurePathTemp, O_WRONLY|O_CREAT, PROTECTION_CLASS_D, 0, S_IRUSR|S_IWUSR);
+#endif
 		if ( fd != -1 ) {
 			::ftruncate(fd, result->size());
 			::write(fd, result, result->size());
@@ -6418,6 +6495,7 @@
 				}
 			}
 			if ( launched ) {
+				gLinkContext.startedInitializingMainExecutable = true;
 #if __has_feature(ptrauth_calls)
 				// start() calls the result pointer as a function pointer so we need to sign it.
 				result = (uintptr_t)__builtin_ptrauth_sign_unauthenticated((void*)result, 0, 0);
@@ -6594,20 +6672,24 @@
 				link(image, sEnv.DYLD_BIND_AT_LAUNCH, true, ImageLoader::RPathChain(NULL, NULL), -1);
 				image->setNeverUnloadRecursive();
 			}
-			// only INSERTED libraries can interpose
-			// register interposing info after all inserted libraries are bound so chaining works
-			for(unsigned int i=0; i < sInsertedDylibCount; ++i) {
-				ImageLoader* image = sAllImages[i+1];
+			if ( gLinkContext.allowInterposing ) {
+				// only INSERTED libraries can interpose
+				// register interposing info after all inserted libraries are bound so chaining works
+				for(unsigned int i=0; i < sInsertedDylibCount; ++i) {
+					ImageLoader* image = sAllImages[i+1];
+					image->registerInterposing(gLinkContext);
+				}
+			}
+		}
+
+		if ( gLinkContext.allowInterposing ) {
+			// <rdar://problem/19315404> dyld should support interposition even without DYLD_INSERT_LIBRARIES
+			for (long i=sInsertedDylibCount+1; i < sAllImages.size(); ++i) {
+				ImageLoader* image = sAllImages[i];
+				if ( image->inSharedCache() )
+					continue;
 				image->registerInterposing(gLinkContext);
 			}
-		}
-
-		// <rdar://problem/19315404> dyld should support interposition even without DYLD_INSERT_LIBRARIES
-		for (long i=sInsertedDylibCount+1; i < sAllImages.size(); ++i) {
-			ImageLoader* image = sAllImages[i];
-			if ( image->inSharedCache() )
-				continue;
-			image->registerInterposing(gLinkContext);
 		}
 	#if SUPPORT_ACCELERATE_TABLES
 		if ( (sAllCacheImagesProxy != NULL) && ImageLoader::haveInterposingTuples() ) {