]> git.saurik.com Git - apple/dyld.git/blob - src/dyldAPIsInLibSystem.cpp
dyld-851.27.tar.gz
[apple/dyld.git] / src / dyldAPIsInLibSystem.cpp
1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
2 *
3 * Copyright (c) 2004-2012 Apple Inc. All rights reserved.
4 *
5 * @APPLE_LICENSE_HEADER_START@
6 *
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
12 * file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
25 #include <stddef.h>
26 #include <string.h>
27 #include <malloc/malloc.h>
28 #include <sys/mman.h>
29 #include <execinfo.h>
30
31 #include <TargetConditionals.h>
32 #include <System/sys/csr.h>
33 #include <crt_externs.h>
34 #include <Availability.h>
35 #if !TARGET_OS_DRIVERKIT
36 #include <vproc_priv.h>
37 #endif
38 #include <dirent.h>
39 #include <sys/types.h>
40 #include <sys/stat.h>
41 #include <fcntl.h>
42 #include <System/sys/codesign.h>
43 #include <libc_private.h>
44
45 #include <mach-o/dyld_images.h>
46 #include <mach-o/dyld.h>
47 #include <mach-o/dyld_priv.h>
48
49 #include <ptrauth.h>
50
51 #include "dyld_cache_format.h"
52 #include "objc-shared-cache.h"
53
54 #include "ImageLoader.h"
55 #include "dyldLock.h"
56
57 #include "APIs.h"
58 #include "AllImages.h"
59 #include "StartGlue.h"
60 #include "Tracing.h"
61
62
63 // this was in dyld_priv.h but it is no longer exported
64 extern "C" {
65 const struct dyld_all_image_infos* _dyld_get_all_image_infos() __attribute__((visibility("hidden")));
66 }
67
68
69 extern "C" int __cxa_atexit(void (*func)(void *), void *arg, void *dso);
70 extern "C" void __cxa_finalize(const void *dso);
71 extern "C" void __cxa_finalize_ranges(const struct __cxa_range_t ranges[], int count);
72
73 //
74 // private interface between libSystem.dylib and dyld
75 //
76 extern "C" int _dyld_func_lookup(const char* dyld_func_name, void **address);
77
78 template<typename T>
79 static void dyld_func_lookup_and_resign(const char *dyld_func_name, T *__ptrauth_dyld_function_ptr* address) {
80 void *funcAsVoidPtr;
81 int res = _dyld_func_lookup(dyld_func_name, &funcAsVoidPtr);
82 (void)res;
83
84 // If C function pointer discriminators are type-diverse this cast will be
85 // an authenticate and resign operation.
86 *address = reinterpret_cast<T *>(funcAsVoidPtr);
87 }
88
89 #if TARGET_OS_IOS && !TARGET_OS_SIMULATOR
90 namespace dyld3 {
91 extern int compatFuncLookup(const char* name, void** address) __API_AVAILABLE(ios(13.0));
92 }
93 extern "C" void setLookupFunc(void*);
94 #endif
95
96
97 extern void* __ptrauth_dyld_address_auth gUseDyld3;
98
99
100 // <rdar://problem/61161069> libdyld.dylib should use abort_with_payload() for asserts
101 VIS_HIDDEN
102 void abort_report_np(const char* format, ...)
103 {
104 va_list list;
105 const char *str;
106 _SIMPLE_STRING s = _simple_salloc();
107 if ( s != NULL ) {
108 va_start(list, format);
109 _simple_vsprintf(s, format, list);
110 va_end(list);
111 str = _simple_string(s);
112 }
113 else {
114 // _simple_salloc failed, but at least format may have useful info by itself
115 str = format;
116 }
117 if ( gUseDyld3 ) {
118 dyld3::halt(str);
119 }
120 else {
121 typedef void (*funcType)(const char* msg) __attribute__((__noreturn__));
122 static funcType __ptrauth_dyld_function_ptr p = NULL;
123 dyld_func_lookup_and_resign("__dyld_halt", &p);
124 p(str);
125 }
126 // halt() doesn't return, so we can't call _simple_sfree
127 }
128
129 // libc uses assert()
130 #pragma clang diagnostic push
131 #pragma clang diagnostic ignored "-Winvalid-noreturn"
132 VIS_HIDDEN
133 void __assert_rtn(const char* func, const char* file, int line, const char* failedexpr)
134 {
135 if (func == NULL) {
136 abort_report_np("Assertion failed: (%s), file %s, line %d.\n", failedexpr, file, line);
137 } else {
138 abort_report_np("Assertion failed: (%s), function %s, file %s, line %d.\n", failedexpr, func, file, line);
139 }
140 }
141 #pragma clang diagnostic pop
142
143
144 // deprecated APIs are still availble on Mac OS X, but not on iPhone OS
145 #if TARGET_OS_OSX
146 #define DEPRECATED_APIS_SUPPORTED 1
147 #else
148 #define DEPRECATED_APIS_SUPPORTED 0
149 #endif
150
151 /*
152 * names_match() takes an install_name from an LC_LOAD_DYLIB command and a
153 * libraryName (which is -lx or -framework Foo argument passed to the static
154 * link editor for the same library) and determines if they match. This depends
155 * on conventional use of names including major versioning.
156 */
157 static
158 bool
159 names_match(
160 const char *install_name,
161 const char* libraryName)
162 {
163 const char *basename;
164 unsigned long n;
165
166 /*
167 * Conventional install names have these forms:
168 * /System/Library/Frameworks/AppKit.framework/Versions/A/Appkit
169 * /Local/Library/Frameworks/AppKit.framework/Appkit
170 * /lib/libsys_s.A.dylib
171 * /usr/lib/libsys_s.dylib
172 */
173 basename = strrchr(install_name, '/');
174 if(basename == NULL)
175 basename = install_name;
176 else
177 basename++;
178
179 /*
180 * By checking the base name matching the library name we take care
181 * of the -framework cases.
182 */
183 if(strcmp(basename, libraryName) == 0)
184 return true;
185
186 /*
187 * Now check the base name for "lib" if so proceed to check for the
188 * -lx case dealing with a possible .X.dylib and a .dylib extension.
189 */
190 if(strncmp(basename, "lib", 3) ==0){
191 n = strlen(libraryName);
192 if(strncmp(basename+3, libraryName, n) == 0){
193 if(strncmp(basename+3+n, ".dylib", 6) == 0)
194 return true;
195 if(basename[3+n] == '.' &&
196 basename[3+n+1] != '\0' &&
197 strncmp(basename+3+n+2, ".dylib", 6) == 0)
198 return true;
199 }
200 }
201 return false;
202 }
203
204 #if DEPRECATED_APIS_SUPPORTED
205
206 void NSInstallLinkEditErrorHandlers(
207 const NSLinkEditErrorHandlers* handlers)
208 {
209 if ( gUseDyld3 )
210 return dyld3::NSInstallLinkEditErrorHandlers(handlers);
211
212 DYLD_LOCK_THIS_BLOCK;
213 typedef void (*ucallback_t)(const char* symbol_name);
214 typedef NSModule (*mcallback_t)(NSSymbol s, NSModule old, NSModule newhandler);
215 typedef void (*lcallback_t)(NSLinkEditErrors c, int errorNumber,
216 const char* fileName, const char* errorString);
217 typedef void (*funcType)(ucallback_t undefined, mcallback_t multiple, lcallback_t linkEdit);
218 static funcType __ptrauth_dyld_function_ptr p = NULL;
219
220 if(p == NULL)
221 dyld_func_lookup_and_resign("__dyld_install_handlers", &p);
222 mcallback_t m = handlers->multiple;
223 p(handlers->undefined, m, handlers->linkEdit);
224 }
225
226 const char*
227 NSNameOfModule(
228 NSModule module)
229 {
230 if ( gUseDyld3 )
231 return dyld3::NSNameOfModule(module);
232
233 DYLD_LOCK_THIS_BLOCK;
234 typedef const char* (*funcType)(NSModule module);
235 static funcType __ptrauth_dyld_function_ptr p = NULL;
236
237 if(p == NULL)
238 dyld_func_lookup_and_resign("__dyld_NSNameOfModule", &p);
239 return(p(module));
240 }
241
242 const char*
243 NSLibraryNameForModule(
244 NSModule module)
245 {
246 if ( gUseDyld3 )
247 return dyld3::NSLibraryNameForModule(module);
248
249 DYLD_LOCK_THIS_BLOCK;
250 typedef const char* (*funcType)(NSModule module);
251 static funcType __ptrauth_dyld_function_ptr p = NULL;
252
253 if(p == NULL)
254 dyld_func_lookup_and_resign("__dyld_NSLibraryNameForModule", &p);
255 return(p(module));
256 }
257
258 bool
259 NSIsSymbolNameDefined(
260 const char* symbolName)
261 {
262 if ( gUseDyld3 )
263 return dyld3::NSIsSymbolNameDefined(symbolName);
264
265 DYLD_LOCK_THIS_BLOCK;
266 typedef bool (*funcType)(const char* symbolName);
267 static funcType __ptrauth_dyld_function_ptr p = NULL;
268
269 if(p == NULL)
270 dyld_func_lookup_and_resign("__dyld_NSIsSymbolNameDefined", &p);
271 return(p(symbolName));
272 }
273
274 bool
275 NSIsSymbolNameDefinedWithHint(
276 const char* symbolName,
277 const char* libraryNameHint)
278 {
279 if ( gUseDyld3 )
280 return dyld3::NSIsSymbolNameDefinedWithHint(symbolName, libraryNameHint);
281
282 DYLD_LOCK_THIS_BLOCK;
283 typedef bool (*funcType)(const char* symbolName,
284 const char* libraryNameHint);
285 static funcType __ptrauth_dyld_function_ptr p = NULL;
286
287 if(p == NULL)
288 dyld_func_lookup_and_resign("__dyld_NSIsSymbolNameDefinedWithHint", &p);
289 return(p(symbolName, libraryNameHint));
290 }
291
292 bool
293 NSIsSymbolNameDefinedInImage(
294 const struct mach_header *image,
295 const char* symbolName)
296 {
297 if ( gUseDyld3 )
298 return dyld3::NSIsSymbolNameDefinedInImage(image, symbolName);
299
300 DYLD_LOCK_THIS_BLOCK;
301 typedef bool (*funcType)(const struct mach_header *image,
302 const char* symbolName);
303 static funcType __ptrauth_dyld_function_ptr p = NULL;
304
305 if(p == NULL)
306 dyld_func_lookup_and_resign("__dyld_NSIsSymbolNameDefinedInImage", &p);
307 return(p(image, symbolName));
308 }
309
310 NSSymbol
311 NSLookupAndBindSymbol(
312 const char* symbolName)
313 {
314 if ( gUseDyld3 )
315 return dyld3::NSLookupAndBindSymbol(symbolName);
316
317 DYLD_LOCK_THIS_BLOCK;
318 typedef NSSymbol (*funcType)(const char* symbolName);
319 static funcType __ptrauth_dyld_function_ptr p = NULL;
320
321 if(p == NULL)
322 dyld_func_lookup_and_resign("__dyld_NSLookupAndBindSymbol", &p);
323 return(p(symbolName));
324 }
325
326 NSSymbol
327 NSLookupAndBindSymbolWithHint(
328 const char* symbolName,
329 const char* libraryNameHint)
330 {
331 if ( gUseDyld3 )
332 return dyld3::NSLookupAndBindSymbolWithHint(symbolName, libraryNameHint);
333
334 DYLD_LOCK_THIS_BLOCK;
335 typedef NSSymbol (*funcType)(const char* symbolName,
336 const char* libraryNameHint);
337 static funcType __ptrauth_dyld_function_ptr p = NULL;
338
339 if(p == NULL)
340 dyld_func_lookup_and_resign("__dyld_NSLookupAndBindSymbolWithHint", &p);
341 return(p(symbolName, libraryNameHint));
342 }
343
344 NSSymbol
345 NSLookupSymbolInModule(
346 NSModule module,
347 const char* symbolName)
348 {
349 if ( gUseDyld3 )
350 return dyld3::NSLookupSymbolInModule(module, symbolName);
351
352 DYLD_LOCK_THIS_BLOCK;
353 typedef NSSymbol (*funcType)(NSModule module, const char* symbolName);
354 static funcType __ptrauth_dyld_function_ptr p = NULL;
355
356 if(p == NULL)
357 dyld_func_lookup_and_resign("__dyld_NSLookupSymbolInModule", &p);
358 return(p(module, symbolName));
359 }
360
361 NSSymbol
362 NSLookupSymbolInImage(
363 const struct mach_header *image,
364 const char* symbolName,
365 uint32_t options)
366 {
367 if ( gUseDyld3 )
368 return dyld3::NSLookupSymbolInImage(image, symbolName, options);
369
370 DYLD_LOCK_THIS_BLOCK;
371 typedef NSSymbol (*funcType)(const struct mach_header *image,
372 const char* symbolName,
373 uint32_t options);
374 static funcType __ptrauth_dyld_function_ptr p = NULL;
375
376 if(p == NULL)
377 dyld_func_lookup_and_resign("__dyld_NSLookupSymbolInImage", &p);
378 return(p(image, symbolName, options));
379 }
380
381 const char*
382 NSNameOfSymbol(
383 NSSymbol symbol)
384 {
385 if ( gUseDyld3 )
386 return dyld3::NSNameOfSymbol(symbol);
387
388 DYLD_LOCK_THIS_BLOCK;
389 typedef char * (*funcType)(NSSymbol symbol);
390 static funcType __ptrauth_dyld_function_ptr p = NULL;
391
392 if(p == NULL)
393 dyld_func_lookup_and_resign("__dyld_NSNameOfSymbol",&p);
394 return(p(symbol));
395 }
396
397 void *
398 NSAddressOfSymbol(
399 NSSymbol symbol)
400 {
401 if ( gUseDyld3 )
402 return dyld3::NSAddressOfSymbol(symbol);
403
404 DYLD_LOCK_THIS_BLOCK;
405 typedef void * (*funcType)(NSSymbol symbol);
406 static funcType __ptrauth_dyld_function_ptr p = NULL;
407
408 if(p == NULL)
409 dyld_func_lookup_and_resign("__dyld_NSAddressOfSymbol", &p);
410 return(p(symbol));
411 }
412
413 NSModule
414 NSModuleForSymbol(
415 NSSymbol symbol)
416 {
417 if ( gUseDyld3 )
418 return dyld3::NSModuleForSymbol(symbol);
419
420 DYLD_LOCK_THIS_BLOCK;
421 typedef NSModule (*funcType)(NSSymbol symbol);
422 static funcType __ptrauth_dyld_function_ptr p = NULL;
423
424 if(p == NULL)
425 dyld_func_lookup_and_resign("__dyld_NSModuleForSymbol", &p);
426 return(p(symbol));
427 }
428
429 bool
430 NSAddLibrary(
431 const char* pathName)
432 {
433 if ( gUseDyld3 )
434 return dyld3::NSAddLibrary(pathName);
435
436 DYLD_LOCK_THIS_BLOCK;
437 typedef bool (*funcType)(const char* pathName);
438 static funcType __ptrauth_dyld_function_ptr p = NULL;
439
440 if(p == NULL)
441 dyld_func_lookup_and_resign("__dyld_NSAddLibrary", &p);
442 return(p(pathName));
443 }
444
445 bool
446 NSAddLibraryWithSearching(
447 const char* pathName)
448 {
449 if ( gUseDyld3 )
450 return dyld3::NSAddLibrary(pathName);
451
452 DYLD_LOCK_THIS_BLOCK;
453 typedef bool (*funcType)(const char* pathName);
454 static funcType __ptrauth_dyld_function_ptr p = NULL;
455
456 if(p == NULL)
457 dyld_func_lookup_and_resign("__dyld_NSAddLibraryWithSearching", &p);
458 return(p(pathName));
459 }
460
461 const struct mach_header *
462 NSAddImage(
463 const char* image_name,
464 uint32_t options)
465 {
466 if ( gUseDyld3 )
467 return dyld3::NSAddImage(image_name, options);
468
469 DYLD_LOCK_THIS_BLOCK;
470 typedef const struct mach_header * (*funcType)(const char* image_name,
471 uint32_t options);
472 static funcType __ptrauth_dyld_function_ptr p = NULL;
473
474 if(p == NULL)
475 dyld_func_lookup_and_resign("__dyld_NSAddImage", &p);
476 return(p(image_name, options));
477 }
478 #endif // DEPRECATED_APIS_SUPPORTED
479
480 /*
481 * This routine returns the current version of the named shared library the
482 * executable it was built with. The libraryName parameter is the same as the
483 * -lx or -framework Foo argument passed to the static link editor when building
484 * the executable (with -lx it would be "x" and with -framework Foo it would be
485 * "Foo"). If this the executable was not built against the specified library
486 * it returns -1. It should be noted that if this only returns the value the
487 * current version of the named shared library the executable was built with
488 * and not a list of current versions that dependent libraries and bundles the
489 * program is using were built with.
490 */
491 int32_t NSVersionOfLinkTimeLibrary(const char* libraryName)
492 {
493 if ( gUseDyld3 )
494 return dyld3::NSVersionOfLinkTimeLibrary(libraryName);
495
496 // Lazily call _NSGetMachExecuteHeader() and cache result
497 #if __LP64__
498 static mach_header_64* mh = NULL;
499 #else
500 static mach_header* mh = NULL;
501 #endif
502 if ( mh == NULL )
503 mh = _NSGetMachExecuteHeader();
504 #if __LP64__
505 const load_command* lc = (load_command*)((char*)mh + sizeof(mach_header_64));
506 #else
507 const load_command* lc = (load_command*)((char*)mh + sizeof(mach_header));
508 #endif
509 for(uint32_t i = 0; i < mh->ncmds; i++){
510 switch ( lc->cmd ) {
511 case LC_LOAD_DYLIB:
512 case LC_LOAD_WEAK_DYLIB:
513 case LC_LOAD_UPWARD_DYLIB:
514 const dylib_command* dl = (dylib_command *)lc;
515 const char* install_name = (char*)dl + dl->dylib.name.offset;
516 if ( names_match(install_name, libraryName) )
517 return dl->dylib.current_version;
518 break;
519 }
520 lc = (load_command*)((char*)lc + lc->cmdsize);
521 }
522 return (-1);
523 }
524
525 /*
526 * This routine returns the current version of the named shared library the
527 * program it is running against. The libraryName parameter is the same as
528 * would be static link editor using the -lx or -framework Foo flags (with -lx
529 * it would be "x" and with -framework Foo it would be "Foo"). If the program
530 * is not using the specified library it returns -1.
531 */
532 int32_t NSVersionOfRunTimeLibrary(const char* libraryName)
533 {
534 if ( gUseDyld3 )
535 return dyld3::NSVersionOfRunTimeLibrary(libraryName);
536
537 uint32_t n = _dyld_image_count();
538 for(uint32_t i = 0; i < n; i++){
539 const mach_header* mh = _dyld_get_image_header(i);
540 if ( mh == NULL )
541 continue;
542 if ( mh->filetype != MH_DYLIB )
543 continue;
544 #if __LP64__
545 const load_command* lc = (load_command*)((char*)mh + sizeof(mach_header_64));
546 #else
547 const load_command* lc = (load_command*)((char*)mh + sizeof(mach_header));
548 #endif
549 for(uint32_t j = 0; j < mh->ncmds; j++){
550 if ( lc->cmd == LC_ID_DYLIB ) {
551 const dylib_command* dl = (dylib_command*)lc;
552 const char* install_name = (char *)dl + dl->dylib.name.offset;
553 if ( names_match(install_name, libraryName) )
554 return dl->dylib.current_version;
555 }
556 lc = (load_command*)((char*)lc + lc->cmdsize);
557 }
558 }
559 return (-1);
560 }
561
562 #if TARGET_OS_WATCH
563 uint32_t dyld_get_program_sdk_watch_os_version()
564 {
565 if (gUseDyld3)
566 return dyld3::dyld_get_program_sdk_watch_os_version();
567
568 __block uint32_t retval = 0;
569 __block bool versionFound = false;
570 dyld3::dyld_get_image_versions((mach_header*)_NSGetMachExecuteHeader(), ^(dyld_platform_t platform, uint32_t sdk_version, uint32_t min_version) {
571 if (versionFound) return;
572
573 if (dyld_get_base_platform(platform) == PLATFORM_WATCHOS) {
574 versionFound = true;
575 retval = sdk_version;
576 }
577 });
578
579 return retval;
580 }
581
582 uint32_t dyld_get_program_min_watch_os_version()
583 {
584 if (gUseDyld3)
585 return dyld3::dyld_get_program_min_watch_os_version();
586
587 __block uint32_t retval = 0;
588 __block bool versionFound = false;
589 dyld3::dyld_get_image_versions((mach_header*)_NSGetMachExecuteHeader(), ^(dyld_platform_t platform, uint32_t sdk_version, uint32_t min_version) {
590 if (versionFound) return;
591
592 if (dyld_get_base_platform(platform) == PLATFORM_WATCHOS) {
593 versionFound = true;
594 retval = min_version;
595 }
596 });
597
598 return retval;
599 }
600 #endif
601
602 #if TARGET_OS_BRIDGE
603 uint32_t dyld_get_program_sdk_bridge_os_version()
604 {
605 if (gUseDyld3)
606 return dyld3::dyld_get_program_sdk_bridge_os_version();
607
608 __block uint32_t retval = 0;
609 __block bool versionFound = false;
610 dyld3::dyld_get_image_versions((mach_header*)_NSGetMachExecuteHeader(), ^(dyld_platform_t platform, uint32_t sdk_version, uint32_t min_version) {
611 if (versionFound) return;
612
613 if (dyld_get_base_platform(platform) == PLATFORM_BRIDGEOS) {
614 versionFound = true;
615 retval = sdk_version;
616 }
617 });
618
619 return retval;
620 }
621
622 uint32_t dyld_get_program_min_bridge_os_version()
623 {
624 if (gUseDyld3)
625 return dyld3::dyld_get_program_min_bridge_os_version();
626
627 __block uint32_t retval = 0;
628 __block bool versionFound = false;
629 dyld3::dyld_get_image_versions((mach_header*)_NSGetMachExecuteHeader(), ^(dyld_platform_t platform, uint32_t sdk_version, uint32_t min_version) {
630 if (versionFound) return;
631
632 if (dyld_get_base_platform(platform) == PLATFORM_BRIDGEOS) {
633 versionFound = true;
634 retval = min_version;
635 }
636 });
637
638 return retval;
639 }
640 #endif
641
642 /*
643 * Returns the sdk version (encode as nibble XXXX.YY.ZZ) the
644 * specified binary was built against.
645 *
646 * First looks for LC_VERSION_MIN_* in binary and if sdk field is
647 * not zero, return that value.
648 * Otherwise, looks for the libSystem.B.dylib the binary linked
649 * against and uses a table to convert that to an sdk version.
650 */
651 uint32_t dyld_get_sdk_version(const mach_header* mh)
652 {
653 return dyld3::dyld_get_sdk_version(mh);
654 }
655
656 uint32_t dyld_get_program_sdk_version()
657 {
658 return dyld3::dyld_get_sdk_version((mach_header*)_NSGetMachExecuteHeader());
659 }
660
661 uint32_t dyld_get_min_os_version(const struct mach_header* mh)
662 {
663 return dyld3::dyld_get_min_os_version(mh);
664 }
665
666
667 uint32_t dyld_get_program_min_os_version()
668 {
669 return dyld3::dyld_get_min_os_version((mach_header*)_NSGetMachExecuteHeader());
670 }
671
672
673 bool _dyld_get_image_uuid(const struct mach_header* mh, uuid_t uuid)
674 {
675 if ( gUseDyld3 )
676 return dyld3::_dyld_get_image_uuid(mh, uuid);
677
678 const load_command* startCmds = NULL;
679 if ( mh->magic == MH_MAGIC_64 )
680 startCmds = (load_command*)((char *)mh + sizeof(mach_header_64));
681 else if ( mh->magic == MH_MAGIC )
682 startCmds = (load_command*)((char *)mh + sizeof(mach_header));
683 else
684 return false; // not a mach-o file, or wrong endianness
685
686 const load_command* const cmdsEnd = (load_command*)((char*)startCmds + mh->sizeofcmds);
687 const load_command* cmd = startCmds;
688 for(uint32_t i = 0; i < mh->ncmds; ++i) {
689 const load_command* nextCmd = (load_command*)((char *)cmd + cmd->cmdsize);
690 if ( (cmd->cmdsize < 8) || (nextCmd > cmdsEnd) || (nextCmd < startCmds)) {
691 return false;
692 }
693 if ( cmd->cmd == LC_UUID ) {
694 const uuid_command* uuidCmd = (uuid_command*)cmd;
695 memcpy(uuid, uuidCmd->uuid, 16);
696 return true;
697 }
698 cmd = nextCmd;
699 }
700 bzero(uuid, 16);
701 return false;
702 }
703
704 dyld_platform_t dyld_get_active_platform(void) {
705 if (gUseDyld3)
706 return dyld3::dyld_get_active_platform();
707
708 return (dyld_platform_t)_dyld_get_all_image_infos()->platform;
709 }
710
711 dyld_platform_t dyld_get_base_platform(dyld_platform_t platform) {
712 return dyld3::dyld_get_base_platform(platform);
713 }
714
715 bool dyld_is_simulator_platform(dyld_platform_t platform) {
716 return dyld3::dyld_is_simulator_platform(platform);
717 }
718
719 bool dyld_sdk_at_least(const struct mach_header* mh, dyld_build_version_t version) {
720 return dyld3::dyld_sdk_at_least(mh, version);
721 }
722
723 bool dyld_minos_at_least(const struct mach_header* mh, dyld_build_version_t version) {
724 return dyld3::dyld_minos_at_least(mh, version);
725 }
726
727 bool dyld_program_sdk_at_least(dyld_build_version_t version) {
728 return dyld3::dyld_program_sdk_at_least(version);
729 }
730
731 bool dyld_program_minos_at_least(dyld_build_version_t version) {
732 return dyld3::dyld_program_minos_at_least(version);
733 }
734
735 // Function that walks through the load commands and calls the internal block for every version found
736 // Intended as a fallback for very complex (and rare) version checks, or for tools that need to
737 // print our everything for diagnostic reasons
738 void dyld_get_image_versions(const struct mach_header* mh, void (^callback)(dyld_platform_t platform, uint32_t sdk_version, uint32_t min_version)) {
739 dyld3::dyld_get_image_versions(mh, callback);
740 }
741
742
743
744 #if DEPRECATED_APIS_SUPPORTED
745 /*
746 * NSCreateObjectFileImageFromFile() creates an NSObjectFileImage for the
747 * specified file name if the file is a correct Mach-O file that can be loaded
748 * with NSloadModule(). For return codes of NSObjectFileImageFailure and
749 * NSObjectFileImageFormat an error message is printed to stderr. All
750 * other codes cause no printing.
751 */
752 NSObjectFileImageReturnCode
753 NSCreateObjectFileImageFromFile(
754 const char* pathName,
755 NSObjectFileImage *objectFileImage)
756 {
757 if ( gUseDyld3 )
758 return dyld3::NSCreateObjectFileImageFromFile(pathName, objectFileImage);
759
760 DYLD_LOCK_THIS_BLOCK;
761 typedef NSObjectFileImageReturnCode (*funcType)(const char*, NSObjectFileImage*);
762 static funcType __ptrauth_dyld_function_ptr p = NULL;
763
764 if(p == NULL)
765 dyld_func_lookup_and_resign("__dyld_NSCreateObjectFileImageFromFile", &p);
766 return p(pathName, objectFileImage);
767 }
768
769
770 /*
771 * NSCreateObjectFileImageFromMemory() creates an NSObjectFileImage for the
772 * object file mapped into memory at address of size length if the object file
773 * is a correct Mach-O file that can be loaded with NSloadModule(). For return
774 * codes of NSObjectFileImageFailure and NSObjectFileImageFormat an error
775 * message is printed to stderr. All other codes cause no printing.
776 */
777 NSObjectFileImageReturnCode
778 NSCreateObjectFileImageFromMemory(
779 const void* address,
780 size_t size,
781 NSObjectFileImage *objectFileImage)
782 {
783 // <rdar://problem/51812762> NSCreatObjectFileImageFromMemory fail opaquely if Hardened runtime is enabled
784 uint32_t flags;
785 if ( csops(0, CS_OPS_STATUS, &flags, sizeof(flags)) != -1 ) {
786 if ( (flags & (CS_ENFORCEMENT|CS_KILL)) == (CS_ENFORCEMENT|CS_KILL) ) {
787 //fprintf(stderr, "dyld: warning: NSCreatObjectFileImageFromMemory() cannot be used in harden process 0x%08X\n", flags);
788 return NSObjectFileImageAccess;
789 }
790 }
791
792 if ( gUseDyld3 )
793 return dyld3::NSCreateObjectFileImageFromMemory(address, size, objectFileImage);
794
795 DYLD_LOCK_THIS_BLOCK;
796 typedef NSObjectFileImageReturnCode (*funcType)(const void*, size_t, NSObjectFileImage*);
797 static funcType __ptrauth_dyld_function_ptr p = NULL;
798
799 if(p == NULL)
800 dyld_func_lookup_and_resign("__dyld_NSCreateObjectFileImageFromMemory", &p);
801 return p(address, size, objectFileImage);
802 }
803
804 #if OBSOLETE_DYLD_API
805 /*
806 * NSCreateCoreFileImageFromFile() creates an NSObjectFileImage for the
807 * specified core file name if the file is a correct Mach-O core file.
808 * For return codes of NSObjectFileImageFailure and NSObjectFileImageFormat
809 * an error message is printed to stderr. All other codes cause no printing.
810 */
811 NSObjectFileImageReturnCode
812 NSCreateCoreFileImageFromFile(
813 const char* pathName,
814 NSObjectFileImage *objectFileImage)
815 {
816 DYLD_LOCK_THIS_BLOCK;
817 typedef NSObjectFileImageReturnCode (*funcType)(const char*, NSObjectFileImage*) = NULL;
818
819 if(p == NULL)
820 dyld_func_lookup_and_resign("__dyld_NSCreateCoreFileImageFromFile", &p);
821 return p(pathName, objectFileImage);
822 }
823 #endif
824
825 bool
826 NSDestroyObjectFileImage(
827 NSObjectFileImage objectFileImage)
828 {
829 if ( gUseDyld3 )
830 return dyld3::NSDestroyObjectFileImage(objectFileImage);
831
832 DYLD_LOCK_THIS_BLOCK;
833 typedef bool (*funcType)(NSObjectFileImage);
834 static funcType __ptrauth_dyld_function_ptr p = NULL;
835
836 if(p == NULL)
837 dyld_func_lookup_and_resign("__dyld_NSDestroyObjectFileImage", &p);
838 return p(objectFileImage);
839 }
840
841
842 NSModule
843 NSLinkModule(
844 NSObjectFileImage objectFileImage,
845 const char* moduleName,
846 uint32_t options)
847 {
848 if ( gUseDyld3 )
849 return dyld3::NSLinkModule(objectFileImage, moduleName, options);
850
851 DYLD_LOCK_THIS_BLOCK;
852 typedef NSModule (*funcType)(NSObjectFileImage, const char*, unsigned long);
853 static funcType __ptrauth_dyld_function_ptr p = NULL;
854
855 if(p == NULL)
856 dyld_func_lookup_and_resign("__dyld_NSLinkModule", &p);
857
858 return p(objectFileImage, moduleName, options);
859 }
860
861
862
863
864 /*
865 * NSSymbolDefinitionCountInObjectFileImage() returns the number of symbol
866 * definitions in the NSObjectFileImage.
867 */
868 uint32_t
869 NSSymbolDefinitionCountInObjectFileImage(
870 NSObjectFileImage objectFileImage)
871 {
872 if ( gUseDyld3 )
873 return dyld3::NSSymbolDefinitionCountInObjectFileImage(objectFileImage);
874
875 DYLD_LOCK_THIS_BLOCK;
876 typedef uint32_t (*funcType)(NSObjectFileImage);
877 static funcType __ptrauth_dyld_function_ptr p = NULL;
878
879 if(p == NULL)
880 dyld_func_lookup_and_resign("__dyld_NSSymbolDefinitionCountInObjectFileImage", &p);
881
882 return p(objectFileImage);
883 }
884
885 /*
886 * NSSymbolDefinitionNameInObjectFileImage() returns the name of the i'th
887 * symbol definitions in the NSObjectFileImage. If the ordinal specified is
888 * outside the range [0..NSSymbolDefinitionCountInObjectFileImage], NULL will
889 * be returned.
890 */
891 const char*
892 NSSymbolDefinitionNameInObjectFileImage(
893 NSObjectFileImage objectFileImage,
894 uint32_t ordinal)
895 {
896 if ( gUseDyld3 )
897 return dyld3::NSSymbolDefinitionNameInObjectFileImage(objectFileImage, ordinal);
898
899 DYLD_LOCK_THIS_BLOCK;
900 typedef const char* (*funcType)(NSObjectFileImage, uint32_t);
901 static funcType __ptrauth_dyld_function_ptr p = NULL;
902
903 if(p == NULL)
904 dyld_func_lookup_and_resign("__dyld_NSSymbolDefinitionNameInObjectFileImage", &p);
905
906 return p(objectFileImage, ordinal);
907 }
908
909 /*
910 * NSSymbolReferenceCountInObjectFileImage() returns the number of references
911 * to undefined symbols the NSObjectFileImage.
912 */
913 uint32_t
914 NSSymbolReferenceCountInObjectFileImage(
915 NSObjectFileImage objectFileImage)
916 {
917 if ( gUseDyld3 )
918 return dyld3::NSSymbolReferenceCountInObjectFileImage(objectFileImage);
919
920 DYLD_LOCK_THIS_BLOCK;
921 typedef uint32_t (*funcType)(NSObjectFileImage);
922 static funcType __ptrauth_dyld_function_ptr p = NULL;
923
924 if(p == NULL)
925 dyld_func_lookup_and_resign("__dyld_NSSymbolReferenceCountInObjectFileImage", &p);
926
927 return p(objectFileImage);
928 }
929
930 /*
931 * NSSymbolReferenceNameInObjectFileImage() returns the name of the i'th
932 * undefined symbol in the NSObjectFileImage. If the ordinal specified is
933 * outside the range [0..NSSymbolReferenceCountInObjectFileImage], NULL will be
934 * returned.
935 */
936 const char*
937 NSSymbolReferenceNameInObjectFileImage(
938 NSObjectFileImage objectFileImage,
939 uint32_t ordinal,
940 bool *tentative_definition) /* can be NULL */
941 {
942 if ( gUseDyld3 )
943 return dyld3::NSSymbolReferenceNameInObjectFileImage(objectFileImage, ordinal, tentative_definition);
944
945 DYLD_LOCK_THIS_BLOCK;
946 typedef const char* (*funcType)(NSObjectFileImage, uint32_t, bool*);
947 static funcType __ptrauth_dyld_function_ptr p = NULL;
948
949 if(p == NULL)
950 dyld_func_lookup_and_resign("__dyld_NSSymbolReferenceNameInObjectFileImage", &p);
951
952 return p(objectFileImage, ordinal, tentative_definition);
953 }
954
955 /*
956 * NSIsSymbolDefinedInObjectFileImage() returns TRUE if the specified symbol
957 * name has a definition in the NSObjectFileImage and FALSE otherwise.
958 */
959 bool
960 NSIsSymbolDefinedInObjectFileImage(
961 NSObjectFileImage objectFileImage,
962 const char* symbolName)
963 {
964 if ( gUseDyld3 )
965 return dyld3::NSIsSymbolDefinedInObjectFileImage(objectFileImage, symbolName);
966
967 DYLD_LOCK_THIS_BLOCK;
968 typedef bool (*funcType)(NSObjectFileImage, const char*);
969 static funcType __ptrauth_dyld_function_ptr p = NULL;
970
971 if(p == NULL)
972 dyld_func_lookup_and_resign("__dyld_NSIsSymbolDefinedInObjectFileImage", &p);
973
974 return p(objectFileImage, symbolName);
975 }
976
977 /*
978 * NSGetSectionDataInObjectFileImage() returns a pointer to the section contents
979 * in the NSObjectFileImage for the specified segmentName and sectionName if
980 * it exists and it is not a zerofill section. If not it returns NULL. If
981 * the parameter size is not NULL the size of the section is also returned
982 * indirectly through that pointer.
983 */
984 void *
985 NSGetSectionDataInObjectFileImage(
986 NSObjectFileImage objectFileImage,
987 const char* segmentName,
988 const char* sectionName,
989 unsigned long *size) /* can be NULL */
990 {
991 if ( gUseDyld3 )
992 return dyld3::NSGetSectionDataInObjectFileImage(objectFileImage, segmentName, sectionName, size);
993
994 DYLD_LOCK_THIS_BLOCK;
995 typedef void* (*funcType)(NSObjectFileImage, const char*, const char*, unsigned long*);
996 static funcType __ptrauth_dyld_function_ptr p = NULL;
997
998 if(p == NULL)
999 dyld_func_lookup_and_resign("__dyld_NSGetSectionDataInObjectFileImage", &p);
1000
1001 return p(objectFileImage, segmentName, sectionName, size);
1002 }
1003
1004
1005 void
1006 NSLinkEditError(
1007 NSLinkEditErrors *c,
1008 int *errorNumber,
1009 const char* *fileName,
1010 const char* *errorString)
1011 {
1012 if ( gUseDyld3 )
1013 return dyld3::NSLinkEditError(c, errorNumber, fileName, errorString);
1014
1015 DYLD_LOCK_THIS_BLOCK;
1016 typedef void (*funcType)(NSLinkEditErrors *c,
1017 int *errorNumber,
1018 const char* *fileName,
1019 const char* *errorString);
1020 static funcType __ptrauth_dyld_function_ptr p = NULL;
1021
1022 if(p == NULL)
1023 dyld_func_lookup_and_resign("__dyld_link_edit_error", &p);
1024 if(p != NULL)
1025 p(c, errorNumber, fileName, errorString);
1026 }
1027
1028 bool
1029 NSUnLinkModule(
1030 NSModule module,
1031 uint32_t options)
1032 {
1033 if ( gUseDyld3 )
1034 return dyld3::NSUnLinkModule(module, options);
1035
1036 DYLD_LOCK_THIS_BLOCK;
1037 typedef bool (*funcType)(NSModule module, uint32_t options);
1038 static funcType __ptrauth_dyld_function_ptr p = NULL;
1039
1040 if(p == NULL)
1041 dyld_func_lookup_and_resign("__dyld_unlink_module", &p);
1042
1043 return p(module, options);
1044 }
1045
1046 #if OBSOLETE_DYLD_API
1047 NSModule
1048 NSReplaceModule(
1049 NSModule moduleToReplace,
1050 NSObjectFileImage newObjectFileImage,
1051 uint32_t options)
1052 {
1053 return(NULL);
1054 }
1055 #endif
1056
1057
1058 #endif // DEPRECATED_APIS_SUPPORTED
1059
1060 /*
1061 *_NSGetExecutablePath copies the path of the executable into the buffer and
1062 * returns 0 if the path was successfully copied in the provided buffer. If the
1063 * buffer is not large enough, -1 is returned and the expected buffer size is
1064 * copied in *bufsize. Note that _NSGetExecutablePath will return "a path" to
1065 * the executable not a "real path" to the executable. That is the path may be
1066 * a symbolic link and not the real file. And with deep directories the total
1067 * bufsize needed could be more than MAXPATHLEN.
1068 */
1069 int
1070 _NSGetExecutablePath(
1071 char *buf,
1072 uint32_t *bufsize)
1073 {
1074 if ( gUseDyld3 )
1075 return dyld3::_NSGetExecutablePath(buf, bufsize);
1076
1077 DYLD_NO_LOCK_THIS_BLOCK;
1078 typedef int (*funcType)(char *buf, uint32_t *bufsize);
1079 static funcType __ptrauth_dyld_function_ptr p = NULL;
1080
1081 if(p == NULL)
1082 dyld_func_lookup_and_resign("__dyld__NSGetExecutablePath", &p);
1083 return(p(buf, bufsize));
1084 }
1085
1086 #if DEPRECATED_APIS_SUPPORTED
1087 void
1088 _dyld_lookup_and_bind(
1089 const char* symbol_name,
1090 void** address,
1091 NSModule* module)
1092 {
1093 if ( gUseDyld3 )
1094 return dyld3::_dyld_lookup_and_bind(symbol_name, address, module);
1095
1096 DYLD_LOCK_THIS_BLOCK;
1097 typedef void (*funcType)(const char*, void** , NSModule*);
1098 static funcType __ptrauth_dyld_function_ptr p = NULL;
1099
1100 if(p == NULL)
1101 dyld_func_lookup_and_resign("__dyld_lookup_and_bind", &p);
1102 p(symbol_name, address, module);
1103 }
1104
1105 void
1106 _dyld_lookup_and_bind_with_hint(
1107 const char* symbol_name,
1108 const char* library_name_hint,
1109 void** address,
1110 NSModule* module)
1111 {
1112 DYLD_LOCK_THIS_BLOCK;
1113 typedef void (*funcType)(const char*, const char*, void**, NSModule*);
1114 static funcType __ptrauth_dyld_function_ptr p = NULL;
1115
1116 if(p == NULL)
1117 dyld_func_lookup_and_resign("__dyld_lookup_and_bind_with_hint", &p);
1118 p(symbol_name, library_name_hint, address, module);
1119 }
1120
1121 #if OBSOLETE_DYLD_API
1122 void
1123 _dyld_lookup_and_bind_objc(
1124 const char* symbol_name,
1125 void** address,
1126 NSModule* module)
1127 {
1128 DYLD_LOCK_THIS_BLOCK;
1129 typedef void (*funcType)(const char* , void**, NSModule*) = NULL;
1130
1131 if(p == NULL)
1132 dyld_func_lookup_and_resign("__dyld_lookup_and_bind_objc", &p);
1133 p(symbol_name, address, module);
1134 }
1135 #endif
1136
1137 void
1138 _dyld_lookup_and_bind_fully(
1139 const char* symbol_name,
1140 void** address,
1141 NSModule* module)
1142 {
1143 DYLD_LOCK_THIS_BLOCK;
1144 typedef void (*funcType)(const char*, void**, NSModule*);
1145 static funcType __ptrauth_dyld_function_ptr p = NULL;
1146
1147 if(p == NULL)
1148 dyld_func_lookup_and_resign("__dyld_lookup_and_bind_fully", &p);
1149 p(symbol_name, address, module);
1150 }
1151
1152 bool
1153 _dyld_bind_fully_image_containing_address(
1154 const void* address)
1155 {
1156 DYLD_LOCK_THIS_BLOCK;
1157 typedef bool (*funcType)(const void*);
1158 static funcType __ptrauth_dyld_function_ptr p = NULL;
1159
1160 if(p == NULL)
1161 dyld_func_lookup_and_resign("__dyld_bind_fully_image_containing_address", &p);
1162 return p(address);
1163 }
1164 #endif // DEPRECATED_APIS_SUPPORTED
1165
1166
1167 /*
1168 * _dyld_register_func_for_add_image registers the specified function to be
1169 * called when a new image is added (a bundle or a dynamic shared library) to
1170 * the program. When this function is first registered it is called for once
1171 * for each image that is currently part of the program.
1172 */
1173 void
1174 _dyld_register_func_for_add_image(
1175 void (*func)(const struct mach_header *mh, intptr_t vmaddr_slide))
1176 {
1177 if ( gUseDyld3 )
1178 return dyld3::_dyld_register_func_for_add_image(func);
1179
1180 DYLD_LOCK_THIS_BLOCK;
1181 // Func must be a "void *" because dyld itself calls it. DriverKit
1182 // libdyld.dylib uses diversified C function pointers but its dyld (the
1183 // plain OS one) doesn't, so it must be resigned with 0 discriminator.
1184 typedef void (*funcType)(void *func);
1185 static funcType __ptrauth_dyld_function_ptr p = NULL;
1186
1187 if(p == NULL)
1188 dyld_func_lookup_and_resign("__dyld_register_func_for_add_image", &p);
1189 p(reinterpret_cast<void *>(func));
1190 }
1191
1192 /*
1193 * _dyld_register_func_for_remove_image registers the specified function to be
1194 * called when an image is removed (a bundle or a dynamic shared library) from
1195 * the program.
1196 */
1197 void
1198 _dyld_register_func_for_remove_image(
1199 void (*func)(const struct mach_header *mh, intptr_t vmaddr_slide))
1200 {
1201 if ( gUseDyld3 )
1202 return dyld3::_dyld_register_func_for_remove_image(func);
1203
1204 DYLD_LOCK_THIS_BLOCK;
1205 // Func must be a "void *" because dyld itself calls it. DriverKit
1206 // libdyld.dylib uses diversified C function pointers but its dyld (the
1207 // plain OS one) doesn't, so it must be resigned with 0 discriminator.
1208 typedef void (*funcType)(void *func);
1209 static funcType __ptrauth_dyld_function_ptr p = NULL;
1210
1211 if(p == NULL)
1212 dyld_func_lookup_and_resign("__dyld_register_func_for_remove_image", &p);
1213 p(reinterpret_cast<void *>(func));
1214 }
1215
1216 #if OBSOLETE_DYLD_API
1217 /*
1218 * _dyld_register_func_for_link_module registers the specified function to be
1219 * called when a module is bound into the program. When this function is first
1220 * registered it is called for once for each module that is currently bound into
1221 * the program.
1222 */
1223 void
1224 _dyld_register_func_for_link_module(
1225 void (*func)(NSModule module))
1226 {
1227 DYLD_LOCK_THIS_BLOCK;
1228 // Func must be a "void *" because dyld itself calls it. DriverKit
1229 // libdyld.dylib uses diversified C function pointers but its dyld (the
1230 // plain OS one) doesn't, so it must be resigned with 0 discriminator.
1231 static void (*funcType)(void *func) = NULL;
1232
1233 if(p == NULL)
1234 dyld_func_lookup_and_resign("__dyld_register_func_for_link_module", &p);
1235 p(reinterpret_cast<void *>(func));
1236 }
1237
1238 /*
1239 * _dyld_register_func_for_unlink_module registers the specified function to be
1240 * called when a module is unbound from the program.
1241 */
1242 void
1243 _dyld_register_func_for_unlink_module(
1244 void (*func)(NSModule module))
1245 {
1246 DYLD_LOCK_THIS_BLOCK;
1247 // Func must be a "void *" because dyld itself calls it. DriverKit
1248 // libdyld.dylib uses diversified C function pointers but its dyld (the
1249 // plain OS one) doesn't, so it must be resigned with 0 discriminator.
1250 static void (*funcType)(void *func) = NULL;
1251
1252 if(p == NULL)
1253 dyld_func_lookup_and_resign("__dyld_register_func_for_unlink_module", &p);
1254 p(reinterpret_cast<void *>(func));
1255 }
1256
1257 /*
1258 * _dyld_register_func_for_replace_module registers the specified function to be
1259 * called when a module is to be replace with another module in the program.
1260 */
1261 void
1262 _dyld_register_func_for_replace_module(
1263 void (*func)(NSModule oldmodule, NSModule newmodule))
1264 {
1265 DYLD_LOCK_THIS_BLOCK;
1266 // Func must be a "void *" because dyld itself calls it. DriverKit
1267 // libdyld.dylib uses diversified C function pointers but its dyld (the
1268 // plain OS one) doesn't, so it must be resigned with 0 discriminator.
1269 typedef void (*funcType)(void *func) = NULL;
1270
1271 if(p == NULL)
1272 dyld_func_lookup_and_resign("__dyld_register_func_for_replace_module", &p);
1273 p(reinterpret_cast<void *>(func));
1274 }
1275
1276
1277 /*
1278 * _dyld_get_objc_module_sect_for_module is passed a module and sets a
1279 * pointer to the (__OBJC,__module) section and its size for the specified
1280 * module.
1281 */
1282 void
1283 _dyld_get_objc_module_sect_for_module(
1284 NSModule module,
1285 void **objc_module,
1286 unsigned long *size)
1287 {
1288 DYLD_LOCK_THIS_BLOCK;
1289 typedef void (*funcType)(NSModule module,
1290 void **objc_module,
1291 unsigned long *size) = NULL;
1292
1293 if(p == NULL)
1294 dyld_func_lookup_and_resign("__dyld_get_objc_module_sect_for_module", &p);
1295 p(module, objc_module, size);
1296 }
1297
1298 #endif
1299
1300 #if DEPRECATED_APIS_SUPPORTED
1301 bool
1302 _dyld_present(void)
1303 {
1304 // this function exists for compatiblity only
1305 return true;
1306 }
1307 #endif
1308
1309 uint32_t
1310 _dyld_image_count(void)
1311 {
1312 if ( gUseDyld3 )
1313 return dyld3::_dyld_image_count();
1314
1315 DYLD_NO_LOCK_THIS_BLOCK;
1316 typedef uint32_t (*funcType)(void);
1317 static funcType __ptrauth_dyld_function_ptr p = NULL;
1318
1319 if(p == NULL)
1320 dyld_func_lookup_and_resign("__dyld_image_count", &p);
1321 return(p());
1322 }
1323
1324 const struct mach_header *
1325 _dyld_get_image_header(uint32_t image_index)
1326 {
1327 if ( gUseDyld3 )
1328 return dyld3::_dyld_get_image_header(image_index);
1329
1330 DYLD_NO_LOCK_THIS_BLOCK;
1331 typedef struct mach_header * (*funcType)(uint32_t image_index);
1332 static funcType __ptrauth_dyld_function_ptr p = NULL;
1333
1334 if(p == NULL)
1335 dyld_func_lookup_and_resign("__dyld_get_image_header", &p);
1336 return(p(image_index));
1337 }
1338
1339 intptr_t
1340 _dyld_get_image_vmaddr_slide(uint32_t image_index)
1341 {
1342 if ( gUseDyld3 )
1343 return dyld3::_dyld_get_image_vmaddr_slide(image_index);
1344
1345 DYLD_NO_LOCK_THIS_BLOCK;
1346 typedef unsigned long (*funcType)(uint32_t image_index);
1347 static funcType __ptrauth_dyld_function_ptr p = NULL;
1348
1349 if(p == NULL)
1350 dyld_func_lookup_and_resign("__dyld_get_image_vmaddr_slide", &p);
1351 return(p(image_index));
1352 }
1353
1354 const char*
1355 _dyld_get_image_name(uint32_t image_index)
1356 {
1357 if ( gUseDyld3 )
1358 return dyld3::_dyld_get_image_name(image_index);
1359
1360 DYLD_NO_LOCK_THIS_BLOCK;
1361 typedef const char* (*funcType)(uint32_t image_index);
1362 static funcType __ptrauth_dyld_function_ptr p = NULL;
1363
1364 if(p == NULL)
1365 dyld_func_lookup_and_resign("__dyld_get_image_name", &p);
1366 return(p(image_index));
1367 }
1368
1369 // SPI in Mac OS X 10.6
1370 intptr_t _dyld_get_image_slide(const struct mach_header* mh)
1371 {
1372 // always use dyld3 version because it does better error handling
1373 return dyld3::_dyld_get_image_slide(mh);
1374 }
1375
1376 const struct mach_header *
1377 _dyld_get_prog_image_header()
1378 {
1379 if ( gUseDyld3 )
1380 return dyld3::_dyld_get_prog_image_header();
1381
1382 DYLD_LOCK_THIS_BLOCK;
1383 typedef const struct mach_header * (*funcType)(void);
1384 static funcType __ptrauth_dyld_function_ptr p = NULL;
1385
1386 if(p == NULL)
1387 dyld_func_lookup_and_resign("__dyld_get_prog_image_header", &p);
1388 return p();
1389 }
1390
1391 #if DEPRECATED_APIS_SUPPORTED
1392 bool
1393 _dyld_image_containing_address(const void* address)
1394 {
1395 if ( gUseDyld3 )
1396 return dyld3::_dyld_image_containing_address(address);
1397
1398 DYLD_LOCK_THIS_BLOCK;
1399 typedef bool (*funcType)(const void*);
1400 static funcType __ptrauth_dyld_function_ptr p = NULL;
1401
1402 if(p == NULL)
1403 dyld_func_lookup_and_resign("__dyld_image_containing_address", &p);
1404 return(p(address));
1405 }
1406
1407 const struct mach_header *
1408 _dyld_get_image_header_containing_address(
1409 const void* address)
1410 {
1411 if ( gUseDyld3 )
1412 return dyld3::_dyld_get_image_header_containing_address(address);
1413
1414 DYLD_LOCK_THIS_BLOCK;
1415 typedef const struct mach_header * (*funcType)(const void*);
1416 static funcType __ptrauth_dyld_function_ptr p = NULL;
1417
1418 if(p == NULL)
1419 dyld_func_lookup_and_resign("__dyld_get_image_header_containing_address", &p);
1420 return p(address);
1421 }
1422
1423 bool _dyld_launched_prebound(void)
1424 {
1425 DYLD_LOCK_THIS_BLOCK;
1426 typedef bool (*funcType)(void);
1427 static funcType __ptrauth_dyld_function_ptr p = NULL;
1428
1429 if(p == NULL)
1430 dyld_func_lookup_and_resign("__dyld_launched_prebound", &p);
1431 return(p());
1432 }
1433
1434 bool _dyld_all_twolevel_modules_prebound(void)
1435 {
1436 DYLD_LOCK_THIS_BLOCK;
1437 typedef bool (*funcType)(void);
1438 static funcType __ptrauth_dyld_function_ptr p = NULL;
1439
1440 if(p == NULL)
1441 dyld_func_lookup_and_resign("__dyld_all_twolevel_modules_prebound", &p);
1442 return(p());
1443 }
1444 #endif // DEPRECATED_APIS_SUPPORTED
1445
1446
1447 #include <dlfcn_private.h>
1448 #include <stddef.h>
1449 #include <pthread.h>
1450 #include <stdlib.h>
1451 #include <mach-o/dyld.h>
1452 #include "dyldLibSystemInterface.h"
1453
1454
1455 // pthread key used to access per-thread dlerror message
1456 static pthread_key_t dlerrorPerThreadKey;
1457 static bool dlerrorPerThreadKeyInitialized = false;
1458
1459 // data kept per-thread
1460 struct dlerrorPerThreadData
1461 {
1462 size_t sizeAllocated;
1463 char message[1];
1464 };
1465
1466 // function called by dyld to get buffer to store dlerror message
1467 static char* getPerThreadBufferFor_dlerror(size_t sizeRequired)
1468 {
1469 // ok to create key lazily because this function is called within dyld lock, so there is no race condition
1470 if (!dlerrorPerThreadKeyInitialized ) {
1471 // create key and tell pthread package to call free() on any data associated with key if thread dies
1472 pthread_key_create(&dlerrorPerThreadKey, &free);
1473 dlerrorPerThreadKeyInitialized = true;
1474 }
1475
1476 const size_t size = (sizeRequired < 256) ? 256 : sizeRequired;
1477 dlerrorPerThreadData* data = (dlerrorPerThreadData*)pthread_getspecific(dlerrorPerThreadKey);
1478 if ( data == NULL ) {
1479 //int mallocSize = offsetof(dlerrorPerThreadData, message[size]);
1480 const size_t mallocSize = sizeof(dlerrorPerThreadData)+size;
1481 data = (dlerrorPerThreadData*)malloc(mallocSize);
1482 data->sizeAllocated = size;
1483 pthread_setspecific(dlerrorPerThreadKey, data);
1484 }
1485 else if ( data->sizeAllocated < sizeRequired ) {
1486 free(data);
1487 //int mallocSize = offsetof(dlerrorPerThreadData, message[size]);
1488 const size_t mallocSize = sizeof(dlerrorPerThreadData)+size;
1489 data = (dlerrorPerThreadData*)malloc(mallocSize);
1490 data->sizeAllocated = size;
1491 pthread_setspecific(dlerrorPerThreadKey, data);
1492 }
1493 return data->message;
1494 }
1495
1496 // <rdar://problem/10595338> dlerror buffer leak
1497 // Only allocate buffer if an actual error message needs to be set
1498 static bool hasPerThreadBufferFor_dlerror()
1499 {
1500 if (!dlerrorPerThreadKeyInitialized )
1501 return false;
1502
1503 return (pthread_getspecific(dlerrorPerThreadKey) != NULL);
1504 }
1505
1506 #if TARGET_OS_DRIVERKIT
1507 static bool isLaunchdOwned()
1508 {
1509 return false;
1510 }
1511 #else
1512 // use non-lazy pointer to vproc_swap_integer so that lazy binding does not recurse
1513 typedef vproc_err_t (*vswapproc)(vproc_t vp, vproc_gsk_t key,int64_t *inval, int64_t *outval);
1514 static vswapproc swapProc = &vproc_swap_integer;
1515
1516 static bool isLaunchdOwned()
1517 {
1518 static bool checked = false;
1519 static bool result = false;
1520 if ( !checked ) {
1521 checked = true;
1522 int64_t val = 0;
1523 (*swapProc)(NULL, VPROC_GSK_IS_MANAGED, NULL, &val);
1524 result = ( val != 0 );
1525 }
1526 return result;
1527 }
1528 #endif
1529
1530 static void shared_cache_missing()
1531 {
1532 // leave until dyld's that might call this are rare
1533 }
1534
1535 static void shared_cache_out_of_date()
1536 {
1537 // leave until dyld's that might call this are rare
1538 }
1539
1540 // FIXME: This is a mess. Why can't Driverkit have its own dyld?
1541 static int cxa_atexit_thunk(void (*func)(void *), void *arg, void *dso)
1542 {
1543 // Func will have come from dyld and so be signed with 0 discriminator,
1544 // resign it appropriately before passing to the real __cxa_atexit.
1545 func = ptrauth_auth_and_resign(func, ptrauth_key_function_pointer, 0,
1546 ptrauth_key_function_pointer,
1547 ptrauth_function_pointer_type_discriminator(__typeof__(func)));
1548 return __cxa_atexit(func, arg, dso);
1549 }
1550
1551 template<typename FTy> static FTy *resign_for_dyld(FTy *func) {
1552 return ptrauth_auth_and_resign(func, ptrauth_key_function_pointer,
1553 ptrauth_function_pointer_type_discriminator(__typeof__(func)),
1554 ptrauth_key_function_pointer, 0);
1555 }
1556
1557
1558 // the table passed to dyld containing thread helpers
1559 static dyld::LibSystemHelpers sHelpers = { 13 };
1560
1561 static const objc_opt::objc_opt_t* gObjCOpt = nullptr;
1562 //
1563 // during initialization of libSystem this routine will run
1564 // and call dyld, registering the helper functions.
1565 //
1566 extern "C" void tlv_initializer();
1567 void _dyld_initializer()
1568 {
1569 sHelpers.acquireGlobalDyldLock = resign_for_dyld(&dyldGlobalLockAcquire);
1570 sHelpers.releaseGlobalDyldLock = resign_for_dyld(&dyldGlobalLockRelease);
1571 sHelpers.getThreadBufferFor_dlerror = resign_for_dyld(&getPerThreadBufferFor_dlerror);
1572 sHelpers.malloc = resign_for_dyld(&malloc);
1573 sHelpers.free = resign_for_dyld(&free);
1574 sHelpers.cxa_atexit = resign_for_dyld(&cxa_atexit_thunk);
1575 sHelpers.dyld_shared_cache_missing = resign_for_dyld(&shared_cache_missing);
1576 sHelpers.dyld_shared_cache_out_of_date = resign_for_dyld(&shared_cache_out_of_date);
1577 sHelpers.acquireDyldInitializerLock = NULL;
1578 sHelpers.releaseDyldInitializerLock = NULL;
1579 sHelpers.pthread_key_create = resign_for_dyld(&pthread_key_create);
1580 sHelpers.pthread_setspecific = resign_for_dyld(&pthread_setspecific);
1581 sHelpers.malloc_size = resign_for_dyld(&malloc_size);
1582 sHelpers.pthread_getspecific = resign_for_dyld(&pthread_getspecific);
1583 sHelpers.cxa_finalize = resign_for_dyld(&__cxa_finalize);
1584 sHelpers.startGlueToCallExit = address_of_start;
1585 sHelpers.hasPerThreadBufferFor_dlerror = resign_for_dyld(&hasPerThreadBufferFor_dlerror);
1586 sHelpers.isLaunchdOwned = resign_for_dyld(&isLaunchdOwned);
1587 sHelpers.vm_alloc = resign_for_dyld(&vm_allocate);
1588 sHelpers.mmap = resign_for_dyld(&mmap);
1589 sHelpers.cxa_finalize_ranges = resign_for_dyld(&__cxa_finalize_ranges);
1590
1591 typedef void (*funcType)(dyld::LibSystemHelpers*);
1592 static funcType __ptrauth_dyld_function_ptr p = NULL;
1593
1594 // Get the optimized objc pointer now that the cache is loaded
1595 const dyld_all_image_infos* allInfo = _dyld_get_all_image_infos();
1596 if ( allInfo != nullptr ) {
1597 const DyldSharedCache* cache = (const DyldSharedCache*)(allInfo->sharedCacheBaseAddress);
1598 if ( cache != nullptr )
1599 gObjCOpt = cache->objcOpt();
1600 }
1601
1602 if ( gUseDyld3 ) {
1603 dyld3::gAllImages.applyInitialImages();
1604 #if TARGET_OS_IOS && !TARGET_OS_SIMULATOR
1605 // For binaries built before 13.0, set the lookup function if they need it
1606 if (dyld_get_program_sdk_version() < DYLD_PACKED_VERSION(13,0,0))
1607 setLookupFunc((void*)&dyld3::compatFuncLookup);
1608 #endif
1609 }
1610 else {
1611 dyld_func_lookup_and_resign("__dyld_register_thread_helpers", &p);
1612 if(p != NULL)
1613 p(&sHelpers);
1614 }
1615
1616 tlv_initializer();
1617 }
1618
1619 int dladdr(const void* addr, Dl_info* info)
1620 {
1621 dyld3::ScopedTimer timer(DBG_DYLD_TIMING_DLADDR, (uint64_t)addr, 0, 0);
1622 int result = 0;
1623 if ( gUseDyld3 ) {
1624 result = dyld3::dladdr(addr, info);
1625 } else {
1626 DYLD_LOCK_THIS_BLOCK;
1627 typedef int (*funcType)(const void* , Dl_info*);
1628 static funcType __ptrauth_dyld_function_ptr p = NULL;
1629
1630 if(p == NULL)
1631 dyld_func_lookup_and_resign("__dyld_dladdr", &p);
1632 result = p(addr, info);
1633 }
1634 timer.setData4(result);
1635 timer.setData5(info != NULL ? info->dli_fbase : 0);
1636 timer.setData6(info != NULL ? info->dli_saddr : 0);
1637 return result;
1638 }
1639
1640 #if !TARGET_OS_DRIVERKIT
1641 char* dlerror()
1642 {
1643 if ( gUseDyld3 )
1644 return dyld3::dlerror();
1645
1646 DYLD_LOCK_THIS_BLOCK;
1647 typedef char* (*funcType)();
1648 static funcType __ptrauth_dyld_function_ptr p = NULL;
1649
1650 if(p == NULL)
1651 dyld_func_lookup_and_resign("__dyld_dlerror", &p);
1652 return(p());
1653 }
1654
1655 int dlclose(void* handle)
1656 {
1657 dyld3::ScopedTimer timer(DBG_DYLD_TIMING_DLCLOSE, (uint64_t)handle, 0, 0);
1658 int result = 0;
1659 if ( gUseDyld3 ) {
1660 timer.setData4(result);
1661 return dyld3::dlclose(handle);
1662 }
1663
1664 DYLD_LOCK_THIS_BLOCK;
1665 typedef int (*funcType)(void* handle);
1666 static funcType __ptrauth_dyld_function_ptr p = NULL;
1667
1668 if(p == NULL)
1669 dyld_func_lookup_and_resign("__dyld_dlclose", &p);
1670 result = p(handle);
1671 timer.setData4(result);
1672 return result;
1673 }
1674
1675 static void* dlopen_internal(const char* path, int mode, void* callerAddress)
1676 {
1677 dyld3::ScopedTimer timer(DBG_DYLD_TIMING_DLOPEN, path, mode, 0);
1678 void* result = nullptr;
1679 if ( gUseDyld3 ) {
1680 result = dyld3::dlopen_internal(path, mode, callerAddress);
1681 timer.setData4(result);
1682 return result;
1683 }
1684
1685 // dlopen is special. locking is done inside dyld to allow initializer to run without lock
1686 DYLD_NO_LOCK_THIS_BLOCK;
1687
1688 typedef void* (*funcType)(const char* path, int, void*);
1689 static funcType __ptrauth_dyld_function_ptr p = NULL;
1690
1691 if(p == NULL)
1692 dyld_func_lookup_and_resign("__dyld_dlopen_internal", &p);
1693 result = p(path, mode, callerAddress);
1694 // use asm block to prevent tail call optimization
1695 // this is needed because dlopen uses __builtin_return_address() and depends on this glue being in the frame chain
1696 // <rdar://problem/5313172 dlopen() looks too far up stack, can cause crash>
1697 __asm__ volatile("");
1698 timer.setData4(result);
1699
1700 return result;
1701 }
1702
1703 void* dlopen(const char* path, int mode)
1704 {
1705 void* result = dlopen_internal(path, mode, __builtin_return_address(0));
1706 if ( result )
1707 return result;
1708
1709
1710 return nullptr;
1711 }
1712
1713 void* dlopen_from(const char* path, int mode, void* addressInCaller)
1714 {
1715 #if __has_feature(ptrauth_calls)
1716 addressInCaller = __builtin_ptrauth_strip(addressInCaller, ptrauth_key_asia);
1717 #endif
1718 return dlopen_internal(path, mode, addressInCaller);
1719 }
1720
1721 #if !__i386__
1722 void* dlopen_audited(const char* path, int mode)
1723 {
1724 return dlopen(path, mode);
1725 }
1726 #endif // !__i386__
1727
1728 bool dlopen_preflight(const char* path)
1729 {
1730 dyld3::ScopedTimer timer(DBG_DYLD_TIMING_DLOPEN_PREFLIGHT, path, 0, 0);
1731 bool result = false;
1732
1733 if ( gUseDyld3 ) {
1734 result = dyld3::dlopen_preflight_internal(path);
1735 timer.setData4(result);
1736 return result;
1737 }
1738
1739 DYLD_LOCK_THIS_BLOCK;
1740 typedef bool (*funcType)(const char* path, void* callerAddress);
1741 static funcType __ptrauth_dyld_function_ptr p = NULL;
1742
1743 if(p == NULL)
1744 dyld_func_lookup_and_resign("__dyld_dlopen_preflight_internal", &p);
1745 result = p(path, __builtin_return_address(0));
1746 timer.setData4(result);
1747 return result;
1748 }
1749
1750 void* dlsym(void* handle, const char* symbol)
1751 {
1752 dyld3::ScopedTimer timer(DBG_DYLD_TIMING_DLSYM, handle, symbol, 0);
1753 void* result = nullptr;
1754
1755 if ( gUseDyld3 ) {
1756 result = dyld3::dlsym_internal(handle, symbol, __builtin_return_address(0));
1757 timer.setData4(result);
1758 return result;
1759 }
1760
1761 DYLD_LOCK_THIS_BLOCK;
1762 typedef void* (*funcType)(void* handle, const char* symbol, void *callerAddress);
1763 static funcType __ptrauth_dyld_function_ptr p = NULL;
1764
1765 if(p == NULL)
1766 dyld_func_lookup_and_resign("__dyld_dlsym_internal", &p);
1767 result = p(handle, symbol, __builtin_return_address(0));
1768 timer.setData4(result);
1769 return result;
1770 }
1771 #endif // !TARGET_OS_DRIVERKIT
1772
1773
1774 const struct dyld_all_image_infos* _dyld_get_all_image_infos()
1775 {
1776 if ( gUseDyld3 )
1777 return dyld3::_dyld_get_all_image_infos();
1778
1779 DYLD_NO_LOCK_THIS_BLOCK;
1780 typedef struct dyld_all_image_infos* (*funcType)();
1781 static funcType __ptrauth_dyld_function_ptr p = NULL;
1782
1783 if(p == NULL)
1784 dyld_func_lookup_and_resign("__dyld_get_all_image_infos", &p);
1785 return p();
1786 }
1787
1788 #if SUPPORT_ZERO_COST_EXCEPTIONS
1789 bool _dyld_find_unwind_sections(void* addr, dyld_unwind_sections* info)
1790 {
1791 if ( gUseDyld3 )
1792 return dyld3::_dyld_find_unwind_sections(addr, info);
1793
1794 DYLD_NO_LOCK_THIS_BLOCK;
1795 typedef void* (*funcType)(void*, dyld_unwind_sections*);
1796 static funcType __ptrauth_dyld_function_ptr p = NULL;
1797
1798 if(p == NULL)
1799 dyld_func_lookup_and_resign("__dyld_find_unwind_sections", &p);
1800 return p(addr, info);
1801 }
1802 #endif
1803
1804
1805 #if __i386__ || __x86_64__ || __arm__ || __arm64__
1806 __attribute__((visibility("hidden")))
1807 void* _dyld_fast_stub_entry(void* loadercache, long lazyinfo)
1808 {
1809 DYLD_NO_LOCK_THIS_BLOCK;
1810 typedef void* (*funcType)(void*, long);
1811 static funcType __ptrauth_dyld_function_ptr p = NULL;
1812
1813 if(p == NULL)
1814 dyld_func_lookup_and_resign("__dyld_fast_stub_entry", &p);
1815 return p(loadercache, lazyinfo);
1816 }
1817 #endif
1818
1819
1820 const char* dyld_image_path_containing_address(const void* addr)
1821 {
1822 if ( gUseDyld3 )
1823 return dyld3::dyld_image_path_containing_address(addr);
1824
1825 DYLD_NO_LOCK_THIS_BLOCK;
1826 typedef const char* (*funcType)(const void*);
1827 static funcType __ptrauth_dyld_function_ptr p = NULL;
1828
1829 if(p == NULL)
1830 dyld_func_lookup_and_resign("__dyld_image_path_containing_address", &p);
1831 return p(addr);
1832 }
1833
1834 const struct mach_header* dyld_image_header_containing_address(const void* addr)
1835 {
1836 if ( gUseDyld3 )
1837 return dyld3::dyld_image_header_containing_address(addr);
1838
1839 DYLD_NO_LOCK_THIS_BLOCK;
1840 typedef const mach_header* (*funcType)(const void*);
1841 static funcType __ptrauth_dyld_function_ptr p = NULL;
1842
1843 if(p == NULL)
1844 dyld_func_lookup_and_resign("__dyld_get_image_header_containing_address", &p);
1845 return p(addr);
1846 }
1847
1848
1849 bool dyld_shared_cache_some_image_overridden()
1850 {
1851 if ( gUseDyld3 )
1852 return dyld3::dyld_shared_cache_some_image_overridden();
1853
1854 DYLD_NO_LOCK_THIS_BLOCK;
1855 typedef bool (*funcType)();
1856 static funcType __ptrauth_dyld_function_ptr p = NULL;
1857
1858 if(p == NULL)
1859 dyld_func_lookup_and_resign("__dyld_shared_cache_some_image_overridden", &p);
1860 return p();
1861 }
1862
1863 bool _dyld_get_shared_cache_uuid(uuid_t uuid)
1864 {
1865 if ( gUseDyld3 )
1866 return dyld3::_dyld_get_shared_cache_uuid(uuid);
1867
1868 DYLD_NO_LOCK_THIS_BLOCK;
1869 typedef bool (*funcType)(uuid_t);
1870 static funcType __ptrauth_dyld_function_ptr p = NULL;
1871
1872 if(p == NULL)
1873 dyld_func_lookup_and_resign("__dyld_get_shared_cache_uuid", &p);
1874 return p(uuid);
1875 }
1876
1877 const void* _dyld_get_shared_cache_range(size_t* length)
1878 {
1879 if ( gUseDyld3 )
1880 return dyld3::_dyld_get_shared_cache_range(length);
1881
1882 DYLD_NO_LOCK_THIS_BLOCK;
1883 typedef const void* (*funcType)(size_t*);
1884 static funcType __ptrauth_dyld_function_ptr p = NULL;
1885
1886 if(p == NULL)
1887 dyld_func_lookup_and_resign("__dyld_get_shared_cache_range", &p);
1888 return p(length);
1889 }
1890
1891 bool _dyld_shared_cache_optimized()
1892 {
1893 if ( gUseDyld3 )
1894 return dyld3::_dyld_shared_cache_optimized();
1895
1896 const dyld_all_image_infos* allInfo = _dyld_get_all_image_infos();
1897 if ( allInfo != nullptr ) {
1898 const dyld_cache_header* cacheHeader = (dyld_cache_header*)(allInfo->sharedCacheBaseAddress);
1899 if ( cacheHeader != nullptr )
1900 return (cacheHeader->cacheType == kDyldSharedCacheTypeProduction);
1901 }
1902 return false;
1903 }
1904
1905 bool _dyld_shared_cache_is_locally_built()
1906 {
1907 if ( gUseDyld3 )
1908 return dyld3::_dyld_shared_cache_is_locally_built();
1909
1910 const dyld_all_image_infos* allInfo = _dyld_get_all_image_infos();
1911 if ( allInfo != nullptr ) {
1912 const dyld_cache_header* cacheHeader = (dyld_cache_header*)(allInfo->sharedCacheBaseAddress);
1913 if ( cacheHeader != nullptr )
1914 return (cacheHeader->locallyBuiltCache == 1);
1915 }
1916 return false;
1917 }
1918
1919 const char* _dyld_shared_cache_real_path(const char* path)
1920 {
1921 const dyld_all_image_infos* allInfo = _dyld_get_all_image_infos();
1922 if ( allInfo != nullptr ) {
1923 const DyldSharedCache* cache = (const DyldSharedCache*)(allInfo->sharedCacheBaseAddress);
1924 if ( cache != nullptr )
1925 return cache->getCanonicalPath(path);
1926 }
1927 return nullptr;
1928 }
1929
1930 bool _dyld_shared_cache_contains_path(const char* path)
1931 {
1932 return _dyld_shared_cache_real_path(path) != nullptr;
1933 }
1934
1935
1936 uint32_t _dyld_launch_mode()
1937 {
1938 if ( gUseDyld3 )
1939 return dyld3::_dyld_launch_mode();
1940
1941 // in dyld2 mode all flag bits are zero
1942 return 0;
1943 }
1944
1945 void _dyld_images_for_addresses(unsigned count, const void* addresses[], struct dyld_image_uuid_offset infos[])
1946 {
1947 if ( gUseDyld3 )
1948 return dyld3::_dyld_images_for_addresses(count, addresses, infos);
1949
1950 DYLD_NO_LOCK_THIS_BLOCK;
1951 typedef const void (*funcType)(unsigned, const void*[], struct dyld_image_uuid_offset[]);
1952 static funcType __ptrauth_dyld_function_ptr p = NULL;
1953
1954 if(p == NULL)
1955 dyld_func_lookup_and_resign("__dyld_images_for_addresses", &p);
1956 return p(count, addresses, infos);
1957 }
1958
1959 void _dyld_register_for_image_loads(void (*func)(const mach_header* mh, const char* path, bool unloadable))
1960 {
1961 if ( gUseDyld3 )
1962 return dyld3::_dyld_register_for_image_loads(func);
1963
1964 DYLD_NO_LOCK_THIS_BLOCK;
1965 typedef const void (*funcType)(void (*)(const mach_header* mh, const char* path, bool unloadable));
1966 static funcType __ptrauth_dyld_function_ptr p = NULL;
1967
1968 if(p == NULL)
1969 dyld_func_lookup_and_resign("__dyld_register_for_image_loads", &p);
1970 return p(func);
1971 }
1972
1973 void _dyld_register_for_bulk_image_loads(void (*func)(unsigned imageCount, const struct mach_header* mhs[], const char* paths[]))
1974 {
1975 if ( gUseDyld3 )
1976 return dyld3::_dyld_register_for_bulk_image_loads(func);
1977
1978 DYLD_NO_LOCK_THIS_BLOCK;
1979 typedef const void (*funcType)(void (*)(unsigned imageCount, const mach_header* mhs[], const char* paths[]));
1980 static funcType __ptrauth_dyld_function_ptr p = NULL;
1981
1982 if(p == NULL)
1983 dyld_func_lookup_and_resign("__dyld_register_for_bulk_image_loads", &p);
1984 return p(func);
1985 }
1986
1987 bool dyld_need_closure(const char* execPath, const char* dataContainerRootDir)
1988 {
1989 return dyld3::dyld_need_closure(execPath, dataContainerRootDir);
1990 }
1991
1992 bool dyld_process_is_restricted()
1993 {
1994 if ( gUseDyld3 )
1995 return dyld3::dyld_process_is_restricted();
1996
1997 DYLD_NO_LOCK_THIS_BLOCK;
1998 typedef bool (*funcType)();
1999 static funcType __ptrauth_dyld_function_ptr p = NULL;
2000
2001 if(p == NULL)
2002 dyld_func_lookup_and_resign("__dyld_process_is_restricted", &p);
2003 return p();
2004 }
2005
2006 const char* dyld_shared_cache_file_path()
2007 {
2008 if ( gUseDyld3 )
2009 return dyld3::dyld_shared_cache_file_path();
2010
2011 DYLD_NO_LOCK_THIS_BLOCK;
2012 typedef const char* (*funcType)();
2013 static funcType __ptrauth_dyld_function_ptr p = NULL;
2014
2015 if(p == NULL)
2016 dyld_func_lookup_and_resign("__dyld_shared_cache_file_path", &p);
2017 return p();
2018 }
2019
2020 bool dyld_has_inserted_or_interposing_libraries()
2021 {
2022 if ( gUseDyld3 )
2023 return dyld3::dyld_has_inserted_or_interposing_libraries();
2024
2025 DYLD_NO_LOCK_THIS_BLOCK;
2026 typedef bool (*funcType)();
2027 static funcType __ptrauth_dyld_function_ptr p = NULL;
2028
2029 if (p == NULL)
2030 dyld_func_lookup_and_resign("__dyld_has_inserted_or_interposing_libraries", &p);
2031 return p();
2032 }
2033
2034 bool _dyld_has_fix_for_radar(const char *rdar) {
2035 // There is no point in shimming this to dyld3, actual functionality can exist purely in libSystem for
2036 // both dyld2 and dyld3.
2037 return false;
2038 }
2039
2040
2041 void dyld_dynamic_interpose(const struct mach_header* mh, const struct dyld_interpose_tuple array[], size_t count)
2042 {
2043 if ( gUseDyld3 )
2044 return dyld3::dyld_dynamic_interpose(mh, array, count);
2045
2046 DYLD_LOCK_THIS_BLOCK;
2047 typedef void (*funcType)(const struct mach_header* mh, const struct dyld_interpose_tuple array[], size_t count);
2048 static funcType __ptrauth_dyld_function_ptr p = NULL;
2049
2050 if (p == NULL)
2051 dyld_func_lookup_and_resign("__dyld_dynamic_interpose", &p);
2052 p(mh, array, count);
2053 }
2054
2055 // SPI called __fork
2056 void _dyld_atfork_prepare()
2057 {
2058 if ( gUseDyld3 )
2059 return dyld3::_dyld_atfork_prepare();
2060 }
2061
2062 // SPI called __fork
2063 void _dyld_atfork_parent()
2064 {
2065 if ( gUseDyld3 )
2066 return dyld3::_dyld_atfork_parent();
2067 }
2068
2069 // SPI called __fork
2070 void _dyld_fork_child()
2071 {
2072 if ( gUseDyld3 )
2073 return dyld3::_dyld_fork_child();
2074
2075 DYLD_NO_LOCK_THIS_BLOCK;
2076 typedef void (*funcType)();
2077 static funcType __ptrauth_dyld_function_ptr p = NULL;
2078
2079 if(p == NULL)
2080 dyld_func_lookup_and_resign("__dyld_fork_child", &p);
2081 return p();
2082 }
2083
2084
2085
2086 static void* mapStartOfCache(const char* path, size_t length)
2087 {
2088 struct stat statbuf;
2089 if ( dyld3::stat(path, &statbuf) == -1 )
2090 return NULL;
2091
2092 if ( (size_t)statbuf.st_size < length )
2093 return NULL;
2094
2095 int cache_fd = dyld3::open(path, O_RDONLY, 0);
2096 if ( cache_fd < 0 )
2097 return NULL;
2098
2099 void* result = ::mmap(NULL, length, PROT_READ, MAP_PRIVATE, cache_fd, 0);
2100 close(cache_fd);
2101
2102 if ( result == MAP_FAILED )
2103 return NULL;
2104
2105 return result;
2106 }
2107
2108
2109 static const dyld_cache_header* findCacheInDirAndMap(const uuid_t cacheUuid, const char* dirPath)
2110 {
2111 DIR* dirp = ::opendir(dirPath);
2112 if ( dirp != NULL) {
2113 dirent entry;
2114 dirent* entp = NULL;
2115 char cachePath[PATH_MAX];
2116 while ( ::readdir_r(dirp, &entry, &entp) == 0 ) {
2117 if ( entp == NULL )
2118 break;
2119 if ( entp->d_type != DT_REG )
2120 continue;
2121 if ( strlcpy(cachePath, dirPath, PATH_MAX) >= PATH_MAX )
2122 continue;
2123 if ( strlcat(cachePath, "/", PATH_MAX) >= PATH_MAX )
2124 continue;
2125 if ( strlcat(cachePath, entp->d_name, PATH_MAX) >= PATH_MAX )
2126 continue;
2127 if ( const dyld_cache_header* cacheHeader = (dyld_cache_header*)mapStartOfCache(cachePath, 0x00100000) ) {
2128 if ( (::memcmp(cacheHeader, "dyld_", 5) != 0) || (::memcmp(cacheHeader->uuid, cacheUuid, 16) != 0) ) {
2129 // wrong uuid, unmap and keep looking
2130 ::munmap((void*)cacheHeader, 0x00100000);
2131 }
2132 else {
2133 // found cache
2134 closedir(dirp);
2135 return cacheHeader;
2136 }
2137 }
2138 }
2139 closedir(dirp);
2140 }
2141 return NULL;
2142 }
2143
2144 int dyld_shared_cache_find_iterate_text(const uuid_t cacheUuid, const char* extraSearchDirs[], void (^callback)(const dyld_shared_cache_dylib_text_info* info))
2145 {
2146 if ( gUseDyld3 )
2147 return dyld3::dyld_shared_cache_find_iterate_text(cacheUuid, extraSearchDirs, callback);
2148
2149 const dyld_cache_header* cacheHeader = NULL;
2150 bool needToUnmap = true;
2151
2152 // get info from dyld about this process, to see if requested cache is already mapped into this process
2153 const dyld_all_image_infos* allInfo = _dyld_get_all_image_infos();
2154 if ( (allInfo != NULL) && (allInfo->sharedCacheBaseAddress != 0) && (memcmp(allInfo->sharedCacheUUID, cacheUuid, 16) == 0) ) {
2155 // requested cache is already mapped, just re-use it
2156 cacheHeader = (dyld_cache_header*)(allInfo->sharedCacheBaseAddress);
2157 needToUnmap = false;
2158 }
2159 else {
2160 // look first is default location for cache files
2161 #if TARGET_OS_IPHONE
2162 cacheHeader = findCacheInDirAndMap(cacheUuid, IPHONE_DYLD_SHARED_CACHE_DIR);
2163 #else
2164 cacheHeader = findCacheInDirAndMap(cacheUuid, MACOSX_MRM_DYLD_SHARED_CACHE_DIR);
2165 #endif
2166 // if not there, look in extra search locations
2167 if ( cacheHeader == NULL ) {
2168 for (const char** p = extraSearchDirs; *p != NULL; ++p) {
2169 cacheHeader = findCacheInDirAndMap(cacheUuid, *p);
2170 if ( cacheHeader != NULL )
2171 break;
2172 }
2173 }
2174 }
2175
2176 if ( cacheHeader == NULL )
2177 return -1;
2178
2179 if ( cacheHeader->mappingOffset <= __offsetof(dyld_cache_header, imagesTextOffset) ) {
2180 // old cache without imagesText array
2181 if ( needToUnmap )
2182 ::munmap((void*)cacheHeader, 0x00100000);
2183 return -1;
2184 }
2185
2186 // walk imageText table and call callback for each entry
2187 const dyld_cache_mapping_info* mappings = (dyld_cache_mapping_info*)((char*)cacheHeader + cacheHeader->mappingOffset);
2188 const uint64_t cacheUnslidBaseAddress = mappings[0].address;
2189 const dyld_cache_image_text_info* imagesText = (dyld_cache_image_text_info*)((char*)cacheHeader + cacheHeader->imagesTextOffset);
2190 const dyld_cache_image_text_info* imagesTextEnd = &imagesText[cacheHeader->imagesTextCount];
2191 for (const dyld_cache_image_text_info* p=imagesText; p < imagesTextEnd; ++p) {
2192 dyld_shared_cache_dylib_text_info dylibTextInfo;
2193 dylibTextInfo.version = 2;
2194 dylibTextInfo.loadAddressUnslid = p->loadAddress;
2195 dylibTextInfo.textSegmentSize = p->textSegmentSize;
2196 dylibTextInfo.path = (char*)cacheHeader + p->pathOffset;
2197 ::memcpy(dylibTextInfo.dylibUuid, p->uuid, 16);
2198 dylibTextInfo.textSegmentOffset = p->loadAddress - cacheUnslidBaseAddress;
2199 callback(&dylibTextInfo);
2200 }
2201
2202 if ( needToUnmap )
2203 ::munmap((void*)cacheHeader, 0x00100000);
2204
2205 return 0;
2206 }
2207
2208 int dyld_shared_cache_iterate_text(const uuid_t cacheUuid, void (^callback)(const dyld_shared_cache_dylib_text_info* info))
2209 {
2210 if ( gUseDyld3 )
2211 return dyld3::dyld_shared_cache_iterate_text(cacheUuid, callback);
2212
2213 const char* extraSearchDirs[] = { NULL };
2214 return dyld_shared_cache_find_iterate_text(cacheUuid, extraSearchDirs, callback);
2215 }
2216
2217
2218 bool _dyld_is_memory_immutable(const void* addr, size_t length)
2219 {
2220 if ( gUseDyld3 )
2221 return dyld3::_dyld_is_memory_immutable(addr, length);
2222
2223 DYLD_NO_LOCK_THIS_BLOCK;
2224 typedef bool (*funcType)(const void*, size_t);
2225 static funcType __ptrauth_dyld_function_ptr p = NULL;
2226
2227 if(p == NULL)
2228 dyld_func_lookup_and_resign("__dyld_is_memory_immutable", &p);
2229 return p(addr, length);
2230 }
2231
2232
2233 void _dyld_objc_notify_register(_dyld_objc_notify_mapped mapped,
2234 _dyld_objc_notify_init init,
2235 _dyld_objc_notify_unmapped unmapped)
2236 {
2237 if ( gUseDyld3 )
2238 return dyld3::_dyld_objc_notify_register(mapped, init, unmapped);
2239
2240 DYLD_LOCK_THIS_BLOCK;
2241 typedef bool (*funcType)(_dyld_objc_notify_mapped, _dyld_objc_notify_init, _dyld_objc_notify_unmapped);
2242 static funcType __ptrauth_dyld_function_ptr p = NULL;
2243
2244 if(p == NULL)
2245 dyld_func_lookup_and_resign("__dyld_objc_notify_register", &p);
2246 p(mapped, init, unmapped);
2247 }
2248
2249 void _dyld_missing_symbol_abort()
2250 {
2251 return dyld3::_dyld_missing_symbol_abort();
2252 }
2253
2254 const char* _dyld_get_objc_selector(const char* selName)
2255 {
2256 // Check the shared cache table if it exists.
2257 if ( gObjCOpt != nullptr ) {
2258 if ( const objc_opt::objc_selopt_t* selopt = gObjCOpt->selopt() ) {
2259 const char* name = selopt->get(selName);
2260 if (name != nullptr)
2261 return name;
2262 }
2263 }
2264
2265 if ( gUseDyld3 )
2266 return dyld3::_dyld_get_objc_selector(selName);
2267
2268 return nullptr;
2269 }
2270
2271 void _dyld_for_each_objc_class(const char* className,
2272 void (^callback)(void* classPtr, bool isLoaded, bool* stop)) {
2273 if ( gUseDyld3 )
2274 return dyld3::_dyld_for_each_objc_class(className, callback);
2275 }
2276
2277 void _dyld_for_each_objc_protocol(const char* protocolName,
2278 void (^callback)(void* protocolPtr, bool isLoaded, bool* stop)) {
2279 if ( gUseDyld3 )
2280 return dyld3::_dyld_for_each_objc_protocol(protocolName, callback);
2281 }
2282
2283 void _dyld_register_driverkit_main(void (*mainFunc)(void))
2284 {
2285 if ( gUseDyld3 )
2286 return dyld3::_dyld_register_driverkit_main(mainFunc);
2287
2288 typedef bool (*funcType)(void *);
2289 static funcType __ptrauth_dyld_function_ptr p = NULL;
2290
2291 if(p == NULL)
2292 dyld_func_lookup_and_resign("__dyld_register_driverkit_main", &p);
2293 p(reinterpret_cast<void *>(mainFunc));
2294 }
2295
2296 // This is populated in the shared cache builder, so that the ranges are protected by __DATA_CONST
2297 // If we have a root, we can find this range in the shared cache libdyld at runtime
2298 typedef std::pair<const uint8_t*, const uint8_t*> ObjCConstantRange;
2299
2300 #if TARGET_OS_OSX
2301 __attribute__((section(("__DATA, __objc_ranges"))))
2302 #else
2303 __attribute__((section(("__DATA_CONST, __objc_ranges"))))
2304 #endif
2305 __attribute__((used))
2306 static ObjCConstantRange gSharedCacheObjCConstantRanges[dyld_objc_string_kind + 1];
2307
2308 static std::pair<const void*, uint64_t> getDyldCacheConstantRanges() {
2309 const dyld_all_image_infos* allInfo = _dyld_get_all_image_infos();
2310 if ( allInfo != nullptr ) {
2311 const DyldSharedCache* cache = (const DyldSharedCache*)(allInfo->sharedCacheBaseAddress);
2312 if ( cache != nullptr ) {
2313 return cache->getObjCConstantRange();
2314 }
2315 }
2316 return { nullptr, 0 };
2317 }
2318
2319 bool _dyld_is_objc_constant(DyldObjCConstantKind kind, const void* addr) {
2320 assert(kind <= dyld_objc_string_kind);
2321 // The common case should be that the value is in range, as this is a security
2322 // check, so first test against the values in the struct. If we have a root then
2323 // we'll take the slow path later
2324 if ( (addr >= gSharedCacheObjCConstantRanges[kind].first) && (addr < gSharedCacheObjCConstantRanges[kind].second) ) {
2325 // Make sure that we are pointing at the start of a constant object, not in to the middle of it
2326 uint64_t offset = (uint64_t)addr - (uint64_t)gSharedCacheObjCConstantRanges[kind].first;
2327 return (offset % (uint64_t)DyldSharedCache::ConstantClasses::cfStringAtomSize) == 0;
2328 }
2329
2330 // If we are in the shared cache, then the above check was sufficient, so this really isn't a valid constant address
2331 extern void* __dso_handle;
2332 const dyld3::MachOAnalyzer* ma = (const dyld3::MachOAnalyzer*)&__dso_handle;
2333 if ( ma->inDyldCache() )
2334 return false;
2335
2336 // We now know we are a root, so use the pointers in the shared cache libdyld version of gSharedCacheObjCConstantRanges
2337 static std::pair<const void*, uint64_t> sharedCacheRanges = { nullptr, ~0ULL };
2338
2339 // FIXME: Should we fold this in as an inititalizer above?
2340 // That would mean we need to link against somewhere to get ___cxa_guard_acquire/___cxa_guard_release
2341 if ( sharedCacheRanges.second == ~0ULL )
2342 sharedCacheRanges = getDyldCacheConstantRanges();
2343
2344 // We have the range of the section in libdyld in the shared cache, now get an array of ranges from it
2345 uint64_t numRanges = sharedCacheRanges.second / sizeof(ObjCConstantRange);
2346 if ( kind >= numRanges )
2347 return false;
2348
2349 const ObjCConstantRange* rangeArrayBase = (const ObjCConstantRange*)sharedCacheRanges.first;
2350 if ( (addr >= rangeArrayBase[kind].first) && (addr < rangeArrayBase[kind].second) ) {
2351 // Make sure that we are pointing at the start of a constant object, not in to the middle of it
2352 uint64_t offset = (uint64_t)addr - (uint64_t)rangeArrayBase[kind].first;
2353 return (offset % (uint64_t)DyldSharedCache::ConstantClasses::cfStringAtomSize) == 0;
2354 }
2355 return false;
2356 }