this repo has no description
at fixPythonPipStalling 1061 lines 26 kB view raw
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 66void _vproc_transactions_enable_internal(void *arg); 67void _vproc_transaction_begin_internal(void *arg __unused); 68void _vproc_transaction_end_internal(void *arg __unused); 69 70#pragma mark vproc Object 71struct vproc_s { 72 int32_t refcount; 73 mach_port_t j_port; 74}; 75 76vproc_t 77vprocmgr_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 96vproc_t 97vproc_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 108void 109vproc_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 122static 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 136void 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 151void 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 160void 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 178void 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 187vproc_transaction_t 188vproc_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 198void _vproc_transaction_end_flush(void); 199 200void 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 209void 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 232void 233_vproc_transaction_end_flush2(void *ctx __unused) 234{ 235 _vproc_transaction_end_internal((void *)1); 236} 237 238void 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 246void 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 255void 256vproc_transaction_end(vproc_t vp __unused, vproc_transaction_t vpt __unused) 257{ 258 _vproc_transaction_end(); 259} 260 261size_t 262_vproc_transaction_count(void) 263{ 264 launch_globals_t globals = _launch_globals(); 265 266 return globals->_vproc_transaction_cnt; 267} 268 269size_t 270_vproc_standby_count(void) 271{ 272 return 0; 273} 274 275size_t 276_vproc_standby_timeout(void) 277{ 278 return 0; 279} 280 281bool 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 290kern_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} 324void 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 337void 338_vproc_standby_begin(void) 339{ 340 341} 342 343vproc_standby_t 344vproc_standby_begin(vproc_t vp __unused) 345{ 346 return (vproc_standby_t)vproc_standby_begin; 347} 348 349void 350_vproc_standby_end(void) 351{ 352 353} 354 355void 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 367void 368vproc_standby_end(vproc_t vp __unused, vproc_standby_t vpt __unused) 369{ 370 371} 372 373#pragma mark Miscellaneous SPI 374kern_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 395out: 396 if (outdata) { 397 mig_deallocate(outdata, outdata_cnt); 398 } 399 400 return kr; 401} 402 403vproc_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 453vproc_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 473vproc_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 479vproc_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 496vproc_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 506pid_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 663out: 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 699kern_return_t 700mpm_wait(mach_port_t ajob __attribute__((unused)), int *wstatus) 701{ 702 *wstatus = 0; 703 return 0; 704} 705 706kern_return_t 707mpm_uncork_fork(mach_port_t ajob __attribute__((unused))) 708{ 709 return KERN_FAILURE; 710} 711 712kern_return_t 713_vprocmgr_getsocket(name_t sockpath) 714{ 715 return vproc_mig_getsocket(bootstrap_port, sockpath); 716} 717 718vproc_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 731vproc_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 741vproc_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 751vproc_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 799vproc_err_t 800vproc_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 829vproc_err_t 830vproc_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; 867out: 868 if (buf) { 869 free(buf); 870 } 871 872 if (outdata) { 873 mig_deallocate(outdata, outdata_cnt); 874 } 875 876 return rval; 877} 878 879vproc_err_t 880vproc_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 901void * 902reboot2(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 914vproc_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 930vproc_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 942void 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 952void 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 962void 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 */ 979union maxmsgsz { 980 union __RequestUnion__helper_downcall_launchd_helper_subsystem req; 981 union __ReplyUnion__helper_downcall_launchd_helper_subsystem rep; 982}; 983 984const size_t vprocmgr_helper_maxmsgsz = sizeof(union maxmsgsz); 985 986kern_return_t 987helper_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 998int 999launch_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 1017launch_data_t 1018launch_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}