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