]>
Commit | Line | Data |
---|---|---|
5b0a4722 | 1 | /* |
95379394 | 2 | * Copyright (c) 1999-2012 Apple Inc. All rights reserved. |
5b0a4722 A |
3 | * |
4 | * @APPLE_APACHE_LICENSE_HEADER_START@ | |
5 | * | |
6 | * Licensed under the Apache License, Version 2.0 (the "License"); | |
7 | * you may not use this file except in compliance with the License. | |
8 | * You may obtain a copy of the License at | |
9 | * | |
10 | * http://www.apache.org/licenses/LICENSE-2.0 | |
11 | * | |
12 | * Unless required by applicable law or agreed to in writing, software | |
13 | * distributed under the License is distributed on an "AS IS" BASIS, | |
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
15 | * See the License for the specific language governing permissions and | |
16 | * limitations under the License. | |
17 | * | |
18 | * @APPLE_APACHE_LICENSE_HEADER_END@ | |
19 | */ | |
20 | ||
21 | #include "config.h" | |
ef398931 A |
22 | #include "vproc.h" |
23 | #include "vproc_priv.h" | |
24 | #include "vproc_internal.h" | |
5b0a4722 | 25 | |
eabd1701 A |
26 | #include <dispatch/dispatch.h> |
27 | #include <libproc.h> | |
5b0a4722 A |
28 | #include <mach/mach.h> |
29 | #include <mach/vm_map.h> | |
30 | #include <sys/param.h> | |
31 | #include <stdlib.h> | |
32 | #include <stdio.h> | |
33 | #include <errno.h> | |
34 | #include <unistd.h> | |
35 | #include <syslog.h> | |
36 | #include <pthread.h> | |
ddbbfbc1 A |
37 | #include <signal.h> |
38 | #include <assert.h> | |
39 | #include <libkern/OSAtomic.h> | |
40 | #include <sys/syscall.h> | |
dcace88f | 41 | #include <sys/event.h> |
eabd1701 | 42 | #include <System/sys/fileport.h> |
95379394 | 43 | #include <os/assumes.h> |
ddbbfbc1 | 44 | |
f36da725 A |
45 | #if HAVE_QUARANTINE |
46 | #include <quarantine.h> | |
47 | #endif | |
5b0a4722 | 48 | |
ef398931 A |
49 | #include "launch.h" |
50 | #include "launch_priv.h" | |
51 | #include "launch_internal.h" | |
eabd1701 | 52 | #include "ktrace.h" |
5b0a4722 | 53 | |
eabd1701 | 54 | #include "job.h" |
5b0a4722 | 55 | |
eabd1701 A |
56 | #include "helper.h" |
57 | #include "helperServer.h" | |
dcace88f | 58 | |
5b0a4722 A |
59 | #include "reboot2.h" |
60 | ||
eabd1701 A |
61 | #define likely(x) __builtin_expect((bool)(x), true) |
62 | #define unlikely(x) __builtin_expect((bool)(x), false) | |
ddbbfbc1 | 63 | |
eabd1701 | 64 | #define _vproc_set_crash_log_message(x) |
5b0a4722 | 65 | |
eabd1701 A |
66 | void _vproc_transactions_enable_internal(void *arg); |
67 | void _vproc_transaction_begin_internal(void *arg __unused); | |
68 | void _vproc_transaction_end_internal(void *arg __unused); | |
ddbbfbc1 | 69 | |
eabd1701 | 70 | #pragma mark vproc Object |
ddbbfbc1 A |
71 | struct vproc_s { |
72 | int32_t refcount; | |
73 | mach_port_t j_port; | |
74 | }; | |
75 | ||
eabd1701 A |
76 | vproc_t |
77 | vprocmgr_lookup_vproc(const char *label) | |
ddbbfbc1 A |
78 | { |
79 | struct vproc_s *vp = NULL; | |
eabd1701 | 80 | |
ddbbfbc1 A |
81 | mach_port_t mp = MACH_PORT_NULL; |
82 | kern_return_t kr = vproc_mig_port_for_label(bootstrap_port, (char *)label, &mp); | |
dcace88f | 83 | if (kr == BOOTSTRAP_SUCCESS) { |
ddbbfbc1 | 84 | vp = (struct vproc_s *)calloc(1, sizeof(struct vproc_s)); |
dcace88f | 85 | if (vp) { |
ddbbfbc1 A |
86 | vp->refcount = 1; |
87 | mach_port_mod_refs(mach_task_self(), mp, MACH_PORT_RIGHT_SEND, 1); | |
88 | vp->j_port = mp; | |
89 | } | |
dcace88f | 90 | (void)mach_port_deallocate(mach_task_self(), mp); |
ddbbfbc1 | 91 | } |
eabd1701 | 92 | |
ddbbfbc1 A |
93 | return vp; |
94 | } | |
95 | ||
eabd1701 A |
96 | vproc_t |
97 | vproc_retain(vproc_t vp) | |
ddbbfbc1 A |
98 | { |
99 | int32_t orig = OSAtomicAdd32(1, &vp->refcount) - 1; | |
dcace88f | 100 | if (orig <= 0) { |
dcace88f | 101 | _vproc_set_crash_log_message("Under-retain / over-release of vproc_t."); |
ddbbfbc1 A |
102 | abort(); |
103 | } | |
eabd1701 | 104 | |
ddbbfbc1 A |
105 | return vp; |
106 | } | |
107 | ||
eabd1701 A |
108 | void |
109 | vproc_release(vproc_t vp) | |
ddbbfbc1 A |
110 | { |
111 | int32_t newval = OSAtomicAdd32(-1, &vp->refcount); | |
dcace88f | 112 | if (newval < 0) { |
dcace88f | 113 | _vproc_set_crash_log_message("Over-release of vproc_t."); |
ddbbfbc1 | 114 | abort(); |
dcace88f | 115 | } else if (newval == 0) { |
ddbbfbc1 A |
116 | mach_port_deallocate(mach_task_self(), vp->j_port); |
117 | free(vp); | |
118 | } | |
119 | } | |
120 | ||
eabd1701 | 121 | #pragma mark Transactions |
ddbbfbc1 | 122 | static void |
eabd1701 | 123 | _vproc_transaction_init_once(void *arg __unused) |
ddbbfbc1 | 124 | { |
95379394 A |
125 | launch_globals_t globals = _launch_globals(); |
126 | ||
eabd1701 A |
127 | int64_t enable_transactions = 0; |
128 | (void)vproc_swap_integer(NULL, VPROC_GSK_TRANSACTIONS_ENABLED, 0, &enable_transactions); | |
129 | if (enable_transactions != 0) { | |
95379394 A |
130 | (void)os_assumes_zero(proc_track_dirty(getpid(), PROC_DIRTY_TRACK)); |
131 | globals->_vproc_transaction_enabled = 1; | |
eabd1701 | 132 | } |
95379394 | 133 | globals->_vproc_transaction_queue = dispatch_queue_create("com.apple.idle-exit-queue", NULL); |
eabd1701 | 134 | } |
ddbbfbc1 | 135 | |
eabd1701 A |
136 | void |
137 | _vproc_transactions_enable_internal(void *arg __unused) | |
138 | { | |
95379394 A |
139 | launch_globals_t globals = _launch_globals(); |
140 | ||
141 | if (!globals->_vproc_transaction_enabled) { | |
142 | (void)os_assumes_zero(proc_track_dirty(getpid(), PROC_DIRTY_TRACK)); | |
143 | globals->_vproc_transaction_enabled = 1; | |
144 | } | |
ddbbfbc1 | 145 | |
95379394 A |
146 | if (globals->_vproc_transaction_cnt > 0) { |
147 | (void)os_assumes_zero(proc_set_dirty(getpid(), true)); | |
ddbbfbc1 | 148 | } |
eabd1701 | 149 | } |
ddbbfbc1 | 150 | |
eabd1701 A |
151 | void |
152 | _vproc_transactions_enable(void) | |
153 | { | |
95379394 A |
154 | launch_globals_t globals = _launch_globals(); |
155 | ||
156 | dispatch_once_f(&globals->_vproc_transaction_once, NULL, _vproc_transaction_init_once); | |
157 | dispatch_sync_f(globals->_vproc_transaction_queue, NULL, _vproc_transactions_enable_internal); | |
ddbbfbc1 A |
158 | } |
159 | ||
eabd1701 A |
160 | void |
161 | _vproc_transaction_begin_internal(void *ctx __unused) | |
ddbbfbc1 | 162 | { |
95379394 A |
163 | launch_globals_t globals = _launch_globals(); |
164 | ||
165 | int64_t new = ++globals->_vproc_transaction_cnt; | |
166 | if (!globals->_vproc_transaction_enabled || new > 1) { | |
167 | return; | |
168 | } | |
169 | ||
170 | if (new < 1) { | |
171 | _vproc_set_crash_log_message("Underflow of transaction count."); | |
172 | abort(); | |
ddbbfbc1 | 173 | } |
95379394 A |
174 | |
175 | (void)os_assumes_zero(proc_set_dirty(getpid(), true)); | |
eabd1701 A |
176 | } |
177 | ||
178 | void | |
179 | _vproc_transaction_begin(void) | |
180 | { | |
95379394 A |
181 | launch_globals_t globals = _launch_globals(); |
182 | ||
183 | dispatch_once_f(&globals->_vproc_transaction_once, NULL, _vproc_transaction_init_once); | |
184 | dispatch_sync_f(globals->_vproc_transaction_queue, NULL, _vproc_transaction_begin_internal); | |
ddbbfbc1 A |
185 | } |
186 | ||
187 | vproc_transaction_t | |
eabd1701 | 188 | vproc_transaction_begin(vproc_t vp __unused) |
ddbbfbc1 | 189 | { |
ddbbfbc1 | 190 | _vproc_transaction_begin(); |
ddbbfbc1 | 191 | |
eabd1701 A |
192 | /* Return non-NULL on success. Originally, there were dreams of returning |
193 | * an object or something, but those never panned out. | |
194 | */ | |
95379394 | 195 | return (vproc_transaction_t)vproc_transaction_begin; |
ddbbfbc1 A |
196 | } |
197 | ||
95379394 A |
198 | void _vproc_transaction_end_flush(void); |
199 | ||
ddbbfbc1 | 200 | void |
95379394 | 201 | _vproc_transaction_end_internal2(void *ctx) |
ddbbfbc1 | 202 | { |
95379394 A |
203 | launch_globals_t globals = _launch_globals(); |
204 | ||
205 | globals->_vproc_gone2zero_callout(ctx); | |
206 | _vproc_transaction_end_flush(); | |
207 | } | |
208 | ||
209 | void | |
210 | _vproc_transaction_end_internal(void *arg) | |
211 | { | |
212 | launch_globals_t globals = _launch_globals(); | |
213 | ||
214 | int64_t new = --globals->_vproc_transaction_cnt; | |
215 | if (!globals->_vproc_transaction_enabled || new > 0) { | |
216 | return; | |
217 | } | |
218 | ||
219 | if (new < 0) { | |
eabd1701 | 220 | _vproc_set_crash_log_message("Underflow of transaction count."); |
95379394 | 221 | abort(); |
ddbbfbc1 | 222 | } |
95379394 A |
223 | |
224 | if (globals->_vproc_gone2zero_callout && !arg) { | |
225 | globals->_vproc_transaction_cnt = 1; | |
226 | dispatch_async_f(globals->_vproc_gone2zero_queue, globals->_vproc_gone2zero_ctx, _vproc_transaction_end_internal2); | |
227 | } else { | |
228 | (void)os_assumes_zero(proc_set_dirty(getpid(), false)); | |
229 | } | |
230 | } | |
231 | ||
232 | void | |
233 | _vproc_transaction_end_flush2(void *ctx __unused) | |
234 | { | |
235 | _vproc_transaction_end_internal((void *)1); | |
236 | } | |
237 | ||
238 | void | |
239 | _vproc_transaction_end_flush(void) | |
240 | { | |
241 | launch_globals_t globals = _launch_globals(); | |
242 | ||
243 | dispatch_sync_f(globals->_vproc_transaction_queue, NULL, _vproc_transaction_end_flush2); | |
eabd1701 | 244 | } |
ddbbfbc1 | 245 | |
eabd1701 A |
246 | void |
247 | _vproc_transaction_end(void) | |
248 | { | |
95379394 A |
249 | launch_globals_t globals = _launch_globals(); |
250 | ||
251 | dispatch_once_f(&globals->_vproc_transaction_once, NULL, _vproc_transaction_init_once); | |
252 | dispatch_sync_f(globals->_vproc_transaction_queue, NULL, _vproc_transaction_end_internal); | |
eabd1701 A |
253 | } |
254 | ||
255 | void | |
256 | vproc_transaction_end(vproc_t vp __unused, vproc_transaction_t vpt __unused) | |
257 | { | |
258 | _vproc_transaction_end(); | |
ddbbfbc1 A |
259 | } |
260 | ||
261 | size_t | |
262 | _vproc_transaction_count(void) | |
263 | { | |
95379394 A |
264 | launch_globals_t globals = _launch_globals(); |
265 | ||
266 | return globals->_vproc_transaction_cnt; | |
ddbbfbc1 A |
267 | } |
268 | ||
269 | size_t | |
270 | _vproc_standby_count(void) | |
271 | { | |
ddbbfbc1 | 272 | return 0; |
eabd1701 | 273 | } |
ddbbfbc1 A |
274 | |
275 | size_t | |
276 | _vproc_standby_timeout(void) | |
277 | { | |
eabd1701 | 278 | return 0; |
ddbbfbc1 A |
279 | } |
280 | ||
281 | bool | |
282 | _vproc_pid_is_managed(pid_t p) | |
283 | { | |
284 | boolean_t result = false; | |
285 | vproc_mig_pid_is_managed(bootstrap_port, p, &result); | |
eabd1701 | 286 | |
ddbbfbc1 A |
287 | return result; |
288 | } | |
289 | ||
290 | kern_return_t | |
291 | _vproc_transaction_count_for_pid(pid_t p, int32_t *count, bool *condemned) | |
292 | { | |
eabd1701 A |
293 | /* Activity Monitor relies on us returning this error code when the process |
294 | * is not opted into Instant Off. | |
295 | */ | |
296 | kern_return_t error = BOOTSTRAP_NO_MEMORY; | |
ddbbfbc1 | 297 | |
eabd1701 A |
298 | if (condemned) { |
299 | *condemned = false; | |
ddbbfbc1 A |
300 | } |
301 | ||
eabd1701 A |
302 | if (count) { |
303 | uint32_t flags; | |
304 | int ret = proc_get_dirty(p, &flags); | |
305 | if (ret == 0) { | |
306 | if (flags & PROC_DIRTY_TRACKED) { | |
307 | *count = (flags & PROC_DIRTY_IS_DIRTY) ? 1 : 0; | |
308 | error = BOOTSTRAP_SUCCESS; | |
309 | } else { | |
310 | error = BOOTSTRAP_NO_MEMORY; | |
311 | } | |
312 | } else if (ret == ENOTSUP) { | |
313 | error = BOOTSTRAP_NO_MEMORY; | |
314 | } else if (ret == ESRCH) { | |
315 | error = BOOTSTRAP_UNKNOWN_SERVICE; | |
316 | } else if (ret == EPERM) { | |
317 | error = BOOTSTRAP_NOT_PRIVILEGED; | |
318 | } else { | |
319 | error = ret; | |
320 | } | |
ddbbfbc1 | 321 | } |
eabd1701 | 322 | return error; |
dcace88f | 323 | } |
ddbbfbc1 | 324 | void |
eabd1701 | 325 | _vproc_transaction_try_exit(int status) |
ddbbfbc1 | 326 | { |
eabd1701 | 327 | #if !TARGET_OS_EMBEDDED |
95379394 A |
328 | launch_globals_t globals = _launch_globals(); |
329 | if (globals->_vproc_transaction_cnt == 0) { | |
eabd1701 | 330 | _exit(status); |
ddbbfbc1 | 331 | } |
ddbbfbc1 | 332 | #else |
eabd1701 | 333 | _exit(status); |
ddbbfbc1 A |
334 | #endif |
335 | } | |
336 | ||
337 | void | |
338 | _vproc_standby_begin(void) | |
339 | { | |
ddbbfbc1 | 340 | |
ddbbfbc1 A |
341 | } |
342 | ||
eabd1701 A |
343 | vproc_standby_t |
344 | vproc_standby_begin(vproc_t vp __unused) | |
ddbbfbc1 | 345 | { |
eabd1701 | 346 | return (vproc_standby_t)vproc_standby_begin; |
ddbbfbc1 A |
347 | } |
348 | ||
349 | void | |
350 | _vproc_standby_end(void) | |
351 | { | |
ddbbfbc1 | 352 | |
ddbbfbc1 | 353 | } |
5b0a4722 | 354 | |
dcace88f | 355 | void |
95379394 | 356 | _vproc_transaction_set_clean_callback(dispatch_queue_t targetq, void *ctx, dispatch_function_t func) |
dcace88f | 357 | { |
95379394 | 358 | launch_globals_t globals = _launch_globals(); |
dcace88f | 359 | |
95379394 A |
360 | globals->_vproc_gone2zero_queue = targetq; |
361 | dispatch_retain(targetq); | |
362 | ||
363 | globals->_vproc_gone2zero_callout = func; | |
364 | globals->_vproc_gone2zero_ctx = ctx; | |
365 | } | |
dcace88f | 366 | |
eabd1701 A |
367 | void |
368 | vproc_standby_end(vproc_t vp __unused, vproc_standby_t vpt __unused) | |
369 | { | |
dcace88f | 370 | |
dcace88f A |
371 | } |
372 | ||
eabd1701 | 373 | #pragma mark Miscellaneous SPI |
5b0a4722 | 374 | kern_return_t |
eabd1701 A |
375 | _vproc_grab_subset(mach_port_t bp, mach_port_t *reqport, mach_port_t *rcvright, |
376 | launch_data_t *outval, mach_port_array_t *ports, | |
377 | mach_msg_type_number_t *portCnt) | |
5b0a4722 A |
378 | { |
379 | mach_msg_type_number_t outdata_cnt; | |
380 | vm_offset_t outdata = 0; | |
381 | size_t data_offset = 0; | |
382 | launch_data_t out_obj; | |
383 | kern_return_t kr; | |
384 | ||
385 | if ((kr = vproc_mig_take_subset(bp, reqport, rcvright, &outdata, &outdata_cnt, ports, portCnt))) { | |
386 | goto out; | |
387 | } | |
388 | ||
389 | if ((out_obj = launch_data_unpack((void *)outdata, outdata_cnt, NULL, 0, &data_offset, NULL))) { | |
390 | *outval = launch_data_copy(out_obj); | |
391 | } else { | |
392 | kr = 1; | |
393 | } | |
394 | ||
395 | out: | |
396 | if (outdata) { | |
397 | mig_deallocate(outdata, outdata_cnt); | |
398 | } | |
399 | ||
400 | return kr; | |
401 | } | |
402 | ||
5b0a4722 | 403 | vproc_err_t |
ddbbfbc1 | 404 | _vprocmgr_move_subset_to_user(uid_t target_user, const char *session_type, uint64_t flags) |
5b0a4722 | 405 | { |
5b0a4722 A |
406 | kern_return_t kr = 0; |
407 | bool is_bkgd = (strcmp(session_type, VPROCMGR_SESSION_BACKGROUND) == 0); | |
408 | int64_t ldpid, lduid; | |
409 | ||
410 | if (vproc_swap_integer(NULL, VPROC_GSK_MGR_PID, 0, &ldpid) != 0) { | |
411 | return (vproc_err_t)_vprocmgr_move_subset_to_user; | |
412 | } | |
413 | ||
414 | if (vproc_swap_integer(NULL, VPROC_GSK_MGR_UID, 0, &lduid) != 0) { | |
415 | return (vproc_err_t)_vprocmgr_move_subset_to_user; | |
416 | } | |
417 | ||
418 | if (!is_bkgd && ldpid != 1) { | |
419 | if (lduid == getuid()) { | |
420 | return NULL; | |
421 | } | |
422 | /* | |
423 | * Not all sessions can be moved. | |
424 | * We should clean up this mess someday. | |
425 | */ | |
426 | return (vproc_err_t)_vprocmgr_move_subset_to_user; | |
427 | } | |
428 | ||
eabd1701 A |
429 | mach_port_t puc = 0; |
430 | mach_port_t rootbs = MACH_PORT_NULL; | |
431 | (void)bootstrap_get_root(bootstrap_port, &rootbs); | |
432 | ||
ddbbfbc1 A |
433 | if (vproc_mig_lookup_per_user_context(rootbs, target_user, &puc) != 0) { |
434 | return (vproc_err_t)_vprocmgr_move_subset_to_user; | |
435 | } | |
eabd1701 | 436 | |
dcace88f | 437 | if (is_bkgd) { |
ddbbfbc1 A |
438 | task_set_bootstrap_port(mach_task_self(), puc); |
439 | mach_port_deallocate(mach_task_self(), bootstrap_port); | |
440 | bootstrap_port = puc; | |
5b0a4722 | 441 | } else { |
ddbbfbc1 A |
442 | kr = vproc_mig_move_subset(puc, bootstrap_port, (char *)session_type, _audit_session_self(), flags); |
443 | mach_port_deallocate(mach_task_self(), puc); | |
5b0a4722 | 444 | } |
5b0a4722 A |
445 | |
446 | if (kr) { | |
447 | return (vproc_err_t)_vprocmgr_move_subset_to_user; | |
448 | } | |
449 | ||
5b0a4722 A |
450 | return _vproc_post_fork_ping(); |
451 | } | |
452 | ||
ddbbfbc1 A |
453 | vproc_err_t |
454 | _vprocmgr_switch_to_session(const char *target_session, vproc_flags_t flags __attribute__((unused))) | |
455 | { | |
456 | mach_port_t new_bsport = MACH_PORT_NULL; | |
457 | kern_return_t kr = KERN_FAILURE; | |
458 | ||
459 | mach_port_t tnp = MACH_PORT_NULL; | |
460 | task_name_for_pid(mach_task_self(), getpid(), &tnp); | |
dcace88f | 461 | if ((kr = vproc_mig_switch_to_session(bootstrap_port, tnp, (char *)target_session, _audit_session_self(), &new_bsport)) != KERN_SUCCESS) { |
ddbbfbc1 A |
462 | _vproc_log(LOG_NOTICE, "_vprocmgr_switch_to_session(): kr = 0x%x", kr); |
463 | return (vproc_err_t)_vprocmgr_switch_to_session; | |
464 | } | |
eabd1701 | 465 | |
ddbbfbc1 A |
466 | task_set_bootstrap_port(mach_task_self(), new_bsport); |
467 | mach_port_deallocate(mach_task_self(), bootstrap_port); | |
468 | bootstrap_port = new_bsport; | |
eabd1701 | 469 | |
ddbbfbc1 A |
470 | return !issetugid() ? _vproc_post_fork_ping() : NULL; |
471 | } | |
472 | ||
473 | vproc_err_t | |
474 | _vprocmgr_detach_from_console(vproc_flags_t flags __attribute__((unused))) | |
475 | { | |
476 | return _vprocmgr_switch_to_session(VPROCMGR_SESSION_BACKGROUND, 0); | |
477 | } | |
5b0a4722 | 478 | |
eabd1701 A |
479 | vproc_err_t |
480 | _vproc_post_fork_ping(void) | |
481 | { | |
95379394 A |
482 | mach_port_t session = MACH_PORT_NULL; |
483 | kern_return_t kr = vproc_mig_post_fork_ping(bootstrap_port, mach_task_self(), &session); | |
484 | if (kr) { | |
485 | return _vproc_post_fork_ping; | |
486 | } | |
eabd1701 | 487 | |
95379394 A |
488 | if (session) { |
489 | (void)_audit_session_join(session); | |
490 | (void)mach_port_deallocate(mach_task_self(), session); | |
491 | } | |
eabd1701 | 492 | |
95379394 | 493 | return NULL; |
eabd1701 A |
494 | } |
495 | ||
496 | vproc_err_t | |
497 | _vprocmgr_init(const char *session_type) | |
498 | { | |
499 | if (vproc_mig_init_session(bootstrap_port, (char *)session_type, _audit_session_self()) == 0) { | |
500 | return NULL; | |
501 | } | |
502 | ||
503 | return (vproc_err_t)_vprocmgr_init; | |
504 | } | |
505 | ||
5b0a4722 A |
506 | pid_t |
507 | _spawn_via_launchd(const char *label, const char *const *argv, const struct spawn_via_launchd_attr *spawn_attrs, int struct_version) | |
508 | { | |
509 | size_t i, good_enough_size = 10*1024*1024; | |
510 | mach_msg_type_number_t indata_cnt = 0; | |
511 | vm_offset_t indata = 0; | |
512 | mach_port_t obsvr_port = MACH_PORT_NULL; | |
513 | launch_data_t tmp, tmp_array, in_obj; | |
514 | const char *const *tmpp; | |
515 | kern_return_t kr = 1; | |
516 | void *buf = NULL; | |
517 | pid_t p = -1; | |
518 | ||
519 | if ((in_obj = launch_data_alloc(LAUNCH_DATA_DICTIONARY)) == NULL) { | |
520 | goto out; | |
521 | } | |
522 | ||
523 | if ((tmp = launch_data_new_string(label)) == NULL) { | |
524 | goto out; | |
525 | } | |
526 | ||
527 | launch_data_dict_insert(in_obj, tmp, LAUNCH_JOBKEY_LABEL); | |
528 | ||
529 | if ((tmp_array = launch_data_alloc(LAUNCH_DATA_ARRAY)) == NULL) { | |
530 | goto out; | |
531 | } | |
532 | ||
533 | for (i = 0; *argv; i++, argv++) { | |
534 | tmp = launch_data_new_string(*argv); | |
535 | if (tmp == NULL) { | |
536 | goto out; | |
537 | } | |
538 | ||
539 | launch_data_array_set_index(tmp_array, tmp, i); | |
540 | } | |
541 | ||
542 | launch_data_dict_insert(in_obj, tmp_array, LAUNCH_JOBKEY_PROGRAMARGUMENTS); | |
543 | ||
544 | if (spawn_attrs) switch (struct_version) { | |
dcace88f | 545 | case 3: |
5b0a4722 | 546 | case 2: |
f36da725 | 547 | #if HAVE_QUARANTINE |
5b0a4722 A |
548 | if (spawn_attrs->spawn_quarantine) { |
549 | char qbuf[QTN_SERIALIZED_DATA_MAX]; | |
550 | size_t qbuf_sz = QTN_SERIALIZED_DATA_MAX; | |
551 | ||
552 | if (qtn_proc_to_data(spawn_attrs->spawn_quarantine, qbuf, &qbuf_sz) == 0) { | |
553 | tmp = launch_data_new_opaque(qbuf, qbuf_sz); | |
554 | launch_data_dict_insert(in_obj, tmp, LAUNCH_JOBKEY_QUARANTINEDATA); | |
555 | } | |
556 | } | |
f36da725 | 557 | #endif |
5b0a4722 A |
558 | |
559 | if (spawn_attrs->spawn_seatbelt_profile) { | |
560 | tmp = launch_data_new_string(spawn_attrs->spawn_seatbelt_profile); | |
561 | launch_data_dict_insert(in_obj, tmp, LAUNCH_JOBKEY_SANDBOXPROFILE); | |
562 | } | |
563 | ||
564 | if (spawn_attrs->spawn_seatbelt_flags) { | |
565 | tmp = launch_data_new_integer(*spawn_attrs->spawn_seatbelt_flags); | |
566 | launch_data_dict_insert(in_obj, tmp, LAUNCH_JOBKEY_SANDBOXFLAGS); | |
567 | } | |
568 | ||
569 | /* fall through */ | |
570 | case 1: | |
571 | if (spawn_attrs->spawn_binpref) { | |
572 | tmp_array = launch_data_alloc(LAUNCH_DATA_ARRAY); | |
573 | for (i = 0; i < spawn_attrs->spawn_binpref_cnt; i++) { | |
574 | tmp = launch_data_new_integer(spawn_attrs->spawn_binpref[i]); | |
575 | launch_data_array_set_index(tmp_array, tmp, i); | |
576 | } | |
577 | launch_data_dict_insert(in_obj, tmp_array, LAUNCH_JOBKEY_BINARYORDERPREFERENCE); | |
578 | } | |
579 | /* fall through */ | |
580 | case 0: | |
581 | if (spawn_attrs->spawn_flags & SPAWN_VIA_LAUNCHD_STOPPED) { | |
582 | tmp = launch_data_new_bool(true); | |
583 | launch_data_dict_insert(in_obj, tmp, LAUNCH_JOBKEY_WAITFORDEBUGGER); | |
584 | } | |
dcace88f A |
585 | if (spawn_attrs->spawn_flags & SPAWN_VIA_LAUNCHD_TALAPP) { |
586 | tmp = launch_data_new_string(LAUNCH_KEY_POSIXSPAWNTYPE_TALAPP); | |
587 | launch_data_dict_insert(in_obj, tmp, LAUNCH_JOBKEY_POSIXSPAWNTYPE); | |
588 | } | |
dcace88f A |
589 | if (spawn_attrs->spawn_flags & SPAWN_VIA_LAUNCHD_DISABLE_ASLR) { |
590 | tmp = launch_data_new_bool(true); | |
591 | launch_data_dict_insert(in_obj, tmp, LAUNCH_JOBKEY_DISABLEASLR); | |
592 | } | |
5b0a4722 A |
593 | |
594 | if (spawn_attrs->spawn_env) { | |
595 | launch_data_t tmp_dict = launch_data_alloc(LAUNCH_DATA_DICTIONARY); | |
596 | ||
597 | for (tmpp = spawn_attrs->spawn_env; *tmpp; tmpp++) { | |
598 | char *eqoff, tmpstr[strlen(*tmpp) + 1]; | |
599 | ||
600 | strcpy(tmpstr, *tmpp); | |
601 | ||
602 | eqoff = strchr(tmpstr, '='); | |
603 | ||
604 | if (!eqoff) { | |
605 | goto out; | |
606 | } | |
eabd1701 | 607 | |
5b0a4722 | 608 | *eqoff = '\0'; |
eabd1701 | 609 | |
5b0a4722 A |
610 | launch_data_dict_insert(tmp_dict, launch_data_new_string(eqoff + 1), tmpstr); |
611 | } | |
612 | ||
613 | launch_data_dict_insert(in_obj, tmp_dict, LAUNCH_JOBKEY_ENVIRONMENTVARIABLES); | |
614 | } | |
615 | ||
616 | if (spawn_attrs->spawn_path) { | |
617 | tmp = launch_data_new_string(spawn_attrs->spawn_path); | |
618 | launch_data_dict_insert(in_obj, tmp, LAUNCH_JOBKEY_PROGRAM); | |
619 | } | |
620 | ||
621 | if (spawn_attrs->spawn_chdir) { | |
622 | tmp = launch_data_new_string(spawn_attrs->spawn_chdir); | |
623 | launch_data_dict_insert(in_obj, tmp, LAUNCH_JOBKEY_WORKINGDIRECTORY); | |
624 | } | |
625 | ||
626 | if (spawn_attrs->spawn_umask) { | |
627 | tmp = launch_data_new_integer(*spawn_attrs->spawn_umask); | |
628 | launch_data_dict_insert(in_obj, tmp, LAUNCH_JOBKEY_UMASK); | |
629 | } | |
630 | ||
631 | break; | |
632 | default: | |
633 | break; | |
634 | } | |
635 | ||
636 | if (!(buf = malloc(good_enough_size))) { | |
637 | goto out; | |
638 | } | |
639 | ||
640 | if ((indata_cnt = launch_data_pack(in_obj, buf, good_enough_size, NULL, NULL)) == 0) { | |
641 | goto out; | |
642 | } | |
643 | ||
644 | indata = (vm_offset_t)buf; | |
645 | ||
dcace88f A |
646 | if (struct_version == 3) { |
647 | kr = vproc_mig_spawn2(bootstrap_port, indata, indata_cnt, _audit_session_self(), &p, &obsvr_port); | |
648 | } else { | |
649 | _vproc_set_crash_log_message("Bogus version passed to _spawn_via_launchd(). For this release, the only valid version is 3."); | |
650 | } | |
5b0a4722 A |
651 | |
652 | if (kr == VPROC_ERR_TRY_PER_USER) { | |
653 | mach_port_t puc; | |
654 | ||
655 | if (vproc_mig_lookup_per_user_context(bootstrap_port, 0, &puc) == 0) { | |
dcace88f A |
656 | if (struct_version == 3) { |
657 | kr = vproc_mig_spawn2(puc, indata, indata_cnt, _audit_session_self(), &p, &obsvr_port); | |
658 | } | |
5b0a4722 A |
659 | mach_port_deallocate(mach_task_self(), puc); |
660 | } | |
661 | } | |
662 | ||
663 | out: | |
664 | if (in_obj) { | |
665 | launch_data_free(in_obj); | |
666 | } | |
667 | ||
668 | if (buf) { | |
669 | free(buf); | |
670 | } | |
671 | ||
672 | switch (kr) { | |
673 | case BOOTSTRAP_SUCCESS: | |
674 | if (spawn_attrs && spawn_attrs->spawn_observer_port) { | |
675 | *spawn_attrs->spawn_observer_port = obsvr_port; | |
676 | } else { | |
dcace88f A |
677 | if (struct_version == 3) { |
678 | mach_port_mod_refs(mach_task_self(), obsvr_port, MACH_PORT_RIGHT_RECEIVE, -1); | |
679 | } else { | |
680 | mach_port_deallocate(mach_task_self(), obsvr_port); | |
681 | } | |
5b0a4722 A |
682 | } |
683 | return p; | |
684 | case BOOTSTRAP_NOT_PRIVILEGED: | |
685 | errno = EPERM; break; | |
686 | case BOOTSTRAP_NO_MEMORY: | |
687 | errno = ENOMEM; break; | |
688 | case BOOTSTRAP_NAME_IN_USE: | |
689 | errno = EEXIST; break; | |
690 | case 1: | |
691 | errno = EIO; break; | |
692 | default: | |
693 | errno = EINVAL; break; | |
694 | } | |
695 | ||
696 | return -1; | |
697 | } | |
698 | ||
699 | kern_return_t | |
dcace88f | 700 | mpm_wait(mach_port_t ajob __attribute__((unused)), int *wstatus) |
5b0a4722 | 701 | { |
dcace88f A |
702 | *wstatus = 0; |
703 | return 0; | |
5b0a4722 A |
704 | } |
705 | ||
706 | kern_return_t | |
dcace88f | 707 | mpm_uncork_fork(mach_port_t ajob __attribute__((unused))) |
5b0a4722 | 708 | { |
dcace88f | 709 | return KERN_FAILURE; |
5b0a4722 A |
710 | } |
711 | ||
712 | kern_return_t | |
713 | _vprocmgr_getsocket(name_t sockpath) | |
714 | { | |
715 | return vproc_mig_getsocket(bootstrap_port, sockpath); | |
716 | } | |
717 | ||
718 | vproc_err_t | |
719 | _vproc_get_last_exit_status(int *wstatus) | |
720 | { | |
721 | int64_t val; | |
722 | ||
723 | if (vproc_swap_integer(NULL, VPROC_GSK_LAST_EXIT_STATUS, 0, &val) == 0) { | |
724 | *wstatus = (int)val; | |
725 | return NULL; | |
726 | } | |
727 | ||
728 | return (vproc_err_t)_vproc_get_last_exit_status; | |
729 | } | |
730 | ||
731 | vproc_err_t | |
732 | _vproc_send_signal_by_label(const char *label, int sig) | |
733 | { | |
734 | if (vproc_mig_send_signal(bootstrap_port, (char *)label, sig) == 0) { | |
735 | return NULL; | |
736 | } | |
737 | ||
738 | return _vproc_send_signal_by_label; | |
739 | } | |
740 | ||
741 | vproc_err_t | |
742 | _vprocmgr_log_forward(mach_port_t mp, void *data, size_t len) | |
743 | { | |
744 | if (vproc_mig_log_forward(mp, (vm_offset_t)data, len) == 0) { | |
745 | return NULL; | |
746 | } | |
747 | ||
748 | return _vprocmgr_log_forward; | |
749 | } | |
750 | ||
751 | vproc_err_t | |
752 | _vprocmgr_log_drain(vproc_t vp __attribute__((unused)), pthread_mutex_t *mutex, _vprocmgr_log_drain_callback_t func) | |
753 | { | |
754 | mach_msg_type_number_t outdata_cnt, tmp_cnt; | |
755 | vm_offset_t outdata = 0; | |
ddbbfbc1 | 756 | struct timeval tv; |
5b0a4722 A |
757 | struct logmsg_s *lm; |
758 | ||
759 | if (!func) { | |
760 | return _vprocmgr_log_drain; | |
761 | } | |
762 | ||
763 | if (vproc_mig_log_drain(bootstrap_port, &outdata, &outdata_cnt) != 0) { | |
764 | return _vprocmgr_log_drain; | |
765 | } | |
766 | ||
767 | tmp_cnt = outdata_cnt; | |
768 | ||
769 | if (mutex) { | |
770 | pthread_mutex_lock(mutex); | |
771 | } | |
772 | ||
773 | for (lm = (struct logmsg_s *)outdata; tmp_cnt > 0; lm = ((void *)lm + lm->obj_sz)) { | |
ddbbfbc1 A |
774 | lm->from_name = (char *)lm + lm->from_name_offset; |
775 | lm->about_name = (char *)lm + lm->about_name_offset; | |
776 | lm->msg = (char *)lm + lm->msg_offset; | |
777 | lm->session_name = (char *)lm + lm->session_name_offset; | |
778 | ||
779 | tv.tv_sec = lm->when / USEC_PER_SEC; | |
780 | tv.tv_usec = lm->when % USEC_PER_SEC; | |
5b0a4722 | 781 | |
ddbbfbc1 | 782 | func(&tv, lm->from_pid, lm->about_pid, lm->sender_uid, lm->sender_gid, lm->pri, |
5b0a4722 A |
783 | lm->from_name, lm->about_name, lm->session_name, lm->msg); |
784 | ||
785 | tmp_cnt -= lm->obj_sz; | |
786 | } | |
787 | ||
788 | if (mutex) { | |
789 | pthread_mutex_unlock(mutex); | |
790 | } | |
791 | ||
792 | if (outdata) { | |
793 | mig_deallocate(outdata, outdata_cnt); | |
794 | } | |
795 | ||
796 | return NULL; | |
797 | } | |
798 | ||
799 | vproc_err_t | |
ddbbfbc1 | 800 | vproc_swap_integer(vproc_t vp, vproc_gsk_t key, int64_t *inval, int64_t *outval) |
5b0a4722 | 801 | { |
ddbbfbc1 | 802 | kern_return_t kr = KERN_FAILURE; |
eabd1701 | 803 | int64_t dummyval = 0; |
ddbbfbc1 A |
804 | mach_port_t mp = vp ? vp->j_port : bootstrap_port; |
805 | if ((kr = vproc_mig_swap_integer(mp, inval ? key : 0, outval ? key : 0, inval ? *inval : 0, outval ? outval : &dummyval)) == 0) { | |
5b0a4722 | 806 | switch (key) { |
dcace88f A |
807 | case VPROC_GSK_PERUSER_SUSPEND: |
808 | if (dummyval) { | |
809 | /* Wait for the per-user launchd to exit before returning. */ | |
810 | int kq = kqueue(); | |
811 | struct kevent kev; | |
812 | EV_SET(&kev, dummyval, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, 0); | |
813 | int r = kevent(kq, &kev, 1, &kev, 1, NULL); | |
814 | (void)close(kq); | |
815 | if (r != 1) { | |
816 | return NULL; | |
817 | } | |
818 | break; | |
ddbbfbc1 | 819 | } |
5b0a4722 A |
820 | default: |
821 | break; | |
822 | } | |
823 | return NULL; | |
824 | } | |
825 | ||
826 | return (vproc_err_t)vproc_swap_integer; | |
827 | } | |
828 | ||
5b0a4722 | 829 | vproc_err_t |
ddbbfbc1 | 830 | vproc_swap_complex(vproc_t vp, vproc_gsk_t key, launch_data_t inval, launch_data_t *outval) |
5b0a4722 A |
831 | { |
832 | size_t data_offset = 0, good_enough_size = 10*1024*1024; | |
833 | mach_msg_type_number_t indata_cnt = 0, outdata_cnt; | |
834 | vm_offset_t indata = 0, outdata = 0; | |
835 | launch_data_t out_obj; | |
836 | void *rval = vproc_swap_complex; | |
837 | void *buf = NULL; | |
838 | ||
839 | if (inval) { | |
840 | if (!(buf = malloc(good_enough_size))) { | |
841 | goto out; | |
842 | } | |
843 | ||
844 | if ((indata_cnt = launch_data_pack(inval, buf, good_enough_size, NULL, NULL)) == 0) { | |
845 | goto out; | |
846 | } | |
847 | ||
848 | indata = (vm_offset_t)buf; | |
849 | } | |
850 | ||
ddbbfbc1 A |
851 | mach_port_t mp = vp ? vp->j_port : bootstrap_port; |
852 | if (vproc_mig_swap_complex(mp, inval ? key : 0, outval ? key : 0, indata, indata_cnt, &outdata, &outdata_cnt) != 0) { | |
5b0a4722 A |
853 | goto out; |
854 | } | |
855 | ||
856 | if (outval) { | |
857 | if (!(out_obj = launch_data_unpack((void *)outdata, outdata_cnt, NULL, 0, &data_offset, NULL))) { | |
858 | goto out; | |
859 | } | |
860 | ||
861 | if (!(*outval = launch_data_copy(out_obj))) { | |
862 | goto out; | |
863 | } | |
864 | } | |
865 | ||
866 | rval = NULL; | |
867 | out: | |
868 | if (buf) { | |
869 | free(buf); | |
870 | } | |
871 | ||
872 | if (outdata) { | |
873 | mig_deallocate(outdata, outdata_cnt); | |
874 | } | |
875 | ||
876 | return rval; | |
877 | } | |
878 | ||
ddbbfbc1 A |
879 | vproc_err_t |
880 | vproc_swap_string(vproc_t vp, vproc_gsk_t key, const char *instr, char **outstr) | |
881 | { | |
882 | launch_data_t instr_data = instr ? launch_data_new_string(instr) : NULL; | |
883 | launch_data_t outstr_data = NULL; | |
eabd1701 | 884 | |
ddbbfbc1 | 885 | vproc_err_t verr = vproc_swap_complex(vp, key, instr_data, &outstr_data); |
dcace88f A |
886 | if (!verr && outstr) { |
887 | if (launch_data_get_type(outstr_data) == LAUNCH_DATA_STRING) { | |
ddbbfbc1 A |
888 | *outstr = strdup(launch_data_get_string(outstr_data)); |
889 | } else { | |
890 | verr = (vproc_err_t)vproc_swap_string; | |
891 | } | |
892 | launch_data_free(outstr_data); | |
893 | } | |
dcace88f | 894 | if (instr_data) { |
ddbbfbc1 A |
895 | launch_data_free(instr_data); |
896 | } | |
eabd1701 | 897 | |
ddbbfbc1 A |
898 | return verr; |
899 | } | |
900 | ||
5b0a4722 A |
901 | void * |
902 | reboot2(uint64_t flags) | |
903 | { | |
eabd1701 A |
904 | mach_port_t rootbs = MACH_PORT_NULL; |
905 | (void)bootstrap_get_root(bootstrap_port, &rootbs); | |
906 | if (vproc_mig_reboot2(rootbs, flags) == 0) { | |
907 | (void)mach_port_deallocate(mach_task_self(), rootbs); | |
5b0a4722 A |
908 | return NULL; |
909 | } | |
910 | ||
911 | return reboot2; | |
912 | } | |
913 | ||
f36da725 | 914 | vproc_err_t |
eabd1701 A |
915 | _vproc_kickstart_by_label(const char *label, pid_t *out_pid, |
916 | mach_port_t *out_port_name __unused, mach_port_t *out_obsrvr_port __unused, | |
917 | vproc_flags_t flags) | |
f36da725 | 918 | { |
dcace88f A |
919 | /* Ignore the two port parameters. This SPI isn't long for this world, and |
920 | * all the current clients just leak them anyway. | |
921 | */ | |
922 | kern_return_t kr = vproc_mig_kickstart(bootstrap_port, (char *)label, out_pid, flags); | |
923 | if (kr == KERN_SUCCESS) { | |
f36da725 A |
924 | return NULL; |
925 | } | |
926 | ||
927 | return (vproc_err_t)_vproc_kickstart_by_label; | |
928 | } | |
929 | ||
5b0a4722 A |
930 | vproc_err_t |
931 | _vproc_set_global_on_demand(bool state) | |
932 | { | |
933 | int64_t val = state ? ~0 : 0; | |
934 | ||
935 | if (vproc_swap_integer(NULL, VPROC_GSK_GLOBAL_ON_DEMAND, &val, NULL) == 0) { | |
936 | return NULL; | |
937 | } | |
938 | ||
939 | return (vproc_err_t)_vproc_set_global_on_demand; | |
940 | } | |
941 | ||
942 | void | |
943 | _vproc_logv(int pri, int err, const char *msg, va_list ap) | |
944 | { | |
945 | char flat_msg[3000]; | |
946 | ||
947 | vsnprintf(flat_msg, sizeof(flat_msg), msg, ap); | |
948 | ||
949 | vproc_mig_log(bootstrap_port, pri, err, flat_msg); | |
950 | } | |
951 | ||
952 | void | |
953 | _vproc_log(int pri, const char *msg, ...) | |
954 | { | |
955 | va_list ap; | |
956 | ||
957 | va_start(ap, msg); | |
958 | _vproc_logv(pri, 0, msg, ap); | |
959 | va_end(ap); | |
960 | } | |
961 | ||
962 | void | |
963 | _vproc_log_error(int pri, const char *msg, ...) | |
964 | { | |
965 | int saved_errno = errno; | |
966 | va_list ap; | |
967 | ||
968 | va_start(ap, msg); | |
969 | _vproc_logv(pri, saved_errno, msg, ap); | |
970 | va_end(ap); | |
971 | } | |
dcace88f | 972 | |
dcace88f A |
973 | /* The type naming convention is as follows: |
974 | * For requests... | |
975 | * union __RequestUnion__<userprefix><subsystem>_subsystem | |
976 | * For replies... | |
977 | * union __ReplyUnion__<userprefix><subsystem>_subsystem | |
978 | */ | |
979 | union maxmsgsz { | |
980 | union __RequestUnion__helper_downcall_launchd_helper_subsystem req; | |
981 | union __ReplyUnion__helper_downcall_launchd_helper_subsystem rep; | |
982 | }; | |
983 | ||
95379394 | 984 | const size_t vprocmgr_helper_maxmsgsz = sizeof(union maxmsgsz); |
dcace88f | 985 | |
dcace88f A |
986 | kern_return_t |
987 | helper_recv_wait(mach_port_t p, int status) | |
988 | { | |
eabd1701 A |
989 | #if __LAUNCH_MACH_PORT_CONTEXT_T_DEFINED__ |
990 | mach_port_context_t ctx = status; | |
991 | #else | |
992 | mach_vm_address_t ctx = status; | |
993 | #endif | |
994 | ||
995 | return (errno = mach_port_set_context(mach_task_self(), p, ctx)); | |
dcace88f A |
996 | } |
997 | ||
998 | int | |
999 | launch_wait(mach_port_t port) | |
1000 | { | |
1001 | int status = -1; | |
1002 | errno = mach_msg_server_once(launchd_helper_server, vprocmgr_helper_maxmsgsz, port, 0); | |
1003 | if (errno == MACH_MSG_SUCCESS) { | |
eabd1701 A |
1004 | #if __LAUNCH_MACH_PORT_CONTEXT_T_DEFINED__ |
1005 | mach_port_context_t ctx = 0; | |
1006 | #else | |
dcace88f | 1007 | mach_vm_address_t ctx = 0; |
eabd1701 | 1008 | #endif |
dcace88f A |
1009 | if ((errno = mach_port_get_context(mach_task_self(), port, &ctx)) == KERN_SUCCESS) { |
1010 | status = ctx; | |
1011 | } | |
1012 | } | |
1013 | ||
1014 | return status; | |
1015 | } | |
eabd1701 A |
1016 | |
1017 | launch_data_t | |
1018 | launch_socket_service_check_in(void) | |
1019 | { | |
1020 | launch_data_t reply = NULL; | |
1021 | ||
1022 | size_t big_enough = 10 * 1024; | |
1023 | void *buff = malloc(big_enough); | |
1024 | if (buff) { | |
1025 | launch_data_t req = launch_data_new_string(LAUNCH_KEY_CHECKIN); | |
1026 | if (req) { | |
1027 | size_t sz = launch_data_pack(req, buff, big_enough, NULL, NULL); | |
1028 | if (sz) { | |
1029 | vm_address_t sreply = 0; | |
1030 | mach_msg_size_t sreplyCnt = 0; | |
1031 | mach_port_array_t fdps = NULL; | |
1032 | mach_msg_size_t fdpsCnt = 0; | |
1033 | kern_return_t kr = vproc_mig_legacy_ipc_request(bootstrap_port, (vm_address_t)buff, sz, NULL, 0, &sreply, &sreplyCnt, &fdps, &fdpsCnt, _audit_session_self()); | |
1034 | if (kr == BOOTSTRAP_SUCCESS) { | |
1035 | int fds[128]; | |
1036 | ||
1037 | size_t i = 0; | |
1038 | size_t nfds = fdpsCnt / sizeof(fdps[0]); | |
1039 | for (i = 0; i < nfds; i++) { | |
1040 | fds[i] = fileport_makefd(fdps[i]); | |
1041 | (void)mach_port_deallocate(mach_task_self(), fdps[i]); | |
1042 | } | |
1043 | ||
1044 | size_t dataoff = 0; | |
1045 | size_t fdoff = 0; | |
1046 | reply = launch_data_unpack((void *)sreply, sreplyCnt, fds, nfds, &dataoff, &fdoff); | |
1047 | reply = launch_data_copy(reply); | |
1048 | ||
1049 | mig_deallocate(sreply, sreplyCnt); | |
1050 | mig_deallocate((vm_address_t)fdps, fdpsCnt); | |
1051 | } | |
1052 | } | |
1053 | ||
1054 | launch_data_free(req); | |
1055 | } | |
1056 | ||
1057 | free(buff); | |
1058 | } | |
1059 | ||
1060 | return reply; | |
1061 | } |