dyld-732.8.tar.gz
[apple/dyld.git] / src / ImageLoaderMachO.cpp
1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
2 *
3 * Copyright (c) 2004-2010 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 // work around until conformance work is complete rdar://problem/4508801
26 #define __srr0 srr0
27 #define __eip eip
28 #define __rip rip
29
30 #define __STDC_LIMIT_MACROS
31 #include <string.h>
32 #include <fcntl.h>
33 #include <errno.h>
34 #include <sys/types.h>
35 #include <sys/fcntl.h>
36 #include <sys/stat.h>
37 #include <sys/mman.h>
38 #include <mach/mach.h>
39 #include <mach/thread_status.h>
40 #include <mach-o/loader.h>
41 #include <mach-o/nlist.h>
42 #include <mach-o/dyld_images.h>
43 #include <sys/sysctl.h>
44 #include <sys/syscall.h>
45 #include <libkern/OSAtomic.h>
46 #include <libkern/OSCacheControl.h>
47 #include <stdint.h>
48 #include <System/sys/codesign.h>
49
50 #if __has_feature(ptrauth_calls)
51 #include <ptrauth.h>
52 #endif
53
54 #include "ImageLoaderMachO.h"
55 #include "ImageLoaderMachOCompressed.h"
56 #if SUPPORT_CLASSIC_MACHO
57 #include "ImageLoaderMachOClassic.h"
58 #endif
59 #include "Tracing.h"
60 #include "dyld2.h"
61
62 // <rdar://problem/8718137> use stack guard random value to add padding between dylibs
63 extern "C" long __stack_chk_guard;
64
65 #define LIBSYSTEM_DYLIB_PATH "/usr/lib/libSystem.B.dylib"
66 #define LIBDYLD_DYLIB_PATH "/usr/lib/system/libdyld.dylib"
67 #if __MAC_OS_X_VERSION_MIN_REQUIRED
68 #define DRIVERKIT_LIBSYSTEM_DYLIB_PATH "/System/DriverKit/usr/lib/libSystem.dylib"
69 #define DRIVERKIT_LIBDYLD_DYLIB_PATH "/System/DriverKit/usr/lib/system/libdyld.dylib"
70 #endif
71
72 // relocation_info.r_length field has value 3 for 64-bit executables and value 2 for 32-bit executables
73 #if __LP64__
74 #define LC_SEGMENT_COMMAND LC_SEGMENT_64
75 #define LC_ROUTINES_COMMAND LC_ROUTINES_64
76 #define LC_SEGMENT_COMMAND_WRONG LC_SEGMENT
77 struct macho_segment_command : public segment_command_64 {};
78 struct macho_section : public section_64 {};
79 struct macho_routines_command : public routines_command_64 {};
80 #else
81 #define LC_SEGMENT_COMMAND LC_SEGMENT
82 #define LC_ROUTINES_COMMAND LC_ROUTINES
83 #define LC_SEGMENT_COMMAND_WRONG LC_SEGMENT_64
84 struct macho_segment_command : public segment_command {};
85 struct macho_section : public section {};
86 struct macho_routines_command : public routines_command {};
87 #endif
88
89 uint32_t ImageLoaderMachO::fgSymbolTableBinarySearchs = 0;
90
91
92 ImageLoaderMachO::ImageLoaderMachO(const macho_header* mh, const char* path, unsigned int segCount,
93 uint32_t segOffsets[], unsigned int libCount)
94 : ImageLoader(path, libCount), fCoveredCodeLength(0), fMachOData((uint8_t*)mh), fLinkEditBase(NULL), fSlide(0),
95 fEHFrameSectionOffset(0), fUnwindInfoSectionOffset(0), fDylibIDOffset(0),
96 fSegmentsCount(segCount), fIsSplitSeg(false), fInSharedCache(false),
97 #if TEXT_RELOC_SUPPORT
98 fTextSegmentRebases(false),
99 fTextSegmentBinds(false),
100 #else
101 fReadOnlyDataSegment(false),
102 #endif
103 #if __i386__
104 fReadOnlyImportSegment(false),
105 #endif
106 fHasSubLibraries(false), fHasSubUmbrella(false), fInUmbrella(false), fHasDOFSections(false), fHasDashInit(false),
107 fHasInitializers(false), fHasTerminators(false), fNotifyObjC(false), fRetainForObjC(false), fRegisteredAsRequiresCoalescing(false), fOverrideOfCacheImageNum(0)
108 {
109 fIsSplitSeg = ((mh->flags & MH_SPLIT_SEGS) != 0);
110
111 // construct SegmentMachO object for each LC_SEGMENT cmd using "placement new" to put
112 // each SegmentMachO object in array at end of ImageLoaderMachO object
113 const uint32_t cmd_count = mh->ncmds;
114 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
115 const struct load_command* cmd = cmds;
116 for (uint32_t i = 0, segIndex=0; i < cmd_count; ++i) {
117 if ( cmd->cmd == LC_SEGMENT_COMMAND ) {
118 const struct macho_segment_command* segCmd = (struct macho_segment_command*)cmd;
119 // ignore zero-sized segments
120 if ( segCmd->vmsize != 0 ) {
121 // record offset of load command
122 segOffsets[segIndex++] = (uint32_t)((uint8_t*)segCmd - fMachOData);
123 }
124 }
125 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
126 }
127
128 }
129
130 #if __MAC_OS_X_VERSION_MIN_REQUIRED
131 static uintptr_t pageAlign(uintptr_t value)
132 {
133 return (value + 4095) & (-4096);
134 }
135 #endif
136
137 // determine if this mach-o file has classic or compressed LINKEDIT and number of segments it has
138 void ImageLoaderMachO::sniffLoadCommands(const macho_header* mh, const char* path, bool inCache, bool* compressed,
139 unsigned int* segCount, unsigned int* libCount, const LinkContext& context,
140 const linkedit_data_command** codeSigCmd,
141 const encryption_info_command** encryptCmd)
142 {
143 *compressed = false;
144 *segCount = 0;
145 *libCount = 0;
146 *codeSigCmd = NULL;
147 *encryptCmd = NULL;
148
149 const uint32_t cmd_count = mh->ncmds;
150 const uint32_t sizeofcmds = mh->sizeofcmds;
151 if ( sizeofcmds > (MAX_MACH_O_HEADER_AND_LOAD_COMMANDS_SIZE-sizeof(macho_header)) )
152 dyld::throwf("malformed mach-o: load commands size (%u) > %u", sizeofcmds, MAX_MACH_O_HEADER_AND_LOAD_COMMANDS_SIZE);
153 if ( cmd_count > (sizeofcmds/sizeof(load_command)) )
154 dyld::throwf("malformed mach-o: ncmds (%u) too large to fit in sizeofcmds (%u)", cmd_count, sizeofcmds);
155 const struct load_command* const startCmds = (struct load_command*)(((uint8_t*)mh) + sizeof(macho_header));
156 const struct load_command* const endCmds = (struct load_command*)(((uint8_t*)mh) + sizeof(macho_header) + sizeofcmds);
157 const struct load_command* cmd = startCmds;
158 bool foundLoadCommandSegment = false;
159 const macho_segment_command* linkeditSegCmd = NULL;
160 const macho_segment_command* startOfFileSegCmd = NULL;
161 const dyld_info_command* dyldInfoCmd = NULL;
162 const linkedit_data_command* chainedFixupsCmd = NULL;
163 const linkedit_data_command* exportsTrieCmd = NULL;
164 const symtab_command* symTabCmd = NULL;
165 const dysymtab_command* dynSymbTabCmd = NULL;
166 for (uint32_t i = 0; i < cmd_count; ++i) {
167 uint32_t cmdLength = cmd->cmdsize;
168 const macho_segment_command* segCmd;
169 const dylib_command* dylibCmd;
170 if ( cmdLength < 8 ) {
171 dyld::throwf("malformed mach-o image: load command #%d length (%u) too small in %s",
172 i, cmdLength, path);
173 }
174 const struct load_command* const nextCmd = (const struct load_command*)(((char*)cmd)+cmdLength);
175 if ( (nextCmd > endCmds) || (nextCmd < cmd) ) {
176 dyld::throwf("malformed mach-o image: load command #%d length (%u) would exceed sizeofcmds (%u) in %s",
177 i, cmdLength, mh->sizeofcmds, path);
178 }
179 switch (cmd->cmd) {
180 case LC_DYLD_INFO:
181 case LC_DYLD_INFO_ONLY:
182 if ( cmd->cmdsize != sizeof(dyld_info_command) )
183 throw "malformed mach-o image: LC_DYLD_INFO size wrong";
184 dyldInfoCmd = (struct dyld_info_command*)cmd;
185 *compressed = true;
186 break;
187 case LC_DYLD_CHAINED_FIXUPS:
188 if ( cmd->cmdsize != sizeof(linkedit_data_command) )
189 throw "malformed mach-o image: LC_DYLD_CHAINED_FIXUPS size wrong";
190 chainedFixupsCmd = (struct linkedit_data_command*)cmd;
191 *compressed = true;
192 break;
193 case LC_DYLD_EXPORTS_TRIE:
194 if ( cmd->cmdsize != sizeof(linkedit_data_command) )
195 throw "malformed mach-o image: LC_DYLD_EXPORTS_TRIE size wrong";
196 exportsTrieCmd = (struct linkedit_data_command*)cmd;
197 break;
198 case LC_SEGMENT_COMMAND:
199 segCmd = (struct macho_segment_command*)cmd;
200 #if __MAC_OS_X_VERSION_MIN_REQUIRED
201 // rdar://problem/19617624 allow unmapped segments on OSX (but not iOS)
202 if ( ((segCmd->filesize) > pageAlign(segCmd->vmsize)) && (segCmd->vmsize != 0) )
203 #else
204 // <rdar://problem/19986776> dyld should support non-allocatable __LLVM segment
205 if ( (segCmd->filesize > segCmd->vmsize) && ((segCmd->vmsize != 0) || ((segCmd->flags & SG_NORELOC) == 0)) )
206 #endif
207 dyld::throwf("malformed mach-o image: segment load command %s filesize (0x%0lX) is larger than vmsize (0x%0lX)", segCmd->segname, (long)segCmd->filesize , (long)segCmd->vmsize );
208 if ( cmd->cmdsize < sizeof(macho_segment_command) )
209 throw "malformed mach-o image: LC_SEGMENT size too small";
210 if ( cmd->cmdsize != (sizeof(macho_segment_command) + segCmd->nsects * sizeof(macho_section)) )
211 throw "malformed mach-o image: LC_SEGMENT size wrong for number of sections";
212 // ignore zero-sized segments
213 if ( segCmd->vmsize != 0 )
214 *segCount += 1;
215 if ( strcmp(segCmd->segname, "__LINKEDIT") == 0 ) {
216 #if TARGET_OS_SIMULATOR
217 // Note: should check on all platforms that __LINKEDIT is read-only, but <rdar://problem/22637626&22525618>
218 if ( segCmd->initprot != VM_PROT_READ )
219 throw "malformed mach-o image: __LINKEDIT segment does not have read-only permissions";
220 #endif
221 if ( segCmd->fileoff == 0 )
222 throw "malformed mach-o image: __LINKEDIT has fileoff==0 which overlaps mach_header";
223 if ( linkeditSegCmd != NULL )
224 throw "malformed mach-o image: multiple __LINKEDIT segments";
225 linkeditSegCmd = segCmd;
226 }
227 else {
228 if ( segCmd->initprot & 0xFFFFFFF8 )
229 dyld::throwf("malformed mach-o image: %s segment has invalid permission bits (0x%X) in initprot", segCmd->segname, segCmd->initprot);
230 if ( segCmd->maxprot & 0xFFFFFFF8 )
231 dyld::throwf("malformed mach-o image: %s segment has invalid permission bits (0x%X) in maxprot", segCmd->segname, segCmd->maxprot);
232 if ( (segCmd->initprot != 0) && ((segCmd->initprot & VM_PROT_READ) == 0) )
233 dyld::throwf("malformed mach-o image: %s segment is not mapped readable", segCmd->segname);
234 }
235 if ( (segCmd->fileoff == 0) && (segCmd->filesize != 0) ) {
236 if ( (segCmd->initprot & VM_PROT_READ) == 0 )
237 dyld::throwf("malformed mach-o image: %s segment maps start of file but is not readable", segCmd->segname);
238 if ( (segCmd->initprot & VM_PROT_WRITE) == VM_PROT_WRITE ) {
239 if ( context.strictMachORequired )
240 dyld::throwf("malformed mach-o image: %s segment maps start of file but is writable", segCmd->segname);
241 }
242 if ( segCmd->filesize < (sizeof(macho_header) + mh->sizeofcmds) )
243 dyld::throwf("malformed mach-o image: %s segment does not map all of load commands", segCmd->segname);
244 if ( startOfFileSegCmd != NULL )
245 dyld::throwf("malformed mach-o image: multiple segments map start of file: %s %s", startOfFileSegCmd->segname, segCmd->segname);
246 startOfFileSegCmd = segCmd;
247 }
248 if ( context.strictMachORequired ) {
249 uintptr_t vmStart = segCmd->vmaddr;
250 uintptr_t vmSize = segCmd->vmsize;
251 uintptr_t vmEnd = vmStart + vmSize;
252 uintptr_t fileStart = segCmd->fileoff;
253 uintptr_t fileSize = segCmd->filesize;
254 if ( (intptr_t)(vmSize) < 0 )
255 dyld::throwf("malformed mach-o image: segment load command %s vmsize too large in %s", segCmd->segname, path);
256 if ( vmStart > vmEnd )
257 dyld::throwf("malformed mach-o image: segment load command %s wraps around address space", segCmd->segname);
258 if ( vmSize != fileSize ) {
259 if ( segCmd->initprot == 0 ) {
260 // allow: fileSize == 0 && initprot == 0 e.g. __PAGEZERO
261 // allow: vmSize == 0 && initprot == 0 e.g. __LLVM
262 if ( (fileSize != 0) && (vmSize != 0) )
263 dyld::throwf("malformed mach-o image: unaccessable segment %s has non-zero filesize and vmsize", segCmd->segname);
264 }
265 else {
266 // allow: vmSize > fileSize && initprot != X e.g. __DATA
267 if ( vmSize < fileSize ) {
268 dyld::throwf("malformed mach-o image: segment %s has vmsize < filesize", segCmd->segname);
269 }
270 if ( segCmd->initprot & VM_PROT_EXECUTE ) {
271 dyld::throwf("malformed mach-o image: segment %s has vmsize != filesize and is executable", segCmd->segname);
272 }
273 }
274 }
275 if ( inCache ) {
276 if ( (fileSize != 0) && (segCmd->initprot == (VM_PROT_READ | VM_PROT_EXECUTE)) ) {
277 if ( foundLoadCommandSegment )
278 throw "load commands in multiple segments";
279 foundLoadCommandSegment = true;
280 }
281 }
282 else if ( (fileStart < mh->sizeofcmds) && (fileSize != 0) ) {
283 // <rdar://problem/7942521> all load commands must be in an executable segment
284 if ( (fileStart != 0) || (fileSize < (mh->sizeofcmds+sizeof(macho_header))) )
285 dyld::throwf("malformed mach-o image: segment %s does not span all load commands", segCmd->segname);
286 if ( segCmd->initprot != (VM_PROT_READ | VM_PROT_EXECUTE) )
287 dyld::throwf("malformed mach-o image: load commands found in segment %s with wrong permissions", segCmd->segname);
288 if ( foundLoadCommandSegment )
289 throw "load commands in multiple segments";
290 foundLoadCommandSegment = true;
291 }
292
293 const struct macho_section* const sectionsStart = (struct macho_section*)((char*)segCmd + sizeof(struct macho_segment_command));
294 const struct macho_section* const sectionsEnd = &sectionsStart[segCmd->nsects];
295 for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
296 if (!inCache && sect->offset != 0 && ((sect->offset + sect->size) > (segCmd->fileoff + segCmd->filesize)))
297 dyld::throwf("malformed mach-o image: section %s,%s of '%s' exceeds segment %s booundary", sect->segname, sect->sectname, path, segCmd->segname);
298 }
299 }
300 break;
301 case LC_SEGMENT_COMMAND_WRONG:
302 dyld::throwf("malformed mach-o image: wrong LC_SEGMENT[_64] for architecture");
303 break;
304 case LC_LOAD_DYLIB:
305 case LC_LOAD_WEAK_DYLIB:
306 case LC_REEXPORT_DYLIB:
307 case LC_LOAD_UPWARD_DYLIB:
308 *libCount += 1;
309 // fall thru
310 [[clang::fallthrough]];
311 case LC_ID_DYLIB:
312 dylibCmd = (dylib_command*)cmd;
313 if ( dylibCmd->dylib.name.offset > cmdLength )
314 dyld::throwf("malformed mach-o image: dylib load command #%d has offset (%u) outside its size (%u)", i, dylibCmd->dylib.name.offset, cmdLength);
315 if ( (dylibCmd->dylib.name.offset + strlen((char*)dylibCmd + dylibCmd->dylib.name.offset) + 1) > cmdLength )
316 dyld::throwf("malformed mach-o image: dylib load command #%d string extends beyond end of load command", i);
317 break;
318 case LC_CODE_SIGNATURE:
319 if ( cmd->cmdsize != sizeof(linkedit_data_command) )
320 throw "malformed mach-o image: LC_CODE_SIGNATURE size wrong";
321 // <rdar://problem/22799652> only support one LC_CODE_SIGNATURE per image
322 if ( *codeSigCmd != NULL )
323 throw "malformed mach-o image: multiple LC_CODE_SIGNATURE load commands";
324 *codeSigCmd = (struct linkedit_data_command*)cmd;
325 break;
326 case LC_ENCRYPTION_INFO:
327 if ( cmd->cmdsize != sizeof(encryption_info_command) )
328 throw "malformed mach-o image: LC_ENCRYPTION_INFO size wrong";
329 // <rdar://problem/22799652> only support one LC_ENCRYPTION_INFO per image
330 if ( *encryptCmd != NULL )
331 throw "malformed mach-o image: multiple LC_ENCRYPTION_INFO load commands";
332 *encryptCmd = (encryption_info_command*)cmd;
333 break;
334 case LC_ENCRYPTION_INFO_64:
335 if ( cmd->cmdsize != sizeof(encryption_info_command_64) )
336 throw "malformed mach-o image: LC_ENCRYPTION_INFO_64 size wrong";
337 // <rdar://problem/22799652> only support one LC_ENCRYPTION_INFO_64 per image
338 if ( *encryptCmd != NULL )
339 throw "malformed mach-o image: multiple LC_ENCRYPTION_INFO_64 load commands";
340 *encryptCmd = (encryption_info_command*)cmd;
341 break;
342 case LC_SYMTAB:
343 if ( cmd->cmdsize != sizeof(symtab_command) )
344 throw "malformed mach-o image: LC_SYMTAB size wrong";
345 symTabCmd = (symtab_command*)cmd;
346 break;
347 case LC_DYSYMTAB:
348 if ( cmd->cmdsize != sizeof(dysymtab_command) )
349 throw "malformed mach-o image: LC_DYSYMTAB size wrong";
350 dynSymbTabCmd = (dysymtab_command*)cmd;
351 break;
352 #if __MAC_OS_X_VERSION_MIN_REQUIRED
353 // <rdar://problem/26797345> error when loading iOS Simulator mach-o binary into macOS process
354 case LC_VERSION_MIN_WATCHOS:
355 case LC_VERSION_MIN_TVOS:
356 case LC_VERSION_MIN_IPHONEOS:
357 if ( !context.iOSonMac )
358 throw "mach-o, but built for simulator (not macOS)";
359 break;
360 #endif
361 }
362 cmd = nextCmd;
363 }
364
365 if ( context.strictMachORequired && !foundLoadCommandSegment )
366 throw "load commands not in a segment";
367 if ( linkeditSegCmd == NULL )
368 throw "malformed mach-o image: missing __LINKEDIT segment";
369 if ( !inCache && (startOfFileSegCmd == NULL) )
370 throw "malformed mach-o image: missing __TEXT segment that maps start of file";
371 // <rdar://problem/13145644> verify every segment does not overlap another segment
372 if ( context.strictMachORequired ) {
373 uintptr_t lastFileStart = 0;
374 uintptr_t linkeditFileStart = 0;
375 const struct load_command* cmd1 = startCmds;
376 for (uint32_t i = 0; i < cmd_count; ++i) {
377 if ( cmd1->cmd == LC_SEGMENT_COMMAND ) {
378 struct macho_segment_command* segCmd1 = (struct macho_segment_command*)cmd1;
379 uintptr_t vmStart1 = segCmd1->vmaddr;
380 uintptr_t vmEnd1 = segCmd1->vmaddr + segCmd1->vmsize;
381 uintptr_t fileStart1 = segCmd1->fileoff;
382 uintptr_t fileEnd1 = segCmd1->fileoff + segCmd1->filesize;
383
384 if (fileStart1 > lastFileStart)
385 lastFileStart = fileStart1;
386
387 if ( strcmp(&segCmd1->segname[0], "__LINKEDIT") == 0 ) {
388 linkeditFileStart = fileStart1;
389 }
390
391 const struct load_command* cmd2 = startCmds;
392 for (uint32_t j = 0; j < cmd_count; ++j) {
393 if ( cmd2 == cmd1 )
394 continue;
395 if ( cmd2->cmd == LC_SEGMENT_COMMAND ) {
396 struct macho_segment_command* segCmd2 = (struct macho_segment_command*)cmd2;
397 uintptr_t vmStart2 = segCmd2->vmaddr;
398 uintptr_t vmEnd2 = segCmd2->vmaddr + segCmd2->vmsize;
399 uintptr_t fileStart2 = segCmd2->fileoff;
400 uintptr_t fileEnd2 = segCmd2->fileoff + segCmd2->filesize;
401 if ( ((vmStart2 <= vmStart1) && (vmEnd2 > vmStart1) && (vmEnd1 > vmStart1))
402 || ((vmStart2 >= vmStart1) && (vmStart2 < vmEnd1) && (vmEnd2 > vmStart2)) )
403 dyld::throwf("malformed mach-o image: segment %s vm overlaps segment %s", segCmd1->segname, segCmd2->segname);
404 if ( ((fileStart2 <= fileStart1) && (fileEnd2 > fileStart1) && (fileEnd1 > fileStart1))
405 || ((fileStart2 >= fileStart1) && (fileStart2 < fileEnd1) && (fileEnd2 > fileStart2)) )
406 dyld::throwf("malformed mach-o image: segment %s file content overlaps segment %s", segCmd1->segname, segCmd2->segname);
407 }
408 cmd2 = (const struct load_command*)(((char*)cmd2)+cmd2->cmdsize);
409 }
410 }
411 cmd1 = (const struct load_command*)(((char*)cmd1)+cmd1->cmdsize);
412 }
413
414 if (lastFileStart != linkeditFileStart)
415 dyld::throwf("malformed mach-o image: __LINKEDIT must be last segment");
416 }
417
418 // validate linkedit content
419 if ( (dyldInfoCmd == NULL) && (chainedFixupsCmd == NULL) && (symTabCmd == NULL) )
420 throw "malformed mach-o image: missing LC_SYMTAB, LC_DYLD_INFO, or LC_DYLD_CHAINED_FIXUPS";
421 if ( dynSymbTabCmd == NULL )
422 throw "malformed mach-o image: missing LC_DYSYMTAB";
423
424 uint32_t linkeditFileOffsetStart = (uint32_t)linkeditSegCmd->fileoff;
425 uint32_t linkeditFileOffsetEnd = (uint32_t)linkeditSegCmd->fileoff + (uint32_t)linkeditSegCmd->filesize;
426
427 if ( !inCache && (dyldInfoCmd != NULL) && context.strictMachORequired ) {
428 // validate all LC_DYLD_INFO chunks fit in LINKEDIT and don't overlap
429 uint32_t offset = linkeditFileOffsetStart;
430 if ( dyldInfoCmd->rebase_size != 0 ) {
431 if ( dyldInfoCmd->rebase_size & 0x80000000 )
432 throw "malformed mach-o image: dyld rebase info size overflow";
433 if ( dyldInfoCmd->rebase_off < offset )
434 throw "malformed mach-o image: dyld rebase info underruns __LINKEDIT";
435 offset = dyldInfoCmd->rebase_off + dyldInfoCmd->rebase_size;
436 if ( offset > linkeditFileOffsetEnd )
437 throw "malformed mach-o image: dyld rebase info overruns __LINKEDIT";
438 }
439 if ( dyldInfoCmd->bind_size != 0 ) {
440 if ( dyldInfoCmd->bind_size & 0x80000000 )
441 throw "malformed mach-o image: dyld bind info size overflow";
442 if ( dyldInfoCmd->bind_off < offset )
443 throw "malformed mach-o image: dyld bind info overlaps rebase info";
444 offset = dyldInfoCmd->bind_off + dyldInfoCmd->bind_size;
445 if ( offset > linkeditFileOffsetEnd )
446 throw "malformed mach-o image: dyld bind info overruns __LINKEDIT";
447 }
448 if ( dyldInfoCmd->weak_bind_size != 0 ) {
449 if ( dyldInfoCmd->weak_bind_size & 0x80000000 )
450 throw "malformed mach-o image: dyld weak bind info size overflow";
451 if ( dyldInfoCmd->weak_bind_off < offset )
452 throw "malformed mach-o image: dyld weak bind info overlaps bind info";
453 offset = dyldInfoCmd->weak_bind_off + dyldInfoCmd->weak_bind_size;
454 if ( offset > linkeditFileOffsetEnd )
455 throw "malformed mach-o image: dyld weak bind info overruns __LINKEDIT";
456 }
457 if ( dyldInfoCmd->lazy_bind_size != 0 ) {
458 if ( dyldInfoCmd->lazy_bind_size & 0x80000000 )
459 throw "malformed mach-o image: dyld lazy bind info size overflow";
460 if ( dyldInfoCmd->lazy_bind_off < offset )
461 throw "malformed mach-o image: dyld lazy bind info overlaps weak bind info";
462 offset = dyldInfoCmd->lazy_bind_off + dyldInfoCmd->lazy_bind_size;
463 if ( offset > linkeditFileOffsetEnd )
464 throw "malformed mach-o image: dyld lazy bind info overruns __LINKEDIT";
465 }
466 if ( dyldInfoCmd->export_size != 0 ) {
467 if ( dyldInfoCmd->export_size & 0x80000000 )
468 throw "malformed mach-o image: dyld export info size overflow";
469 if ( dyldInfoCmd->export_off < offset )
470 throw "malformed mach-o image: dyld export info overlaps lazy bind info";
471 offset = dyldInfoCmd->export_off + dyldInfoCmd->export_size;
472 if ( offset > linkeditFileOffsetEnd )
473 throw "malformed mach-o image: dyld export info overruns __LINKEDIT";
474 }
475 }
476
477 if ( !inCache && (chainedFixupsCmd != NULL) && context.strictMachORequired ) {
478 // validate all LC_DYLD_CHAINED_FIXUPS chunks fit in LINKEDIT and don't overlap
479 if ( chainedFixupsCmd->dataoff < linkeditFileOffsetStart )
480 throw "malformed mach-o image: dyld chained fixups info underruns __LINKEDIT";
481 if ( (chainedFixupsCmd->dataoff + chainedFixupsCmd->datasize) > linkeditFileOffsetEnd )
482 throw "malformed mach-o image: dyld chained fixups info overruns __LINKEDIT";
483 }
484
485 if ( !inCache && (exportsTrieCmd != NULL) && context.strictMachORequired ) {
486 // validate all LC_DYLD_EXPORTS_TRIE chunks fit in LINKEDIT and don't overlap
487 if ( exportsTrieCmd->dataoff < linkeditFileOffsetStart )
488 throw "malformed mach-o image: dyld chained fixups info underruns __LINKEDIT";
489 if ( (exportsTrieCmd->dataoff + exportsTrieCmd->datasize) > linkeditFileOffsetEnd )
490 throw "malformed mach-o image: dyld chained fixups info overruns __LINKEDIT";
491 }
492
493 if ( symTabCmd != NULL ) {
494 // validate symbol table fits in LINKEDIT
495 if ( (symTabCmd->nsyms > 0) && (symTabCmd->symoff < linkeditFileOffsetStart) )
496 throw "malformed mach-o image: symbol table underruns __LINKEDIT";
497 if ( symTabCmd->nsyms > 0x10000000 )
498 throw "malformed mach-o image: symbol table too large";
499 uint32_t symbolsSize = symTabCmd->nsyms * sizeof(macho_nlist);
500 if ( symbolsSize > linkeditSegCmd->filesize )
501 throw "malformed mach-o image: symbol table overruns __LINKEDIT";
502 if ( symTabCmd->symoff + symbolsSize < symTabCmd->symoff )
503 throw "malformed mach-o image: symbol table size wraps";
504 if ( symTabCmd->symoff + symbolsSize > symTabCmd->stroff )
505 throw "malformed mach-o image: symbol table overlaps symbol strings";
506 if ( symTabCmd->stroff + symTabCmd->strsize < symTabCmd->stroff )
507 throw "malformed mach-o image: symbol string size wraps";
508 if ( symTabCmd->stroff + symTabCmd->strsize > linkeditFileOffsetEnd ) {
509 // <rdar://problem/24220313> let old apps overflow as long as it stays within mapped page
510 if ( context.strictMachORequired || (symTabCmd->stroff + symTabCmd->strsize > ((linkeditFileOffsetEnd + 4095) & (-4096))) )
511 throw "malformed mach-o image: symbol strings overrun __LINKEDIT";
512 }
513 #if __MAC_OS_X_VERSION_MIN_REQUIRED
514 if ( (symTabCmd->symoff % sizeof(void*)) != 0 ) {
515 // <rdar://53723577> allow old malformed plugins in new app
516 if ( sdkVersion((mach_header*)mh) >= DYLD_PACKED_VERSION(10,15,0) )
517 throw "malformed mach-o image: mis-aligned symbol table __LINKEDIT";
518 }
519 #endif
520 // validate indirect symbol table
521 if ( dynSymbTabCmd->nindirectsyms != 0 ) {
522 if ( dynSymbTabCmd->indirectsymoff < linkeditFileOffsetStart )
523 throw "malformed mach-o image: indirect symbol table underruns __LINKEDIT";
524 if ( dynSymbTabCmd->nindirectsyms > 0x10000000 )
525 throw "malformed mach-o image: indirect symbol table too large";
526 uint32_t indirectTableSize = dynSymbTabCmd->nindirectsyms * sizeof(uint32_t);
527 if ( indirectTableSize > linkeditSegCmd->filesize )
528 throw "malformed mach-o image: indirect symbol table overruns __LINKEDIT";
529 if ( dynSymbTabCmd->indirectsymoff + indirectTableSize < dynSymbTabCmd->indirectsymoff )
530 throw "malformed mach-o image: indirect symbol table size wraps";
531 if ( context.strictMachORequired && (dynSymbTabCmd->indirectsymoff + indirectTableSize > symTabCmd->stroff) )
532 throw "malformed mach-o image: indirect symbol table overruns string pool";
533 }
534 if ( (dynSymbTabCmd->nlocalsym > symTabCmd->nsyms) || (dynSymbTabCmd->ilocalsym > symTabCmd->nsyms) )
535 throw "malformed mach-o image: indirect symbol table local symbol count exceeds total symbols";
536 if ( dynSymbTabCmd->ilocalsym + dynSymbTabCmd->nlocalsym < dynSymbTabCmd->ilocalsym )
537 throw "malformed mach-o image: indirect symbol table local symbol count wraps";
538 if ( (dynSymbTabCmd->nextdefsym > symTabCmd->nsyms) || (dynSymbTabCmd->iextdefsym > symTabCmd->nsyms) )
539 throw "malformed mach-o image: indirect symbol table extern symbol count exceeds total symbols";
540 if ( dynSymbTabCmd->iextdefsym + dynSymbTabCmd->nextdefsym < dynSymbTabCmd->iextdefsym )
541 throw "malformed mach-o image: indirect symbol table extern symbol count wraps";
542 if ( (dynSymbTabCmd->nundefsym > symTabCmd->nsyms) || (dynSymbTabCmd->iundefsym > symTabCmd->nsyms) )
543 throw "malformed mach-o image: indirect symbol table undefined symbol count exceeds total symbols";
544 if ( dynSymbTabCmd->iundefsym + dynSymbTabCmd->nundefsym < dynSymbTabCmd->iundefsym )
545 throw "malformed mach-o image: indirect symbol table undefined symbol count wraps";
546 }
547
548
549 // fSegmentsArrayCount is only 8-bits
550 if ( *segCount > 255 )
551 dyld::throwf("malformed mach-o image: more than 255 segments in %s", path);
552
553 // fSegmentsArrayCount is only 8-bits
554 if ( *libCount > 4095 )
555 dyld::throwf("malformed mach-o image: more than 4095 dependent libraries in %s", path);
556
557 if ( needsAddedLibSystemDepency(*libCount, mh) )
558 *libCount = 1;
559 }
560
561
562
563 // create image for main executable
564 ImageLoader* ImageLoaderMachO::instantiateMainExecutable(const macho_header* mh, uintptr_t slide, const char* path, const LinkContext& context)
565 {
566 //dyld::log("ImageLoader=%ld, ImageLoaderMachO=%ld, ImageLoaderMachOClassic=%ld, ImageLoaderMachOCompressed=%ld\n",
567 // sizeof(ImageLoader), sizeof(ImageLoaderMachO), sizeof(ImageLoaderMachOClassic), sizeof(ImageLoaderMachOCompressed));
568 bool compressed;
569 unsigned int segCount;
570 unsigned int libCount;
571 const linkedit_data_command* codeSigCmd;
572 const encryption_info_command* encryptCmd;
573 sniffLoadCommands(mh, path, false, &compressed, &segCount, &libCount, context, &codeSigCmd, &encryptCmd);
574 // instantiate concrete class based on content of load commands
575 if ( compressed )
576 return ImageLoaderMachOCompressed::instantiateMainExecutable(mh, slide, path, segCount, libCount, context);
577 else
578 #if SUPPORT_CLASSIC_MACHO
579 return ImageLoaderMachOClassic::instantiateMainExecutable(mh, slide, path, segCount, libCount, context);
580 #else
581 throw "missing LC_DYLD_INFO load command";
582 #endif
583 }
584
585
586 // create image by mapping in a mach-o file
587 ImageLoader* ImageLoaderMachO::instantiateFromFile(const char* path, int fd, const uint8_t firstPages[], size_t firstPagesSize, uint64_t offsetInFat,
588 uint64_t lenInFat, const struct stat& info, const LinkContext& context)
589 {
590 bool compressed;
591 unsigned int segCount;
592 unsigned int libCount;
593 const linkedit_data_command* codeSigCmd;
594 const encryption_info_command* encryptCmd;
595 sniffLoadCommands((const macho_header*)firstPages, path, false, &compressed, &segCount, &libCount, context, &codeSigCmd, &encryptCmd);
596 // instantiate concrete class based on content of load commands
597 if ( compressed )
598 return ImageLoaderMachOCompressed::instantiateFromFile(path, fd, firstPages, firstPagesSize, offsetInFat, lenInFat, info, segCount, libCount, codeSigCmd, encryptCmd, context);
599 else
600 #if SUPPORT_CLASSIC_MACHO
601 return ImageLoaderMachOClassic::instantiateFromFile(path, fd, firstPages, firstPagesSize, offsetInFat, lenInFat, info, segCount, libCount, codeSigCmd, context);
602 #else
603 throw "missing LC_DYLD_INFO load command";
604 #endif
605 }
606
607 // create image by using cached mach-o file
608 ImageLoader* ImageLoaderMachO::instantiateFromCache(const macho_header* mh, const char* path, long slide, const struct stat& info, const LinkContext& context)
609 {
610 // instantiate right concrete class
611 bool compressed;
612 unsigned int segCount;
613 unsigned int libCount;
614 const linkedit_data_command* codeSigCmd;
615 const encryption_info_command* encryptCmd;
616 sniffLoadCommands(mh, path, true, &compressed, &segCount, &libCount, context, &codeSigCmd, &encryptCmd);
617 // instantiate concrete class based on content of load commands
618 if ( compressed )
619 return ImageLoaderMachOCompressed::instantiateFromCache(mh, path, slide, info, segCount, libCount, context);
620 else
621 #if SUPPORT_CLASSIC_MACHO
622 return ImageLoaderMachOClassic::instantiateFromCache(mh, path, slide, info, segCount, libCount, context);
623 #else
624 throw "missing LC_DYLD_INFO load command";
625 #endif
626 }
627
628 // create image by copying an in-memory mach-o file
629 ImageLoader* ImageLoaderMachO::instantiateFromMemory(const char* moduleName, const macho_header* mh, uint64_t len, const LinkContext& context)
630 {
631 bool compressed;
632 unsigned int segCount;
633 unsigned int libCount;
634 const linkedit_data_command* sigcmd;
635 const encryption_info_command* encryptCmd;
636 sniffLoadCommands(mh, moduleName, false, &compressed, &segCount, &libCount, context, &sigcmd, &encryptCmd);
637 // instantiate concrete class based on content of load commands
638 if ( compressed )
639 return ImageLoaderMachOCompressed::instantiateFromMemory(moduleName, mh, len, segCount, libCount, context);
640 else
641 #if SUPPORT_CLASSIC_MACHO
642 return ImageLoaderMachOClassic::instantiateFromMemory(moduleName, mh, len, segCount, libCount, context);
643 #else
644 throw "missing LC_DYLD_INFO load command";
645 #endif
646 }
647
648
649 int ImageLoaderMachO::crashIfInvalidCodeSignature()
650 {
651 // Now that segments are mapped in, try reading from first executable segment.
652 // If code signing is enabled the kernel will validate the code signature
653 // when paging in, and kill the process if invalid.
654 for(unsigned int i=0; i < fSegmentsCount; ++i) {
655 if ( (segFileOffset(i) == 0) && (segFileSize(i) != 0) ) {
656 // return read value to ensure compiler does not optimize away load
657 int* p = (int*)segActualLoadAddress(i);
658 return *p;
659 }
660 }
661 return 0;
662 }
663
664
665 void ImageLoaderMachO::parseLoadCmds(const LinkContext& context)
666 {
667 // now that segments are mapped in, get real fMachOData, fLinkEditBase, and fSlide
668 for(unsigned int i=0; i < fSegmentsCount; ++i) {
669 // set up pointer to __LINKEDIT segment
670 if ( strcmp(segName(i),"__LINKEDIT") == 0 ) {
671 #if !__MAC_OS_X_VERSION_MIN_REQUIRED
672 // <rdar://problem/42419336> historically, macOS never did this check
673 if ( segFileOffset(i) > fCoveredCodeLength )
674 dyld::throwf("cannot load '%s' (segment outside of code signature)", this->getShortName());
675 #endif
676 fLinkEditBase = (uint8_t*)(segActualLoadAddress(i) - segFileOffset(i));
677 }
678 #if TEXT_RELOC_SUPPORT
679 // __TEXT segment always starts at beginning of file and contains mach_header and load commands
680 if ( segExecutable(i) ) {
681 if ( segHasRebaseFixUps(i) && (fSlide != 0) )
682 fTextSegmentRebases = true;
683 if ( segHasBindFixUps(i) )
684 fTextSegmentBinds = true;
685 }
686 #else
687 if ( segIsReadOnlyData(i) )
688 fReadOnlyDataSegment = true;
689 #endif
690 #if __i386__
691 if ( segIsReadOnlyImport(i) )
692 fReadOnlyImportSegment = true;
693 #endif
694 // some segment always starts at beginning of file and contains mach_header and load commands
695 if ( (segFileOffset(i) == 0) && (segFileSize(i) != 0) ) {
696 fMachOData = (uint8_t*)(segActualLoadAddress(i));
697 }
698 }
699
700 // keep count of prebound images with weak exports
701 if ( this->participatesInCoalescing() ) {
702 ++fgImagesRequiringCoalescing;
703 fRegisteredAsRequiresCoalescing = true;
704 if ( this->hasCoalescedExports() )
705 ++fgImagesHasWeakDefinitions;
706 }
707
708 // keep count of images used in shared cache
709 if ( fInSharedCache )
710 ++fgImagesUsedFromSharedCache;
711
712 // walk load commands (mapped in at start of __TEXT segment)
713 const dyld_info_command* dyldInfo = NULL;
714 const linkedit_data_command* chainedFixupsCmd = NULL;
715 const linkedit_data_command* exportsTrieCmd = NULL;
716 const macho_nlist* symbolTable = NULL;
717 const char* symbolTableStrings = NULL;
718 const struct load_command* firstUnknownCmd = NULL;
719 const struct version_min_command* minOSVersionCmd = NULL;
720 const dysymtab_command* dynSymbolTable = NULL;
721 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
722 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
723 const struct load_command* cmd = cmds;
724 for (uint32_t i = 0; i < cmd_count; ++i) {
725 switch (cmd->cmd) {
726 case LC_SYMTAB:
727 {
728 const struct symtab_command* symtab = (struct symtab_command*)cmd;
729 symbolTableStrings = (const char*)&fLinkEditBase[symtab->stroff];
730 symbolTable = (macho_nlist*)(&fLinkEditBase[symtab->symoff]);
731 }
732 break;
733 case LC_DYSYMTAB:
734 dynSymbolTable = (struct dysymtab_command*)cmd;
735 break;
736 case LC_SUB_UMBRELLA:
737 fHasSubUmbrella = true;
738 break;
739 case LC_SUB_FRAMEWORK:
740 fInUmbrella = true;
741 break;
742 case LC_SUB_LIBRARY:
743 fHasSubLibraries = true;
744 break;
745 case LC_ROUTINES_COMMAND:
746 fHasDashInit = true;
747 break;
748 case LC_DYLD_INFO:
749 case LC_DYLD_INFO_ONLY:
750 dyldInfo = (struct dyld_info_command*)cmd;
751 break;
752 case LC_DYLD_CHAINED_FIXUPS:
753 chainedFixupsCmd = (struct linkedit_data_command*)cmd;
754 break;
755 case LC_DYLD_EXPORTS_TRIE:
756 exportsTrieCmd = (struct linkedit_data_command*)cmd;
757 break;
758 case LC_SEGMENT_COMMAND:
759 {
760 const struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
761 const bool isTextSeg = (strcmp(seg->segname, "__TEXT") == 0);
762 #if __i386__ && __MAC_OS_X_VERSION_MIN_REQUIRED
763 const bool isObjCSeg = (strcmp(seg->segname, "__OBJC") == 0);
764 if ( isObjCSeg )
765 fNotifyObjC = true;
766 #else
767 const bool isDataSeg = (strncmp(seg->segname, "__DATA", 6) == 0);
768 #endif
769 const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command));
770 const struct macho_section* const sectionsEnd = &sectionsStart[seg->nsects];
771 for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
772 const uint8_t type = sect->flags & SECTION_TYPE;
773 if ( type == S_MOD_INIT_FUNC_POINTERS )
774 fHasInitializers = true;
775 else if ( type == S_INIT_FUNC_OFFSETS )
776 fHasInitializers = true;
777 else if ( type == S_MOD_TERM_FUNC_POINTERS )
778 fHasTerminators = true;
779 else if ( type == S_DTRACE_DOF )
780 fHasDOFSections = true;
781 else if ( isTextSeg && (strcmp(sect->sectname, "__eh_frame") == 0) )
782 fEHFrameSectionOffset = (uint32_t)((uint8_t*)sect - fMachOData);
783 else if ( isTextSeg && (strcmp(sect->sectname, "__unwind_info") == 0) )
784 fUnwindInfoSectionOffset = (uint32_t)((uint8_t*)sect - fMachOData);
785
786 #if __i386__ && __MAC_OS_X_VERSION_MIN_REQUIRED
787 else if ( isObjCSeg ) {
788 if ( strcmp(sect->sectname, "__image_info") == 0 ) {
789 const uint32_t* imageInfo = (uint32_t*)(sect->addr + fSlide);
790 uint32_t flags = imageInfo[1];
791 if ( (flags & 4) && (((macho_header*)fMachOData)->filetype != MH_EXECUTE) )
792 dyld::throwf("cannot load '%s' because Objective-C garbage collection is not supported", getPath());
793 }
794 else if ( ((macho_header*)fMachOData)->filetype == MH_DYLIB ) {
795 fRetainForObjC = true;
796 }
797 }
798 #else
799 else if ( isDataSeg && (strncmp(sect->sectname, "__objc_imageinfo", 16) == 0) ) {
800 #if __MAC_OS_X_VERSION_MIN_REQUIRED
801 const uint32_t* imageInfo = (uint32_t*)(sect->addr + fSlide);
802 uint32_t flags = imageInfo[1];
803 if ( (flags & 4) && (((macho_header*)fMachOData)->filetype != MH_EXECUTE) )
804 dyld::throwf("cannot load '%s' because Objective-C garbage collection is not supported", getPath());
805 #endif
806 fNotifyObjC = true;
807 }
808 else if ( isDataSeg && (strncmp(sect->sectname, "__objc_", 7) == 0) && (((macho_header*)fMachOData)->filetype == MH_DYLIB) )
809 fRetainForObjC = true;
810 #endif
811 }
812 }
813 break;
814 case LC_TWOLEVEL_HINTS:
815 // no longer supported
816 break;
817 case LC_ID_DYLIB:
818 {
819 fDylibIDOffset = (uint32_t)((uint8_t*)cmd - fMachOData);
820 }
821 break;
822 case LC_RPATH:
823 case LC_LOAD_WEAK_DYLIB:
824 case LC_REEXPORT_DYLIB:
825 case LC_LOAD_UPWARD_DYLIB:
826 case LC_MAIN:
827 break;
828 case LC_VERSION_MIN_MACOSX:
829 case LC_VERSION_MIN_IPHONEOS:
830 case LC_VERSION_MIN_TVOS:
831 case LC_VERSION_MIN_WATCHOS:
832 minOSVersionCmd = (version_min_command*)cmd;
833 break;
834 default:
835 if ( (cmd->cmd & LC_REQ_DYLD) != 0 ) {
836 if ( firstUnknownCmd == NULL )
837 firstUnknownCmd = cmd;
838 }
839 break;
840 }
841 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
842 }
843 if ( firstUnknownCmd != NULL ) {
844 if ( minOSVersionCmd != NULL ) {
845 dyld::throwf("cannot load '%s' because it was built for OS version %u.%u (load command 0x%08X is unknown)",
846 this->getShortName(),
847 minOSVersionCmd->version >> 16, ((minOSVersionCmd->version >> 8) & 0xff),
848 firstUnknownCmd->cmd);
849 }
850 else {
851 dyld::throwf("cannot load '%s' (load command 0x%08X is unknown)", this->getShortName(), firstUnknownCmd->cmd);
852 }
853 }
854
855
856 if ( dyldInfo != NULL )
857 this->setDyldInfo(dyldInfo);
858 if ( chainedFixupsCmd != NULL )
859 this->setChainedFixups(chainedFixupsCmd);
860 if ( exportsTrieCmd != NULL )
861 this->setExportsTrie(exportsTrieCmd);
862
863 if ( symbolTable != NULL)
864 this->setSymbolTableInfo(symbolTable, symbolTableStrings, dynSymbolTable);
865 }
866
867 // don't do this work in destructor because we need object to be full subclass
868 // for UnmapSegments() to work
869 void ImageLoaderMachO::destroy()
870 {
871 // update count of images with weak exports
872 if ( fRegisteredAsRequiresCoalescing ) {
873 --fgImagesRequiringCoalescing;
874 if ( this->hasCoalescedExports() )
875 --fgImagesHasWeakDefinitions;
876 }
877
878 // keep count of images used in shared cache
879 if ( fInSharedCache )
880 --fgImagesUsedFromSharedCache;
881
882 // unmap image when done
883 UnmapSegments();
884 }
885
886
887 unsigned int ImageLoaderMachO::segmentCount() const
888 {
889 return fSegmentsCount;
890 }
891
892
893 const macho_segment_command* ImageLoaderMachO::segLoadCommand(unsigned int segIndex) const
894 {
895 uint32_t* lcOffsets = this->segmentCommandOffsets();
896 uint32_t lcOffset = lcOffsets[segIndex];
897 return (macho_segment_command*)(&fMachOData[lcOffset]);
898 }
899
900 const char* ImageLoaderMachO::segName(unsigned int segIndex) const
901 {
902 return segLoadCommand(segIndex)->segname;
903 }
904
905
906 uintptr_t ImageLoaderMachO::segSize(unsigned int segIndex) const
907 {
908 return segLoadCommand(segIndex)->vmsize;
909 }
910
911
912 uintptr_t ImageLoaderMachO::segFileSize(unsigned int segIndex) const
913 {
914 return segLoadCommand(segIndex)->filesize;
915 }
916
917
918 bool ImageLoaderMachO::segHasTrailingZeroFill(unsigned int segIndex)
919 {
920 return ( segWriteable(segIndex) && (segSize(segIndex) > segFileSize(segIndex)) );
921 }
922
923
924 uintptr_t ImageLoaderMachO::segFileOffset(unsigned int segIndex) const
925 {
926 return segLoadCommand(segIndex)->fileoff;
927 }
928
929
930 bool ImageLoaderMachO::segReadable(unsigned int segIndex) const
931 {
932 return ( (segLoadCommand(segIndex)->initprot & VM_PROT_READ) != 0);
933 }
934
935
936 bool ImageLoaderMachO::segWriteable(unsigned int segIndex) const
937 {
938 return ( (segLoadCommand(segIndex)->initprot & VM_PROT_WRITE) != 0);
939 }
940
941
942 bool ImageLoaderMachO::segExecutable(unsigned int segIndex) const
943 {
944 return ( (segLoadCommand(segIndex)->initprot & VM_PROT_EXECUTE) != 0);
945 }
946
947
948 bool ImageLoaderMachO::segUnaccessible(unsigned int segIndex) const
949 {
950 return (segLoadCommand(segIndex)->initprot == 0);
951 }
952
953 bool ImageLoaderMachO::segHasPreferredLoadAddress(unsigned int segIndex) const
954 {
955 return (segLoadCommand(segIndex)->vmaddr != 0);
956 }
957
958 uintptr_t ImageLoaderMachO::segPreferredLoadAddress(unsigned int segIndex) const
959 {
960 return segLoadCommand(segIndex)->vmaddr;
961 }
962
963 uintptr_t ImageLoaderMachO::segActualLoadAddress(unsigned int segIndex) const
964 {
965 return segLoadCommand(segIndex)->vmaddr + fSlide;
966 }
967
968
969 uintptr_t ImageLoaderMachO::segActualEndAddress(unsigned int segIndex) const
970 {
971 return segActualLoadAddress(segIndex) + segSize(segIndex);
972 }
973
974 bool ImageLoaderMachO::segHasRebaseFixUps(unsigned int segIndex) const
975 {
976 #if TEXT_RELOC_SUPPORT
977 // scan sections for fix-up bit
978 const macho_segment_command* segCmd = segLoadCommand(segIndex);
979 const struct macho_section* const sectionsStart = (struct macho_section*)((char*)segCmd + sizeof(struct macho_segment_command));
980 const struct macho_section* const sectionsEnd = &sectionsStart[segCmd->nsects];
981 for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
982 if ( (sect->flags & S_ATTR_LOC_RELOC) != 0 )
983 return true;
984 }
985 #endif
986 return false;
987 }
988
989 bool ImageLoaderMachO::segHasBindFixUps(unsigned int segIndex) const
990 {
991 #if TEXT_RELOC_SUPPORT
992 // scan sections for fix-up bit
993 const macho_segment_command* segCmd = segLoadCommand(segIndex);
994 const struct macho_section* const sectionsStart = (struct macho_section*)((char*)segCmd + sizeof(struct macho_segment_command));
995 const struct macho_section* const sectionsEnd = &sectionsStart[segCmd->nsects];
996 for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
997 if ( (sect->flags & S_ATTR_EXT_RELOC) != 0 )
998 return true;
999 }
1000 #endif
1001 return false;
1002 }
1003
1004 #if __i386__
1005 bool ImageLoaderMachO::segIsReadOnlyImport(unsigned int segIndex) const
1006 {
1007 const macho_segment_command* segCmd = segLoadCommand(segIndex);
1008 return ( (segCmd->initprot & VM_PROT_EXECUTE)
1009 && ((segCmd->initprot & VM_PROT_WRITE) == 0)
1010 && (strcmp(segCmd->segname, "__IMPORT") == 0) );
1011 }
1012 #endif
1013
1014 bool ImageLoaderMachO::segIsReadOnlyData(unsigned int segIndex) const
1015 {
1016 const macho_segment_command* segCmd = segLoadCommand(segIndex);
1017 return ( (segCmd->initprot & VM_PROT_WRITE)
1018 && ((segCmd->initprot & VM_PROT_EXECUTE) == 0)
1019 && (segCmd->flags & SG_READ_ONLY) );
1020 }
1021
1022 void ImageLoaderMachO::UnmapSegments()
1023 {
1024 // usually unmap image when done
1025 if ( ! this->leaveMapped() && (this->getState() >= dyld_image_state_mapped) ) {
1026 // unmap TEXT segment last because it contains load command being inspected
1027 unsigned int textSegmentIndex = 0;
1028 for(unsigned int i=0; i < fSegmentsCount; ++i) {
1029 //dyld::log("unmap %s at 0x%08lX\n", seg->getName(), seg->getActualLoadAddress(this));
1030 if ( (segFileOffset(i) == 0) && (segFileSize(i) != 0) ) {
1031 textSegmentIndex = i;
1032 }
1033 else {
1034 // update stats
1035 --ImageLoader::fgTotalSegmentsMapped;
1036 ImageLoader::fgTotalBytesMapped -= segSize(i);
1037 munmap((void*)segActualLoadAddress(i), segSize(i));
1038 }
1039 }
1040 // now unmap TEXT
1041 --ImageLoader::fgTotalSegmentsMapped;
1042 ImageLoader::fgTotalBytesMapped -= segSize(textSegmentIndex);
1043 munmap((void*)segActualLoadAddress(textSegmentIndex), segSize(textSegmentIndex));
1044 }
1045 }
1046
1047
1048 bool ImageLoaderMachO::segmentsMustSlideTogether() const
1049 {
1050 return true;
1051 }
1052
1053 bool ImageLoaderMachO::segmentsCanSlide() const
1054 {
1055 return (this->isDylib() || this->isBundle() || this->isPositionIndependentExecutable());
1056 }
1057
1058 bool ImageLoaderMachO::isBundle() const
1059 {
1060 const macho_header* mh = (macho_header*)fMachOData;
1061 return ( mh->filetype == MH_BUNDLE );
1062 }
1063
1064 bool ImageLoaderMachO::isDylib() const
1065 {
1066 const macho_header* mh = (macho_header*)fMachOData;
1067 return ( mh->filetype == MH_DYLIB );
1068 }
1069
1070 bool ImageLoaderMachO::isExecutable() const
1071 {
1072 const macho_header* mh = (macho_header*)fMachOData;
1073 return ( mh->filetype == MH_EXECUTE );
1074 }
1075
1076 bool ImageLoaderMachO::isPositionIndependentExecutable() const
1077 {
1078 const macho_header* mh = (macho_header*)fMachOData;
1079 return ( (mh->filetype == MH_EXECUTE) && ((mh->flags & MH_PIE) != 0) );
1080 }
1081
1082
1083 bool ImageLoaderMachO::forceFlat() const
1084 {
1085 const macho_header* mh = (macho_header*)fMachOData;
1086 return ( (mh->flags & MH_FORCE_FLAT) != 0 );
1087 }
1088
1089 bool ImageLoaderMachO::usesTwoLevelNameSpace() const
1090 {
1091 const macho_header* mh = (macho_header*)fMachOData;
1092 return ( (mh->flags & MH_TWOLEVEL) != 0 );
1093 }
1094
1095 bool ImageLoaderMachO::isPrebindable() const
1096 {
1097 const macho_header* mh = (macho_header*)fMachOData;
1098 return ( (mh->flags & MH_PREBOUND) != 0 );
1099 }
1100
1101 bool ImageLoaderMachO::hasCoalescedExports() const
1102 {
1103 const macho_header* mh = (macho_header*)fMachOData;
1104 return ( (mh->flags & MH_WEAK_DEFINES) != 0 );
1105 }
1106
1107 bool ImageLoaderMachO::hasReferencesToWeakSymbols() const
1108 {
1109 const macho_header* mh = (macho_header*)fMachOData;
1110 return ( (mh->flags & MH_BINDS_TO_WEAK) != 0 );
1111 }
1112
1113 bool ImageLoaderMachO::participatesInCoalescing() const
1114 {
1115 const macho_header* mh = (macho_header*)fMachOData;
1116 // if image is loaded with RTLD_LOCAL, then its symbols' visibility
1117 // is reduced and it can't coalesce with other images
1118 if ( this->hasHiddenExports() )
1119 return false;
1120 return ( (mh->flags & (MH_WEAK_DEFINES|MH_BINDS_TO_WEAK)) != 0 );
1121 }
1122
1123
1124
1125 void ImageLoaderMachO::setSlide(intptr_t slide)
1126 {
1127 fSlide = slide;
1128 }
1129
1130 void ImageLoaderMachO::loadCodeSignature(const struct linkedit_data_command* codeSigCmd, int fd, uint64_t offsetInFatFile, const LinkContext& context)
1131 {
1132 dyld3::ScopedTimer(DBG_DYLD_TIMING_ATTACH_CODESIGNATURE, 0, 0, 0);
1133 // if dylib being loaded has no code signature load command
1134 if ( codeSigCmd == NULL) {
1135 disableCoverageCheck();
1136 }
1137 else {
1138 #if __MAC_OS_X_VERSION_MIN_REQUIRED
1139 // <rdar://problem/13622786> ignore code signatures in binaries built with pre-10.9 tools
1140 if ( this->sdkVersion() < DYLD_PACKED_VERSION(10,9,0) ) {
1141 disableCoverageCheck();
1142 return;
1143 }
1144 #endif
1145
1146 fsignatures_t siginfo;
1147 siginfo.fs_file_start=offsetInFatFile; // start of mach-o slice in fat file
1148 siginfo.fs_blob_start=(void*)(long)(codeSigCmd->dataoff); // start of CD in mach-o file
1149 siginfo.fs_blob_size=codeSigCmd->datasize; // size of CD
1150 int result = fcntl(fd, F_ADDFILESIGS_RETURN, &siginfo);
1151
1152 #if TARGET_OS_SIMULATOR
1153 // rdar://problem/18759224> check range covered by the code directory after loading
1154 // Attempt to fallback only if we are in the simulator
1155
1156 if ( result == -1 ) {
1157 result = fcntl(fd, F_ADDFILESIGS, &siginfo);
1158 siginfo.fs_file_start = codeSigCmd->dataoff;
1159 }
1160 #endif
1161
1162 if ( result == -1 ) {
1163 if ( (errno == EPERM) || (errno == EBADEXEC) )
1164 dyld::throwf("code signature invalid for '%s'\n", this->getPath());
1165 if ( context.verboseCodeSignatures )
1166 dyld::log("dyld: Failed registering code signature for %s, errno=%d\n", this->getPath(), errno);
1167 siginfo.fs_file_start = UINT64_MAX;
1168 } else if ( context.verboseCodeSignatures ) {
1169 dyld::log("dyld: Registered code signature for %s\n", this->getPath());
1170 }
1171 fCoveredCodeLength = siginfo.fs_file_start;
1172 }
1173
1174 {
1175 fchecklv checkInfo;
1176 char messageBuffer[512];
1177 messageBuffer[0] = '\0';
1178 checkInfo.lv_file_start = offsetInFatFile;
1179 checkInfo.lv_error_message_size = sizeof(messageBuffer);
1180 checkInfo.lv_error_message = messageBuffer;
1181 int res = fcntl(fd, F_CHECK_LV, &checkInfo);
1182 if ( res == -1 ) {
1183 dyld::throwf("code signature in (%s) not valid for use in process using Library Validation: %s", this->getPath(), messageBuffer);
1184 }
1185 }
1186 }
1187
1188 void ImageLoaderMachO::validateFirstPages(const struct linkedit_data_command* codeSigCmd, int fd, const uint8_t *fileData, size_t lenFileData, off_t offsetInFat, const LinkContext& context)
1189 {
1190 #if __MAC_OS_X_VERSION_MIN_REQUIRED
1191 // rdar://problem/21839703> 15A226d: dyld crashes in mageLoaderMachO::validateFirstPages during dlopen() after encountering an mmap failure
1192 // We need to ignore older code signatures because they will be bad.
1193 if ( this->sdkVersion() < DYLD_PACKED_VERSION(10,9,0) ) {
1194 return;
1195 }
1196 #endif
1197 if (codeSigCmd != NULL) {
1198 void *fdata = xmmap(NULL, lenFileData, PROT_READ, MAP_SHARED, fd, offsetInFat);
1199 if ( fdata == MAP_FAILED ) {
1200 int errnoCopy = errno;
1201 if ( errnoCopy == EPERM ) {
1202 if ( dyld::sandboxBlockedMmap(getPath()) )
1203 dyld::throwf("file system sandbox blocked mmap() of '%s'", getPath());
1204 else
1205 dyld::throwf("code signing blocked mmap() of '%s'", getPath());
1206 }
1207 else
1208 dyld::throwf("mmap() errno=%d validating first page of '%s'", errnoCopy, getPath());
1209 }
1210 if ( memcmp(fdata, fileData, lenFileData) != 0 )
1211 dyld::throwf("mmap() page compare failed for '%s'", getPath());
1212 munmap(fdata, lenFileData);
1213 }
1214 }
1215
1216
1217 const char* ImageLoaderMachO::getInstallPath() const
1218 {
1219 if ( fDylibIDOffset != 0 ) {
1220 const dylib_command* dylibID = (dylib_command*)(&fMachOData[fDylibIDOffset]);
1221 return (char*)dylibID + dylibID->dylib.name.offset;
1222 }
1223 return NULL;
1224 }
1225
1226 void ImageLoaderMachO::registerInterposing(const LinkContext& context)
1227 {
1228 // mach-o files advertise interposing by having a __DATA __interpose section
1229 struct InterposeData { uintptr_t replacement; uintptr_t replacee; };
1230 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
1231 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
1232 const struct load_command* cmd = cmds;
1233 for (uint32_t i = 0; i < cmd_count; ++i) {
1234 switch (cmd->cmd) {
1235 case LC_SEGMENT_COMMAND:
1236 {
1237 const struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
1238 const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command));
1239 const struct macho_section* const sectionsEnd = &sectionsStart[seg->nsects];
1240 for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
1241 if ( ((sect->flags & SECTION_TYPE) == S_INTERPOSING) || ((strcmp(sect->sectname, "__interpose") == 0) && (strcmp(seg->segname, "__DATA") == 0)) ) {
1242 // <rdar://problem/23929217> Ensure section is within segment
1243 if ( (sect->addr < seg->vmaddr) || (sect->addr+sect->size > seg->vmaddr+seg->vmsize) || (sect->addr+sect->size < sect->addr) )
1244 dyld::throwf("interpose section has malformed address range for %s\n", this->getPath());
1245 const InterposeData* interposeArray = (InterposeData*)(sect->addr + fSlide);
1246 const size_t count = sect->size / sizeof(InterposeData);
1247 for (size_t j=0; j < count; ++j) {
1248 ImageLoader::InterposeTuple tuple;
1249 tuple.replacement = interposeArray[j].replacement;
1250 tuple.neverImage = this;
1251 tuple.onlyImage = NULL;
1252 tuple.replacee = interposeArray[j].replacee;
1253 // <rdar://problem/25686570> ignore interposing on a weak function that does not exist
1254 if ( tuple.replacee == 0 )
1255 continue;
1256 // <rdar://problem/7937695> verify that replacement is in this image
1257 if ( this->containsAddress((void*)tuple.replacement) ) {
1258 // chain to any existing interpositions
1259 for (std::vector<InterposeTuple>::iterator it=fgInterposingTuples.begin(); it != fgInterposingTuples.end(); it++) {
1260 if ( it->replacee == tuple.replacee ) {
1261 tuple.replacee = it->replacement;
1262 }
1263 }
1264 ImageLoader::fgInterposingTuples.push_back(tuple);
1265 }
1266 }
1267 }
1268 }
1269 }
1270 break;
1271 }
1272 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
1273 }
1274 }
1275
1276 uint32_t ImageLoaderMachO::sdkVersion(const mach_header* mh)
1277 {
1278 const uint32_t cmd_count = mh->ncmds;
1279 const struct load_command* const cmds = (struct load_command*)(((char*)mh) + sizeof(macho_header));
1280 const struct load_command* cmd = cmds;
1281 const struct version_min_command* versCmd;
1282 const struct build_version_command* buildVersCmd;
1283 for (uint32_t i = 0; i < cmd_count; ++i) {
1284 switch ( cmd->cmd ) {
1285 case LC_VERSION_MIN_MACOSX:
1286 case LC_VERSION_MIN_IPHONEOS:
1287 case LC_VERSION_MIN_TVOS:
1288 case LC_VERSION_MIN_WATCHOS:
1289 versCmd = (version_min_command*)cmd;
1290 return versCmd->sdk;
1291 case LC_BUILD_VERSION:
1292 buildVersCmd = (build_version_command*)cmd;
1293 return buildVersCmd->sdk;
1294 }
1295 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
1296 }
1297 return 0;
1298 }
1299
1300 uint32_t ImageLoaderMachO::sdkVersion() const
1301 {
1302 return ImageLoaderMachO::sdkVersion(machHeader());
1303 }
1304
1305 uint32_t ImageLoaderMachO::minOSVersion(const mach_header* mh)
1306 {
1307 const uint32_t cmd_count = mh->ncmds;
1308 const struct load_command* const cmds = (struct load_command*)(((char*)mh) + sizeof(macho_header));
1309 const struct load_command* cmd = cmds;
1310 const struct version_min_command* versCmd;
1311 const struct build_version_command* buildVersCmd;
1312 for (uint32_t i = 0; i < cmd_count; ++i) {
1313 switch ( cmd->cmd ) {
1314 case LC_VERSION_MIN_MACOSX:
1315 case LC_VERSION_MIN_IPHONEOS:
1316 case LC_VERSION_MIN_TVOS:
1317 case LC_VERSION_MIN_WATCHOS:
1318 versCmd = (version_min_command*)cmd;
1319 return versCmd->version;
1320 case LC_BUILD_VERSION:
1321 buildVersCmd = (build_version_command*)cmd;
1322 return buildVersCmd->minos;
1323 }
1324 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
1325 }
1326 return 0;
1327 }
1328
1329 uint32_t ImageLoaderMachO::minOSVersion() const
1330 {
1331 return ImageLoaderMachO::minOSVersion(machHeader());
1332 }
1333
1334
1335 void* ImageLoaderMachO::getEntryFromLC_MAIN() const
1336 {
1337 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
1338 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
1339 const struct load_command* cmd = cmds;
1340 for (uint32_t i = 0; i < cmd_count; ++i) {
1341 if ( cmd->cmd == LC_MAIN ) {
1342 entry_point_command* mainCmd = (entry_point_command*)cmd;
1343 void* entry = (void*)(mainCmd->entryoff + (char*)fMachOData);
1344 // <rdar://problem/8543820&9228031> verify entry point is in image
1345 if ( this->containsAddress(entry) )
1346 return entry;
1347 else
1348 throw "LC_MAIN entryoff is out of range";
1349 }
1350 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
1351 }
1352 return NULL;
1353 }
1354
1355
1356 void* ImageLoaderMachO::getEntryFromLC_UNIXTHREAD() const
1357 {
1358 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
1359 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
1360 const struct load_command* cmd = cmds;
1361 for (uint32_t i = 0; i < cmd_count; ++i) {
1362 if ( cmd->cmd == LC_UNIXTHREAD ) {
1363 #if __i386__
1364 const i386_thread_state_t* registers = (i386_thread_state_t*)(((char*)cmd) + 16);
1365 void* entry = (void*)(registers->eip + fSlide);
1366 // <rdar://problem/8543820&9228031> verify entry point is in image
1367 if ( this->containsAddress(entry) )
1368 return entry;
1369 #elif __x86_64__
1370 const x86_thread_state64_t* registers = (x86_thread_state64_t*)(((char*)cmd) + 16);
1371 void* entry = (void*)(registers->rip + fSlide);
1372 // <rdar://problem/8543820&9228031> verify entry point is in image
1373 if ( this->containsAddress(entry) )
1374 return entry;
1375 #elif __arm64__ && !__arm64e__
1376 // temp support until <rdar://39514191> is fixed
1377 const uint64_t* regs64 = (uint64_t*)(((char*)cmd) + 16);
1378 void* entry = (void*)(regs64[32] + fSlide); // arm_thread_state64_t.__pc
1379 // <rdar://problem/8543820&9228031> verify entry point is in image
1380 if ( this->containsAddress(entry) )
1381 return entry;
1382 #endif
1383 }
1384 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
1385 }
1386 throw "no valid entry point";
1387 }
1388
1389 bool ImageLoaderMachO::needsAddedLibSystemDepency(unsigned int libCount, const macho_header* mh)
1390 {
1391 // <rdar://problem/6357561> ensure that every image depends on something which depends on libSystem
1392 if ( libCount > 1 )
1393 return false;
1394
1395 // <rdar://problem/6409800> dyld implicit-libSystem breaks valgrind
1396 if ( mh->filetype == MH_EXECUTE )
1397 return false;
1398
1399 bool isNonOSdylib = false;
1400 const uint32_t cmd_count = mh->ncmds;
1401 const struct load_command* const cmds = (struct load_command*)((uint8_t*)mh+sizeof(macho_header));
1402 const struct load_command* cmd = cmds;
1403 for (uint32_t i = 0; i < cmd_count; ++i) {
1404 switch (cmd->cmd) {
1405 case LC_LOAD_DYLIB:
1406 case LC_LOAD_WEAK_DYLIB:
1407 case LC_REEXPORT_DYLIB:
1408 case LC_LOAD_UPWARD_DYLIB:
1409 return false;
1410 case LC_ID_DYLIB:
1411 {
1412 const dylib_command* dylibID = (dylib_command*)cmd;
1413 const char* installPath = (char*)cmd + dylibID->dylib.name.offset;
1414 // It is OK for OS dylibs (libSystem or libmath or Rosetta shims) to have no dependents
1415 // but all other dylibs must depend on libSystem for initialization to initialize libSystem first
1416 // <rdar://problem/6497528> rosetta circular dependency spew
1417 isNonOSdylib = ( (strncmp(installPath, "/usr/lib/", 9) != 0) && (strncmp(installPath, "/System/DriverKit/usr/lib/", 26) != 0) && (strncmp(installPath, "/usr/libexec/oah/Shims", 9) != 0) );
1418 // if (isNonOSdylib) dyld::log("ImageLoaderMachO::needsAddedLibSystemDepency(%s)\n", installPath);
1419 }
1420 break;
1421 }
1422 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
1423 }
1424 return isNonOSdylib;
1425 }
1426
1427
1428 void ImageLoaderMachO::doGetDependentLibraries(DependentLibraryInfo libs[])
1429 {
1430 if ( needsAddedLibSystemDepency(libraryCount(), (macho_header*)fMachOData) ) {
1431 DependentLibraryInfo* lib = &libs[0];
1432 lib->name = LIBSYSTEM_DYLIB_PATH;
1433 lib->info.checksum = 0;
1434 lib->info.minVersion = 0;
1435 lib->info.maxVersion = 0;
1436 lib->required = false;
1437 lib->reExported = false;
1438 lib->upward = false;
1439 }
1440 else {
1441 uint32_t index = 0;
1442 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
1443 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
1444 const struct load_command* cmd = cmds;
1445 for (uint32_t i = 0; i < cmd_count; ++i) {
1446 switch (cmd->cmd) {
1447 case LC_LOAD_DYLIB:
1448 case LC_LOAD_WEAK_DYLIB:
1449 case LC_REEXPORT_DYLIB:
1450 case LC_LOAD_UPWARD_DYLIB:
1451 {
1452 const struct dylib_command* dylib = (struct dylib_command*)cmd;
1453 DependentLibraryInfo* lib = &libs[index++];
1454 lib->name = (char*)cmd + dylib->dylib.name.offset;
1455 //lib->name = strdup((char*)cmd + dylib->dylib.name.offset);
1456 lib->info.checksum = dylib->dylib.timestamp;
1457 lib->info.minVersion = dylib->dylib.compatibility_version;
1458 lib->info.maxVersion = dylib->dylib.current_version;
1459 lib->required = (cmd->cmd != LC_LOAD_WEAK_DYLIB);
1460 lib->reExported = (cmd->cmd == LC_REEXPORT_DYLIB);
1461 lib->upward = (cmd->cmd == LC_LOAD_UPWARD_DYLIB);
1462 }
1463 break;
1464 }
1465 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
1466 }
1467 }
1468 }
1469
1470 ImageLoader::LibraryInfo ImageLoaderMachO::doGetLibraryInfo(const LibraryInfo&)
1471 {
1472 LibraryInfo info;
1473 if ( fDylibIDOffset != 0 ) {
1474 const dylib_command* dylibID = (dylib_command*)(&fMachOData[fDylibIDOffset]);
1475 info.minVersion = dylibID->dylib.compatibility_version;
1476 info.maxVersion = dylibID->dylib.current_version;
1477 info.checksum = dylibID->dylib.timestamp;
1478 }
1479 else {
1480 info.minVersion = 0;
1481 info.maxVersion = 0;
1482 info.checksum = 0;
1483 }
1484 return info;
1485 }
1486
1487 void ImageLoaderMachO::getRPaths(const LinkContext& context, std::vector<const char*>& paths) const
1488 {
1489 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
1490 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
1491 const struct load_command* cmd = cmds;
1492 for (uint32_t i = 0; i < cmd_count; ++i) {
1493 switch (cmd->cmd) {
1494 case LC_RPATH:
1495 const char* pathToAdd = NULL;
1496 const char* path = (char*)cmd + ((struct rpath_command*)cmd)->path.offset;
1497 if ( (strncmp(path, "@loader_path", 12) == 0) && ((path[12] == '/') || (path[12] == '\0')) ) {
1498 if ( !context.allowAtPaths && (context.mainExecutable == this) ) {
1499 dyld::warn("LC_RPATH %s in %s being ignored in restricted program because of @loader_path (Codesign main executable with Library Validation to allow @ paths)\n", path, this->getPath());
1500 break;
1501 }
1502 char resolvedPath[PATH_MAX];
1503 if ( realpath(this->getPath(), resolvedPath) != NULL ) {
1504 char newRealPath[strlen(resolvedPath) + strlen(path)];
1505 strcpy(newRealPath, resolvedPath);
1506 char* addPoint = strrchr(newRealPath,'/');
1507 if ( addPoint != NULL ) {
1508 strcpy(addPoint, &path[12]);
1509 pathToAdd = strdup(newRealPath);
1510 }
1511 }
1512 }
1513 else if ( (strncmp(path, "@executable_path", 16) == 0) && ((path[16] == '/') || (path[16] == '\0')) ) {
1514 if ( !context.allowAtPaths) {
1515 dyld::warn("LC_RPATH %s in %s being ignored in restricted program because of @executable_path (Codesign main executable with Library Validation to allow @ paths)\n", path, this->getPath());
1516 break;
1517 }
1518 char resolvedPath[PATH_MAX];
1519 if ( realpath(context.mainExecutable->getPath(), resolvedPath) != NULL ) {
1520 char newRealPath[strlen(resolvedPath) + strlen(path)];
1521 strcpy(newRealPath, resolvedPath);
1522 char* addPoint = strrchr(newRealPath,'/');
1523 if ( addPoint != NULL ) {
1524 strcpy(addPoint, &path[16]);
1525 pathToAdd = strdup(newRealPath);
1526 }
1527 }
1528 }
1529 else if ( (path[0] != '/') && !context.allowAtPaths) {
1530 dyld::warn("LC_RPATH %s in %s being ignored in restricted program because it is a relative path\n", path, this->getPath());
1531 break;
1532 }
1533 #if SUPPORT_ROOT_PATH
1534 else if ( (path[0] == '/') && (context.rootPaths != NULL) ) {
1535 // <rdar://problem/5869973> DYLD_ROOT_PATH should apply to LC_RPATH rpaths
1536 // <rdar://problem/49576123> Even if DYLD_ROOT_PATH exists, LC_RPATH should add raw path to rpaths
1537 // DYLD_ROOT_PATH can be a list of paths, but at this point we can only support one, so use first combination that exists
1538 for (const char** rp = context.rootPaths; *rp != NULL; ++rp) {
1539 char newPath[PATH_MAX];
1540 strlcpy(newPath, *rp, PATH_MAX);
1541 strlcat(newPath, path, PATH_MAX);
1542 struct stat stat_buf;
1543 if ( stat(newPath, &stat_buf) != -1 ) {
1544 // dyld::log("combined DYLD_ROOT_PATH and LC_RPATH: %s\n", newPath);
1545 paths.push_back(strdup(newPath));
1546 }
1547 }
1548 // add in raw absolute path without root prefix
1549 pathToAdd = strdup(path);
1550 }
1551 #endif
1552 else {
1553 // realpath() is slow, and /usr/lib/swift is a real path, so don't realpath it
1554 if ( strcmp(path, "/usr/lib/swift") != 0 ) {
1555 char resolvedPath[PATH_MAX];
1556 if ( (realpath(path, resolvedPath) != NULL) && (strcmp(path, resolvedPath) != 0) ) {
1557 // <rdar://problem/45470293> support LC_RPATH symlinks to directories of things in the dyld cache
1558 path = resolvedPath;
1559 }
1560 }
1561 // make copy so that all elements of 'paths' can be freed
1562 pathToAdd = strdup(path);
1563 }
1564 if ( pathToAdd != NULL )
1565 paths.push_back(pathToAdd);
1566 break;
1567 }
1568 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
1569 }
1570 }
1571
1572
1573 bool ImageLoaderMachO::getUUID(uuid_t uuid) const
1574 {
1575 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
1576 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
1577 const struct load_command* cmd = cmds;
1578 for (uint32_t i = 0; i < cmd_count; ++i) {
1579 switch (cmd->cmd) {
1580 case LC_UUID:
1581 uuid_command* uc = (uuid_command*)cmd;
1582 memcpy(uuid, uc->uuid, 16);
1583 return true;
1584 }
1585 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
1586 }
1587 bzero(uuid, 16);
1588 return false;
1589 }
1590
1591 void ImageLoaderMachO::doRebase(const LinkContext& context)
1592 {
1593 // <rdar://problem/25329861> Delay calling setNeverUnload() until we know this is not for dlopen_preflight()
1594 if ( fRetainForObjC )
1595 this->setNeverUnload();
1596
1597 // dylibs with thread local variables cannot be unloaded because there is no way to clean up all threads
1598 if ( !this->inSharedCache() && (this->machHeader()->flags & MH_HAS_TLV_DESCRIPTORS) )
1599 this->setNeverUnload();
1600
1601 // if prebound and loaded at prebound address, then no need to rebase
1602 if ( this->usablePrebinding(context) ) {
1603 // skip rebasing because prebinding is valid
1604 ++fgImagesWithUsedPrebinding; // bump totals for statistics
1605 return;
1606 }
1607
1608 // print why prebinding was not used
1609 if ( context.verbosePrebinding ) {
1610 if ( !this->isPrebindable() ) {
1611 dyld::log("dyld: image not prebound, so could not use prebinding in %s\n", this->getPath());
1612 }
1613 else if ( fSlide != 0 ) {
1614 dyld::log("dyld: image slid, so could not use prebinding in %s\n", this->getPath());
1615 }
1616 else if ( !this->allDependentLibrariesAsWhenPreBound() ) {
1617 dyld::log("dyld: dependent libraries changed, so could not use prebinding in %s\n", this->getPath());
1618 }
1619 else if ( !this->usesTwoLevelNameSpace() ){
1620 dyld::log("dyld: image uses flat-namespace so, parts of prebinding ignored %s\n", this->getPath());
1621 }
1622 else {
1623 dyld::log("dyld: environment variable disabled use of prebinding in %s\n", this->getPath());
1624 }
1625 }
1626
1627 //dyld::log("slide=0x%08lX for %s\n", slide, this->getPath());
1628
1629 #if PREBOUND_IMAGE_SUPPORT
1630 // if prebound and we got here, then prebinding is not valid, so reset all lazy pointers
1631 // if this image is in the shared cache, do not reset, they will be bound in doBind()
1632 if ( this->isPrebindable() && !fInSharedCache )
1633 this->resetPreboundLazyPointers(context);
1634 #endif
1635
1636 // if loaded at preferred address, no rebasing necessary
1637 if ( this->fSlide == 0 )
1638 return;
1639
1640 #if TEXT_RELOC_SUPPORT
1641 // if there are __TEXT fixups, temporarily make __TEXT writable
1642 if ( fTextSegmentRebases )
1643 this->makeTextSegmentWritable(context, true);
1644 #endif
1645
1646 // do actual rebasing
1647 this->rebase(context, fSlide);
1648
1649 #if TEXT_RELOC_SUPPORT
1650 // if there were __TEXT fixups, restore write protection
1651 if ( fTextSegmentRebases )
1652 this->makeTextSegmentWritable(context, false);
1653
1654 #endif
1655 }
1656
1657 #if TEXT_RELOC_SUPPORT
1658 void ImageLoaderMachO::makeTextSegmentWritable(const LinkContext& context, bool writeable)
1659 {
1660 for(unsigned int i=0; i < fSegmentsCount; ++i) {
1661 if ( segExecutable(i) ) {
1662 if ( writeable ) {
1663 segMakeWritable(i, context);
1664 }
1665 else {
1666 #if !__i386__ && !__x86_64__
1667 // some processors require range to be invalidated before it is made executable
1668 sys_icache_invalidate((void*)segActualLoadAddress(i), segSize(textSegmentIndex));
1669 #endif
1670 segProtect(i, context);
1671 }
1672 }
1673 }
1674
1675 }
1676 #endif
1677
1678 const ImageLoader::Symbol* ImageLoaderMachO::findExportedSymbol(const char* name, bool searchReExports, const char* thisPath, const ImageLoader** foundIn) const
1679 {
1680 // look in this image first
1681 const ImageLoader::Symbol* result = this->findShallowExportedSymbol(name, foundIn);
1682 if ( result != NULL )
1683 return result;
1684
1685 if ( searchReExports ) {
1686 for(unsigned int i=0; i < libraryCount(); ++i){
1687 if ( libReExported(i) ) {
1688 ImageLoader* image = libImage(i);
1689 if ( image != NULL ) {
1690 const char* reExPath = libPath(i);
1691 result = image->findExportedSymbol(name, searchReExports, reExPath, foundIn);
1692 if ( result != NULL )
1693 return result;
1694 }
1695 }
1696 }
1697 }
1698
1699
1700 return NULL;
1701 }
1702
1703
1704
1705 uintptr_t ImageLoaderMachO::getExportedSymbolAddress(const Symbol* sym, const LinkContext& context,
1706 const ImageLoader* requestor, bool runResolver, const char* symbolName) const
1707 {
1708 return this->getSymbolAddress(sym, requestor, context, runResolver);
1709 }
1710
1711 uintptr_t ImageLoaderMachO::getSymbolAddress(const Symbol* sym, const ImageLoader* requestor,
1712 const LinkContext& context, bool runResolver) const
1713 {
1714 uintptr_t result = exportedSymbolAddress(context, sym, requestor, runResolver);
1715 // check for interposing overrides
1716 result = interposedAddress(context, result, requestor);
1717 return result;
1718 }
1719
1720 ImageLoader::DefinitionFlags ImageLoaderMachO::getExportedSymbolInfo(const Symbol* sym) const
1721 {
1722 if ( exportedSymbolIsWeakDefintion(sym) )
1723 return kWeakDefinition;
1724 else
1725 return kNoDefinitionOptions;
1726 }
1727
1728 const char* ImageLoaderMachO::getExportedSymbolName(const Symbol* sym) const
1729 {
1730 return exportedSymbolName(sym);
1731 }
1732
1733 uint32_t ImageLoaderMachO::getExportedSymbolCount() const
1734 {
1735 return exportedSymbolCount();
1736 }
1737
1738
1739 const ImageLoader::Symbol* ImageLoaderMachO::getIndexedExportedSymbol(uint32_t index) const
1740 {
1741 return exportedSymbolIndexed(index);
1742 }
1743
1744
1745 uint32_t ImageLoaderMachO::getImportedSymbolCount() const
1746 {
1747 return importedSymbolCount();
1748 }
1749
1750
1751 const ImageLoader::Symbol* ImageLoaderMachO::getIndexedImportedSymbol(uint32_t index) const
1752 {
1753 return importedSymbolIndexed(index);
1754 }
1755
1756
1757 ImageLoader::ReferenceFlags ImageLoaderMachO::getImportedSymbolInfo(const ImageLoader::Symbol* sym) const
1758 {
1759 ImageLoader::ReferenceFlags flags = kNoReferenceOptions;
1760 return flags;
1761 }
1762
1763
1764 const char* ImageLoaderMachO::getImportedSymbolName(const ImageLoader::Symbol* sym) const
1765 {
1766 return importedSymbolName(sym);
1767 }
1768
1769
1770 bool ImageLoaderMachO::getSectionContent(const char* segmentName, const char* sectionName, void** start, size_t* length)
1771 {
1772 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
1773 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
1774 const struct load_command* cmd = cmds;
1775 for (uint32_t i = 0; i < cmd_count; ++i) {
1776 switch (cmd->cmd) {
1777 case LC_SEGMENT_COMMAND:
1778 {
1779 const struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
1780 const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command));
1781 const struct macho_section* const sectionsEnd = &sectionsStart[seg->nsects];
1782 for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
1783 if ( (strcmp(sect->segname, segmentName) == 0) && (strcmp(sect->sectname, sectionName) == 0) ) {
1784 *start = (uintptr_t*)(sect->addr + fSlide);
1785 *length = sect->size;
1786 return true;
1787 }
1788 }
1789 }
1790 break;
1791 }
1792 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
1793 }
1794 *start = NULL;
1795 *length = 0;
1796 return false;
1797 }
1798
1799 void ImageLoaderMachO::getUnwindInfo(dyld_unwind_sections* info)
1800 {
1801 info->mh = this->machHeader();
1802 info->dwarf_section = 0;
1803 info->dwarf_section_length = 0;
1804 info->compact_unwind_section = 0;
1805 info->compact_unwind_section_length = 0;
1806 if ( fEHFrameSectionOffset != 0 ) {
1807 const macho_section* sect = (macho_section*)&fMachOData[fEHFrameSectionOffset];
1808 info->dwarf_section = (void*)(sect->addr + fSlide);
1809 info->dwarf_section_length = sect->size;
1810 }
1811 if ( fUnwindInfoSectionOffset != 0 ) {
1812 const macho_section* sect = (macho_section*)&fMachOData[fUnwindInfoSectionOffset];
1813 info->compact_unwind_section = (void*)(sect->addr + fSlide);
1814 info->compact_unwind_section_length = sect->size;
1815 }
1816 }
1817
1818 intptr_t ImageLoaderMachO::computeSlide(const mach_header* mh)
1819 {
1820 const uint32_t cmd_count = mh->ncmds;
1821 const load_command* const cmds = (load_command*)((char*)mh + sizeof(macho_header));
1822 const load_command* cmd = cmds;
1823 for (uint32_t i = 0; i < cmd_count; ++i) {
1824 if ( cmd->cmd == LC_SEGMENT_COMMAND ) {
1825 const macho_segment_command* seg = (macho_segment_command*)cmd;
1826 if ( strcmp(seg->segname, "__TEXT") == 0 )
1827 return (char*)mh - (char*)(seg->vmaddr);
1828 }
1829 cmd = (const load_command*)(((char*)cmd)+cmd->cmdsize);
1830 }
1831 return 0;
1832 }
1833
1834 bool ImageLoaderMachO::findSection(const mach_header* mh, const char* segmentName, const char* sectionName, void** sectAddress, size_t* sectSize)
1835 {
1836 const uint32_t cmd_count = mh->ncmds;
1837 const load_command* const cmds = (load_command*)((char*)mh + sizeof(macho_header));
1838 const load_command* cmd = cmds;
1839 for (uint32_t i = 0; i < cmd_count; ++i) {
1840 switch (cmd->cmd) {
1841 case LC_SEGMENT_COMMAND:
1842 {
1843 const macho_segment_command* seg = (macho_segment_command*)cmd;
1844 const macho_section* const sectionsStart = (macho_section*)((char*)seg + sizeof(macho_segment_command));
1845 const macho_section* const sectionsEnd = &sectionsStart[seg->nsects];
1846 for (const macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
1847 if ( (strcmp(sect->segname, segmentName) == 0) && (strcmp(sect->sectname, sectionName) == 0) ) {
1848 *sectAddress = (void*)(sect->addr + computeSlide(mh));
1849 *sectSize = sect->size;
1850 return true;
1851 }
1852 }
1853 }
1854 break;
1855 }
1856 cmd = (const load_command*)(((char*)cmd)+cmd->cmdsize);
1857 }
1858 return false;
1859 }
1860
1861
1862 const macho_section* ImageLoaderMachO::findSection(const void* imageInterior) const
1863 {
1864 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
1865 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
1866 const struct load_command* cmd = cmds;
1867 const uintptr_t unslidInteriorAddress = (uintptr_t)imageInterior - this->getSlide();
1868 for (uint32_t i = 0; i < cmd_count; ++i) {
1869 switch (cmd->cmd) {
1870 case LC_SEGMENT_COMMAND:
1871 {
1872 const struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
1873 if ( (unslidInteriorAddress >= seg->vmaddr) && (unslidInteriorAddress < (seg->vmaddr+seg->vmsize)) ) {
1874 const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command));
1875 const struct macho_section* const sectionsEnd = &sectionsStart[seg->nsects];
1876 for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
1877 if ((sect->addr <= unslidInteriorAddress) && (unslidInteriorAddress < (sect->addr+sect->size))) {
1878 return sect;
1879 }
1880 }
1881 }
1882 }
1883 break;
1884 }
1885 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
1886 }
1887 return nullptr;
1888 }
1889
1890
1891 bool ImageLoaderMachO::findSection(const void* imageInterior, const char** segmentName, const char** sectionName, size_t* sectionOffset)
1892 {
1893 if (const struct macho_section* sect = findSection(imageInterior)) {
1894 const uintptr_t unslidInteriorAddress = (uintptr_t)imageInterior - this->getSlide();
1895 if ( segmentName != NULL )
1896 *segmentName = sect->segname;
1897 if ( sectionName != NULL )
1898 *sectionName = sect->sectname;
1899 if ( sectionOffset != NULL )
1900 *sectionOffset = unslidInteriorAddress - sect->addr;
1901 return true;
1902 }
1903 return false;
1904 }
1905
1906 const char* ImageLoaderMachO::libPath(unsigned int index) const
1907 {
1908 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
1909 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
1910 const struct load_command* cmd = cmds;
1911 unsigned count = 0;
1912 for (uint32_t i = 0; i < cmd_count; ++i) {
1913 switch ( cmd->cmd ) {
1914 case LC_LOAD_DYLIB:
1915 case LC_LOAD_WEAK_DYLIB:
1916 case LC_REEXPORT_DYLIB:
1917 case LC_LOAD_UPWARD_DYLIB:
1918 if ( index == count ) {
1919 const struct dylib_command* dylibCmd = (struct dylib_command*)cmd;
1920 return (char*)cmd + dylibCmd->dylib.name.offset;
1921 }
1922 ++count;
1923 break;
1924 }
1925 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
1926 }
1927
1928 // <rdar://problem/24256354> if image linked with nothing and we implicitly added libSystem.dylib, return that
1929 if ( needsAddedLibSystemDepency(libraryCount(), (macho_header*)fMachOData) ) {
1930 return LIBSYSTEM_DYLIB_PATH;
1931 }
1932
1933 return NULL;
1934 }
1935
1936
1937 void __attribute__((noreturn)) ImageLoaderMachO::throwSymbolNotFound(const LinkContext& context, const char* symbol,
1938 const char* referencedFrom, const char* fromVersMismatch,
1939 const char* expectedIn)
1940 {
1941 // record values for possible use by CrashReporter or Finder
1942 (*context.setErrorStrings)(DYLD_EXIT_REASON_SYMBOL_MISSING, referencedFrom, expectedIn, symbol);
1943 dyld::throwf("Symbol not found: %s\n Referenced from: %s%s\n Expected in: %s\n",
1944 symbol, referencedFrom, fromVersMismatch, expectedIn);
1945 }
1946
1947 const mach_header* ImageLoaderMachO::machHeader() const
1948 {
1949 return (mach_header*)fMachOData;
1950 }
1951
1952 uintptr_t ImageLoaderMachO::getSlide() const
1953 {
1954 return fSlide;
1955 }
1956
1957 // hmm. maybe this should be up in ImageLoader??
1958 const void* ImageLoaderMachO::getEnd() const
1959 {
1960 uintptr_t lastAddress = 0;
1961 for(unsigned int i=0; i < fSegmentsCount; ++i) {
1962 uintptr_t segEnd = segActualEndAddress(i);
1963 if ( strcmp(segName(i), "__UNIXSTACK") != 0 ) {
1964 if ( segEnd > lastAddress )
1965 lastAddress = segEnd;
1966 }
1967 }
1968 return (const void*)lastAddress;
1969 }
1970
1971 uintptr_t ImageLoaderMachO::bindLocation(const LinkContext& context, uintptr_t baseVMAddress,
1972 uintptr_t location, uintptr_t value,
1973 uint8_t type, const char* symbolName,
1974 intptr_t addend, const char* inPath, const char* toPath, const char* msg,
1975 ExtraBindData *extraBindData, uintptr_t slide)
1976 {
1977 auto logBind = [&]() {
1978 if ( !context.verboseBind )
1979 return;
1980 if ( addend != 0 ) {
1981 dyld::log("dyld: %sbind: %s:0x%08lX = %s:%s, *0x%08lX = 0x%08lX + %ld\n",
1982 msg, shortName(inPath), (uintptr_t)location,
1983 ((toPath != NULL) ? shortName(toPath) : "<missing weak_import>"),
1984 symbolName, (uintptr_t)location, value, addend);
1985 } else {
1986 dyld::log("dyld: %sbind: %s:0x%08lX = %s:%s, *0x%08lX = 0x%08lX\n",
1987 msg, shortName(inPath), (uintptr_t)location,
1988 ((toPath != NULL) ? shortName(toPath) : "<missing weak_import>"),
1989 symbolName, (uintptr_t)location, value);
1990 }
1991 };
1992
1993
1994 #if LOG_BINDINGS
1995 // dyld::logBindings("%s: %s\n", targetImage->getShortName(), symbolName);
1996 #endif
1997
1998 // do actual update
1999 uintptr_t* locationToFix = (uintptr_t*)location;
2000 uint32_t* loc32;
2001 uintptr_t newValue = value+addend;
2002 uint32_t value32;
2003 switch (type) {
2004 case BIND_TYPE_POINTER:
2005 logBind();
2006 // test first so we don't needless dirty pages
2007 if ( *locationToFix != newValue )
2008 *locationToFix = newValue;
2009 break;
2010 case BIND_TYPE_TEXT_ABSOLUTE32:
2011 logBind();
2012 loc32 = (uint32_t*)locationToFix;
2013 value32 = (uint32_t)newValue;
2014 if ( *loc32 != value32 )
2015 *loc32 = value32;
2016 break;
2017 case BIND_TYPE_TEXT_PCREL32:
2018 logBind();
2019 loc32 = (uint32_t*)locationToFix;
2020 value32 = (uint32_t)(newValue - (((uintptr_t)locationToFix) + 4));
2021 if ( *loc32 != value32 )
2022 *loc32 = value32;
2023 break;
2024 case BIND_TYPE_THREADED_BIND:
2025 logBind();
2026 // test first so we don't needless dirty pages
2027 if ( *locationToFix != newValue )
2028 *locationToFix = newValue;
2029 break;
2030 case BIND_TYPE_THREADED_REBASE: {
2031 // Regular pointer which needs to fit in 51-bits of value.
2032 // C++ RTTI uses the top bit, so we'll allow the whole top-byte
2033 // and the signed-extended bottom 43-bits to be fit in to 51-bits.
2034 uint64_t top8Bits = *locationToFix & 0x0007F80000000000ULL;
2035 uint64_t bottom43Bits = *locationToFix & 0x000007FFFFFFFFFFULL;
2036 uint64_t targetValue = ( top8Bits << 13 ) | (((intptr_t)(bottom43Bits << 21) >> 21) & 0x00FFFFFFFFFFFFFF);
2037 newValue = (uintptr_t)(targetValue + slide);
2038 if ( context.verboseRebase ) {
2039 dyld::log("dyld: rebase: %s:*0x%08lX += 0x%08lX = 0x%08lX\n", shortName(inPath), (uintptr_t)locationToFix, slide, newValue);
2040 }
2041 *locationToFix = newValue;
2042 break;
2043 }
2044 default:
2045 dyld::throwf("bad bind type %d", type);
2046 }
2047
2048 // update statistics
2049 ++fgTotalBindFixups;
2050
2051 return newValue;
2052 }
2053
2054
2055
2056
2057
2058 #if SUPPORT_OLD_CRT_INITIALIZATION
2059 // first 16 bytes of "start" in crt1.o
2060 #if __i386__
2061 static uint8_t sStandardEntryPointInstructions[16] = { 0x6a, 0x00, 0x89, 0xe5, 0x83, 0xe4, 0xf0, 0x83, 0xec, 0x10, 0x8b, 0x5d, 0x04, 0x89, 0x5c, 0x24 };
2062 #endif
2063 #endif
2064
2065 struct DATAdyld {
2066 void* dyldLazyBinder; // filled in at launch by dyld to point into dyld to &stub_binding_helper
2067 void* dyldFuncLookup; // filled in at launch by dyld to point into dyld to &_dyld_func_lookup
2068 // the following only exist in main executables built for 10.5 or later
2069 ProgramVars vars;
2070 };
2071
2072 // These are defined in dyldStartup.s
2073 extern "C" void stub_binding_helper();
2074 extern "C" int _dyld_func_lookup(const char* name, void** address);
2075
2076 static const char* libDyldPath(const ImageLoader::LinkContext& context)
2077 {
2078 #if __MAC_OS_X_VERSION_MIN_REQUIRED
2079 if ( context.driverKit )
2080 return DRIVERKIT_LIBDYLD_DYLIB_PATH;
2081 else
2082 #endif
2083 return LIBDYLD_DYLIB_PATH;
2084 }
2085
2086 void ImageLoaderMachO::setupLazyPointerHandler(const LinkContext& context)
2087 {
2088 const macho_header* mh = (macho_header*)fMachOData;
2089 const uint32_t cmd_count = mh->ncmds;
2090 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
2091 const struct load_command* cmd;
2092 // There used to be some optimizations to skip this section scan, but we need to handle the
2093 // __dyld section in libdyld.dylib, so everything needs to be scanned for now.
2094 // <rdar://problem/10910062> CrashTracer: 1,295 crashes in bash at bash: getenv
2095 if ( true ) {
2096 cmd = cmds;
2097 for (uint32_t i = 0; i < cmd_count; ++i) {
2098 if ( cmd->cmd == LC_SEGMENT_COMMAND ) {
2099 const struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
2100 if ( strncmp(seg->segname, "__DATA", 6) == 0 ) {
2101 const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command));
2102 const struct macho_section* const sectionsEnd = &sectionsStart[seg->nsects];
2103 for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
2104 if ( strcmp(sect->sectname, "__dyld" ) == 0 ) {
2105 struct DATAdyld* dd = (struct DATAdyld*)(sect->addr + fSlide);
2106 #if !__arm64__ && !__ARM_ARCH_7K__
2107 if ( sect->size > offsetof(DATAdyld, dyldLazyBinder) ) {
2108 if ( dd->dyldLazyBinder != (void*)&stub_binding_helper )
2109 dd->dyldLazyBinder = (void*)&stub_binding_helper;
2110 }
2111 #endif // !__arm64__
2112 // <rdar://problem/40352925> Add work around for existing apps that have deprecated __dyld section
2113 const char* installNm = this->getInstallPath();
2114 if ( (mh->filetype != MH_DYLIB) || (installNm == NULL) || (strcmp(installNm, libDyldPath(context)) != 0) ) {
2115 #if TARGET_OS_OSX
2116 // don't allow macOS apps build with 10.14 or later SDK and targeting 10.8 or later to have a __dyld section
2117 if ( (minOSVersion() >= 0x000a0800) && (sdkVersion() >= 0x000a0e00) )
2118 dyld::throwf("__dyld section not supported in %s", this->getPath());
2119 #endif
2120 #if TARGET_OS_IOS || TARGET_OS_TV
2121 // don't allow iOS apps build with 12.0 or later SDK to have a __dyld section
2122 if ( sdkVersion() >= 0x000c0000 )
2123 dyld::throwf("__dyld section not supported in %s", this->getPath());
2124 #endif
2125 #if TARGET_OS_WATCH
2126 if ( sdkVersion() >= 0x00050000 )
2127 dyld::throwf("__dyld section not supported in %s", this->getPath());
2128 #endif
2129 }
2130 if ( sect->size > offsetof(DATAdyld, dyldFuncLookup) ) {
2131 if ( dd->dyldFuncLookup != (void*)&_dyld_func_lookup )
2132 dd->dyldFuncLookup = (void*)&_dyld_func_lookup;
2133 }
2134 if ( mh->filetype == MH_EXECUTE ) {
2135 // there are two ways to get the program variables
2136 if ( (sect->size > offsetof(DATAdyld, vars)) && (dd->vars.mh == mh) ) {
2137 // some really old binaries have space for vars, but it is zero filled
2138 // main executable has 10.5 style __dyld section that has program variable pointers
2139 context.setNewProgramVars(dd->vars);
2140 }
2141 else {
2142 // main executable is pre-10.5 and requires the symbols names to be looked up
2143 this->lookupProgramVars(context);
2144 #if SUPPORT_OLD_CRT_INITIALIZATION
2145 // If the first 16 bytes of the entry point's instructions do not
2146 // match what crt1.o supplies, then the program has a custom entry point.
2147 // This means it might be doing something that needs to be executed before
2148 // initializers are run.
2149 if ( memcmp(this->getEntryFromLC_UNIXTHREAD(), sStandardEntryPointInstructions, 16) != 0 ) {
2150 if ( context.verboseInit )
2151 dyld::log("dyld: program uses non-standard entry point so delaying running of initializers\n");
2152 context.setRunInitialzersOldWay();
2153 }
2154 #endif
2155 }
2156 }
2157 else if ( mh->filetype == MH_DYLIB ) {
2158 const char* installPath = this->getInstallPath();
2159 if ( (installPath != NULL) && ((strncmp(installPath, "/usr/lib/", 9) == 0) || (strncmp(installPath, "/System/DriverKit/usr/lib/", 26) == 0)) ) {
2160 if ( sect->size > offsetof(DATAdyld, vars) ) {
2161 // use ProgramVars from libdyld.dylib but tweak mh field to correct value
2162 dd->vars.mh = context.mainExecutable->machHeader();
2163 context.setNewProgramVars(dd->vars);
2164 }
2165 }
2166 }
2167 }
2168 else if ( (strcmp(sect->sectname, "__program_vars" ) == 0) && (mh->filetype == MH_EXECUTE) ) {
2169 // this is a Mac OS X 10.6 or later main executable
2170 struct ProgramVars* pv = (struct ProgramVars*)(sect->addr + fSlide);
2171 context.setNewProgramVars(*pv);
2172 }
2173 }
2174 }
2175 }
2176 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
2177 }
2178 }
2179 }
2180
2181
2182 void ImageLoaderMachO::lookupProgramVars(const LinkContext& context) const
2183 {
2184 ProgramVars vars = context.programVars;
2185 const ImageLoader::Symbol* sym;
2186
2187 // get mach header directly
2188 vars.mh = (macho_header*)fMachOData;
2189
2190 // lookup _NXArgc
2191 sym = this->findShallowExportedSymbol("_NXArgc", NULL);
2192 if ( sym != NULL )
2193 vars.NXArgcPtr = (int*)this->getExportedSymbolAddress(sym, context, this, false, NULL);
2194
2195 // lookup _NXArgv
2196 sym = this->findShallowExportedSymbol("_NXArgv", NULL);
2197 if ( sym != NULL )
2198 vars.NXArgvPtr = (const char***)this->getExportedSymbolAddress(sym, context, this, false, NULL);
2199
2200 // lookup _environ
2201 sym = this->findShallowExportedSymbol("_environ", NULL);
2202 if ( sym != NULL )
2203 vars.environPtr = (const char***)this->getExportedSymbolAddress(sym, context, this, false, NULL);
2204
2205 // lookup __progname
2206 sym = this->findShallowExportedSymbol("___progname", NULL);
2207 if ( sym != NULL )
2208 vars.__prognamePtr = (const char**)this->getExportedSymbolAddress(sym, context, this, false, NULL);
2209
2210 context.setNewProgramVars(vars);
2211 }
2212
2213
2214 bool ImageLoaderMachO::usablePrebinding(const LinkContext& context) const
2215 {
2216 // dylibs in dyld cache do not need to be rebased or bound
2217 // for chained fixups always pretend dylib is up to date, patch tables will be used later
2218 if ( fInSharedCache && (this->allDependentLibrariesAsWhenPreBound() || context.dyldCache->header.builtFromChainedFixups) ) {
2219 // allow environment variables to disable prebinding
2220 if ( context.bindFlat )
2221 return false;
2222 switch ( context.prebindUsage ) {
2223 case kUseAllPrebinding:
2224 return true;
2225 case kUseSplitSegPrebinding:
2226 return this->fIsSplitSeg;
2227 case kUseAllButAppPredbinding:
2228 return (this != context.mainExecutable);
2229 case kUseNoPrebinding:
2230 return false;
2231 }
2232 }
2233 return false;
2234 }
2235
2236 static void *stripPointer(void *ptr) {
2237 #if __has_feature(ptrauth_calls)
2238 return __builtin_ptrauth_strip(ptr, ptrauth_key_asia);
2239 #else
2240 return ptr;
2241 #endif
2242 }
2243
2244
2245 void ImageLoaderMachO::doImageInit(const LinkContext& context)
2246 {
2247 if ( fHasDashInit ) {
2248 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
2249 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
2250 const struct load_command* cmd = cmds;
2251 for (uint32_t i = 0; i < cmd_count; ++i) {
2252 switch (cmd->cmd) {
2253 case LC_ROUTINES_COMMAND:
2254 Initializer func = (Initializer)(((struct macho_routines_command*)cmd)->init_address + fSlide);
2255 #if __has_feature(ptrauth_calls)
2256 func = (Initializer)__builtin_ptrauth_sign_unauthenticated((void*)func, ptrauth_key_asia, 0);
2257 #endif
2258 // <rdar://problem/8543820&9228031> verify initializers are in image
2259 if ( ! this->containsAddress(stripPointer((void*)func)) ) {
2260 dyld::throwf("initializer function %p not in mapped image for %s\n", func, this->getPath());
2261 }
2262 if ( ! dyld::gProcessInfo->libSystemInitialized ) {
2263 // <rdar://problem/17973316> libSystem initializer must run first
2264 dyld::throwf("-init function in image (%s) that does not link with libSystem.dylib\n", this->getPath());
2265 }
2266 if ( context.verboseInit )
2267 dyld::log("dyld: calling -init function %p in %s\n", func, this->getPath());
2268 {
2269 dyld3::ScopedTimer(DBG_DYLD_TIMING_STATIC_INITIALIZER, (uint64_t)fMachOData, (uint64_t)func, 0);
2270 func(context.argc, context.argv, context.envp, context.apple, &context.programVars);
2271 }
2272 break;
2273 }
2274 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
2275 }
2276 }
2277 }
2278
2279 static const char* libSystemPath(const ImageLoader::LinkContext& context)
2280 {
2281 #if __MAC_OS_X_VERSION_MIN_REQUIRED
2282 if ( context.driverKit )
2283 return DRIVERKIT_LIBSYSTEM_DYLIB_PATH;
2284 else
2285 #endif
2286 return LIBSYSTEM_DYLIB_PATH;
2287 }
2288
2289
2290
2291 void ImageLoaderMachO::doModInitFunctions(const LinkContext& context)
2292 {
2293 if ( fHasInitializers ) {
2294 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
2295 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
2296 const struct load_command* cmd = cmds;
2297 for (uint32_t i = 0; i < cmd_count; ++i) {
2298 if ( cmd->cmd == LC_SEGMENT_COMMAND ) {
2299 const struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
2300 const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command));
2301 const struct macho_section* const sectionsEnd = &sectionsStart[seg->nsects];
2302 for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
2303 const uint8_t type = sect->flags & SECTION_TYPE;
2304 if ( type == S_MOD_INIT_FUNC_POINTERS ) {
2305 Initializer* inits = (Initializer*)(sect->addr + fSlide);
2306 const size_t count = sect->size / sizeof(uintptr_t);
2307 // <rdar://problem/23929217> Ensure __mod_init_func section is within segment
2308 if ( (sect->addr < seg->vmaddr) || (sect->addr+sect->size > seg->vmaddr+seg->vmsize) || (sect->addr+sect->size < sect->addr) )
2309 dyld::throwf("__mod_init_funcs section has malformed address range for %s\n", this->getPath());
2310 for (size_t j=0; j < count; ++j) {
2311 Initializer func = inits[j];
2312 // <rdar://problem/8543820&9228031> verify initializers are in image
2313 if ( ! this->containsAddress(stripPointer((void*)func)) ) {
2314 dyld::throwf("initializer function %p not in mapped image for %s\n", func, this->getPath());
2315 }
2316 if ( ! dyld::gProcessInfo->libSystemInitialized ) {
2317 // <rdar://problem/17973316> libSystem initializer must run first
2318 const char* installPath = getInstallPath();
2319 if ( (installPath == NULL) || (strcmp(installPath, libSystemPath(context)) != 0) )
2320 dyld::throwf("initializer in image (%s) that does not link with libSystem.dylib\n", this->getPath());
2321 }
2322 if ( context.verboseInit )
2323 dyld::log("dyld: calling initializer function %p in %s\n", func, this->getPath());
2324 bool haveLibSystemHelpersBefore = (dyld::gLibSystemHelpers != NULL);
2325 {
2326 dyld3::ScopedTimer(DBG_DYLD_TIMING_STATIC_INITIALIZER, (uint64_t)fMachOData, (uint64_t)func, 0);
2327 func(context.argc, context.argv, context.envp, context.apple, &context.programVars);
2328 }
2329 bool haveLibSystemHelpersAfter = (dyld::gLibSystemHelpers != NULL);
2330 if ( !haveLibSystemHelpersBefore && haveLibSystemHelpersAfter ) {
2331 // now safe to use malloc() and other calls in libSystem.dylib
2332 dyld::gProcessInfo->libSystemInitialized = true;
2333 }
2334 }
2335 }
2336 else if ( type == S_INIT_FUNC_OFFSETS ) {
2337 const uint32_t* inits = (uint32_t*)(sect->addr + fSlide);
2338 const size_t count = sect->size / sizeof(uint32_t);
2339 // Ensure section is within segment
2340 if ( (sect->addr < seg->vmaddr) || (sect->addr+sect->size > seg->vmaddr+seg->vmsize) || (sect->addr+sect->size < sect->addr) )
2341 dyld::throwf("__init_offsets section has malformed address range for %s\n", this->getPath());
2342 if ( seg->initprot & VM_PROT_WRITE )
2343 dyld::throwf("__init_offsets section is not in read-only segment %s\n", this->getPath());
2344 for (size_t j=0; j < count; ++j) {
2345 uint32_t funcOffset = inits[j];
2346 // verify initializers are in TEXT segment
2347 if ( funcOffset > seg->filesize ) {
2348 dyld::throwf("initializer function offset 0x%08X not in mapped image for %s\n", funcOffset, this->getPath());
2349 }
2350 if ( ! dyld::gProcessInfo->libSystemInitialized ) {
2351 // <rdar://problem/17973316> libSystem initializer must run first
2352 const char* installPath = getInstallPath();
2353 if ( (installPath == NULL) || (strcmp(installPath, libSystemPath(context)) != 0) )
2354 dyld::throwf("initializer in image (%s) that does not link with libSystem.dylib\n", this->getPath());
2355 }
2356 Initializer func = (Initializer)((uint8_t*)this->machHeader() + funcOffset);
2357 if ( context.verboseInit )
2358 dyld::log("dyld: calling initializer function %p in %s\n", func, this->getPath());
2359 bool haveLibSystemHelpersBefore = (dyld::gLibSystemHelpers != NULL);
2360 {
2361 dyld3::ScopedTimer(DBG_DYLD_TIMING_STATIC_INITIALIZER, (uint64_t)fMachOData, (uint64_t)func, 0);
2362 func(context.argc, context.argv, context.envp, context.apple, &context.programVars);
2363 }
2364 bool haveLibSystemHelpersAfter = (dyld::gLibSystemHelpers != NULL);
2365 if ( !haveLibSystemHelpersBefore && haveLibSystemHelpersAfter ) {
2366 // now safe to use malloc() and other calls in libSystem.dylib
2367 dyld::gProcessInfo->libSystemInitialized = true;
2368 }
2369 }
2370 }
2371 }
2372 }
2373 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
2374 }
2375 }
2376 }
2377
2378
2379
2380 void ImageLoaderMachO::doGetDOFSections(const LinkContext& context, std::vector<ImageLoader::DOFInfo>& dofs)
2381 {
2382 if ( fHasDOFSections ) {
2383 // walk load commands (mapped in at start of __TEXT segment)
2384 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
2385 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
2386 const struct load_command* cmd = cmds;
2387 for (uint32_t i = 0; i < cmd_count; ++i) {
2388 switch (cmd->cmd) {
2389 case LC_SEGMENT_COMMAND:
2390 {
2391 const struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
2392 const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command));
2393 const struct macho_section* const sectionsEnd = &sectionsStart[seg->nsects];
2394 for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
2395 if ( (sect->flags & SECTION_TYPE) == S_DTRACE_DOF ) {
2396 // <rdar://problem/23929217> Ensure section is within segment
2397 if ( (sect->addr < seg->vmaddr) || (sect->addr+sect->size > seg->vmaddr+seg->vmsize) || (sect->addr+sect->size < sect->addr) )
2398 dyld::throwf("DOF section has malformed address range for %s\n", this->getPath());
2399 ImageLoader::DOFInfo info;
2400 info.dof = (void*)(sect->addr + fSlide);
2401 info.imageHeader = this->machHeader();
2402 info.imageShortName = this->getShortName();
2403 dofs.push_back(info);
2404 }
2405 }
2406 }
2407 break;
2408 }
2409 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
2410 }
2411 }
2412 }
2413
2414
2415 bool ImageLoaderMachO::doInitialization(const LinkContext& context)
2416 {
2417 CRSetCrashLogMessage2(this->getPath());
2418
2419 // mach-o has -init and static initializers
2420 doImageInit(context);
2421 doModInitFunctions(context);
2422
2423 CRSetCrashLogMessage2(NULL);
2424
2425 return (fHasDashInit || fHasInitializers);
2426 }
2427
2428 bool ImageLoaderMachO::needsInitialization()
2429 {
2430 return ( fHasDashInit || fHasInitializers );
2431 }
2432
2433
2434 bool ImageLoaderMachO::needsTermination()
2435 {
2436 return fHasTerminators;
2437 }
2438
2439
2440 void ImageLoaderMachO::doTermination(const LinkContext& context)
2441 {
2442 if ( fHasTerminators ) {
2443 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
2444 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
2445 const struct load_command* cmd = cmds;
2446 for (uint32_t i = 0; i < cmd_count; ++i) {
2447 if ( cmd->cmd == LC_SEGMENT_COMMAND ) {
2448 const struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
2449 const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command));
2450 const struct macho_section* const sectionsEnd = &sectionsStart[seg->nsects];
2451 for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
2452 const uint8_t type = sect->flags & SECTION_TYPE;
2453 if ( type == S_MOD_TERM_FUNC_POINTERS ) {
2454 // <rdar://problem/23929217> Ensure section is within segment
2455 if ( (sect->addr < seg->vmaddr) || (sect->addr+sect->size > seg->vmaddr+seg->vmsize) || (sect->addr+sect->size < sect->addr) )
2456 dyld::throwf("DOF section has malformed address range for %s\n", this->getPath());
2457 Terminator* terms = (Terminator*)(sect->addr + fSlide);
2458 const size_t count = sect->size / sizeof(uintptr_t);
2459 for (size_t j=count; j > 0; --j) {
2460 Terminator func = terms[j-1];
2461 #if __has_feature(ptrauth_calls)
2462 func = (Terminator)__builtin_ptrauth_sign_unauthenticated((void*)func, ptrauth_key_asia, 0);
2463 #endif
2464 // <rdar://problem/8543820&9228031> verify terminators are in image
2465 if ( ! this->containsAddress(stripPointer((void*)func)) ) {
2466 dyld::throwf("termination function %p not in mapped image for %s\n", func, this->getPath());
2467 }
2468 if ( context.verboseInit )
2469 dyld::log("dyld: calling termination function %p in %s\n", func, this->getPath());
2470 func();
2471 }
2472 }
2473 }
2474 }
2475 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
2476 }
2477 }
2478 }
2479
2480
2481 void ImageLoaderMachO::printStatisticsDetails(unsigned int imageCount, const InitializerTimingList& timingInfo)
2482 {
2483 ImageLoader::printStatisticsDetails(imageCount, timingInfo);
2484 dyld::log("total symbol trie searches: %d\n", fgSymbolTrieSearchs);
2485 dyld::log("total symbol table binary searches: %d\n", fgSymbolTableBinarySearchs);
2486 dyld::log("total images defining weak symbols: %u\n", fgImagesHasWeakDefinitions);
2487 dyld::log("total images using weak symbols: %u\n", fgImagesRequiringCoalescing);
2488 }
2489
2490
2491 intptr_t ImageLoaderMachO::assignSegmentAddresses(const LinkContext& context)
2492 {
2493 // preflight and calculate slide if needed
2494 const bool inPIE = (fgNextPIEDylibAddress != 0);
2495 intptr_t slide = 0;
2496 if ( this->segmentsCanSlide() && this->segmentsMustSlideTogether() ) {
2497 bool needsToSlide = false;
2498 bool imageHasPreferredLoadAddress = segHasPreferredLoadAddress(0);
2499 uintptr_t lowAddr = (unsigned long)(-1);
2500 uintptr_t highAddr = 0;
2501 for(unsigned int i=0, e=segmentCount(); i < e; ++i) {
2502 const uintptr_t segLow = segPreferredLoadAddress(i);
2503 const uintptr_t segHigh = dyld_page_round(segLow + segSize(i));
2504 if ( segLow < highAddr ) {
2505 if ( dyld_page_size > 4096 )
2506 dyld::throwf("can't map segments into 16KB pages");
2507 else
2508 dyld::throwf("overlapping segments");
2509 }
2510 if ( segLow < lowAddr )
2511 lowAddr = segLow;
2512 if ( segHigh > highAddr )
2513 highAddr = segHigh;
2514
2515 if ( needsToSlide || !imageHasPreferredLoadAddress || inPIE || !reserveAddressRange(segPreferredLoadAddress(i), segSize(i)) )
2516 needsToSlide = true;
2517 }
2518 if ( needsToSlide ) {
2519 // find a chunk of address space to hold all segments
2520 uintptr_t addr = reserveAnAddressRange(highAddr-lowAddr, context);
2521 slide = addr - lowAddr;
2522 }
2523 }
2524 else if ( ! this->segmentsCanSlide() ) {
2525 for(unsigned int i=0, e=segmentCount(); i < e; ++i) {
2526 if ( (strcmp(segName(i), "__PAGEZERO") == 0) && (segFileSize(i) == 0) && (segPreferredLoadAddress(i) == 0) )
2527 continue;
2528 if ( !reserveAddressRange(segPreferredLoadAddress(i), segSize(i)) )
2529 dyld::throwf("can't map unslidable segment %s to 0x%lX with size 0x%lX", segName(i), segPreferredLoadAddress(i), segSize(i));
2530 }
2531 }
2532 else {
2533 throw "mach-o does not support independently sliding segments";
2534 }
2535 return slide;
2536 }
2537
2538
2539 uintptr_t ImageLoaderMachO::reserveAnAddressRange(size_t length, const ImageLoader::LinkContext& context)
2540 {
2541 vm_address_t addr = 0;
2542 vm_size_t size = length;
2543 // in PIE programs, load initial dylibs after main executable so they don't have fixed addresses either
2544 if ( fgNextPIEDylibAddress != 0 ) {
2545 // add small (0-3 pages) random padding between dylibs
2546 addr = fgNextPIEDylibAddress + (__stack_chk_guard/fgNextPIEDylibAddress & (sizeof(long)-1))*dyld_page_size;
2547 //dyld::log("padding 0x%08llX, guard=0x%08llX\n", (long long)(addr - fgNextPIEDylibAddress), (long long)(__stack_chk_guard));
2548 kern_return_t r = vm_alloc(&addr, size, VM_FLAGS_FIXED | VM_MAKE_TAG(VM_MEMORY_DYLIB));
2549 if ( r == KERN_SUCCESS ) {
2550 fgNextPIEDylibAddress = addr + size;
2551 return addr;
2552 }
2553 fgNextPIEDylibAddress = 0;
2554 }
2555 kern_return_t r = vm_alloc(&addr, size, VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_MEMORY_DYLIB));
2556 if ( r != KERN_SUCCESS )
2557 throw "out of address space";
2558
2559 return addr;
2560 }
2561
2562 bool ImageLoaderMachO::reserveAddressRange(uintptr_t start, size_t length)
2563 {
2564 vm_address_t addr = start;
2565 vm_size_t size = length;
2566 kern_return_t r = vm_alloc(&addr, size, VM_FLAGS_FIXED | VM_MAKE_TAG(VM_MEMORY_DYLIB));
2567 if ( r != KERN_SUCCESS )
2568 return false;
2569 return true;
2570 }
2571
2572
2573
2574 void ImageLoaderMachO::mapSegments(int fd, uint64_t offsetInFat, uint64_t lenInFat, uint64_t fileLen, const LinkContext& context)
2575 {
2576 // find address range for image
2577 intptr_t slide = this->assignSegmentAddresses(context);
2578 if ( context.verboseMapping ) {
2579 if ( offsetInFat != 0 )
2580 dyld::log("dyld: Mapping %s (slice offset=%llu)\n", this->getPath(), (unsigned long long)offsetInFat);
2581 else
2582 dyld::log("dyld: Mapping %s\n", this->getPath());
2583 }
2584
2585 // <rdar://problem/47163421> speculatively read whole slice
2586 fspecread_t specread = {} ;
2587 specread.fsr_offset = offsetInFat;
2588 specread.fsr_length = lenInFat;
2589 specread.fsr_flags = 0;
2590 fcntl(fd, F_SPECULATIVE_READ, &specread);
2591 if ( context.verboseMapping )
2592 dyld::log("dyld: Speculatively read offset=0x%08llX, len=0x%08llX, path=%s\n", offsetInFat, lenInFat, this->getPath());
2593
2594 // map in all segments
2595 for(unsigned int i=0, e=segmentCount(); i < e; ++i) {
2596 vm_offset_t fileOffset = (vm_offset_t)(segFileOffset(i) + offsetInFat);
2597 vm_size_t size = segFileSize(i);
2598 uintptr_t requestedLoadAddress = segPreferredLoadAddress(i) + slide;
2599 int protection = 0;
2600 if ( !segUnaccessible(i) ) {
2601 if ( segExecutable(i) )
2602 protection |= PROT_EXEC;
2603 if ( segReadable(i) )
2604 protection |= PROT_READ;
2605 if ( segWriteable(i) ) {
2606 protection |= PROT_WRITE;
2607 // rdar://problem/22525618 force __LINKEDIT to always be mapped read-only
2608 if ( strcmp(segName(i), "__LINKEDIT") == 0 )
2609 protection = PROT_READ;
2610 }
2611 }
2612 #if __i386__
2613 // initially map __IMPORT segments R/W so dyld can update them
2614 if ( segIsReadOnlyImport(i) )
2615 protection |= PROT_WRITE;
2616 #endif
2617 // wholly zero-fill segments have nothing to mmap() in
2618 if ( size > 0 ) {
2619 if ( (fileOffset+size) > fileLen ) {
2620 dyld::throwf("truncated mach-o error: segment %s extends to %llu which is past end of file %llu",
2621 segName(i), (uint64_t)(fileOffset+size), fileLen);
2622 }
2623 void* loadAddress = xmmap((void*)requestedLoadAddress, size, protection, MAP_FIXED | MAP_PRIVATE, fd, fileOffset);
2624 if ( loadAddress == ((void*)(-1)) ) {
2625 int mmapErr = errno;
2626 if ( mmapErr == EPERM ) {
2627 if ( dyld::sandboxBlockedMmap(getPath()) )
2628 dyld::throwf("file system sandbox blocked mmap() of '%s'", this->getPath());
2629 else
2630 dyld::throwf("code signing blocked mmap() of '%s'", this->getPath());
2631 }
2632 else
2633 dyld::throwf("mmap() errno=%d at address=0x%08lX, size=0x%08lX segment=%s in Segment::map() mapping %s",
2634 mmapErr, requestedLoadAddress, (uintptr_t)size, segName(i), getPath());
2635 }
2636 }
2637 // update stats
2638 ++ImageLoader::fgTotalSegmentsMapped;
2639 ImageLoader::fgTotalBytesMapped += size;
2640 if ( context.verboseMapping )
2641 dyld::log("%18s at 0x%08lX->0x%08lX with permissions %c%c%c\n", segName(i), requestedLoadAddress, requestedLoadAddress+size-1,
2642 (protection & PROT_READ) ? 'r' : '.', (protection & PROT_WRITE) ? 'w' : '.', (protection & PROT_EXEC) ? 'x' : '.' );
2643 }
2644
2645 // update slide to reflect load location
2646 this->setSlide(slide);
2647 }
2648
2649 void ImageLoaderMachO::mapSegments(const void* memoryImage, uint64_t imageLen, const LinkContext& context)
2650 {
2651 // find address range for image
2652 intptr_t slide = this->assignSegmentAddresses(context);
2653 if ( context.verboseMapping )
2654 dyld::log("dyld: Mapping memory %p\n", memoryImage);
2655 // map in all segments
2656 for(unsigned int i=0, e=segmentCount(); i < e; ++i) {
2657 vm_address_t loadAddress = segPreferredLoadAddress(i) + slide;
2658 vm_address_t srcAddr = (uintptr_t)memoryImage + segFileOffset(i);
2659 vm_size_t size = segFileSize(i);
2660 kern_return_t r = vm_copy(mach_task_self(), srcAddr, size, loadAddress);
2661 if ( r != KERN_SUCCESS )
2662 throw "can't map segment";
2663 if ( context.verboseMapping )
2664 dyld::log("%18s at 0x%08lX->0x%08lX\n", segName(i), (uintptr_t)loadAddress, (uintptr_t)loadAddress+size-1);
2665 }
2666 // update slide to reflect load location
2667 this->setSlide(slide);
2668 // set R/W permissions on all segments at slide location
2669 for(unsigned int i=0, e=segmentCount(); i < e; ++i) {
2670 segProtect(i, context);
2671 }
2672 }
2673
2674
2675 void ImageLoaderMachO::segProtect(unsigned int segIndex, const ImageLoader::LinkContext& context)
2676 {
2677 vm_prot_t protection = 0;
2678 if ( !segUnaccessible(segIndex) ) {
2679 if ( segExecutable(segIndex) )
2680 protection |= PROT_EXEC;
2681 if ( segReadable(segIndex) )
2682 protection |= PROT_READ;
2683 if ( segWriteable(segIndex) )
2684 protection |= PROT_WRITE;
2685 }
2686 vm_address_t addr = segActualLoadAddress(segIndex);
2687 vm_size_t size = segSize(segIndex);
2688 const bool setCurrentPermissions = false;
2689 kern_return_t r = vm_protect(mach_task_self(), addr, size, setCurrentPermissions, protection);
2690 if ( r != KERN_SUCCESS ) {
2691 dyld::throwf("vm_protect(0x%08llX, 0x%08llX, false, 0x%02X) failed, result=%d for segment %s in %s",
2692 (long long)addr, (long long)size, protection, r, segName(segIndex), this->getPath());
2693 }
2694 if ( context.verboseMapping ) {
2695 dyld::log("%18s at 0x%08lX->0x%08lX altered permissions to %c%c%c\n", segName(segIndex), (uintptr_t)addr, (uintptr_t)addr+size-1,
2696 (protection & PROT_READ) ? 'r' : '.', (protection & PROT_WRITE) ? 'w' : '.', (protection & PROT_EXEC) ? 'x' : '.' );
2697 }
2698 }
2699
2700 #if TEXT_RELOC_SUPPORT
2701 void ImageLoaderMachO::segMakeWritable(unsigned int segIndex, const ImageLoader::LinkContext& context)
2702 {
2703 vm_address_t addr = segActualLoadAddress(segIndex);
2704 vm_size_t size = segSize(segIndex);
2705 const bool setCurrentPermissions = false;
2706 vm_prot_t protection = VM_PROT_WRITE | VM_PROT_READ | VM_PROT_COPY;
2707 if ( segExecutable(segIndex) && !segHasRebaseFixUps(segIndex) )
2708 protection |= VM_PROT_EXECUTE;
2709 kern_return_t r = vm_protect(mach_task_self(), addr, size, setCurrentPermissions, protection);
2710 if ( r != KERN_SUCCESS ) {
2711 dyld::throwf("vm_protect(0x%08llX, 0x%08llX, false, 0x%02X) failed, result=%d for segment %s in %s",
2712 (long long)addr, (long long)size, protection, r, segName(segIndex), this->getPath());
2713 }
2714 if ( context.verboseMapping ) {
2715 dyld::log("%18s at 0x%08lX->0x%08lX altered permissions to %c%c%c\n", segName(segIndex), (uintptr_t)addr, (uintptr_t)addr+size-1,
2716 (protection & PROT_READ) ? 'r' : '.', (protection & PROT_WRITE) ? 'w' : '.', (protection & PROT_EXEC) ? 'x' : '.' );
2717 }
2718 }
2719 #endif
2720
2721 const char* ImageLoaderMachO::findClosestSymbol(const mach_header* mh, const void* addr, const void** closestAddr)
2722 {
2723 // called by dladdr()
2724 // only works with compressed LINKEDIT if classic symbol table is also present
2725 const dysymtab_command* dynSymbolTable = NULL;
2726 const symtab_command* symtab = NULL;
2727 const macho_segment_command* seg;
2728 const uint8_t* unslidLinkEditBase = NULL;
2729 bool linkEditBaseFound = false;
2730 intptr_t slide = 0;
2731 const uint32_t cmd_count = mh->ncmds;
2732 const load_command* const cmds = (load_command*)((char*)mh + sizeof(macho_header));
2733 const load_command* cmd = cmds;
2734 for (uint32_t i = 0; i < cmd_count; ++i) {
2735 switch (cmd->cmd) {
2736 case LC_SEGMENT_COMMAND:
2737 seg = (macho_segment_command*)cmd;
2738 if ( strcmp(seg->segname, "__LINKEDIT") == 0 ) {
2739 unslidLinkEditBase = (uint8_t*)(seg->vmaddr - seg->fileoff);
2740 linkEditBaseFound = true;
2741 }
2742 else if ( strcmp(seg->segname, "__TEXT") == 0 ) {
2743 slide = (uintptr_t)mh - seg->vmaddr;
2744 }
2745 break;
2746 case LC_SYMTAB:
2747 symtab = (symtab_command*)cmd;
2748 break;
2749 case LC_DYSYMTAB:
2750 dynSymbolTable = (dysymtab_command*)cmd;
2751 break;
2752 }
2753 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
2754 }
2755 // no symbol table => no lookup by address
2756 if ( (symtab == NULL) || (dynSymbolTable == NULL) || !linkEditBaseFound )
2757 return NULL;
2758
2759 const uint8_t* linkEditBase = unslidLinkEditBase + slide;
2760 const char* symbolTableStrings = (const char*)&linkEditBase[symtab->stroff];
2761 const macho_nlist* symbolTable = (macho_nlist*)(&linkEditBase[symtab->symoff]);
2762
2763 uintptr_t targetAddress = (uintptr_t)addr - slide;
2764 const struct macho_nlist* bestSymbol = NULL;
2765 // first walk all global symbols
2766 const struct macho_nlist* const globalsStart = &symbolTable[dynSymbolTable->iextdefsym];
2767 const struct macho_nlist* const globalsEnd= &globalsStart[dynSymbolTable->nextdefsym];
2768 for (const struct macho_nlist* s = globalsStart; s < globalsEnd; ++s) {
2769 if ( (s->n_type & N_TYPE) == N_SECT ) {
2770 if ( bestSymbol == NULL ) {
2771 if ( s->n_value <= targetAddress )
2772 bestSymbol = s;
2773 }
2774 else if ( (s->n_value <= targetAddress) && (bestSymbol->n_value < s->n_value) ) {
2775 bestSymbol = s;
2776 }
2777 }
2778 }
2779 // next walk all local symbols
2780 const struct macho_nlist* const localsStart = &symbolTable[dynSymbolTable->ilocalsym];
2781 const struct macho_nlist* const localsEnd= &localsStart[dynSymbolTable->nlocalsym];
2782 for (const struct macho_nlist* s = localsStart; s < localsEnd; ++s) {
2783 if ( ((s->n_type & N_TYPE) == N_SECT) && ((s->n_type & N_STAB) == 0) ) {
2784 if ( bestSymbol == NULL ) {
2785 if ( s->n_value <= targetAddress )
2786 bestSymbol = s;
2787 }
2788 else if ( (s->n_value <= targetAddress) && (bestSymbol->n_value < s->n_value) ) {
2789 bestSymbol = s;
2790 }
2791 }
2792 }
2793 if ( bestSymbol != NULL ) {
2794 #if __arm__
2795 if (bestSymbol->n_desc & N_ARM_THUMB_DEF)
2796 *closestAddr = (void*)((bestSymbol->n_value | 1) + slide);
2797 else
2798 *closestAddr = (void*)(bestSymbol->n_value + slide);
2799 #else
2800 *closestAddr = (void*)(bestSymbol->n_value + slide);
2801 #endif
2802 return &symbolTableStrings[bestSymbol->n_un.n_strx];
2803 }
2804 return NULL;
2805 }
2806
2807 bool ImageLoaderMachO::getLazyBindingInfo(uint32_t& lazyBindingInfoOffset, const uint8_t* lazyInfoStart, const uint8_t* lazyInfoEnd,
2808 uint8_t* segIndex, uintptr_t* segOffset, int* ordinal, const char** symbolName, bool* doneAfterBind)
2809 {
2810 if ( lazyBindingInfoOffset > (lazyInfoEnd-lazyInfoStart) )
2811 return false;
2812 bool done = false;
2813 const uint8_t* p = &lazyInfoStart[lazyBindingInfoOffset];
2814 while ( !done && (p < lazyInfoEnd) ) {
2815 uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
2816 uint8_t opcode = *p & BIND_OPCODE_MASK;
2817 ++p;
2818 switch (opcode) {
2819 case BIND_OPCODE_DONE:
2820 *doneAfterBind = false;
2821 return true;
2822 break;
2823 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
2824 *ordinal = immediate;
2825 break;
2826 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
2827 *ordinal = (int)read_uleb128(p, lazyInfoEnd);
2828 break;
2829 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
2830 // the special ordinals are negative numbers
2831 if ( immediate == 0 )
2832 *ordinal = 0;
2833 else {
2834 int8_t signExtended = BIND_OPCODE_MASK | immediate;
2835 *ordinal = signExtended;
2836 }
2837 break;
2838 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
2839 *symbolName = (char*)p;
2840 while (*p != '\0')
2841 ++p;
2842 ++p;
2843 break;
2844 case BIND_OPCODE_SET_TYPE_IMM:
2845 break;
2846 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
2847 *segIndex = immediate;
2848 *segOffset = read_uleb128(p, lazyInfoEnd);
2849 break;
2850 case BIND_OPCODE_DO_BIND:
2851 *doneAfterBind = ((*p & BIND_OPCODE_MASK) == BIND_OPCODE_DONE);
2852 lazyBindingInfoOffset += p - &lazyInfoStart[lazyBindingInfoOffset];
2853 return true;
2854 break;
2855 case BIND_OPCODE_SET_ADDEND_SLEB:
2856 case BIND_OPCODE_ADD_ADDR_ULEB:
2857 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
2858 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
2859 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
2860 default:
2861 return false;
2862 }
2863 }
2864 return false;
2865 }
2866
2867 const dyld_info_command* ImageLoaderMachO::findDyldInfoLoadCommand(const mach_header* mh)
2868 {
2869 const uint32_t cmd_count = mh->ncmds;
2870 const load_command* const cmds = (load_command*)((char*)mh + sizeof(macho_header));
2871 const load_command* cmd = cmds;
2872 for (uint32_t i = 0; i < cmd_count; ++i) {
2873 switch (cmd->cmd) {
2874 case LC_DYLD_INFO:
2875 case LC_DYLD_INFO_ONLY:
2876 return (dyld_info_command*)cmd;
2877 }
2878 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
2879 }
2880 return NULL;
2881 }
2882
2883
2884 uintptr_t ImageLoaderMachO::segPreferredAddress(const mach_header* mh, unsigned segIndex)
2885 {
2886 const uint32_t cmd_count = mh->ncmds;
2887 const load_command* const cmds = (load_command*)((char*)mh + sizeof(macho_header));
2888 const load_command* cmd = cmds;
2889 unsigned curSegIndex = 0;
2890 for (uint32_t i = 0; i < cmd_count; ++i) {
2891 if ( cmd->cmd == LC_SEGMENT_COMMAND ) {
2892 if ( segIndex == curSegIndex ) {
2893 const macho_segment_command* segCmd = (macho_segment_command*)cmd;
2894 return segCmd->vmaddr;
2895 }
2896 ++curSegIndex;
2897 }
2898 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
2899 }
2900 return 0;
2901 }
2902
2903
2904
2905 uintptr_t ImageLoaderMachO::imageBaseAddress() const {
2906 //printf("imageBaseAddress: %s %d->%d\n", getPath(), 0, segmentCount());
2907 for (unsigned int i = 0, e = segmentCount(); i != e; ++i) {
2908 if ( (segFileOffset(i) == 0) && (segFileSize(i) != 0) )
2909 return segPreferredLoadAddress(i);
2910 }
2911 return 0;
2912 }
2913