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 <mach/mach.h>
27 #include <mach/vm_map.h>
28 #include <sys/param.h>
37 #include <libkern/OSAtomic.h>
38 #include <sys/syscall.h>
41 #include <quarantine.h>
45 #include "launch_priv.h"
46 #include "launch_internal.h"
47 #include "launchd_ktrace.h"
49 #include "protocol_vproc.h"
53 #define likely(x) __builtin_expect((bool)(x), true)
54 #define unlikely(x) __builtin_expect((bool)(x), false)
56 static mach_port_t
get_root_bootstrap_port(void);
58 const char *__crashreporter_info__
; /* this should get merged with other versions of the symbol */
60 static int64_t cached_pid
= -1;
61 static struct vproc_shmem_s
*vproc_shmem
;
62 static pthread_once_t shmem_inited
= PTHREAD_ONCE_INIT
;
63 static uint64_t s_cached_transactions_enabled
= 0;
70 vproc_t
vprocmgr_lookup_vproc(const char *label
)
72 struct vproc_s
*vp
= NULL
;
74 mach_port_t mp
= MACH_PORT_NULL
;
75 kern_return_t kr
= vproc_mig_port_for_label(bootstrap_port
, (char *)label
, &mp
);
76 if( kr
== BOOTSTRAP_SUCCESS
) {
77 vp
= (struct vproc_s
*)calloc(1, sizeof(struct vproc_s
));
80 mach_port_mod_refs(mach_task_self(), mp
, MACH_PORT_RIGHT_SEND
, 1);
83 mach_port_mod_refs(mach_task_self(), mp
, MACH_PORT_RIGHT_SEND
, -1);
89 vproc_t
vproc_retain(vproc_t vp
)
91 int32_t orig
= OSAtomicAdd32(1, &vp
->refcount
) - 1;
93 /* We've gone from 0 to 1, which means that this object was due to be freed. */
94 __crashreporter_info__
= "Under-retain / over-release of vproc_t.";
101 void vproc_release(vproc_t vp
)
103 int32_t newval
= OSAtomicAdd32(-1, &vp
->refcount
);
105 /* We're in negative numbers, which is bad. */
106 __crashreporter_info__
= "Over-release of vproc_t.";
108 } else if( newval
== 0 ) {
109 mach_port_deallocate(mach_task_self(), vp
->j_port
);
115 vproc_shmem_init(void)
117 vm_address_t vm_addr
= 0;
118 mach_port_t shmem_port
;
121 kr
= vproc_mig_setup_shmem(bootstrap_port
, &shmem_port
);
125 /* rdar://problem/6416724
126 * If we fail to set up a shared memory page, just allocate a local chunk
127 * of memory. This way, processes can still introspect their own transaction
128 * counts if they're being run under a debugger. Moral of the story: Debug
129 * from the environment you intend to run in.
131 void *_vm_addr
= calloc(1, sizeof(struct vproc_shmem_s
));
136 vm_addr
= (vm_address_t
)_vm_addr
;
138 kr
= vm_map(mach_task_self(), &vm_addr
, getpagesize(), 0, true, shmem_port
, 0, false,
139 VM_PROT_READ
|VM_PROT_WRITE
, VM_PROT_READ
|VM_PROT_WRITE
, VM_INHERIT_NONE
);
144 kr
= mach_port_deallocate(mach_task_self(), shmem_port
);
149 vproc_shmem
= (struct vproc_shmem_s
*)vm_addr
;
153 vproc_client_init(void)
155 char *val
= getenv(LAUNCHD_DO_APPLE_INTERNAL_LOGGING
);
157 if( strncmp(val
, "true", sizeof("true") - 1) == 0 ) {
158 do_apple_internal_logging
= true;
166 vproc_transaction_begin(vproc_t vp
__attribute__((unused
)))
168 vproc_transaction_t vpt
= (vproc_transaction_t
)vproc_shmem_init
; /* we need a "random" variable that is testable */
169 #if !TARGET_OS_EMBEDDED
170 _vproc_transaction_begin();
177 _vproc_transaction_begin(void)
179 #if !TARGET_OS_EMBEDDED
180 if (unlikely(vproc_shmem
== NULL
)) {
181 int po_r
= pthread_once(&shmem_inited
, vproc_client_init
);
182 if (po_r
!= 0 || vproc_shmem
== NULL
) {
187 typeof(vproc_shmem
->vp_shmem_transaction_cnt
) old
= 0;
189 old
= vproc_shmem
->vp_shmem_transaction_cnt
;
191 if (unlikely(old
< 0)) {
192 if (vproc_shmem
->vp_shmem_flags
& VPROC_SHMEM_EXITING
) {
195 __crashreporter_info__
= "Unbalanced: vproc_transaction_begin()";
199 } while( !__sync_bool_compare_and_swap(&vproc_shmem
->vp_shmem_transaction_cnt
, old
, old
+ 1) );
201 runtime_ktrace(RTKT_VPROC_TRANSACTION_INCREMENT
, old
+ 1, 0, 0);
206 _vproc_transaction_count(void)
208 return likely(vproc_shmem
) ? vproc_shmem
->vp_shmem_transaction_cnt
: INT32_MAX
;
212 _vproc_standby_count(void)
214 #ifdef VPROC_STANDBY_IMPLEMENTED
215 return likely(vproc_shmem
) ? vproc_shmem
->vp_shmem_standby_cnt
: INT32_MAX
;
222 _vproc_standby_timeout(void)
224 return likely(vproc_shmem
) ? vproc_shmem
->vp_shmem_standby_timeout
: 0;
228 _vproc_pid_is_managed(pid_t p
)
230 boolean_t result
= false;
231 vproc_mig_pid_is_managed(bootstrap_port
, p
, &result
);
237 _vproc_transaction_count_for_pid(pid_t p
, int32_t *count
, bool *condemned
)
239 boolean_t _condemned
= false;
240 kern_return_t kr
= vproc_mig_transaction_count_for_pid(bootstrap_port
, p
, count
, &_condemned
);
241 if( kr
== KERN_SUCCESS
&& condemned
) {
242 *condemned
= _condemned
? true : false;
249 #if !TARGET_OS_EMBEDDED
250 _vproc_transaction_try_exit(int status
)
252 if (unlikely(vproc_shmem
== NULL
)) {
256 if (__sync_bool_compare_and_swap(&vproc_shmem
->vp_shmem_transaction_cnt
, 0, -1)) {
257 vproc_shmem
->vp_shmem_flags
|= VPROC_SHMEM_EXITING
;
262 _vproc_transaction_try_exit(int status
__attribute__((unused
)))
269 vproc_transaction_end(vproc_t vp
__attribute__((unused
)), vproc_transaction_t vpt
)
271 if (unlikely(vpt
!= (vproc_transaction_t
)vproc_shmem_init
)) {
272 __crashreporter_info__
= "Bogus transaction handle passed to vproc_transaction_end() ";
276 #if !TARGET_OS_EMBEDDED
277 _vproc_transaction_end();
282 _vproc_transaction_end(void)
284 #if !TARGET_OS_EMBEDDED
285 typeof(vproc_shmem
->vp_shmem_transaction_cnt
) newval
;
287 if (unlikely(vproc_shmem
== NULL
)) {
291 newval
= __sync_sub_and_fetch(&vproc_shmem
->vp_shmem_transaction_cnt
, 1);
293 runtime_ktrace(RTKT_VPROC_TRANSACTION_DECREMENT
, newval
, 0, 0);
294 if (unlikely(newval
< 0)) {
295 if (vproc_shmem
->vp_shmem_flags
& VPROC_SHMEM_EXITING
) {
298 __crashreporter_info__
= "Unbalanced: vproc_transaction_end()";
306 vproc_standby_begin(vproc_t vp
__attribute__((unused
)))
308 #ifdef VPROC_STANDBY_IMPLEMENTED
309 vproc_standby_t vpsb
= (vproc_standby_t
)vproc_shmem_init
; /* we need a "random" variable that is testable */
311 _vproc_standby_begin();
320 _vproc_standby_begin(void)
322 #ifdef VPROC_STANDBY_IMPLEMENTED
323 typeof(vproc_shmem
->vp_shmem_standby_cnt
) newval
;
325 if (unlikely(vproc_shmem
== NULL
)) {
326 int po_r
= pthread_once(&shmem_inited
, vproc_client_init
);
327 if (po_r
!= 0 || vproc_shmem
== NULL
) {
332 newval
= __sync_add_and_fetch(&vproc_shmem
->vp_shmem_standby_cnt
, 1);
334 if (unlikely(newval
< 1)) {
335 __crashreporter_info__
= "Unbalanced: vproc_standby_begin()";
344 vproc_standby_end(vproc_t vp
__attribute__((unused
)), vproc_standby_t vpt
__attribute__((unused
)))
346 #ifdef VPROC_STANDBY_IMPLEMENTED
347 if (unlikely(vpt
!= (vproc_standby_t
)vproc_shmem_init
)) {
348 __crashreporter_info__
= "Bogus standby handle passed to vproc_standby_end() ";
352 _vproc_standby_end();
359 _vproc_standby_end(void)
361 #ifdef VPROC_STANDBY_IMPLEMENTED
362 typeof(vproc_shmem
->vp_shmem_standby_cnt
) newval
;
364 if( unlikely(vproc_shmem
== NULL
) ) {
365 __crashreporter_info__
= "Process called vproc_standby_end() when not enrolled in transaction model.";
369 newval
= __sync_sub_and_fetch(&vproc_shmem
->vp_shmem_standby_cnt
, 1);
371 if (unlikely(newval
< 0)) {
372 __crashreporter_info__
= "Unbalanced: vproc_standby_end()";
381 _vproc_grab_subset(mach_port_t bp
, mach_port_t
*reqport
, mach_port_t
*rcvright
, launch_data_t
*outval
,
382 mach_port_array_t
*ports
, mach_msg_type_number_t
*portCnt
)
384 mach_msg_type_number_t outdata_cnt
;
385 vm_offset_t outdata
= 0;
386 size_t data_offset
= 0;
387 launch_data_t out_obj
;
390 if ((kr
= vproc_mig_take_subset(bp
, reqport
, rcvright
, &outdata
, &outdata_cnt
, ports
, portCnt
))) {
394 if ((out_obj
= launch_data_unpack((void *)outdata
, outdata_cnt
, NULL
, 0, &data_offset
, NULL
))) {
395 *outval
= launch_data_copy(out_obj
);
402 mig_deallocate(outdata
, outdata_cnt
);
409 _vproc_post_fork_ping(void)
411 #if !TARGET_OS_EMBEDDED
412 au_asid_t s
= AU_DEFAUDITSID
;
414 mach_port_t session
= MACH_PORT_NULL
;
415 kern_return_t kr
= vproc_mig_post_fork_ping(bootstrap_port
, mach_task_self(), &session
);
416 if( kr
!= KERN_SUCCESS
) {
417 /* If this happens, our bootstrap port probably got hosed. */
418 _vproc_log(LOG_ERR
, "Post-fork ping failed!");
422 /* If we get back MACH_PORT_NULL, that means we just stick with the session
423 * we inherited across fork(2).
425 if( session
== MACH_PORT_NULL
) {
430 s
= _audit_session_join(session
);
432 _vproc_log_error(LOG_ERR
, "Could not join security session!");
435 _vproc_log(LOG_DEBUG
, "Joined session %d.", s
);
439 return s
!= AU_DEFAUDITSID
? NULL
: _vproc_post_fork_ping
;
441 mach_port_t session
= MACH_PORT_NULL
;
442 return vproc_mig_post_fork_ping(bootstrap_port
, mach_task_self(), &session
) ? _vproc_post_fork_ping
: NULL
;
447 _vprocmgr_init(const char *session_type
)
449 if (vproc_mig_init_session(bootstrap_port
, (char *)session_type
, _audit_session_self()) == 0) {
453 return (vproc_err_t
)_vprocmgr_init
;
457 _vprocmgr_move_subset_to_user(uid_t target_user
, const char *session_type
, uint64_t flags
)
459 kern_return_t kr
= 0;
460 bool is_bkgd
= (strcmp(session_type
, VPROCMGR_SESSION_BACKGROUND
) == 0);
461 int64_t ldpid
, lduid
;
463 if (vproc_swap_integer(NULL
, VPROC_GSK_MGR_PID
, 0, &ldpid
) != 0) {
464 return (vproc_err_t
)_vprocmgr_move_subset_to_user
;
467 if (vproc_swap_integer(NULL
, VPROC_GSK_MGR_UID
, 0, &lduid
) != 0) {
468 return (vproc_err_t
)_vprocmgr_move_subset_to_user
;
471 if (!is_bkgd
&& ldpid
!= 1) {
472 if (lduid
== getuid()) {
476 * Not all sessions can be moved.
477 * We should clean up this mess someday.
479 return (vproc_err_t
)_vprocmgr_move_subset_to_user
;
482 mach_port_t puc
= 0, rootbs
= get_root_bootstrap_port();
484 if (vproc_mig_lookup_per_user_context(rootbs
, target_user
, &puc
) != 0) {
485 return (vproc_err_t
)_vprocmgr_move_subset_to_user
;
489 task_set_bootstrap_port(mach_task_self(), puc
);
490 mach_port_deallocate(mach_task_self(), bootstrap_port
);
491 bootstrap_port
= puc
;
493 kr
= vproc_mig_move_subset(puc
, bootstrap_port
, (char *)session_type
, _audit_session_self(), flags
);
494 mach_port_deallocate(mach_task_self(), puc
);
500 return (vproc_err_t
)_vprocmgr_move_subset_to_user
;
503 return _vproc_post_fork_ping();
507 _vprocmgr_switch_to_session(const char *target_session
, vproc_flags_t flags
__attribute__((unused
)))
509 mach_port_t new_bsport
= MACH_PORT_NULL
;
510 kern_return_t kr
= KERN_FAILURE
;
512 mach_port_t tnp
= MACH_PORT_NULL
;
513 task_name_for_pid(mach_task_self(), getpid(), &tnp
);
514 if( (kr
= vproc_mig_switch_to_session(bootstrap_port
, tnp
, (char *)target_session
, _audit_session_self(), &new_bsport
)) != KERN_SUCCESS
) {
515 _vproc_log(LOG_NOTICE
, "_vprocmgr_switch_to_session(): kr = 0x%x", kr
);
516 return (vproc_err_t
)_vprocmgr_switch_to_session
;
519 task_set_bootstrap_port(mach_task_self(), new_bsport
);
520 mach_port_deallocate(mach_task_self(), bootstrap_port
);
521 bootstrap_port
= new_bsport
;
523 return !issetugid() ? _vproc_post_fork_ping() : NULL
;
527 _vprocmgr_detach_from_console(vproc_flags_t flags
__attribute__((unused
)))
529 return _vprocmgr_switch_to_session(VPROCMGR_SESSION_BACKGROUND
, 0);
533 _spawn_via_launchd(const char *label
, const char *const *argv
, const struct spawn_via_launchd_attr
*spawn_attrs
, int struct_version
)
535 size_t i
, good_enough_size
= 10*1024*1024;
536 mach_msg_type_number_t indata_cnt
= 0;
537 vm_offset_t indata
= 0;
538 mach_port_t obsvr_port
= MACH_PORT_NULL
;
539 launch_data_t tmp
, tmp_array
, in_obj
;
540 const char *const *tmpp
;
541 kern_return_t kr
= 1;
545 if ((in_obj
= launch_data_alloc(LAUNCH_DATA_DICTIONARY
)) == NULL
) {
549 if ((tmp
= launch_data_new_string(label
)) == NULL
) {
553 launch_data_dict_insert(in_obj
, tmp
, LAUNCH_JOBKEY_LABEL
);
555 if ((tmp_array
= launch_data_alloc(LAUNCH_DATA_ARRAY
)) == NULL
) {
559 for (i
= 0; *argv
; i
++, argv
++) {
560 tmp
= launch_data_new_string(*argv
);
565 launch_data_array_set_index(tmp_array
, tmp
, i
);
568 launch_data_dict_insert(in_obj
, tmp_array
, LAUNCH_JOBKEY_PROGRAMARGUMENTS
);
570 if (spawn_attrs
) switch (struct_version
) {
573 if (spawn_attrs
->spawn_quarantine
) {
574 char qbuf
[QTN_SERIALIZED_DATA_MAX
];
575 size_t qbuf_sz
= QTN_SERIALIZED_DATA_MAX
;
577 if (qtn_proc_to_data(spawn_attrs
->spawn_quarantine
, qbuf
, &qbuf_sz
) == 0) {
578 tmp
= launch_data_new_opaque(qbuf
, qbuf_sz
);
579 launch_data_dict_insert(in_obj
, tmp
, LAUNCH_JOBKEY_QUARANTINEDATA
);
584 if (spawn_attrs
->spawn_seatbelt_profile
) {
585 tmp
= launch_data_new_string(spawn_attrs
->spawn_seatbelt_profile
);
586 launch_data_dict_insert(in_obj
, tmp
, LAUNCH_JOBKEY_SANDBOXPROFILE
);
589 if (spawn_attrs
->spawn_seatbelt_flags
) {
590 tmp
= launch_data_new_integer(*spawn_attrs
->spawn_seatbelt_flags
);
591 launch_data_dict_insert(in_obj
, tmp
, LAUNCH_JOBKEY_SANDBOXFLAGS
);
596 if (spawn_attrs
->spawn_binpref
) {
597 tmp_array
= launch_data_alloc(LAUNCH_DATA_ARRAY
);
598 for (i
= 0; i
< spawn_attrs
->spawn_binpref_cnt
; i
++) {
599 tmp
= launch_data_new_integer(spawn_attrs
->spawn_binpref
[i
]);
600 launch_data_array_set_index(tmp_array
, tmp
, i
);
602 launch_data_dict_insert(in_obj
, tmp_array
, LAUNCH_JOBKEY_BINARYORDERPREFERENCE
);
606 if (spawn_attrs
->spawn_flags
& SPAWN_VIA_LAUNCHD_STOPPED
) {
607 tmp
= launch_data_new_bool(true);
608 launch_data_dict_insert(in_obj
, tmp
, LAUNCH_JOBKEY_WAITFORDEBUGGER
);
611 if (spawn_attrs
->spawn_env
) {
612 launch_data_t tmp_dict
= launch_data_alloc(LAUNCH_DATA_DICTIONARY
);
614 for (tmpp
= spawn_attrs
->spawn_env
; *tmpp
; tmpp
++) {
615 char *eqoff
, tmpstr
[strlen(*tmpp
) + 1];
617 strcpy(tmpstr
, *tmpp
);
619 eqoff
= strchr(tmpstr
, '=');
627 launch_data_dict_insert(tmp_dict
, launch_data_new_string(eqoff
+ 1), tmpstr
);
630 launch_data_dict_insert(in_obj
, tmp_dict
, LAUNCH_JOBKEY_ENVIRONMENTVARIABLES
);
633 if (spawn_attrs
->spawn_path
) {
634 tmp
= launch_data_new_string(spawn_attrs
->spawn_path
);
635 launch_data_dict_insert(in_obj
, tmp
, LAUNCH_JOBKEY_PROGRAM
);
638 if (spawn_attrs
->spawn_chdir
) {
639 tmp
= launch_data_new_string(spawn_attrs
->spawn_chdir
);
640 launch_data_dict_insert(in_obj
, tmp
, LAUNCH_JOBKEY_WORKINGDIRECTORY
);
643 if (spawn_attrs
->spawn_umask
) {
644 tmp
= launch_data_new_integer(*spawn_attrs
->spawn_umask
);
645 launch_data_dict_insert(in_obj
, tmp
, LAUNCH_JOBKEY_UMASK
);
653 if (!(buf
= malloc(good_enough_size
))) {
657 if ((indata_cnt
= launch_data_pack(in_obj
, buf
, good_enough_size
, NULL
, NULL
)) == 0) {
661 indata
= (vm_offset_t
)buf
;
663 kr
= vproc_mig_spawn(bootstrap_port
, indata
, indata_cnt
, _audit_session_self(), &p
, &obsvr_port
);
665 if (kr
== VPROC_ERR_TRY_PER_USER
) {
668 if (vproc_mig_lookup_per_user_context(bootstrap_port
, 0, &puc
) == 0) {
669 kr
= vproc_mig_spawn(puc
, indata
, indata_cnt
, _audit_session_self(), &p
, &obsvr_port
);
670 mach_port_deallocate(mach_task_self(), puc
);
676 launch_data_free(in_obj
);
684 case BOOTSTRAP_SUCCESS
:
685 if (spawn_attrs
&& spawn_attrs
->spawn_observer_port
) {
686 *spawn_attrs
->spawn_observer_port
= obsvr_port
;
688 mach_port_deallocate(mach_task_self(), obsvr_port
);
691 case BOOTSTRAP_NOT_PRIVILEGED
:
692 errno
= EPERM
; break;
693 case BOOTSTRAP_NO_MEMORY
:
694 errno
= ENOMEM
; break;
695 case BOOTSTRAP_NAME_IN_USE
:
696 errno
= EEXIST
; break;
700 errno
= EINVAL
; break;
707 mpm_wait(mach_port_t ajob
, int *wstatus
)
709 return vproc_mig_wait(ajob
, wstatus
);
713 mpm_uncork_fork(mach_port_t ajob
)
715 return vproc_mig_uncork_fork(ajob
);
719 _vprocmgr_getsocket(name_t sockpath
)
721 return vproc_mig_getsocket(bootstrap_port
, sockpath
);
725 _vproc_get_last_exit_status(int *wstatus
)
729 if (vproc_swap_integer(NULL
, VPROC_GSK_LAST_EXIT_STATUS
, 0, &val
) == 0) {
734 return (vproc_err_t
)_vproc_get_last_exit_status
;
738 _vproc_send_signal_by_label(const char *label
, int sig
)
740 if (vproc_mig_send_signal(bootstrap_port
, (char *)label
, sig
) == 0) {
744 return _vproc_send_signal_by_label
;
748 _vprocmgr_log_forward(mach_port_t mp
, void *data
, size_t len
)
750 if (vproc_mig_log_forward(mp
, (vm_offset_t
)data
, len
) == 0) {
754 return _vprocmgr_log_forward
;
758 _vprocmgr_log_drain(vproc_t vp
__attribute__((unused
)), pthread_mutex_t
*mutex
, _vprocmgr_log_drain_callback_t func
)
760 mach_msg_type_number_t outdata_cnt
, tmp_cnt
;
761 vm_offset_t outdata
= 0;
766 return _vprocmgr_log_drain
;
769 if (vproc_mig_log_drain(bootstrap_port
, &outdata
, &outdata_cnt
) != 0) {
770 return _vprocmgr_log_drain
;
773 tmp_cnt
= outdata_cnt
;
776 pthread_mutex_lock(mutex
);
779 for (lm
= (struct logmsg_s
*)outdata
; tmp_cnt
> 0; lm
= ((void *)lm
+ lm
->obj_sz
)) {
780 lm
->from_name
= (char *)lm
+ lm
->from_name_offset
;
781 lm
->about_name
= (char *)lm
+ lm
->about_name_offset
;
782 lm
->msg
= (char *)lm
+ lm
->msg_offset
;
783 lm
->session_name
= (char *)lm
+ lm
->session_name_offset
;
785 tv
.tv_sec
= lm
->when
/ USEC_PER_SEC
;
786 tv
.tv_usec
= lm
->when
% USEC_PER_SEC
;
788 func(&tv
, lm
->from_pid
, lm
->about_pid
, lm
->sender_uid
, lm
->sender_gid
, lm
->pri
,
789 lm
->from_name
, lm
->about_name
, lm
->session_name
, lm
->msg
);
791 tmp_cnt
-= lm
->obj_sz
;
795 pthread_mutex_unlock(mutex
);
799 mig_deallocate(outdata
, outdata_cnt
);
806 vproc_swap_integer(vproc_t vp
, vproc_gsk_t key
, int64_t *inval
, int64_t *outval
)
808 static int64_t cached_is_managed
= -1;
809 int64_t dummyval
= 0;
812 case VPROC_GSK_MGR_PID
:
813 if (cached_pid
!= -1 && outval
) {
814 *outval
= cached_pid
;
818 case VPROC_GSK_IS_MANAGED
:
819 if (cached_is_managed
!= -1 && outval
) {
820 *outval
= cached_is_managed
;
824 case VPROC_GSK_TRANSACTIONS_ENABLED
:
825 /* Shared memory region is required for transactions. */
826 if( unlikely(vproc_shmem
== NULL
) ) {
827 int po_r
= pthread_once(&shmem_inited
, vproc_client_init
);
828 if( po_r
!= 0 || vproc_shmem
== NULL
) {
832 return (vproc_err_t
)vproc_swap_integer
;
836 if( s_cached_transactions_enabled
&& outval
) {
837 *outval
= s_cached_transactions_enabled
;
845 kern_return_t kr
= KERN_FAILURE
;
846 mach_port_t mp
= vp
? vp
->j_port
: bootstrap_port
;
847 if ((kr
= vproc_mig_swap_integer(mp
, inval
? key
: 0, outval
? key
: 0, inval
? *inval
: 0, outval
? outval
: &dummyval
)) == 0) {
849 case VPROC_GSK_MGR_PID
:
850 cached_pid
= outval
? *outval
: dummyval
;
852 case VPROC_GSK_IS_MANAGED
:
853 cached_is_managed
= outval
? *outval
: dummyval
;
855 case VPROC_GSK_TRANSACTIONS_ENABLED
:
856 /* Once you're in the transaction model, you're in for good. Like the Mafia. */
857 s_cached_transactions_enabled
= 1;
859 case VPROC_GSK_PERUSER_SUSPEND
: {
860 char peruser_label
[NAME_MAX
];
861 snprintf(peruser_label
, NAME_MAX
- 1, "com.apple.launchd.peruser.%u", (uid_t
)*inval
);
863 vproc_t pu_vp
= vprocmgr_lookup_vproc(peruser_label
);
866 kr
= vproc_mig_wait2(bootstrap_port
, pu_vp
->j_port
, &status
, false);
867 vproc_release(pu_vp
);
877 return (vproc_err_t
)vproc_swap_integer
;
881 get_root_bootstrap_port(void)
883 mach_port_t parent_port
= 0;
884 mach_port_t previous_port
= 0;
888 if (previous_port
!= bootstrap_port
) {
889 mach_port_deallocate(mach_task_self(), previous_port
);
891 previous_port
= parent_port
;
893 previous_port
= bootstrap_port
;
896 if (bootstrap_parent(previous_port
, &parent_port
) != 0) {
897 return MACH_PORT_NULL
;
900 } while (parent_port
!= previous_port
);
906 vproc_swap_complex(vproc_t vp
, vproc_gsk_t key
, launch_data_t inval
, launch_data_t
*outval
)
908 size_t data_offset
= 0, good_enough_size
= 10*1024*1024;
909 mach_msg_type_number_t indata_cnt
= 0, outdata_cnt
;
910 vm_offset_t indata
= 0, outdata
= 0;
911 launch_data_t out_obj
;
912 void *rval
= vproc_swap_complex
;
916 if (!(buf
= malloc(good_enough_size
))) {
920 if ((indata_cnt
= launch_data_pack(inval
, buf
, good_enough_size
, NULL
, NULL
)) == 0) {
924 indata
= (vm_offset_t
)buf
;
927 mach_port_t mp
= vp
? vp
->j_port
: bootstrap_port
;
928 if (vproc_mig_swap_complex(mp
, inval
? key
: 0, outval
? key
: 0, indata
, indata_cnt
, &outdata
, &outdata_cnt
) != 0) {
933 if (!(out_obj
= launch_data_unpack((void *)outdata
, outdata_cnt
, NULL
, 0, &data_offset
, NULL
))) {
937 if (!(*outval
= launch_data_copy(out_obj
))) {
949 mig_deallocate(outdata
, outdata_cnt
);
956 vproc_swap_string(vproc_t vp
, vproc_gsk_t key
, const char *instr
, char **outstr
)
958 launch_data_t instr_data
= instr
? launch_data_new_string(instr
) : NULL
;
959 launch_data_t outstr_data
= NULL
;
961 vproc_err_t verr
= vproc_swap_complex(vp
, key
, instr_data
, &outstr_data
);
962 if( !verr
&& outstr
) {
963 if( launch_data_get_type(outstr_data
) == LAUNCH_DATA_STRING
) {
964 *outstr
= strdup(launch_data_get_string(outstr_data
));
966 verr
= (vproc_err_t
)vproc_swap_string
;
968 launch_data_free(outstr_data
);
971 launch_data_free(instr_data
);
978 reboot2(uint64_t flags
)
980 if (vproc_mig_reboot2(get_root_bootstrap_port(), flags
) == 0) {
988 _vproc_kickstart_by_label(const char *label
, pid_t
*out_pid
, mach_port_t
*out_port_name
, mach_port_t
*out_obsrvr_port
, vproc_flags_t flags
)
990 mach_port_t junk
= MACH_PORT_NULL
;
991 mach_port_t junk2
= MACH_PORT_NULL
;
993 kern_return_t kr
= vproc_mig_kickstart(bootstrap_port
, (char *)label
, out_pid
, out_port_name
?: &junk
, out_obsrvr_port
?: &junk2
, flags
);
994 if( kr
== KERN_SUCCESS
) {
995 if( !out_port_name
) {
996 mach_port_mod_refs(mach_task_self(), junk
, MACH_PORT_RIGHT_SEND
, -1);
999 if( !out_obsrvr_port
) {
1000 mach_port_mod_refs(mach_task_self(), junk2
, MACH_PORT_RIGHT_SEND
, -1);
1006 return (vproc_err_t
)_vproc_kickstart_by_label
;
1010 _vproc_wait_by_label(const char *label
, int *out_wstatus
)
1012 if (vproc_mig_embedded_wait(bootstrap_port
, (char *)label
, out_wstatus
) == 0) {
1016 return (vproc_err_t
)_vproc_wait_by_label
;
1020 _vproc_set_global_on_demand(bool state
)
1022 int64_t val
= state
? ~0 : 0;
1024 if (vproc_swap_integer(NULL
, VPROC_GSK_GLOBAL_ON_DEMAND
, &val
, NULL
) == 0) {
1028 return (vproc_err_t
)_vproc_set_global_on_demand
;
1032 _vproc_logv(int pri
, int err
, const char *msg
, va_list ap
)
1034 char flat_msg
[3000];
1036 vsnprintf(flat_msg
, sizeof(flat_msg
), msg
, ap
);
1038 vproc_mig_log(bootstrap_port
, pri
, err
, flat_msg
);
1042 _vproc_log(int pri
, const char *msg
, ...)
1047 _vproc_logv(pri
, 0, msg
, ap
);
1052 _vproc_log_error(int pri
, const char *msg
, ...)
1054 int saved_errno
= errno
;
1058 _vproc_logv(pri
, saved_errno
, msg
, ap
);