2 * Copyright (c) 1999-2005 Apple Computer, Inc. All rights reserved.
4 * @APPLE_APACHE_LICENSE_HEADER_START@
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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 * @APPLE_APACHE_LICENSE_HEADER_END@
23 #include "vproc_priv.h"
24 #include "vproc_internal.h"
26 #include <dispatch/dispatch.h>
28 #include <mach/mach.h>
29 #include <mach/vm_map.h>
30 #include <sys/param.h>
39 #include <libkern/OSAtomic.h>
40 #include <sys/syscall.h>
41 #include <sys/event.h>
42 #include <System/sys/fileport.h>
46 #include <quarantine.h>
50 #include "launch_priv.h"
51 #include "launch_internal.h"
57 #include "helperServer.h"
61 #define likely(x) __builtin_expect((bool)(x), true)
62 #define unlikely(x) __builtin_expect((bool)(x), false)
64 #define _vproc_set_crash_log_message(x)
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
);
70 static dispatch_once_t _vproc_transaction_once
= 0;
71 static uint64_t _vproc_transaction_enabled
= 0;
72 static dispatch_queue_t _vproc_transaction_queue
= NULL
;
73 static int64_t _vproc_transaction_cnt
= 0;
75 #pragma mark vproc Object
82 vprocmgr_lookup_vproc(const char *label
)
84 struct vproc_s
*vp
= NULL
;
86 mach_port_t mp
= MACH_PORT_NULL
;
87 kern_return_t kr
= vproc_mig_port_for_label(bootstrap_port
, (char *)label
, &mp
);
88 if (kr
== BOOTSTRAP_SUCCESS
) {
89 vp
= (struct vproc_s
*)calloc(1, sizeof(struct vproc_s
));
92 mach_port_mod_refs(mach_task_self(), mp
, MACH_PORT_RIGHT_SEND
, 1);
95 (void)mach_port_deallocate(mach_task_self(), mp
);
102 vproc_retain(vproc_t vp
)
104 int32_t orig
= OSAtomicAdd32(1, &vp
->refcount
) - 1;
106 _vproc_set_crash_log_message("Under-retain / over-release of vproc_t.");
114 vproc_release(vproc_t vp
)
116 int32_t newval
= OSAtomicAdd32(-1, &vp
->refcount
);
118 _vproc_set_crash_log_message("Over-release of vproc_t.");
120 } else if (newval
== 0) {
121 mach_port_deallocate(mach_task_self(), vp
->j_port
);
126 #pragma mark Transactions
128 _vproc_transaction_init_once(void *arg __unused
)
130 int64_t enable_transactions
= 0;
131 (void)vproc_swap_integer(NULL
, VPROC_GSK_TRANSACTIONS_ENABLED
, 0, &enable_transactions
);
132 if (enable_transactions
!= 0) {
133 (void)osx_assumes_zero(proc_track_dirty(getpid(), PROC_DIRTY_TRACK
));
134 _vproc_transaction_enabled
= 1;
136 _vproc_transaction_queue
= dispatch_queue_create("com.apple.idle-exit-queue", NULL
);
140 _vproc_transactions_enable_internal(void *arg __unused
)
142 (void)osx_assumes_zero(proc_track_dirty(getpid(), PROC_DIRTY_TRACK
));
143 _vproc_transaction_enabled
= 1;
145 if (_vproc_transaction_cnt
> 0) {
146 (void)osx_assumes_zero(proc_set_dirty(getpid(), true));
151 _vproc_transactions_enable(void)
153 dispatch_once_f(&_vproc_transaction_once
, NULL
, _vproc_transaction_init_once
);
154 dispatch_sync_f(_vproc_transaction_queue
, NULL
, _vproc_transactions_enable_internal
);
158 _vproc_transaction_begin_internal(void *ctx __unused
)
160 int64_t new = ++_vproc_transaction_cnt
;
161 if (new == 1 && _vproc_transaction_enabled
) {
162 (void)osx_assumes_zero(proc_set_dirty(getpid(), true));
167 _vproc_transaction_begin(void)
169 dispatch_once_f(&_vproc_transaction_once
, NULL
, _vproc_transaction_init_once
);
170 dispatch_sync_f(_vproc_transaction_queue
, NULL
, _vproc_transaction_begin_internal
);
174 vproc_transaction_begin(vproc_t vp __unused
)
176 _vproc_transaction_begin();
178 /* Return non-NULL on success. Originally, there were dreams of returning
179 * an object or something, but those never panned out.
181 return (vproc_transaction_t
)vproc_transaction_begin
;;
185 _vproc_transaction_end_internal(void *arg __unused
)
187 int64_t new = --_vproc_transaction_cnt
;
188 if (new == 0 && _vproc_transaction_enabled
) {
189 (void)osx_assumes_zero(proc_set_dirty(getpid(), false));
190 } else if (new < 0) {
191 _vproc_set_crash_log_message("Underflow of transaction count.");
196 _vproc_transaction_end(void)
198 dispatch_once_f(&_vproc_transaction_once
, NULL
, _vproc_transaction_init_once
);
199 dispatch_sync_f(_vproc_transaction_queue
, NULL
, _vproc_transaction_end_internal
);
203 vproc_transaction_end(vproc_t vp __unused
, vproc_transaction_t vpt __unused
)
205 _vproc_transaction_end();
209 _vproc_transaction_count(void)
211 return _vproc_transaction_cnt
;
215 _vproc_standby_count(void)
221 _vproc_standby_timeout(void)
227 _vproc_pid_is_managed(pid_t p
)
229 boolean_t result
= false;
230 vproc_mig_pid_is_managed(bootstrap_port
, p
, &result
);
236 _vproc_transaction_count_for_pid(pid_t p
, int32_t *count
, bool *condemned
)
238 /* Activity Monitor relies on us returning this error code when the process
239 * is not opted into Instant Off.
241 kern_return_t error
= BOOTSTRAP_NO_MEMORY
;
249 int ret
= proc_get_dirty(p
, &flags
);
251 if (flags
& PROC_DIRTY_TRACKED
) {
252 *count
= (flags
& PROC_DIRTY_IS_DIRTY
) ? 1 : 0;
253 error
= BOOTSTRAP_SUCCESS
;
255 error
= BOOTSTRAP_NO_MEMORY
;
257 } else if (ret
== ENOTSUP
) {
258 error
= BOOTSTRAP_NO_MEMORY
;
259 } else if (ret
== ESRCH
) {
260 error
= BOOTSTRAP_UNKNOWN_SERVICE
;
261 } else if (ret
== EPERM
) {
262 error
= BOOTSTRAP_NOT_PRIVILEGED
;
271 _vproc_transaction_try_exit(int status
)
273 #if !TARGET_OS_EMBEDDED
274 if (_vproc_transaction_cnt
== 0) {
283 _vproc_standby_begin(void)
289 vproc_standby_begin(vproc_t vp __unused
)
291 return (vproc_standby_t
)vproc_standby_begin
;
295 _vproc_standby_end(void)
300 /* TODO: obsoleted - remove post-build submission */
303 _vproc_transaction_ptr(void)
305 static int32_t dummy
= 1;
310 _vproc_transaction_set_callouts(_vproc_transaction_callout gone2zero __unused
, _vproc_transaction_callout gonenonzero __unused
)
317 vproc_standby_end(vproc_t vp __unused
, vproc_standby_t vpt __unused
)
322 #pragma mark Miscellaneous SPI
324 _vproc_grab_subset(mach_port_t bp
, mach_port_t
*reqport
, mach_port_t
*rcvright
,
325 launch_data_t
*outval
, mach_port_array_t
*ports
,
326 mach_msg_type_number_t
*portCnt
)
328 mach_msg_type_number_t outdata_cnt
;
329 vm_offset_t outdata
= 0;
330 size_t data_offset
= 0;
331 launch_data_t out_obj
;
334 if ((kr
= vproc_mig_take_subset(bp
, reqport
, rcvright
, &outdata
, &outdata_cnt
, ports
, portCnt
))) {
338 if ((out_obj
= launch_data_unpack((void *)outdata
, outdata_cnt
, NULL
, 0, &data_offset
, NULL
))) {
339 *outval
= launch_data_copy(out_obj
);
346 mig_deallocate(outdata
, outdata_cnt
);
353 _vprocmgr_move_subset_to_user(uid_t target_user
, const char *session_type
, uint64_t flags
)
355 kern_return_t kr
= 0;
356 bool is_bkgd
= (strcmp(session_type
, VPROCMGR_SESSION_BACKGROUND
) == 0);
357 int64_t ldpid
, lduid
;
359 if (vproc_swap_integer(NULL
, VPROC_GSK_MGR_PID
, 0, &ldpid
) != 0) {
360 return (vproc_err_t
)_vprocmgr_move_subset_to_user
;
363 if (vproc_swap_integer(NULL
, VPROC_GSK_MGR_UID
, 0, &lduid
) != 0) {
364 return (vproc_err_t
)_vprocmgr_move_subset_to_user
;
367 if (!is_bkgd
&& ldpid
!= 1) {
368 if (lduid
== getuid()) {
372 * Not all sessions can be moved.
373 * We should clean up this mess someday.
375 return (vproc_err_t
)_vprocmgr_move_subset_to_user
;
379 mach_port_t rootbs
= MACH_PORT_NULL
;
380 (void)bootstrap_get_root(bootstrap_port
, &rootbs
);
382 if (vproc_mig_lookup_per_user_context(rootbs
, target_user
, &puc
) != 0) {
383 return (vproc_err_t
)_vprocmgr_move_subset_to_user
;
387 task_set_bootstrap_port(mach_task_self(), puc
);
388 mach_port_deallocate(mach_task_self(), bootstrap_port
);
389 bootstrap_port
= puc
;
391 kr
= vproc_mig_move_subset(puc
, bootstrap_port
, (char *)session_type
, _audit_session_self(), flags
);
392 mach_port_deallocate(mach_task_self(), puc
);
396 return (vproc_err_t
)_vprocmgr_move_subset_to_user
;
399 return _vproc_post_fork_ping();
403 _vprocmgr_switch_to_session(const char *target_session
, vproc_flags_t flags
__attribute__((unused
)))
405 mach_port_t new_bsport
= MACH_PORT_NULL
;
406 kern_return_t kr
= KERN_FAILURE
;
408 mach_port_t tnp
= MACH_PORT_NULL
;
409 task_name_for_pid(mach_task_self(), getpid(), &tnp
);
410 if ((kr
= vproc_mig_switch_to_session(bootstrap_port
, tnp
, (char *)target_session
, _audit_session_self(), &new_bsport
)) != KERN_SUCCESS
) {
411 _vproc_log(LOG_NOTICE
, "_vprocmgr_switch_to_session(): kr = 0x%x", kr
);
412 return (vproc_err_t
)_vprocmgr_switch_to_session
;
415 task_set_bootstrap_port(mach_task_self(), new_bsport
);
416 mach_port_deallocate(mach_task_self(), bootstrap_port
);
417 bootstrap_port
= new_bsport
;
419 return !issetugid() ? _vproc_post_fork_ping() : NULL
;
423 _vprocmgr_detach_from_console(vproc_flags_t flags
__attribute__((unused
)))
425 return _vprocmgr_switch_to_session(VPROCMGR_SESSION_BACKGROUND
, 0);
429 _vproc_post_fork_ping(void)
431 #if !TARGET_OS_EMBEDDED
432 au_asid_t s
= AU_DEFAUDITSID
;
434 mach_port_t session
= MACH_PORT_NULL
;
435 kern_return_t kr
= vproc_mig_post_fork_ping(bootstrap_port
, mach_task_self(), &session
);
436 if (kr
!= KERN_SUCCESS
) {
437 /* If this happens, our bootstrap port probably got hosed. */
438 _vproc_log(LOG_ERR
, "Post-fork ping failed!");
442 /* If we get back MACH_PORT_NULL, that means we just stick with the session
443 * we inherited across fork(2).
445 if (session
== MACH_PORT_NULL
) {
450 s
= _audit_session_join(session
);
452 _vproc_log_error(LOG_ERR
, "Could not join security session!");
455 _vproc_log(LOG_DEBUG
, "Joined session %d.", s
);
459 return s
!= AU_DEFAUDITSID
? NULL
: _vproc_post_fork_ping
;
461 mach_port_t session
= MACH_PORT_NULL
;
462 return vproc_mig_post_fork_ping(bootstrap_port
, mach_task_self(), &session
) ? _vproc_post_fork_ping
: NULL
;
467 _vprocmgr_init(const char *session_type
)
469 if (vproc_mig_init_session(bootstrap_port
, (char *)session_type
, _audit_session_self()) == 0) {
473 return (vproc_err_t
)_vprocmgr_init
;
477 _spawn_via_launchd(const char *label
, const char *const *argv
, const struct spawn_via_launchd_attr
*spawn_attrs
, int struct_version
)
479 size_t i
, good_enough_size
= 10*1024*1024;
480 mach_msg_type_number_t indata_cnt
= 0;
481 vm_offset_t indata
= 0;
482 mach_port_t obsvr_port
= MACH_PORT_NULL
;
483 launch_data_t tmp
, tmp_array
, in_obj
;
484 const char *const *tmpp
;
485 kern_return_t kr
= 1;
489 if ((in_obj
= launch_data_alloc(LAUNCH_DATA_DICTIONARY
)) == NULL
) {
493 if ((tmp
= launch_data_new_string(label
)) == NULL
) {
497 launch_data_dict_insert(in_obj
, tmp
, LAUNCH_JOBKEY_LABEL
);
499 if ((tmp_array
= launch_data_alloc(LAUNCH_DATA_ARRAY
)) == NULL
) {
503 for (i
= 0; *argv
; i
++, argv
++) {
504 tmp
= launch_data_new_string(*argv
);
509 launch_data_array_set_index(tmp_array
, tmp
, i
);
512 launch_data_dict_insert(in_obj
, tmp_array
, LAUNCH_JOBKEY_PROGRAMARGUMENTS
);
514 if (spawn_attrs
) switch (struct_version
) {
518 if (spawn_attrs
->spawn_quarantine
) {
519 char qbuf
[QTN_SERIALIZED_DATA_MAX
];
520 size_t qbuf_sz
= QTN_SERIALIZED_DATA_MAX
;
522 if (qtn_proc_to_data(spawn_attrs
->spawn_quarantine
, qbuf
, &qbuf_sz
) == 0) {
523 tmp
= launch_data_new_opaque(qbuf
, qbuf_sz
);
524 launch_data_dict_insert(in_obj
, tmp
, LAUNCH_JOBKEY_QUARANTINEDATA
);
529 if (spawn_attrs
->spawn_seatbelt_profile
) {
530 tmp
= launch_data_new_string(spawn_attrs
->spawn_seatbelt_profile
);
531 launch_data_dict_insert(in_obj
, tmp
, LAUNCH_JOBKEY_SANDBOXPROFILE
);
534 if (spawn_attrs
->spawn_seatbelt_flags
) {
535 tmp
= launch_data_new_integer(*spawn_attrs
->spawn_seatbelt_flags
);
536 launch_data_dict_insert(in_obj
, tmp
, LAUNCH_JOBKEY_SANDBOXFLAGS
);
541 if (spawn_attrs
->spawn_binpref
) {
542 tmp_array
= launch_data_alloc(LAUNCH_DATA_ARRAY
);
543 for (i
= 0; i
< spawn_attrs
->spawn_binpref_cnt
; i
++) {
544 tmp
= launch_data_new_integer(spawn_attrs
->spawn_binpref
[i
]);
545 launch_data_array_set_index(tmp_array
, tmp
, i
);
547 launch_data_dict_insert(in_obj
, tmp_array
, LAUNCH_JOBKEY_BINARYORDERPREFERENCE
);
551 if (spawn_attrs
->spawn_flags
& SPAWN_VIA_LAUNCHD_STOPPED
) {
552 tmp
= launch_data_new_bool(true);
553 launch_data_dict_insert(in_obj
, tmp
, LAUNCH_JOBKEY_WAITFORDEBUGGER
);
555 if (spawn_attrs
->spawn_flags
& SPAWN_VIA_LAUNCHD_TALAPP
) {
556 tmp
= launch_data_new_string(LAUNCH_KEY_POSIXSPAWNTYPE_TALAPP
);
557 launch_data_dict_insert(in_obj
, tmp
, LAUNCH_JOBKEY_POSIXSPAWNTYPE
);
559 if (spawn_attrs
->spawn_flags
& SPAWN_VIA_LAUNCHD_WIDGET
) {
560 tmp
= launch_data_new_string(LAUNCH_KEY_POSIXSPAWNTYPE_WIDGET
);
561 launch_data_dict_insert(in_obj
, tmp
, LAUNCH_JOBKEY_POSIXSPAWNTYPE
);
563 if (spawn_attrs
->spawn_flags
& SPAWN_VIA_LAUNCHD_DISABLE_ASLR
) {
564 tmp
= launch_data_new_bool(true);
565 launch_data_dict_insert(in_obj
, tmp
, LAUNCH_JOBKEY_DISABLEASLR
);
568 if (spawn_attrs
->spawn_env
) {
569 launch_data_t tmp_dict
= launch_data_alloc(LAUNCH_DATA_DICTIONARY
);
571 for (tmpp
= spawn_attrs
->spawn_env
; *tmpp
; tmpp
++) {
572 char *eqoff
, tmpstr
[strlen(*tmpp
) + 1];
574 strcpy(tmpstr
, *tmpp
);
576 eqoff
= strchr(tmpstr
, '=');
584 launch_data_dict_insert(tmp_dict
, launch_data_new_string(eqoff
+ 1), tmpstr
);
587 launch_data_dict_insert(in_obj
, tmp_dict
, LAUNCH_JOBKEY_ENVIRONMENTVARIABLES
);
590 if (spawn_attrs
->spawn_path
) {
591 tmp
= launch_data_new_string(spawn_attrs
->spawn_path
);
592 launch_data_dict_insert(in_obj
, tmp
, LAUNCH_JOBKEY_PROGRAM
);
595 if (spawn_attrs
->spawn_chdir
) {
596 tmp
= launch_data_new_string(spawn_attrs
->spawn_chdir
);
597 launch_data_dict_insert(in_obj
, tmp
, LAUNCH_JOBKEY_WORKINGDIRECTORY
);
600 if (spawn_attrs
->spawn_umask
) {
601 tmp
= launch_data_new_integer(*spawn_attrs
->spawn_umask
);
602 launch_data_dict_insert(in_obj
, tmp
, LAUNCH_JOBKEY_UMASK
);
610 if (!(buf
= malloc(good_enough_size
))) {
614 if ((indata_cnt
= launch_data_pack(in_obj
, buf
, good_enough_size
, NULL
, NULL
)) == 0) {
618 indata
= (vm_offset_t
)buf
;
620 if (struct_version
== 3) {
621 kr
= vproc_mig_spawn2(bootstrap_port
, indata
, indata_cnt
, _audit_session_self(), &p
, &obsvr_port
);
623 _vproc_set_crash_log_message("Bogus version passed to _spawn_via_launchd(). For this release, the only valid version is 3.");
626 if (kr
== VPROC_ERR_TRY_PER_USER
) {
629 if (vproc_mig_lookup_per_user_context(bootstrap_port
, 0, &puc
) == 0) {
630 if (struct_version
== 3) {
631 kr
= vproc_mig_spawn2(puc
, indata
, indata_cnt
, _audit_session_self(), &p
, &obsvr_port
);
633 mach_port_deallocate(mach_task_self(), puc
);
639 launch_data_free(in_obj
);
647 case BOOTSTRAP_SUCCESS
:
648 if (spawn_attrs
&& spawn_attrs
->spawn_observer_port
) {
649 *spawn_attrs
->spawn_observer_port
= obsvr_port
;
651 if (struct_version
== 3) {
652 mach_port_mod_refs(mach_task_self(), obsvr_port
, MACH_PORT_RIGHT_RECEIVE
, -1);
654 mach_port_deallocate(mach_task_self(), obsvr_port
);
658 case BOOTSTRAP_NOT_PRIVILEGED
:
659 errno
= EPERM
; break;
660 case BOOTSTRAP_NO_MEMORY
:
661 errno
= ENOMEM
; break;
662 case BOOTSTRAP_NAME_IN_USE
:
663 errno
= EEXIST
; break;
667 errno
= EINVAL
; break;
674 mpm_wait(mach_port_t ajob
__attribute__((unused
)), int *wstatus
)
681 mpm_uncork_fork(mach_port_t ajob
__attribute__((unused
)))
687 _vprocmgr_getsocket(name_t sockpath
)
689 return vproc_mig_getsocket(bootstrap_port
, sockpath
);
693 _vproc_get_last_exit_status(int *wstatus
)
697 if (vproc_swap_integer(NULL
, VPROC_GSK_LAST_EXIT_STATUS
, 0, &val
) == 0) {
702 return (vproc_err_t
)_vproc_get_last_exit_status
;
706 _vproc_send_signal_by_label(const char *label
, int sig
)
708 if (vproc_mig_send_signal(bootstrap_port
, (char *)label
, sig
) == 0) {
712 return _vproc_send_signal_by_label
;
716 _vprocmgr_log_forward(mach_port_t mp
, void *data
, size_t len
)
718 if (vproc_mig_log_forward(mp
, (vm_offset_t
)data
, len
) == 0) {
722 return _vprocmgr_log_forward
;
726 _vprocmgr_log_drain(vproc_t vp
__attribute__((unused
)), pthread_mutex_t
*mutex
, _vprocmgr_log_drain_callback_t func
)
728 mach_msg_type_number_t outdata_cnt
, tmp_cnt
;
729 vm_offset_t outdata
= 0;
734 return _vprocmgr_log_drain
;
737 if (vproc_mig_log_drain(bootstrap_port
, &outdata
, &outdata_cnt
) != 0) {
738 return _vprocmgr_log_drain
;
741 tmp_cnt
= outdata_cnt
;
744 pthread_mutex_lock(mutex
);
747 for (lm
= (struct logmsg_s
*)outdata
; tmp_cnt
> 0; lm
= ((void *)lm
+ lm
->obj_sz
)) {
748 lm
->from_name
= (char *)lm
+ lm
->from_name_offset
;
749 lm
->about_name
= (char *)lm
+ lm
->about_name_offset
;
750 lm
->msg
= (char *)lm
+ lm
->msg_offset
;
751 lm
->session_name
= (char *)lm
+ lm
->session_name_offset
;
753 tv
.tv_sec
= lm
->when
/ USEC_PER_SEC
;
754 tv
.tv_usec
= lm
->when
% USEC_PER_SEC
;
756 func(&tv
, lm
->from_pid
, lm
->about_pid
, lm
->sender_uid
, lm
->sender_gid
, lm
->pri
,
757 lm
->from_name
, lm
->about_name
, lm
->session_name
, lm
->msg
);
759 tmp_cnt
-= lm
->obj_sz
;
763 pthread_mutex_unlock(mutex
);
767 mig_deallocate(outdata
, outdata_cnt
);
774 vproc_swap_integer(vproc_t vp
, vproc_gsk_t key
, int64_t *inval
, int64_t *outval
)
776 kern_return_t kr
= KERN_FAILURE
;
777 int64_t dummyval
= 0;
778 mach_port_t mp
= vp
? vp
->j_port
: bootstrap_port
;
779 if ((kr
= vproc_mig_swap_integer(mp
, inval
? key
: 0, outval
? key
: 0, inval
? *inval
: 0, outval
? outval
: &dummyval
)) == 0) {
781 case VPROC_GSK_PERUSER_SUSPEND
:
783 /* Wait for the per-user launchd to exit before returning. */
786 EV_SET(&kev
, dummyval
, EVFILT_PROC
, EV_ADD
, NOTE_EXIT
, 0, 0);
787 int r
= kevent(kq
, &kev
, 1, &kev
, 1, NULL
);
800 return (vproc_err_t
)vproc_swap_integer
;
804 vproc_swap_complex(vproc_t vp
, vproc_gsk_t key
, launch_data_t inval
, launch_data_t
*outval
)
806 size_t data_offset
= 0, good_enough_size
= 10*1024*1024;
807 mach_msg_type_number_t indata_cnt
= 0, outdata_cnt
;
808 vm_offset_t indata
= 0, outdata
= 0;
809 launch_data_t out_obj
;
810 void *rval
= vproc_swap_complex
;
814 if (!(buf
= malloc(good_enough_size
))) {
818 if ((indata_cnt
= launch_data_pack(inval
, buf
, good_enough_size
, NULL
, NULL
)) == 0) {
822 indata
= (vm_offset_t
)buf
;
825 mach_port_t mp
= vp
? vp
->j_port
: bootstrap_port
;
826 if (vproc_mig_swap_complex(mp
, inval
? key
: 0, outval
? key
: 0, indata
, indata_cnt
, &outdata
, &outdata_cnt
) != 0) {
831 if (!(out_obj
= launch_data_unpack((void *)outdata
, outdata_cnt
, NULL
, 0, &data_offset
, NULL
))) {
835 if (!(*outval
= launch_data_copy(out_obj
))) {
847 mig_deallocate(outdata
, outdata_cnt
);
854 vproc_swap_string(vproc_t vp
, vproc_gsk_t key
, const char *instr
, char **outstr
)
856 launch_data_t instr_data
= instr
? launch_data_new_string(instr
) : NULL
;
857 launch_data_t outstr_data
= NULL
;
859 vproc_err_t verr
= vproc_swap_complex(vp
, key
, instr_data
, &outstr_data
);
860 if (!verr
&& outstr
) {
861 if (launch_data_get_type(outstr_data
) == LAUNCH_DATA_STRING
) {
862 *outstr
= strdup(launch_data_get_string(outstr_data
));
864 verr
= (vproc_err_t
)vproc_swap_string
;
866 launch_data_free(outstr_data
);
869 launch_data_free(instr_data
);
876 reboot2(uint64_t flags
)
878 mach_port_t rootbs
= MACH_PORT_NULL
;
879 (void)bootstrap_get_root(bootstrap_port
, &rootbs
);
880 if (vproc_mig_reboot2(rootbs
, flags
) == 0) {
881 (void)mach_port_deallocate(mach_task_self(), rootbs
);
889 _vproc_kickstart_by_label(const char *label
, pid_t
*out_pid
,
890 mach_port_t
*out_port_name __unused
, mach_port_t
*out_obsrvr_port __unused
,
893 /* Ignore the two port parameters. This SPI isn't long for this world, and
894 * all the current clients just leak them anyway.
896 kern_return_t kr
= vproc_mig_kickstart(bootstrap_port
, (char *)label
, out_pid
, flags
);
897 if (kr
== KERN_SUCCESS
) {
901 return (vproc_err_t
)_vproc_kickstart_by_label
;
905 _vproc_set_global_on_demand(bool state
)
907 int64_t val
= state
? ~0 : 0;
909 if (vproc_swap_integer(NULL
, VPROC_GSK_GLOBAL_ON_DEMAND
, &val
, NULL
) == 0) {
913 return (vproc_err_t
)_vproc_set_global_on_demand
;
917 _vproc_logv(int pri
, int err
, const char *msg
, va_list ap
)
921 vsnprintf(flat_msg
, sizeof(flat_msg
), msg
, ap
);
923 vproc_mig_log(bootstrap_port
, pri
, err
, flat_msg
);
927 _vproc_log(int pri
, const char *msg
, ...)
932 _vproc_logv(pri
, 0, msg
, ap
);
937 _vproc_log_error(int pri
, const char *msg
, ...)
939 int saved_errno
= errno
;
943 _vproc_logv(pri
, saved_errno
, msg
, ap
);
947 /* The type naming convention is as follows:
949 * union __RequestUnion__<userprefix><subsystem>_subsystem
951 * union __ReplyUnion__<userprefix><subsystem>_subsystem
954 union __RequestUnion__helper_downcall_launchd_helper_subsystem req
;
955 union __ReplyUnion__helper_downcall_launchd_helper_subsystem rep
;
958 size_t vprocmgr_helper_maxmsgsz
= sizeof(union maxmsgsz
);
961 helper_recv_wait(mach_port_t p
, int status
)
963 #if __LAUNCH_MACH_PORT_CONTEXT_T_DEFINED__
964 mach_port_context_t ctx
= status
;
966 mach_vm_address_t ctx
= status
;
969 return (errno
= mach_port_set_context(mach_task_self(), p
, ctx
));
973 launch_wait(mach_port_t port
)
976 errno
= mach_msg_server_once(launchd_helper_server
, vprocmgr_helper_maxmsgsz
, port
, 0);
977 if (errno
== MACH_MSG_SUCCESS
) {
978 #if __LAUNCH_MACH_PORT_CONTEXT_T_DEFINED__
979 mach_port_context_t ctx
= 0;
981 mach_vm_address_t ctx
= 0;
983 if ((errno
= mach_port_get_context(mach_task_self(), port
, &ctx
)) == KERN_SUCCESS
) {
992 launch_socket_service_check_in(void)
994 launch_data_t reply
= NULL
;
996 size_t big_enough
= 10 * 1024;
997 void *buff
= malloc(big_enough
);
999 launch_data_t req
= launch_data_new_string(LAUNCH_KEY_CHECKIN
);
1001 size_t sz
= launch_data_pack(req
, buff
, big_enough
, NULL
, NULL
);
1003 vm_address_t sreply
= 0;
1004 mach_msg_size_t sreplyCnt
= 0;
1005 mach_port_array_t fdps
= NULL
;
1006 mach_msg_size_t fdpsCnt
= 0;
1007 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());
1008 if (kr
== BOOTSTRAP_SUCCESS
) {
1012 size_t nfds
= fdpsCnt
/ sizeof(fdps
[0]);
1013 for (i
= 0; i
< nfds
; i
++) {
1014 fds
[i
] = fileport_makefd(fdps
[i
]);
1015 (void)mach_port_deallocate(mach_task_self(), fdps
[i
]);
1020 reply
= launch_data_unpack((void *)sreply
, sreplyCnt
, fds
, nfds
, &dataoff
, &fdoff
);
1021 reply
= launch_data_copy(reply
);
1023 mig_deallocate(sreply
, sreplyCnt
);
1024 mig_deallocate((vm_address_t
)fdps
, fdpsCnt
);
1028 launch_data_free(req
);