1 /*
2 * Copyright (c) 1999-2008 Apple Computer, 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 "runtime.h"
23
24 #include <mach/mach.h>
25 #include <mach/mach_error.h>
26 #include <mach/boolean.h>
27 #include <mach/message.h>
28 #include <mach/notify.h>
29 #include <mach/mig_errors.h>
30 #include <mach/mach_traps.h>
31 #include <mach/mach_interface.h>
32 #include <mach/host_info.h>
33 #include <mach/mach_host.h>
34 #include <mach/mach_time.h>
35 #include <mach/exception.h>
36 #include <sys/types.h>
37 #include <sys/event.h>
38 #include <sys/stat.h>
39 #include <sys/sysctl.h>
40 #include <sys/time.h>
41 #include <sys/proc.h>
42 #include <sys/proc_info.h>
43 #include <libproc.h>
44 #include <sys/event.h>
45 #include <sys/queue.h>
46 #include <sys/socket.h>
47 #include <sys/mount.h>
48 #include <sys/reboot.h>
49 #include <sys/fcntl.h>
50 #include <sys/kdebug.h>
51 #include <sys/wait.h>
52 #include <bsm/libbsm.h>
53 #include <unistd.h>
54 #include <pthread.h>
55 #include <errno.h>
56 #include <string.h>
57 #include <ctype.h>
58 #include <stdio.h>
59 #include <stdlib.h>
60 #include <stdbool.h>
61 #include <syslog.h>
62 #include <signal.h>
63 #include <dlfcn.h>
64 #include <os/assumes.h>
65
66 #include <bsm/libbsm.h>
67
68
69 #include "internalServer.h"
70 #include "internal.h"
71 #include "notifyServer.h"
72 #include "mach_excServer.h"
73
74 /* We shouldn't be including these */
75 #include "launch.h"
76 #include "launchd.h"
77 #include "core.h"
78 #include "vproc.h"
79 #include "vproc_priv.h"
80 #include "vproc_internal.h"
81 #include "jobServer.h"
82 #include "job_reply.h"
83 #include <xpc/launchd.h>
84 #include "shim.h"
85 static mach_port_t ipc_port_set;
86 static mach_port_t demand_port_set;
87 static mach_port_t launchd_internal_port;
88 static int mainkq;
89
90 #define BULK_KEV_MAX 100
91 static struct kevent *bulk_kev;
92 static int bulk_kev_i;
93 static int bulk_kev_cnt;
94
95 static pthread_t kqueue_demand_thread;
96 static pthread_t waitpid_thread;
97
98 static void mportset_callback(void);
99 static kq_callback kqmportset_callback = (kq_callback)mportset_callback;
100 static void *kqueue_demand_loop(void *arg);
101 static void *waitpid_loop(void *arg);
102
103 boolean_t launchd_internal_demux(mach_msg_header_t *Request, mach_msg_header_t *Reply);
104 static void launchd_runtime2(mach_msg_size_t msg_size);
105 static mach_msg_size_t max_msg_size;
106 static mig_callback *mig_cb_table;
107 static size_t mig_cb_table_sz;
108 static timeout_callback runtime_idle_callback;
109 static mach_msg_timeout_t runtime_idle_timeout;
110 static struct ldcred ldc;
111 static audit_token_t ldc_token;
112 static size_t runtime_standby_cnt;
113
114 static void do_file_init(void) __attribute__((constructor));
115 static mach_timebase_info_data_t tbi;
116 static uint64_t tbi_safe_math_max;
117 static uint64_t time_of_mach_msg_return;
118 static double tbi_float_val;
119
120
121 #define VERBOSE_DEBUGGING 0
122
123 #if VERBOSE_DEBUGGING
124 #define _launchd_syslog syslog
125 #else
126 #define _launchd_syslog launchd_syslog
127 #endif
128
129
130 static const int init_compat_signals[] = {
131 SIGUSR1, // halt
132 SIGUSR2, // halt & power off
133 SIGTERM, // Go to single user mode
134 SIGINT, // Reboot
135 SIGTSTP, // Stop further logins
136 };
137
138 static const int sigigns[] = { SIGHUP, SIGPIPE, SIGALRM,
139 SIGURG, SIGTSTP, SIGCONT, SIGTTIN, SIGTTOU, SIGIO, SIGXCPU,
140 SIGXFSZ, SIGVTALRM, SIGPROF, SIGWINCH, SIGINFO,
141 };
142 static sigset_t sigign_set;
143 bool pid1_magic;
144 bool launchd_apple_internal;
145 bool launchd_flat_mach_namespace = true;
146 bool launchd_malloc_log_stacks = false;
147 bool launchd_use_gmalloc = false;
148 #if !TARGET_OS_EMBEDDED
149 bool launchd_log_shutdown = true;
150 #else
151 bool launchd_log_shutdown = false;
152 #endif
153 bool launchd_log_perf = false;
154 bool launchd_log_debug = false;
155 bool launchd_trap_sigkill_bugs = false;
156 bool launchd_no_jetsam_perm_check = false;
157 bool launchd_osinstaller = false;
158 bool launchd_allow_global_dyld_envvars = false;
159 #if TARGET_OS_EMBEDDED
160 bool launchd_appletv = false;
161 #endif
162 pid_t launchd_wsp = 0;
163 size_t runtime_busy_cnt;
164
165 #if TARGET_OS_EMBEDDED
166 #define LAUNCHD_CONFIG_PREFIX "/"
167 #else
168 #define LAUNCHD_CONFIG_PREFIX "/private/var/db/"
169 #endif
170
171 #define config_check(s, sb) (stat(LAUNCHD_CONFIG_PREFIX s, &sb) == 0)
172
173 #ifdef notyet
174 /* defined in libbsm */
175 int audit_set_terminal_host(uint32_t *m);
176
177 int
audit_set_terminal_host(uint32_t * m)178 audit_set_terminal_host(uint32_t *m)
179 {
180
181 #ifdef KERN_HOSTID
182 int name[2] = { CTL_KERN, KERN_HOSTID };
183 size_t len;
184
185 if (m == NULL)
186 return (kAUBadParamErr);
187 *m = 0;
188 len = sizeof(*m);
189 if (sysctl(name, 2, m, &len, NULL, 0) != 0) {
190 syslog(LOG_ERR, "sysctl() failed (%s)", strerror(errno));
191 return (kAUSysctlErr);
192 }
193 return (kAUNoErr);
194 #else
195 *m = -1;
196 return (kAUNoErr);
197 #endif
198 }
199 #endif
200
201 mach_port_t
runtime_get_kernel_port(void)202 runtime_get_kernel_port(void)
203 {
204 return launchd_internal_port;
205 }
206
207 union vproc_mig_max_sz {
208 union __RequestUnion__job_mig_job_subsystem req;
209 union __ReplyUnion__job_mig_job_subsystem rep;
210 };
211
212 union internal_max_sz {
213 union __RequestUnion__x_internal_subsystem req;
214 union __ReplyUnion__internal_subsystem rep;
215 };
216
217 union xpc_domain_max_sz {
218 #ifdef notyet
219 union __RequestUnion__xpc_domain_xpc_domain_subsystem req;
220 union __ReplyUnion__xpc_domain_xpc_domain_subsystem rep;
221 #endif
222 };
223
224 union mach_exc_max_sz {
225 union __RequestUnion__catch_mach_exc_subsystem req;
226 union __ReplyUnion__catch_mach_exc_subsystem rep;
227 };
228
229 union do_notify_max_sz {
230 union __RequestUnion__do_notify_subsystem req;
231 union __ReplyUnion__do_notify_subsystem rep;
232 };
233
234 void
launchd_runtime_init(void)235 launchd_runtime_init(void)
236 {
237 #ifdef notyet
238 pid_t p = getpid();
239 #endif
240 (void)posix_assert_zero((mainkq = kqueue()));
241
242 os_assert_zero(mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_PORT_SET, &demand_port_set));
243 os_assert_zero(mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_PORT_SET, &ipc_port_set));
244 posix_assert_zero(kevent_mod(demand_port_set, EVFILT_MACHPORT, EV_ADD, 0, 0, &kqmportset_callback));
245
246 os_assert_zero(launchd_mport_create_recv(&launchd_internal_port));
247 os_assert_zero(launchd_mport_make_send(launchd_internal_port));
248
249 max_msg_size = sizeof(union vproc_mig_max_sz);
250 #ifdef notyet
251 if (sizeof(union xpc_domain_max_sz) > max_msg_size) {
252 max_msg_size = sizeof(union xpc_domain_max_sz);
253 }
254 #endif
255
256 os_assert_zero(runtime_add_mport(launchd_internal_port, launchd_internal_demux));
257 os_assert_zero(pthread_create(&kqueue_demand_thread, NULL, kqueue_demand_loop, NULL));
258 os_assert_zero(pthread_detach(kqueue_demand_thread));
259
260 os_assert_zero(pthread_create(&waitpid_thread, NULL, waitpid_loop, NULL));
261 os_assert_zero(pthread_detach(waitpid_thread));
262
263 #ifdef notyet
264 (void)posix_assumes_zero(sysctlbyname("vfs.generic.noremotehang", NULL, NULL, &p, sizeof(p)));
265 #endif
266 }
267
268 static void
sighandler_init_compat(int signo)269 sighandler_init_compat(int signo)
270 {
271 int kr;
272 int rflags = 0;
273 _launchd_syslog(LOG_CRIT, "%s(%d)", __FUNCTION__, signo);
274 switch (signo) {
275 case SIGUSR2:
276 rflags = RB_POWEROFF;
277 case SIGUSR1:
278 rflags |= RB_HALT;
279 // halt and power off
280 kr = job_mig_reboot2(root_jobmgr, rflags);
281 if (kr != KERN_SUCCESS) {
282 _launchd_syslog(LOG_CRIT, "%s(%d): kr = %d", __FUNCTION__, __LINE__, kr);
283 }
284 break;
285 case SIGTERM:
286 _launchd_syslog(LOG_CRIT, "%s(%d): Got SIGTERM", __FUNCTION__, __LINE__);
287 // Single user mode
288 break;
289 case SIGINT:
290 // Reboot
291 kr = job_mig_reboot2(root_jobmgr, RB_AUTOBOOT);
292 if (kr != KERN_SUCCESS) {
293 _launchd_syslog(LOG_CRIT, "%s(%d): kr = %d", __FUNCTION__, __LINE__, kr);
294 }
295 break;
296 case SIGTSTP:
297 // Block further logins
298 break;
299 case SIGHUP:
300 // Rescan the ttys file
301 break;
302 default:
303 _launchd_syslog(LOG_DEBUG, "%s: unknown signal number %d", __FUNCTION__, signo);
304 break;
305 }
306 }
307
308 void
launchd_runtime_init2(void)309 launchd_runtime_init2(void)
310 {
311 size_t i;
312
313 __OS_COMPILETIME_ASSERT__(SIG_ERR == (typeof(SIG_ERR))-1);
314 for (i = 0; i < (sizeof(init_compat_signals) / sizeof(int)); i++) {
315 signal(init_compat_signals[i], sighandler_init_compat);
316 }
317 for (i = 0; i < (sizeof(sigigns) / sizeof(int)); i++) {
318 sigaddset(&sigign_set, sigigns[i]);
319 (void)posix_assumes_zero(signal(sigigns[i], SIG_IGN));
320 }
321 }
322
323 #define FLAGIF(f) if (flags & f) { flags_off += sprintf(flags_off, #f); flags &= ~f; }
324 const char *
reboot_flags_to_C_names(unsigned int flags)325 reboot_flags_to_C_names(unsigned int flags)
326 {
327 #define MAX_RB_STR "RB_ASKNAME|RB_SINGLE|RB_NOSYNC|RB_HALT|RB_INITNAME|RB_DFLTROOT|RB_ALTBOOT|RB_UNIPROC|RB_SAFEBOOT|RB_UPSDELAY|0xdeadbeeffeedface"
328 static char flags_buf[sizeof(MAX_RB_STR)];
329 char *flags_off = NULL;
330
331 if (flags == 0) {
332 return "RB_AUTOBOOT";
333 }
334
335 while (flags) {
336 if (flags_off) {
337 *flags_off = '|';
338 flags_off++;
339 *flags_off = '\0';
340 } else {
341 flags_off = flags_buf;
342 }
343
344 FLAGIF(RB_ASKNAME)
345 else FLAGIF(RB_SINGLE)
346 else FLAGIF(RB_NOSYNC)
347 else FLAGIF(RB_HALT)
348 else FLAGIF(RB_INITNAME)
349 else FLAGIF(RB_DFLTROOT)
350 else FLAGIF(RB_ALTBOOT)
351 else FLAGIF(RB_UNIPROC)
352 else FLAGIF(RB_SAFEBOOT)
353 else FLAGIF(RB_UPSDELAY)
354 else {
355 flags_off += sprintf(flags_off, "0x%x", flags);
356 flags = 0;
357 }
358 }
359
360 return flags_buf;
361 }
362
363 const char *
signal_to_C_name(unsigned int sig)364 signal_to_C_name(unsigned int sig)
365 {
366 static char unknown[25];
367
368 #define SIG2CASE(sg) case sg: return #sg
369
370 switch (sig) {
371 SIG2CASE(SIGHUP);
372 SIG2CASE(SIGINT);
373 SIG2CASE(SIGQUIT);
374 SIG2CASE(SIGILL);
375 SIG2CASE(SIGTRAP);
376 SIG2CASE(SIGABRT);
377 SIG2CASE(SIGFPE);
378 SIG2CASE(SIGKILL);
379 SIG2CASE(SIGBUS);
380 SIG2CASE(SIGSEGV);
381 SIG2CASE(SIGSYS);
382 SIG2CASE(SIGPIPE);
383 SIG2CASE(SIGALRM);
384 SIG2CASE(SIGTERM);
385 SIG2CASE(SIGURG);
386 SIG2CASE(SIGSTOP);
387 SIG2CASE(SIGTSTP);
388 SIG2CASE(SIGCONT);
389 SIG2CASE(SIGCHLD);
390 SIG2CASE(SIGTTIN);
391 SIG2CASE(SIGTTOU);
392 SIG2CASE(SIGIO);
393 SIG2CASE(SIGXCPU);
394 SIG2CASE(SIGXFSZ);
395 SIG2CASE(SIGVTALRM);
396 SIG2CASE(SIGPROF);
397 SIG2CASE(SIGWINCH);
398 SIG2CASE(SIGINFO);
399 SIG2CASE(SIGUSR1);
400 SIG2CASE(SIGUSR2);
401 default:
402 snprintf(unknown, sizeof(unknown), "%u", sig);
403 return unknown;
404 }
405 }
406
407 void
log_kevent_struct(int level,struct kevent * kev_base,int indx)408 log_kevent_struct(int level, struct kevent *kev_base, int indx)
409 {
410 struct kevent *kev = &kev_base[indx];
411 const char *filter_str;
412 char ident_buf[100];
413 char filter_buf[100];
414 char fflags_buf[1000];
415 char flags_buf[1000] = "0x0";
416 char *flags_off = NULL;
417 char *fflags_off = NULL;
418 unsigned short flags = kev->flags;
419 unsigned int fflags = kev->fflags;
420
421 if (likely(!(LOG_MASK(level & ~LOG_CONSOLE) & LOG_DEBUG))) {
422 return;
423 }
424
425 if (flags) while (flags) {
426 if (flags_off) {
427 *flags_off = '|';
428 flags_off++;
429 *flags_off = '\0';
430 } else {
431 flags_off = flags_buf;
432 }
433
434 FLAGIF(EV_ADD)
435 else FLAGIF(EV_RECEIPT)
436 else FLAGIF(EV_DELETE)
437 else FLAGIF(EV_ENABLE)
438 else FLAGIF(EV_DISABLE)
439 else FLAGIF(EV_CLEAR)
440 else FLAGIF(EV_EOF)
441 else FLAGIF(EV_ONESHOT)
442 else FLAGIF(EV_ERROR)
443 else {
444 flags_off += sprintf(flags_off, "0x%hx", flags);
445 flags = 0;
446 }
447 }
448
449 snprintf(ident_buf, sizeof(ident_buf), "%ld", kev->ident);
450 snprintf(fflags_buf, sizeof(fflags_buf), "0x%x", fflags);
451
452 switch (kev->filter) {
453 case EVFILT_READ:
454 filter_str = "EVFILT_READ";
455 break;
456 case EVFILT_WRITE:
457 filter_str = "EVFILT_WRITE";
458 break;
459 case EVFILT_AIO:
460 filter_str = "EVFILT_AIO";
461 break;
462 case EVFILT_VNODE:
463 filter_str = "EVFILT_VNODE";
464 if (fflags) while (fflags) {
465 if (fflags_off) {
466 *fflags_off = '|';
467 fflags_off++;
468 *fflags_off = '\0';
469 } else {
470 fflags_off = fflags_buf;
471 }
472
473 #define FFLAGIF(ff) if (fflags & ff) { fflags_off += sprintf(fflags_off, #ff); fflags &= ~ff; }
474
475 FFLAGIF(NOTE_DELETE)
476 else FFLAGIF(NOTE_WRITE)
477 else FFLAGIF(NOTE_EXTEND)
478 else FFLAGIF(NOTE_ATTRIB)
479 else FFLAGIF(NOTE_LINK)
480 else FFLAGIF(NOTE_RENAME)
481 else FFLAGIF(NOTE_REVOKE)
482 else {
483 fflags_off += sprintf(fflags_off, "0x%x", fflags);
484 fflags = 0;
485 }
486 }
487 break;
488 case EVFILT_PROC:
489 filter_str = "EVFILT_PROC";
490 if (fflags) while (fflags) {
491 if (fflags_off) {
492 *fflags_off = '|';
493 fflags_off++;
494 *fflags_off = '\0';
495 } else {
496 fflags_off = fflags_buf;
497 }
498
499 FFLAGIF(NOTE_EXIT)
500 else FFLAGIF(NOTE_FORK)
501 else FFLAGIF(NOTE_EXEC)
502 else FFLAGIF(NOTE_SIGNAL)
503 else FFLAGIF(NOTE_TRACK)
504 else FFLAGIF(NOTE_TRACKERR)
505 else FFLAGIF(NOTE_CHILD)
506 else {
507 fflags_off += sprintf(fflags_off, "0x%x", fflags);
508 fflags = 0;
509 }
510 }
511 break;
512 case EVFILT_SIGNAL:
513 filter_str = "EVFILT_SIGNAL";
514 strcpy(ident_buf, signal_to_C_name(kev->ident));
515 break;
516 case EVFILT_TIMER:
517 filter_str = "EVFILT_TIMER";
518 snprintf(ident_buf, sizeof(ident_buf), "0x%lx", kev->ident);
519 if (fflags) while (fflags) {
520 if (fflags_off) {
521 *fflags_off = '|';
522 fflags_off++;
523 *fflags_off = '\0';
524 } else {
525 fflags_off = fflags_buf;
526 }
527
528 FFLAGIF(NOTE_SECONDS)
529 else FFLAGIF(NOTE_USECONDS)
530 else FFLAGIF(NOTE_NSECONDS)
531 else FFLAGIF(NOTE_ABSOLUTE)
532 else {
533 fflags_off += sprintf(fflags_off, "0x%x", fflags);
534 fflags = 0;
535 }
536 }
537 break;
538 case EVFILT_MACHPORT:
539 filter_str = "EVFILT_MACHPORT";
540 snprintf(ident_buf, sizeof(ident_buf), "0x%lx", kev->ident);
541 break;
542 case EVFILT_FS:
543 filter_str = "EVFILT_FS";
544 snprintf(ident_buf, sizeof(ident_buf), "0x%lx", kev->ident);
545 if (fflags) while (fflags) {
546 if (fflags_off) {
547 *fflags_off = '|';
548 fflags_off++;
549 *fflags_off = '\0';
550 } else {
551 fflags_off = fflags_buf;
552 }
553
554 FFLAGIF(VQ_NOTRESP)
555 else FFLAGIF(VQ_NEEDAUTH)
556 else FFLAGIF(VQ_LOWDISK)
557 else FFLAGIF(VQ_MOUNT)
558 else FFLAGIF(VQ_UNMOUNT)
559 else FFLAGIF(VQ_DEAD)
560 else FFLAGIF(VQ_ASSIST)
561 else FFLAGIF(VQ_NOTRESPLOCK)
562 else FFLAGIF(VQ_UPDATE)
563 else {
564 fflags_off += sprintf(fflags_off, "0x%x", fflags);
565 fflags = 0;
566 }
567 }
568 break;
569 default:
570 snprintf(filter_buf, sizeof(filter_buf), "%hd", kev->filter);
571 filter_str = filter_buf;
572 break;
573 }
574
575 _launchd_syslog(level, "KEVENT[%d]: udata = %p data = 0x%lx ident = %s filter = %s flags = %s fflags = %s",
576 indx, kev->udata, kev->data, ident_buf, filter_str, flags_buf, fflags_buf);
577 }
578
579 void
mportset_callback(void)580 mportset_callback(void)
581 {
582 mach_port_name_array_t members;
583 mach_msg_type_number_t membersCnt;
584 mach_port_status_t status;
585 mach_msg_type_number_t statusCnt;
586 struct kevent kev;
587 unsigned int i;
588
589 if (os_assumes_zero(mach_port_get_set_status(mach_task_self(), demand_port_set, &members, &membersCnt)) != 0) {
590 return;
591 }
592
593 for (i = 0; i < membersCnt; i++) {
594 statusCnt = MACH_PORT_RECEIVE_STATUS_COUNT;
595 if (mach_port_get_attributes(mach_task_self(), members[i], MACH_PORT_RECEIVE_STATUS, (mach_port_info_t)&status,
596 &statusCnt) != KERN_SUCCESS) {
597 continue;
598 }
599 if (status.mps_msgcount) {
600 EV_SET(&kev, members[i], EVFILT_MACHPORT, 0, 0, 0, job_find_by_service_port(members[i]));
601 #if 0
602 if (kev.udata != NULL) {
603 #endif
604 log_kevent_struct(LOG_DEBUG, &kev, 0);
605 (*((kq_callback *)kev.udata))(kev.udata, &kev);
606 #if 0
607 } else {
608 log_kevent_struct(LOG_ERR, &kev, 0);
609 }
610 #endif
611 /* the callback may have tainted our ability to continue this for loop */
612 break;
613 }
614 }
615
616 (void)os_assumes_zero(vm_deallocate(mach_task_self(), (vm_address_t)members, (vm_size_t) membersCnt * sizeof(mach_port_name_t)));
617 }
618
619 void *
kqueue_demand_loop(void * arg)620 kqueue_demand_loop(void *arg __attribute__((unused)))
621 {
622 fd_set rfds;
623
624 /*
625 * Yes, at first glance, calling select() on a kqueue seems silly.
626 *
627 * This avoids a race condition between the main thread and this helper
628 * thread by ensuring that we drain kqueue events on the same thread
629 * that manipulates the kqueue.
630 */
631
632 for (;;) {
633 FD_ZERO(&rfds);
634 FD_SET(mainkq, &rfds);
635 int r = select(mainkq + 1, &rfds, NULL, NULL, NULL);
636 if (r == 1) {
637 (void)os_assumes_zero(handle_kqueue(launchd_internal_port, mainkq));
638 } else if (posix_assumes_zero(r) != -1) {
639 (void)os_assumes_zero(r);
640 }
641 }
642
643 return NULL;
644 }
645
646 void *
waitpid_loop(void * arg)647 waitpid_loop(void *arg __attribute__((unused)))
648 {
649 pid_t pid;
650
651 for (;;) {
652 if ((pid = waitpid(-1, (int *) 0, WNOWAIT)) != -1)
653 jobmgr_reap_pid(root_jobmgr, pid);
654 }
655
656 return (NULL);
657 }
658
659 kern_return_t
x_handle_kqueue(mach_port_t junk,integer_t fd)660 x_handle_kqueue(mach_port_t junk __attribute__((unused)), integer_t fd)
661 {
662 struct timespec ts = { 0, 0 };
663 struct kevent *kevi, kev[BULK_KEV_MAX];
664 int i;
665
666 bulk_kev = kev;
667
668 if ((bulk_kev_cnt = kevent(fd, NULL, 0, kev, BULK_KEV_MAX, &ts)) != -1) {
669 #if 0
670 for (i = 0; i < bulk_kev_cnt; i++) {
671 log_kevent_struct(LOG_DEBUG, &kev[0], i);
672 }
673 #endif
674 for (i = 0; i < bulk_kev_cnt; i++) {
675 bulk_kev_i = i;
676 kevi = &kev[i];
677
678 if (kevi->filter) {
679 log_kevent_struct(LOG_DEBUG, kev, i);
680
681 struct job_check_s {
682 kq_callback kqc;
683 };
684
685 struct job_check_s *check = kevi->udata;
686 if (check && check->kqc) {
687 runtime_ktrace(RTKT_LAUNCHD_BSD_KEVENT|DBG_FUNC_START, kevi->ident, kevi->filter, kevi->fflags);
688 (*((kq_callback *)kevi->udata))(kevi->udata, kevi);
689 runtime_ktrace0(RTKT_LAUNCHD_BSD_KEVENT|DBG_FUNC_END);
690 } else {
691 _launchd_syslog(LOG_ERR, "The following kevent had invalid context data. Please file a bug with the following information:");
692 log_kevent_struct(LOG_EMERG, &kev[0], i);
693 }
694 }
695 }
696 } else {
697 (void)os_assumes_zero(errno);
698 }
699
700 bulk_kev = NULL;
701
702 return 0;
703 }
704
705 void
launchd_runtime(void)706 launchd_runtime(void)
707 {
708 launchd_runtime2(max_msg_size);
709 dispatch_main();
710 }
711
712 kern_return_t
launchd_set_bport(mach_port_t name)713 launchd_set_bport(mach_port_t name)
714 {
715 return errno = task_set_bootstrap_port(mach_task_self(), name);
716 }
717
718 kern_return_t
launchd_get_bport(mach_port_t * name)719 launchd_get_bport(mach_port_t *name)
720 {
721 return errno = task_get_bootstrap_port(mach_task_self(), name);
722 }
723
724 kern_return_t
launchd_mport_notify_req(mach_port_t name,mach_msg_id_t which)725 launchd_mport_notify_req(mach_port_t name, mach_msg_id_t which)
726 {
727 mach_port_mscount_t msgc = (which == MACH_NOTIFY_PORT_DESTROYED) ? 0 : 1;
728 mach_port_t previous, where = (which == MACH_NOTIFY_NO_SENDERS) ? name : launchd_internal_port;
729 int err;
730
731 if (which == MACH_NOTIFY_NO_SENDERS) {
732 /* Always make sure the send count is zero, in case a receive right is
733 * reused
734 */
735 err = mach_port_set_mscount(mach_task_self(), name, 0);
736 if (unlikely(err != KERN_SUCCESS)) {
737 return err;
738 }
739 }
740
741 err = mach_port_request_notification(mach_task_self(), name, which, msgc, where, MACH_MSG_TYPE_MAKE_SEND_ONCE, &previous);
742
743 if (likely(err == 0) && previous != MACH_PORT_NULL) {
744 (void)os_assumes_zero(launchd_mport_deallocate(previous));
745 }
746
747 return (err);
748 }
749
750 pid_t
runtime_fork(mach_port_t bsport)751 runtime_fork(mach_port_t bsport)
752 {
753 sigset_t emptyset, oset;
754 pid_t r = -1;
755 int saved_errno;
756 size_t i;
757
758 sigemptyset(&emptyset);
759
760 (void)os_assumes_zero(launchd_mport_make_send(bsport));
761 (void)os_assumes_zero(launchd_set_bport(bsport));
762 (void)os_assumes_zero(launchd_mport_deallocate(bsport));
763
764 __OS_COMPILETIME_ASSERT__(SIG_ERR == (typeof(SIG_ERR))-1);
765 if (uflag == false) {
766 (void)posix_assumes_zero(sigprocmask(SIG_BLOCK, &sigign_set, &oset));
767 for (i = 0; i < (sizeof(sigigns) / sizeof(int)); i++) {
768 (void)posix_assumes_zero(signal(sigigns[i], SIG_DFL));
769 }
770 }
771
772 r = fork();
773 saved_errno = errno;
774
775 if (r != 0) {
776 for (i = 0; i < (sizeof(sigigns) / sizeof(int)); i++) {
777 (void)posix_assumes_zero(signal(sigigns[i], SIG_IGN));
778 }
779 if (uflag == false)
780 (void)posix_assumes_zero(sigprocmask(SIG_SETMASK, &oset, NULL));
781 (void)os_assumes_zero(launchd_set_bport(MACH_PORT_NULL));
782 } else {
783 pid_t p = -getpid();
784 (void)posix_assumes_zero(sysctlbyname("vfs.generic.noremotehang", NULL, NULL, &p, sizeof(p)));
785 (void)posix_assumes_zero(sigprocmask(SIG_SETMASK, &emptyset, NULL));
786 }
787
788 errno = saved_errno;
789
790 return r;
791 }
792
793
794 void
runtime_set_timeout(timeout_callback to_cb,unsigned int sec)795 runtime_set_timeout(timeout_callback to_cb, unsigned int sec)
796 {
797 if (sec == 0 || to_cb == NULL) {
798 runtime_idle_callback = NULL;
799 runtime_idle_timeout = 0;
800 }
801
802 runtime_idle_callback = to_cb;
803 runtime_idle_timeout = sec * 1000;
804 }
805
806 kern_return_t
runtime_add_mport(mach_port_t name,mig_callback demux)807 runtime_add_mport(mach_port_t name, mig_callback demux)
808 {
809 size_t needed_table_sz = (MACH_PORT_INDEX(name) + 1) * sizeof(mig_callback);
810 mach_port_t target_set = demux ? ipc_port_set : demand_port_set;
811
812 if (unlikely(needed_table_sz > mig_cb_table_sz)) {
813 needed_table_sz *= 2; /* Let's try and avoid realloc'ing for a while */
814 mig_callback *new_table = malloc(needed_table_sz);
815
816 if (!new_table) {
817 return KERN_RESOURCE_SHORTAGE;
818 }
819
820 if (likely(mig_cb_table)) {
821 memcpy(new_table, mig_cb_table, mig_cb_table_sz);
822 free(mig_cb_table);
823 }
824
825 mig_cb_table_sz = needed_table_sz;
826 mig_cb_table = new_table;
827 }
828
829 mig_cb_table[MACH_PORT_INDEX(name)] = demux;
830
831 return errno = mach_port_move_member(mach_task_self(), name, target_set);
832 }
833
834 kern_return_t
runtime_remove_mport(mach_port_t name)835 runtime_remove_mport(mach_port_t name)
836 {
837 mig_cb_table[MACH_PORT_INDEX(name)] = NULL;
838
839 return errno = mach_port_move_member(mach_task_self(), name, MACH_PORT_NULL);
840 }
841
842 kern_return_t
launchd_mport_make_send(mach_port_t name)843 launchd_mport_make_send(mach_port_t name)
844 {
845 return errno = mach_port_insert_right(mach_task_self(), name, name, MACH_MSG_TYPE_MAKE_SEND);
846 }
847
848 kern_return_t
launchd_mport_copy_send(mach_port_t name)849 launchd_mport_copy_send(mach_port_t name)
850 {
851 return errno = mach_port_insert_right(mach_task_self(), name, name, MACH_MSG_TYPE_COPY_SEND);
852 }
853
854 kern_return_t
launchd_mport_make_send_once(mach_port_t name,mach_port_t * so)855 launchd_mport_make_send_once(mach_port_t name, mach_port_t *so)
856 {
857 mach_msg_type_name_t right = 0;
858 return errno = mach_port_extract_right(mach_task_self(), name, MACH_MSG_TYPE_MAKE_SEND_ONCE, so, &right);
859 }
860
861 kern_return_t
launchd_mport_close_recv(mach_port_t name)862 launchd_mport_close_recv(mach_port_t name)
863 {
864 return errno = mach_port_mod_refs(mach_task_self(), name, MACH_PORT_RIGHT_RECEIVE, -1);
865 }
866
867 kern_return_t
launchd_mport_create_recv(mach_port_t * name)868 launchd_mport_create_recv(mach_port_t *name)
869 {
870 return errno = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, name);
871 }
872
873 kern_return_t
launchd_mport_deallocate(mach_port_t name)874 launchd_mport_deallocate(mach_port_t name)
875 {
876 return errno = mach_port_deallocate(mach_task_self(), name);
877 }
878
879 int
kevent_bulk_mod(struct kevent * kev,size_t kev_cnt)880 kevent_bulk_mod(struct kevent *kev, size_t kev_cnt)
881 {
882 size_t i;
883
884 for (i = 0; i < kev_cnt; i++) {
885 kev[i].flags |= EV_CLEAR|EV_RECEIPT;
886 }
887
888 return kevent(mainkq, kev, kev_cnt, kev, kev_cnt, NULL);
889 }
890
891 int
kevent_mod(uintptr_t ident,short filter,u_short flags,u_int fflags,intptr_t data,void * udata)892 kevent_mod(uintptr_t ident, short filter, u_short flags, u_int fflags, intptr_t data, void *udata)
893 {
894 struct kevent kev;
895 int r;
896
897 switch (filter) {
898 case EVFILT_READ:
899 case EVFILT_WRITE:
900 break;
901 case EVFILT_TIMER:
902 /* Workaround 5225889 */
903 if (flags & EV_ADD) {
904 (void)kevent_mod(ident, EVFILT_TIMER, EV_DELETE, 0, 0, NULL);
905 }
906 /* fall through */
907 default:
908 flags |= EV_CLEAR;
909 break;
910 }
911
912 flags |= EV_RECEIPT;
913
914 if (flags & EV_ADD && !udata) {
915 errno = EINVAL;
916 return -1;
917 } else if ((flags & EV_DELETE) && bulk_kev) {
918 int i = 0;
919 for (i = bulk_kev_i + 1; i < bulk_kev_cnt; i++) {
920 if (bulk_kev[i].filter == filter && bulk_kev[i].ident == ident) {
921 _launchd_syslog(LOG_DEBUG, "Pruning the following kevent:");
922 log_kevent_struct(LOG_DEBUG, &bulk_kev[0], i);
923 bulk_kev[i].filter = (short)0;
924 }
925 }
926 }
927
928 EV_SET(&kev, ident, filter, flags, fflags, data, udata);
929
930 r = kevent(mainkq, &kev, 1, &kev, 1, NULL);
931
932 if (r != 1) {
933 return -1;
934 }
935
936 if (kev.flags & EV_ERROR) {
937 if ((flags & EV_ADD) && kev.data) {
938 _launchd_syslog(LOG_DEBUG, "%s(): See the next line...", __func__);
939 log_kevent_struct(LOG_DEBUG, &kev, 0);
940 errno = kev.data;
941 return -1;
942 }
943 } else {
944 (void)os_assert_zero(kev.flags);
945 }
946
947 return r;
948 }
949
950 boolean_t
launchd_internal_demux(mach_msg_header_t * Request,mach_msg_header_t * Reply)951 launchd_internal_demux(mach_msg_header_t *Request, mach_msg_header_t *Reply)
952 {
953 if (internal_server_routine(Request)) {
954 return internal_server(Request, Reply);
955 } else if (notify_server_routine(Request)) {
956 return notify_server(Request, Reply);
957 } else {
958 return mach_exc_server(Request, Reply);
959 }
960 }
961
962 kern_return_t
do_mach_notify_port_destroyed(mach_port_t notify,mach_port_t rights)963 do_mach_notify_port_destroyed(mach_port_t notify __attribute__((unused)), mach_port_t rights)
964 {
965 /* This message is sent to us when a receive right is returned to us. */
966 if (!job_ack_port_destruction(rights)) {
967 (void)os_assumes_zero(launchd_mport_close_recv(rights));
968 }
969
970 return KERN_SUCCESS;
971 }
972
973 kern_return_t
do_mach_notify_port_deleted(mach_port_t notify,mach_port_name_t name)974 do_mach_notify_port_deleted(mach_port_t notify __attribute__((unused)), mach_port_name_t name __attribute__((unused)))
975 {
976 /* If we deallocate/destroy/mod_ref away a port with a pending
977 * notification, the original notification message is replaced with
978 * this message. To quote a Mach kernel expert, "the kernel has a
979 * send-once right that has to be used somehow."
980 */
981 return KERN_SUCCESS;
982 }
983
984 kern_return_t
do_mach_notify_no_senders(mach_port_t notify,mach_port_mscount_t mscount)985 do_mach_notify_no_senders(mach_port_t notify, mach_port_mscount_t mscount __attribute__((unused)))
986 {
987 job_t j = job_mig_intran(notify);
988
989 /* This message is sent to us when the last customer of one of our objects
990 * goes away.
991 */
992
993 if (!j) {
994 return KERN_FAILURE;
995 }
996
997 job_ack_no_senders(j);
998
999 return KERN_SUCCESS;
1000 }
1001
1002 kern_return_t
do_mach_notify_send_once(mach_port_t notify)1003 do_mach_notify_send_once(mach_port_t notify __attribute__((unused)))
1004 {
1005 /*
1006 * This message is sent for each send-once right that is deallocated without
1007 * being used.
1008 */
1009
1010 return KERN_SUCCESS;
1011 }
1012
1013 kern_return_t
do_mach_notify_dead_name(mach_port_t notify,mach_port_name_t name)1014 do_mach_notify_dead_name(mach_port_t notify __attribute__((unused)), mach_port_name_t name)
1015 {
1016 /* This message is sent to us when one of our send rights no longer has a
1017 * receiver somewhere else on the system.
1018 */
1019 if (name == launchd_drain_reply_port) {
1020 (void)os_assumes_zero(launchd_mport_deallocate(name));
1021 launchd_drain_reply_port = MACH_PORT_NULL;
1022 }
1023
1024 if (root_jobmgr) {
1025 root_jobmgr = jobmgr_delete_anything_with_port(root_jobmgr, name);
1026 }
1027
1028 /* A dead-name notification about a port appears to increment the rights on
1029 * said port. Let's deallocate it so that we don't leak dead-name ports.
1030 */
1031 (void)os_assumes_zero(launchd_mport_deallocate(name));
1032
1033 return KERN_SUCCESS;
1034 }
1035
1036 mach_msg_return_t
launchd_exc_runtime_once(mach_port_t port,mach_msg_size_t rcv_msg_size,mach_msg_size_t send_msg_size,mig_reply_error_t * bufRequest,mig_reply_error_t * bufReply,mach_msg_timeout_t to)1037 launchd_exc_runtime_once(mach_port_t port, mach_msg_size_t rcv_msg_size, mach_msg_size_t send_msg_size, mig_reply_error_t *bufRequest, mig_reply_error_t *bufReply, mach_msg_timeout_t to)
1038 {
1039 mach_msg_return_t mr = ~MACH_MSG_SUCCESS;
1040 mach_msg_option_t rcv_options = MACH_RCV_MSG
1041 | MACH_RCV_TIMEOUT
1042 | MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT)
1043 | MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0);
1044
1045 do {
1046 mr = mach_msg(&bufRequest->Head, rcv_options, 0, rcv_msg_size, port, to, MACH_PORT_NULL);
1047 switch (mr) {
1048 case MACH_RCV_TIMED_OUT:
1049 _launchd_syslog(LOG_DEBUG, "Message queue is empty.");
1050 break;
1051 case MACH_RCV_TOO_LARGE:
1052 _launchd_syslog(LOG_INFO, "Message is larger than %u bytes.", rcv_msg_size);
1053 break;
1054 default:
1055 (void)os_assumes_zero(mr);
1056 }
1057
1058 if (mr == MACH_MSG_SUCCESS) {
1059 if (!mach_exc_server(&bufRequest->Head, &bufReply->Head)) {
1060 _launchd_syslog(LOG_WARNING, "Exception server routine failed.");
1061 break;
1062 }
1063
1064 mach_msg_return_t smr = ~MACH_MSG_SUCCESS;
1065 mach_msg_option_t send_options = MACH_SEND_MSG | MACH_SEND_TIMEOUT;
1066
1067 (void)os_assumes(bufReply->Head.msgh_size <= send_msg_size);
1068 smr = mach_msg(&bufReply->Head, send_options, bufReply->Head.msgh_size, 0, MACH_PORT_NULL, to + 100, MACH_PORT_NULL);
1069 switch (smr) {
1070 case MACH_SEND_TIMED_OUT:
1071 _launchd_syslog(LOG_WARNING, "Timed out while trying to send reply to exception message.");
1072 break;
1073 case MACH_SEND_INVALID_DEST:
1074 _launchd_syslog(LOG_WARNING, "Tried sending a message to a port that we don't possess a send right to.");
1075 break;
1076 default:
1077 if (smr) {
1078 _launchd_syslog(LOG_WARNING, "Couldn't deliver exception reply: 0x%x", smr);
1079 }
1080 break;
1081 }
1082 }
1083 } while (0);
1084
1085 return mr;
1086 }
1087
1088 void
runtime_record_caller_creds(audit_token_t * token)1089 runtime_record_caller_creds(audit_token_t *token)
1090 {
1091 (void)memcpy(&ldc_token, token, sizeof(*token));
1092 audit_token_to_au32(*token, NULL, &ldc.euid,&ldc.egid, &ldc.uid, &ldc.gid,
1093 &ldc.pid, &ldc.asid, NULL);
1094 }
1095
1096 struct ldcred *
runtime_get_caller_creds(void)1097 runtime_get_caller_creds(void)
1098 {
1099 return &ldc;
1100 }
1101
1102 audit_token_t *
runtime_get_caller_token(void)1103 runtime_get_caller_token(void)
1104 {
1105 return &ldc_token;
1106 }
1107
1108 static boolean_t
launchd_mig_demux(mach_msg_header_t * request,mach_msg_header_t * reply)1109 launchd_mig_demux(mach_msg_header_t *request, mach_msg_header_t *reply)
1110 {
1111 boolean_t result = false;
1112
1113 time_of_mach_msg_return = runtime_get_opaque_time();
1114 #ifdef _EXTRA_LAUNCHD_SPEW
1115 _launchd_syslog(LOG_DEBUG, "MIG callout: %u", request->msgh_id);
1116 #endif
1117 mig_callback the_demux = mig_cb_table[MACH_PORT_INDEX(request->msgh_local_port)];
1118 mach_msg_audit_trailer_t *tp = (mach_msg_audit_trailer_t *)((vm_offset_t)request + round_msg(request->msgh_size));
1119 runtime_record_caller_creds(&tp->msgh_audit);
1120
1121 result = the_demux(request, reply);
1122 if (!result) {
1123 _launchd_syslog(LOG_DEBUG, "Demux failed. Trying other subsystems...");
1124 if (request->msgh_id == MACH_NOTIFY_NO_SENDERS) {
1125 _launchd_syslog(LOG_DEBUG, "MACH_NOTIFY_NO_SENDERS");
1126 result = notify_server(request, reply);
1127 #ifdef notyet
1128 } else if (the_demux == job_server) {
1129 _launchd_syslog(LOG_DEBUG, "Trying domain subsystem...");
1130 result = xpc_domain_server(request, reply);
1131 #endif
1132 } else {
1133 _launchd_syslog(LOG_ERR, "Cannot handle MIG request with ID: 0x%x", request->msgh_id);
1134 }
1135 } else {
1136 #ifdef _EXTRA_LAUNCHD_SPEW
1137 _launchd_syslog(LOG_DEBUG, "MIG demux succeeded.");
1138 #endif
1139 }
1140
1141 return result;
1142 }
1143
1144 void
launchd_runtime2(mach_msg_size_t msg_size)1145 launchd_runtime2(mach_msg_size_t msg_size)
1146 {
1147 for (;;) {
1148 launchd_log_push();
1149
1150 mach_port_t recvp = MACH_PORT_NULL;
1151 xpc_object_t request = NULL;
1152
1153 int result;
1154 result = xpc_pipe_try_receive(ipc_port_set, &request, &recvp, launchd_mig_demux, msg_size, 0);
1155 if (result != 1)
1156 syslog(LOG_ERR, "result=%d", result);
1157 if (result == 0 && request) {
1158 boolean_t handled = false;
1159 time_of_mach_msg_return = runtime_get_opaque_time();
1160 _launchd_syslog(LOG_DEBUG, "XPC request.");
1161
1162 xpc_object_t reply = NULL;
1163 if (xpc_event_demux(recvp, request, &reply)) {
1164 handled = true;
1165 } else if (xpc_process_demux(recvp, request, &reply)) {
1166 handled = true;
1167 }
1168
1169 if (!handled) {
1170 _launchd_syslog(LOG_DEBUG, "XPC routine could not be handled.");
1171 xpc_release(request);
1172 continue;
1173 }
1174
1175 _launchd_syslog(LOG_DEBUG, "XPC routine was handled.");
1176 if (reply) {
1177 _launchd_syslog(LOG_DEBUG, "Sending reply.");
1178 result = xpc_pipe_routine_reply(reply);
1179 if (result == 0) {
1180 _launchd_syslog(LOG_DEBUG, "Reply sent successfully.");
1181 } else if (result != EPIPE) {
1182 _launchd_syslog(LOG_ERR, "Failed to send reply message: 0x%x", result);
1183 }
1184
1185 xpc_release(reply);
1186 }
1187
1188 xpc_release(request);
1189 } else if (result == 0) {
1190 _launchd_syslog(LOG_DEBUG, "MIG request.");
1191 } else if (result == EINVAL) {
1192 _launchd_syslog(LOG_ERR, "Rejected invalid request message.");
1193 }
1194 }
1195 }
1196
1197 int
runtime_close(int fd)1198 runtime_close(int fd)
1199 {
1200 int i;
1201
1202 if (bulk_kev) for (i = bulk_kev_i + 1; i < bulk_kev_cnt; i++) {
1203 switch (bulk_kev[i].filter) {
1204 case EVFILT_VNODE:
1205 case EVFILT_WRITE:
1206 case EVFILT_READ:
1207 if (unlikely((int)bulk_kev[i].ident == fd)) {
1208 _launchd_syslog(LOG_DEBUG, "Skipping kevent index: %d", i);
1209 bulk_kev[i].filter = 0;
1210 }
1211 default:
1212 break;
1213 }
1214 }
1215
1216 return close(fd);
1217 }
1218
1219 int
runtime_fsync(int fd)1220 runtime_fsync(int fd)
1221 {
1222 #if 0
1223 if (launchd_apple_internal) {
1224 return fcntl(fd, F_FULLFSYNC, NULL);
1225 } else {
1226 return fsync(fd);
1227 }
1228 #else
1229 return fsync(fd);
1230 #endif
1231 }
1232
1233 #undef TARGET_OS_EMBEDDED
1234 #define TARGET_OS_EMBEDDED 1
1235 static int launchd_appletv;
1236
1237 /*
1238 * We should break this into two reference counts.
1239 *
1240 * One for hard references that would prevent exiting.
1241 * One for soft references that would only prevent idle exiting.
1242 *
1243 * In the long run, reference counting should completely automate when a
1244 * process can and should exit.
1245 */
1246 void
runtime_add_ref(void)1247 runtime_add_ref(void)
1248 {
1249 if (!pid1_magic) {
1250 #if !TARGET_OS_EMBEDDED
1251 vproc_transaction_begin(NULL);
1252 #endif
1253 }
1254
1255 runtime_busy_cnt++;
1256 _launchd_syslog(LOG_PERF, "Incremented busy count. Now: %lu", runtime_busy_cnt);
1257 runtime_remove_timer();
1258 }
1259
1260 void
runtime_del_ref(void)1261 runtime_del_ref(void)
1262 {
1263 if (!pid1_magic) {
1264 #if !TARGET_OS_EMBEDDED
1265 if (_vproc_transaction_count() == 0) {
1266 _launchd_syslog(LOG_PERF, "Exiting cleanly.");
1267 }
1268
1269 vproc_transaction_end(NULL, NULL);
1270 #endif
1271 }
1272
1273 runtime_busy_cnt--;
1274 _launchd_syslog(LOG_PERF, "Decremented busy count. Now: %lu", runtime_busy_cnt);
1275 runtime_install_timer();
1276 }
1277
1278 void
runtime_add_weak_ref(void)1279 runtime_add_weak_ref(void)
1280 {
1281 if (!pid1_magic) {
1282 #if !TARGET_OS_EMBEDDED
1283 _vproc_standby_begin();
1284 #endif
1285 }
1286 runtime_standby_cnt++;
1287 }
1288
1289 void
runtime_del_weak_ref(void)1290 runtime_del_weak_ref(void)
1291 {
1292 if (!pid1_magic) {
1293 #if !TARGET_OS_EMBEDDED
1294 _vproc_standby_end();
1295 #endif
1296 }
1297 runtime_standby_cnt--;
1298 }
1299
1300 void
runtime_install_timer(void)1301 runtime_install_timer(void)
1302 {
1303 if (!pid1_magic && runtime_busy_cnt == 0) {
1304 _launchd_syslog(LOG_PERF, "Gone idle. Installing idle-exit timer.");
1305 (void)posix_assumes_zero(kevent_mod((uintptr_t)&launchd_runtime_busy_time, EVFILT_TIMER, EV_ADD, NOTE_SECONDS, 10, root_jobmgr));
1306 }
1307 }
1308
1309 void
runtime_remove_timer(void)1310 runtime_remove_timer(void)
1311 {
1312 if (!pid1_magic && runtime_busy_cnt > 0) {
1313 if (runtime_busy_cnt == 1) {
1314 _launchd_syslog(LOG_PERF, "No longer idle. Removing idle-exit timer.");
1315 }
1316 (void)posix_assumes_zero(kevent_mod((uintptr_t)&launchd_runtime_busy_time, EVFILT_TIMER, EV_DELETE, 0, 0, NULL));
1317 }
1318 }
1319
1320 kern_return_t
catch_mach_exception_raise(mach_port_t exception_port,mach_port_t thread,mach_port_t task,exception_type_t exception,mach_exception_data_t code,mach_msg_type_number_t codeCnt)1321 catch_mach_exception_raise(mach_port_t exception_port __attribute__((unused)), mach_port_t thread, mach_port_t task,
1322 exception_type_t exception, mach_exception_data_t code, mach_msg_type_number_t codeCnt)
1323 {
1324 pid_t p4t = -1;
1325
1326 (void)os_assumes_zero(pid_for_task(task, &p4t));
1327
1328 _launchd_syslog(LOG_NOTICE, "%s(): PID: %u thread: 0x%x type: 0x%x code: %p codeCnt: 0x%x",
1329 __func__, p4t, thread, exception, code, codeCnt);
1330
1331 (void)os_assumes_zero(launchd_mport_deallocate(thread));
1332 (void)os_assumes_zero(launchd_mport_deallocate(task));
1333
1334 return KERN_SUCCESS;
1335 }
1336
1337 kern_return_t
catch_mach_exception_raise_state(mach_port_t exception_port,exception_type_t exception,const mach_exception_data_t code,mach_msg_type_number_t codeCnt,int * flavor,const thread_state_t old_state,mach_msg_type_number_t old_stateCnt,thread_state_t new_state,mach_msg_type_number_t * new_stateCnt)1338 catch_mach_exception_raise_state(mach_port_t exception_port __attribute__((unused)),
1339 exception_type_t exception, const mach_exception_data_t code, mach_msg_type_number_t codeCnt,
1340 int *flavor, const thread_state_t old_state, mach_msg_type_number_t old_stateCnt,
1341 thread_state_t new_state, mach_msg_type_number_t *new_stateCnt)
1342 {
1343 _launchd_syslog(LOG_NOTICE, "%s(): type: 0x%x code: %p codeCnt: 0x%x flavor: %p old_state: %p old_stateCnt: 0x%x new_state: %p new_stateCnt: %p",
1344 __func__, exception, code, codeCnt, flavor, old_state, old_stateCnt, new_state, new_stateCnt);
1345
1346 memcpy(new_state, old_state, old_stateCnt * sizeof(old_state[0]));
1347 *new_stateCnt = old_stateCnt;
1348
1349 return KERN_SUCCESS;
1350 }
1351
1352 kern_return_t
catch_mach_exception_raise_state_identity(mach_port_t exception_port,mach_port_t thread,mach_port_t task,exception_type_t exception,mach_exception_data_t code,mach_msg_type_number_t codeCnt,int * flavor,thread_state_t old_state,mach_msg_type_number_t old_stateCnt,thread_state_t new_state,mach_msg_type_number_t * new_stateCnt)1353 catch_mach_exception_raise_state_identity(mach_port_t exception_port __attribute__((unused)), mach_port_t thread, mach_port_t task,
1354 exception_type_t exception, mach_exception_data_t code, mach_msg_type_number_t codeCnt,
1355 int *flavor, thread_state_t old_state, mach_msg_type_number_t old_stateCnt,
1356 thread_state_t new_state, mach_msg_type_number_t *new_stateCnt)
1357 {
1358 pid_t p4t = -1;
1359
1360 (void)os_assumes_zero(pid_for_task(task, &p4t));
1361
1362 _launchd_syslog(LOG_NOTICE, "%s(): PID: %u thread: 0x%x type: 0x%x code: %p codeCnt: 0x%x flavor: %p old_state: %p old_stateCnt: 0x%x new_state: %p new_stateCnt: %p",
1363 __func__, p4t, thread, exception, code, codeCnt, flavor, old_state, old_stateCnt, new_state, new_stateCnt);
1364
1365 memcpy(new_state, old_state, old_stateCnt * sizeof(old_state[0]));
1366 *new_stateCnt = old_stateCnt;
1367
1368 (void)os_assumes_zero(launchd_mport_deallocate(thread));
1369 (void)os_assumes_zero(launchd_mport_deallocate(task));
1370
1371 return KERN_SUCCESS;
1372 }
1373
1374 // FIXME: should this be thread safe? With dispatch_once?
1375 uint64_t
runtime_get_uniqueid(void)1376 runtime_get_uniqueid(void)
1377 {
1378 static bool once;
1379 static uint64_t uniqueid;
1380 if (unlikely(!once)) {
1381 once = true;
1382
1383 struct proc_uniqidentifierinfo info;
1384 int size;
1385 size = proc_pidinfo(getpid(), PROC_PIDUNIQIDENTIFIERINFO, 0, &info, sizeof(info));
1386 if (size == PROC_PIDUNIQIDENTIFIERINFO_SIZE) {
1387 uniqueid = info.p_uniqueid;
1388 }
1389 }
1390 return uniqueid;
1391 }
1392
1393 void
launchd_log_vm_stats(void)1394 launchd_log_vm_stats(void)
1395 {
1396 static struct vm_statistics orig_stats;
1397 static bool did_first_pass;
1398 unsigned int count = HOST_VM_INFO_COUNT;
1399 struct vm_statistics stats, *statsp;
1400 mach_port_t mhs = mach_host_self();
1401
1402 statsp = did_first_pass ? &stats : &orig_stats;
1403
1404 if (os_assumes_zero(host_statistics(mhs, HOST_VM_INFO, (host_info_t)statsp, &count)) != KERN_SUCCESS) {
1405 return;
1406 }
1407
1408 if (count != HOST_VM_INFO_COUNT) {
1409 (void)os_assumes_zero(count);
1410 }
1411
1412 if (did_first_pass) {
1413 _launchd_syslog(LOG_DEBUG, "VM statistics (now - orig): Free: %d Active: %d Inactive: %d Reactivations: %d PageIns: %d PageOuts: %d Faults: %d COW-Faults: %d Purgeable: %d Purges: %d",
1414 stats.free_count - orig_stats.free_count,
1415 stats.active_count - orig_stats.active_count,
1416 stats.inactive_count - orig_stats.inactive_count,
1417 stats.reactivations - orig_stats.reactivations,
1418 stats.pageins - orig_stats.pageins,
1419 stats.pageouts - orig_stats.pageouts,
1420 stats.faults - orig_stats.faults,
1421 stats.cow_faults - orig_stats.cow_faults,
1422 stats.purgeable_count - orig_stats.purgeable_count,
1423 stats.purges - orig_stats.purges);
1424 } else {
1425 _launchd_syslog(LOG_DEBUG, "VM statistics (now): Free: %d Active: %d Inactive: %d Reactivations: %d PageIns: %d PageOuts: %d Faults: %d COW-Faults: %d Purgeable: %d Purges: %d",
1426 orig_stats.free_count,
1427 orig_stats.active_count,
1428 orig_stats.inactive_count,
1429 orig_stats.reactivations,
1430 orig_stats.pageins,
1431 orig_stats.pageouts,
1432 orig_stats.faults,
1433 orig_stats.cow_faults,
1434 orig_stats.purgeable_count,
1435 orig_stats.purges);
1436
1437 did_first_pass = true;
1438 }
1439
1440 launchd_mport_deallocate(mhs);
1441 }
1442
1443 int64_t
runtime_get_wall_time(void)1444 runtime_get_wall_time(void)
1445 {
1446 struct timeval tv;
1447 int64_t r;
1448
1449 (void)posix_assumes_zero(gettimeofday(&tv, NULL));
1450
1451 r = tv.tv_sec;
1452 r *= USEC_PER_SEC;
1453 r += tv.tv_usec;
1454
1455 return r;
1456 }
1457
1458 uint64_t
runtime_get_opaque_time(void)1459 runtime_get_opaque_time(void)
1460 {
1461 return mach_absolute_time();
1462 }
1463
1464 uint64_t
runtime_get_opaque_time_of_event(void)1465 runtime_get_opaque_time_of_event(void)
1466 {
1467 return time_of_mach_msg_return;
1468 }
1469
1470 uint64_t
runtime_get_nanoseconds_since(uint64_t o)1471 runtime_get_nanoseconds_since(uint64_t o)
1472 {
1473 return runtime_opaque_time_to_nano(runtime_get_opaque_time_of_event() - o);
1474 }
1475
1476 uint64_t
runtime_opaque_time_to_nano(uint64_t o)1477 runtime_opaque_time_to_nano(uint64_t o)
1478 {
1479 #if defined(__i386__) || defined(__x86_64__)
1480 if (unlikely(tbi.numer != tbi.denom)) {
1481 #elif defined(__ppc__) || defined(__ppc64__)
1482 if (likely(tbi.numer != tbi.denom)) {
1483 #else
1484 if (tbi.numer != tbi.denom) {
1485 #endif
1486 #ifdef __LP64__
1487 __uint128_t tmp = o;
1488 tmp *= tbi.numer;
1489 tmp /= tbi.denom;
1490 o = tmp;
1491 #else
1492 if (o <= tbi_safe_math_max) {
1493 o *= tbi.numer;
1494 o /= tbi.denom;
1495 } else {
1496 double d = o;
1497 d *= tbi_float_val;
1498 o = d;
1499 }
1500 #endif
1501 }
1502
1503 return o;
1504 }
1505
1506 void
1507 do_file_init(void)
1508 {
1509 struct stat sb;
1510
1511 os_assert_zero(mach_timebase_info(&tbi));
1512 tbi_float_val = tbi.numer;
1513 tbi_float_val /= tbi.denom;
1514 tbi_safe_math_max = UINT64_MAX / tbi.numer;
1515
1516 launchd_system_start = runtime_get_wall_time();
1517
1518 if (getpid() == 1) {
1519 pid1_magic = true;
1520 }
1521
1522 if (stat("/AppleInternal", &sb) == 0 && stat("/var/db/disableAppleInternal", &sb) == -1) {
1523 launchd_apple_internal = true;
1524 }
1525
1526 if (config_check(".launchd_use_gmalloc", sb)) {
1527 launchd_use_gmalloc = true;
1528 }
1529
1530 if (config_check(".launchd_log_shutdown", sb)) {
1531 launchd_log_shutdown = true;
1532 }
1533
1534 if (config_check(".launchd_log_debug", sb)) {
1535 launchd_log_debug = true;
1536 }
1537
1538 if (config_check(".launchd_log_perf", sb)) {
1539 launchd_log_perf = true;
1540 }
1541
1542 if (config_check("/etc/rc.cdrom", sb)) {
1543 launchd_osinstaller = true;
1544 }
1545
1546 if (!pid1_magic && config_check(".launchd_allow_global_dyld_envvars", sb)) {
1547 launchd_allow_global_dyld_envvars = true;
1548 }
1549
1550 char buff[1024];
1551 size_t len = sizeof(buff) - 1;
1552 int r = pid1_magic ? sysctlbyname("kern.bootargs", buff, &len, NULL, 0) : -1;
1553 if (r == 0) {
1554 if (strnstr(buff, "-v", len)) {
1555 launchd_verbose_boot = true;
1556 }
1557 if (strnstr(buff, "launchd_trap_sigkill_bugs", len)) {
1558 launchd_trap_sigkill_bugs = true;
1559 }
1560 if (strnstr(buff, "launchd_no_jetsam_perm_check", len)) {
1561 launchd_no_jetsam_perm_check = true;
1562 }
1563 }
1564
1565 len = sizeof(buff) - 1;
1566 #if TARGET_OS_EMBEDDED
1567 r = sysctlbyname("hw.machine", buff, &len, NULL, 0);
1568 if (r == 0) {
1569 if (strnstr(buff, "AppleTV", len)) {
1570 launchd_appletv = true;
1571 }
1572 }
1573 #endif
1574
1575 #if !TARGET_OS_EMBEDDED
1576 if (pid1_magic && launchd_verbose_boot && config_check(".launchd_shutdown_debugging", sb)) {
1577 launchd_shutdown_debugging = true;
1578 }
1579 #else
1580 if (pid1_magic && config_check(".launchd_shutdown_debugging", sb)) {
1581 launchd_shutdown_debugging = true;
1582 }
1583 #endif
1584 }
1585