]> git.saurik.com Git - apple/launchd.git/blob - liblaunch/libvproc.c
launchd-842.92.1.tar.gz
[apple/launchd.git] / liblaunch / libvproc.c
1 /*
2 * Copyright (c) 1999-2012 Apple Inc. All rights reserved.
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"
22 #include "vproc.h"
23 #include "vproc_priv.h"
24 #include "vproc_internal.h"
25
26 #include <dispatch/dispatch.h>
27 #include <libproc.h>
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>
37 #include <signal.h>
38 #include <assert.h>
39 #include <libkern/OSAtomic.h>
40 #include <sys/syscall.h>
41 #include <sys/event.h>
42 #include <System/sys/fileport.h>
43 #include <os/assumes.h>
44
45 #if HAVE_QUARANTINE
46 #include <quarantine.h>
47 #endif
48
49 #include "launch.h"
50 #include "launch_priv.h"
51 #include "launch_internal.h"
52 #include "ktrace.h"
53
54 #include "job.h"
55
56 #include "helper.h"
57 #include "helperServer.h"
58
59 #include "reboot2.h"
60
61 #define likely(x) __builtin_expect((bool)(x), true)
62 #define unlikely(x) __builtin_expect((bool)(x), false)
63
64 #define _vproc_set_crash_log_message(x)
65
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);
69
70 #pragma mark vproc Object
71 struct vproc_s {
72 int32_t refcount;
73 mach_port_t j_port;
74 };
75
76 vproc_t
77 vprocmgr_lookup_vproc(const char *label)
78 {
79 struct vproc_s *vp = NULL;
80
81 mach_port_t mp = MACH_PORT_NULL;
82 kern_return_t kr = vproc_mig_port_for_label(bootstrap_port, (char *)label, &mp);
83 if (kr == BOOTSTRAP_SUCCESS) {
84 vp = (struct vproc_s *)calloc(1, sizeof(struct vproc_s));
85 if (vp) {
86 vp->refcount = 1;
87 mach_port_mod_refs(mach_task_self(), mp, MACH_PORT_RIGHT_SEND, 1);
88 vp->j_port = mp;
89 }
90 (void)mach_port_deallocate(mach_task_self(), mp);
91 }
92
93 return vp;
94 }
95
96 vproc_t
97 vproc_retain(vproc_t vp)
98 {
99 int32_t orig = OSAtomicAdd32(1, &vp->refcount) - 1;
100 if (orig <= 0) {
101 _vproc_set_crash_log_message("Under-retain / over-release of vproc_t.");
102 abort();
103 }
104
105 return vp;
106 }
107
108 void
109 vproc_release(vproc_t vp)
110 {
111 int32_t newval = OSAtomicAdd32(-1, &vp->refcount);
112 if (newval < 0) {
113 _vproc_set_crash_log_message("Over-release of vproc_t.");
114 abort();
115 } else if (newval == 0) {
116 mach_port_deallocate(mach_task_self(), vp->j_port);
117 free(vp);
118 }
119 }
120
121 #pragma mark Transactions
122 static void
123 _vproc_transaction_init_once(void *arg __unused)
124 {
125 launch_globals_t globals = _launch_globals();
126
127 int64_t enable_transactions = 0;
128 (void)vproc_swap_integer(NULL, VPROC_GSK_TRANSACTIONS_ENABLED, 0, &enable_transactions);
129 if (enable_transactions != 0) {
130 (void)os_assumes_zero(proc_track_dirty(getpid(), PROC_DIRTY_TRACK));
131 globals->_vproc_transaction_enabled = 1;
132 }
133 globals->_vproc_transaction_queue = dispatch_queue_create("com.apple.idle-exit-queue", NULL);
134 }
135
136 void
137 _vproc_transactions_enable_internal(void *arg __unused)
138 {
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 }
145
146 if (globals->_vproc_transaction_cnt > 0) {
147 (void)os_assumes_zero(proc_set_dirty(getpid(), true));
148 }
149 }
150
151 void
152 _vproc_transactions_enable(void)
153 {
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);
158 }
159
160 void
161 _vproc_transaction_begin_internal(void *ctx __unused)
162 {
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();
173 }
174
175 (void)os_assumes_zero(proc_set_dirty(getpid(), true));
176 }
177
178 void
179 _vproc_transaction_begin(void)
180 {
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);
185 }
186
187 vproc_transaction_t
188 vproc_transaction_begin(vproc_t vp __unused)
189 {
190 _vproc_transaction_begin();
191
192 /* Return non-NULL on success. Originally, there were dreams of returning
193 * an object or something, but those never panned out.
194 */
195 return (vproc_transaction_t)vproc_transaction_begin;
196 }
197
198 void _vproc_transaction_end_flush(void);
199
200 void
201 _vproc_transaction_end_internal2(void *ctx)
202 {
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) {
220 _vproc_set_crash_log_message("Underflow of transaction count.");
221 abort();
222 }
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);
244 }
245
246 void
247 _vproc_transaction_end(void)
248 {
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);
253 }
254
255 void
256 vproc_transaction_end(vproc_t vp __unused, vproc_transaction_t vpt __unused)
257 {
258 _vproc_transaction_end();
259 }
260
261 size_t
262 _vproc_transaction_count(void)
263 {
264 launch_globals_t globals = _launch_globals();
265
266 return globals->_vproc_transaction_cnt;
267 }
268
269 size_t
270 _vproc_standby_count(void)
271 {
272 return 0;
273 }
274
275 size_t
276 _vproc_standby_timeout(void)
277 {
278 return 0;
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);
286
287 return result;
288 }
289
290 kern_return_t
291 _vproc_transaction_count_for_pid(pid_t p, int32_t *count, bool *condemned)
292 {
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;
297
298 if (condemned) {
299 *condemned = false;
300 }
301
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 }
321 }
322 return error;
323 }
324 void
325 _vproc_transaction_try_exit(int status)
326 {
327 #if !TARGET_OS_EMBEDDED
328 launch_globals_t globals = _launch_globals();
329 if (globals->_vproc_transaction_cnt == 0) {
330 _exit(status);
331 }
332 #else
333 _exit(status);
334 #endif
335 }
336
337 void
338 _vproc_standby_begin(void)
339 {
340
341 }
342
343 vproc_standby_t
344 vproc_standby_begin(vproc_t vp __unused)
345 {
346 return (vproc_standby_t)vproc_standby_begin;
347 }
348
349 void
350 _vproc_standby_end(void)
351 {
352
353 }
354
355 void
356 _vproc_transaction_set_clean_callback(dispatch_queue_t targetq, void *ctx, dispatch_function_t func)
357 {
358 launch_globals_t globals = _launch_globals();
359
360 globals->_vproc_gone2zero_queue = targetq;
361 dispatch_retain(targetq);
362
363 globals->_vproc_gone2zero_callout = func;
364 globals->_vproc_gone2zero_ctx = ctx;
365 }
366
367 void
368 vproc_standby_end(vproc_t vp __unused, vproc_standby_t vpt __unused)
369 {
370
371 }
372
373 #pragma mark Miscellaneous SPI
374 kern_return_t
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)
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
403 vproc_err_t
404 _vprocmgr_move_subset_to_user(uid_t target_user, const char *session_type, uint64_t flags)
405 {
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
429 mach_port_t puc = 0;
430 mach_port_t rootbs = MACH_PORT_NULL;
431 (void)bootstrap_get_root(bootstrap_port, &rootbs);
432
433 if (vproc_mig_lookup_per_user_context(rootbs, target_user, &puc) != 0) {
434 return (vproc_err_t)_vprocmgr_move_subset_to_user;
435 }
436
437 if (is_bkgd) {
438 task_set_bootstrap_port(mach_task_self(), puc);
439 mach_port_deallocate(mach_task_self(), bootstrap_port);
440 bootstrap_port = puc;
441 } else {
442 kr = vproc_mig_move_subset(puc, bootstrap_port, (char *)session_type, _audit_session_self(), flags);
443 mach_port_deallocate(mach_task_self(), puc);
444 }
445
446 if (kr) {
447 return (vproc_err_t)_vprocmgr_move_subset_to_user;
448 }
449
450 return _vproc_post_fork_ping();
451 }
452
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);
461 if ((kr = vproc_mig_switch_to_session(bootstrap_port, tnp, (char *)target_session, _audit_session_self(), &new_bsport)) != KERN_SUCCESS) {
462 _vproc_log(LOG_NOTICE, "_vprocmgr_switch_to_session(): kr = 0x%x", kr);
463 return (vproc_err_t)_vprocmgr_switch_to_session;
464 }
465
466 task_set_bootstrap_port(mach_task_self(), new_bsport);
467 mach_port_deallocate(mach_task_self(), bootstrap_port);
468 bootstrap_port = new_bsport;
469
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 }
478
479 vproc_err_t
480 _vproc_post_fork_ping(void)
481 {
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 }
487
488 if (session) {
489 (void)_audit_session_join(session);
490 (void)mach_port_deallocate(mach_task_self(), session);
491 }
492
493 return NULL;
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
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) {
545 case 3:
546 case 2:
547 #if HAVE_QUARANTINE
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 }
557 #endif
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 }
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 }
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 }
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 }
607
608 *eqoff = '\0';
609
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
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 }
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) {
656 if (struct_version == 3) {
657 kr = vproc_mig_spawn2(puc, indata, indata_cnt, _audit_session_self(), &p, &obsvr_port);
658 }
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 {
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 }
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
700 mpm_wait(mach_port_t ajob __attribute__((unused)), int *wstatus)
701 {
702 *wstatus = 0;
703 return 0;
704 }
705
706 kern_return_t
707 mpm_uncork_fork(mach_port_t ajob __attribute__((unused)))
708 {
709 return KERN_FAILURE;
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;
756 struct timeval tv;
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)) {
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;
781
782 func(&tv, lm->from_pid, lm->about_pid, lm->sender_uid, lm->sender_gid, lm->pri,
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
800 vproc_swap_integer(vproc_t vp, vproc_gsk_t key, int64_t *inval, int64_t *outval)
801 {
802 kern_return_t kr = KERN_FAILURE;
803 int64_t dummyval = 0;
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) {
806 switch (key) {
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;
819 }
820 default:
821 break;
822 }
823 return NULL;
824 }
825
826 return (vproc_err_t)vproc_swap_integer;
827 }
828
829 vproc_err_t
830 vproc_swap_complex(vproc_t vp, vproc_gsk_t key, launch_data_t inval, launch_data_t *outval)
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
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) {
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
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;
884
885 vproc_err_t verr = vproc_swap_complex(vp, key, instr_data, &outstr_data);
886 if (!verr && outstr) {
887 if (launch_data_get_type(outstr_data) == LAUNCH_DATA_STRING) {
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 }
894 if (instr_data) {
895 launch_data_free(instr_data);
896 }
897
898 return verr;
899 }
900
901 void *
902 reboot2(uint64_t flags)
903 {
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);
908 return NULL;
909 }
910
911 return reboot2;
912 }
913
914 vproc_err_t
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)
918 {
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) {
924 return NULL;
925 }
926
927 return (vproc_err_t)_vproc_kickstart_by_label;
928 }
929
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 }
972
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
984 const size_t vprocmgr_helper_maxmsgsz = sizeof(union maxmsgsz);
985
986 kern_return_t
987 helper_recv_wait(mach_port_t p, int status)
988 {
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));
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) {
1004 #if __LAUNCH_MACH_PORT_CONTEXT_T_DEFINED__
1005 mach_port_context_t ctx = 0;
1006 #else
1007 mach_vm_address_t ctx = 0;
1008 #endif
1009 if ((errno = mach_port_get_context(mach_task_self(), port, &ctx)) == KERN_SUCCESS) {
1010 status = ctx;
1011 }
1012 }
1013
1014 return status;
1015 }
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 }