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