/* * 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 __ALL_IMAGES_H__ #define __ALL_IMAGES_H__ #include #include #include #include #include #include "Closure.h" #include "Loading.h" #include "MachOLoaded.h" #include "DyldSharedCache.h" #include "PointerAuth.h" #if TARGET_OS_OSX // only in macOS and deprecated struct VIS_HIDDEN OFIInfo { const char* path; // = nullptr; const void* memSource; // = nullptr; size_t memLength; // = 0; const dyld3::MachOLoaded* loadAddress; // = nullptr; uint64_t imageNum; // = 0; }; #endif namespace dyld3 { class VIS_HIDDEN AllImages { public: typedef void (*NotifyFunc)(const mach_header* mh, intptr_t slide); typedef void (*LoadNotifyFunc)(const mach_header* mh, const char* path, bool unloadable); typedef void (*BulkLoadNotifier)(unsigned count, const mach_header* mhs[], const char* paths[]); typedef void (*MainFunc)(void); void init(const closure::LaunchClosure* closure, const DyldSharedCache* dyldCacheLoadAddress, const char* dyldCachePath, const Array& initialImages); void setRestrictions(bool allowAtPaths, bool allowEnvPaths); void setHasCacheOverrides(bool someCacheImageOverriden); bool hasCacheOverrides() const; void setMainPath(const char* path); void setLaunchMode(uint32_t flags); void applyInitialImages(); void addImages(const Array& newImages); void removeImages(const Array& unloadImages); void runImageNotifiers(const Array& newImages); void runImageCallbacks(const Array& newImages); void applyInterposingToDyldCache(const closure::Closure* closure, mach_port_t mach_task_self); void runStartupInitialzers(); void runInitialzersBottomUp(const closure::Image* topImage); void runLibSystemInitializer(LoadedImage& libSystem); uint32_t count() const; void forEachImage(void (^handler)(const LoadedImage& loadedImage, bool& stop)) const; const MachOLoaded* findDependent(const MachOLoaded* mh, uint32_t depIndex); void visitDependentsTopDown(const LoadedImage& start, void (^handler)(const LoadedImage& aLoadedImage, bool& stop)) const; void infoForImageMappedAt(const void* addr, void (^handler)(const LoadedImage& foundImage, uint8_t permissions)) const; bool infoForImageMappedAt(const void* addr, const MachOLoaded** ml, uint64_t* textSize, const char** path) const; void infoForNonCachedImageMappedAt(const void* addr, void (^handler)(const LoadedImage& foundImage, uint8_t permissions)) const; void infoForImageWithLoadAddress(const MachOLoaded*, void (^handler)(const LoadedImage& foundImage)) const; const char* pathForImageMappedAt(const void* addr) const; const char* imagePathByIndex(uint32_t index) const; const mach_header* imageLoadAddressByIndex(uint32_t index) const; bool immutableMemory(const void* addr, size_t length) const; void* interposeValue(void* value) const; bool hasInsertedOrInterposingLibraries() const; bool isRestricted() const; const MachOLoaded* mainExecutable() const; const closure::Image* mainExecutableImage() const; const void* cacheLoadAddress() const { return _dyldCacheAddress; } const char* dyldCachePath() const { return _dyldCachePath; } bool dyldCacheHasPath(const char* path) const; const char* imagePath(const closure::Image*) const; dyld_platform_t platform() const; const GradedArchs& archs() const; uint32_t launchMode() const { return _launchMode; } const Array& imagesArrays(); void incRefCount(const mach_header* loadAddress); void decRefCount(const mach_header* loadAddress); void addLoadNotifier(NotifyFunc); void addUnloadNotifier(NotifyFunc); void setObjCNotifiers(_dyld_objc_notify_mapped, _dyld_objc_notify_init, _dyld_objc_notify_unmapped); void notifyObjCUnmap(const char* path, const struct mach_header* mh); void addLoadNotifier(LoadNotifyFunc); void addBulkLoadNotifier(BulkLoadNotifier); void setOldAllImageInfo(dyld_all_image_infos* old) { _oldAllImageInfos = old; } dyld_all_image_infos* oldAllImageInfo() const { return _oldAllImageInfos;} void notifyMonitorMain(); void notifyMonitorLoads(const Array& newImages); void notifyMonitorUnloads(const Array& unloadingImages); #if TARGET_OS_OSX NSObjectFileImage addNSObjectFileImage(const OFIInfo&); void removeNSObjectFileImage(NSObjectFileImage); bool forNSObjectFileImage(NSObjectFileImage imageHandle, void (^handler)(OFIInfo& image)); #endif const char* getObjCSelector(const char* selName) const; void forEachObjCClass(const char* className, void (^callback)(void* classPtr, bool isLoaded, bool* stop)) const; void forEachObjCProtocol(const char* protocolName, void (^callback)(void* protocolPtr, bool isLoaded, bool* stop)) const; MainFunc getDriverkitMain(); void setDriverkitMain(MainFunc mainFunc); const MachOLoaded* dlopen(Diagnostics& diag, const char* path, bool rtldNoLoad, bool rtldLocal, bool rtldNoDelete, bool forceBindLazies, bool fromOFI, const void* callerAddress, bool canUsePrebuiltSharedCacheClosure = true); struct ProgramVars { const void* mh; int* NXArgcPtr; const char*** NXArgvPtr; const char*** environPtr; const char** __prognamePtr; }; void setProgramVars(ProgramVars* vars, bool keysOff, bool platformBinariesOnly); // Note these are to be used exclusively by forking void takeLockBeforeFork(); void releaseLockInForkParent(); void resetLockInForkChild(); private: friend class Reaper; struct DlopenCount { const mach_header* loadAddress; uintptr_t refCount; }; // // The ImmutableRanges structure is used to make dyld_is_memory_immutable() // fast and lock free. The table contains just ranges that are immutable, // which means they are non-writable and will never be unloaded. // This means the table is only every appended to. No entries are ever removed // or changed. This makes it easier to be lock-less. The array fields // all start as zero. Entries are only appended with the writer lock, // so we don't need to worry about multiple writers colliding. And when // appending, the end field is set before the start field. Readers // of this structure just walk down the array and quit at the first // start field that is zero. // struct ImmutableRanges { std::atomic next; uintptr_t arraySize; struct { std::atomic start; std::atomic end; } array[2]; // programs with only main-exe and dyld cache fit in here }; const MachOLoaded* loadImage(Diagnostics& diag, const char* path, closure::ImageNum topImageNum, const closure::DlopenClosure* newClosure, bool rtldLocal, bool rtldNoDelete, bool rtldNow, bool fromOFI, const void* callerAddress); typedef void (*Initializer)(int argc, const char* argv[], char* envp[], const char* apple[], const ProgramVars* vars); typedef const Array StartImageArray; void runInitialzersInImage(const mach_header* imageLoadAddress, const closure::Image* image); void mirrorToOldAllImageInfos(); void garbageCollectImages(); void breadthFirstRecurseDependents(Array& visited, const LoadedImage& nodeLi, bool& stop, void (^handler)(const LoadedImage& aLoadedImage, bool& stop)) const; void appendToImagesArray(const closure::ImageArray* newArray); void withReadLock(void (^work)()) const; void withWriteLock(void (^work)()); void withNotifiersLock(void (^work)()) const; bool findImage(const mach_header* loadAddress, LoadedImage& foundImage) const; bool findImageNum(closure::ImageNum imageNum, LoadedImage& foundImage) const; LoadedImage findImageNum(closure::ImageNum num, uint32_t& indexHint); bool swapImageState(closure::ImageNum num, uint32_t& indexHint, LoadedImage::State expectedCurrentState, LoadedImage::State newState); void runAllInitializersInImage(const closure::Image* image, const MachOLoaded* ml); void recomputeBounds(); void runAllStaticTerminators(); uintptr_t resolveTarget(closure::Image::ResolvedSymbolTarget target) const; void addImmutableRange(uintptr_t start, uintptr_t end); static void runAllStaticTerminatorsHelper(void*); typedef closure::ImageArray ImageArray; typedef const closure::LaunchClosure* __ptrauth_dyld_address_auth MainClosurePtrType; MainClosurePtrType _mainClosure = nullptr; const DyldSharedCache* _dyldCacheAddress = nullptr; const char* _dyldCachePath = nullptr; uint64_t _dyldCacheSlide = 0; StartImageArray* _initialImages = nullptr; const char* _mainExeOverridePath = nullptr; _dyld_objc_notify_mapped _objcNotifyMapped = nullptr; _dyld_objc_notify_init _objcNotifyInit = nullptr; _dyld_objc_notify_unmapped _objcNotifyUnmapped = nullptr; ProgramVars* _programVars = nullptr; dyld_all_image_infos* _oldAllImageInfos = nullptr; dyld_image_info* _oldAllImageArray = nullptr; dyld_uuid_info* _oldUUIDArray = nullptr; const GradedArchs* _archs = nullptr; ImmutableRanges _immutableRanges = { nullptr, 2 }; uint32_t _oldArrayAllocCount = 0; uint32_t _oldUUIDAllocCount = 0; closure::ImageNum _nextImageNum = 0; int32_t _gcCount = 0; bool _processDOFs = false; bool _allowAtPaths = false; bool _allowEnvPaths = false; bool _someImageOverridden = false; uint32_t _launchMode = 0; uintptr_t _lowestNonCached = 0; uintptr_t _highestNonCached = UINTPTR_MAX; MainFunc _driverkitMain = nullptr; #ifdef OS_UNFAIR_RECURSIVE_LOCK_INIT mutable os_unfair_recursive_lock _globalLock = OS_UNFAIR_RECURSIVE_LOCK_INIT; #else mutable pthread_mutex_t _globalLock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER; #endif GrowableArray _imagesArrays; GrowableArray _loadNotifiers; GrowableArray _unloadNotifiers; GrowableArray _loadNotifiers2; GrowableArray _loadBulkNotifiers; GrowableArray _dlopenRefCounts; GrowableArray _loadedImages; #if TARGET_OS_OSX uint64_t _nextObjectFileImageNum = 0; GrowableArray _objectFileImages; #endif // ObjC selectors // This is an array of the base addresses of sections containing selector strings GrowableArray _objcSelectorHashTableImages; const closure::ObjCSelectorOpt* _objcSelectorHashTable = nullptr; // ObjC classes // This is an array of the base addresses of (name vmaddr, data vmaddr) pairs of sections in each image GrowableArray, 4, 4> _objcClassHashTableImages; const closure::ObjCClassOpt* _objcClassHashTable = nullptr; const closure::ObjCClassDuplicatesOpt* _objcClassDuplicatesHashTable = nullptr; const closure::ObjCClassOpt* _objcProtocolHashTable = nullptr; const objc_opt::objc_opt_t* _dyldCacheObjCOpt = nullptr; }; extern AllImages gAllImages; } // dyld3 #endif // __ALL_IMAGES_H__