Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 | /* * Copyright (c) 2017 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */ #ifndef AppCacheBuilder_h #define AppCacheBuilder_h #include "ASLRTracker.h" #include "CacheBuilder.h" #include "MachOFileAbstraction.hpp" #include "MachOAppCache.h" #include <list> #include <CoreFoundation/CFDictionary.h> struct DylibSymbols; struct VTableBindSymbol; class AppCacheBuilder final : public CacheBuilder { public: struct Options { enum class AppCacheKind { none, kernel, // The base first party kernel collection with xnu and boot time kexts pageableKC, // Other first party kexts which are usually only for some HW, eg, different GPUs kernelCollectionLevel2, // Placeholder until we find a use for this auxKC, // Third party kexts, or Apple kexts updated out of band with the OS, if any }; enum class StripMode { none, // Don't strip anything all, // Strip everything allExceptKernel // Strip everything other than the static kernel }; AppCacheKind cacheKind = AppCacheKind::none; StripMode stripMode = StripMode::none; }; AppCacheBuilder(const DyldSharedCache::CreateOptions& dyldCacheOptions, const Options& appCacheOptions, const dyld3::closure::FileSystem& fileSystem); ~AppCacheBuilder() override final; // Wraps up a loaded macho with the other information required by kext's, eg, the list of dependencies struct InputDylib { LoadedMachO dylib; std::string dylibID; std::vector<std::string> dylibDeps; CFDictionaryRef infoPlist = nullptr; std::string bundlePath; Diagnostics* errors = nullptr; CacheBuilder::DylibStripMode stripMode = CacheBuilder::DylibStripMode::stripNone; }; // The payload for -sectcreate struct CustomSegment { struct CustomSection { std::string sectionName; std::vector<uint8_t> data; uint64_t offsetInRegion = 0; }; std::string segmentName; std::vector<CustomSection> sections; Region* parentRegion = nullptr; }; bool addCustomSection(const std::string& segmentName, CustomSegment::CustomSection section); void setExistingKernelCollection(const dyld3::MachOAppCache* appCacheMA); void setExistingPageableKernelCollection(const dyld3::MachOAppCache* appCacheMA); void setExtraPrelinkInfo(CFDictionaryRef dictionary); void buildAppCache(const std::vector<InputDylib>& dylibs); void writeFile(const std::string& path); void writeBuffer(uint8_t*& buffer, uint64_t& bufferSize) const; private: enum { // The fixup format can't support more than 3 levels right now numFixupLevels = 4 }; struct AppCacheDylibInfo : CacheBuilder::DylibInfo { // From CacheBuilder::DylibInfo // const LoadedMachO* input; // std::string dylibID; // std::vector<SegmentMappingInfo> cacheLocation; DylibStripMode stripMode = DylibStripMode::stripNone; std::vector<std::string> dependencies; CFDictionaryRef infoPlist = nullptr; Diagnostics* errors = nullptr; std::string bundlePath; DylibSectionCoalescer _coalescer; }; static_assert(std::is_move_constructible<AppCacheDylibInfo>::value); struct AlignedRegion { AlignedRegion(Region* region, uint32_t alignmentBefore, uint32_t alignmentAfter) : region(region), alignmentBefore(alignmentBefore), alignmentAfter(alignmentAfter) { } Region* region; uint32_t alignmentBefore; uint32_t alignmentAfter; }; void forEachDylibInfo(void (^callback)(const DylibInfo& dylib, Diagnostics& dylibDiag, cache_builder::ASLR_Tracker& dylibASLRTracker, const CacheBuilder::DylibSectionCoalescer* sectionCoalescer)) override final; void forEachCacheDylib(void (^callback)(const dyld3::MachOAnalyzer* ma, const std::string& dylibID, DylibStripMode stripMode, const std::vector<std::string>& dependencies, Diagnostics& dylibDiag, bool& stop)) const; const DylibInfo* getKernelStaticExecutableInputFile() const; const dyld3::MachOAnalyzer* getKernelStaticExecutableFromCache() const; void makeSortedDylibs(const std::vector<InputDylib>& dylibs); bool removeStubs(); void parseStubs(); void getRegionOrder(bool dataRegionFirstInVMOrder, bool hibernateRegionFirstInVMOrder, std::vector<AlignedRegion>& fileOrder, std::vector<AlignedRegion>& vmOrder, std::map<const Region*, uint32_t>& sectionsToAddToRegions); void allocateBuffer(); void assignSegmentRegionsAndOffsets(); void copyRawSegments(); void assignSegmentAddresses(); void generateCacheHeader(); void generatePrelinkInfo(); uint32_t getCurrentFixupLevel() const; void processFixups(); void rewriteRemovedStubs(); void patchVTables(const dyld3::MachOAnalyzer* kernelMA, const std::string& kernelID, std::map<std::string, DylibSymbols>& dylibsToSymbols, std::map<const uint8_t*, const VTableBindSymbol>& missingBindLocations); void writeFixups(); void fipsSign(); void generateUUID(); uint64_t numRegions() const; uint64_t numBranchRelocationTargets(); uint64_t fixupsPageSize() const; uint64_t numWritablePagesToFixup(uint64_t numBytesToFixup) const; bool fixupsArePerKext() const; void forEachRegion(void (^callback)(const Region& region)) const; bool hasSancovGateSection() const; Options appCacheOptions; const dyld3::MachOAppCache* existingKernelCollection = nullptr; const dyld3::MachOAppCache* pageableKernelCollection = nullptr; CFDictionaryRef extraPrelinkInfo = nullptr; // Note this is mutable as the only parallel writes to it are done atomically to the bitmap mutable cache_builder::ASLR_Tracker _aslrTracker; uint64_t _nonLinkEditReadOnlySize = 0; Region _readOnlyRegion; std::vector<AppCacheDylibInfo> sortedDylibs; std::vector<InputDylib> codelessKexts; std::vector<CustomSegment> customSegments; Region cacheHeaderRegion; Region readExecuteRegion; Region branchStubsRegion; Region textBootExecRegion; Region dataConstRegion; Region lateConstRegion; Region dataSptmRegion; Region branchGOTsRegion; Region readWriteRegion; Region hibernateRegion; Region readOnlyTextRegion; std::list<Region> customDataRegions; // -sectcreate Region prelinkInfoRegion; std::list<Region> nonSplitSegRegions; // Region _readOnlyRegion; // This comes from the base class Region fixupsSubRegion; // This will be in the __LINKEDIT when we write the file // This is the base address from the statically linked kernel, or 0 for other caches // In x86_64, we hack the base address to the address of __HIB as that starts below // the __TEXT address in xnu uint64_t cacheBaseAddress = 0; uint16_t chainedPointerFormat = 0; // The dictionary we ultimately store in the __PRELINK_INFO region CFMutableDictionaryRef prelinkInfoDict = nullptr; // Cache header fields // FIXME: 32-bit struct CacheHeader64 { typedef std::pair<segment_command_64*, Region*> SegmentCommandAndRegion; typedef std::pair<fileset_entry_command*, const DylibInfo*> DylibCommandAndInfo; mach_header_64* header = nullptr; uint64_t numLoadCommands = 0; uint64_t loadCommandsSize = 0; uuid_command* uuid = nullptr; build_version_command* buildVersion = nullptr; thread_command* unixThread = nullptr; symtab_command* symbolTable = nullptr; dysymtab_command* dynSymbolTable = nullptr; linkedit_data_command* chainedFixups = nullptr; std::vector<SegmentCommandAndRegion> segments; std::vector<DylibCommandAndInfo> dylibs; }; CacheHeader64 cacheHeader; }; #endif /* AppCacheBuilder_h */ |