2 * Copyright (c) 2020 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@
24 #include <TargetConditionals.h>
26 #include "ClosureFileSystemPhysical.h"
27 #include "DyldSharedCache.h"
28 #include "MachOAnalyzer.h"
29 #include "RootsChecker.h"
31 #if DYLD_SIMULATOR_ROOTS_SUPPORT
32 #include "SharedCacheRuntime.h"
37 #if DYLD_SIMULATOR_ROOTS_SUPPORT
38 static bool imageUUIDMatchesSharedCache(const char* path
, const closure::FileSystem
* fileSystem
,
39 const DyldSharedCache
* cache
, const closure::Image
* image
) {
40 // We can only use the cache if the file UUID matches the shared cache
41 bool uuidMatchesCache
= false;
43 // The simulator can't pass in a file system as its not hooked up to the vector.
44 // They can just pass in nullptr where needed and we'll assume its the physical file system
45 closure::FileSystemPhysical fileSystemPhysical
;
46 if ( fileSystem
== nullptr )
47 fileSystem
= &fileSystemPhysical
;
50 Platform platform
= cache
->platform();
51 const GradedArchs
& archs
= GradedArchs::forName(cache
->archName(), true);
52 char realerPath
[MAXPATHLEN
];
53 dyld3::closure::LoadedFileInfo loadedFileInfo
= dyld3::MachOAnalyzer::load(diag
, *fileSystem
, path
, archs
, platform
, realerPath
);
54 const dyld3::MachOAnalyzer
* ma
= (const dyld3::MachOAnalyzer
*)loadedFileInfo
.fileContent
;
55 if ( ma
!= nullptr ) {
58 if ( !ma
->getUuid(uuid
) )
59 memset(&uuid
, 0, sizeof(uuid_t
));
60 if ( !image
->getUuid(image_uuid
) )
61 memset(&image_uuid
, 0, sizeof(uuid_t
));
62 uuidMatchesCache
= ( memcmp(uuid
, image_uuid
, sizeof(uuid_t
)) == 0 );
63 fileSystem
->unloadFile(loadedFileInfo
);
65 return uuidMatchesCache
;
68 bool RootsChecker::uuidMatchesSharedCache(const char* path
, const closure::FileSystem
* fileSystem
,
69 const DyldSharedCache
* cache
) {
70 const dyld3::closure::ImageArray
* images
= cache
->cachedDylibsImageArray();
71 const closure::Image
* image
= nullptr;
73 if ( cache
->hasImagePath(path
, imageIndex
) ) {
74 image
= images
->imageForNum(imageIndex
+1);
76 return imageUUIDMatchesSharedCache(path
, fileSystem
, cache
, image
);
80 bool RootsChecker::onDiskFileIsRoot(const char* path
, const DyldSharedCache
* cache
,
81 const closure::Image
* image
,
82 const closure::FileSystem
* fileSystem
,
83 uint64_t inode
, uint64_t modtime
) const {
85 // Upon entry, we know the dylib exists and has a mod time and inode. Now
86 // we need to see if its a root or not
88 // Note we don't check if dylibs are expected on disk here. We assume that an
89 // image only has a mod time and inode if its expected on disk
90 uint64_t expectedINode
;
91 uint64_t expectedMtime
;
92 if ( image
->hasFileModTimeAndInode(expectedINode
, expectedMtime
) ) {
93 if ( (expectedMtime
== modtime
) && (expectedINode
== inode
) )
95 // mod time or inode don't match, so this is a root
99 #if DYLD_SIMULATOR_ROOTS_SUPPORT
100 if ( strcmp(path
, "/usr/lib/system/libsystem_kernel.dylib") == 0 ) {
101 // If this was a root when launchd checked, then assume we are a root now
102 if ( libsystemKernelIsRoot
)
105 // If the file system is read-only, then this cannot be a root now
106 if ( !fileSystemCanBeModified
)
109 // Possibly a root. Open the file and check
110 return !imageUUIDMatchesSharedCache(path
, fileSystem
, cache
, image
);
111 } else if ( strcmp(path
, "/usr/lib/system/libsystem_platform.dylib") == 0 ) {
112 // If this was a root when launchd checked, then assume we are a root now
113 if ( libsystemPlatformIsRoot
)
116 // If the file system is read-only, then this cannot be a root now
117 if ( !fileSystemCanBeModified
)
120 // Possibly a root. Open the file and check
121 return !imageUUIDMatchesSharedCache(path
, fileSystem
, cache
, image
);
122 } else if ( strcmp(path
, "/usr/lib/system/libsystem_pthread.dylib") == 0 ) {
123 // If this was a root when launchd checked, then assume we are a root now
124 if ( libsystemPThreadIsRoot
)
127 // If the file system is read-only, then this cannot be a root now
128 if ( !fileSystemCanBeModified
)
131 // Possibly a root. Open the file and check
132 return !imageUUIDMatchesSharedCache(path
, fileSystem
, cache
, image
);
136 // If we aren't a special simulator dylib, then we must be a root