1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
   3  * Copyright (c) 2004-2008 Apple Inc. All rights reserved. 
   5  * @APPLE_LICENSE_HEADER_START@ 
   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 
  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. 
  22  * @APPLE_LICENSE_HEADER_END@ 
  25 #define __STDC_LIMIT_MACROS 
  30 #include <mach/mach.h> 
  31 #include <mach-o/loader.h> 
  32 #include <mach-o/ldsyms.h> 
  33 #include <mach-o/reloc.h> 
  34 #if __ppc__ || __ppc64__ 
  35         #include <mach-o/ppc/reloc.h> 
  38         #include <mach-o/x86_64/reloc.h> 
  43         #define MH_PIE 0x200000  
  48         #define LC_SEGMENT_COMMAND              LC_SEGMENT_64 
  49         #define macho_segment_command   segment_command_64 
  50         #define macho_section                   section_64 
  53         #define LC_SEGMENT_COMMAND              LC_SEGMENT 
  54         #define macho_segment_command   segment_command 
  55         #define macho_section                   section 
  60         #define POINTER_RELOC X86_64_RELOC_UNSIGNED 
  62         #define POINTER_RELOC GENERIC_RELOC_VANILLA 
  66 namespace dyld 
{ extern bool isRosetta(); }; 
  70 //  Code to bootstrap dyld into a runnable state 
  74 namespace dyldbootstrap 
{ 
  77 typedef void (*Initializer
)(int argc
, const char* argv
[], const char* envp
[], const char* apple
[]); 
  80 // For a regular executable, the crt code calls dyld to run the executables initializers. 
  81 // For a static executable, crt directly runs the initializers. 
  82 // dyld (should be static) but is a dynamic executable and needs this hack to run its own initializers. 
  83 // We pass argc, argv, etc in case libc.a uses those arguments 
  85 static void runDyldInitializers(const struct macho_header
* mh
, intptr_t slide
, int argc
, const char* argv
[], const char* envp
[], const char* apple
[]) 
  87         const uint32_t cmd_count 
= mh
->ncmds
; 
  88         const struct load_command
* const cmds 
= (struct load_command
*)(((char*)mh
)+sizeof(macho_header
)); 
  89         const struct load_command
* cmd 
= cmds
; 
  90         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
  92                         case LC_SEGMENT_COMMAND
: 
  94                                         const struct macho_segment_command
* seg 
= (struct macho_segment_command
*)cmd
; 
  95                                         const struct macho_section
* const sectionsStart 
= (struct macho_section
*)((char*)seg 
+ sizeof(struct macho_segment_command
)); 
  96                                         const struct macho_section
* const sectionsEnd 
= §ionsStart
[seg
->nsects
]; 
  97                                         for (const struct macho_section
* sect
=sectionsStart
; sect 
< sectionsEnd
; ++sect
) { 
  98                                                 const uint8_t type 
= sect
->flags 
& SECTION_TYPE
; 
  99                                                 if ( type 
== S_MOD_INIT_FUNC_POINTERS 
){ 
 100                                                         Initializer
* inits 
= (Initializer
*)(sect
->addr 
+ slide
); 
 101                                                         const uint32_t count 
= sect
->size 
/ sizeof(uintptr_t); 
 102                                                         for (uint32_t i
=0; i 
< count
; ++i
) { 
 103                                                                 Initializer func 
= inits
[i
]; 
 104                                                                 func(argc
, argv
, envp
, apple
); 
 111                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
 116 // If the kernel does not load dyld at its preferred address, we need to apply  
 117 // fixups to various initialized parts of the __DATA segment 
 119 static void rebaseDyld(const struct macho_header
* mh
, intptr_t slide
) 
 121         // rebase non-lazy pointers (which all point internal to dyld, since dyld uses no shared libraries) 
 122         // and get interesting pointers into dyld 
 123         const uint32_t cmd_count 
= mh
->ncmds
; 
 124         const struct load_command
* const cmds 
= (struct load_command
*)(((char*)mh
)+sizeof(macho_header
)); 
 125         const struct load_command
* cmd 
= cmds
; 
 126         const struct macho_segment_command
* linkEditSeg 
= NULL
; 
 128         const struct macho_segment_command
* firstWritableSeg 
= NULL
; 
 130         const struct dysymtab_command
* dynamicSymbolTable 
= NULL
; 
 131         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
 133                         case LC_SEGMENT_COMMAND
: 
 135                                         const struct macho_segment_command
* seg 
= (struct macho_segment_command
*)cmd
; 
 136                                         if ( strcmp(seg
->segname
, "__LINKEDIT") == 0 ) 
 138                                         const struct macho_section
* const sectionsStart 
= (struct macho_section
*)((char*)seg 
+ sizeof(struct macho_segment_command
)); 
 139                                         const struct macho_section
* const sectionsEnd 
= §ionsStart
[seg
->nsects
]; 
 140                                         for (const struct macho_section
* sect
=sectionsStart
; sect 
< sectionsEnd
; ++sect
) { 
 141                                                 const uint8_t type 
= sect
->flags 
& SECTION_TYPE
; 
 142                                                 if ( type 
== S_NON_LAZY_SYMBOL_POINTERS 
) { 
 143                                                         // rebase non-lazy pointers (which all point internal to dyld, since dyld uses no shared libraries) 
 144                                                         const uint32_t pointerCount 
= sect
->size 
/ sizeof(uintptr_t); 
 145                                                         uintptr_t* const symbolPointers 
= (uintptr_t*)(sect
->addr 
+ slide
); 
 146                                                         for (uint32_t j
=0; j 
< pointerCount
; ++j
) { 
 147                                                                 symbolPointers
[j
] += slide
; 
 152                                         if ( (firstWritableSeg 
== NULL
) && (seg
->initprot 
& VM_PROT_WRITE
) ) 
 153                                                 firstWritableSeg 
= seg
; 
 158                                 dynamicSymbolTable 
= (struct dysymtab_command 
*)cmd
; 
 161                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
 164         // use reloc's to rebase all random data pointers 
 166         const uintptr_t relocBase 
= firstWritableSeg
->vmaddr 
+ slide
; 
 168         const uintptr_t relocBase 
= (uintptr_t)mh
; 
 170         const relocation_info
* const relocsStart 
= (struct relocation_info
*)(linkEditSeg
->vmaddr 
+ slide 
+ dynamicSymbolTable
->locreloff 
- linkEditSeg
->fileoff
); 
 171         const relocation_info
* const relocsEnd 
= &relocsStart
[dynamicSymbolTable
->nlocrel
]; 
 172         for (const relocation_info
* reloc
=relocsStart
; reloc 
< relocsEnd
; ++reloc
) { 
 173         #if __ppc__ || __ppc64__ || __i36__ 
 174                 if ( (reloc
->r_address 
& R_SCATTERED
) != 0 ) 
 175                         throw "scattered relocation in dyld"; 
 177                 if ( reloc
->r_length 
!= RELOC_SIZE 
)  
 178                         throw "relocation in dyld has wrong size"; 
 180                 if ( reloc
->r_type 
!= POINTER_RELOC 
)  
 181                         throw "relocation in dyld has wrong type"; 
 183                 // update pointer by amount dyld slid 
 184                 *((uintptr_t*)(reloc
->r_address 
+ relocBase
)) += slide
; 
 190 // For some reason the kernel loads dyld with __TEXT and __LINKEDIT writable 
 191 // rdar://problem/3702311  
 193 static void segmentProtectDyld(const struct macho_header
* mh
, intptr_t slide
) 
 195         const uint32_t cmd_count 
= mh
->ncmds
; 
 196         const struct load_command
* const cmds 
= (struct load_command
*)(((char*)mh
)+sizeof(macho_header
)); 
 197         const struct load_command
* cmd 
= cmds
; 
 198         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
 200                         case LC_SEGMENT_COMMAND
: 
 202                                         const struct macho_segment_command
* seg 
= (struct macho_segment_command
*)cmd
; 
 203                                         vm_address_t addr 
= seg
->vmaddr 
+ slide
; 
 204                                         vm_size_t size 
= seg
->vmsize
; 
 205                                         const bool setCurrentPermissions 
= false; 
 206                                         vm_protect(mach_task_self(), addr
, size
, setCurrentPermissions
, seg
->initprot
); 
 207                                         //dyld::log("dyld: segment %s, 0x%08X -> 0x%08X, set to %d\n", seg->segname, addr, addr+size-1, seg->initprot); 
 211                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
 218 // re-map the main executable to a new random address 
 220 static const struct macho_header
* randomizeExecutableLoadAddress(const struct macho_header
* orgMH
, const char* envp
[], uintptr_t* appsSlide
) 
 223         // don't slide PIE programs running under rosetta 
 224         if ( dyld::isRosetta() ) 
 227         // environment variable DYLD_NO_PIE can disable PIE 
 228         for(const char** p 
= envp
; *p 
!= NULL
; p
++) { 
 229                 if ( strncmp(*p
, "DYLD_NO_PIE=", 12) == 0 ) 
 234         uint32_t segCount 
= 0; 
 235         const uint32_t cmd_count 
= orgMH
->ncmds
; 
 236         const struct load_command
* const cmds 
= (struct load_command
*)(((char*)orgMH
)+sizeof(macho_header
)); 
 237         const struct load_command
* cmd 
= cmds
; 
 238         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
 239                 if ( cmd
->cmd 
== LC_SEGMENT_COMMAND 
) { 
 240                         const struct macho_segment_command
* segCmd 
= (struct macho_segment_command
*)cmd
; 
 241                         // page-zero and custom stacks don't move 
 242                         if ( (strcmp(segCmd
->segname
, "__PAGEZERO") != 0) && (strcmp(segCmd
->segname
, "__UNIXSTACK") != 0) )  
 245                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
 248         // make copy of segment info 
 249         macho_segment_command segs
[segCount
]; 
 251         uintptr_t highestAddressUsed 
= 0; 
 252         uintptr_t lowestAddressUsed 
= UINTPTR_MAX
; 
 254         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
 255                 if ( cmd
->cmd 
== LC_SEGMENT_COMMAND 
) { 
 256                         const struct macho_segment_command
* segCmd 
= (struct macho_segment_command
*)cmd
; 
 257                         if ( (strcmp(segCmd
->segname
, "__PAGEZERO") != 0) && (strcmp(segCmd
->segname
, "__UNIXSTACK") != 0) ) { 
 258                                 segs
[index
++] = *segCmd
; 
 259                                 if ( (segCmd
->vmaddr 
+ segCmd
->vmsize
) > highestAddressUsed 
) 
 260                                         highestAddressUsed 
= ((segCmd
->vmaddr 
+ segCmd
->vmsize
) + 4095) & -4096; 
 261                                 if ( segCmd
->vmaddr 
< lowestAddressUsed 
) 
 262                                         lowestAddressUsed 
= segCmd
->vmaddr
; 
 263                                 // do nothing if kernel has already randomized load address 
 264                                 if ( (strcmp(segCmd
->segname
, "__TEXT") == 0) && (segCmd
->vmaddr 
!= (uintptr_t)orgMH
) ) 
 268                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
 271         // choose a random new base address 
 273         uintptr_t highestAddressPossible 
= highestAddressUsed 
+ 0x100000000ULL
; 
 275         uintptr_t highestAddressPossible 
= 0x2fe00000; 
 277         uintptr_t highestAddressPossible 
= 0x80000000; 
 279         uintptr_t sizeNeeded 
= highestAddressUsed
-lowestAddressUsed
; 
 280         if ( (highestAddressPossible
-sizeNeeded
) < highestAddressUsed 
) { 
 281                 // new and old segments will overlap  
 282                 // need better algorithm for remapping 
 283                 // punt and don't re-map 
 286         uintptr_t possibleRange 
= (highestAddressPossible
-sizeNeeded
) - highestAddressUsed
; 
 287         uintptr_t newBaseAddress 
= highestAddressUsed 
+ ((arc4random() % possibleRange
) & -4096); 
 289         vm_address_t addr 
= newBaseAddress
; 
 290         // reserve new address range 
 291         if ( vm_allocate(mach_task_self(), &addr
, sizeNeeded
, VM_FLAGS_FIXED
) == KERN_SUCCESS 
) { 
 292                 // copy each segment to new address 
 293                 for (uint32_t i 
= 0; i 
< segCount
; ++i
) { 
 294                         uintptr_t newSegAddress 
= segs
[i
].vmaddr 
- lowestAddressUsed 
+ newBaseAddress
; 
 295                         if ( (vm_copy(mach_task_self(), segs
[i
].vmaddr
, segs
[i
].vmsize
, newSegAddress
) != KERN_SUCCESS
) 
 296                 #if !__arm__  // work around for <rdar://problem/5736393> 
 297                                 || (vm_protect(mach_task_self(), newSegAddress
, segs
[i
].vmsize
, true, segs
[i
].maxprot
) != KERN_SUCCESS
)  
 299                                 || (vm_protect(mach_task_self(), newSegAddress
, segs
[i
].vmsize
, false, segs
[i
].initprot
) != KERN_SUCCESS
) ) { 
 300                                 // can't copy so dealloc new region and run with original base address 
 301                                 vm_deallocate(mach_task_self(), newBaseAddress
, sizeNeeded
); 
 302                                 dyld::warn("could not relocate position independent executable\n"); 
 306                 // unmap original segments 
 307                 vm_deallocate(mach_task_self(), lowestAddressUsed
, highestAddressUsed
-lowestAddressUsed
); 
 309                 // run with newly mapped executable 
 310                 *appsSlide 
= newBaseAddress 
- lowestAddressUsed
; 
 311                 return (const struct macho_header
*)newBaseAddress
; 
 314         // can't get new range, so don't slide to random address 
 319 extern "C" void dyld_exceptions_init(const struct macho_header
*, uintptr_t slide
); // in dyldExceptions.cpp 
 320 extern "C" void mach_init(); 
 323 // _pthread_keys is partitioned in a lower part that dyld will use; libSystem 
 324 // will use the upper part.  We set __pthread_tsd_first to 1 as the start of 
 325 // the lower part.  Libc will take #1 and c++ exceptions will take #2.  There 
 326 // is one free key=3 left. 
 329         extern int __pthread_tsd_first
; 
 330         extern void _pthread_keys_init(); 
 335 //  This is code to bootstrap dyld.  This work in normally done for a program by dyld and crt. 
 336 //  In dyld we have to do this manually. 
 338 uintptr_t start(const struct macho_header
* appsMachHeader
, int argc
, const char* argv
[], intptr_t slide
) 
 340         // _mh_dylinker_header is magic symbol defined by static linker (ld), see <mach-o/ldsyms.h> 
 341         const struct macho_header
* dyldsMachHeader 
=  (const struct macho_header
*)(((char*)&_mh_dylinker_header
)+slide
); 
 343         // if kernel had to slide dyld, we need to fix up load sensitive locations 
 344         // we have to do this before using any global variables 
 346                 rebaseDyld(dyldsMachHeader
, slide
); 
 349         uintptr_t appsSlide 
= 0; 
 351         // enable C++ exceptions to work inside dyld 
 352         dyld_exceptions_init(dyldsMachHeader
, slide
); 
 354         // allow dyld to use mach messaging 
 357         // set protection on segments (has to be done after mach_init) 
 358         segmentProtectDyld(dyldsMachHeader
, slide
); 
 360         // kernel sets up env pointer to be just past end of agv array 
 361         const char** envp 
= &argv
[argc
+1]; 
 363         // kernel sets up apple pointer to be just past end of envp array 
 364         const char** apple 
= envp
; 
 365         while(*apple 
!= NULL
) { ++apple
; } 
 368         // run all C++ initializers inside dyld 
 369         runDyldInitializers(dyldsMachHeader
, slide
, argc
, argv
, envp
, apple
); 
 371         // if main executable was linked -pie, then randomize its load address 
 372         if ( appsMachHeader
->flags 
& MH_PIE 
) 
 373                 appsMachHeader 
= randomizeExecutableLoadAddress(appsMachHeader
, envp
, &appsSlide
); 
 375         // now that we are done bootstrapping dyld, call dyld's main 
 376         return dyld::_main(appsMachHeader
, appsSlide
, argc
, argv
, envp
, apple
); 
 382 } // end of namespace