Loading...
src/dyld.cpp dyld-421.2 dyld-433.5
--- dyld/dyld-421.2/src/dyld.cpp
+++ dyld/dyld-433.5/src/dyld.cpp
@@ -312,7 +312,7 @@
 static bool							sLogToFile = false;
 #endif
 static char							sLoadingCrashMessage[1024] = "dyld: launch, loading dependent libraries";
-
+static bool							sSafeMode = false;
 static _dyld_objc_notify_mapped		sNotifyObjCMapped;
 static _dyld_objc_notify_init		sNotifyObjCInit;
 static _dyld_objc_notify_unmapped	sNotifyObjCUnmapped;
@@ -779,7 +779,7 @@
 	header->imageCount		= imageCount;
 	header->imagesOffset	= sizeof(dyld_process_info_notify_header);
 	header->stringsOffset	= sizeof(dyld_process_info_notify_header) + entriesSize;
-	header->timestamp		= mach_absolute_time();
+	header->timestamp		= dyld::gProcessInfo->infoArrayChangeTimestamp;
 	dyld_process_info_image_entry* entries = (dyld_process_info_image_entry*)&buffer[header->imagesOffset];
 	char* const pathPoolStart = (char*)&buffer[header->stringsOffset];
 	char* pathPool = pathPoolStart;
@@ -831,6 +831,38 @@
 		mach_port_deallocate(mach_task_self(), sNotifyReplyPorts[portSlot]);
 		dyld::gProcessInfo->notifyPorts[portSlot] = 0;
 		sNotifyReplyPorts[portSlot] = 0;
+	}
+}
+
+static void notifyMonitoringDyldMain()
+{
+	for (int slot=0; slot < DYLD_MAX_PROCESS_INFO_NOTIFY_COUNT; ++slot) {
+		if ( dyld::gProcessInfo->notifyPorts[slot] != 0 ) {
+			if ( sNotifyReplyPorts[slot] == 0 ) {
+				if ( !mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &sNotifyReplyPorts[slot]) )
+					mach_port_insert_right(mach_task_self(), sNotifyReplyPorts[slot], sNotifyReplyPorts[slot], MACH_MSG_TYPE_MAKE_SEND);
+				//dyld::log("allocated reply port %d\n", sNotifyReplyPorts[slot]);
+			}
+			//dyld::log("found port to send to\n");
+			mach_msg_header_t h;
+			h.msgh_bits			= MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND,MACH_MSG_TYPE_MAKE_SEND); // MACH_MSG_TYPE_MAKE_SEND_ONCE
+			h.msgh_id			= DYLD_PROCESS_INFO_NOTIFY_MAIN_ID;
+			h.msgh_local_port	= sNotifyReplyPorts[slot];
+			h.msgh_remote_port	= dyld::gProcessInfo->notifyPorts[slot];
+			h.msgh_reserved		= 0;
+			h.msgh_size			= (mach_msg_size_t)sizeof(mach_msg_header_t);
+			//dyld::log("sending to port[%d]=%d, size=%d, reply port=%d, id=0x%X\n", slot, dyld::gProcessInfo->notifyPorts[slot], h.msgh_size, sNotifyReplyPorts[slot], h.msgh_id);
+			kern_return_t sendResult = mach_msg(&h, MACH_SEND_MSG | MACH_RCV_MSG | MACH_SEND_TIMEOUT, h.msgh_size, h.msgh_size, sNotifyReplyPorts[slot], 100, MACH_PORT_NULL);
+			//dyld::log("send result = 0x%X, msg_id=%d, msg_size=%d\n", sendResult, h.msgh_id, h.msgh_size);
+			if ( sendResult == MACH_SEND_INVALID_DEST ) {
+				// sender is not responding, detatch
+				//dyld::log("process requesting notification gone. deallocation send port %d and receive port %d\n", dyld::gProcessInfo->notifyPorts[slot], sNotifyReplyPorts[slot]);
+				mach_port_deallocate(mach_task_self(), dyld::gProcessInfo->notifyPorts[slot]);
+				mach_port_deallocate(mach_task_self(), sNotifyReplyPorts[slot]);
+				dyld::gProcessInfo->notifyPorts[slot] = 0;
+				sNotifyReplyPorts[slot] = 0;
+			}
+		}
 	}
 }
 
@@ -1903,7 +1935,7 @@
 	else if ( strcmp(key, "DYLD_PRINT_CODE_SIGNATURES") == 0 ) {
 		gLinkContext.verboseCodeSignatures = true;
 	}
-	else if ( strcmp(key, "DYLD_SHARED_REGION") == 0 ) {
+	else if ( (strcmp(key, "DYLD_SHARED_REGION") == 0) && !sSafeMode ) {
 		if ( strcmp(value, "private") == 0 ) {
 			gLinkContext.sharedRegionMode = ImageLoader::kUsePrivateSharedRegion;
 		}
@@ -1921,10 +1953,10 @@
 		}
 	}
 #if DYLD_SHARED_CACHE_SUPPORT
-	else if ( strcmp(key, "DYLD_SHARED_CACHE_DIR") == 0 ) {
+	else if ( (strcmp(key, "DYLD_SHARED_CACHE_DIR") == 0) && !sSafeMode  ) {
         sSharedCacheDir = value;
 	}
-	else if ( strcmp(key, "DYLD_SHARED_CACHE_DONT_VALIDATE") == 0 ) {
+	else if ( (strcmp(key, "DYLD_SHARED_CACHE_DONT_VALIDATE") == 0) && !sSafeMode  ) {
 		sSharedCacheIgnoreInodeAndTimeStamp = true;
 	}
 #endif
@@ -1960,7 +1992,7 @@
 	}
 #endif
 #if !TARGET_IPHONE_SIMULATOR
-	else if ( (strcmp(key, "DYLD_PRINT_TO_FILE") == 0) && (mainExecutableDir == NULL) ) {
+	else if ( (strcmp(key, "DYLD_PRINT_TO_FILE") == 0) && (mainExecutableDir == NULL) && !sSafeMode ) {
 		int fd = open(value, O_WRONLY | O_CREAT | O_APPEND, 0644);
 		if ( fd != -1 ) {
 			sLogfile = fd;
@@ -3422,6 +3454,23 @@
 	return loadPhase4(path, orgPath, context, cacheIndex, exceptions);
 }
 
+static ImageLoader* loadPhase2cache(const char* path, const char *orgPath, const LoadContext& context, unsigned& cacheIndex, std::vector<const char*>* exceptions) {
+	ImageLoader* image = NULL;
+#if !TARGET_IPHONE_SIMULATOR
+	if ( exceptions != NULL) {
+		char resolvedPath[PATH_MAX];
+		realpath(path, resolvedPath);
+		int myerr = errno;
+		// If realpath() resolves to a path which does not exist on disk, errno is set to ENOENT
+		if ( (myerr == ENOENT) || (myerr == 0) )
+		{
+			image = loadPhase4(resolvedPath, orgPath, context, cacheIndex, exceptions);
+		}
+	}
+#endif
+	return image;
+}
+
 
 // try search paths
 static ImageLoader* loadPhase2(const char* path, const char* orgPath, const LoadContext& context,
@@ -3441,6 +3490,9 @@
 				strcat(npath, frameworkPartialPath);
 				//dyld::log("dyld: fallback framework path used: %s() -> loadPhase4(\"%s\", ...)\n", __func__, npath);
 				image = loadPhase4(npath, orgPath, context, cacheIndex, exceptions);
+				// Look in the cache if appropriate
+				if ( image == NULL)
+					image = loadPhase2cache(npath, orgPath, context, cacheIndex, exceptions);
 				if ( image != NULL )
 					return image;
 			}
@@ -3458,6 +3510,9 @@
 			strcat(libpath, libraryLeafName);
 			//dyld::log("dyld: fallback library path used: %s() -> loadPhase4(\"%s\", ...)\n", __func__, libpath);
 			image = loadPhase4(libpath, orgPath, context, cacheIndex, exceptions);
+			// Look in the cache if appropriate
+			if ( image == NULL)
+				image = loadPhase2cache(libpath, orgPath, context, cacheIndex, exceptions);
 			if ( image != NULL )
 				return image;
 		}
@@ -3575,32 +3630,10 @@
 	// try all path permutations and try open() until first success
 	std::vector<const char*> exceptions;
 	image = loadPhase0(path, orgPath, context, cacheIndex, &exceptions);
-#if __IPHONE_OS_VERSION_MIN_REQUIRED && DYLD_SHARED_CACHE_SUPPORT && !TARGET_IPHONE_SIMULATOR
+#if !TARGET_IPHONE_SIMULATOR
 	// <rdar://problem/16704628> support symlinks on disk to a path in dyld shared cache
-	if ( (image == NULL) && cacheablePath(path) && !context.dontLoad ) {
-		char resolvedPath[PATH_MAX];
-		realpath(path, resolvedPath);
-		int myerr = errno;
-		// If realpath() resolves to a path which does not exist on disk, errno is set to ENOENT
-		if ( (myerr == ENOENT) || (myerr == 0) )
-		{
-			// see if this image is in shared cache
-			const macho_header* mhInCache;
-			const char*			pathInCache;
-			long				slideInCache;
-			if ( findInSharedCacheImage(resolvedPath, false, NULL, &mhInCache, &pathInCache, &slideInCache) ) {
-				struct stat stat_buf;
-				bzero(&stat_buf, sizeof(stat_buf));
-				try {
-					image = ImageLoaderMachO::instantiateFromCache(mhInCache, pathInCache, slideInCache, stat_buf, gLinkContext);
-					image = checkandAddImage(image, context);
-				}
-				catch (...) {
-					image = NULL;
-				}
-			}
-		}
-	}
+	if ( image == NULL)
+		image = loadPhase2cache(path, orgPath, context, cacheIndex, &exceptions);
 #endif
     CRSetCrashLogMessage2(NULL);
 	if ( image != NULL ) {
@@ -4002,6 +4035,7 @@
 				return;
 			}
 		}
+		dyld::gProcessInfo->sharedCacheBaseAddress = cacheBaseAddress;
 		// check if cache file is slidable
 		const dyld_cache_header* header = sSharedCache;
 		if ( (header->mappingOffset >= 0x48) && (header->slideInfoSize != 0) ) {
@@ -4011,10 +4045,9 @@
 			const uint8_t* preferedLoadAddress = (uint8_t*)(long)(mappings[0].address);
 			sSharedCacheSlide = loadedAddress - preferedLoadAddress;
 			dyld::gProcessInfo->sharedCacheSlide = sSharedCacheSlide;
-			dyld::gProcessInfo->sharedCacheBaseAddress = cacheBaseAddress;
 			//dyld::log("sSharedCacheSlide=0x%08lX, loadedAddress=%p, preferedLoadAddress=%p\n", sSharedCacheSlide, loadedAddress, preferedLoadAddress);
 		}
-		// if cache has a uuid, copy it 
+		// if cache has a uuid, copy it
 		if ( header->mappingOffset >= 0x68 ) {
 			memcpy(dyld::gProcessInfo->sharedCacheUUID, header->uuid, 16);
 		}
@@ -4778,14 +4811,27 @@
 {
 	if ( sAllCacheImagesProxy == NULL )
 		return false;
+	char fallbackPath[PATH_MAX];
 	bool result = sAllCacheImagesProxy->dlopenFromCache(gLinkContext, path, mode, handle);
 	if ( !result && (strchr(path, '/') == NULL) ) {
 		// POSIX says you can call dlopen() with a leaf name (e.g. dlopen("libz.dylb"))
-		char fallbackPath[PATH_MAX];
 		strcpy(fallbackPath, "/usr/lib/");
 		strlcat(fallbackPath, path, PATH_MAX);
 		result = sAllCacheImagesProxy->dlopenFromCache(gLinkContext, fallbackPath, mode, handle);
-	}
+		if ( !result )
+			path = fallbackPath;
+	}
+	if ( !result ) {
+		// leaf name could be a symlink
+		char resolvedPath[PATH_MAX];
+		realpath(path, resolvedPath);
+		int realpathErrno = errno;
+		// If realpath() resolves to a path which does not exist on disk, errno is set to ENOENT
+		if ( (realpathErrno == ENOENT) || (realpathErrno == 0) ) {
+			result = sAllCacheImagesProxy->dlopenFromCache(gLinkContext, resolvedPath, mode, handle);
+		}
+	}
+
 	return result;
 }
 
@@ -5345,9 +5391,10 @@
     if ( issetugid() || hasRestrictedSegment(mainExecutableMH) ) {
 		gLinkContext.processIsRestricted = true;
 	}
+	bool usingSIP = (csr_check(CSR_ALLOW_TASK_FOR_PID) != 0);
 	if ( csops(0, CS_OPS_STATUS, &flags, sizeof(flags)) != -1 ) {
 		// On OS X CS_RESTRICT means the program was signed with entitlements
-		if ( ((flags & CS_RESTRICT) == CS_RESTRICT) && (csr_check(CSR_ALLOW_TASK_FOR_PID) != 0) ) {
+		if ( ((flags & CS_RESTRICT) == CS_RESTRICT) && usingSIP ) {
 			gLinkContext.processIsRestricted = true;
 		}
 		// Library Validation loosens searching but requires everything to be code signed
@@ -5355,6 +5402,7 @@
 			gLinkContext.processIsRestricted = false;
 			//gLinkContext.requireCodeSignature = true;
 			gLinkContext.processUsingLibraryValidation = true;
+			sSafeMode = usingSIP;
 		}
 	}
 #endif
@@ -5893,8 +5941,10 @@
 #endif
 		char dyldPathBuffer[MAXPATHLEN+1];
 		int len = proc_regionfilename(getpid(), (uint64_t)(long)addressInDyld, dyldPathBuffer, MAXPATHLEN);
-		if ( (len != 0) && (strcmp(dyldPathBuffer, gProcessInfo->dyldPath) != 0) ) {
-			gProcessInfo->dyldPath = strdup(dyldPathBuffer);
+		if ( len > 0 ) {
+			dyldPathBuffer[len] = '\0'; // proc_regionfilename() does not zero terminate returned string
+			if ( strcmp(dyldPathBuffer, gProcessInfo->dyldPath) != 0 )
+				gProcessInfo->dyldPath = strdup(dyldPathBuffer);
 		}
 
 		// load any inserted libraries
@@ -6017,6 +6067,10 @@
 		// run all initializers
 		initializeMainExecutable(); 
 	#endif
+
+		// notify any montoring proccesses that this process is about to enter main()
+		notifyMonitoringDyldMain();
+
 		// find entry point for main executable
 		result = (uintptr_t)sMainExecutable->getThreadPC();
 		if ( result != 0 ) {