]> git.saurik.com Git - apple/launchd.git/blob - launchd/src/launchd_runtime.c
6eb8d40deb7ad982708ab1db888f277d6ec8b9d6
[apple/launchd.git] / launchd / src / launchd_runtime.c
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 static const char *const __rcs_file_version__ = "$Revision: 23929 $";
22
23 #include "config.h"
24 #include "launchd_runtime.h"
25
26 #include <mach/mach.h>
27 #include <mach/mach_error.h>
28 #include <mach/boolean.h>
29 #include <mach/message.h>
30 #include <mach/notify.h>
31 #include <mach/mig_errors.h>
32 #include <mach/mach_traps.h>
33 #include <mach/mach_interface.h>
34 #include <mach/host_info.h>
35 #include <mach/mach_host.h>
36 #include <mach/mach_time.h>
37 #include <mach/exception.h>
38 #include <sys/types.h>
39 #include <sys/stat.h>
40 #include <sys/sysctl.h>
41 #include <sys/time.h>
42 #include <sys/proc.h>
43 #include <sys/event.h>
44 #include <sys/queue.h>
45 #include <sys/socket.h>
46 #include <sys/mount.h>
47 #include <sys/reboot.h>
48 #include <sys/fcntl.h>
49 #include <sys/kdebug.h>
50 #include <bsm/libbsm.h>
51 #include <malloc/malloc.h>
52 #include <unistd.h>
53 #include <pthread.h>
54 #include <errno.h>
55 #include <string.h>
56 #include <ctype.h>
57 #include <stdio.h>
58 #include <stdlib.h>
59 #include <stdbool.h>
60 #include <syslog.h>
61 #include <signal.h>
62 #include <dlfcn.h>
63
64 #include "launchd_internalServer.h"
65 #include "launchd_internal.h"
66 #include "notifyServer.h"
67 #include "mach_excServer.h"
68
69 /* We shouldn't be including these */
70 #include "launch.h"
71 #include "launchd.h"
72 #include "launchd_core_logic.h"
73 #include "vproc.h"
74 #include "vproc_priv.h"
75 #include "vproc_internal.h"
76 #include "protocol_job_reply.h"
77
78 static mach_port_t ipc_port_set;
79 static mach_port_t demand_port_set;
80 static mach_port_t launchd_internal_port;
81 static int mainkq;
82
83 #define BULK_KEV_MAX 100
84 static struct kevent *bulk_kev;
85 static int bulk_kev_i;
86 static int bulk_kev_cnt;
87
88 static pthread_t kqueue_demand_thread;
89
90 static void mportset_callback(void);
91 static kq_callback kqmportset_callback = (kq_callback)mportset_callback;
92 static void *kqueue_demand_loop(void *arg);
93
94 boolean_t launchd_internal_demux(mach_msg_header_t *Request, mach_msg_header_t *Reply);
95 static void record_caller_creds(mach_msg_header_t *mh);
96 static void launchd_runtime2(mach_msg_size_t msg_size, mig_reply_error_t *bufRequest, mig_reply_error_t *bufReply);
97 static mach_msg_size_t max_msg_size;
98 static mig_callback *mig_cb_table;
99 static size_t mig_cb_table_sz;
100 static timeout_callback runtime_idle_callback;
101 static mach_msg_timeout_t runtime_idle_timeout;
102 static struct ldcred ldc;
103 static size_t runtime_busy_cnt;
104 static size_t runtime_standby_cnt;
105
106
107 static STAILQ_HEAD(, logmsg_s) logmsg_queue = STAILQ_HEAD_INITIALIZER(logmsg_queue);
108 static size_t logmsg_queue_sz;
109 static size_t logmsg_queue_cnt;
110 static mach_port_t drain_reply_port;
111 static void runtime_log_uncork_pending_drain(void);
112 static kern_return_t runtime_log_pack(vm_offset_t *outval, mach_msg_type_number_t *outvalCnt);
113
114 static bool logmsg_add(struct runtime_syslog_attr *attr, int err_num, const char *msg);
115 static void logmsg_remove(struct logmsg_s *lm);
116
117 static void do_file_init(void) __attribute__((constructor));
118 static mach_timebase_info_data_t tbi;
119 static uint64_t tbi_safe_math_max;
120 static uint64_t time_of_mach_msg_return;
121 static double tbi_float_val;
122
123 static const int sigigns[] = { SIGHUP, SIGINT, SIGPIPE, SIGALRM, SIGTERM,
124 SIGURG, SIGTSTP, SIGTSTP, SIGCONT, SIGTTIN, SIGTTOU, SIGIO, SIGXCPU,
125 SIGXFSZ, SIGVTALRM, SIGPROF, SIGWINCH, SIGINFO, SIGUSR1, SIGUSR2
126 };
127 static sigset_t sigign_set;
128 static FILE *ourlogfile;
129 bool pid1_magic;
130 bool do_apple_internal_logging;
131 bool low_level_debug;
132 bool g_force_old_kill_path = false;
133 bool g_flat_mach_namespace = true;
134 bool g_simulate_pid1_crash = false;
135 bool g_use_gmalloc = false;
136 bool g_log_per_user_shutdown = false;
137 #if !TARGET_OS_EMBEDDED
138 bool g_log_pid1_shutdown = true;
139 #else
140 bool g_log_pid1_shutdown = false;
141 #endif
142 bool g_log_strict_usage = false;
143 pid_t g_wsp = 0;
144
145 mach_port_t
146 runtime_get_kernel_port(void)
147 {
148 return launchd_internal_port;
149 }
150
151 // static const char *__crashreporter_info__ = "";
152
153 static int internal_mask_pri = LOG_UPTO(LOG_NOTICE);
154
155
156 void
157 launchd_runtime_init(void)
158 {
159 mach_msg_size_t mxmsgsz;
160 pid_t p = getpid();
161
162 launchd_assert((mainkq = kqueue()) != -1);
163
164 launchd_assert((errno = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_PORT_SET, &demand_port_set)) == KERN_SUCCESS);
165 launchd_assert((errno = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_PORT_SET, &ipc_port_set)) == KERN_SUCCESS);
166
167 launchd_assert(kevent_mod(demand_port_set, EVFILT_MACHPORT, EV_ADD, 0, 0, &kqmportset_callback) != -1);
168
169 launchd_assert(launchd_mport_create_recv(&launchd_internal_port) == KERN_SUCCESS);
170 launchd_assert(launchd_mport_make_send(launchd_internal_port) == KERN_SUCCESS);
171
172 /* Sigh... at the moment, MIG has maxsize == sizeof(reply union) */
173 mxmsgsz = sizeof(union __RequestUnion__x_launchd_internal_subsystem);
174 if (x_launchd_internal_subsystem.maxsize > mxmsgsz) {
175 mxmsgsz = x_launchd_internal_subsystem.maxsize;
176 }
177
178 launchd_assert(runtime_add_mport(launchd_internal_port, launchd_internal_demux, mxmsgsz) == KERN_SUCCESS);
179 launchd_assert(pthread_create(&kqueue_demand_thread, NULL, kqueue_demand_loop, NULL) == 0);
180 launchd_assert(pthread_detach(kqueue_demand_thread) == 0);
181
182 launchd_assumes(sysctlbyname("vfs.generic.noremotehang", NULL, NULL, &p, sizeof(p)) != -1);
183 }
184
185 void
186 launchd_runtime_init2(void)
187 {
188 size_t i;
189
190 for (i = 0; i < (sizeof(sigigns) / sizeof(int)); i++) {
191 sigaddset(&sigign_set, sigigns[i]);
192 launchd_assumes(signal(sigigns[i], SIG_IGN) != SIG_ERR);
193 }
194 }
195
196 const char *
197 proc_flags_to_C_names(unsigned int flags)
198 {
199 #define MAX_PFLAG_STR "P_ADVLOCK|P_CONTROLT|P_LP64|P_NOCLDSTOP|P_PPWAIT|P_PROFIL|P_SELECT|P_CONTINUED|P_SUGID|P_SYSTEM|P_TIMEOUT|P_TRACED|P_RESV3|P_WEXIT|P_EXEC|P_OWEUPC|P_AFFINITY|P_TRANSLATED|P_RESV5|P_CHECKOPENEVT|P_DEPENDENCY_CAPABLE|P_REBOOT|P_TBE|P_RESV7|P_THCWD|P_RESV9|P_RESV10|P_RESV11|P_NOSHLIB|P_FORCEQUOTA|P_NOCLDWAIT|P_NOREMOTEHANG|0xdeadbeeffeedface"
200
201 static char flags_buf[sizeof(MAX_PFLAG_STR)];
202 char *flags_off = NULL;
203
204 if (!flags) {
205 return "";
206 }
207
208 while (flags) {
209 if (flags_off) {
210 *flags_off = '|';
211 flags_off++;
212 *flags_off = '\0';
213 } else {
214 flags_off = flags_buf;
215 }
216
217 #define FLAGIF(f) if (flags & f) { flags_off += sprintf(flags_off, #f); flags &= ~f; }
218
219 FLAGIF(P_ADVLOCK)
220 else FLAGIF(P_CONTROLT)
221 else FLAGIF(P_LP64)
222 else FLAGIF(P_NOCLDSTOP)
223 else FLAGIF(P_PPWAIT)
224 else FLAGIF(P_PROFIL)
225 else FLAGIF(P_SELECT)
226 else FLAGIF(P_CONTINUED)
227 else FLAGIF(P_SUGID)
228 else FLAGIF(P_SYSTEM)
229 else FLAGIF(P_TIMEOUT)
230 else FLAGIF(P_TRACED)
231 else FLAGIF(P_RESV3)
232 else FLAGIF(P_WEXIT)
233 else FLAGIF(P_EXEC)
234 else FLAGIF(P_OWEUPC)
235 else FLAGIF(P_AFFINITY)
236 else FLAGIF(P_TRANSLATED)
237 else FLAGIF(P_RESV5)
238 else FLAGIF(P_CHECKOPENEVT)
239 else FLAGIF(P_DEPENDENCY_CAPABLE)
240 else FLAGIF(P_REBOOT)
241 else FLAGIF(P_TBE)
242 else FLAGIF(P_RESV7)
243 else FLAGIF(P_THCWD)
244 else FLAGIF(P_RESV9)
245 else FLAGIF(P_RESV10)
246 else FLAGIF(P_RESV11)
247 else FLAGIF(P_NOSHLIB)
248 else FLAGIF(P_FORCEQUOTA)
249 else FLAGIF(P_NOCLDWAIT)
250 else FLAGIF(P_NOREMOTEHANG)
251 else {
252 flags_off += sprintf(flags_off, "0x%x", flags);
253 flags = 0;
254 }
255 }
256
257 return flags_buf;
258 }
259
260 const char *
261 reboot_flags_to_C_names(unsigned int flags)
262 {
263 #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"
264 static char flags_buf[sizeof(MAX_RB_STR)];
265 char *flags_off = NULL;
266
267 if (flags == 0) {
268 return "RB_AUTOBOOT";
269 }
270
271 while (flags) {
272 if (flags_off) {
273 *flags_off = '|';
274 flags_off++;
275 *flags_off = '\0';
276 } else {
277 flags_off = flags_buf;
278 }
279
280 FLAGIF(RB_ASKNAME)
281 else FLAGIF(RB_SINGLE)
282 else FLAGIF(RB_NOSYNC)
283 else FLAGIF(RB_HALT)
284 else FLAGIF(RB_INITNAME)
285 else FLAGIF(RB_DFLTROOT)
286 else FLAGIF(RB_ALTBOOT)
287 else FLAGIF(RB_UNIPROC)
288 else FLAGIF(RB_SAFEBOOT)
289 else FLAGIF(RB_UPSDELAY)
290 else {
291 flags_off += sprintf(flags_off, "0x%x", flags);
292 flags = 0;
293 }
294 }
295
296 return flags_buf;
297 }
298
299 const char *
300 signal_to_C_name(unsigned int sig)
301 {
302 static char unknown[25];
303
304 #define SIG2CASE(sg) case sg: return #sg
305
306 switch (sig) {
307 SIG2CASE(SIGHUP);
308 SIG2CASE(SIGINT);
309 SIG2CASE(SIGQUIT);
310 SIG2CASE(SIGILL);
311 SIG2CASE(SIGTRAP);
312 SIG2CASE(SIGABRT);
313 SIG2CASE(SIGFPE);
314 SIG2CASE(SIGKILL);
315 SIG2CASE(SIGBUS);
316 SIG2CASE(SIGSEGV);
317 SIG2CASE(SIGSYS);
318 SIG2CASE(SIGPIPE);
319 SIG2CASE(SIGALRM);
320 SIG2CASE(SIGTERM);
321 SIG2CASE(SIGURG);
322 SIG2CASE(SIGSTOP);
323 SIG2CASE(SIGTSTP);
324 SIG2CASE(SIGCONT);
325 SIG2CASE(SIGCHLD);
326 SIG2CASE(SIGTTIN);
327 SIG2CASE(SIGTTOU);
328 SIG2CASE(SIGIO);
329 SIG2CASE(SIGXCPU);
330 SIG2CASE(SIGXFSZ);
331 SIG2CASE(SIGVTALRM);
332 SIG2CASE(SIGPROF);
333 SIG2CASE(SIGWINCH);
334 SIG2CASE(SIGINFO);
335 SIG2CASE(SIGUSR1);
336 SIG2CASE(SIGUSR2);
337 default:
338 snprintf(unknown, sizeof(unknown), "%u", sig);
339 return unknown;
340 }
341 }
342
343 void
344 log_kevent_struct(int level, struct kevent *kev_base, int indx)
345 {
346 struct kevent *kev = &kev_base[indx];
347 const char *filter_str;
348 char ident_buf[100];
349 char filter_buf[100];
350 char fflags_buf[1000];
351 char flags_buf[1000] = "0x0";
352 char *flags_off = NULL;
353 char *fflags_off = NULL;
354 unsigned short flags = kev->flags;
355 unsigned int fflags = kev->fflags;
356
357 if (likely(!(LOG_MASK(level) & internal_mask_pri))) {
358 return;
359 }
360
361 if (flags) while (flags) {
362 if (flags_off) {
363 *flags_off = '|';
364 flags_off++;
365 *flags_off = '\0';
366 } else {
367 flags_off = flags_buf;
368 }
369
370 FLAGIF(EV_ADD)
371 else FLAGIF(EV_RECEIPT)
372 else FLAGIF(EV_DELETE)
373 else FLAGIF(EV_ENABLE)
374 else FLAGIF(EV_DISABLE)
375 else FLAGIF(EV_CLEAR)
376 else FLAGIF(EV_EOF)
377 else FLAGIF(EV_ONESHOT)
378 else FLAGIF(EV_ERROR)
379 else {
380 flags_off += sprintf(flags_off, "0x%hx", flags);
381 flags = 0;
382 }
383 }
384
385 snprintf(ident_buf, sizeof(ident_buf), "%ld", kev->ident);
386 snprintf(fflags_buf, sizeof(fflags_buf), "0x%x", fflags);
387
388 switch (kev->filter) {
389 case EVFILT_READ:
390 filter_str = "EVFILT_READ";
391 break;
392 case EVFILT_WRITE:
393 filter_str = "EVFILT_WRITE";
394 break;
395 case EVFILT_AIO:
396 filter_str = "EVFILT_AIO";
397 break;
398 case EVFILT_VNODE:
399 filter_str = "EVFILT_VNODE";
400 if (fflags) while (fflags) {
401 if (fflags_off) {
402 *fflags_off = '|';
403 fflags_off++;
404 *fflags_off = '\0';
405 } else {
406 fflags_off = fflags_buf;
407 }
408
409 #define FFLAGIF(ff) if (fflags & ff) { fflags_off += sprintf(fflags_off, #ff); fflags &= ~ff; }
410
411 FFLAGIF(NOTE_DELETE)
412 else FFLAGIF(NOTE_WRITE)
413 else FFLAGIF(NOTE_EXTEND)
414 else FFLAGIF(NOTE_ATTRIB)
415 else FFLAGIF(NOTE_LINK)
416 else FFLAGIF(NOTE_RENAME)
417 else FFLAGIF(NOTE_REVOKE)
418 else {
419 fflags_off += sprintf(fflags_off, "0x%x", fflags);
420 fflags = 0;
421 }
422 }
423 break;
424 case EVFILT_PROC:
425 filter_str = "EVFILT_PROC";
426 if (fflags) while (fflags) {
427 if (fflags_off) {
428 *fflags_off = '|';
429 fflags_off++;
430 *fflags_off = '\0';
431 } else {
432 fflags_off = fflags_buf;
433 }
434
435 FFLAGIF(NOTE_EXIT)
436 else FFLAGIF(NOTE_REAP)
437 else FFLAGIF(NOTE_FORK)
438 else FFLAGIF(NOTE_EXEC)
439 else FFLAGIF(NOTE_SIGNAL)
440 else FFLAGIF(NOTE_TRACK)
441 else FFLAGIF(NOTE_TRACKERR)
442 else FFLAGIF(NOTE_CHILD)
443 else {
444 fflags_off += sprintf(fflags_off, "0x%x", fflags);
445 fflags = 0;
446 }
447 }
448 break;
449 case EVFILT_SIGNAL:
450 filter_str = "EVFILT_SIGNAL";
451 strcpy(ident_buf, signal_to_C_name(kev->ident));
452 break;
453 case EVFILT_TIMER:
454 filter_str = "EVFILT_TIMER";
455 snprintf(ident_buf, sizeof(ident_buf), "0x%lx", kev->ident);
456 if (fflags) while (fflags) {
457 if (fflags_off) {
458 *fflags_off = '|';
459 fflags_off++;
460 *fflags_off = '\0';
461 } else {
462 fflags_off = fflags_buf;
463 }
464
465 FFLAGIF(NOTE_SECONDS)
466 else FFLAGIF(NOTE_USECONDS)
467 else FFLAGIF(NOTE_NSECONDS)
468 else FFLAGIF(NOTE_ABSOLUTE)
469 else {
470 fflags_off += sprintf(fflags_off, "0x%x", fflags);
471 fflags = 0;
472 }
473 }
474 break;
475 case EVFILT_MACHPORT:
476 filter_str = "EVFILT_MACHPORT";
477 snprintf(ident_buf, sizeof(ident_buf), "0x%lx", kev->ident);
478 break;
479 case EVFILT_FS:
480 filter_str = "EVFILT_FS";
481 snprintf(ident_buf, sizeof(ident_buf), "0x%lx", kev->ident);
482 if (fflags) while (fflags) {
483 if (fflags_off) {
484 *fflags_off = '|';
485 fflags_off++;
486 *fflags_off = '\0';
487 } else {
488 fflags_off = fflags_buf;
489 }
490
491 FFLAGIF(VQ_NOTRESP)
492 else FFLAGIF(VQ_NEEDAUTH)
493 else FFLAGIF(VQ_LOWDISK)
494 else FFLAGIF(VQ_MOUNT)
495 else FFLAGIF(VQ_UNMOUNT)
496 else FFLAGIF(VQ_DEAD)
497 else FFLAGIF(VQ_ASSIST)
498 else FFLAGIF(VQ_NOTRESPLOCK)
499 else FFLAGIF(VQ_UPDATE)
500 else {
501 fflags_off += sprintf(fflags_off, "0x%x", fflags);
502 fflags = 0;
503 }
504 }
505 break;
506 default:
507 snprintf(filter_buf, sizeof(filter_buf), "%hd", kev->filter);
508 filter_str = filter_buf;
509 break;
510 }
511
512 runtime_syslog(level, "KEVENT[%d]: udata = %p data = 0x%lx ident = %s filter = %s flags = %s fflags = %s",
513 indx, kev->udata, kev->data, ident_buf, filter_str, flags_buf, fflags_buf);
514 }
515
516 void
517 mportset_callback(void)
518 {
519 mach_port_name_array_t members;
520 mach_msg_type_number_t membersCnt;
521 mach_port_status_t status;
522 mach_msg_type_number_t statusCnt;
523 struct kevent kev;
524 unsigned int i;
525
526 if (!launchd_assumes((errno = mach_port_get_set_status(mach_task_self(), demand_port_set, &members, &membersCnt)) == KERN_SUCCESS)) {
527 return;
528 }
529
530 for (i = 0; i < membersCnt; i++) {
531 statusCnt = MACH_PORT_RECEIVE_STATUS_COUNT;
532 if (mach_port_get_attributes(mach_task_self(), members[i], MACH_PORT_RECEIVE_STATUS, (mach_port_info_t)&status,
533 &statusCnt) != KERN_SUCCESS) {
534 continue;
535 }
536 if (status.mps_msgcount) {
537 EV_SET(&kev, members[i], EVFILT_MACHPORT, 0, 0, 0, job_find_by_service_port(members[i]));
538 #if 0
539 if (launchd_assumes(kev.udata != NULL)) {
540 #endif
541 log_kevent_struct(LOG_DEBUG, &kev, i);
542 (*((kq_callback *)kev.udata))(kev.udata, &kev);
543 #if 0
544 } else {
545 log_kevent_struct(LOG_ERR, &kev, i);
546 }
547 #endif
548 /* the callback may have tainted our ability to continue this for loop */
549 break;
550 }
551 }
552
553 launchd_assumes(vm_deallocate(mach_task_self(), (vm_address_t)members,
554 (vm_size_t) membersCnt * sizeof(mach_port_name_t)) == KERN_SUCCESS);
555 }
556
557 void *
558 kqueue_demand_loop(void *arg __attribute__((unused)))
559 {
560 fd_set rfds;
561
562 /*
563 * Yes, at first glance, calling select() on a kqueue seems silly.
564 *
565 * This avoids a race condition between the main thread and this helper
566 * thread by ensuring that we drain kqueue events on the same thread
567 * that manipulates the kqueue.
568 */
569
570 for (;;) {
571 FD_ZERO(&rfds);
572 FD_SET(mainkq, &rfds);
573 if (launchd_assumes(select(mainkq + 1, &rfds, NULL, NULL, NULL) == 1)) {
574 launchd_assumes(handle_kqueue(launchd_internal_port, mainkq) == 0);
575 }
576 }
577
578 return NULL;
579 }
580
581 kern_return_t
582 x_handle_kqueue(mach_port_t junk __attribute__((unused)), integer_t fd)
583 {
584 struct timespec ts = { 0, 0 };
585 struct kevent *kevi, kev[BULK_KEV_MAX];
586 int i;
587
588 bulk_kev = kev;
589
590 if (launchd_assumes((bulk_kev_cnt = kevent(fd, NULL, 0, kev, BULK_KEV_MAX, &ts)) != -1)) {
591 #if 0
592 for (i = 0; i < bulk_kev_cnt; i++) {
593 log_kevent_struct(LOG_DEBUG, kev, i);
594 }
595 #endif
596 for (i = 0; i < bulk_kev_cnt; i++) {
597 bulk_kev_i = i;
598 kevi = &kev[i];
599
600 if (kevi->filter) {
601 runtime_syslog(LOG_DEBUG, "Dispatching kevent...");
602 log_kevent_struct(LOG_DEBUG, kev, i);
603 #if 0
604 /* Check if kevi->udata was either malloc(3)ed or is a valid function pointer.
605 * If neither, it's probably an invalid pointer and we should log it.
606 */
607 Dl_info dli;
608 if (launchd_assumes(malloc_size(kevi->udata) || dladdr(kevi->udata, &dli))) {
609 runtime_ktrace(RTKT_LAUNCHD_BSD_KEVENT|DBG_FUNC_START, kevi->ident, kevi->filter, kevi->fflags);
610 (*((kq_callback *)kevi->udata))(kevi->udata, kevi);
611 runtime_ktrace0(RTKT_LAUNCHD_BSD_KEVENT|DBG_FUNC_END);
612 } else {
613 runtime_syslog(LOG_ERR, "The following kevent had invalid context data.");
614 log_kevent_struct(LOG_EMERG, kevi, i);
615 }
616 #else
617 runtime_ktrace(RTKT_LAUNCHD_BSD_KEVENT|DBG_FUNC_START, kevi->ident, kevi->filter, kevi->fflags);
618 (*((kq_callback *)kevi->udata))(kevi->udata, kevi);
619 runtime_ktrace0(RTKT_LAUNCHD_BSD_KEVENT|DBG_FUNC_END);
620 #endif
621 }
622 }
623 }
624
625 bulk_kev = NULL;
626
627 return 0;
628 }
629
630 void
631 launchd_runtime(void)
632 {
633 mig_reply_error_t *req = NULL, *resp = NULL;
634 mach_msg_size_t mz = max_msg_size;
635 int flags = VM_MAKE_TAG(VM_MEMORY_MACH_MSG)|TRUE;
636
637 for (;;) {
638 if (likely(req)) {
639 launchd_assumes(vm_deallocate(mach_task_self(), (vm_address_t)req, mz) == KERN_SUCCESS);
640 req = NULL;
641 }
642 if (likely(resp)) {
643 launchd_assumes(vm_deallocate(mach_task_self(), (vm_address_t)resp, mz) == KERN_SUCCESS);
644 resp = NULL;
645 }
646
647 mz = max_msg_size;
648
649 if (!launchd_assumes(vm_allocate(mach_task_self(), (vm_address_t *)&req, mz, flags) == KERN_SUCCESS)) {
650 continue;
651 }
652 if (!launchd_assumes(vm_allocate(mach_task_self(), (vm_address_t *)&resp, mz, flags) == KERN_SUCCESS)) {
653 continue;
654 }
655
656 launchd_runtime2(mz, req, resp);
657
658 /* If we get here, max_msg_size probably changed... */
659 }
660 }
661
662 kern_return_t
663 launchd_set_bport(mach_port_t name)
664 {
665 return errno = task_set_bootstrap_port(mach_task_self(), name);
666 }
667
668 kern_return_t
669 launchd_get_bport(mach_port_t *name)
670 {
671 return errno = task_get_bootstrap_port(mach_task_self(), name);
672 }
673
674 kern_return_t
675 launchd_mport_notify_req(mach_port_t name, mach_msg_id_t which)
676 {
677 mach_port_mscount_t msgc = (which == MACH_NOTIFY_PORT_DESTROYED) ? 0 : 1;
678 mach_port_t previous, where = (which == MACH_NOTIFY_NO_SENDERS) ? name : launchd_internal_port;
679
680 if (which == MACH_NOTIFY_NO_SENDERS) {
681 /* Always make sure the send count is zero, in case a receive right is reused */
682 errno = mach_port_set_mscount(mach_task_self(), name, 0);
683 if (unlikely(errno != KERN_SUCCESS)) {
684 return errno;
685 }
686 }
687
688 errno = mach_port_request_notification(mach_task_self(), name, which, msgc, where,
689 MACH_MSG_TYPE_MAKE_SEND_ONCE, &previous);
690
691 if (likely(errno == 0) && previous != MACH_PORT_NULL) {
692 launchd_assumes(launchd_mport_deallocate(previous) == KERN_SUCCESS);
693 }
694
695 return errno;
696 }
697
698 pid_t
699 runtime_fork(mach_port_t bsport)
700 {
701 sigset_t emptyset, oset;
702 pid_t r = -1;
703 int saved_errno;
704 size_t i;
705
706 sigemptyset(&emptyset);
707
708 launchd_assumes(launchd_mport_make_send(bsport) == KERN_SUCCESS);
709 launchd_assumes(launchd_set_bport(bsport) == KERN_SUCCESS);
710 launchd_assumes(launchd_mport_deallocate(bsport) == KERN_SUCCESS);
711
712 launchd_assumes(sigprocmask(SIG_BLOCK, &sigign_set, &oset) != -1);
713 for (i = 0; i < (sizeof(sigigns) / sizeof(int)); i++) {
714 launchd_assumes(signal(sigigns[i], SIG_DFL) != SIG_ERR);
715 }
716
717 r = fork();
718 saved_errno = errno;
719
720 if (r != 0) {
721 for (i = 0; i < (sizeof(sigigns) / sizeof(int)); i++) {
722 launchd_assumes(signal(sigigns[i], SIG_IGN) != SIG_ERR);
723 }
724 launchd_assumes(sigprocmask(SIG_SETMASK, &oset, NULL) != -1);
725 launchd_assumes(launchd_set_bport(MACH_PORT_NULL) == KERN_SUCCESS);
726 } else {
727 pid_t p = -getpid();
728 launchd_assumes(sysctlbyname("vfs.generic.noremotehang", NULL, NULL, &p, sizeof(p)) != -1);
729
730 launchd_assumes(sigprocmask(SIG_SETMASK, &emptyset, NULL) != -1);
731 }
732
733 errno = saved_errno;
734
735 return r;
736 }
737
738
739 void
740 runtime_set_timeout(timeout_callback to_cb, unsigned int sec)
741 {
742 if (sec == 0 || to_cb == NULL) {
743 runtime_idle_callback = NULL;
744 runtime_idle_timeout = 0;
745 }
746
747 runtime_idle_callback = to_cb;
748 runtime_idle_timeout = sec * 1000;
749 }
750
751 kern_return_t
752 runtime_add_mport(mach_port_t name, mig_callback demux, mach_msg_size_t msg_size)
753 {
754 size_t needed_table_sz = (MACH_PORT_INDEX(name) + 1) * sizeof(mig_callback);
755 mach_port_t target_set = demux ? ipc_port_set : demand_port_set;
756
757 msg_size = round_page(msg_size + MAX_TRAILER_SIZE);
758
759 if (unlikely(needed_table_sz > mig_cb_table_sz)) {
760 needed_table_sz *= 2; /* Let's try and avoid realloc'ing for a while */
761 mig_callback *new_table = malloc(needed_table_sz);
762
763 if (!launchd_assumes(new_table != NULL)) {
764 return KERN_RESOURCE_SHORTAGE;
765 }
766
767 if (likely(mig_cb_table)) {
768 memcpy(new_table, mig_cb_table, mig_cb_table_sz);
769 free(mig_cb_table);
770 }
771
772 mig_cb_table_sz = needed_table_sz;
773 mig_cb_table = new_table;
774 }
775
776 mig_cb_table[MACH_PORT_INDEX(name)] = demux;
777
778 if (msg_size > max_msg_size) {
779 max_msg_size = msg_size;
780 }
781
782 return errno = mach_port_move_member(mach_task_self(), name, target_set);
783 }
784
785 kern_return_t
786 runtime_remove_mport(mach_port_t name)
787 {
788 mig_cb_table[MACH_PORT_INDEX(name)] = NULL;
789
790 return errno = mach_port_move_member(mach_task_self(), name, MACH_PORT_NULL);
791 }
792
793 kern_return_t
794 launchd_mport_make_send(mach_port_t name)
795 {
796 return errno = mach_port_insert_right(mach_task_self(), name, name, MACH_MSG_TYPE_MAKE_SEND);
797 }
798
799 kern_return_t
800 launchd_mport_copy_send(mach_port_t name)
801 {
802 return errno = mach_port_insert_right(mach_task_self(), name, name, MACH_MSG_TYPE_COPY_SEND);
803 }
804
805 kern_return_t
806 launchd_mport_close_recv(mach_port_t name)
807 {
808 return errno = mach_port_mod_refs(mach_task_self(), name, MACH_PORT_RIGHT_RECEIVE, -1);
809 }
810
811 kern_return_t
812 launchd_mport_create_recv(mach_port_t *name)
813 {
814 return errno = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, name);
815 }
816
817 kern_return_t
818 launchd_mport_deallocate(mach_port_t name)
819 {
820 return errno = mach_port_deallocate(mach_task_self(), name);
821 }
822
823 int
824 kevent_bulk_mod(struct kevent *kev, size_t kev_cnt)
825 {
826 size_t i;
827
828 for (i = 0; i < kev_cnt; i++) {
829 kev[i].flags |= EV_CLEAR|EV_RECEIPT;
830 }
831
832 return kevent(mainkq, kev, kev_cnt, kev, kev_cnt, NULL);
833 }
834
835 int
836 kevent_mod(uintptr_t ident, short filter, u_short flags, u_int fflags, intptr_t data, void *udata)
837 {
838 struct kevent kev;
839 int r;
840
841 switch (filter) {
842 case EVFILT_READ:
843 case EVFILT_WRITE:
844 break;
845 case EVFILT_TIMER:
846 /* Workaround 5225889 */
847 if (flags & EV_ADD) {
848 kevent_mod(ident, EVFILT_TIMER, EV_DELETE, 0, 0, NULL);
849 }
850 /* fall through */
851 default:
852 flags |= EV_CLEAR;
853 break;
854 }
855
856 flags |= EV_RECEIPT;
857
858 if (flags & EV_ADD && !launchd_assumes(udata != NULL)) {
859 errno = EINVAL;
860 return -1;
861 } else if( (flags & EV_DELETE) && bulk_kev ) {
862 int i = 0;
863 for( i = bulk_kev_i + 1; i < bulk_kev_cnt; i++ ) {
864 if( bulk_kev[i].filter == filter && bulk_kev[i].ident == ident ) {
865 runtime_syslog(LOG_DEBUG, "Pruning the following kevent:");
866 log_kevent_struct(LOG_DEBUG, &bulk_kev[i], i);
867 bulk_kev[i].filter = (short)0;
868 }
869 }
870 }
871
872 EV_SET(&kev, ident, filter, flags, fflags, data, udata);
873
874 r = kevent(mainkq, &kev, 1, &kev, 1, NULL);
875
876 if (!launchd_assumes(r == 1)) {
877 return -1;
878 }
879
880 if (launchd_assumes(kev.flags & EV_ERROR)) {
881 if ((flags & EV_ADD) && kev.data) {
882 runtime_syslog(LOG_DEBUG, "%s(): See the next line...", __func__);
883 log_kevent_struct(LOG_DEBUG, &kev, 0);
884 errno = kev.data;
885 return -1;
886 }
887 }
888
889 return r;
890 }
891
892 boolean_t
893 launchd_internal_demux(mach_msg_header_t *Request, mach_msg_header_t *Reply)
894 {
895 if (launchd_internal_server_routine(Request)) {
896 return launchd_internal_server(Request, Reply);
897 } else if (notify_server_routine(Request)) {
898 return notify_server(Request, Reply);
899 } else {
900 return mach_exc_server(Request, Reply);
901 }
902 }
903
904 kern_return_t
905 do_mach_notify_port_destroyed(mach_port_t notify __attribute__((unused)), mach_port_t rights)
906 {
907 /* This message is sent to us when a receive right is returned to us. */
908
909 if (!launchd_assumes(job_ack_port_destruction(rights))) {
910 launchd_assumes(launchd_mport_close_recv(rights) == KERN_SUCCESS);
911 }
912
913 return KERN_SUCCESS;
914 }
915
916 kern_return_t
917 do_mach_notify_port_deleted(mach_port_t notify __attribute__((unused)), mach_port_name_t name __attribute__((unused)))
918 {
919 /* If we deallocate/destroy/mod_ref away a port with a pending
920 * notification, the original notification message is replaced with
921 * this message. To quote a Mach kernel expert, "the kernel has a
922 * send-once right that has to be used somehow."
923 */
924 return KERN_SUCCESS;
925 }
926
927 kern_return_t
928 do_mach_notify_no_senders(mach_port_t notify, mach_port_mscount_t mscount __attribute__((unused)))
929 {
930 job_t j = job_mig_intran(notify);
931
932 /* This message is sent to us when the last customer of one of our
933 * objects goes away.
934 */
935
936 if (!launchd_assumes(j != NULL)) {
937 return KERN_FAILURE;
938 }
939
940 job_ack_no_senders(j);
941
942 return KERN_SUCCESS;
943 }
944
945 kern_return_t
946 do_mach_notify_send_once(mach_port_t notify __attribute__((unused)))
947 {
948 /*
949 * This message is sent for each send-once right that is deallocated
950 * without being used.
951 */
952
953 return KERN_SUCCESS;
954 }
955
956 kern_return_t
957 do_mach_notify_dead_name(mach_port_t notify __attribute__((unused)), mach_port_name_t name)
958 {
959 /* This message is sent to us when one of our send rights no longer has
960 * a receiver somewhere else on the system.
961 */
962
963 if (name == drain_reply_port) {
964 launchd_assumes(launchd_mport_deallocate(name) == KERN_SUCCESS);
965 drain_reply_port = MACH_PORT_NULL;
966 }
967
968 if (launchd_assumes(root_jobmgr != NULL)) {
969 root_jobmgr = jobmgr_delete_anything_with_port(root_jobmgr, name);
970 }
971
972 /* A dead-name notification about a port appears to increment the
973 * rights on said port. Let's deallocate it so that we don't leak
974 * dead-name ports.
975 */
976 launchd_assumes(launchd_mport_deallocate(name) == KERN_SUCCESS);
977
978 return KERN_SUCCESS;
979 }
980
981 void
982 record_caller_creds(mach_msg_header_t *mh)
983 {
984 mach_msg_max_trailer_t *tp;
985 size_t trailer_size;
986
987 tp = (mach_msg_max_trailer_t *)((vm_offset_t)mh + round_msg(mh->msgh_size));
988
989 trailer_size = tp->msgh_trailer_size - (mach_msg_size_t)(sizeof(mach_msg_trailer_type_t) - sizeof(mach_msg_trailer_size_t));
990
991 if (launchd_assumes(trailer_size >= (mach_msg_size_t)sizeof(audit_token_t))) {
992 audit_token_to_au32(tp->msgh_audit, /* audit UID */ NULL, &ldc.euid,
993 &ldc.egid, &ldc.uid, &ldc.gid, &ldc.pid,
994 /* au_asid_t */ NULL, /* au_tid_t */ NULL);
995 }
996
997 }
998
999 struct ldcred *
1000 runtime_get_caller_creds(void)
1001 {
1002 return &ldc;
1003 }
1004
1005 mach_msg_return_t
1006 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)
1007 {
1008 mach_msg_return_t mr = ~MACH_MSG_SUCCESS;
1009 mach_msg_option_t rcv_options = MACH_RCV_MSG |
1010 MACH_RCV_TIMEOUT |
1011 MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT) |
1012 MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0) ;
1013
1014 do {
1015 mr = mach_msg(&bufRequest->Head, rcv_options, 0, rcv_msg_size, port, to, MACH_PORT_NULL);
1016 switch( mr ) {
1017 case MACH_RCV_TIMED_OUT :
1018 runtime_syslog(LOG_DEBUG, "Message queue is empty.");
1019 break;
1020 case MACH_RCV_TOO_LARGE :
1021 runtime_syslog(LOG_INFO, "Message is larger than %u bytes.", rcv_msg_size);
1022 break;
1023 default :
1024 launchd_assumes(mr == MACH_MSG_SUCCESS);
1025 }
1026
1027 if( mr == MACH_MSG_SUCCESS ) {
1028 if( !launchd_assumes(mach_exc_server(&bufRequest->Head, &bufReply->Head) == TRUE) ) {
1029 runtime_syslog(LOG_WARNING, "Exception server routine failed.");
1030 break;
1031 }
1032
1033 mach_msg_return_t smr = ~MACH_MSG_SUCCESS;
1034 mach_msg_option_t send_options = MACH_SEND_MSG |
1035 MACH_SEND_TIMEOUT ;
1036
1037 launchd_assumes(bufReply->Head.msgh_size <= send_msg_size);
1038 smr = mach_msg(&bufReply->Head, send_options, bufReply->Head.msgh_size, 0, MACH_PORT_NULL, to + 100, MACH_PORT_NULL);
1039 switch( smr ) {
1040 case MACH_SEND_TIMED_OUT :
1041 runtime_syslog(LOG_WARNING, "Timed out while trying to send reply to exception message.");
1042 break;
1043 case MACH_SEND_INVALID_DEST :
1044 runtime_syslog(LOG_WARNING, "Tried sending a message to a port that we don't possess a send right to.");
1045 break;
1046 default :
1047 if( !launchd_assumes(smr == MACH_MSG_SUCCESS) ) {
1048 runtime_syslog(LOG_WARNING, "Couldn't deliver exception reply: 0x%x", smr);
1049 }
1050 break;
1051 }
1052 }
1053 } while( 0 );
1054
1055 return mr;
1056 }
1057
1058 void
1059 launchd_runtime2(mach_msg_size_t msg_size, mig_reply_error_t *bufRequest, mig_reply_error_t *bufReply)
1060 {
1061 mach_msg_options_t options, tmp_options;
1062 mig_reply_error_t *bufTemp;
1063 mig_callback the_demux;
1064 mach_msg_timeout_t to;
1065 mach_msg_return_t mr;
1066 size_t busy_cnt;
1067
1068 options = MACH_RCV_MSG|MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT) |
1069 MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0);
1070
1071 tmp_options = options;
1072
1073 for (;;) {
1074 busy_cnt = runtime_busy_cnt + runtime_standby_cnt;
1075 to = MACH_MSG_TIMEOUT_NONE;
1076
1077 if (unlikely(msg_size != max_msg_size)) {
1078 /* The buffer isn't big enough to receive messages anymore... */
1079 tmp_options &= ~MACH_RCV_MSG;
1080 options &= ~MACH_RCV_MSG;
1081 if (!(tmp_options & MACH_SEND_MSG)) {
1082 return;
1083 }
1084 }
1085
1086 if ((tmp_options & MACH_RCV_MSG) && (runtime_idle_callback || (busy_cnt == 0))) {
1087 tmp_options |= MACH_RCV_TIMEOUT;
1088
1089 if (!(tmp_options & MACH_SEND_TIMEOUT)) {
1090 #if !TARGET_OS_EMBEDDED
1091 to = busy_cnt ? runtime_idle_timeout : (_vproc_standby_timeout() * 1000);
1092 #else
1093 to = runtime_idle_timeout;
1094 #endif
1095 }
1096 }
1097
1098 runtime_log_push();
1099
1100 mr = mach_msg(&bufReply->Head, tmp_options, bufReply->Head.msgh_size,
1101 msg_size, ipc_port_set, to, MACH_PORT_NULL);
1102
1103 time_of_mach_msg_return = runtime_get_opaque_time();
1104
1105 tmp_options = options;
1106
1107 /* It looks like the compiler doesn't optimize switch(unlikely(...)) See: 5691066 */
1108 if (unlikely(mr)) switch (mr) {
1109 case MACH_SEND_INVALID_DEST:
1110 case MACH_SEND_TIMED_OUT:
1111 /* We need to clean up and start over. */
1112 if (bufReply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) {
1113 mach_msg_destroy(&bufReply->Head);
1114 }
1115 continue;
1116 case MACH_RCV_TIMED_OUT:
1117 if (to != MACH_MSG_TIMEOUT_NONE) {
1118 if (busy_cnt == 0) {
1119 runtime_syslog(LOG_INFO, "Idle exiting.");
1120 launchd_shutdown();
1121 } else if (runtime_idle_callback) {
1122 runtime_idle_callback();
1123 }
1124 }
1125 continue;
1126 default:
1127 if( !launchd_assumes(mr == MACH_MSG_SUCCESS) ) {
1128 runtime_syslog(LOG_ERR, "mach_msg(): %u: %s", mr, mach_error_string(mr));
1129 }
1130 continue;
1131 }
1132
1133 bufTemp = bufRequest;
1134 bufRequest = bufReply;
1135 bufReply = bufTemp;
1136
1137 if (unlikely(!(tmp_options & MACH_RCV_MSG))) {
1138 continue;
1139 }
1140
1141 /* we have another request message */
1142 #if 0
1143 if (!launchd_assumes(mig_cb_table != NULL)) {
1144 break;
1145 }
1146 #endif
1147
1148 the_demux = mig_cb_table[MACH_PORT_INDEX(bufRequest->Head.msgh_local_port)];
1149
1150 #if 0
1151 if (!launchd_assumes(the_demux != NULL)) {
1152 break;
1153 }
1154 #endif
1155
1156 record_caller_creds(&bufRequest->Head);
1157 runtime_ktrace(RTKT_LAUNCHD_MACH_IPC|DBG_FUNC_START, bufRequest->Head.msgh_local_port, bufRequest->Head.msgh_id, (long)the_demux);
1158
1159 if (the_demux(&bufRequest->Head, &bufReply->Head) == FALSE) {
1160 /* XXX - also gross */
1161 if (likely(bufRequest->Head.msgh_id == MACH_NOTIFY_NO_SENDERS)) {
1162 notify_server(&bufRequest->Head, &bufReply->Head);
1163 }
1164 }
1165
1166 runtime_ktrace(RTKT_LAUNCHD_MACH_IPC|DBG_FUNC_END, bufReply->Head.msgh_remote_port, bufReply->Head.msgh_bits, bufReply->RetCode);
1167
1168 /* bufReply is a union. If MACH_MSGH_BITS_COMPLEX is set, then bufReply->RetCode is assumed to be zero. */
1169 if (!(bufReply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX)) {
1170 if (unlikely(bufReply->RetCode != KERN_SUCCESS)) {
1171 if (likely(bufReply->RetCode == MIG_NO_REPLY)) {
1172 bufReply->Head.msgh_remote_port = MACH_PORT_NULL;
1173 } else if (bufRequest->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) {
1174 /* destroy the request - but not the reply port */
1175 bufRequest->Head.msgh_remote_port = MACH_PORT_NULL;
1176 mach_msg_destroy(&bufRequest->Head);
1177 }
1178 }
1179 }
1180
1181 if (likely(bufReply->Head.msgh_remote_port != MACH_PORT_NULL)) {
1182 tmp_options |= MACH_SEND_MSG;
1183
1184 if (unlikely(MACH_MSGH_BITS_REMOTE(bufReply->Head.msgh_bits) != MACH_MSG_TYPE_MOVE_SEND_ONCE)) {
1185 tmp_options |= MACH_SEND_TIMEOUT;
1186 }
1187 }
1188 }
1189 }
1190
1191 int
1192 runtime_close(int fd)
1193 {
1194 int i;
1195
1196 if (bulk_kev) for (i = bulk_kev_i + 1; i < bulk_kev_cnt; i++) {
1197 switch (bulk_kev[i].filter) {
1198 case EVFILT_VNODE:
1199 case EVFILT_WRITE:
1200 case EVFILT_READ:
1201 if (unlikely((int)bulk_kev[i].ident == fd)) {
1202 runtime_syslog(LOG_DEBUG, "Skipping kevent index: %d", i);
1203 bulk_kev[i].filter = 0;
1204 }
1205 default:
1206 break;
1207 }
1208 }
1209
1210 return close(fd);
1211 }
1212
1213 void
1214 runtime_closelog(void)
1215 {
1216 runtime_log_push();
1217
1218 if (ourlogfile) {
1219 launchd_assumes(fflush(ourlogfile) == 0);
1220 launchd_assumes(runtime_fsync(fileno(ourlogfile)) != -1);
1221 }
1222 }
1223
1224 int
1225 runtime_fsync(int fd)
1226 {
1227 #if 0
1228 if (do_apple_internal_logging) {
1229 return fcntl(fd, F_FULLFSYNC, NULL);
1230 } else {
1231 return fsync(fd);
1232 }
1233 #else
1234 return fsync(fd);
1235 #endif
1236 }
1237
1238 int
1239 runtime_setlogmask(int maskpri)
1240 {
1241 internal_mask_pri = maskpri;
1242
1243 return internal_mask_pri;
1244 }
1245
1246 void
1247 runtime_syslog(int pri, const char *message, ...)
1248 {
1249 struct runtime_syslog_attr attr = {
1250 g_my_label,
1251 g_my_label,
1252 pid1_magic ? "System" : "Background",
1253 pri,
1254 getuid(),
1255 getpid(),
1256 getpid()
1257 };
1258 va_list ap;
1259
1260 va_start(ap, message);
1261 runtime_vsyslog(&attr, message, ap);
1262
1263 va_end(ap);
1264 }
1265
1266 void
1267 runtime_vsyslog(struct runtime_syslog_attr *attr, const char *message, va_list args)
1268 {
1269 int saved_errno = errno;
1270 char newmsg[10000];
1271 bool echo_to_console= false;
1272
1273 if (attr->priority == LOG_APPLEONLY) {
1274 if (do_apple_internal_logging) {
1275 attr->priority = LOG_NOTICE;
1276 } else {
1277 return;
1278 }
1279 } else if( attr->priority == LOG_SCOLDING ) {
1280 attr->priority = g_log_strict_usage ? LOG_NOTICE : LOG_DEBUG;
1281 }
1282
1283 if( attr->priority & LOG_CONSOLE ) {
1284 echo_to_console = true;
1285 attr->priority &= ~LOG_CONSOLE;
1286 }
1287
1288 if (!(LOG_MASK(attr->priority) & internal_mask_pri)) {
1289 return;
1290 }
1291
1292 vsnprintf(newmsg, sizeof(newmsg), message, args);
1293
1294 if( g_console && (unlikely(low_level_debug) || echo_to_console) ) {
1295 fprintf(g_console, "%s %u\t%s %u\t%s\n", attr->from_name, attr->from_pid, attr->about_name, attr->about_pid, newmsg);
1296 }
1297
1298 logmsg_add(attr, saved_errno, newmsg);
1299 }
1300
1301 bool
1302 logmsg_add(struct runtime_syslog_attr *attr, int err_num, const char *msg)
1303 {
1304 size_t lm_sz = sizeof(struct logmsg_s) + strlen(msg) + strlen(attr->from_name) + strlen(attr->about_name) + strlen(attr->session_name) + 4;
1305 char *data_off;
1306 struct logmsg_s *lm;
1307
1308 #define ROUND_TO_64BIT_WORD_SIZE(x) ((x + 7) & ~7)
1309
1310 /* we do this to make the unpacking for the log_drain cause unalignment faults */
1311 lm_sz = ROUND_TO_64BIT_WORD_SIZE(lm_sz);
1312
1313 if (unlikely((lm = calloc(1, lm_sz)) == NULL)) {
1314 return false;
1315 }
1316
1317 data_off = lm->data;
1318
1319 lm->when = runtime_get_wall_time();
1320 lm->from_pid = attr->from_pid;
1321 lm->about_pid = attr->about_pid;
1322 lm->err_num = err_num;
1323 lm->pri = attr->priority;
1324 lm->obj_sz = lm_sz;
1325 lm->msg = data_off;
1326 data_off += sprintf(data_off, "%s", msg) + 1;
1327 lm->from_name = data_off;
1328 data_off += sprintf(data_off, "%s", attr->from_name) + 1;
1329 lm->about_name = data_off;
1330 data_off += sprintf(data_off, "%s", attr->about_name) + 1;
1331 lm->session_name = data_off;
1332 data_off += sprintf(data_off, "%s", attr->session_name) + 1;
1333
1334 STAILQ_INSERT_TAIL(&logmsg_queue, lm, sqe);
1335 logmsg_queue_sz += lm_sz;
1336 logmsg_queue_cnt++;
1337
1338 return true;
1339 }
1340
1341 void
1342 logmsg_remove(struct logmsg_s *lm)
1343 {
1344 STAILQ_REMOVE(&logmsg_queue, lm, logmsg_s, sqe);
1345 logmsg_queue_sz -= lm->obj_sz;
1346 logmsg_queue_cnt--;
1347
1348 free(lm);
1349 }
1350
1351 kern_return_t
1352 runtime_log_pack(vm_offset_t *outval, mach_msg_type_number_t *outvalCnt)
1353 {
1354 struct logmsg_s *lm;
1355 void *offset;
1356
1357 *outvalCnt = logmsg_queue_sz;
1358
1359 mig_allocate(outval, *outvalCnt);
1360
1361 if (unlikely(*outval == 0)) {
1362 return 1;
1363 }
1364
1365 offset = (void *)*outval;
1366
1367 if( g_log_per_user_shutdown && !ourlogfile && !pid1_magic && shutdown_in_progress ) {
1368 char logfile[NAME_MAX];
1369 snprintf(logfile, sizeof(logfile), "/var/tmp/launchd-%s.shutdown.log", g_username);
1370
1371 char logfile1[NAME_MAX];
1372 snprintf(logfile1, sizeof(logfile1), "/var/tmp/launchd-%s.shutdown.log.1", g_username);
1373
1374 rename(logfile, logfile1);
1375 ourlogfile = fopen(logfile, "a");
1376 }
1377
1378 static int64_t shutdown_start = 0;
1379 if( shutdown_start == 0 ) {
1380 shutdown_start = runtime_get_wall_time();
1381 }
1382
1383 while ((lm = STAILQ_FIRST(&logmsg_queue))) {
1384 int64_t log_delta = lm->when - shutdown_start;
1385 if( !pid1_magic && ourlogfile ) {
1386 fprintf(ourlogfile, "%8lld%6u %-40s%6u %-40s %s\n", log_delta,
1387 lm->from_pid, lm->from_name, lm->about_pid, lm->about_name, lm->msg);
1388 }
1389
1390 lm->from_name_offset = lm->from_name - (char *)lm;
1391 lm->about_name_offset = lm->about_name - (char *)lm;
1392 lm->msg_offset = lm->msg - (char *)lm;
1393 lm->session_name_offset = lm->session_name - (char *)lm;
1394
1395 memcpy(offset, lm, lm->obj_sz);
1396
1397 offset += lm->obj_sz;
1398
1399 logmsg_remove(lm);
1400 }
1401
1402 if( ourlogfile ) {
1403 fflush(ourlogfile);
1404 }
1405
1406 return 0;
1407 }
1408
1409 void
1410 runtime_log_uncork_pending_drain(void)
1411 {
1412 mach_msg_type_number_t outvalCnt;
1413 mach_port_t tmp_port;
1414 vm_offset_t outval;
1415
1416 if (!drain_reply_port) {
1417 return;
1418 }
1419
1420 if (logmsg_queue_cnt == 0) {
1421 return;
1422 }
1423
1424 if (runtime_log_pack(&outval, &outvalCnt) != 0) {
1425 return;
1426 }
1427
1428 tmp_port = drain_reply_port;
1429 drain_reply_port = MACH_PORT_NULL;
1430
1431 if (unlikely(errno = job_mig_log_drain_reply(tmp_port, 0, outval, outvalCnt))) {
1432 launchd_assumes(errno == MACH_SEND_INVALID_DEST);
1433 launchd_assumes(launchd_mport_deallocate(tmp_port) == KERN_SUCCESS);
1434 }
1435
1436 mig_deallocate(outval, outvalCnt);
1437 }
1438
1439 void
1440 runtime_log_push(void)
1441 {
1442 static pthread_mutex_t ourlock = PTHREAD_MUTEX_INITIALIZER;
1443 static int64_t shutdown_start, log_delta;
1444 mach_msg_type_number_t outvalCnt;
1445 struct logmsg_s *lm;
1446 vm_offset_t outval;
1447
1448 if (logmsg_queue_cnt == 0) {
1449 launchd_assumes(STAILQ_EMPTY(&logmsg_queue));
1450 return;
1451 } else if (!pid1_magic) {
1452 if (runtime_log_pack(&outval, &outvalCnt) == 0) {
1453 launchd_assumes(_vprocmgr_log_forward(inherited_bootstrap_port, (void *)outval, outvalCnt) == NULL);
1454 mig_deallocate(outval, outvalCnt);
1455 }
1456 return;
1457 }
1458
1459 if (likely(!shutdown_in_progress && !fake_shutdown_in_progress)) {
1460 runtime_log_uncork_pending_drain();
1461 return;
1462 }
1463
1464 if (unlikely(shutdown_start == 0)) {
1465 shutdown_start = runtime_get_wall_time();
1466 launchd_log_vm_stats();
1467 }
1468
1469 pthread_mutex_lock(&ourlock);
1470
1471 if( unlikely(ourlogfile == NULL) && g_log_pid1_shutdown ) {
1472 rename("/var/log/launchd-shutdown.log", "/var/log/launchd-shutdown.log.1");
1473 ourlogfile = fopen("/var/log/launchd-shutdown.log", "a");
1474 }
1475
1476 pthread_mutex_unlock(&ourlock);
1477
1478 if (unlikely(!ourlogfile)) {
1479 return;
1480 }
1481
1482 while ((lm = STAILQ_FIRST(&logmsg_queue))) {
1483 log_delta = lm->when - shutdown_start;
1484
1485 fprintf(ourlogfile, "%8lld%6u %-40s%6u %-40s %s\n", log_delta,
1486 lm->from_pid, lm->from_name, lm->about_pid, lm->about_name, lm->msg);
1487
1488 logmsg_remove(lm);
1489 }
1490
1491 fflush(ourlogfile);
1492 }
1493
1494 kern_return_t
1495 runtime_log_forward(uid_t forward_uid, gid_t forward_gid, vm_offset_t inval, mach_msg_type_number_t invalCnt)
1496 {
1497 struct logmsg_s *lm, *lm_walk;
1498 mach_msg_type_number_t data_left = invalCnt;
1499
1500 if (inval == 0) {
1501 return 0;
1502 }
1503
1504 for (lm_walk = (struct logmsg_s *)inval; (data_left > 0) && (lm_walk->obj_sz <= data_left); lm_walk = ((void *)lm_walk + lm_walk->obj_sz)) {
1505 /* malloc() does not return NULL if you ask it for an allocation of size 0.
1506 * It will return a valid pointer that can be passed to free(). If we don't
1507 * do this check, we'll wind up corrupting our heap in the subsequent
1508 * assignments.
1509 *
1510 * We break out if this check fails because, obj_sz is supposed to include
1511 * the size of the logmsg_s struct. If it claims to be of zero size, we
1512 * can't safely increment our counter because something obviously got screwed
1513 * up along the way, since this should always be at least sizeof(struct logmsg_s).
1514 */
1515 if( !launchd_assumes(lm_walk->obj_sz > 0) ) {
1516 runtime_syslog(LOG_WARNING, "Encountered a log message of size 0 with %u bytes left in forwarded data. Ignoring remaining messages.", data_left);
1517 break;
1518 }
1519
1520 /* If malloc() keeps failing, we shouldn't put additional pressure on the system
1521 * by attempting to add more messages to the log until it returns success
1522 * log a failure, hope pressure lets off, and move on.
1523 */
1524 if (!launchd_assumes(lm = malloc(lm_walk->obj_sz))) {
1525 runtime_syslog(LOG_WARNING, "Failed to allocate %llu bytes for log message with %u bytes left in forwarded data. Ignoring remaining messages.", lm_walk->obj_sz, data_left);
1526 break;
1527 }
1528
1529 memcpy(lm, lm_walk, lm_walk->obj_sz);
1530 lm->sender_uid = forward_uid;
1531 lm->sender_gid = forward_gid;
1532
1533 lm->from_name += (size_t)lm;
1534 lm->about_name += (size_t)lm;
1535 lm->msg += (size_t)lm;
1536 lm->session_name += (size_t)lm;
1537
1538 STAILQ_INSERT_TAIL(&logmsg_queue, lm, sqe);
1539 logmsg_queue_sz += lm->obj_sz;
1540 logmsg_queue_cnt++;
1541
1542 data_left -= lm->obj_sz;
1543 }
1544
1545 mig_deallocate(inval, invalCnt);
1546
1547 return 0;
1548 }
1549
1550 kern_return_t
1551 runtime_log_drain(mach_port_t srp, vm_offset_t *outval, mach_msg_type_number_t *outvalCnt)
1552 {
1553 launchd_assumes(drain_reply_port == 0);
1554
1555 if ((logmsg_queue_cnt == 0) || shutdown_in_progress || fake_shutdown_in_progress) {
1556 drain_reply_port = srp;
1557 launchd_assumes(launchd_mport_notify_req(drain_reply_port, MACH_NOTIFY_DEAD_NAME) == KERN_SUCCESS);
1558
1559 return MIG_NO_REPLY;
1560 }
1561
1562 return runtime_log_pack(outval, outvalCnt);
1563 }
1564
1565 /*
1566 * We should break this into two reference counts.
1567 *
1568 * One for hard references that would prevent exiting.
1569 * One for soft references that would only prevent idle exiting.
1570 *
1571 * In the long run, reference counting should completely automate when a
1572 * process can and should exit.
1573 */
1574 void
1575 runtime_add_ref(void)
1576 {
1577 if (!pid1_magic) {
1578 #if !TARGET_OS_EMBEDDED
1579 _vproc_transaction_begin();
1580 #endif
1581 }
1582 runtime_busy_cnt++;
1583 }
1584
1585 void
1586 runtime_del_ref(void)
1587 {
1588 if (!pid1_magic) {
1589 #if !TARGET_OS_EMBEDDED
1590 if( _vproc_transaction_count() == 0 ) {
1591 runtime_syslog(LOG_INFO, "Exiting cleanly.");
1592 }
1593
1594 runtime_closelog();
1595 _vproc_transaction_end();
1596 #endif
1597 }
1598 runtime_busy_cnt--;
1599 }
1600
1601 void
1602 runtime_add_weak_ref(void)
1603 {
1604 if (!pid1_magic) {
1605 #if !TARGET_OS_EMBEDDED
1606 _vproc_standby_begin();
1607 #endif
1608 }
1609 runtime_standby_cnt++;
1610 }
1611
1612 void
1613 runtime_del_weak_ref(void)
1614 {
1615 if (!pid1_magic) {
1616 #if !TARGET_OS_EMBEDDED
1617 _vproc_standby_end();
1618 #endif
1619 }
1620 runtime_standby_cnt--;
1621 }
1622
1623 kern_return_t
1624 catch_mach_exception_raise(mach_port_t exception_port __attribute__((unused)), mach_port_t thread, mach_port_t task,
1625 exception_type_t exception, mach_exception_data_t code, mach_msg_type_number_t codeCnt)
1626 {
1627 pid_t p4t = -1;
1628
1629 launchd_assumes(pid_for_task(task, &p4t) == 0);
1630
1631 runtime_syslog(LOG_NOTICE, "%s(): PID: %u thread: 0x%x type: 0x%x code: %p codeCnt: 0x%x",
1632 __func__, p4t, thread, exception, code, codeCnt);
1633
1634 launchd_assumes(launchd_mport_deallocate(thread) == KERN_SUCCESS);
1635 launchd_assumes(launchd_mport_deallocate(task) == KERN_SUCCESS);
1636
1637 return KERN_SUCCESS;
1638 }
1639
1640 kern_return_t
1641 catch_mach_exception_raise_state(mach_port_t exception_port __attribute__((unused)),
1642 exception_type_t exception, const mach_exception_data_t code, mach_msg_type_number_t codeCnt,
1643 int *flavor, const thread_state_t old_state, mach_msg_type_number_t old_stateCnt,
1644 thread_state_t new_state, mach_msg_type_number_t *new_stateCnt)
1645 {
1646 runtime_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",
1647 __func__, exception, code, codeCnt, flavor, old_state, old_stateCnt, new_state, new_stateCnt);
1648
1649 memcpy(new_state, old_state, old_stateCnt * sizeof(old_state[0]));
1650 *new_stateCnt = old_stateCnt;
1651
1652 return KERN_SUCCESS;
1653 }
1654
1655 kern_return_t
1656 catch_mach_exception_raise_state_identity(mach_port_t exception_port __attribute__((unused)), mach_port_t thread, mach_port_t task,
1657 exception_type_t exception, mach_exception_data_t code, mach_msg_type_number_t codeCnt,
1658 int *flavor, thread_state_t old_state, mach_msg_type_number_t old_stateCnt,
1659 thread_state_t new_state, mach_msg_type_number_t *new_stateCnt)
1660 {
1661 pid_t p4t = -1;
1662
1663 launchd_assumes(pid_for_task(task, &p4t) == 0);
1664
1665 runtime_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",
1666 __func__, p4t, thread, exception, code, codeCnt, flavor, old_state, old_stateCnt, new_state, new_stateCnt);
1667
1668 memcpy(new_state, old_state, old_stateCnt * sizeof(old_state[0]));
1669 *new_stateCnt = old_stateCnt;
1670
1671 launchd_assumes(launchd_mport_deallocate(thread) == KERN_SUCCESS);
1672 launchd_assumes(launchd_mport_deallocate(task) == KERN_SUCCESS);
1673
1674 return KERN_SUCCESS;
1675 }
1676
1677 void
1678 launchd_log_vm_stats(void)
1679 {
1680 static struct vm_statistics orig_stats;
1681 static bool did_first_pass;
1682 unsigned int count = HOST_VM_INFO_COUNT;
1683 struct vm_statistics stats, *statsp;
1684 mach_port_t mhs = mach_host_self();
1685
1686 statsp = did_first_pass ? &stats : &orig_stats;
1687
1688 if (!launchd_assumes(host_statistics(mhs, HOST_VM_INFO, (host_info_t)statsp, &count) == KERN_SUCCESS)) {
1689 return;
1690 }
1691
1692 launchd_assumes(count == HOST_VM_INFO_COUNT);
1693
1694 if (did_first_pass) {
1695 runtime_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",
1696 stats.free_count - orig_stats.free_count,
1697 stats.active_count - orig_stats.active_count,
1698 stats.inactive_count - orig_stats.inactive_count,
1699 stats.reactivations - orig_stats.reactivations,
1700 stats.pageins - orig_stats.pageins,
1701 stats.pageouts - orig_stats.pageouts,
1702 stats.faults - orig_stats.faults,
1703 stats.cow_faults - orig_stats.cow_faults,
1704 stats.purgeable_count - orig_stats.purgeable_count,
1705 stats.purges - orig_stats.purges);
1706 } else {
1707 runtime_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",
1708 orig_stats.free_count,
1709 orig_stats.active_count,
1710 orig_stats.inactive_count,
1711 orig_stats.reactivations,
1712 orig_stats.pageins,
1713 orig_stats.pageouts,
1714 orig_stats.faults,
1715 orig_stats.cow_faults,
1716 orig_stats.purgeable_count,
1717 orig_stats.purges);
1718
1719 did_first_pass = true;
1720 }
1721
1722 launchd_mport_deallocate(mhs);
1723 }
1724
1725 int64_t
1726 runtime_get_wall_time(void)
1727 {
1728 struct timeval tv;
1729 int64_t r;
1730
1731 launchd_assumes(gettimeofday(&tv, NULL) != -1);
1732
1733 r = tv.tv_sec;
1734 r *= USEC_PER_SEC;
1735 r += tv.tv_usec;
1736
1737 return r;
1738 }
1739
1740 uint64_t
1741 runtime_get_opaque_time(void)
1742 {
1743 return mach_absolute_time();
1744 }
1745
1746 uint64_t
1747 runtime_get_opaque_time_of_event(void)
1748 {
1749 return time_of_mach_msg_return;
1750 }
1751
1752 uint64_t
1753 runtime_get_nanoseconds_since(uint64_t o)
1754 {
1755 return runtime_opaque_time_to_nano(runtime_get_opaque_time_of_event() - o);
1756 }
1757
1758 uint64_t
1759 runtime_opaque_time_to_nano(uint64_t o)
1760 {
1761 #if defined(__i386__) || defined(__x86_64__)
1762 if (unlikely(tbi.numer != tbi.denom)) {
1763 #elif defined(__ppc__) || defined(__ppc64__)
1764 if (likely(tbi.numer != tbi.denom)) {
1765 #else
1766 if (tbi.numer != tbi.denom) {
1767 #endif
1768 #ifdef __LP64__
1769 __uint128_t tmp = o;
1770 tmp *= tbi.numer;
1771 tmp /= tbi.denom;
1772 o = tmp;
1773 #else
1774 if (o <= tbi_safe_math_max) {
1775 o *= tbi.numer;
1776 o /= tbi.denom;
1777 } else {
1778 double d = o;
1779 d *= tbi_float_val;
1780 o = d;
1781 }
1782 #endif
1783 }
1784
1785 return o;
1786 }
1787
1788 void
1789 do_file_init(void)
1790 {
1791 struct stat sb;
1792
1793 launchd_assert(mach_timebase_info(&tbi) == 0);
1794 tbi_float_val = tbi.numer;
1795 tbi_float_val /= tbi.denom;
1796 tbi_safe_math_max = UINT64_MAX / tbi.numer;
1797
1798 if (getpid() == 1) {
1799 pid1_magic = true;
1800 }
1801
1802 if (stat("/AppleInternal", &sb) == 0 && stat("/var/db/disableAppleInternal", &sb) == -1) {
1803 do_apple_internal_logging = true;
1804 }
1805
1806 if (stat("/var/db/.debug_launchd", &sb) == 0) {
1807 internal_mask_pri = LOG_UPTO(LOG_DEBUG);
1808 low_level_debug = true;
1809 }
1810
1811 if( stat("/var/db/.launchd_disable_sudden_termination", &sb) == 0 ) {
1812 g_force_old_kill_path = true;
1813 }
1814
1815 if( stat("/var/db/.launchd_log_per_user_shutdown", &sb) == 0 ) {
1816 g_log_per_user_shutdown = true;
1817 }
1818
1819 if( !pid1_magic && stat("/var/db/.launchd_no_flat_per_user_namespace", &sb) == 0 ) {
1820 g_flat_mach_namespace = false;
1821 }
1822
1823 if( pid1_magic && stat("/var/db/.launchd_simulate_pid1_crash", &sb) == 0 ) {
1824 g_simulate_pid1_crash = true;
1825 }
1826
1827 if( pid1_magic && stat("/var/db/.launchd_use_gmalloc", &sb) == 0 ) {
1828 g_use_gmalloc = true;
1829 }
1830
1831 if( pid1_magic && stat("/var/db/.launchd_log_pid1_shutdown", &sb) == 0 ) {
1832 g_log_pid1_shutdown = true;
1833 }
1834
1835 char bootargs[128];
1836 size_t len = sizeof(bootargs) - 1;
1837 int r = pid1_magic ? sysctlbyname("kern.bootargs", bootargs, &len, NULL, 0) : -1;
1838 if( r == 0 && strnstr(bootargs, "-v", len) != NULL ) {
1839 g_verbose_boot = true;
1840 }
1841
1842 if( pid1_magic && g_verbose_boot && stat("/var/db/.launchd_shutdown_debugging", &sb) == 0 ) {
1843 g_shutdown_debugging = true;
1844 }
1845
1846 if( stat("/var/db/.launchd_log_strict_usage", &sb) == 0 ) {
1847 g_log_strict_usage = true;
1848 }
1849 }