2 * Copyright (c) 1999-2012 Apple 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>
43 #include <os/assumes.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 #pragma mark vproc Object
77 vprocmgr_lookup_vproc(const char *label
)
79 struct vproc_s
*vp
= NULL
;
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
));
87 mach_port_mod_refs(mach_task_self(), mp
, MACH_PORT_RIGHT_SEND
, 1);
90 (void)mach_port_deallocate(mach_task_self(), mp
);
97 vproc_retain(vproc_t vp
)
99 int32_t orig
= OSAtomicAdd32(1, &vp
->refcount
) - 1;
101 _vproc_set_crash_log_message("Under-retain / over-release of vproc_t.");
109 vproc_release(vproc_t vp
)
111 int32_t newval
= OSAtomicAdd32(-1, &vp
->refcount
);
113 _vproc_set_crash_log_message("Over-release of vproc_t.");
115 } else if (newval
== 0) {
116 mach_port_deallocate(mach_task_self(), vp
->j_port
);
121 #pragma mark Transactions
123 _vproc_transaction_init_once(void *arg __unused
)
125 launch_globals_t globals
= _launch_globals();
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;
133 globals
->_vproc_transaction_queue
= dispatch_queue_create("com.apple.idle-exit-queue", NULL
);
137 _vproc_transactions_enable_internal(void *arg __unused
)
139 launch_globals_t globals
= _launch_globals();
141 if (!globals
->_vproc_transaction_enabled
) {
142 (void)os_assumes_zero(proc_track_dirty(getpid(), PROC_DIRTY_TRACK
));
143 globals
->_vproc_transaction_enabled
= 1;
146 if (globals
->_vproc_transaction_cnt
> 0) {
147 (void)os_assumes_zero(proc_set_dirty(getpid(), true));
152 _vproc_transactions_enable(void)
154 launch_globals_t globals
= _launch_globals();
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
);
161 _vproc_transaction_begin_internal(void *ctx __unused
)
163 launch_globals_t globals
= _launch_globals();
165 int64_t new = ++globals
->_vproc_transaction_cnt
;
166 if (!globals
->_vproc_transaction_enabled
|| new > 1) {
171 _vproc_set_crash_log_message("Underflow of transaction count.");
175 (void)os_assumes_zero(proc_set_dirty(getpid(), true));
179 _vproc_transaction_begin(void)
181 launch_globals_t globals
= _launch_globals();
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
);
188 vproc_transaction_begin(vproc_t vp __unused
)
190 _vproc_transaction_begin();
192 /* Return non-NULL on success. Originally, there were dreams of returning
193 * an object or something, but those never panned out.
195 return (vproc_transaction_t
)vproc_transaction_begin
;
198 void _vproc_transaction_end_flush(void);
201 _vproc_transaction_end_internal2(void *ctx
)
203 launch_globals_t globals
= _launch_globals();
205 globals
->_vproc_gone2zero_callout(ctx
);
206 _vproc_transaction_end_flush();
210 _vproc_transaction_end_internal(void *arg
)
212 launch_globals_t globals
= _launch_globals();
214 int64_t new = --globals
->_vproc_transaction_cnt
;
215 if (!globals
->_vproc_transaction_enabled
|| new > 0) {
220 _vproc_set_crash_log_message("Underflow of transaction count.");
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
);
228 (void)os_assumes_zero(proc_set_dirty(getpid(), false));
233 _vproc_transaction_end_flush2(void *ctx __unused
)
235 _vproc_transaction_end_internal((void *)1);
239 _vproc_transaction_end_flush(void)
241 launch_globals_t globals
= _launch_globals();
243 dispatch_sync_f(globals
->_vproc_transaction_queue
, NULL
, _vproc_transaction_end_flush2
);
247 _vproc_transaction_end(void)
249 launch_globals_t globals
= _launch_globals();
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
);
256 vproc_transaction_end(vproc_t vp __unused
, vproc_transaction_t vpt __unused
)
258 _vproc_transaction_end();
262 _vproc_transaction_count(void)
264 launch_globals_t globals
= _launch_globals();
266 return globals
->_vproc_transaction_cnt
;
270 _vproc_standby_count(void)
276 _vproc_standby_timeout(void)
282 _vproc_pid_is_managed(pid_t p
)
284 boolean_t result
= false;
285 vproc_mig_pid_is_managed(bootstrap_port
, p
, &result
);
291 _vproc_transaction_count_for_pid(pid_t p
, int32_t *count
, bool *condemned
)
293 /* Activity Monitor relies on us returning this error code when the process
294 * is not opted into Instant Off.
296 kern_return_t error
= BOOTSTRAP_NO_MEMORY
;
304 int ret
= proc_get_dirty(p
, &flags
);
306 if (flags
& PROC_DIRTY_TRACKED
) {
307 *count
= (flags
& PROC_DIRTY_IS_DIRTY
) ? 1 : 0;
308 error
= BOOTSTRAP_SUCCESS
;
310 error
= BOOTSTRAP_NO_MEMORY
;
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
;
325 _vproc_transaction_try_exit(int status
)
327 #if !TARGET_OS_EMBEDDED
328 launch_globals_t globals
= _launch_globals();
329 if (globals
->_vproc_transaction_cnt
== 0) {
338 _vproc_standby_begin(void)
344 vproc_standby_begin(vproc_t vp __unused
)
346 return (vproc_standby_t
)vproc_standby_begin
;
350 _vproc_standby_end(void)
356 _vproc_transaction_set_clean_callback(dispatch_queue_t targetq
, void *ctx
, dispatch_function_t func
)
358 launch_globals_t globals
= _launch_globals();
360 globals
->_vproc_gone2zero_queue
= targetq
;
361 dispatch_retain(targetq
);
363 globals
->_vproc_gone2zero_callout
= func
;
364 globals
->_vproc_gone2zero_ctx
= ctx
;
368 vproc_standby_end(vproc_t vp __unused
, vproc_standby_t vpt __unused
)
373 #pragma mark Miscellaneous SPI
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
)
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
;
385 if ((kr
= vproc_mig_take_subset(bp
, reqport
, rcvright
, &outdata
, &outdata_cnt
, ports
, portCnt
))) {
389 if ((out_obj
= launch_data_unpack((void *)outdata
, outdata_cnt
, NULL
, 0, &data_offset
, NULL
))) {
390 *outval
= launch_data_copy(out_obj
);
397 mig_deallocate(outdata
, outdata_cnt
);
404 _vprocmgr_move_subset_to_user(uid_t target_user
, const char *session_type
, uint64_t flags
)
406 kern_return_t kr
= 0;
407 bool is_bkgd
= (strcmp(session_type
, VPROCMGR_SESSION_BACKGROUND
) == 0);
408 int64_t ldpid
, lduid
;
410 if (vproc_swap_integer(NULL
, VPROC_GSK_MGR_PID
, 0, &ldpid
) != 0) {
411 return (vproc_err_t
)_vprocmgr_move_subset_to_user
;
414 if (vproc_swap_integer(NULL
, VPROC_GSK_MGR_UID
, 0, &lduid
) != 0) {
415 return (vproc_err_t
)_vprocmgr_move_subset_to_user
;
418 if (!is_bkgd
&& ldpid
!= 1) {
419 if (lduid
== getuid()) {
423 * Not all sessions can be moved.
424 * We should clean up this mess someday.
426 return (vproc_err_t
)_vprocmgr_move_subset_to_user
;
430 mach_port_t rootbs
= MACH_PORT_NULL
;
431 (void)bootstrap_get_root(bootstrap_port
, &rootbs
);
433 if (vproc_mig_lookup_per_user_context(rootbs
, target_user
, &puc
) != 0) {
434 return (vproc_err_t
)_vprocmgr_move_subset_to_user
;
438 task_set_bootstrap_port(mach_task_self(), puc
);
439 mach_port_deallocate(mach_task_self(), bootstrap_port
);
440 bootstrap_port
= puc
;
442 kr
= vproc_mig_move_subset(puc
, bootstrap_port
, (char *)session_type
, _audit_session_self(), flags
);
443 mach_port_deallocate(mach_task_self(), puc
);
447 return (vproc_err_t
)_vprocmgr_move_subset_to_user
;
450 return _vproc_post_fork_ping();
454 _vprocmgr_switch_to_session(const char *target_session
, vproc_flags_t flags
__attribute__((unused
)))
456 mach_port_t new_bsport
= MACH_PORT_NULL
;
457 kern_return_t kr
= KERN_FAILURE
;
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
;
466 task_set_bootstrap_port(mach_task_self(), new_bsport
);
467 mach_port_deallocate(mach_task_self(), bootstrap_port
);
468 bootstrap_port
= new_bsport
;
470 return !issetugid() ? _vproc_post_fork_ping() : NULL
;
474 _vprocmgr_detach_from_console(vproc_flags_t flags
__attribute__((unused
)))
476 return _vprocmgr_switch_to_session(VPROCMGR_SESSION_BACKGROUND
, 0);
480 _vproc_post_fork_ping(void)
482 mach_port_t session
= MACH_PORT_NULL
;
483 kern_return_t kr
= vproc_mig_post_fork_ping(bootstrap_port
, mach_task_self(), &session
);
485 return _vproc_post_fork_ping
;
489 (void)_audit_session_join(session
);
490 (void)mach_port_deallocate(mach_task_self(), session
);
497 _vprocmgr_init(const char *session_type
)
499 if (vproc_mig_init_session(bootstrap_port
, (char *)session_type
, _audit_session_self()) == 0) {
503 return (vproc_err_t
)_vprocmgr_init
;
507 _spawn_via_launchd(const char *label
, const char *const *argv
, const struct spawn_via_launchd_attr
*spawn_attrs
, int struct_version
)
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;
519 if ((in_obj
= launch_data_alloc(LAUNCH_DATA_DICTIONARY
)) == NULL
) {
523 if ((tmp
= launch_data_new_string(label
)) == NULL
) {
527 launch_data_dict_insert(in_obj
, tmp
, LAUNCH_JOBKEY_LABEL
);
529 if ((tmp_array
= launch_data_alloc(LAUNCH_DATA_ARRAY
)) == NULL
) {
533 for (i
= 0; *argv
; i
++, argv
++) {
534 tmp
= launch_data_new_string(*argv
);
539 launch_data_array_set_index(tmp_array
, tmp
, i
);
542 launch_data_dict_insert(in_obj
, tmp_array
, LAUNCH_JOBKEY_PROGRAMARGUMENTS
);
544 if (spawn_attrs
) switch (struct_version
) {
548 if (spawn_attrs
->spawn_quarantine
) {
549 char qbuf
[QTN_SERIALIZED_DATA_MAX
];
550 size_t qbuf_sz
= QTN_SERIALIZED_DATA_MAX
;
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
);
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
);
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
);
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
);
577 launch_data_dict_insert(in_obj
, tmp_array
, LAUNCH_JOBKEY_BINARYORDERPREFERENCE
);
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
);
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
);
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
);
594 if (spawn_attrs
->spawn_env
) {
595 launch_data_t tmp_dict
= launch_data_alloc(LAUNCH_DATA_DICTIONARY
);
597 for (tmpp
= spawn_attrs
->spawn_env
; *tmpp
; tmpp
++) {
598 char *eqoff
, tmpstr
[strlen(*tmpp
) + 1];
600 strcpy(tmpstr
, *tmpp
);
602 eqoff
= strchr(tmpstr
, '=');
610 launch_data_dict_insert(tmp_dict
, launch_data_new_string(eqoff
+ 1), tmpstr
);
613 launch_data_dict_insert(in_obj
, tmp_dict
, LAUNCH_JOBKEY_ENVIRONMENTVARIABLES
);
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
);
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
);
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
);
636 if (!(buf
= malloc(good_enough_size
))) {
640 if ((indata_cnt
= launch_data_pack(in_obj
, buf
, good_enough_size
, NULL
, NULL
)) == 0) {
644 indata
= (vm_offset_t
)buf
;
646 if (struct_version
== 3) {
647 kr
= vproc_mig_spawn2(bootstrap_port
, indata
, indata_cnt
, _audit_session_self(), &p
, &obsvr_port
);
649 _vproc_set_crash_log_message("Bogus version passed to _spawn_via_launchd(). For this release, the only valid version is 3.");
652 if (kr
== VPROC_ERR_TRY_PER_USER
) {
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
);
659 mach_port_deallocate(mach_task_self(), puc
);
665 launch_data_free(in_obj
);
673 case BOOTSTRAP_SUCCESS
:
674 if (spawn_attrs
&& spawn_attrs
->spawn_observer_port
) {
675 *spawn_attrs
->spawn_observer_port
= obsvr_port
;
677 if (struct_version
== 3) {
678 mach_port_mod_refs(mach_task_self(), obsvr_port
, MACH_PORT_RIGHT_RECEIVE
, -1);
680 mach_port_deallocate(mach_task_self(), obsvr_port
);
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;
693 errno
= EINVAL
; break;
700 mpm_wait(mach_port_t ajob
__attribute__((unused
)), int *wstatus
)
707 mpm_uncork_fork(mach_port_t ajob
__attribute__((unused
)))
713 _vprocmgr_getsocket(name_t sockpath
)
715 return vproc_mig_getsocket(bootstrap_port
, sockpath
);
719 _vproc_get_last_exit_status(int *wstatus
)
723 if (vproc_swap_integer(NULL
, VPROC_GSK_LAST_EXIT_STATUS
, 0, &val
) == 0) {
728 return (vproc_err_t
)_vproc_get_last_exit_status
;
732 _vproc_send_signal_by_label(const char *label
, int sig
)
734 if (vproc_mig_send_signal(bootstrap_port
, (char *)label
, sig
) == 0) {
738 return _vproc_send_signal_by_label
;
742 _vprocmgr_log_forward(mach_port_t mp
, void *data
, size_t len
)
744 if (vproc_mig_log_forward(mp
, (vm_offset_t
)data
, len
) == 0) {
748 return _vprocmgr_log_forward
;
752 _vprocmgr_log_drain(vproc_t vp
__attribute__((unused
)), pthread_mutex_t
*mutex
, _vprocmgr_log_drain_callback_t func
)
754 mach_msg_type_number_t outdata_cnt
, tmp_cnt
;
755 vm_offset_t outdata
= 0;
760 return _vprocmgr_log_drain
;
763 if (vproc_mig_log_drain(bootstrap_port
, &outdata
, &outdata_cnt
) != 0) {
764 return _vprocmgr_log_drain
;
767 tmp_cnt
= outdata_cnt
;
770 pthread_mutex_lock(mutex
);
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
;
779 tv
.tv_sec
= lm
->when
/ USEC_PER_SEC
;
780 tv
.tv_usec
= lm
->when
% USEC_PER_SEC
;
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
);
785 tmp_cnt
-= lm
->obj_sz
;
789 pthread_mutex_unlock(mutex
);
793 mig_deallocate(outdata
, outdata_cnt
);
800 vproc_swap_integer(vproc_t vp
, vproc_gsk_t key
, int64_t *inval
, int64_t *outval
)
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) {
807 case VPROC_GSK_PERUSER_SUSPEND
:
809 /* Wait for the per-user launchd to exit before returning. */
812 EV_SET(&kev
, dummyval
, EVFILT_PROC
, EV_ADD
, NOTE_EXIT
, 0, 0);
813 int r
= kevent(kq
, &kev
, 1, &kev
, 1, NULL
);
826 return (vproc_err_t
)vproc_swap_integer
;
830 vproc_swap_complex(vproc_t vp
, vproc_gsk_t key
, launch_data_t inval
, launch_data_t
*outval
)
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
;
840 if (!(buf
= malloc(good_enough_size
))) {
844 if ((indata_cnt
= launch_data_pack(inval
, buf
, good_enough_size
, NULL
, NULL
)) == 0) {
848 indata
= (vm_offset_t
)buf
;
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) {
857 if (!(out_obj
= launch_data_unpack((void *)outdata
, outdata_cnt
, NULL
, 0, &data_offset
, NULL
))) {
861 if (!(*outval
= launch_data_copy(out_obj
))) {
873 mig_deallocate(outdata
, outdata_cnt
);
880 vproc_swap_string(vproc_t vp
, vproc_gsk_t key
, const char *instr
, char **outstr
)
882 launch_data_t instr_data
= instr
? launch_data_new_string(instr
) : NULL
;
883 launch_data_t outstr_data
= NULL
;
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
));
890 verr
= (vproc_err_t
)vproc_swap_string
;
892 launch_data_free(outstr_data
);
895 launch_data_free(instr_data
);
902 reboot2(uint64_t flags
)
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
);
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
,
919 /* Ignore the two port parameters. This SPI isn't long for this world, and
920 * all the current clients just leak them anyway.
922 kern_return_t kr
= vproc_mig_kickstart(bootstrap_port
, (char *)label
, out_pid
, flags
);
923 if (kr
== KERN_SUCCESS
) {
927 return (vproc_err_t
)_vproc_kickstart_by_label
;
931 _vproc_set_global_on_demand(bool state
)
933 int64_t val
= state
? ~0 : 0;
935 if (vproc_swap_integer(NULL
, VPROC_GSK_GLOBAL_ON_DEMAND
, &val
, NULL
) == 0) {
939 return (vproc_err_t
)_vproc_set_global_on_demand
;
943 _vproc_logv(int pri
, int err
, const char *msg
, va_list ap
)
947 vsnprintf(flat_msg
, sizeof(flat_msg
), msg
, ap
);
949 vproc_mig_log(bootstrap_port
, pri
, err
, flat_msg
);
953 _vproc_log(int pri
, const char *msg
, ...)
958 _vproc_logv(pri
, 0, msg
, ap
);
963 _vproc_log_error(int pri
, const char *msg
, ...)
965 int saved_errno
= errno
;
969 _vproc_logv(pri
, saved_errno
, msg
, ap
);
973 /* The type naming convention is as follows:
975 * union __RequestUnion__<userprefix><subsystem>_subsystem
977 * union __ReplyUnion__<userprefix><subsystem>_subsystem
980 union __RequestUnion__helper_downcall_launchd_helper_subsystem req
;
981 union __ReplyUnion__helper_downcall_launchd_helper_subsystem rep
;
984 const size_t vprocmgr_helper_maxmsgsz
= sizeof(union maxmsgsz
);
987 helper_recv_wait(mach_port_t p
, int status
)
989 #if __LAUNCH_MACH_PORT_CONTEXT_T_DEFINED__
990 mach_port_context_t ctx
= status
;
992 mach_vm_address_t ctx
= status
;
995 return (errno
= mach_port_set_context(mach_task_self(), p
, ctx
));
999 launch_wait(mach_port_t port
)
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;
1007 mach_vm_address_t ctx
= 0;
1009 if ((errno
= mach_port_get_context(mach_task_self(), port
, &ctx
)) == KERN_SUCCESS
) {
1018 launch_socket_service_check_in(void)
1020 launch_data_t reply
= NULL
;
1022 size_t big_enough
= 10 * 1024;
1023 void *buff
= malloc(big_enough
);
1025 launch_data_t req
= launch_data_new_string(LAUNCH_KEY_CHECKIN
);
1027 size_t sz
= launch_data_pack(req
, buff
, big_enough
, NULL
, NULL
);
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
) {
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
]);
1046 reply
= launch_data_unpack((void *)sreply
, sreplyCnt
, fds
, nfds
, &dataoff
, &fdoff
);
1047 reply
= launch_data_copy(reply
);
1049 mig_deallocate(sreply
, sreplyCnt
);
1050 mig_deallocate((vm_address_t
)fdps
, fdpsCnt
);
1054 launch_data_free(req
);