2 * Copyright (c) 2017 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
32 #include <uuid/uuid.h>
33 #include <mach/mach.h>
34 #include <mach-o/loader.h>
38 #include <unordered_set>
40 #include "shared-cache/DyldSharedCache.h"
43 #include "Diagnostics.h"
45 #define VIS_HIDDEN __attribute__((visibility("hidden")))
50 class DyldCacheParser
;
52 namespace launch_cache
{
55 namespace binary_format
{
62 struct AllFixupsBySegment
;
63 struct SegmentFixupsByPage
;
66 typedef binary_format::Image BinaryImageData
;
67 typedef binary_format::ImageGroup BinaryImageGroupData
;
68 typedef binary_format::Closure BinaryClosureData
;
71 struct VIS_HIDDEN MemoryRange
73 bool contains(const MemoryRange
& other
) const;
74 bool intersects(const MemoryRange
& other
) const;
81 class VIS_HIDDEN SlowLoadSet
84 SlowLoadSet(const BinaryImageData
** start
, const BinaryImageData
** end
) : _start(start
), _end(end
), _current(start
) { }
85 bool contains(const BinaryImageData
*);
86 bool add(const BinaryImageData
*);
87 void forEach(void (^handler
)(const BinaryImageData
*));
88 void forEach(void (^handler
)(const BinaryImageData
*, bool& stop
));
91 const BinaryImageData
** const _start
;
92 const BinaryImageData
** const _end
;
93 const BinaryImageData
** _current
;
100 class VIS_HIDDEN DynArray
103 DynArray(uintptr_t count
, T
* storage
) : _count(count
), _elements(storage
) { }
105 DynArray(const std::vector
<T
>& vec
) : _count(vec
.size()), _elements((T
*)&vec
[0]) { }
108 T
& operator[](size_t idx
) { assert(idx
< _count
); return _elements
[idx
]; }
109 const T
& operator[](size_t idx
) const { assert(idx
< _count
); return _elements
[idx
]; }
110 uintptr_t count() const { return _count
; }
117 // STACK_ALLOC_DYNARRAY(foo, 10, myarray);
118 #define STACK_ALLOC_DYNARRAY(_type, _count, _name) \
119 uintptr_t __##_name##_array_alloc[1 + ((sizeof(_type)*(_count))/sizeof(uintptr_t))]; \
120 dyld3::launch_cache::DynArray<_type> _name(_count, (_type*)__##_name##_array_alloc);
123 typedef DynArray
<const BinaryImageGroupData
*> ImageGroupList
;
126 // In the pre-computed fixups for an Image, each fixup location is set to a TargetSymbolValue
127 // which is an abstract encoding of a resolved symbol in an image that can be turned into a
128 // real address once all ASLR slides are known.
129 struct VIS_HIDDEN TargetSymbolValue
135 virtual const uint8_t* dyldCacheLoadAddressForImage() = 0;
136 virtual const mach_header
* loadAddressFromGroupAndIndex(uint32_t groupNum
, uint32_t indexInGroup
) = 0;
137 virtual void forEachImage(void (^handler
)(uint32_t anIndex
, const BinaryImageData
*, const mach_header
*, bool& stop
)) = 0;
138 virtual void setAsNeverUnload(uint32_t anIndex
) = 0;
141 uintptr_t resolveTarget(Diagnostics
& diag
, const ImageGroup
& inGroup
, LoadedImages
& images
) const;
143 static TargetSymbolValue
makeInvalid();
144 static TargetSymbolValue
makeAbsolute(uint64_t value
);
145 static TargetSymbolValue
makeSharedCacheOffset(uint32_t offset
);
146 static TargetSymbolValue
makeGroupValue(uint32_t groupIndex
, uint32_t imageIndexInGroup
, uint64_t offsetInImage
, bool isIndirectGroupNum
);
147 static TargetSymbolValue
makeDynamicGroupValue(uint32_t imagePathPoolOffset
, uint32_t imageSymbolPoolOffset
, bool weakImport
);
148 std::string
asString(ImageGroup group
) const;
149 bool operator==(const TargetSymbolValue
& other
) const { return (_data
.raw
== other
._data
.raw
); }
150 bool isSharedCacheTarget(uint64_t& offsetInCache
) const;
151 bool isGroupImageTarget(uint32_t& groupNum
, uint32_t& indexInGroup
, uint64_t& offsetInImage
) const;
152 bool isInvalid() const;
157 enum Kinds
{ kindSharedCache
, kindAbsolute
, kindGroup
, kindDynamicGroup
};
160 struct SharedCacheOffsetTarget
{
161 uint64_t kind
: 2, // kindSharedCache
162 offsetIntoCache
: 62;
164 struct AbsoluteTarget
{
165 uint64_t kind
: 2, // kindAbsolute
168 struct GroupImageTarget
{
169 uint64_t kind
: 2, // kindGroup
170 isIndirectGroup
: 1, // 0 => use groupNum directly. 1 => index indirect side table
171 groupNum
: 7, // 0 not used, 1 => other dylibs, 2 => main closure, 3 => first dlopen group
175 struct DynamicGroupImageTarget
{
176 uint64_t kind
: 2, // kindDynamicGroup
178 imagePathOffset
: 30,
179 symbolNameOffset
: 31;
182 SharedCacheOffsetTarget sharedCache
;
183 AbsoluteTarget absolute
;
184 GroupImageTarget group
;
185 DynamicGroupImageTarget dynamicGroup
;
189 static_assert(sizeof(_data
) == 8, "Overflow in size of TargetSymbolValue");
193 struct VIS_HIDDEN Image
195 enum class LinkKind
{ regular
=0, weak
=1, upward
=2, reExport
=3 };
196 enum class FixupKind
{ rebase32
, rebase64
, bind32
, bind64
, rebaseText32
, bindText32
, bindTextRel32
, bindImportJmp32
};
198 Image(const BinaryImageData
* binaryData
) : _binaryData(binaryData
) { }
200 bool valid() const { return (_binaryData
!= nullptr); }
201 const BinaryImageData
* binaryData() const { return _binaryData
; }
202 const ImageGroup
group() const;
203 uint32_t maxLoadCount() const;
204 const char* path() const;
205 const char* leafName() const;
206 uint32_t pathHash() const;
207 const uuid_t
* uuid() const;
208 bool isInvalid() const;
209 bool hasObjC() const;
210 bool isBundle() const;
211 bool hasWeakDefs() const;
212 bool mayHavePlusLoads() const;
213 bool hasTextRelocs() const;
214 bool neverUnload() const;
215 bool cwdMustBeThisDir() const;
216 bool isPlatformBinary() const;
217 bool overridableDylib() const;
218 bool validateUsingModTimeAndInode() const;
219 bool validateUsingCdHash() const;
220 uint64_t fileModTime() const;
221 uint64_t fileINode() const;
222 const uint8_t* cdHash16() const;
223 void forEachDependentImage(const ImageGroupList
& groups
, void (^handler
)(uint32_t depIndex
, Image depImage
, LinkKind kind
, bool& stop
)) const;
225 bool recurseAllDependentImages(const ImageGroupList
& groups
, std::unordered_set
<const BinaryImageData
*>& allDependents
) const;
227 bool recurseAllDependentImages(const ImageGroupList
& groups
, SlowLoadSet
& allDependents
,
228 void (^handler
)(const dyld3::launch_cache::binary_format::Image
* aBinImage
, bool& stop
)) const;
229 bool containsAddress(const void* addr
, const void* imageLoadAddress
, uint8_t* permissions
) const;
230 bool segmentHasFixups(uint32_t segIndex
) const;
231 void forEachInitializer(const void* imageLoadAddress
, void (^handler
)(const void* initializer
)) const;
232 void forEachInitBefore(const ImageGroupList
& groups
, void (^handler
)(Image imageToInit
)) const;
233 void forEachInitBefore(void (^handler
)(binary_format::ImageRef imageToInit
)) const;
234 void forEachDOF(const void* imageLoadAddress
, void (^handler
)(const void* initializer
)) const;
236 bool isDiskImage() const;
238 // the following are only valid if isDiskImage() returns false
239 const binary_format::CachedImage
* asCachedImage() const;
240 uint32_t cacheOffset() const;
241 uint32_t patchStartIndex() const;
242 uint32_t patchCount() const;
245 // the following are only valid if isDiskImage() returns true
246 const binary_format::DiskImage
* asDiskImage() const;
247 uint64_t sliceOffsetInFile() const;
248 bool hasCodeSignature(uint32_t& fileOffset
, uint32_t& size
) const;
249 bool isFairPlayEncrypted(uint32_t& textOffset
, uint32_t& size
) const;
250 uint64_t vmSizeToMap() const;
251 void forEachDiskSegment(void (^handler
)(uint32_t segIndex
, uint32_t fileOffset
, uint32_t fileSize
, int64_t vmOffset
, uint64_t vmSize
, uint8_t permissions
, bool& stop
)) const;
252 void forEachCacheSegment(void (^handler
)(uint32_t segIndex
, uint64_t vmOffset
, uint64_t vmSize
, uint8_t permissions
, bool& stop
)) const;
253 void forEachFixup(uint32_t segIndex
, MemoryRange segContent
,
254 void (^handler
)(uint64_t segOffset
, FixupKind kind
, TargetSymbolValue value
, bool& stop
)) const;
257 void printAsJSON(const ImageGroupList
& groupList
, bool printFixups
=false, bool printDependentsDetails
=false, FILE* out
=stdout
) const;
260 // todo: fairPlayTextPages
263 friend struct ImageGroup
;
264 friend struct Closure
;
266 bool recurseAllDependentImages(const ImageGroupList
& groups
, SlowLoadSet
& allDependents
, bool& stopped
,
267 void (^handler
)(const dyld3::launch_cache::binary_format::Image
* aBinImage
, bool& stop
)) const;
268 uint32_t pageSize() const;
269 const binary_format::SegmentFixupsByPage
* segmentFixups(uint32_t segIndex
) const;
270 static void forEachFixup(const uint8_t* pageFixups
, const void* segContent
, uint32_t& offset
, uint32_t& ordinal
,
271 void (^handler
)(uint32_t pageOffset
, FixupKind kind
, uint32_t targetOrdinal
, bool& stop
));
272 static Image
resolveImageRef(const ImageGroupList
& groups
, binary_format::ImageRef ref
, bool applyOverrides
=true);
275 const BinaryImageData
* _binaryData
;
279 struct VIS_HIDDEN ImageGroup
281 ImageGroup(const BinaryImageGroupData
* binaryData
) : _binaryData(binaryData
) { }
284 uint32_t imageCount() const;
285 uint32_t groupNum() const;
286 bool dylibsExpectedOnDisk() const;
287 const Image
image(uint32_t index
) const;
288 uint32_t indexInGroup(const BinaryImageData
* image
) const;
289 const BinaryImageData
* findImageByPath(const char* path
, uint32_t& foundIndex
) const;
290 const BinaryImageData
* findImageByCacheOffset(size_t cacheVmOffset
, uint32_t& mhCacheOffset
, uint8_t& foundPermissions
) const;
291 const BinaryImageData
* imageBinary(uint32_t index
) const;
292 binary_format::ImageRef
dependentPool(uint32_t index
) const;
293 const BinaryImageGroupData
* binaryData() const { return _binaryData
; }
294 const char* stringFromPool(uint32_t offset
) const;
295 uint32_t indirectGroupNum(uint32_t index
) const;
296 void forEachImageRefOverride(void (^handler
)(binary_format::ImageRef standardDylibRef
, binary_format::ImageRef overrideDyilbRef
, bool& stop
)) const;
297 void forEachImageRefOverride(const ImageGroupList
& groupList
, void (^handler
)(Image standardDylib
, Image overrideDyilb
, bool& stop
)) const;
298 void forEachAliasOf(uint32_t imageIndex
, void (^handler
)(const char* aliasPath
, uint32_t aliasPathHash
, bool& stop
)) const;
300 void forEachDyldCacheSymbolOverride(void (^handler
)(uint32_t patchTableIndex
, const BinaryImageData
* image
, uint32_t imageOffset
, bool& stop
)) const;
301 void forEachDyldCachePatchLocation(const void* dyldCacheLoadAddress
, uint32_t patchTargetIndex
,
302 void (^handler
)(uintptr_t* locationToPatch
, uintptr_t addend
, bool& stop
)) const;
304 void forEachDyldCacheSymbolOverride(void (^handler
)(uint32_t patchTableIndex
, uint32_t imageIndexInClosure
, uint32_t imageOffset
, bool& stop
)) const;
305 void forEachDyldCachePatchLocation(const DyldCacheParser
& cacheParser
, void (^handler
)(uint32_t targetCacheOffset
, const std::vector
<uint32_t>& usesPointersCacheOffsets
, bool& stop
)) const;
306 bool hasPatchTableIndex(uint32_t targetCacheOffset
, uint32_t& index
) const;
309 static uint32_t hashFunction(const char* s
);
311 void printAsJSON(const ImageGroupList
& groupList
, bool printFixups
=false, bool printDependentsDetails
=false, FILE* out
=stdout
) const;
312 void printStatistics(FILE* out
=stderr
) const;
318 const char* stringPool() const;
319 uint32_t stringPoolSize() const;
320 const uint64_t* segmentPool(uint32_t index
) const;
321 const binary_format::AllFixupsBySegment
* fixUps(uint32_t offset
) const;
322 const TargetSymbolValue
* targetValuesArray() const;
323 uint32_t targetValuesCount() const;
324 uint32_t initializersPoolCount() const;
325 const uint32_t* initializerOffsetsPool() const;
326 const uint32_t initializerOffsetsCount() const;
327 const binary_format::ImageRef
* intializerListPool() const;
328 const uint32_t intializerListPoolCount() const;
329 const uint32_t* dofOffsetsPool() const;
330 const uint32_t dofOffsetsCount() const;
331 const uint32_t* indirectGroupNumsPool() const;
332 const uint32_t indirectGroupNumsCount() const;
333 void forEachDyldCachePatch(uint32_t patchTargetIndex
, uint32_t cacheDataVmOffset
,
334 void (^handler
)(uint32_t targetCacheOffset
, uint32_t usePointersCacheOffset
, bool hasAddend
, bool& stop
)) const;
336 const BinaryImageGroupData
* _binaryData
;
341 struct VIS_HIDDEN Closure
343 Closure(const BinaryClosureData
* binaryData
);
346 const uuid_t
* dyldCacheUUID() const;
347 const uint8_t* cdHash() const;
348 uint32_t initialImageCount() const;
349 uint32_t mainExecutableImageIndex() const;
350 uint32_t mainExecutableEntryOffset() const;
351 bool mainExecutableUsesCRT() const;
352 bool isRestricted() const;
353 bool usesLibraryValidation() const;
354 const BinaryImageData
* libSystem(const ImageGroupList
& groups
);
355 const BinaryImageData
* libDyld(const ImageGroupList
& groups
);
356 uint32_t libdyldVectorOffset() const;
357 const ImageGroup
group() const;
358 const BinaryClosureData
* binaryData() const { return _binaryData
; }
359 void forEachMustBeMissingFile(void (^handler
)(const char* path
, bool& stop
)) const;
360 void forEachEnvVar(void (^handler
)(const char* keyEqualValue
, bool& stop
)) const;
363 void printAsJSON(const ImageGroupList
& groupList
, bool printFixups
=true, bool printDependentsDetails
=false, FILE* out
=stdout
) const;
364 void printStatistics(FILE* out
=stderr
) const;
368 const BinaryClosureData
* _binaryData
;
376 } // namespace launch_cache
380 #endif // LaunchCache_h