]> git.saurik.com Git - apple/dyld.git/blob - dyld3/closured/closured.cpp
dyld-519.2.1.tar.gz
[apple/dyld.git] / dyld3 / closured / closured.cpp
1 /*
2 * Copyright (c) 2017 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 #include <stdio.h>
25 #include <string.h>
26 #include <sandbox/private.h>
27 #include <bootstrap.h>
28 #include <mach/mach.h>
29 #include <os/log.h>
30 #include <sys/mman.h>
31 #include <sys/errno.h>
32 #include <dispatch/dispatch.h>
33 #include <dispatch/private.h>
34 #include <bootstrap_priv.h> // for bootstrap_check_in()
35 #include <CrashReporterClient.h>
36 #include <libproc.h>
37 #include <uuid/uuid.h>
38
39 #include <string>
40 #include <vector>
41 #include <unordered_map>
42
43 #include "dyld_priv.h"
44 #include "ImageProxy.h"
45 #include "DyldSharedCache.h"
46 #include "FileUtils.h"
47
48 extern "C" {
49 #include "closuredProtocolServer.h"
50 }
51
52
53 static os_log_t sLog = os_log_create("com.apple.dyld.closured", "closured");
54
55 static char sCrashMessageBuffer[1024];
56
57
58 kern_return_t
59 do_CreateClosure(
60 mach_port_t port,
61 task_t requestor,
62 vm_address_t buffer,
63 mach_msg_type_number_t bufferCnt,
64 vm_address_t* returnData,
65 mach_msg_type_number_t* returnDataCnt)
66 {
67 dyld3::ClosureBuffer clsBuff((void*)buffer, bufferCnt);
68 const char* imagePath = clsBuff.targetPath();
69 os_log(sLog, "request to build closure for %s\n", imagePath);
70
71 // set crash log message in case there is an assert during processing
72 strlcpy(sCrashMessageBuffer, "building closure for: ", sizeof(sCrashMessageBuffer));
73 strlcat(sCrashMessageBuffer, imagePath, sizeof(sCrashMessageBuffer));
74 CRSetCrashLogMessage(sCrashMessageBuffer);
75
76 Diagnostics diag;
77 const dyld3::launch_cache::binary_format::Closure* cls = dyld3::ImageProxyGroup::makeClosure(diag, clsBuff, requestor);
78
79 os_log_info(sLog, "finished closure build, closure=%p\n", cls);
80 for (const std::string& message: diag.warnings())
81 os_log(sLog, "Image generated warning: %s\n", message.c_str());
82
83 if ( diag.noError() ) {
84 // on success return the closure binary in the "returnData" buffer
85 dyld3::ClosureBuffer result(cls);
86 *returnData = result.vmBuffer();
87 *returnDataCnt = result.vmBufferSize();
88 }
89 else {
90 // on failure return the error message in the "returnData" buffer
91 os_log_error(sLog, "failed to create ImageGroup: %s\n", diag.errorMessage().c_str());
92 dyld3::ClosureBuffer err(diag.errorMessage().c_str());
93 *returnData = err.vmBuffer();
94 *returnDataCnt = err.vmBufferSize();
95 }
96
97 CRSetCrashLogMessage(nullptr);
98 return KERN_SUCCESS;
99 }
100
101 kern_return_t
102 do_CreateImageGroup(
103 mach_port_t port,
104 task_t requestor,
105 vm_address_t buffer,
106 mach_msg_type_number_t bufferCnt,
107 vm_address_t* returnData,
108 mach_msg_type_number_t* returnDataCnt)
109 {
110 dyld3::ClosureBuffer clsBuff((void*)buffer, bufferCnt);
111 const char* imagePath = clsBuff.targetPath();
112 int requestorPid;
113 char requestorName[MAXPATHLEN];
114 if ( pid_for_task(requestor, &requestorPid) == 0 ) {
115 int nameLen = proc_name(requestorPid, requestorName, sizeof(requestorName));
116 if ( nameLen <= 0 )
117 strcpy(requestorName, "???");
118 os_log(sLog, "request from %d (%s) to build dlopen ImageGroup for %s\n", requestorPid, requestorName, imagePath);
119 }
120
121 // set crash log message in case there is an assert during processing
122 strlcpy(sCrashMessageBuffer, "building ImageGroup for dlopen(", sizeof(sCrashMessageBuffer));
123 strlcat(sCrashMessageBuffer, imagePath, sizeof(sCrashMessageBuffer));
124 strlcat(sCrashMessageBuffer, ") requested by ", sizeof(sCrashMessageBuffer));
125 strlcat(sCrashMessageBuffer, requestorName, sizeof(sCrashMessageBuffer));
126 CRSetCrashLogMessage(sCrashMessageBuffer);
127
128 uuid_string_t uuidStr;
129 dyld3::ClosureBuffer::CacheIdent cacheIdent = clsBuff.cacheIndent();
130 uuid_unparse(cacheIdent.cacheUUID, uuidStr);
131 os_log_info(sLog, "findDyldCache(): cache addr=0x%llX, size=0x%0llX, uuid = %s\n", cacheIdent.cacheAddress, cacheIdent.cacheMappedSize, uuidStr);
132
133 Diagnostics diag;
134 const dyld3::launch_cache::binary_format::ImageGroup* imageGroup = dyld3::ImageProxyGroup::makeDlopenGroup(diag, clsBuff, requestor, {""});
135
136 os_log(sLog, "finished ImageGroup build, imageGroup=%p\n", imageGroup);
137 for (const std::string& message: diag.warnings()) {
138 os_log(sLog, "Image generated warning: %s\n", message.c_str());
139 }
140
141 // delete incoming out-of-line data
142 vm_deallocate(mach_task_self(), buffer, bufferCnt);
143
144 if ( diag.noError() ) {
145 // on success return the ImageGroup binary in the "returnData" buffer
146 dyld3::ClosureBuffer result(imageGroup);
147 os_log_info(sLog, "returning closure buffer: 0x%lX, size=0x%X\n", (long)result.vmBuffer(), result.vmBufferSize());
148 *returnData = result.vmBuffer();
149 *returnDataCnt = result.vmBufferSize();
150 free((void*)imageGroup);
151 }
152 else {
153 // on failure return the error message in the "returnData" buffer
154 os_log_error(sLog, "failed to create ImageGroup: %s\n", diag.errorMessage().c_str());
155 dyld3::ClosureBuffer err(diag.errorMessage().c_str());
156 *returnData = err.vmBuffer();
157 *returnDataCnt = err.vmBufferSize();
158 }
159
160 CRSetCrashLogMessage(nullptr);
161 return KERN_SUCCESS;
162 }
163
164
165
166
167 // /usr/libexec/closured -create_closure /Applications/TextEdit.app -pipefd 4 -env DYLD_FOO=1 -cache_uuid C153F90A-69F2-323E-AC9F-2BBAE48ABAF7
168 int runAsTool(int argc, const char* argv[])
169 {
170 const char* progPath = nullptr;
171 int pipeNum = -1;
172 bool verbose = false;
173 std::vector<std::string> dyldEnvVars;
174
175 dyld3::ClosureBuffer::CacheIdent cacheIdent;
176 bzero(&cacheIdent, sizeof(cacheIdent));
177
178 // set crash log message in case there is an assert during processing
179 sCrashMessageBuffer[0] = '\0';
180 for (int i=0; i < argc; ++i) {
181 strlcat(sCrashMessageBuffer, argv[i], sizeof(sCrashMessageBuffer));
182 strlcat(sCrashMessageBuffer, " ", sizeof(sCrashMessageBuffer));
183 }
184 CRSetCrashLogMessage(sCrashMessageBuffer);
185
186 for (int i=1; i < argc; ++i) {
187 const char* arg = argv[i];
188 if ( strcmp(arg, "-create_closure") == 0 ) {
189 progPath = argv[++i];
190 if ( progPath == nullptr ) {
191 fprintf(stderr, "-create_closure option requires a path to follow\n");
192 return 1;
193 }
194 }
195 else if ( strcmp(arg, "-cache_uuid") == 0 ) {
196 const char* uuidStr = argv[++i];
197 if ( uuidStr == nullptr ) {
198 fprintf(stderr, "-cache_uuid option requires a path to follow\n");
199 return 1;
200 }
201 uuid_parse(uuidStr, cacheIdent.cacheUUID);
202 }
203 else if ( strcmp(arg, "-cache_address") == 0 ) {
204 const char* cacheAddr = argv[++i];
205 if ( cacheAddr == nullptr ) {
206 fprintf(stderr, "-cache_address option requires a path to follow\n");
207 return 1;
208 }
209 char *end;
210 cacheIdent.cacheAddress = strtol(cacheAddr, &end, 0);
211 }
212 else if ( strcmp(arg, "-cache_size") == 0 ) {
213 const char* cacheSize = argv[++i];
214 if ( cacheSize == nullptr ) {
215 fprintf(stderr, "-cache_size option requires a path to follow\n");
216 return 1;
217 }
218 char *end;
219 cacheIdent.cacheMappedSize = strtol(cacheSize, &end, 0);
220 }
221 else if ( strcmp(arg, "-pipefd") == 0 ) {
222 const char* numStr = argv[++i];
223 if ( numStr == nullptr ) {
224 fprintf(stderr, "-pipefd option requires an file descriptor number to follow\n");
225 return 1;
226 }
227 char *end;
228 pipeNum = (int)strtol(numStr, &end, 0);
229 if ( (pipeNum == 0) && (errno != 0) ) {
230 fprintf(stderr, "bad value (%s) for -pipefd option %d\n", numStr, pipeNum);
231 return 1;
232 }
233 }
234 else if ( strcmp(arg, "-env") == 0 ) {
235 const char* var = argv[++i];
236 if ( var == nullptr ) {
237 fprintf(stderr, "-env option requires a following VAR=XXX\n");
238 return 1;
239 }
240 dyldEnvVars.push_back(var);
241 }
242 else {
243 fprintf(stderr, "unknown option: %s\n", arg);
244 return 1;
245 }
246 }
247 if ( progPath == nullptr ) {
248 fprintf(stderr, "missing required -create_closure option\n");
249 return 1;
250 }
251 if ( pipeNum == -1 ) {
252 fprintf(stderr, "missing required -pipefd option\n");
253 return 1;
254 }
255
256 if ( verbose ) {
257 fprintf(stderr, "closured: runAsTool()\n");
258 for (int i=1; i < argc; ++i)
259 fprintf(stderr, " argv[%d] = %s\n", i, argv[i]);
260 }
261
262 os_log(sLog, "fork/exec request to build closure for %s\n", progPath);
263 SocketBasedClousureHeader header;
264
265 // find dyld cache for requested arch
266 size_t currentCacheSize;
267 const DyldSharedCache* currentCache = (const DyldSharedCache*)_dyld_get_shared_cache_range(&currentCacheSize);
268 if ( currentCache == nullptr ) {
269 os_log_error(sLog, "closured is running without a dyld cache\n");
270 return 1;
271 }
272 uuid_t currentCacheUUID;
273 currentCache->getUUID(currentCacheUUID);
274 if ( memcmp(currentCacheUUID, cacheIdent.cacheUUID, 16) != 0 ) {
275 const char* errorString = "closured is running with a different dyld cache than client";
276 os_log_error(sLog, "%s\n", errorString);
277 header.success = 0;
278 header.length = (int)strlen(errorString) + 1;
279 write(pipeNum, &header, sizeof(SocketBasedClousureHeader));
280 write(pipeNum, errorString, header.length);
281 close(pipeNum);
282 return 0;
283 }
284 dyld3::DyldCacheParser cacheParser(currentCache, false);
285
286 Diagnostics diag;
287 os_log_info(sLog, "starting closure build\n");
288 const dyld3::launch_cache::BinaryClosureData* cls = dyld3::ImageProxyGroup::makeClosure(diag, cacheParser, progPath, false, {""}, dyldEnvVars);
289 os_log_info(sLog, "finished closure build, cls=%p\n", cls);
290 if ( diag.noError() ) {
291 // on success write the closure binary after the header to the socket
292 dyld3::launch_cache::Closure closure(cls);
293 os_log(sLog, "returning closure, size=%lu\n", closure.size());
294 header.success = 1;
295 header.length = (uint32_t)closure.size();
296 write(pipeNum, &header, sizeof(SocketBasedClousureHeader));
297 write(pipeNum, cls, closure.size());
298 }
299 else {
300 // on failure write the error message after the header to the socket
301 const std::string& message = diag.errorMessage();
302 os_log_error(sLog, "closure could not be created: %s\n", message.c_str());
303 header.success = 0;
304 header.length = (uint32_t)message.size() + 1;
305 write(pipeNum, &header, sizeof(SocketBasedClousureHeader));
306 write(pipeNum, message.c_str(), header.length);
307 }
308
309 close(pipeNum);
310
311 return 0;
312 }
313
314
315 union MaxMsgSize {
316 union __RequestUnion__do_closured_subsystem req;
317 union __ReplyUnion__do_closured_subsystem rep;
318 };
319
320 int main(int argc, const char* argv[])
321 {
322 #if __MAC_OS_X_VERSION_MIN_REQUIRED
323 // establish sandbox around process
324 char* errMsg = nullptr;
325 if ( sandbox_init_with_parameters("com.apple.dyld.closured", SANDBOX_NAMED, nullptr, &errMsg) != 0 ) {
326 os_log_error(sLog, "Failed to enter sandbox: %{public}s", errMsg);
327 exit(EXIT_FAILURE);
328 }
329 #endif
330
331 if ( argc != 1 )
332 return runAsTool(argc, argv);\
333
334 mach_port_t serverPort = MACH_PORT_NULL;
335 kern_return_t kr = bootstrap_check_in(bootstrap_port, CLOSURED_SERVICE_NAME, &serverPort);
336 if (kr != KERN_SUCCESS)
337 exit(-1);
338
339 dispatch_source_t machSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV, serverPort, 0, dispatch_get_main_queue());
340 if (machSource == nullptr)
341 exit(-1);
342
343 dispatch_source_set_event_handler(machSource, ^{
344 dispatch_mig_server(machSource, sizeof(union MaxMsgSize), closured_server);
345 });
346 dispatch_source_set_cancel_handler(machSource, ^{
347 mach_port_t port = (mach_port_t)dispatch_source_get_handle(machSource);
348 kern_return_t kr = mach_port_mod_refs(mach_task_self(), port, MACH_PORT_RIGHT_RECEIVE, -1);
349 if (kr != KERN_SUCCESS)
350 exit(-1);
351 });
352 dispatch_resume(machSource);
353 dispatch_main();
354
355 return 0;
356 }
357