xref: /NextBSD/sbin/launchd/core.c (revision bba9afca3d77f067ecb6fa3aecbe6ad62269715d)
1 /*
2  * @APPLE_APACHE_LICENSE_HEADER_START@
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  * @APPLE_APACHE_LICENSE_HEADER_END@
17  */
18 
19 #define __APPLE_API_PRIVATE
20 #define PRIVATE 1
21 
22 #include "config.h"
23 #include "core.h"
24 
25 #include "internal.h"
26 #include "helper.h"
27 
28 #include <TargetConditionals.h>
29 #include <mach/mach.h>
30 #include <mach/mach_error.h>
31 #include <mach/boolean.h>
32 #include <mach/message.h>
33 #include <mach/notify.h>
34 #include <mach/mig_errors.h>
35 #include <mach/mach_traps.h>
36 #include <mach/mach_interface.h>
37 #include <mach/host_info.h>
38 #include <mach/mach_host.h>
39 #include <mach/exception.h>
40 #include <mach/host_reboot.h>
41 #include <sys/types.h>
42 #include <sys/queue.h>
43 #include <sys/endian.h>
44 #include <sys/event.h>
45 #include <sys/stat.h>
46 #include <sys/ucred.h>
47 #include <sys/fcntl.h>
48 #include <sys/un.h>
49 #include <sys/reboot.h>
50 #include <sys/wait.h>
51 #include <sys/sysctl.h>
52 #include <sys/sockio.h>
53 #include <sys/time.h>
54 #include <sys/resource.h>
55 #include <sys/ioctl.h>
56 #include <sys/mount.h>
57 #if 0
58 #include <sys/pipe.h>
59 #endif
60 #include <sys/mman.h>
61 #include <sys/proc.h>
62 #include <sys/socket.h>
63 #include <sys/syscall.h>
64 #include <sys/kern_memorystatus.h>
65 #include <net/if.h>
66 #include <net/if_var.h>
67 #include <netinet/in.h>
68 #include <netinet/in_var.h>
69 #include <netinet6/nd6.h>
70 #include <bsm/libbsm.h>
71 #include <unistd.h>
72 #include <signal.h>
73 #include <errno.h>
74 #include <libgen.h>
75 #include <stdio.h>
76 #include <stdlib.h>
77 #include <stdarg.h>
78 #include <stdbool.h>
79 #include <paths.h>
80 #include <pwd.h>
81 #include <grp.h>
82 #include <ttyent.h>
83 #include <dlfcn.h>
84 #include <dirent.h>
85 #include <string.h>
86 #include <ctype.h>
87 #include <glob.h>
88 #include <spawn.h>
89 #include <spawn_private.h>
90 #include <sys/spawn_internal.h>
91 #include <System/sys/spawn.h>
92 #include <System/sys/spawn_internal.h>
93 
94 #include <spawn_private.h>
95 #include <time.h>
96 #include <libinfo.h>
97 #include <os/assumes.h>
98 #include <xpc/launchd.h>
99 #include <asl.h>
100 #include <_simple.h>
101 #include <mach/mach_vm.h>
102 
103 #include <libproc.h>
104 #include <libproc_internal.h>
105 #include <System/sys/proc_info.h>
106 
107 #include <pthread.h>
108 #if HAVE_SANDBOX
109 #define __APPLE_API_PRIVATE
110 #include <sandbox.h>
111 #endif
112 #if HAVE_QUARANTINE
113 #include <quarantine.h>
114 #endif
115 #if HAVE_RESPONSIBILITY
116 #include <responsibility.h>
117 #endif
118 
119 #if !TARGET_OS_EMBEDDED
120 extern int gL1CacheEnabled;
121 #endif
122 
123 #if HAVE_SYSTEMSTATS
124 #include <systemstats/systemstats.h>
125 #endif
126 
127 #include "launch.h"
128 #include "launch_priv.h"
129 #include "launch_internal.h"
130 #include "bootstrap.h"
131 #include "bootstrap_priv.h"
132 #include "vproc.h"
133 #include "vproc_internal.h"
134 
135 #include "reboot2.h"
136 
137 #include "launchd.h"
138 #include "runtime.h"
139 #include "ipc.h"
140 #include "job.h"
141 
142 #include "jobServer.h"
143 #include "job_reply.h"
144 #include "job_forward.h"
145 
146 #include "mach_excServer.h"
147 
148 #include "shim.h"
149 
150 
151 #define RETURN_NO_MEMORY()										\
152 	do {														\
153 		if (uflag)												\
154 			printf("launchd failed on line: %d\n", __LINE__);	\
155 		return BOOTSTRAP_NO_MEMORY;								\
156 } while (0)
157 
158 #define POSIX_SPAWN_IOS_INTERACTIVE 0
159 
160 #if TARGET_OS_EMBEDDED
161 /* Default memory highwatermark for daemons as set out in <rdar://problem/10307788>. */
162 #define DEFAULT_JETSAM_DAEMON_HIGHWATERMARK 5
163 #endif
164 
165 /* LAUNCHD_DEFAULT_EXIT_TIMEOUT
166  *   If the job hasn't exited in the given number of seconds after sending
167  *   it a SIGTERM, SIGKILL it. Can be overriden in the job plist.
168  */
169 #define LAUNCHD_MIN_JOB_RUN_TIME 10
170 #define LAUNCHD_DEFAULT_EXIT_TIMEOUT 20
171 #define LAUNCHD_SIGKILL_TIMER 30
172 #define LAUNCHD_LOG_FAILED_EXEC_FREQ 10
173 
174 #define SHUTDOWN_LOG_DIR "/var/log/shutdown"
175 
176 #define TAKE_SUBSET_NAME "TakeSubsetName"
177 #define TAKE_SUBSET_PID "TakeSubsetPID"
178 #define TAKE_SUBSET_PERPID "TakeSubsetPerPID"
179 
180 #define IS_POWER_OF_TWO(v) (!(v & (v - 1)) && v)
181 
182 extern char **environ;
183 extern bool uflag;
184 
185 struct waiting_for_removal {
186 	SLIST_ENTRY(waiting_for_removal) sle;
187 	mach_port_t reply_port;
188 };
189 
190 static bool waiting4removal_new(job_t j, mach_port_t rp);
191 static void waiting4removal_delete(job_t j, struct waiting_for_removal *w4r);
192 
193 struct machservice {
194 	SLIST_ENTRY(machservice) sle;
195 	SLIST_ENTRY(machservice) special_port_sle;
196 	LIST_ENTRY(machservice) name_hash_sle;
197 	LIST_ENTRY(machservice) port_hash_sle;
198 	struct machservice *alias;
199 	job_t job;
200 	unsigned int gen_num;
201 	mach_port_name_t port;
202 	unsigned int
203 		isActive:1,
204 		reset:1,
205 		recv:1,
206 		hide:1,
207 		kUNCServer:1,
208 		per_user_hack:1,
209 		debug_on_close:1,
210 		per_pid:1,
211 		delete_on_destruction:1,
212 		drain_one_on_crash:1,
213 		drain_all_on_crash:1,
214 		upfront:1,
215 		event_channel:1,
216 		recv_race_hack :1,
217 		/* Don't let the size of this field to get too small. It has to be large
218 		 * enough to represent the reasonable range of special port numbers.
219 		 */
220 		special_port_num:17;
221 	const char name[0];
222 };
223 
224 // HACK: This should be per jobmgr_t
225 static SLIST_HEAD(, machservice) special_ports;
226 
227 #define PORT_HASH_SIZE 32
228 #define HASH_PORT(x) (IS_POWER_OF_TWO(PORT_HASH_SIZE) ? (MACH_PORT_INDEX(x) & (PORT_HASH_SIZE - 1)) : (MACH_PORT_INDEX(x) % PORT_HASH_SIZE))
229 
230 static LIST_HEAD(, machservice) port_hash[PORT_HASH_SIZE];
231 
232 static void machservice_setup(launch_data_t obj, const char *key, void *context);
233 static void machservice_setup_options(launch_data_t obj, const char *key, void *context);
234 static void machservice_resetport(job_t j, struct machservice *ms);
235 static void machservice_stamp_port(job_t j, struct machservice *ms);
236 static struct machservice *machservice_new(job_t j, const char *name, mach_port_t *serviceport, bool pid_local);
237 static struct machservice *machservice_new_alias(job_t aj, struct machservice *orig);
238 static void machservice_ignore(job_t j, struct machservice *ms);
239 static void machservice_watch(job_t j, struct machservice *ms);
240 static void machservice_delete(job_t j, struct machservice *, bool port_died);
241 static void machservice_request_notifications(struct machservice *);
242 static mach_port_t machservice_port(struct machservice *);
243 static job_t machservice_job(struct machservice *);
244 static bool machservice_hidden(struct machservice *);
245 static bool machservice_active(struct machservice *);
246 static const char *machservice_name(struct machservice *);
247 static bootstrap_status_t machservice_status(struct machservice *);
248 void machservice_drain_port(struct machservice *);
249 
250 struct socketgroup {
251 	SLIST_ENTRY(socketgroup) sle;
252 	int *fds;
253 	unsigned int fd_cnt;
254 	union {
255 		const char name[0];
256 		char name_init[0];
257 	};
258 };
259 
260 static bool socketgroup_new(job_t j, const char *name, int *fds, size_t fd_cnt);
261 static void socketgroup_delete(job_t j, struct socketgroup *sg);
262 static void socketgroup_watch(job_t j, struct socketgroup *sg);
263 static void socketgroup_ignore(job_t j, struct socketgroup *sg);
264 static void socketgroup_callback(job_t j);
265 static void socketgroup_setup(launch_data_t obj, const char *key, void *context);
266 static void socketgroup_kevent_mod(job_t j, struct socketgroup *sg, bool do_add);
267 
268 struct calendarinterval {
269 	LIST_ENTRY(calendarinterval) global_sle;
270 	SLIST_ENTRY(calendarinterval) sle;
271 	job_t job;
272 	struct tm when;
273 	time_t when_next;
274 };
275 
276 static LIST_HEAD(, calendarinterval) sorted_calendar_events;
277 
278 static bool calendarinterval_new(job_t j, struct tm *w);
279 static bool calendarinterval_new_from_obj(job_t j, launch_data_t obj);
280 static void calendarinterval_new_from_obj_dict_walk(launch_data_t obj, const char *key, void *context);
281 static void calendarinterval_delete(job_t j, struct calendarinterval *ci);
282 static void calendarinterval_setalarm(job_t j, struct calendarinterval *ci);
283 static void calendarinterval_callback(void);
284 static void calendarinterval_sanity_check(void);
285 
286 struct envitem {
287 	SLIST_ENTRY(envitem) sle;
288 	char *value;
289 	union {
290 		const char key[0];
291 		char key_init[0];
292 	};
293 };
294 
295 static bool envitem_new(job_t j, const char *k, const char *v, bool global);
296 static void envitem_delete(job_t j, struct envitem *ei, bool global);
297 static void envitem_setup(launch_data_t obj, const char *key, void *context);
298 
299 struct limititem {
300 	SLIST_ENTRY(limititem) sle;
301 	struct rlimit lim;
302 	unsigned int setsoft:1, sethard:1, which:30;
303 };
304 
305 static bool limititem_update(job_t j, int w, rlim_t r);
306 static void limititem_delete(job_t j, struct limititem *li);
307 static void limititem_setup(launch_data_t obj, const char *key, void *context);
308 #if HAVE_SANDBOX
309 static void seatbelt_setup_flags(launch_data_t obj, const char *key, void *context);
310 #endif
311 
312 static void jetsam_property_setup(launch_data_t obj, const char *key, job_t j);
313 
314 typedef enum {
315 	NETWORK_UP = 1,
316 	NETWORK_DOWN,
317 	SUCCESSFUL_EXIT,
318 	FAILED_EXIT,
319 	CRASHED,
320 	DID_NOT_CRASH,
321 	OTHER_JOB_ENABLED,
322 	OTHER_JOB_DISABLED,
323 	OTHER_JOB_ACTIVE,
324 	OTHER_JOB_INACTIVE,
325 } semaphore_reason_t;
326 
327 struct semaphoreitem {
328 	SLIST_ENTRY(semaphoreitem) sle;
329 	semaphore_reason_t why;
330 
331 	union {
332 		const char what[0];
333 		char what_init[0];
334 	};
335 };
336 
337 struct semaphoreitem_dict_iter_context {
338 	job_t j;
339 	semaphore_reason_t why_true;
340 	semaphore_reason_t why_false;
341 };
342 
343 static bool semaphoreitem_new(job_t j, semaphore_reason_t why, const char *what);
344 static void semaphoreitem_delete(job_t j, struct semaphoreitem *si);
345 static void semaphoreitem_setup(launch_data_t obj, const char *key, void *context);
346 static void semaphoreitem_setup_dict_iter(launch_data_t obj, const char *key, void *context);
347 static void semaphoreitem_runtime_mod_ref(struct semaphoreitem *si, bool add);
348 
349 struct externalevent {
350 	LIST_ENTRY(externalevent) sys_le;
351 	LIST_ENTRY(externalevent) job_le;
352 	struct eventsystem *sys;
353 
354 	uint64_t id;
355 	job_t job;
356 	bool state;
357 	bool wanted_state;
358 	bool internal;
359 	xpc_object_t event;
360 	xpc_object_t entitlements;
361 
362 	char name[0];
363 };
364 
365 struct externalevent_iter_ctx {
366 	job_t j;
367 	struct eventsystem *sys;
368 };
369 
370 static bool externalevent_new(job_t j, struct eventsystem *sys, const char *evname, xpc_object_t event, uint64_t flags);
371 static void externalevent_delete(struct externalevent *ee);
372 static void externalevent_setup(launch_data_t obj, const char *key, void *context);
373 static struct externalevent *externalevent_find(const char *sysname, uint64_t id);
374 
375 struct eventsystem {
376 	LIST_ENTRY(eventsystem) global_le;
377 	LIST_HEAD(, externalevent) events;
378 	uint64_t curid;
379 	char name[0];
380 };
381 
382 static struct eventsystem *eventsystem_new(const char *name);
383 static void eventsystem_delete(struct eventsystem *sys) __attribute__((unused));
384 static void eventsystem_setup(launch_data_t obj, const char *key, void *context);
385 static struct eventsystem *eventsystem_find(const char *name);
386 static void eventsystem_ping(void);
387 
388 struct waiting4attach {
389 	LIST_ENTRY(waiting4attach) le;
390 	mach_port_t port;
391 	pid_t dest;
392 	xpc_service_type_t type;
393 	char name[0];
394 };
395 
396 static LIST_HEAD(, waiting4attach) _launchd_domain_waiters;
397 
398 static struct waiting4attach *waiting4attach_new(jobmgr_t jm, const char *name, mach_port_t port, pid_t dest, xpc_service_type_t type);
399 static void waiting4attach_delete(jobmgr_t jm, struct waiting4attach *w4a);
400 static struct waiting4attach *waiting4attach_find(jobmgr_t jm, job_t j);
401 
402 #define ACTIVE_JOB_HASH_SIZE 32
403 #define ACTIVE_JOB_HASH(x) (IS_POWER_OF_TWO(ACTIVE_JOB_HASH_SIZE) ? (x & (ACTIVE_JOB_HASH_SIZE - 1)) : (x % ACTIVE_JOB_HASH_SIZE))
404 
405 #define MACHSERVICE_HASH_SIZE	37
406 
407 #define LABEL_HASH_SIZE 53
408 struct jobmgr_s {
409 	kq_callback kqjobmgr_callback;
410 	LIST_ENTRY(jobmgr_s) xpc_le;
411 	SLIST_ENTRY(jobmgr_s) sle;
412 	SLIST_HEAD(, jobmgr_s) submgrs;
413 	LIST_HEAD(, job_s) jobs;
414 	LIST_HEAD(, waiting4attach) attaches;
415 
416 	/* For legacy reasons, we keep all job labels that are imported in the root
417 	 * job manager's label hash. If a job manager is an XPC domain, then it gets
418 	 * its own label hash that is separate from the "global" one stored in the
419 	 * root job manager.
420 	 */
421 	LIST_HEAD(, job_s) label_hash[LABEL_HASH_SIZE];
422 	LIST_HEAD(, job_s) active_jobs[ACTIVE_JOB_HASH_SIZE];
423 	LIST_HEAD(, machservice) ms_hash[MACHSERVICE_HASH_SIZE];
424 	LIST_HEAD(, job_s) global_env_jobs;
425 	mach_port_t jm_port;
426 	mach_port_t req_port;
427 	jobmgr_t parentmgr;
428 	int reboot_flags;
429 	time_t shutdown_time;
430 	unsigned int global_on_demand_cnt;
431 	unsigned int normal_active_cnt;
432 	unsigned int
433 		shutting_down:1,
434 		session_initialized:1,
435 		killed_stray_jobs:1,
436 		monitor_shutdown:1,
437 		shutdown_jobs_dirtied:1,
438 		shutdown_jobs_cleaned:1,
439 		xpc_singleton:1;
440 	uint32_t properties;
441 	// XPC-specific properties.
442 	char owner[MAXCOMLEN];
443 	const char *shortdesc;
444 	mach_port_t req_bsport;
445 	mach_port_t req_excport;
446 	mach_port_t req_asport;
447 	mach_port_t req_gui_asport;
448 	pid_t req_pid;
449 	uid_t req_euid;
450 	gid_t req_egid;
451 	au_asid_t req_asid;
452 	vm_offset_t req_ctx;
453 	mach_msg_type_number_t req_ctx_sz;
454 	mach_port_t req_rport;
455 	uint64_t req_uniqueid;
456 	kern_return_t error;
457 	union {
458 		const char name[0];
459 		char name_init[0];
460 	};
461 };
462 
463 // Global XPC domains.
464 static jobmgr_t _s_xpc_system_domain;
465 static LIST_HEAD(, jobmgr_s) _s_xpc_user_domains;
466 static LIST_HEAD(, jobmgr_s) _s_xpc_session_domains;
467 
468 #define jobmgr_assumes(jm, e) os_assumes_ctx(jobmgr_log_bug, jm, (e))
469 #define jobmgr_assumes_zero(jm, e) os_assumes_zero_ctx(jobmgr_log_bug, jm, (e))
470 #define jobmgr_assumes_zero_p(jm, e) posix_assumes_zero_ctx(jobmgr_log_bug, jm, (e))
471 
472 static jobmgr_t jobmgr_new(jobmgr_t jm, mach_port_t requestorport, mach_port_t transfer_port, bool sflag, const char *name, bool no_init, mach_port_t asport);
473 static jobmgr_t jobmgr_new_xpc_singleton_domain(jobmgr_t jm, name_t name);
474 static jobmgr_t jobmgr_find_xpc_per_user_domain(jobmgr_t jm, uid_t uid);
475 static jobmgr_t jobmgr_find_xpc_per_session_domain(jobmgr_t jm, au_asid_t asid);
476 static job_t jobmgr_import2(jobmgr_t jm, launch_data_t pload);
477 static jobmgr_t jobmgr_parent(jobmgr_t jm);
478 static jobmgr_t jobmgr_do_garbage_collection(jobmgr_t jm);
479 static bool jobmgr_label_test(jobmgr_t jm, const char *str);
480 static void jobmgr_reap_bulk(jobmgr_t jm, struct kevent *kev);
481 static void jobmgr_log_stray_children(jobmgr_t jm, bool kill_strays);
482 static void jobmgr_kill_stray_children(jobmgr_t jm, pid_t *p, size_t np);
483 static void jobmgr_remove(jobmgr_t jm);
484 static void jobmgr_dispatch_all(jobmgr_t jm, bool newmounthack);
485 static job_t jobmgr_init_session(jobmgr_t jm, const char *session_type, bool sflag);
486 static job_t jobmgr_find_by_pid_deep(jobmgr_t jm, pid_t p, bool anon_okay);
487 static job_t jobmgr_find_by_pid(jobmgr_t jm, pid_t p, bool create_anon);
488 static job_t managed_job(pid_t p);
489 static jobmgr_t jobmgr_find_by_name(jobmgr_t jm, const char *where);
490 static job_t job_mig_intran2(jobmgr_t jm, mach_port_t mport, pid_t upid);
491 static job_t jobmgr_lookup_per_user_context_internal(job_t j, uid_t which_user, mach_port_t *mp);
492 static void job_export_all2(jobmgr_t jm, launch_data_t where);
493 static void jobmgr_callback(void *obj, struct kevent *kev);
494 static void jobmgr_setup_env_from_other_jobs(jobmgr_t jm);
495 static void jobmgr_export_env_from_other_jobs(jobmgr_t jm, launch_data_t dict);
496 static struct machservice *jobmgr_lookup_service(jobmgr_t jm, const char *name, bool check_parent, pid_t target_pid);
497 static void jobmgr_logv(jobmgr_t jm, int pri, int err, const char *msg, va_list ap) __attribute__((format(printf, 4, 0)));
498 static void jobmgr_log(jobmgr_t jm, int pri, const char *msg, ...) __attribute__((format(printf, 3, 4)));
499 static void jobmgr_log_perf_statistics(jobmgr_t jm, bool signal_children);
500 // static void jobmgr_log_error(jobmgr_t jm, int pri, const char *msg, ...) __attribute__((format(printf, 3, 4)));
501 static bool jobmgr_log_bug(_SIMPLE_STRING asl_message, void *ctx, const char *message);
502 
503 #define AUTO_PICK_LEGACY_LABEL (const char *)(~0)
504 #define AUTO_PICK_ANONYMOUS_LABEL (const char *)(~1)
505 #define AUTO_PICK_XPC_LABEL (const char *)(~2)
506 
507 struct suspended_peruser {
508 	LIST_ENTRY(suspended_peruser) sle;
509 	job_t j;
510 };
511 
512 struct job_s {
513 	// MUST be first element of this structure.
514 	kq_callback kqjob_callback;
515 	LIST_ENTRY(job_s) sle;
516 	LIST_ENTRY(job_s) subjob_sle;
517 	LIST_ENTRY(job_s) needing_session_sle;
518 	LIST_ENTRY(job_s) jetsam_sle;
519 	LIST_ENTRY(job_s) pid_hash_sle;
520 	LIST_ENTRY(job_s) global_pid_hash_sle;
521 	LIST_ENTRY(job_s) label_hash_sle;
522 	LIST_ENTRY(job_s) global_env_sle;
523 	SLIST_ENTRY(job_s) curious_jobs_sle;
524 	LIST_HEAD(, suspended_peruser) suspended_perusers;
525 	LIST_HEAD(, waiting_for_exit) exit_watchers;
526 	LIST_HEAD(, job_s) subjobs;
527 	LIST_HEAD(, externalevent) events;
528 	SLIST_HEAD(, socketgroup) sockets;
529 	SLIST_HEAD(, calendarinterval) cal_intervals;
530 	SLIST_HEAD(, envitem) global_env;
531 	SLIST_HEAD(, envitem) env;
532 	SLIST_HEAD(, limititem) limits;
533 	SLIST_HEAD(, machservice) machservices;
534 	SLIST_HEAD(, semaphoreitem) semaphores;
535 	SLIST_HEAD(, waiting_for_removal) removal_watchers;
536 	struct waiting4attach *w4a;
537 	job_t original;
538 	job_t alias;
539 	cpu_type_t *j_binpref;
540 	size_t j_binpref_cnt;
541 	mach_port_t j_port;
542 	mach_port_t exit_status_dest;
543 	mach_port_t exit_status_port;
544 	mach_port_t spawn_reply_port;
545 	uid_t mach_uid;
546 	jobmgr_t mgr;
547 	size_t argc;
548 	char **argv;
549 	char *prog;
550 	char *rootdir;
551 	char *workingdir;
552 	char *username;
553 	char *groupname;
554 	char *stdinpath;
555 	char *stdoutpath;
556 	char *stderrpath;
557 	char *alt_exc_handler;
558 	char *cfbundleidentifier;
559 	unsigned int nruns;
560 	uint64_t trt;
561 #if HAVE_SANDBOX
562 	char *seatbelt_profile;
563 	uint64_t seatbelt_flags;
564 	char *container_identifier;
565 #endif
566 #if HAVE_QUARANTINE
567 	void *quarantine_data;
568 	size_t quarantine_data_sz;
569 #endif
570 	pid_t p;
571 	uint64_t uniqueid;
572 	int last_exit_status;
573 	int stdin_fd;
574 	int fork_fd;
575 	int nice;
576 	uint32_t pstype;
577 	uint32_t psproctype;
578 	int32_t jetsam_priority;
579 	int32_t jetsam_memlimit;
580 	int32_t main_thread_priority;
581 	uint32_t timeout;
582 	uint32_t exit_timeout;
583 	uint64_t sent_signal_time;
584 	uint64_t start_time;
585 	uint32_t min_run_time;
586 	bool unthrottle;
587 	uint32_t start_interval;
588 	uint32_t peruser_suspend_count;
589 	uuid_t instance_id;
590 	mode_t mask;
591 	mach_port_t asport;
592 	au_asid_t asid;
593 	uuid_t expected_audit_uuid;
594 	bool
595 		// man launchd.plist --> Debug
596 		debug:1,
597 		// man launchd.plist --> KeepAlive == false
598 		ondemand:1,
599 		// man launchd.plist --> SessionCreate
600 		session_create:1,
601 		// man launchd.plist --> LowPriorityIO
602 		low_pri_io:1,
603 		// man launchd.plist --> InitGroups
604 		no_init_groups:1,
605 		/* A legacy mach_init concept to make bootstrap_create_server/service()
606 		 * work
607 		 */
608 		priv_port_has_senders:1,
609 		// A hack during job importing
610 		importing_global_env:1,
611 		// A hack during job importing
612 		importing_hard_limits:1,
613 		// man launchd.plist --> Umask
614 		setmask:1,
615 		// A process that launchd knows about but doesn't manage.
616 		anonymous:1,
617 		// A legacy mach_init concept to detect sick jobs
618 		checkedin:1,
619 		// A job created via bootstrap_create_server()
620 		legacy_mach_job:1,
621 		// A job created via spawn_via_launchd()
622 		legacy_LS_job:1,
623 		// A legacy job that wants inetd compatible semantics
624 		inetcompat:1,
625 		// A twist on inetd compatibility
626 		inetcompat_wait:1,
627 		/* An event fired and the job should start, but not necessarily right
628 		 * away.
629 		 */
630 		start_pending:1,
631 		// man launchd.plist --> EnableGlobbing
632 		globargv:1,
633 		// man launchd.plist --> WaitForDebugger
634 		wait4debugger:1,
635 		// One-shot WaitForDebugger.
636 		wait4debugger_oneshot:1,
637 		// MachExceptionHandler == true
638 		internal_exc_handler:1,
639 		// A hack to support an option of spawn_via_launchd()
640 		stall_before_exec:1,
641 		/* man launchd.plist --> LaunchOnlyOnce.
642 		 *
643 		 * Note: <rdar://problem/5465184> Rename this to "HopefullyNeverExits".
644 		 */
645 		only_once:1,
646 		/* Make job_ignore() / job_watch() work. If these calls were balanced,
647 		 * then this wouldn't be necessarily.
648 		 */
649 		currently_ignored:1,
650 		/* A job that forced all other jobs to be temporarily launch-on-
651 		 * demand
652 		 */
653 		forced_peers_to_demand_mode:1,
654 		// man launchd.plist --> Nice
655 		setnice:1,
656 		/* A job was asked to be unloaded/removed while running, we'll remove it
657 		 * after it exits.
658 		 */
659 		removal_pending:1,
660 		// job_kill() was called.
661 		sent_sigkill:1,
662 		// Enter the kernel debugger before killing a job.
663 		debug_before_kill:1,
664 		// A hack that launchd+launchctl use during jobmgr_t creation.
665 		weird_bootstrap:1,
666 		// man launchd.plist --> StartOnMount
667 		start_on_mount:1,
668 		// This job is a per-user launchd managed by the PID 1 launchd.
669 		per_user:1,
670 		// A job thoroughly confused launchd. We need to unload it ASAP.
671 		unload_at_mig_return:1,
672 		// man launchd.plist --> AbandonProcessGroup
673 		abandon_pg:1,
674 		/* During shutdown, do not send SIGTERM to stray processes in the
675 		 * process group of this job.
676 		 */
677 		ignore_pg_at_shutdown:1,
678 		/* Don't let this job create new 'job_t' objects in launchd. Has been
679 		 * seriously overloaded for the purposes of sandboxing.
680 		 */
681 		deny_job_creation:1,
682 		// man launchd.plist --> EnableTransactions
683 		enable_transactions:1,
684 		// The job was sent SIGKILL because it was clean.
685 		clean_kill:1,
686 		// The job has an OtherJobEnabled KeepAlive criterion.
687 		nosy:1,
688 		// The job exited due to a crash.
689 		crashed:1,
690 		// We've received NOTE_EXIT for the job and reaped it.
691 		reaped:1,
692 		// job_stop() was called.
693 		stopped:1,
694 		/* The job is to be kept alive continuously, but it must first get an
695 		 * initial kick off.
696 		 */
697 		needs_kickoff:1,
698 		// The job is a bootstrapper.
699 		is_bootstrapper:1,
700 		// The job owns the console.
701 		has_console:1,
702 		/* The job runs as a non-root user on embedded but has select privileges
703 		 * of the root user. This is SpringBoard.
704 		 */
705 		embedded_god:1,
706 		// The job is responsible for drawing the home screen on embedded.
707 		embedded_home:1,
708 		// We got NOTE_EXEC for the job.
709 		did_exec:1,
710 		// The job is an XPC service, and XPC proxy successfully exec(3)ed.
711 		xpcproxy_did_exec:1,
712 		// The (anonymous) job called vprocmgr_switch_to_session().
713 		holds_ref:1,
714 		// The job has Jetsam limits in place.
715 		jetsam_properties:1,
716 		// The job's Jetsam memory limits should only be applied in the background
717  		jetsam_memory_limit_background:1,
718 		/* This job was created as the result of a look up of a service provided
719 		 * by a MultipleInstance job.
720 		 */
721 		dedicated_instance:1,
722 		// The job supports creating additional instances of itself.
723 		multiple_instances:1,
724 		/* The sub-job was already removed from the parent's list of
725 		 * sub-jobs.
726 		 */
727 		former_subjob:1,
728 		/* The job is responsible for monitoring external events for this
729 		 * launchd.
730 		 */
731 		event_monitor:1,
732 		// The event monitor job has retrieved the initial list of events.
733 		event_monitor_ready2signal:1,
734 		// A lame hack.
735 		removing:1,
736 		// Disable ASLR when launching this job.
737 		disable_aslr:1,
738 		// The job is an XPC Service.
739 		xpc_service:1,
740 		// The job is the Performance team's shutdown monitor.
741 		shutdown_monitor:1,
742 		// We should open a transaction for the job when shutdown begins.
743 		dirty_at_shutdown:1,
744 		/* The job was sent SIGKILL but did not exit in a timely fashion,
745 		 * indicating a kernel bug.
746 		 */
747 		workaround9359725:1,
748 		// The job is the XPC domain bootstrapper.
749 		xpc_bootstrapper:1,
750 		// The job is an app (on either iOS or OS X) and has different resource
751 		// limitations.
752 		app:1,
753 		// FairPlay decryption failed on the job. This should only ever happen
754 		// to apps.
755 		fpfail:1,
756 		// The job failed to exec(3) for reasons that may be transient, so we're
757 		// waiting for UserEventAgent to tell us when it's okay to try spawning
758 		// again (i.e. when the executable path appears, when the UID appears,
759 		// etc.).
760 		waiting4ok:1,
761 		// The job exited due to memory pressure.
762 		jettisoned:1,
763 		// The job supports idle-exit.
764 		idle_exit:1,
765 		// The job was implicitly reaped by the kernel.
766 		implicit_reap:1,
767 		system_app :1,
768 		joins_gui_session :1,
769 		low_priority_background_io :1,
770 		legacy_timers :1;
771 
772 	const char label[0];
773 };
774 
775 static size_t hash_label(const char *label) __attribute__((pure));
776 static size_t hash_ms(const char *msstr) __attribute__((pure));
777 static SLIST_HEAD(, job_s) s_curious_jobs;
778 static LIST_HEAD(, job_s) managed_actives[ACTIVE_JOB_HASH_SIZE];
779 
780 #define job_assumes(j, e) os_assumes_ctx(job_log_bug, j, (e))
781 #if 1
782 #define job_assumes_zero(j, e) os_assumes_zero_ctx(job_log_bug, j, (e))
783 #else
784 static int
crapout(int value,void * j,const char * e)785 crapout(int value, void *j, const char *e)
786 {
787 	if (value) {
788 		printf("%s=%d j=%p\n", (e), value, j);
789 		abort();
790 	}
791 	return (value);
792 }
793 
794 #define job_assumes_zero(j, e) crapout((e), j, #e)
795 #endif
796 
797 #define job_assumes_zero_p(j, e) posix_assumes_zero_ctx(job_log_bug, j, (e))
798 
799 static void job_import_keys(launch_data_t obj, const char *key, void *context);
800 static void job_import_bool(job_t j, const char *key, bool value);
801 static void job_import_string(job_t j, const char *key, const char *value);
802 static void job_import_integer(job_t j, const char *key, long long value);
803 static void job_import_dictionary(job_t j, const char *key, launch_data_t value);
804 static void job_import_array(job_t j, const char *key, launch_data_t value);
805 static void job_import_opaque(job_t j, const char *key, launch_data_t value);
806 static bool job_set_global_on_demand(job_t j, bool val);
807 static const char *job_active(job_t j);
808 static void job_watch(job_t j);
809 static void job_ignore(job_t j);
810 static void job_reap(job_t j);
811 static bool job_useless(job_t j);
812 static bool job_keepalive(job_t j);
813 static void job_dispatch_curious_jobs(job_t j);
814 static void job_start(job_t j);
815 static void job_start_child(job_t j) __attribute__((noreturn));
816 static void job_setup_attributes(job_t j);
817 static bool job_setup_machport(job_t j);
818 static kern_return_t job_setup_exit_port(job_t j);
819 static void job_setup_fd(job_t j, int target_fd, const char *path, int flags);
820 static void job_postfork_become_user(job_t j);
821 static void job_postfork_test_user(job_t j);
822 static void job_log_pids_with_weird_uids(job_t j);
823 static void job_setup_exception_port(job_t j, task_t target_task);
824 static void job_callback(void *obj, struct kevent *kev);
825 static void job_callback_proc(job_t j, struct kevent *kev);
826 static void job_callback_timer(job_t j, void *ident);
827 static void job_callback_read(job_t j, int ident);
828 static void job_log_stray_pg(job_t j);
829 static void job_log_children_without_exec(job_t j);
830 static job_t job_new_anonymous(jobmgr_t jm, pid_t anonpid) __attribute__((malloc, nonnull, warn_unused_result));
831 static job_t job_new(jobmgr_t jm, const char *label, const char *prog, const char *const *argv) __attribute__((malloc, nonnull(1,2), warn_unused_result));
832 static job_t job_new_alias(jobmgr_t jm, job_t src);
833 static job_t job_new_via_mach_init(job_t j, const char *cmd, uid_t uid, bool ond) __attribute__((malloc, nonnull, warn_unused_result));
834 static job_t job_new_subjob(job_t j, uuid_t identifier);
835 static void job_kill(job_t j);
836 static void job_uncork_fork(job_t j);
837 static void job_logv(job_t j, int pri, int err, const char *msg, va_list ap) __attribute__((format(printf, 4, 0)));
838 static void job_log_error(job_t j, int pri, const char *msg, ...) __attribute__((format(printf, 3, 4)));
839 static bool job_log_bug(_SIMPLE_STRING asl_message, void *ctx, const char *message);
840 static void job_log_perf_statistics(job_t j, struct rusage_info_v1 *ri, int64_t exit_status);
841 #if HAVE_SYSTEMSTATS
842 static void job_log_systemstats(pid_t pid, uint64_t uniqueid, uint64_t parent_uniqueid, pid_t req_pid, uint64_t req_uniqueid, const char *name, struct rusage_info_v1 *ri, int64_t exit_status);
843 #endif
844 static void job_set_exception_port(job_t j, mach_port_t port);
845 static kern_return_t job_mig_spawn_internal(job_t j, vm_offset_t indata, mach_msg_type_number_t indataCnt, mach_port_t asport, job_t *outj);
846 static void job_open_shutdown_transaction(job_t ji);
847 static void job_close_shutdown_transaction(job_t ji);
848 #ifndef __FreeBSD__
849 static launch_data_t job_do_legacy_ipc_request(job_t j, launch_data_t request, mach_port_t asport);
850 #endif
851 static void job_setup_per_user_directory(job_t j, uid_t uid, const char *path);
852 static void job_setup_per_user_directories(job_t j, uid_t uid, const char *label);
853 static void job_update_jetsam_properties(job_t j, xpc_jetsam_band_t band, uint64_t user_data);
854 static void job_update_jetsam_memory_limit(job_t j, int32_t limit);
855 
856 #if TARGET_OS_EMBEDDED
857 static bool job_import_defaults(launch_data_t pload);
858 #endif
859 
860 
861 static struct priority_properties_t {
862 	long long band;
863 	int priority;
864 } _launchd_priority_map[] = {
865 	{ 0, 0}
866 #if 0
867 	{ XPC_JETSAM_BAND_SUSPENDED, JETSAM_PRIORITY_IDLE },
868 	{ XPC_JETSAM_BAND_BACKGROUND_OPPORTUNISTIC, JETSAM_PRIORITY_BACKGROUND_OPPORTUNISTIC },
869 	{ XPC_JETSAM_BAND_BACKGROUND, JETSAM_PRIORITY_BACKGROUND },
870 	{ XPC_JETSAM_BAND_MAIL, JETSAM_PRIORITY_MAIL },
871 	{ XPC_JETSAM_BAND_PHONE, JETSAM_PRIORITY_PHONE },
872 	{ XPC_JETSAM_BAND_UI_SUPPORT, JETSAM_PRIORITY_UI_SUPPORT },
873 	{ XPC_JETSAM_BAND_FOREGROUND_SUPPORT, JETSAM_PRIORITY_FOREGROUND_SUPPORT },
874 	{ XPC_JETSAM_BAND_FOREGROUND, JETSAM_PRIORITY_FOREGROUND },
875 	{ XPC_JETSAM_BAND_AUDIO, JETSAM_PRIORITY_AUDIO_AND_ACCESSORY },
876 	{ XPC_JETSAM_BAND_ACCESSORY, JETSAM_PRIORITY_AUDIO_AND_ACCESSORY },
877 	{ XPC_JETSAM_BAND_CRITICAL, JETSAM_PRIORITY_CRITICAL },
878 	{ XPC_JETSAM_BAND_TELEPHONY, JETSAM_PRIORITY_TELEPHONY },
879 #endif
880 };
881 
882 static const struct {
883 	const char *key;
884 	int val;
885 } launchd_keys2limits[] = {
886 	{ LAUNCH_JOBKEY_RESOURCELIMIT_CORE, RLIMIT_CORE },
887 	{ LAUNCH_JOBKEY_RESOURCELIMIT_CPU, RLIMIT_CPU },
888 	{ LAUNCH_JOBKEY_RESOURCELIMIT_DATA, RLIMIT_DATA },
889 	{ LAUNCH_JOBKEY_RESOURCELIMIT_FSIZE, RLIMIT_FSIZE },
890 	{ LAUNCH_JOBKEY_RESOURCELIMIT_MEMLOCK, RLIMIT_MEMLOCK },
891 	{ LAUNCH_JOBKEY_RESOURCELIMIT_NOFILE, RLIMIT_NOFILE },
892 	{ LAUNCH_JOBKEY_RESOURCELIMIT_NPROC, RLIMIT_NPROC },
893 	{ LAUNCH_JOBKEY_RESOURCELIMIT_RSS, RLIMIT_RSS },
894 	{ LAUNCH_JOBKEY_RESOURCELIMIT_STACK, RLIMIT_STACK },
895 };
896 
897 static time_t cronemu(int mon, int mday, int hour, int min);
898 static time_t cronemu_wday(int wday, int hour, int min);
899 static bool cronemu_mon(struct tm *wtm, int mon, int mday, int hour, int min);
900 static bool cronemu_mday(struct tm *wtm, int mday, int hour, int min);
901 static bool cronemu_hour(struct tm *wtm, int hour, int min);
902 static bool cronemu_min(struct tm *wtm, int min);
903 
904 // miscellaneous file local functions
905 static size_t get_kern_max_proc(void);
906 static char **mach_cmd2argv(const char *string);
907 static size_t our_strhash(const char *s) __attribute__((pure));
908 
909 void eliminate_double_reboot(void);
910 
911 #pragma mark XPC Domain Forward Declarations
912 static job_t _xpc_domain_import_service(jobmgr_t jm, launch_data_t pload);
913 static int _xpc_domain_import_services(job_t j, launch_data_t services);
914 
915 #pragma mark XPC Event Forward Declarations
916 static int xpc_event_find_channel(job_t j, const char *stream, struct machservice **ms);
917 static int xpc_event_get_event_name(job_t j, xpc_object_t request, xpc_object_t *reply);
918 static int xpc_event_set_event(job_t j, xpc_object_t request, xpc_object_t *reply);
919 static int xpc_event_copy_event(job_t j, xpc_object_t request, xpc_object_t *reply);
920 static int xpc_event_channel_check_in(job_t j, xpc_object_t request, xpc_object_t *reply);
921 static int xpc_event_channel_look_up(job_t j, xpc_object_t request, xpc_object_t *reply);
922 static int xpc_event_provider_check_in(job_t j, xpc_object_t request, xpc_object_t *reply);
923 static int xpc_event_provider_set_state(job_t j, xpc_object_t request, xpc_object_t *reply);
924 
925 #pragma mark XPC Process Forward Declarations
926 static int xpc_process_set_jetsam_band(job_t j, xpc_object_t request, xpc_object_t *reply);
927 static int xpc_process_set_jetsam_memory_limit(job_t j, xpc_object_t request, xpc_object_t *reply);
928 
929 // file local globals
930 static job_t _launchd_embedded_god = NULL;
931 static job_t _launchd_embedded_home = NULL;
932 static size_t total_children;
933 static size_t total_anon_children;
934 static mach_port_t the_exception_server;
935 static job_t workaround_5477111;
936 static LIST_HEAD(, job_s) s_needing_sessions;
937 static LIST_HEAD(, eventsystem) _s_event_systems;
938 static struct eventsystem *_launchd_support_system;
939 static job_t _launchd_event_monitor;
940 static job_t _launchd_xpc_bootstrapper;
941 static job_t _launchd_shutdown_monitor;
942 
943 #if TARGET_OS_EMBEDDED
944 static xpc_object_t _launchd_defaults_cache;
945 
946 mach_port_t launchd_audit_port = MACH_PORT_DEAD;
947 pid_t launchd_audit_session = 0;
948 #else
949 mach_port_t launchd_audit_port = MACH_PORT_NULL;
950 au_asid_t launchd_audit_session = AU_DEFAUDITSID;
951 #endif
952 
953 static int s_no_hang_fd = -1;
954 
955 // process wide globals
956 mach_port_t inherited_bootstrap_port;
957 jobmgr_t root_jobmgr;
958 bool launchd_shutdown_debugging = false;
959 bool launchd_verbose_boot = false;
960 bool launchd_embedded_handofgod = false;
961 bool launchd_runtime_busy_time = false;
962 
963 void
job_ignore(job_t j)964 job_ignore(job_t j)
965 {
966 	struct socketgroup *sg;
967 	struct machservice *ms;
968 
969 	if (j->currently_ignored) {
970 		return;
971 	}
972 
973 	job_log(j, LOG_DEBUG, "Ignoring...");
974 
975 	j->currently_ignored = true;
976 
977 	SLIST_FOREACH(sg, &j->sockets, sle) {
978 		socketgroup_ignore(j, sg);
979 	}
980 
981 	SLIST_FOREACH(ms, &j->machservices, sle) {
982 		machservice_ignore(j, ms);
983 	}
984 }
985 
986 void
job_watch(job_t j)987 job_watch(job_t j)
988 {
989 	struct socketgroup *sg;
990 	struct machservice *ms;
991 
992 	if (!j->currently_ignored) {
993 		return;
994 	}
995 
996 	job_log(j, LOG_DEBUG, "Watching...");
997 
998 	j->currently_ignored = false;
999 
1000 	SLIST_FOREACH(sg, &j->sockets, sle) {
1001 		socketgroup_watch(j, sg);
1002 	}
1003 
1004 	SLIST_FOREACH(ms, &j->machservices, sle) {
1005 		machservice_watch(j, ms);
1006 	}
1007 }
1008 
1009 void
job_stop(job_t j)1010 job_stop(job_t j)
1011 {
1012 	int sig;
1013 
1014 	if (unlikely(!j->p || j->stopped || j->anonymous)) {
1015 		return;
1016 	}
1017 
1018 #if TARGET_OS_EMBEDDED
1019 	if (launchd_embedded_handofgod && _launchd_embedded_god) {
1020 		if (!_launchd_embedded_god->username || !j->username) {
1021 			errno = EPERM;
1022 			return;
1023 		}
1024 
1025 		if (strcmp(j->username, _launchd_embedded_god->username) != 0) {
1026 			errno = EPERM;
1027 			return;
1028 		}
1029 	} else if (launchd_embedded_handofgod) {
1030 		errno = EINVAL;
1031 		return;
1032 	}
1033 #endif
1034 
1035 	j->sent_signal_time = runtime_get_opaque_time();
1036 
1037 	job_log(j, LOG_DEBUG | LOG_CONSOLE, "Stopping job...");
1038 
1039 	int error = -1;
1040 	error = proc_terminate(j->p, &sig);
1041 	if (error) {
1042 		job_log(j, LOG_ERR | LOG_CONSOLE, "Could not terminate job: %d: %s", error, strerror(error));
1043 		job_log(j, LOG_NOTICE | LOG_CONSOLE, "Using fallback option to terminate job...");
1044 		error = kill2(j->p, SIGTERM);
1045 		if (error) {
1046 			job_log(j, LOG_ERR, "Could not signal job: %d: %s", error, strerror(error));
1047 		} else {
1048 			sig = SIGTERM;
1049 		}
1050 	}
1051 
1052 	if (!error) {
1053 		switch (sig) {
1054 		case SIGKILL:
1055 			j->sent_sigkill = true;
1056 			j->clean_kill = true;
1057 
1058 			/* We cannot effectively simulate an exit for jobs during the course
1059 			 * of a normal run. Even if we pretend that the job exited, we will
1060 			 * still not have gotten the receive rights associated with the
1061 			 * job's MachServices back, so we cannot safely respawn it.
1062 			 */
1063 			if (j->mgr->shutting_down) {
1064 				error = kevent_mod((uintptr_t)&j->exit_timeout, EVFILT_TIMER, EV_ADD|EV_ONESHOT, NOTE_SECONDS, LAUNCHD_SIGKILL_TIMER, j);
1065 				(void)job_assumes_zero_p(j, error);
1066 			}
1067 
1068 			job_log(j, LOG_DEBUG | LOG_CONSOLE, "Sent job SIGKILL.");
1069 			break;
1070 		case SIGTERM:
1071 			if (j->exit_timeout) {
1072 				error = kevent_mod((uintptr_t)&j->exit_timeout, EVFILT_TIMER, EV_ADD|EV_ONESHOT, NOTE_SECONDS, j->exit_timeout, j);
1073 				(void)job_assumes_zero_p(j, error);
1074 			} else {
1075 				job_log(j, LOG_NOTICE, "This job has an infinite exit timeout");
1076 			}
1077 			job_log(j, LOG_DEBUG, "Sent job SIGTERM.");
1078 			break;
1079 		default:
1080 			job_log(j, LOG_ERR | LOG_CONSOLE, "Job was sent unexpected signal: %d: %s", sig, strsignal(sig));
1081 			break;
1082 		}
1083 	}
1084 
1085 	j->stopped = true;
1086 }
1087 
1088 launch_data_t
job_export(job_t j)1089 job_export(job_t j)
1090 {
1091 	launch_data_t tmp, tmp2, tmp3, r = launch_data_alloc(LAUNCH_DATA_DICTIONARY);
1092 
1093 	if (r == NULL) {
1094 		return NULL;
1095 	}
1096 
1097 	if ((tmp = launch_data_new_string(j->label))) {
1098 		launch_data_dict_insert(r, tmp, LAUNCH_JOBKEY_LABEL);
1099 	}
1100 	if ((tmp = launch_data_new_string(j->mgr->name))) {
1101 		launch_data_dict_insert(r, tmp, LAUNCH_JOBKEY_LIMITLOADTOSESSIONTYPE);
1102 	}
1103 	if ((tmp = launch_data_new_bool(j->ondemand))) {
1104 		launch_data_dict_insert(r, tmp, LAUNCH_JOBKEY_ONDEMAND);
1105 	}
1106 
1107 	long long status = j->last_exit_status;
1108 	if (j->fpfail) {
1109 		status = LAUNCH_EXITSTATUS_FAIRPLAY_FAIL;
1110 	}
1111 	if ((tmp = launch_data_new_integer(status))) {
1112 		launch_data_dict_insert(r, tmp, LAUNCH_JOBKEY_LASTEXITSTATUS);
1113 	}
1114 
1115 	if (j->p && (tmp = launch_data_new_integer(j->p))) {
1116 		launch_data_dict_insert(r, tmp, LAUNCH_JOBKEY_PID);
1117 	}
1118 	if ((tmp = launch_data_new_integer(j->timeout))) {
1119 		launch_data_dict_insert(r, tmp, LAUNCH_JOBKEY_TIMEOUT);
1120 	}
1121 	if (j->prog && (tmp = launch_data_new_string(j->prog))) {
1122 		launch_data_dict_insert(r, tmp, LAUNCH_JOBKEY_PROGRAM);
1123 	}
1124 	if (j->stdinpath && (tmp = launch_data_new_string(j->stdinpath))) {
1125 		launch_data_dict_insert(r, tmp, LAUNCH_JOBKEY_STANDARDINPATH);
1126 	}
1127 	if (j->stdoutpath && (tmp = launch_data_new_string(j->stdoutpath))) {
1128 		launch_data_dict_insert(r, tmp, LAUNCH_JOBKEY_STANDARDOUTPATH);
1129 	}
1130 	if (j->stderrpath && (tmp = launch_data_new_string(j->stderrpath))) {
1131 		launch_data_dict_insert(r, tmp, LAUNCH_JOBKEY_STANDARDERRORPATH);
1132 	}
1133 	if (likely(j->argv) && (tmp = launch_data_alloc(LAUNCH_DATA_ARRAY))) {
1134 		size_t i;
1135 
1136 		for (i = 0; i < j->argc; i++) {
1137 			if ((tmp2 = launch_data_new_string(j->argv[i]))) {
1138 				launch_data_array_set_index(tmp, tmp2, i);
1139 			}
1140 		}
1141 
1142 		launch_data_dict_insert(r, tmp, LAUNCH_JOBKEY_PROGRAMARGUMENTS);
1143 	}
1144 
1145 	if (!SLIST_EMPTY(&j->env) && (tmp = launch_data_alloc(LAUNCH_DATA_DICTIONARY))) {
1146 		struct envitem *ei = NULL;
1147 		SLIST_FOREACH(ei, &j->env, sle) {
1148 			launch_data_dict_insert(tmp, launch_data_new_string(ei->value), ei->key);
1149 		}
1150 
1151 		launch_data_dict_insert(r, tmp, LAUNCH_JOBKEY_ENVIRONMENTVARIABLES);
1152 	}
1153 
1154 	if (j->enable_transactions && (tmp = launch_data_new_bool(true))) {
1155 		launch_data_dict_insert(r, tmp, LAUNCH_JOBKEY_ENABLETRANSACTIONS);
1156 	}
1157 
1158 	if (j->session_create && (tmp = launch_data_new_bool(true))) {
1159 		launch_data_dict_insert(r, tmp, LAUNCH_JOBKEY_SESSIONCREATE);
1160 	}
1161 
1162 	if (j->inetcompat && (tmp = launch_data_alloc(LAUNCH_DATA_DICTIONARY))) {
1163 		if ((tmp2 = launch_data_new_bool(j->inetcompat_wait))) {
1164 			launch_data_dict_insert(tmp, tmp2, LAUNCH_JOBINETDCOMPATIBILITY_WAIT);
1165 		}
1166 		launch_data_dict_insert(r, tmp, LAUNCH_JOBKEY_INETDCOMPATIBILITY);
1167 	}
1168 
1169 	if (!SLIST_EMPTY(&j->sockets) && (tmp = launch_data_alloc(LAUNCH_DATA_DICTIONARY))) {
1170 		struct socketgroup *sg;
1171 		unsigned int i;
1172 
1173 		SLIST_FOREACH(sg, &j->sockets, sle) {
1174 			if ((tmp2 = launch_data_alloc(LAUNCH_DATA_ARRAY))) {
1175 				for (i = 0; i < sg->fd_cnt; i++) {
1176 					if ((tmp3 = launch_data_new_fd(sg->fds[i]))) {
1177 						launch_data_array_set_index(tmp2, tmp3, i);
1178 					}
1179 				}
1180 				launch_data_dict_insert(tmp, tmp2, sg->name);
1181 			}
1182 		}
1183 
1184 		launch_data_dict_insert(r, tmp, LAUNCH_JOBKEY_SOCKETS);
1185 	}
1186 
1187 	if (!SLIST_EMPTY(&j->machservices) && (tmp = launch_data_alloc(LAUNCH_DATA_DICTIONARY))) {
1188 		struct machservice *ms;
1189 
1190 		tmp3 = NULL;
1191 
1192 		SLIST_FOREACH(ms, &j->machservices, sle) {
1193 			if (ms->per_pid) {
1194 				if (tmp3 == NULL) {
1195 					tmp3 = launch_data_alloc(LAUNCH_DATA_DICTIONARY);
1196 				}
1197 				if (tmp3) {
1198 					tmp2 = launch_data_new_machport(MACH_PORT_NULL);
1199 					launch_data_dict_insert(tmp3, tmp2, ms->name);
1200 				}
1201 			} else {
1202 				tmp2 = launch_data_new_machport(MACH_PORT_NULL);
1203 				launch_data_dict_insert(tmp, tmp2, ms->name);
1204 			}
1205 		}
1206 
1207 		launch_data_dict_insert(r, tmp, LAUNCH_JOBKEY_MACHSERVICES);
1208 
1209 		if (tmp3) {
1210 			launch_data_dict_insert(r, tmp3, LAUNCH_JOBKEY_PERJOBMACHSERVICES);
1211 		}
1212 	}
1213 
1214 	return r;
1215 }
1216 
1217 static void
jobmgr_log_active_jobs(jobmgr_t jm)1218 jobmgr_log_active_jobs(jobmgr_t jm)
1219 {
1220 	const char *why_active;
1221 	jobmgr_t jmi;
1222 	job_t ji;
1223 
1224 	SLIST_FOREACH(jmi, &jm->submgrs, sle) {
1225 		jobmgr_log_active_jobs(jmi);
1226 	}
1227 
1228 	int level = LOG_DEBUG;
1229 	if (pid1_magic) {
1230 		level |= LOG_CONSOLE;
1231 	}
1232 
1233 	LIST_FOREACH(ji, &jm->jobs, sle) {
1234 		if ((why_active = job_active(ji))) {
1235 			if (ji->p != 1) {
1236 				job_log(ji, level, "%s", why_active);
1237 
1238 				uint32_t flags = 0;
1239 				(void)proc_get_dirty(ji->p, &flags);
1240 				if (!(flags & PROC_DIRTY_TRACKED)) {
1241 					continue;
1242 				}
1243 
1244 				const char *dirty = "clean";
1245 				if (flags & PROC_DIRTY_IS_DIRTY) {
1246 					dirty = "dirty";
1247 				}
1248 
1249 				const char *idle_exit = "idle-exit unsupported";
1250 				if (flags & PROC_DIRTY_ALLOWS_IDLE_EXIT) {
1251 					idle_exit = "idle-exit supported";
1252 				}
1253 
1254 				job_log(ji, level, "Killability: %s/%s", dirty, idle_exit);
1255 			}
1256 		}
1257 	}
1258 }
1259 
1260 static void
jobmgr_still_alive_with_check(jobmgr_t jm)1261 jobmgr_still_alive_with_check(jobmgr_t jm)
1262 {
1263 	int level = LOG_DEBUG;
1264 	if (pid1_magic) {
1265 		level |= LOG_CONSOLE;
1266 	}
1267 
1268 	jobmgr_log(jm, level, "Still alive with %lu/%lu (normal/anonymous) children.", total_children, total_anon_children);
1269 	jobmgr_log_active_jobs(jm);
1270 	launchd_log_push();
1271 }
1272 
1273 jobmgr_t
jobmgr_shutdown(jobmgr_t jm)1274 jobmgr_shutdown(jobmgr_t jm)
1275 {
1276 	jobmgr_t jmi, jmn;
1277 	launchd_syslog(LOG_CRIT, "Beginning job manager shutdown with flags: %s", reboot_flags_to_C_names(jm->reboot_flags));
1278 	jobmgr_log(jm, LOG_DEBUG, "Beginning job manager shutdown with flags: %s", reboot_flags_to_C_names(jm->reboot_flags));
1279 
1280 	jm->shutdown_time = runtime_get_wall_time() / USEC_PER_SEC;
1281 
1282 	struct tm curtime;
1283 	(void)localtime_r(&jm->shutdown_time, &curtime);
1284 
1285 	char date[26];
1286 	(void)asctime_r(&curtime, date);
1287 	// Trim the new line that asctime_r(3) puts there for some reason.
1288 	date[24] = 0;
1289 
1290 	if (jm == root_jobmgr && pid1_magic) {
1291 		jobmgr_log(jm, LOG_DEBUG | LOG_CONSOLE, "Userspace shutdown begun at: %s", date);
1292 	} else {
1293 		jobmgr_log(jm, LOG_DEBUG, "Job manager shutdown begun at: %s", date);
1294 	}
1295 
1296 	jm->shutting_down = true;
1297 
1298 	SLIST_FOREACH_SAFE(jmi, &jm->submgrs, sle, jmn) {
1299 		jobmgr_shutdown(jmi);
1300 	}
1301 
1302 	if (!jm->parentmgr) {
1303 		if (pid1_magic) {
1304 			// Spawn the shutdown monitor.
1305 			if (_launchd_shutdown_monitor && !_launchd_shutdown_monitor->p) {
1306 				job_log(_launchd_shutdown_monitor, LOG_NOTICE | LOG_CONSOLE, "Starting shutdown monitor.");
1307 				job_dispatch(_launchd_shutdown_monitor, true);
1308 			}
1309 		}
1310 
1311 		(void)jobmgr_assumes_zero_p(jm, kevent_mod((uintptr_t)jm, EVFILT_TIMER, EV_ADD, NOTE_SECONDS, 5, jm));
1312 	}
1313 
1314 	return jobmgr_do_garbage_collection(jm);
1315 }
1316 
1317 void
jobmgr_remove(jobmgr_t jm)1318 jobmgr_remove(jobmgr_t jm)
1319 {
1320 	jobmgr_t jmi;
1321 	job_t ji;
1322 
1323 	jobmgr_log(jm, LOG_DEBUG, "Removing job manager.");
1324 	if (!SLIST_EMPTY(&jm->submgrs)) {
1325 		size_t cnt = 0;
1326 		while ((jmi = SLIST_FIRST(&jm->submgrs))) {
1327 			jobmgr_remove(jmi);
1328 			cnt++;
1329 		}
1330 
1331 		(void)jobmgr_assumes_zero(jm, cnt);
1332 	}
1333 
1334 	while ((ji = LIST_FIRST(&jm->jobs))) {
1335 		if (!ji->anonymous && ji->p != 0) {
1336 			job_log(ji, LOG_ERR, "Job is still active at job manager teardown.");
1337 			ji->p = 0;
1338 		}
1339 
1340 		job_remove(ji);
1341 	}
1342 
1343 	struct waiting4attach *w4ai = NULL;
1344 	while ((w4ai = LIST_FIRST(&jm->attaches))) {
1345 		waiting4attach_delete(jm, w4ai);
1346 	}
1347 
1348 	if (jm->req_port) {
1349 		(void)jobmgr_assumes_zero(jm, launchd_mport_deallocate(jm->req_port));
1350 	}
1351 	if (jm->jm_port) {
1352 		(void)jobmgr_assumes_zero(jm, launchd_mport_close_recv(jm->jm_port));
1353 	}
1354 
1355 	if (jm->req_bsport) {
1356 		(void)jobmgr_assumes_zero(jm, launchd_mport_deallocate(jm->req_bsport));
1357 	}
1358 	if (jm->req_excport) {
1359 		(void)jobmgr_assumes_zero(jm, launchd_mport_deallocate(jm->req_excport));
1360 	}
1361 	if (MACH_PORT_VALID(jm->req_asport)) {
1362 		(void)jobmgr_assumes_zero(jm, launchd_mport_deallocate(jm->req_asport));
1363 	}
1364 	if (jm->req_rport) {
1365 		kern_return_t kr = xpc_call_wakeup(jm->req_rport, jm->error);
1366 		if (!(kr == KERN_SUCCESS || kr == MACH_SEND_INVALID_DEST)) {
1367 			/* If the originator went away, the reply port will be a dead name,
1368 			 * and we expect this to fail.
1369 			 */
1370 			(void)jobmgr_assumes_zero(jm, kr);
1371 		}
1372 	}
1373 	if (jm->req_ctx) {
1374 		(void)jobmgr_assumes_zero(jm, vm_deallocate(mach_task_self(), jm->req_ctx, jm->req_ctx_sz));
1375 	}
1376 
1377 	time_t ts = runtime_get_wall_time() / USEC_PER_SEC;
1378 	struct tm curtime;
1379 	(void)localtime_r(&ts, &curtime);
1380 
1381 	char date[26];
1382 	(void)asctime_r(&curtime, date);
1383 	date[24] = 0;
1384 
1385 	time_t delta = ts - jm->shutdown_time;
1386 	if (jm == root_jobmgr && pid1_magic) {
1387 		jobmgr_log(jm, LOG_DEBUG | LOG_CONSOLE, "Userspace shutdown finished at: %s", date);
1388 		jobmgr_log(jm, LOG_DEBUG | LOG_CONSOLE, "Userspace shutdown took approximately %ld second%s.", delta, (delta != 1) ? "s" : "");
1389 	} else {
1390 		jobmgr_log(jm, LOG_DEBUG, "Job manager shutdown finished at: %s", date);
1391 		jobmgr_log(jm, LOG_DEBUG, "Job manager shutdown took approximately %ld second%s.", delta, (delta != 1) ? "s" : "");
1392 	}
1393 
1394 	if (jm->parentmgr) {
1395 		runtime_del_weak_ref();
1396 		SLIST_REMOVE(&jm->parentmgr->submgrs, jm, jobmgr_s, sle);
1397 
1398 		// Hack for the guest user so that its stuff doesn't persist.
1399 		//
1400 		// <rdar://problem/14527875>
1401 		if (strcmp(jm->name, VPROCMGR_SESSION_AQUA) == 0 && getuid() == 201) {
1402 			raise(SIGTERM);
1403 		}
1404 	} else if (pid1_magic) {
1405 		eliminate_double_reboot();
1406 		launchd_log_vm_stats();
1407 		jobmgr_log_stray_children(jm, true);
1408 		jobmgr_log(root_jobmgr, LOG_NOTICE | LOG_CONSOLE, "About to call: reboot(%s).", reboot_flags_to_C_names(jm->reboot_flags));
1409 
1410 		syslog(LOG_CRIT, "About to call reboot, flags = %#x (%s)", jm->reboot_flags, reboot_flags_to_C_names(jm->reboot_flags));
1411 		launchd_closelog();
1412 		(void)jobmgr_assumes_zero_p(jm, reboot(jm->reboot_flags));
1413 	} else {
1414 		jobmgr_log(jm, LOG_DEBUG, "About to exit");
1415 		launchd_closelog();
1416 		exit(EXIT_SUCCESS);
1417 	}
1418 
1419 	free(jm);
1420 }
1421 
1422 void
job_remove(job_t j)1423 job_remove(job_t j)
1424 {
1425 	struct waiting_for_removal *w4r;
1426 	struct calendarinterval *ci;
1427 	struct semaphoreitem *si;
1428 	struct socketgroup *sg;
1429 	struct machservice *ms;
1430 	struct limititem *li;
1431 	struct envitem *ei;
1432 
1433 	if (j->alias) {
1434 		/* HACK: Egregious code duplication. But as with machservice_delete(),
1435 		 * job aliases can't (and shouldn't) have any complex behaviors
1436 		 * associated with them.
1437 		 */
1438 		while ((ms = SLIST_FIRST(&j->machservices))) {
1439 			machservice_delete(j, ms, false);
1440 		}
1441 
1442 		LIST_REMOVE(j, sle);
1443 		LIST_REMOVE(j, label_hash_sle);
1444 		free(j);
1445 		return;
1446 	}
1447 
1448 #if TARGET_OS_EMBEDDED
1449 	if (launchd_embedded_handofgod && _launchd_embedded_god) {
1450 		if (!(_launchd_embedded_god->username && j->username)) {
1451 			errno = EPERM;
1452 			return;
1453 		}
1454 
1455 		if (strcmp(j->username, _launchd_embedded_god->username) != 0) {
1456 			errno = EPERM;
1457 			return;
1458 		}
1459 	} else if (launchd_embedded_handofgod) {
1460 		errno = EINVAL;
1461 		return;
1462 	}
1463 #endif
1464 
1465 	/* Do this BEFORE we check and see whether the job is still active. If we're
1466 	 * a sub-job, we're being removed due to the parent job removing us.
1467 	 * Therefore, the parent job will free itself after this call completes. So
1468 	 * if we defer removing ourselves from the parent's list, we'll crash when
1469 	 * we finally get around to it.
1470 	 */
1471 	if (j->dedicated_instance && !j->former_subjob) {
1472 		LIST_REMOVE(j, subjob_sle);
1473 		j->former_subjob = true;
1474 	}
1475 
1476 	if (unlikely(j->p)) {
1477 		if (j->anonymous) {
1478 			job_reap(j);
1479 		} else {
1480 			job_log(j, LOG_DEBUG, "Removal pended until the job exits");
1481 
1482 			if (!j->removal_pending) {
1483 				j->removal_pending = true;
1484 				job_stop(j);
1485 			}
1486 
1487 			return;
1488 		}
1489 	}
1490 
1491 	if (!j->removing) {
1492 		j->removing = true;
1493 		job_dispatch_curious_jobs(j);
1494 	}
1495 
1496 	ipc_close_all_with_job(j);
1497 
1498 	if (j->forced_peers_to_demand_mode) {
1499 		job_set_global_on_demand(j, false);
1500 	}
1501 
1502 	if (job_assumes_zero(j, j->fork_fd)) {
1503 		(void)posix_assumes_zero(runtime_close(j->fork_fd));
1504 	}
1505 
1506 	if (j->stdin_fd) {
1507 		(void)posix_assumes_zero(runtime_close(j->stdin_fd));
1508 	}
1509 
1510 	if (j->j_port) {
1511 		(void)job_assumes_zero(j, launchd_mport_close_recv(j->j_port));
1512 	}
1513 
1514 	while ((sg = SLIST_FIRST(&j->sockets))) {
1515 		socketgroup_delete(j, sg);
1516 	}
1517 	while ((ci = SLIST_FIRST(&j->cal_intervals))) {
1518 		calendarinterval_delete(j, ci);
1519 	}
1520 	while ((ei = SLIST_FIRST(&j->env))) {
1521 		envitem_delete(j, ei, false);
1522 	}
1523 	while ((ei = SLIST_FIRST(&j->global_env))) {
1524 		envitem_delete(j, ei, true);
1525 	}
1526 	while ((li = SLIST_FIRST(&j->limits))) {
1527 		limititem_delete(j, li);
1528 	}
1529 	while ((ms = SLIST_FIRST(&j->machservices))) {
1530 		machservice_delete(j, ms, false);
1531 	}
1532 	while ((si = SLIST_FIRST(&j->semaphores))) {
1533 		semaphoreitem_delete(j, si);
1534 	}
1535 	while ((w4r = SLIST_FIRST(&j->removal_watchers))) {
1536 		waiting4removal_delete(j, w4r);
1537 	}
1538 
1539 	struct externalevent *eei = NULL;
1540 	while ((eei = LIST_FIRST(&j->events))) {
1541 		externalevent_delete(eei);
1542 	}
1543 
1544 	if (j->event_monitor) {
1545 		_launchd_event_monitor = NULL;
1546 	}
1547 	if (j->xpc_bootstrapper) {
1548 		_launchd_xpc_bootstrapper = NULL;
1549 	}
1550 
1551 	if (j->prog) {
1552 		free(j->prog);
1553 	}
1554 	if (j->argv) {
1555 		free(j->argv);
1556 	}
1557 	if (j->rootdir) {
1558 		free(j->rootdir);
1559 	}
1560 	if (j->workingdir) {
1561 		free(j->workingdir);
1562 	}
1563 	if (j->username) {
1564 		free(j->username);
1565 	}
1566 	if (j->groupname) {
1567 		free(j->groupname);
1568 	}
1569 	if (j->stdinpath) {
1570 		free(j->stdinpath);
1571 	}
1572 	if (j->stdoutpath) {
1573 		free(j->stdoutpath);
1574 	}
1575 	if (j->stderrpath) {
1576 		free(j->stderrpath);
1577 	}
1578 	if (j->alt_exc_handler) {
1579 		free(j->alt_exc_handler);
1580 	}
1581 	if (j->cfbundleidentifier) {
1582 		free(j->cfbundleidentifier);
1583 	}
1584 #if HAVE_SANDBOX
1585 	if (j->seatbelt_profile) {
1586 		free(j->seatbelt_profile);
1587 	}
1588 	if (j->container_identifier) {
1589 		free(j->container_identifier);
1590 	}
1591 #endif
1592 #if HAVE_QUARANTINE
1593 	if (j->quarantine_data) {
1594 		free(j->quarantine_data);
1595 	}
1596 #endif
1597 	if (j->j_binpref) {
1598 		free(j->j_binpref);
1599 	}
1600 	if (j->start_interval) {
1601 		runtime_del_weak_ref();
1602 		(void)job_assumes_zero_p(j, kevent_mod((uintptr_t)&j->start_interval, EVFILT_TIMER, EV_DELETE, 0, 0, NULL));
1603 	}
1604 	if (j->exit_timeout) {
1605 		/* If this fails, it just means the timer's already fired, so no need to
1606 		 * wrap it in an assumes() macro.
1607 		 */
1608 		(void)kevent_mod((uintptr_t)&j->exit_timeout, EVFILT_TIMER, EV_DELETE, 0, 0, NULL);
1609 	}
1610 	if (j->asport != MACH_PORT_NULL) {
1611 		(void)job_assumes_zero(j, launchd_mport_deallocate(j->asport));
1612 	}
1613 	if (!uuid_is_null(j->expected_audit_uuid)) {
1614 		LIST_REMOVE(j, needing_session_sle);
1615 	}
1616 	if (j->embedded_god) {
1617 		_launchd_embedded_god = NULL;
1618 	}
1619 	if (j->embedded_home) {
1620 		_launchd_embedded_home = NULL;
1621 	}
1622 	if (j->shutdown_monitor) {
1623 		_launchd_shutdown_monitor = NULL;
1624 	}
1625 
1626 	(void)kevent_mod((uintptr_t)j, EVFILT_TIMER, EV_DELETE, 0, 0, NULL);
1627 
1628 	LIST_REMOVE(j, sle);
1629 	LIST_REMOVE(j, label_hash_sle);
1630 
1631 	job_t ji = NULL;
1632 	job_t jit = NULL;
1633 	LIST_FOREACH_SAFE(ji, &j->subjobs, subjob_sle, jit) {
1634 		job_remove(ji);
1635 	}
1636 
1637 	job_log(j, LOG_DEBUG, "Removed");
1638 
1639 	j->kqjob_callback = (kq_callback)0x8badf00d;
1640 	free(j);
1641 }
1642 
1643 void
socketgroup_setup(launch_data_t obj,const char * key,void * context)1644 socketgroup_setup(launch_data_t obj, const char *key, void *context)
1645 {
1646 	launch_data_t tmp_oai;
1647 	job_t j = context;
1648 	size_t i, fd_cnt = 1;
1649 	int *fds;
1650 
1651 	if (launch_data_get_type(obj) == LAUNCH_DATA_ARRAY) {
1652 		fd_cnt = launch_data_array_get_count(obj);
1653 	}
1654 
1655 	fds = alloca(fd_cnt * sizeof(int));
1656 
1657 	for (i = 0; i < fd_cnt; i++) {
1658 		if (launch_data_get_type(obj) == LAUNCH_DATA_ARRAY) {
1659 			tmp_oai = launch_data_array_get_index(obj, i);
1660 		} else {
1661 			tmp_oai = obj;
1662 		}
1663 
1664 		fds[i] = launch_data_get_fd(tmp_oai);
1665 	}
1666 
1667 	socketgroup_new(j, key, fds, fd_cnt);
1668 
1669 	ipc_revoke_fds(obj);
1670 }
1671 
1672 bool
job_set_global_on_demand(job_t j,bool val)1673 job_set_global_on_demand(job_t j, bool val)
1674 {
1675 	if (j->forced_peers_to_demand_mode && val) {
1676 		return false;
1677 	} else if (!j->forced_peers_to_demand_mode && !val) {
1678 		return false;
1679 	}
1680 
1681 	if ((j->forced_peers_to_demand_mode = val)) {
1682 		j->mgr->global_on_demand_cnt++;
1683 	} else {
1684 		j->mgr->global_on_demand_cnt--;
1685 	}
1686 
1687 	if (j->mgr->global_on_demand_cnt == 0) {
1688 		jobmgr_dispatch_all(j->mgr, false);
1689 	}
1690 
1691 	return true;
1692 }
1693 
1694 bool
job_setup_machport(job_t j)1695 job_setup_machport(job_t j)
1696 {
1697 	if (job_assumes_zero(j, launchd_mport_create_recv(&j->j_port)) != KERN_SUCCESS) {
1698 		goto out_bad;
1699 	}
1700 
1701 	if (job_assumes_zero(j, runtime_add_mport(j->j_port, job_server)) != KERN_SUCCESS) {
1702 		goto out_bad2;
1703 	}
1704 
1705 	if (job_assumes_zero(j, launchd_mport_notify_req(j->j_port, MACH_NOTIFY_NO_SENDERS)) != KERN_SUCCESS) {
1706 		(void)job_assumes_zero(j, launchd_mport_close_recv(j->j_port));
1707 		goto out_bad;
1708 	}
1709 
1710 	return true;
1711 out_bad2:
1712 	(void)job_assumes_zero(j, launchd_mport_close_recv(j->j_port));
1713 out_bad:
1714 	return false;
1715 }
1716 
1717 kern_return_t
job_setup_exit_port(job_t j)1718 job_setup_exit_port(job_t j)
1719 {
1720 	kern_return_t kr = launchd_mport_create_recv(&j->exit_status_port);
1721 	if (job_assumes_zero(j, kr) != KERN_SUCCESS) {
1722 		return MACH_PORT_NULL;
1723 	}
1724 
1725 	struct mach_port_limits limits = {
1726 		.mpl_qlimit = 1,
1727 	};
1728 	kr = mach_port_set_attributes(mach_task_self(), j->exit_status_port, MACH_PORT_LIMITS_INFO, (mach_port_info_t)&limits, sizeof(limits));
1729 	(void)job_assumes_zero(j, kr);
1730 
1731 	kr = launchd_mport_make_send_once(j->exit_status_port, &j->exit_status_dest);
1732 	if (job_assumes_zero(j, kr) != KERN_SUCCESS) {
1733 		(void)job_assumes_zero(j, launchd_mport_close_recv(j->exit_status_port));
1734 		j->exit_status_port = MACH_PORT_NULL;
1735 	}
1736 
1737 	return kr;
1738 }
1739 
1740 job_t
job_new_via_mach_init(job_t j,const char * cmd,uid_t uid,bool ond)1741 job_new_via_mach_init(job_t j, const char *cmd, uid_t uid, bool ond)
1742 {
1743 	const char **argv = (const char **)mach_cmd2argv(cmd);
1744 	job_t jr = NULL;
1745 
1746 	if (!argv) {
1747 		goto out_bad;
1748 	}
1749 
1750 	jr = job_new(j->mgr, AUTO_PICK_LEGACY_LABEL, NULL, argv);
1751 	free(argv);
1752 
1753 	// Job creation can be denied during shutdown.
1754 	if (unlikely(jr == NULL)) {
1755 		goto out_bad;
1756 	}
1757 
1758 	jr->mach_uid = uid;
1759 	jr->ondemand = ond;
1760 	jr->legacy_mach_job = true;
1761 	jr->abandon_pg = true;
1762 	jr->priv_port_has_senders = true; // the IPC that called us will make-send on this port
1763 
1764 	if (!job_setup_machport(jr)) {
1765 		goto out_bad;
1766 	}
1767 
1768 	job_log(jr, LOG_INFO, "Legacy%s server created", ond ? " on-demand" : "");
1769 
1770 	return jr;
1771 
1772 out_bad:
1773 	if (jr) {
1774 		job_remove(jr);
1775 	}
1776 	return NULL;
1777 }
1778 
1779 job_t
job_new_anonymous(jobmgr_t jm,pid_t anonpid)1780 job_new_anonymous(jobmgr_t jm, pid_t anonpid)
1781 {
1782 	struct proc_bsdshortinfo proc;
1783 	bool shutdown_state;
1784 	job_t jp = NULL, jr = NULL;
1785 	uid_t kp_euid, kp_uid, kp_svuid;
1786 	gid_t kp_egid, kp_gid, kp_svgid;
1787 
1788 	if (anonpid == 0) {
1789 		errno = EINVAL;
1790 		return NULL;
1791 	}
1792 
1793 	if (anonpid >= 100000) {
1794 		/* The kernel current defines PID_MAX to be 99999, but that define isn't
1795 		 * exported.
1796 		 */
1797 		launchd_syslog(LOG_WARNING, "Did PID_MAX change? Got request from PID: %d", anonpid);
1798 		errno = EINVAL;
1799 		return NULL;
1800 	}
1801 
1802 	/* libproc returns the number of bytes written into the buffer upon success,
1803 	 * zero on failure. I'd much rather it return -1 on failure, like sysctl(3).
1804 	 */
1805 	if (proc_pidinfo(anonpid, PROC_PIDT_SHORTBSDINFO, 1, &proc, PROC_PIDT_SHORTBSDINFO_SIZE) == 0) {
1806 		if (errno != ESRCH) {
1807 			(void)jobmgr_assumes_zero(jm, errno);
1808 		}
1809 		return NULL;
1810 	}
1811 
1812 	if (proc.pbsi_comm[0] == '\0') {
1813 		launchd_syslog(LOG_WARNING, "Blank command for PID: %d", anonpid);
1814 		errno = EINVAL;
1815 		return NULL;
1816 	}
1817 
1818 	if (unlikely(proc.pbsi_status == SZOMB)) {
1819 		jobmgr_log(jm, LOG_DEBUG, "Tried to create an anonymous job for zombie PID %u: %s", anonpid, proc.pbsi_comm);
1820 	}
1821 
1822 	if (unlikely(proc.pbsi_flags & P_SUGID)) {
1823 		jobmgr_log(jm, LOG_DEBUG, "Inconsistency: P_SUGID is set on PID %u: %s", anonpid, proc.pbsi_comm);
1824 	}
1825 
1826 	kp_euid = proc.pbsi_uid;
1827 	kp_uid = proc.pbsi_ruid;
1828 	kp_svuid = proc.pbsi_svuid;
1829 	kp_egid = proc.pbsi_gid;
1830 	kp_gid = proc.pbsi_rgid;
1831 	kp_svgid = proc.pbsi_svgid;
1832 
1833 	if (unlikely(kp_euid != kp_uid || kp_euid != kp_svuid || kp_uid != kp_svuid || kp_egid != kp_gid || kp_egid != kp_svgid || kp_gid != kp_svgid)) {
1834 		jobmgr_log(jm, LOG_DEBUG, "Inconsistency: Mixed credentials (e/r/s UID %u/%u/%u GID %u/%u/%u) detected on PID %u: %s",
1835 				kp_euid, kp_uid, kp_svuid, kp_egid, kp_gid, kp_svgid, anonpid, proc.pbsi_comm);
1836 	}
1837 
1838 	/* "Fix" for when the kernel turns the process tree into a weird, cyclic
1839 	 * graph.
1840 	 *
1841 	 * See <rdar://problem/7264615> for the symptom and <rdar://problem/5020256>
1842 	 * as to why this can happen.
1843 	 */
1844 	if ((pid_t)proc.pbsi_ppid == anonpid) {
1845 		jobmgr_log(jm, LOG_WARNING, "Process has become its own parent through ptrace(3). Ignoring: %s", proc.pbsi_comm);
1846 		errno = EINVAL;
1847 		return NULL;
1848 	}
1849 
1850 	/* HACK: Normally, job_new() returns an error during shutdown, but anonymous
1851 	 * jobs can pop up during shutdown and need to talk to us.
1852 	 */
1853 	if (unlikely(shutdown_state = jm->shutting_down)) {
1854 		jm->shutting_down = false;
1855 	}
1856 
1857 	// We only set requestor_pid for XPC domains.
1858 	const char *whichlabel = (jm->req_pid == anonpid) ? AUTO_PICK_XPC_LABEL : AUTO_PICK_ANONYMOUS_LABEL;
1859 	if ((jr = job_new(jm, whichlabel, proc.pbsi_comm, NULL))) {
1860 		u_int proc_fflags = NOTE_EXEC|NOTE_FORK|NOTE_EXIT;
1861 
1862 		total_anon_children++;
1863 		jr->anonymous = true;
1864 		jr->p = anonpid;
1865 
1866 		// Anonymous process reaping is messy.
1867 		LIST_INSERT_HEAD(&jm->active_jobs[ACTIVE_JOB_HASH(jr->p)], jr, pid_hash_sle);
1868 
1869 		if (unlikely(kevent_mod(jr->p, EVFILT_PROC, EV_ADD, proc_fflags, 0, root_jobmgr) == -1)) {
1870 			if (errno != ESRCH) {
1871 				(void)job_assumes_zero(jr, errno);
1872 			}
1873 
1874 			// Zombies interact weirdly with kevent(3).
1875 			job_log(jr, LOG_ERR, "Failed to add kevent for PID %u. Will unload at MIG return", jr->p);
1876 			jr->unload_at_mig_return = true;
1877 		}
1878 
1879 		if (unlikely(shutdown_state)) {
1880 			job_log(jr, LOG_APPLEONLY, "This process showed up to the party while all the guests were leaving. Odds are that it will have a miserable time.");
1881 		}
1882 
1883 		job_log(jr, LOG_DEBUG, "Created PID %u anonymously by PPID %u%s%s", anonpid, proc.pbsi_ppid, jp ? ": " : "", jp ? jp->label : "");
1884 	} else {
1885 		(void)os_assumes_zero(errno);
1886 	}
1887 
1888 	// Undo our hack from above.
1889 	if (unlikely(shutdown_state)) {
1890 		jm->shutting_down = true;
1891 	}
1892 
1893 	/* This is down here to prevent infinite recursion due to a process
1894 	 * attaching to its parent through ptrace(3) -- causing a cycle in the
1895 	 * process tree and thereby not making it a tree anymore. We need to make
1896 	 * sure that the anonymous job has been added to the process list so that
1897 	 * we'll find the tracing parent PID of the parent process, which is the
1898 	 * child, when we go looking for it in jobmgr_find_by_pid().
1899 	 *
1900 	 * <rdar://problem/7264615>
1901 	 */
1902 	switch (proc.pbsi_ppid) {
1903 	case 0:
1904 		// The kernel.
1905 		break;
1906 	case 1:
1907 		if (!pid1_magic) {
1908 			break;
1909 		}
1910 		// Fall through.
1911 	default:
1912 		jp = jobmgr_find_by_pid(jm, proc.pbsi_ppid, true);
1913 		if (jobmgr_assumes(jm, jp != NULL)) {
1914 			if (jp && !jp->anonymous && unlikely(!(proc.pbsi_flags & P_EXEC))) {
1915 				job_log(jp, LOG_DEBUG, "Called *fork(). Please switch to posix_spawn*(), pthreads or launchd. Child PID %u", proc.pbsi_pid);
1916 			}
1917 		}
1918 		break;
1919 	}
1920 
1921 	return jr;
1922 }
1923 
1924 job_t
job_new_subjob(job_t j,uuid_t identifier)1925 job_new_subjob(job_t j, uuid_t identifier)
1926 {
1927 	char label[0];
1928 	uuid_string_t idstr;
1929 	uuid_unparse(identifier, idstr);
1930 	size_t label_sz = snprintf(label, 0, "%s.%s", j->label, idstr);
1931 
1932 	job_t nj = (struct job_s *)calloc(1, sizeof(struct job_s) + label_sz + 1);
1933 	if (nj != NULL) {
1934 		nj->kqjob_callback = job_callback;
1935 		nj->original = j;
1936 		nj->mgr = j->mgr;
1937 		nj->min_run_time = j->min_run_time;
1938 		nj->timeout = j->timeout;
1939 		nj->exit_timeout = j->exit_timeout;
1940 
1941 		snprintf((char *)nj->label, label_sz + 1, "%s.%s", j->label, idstr);
1942 
1943 		// Set all our simple Booleans that are applicable.
1944 		nj->debug = j->debug;
1945 		nj->ondemand = j->ondemand;
1946 		nj->checkedin = true;
1947 		nj->low_pri_io = j->low_pri_io;
1948 		nj->setmask = j->setmask;
1949 		nj->wait4debugger = j->wait4debugger;
1950 		nj->internal_exc_handler = j->internal_exc_handler;
1951 		nj->setnice = j->setnice;
1952 		nj->abandon_pg = j->abandon_pg;
1953 		nj->ignore_pg_at_shutdown = j->ignore_pg_at_shutdown;
1954 		nj->deny_job_creation = j->deny_job_creation;
1955 		nj->enable_transactions = j->enable_transactions;
1956 		nj->needs_kickoff = j->needs_kickoff;
1957 		nj->currently_ignored = true;
1958 		nj->dedicated_instance = true;
1959 		nj->xpc_service = j->xpc_service;
1960 		nj->xpc_bootstrapper = j->xpc_bootstrapper;
1961 		nj->jetsam_priority = j->jetsam_priority;
1962 		nj->jetsam_memlimit = j->jetsam_memlimit;
1963 		nj->psproctype = j->psproctype;
1964 
1965 		nj->mask = j->mask;
1966 		uuid_copy(nj->instance_id, identifier);
1967 
1968 		// These jobs are purely on-demand Mach jobs.
1969 		// {Hard | Soft}ResourceLimits are not supported.
1970 		// JetsamPriority is not supported.
1971 
1972 		if (j->prog) {
1973 			nj->prog = strdup(j->prog);
1974 		}
1975 		if (j->argv) {
1976 			size_t sz = malloc_size(j->argv);
1977 			nj->argv = (char **)malloc(sz);
1978 			if (nj->argv != NULL) {
1979 				// This is the start of our strings.
1980 				char *p = ((char *)nj->argv) + ((j->argc + 1) * sizeof(char *));
1981 
1982 				size_t i = 0;
1983 				for (i = 0; i < j->argc; i++) {
1984 					(void)strcpy(p, j->argv[i]);
1985 					nj->argv[i] = p;
1986 					p += (strlen(j->argv[i]) + 1);
1987 				}
1988 				nj->argv[i] = NULL;
1989 			} else {
1990 				(void)job_assumes_zero(nj, errno);
1991 			}
1992 
1993 			nj->argc = j->argc;
1994 		}
1995 
1996 		struct machservice *msi = NULL;
1997 		SLIST_FOREACH(msi, &j->machservices, sle) {
1998 			/* Only copy MachServices that were actually declared in the plist.
1999 			 * So skip over per-PID ones and ones that were created via
2000 			 * bootstrap_register().
2001 			 */
2002 			if (msi->upfront) {
2003 				mach_port_t mp = MACH_PORT_NULL;
2004 				struct machservice *msj = machservice_new(nj, msi->name, &mp, false);
2005 				if (msj != NULL) {
2006 					msj->reset = msi->reset;
2007 					msj->delete_on_destruction = msi->delete_on_destruction;
2008 					msj->drain_one_on_crash = msi->drain_one_on_crash;
2009 					msj->drain_all_on_crash = msi->drain_all_on_crash;
2010 
2011 					kern_return_t kr = mach_port_set_attributes(mach_task_self(), msj->port, MACH_PORT_TEMPOWNER, NULL, 0);
2012 					(void)job_assumes_zero(j, kr);
2013 				} else {
2014 					(void)job_assumes_zero(nj, errno);
2015 				}
2016 			}
2017 		}
2018 
2019 		// We ignore global environment variables.
2020 		struct envitem *ei = NULL;
2021 		SLIST_FOREACH(ei, &j->env, sle) {
2022 			if (envitem_new(nj, ei->key, ei->value, false)) {
2023 				(void)job_assumes_zero(nj, errno);
2024 			}
2025 		}
2026 		uuid_string_t val;
2027 		uuid_unparse(identifier, val);
2028 		if (envitem_new(nj, LAUNCH_ENV_INSTANCEID, val, false)) {
2029 			(void)job_assumes_zero(nj, errno);
2030 		}
2031 
2032 		if (j->rootdir) {
2033 			nj->rootdir = strdup(j->rootdir);
2034 		}
2035 		if (j->workingdir) {
2036 			nj->workingdir = strdup(j->workingdir);
2037 		}
2038 		if (j->username) {
2039 			nj->username = strdup(j->username);
2040 		}
2041 		if (j->groupname) {
2042 			nj->groupname = strdup(j->groupname);
2043 		}
2044 
2045 		/* FIXME: We shouldn't redirect all the output from these jobs to the
2046 		 * same file. We should uniquify the file names. But this hasn't shown
2047 		 * to be a problem in practice.
2048 		 */
2049 		if (j->stdinpath) {
2050 			nj->stdinpath = strdup(j->stdinpath);
2051 		}
2052 		if (j->stdoutpath) {
2053 			nj->stdoutpath = strdup(j->stdinpath);
2054 		}
2055 		if (j->stderrpath) {
2056 			nj->stderrpath = strdup(j->stderrpath);
2057 		}
2058 		if (j->alt_exc_handler) {
2059 			nj->alt_exc_handler = strdup(j->alt_exc_handler);
2060 		}
2061 		if (j->cfbundleidentifier) {
2062 			nj->cfbundleidentifier = strdup(j->cfbundleidentifier);
2063 		}
2064 #if HAVE_SANDBOX
2065 		if (j->seatbelt_profile) {
2066 			nj->seatbelt_profile = strdup(j->seatbelt_profile);
2067 		}
2068 		if (j->container_identifier) {
2069 			nj->container_identifier = strdup(j->container_identifier);
2070 		}
2071 #endif
2072 
2073 #if HAVE_QUARANTINE
2074 		if (j->quarantine_data) {
2075 			nj->quarantine_data = strdup(j->quarantine_data);
2076 		}
2077 		nj->quarantine_data_sz = j->quarantine_data_sz;
2078 #endif
2079 		if (j->j_binpref) {
2080 			size_t sz = malloc_size(j->j_binpref);
2081 			nj->j_binpref = (cpu_type_t *)malloc(sz);
2082 			if (nj->j_binpref) {
2083 				memcpy(&nj->j_binpref, &j->j_binpref, sz);
2084 			} else {
2085 				(void)job_assumes_zero(nj, errno);
2086 			}
2087 		}
2088 
2089 		if (j->asport != MACH_PORT_NULL) {
2090 			(void)job_assumes_zero(nj, launchd_mport_copy_send(j->asport));
2091 			nj->asport = j->asport;
2092 		}
2093 
2094 		LIST_INSERT_HEAD(&nj->mgr->jobs, nj, sle);
2095 
2096 		jobmgr_t where2put = root_jobmgr;
2097 		if (j->mgr->properties & BOOTSTRAP_PROPERTY_XPC_DOMAIN) {
2098 			where2put = j->mgr;
2099 		}
2100 		LIST_INSERT_HEAD(&where2put->label_hash[hash_label(nj->label)], nj, label_hash_sle);
2101 		LIST_INSERT_HEAD(&j->subjobs, nj, subjob_sle);
2102 	} else {
2103 		(void)os_assumes_zero(errno);
2104 	}
2105 
2106 	return nj;
2107 }
2108 
2109 job_t
job_new(jobmgr_t jm,const char * label,const char * prog,const char * const * argv)2110 job_new(jobmgr_t jm, const char *label, const char *prog, const char *const *argv)
2111 {
2112 	const char *const *argv_tmp = argv;
2113 	char tmp_path[PATH_MAX];
2114 	char auto_label[1000];
2115 	const char *bn = NULL;
2116 	char *co;
2117 	size_t minlabel_len;
2118 	size_t i, cc = 0;
2119 	job_t j;
2120 
2121 	__OS_COMPILETIME_ASSERT__(offsetof(struct job_s, kqjob_callback) == 0);
2122 
2123 	if (unlikely(jm->shutting_down)) {
2124 		errno = EINVAL;
2125 		return NULL;
2126 	}
2127 
2128 	if (unlikely(prog == NULL && argv == NULL)) {
2129 		errno = EINVAL;
2130 		return NULL;
2131 	}
2132 
2133 	/* I'd really like to redo this someday. Anonymous jobs carry all the
2134 	 * baggage of managed jobs with them, even though most of it is unused.
2135 	 * Maybe when we have Objective-C objects in libSystem, there can be a base
2136 	 * job type that anonymous and managed jobs inherit from...
2137 	 */
2138 	const char *anon_or_legacy = (label == AUTO_PICK_ANONYMOUS_LABEL) ? "anonymous" : "mach_init";
2139 	if (unlikely(label == AUTO_PICK_LEGACY_LABEL || label == AUTO_PICK_ANONYMOUS_LABEL)) {
2140 		if (prog) {
2141 			bn = prog;
2142 		} else {
2143 			strlcpy(tmp_path, argv[0], sizeof(tmp_path));
2144 			// prog for auto labels is kp.kp_kproc.p_comm.
2145 			bn = basename(tmp_path);
2146 		}
2147 
2148 		(void)snprintf(auto_label, sizeof(auto_label), "%s.%s.%s", sizeof(void *) == 8 ? "0xdeadbeeffeedface" : "0xbabecafe", anon_or_legacy, bn);
2149 		label = auto_label;
2150 		/* This is so we can do gross things later. See NOTE_EXEC for anonymous
2151 		 * jobs.
2152 		 */
2153 		minlabel_len = strlen(label) + MAXCOMLEN;
2154 	} else {
2155 		if (label == AUTO_PICK_XPC_LABEL) {
2156 			minlabel_len = snprintf(auto_label, sizeof(auto_label), "com.apple.xpc.domain-owner.%s", jm->owner);
2157 		} else {
2158 			minlabel_len = strlen(label);
2159 		}
2160 	}
2161 
2162 	j = calloc(1, sizeof(struct job_s) + minlabel_len + 1);
2163 
2164 	if (!j) {
2165 		(void)os_assumes_zero(errno);
2166 		return NULL;
2167 	}
2168 
2169 	if (unlikely(label == auto_label)) {
2170 		(void)snprintf((char *)j->label, strlen(label) + 1, "%p.%s.%s", j, anon_or_legacy, bn);
2171 	} else {
2172 		(void)strcpy((char *)j->label, (label == AUTO_PICK_XPC_LABEL) ? auto_label : label);
2173 	}
2174 
2175 	j->kqjob_callback = job_callback;
2176 	j->mgr = jm;
2177 	j->min_run_time = LAUNCHD_MIN_JOB_RUN_TIME;
2178 	j->timeout = RUNTIME_ADVISABLE_IDLE_TIMEOUT;
2179 	if (uflag == true)
2180 		j->exit_timeout = 60;
2181 	else
2182 		j->exit_timeout = LAUNCHD_DEFAULT_EXIT_TIMEOUT;
2183 	j->currently_ignored = true;
2184 	j->ondemand = true;
2185 	j->checkedin = true;
2186 	j->jetsam_priority = DEFAULT_JETSAM_PRIORITY;
2187 	j->jetsam_memlimit = -1;
2188 	uuid_clear(j->expected_audit_uuid);
2189 #if TARGET_OS_EMBEDDED
2190 	/* Run embedded daemons as background by default. SpringBoard jobs are
2191 	 * Interactive by default. Unfortunately, so many daemons have opted into
2192 	 * this priority band that its usefulness is highly questionable.
2193 	 *
2194 	 * See <rdar://problem/9539873>.
2195 	 *
2196 	 * Also ensure that daemons have a default memory highwatermark unless
2197 	 * otherwise specified, as per <rdar://problem/10307814>.
2198 	 */
2199 	if (launchd_embedded_handofgod) {
2200 		j->psproctype = POSIX_SPAWN_PROC_TYPE_APP_DEFAULT;
2201 		j->app = true;
2202 	} else {
2203 		j->psproctype = POSIX_SPAWN_PROC_TYPE_DAEMON_BACKGROUND;
2204 		j->jetsam_memlimit = DEFAULT_JETSAM_DAEMON_HIGHWATERMARK;
2205 	}
2206 #else
2207 	/* Jobs on OS X that just come from disk are "standard" by default so that
2208 	 * third-party daemons/agents don't encounter unexpected throttling.
2209 	 */
2210 	j->psproctype = POSIX_SPAWN_PROC_TYPE_DAEMON_STANDARD;
2211 #endif
2212 
2213 	if (prog) {
2214 		j->prog = strdup(prog);
2215 		if (!j->prog) {
2216 			(void)os_assumes_zero(errno);
2217 			goto out_bad;
2218 		}
2219 	}
2220 
2221 	if (likely(argv)) {
2222 		while (*argv_tmp++) {
2223 			j->argc++;
2224 		}
2225 
2226 		for (i = 0; i < j->argc; i++) {
2227 			cc += strlen(argv[i]) + 1;
2228 		}
2229 
2230 		j->argv = malloc((j->argc + 1) * sizeof(char *) + cc);
2231 		if (!j->argv) {
2232 			(void)job_assumes_zero(j, errno);
2233 			goto out_bad;
2234 		}
2235 
2236 		co = ((char *)j->argv) + ((j->argc + 1) * sizeof(char *));
2237 
2238 		for (i = 0; i < j->argc; i++) {
2239 			j->argv[i] = co;
2240 			(void)strcpy(co, argv[i]);
2241 			co += strlen(argv[i]) + 1;
2242 		}
2243 		j->argv[i] = NULL;
2244 	}
2245 
2246 	// Sssshhh... don't tell anyone.
2247 	if (strcmp(j->label, "com.apple.WindowServer") == 0) {
2248 		j->has_console = true;
2249 	}
2250 
2251 	LIST_INSERT_HEAD(&jm->jobs, j, sle);
2252 
2253 	jobmgr_t where2put_label = root_jobmgr;
2254 	if (j->mgr->properties & BOOTSTRAP_PROPERTY_XPC_DOMAIN) {
2255 		where2put_label = j->mgr;
2256 	}
2257 	LIST_INSERT_HEAD(&where2put_label->label_hash[hash_label(j->label)], j, label_hash_sle);
2258 	uuid_clear(j->expected_audit_uuid);
2259 
2260 	job_log(j, LOG_DEBUG, "Conceived");
2261 
2262 	return j;
2263 
2264 out_bad:
2265 	if (j->prog) {
2266 		free(j->prog);
2267 	}
2268 	free(j);
2269 
2270 	return NULL;
2271 }
2272 
2273 job_t
job_new_alias(jobmgr_t jm,job_t src)2274 job_new_alias(jobmgr_t jm, job_t src)
2275 {
2276 	if (job_find(jm, src->label)) {
2277 		errno = EEXIST;
2278 		return NULL;
2279 	}
2280 
2281 	job_t j = calloc(1, sizeof(struct job_s) + strlen(src->label) + 1);
2282 	if (!j) {
2283 		(void)os_assumes_zero(errno);
2284 		return NULL;
2285 	}
2286 
2287 	(void)strcpy((char *)j->label, src->label);
2288 	LIST_INSERT_HEAD(&jm->jobs, j, sle);
2289 	LIST_INSERT_HEAD(&jm->label_hash[hash_label(j->label)], j, label_hash_sle);
2290 	/* Bad jump address. The kqueue callback for aliases should never be
2291 	 * invoked.
2292 	 */
2293 	j->kqjob_callback = (kq_callback)0xfa1afe1;
2294 	j->alias = src;
2295 	j->mgr = jm;
2296 
2297 	struct machservice *msi = NULL;
2298 	SLIST_FOREACH(msi, &src->machservices, sle) {
2299 		if (!machservice_new_alias(j, msi)) {
2300 			jobmgr_log(jm, LOG_ERR, "Failed to alias job: %s", src->label);
2301 			errno = EINVAL;
2302 			job_remove(j);
2303 			j = NULL;
2304 			break;
2305 		}
2306 	}
2307 
2308 	if (j) {
2309 		job_log(j, LOG_DEBUG, "Aliased service into domain: %s", jm->name);
2310 	}
2311 
2312 	return j;
2313 }
2314 
2315 job_t
job_import(launch_data_t pload)2316 job_import(launch_data_t pload)
2317 {
2318 #if TARGET_OS_EMBEDDED
2319 	/* If this is the special payload of default values, handle it here */
2320 	if (unlikely(launch_data_dict_lookup(pload, LAUNCH_JOBKEY_DEFAULTS))) {
2321 		job_import_defaults(pload);
2322 		return NULL;
2323 	}
2324 #endif
2325 
2326 	job_t j = jobmgr_import2(root_jobmgr, pload);
2327 
2328 	if (unlikely(j == NULL)) {
2329 		return NULL;
2330 	}
2331 
2332 	/* Since jobs are effectively stalled until they get security sessions
2333 	 * assigned to them, we may wish to reconsider this behavior of calling the
2334 	 * job "enabled" as far as other jobs with the OtherJobEnabled KeepAlive
2335 	 * criterion set.
2336 	 */
2337 	job_dispatch_curious_jobs(j);
2338 	return job_dispatch(j, false);
2339 }
2340 
2341 #if TARGET_OS_EMBEDDED
2342 
2343 bool
job_import_defaults(launch_data_t pload)2344 job_import_defaults(launch_data_t pload)
2345 {
2346 	bool result = false;
2347 	xpc_object_t xd = NULL, defaults;
2348 
2349 	if (_launchd_defaults_cache) {
2350 		xpc_release(_launchd_defaults_cache);
2351 		_launchd_defaults_cache = NULL;
2352 	}
2353 
2354 	xd = ld2xpc(pload);
2355 	if (!xd || xpc_get_type(xd) != XPC_TYPE_DICTIONARY) {
2356 		goto out;
2357 	}
2358 
2359 	defaults = xpc_dictionary_get_value(xd, LAUNCHD_JOB_DEFAULTS);
2360 	if (!defaults || xpc_get_type(defaults) != XPC_TYPE_DICTIONARY) {
2361 		goto out;
2362 	}
2363 
2364 	_launchd_defaults_cache = xpc_copy(defaults);
2365 	result = true;
2366 out:
2367 	if (xd) {
2368 		xpc_release(xd);
2369 	}
2370 
2371 	return result;
2372 }
2373 
2374 bool
job_apply_defaults(job_t j)2375 job_apply_defaults(job_t j) {
2376 	const char *test_prefix = "com.apple.test.";
2377 
2378 	char *sb_prefix_end, *sb_suffix_start;
2379 	char true_job_label[strlen(j->label)];
2380 	const char *label;
2381 
2382 	if (((sb_prefix_end = strchr(j->label, ':')) != NULL) &&
2383 	    ((sb_suffix_start = strchr(sb_prefix_end + 1, '[')) != NULL)) {
2384  		/*
2385  		 * Workaround 'UIKitApplication:com.apple.foo[bar]' convention for the processes
2386  		 * we're interested in. To be removed when <rdar://problem/13066361> is addressed.
2387  		 */
2388 		snprintf(true_job_label, sb_suffix_start - sb_prefix_end, "%s", sb_prefix_end + 1);
2389  		label = true_job_label;
2390 	} else {
2391 		/* Just test the standard label */
2392 		label = j->label;
2393 	}
2394 
2395 	/* Test for cache presence and apply if found */
2396 	if (_launchd_defaults_cache) {
2397 		xpc_object_t props = xpc_dictionary_get_value(_launchd_defaults_cache, label);
2398 		if (props && xpc_get_type(props) == XPC_TYPE_DICTIONARY) {
2399 			launch_data_t lv = xpc2ld(props);
2400 			launch_data_dict_iterate(lv, job_import_keys, j);
2401 			launch_data_free(lv);
2402 			return true;
2403 		}
2404 	}
2405 
2406 	/* Limit free? Disable the memory limit if this is a test job; see <rdar://problem/13180697> */
2407 	if (!strncmp(label, test_prefix, strlen(test_prefix))) {
2408 		j->jetsam_memlimit = -1;
2409 		return true;
2410 	}
2411 
2412 	return false;
2413 }
2414 
2415 #endif
2416 
2417 launch_data_t
job_import_bulk(launch_data_t pload)2418 job_import_bulk(launch_data_t pload)
2419 {
2420 	launch_data_t resp = launch_data_alloc(LAUNCH_DATA_ARRAY);
2421 	job_t *ja;
2422 	size_t i, c = launch_data_array_get_count(pload);
2423 
2424 	ja = alloca(c * sizeof(job_t));
2425 
2426 	for (i = 0; i < c; i++) {
2427 		if ((likely(ja[i] = jobmgr_import2(root_jobmgr, launch_data_array_get_index(pload, i)))) && errno != ENEEDAUTH) {
2428 			errno = 0;
2429 		}
2430 		launch_data_array_set_index(resp, launch_data_new_errno(errno), i);
2431 	}
2432 
2433 	for (i = 0; i < c; i++) {
2434 		if (likely(ja[i])) {
2435 			job_dispatch_curious_jobs(ja[i]);
2436 			job_dispatch(ja[i], false);
2437 		}
2438 	}
2439 
2440 	return resp;
2441 }
2442 
2443 void
job_import_bool(job_t j,const char * key,bool value)2444 job_import_bool(job_t j, const char *key, bool value)
2445 {
2446 	bool found_key = false;
2447 
2448 	switch (key[0]) {
2449 	case 'a':
2450 	case 'A':
2451 		if (strcasecmp(key, LAUNCH_JOBKEY_ABANDONPROCESSGROUP) == 0) {
2452 			j->abandon_pg = value;
2453 			found_key = true;
2454 		}
2455 		break;
2456 	case 'b':
2457 	case 'B':
2458 		if (strcasecmp(key, LAUNCH_JOBKEY_BEGINTRANSACTIONATSHUTDOWN) == 0) {
2459 			j->dirty_at_shutdown = value;
2460 			found_key = true;
2461 		}
2462 		break;
2463 	case 'j':
2464 	case 'J':
2465 		if (strcasecmp(key, LAUNCH_JOBKEY_JOINGUISESSION) == 0) {
2466 			j->joins_gui_session = value;
2467 			found_key = true;
2468 		}
2469 		break;
2470 	case 'k':
2471 	case 'K':
2472 		if (strcasecmp(key, LAUNCH_JOBKEY_KEEPALIVE) == 0) {
2473 			j->ondemand = !value;
2474 			found_key = true;
2475 		}
2476 		break;
2477 	case 'o':
2478 	case 'O':
2479 		if (strcasecmp(key, LAUNCH_JOBKEY_ONDEMAND) == 0) {
2480 			j->ondemand = value;
2481 			found_key = true;
2482 		}
2483 		break;
2484 	case 'd':
2485 	case 'D':
2486 		if (strcasecmp(key, LAUNCH_JOBKEY_DEBUG) == 0) {
2487 			j->debug = value;
2488 			found_key = true;
2489 		} else if (strcasecmp(key, LAUNCH_JOBKEY_DISABLED) == 0) {
2490 			(void)job_assumes(j, !value);
2491 			found_key = true;
2492 		} else if (strcasecmp(key, LAUNCH_JOBKEY_DISABLEASLR) == 0) {
2493 			j->disable_aslr = value;
2494 			found_key = true;
2495 		}
2496 		break;
2497 	case 'h':
2498 	case 'H':
2499 		if (strcasecmp(key, LAUNCH_JOBKEY_HOPEFULLYEXITSLAST) == 0) {
2500 			job_log(j, LOG_PERF, "%s has been deprecated. Please use the new %s key instead and add EnableTransactions to your launchd.plist.", LAUNCH_JOBKEY_HOPEFULLYEXITSLAST, LAUNCH_JOBKEY_BEGINTRANSACTIONATSHUTDOWN);
2501 			j->dirty_at_shutdown = value;
2502 			found_key = true;
2503 		}
2504 		break;
2505 	case 's':
2506 	case 'S':
2507 		if (strcasecmp(key, LAUNCH_JOBKEY_SESSIONCREATE) == 0) {
2508 			j->session_create = value;
2509 			found_key = true;
2510 		} else if (strcasecmp(key, LAUNCH_JOBKEY_STARTONMOUNT) == 0) {
2511 			j->start_on_mount = value;
2512 			found_key = true;
2513 		} else if (strcasecmp(key, LAUNCH_JOBKEY_SERVICEIPC) == 0) {
2514 			// this only does something on Mac OS X 10.4 "Tiger"
2515 			found_key = true;
2516 		} else if (strcasecmp(key, LAUNCH_JOBKEY_SHUTDOWNMONITOR) == 0) {
2517 			if (_launchd_shutdown_monitor) {
2518 				job_log(j, LOG_ERR, "Only one job may monitor shutdown.");
2519 			} else {
2520 				j->shutdown_monitor = true;
2521 				_launchd_shutdown_monitor = j;
2522 			}
2523 			found_key = true;
2524 		}
2525 		break;
2526 	case 'l':
2527 	case 'L':
2528 		if (strcasecmp(key, LAUNCH_JOBKEY_LOWPRIORITYIO) == 0) {
2529 			j->low_pri_io = value;
2530 			found_key = true;
2531 		} else if (strcasecmp(key, LAUNCH_JOBKEY_LAUNCHONLYONCE) == 0) {
2532 			j->only_once = value;
2533 			found_key = true;
2534 		} else if (strcasecmp(key, LAUNCH_JOBKEY_LOWPRIORITYBACKGROUNDIO) == 0) {
2535 			j->low_priority_background_io = true;
2536 			found_key = true;
2537 		} else if (strcasecmp(key, LAUNCH_JOBKEY_LEGACYTIMERS) == 0) {
2538 #if !TARGET_OS_EMBEDDED
2539 			j->legacy_timers = value;
2540 #else // !TARGET_OS_EMBEDDED
2541 			job_log(j, LOG_ERR, "This key is not supported on this platform: %s", key);
2542 #endif // !TARGET_OS_EMBEDDED
2543 			found_key = true;
2544 		}
2545 		break;
2546 	case 'm':
2547 	case 'M':
2548 		if (strcasecmp(key, LAUNCH_JOBKEY_MACHEXCEPTIONHANDLER) == 0) {
2549 			j->internal_exc_handler = value;
2550 			found_key = true;
2551 		} else if (strcasecmp(key, LAUNCH_JOBKEY_MULTIPLEINSTANCES) == 0) {
2552 			j->multiple_instances = value;
2553 			found_key = true;
2554 		}
2555 		break;
2556 	case 'i':
2557 	case 'I':
2558 		if (strcasecmp(key, LAUNCH_JOBKEY_INITGROUPS) == 0) {
2559 			if (getuid() != 0) {
2560 				job_log(j, LOG_WARNING, "Ignored this key: %s", key);
2561 				return;
2562 			}
2563 			j->no_init_groups = !value;
2564 			found_key = true;
2565 		} else if (strcasecmp(key, LAUNCH_JOBKEY_IGNOREPROCESSGROUPATSHUTDOWN) == 0) {
2566 			j->ignore_pg_at_shutdown = value;
2567 			found_key = true;
2568 		}
2569 		break;
2570 	case 'r':
2571 	case 'R':
2572 		if (strcasecmp(key, LAUNCH_JOBKEY_RUNATLOAD) == 0) {
2573 			if (value) {
2574 				// We don't want value == false to change j->start_pending
2575 				j->start_pending = true;
2576 			}
2577 			found_key = true;
2578 		}
2579 		break;
2580 	case 'e':
2581 	case 'E':
2582 		if (strcasecmp(key, LAUNCH_JOBKEY_ENABLEGLOBBING) == 0) {
2583 			j->globargv = value;
2584 			found_key = true;
2585 		} else if (strcasecmp(key, LAUNCH_JOBKEY_ENABLETRANSACTIONS) == 0) {
2586 			j->enable_transactions = value;
2587 			found_key = true;
2588 		} else if (strcasecmp(key, LAUNCH_JOBKEY_ENTERKERNELDEBUGGERBEFOREKILL) == 0) {
2589 			j->debug_before_kill = value;
2590 			found_key = true;
2591 		} else if (strcasecmp(key, LAUNCH_JOBKEY_EMBEDDEDPRIVILEGEDISPENSATION) == 0) {
2592 #if TARGET_OS_EMBEDDED
2593 			if (!_launchd_embedded_god) {
2594 				if ((j->embedded_god = value)) {
2595 					_launchd_embedded_god = j;
2596 				}
2597 			} else {
2598 				job_log(j, LOG_ERR, "Job tried to claim %s after it has already been claimed.", key);
2599 			}
2600 #else
2601 			job_log(j, LOG_ERR, "This key is not supported on this platform: %s", key);
2602 #endif
2603 			found_key = true;
2604 		} else if (strcasecmp(key, LAUNCH_JOBKEY_EMBEDDEDHOMESCREEN) == 0) {
2605 #if TARGET_OS_EMBEDDED
2606 			if (!_launchd_embedded_home) {
2607 				if ((j->embedded_home = value)) {
2608 					_launchd_embedded_home = j;
2609 				}
2610 			} else {
2611 				job_log(j, LOG_ERR, "Job tried to claim %s after it has already been claimed.", key);
2612 			}
2613 #else
2614 			job_log(j, LOG_ERR, "This key is not supported on this platform: %s", key);
2615 #endif
2616 		} else if (strcasecmp(key, LAUNCH_JOBKEY_EVENTMONITOR) == 0) {
2617 			if (!_launchd_event_monitor) {
2618 				j->event_monitor = value;
2619 				if (value) {
2620 					_launchd_event_monitor = j;
2621 				}
2622 			} else {
2623 				job_log(j, LOG_NOTICE, "Job tried to steal event monitoring responsibility from: %s", _launchd_event_monitor->label);
2624 			}
2625 			found_key = true;
2626 		}
2627 		break;
2628 	case 'w':
2629 	case 'W':
2630 		if (strcasecmp(key, LAUNCH_JOBKEY_WAITFORDEBUGGER) == 0) {
2631 			j->wait4debugger = value;
2632 			found_key = true;
2633 		}
2634 		break;
2635 	case 'x':
2636 	case 'X':
2637 		if (strcasecmp(key, LAUNCH_JOBKEY_XPCDOMAINBOOTSTRAPPER) == 0) {
2638 			if (pid1_magic) {
2639 				if (_launchd_xpc_bootstrapper) {
2640 					job_log(j, LOG_ERR, "This job tried to steal the XPC domain bootstrapper property from the following job: %s", _launchd_xpc_bootstrapper->label);
2641 				} else {
2642 					_launchd_xpc_bootstrapper = j;
2643 					j->xpc_bootstrapper = value;
2644 				}
2645 			} else {
2646 				job_log(j, LOG_ERR, "Non-daemon tried to claim XPC bootstrapper property.");
2647 			}
2648 		}
2649 		found_key = true;
2650 		break;
2651 	default:
2652 		break;
2653 	}
2654 
2655 	if (unlikely(!found_key)) {
2656 		job_log(j, LOG_WARNING, "Unknown key for boolean: %s", key);
2657 	}
2658 }
2659 
2660 void
job_import_string(job_t j,const char * key,const char * value)2661 job_import_string(job_t j, const char *key, const char *value)
2662 {
2663 	char **where2put = NULL;
2664 
2665 	switch (key[0]) {
2666 	case 'c':
2667 	case 'C':
2668 		if (strcasecmp(key, LAUNCH_JOBKEY_CFBUNDLEIDENTIFIER) == 0) {
2669 			where2put = &j->cfbundleidentifier;
2670 		}
2671 		break;
2672 	case 'm':
2673 	case 'M':
2674 		if (strcasecmp(key, LAUNCH_JOBKEY_MACHEXCEPTIONHANDLER) == 0) {
2675 			where2put = &j->alt_exc_handler;
2676 		}
2677 		break;
2678 	case 'p':
2679 	case 'P':
2680 		if (strcasecmp(key, LAUNCH_JOBKEY_PROGRAM) == 0) {
2681 			return;
2682 		} else if (strcasecmp(key, LAUNCH_JOBKEY_POSIXSPAWNTYPE) == 0
2683 				|| strcasecmp(key, LAUNCH_JOBKEY_PROCESSTYPE) == 0) {
2684 			if (strcasecmp(value, LAUNCH_KEY_POSIXSPAWNTYPE_INTERACTIVE) == 0) {
2685 				j->psproctype = POSIX_SPAWN_PROC_TYPE_DAEMON_INTERACTIVE;
2686 			} else if (strcasecmp(value, LAUNCH_KEY_POSIXSPAWNTYPE_ADAPTIVE) == 0) {
2687 				j->psproctype = POSIX_SPAWN_PROC_TYPE_DAEMON_ADAPTIVE;
2688 			} else if (strcasecmp(value, LAUNCH_KEY_POSIXSPAWNTYPE_STANDARD) == 0) {
2689 				j->psproctype = POSIX_SPAWN_PROC_TYPE_DAEMON_STANDARD;
2690 			} else if (strcasecmp(value, LAUNCH_KEY_POSIXSPAWNTYPE_BACKGROUND) == 0) {
2691 				j->psproctype = POSIX_SPAWN_PROC_TYPE_DAEMON_BACKGROUND;
2692 			} else if (strcasecmp(value, LAUNCH_KEY_POSIXSPAWNTYPE_TALAPP) == 0) {
2693 				j->psproctype = POSIX_SPAWN_PROC_TYPE_APP_TAL;
2694 			} else if (strcasecmp(value, LAUNCH_KEY_POSIXSPAWNTYPE_SYSTEMAPP) == 0) {
2695 				j->psproctype = POSIX_SPAWN_PROC_TYPE_APP_DEFAULT;
2696 				j->system_app = true;
2697 			} else if (strcasecmp(value, LAUNCH_KEY_POSIXSPAWNTYPE_APP) == 0) {
2698 				j->psproctype = POSIX_SPAWN_PROC_TYPE_APP_DEFAULT;
2699 				j->app = true;
2700 			} else {
2701 				job_log(j, LOG_ERR, "Unknown value for key %s: %s", key, value);
2702 			}
2703 			return;
2704 		}
2705 		break;
2706 	case 'l':
2707 	case 'L':
2708 		if (strcasecmp(key, LAUNCH_JOBKEY_LABEL) == 0) {
2709 			return;
2710 		} else if (strcasecmp(key, LAUNCH_JOBKEY_LIMITLOADTOHOSTS) == 0) {
2711 			return;
2712 		} else if (strcasecmp(key, LAUNCH_JOBKEY_LIMITLOADFROMHOSTS) == 0) {
2713 			return;
2714 		} else if (strcasecmp(key, LAUNCH_JOBKEY_LIMITLOADTOSESSIONTYPE) == 0) {
2715 			return;
2716 		}
2717 		break;
2718 	case 'r':
2719 	case 'R':
2720 		if (strcasecmp(key, LAUNCH_JOBKEY_ROOTDIRECTORY) == 0) {
2721 			if (getuid() != 0) {
2722 				job_log(j, LOG_WARNING, "Ignored this key: %s", key);
2723 				return;
2724 			}
2725 			where2put = &j->rootdir;
2726 		}
2727 		break;
2728 	case 'w':
2729 	case 'W':
2730 		if (strcasecmp(key, LAUNCH_JOBKEY_WORKINGDIRECTORY) == 0) {
2731 			where2put = &j->workingdir;
2732 		}
2733 		break;
2734 	case 'u':
2735 	case 'U':
2736 		if (strcasecmp(key, LAUNCH_JOBKEY_USERNAME) == 0) {
2737 			if (getuid() != 0) {
2738 				job_log(j, LOG_WARNING, "Ignored this key: %s", key);
2739 				return;
2740 			} else if (strcmp(value, "root") == 0) {
2741 				return;
2742 			}
2743 			where2put = &j->username;
2744 		}
2745 		break;
2746 	case 'g':
2747 	case 'G':
2748 		if (strcasecmp(key, LAUNCH_JOBKEY_GROUPNAME) == 0) {
2749 			if (getuid() != 0) {
2750 				job_log(j, LOG_WARNING, "Ignored this key: %s", key);
2751 				return;
2752 			} else if (strcmp(value, "wheel") == 0) {
2753 				return;
2754 			}
2755 			where2put = &j->groupname;
2756 		}
2757 		break;
2758 	case 's':
2759 	case 'S':
2760 		if (strcasecmp(key, LAUNCH_JOBKEY_STANDARDOUTPATH) == 0) {
2761 			where2put = &j->stdoutpath;
2762 		} else if (strcasecmp(key, LAUNCH_JOBKEY_STANDARDERRORPATH) == 0) {
2763 			where2put = &j->stderrpath;
2764 		} else if (strcasecmp(key, LAUNCH_JOBKEY_STANDARDINPATH) == 0) {
2765 			where2put = &j->stdinpath;
2766 			j->stdin_fd = _fd(open(value, O_RDONLY|O_CREAT|O_NOCTTY|O_NONBLOCK, DEFFILEMODE));
2767 			if (job_assumes_zero_p(j, j->stdin_fd) != -1) {
2768 				// open() should not block, but regular IO by the job should
2769 				(void)job_assumes_zero_p(j, fcntl(j->stdin_fd, F_SETFL, 0));
2770 				// XXX -- EV_CLEAR should make named pipes happy?
2771 				(void)job_assumes_zero_p(j, kevent_mod(j->stdin_fd, EVFILT_READ, EV_ADD|EV_CLEAR, 0, 0, j));
2772 			} else {
2773 				j->stdin_fd = 0;
2774 			}
2775 #if HAVE_SANDBOX
2776 		} else if (strcasecmp(key, LAUNCH_JOBKEY_SANDBOXPROFILE) == 0) {
2777 			where2put = &j->seatbelt_profile;
2778 		} else if (strcasecmp(key, LAUNCH_JOBKEY_SANDBOXCONTAINER) == 0) {
2779 			where2put = &j->container_identifier;
2780 #endif
2781 		}
2782 		break;
2783 	case 'X':
2784 	case 'x':
2785 		if (strcasecmp(key, LAUNCH_JOBKEY_XPCDOMAIN) == 0) {
2786 			return;
2787 		}
2788 		break;
2789 	default:
2790 		job_log(j, LOG_WARNING, "Unknown key for string: %s", key);
2791 		break;
2792 	}
2793 
2794 	if (likely(where2put)) {
2795 		if (!(*where2put = strdup(value))) {
2796 			(void)job_assumes_zero(j, errno);
2797 		}
2798 	} else {
2799 		// See rdar://problem/5496612. These two are okay.
2800 		if (strncmp(key, "SHAuthorizationRight", sizeof("SHAuthorizationRight")) == 0
2801 			|| strncmp(key, "ServiceDescription", sizeof("ServiceDescription")) == 0) {
2802 			job_log(j, LOG_APPLEONLY, "This key is no longer relevant and should be removed: %s", key);
2803 		} else {
2804 			job_log(j, LOG_WARNING, "Unknown key: %s", key);
2805 		}
2806 	}
2807 }
2808 
2809 void
job_import_integer(job_t j,const char * key,long long value)2810 job_import_integer(job_t j, const char *key, long long value)
2811 {
2812 	switch (key[0]) {
2813 	case 'a':
2814 	case 'A':
2815 #if TARGET_OS_EMBEDDED
2816 		if (strcasecmp(key, LAUNCH_JOBKEY_ASID) == 0) {
2817 			if (launchd_embedded_handofgod) {
2818 				if (audit_session_port((au_asid_t)value, &j->asport) == -1 && errno != ENOSYS) {
2819 					(void)job_assumes_zero(j, errno);
2820 				}
2821 			}
2822 		}
2823 #endif
2824 	case 'e':
2825 	case 'E':
2826 		if (strcasecmp(key, LAUNCH_JOBKEY_EXITTIMEOUT) == 0) {
2827 			if (unlikely(value < 0)) {
2828 				job_log(j, LOG_WARNING, "%s less than zero. Ignoring.", LAUNCH_JOBKEY_EXITTIMEOUT);
2829 			} else if (unlikely(value > UINT32_MAX)) {
2830 				job_log(j, LOG_WARNING, "%s is too large. Ignoring.", LAUNCH_JOBKEY_EXITTIMEOUT);
2831 			} else {
2832 				j->exit_timeout = (typeof(j->exit_timeout)) value;
2833 			}
2834 		} else if (strcasecmp(key, LAUNCH_JOBKEY_EMBEDDEDMAINTHREADPRIORITY) == 0) {
2835 			j->main_thread_priority = value;
2836 		}
2837 		break;
2838 	case 'j':
2839 	case 'J':
2840 		if (strcasecmp(key, LAUNCH_JOBKEY_JETSAMPRIORITY) == 0) {
2841 			job_log(j, LOG_WARNING | LOG_CONSOLE, "Please change the JetsamPriority key to be in a dictionary named JetsamProperties.");
2842 
2843 			launch_data_t pri = launch_data_new_integer(value);
2844 			if (job_assumes(j, pri != NULL)) {
2845 				jetsam_property_setup(pri, LAUNCH_JOBKEY_JETSAMPRIORITY, j);
2846 				launch_data_free(pri);
2847 			}
2848 		}
2849 	case 'n':
2850 	case 'N':
2851 		if (strcasecmp(key, LAUNCH_JOBKEY_NICE) == 0) {
2852 			if (unlikely(value < PRIO_MIN)) {
2853 				job_log(j, LOG_WARNING, "%s less than %d. Ignoring.", LAUNCH_JOBKEY_NICE, PRIO_MIN);
2854 			} else if (unlikely(value > PRIO_MAX)) {
2855 				job_log(j, LOG_WARNING, "%s is greater than %d. Ignoring.", LAUNCH_JOBKEY_NICE, PRIO_MAX);
2856 			} else {
2857 				j->nice = (typeof(j->nice)) value;
2858 				j->setnice = true;
2859 			}
2860 		}
2861 		break;
2862 	case 't':
2863 	case 'T':
2864 		if (strcasecmp(key, LAUNCH_JOBKEY_TIMEOUT) == 0) {
2865 			if (unlikely(value < 0)) {
2866 				job_log(j, LOG_WARNING, "%s less than zero. Ignoring.", LAUNCH_JOBKEY_TIMEOUT);
2867 			} else if (unlikely(value > UINT32_MAX)) {
2868 				job_log(j, LOG_WARNING, "%s is too large. Ignoring.", LAUNCH_JOBKEY_TIMEOUT);
2869 			} else {
2870 				j->timeout = (typeof(j->timeout)) value;
2871 			}
2872 		} else if (strcasecmp(key, LAUNCH_JOBKEY_THROTTLEINTERVAL) == 0) {
2873 			if (value < 0) {
2874 				job_log(j, LOG_WARNING, "%s less than zero. Ignoring.", LAUNCH_JOBKEY_THROTTLEINTERVAL);
2875 			} else if (value > UINT32_MAX) {
2876 				job_log(j, LOG_WARNING, "%s is too large. Ignoring.", LAUNCH_JOBKEY_THROTTLEINTERVAL);
2877 			} else {
2878 				j->min_run_time = (typeof(j->min_run_time)) value;
2879 			}
2880 		}
2881 		break;
2882 	case 'u':
2883 	case 'U':
2884 		if (strcasecmp(key, LAUNCH_JOBKEY_UMASK) == 0) {
2885 			j->mask = value;
2886 			j->setmask = true;
2887 		}
2888 		break;
2889 	case 's':
2890 	case 'S':
2891 		if (strcasecmp(key, LAUNCH_JOBKEY_STARTINTERVAL) == 0) {
2892 			if (unlikely(value <= 0)) {
2893 				job_log(j, LOG_WARNING, "%s is not greater than zero. Ignoring.", LAUNCH_JOBKEY_STARTINTERVAL);
2894 			} else if (unlikely(value > UINT32_MAX)) {
2895 				job_log(j, LOG_WARNING, "%s is too large. Ignoring.", LAUNCH_JOBKEY_STARTINTERVAL);
2896 			} else {
2897 				runtime_add_weak_ref();
2898 				j->start_interval = (typeof(j->start_interval)) value;
2899 
2900 				(void)job_assumes_zero_p(j, kevent_mod((uintptr_t)&j->start_interval, EVFILT_TIMER, EV_ADD, NOTE_SECONDS, j->start_interval, j));
2901 			}
2902 #if HAVE_SANDBOX
2903 		} else if (strcasecmp(key, LAUNCH_JOBKEY_SANDBOXFLAGS) == 0) {
2904 			j->seatbelt_flags = value;
2905 #endif
2906 		}
2907 
2908 		break;
2909 	default:
2910 		job_log(j, LOG_WARNING, "Unknown key for integer: %s", key);
2911 		break;
2912 	}
2913 }
2914 
2915 void
job_import_opaque(job_t j,const char * key,launch_data_t value)2916 job_import_opaque(job_t j __attribute__((unused)), const char *key, launch_data_t value __attribute__((unused)))
2917 {
2918 	switch (key[0]) {
2919 	case 'q':
2920 	case 'Q':
2921 #if HAVE_QUARANTINE
2922 		if (strcasecmp(key, LAUNCH_JOBKEY_QUARANTINEDATA) == 0) {
2923 			size_t tmpsz = launch_data_get_opaque_size(value);
2924 
2925 			if (job_assumes(j, j->quarantine_data = malloc(tmpsz))) {
2926 				memcpy(j->quarantine_data, launch_data_get_opaque(value), tmpsz);
2927 				j->quarantine_data_sz = tmpsz;
2928 			}
2929 		}
2930 #endif
2931 	case 's':
2932 	case 'S':
2933 		if (strcasecmp(key, LAUNCH_JOBKEY_SECURITYSESSIONUUID) == 0) {
2934 			size_t tmpsz = launch_data_get_opaque_size(value);
2935 			if (job_assumes(j, tmpsz == sizeof(uuid_t))) {
2936 				memcpy(j->expected_audit_uuid, launch_data_get_opaque(value), sizeof(uuid_t));
2937 			}
2938 		}
2939 		break;
2940 	default:
2941 		break;
2942 	}
2943 }
2944 
2945 static void
policy_setup(launch_data_t obj,const char * key,void * context)2946 policy_setup(launch_data_t obj, const char *key, void *context)
2947 {
2948 	job_t j = context;
2949 	bool found_key = false;
2950 
2951 	switch (key[0]) {
2952 	case 'd':
2953 	case 'D':
2954 		if (strcasecmp(key, LAUNCH_JOBPOLICY_DENYCREATINGOTHERJOBS) == 0) {
2955 			j->deny_job_creation = launch_data_get_bool(obj);
2956 			found_key = true;
2957 		}
2958 		break;
2959 	default:
2960 		break;
2961 	}
2962 
2963 	if (unlikely(!found_key)) {
2964 		job_log(j, LOG_WARNING, "Unknown policy: %s", key);
2965 	}
2966 }
2967 
2968 void
job_import_dictionary(job_t j,const char * key,launch_data_t value)2969 job_import_dictionary(job_t j, const char *key, launch_data_t value)
2970 {
2971 	launch_data_t tmp;
2972 
2973 	switch (key[0]) {
2974 	case 'p':
2975 	case 'P':
2976 		if (strcasecmp(key, LAUNCH_JOBKEY_POLICIES) == 0) {
2977 			launch_data_dict_iterate(value, policy_setup, j);
2978 		}
2979 		break;
2980 	case 'k':
2981 	case 'K':
2982 		if (strcasecmp(key, LAUNCH_JOBKEY_KEEPALIVE) == 0) {
2983 			launch_data_dict_iterate(value, semaphoreitem_setup, j);
2984 		}
2985 		break;
2986 	case 'i':
2987 	case 'I':
2988 		if (strcasecmp(key, LAUNCH_JOBKEY_INETDCOMPATIBILITY) == 0) {
2989 			j->inetcompat = true;
2990 			j->abandon_pg = true;
2991 			if ((tmp = launch_data_dict_lookup(value, LAUNCH_JOBINETDCOMPATIBILITY_WAIT))) {
2992 				j->inetcompat_wait = launch_data_get_bool(tmp);
2993 			}
2994 		}
2995 		break;
2996 	case 'j':
2997 	case 'J':
2998 		if (strcasecmp(key, LAUNCH_JOBKEY_JETSAMPROPERTIES) == 0) {
2999 			launch_data_dict_iterate(value, (void (*)(launch_data_t, const char *, void *))jetsam_property_setup, j);
3000 		}
3001 	case 'e':
3002 	case 'E':
3003 		if (strcasecmp(key, LAUNCH_JOBKEY_ENVIRONMENTVARIABLES) == 0) {
3004 			launch_data_dict_iterate(value, envitem_setup, j);
3005 		}
3006 		break;
3007 	case 'u':
3008 	case 'U':
3009 		if (strcasecmp(key, LAUNCH_JOBKEY_USERENVIRONMENTVARIABLES) == 0) {
3010 			j->importing_global_env = true;
3011 			launch_data_dict_iterate(value, envitem_setup, j);
3012 			j->importing_global_env = false;
3013 		}
3014 		break;
3015 	case 's':
3016 	case 'S':
3017 		if (strcasecmp(key, LAUNCH_JOBKEY_SOCKETS) == 0) {
3018 			launch_data_dict_iterate(value, socketgroup_setup, j);
3019 		} else if (strcasecmp(key, LAUNCH_JOBKEY_STARTCALENDARINTERVAL) == 0) {
3020 			calendarinterval_new_from_obj(j, value);
3021 		} else if (strcasecmp(key, LAUNCH_JOBKEY_SOFTRESOURCELIMITS) == 0) {
3022 			launch_data_dict_iterate(value, limititem_setup, j);
3023 #if HAVE_SANDBOX
3024 		} else if (strcasecmp(key, LAUNCH_JOBKEY_SANDBOXFLAGS) == 0) {
3025 			launch_data_dict_iterate(value, seatbelt_setup_flags, j);
3026 #endif
3027 		}
3028 		break;
3029 	case 'h':
3030 	case 'H':
3031 		if (strcasecmp(key, LAUNCH_JOBKEY_HARDRESOURCELIMITS) == 0) {
3032 			j->importing_hard_limits = true;
3033 			launch_data_dict_iterate(value, limititem_setup, j);
3034 			j->importing_hard_limits = false;
3035 		}
3036 		break;
3037 	case 'm':
3038 	case 'M':
3039 		if (strcasecmp(key, LAUNCH_JOBKEY_MACHSERVICES) == 0) {
3040 			launch_data_dict_iterate(value, machservice_setup, j);
3041 		}
3042 		break;
3043 	case 'l':
3044 	case 'L':
3045 		if (strcasecmp(key, LAUNCH_JOBKEY_LAUNCHEVENTS) == 0) {
3046 			launch_data_dict_iterate(value, eventsystem_setup, j);
3047 		} else {
3048 			if (strcasecmp(key, LAUNCH_JOBKEY_LIMITLOADTOHARDWARE) == 0) {
3049 				return;
3050 			}
3051 			if (strcasecmp(key, LAUNCH_JOBKEY_LIMITLOADFROMHARDWARE) == 0) {
3052 				return;
3053 			}
3054 		}
3055 		break;
3056 	default:
3057 		job_log(j, LOG_WARNING, "Unknown key for dictionary: %s", key);
3058 		break;
3059 	}
3060 }
3061 
3062 void
job_import_array(job_t j,const char * key,launch_data_t value)3063 job_import_array(job_t j, const char *key, launch_data_t value)
3064 {
3065 	size_t i, value_cnt = launch_data_array_get_count(value);
3066 
3067 	switch (key[0]) {
3068 	case 'p':
3069 	case 'P':
3070 		if (strcasecmp(key, LAUNCH_JOBKEY_PROGRAMARGUMENTS) == 0) {
3071 			return;
3072 		}
3073 		break;
3074 	case 'l':
3075 	case 'L':
3076 		if (strcasecmp(key, LAUNCH_JOBKEY_LIMITLOADTOHOSTS) == 0) {
3077 			return;
3078 		} else if (strcasecmp(key, LAUNCH_JOBKEY_LIMITLOADFROMHOSTS) == 0) {
3079 			return;
3080 		} else if (strcasecmp(key, LAUNCH_JOBKEY_LIMITLOADTOSESSIONTYPE) == 0) {
3081 			job_log(j, LOG_NOTICE, "launchctl should have transformed the \"%s\" array to a string", LAUNCH_JOBKEY_LIMITLOADTOSESSIONTYPE);
3082 			return;
3083 		}
3084 		break;
3085 	case 'b':
3086 	case 'B':
3087 		if (strcasecmp(key, LAUNCH_JOBKEY_BINARYORDERPREFERENCE) == 0) {
3088 			if (job_assumes(j, j->j_binpref = malloc(value_cnt * sizeof(*j->j_binpref)))) {
3089 				j->j_binpref_cnt = value_cnt;
3090 				for (i = 0; i < value_cnt; i++) {
3091 					j->j_binpref[i] = (cpu_type_t) launch_data_get_integer(launch_data_array_get_index(value, i));
3092 				}
3093 			}
3094 		}
3095 		break;
3096 	case 's':
3097 	case 'S':
3098 		if (strcasecmp(key, LAUNCH_JOBKEY_STARTCALENDARINTERVAL) == 0) {
3099 			for (i = 0; i < value_cnt; i++) {
3100 				calendarinterval_new_from_obj(j, launch_data_array_get_index(value, i));
3101 			}
3102 		}
3103 		break;
3104 	default:
3105 		job_log(j, LOG_WARNING, "Unknown key for array: %s", key);
3106 		break;
3107 	}
3108 }
3109 
3110 void
job_import_keys(launch_data_t obj,const char * key,void * context)3111 job_import_keys(launch_data_t obj, const char *key, void *context)
3112 {
3113 	job_t j = context;
3114 	launch_data_type_t kind;
3115 
3116 	if (!obj) {
3117 		launchd_syslog(LOG_ERR, "NULL object given to job_import_keys().");
3118 		return;
3119 	}
3120 
3121 	kind = launch_data_get_type(obj);
3122 
3123 	switch (kind) {
3124 	case LAUNCH_DATA_BOOL:
3125 		job_import_bool(j, key, launch_data_get_bool(obj));
3126 		break;
3127 	case LAUNCH_DATA_STRING:
3128 		job_import_string(j, key, launch_data_get_string(obj));
3129 		break;
3130 	case LAUNCH_DATA_INTEGER:
3131 		job_import_integer(j, key, launch_data_get_integer(obj));
3132 		break;
3133 	case LAUNCH_DATA_DICTIONARY:
3134 		job_import_dictionary(j, key, obj);
3135 		break;
3136 	case LAUNCH_DATA_ARRAY:
3137 		job_import_array(j, key, obj);
3138 		break;
3139 	case LAUNCH_DATA_OPAQUE:
3140 		job_import_opaque(j, key, obj);
3141 		break;
3142 	default:
3143 		job_log(j, LOG_WARNING, "Unknown value type '%d' for key: %s", kind, key);
3144 		break;
3145 	}
3146 }
3147 
3148 job_t
jobmgr_import2(jobmgr_t jm,launch_data_t pload)3149 jobmgr_import2(jobmgr_t jm, launch_data_t pload)
3150 {
3151 	launch_data_t tmp, ldpa;
3152 	const char *label = NULL, *prog = NULL;
3153 	const char **argv = NULL;
3154 	job_t j;
3155 
3156 	if (!jobmgr_assumes(jm, pload != NULL)) {
3157 		errno = EINVAL;
3158 		return NULL;
3159 	}
3160 
3161 	if (unlikely(launch_data_get_type(pload) != LAUNCH_DATA_DICTIONARY)) {
3162 		errno = EINVAL;
3163 		return NULL;
3164 	}
3165 
3166 	if (unlikely(!(tmp = launch_data_dict_lookup(pload, LAUNCH_JOBKEY_LABEL)))) {
3167 		errno = EINVAL;
3168 		return NULL;
3169 	}
3170 
3171 	if (unlikely(launch_data_get_type(tmp) != LAUNCH_DATA_STRING)) {
3172 		errno = EINVAL;
3173 		return NULL;
3174 	}
3175 
3176 	if (unlikely(!(label = launch_data_get_string(tmp)))) {
3177 		errno = EINVAL;
3178 		return NULL;
3179 	}
3180 
3181 #if TARGET_OS_EMBEDDED
3182 	if (unlikely(launchd_embedded_handofgod && _launchd_embedded_god)) {
3183 		if (unlikely(!(tmp = launch_data_dict_lookup(pload, LAUNCH_JOBKEY_USERNAME)))) {
3184 			errno = EPERM;
3185 			return NULL;
3186 		}
3187 
3188 		const char *username = NULL;
3189 		if (likely(tmp && launch_data_get_type(tmp) == LAUNCH_DATA_STRING)) {
3190 			username = launch_data_get_string(tmp);
3191 		} else {
3192 			errno = EPERM;
3193 			return NULL;
3194 		}
3195 
3196 		if (!jobmgr_assumes(jm, _launchd_embedded_god->username != NULL && username != NULL)) {
3197 			errno = EPERM;
3198 			return NULL;
3199 		}
3200 
3201 		if (unlikely(strcmp(_launchd_embedded_god->username, username) != 0)) {
3202 			errno = EPERM;
3203 			return NULL;
3204 		}
3205 	} else if (launchd_embedded_handofgod) {
3206 		errno = EINVAL;
3207 		return NULL;
3208 	}
3209 #endif
3210 
3211 	if ((tmp = launch_data_dict_lookup(pload, LAUNCH_JOBKEY_PROGRAM))
3212 		&& (launch_data_get_type(tmp) == LAUNCH_DATA_STRING)) {
3213 		prog = launch_data_get_string(tmp);
3214 	}
3215 
3216 	int argc = 0;
3217 	if ((ldpa = launch_data_dict_lookup(pload, LAUNCH_JOBKEY_PROGRAMARGUMENTS))) {
3218 		size_t i, c;
3219 
3220 		if (launch_data_get_type(ldpa) != LAUNCH_DATA_ARRAY) {
3221 			errno = EINVAL;
3222 			return NULL;
3223 		}
3224 
3225 		c = launch_data_array_get_count(ldpa);
3226 
3227 		argv = alloca((c + 1) * sizeof(char *));
3228 
3229 		for (i = 0; i < c; i++) {
3230 			tmp = launch_data_array_get_index(ldpa, i);
3231 
3232 			if (launch_data_get_type(tmp) != LAUNCH_DATA_STRING) {
3233 				errno = EINVAL;
3234 				return NULL;
3235 			}
3236 
3237 			argv[i] = launch_data_get_string(tmp);
3238 		}
3239 
3240 		argv[i] = NULL;
3241 		argc = i;
3242 	}
3243 
3244 	if (!prog && argc == 0) {
3245 		jobmgr_log(jm, LOG_ERR, "Job specifies neither Program nor ProgramArguments: %s", label);
3246 		errno = EINVAL;
3247 		return NULL;
3248 	}
3249 
3250 	/* Find the requested session. You cannot load services into XPC domains in
3251 	 * this manner.
3252 	 */
3253 	launch_data_t session = launch_data_dict_lookup(pload, LAUNCH_JOBKEY_LIMITLOADTOSESSIONTYPE);
3254 	if (session) {
3255 		jobmgr_t jmt = NULL;
3256 		if (launch_data_get_type(session) == LAUNCH_DATA_STRING) {
3257 			jmt = jobmgr_find_by_name(jm, launch_data_get_string(session));
3258 			if (!jmt) {
3259 				jobmgr_log(jm, LOG_ERR, "Could not find requested session: %s", launch_data_get_string(session));
3260 			} else {
3261 				jm = jmt;
3262 			}
3263 		} else {
3264 			jobmgr_log(jm, LOG_ERR, "Session type is not a string.");
3265 		}
3266 
3267 		if (!jmt) {
3268 			errno = EINVAL;
3269 			return NULL;
3270 		}
3271 	}
3272 
3273 	/* For legacy reasons, we have a global hash of all labels in all job
3274 	 * managers. So rather than make it a global, we store it in the root job
3275 	 * manager. But for an XPC domain, we store a local hash of all services in
3276 	 * the domain.
3277 	 */
3278 	jobmgr_t where2look = (jm->properties & BOOTSTRAP_PROPERTY_XPC_DOMAIN) ? jm : root_jobmgr;
3279 	if (unlikely((j = job_find(where2look, label)) != NULL)) {
3280 		if (jm->xpc_singleton) {
3281 			/* There can (and probably will be) multiple attemtps to import the
3282 			 * same XPC service from the same framework. This is okay. It's
3283 			 * treated as a singleton, so just return the existing one so that
3284 			 * it may be aliased into the requesting process' XPC domain.
3285 			 */
3286 			errno = EEXIST;
3287 			return j;
3288 		} else {
3289 			/* If we're not a global XPC domain, then it's an error to try
3290 			 * importing the same job/service multiple times.
3291 			 */
3292 			errno = EEXIST;
3293 			return NULL;
3294 		}
3295 	} else if (unlikely(!jobmgr_label_test(where2look, label))) {
3296 		errno = EINVAL;
3297 		return NULL;
3298 	}
3299 	jobmgr_log(jm, LOG_DEBUG, "Importing %s.", label);
3300 
3301 	if (likely(j = job_new(jm, label, prog, argv))) {
3302 #if TARGET_OS_EMBEDDED
3303 		job_apply_defaults(j);
3304 #endif
3305 		launch_data_dict_iterate(pload, job_import_keys, j);
3306 		if (!uuid_is_null(j->expected_audit_uuid)) {
3307 			uuid_string_t uuid_str;
3308 			uuid_unparse(j->expected_audit_uuid, uuid_str);
3309 			job_log(j, LOG_DEBUG, "Imported job. Waiting for session for UUID %s.", uuid_str);
3310 			LIST_INSERT_HEAD(&s_needing_sessions, j, needing_session_sle);
3311 			errno = ENEEDAUTH;
3312 		} else {
3313 			job_log(j, LOG_DEBUG, "No security session specified.");
3314 			j->asport = MACH_PORT_NULL;
3315 		}
3316 
3317 		if (pid1_magic && !jm->parentmgr) {
3318 			/* Workaround reentrancy in CF. We don't make this a global variable
3319 			 * because we don't want per-user launchd's to inherit it. So we
3320 			 * just set it for every job that we import into the System session.
3321 			 *
3322 			 * See <rdar://problem/9468837>.
3323 			 */
3324 			envitem_new(j, "__CF_USER_TEXT_ENCODING", "0x0:0:0", false);
3325 		}
3326 
3327 		if (j->event_monitor) {
3328 			eventsystem_ping();
3329 		}
3330 
3331 #if TARGET_OS_EMBEDDED
3332 		/* SpringBoard and backboardd must run at elevated priority.
3333 		 *
3334 		 * See <rdar://problem/9539873> and <rdar://problem/10984383>.
3335 		 */
3336 		if (j->embedded_god || j->embedded_home) {
3337 			j->psproctype = POSIX_SPAWN_PROC_TYPE_APP_DEFAULT;
3338 		}
3339 #endif
3340 	}
3341 
3342 	return j;
3343 }
3344 
3345 bool
jobmgr_label_test(jobmgr_t jm,const char * str)3346 jobmgr_label_test(jobmgr_t jm, const char *str)
3347 {
3348 	const char *ptr;
3349 
3350 	if (str[0] == '\0') {
3351 		jobmgr_log(jm, LOG_ERR, "Empty job labels are not allowed");
3352 		return false;
3353 	}
3354 
3355 	for (ptr = str; *ptr; ptr++) {
3356 		if (iscntrl(*ptr)) {
3357 			jobmgr_log(jm, LOG_ERR, "ASCII control characters are not allowed in job labels. Index: %td Value: 0x%hhx", ptr - str, *ptr);
3358 			return false;
3359 		}
3360 	}
3361 
3362 	if ((strncasecmp(str, "com.apple.launchd", strlen("com.apple.launchd")) == 0)
3363 		|| (strncasecmp(str, "com.apple.launchctl", strlen("com.apple.launchctl")) == 0)) {
3364 		jobmgr_log(jm, LOG_ERR, "Job labels are not allowed to use a reserved prefix: %s", str);
3365 		return false;
3366 	}
3367 
3368 	return true;
3369 }
3370 
3371 job_t
job_find(jobmgr_t jm,const char * label)3372 job_find(jobmgr_t jm, const char *label)
3373 {
3374 	job_t ji;
3375 
3376 	if (!jm) {
3377 		jm = root_jobmgr;
3378 	}
3379 
3380 	LIST_FOREACH(ji, &jm->label_hash[hash_label(label)], label_hash_sle) {
3381 		if (unlikely(ji->removal_pending || ji->mgr->shutting_down)) {
3382 			// 5351245 and 5488633 respectively
3383 			continue;
3384 		}
3385 
3386 		if (strcmp(ji->label, label) == 0) {
3387 			return ji;
3388 		}
3389 	}
3390 
3391 	errno = ESRCH;
3392 	return NULL;
3393 }
3394 
3395 // Should try and consolidate with job_mig_intran2() and jobmgr_find_by_pid().
3396 job_t
jobmgr_find_by_pid_deep(jobmgr_t jm,pid_t p,bool anon_okay)3397 jobmgr_find_by_pid_deep(jobmgr_t jm, pid_t p, bool anon_okay)
3398 {
3399 	job_t ji = NULL;
3400 	LIST_FOREACH(ji, &jm->active_jobs[ACTIVE_JOB_HASH(p)], pid_hash_sle) {
3401 		if (ji->p == p && (!ji->anonymous || (ji->anonymous && anon_okay))) {
3402 			return ji;
3403 		}
3404 	}
3405 
3406 	jobmgr_t jmi = NULL;
3407 	SLIST_FOREACH(jmi, &jm->submgrs, sle) {
3408 		if ((ji = jobmgr_find_by_pid_deep(jmi, p, anon_okay))) {
3409 			break;
3410 		}
3411 	}
3412 
3413 	return ji;
3414 }
3415 
3416 job_t
jobmgr_find_by_pid(jobmgr_t jm,pid_t p,bool create_anon)3417 jobmgr_find_by_pid(jobmgr_t jm, pid_t p, bool create_anon)
3418 {
3419 	job_t ji;
3420 
3421 	LIST_FOREACH(ji, &jm->active_jobs[ACTIVE_JOB_HASH(p)], pid_hash_sle) {
3422 		if (ji->p == p) {
3423 			return ji;
3424 		}
3425 	}
3426 
3427 	return create_anon ? job_new_anonymous(jm, p) : NULL;
3428 }
3429 
3430 job_t
managed_job(pid_t p)3431 managed_job(pid_t p)
3432 {
3433 	job_t ji;
3434 
3435 	LIST_FOREACH(ji, &managed_actives[ACTIVE_JOB_HASH(p)], pid_hash_sle) {
3436 		if (ji->p == p) {
3437 			return ji;
3438 		}
3439 	}
3440 
3441 	return NULL;
3442 }
3443 
3444 job_t
job_mig_intran2(jobmgr_t jm,mach_port_t mport,pid_t upid)3445 job_mig_intran2(jobmgr_t jm, mach_port_t mport, pid_t upid)
3446 {
3447 	jobmgr_t jmi;
3448 	job_t ji;
3449 
3450 	if (jm->jm_port == mport) {
3451 		return jobmgr_find_by_pid(jm, upid, true);
3452 	}
3453 
3454 	SLIST_FOREACH(jmi, &jm->submgrs, sle) {
3455 		job_t jr;
3456 
3457 		if ((jr = job_mig_intran2(jmi, mport, upid))) {
3458 			return jr;
3459 		}
3460 	}
3461 
3462 	LIST_FOREACH(ji, &jm->jobs, sle) {
3463 		if (ji->j_port == mport) {
3464 			return ji;
3465 		}
3466 	}
3467 
3468 	return NULL;
3469 }
3470 
3471 job_t
job_mig_intran(mach_port_t p)3472 job_mig_intran(mach_port_t p)
3473 {
3474 	struct ldcred *ldc = runtime_get_caller_creds();
3475 	job_t jr;
3476 
3477 	jr = job_mig_intran2(root_jobmgr, p, ldc->pid);
3478 
3479 	if (!jr) {
3480 		struct proc_bsdshortinfo proc;
3481 		if (proc_pidinfo(ldc->pid, PROC_PIDT_SHORTBSDINFO, 1, &proc, PROC_PIDT_SHORTBSDINFO_SIZE) == 0) {
3482 			if (errno != ESRCH) {
3483 				(void)jobmgr_assumes_zero(root_jobmgr, errno);
3484 			} else {
3485 				jobmgr_log(root_jobmgr, LOG_ERR, "%s[%i] disappeared out from under us (UID: %u EUID: %u)", proc.pbsi_comm, ldc->pid, ldc->uid, ldc->euid);
3486 			}
3487 		}
3488 	}
3489 
3490 	return jr;
3491 }
3492 
3493 job_t
job_find_by_service_port(mach_port_t p)3494 job_find_by_service_port(mach_port_t p)
3495 {
3496 	struct machservice *ms;
3497 
3498 	LIST_FOREACH(ms, &port_hash[HASH_PORT(p)], port_hash_sle) {
3499 		if (ms->recv && (ms->port == p)) {
3500 			return ms->job;
3501 		}
3502 	}
3503 
3504 	return NULL;
3505 }
3506 
3507 void
job_mig_destructor(job_t j)3508 job_mig_destructor(job_t j)
3509 {
3510 	/* The job can go invalid before this point.
3511 	 *
3512 	 * <rdar://problem/5477111>
3513 	 */
3514 	if (unlikely(j && (j != workaround_5477111) && j->unload_at_mig_return)) {
3515 		job_log(j, LOG_NOTICE, "Unloading PID %u at MIG return.", j->p);
3516 		job_remove(j);
3517 	}
3518 
3519 	workaround_5477111 = NULL;
3520 
3521 	calendarinterval_sanity_check();
3522 }
3523 
3524 void
job_export_all2(jobmgr_t jm,launch_data_t where)3525 job_export_all2(jobmgr_t jm, launch_data_t where)
3526 {
3527 	jobmgr_t jmi;
3528 	job_t ji;
3529 
3530 	SLIST_FOREACH(jmi, &jm->submgrs, sle) {
3531 		job_export_all2(jmi, where);
3532 	}
3533 
3534 	LIST_FOREACH(ji, &jm->jobs, sle) {
3535 		launch_data_t tmp;
3536 
3537 		if (jobmgr_assumes(jm, (tmp = job_export(ji)) != NULL)) {
3538 			launch_data_dict_insert(where, tmp, ji->label);
3539 		}
3540 	}
3541 }
3542 
3543 launch_data_t
job_export_all(void)3544 job_export_all(void)
3545 {
3546 	launch_data_t resp = launch_data_alloc(LAUNCH_DATA_DICTIONARY);
3547 
3548 	if (resp != NULL) {
3549 		job_export_all2(root_jobmgr, resp);
3550 	} else {
3551 		(void)os_assumes_zero(errno);
3552 	}
3553 
3554 	return resp;
3555 }
3556 
3557 void
job_log_stray_pg(job_t j)3558 job_log_stray_pg(job_t j)
3559 {
3560 	pid_t *pids = NULL;
3561 	size_t len = sizeof(pid_t) * get_kern_max_proc();
3562 	int i = 0, kp_cnt = 0;
3563 
3564 	if (!launchd_apple_internal) {
3565 		return;
3566 	}
3567 
3568 	runtime_ktrace(RTKT_LAUNCHD_FINDING_STRAY_PG, j->p, 0, 0);
3569 
3570 	if (!job_assumes(j, (pids = malloc(len)) != NULL)) {
3571 		return;
3572 	}
3573 	if (job_assumes_zero_p(j, (kp_cnt = proc_listpgrppids(j->p, pids, len))) == -1) {
3574 		goto out;
3575 	}
3576 
3577 	for (i = 0; i < kp_cnt; i++) {
3578 		pid_t p_i = pids[i];
3579 		if (p_i == j->p) {
3580 			continue;
3581 		} else if (p_i == 0 || p_i == 1) {
3582 			continue;
3583 		}
3584 
3585 		struct proc_bsdshortinfo proc;
3586 		if (proc_pidinfo(p_i, PROC_PIDT_SHORTBSDINFO, 1, &proc, PROC_PIDT_SHORTBSDINFO_SIZE) == 0) {
3587 			if (errno != ESRCH) {
3588 				(void)job_assumes_zero(j, errno);
3589 			}
3590 			continue;
3591 		}
3592 
3593 		pid_t pp_i = proc.pbsi_ppid;
3594 		const char *z = (proc.pbsi_status == SZOMB) ? "zombie " : "";
3595 		const char *n = proc.pbsi_comm;
3596 
3597 		job_log(j, LOG_WARNING, "Stray %sprocess with PGID equal to this dead job: PID %u PPID %u PGID %u %s", z, p_i, pp_i, proc.pbsi_pgid, n);
3598 	}
3599 
3600 out:
3601 	free(pids);
3602 }
3603 
3604 #if HAVE_SYSTEMSTATS
3605 static void
systemstats_timer_callback(void)3606 systemstats_timer_callback(void)
3607 {
3608 	jobmgr_log_perf_statistics(root_jobmgr, true);
3609 }
3610 
3611 static bool
systemstats_is_enabled(void)3612 systemstats_is_enabled(void)
3613 {
3614 	static bool systemstats_enabled;
3615 
3616 	if (!systemstats_enabled) {
3617 		char *store = launchd_copy_persistent_store(LAUNCHD_PERSISTENT_STORE_LOGS, NULL);
3618 		systemstats_enabled = systemstats_init(SYSTEMSTATS_WRITER_launchd, store);
3619 		free(store);
3620 
3621 		uint64_t interval;
3622 		interval = systemstats_get_log_interval(SYSTEMSTATS_WRITER_launchd);
3623 
3624 		if (pid1_magic && systemstats_enabled && interval) {
3625 			jobmgr_assumes_zero_p(root_jobmgr, kevent_mod((uintptr_t)systemstats_timer_callback, EVFILT_TIMER, EV_ADD, NOTE_SECONDS, interval, root_jobmgr));
3626 		}
3627 	}
3628 
3629 	return systemstats_enabled;
3630 }
3631 #endif // HAVE_SYSTEMSTATS
3632 
3633 void
job_reap(job_t j)3634 job_reap(job_t j)
3635 {
3636 	bool is_system_bootstrapper = ((j->is_bootstrapper && pid1_magic) && !j->mgr->parentmgr);
3637 
3638 	job_log(j, LOG_DEBUG, "Reaping");
3639 
3640 	if (unlikely(j->weird_bootstrap)) {
3641 		int64_t junk = 0;
3642 		job_mig_swap_integer(j, VPROC_GSK_WEIRD_BOOTSTRAP, 0, 0, &junk);
3643 	}
3644 
3645 	if (j->fork_fd) {
3646 		(void)job_assumes_zero_p(j, runtime_close(j->fork_fd));
3647 		j->fork_fd = 0;
3648 	}
3649 
3650 	bool was_dirty = false;
3651 	if (!(j->anonymous || j->implicit_reap)) {
3652 		uint32_t flags = 0;
3653 #if 0
3654 		(void)job_assumes_zero(j, proc_get_dirty(j->p, &flags));
3655 #endif
3656 		j->idle_exit = (flags & PROC_DIRTY_ALLOWS_IDLE_EXIT);
3657 		was_dirty = (flags & PROC_DIRTY_IS_DIRTY);
3658 
3659 		job_log(j, LOG_DEBUG, "%sob exited %s.", j->idle_exit ? "Idle-exit j" : "J", was_dirty ? "while dirty" : "cleanly");
3660 	}
3661 
3662 	if (j->idle_exit && was_dirty) {
3663 		if (j->jettisoned) {
3664 			job_log(j, LOG_NOTICE, "Idle-exit job was jettisoned while dirty. Will respawn immediately.");
3665 			j->unthrottle = true;
3666 			j->start_pending = true;
3667 		} else {
3668 			job_log(j, LOG_INFO, "Idle-exit job exited while dirty.");
3669 		}
3670 	} else if (j->idle_exit && j->jettisoned) {
3671 		/* If an idle-exit job is jettisoned, then we shouldn't throttle its
3672 		 * next respawn because it could not help when it exited. If it ran for
3673 		 * the minimum runtime, then this doesn't really matter. If it ran for
3674 		 * less than the minimum runtime, it will not be throttled.
3675 		 *
3676 		 * <rdar://problem/12098667>
3677 		 */
3678 		job_log(j, LOG_NOTICE, "Idle-exit job was jettisoned. Will bypass throttle interval for next on-demand launch.");
3679 		j->unthrottle = true;
3680 	}
3681 
3682 	if (j->anonymous) {
3683 		j->last_exit_status = 0;
3684 	} else {
3685 		uint64_t rt = runtime_get_nanoseconds_since(j->start_time);
3686 		j->trt += rt;
3687 
3688 		job_log(j, LOG_PERF, "Last instance wall time: %06f", (double)rt / (double)NSEC_PER_SEC);
3689 		j->nruns++;
3690 
3691 		/* The job is dead. While the PID/PGID is still known to be valid, try
3692 		 * to kill abandoned descendant processes.
3693 		 */
3694 		job_log_stray_pg(j);
3695 		if (!j->abandon_pg) {
3696 			if (unlikely(killpg2(j->p, SIGTERM) == -1 && errno != ESRCH)) {
3697 				job_log(j, LOG_APPLEONLY, "Bug: 5487498");
3698 			}
3699 		}
3700 
3701 		int r = -1;
3702 		if (!j->implicit_reap) {
3703 			/* If the shutdown monitor has suspended a task and not resumed it
3704 			 * resumed it before exiting, the kernel will not clean up after the
3705 			 * shutdown monitor. It will, instead, leave the task suspended and
3706 			 * not process any pending signals on the event loop for the task.
3707 			 *
3708 			 * There are a variety of other kernel bugs that could prevent a
3709 			 * process from exiting, usually having to do with faulty hardware
3710 			 * or talking to misbehaving drivers that mark a thread as
3711 			 * uninterruptible and deadlock/hang before unmarking it as such. So
3712 			 * we have to work around that too.
3713 			 *
3714 			 * See <rdar://problem/9284889&9359725>.
3715 			 */
3716 			if (j->workaround9359725) {
3717 				job_log(j, LOG_NOTICE, "Simulated exit: <rdar://problem/9359725>");
3718 				j->last_exit_status = W_EXITCODE(-1, SIGSEGV);
3719 			} else {
3720 #if HAVE_SYSTEMSTATS
3721 				int r2;
3722 				struct rusage_info_v1 ri;
3723 				r2 = job_assumes_zero(j, proc_pid_rusage(j->p, RUSAGE_INFO_V1, (rusage_info_t)&ri));
3724 #endif
3725 				if ((r = wait4(j->p, &j->last_exit_status, 0, NULL)) == -1) {
3726 					job_log(j, LOG_ERR, "Reap failed. Assuming job exited: %d: %s", errno, strerror(errno));
3727 					j->last_exit_status = W_EXITCODE(-1, SIGSEGV);
3728 				}
3729 
3730 				if (j->idle_exit && j->jettisoned) {
3731 					// Treat idle-exit jettisons as successful exit.
3732 					//
3733 					// <rdar://problem/13338973>
3734 					(void)job_assumes_zero(j, WTERMSIG(j->last_exit_status));
3735 					j->last_exit_status = W_EXITCODE(0, 0);
3736 				}
3737 #if HAVE_SYSTEMSTATS
3738 				if (r2 == 0) {
3739 					job_log_perf_statistics(j, &ri, j->last_exit_status);
3740 				}
3741 #endif
3742 			}
3743 		} else {
3744 			job_log(j, LOG_INFO, "Job was implicitly reaped by the kernel.");
3745 		}
3746 	}
3747 
3748 	if (j->exit_timeout) {
3749 		(void)kevent_mod((uintptr_t)&j->exit_timeout, EVFILT_TIMER, EV_DELETE, 0, 0, NULL);
3750 	}
3751 
3752 	LIST_REMOVE(j, pid_hash_sle);
3753 	if (!j->anonymous) {
3754 		LIST_REMOVE(j, global_pid_hash_sle);
3755 	}
3756 
3757 	if (j->sent_signal_time) {
3758 		uint64_t td_sec, td_usec, td = runtime_get_nanoseconds_since(j->sent_signal_time);
3759 
3760 		td_sec = td / NSEC_PER_SEC;
3761 		td_usec = (td % NSEC_PER_SEC) / NSEC_PER_USEC;
3762 
3763 		job_log(j, LOG_DEBUG, "Exited %zu.%06zu seconds after the first signal was sent", td_sec, td_usec);
3764 	}
3765 
3766 	int exit_status = WEXITSTATUS(j->last_exit_status);
3767 	if (WIFEXITED(j->last_exit_status) && exit_status != 0) {
3768 		if (!j->did_exec && _launchd_support_system) {
3769 			xpc_object_t event = NULL;
3770 			switch (exit_status) {
3771 			case ENOENT:
3772 			case ENOTDIR:
3773 			case ESRCH:
3774 				job_log(j, LOG_NOTICE, "Job failed to exec(3). Setting up event to tell us when to try again: %d: %s", exit_status, strerror(exit_status));
3775 				event = xpc_dictionary_create(NULL, NULL, 0);
3776 				xpc_dictionary_set_string(event, "Executable", j->prog ? j->prog : j->argv[0]);
3777 				if (j->mach_uid) {
3778 					xpc_dictionary_set_uint64(event, "UID", j->mach_uid);
3779 				} else if (j->username) {
3780 					xpc_dictionary_set_string(event, "UserName", j->username);
3781 				}
3782 
3783 				if (j->groupname) {
3784 					xpc_dictionary_set_string(event, "GroupName", j->groupname);
3785 				}
3786 
3787 				(void)externalevent_new(j, _launchd_support_system, j->label, event, 0);
3788 				xpc_release(event);
3789 
3790 				j->waiting4ok = true;
3791 			default:
3792 				job_log(j, LOG_NOTICE, "Job failed to exec(3) for weird reason: %d", exit_status);
3793 			}
3794 		} else {
3795 			int level = LOG_INFO;
3796 			if (exit_status != 0) {
3797 				level = LOG_ERR;
3798 			}
3799 
3800 			job_log(j, level, "Exited with code: %d", exit_status);
3801 		}
3802 	}
3803 
3804 	if (WIFSIGNALED(j->last_exit_status)) {
3805 		int s = WTERMSIG(j->last_exit_status);
3806 		if ((SIGKILL == s || SIGTERM == s) && !j->stopped) {
3807 			job_log(j, LOG_NOTICE, "Exited: %s", strsignal(s));
3808 		} else if (!(j->stopped || j->clean_kill || j->jettisoned)) {
3809 			switch (s) {
3810 			// Signals which indicate a crash.
3811 			case SIGILL:
3812 			case SIGABRT:
3813 			case SIGFPE:
3814 			case SIGBUS:
3815 			case SIGSEGV:
3816 			case SIGSYS:
3817 			/* If the kernel has posted NOTE_EXIT and the signal sent to the process was
3818 			 * SIGTRAP, assume that it's a crash.
3819 			 */
3820 			case SIGTRAP:
3821 				j->crashed = true;
3822 				job_log(j, LOG_WARNING, "Job appears to have crashed: %s", strsignal(s));
3823 				break;
3824 			default:
3825 				job_log(j, LOG_WARNING, "Exited abnormally: %s", strsignal(s));
3826 				break;
3827 			}
3828 
3829 			if (is_system_bootstrapper && j->crashed) {
3830 				job_log(j, LOG_ERR | LOG_CONSOLE, "The %s bootstrapper has crashed: %s", j->mgr->name, strsignal(s));
3831 			}
3832 		}
3833 	}
3834 
3835 	j->reaped = true;
3836 
3837 	struct machservice *msi = NULL;
3838 	if (j->crashed || !(j->did_exec || j->anonymous)) {
3839 		SLIST_FOREACH(msi, &j->machservices, sle) {
3840 			if (j->crashed && !msi->isActive && (msi->drain_one_on_crash || msi->drain_all_on_crash)) {
3841 				machservice_drain_port(msi);
3842 			}
3843 
3844 			if (!j->did_exec && msi->reset && job_assumes(j, !msi->isActive)) {
3845 				machservice_resetport(j, msi);
3846 			}
3847 		}
3848 	}
3849 
3850 	/* HACK: Essentially duplicating the logic directly above. But this has
3851 	 * gotten really hairy, and I don't want to try consolidating it right now.
3852 	 */
3853 	if (j->xpc_service && !j->xpcproxy_did_exec) {
3854 		job_log(j, LOG_ERR, "XPC Service could not exec(3). Resetting port.");
3855 		SLIST_FOREACH(msi, &j->machservices, sle) {
3856 			/* Drain the messages but do not reset the port. If xpcproxy could
3857 			 * not exec(3), then we don't want to continue trying, since there
3858 			 * is very likely a serious configuration error with the service.
3859 			 *
3860 			 * The above comment is weird. I originally said we should drain
3861 			 * messages but not reset the port, but that's exactly what we do
3862 			 * below, and I'm not sure which is the mistake, the comment or the
3863 			 * actual behavior.
3864 			 *
3865 			 * Since it's always been this way, I'll assume that the comment is
3866 			 * incorrect, but I'll leave it in place just to remind myself to
3867 			 * actually look into it at some point.
3868 			 *
3869 			 * <rdar://problem/8986802>
3870 			 */
3871 			if (msi->upfront && job_assumes(j, !msi->isActive)) {
3872 				machservice_resetport(j, msi);
3873 			}
3874 		}
3875 	}
3876 
3877 	struct suspended_peruser *spi = NULL;
3878 	while ((spi = LIST_FIRST(&j->suspended_perusers))) {
3879 		job_log(j, LOG_ERR, "Job exited before resuming per-user launchd for UID %u. Will forcibly resume.", spi->j->mach_uid);
3880 		spi->j->peruser_suspend_count--;
3881 		if (spi->j->peruser_suspend_count == 0) {
3882 			job_dispatch(spi->j, false);
3883 		}
3884 		LIST_REMOVE(spi, sle);
3885 		free(spi);
3886 	}
3887 
3888 	if (j->exit_status_dest) {
3889 		errno = helper_downcall_wait(j->exit_status_dest, j->last_exit_status);
3890 		if (errno && errno != MACH_SEND_INVALID_DEST) {
3891 			(void)job_assumes_zero(j, errno);
3892 		}
3893 
3894 		j->exit_status_dest = MACH_PORT_NULL;
3895 	}
3896 
3897 	if (j->spawn_reply_port) {
3898 		/* If the child never called exec(3), we must send a spawn() reply so
3899 		 * that the requestor can get exit status from it. If we fail to send
3900 		 * the reply for some reason, we have to deallocate the exit status port
3901 		 * ourselves.
3902 		 */
3903 		kern_return_t kr = job_mig_spawn2_reply(j->spawn_reply_port, BOOTSTRAP_SUCCESS, j->p, j->exit_status_port);
3904 		if (kr) {
3905 			if (kr != MACH_SEND_INVALID_DEST) {
3906 				(void)job_assumes_zero(j, kr);
3907 			}
3908 
3909 			(void)job_assumes_zero(j, launchd_mport_close_recv(j->exit_status_port));
3910 		}
3911 
3912 		j->exit_status_port = MACH_PORT_NULL;
3913 		j->spawn_reply_port = MACH_PORT_NULL;
3914 	}
3915 
3916 	if (j->anonymous) {
3917 		total_anon_children--;
3918 		if (j->holds_ref) {
3919 			job_log(j, LOG_PERF, "Anonymous job exited holding reference.");
3920 			runtime_del_ref();
3921 		}
3922 	} else {
3923 		job_log(j, LOG_PERF, "Job exited.");
3924 		runtime_del_ref();
3925 		total_children--;
3926 	}
3927 
3928 	if (j->has_console) {
3929 		launchd_wsp = 0;
3930 	}
3931 
3932 	if (j->shutdown_monitor) {
3933 		job_log(j, LOG_NOTICE | LOG_CONSOLE, "Shutdown monitor has exited.");
3934 		_launchd_shutdown_monitor = NULL;
3935 		j->shutdown_monitor = false;
3936 	}
3937 
3938 	if (!j->anonymous) {
3939 		j->mgr->normal_active_cnt--;
3940 	}
3941 	j->sent_signal_time = 0;
3942 	j->sent_sigkill = false;
3943 	j->clean_kill = false;
3944 	j->event_monitor_ready2signal = false;
3945 	j->p = 0;
3946 	j->uniqueid = 0;
3947 }
3948 
3949 void
jobmgr_dispatch_all(jobmgr_t jm,bool newmounthack)3950 jobmgr_dispatch_all(jobmgr_t jm, bool newmounthack)
3951 {
3952 	jobmgr_t jmi, jmn;
3953 	job_t ji, jn;
3954 
3955 	if (jm->shutting_down) {
3956 		return;
3957 	}
3958 
3959 	SLIST_FOREACH_SAFE(jmi, &jm->submgrs, sle, jmn) {
3960 		jobmgr_dispatch_all(jmi, newmounthack);
3961 	}
3962 
3963 	LIST_FOREACH_SAFE(ji, &jm->jobs, sle, jn) {
3964 		if (newmounthack && ji->start_on_mount) {
3965 			ji->start_pending = true;
3966 		}
3967 
3968 		job_dispatch(ji, false);
3969 	}
3970 }
3971 
3972 void
job_dispatch_curious_jobs(job_t j)3973 job_dispatch_curious_jobs(job_t j)
3974 {
3975 	job_t ji = NULL, jt = NULL;
3976 	SLIST_FOREACH_SAFE(ji, &s_curious_jobs, curious_jobs_sle, jt) {
3977 		struct semaphoreitem *si = NULL;
3978 		SLIST_FOREACH(si, &ji->semaphores, sle) {
3979 			if (!(si->why == OTHER_JOB_ENABLED || si->why == OTHER_JOB_DISABLED)) {
3980 				continue;
3981 			}
3982 
3983 			if (strcmp(si->what, j->label) == 0) {
3984 				job_log(ji, LOG_DEBUG, "Dispatching out of interest in \"%s\".", j->label);
3985 
3986 				if (!ji->removing) {
3987 					job_dispatch(ji, false);
3988 				} else {
3989 					job_log(ji, LOG_NOTICE, "The following job is circularly dependent upon this one: %s", j->label);
3990 				}
3991 
3992 				/* ji could be removed here, so don't do anything with it or its semaphores
3993 				 * after this point.
3994 				 */
3995 				break;
3996 			}
3997 		}
3998 	}
3999 }
4000 
4001 job_t
job_dispatch(job_t j,bool kickstart)4002 job_dispatch(job_t j, bool kickstart)
4003 {
4004 	// Don't dispatch a job if it has no audit session set.
4005 	syslog(LOG_DEBUG, "dispatching job j=%p kickstart=%d", j, kickstart);
4006 	#ifdef notyet
4007 	if (!uuid_is_null(j->expected_audit_uuid)) {
4008 		job_log(j, LOG_DEBUG, "Job is still awaiting its audit session UUID. Not dispatching.");
4009 		return NULL;
4010 	}
4011 	#endif
4012 	if (j->alias) {
4013 		job_log(j, LOG_DEBUG, "Job is an alias. Not dispatching.");
4014 		return NULL;
4015 	}
4016 
4017 	if (j->waiting4ok) {
4018 		job_log(j, LOG_DEBUG, "Job cannot exec(3). Not dispatching.");
4019 		return NULL;
4020 	}
4021 
4022 #if TARGET_OS_EMBEDDED
4023 	if (launchd_embedded_handofgod && _launchd_embedded_god) {
4024 		if (!job_assumes(j, _launchd_embedded_god->username != NULL && j->username != NULL)) {
4025 			errno = EPERM;
4026 			return NULL;
4027 		}
4028 
4029 		if (strcmp(j->username, _launchd_embedded_god->username) != 0) {
4030 			errno = EPERM;
4031 			return NULL;
4032 		}
4033 	} else if (launchd_embedded_handofgod) {
4034 		errno = EINVAL;
4035 		return NULL;
4036 	}
4037 #endif
4038 
4039 	/*
4040 	 * The whole job removal logic needs to be consolidated. The fact that
4041 	 * a job can be removed from just about anywhere makes it easy to have
4042 	 * stale pointers left behind somewhere on the stack that might get
4043 	 * used after the deallocation. In particular, during job iteration.
4044 	 *
4045 	 * This is a classic example. The act of dispatching a job may delete it.
4046 	 */
4047 	if (!job_active(j)) {
4048 		if (job_useless(j)) {
4049 			job_log(j, LOG_DEBUG, "Job is useless. Removing.");
4050 			job_remove(j);
4051 			return NULL;
4052 		}
4053 		if (unlikely(j->per_user && j->peruser_suspend_count > 0)) {
4054 			job_log(j, LOG_DEBUG, "Per-user launchd is suspended. Not dispatching.");
4055 			return NULL;
4056 		}
4057 
4058 		if (kickstart || job_keepalive(j) || uflag) {
4059 			job_log(j, LOG_DEBUG, "%starting job", kickstart ? "Kicks" : "S");
4060 			job_start(j);
4061 		} else {
4062 			job_log(j, LOG_DEBUG, "Watching job.");
4063 			job_watch(j);
4064 		}
4065 	} else {
4066 		job_log(j, LOG_DEBUG, "Tried to dispatch an already active job: %s.", job_active(j));
4067 	}
4068 	return j;
4069 }
4070 
4071 void
job_kill(job_t j)4072 job_kill(job_t j)
4073 {
4074 	if (unlikely(!j->p || j->anonymous)) {
4075 		return;
4076 	}
4077 
4078 	(void)job_assumes_zero_p(j, kill2(j->p, SIGKILL));
4079 
4080 	j->sent_sigkill = true;
4081 	(void)job_assumes_zero_p(j, kevent_mod((uintptr_t)&j->exit_timeout, EVFILT_TIMER, EV_ADD|EV_ONESHOT, NOTE_SECONDS, LAUNCHD_SIGKILL_TIMER, j));
4082 
4083 	job_log(j, LOG_DEBUG, "Sent SIGKILL signal");
4084 }
4085 
4086 void
job_open_shutdown_transaction(job_t j)4087 job_open_shutdown_transaction(job_t j)
4088 {
4089 	int rv = proc_set_dirty(j->p, true);
4090 	if (rv != 0) {
4091 		job_log(j, LOG_DEBUG, "Job wants to be dirty at shutdown, but it is not Instant Off-compliant. Treating normally.");
4092 		j->dirty_at_shutdown = false;
4093 	}
4094 }
4095 
4096 void
job_close_shutdown_transaction(job_t j)4097 job_close_shutdown_transaction(job_t j)
4098 {
4099 	if (j->dirty_at_shutdown) {
4100 		job_log(j, LOG_DEBUG, "Closing shutdown transaction for job.");
4101 		(void)job_assumes_zero(j, proc_set_dirty(j->p, false));
4102 		j->dirty_at_shutdown = false;
4103 	}
4104 }
4105 
4106 void
job_log_children_without_exec(job_t j)4107 job_log_children_without_exec(job_t j)
4108 {
4109 	pid_t *pids = NULL;
4110 	size_t len = sizeof(pid_t) * get_kern_max_proc();
4111 	int i = 0, kp_cnt = 0;
4112 
4113 	if (!launchd_apple_internal || j->anonymous || j->per_user) {
4114 		return;
4115 	}
4116 
4117 	if (!job_assumes(j, (pids = malloc(len)) != NULL)) {
4118 		return;
4119 	}
4120 	if (job_assumes_zero_p(j, (kp_cnt = proc_listchildpids(j->p, pids, len))) == -1) {
4121 		goto out;
4122 	}
4123 
4124 	for (i = 0; i < kp_cnt; i++) {
4125 		struct proc_bsdshortinfo proc;
4126 		if (proc_pidinfo(pids[i], PROC_PIDT_SHORTBSDINFO, 1, &proc, PROC_PIDT_SHORTBSDINFO_SIZE) == 0) {
4127 			if (errno != ESRCH) {
4128 				(void)job_assumes_zero(j, errno);
4129 			}
4130 			continue;
4131 		}
4132 		if (proc.pbsi_flags & P_EXEC) {
4133 			continue;
4134 		}
4135 
4136 		job_log(j, LOG_DEBUG, "Called *fork(). Please switch to posix_spawn*(), pthreads or launchd. Child PID %u", pids[i]);
4137 	}
4138 
4139 out:
4140 	free(pids);
4141 }
4142 
4143 void
job_callback_proc(job_t j,struct kevent * kev)4144 job_callback_proc(job_t j, struct kevent *kev)
4145 {
4146 	bool program_changed = false;
4147 	int fflags = kev->fflags;
4148 
4149 	job_log(j, LOG_DEBUG, "EVFILT_PROC event for job.");
4150 	log_kevent_struct(LOG_DEBUG, kev, 0);
4151 
4152 	if (fflags & NOTE_EXEC) {
4153 		program_changed = true;
4154 
4155 		if (j->anonymous) {
4156 			struct proc_bsdshortinfo proc;
4157 			if (proc_pidinfo(j->p, PROC_PIDT_SHORTBSDINFO, 1, &proc, PROC_PIDT_SHORTBSDINFO_SIZE) > 0) {
4158 				char newlabel[1000];
4159 
4160 				snprintf(newlabel, sizeof(newlabel), "%p.anonymous.%s", j, proc.pbsi_comm);
4161 
4162 				job_log(j, LOG_INFO, "Program changed. Updating the label to: %s", newlabel);
4163 
4164 				LIST_REMOVE(j, label_hash_sle);
4165 				strcpy((char *)j->label, newlabel);
4166 
4167 				jobmgr_t where2put = root_jobmgr;
4168 				if (j->mgr->properties & BOOTSTRAP_PROPERTY_XPC_DOMAIN) {
4169 					where2put = j->mgr;
4170 				}
4171 				LIST_INSERT_HEAD(&where2put->label_hash[hash_label(j->label)], j, label_hash_sle);
4172 			} else if (errno != ESRCH) {
4173 				(void)job_assumes_zero(j, errno);
4174 			}
4175 		} else {
4176 			if (j->spawn_reply_port) {
4177 				errno = job_mig_spawn2_reply(j->spawn_reply_port, BOOTSTRAP_SUCCESS, j->p, j->exit_status_port);
4178 				if (errno) {
4179 					if (errno != MACH_SEND_INVALID_DEST) {
4180 						(void)job_assumes_zero(j, errno);
4181 					}
4182 					(void)job_assumes_zero(j, launchd_mport_close_recv(j->exit_status_port));
4183 				}
4184 
4185 				j->spawn_reply_port = MACH_PORT_NULL;
4186 				j->exit_status_port = MACH_PORT_NULL;
4187 			}
4188 
4189 			if (j->xpc_service && j->did_exec) {
4190 				j->xpcproxy_did_exec = true;
4191 			}
4192 
4193 			j->did_exec = true;
4194 			job_log(j, LOG_DEBUG, "Program changed");
4195 		}
4196 	}
4197 
4198 	if (fflags & NOTE_FORK) {
4199 		job_log(j, LOG_DEBUG, "fork()ed%s", program_changed ? ". For this message only: We don't know whether this event happened before or after execve()." : "");
4200 		job_log_children_without_exec(j);
4201 	}
4202 
4203 	if (fflags & NOTE_EXIT) {
4204 		if (kev->data & NOTE_EXIT_DECRYPTFAIL) {
4205 			j->fpfail = true;
4206 			job_log(j, LOG_WARNING, "FairPlay decryption failed on binary for job.");
4207 		} else if (kev->data & NOTE_EXIT_MEMORY) {
4208 			j->jettisoned = true;
4209 			job_log(j, LOG_INFO, "Job was killed due to memory pressure.");
4210 		}
4211 
4212 		job_reap(j);
4213 
4214 		if (j->anonymous) {
4215 			job_remove(j);
4216 			j = NULL;
4217 		} else {
4218 			struct waiting4attach *w4ai = NULL;
4219 			struct waiting4attach *w4ait = NULL;
4220 			LIST_FOREACH_SAFE(w4ai, &_launchd_domain_waiters, le, w4ait) {
4221 				if (w4ai->dest == (pid_t)kev->ident) {
4222 					waiting4attach_delete(j->mgr, w4ai);
4223 				}
4224 			}
4225 
4226 			(void)job_dispatch(j, false);
4227 		}
4228 	}
4229 }
4230 
4231 void
job_callback_timer(job_t j,void * ident)4232 job_callback_timer(job_t j, void *ident)
4233 {
4234 	if (j == ident) {
4235 		job_log(j, LOG_DEBUG, "j == ident (%p)", ident);
4236 		job_dispatch(j, true);
4237 	} else if (&j->semaphores == ident) {
4238 		job_log(j, LOG_DEBUG, "&j->semaphores == ident (%p)", ident);
4239 		job_dispatch(j, false);
4240 	} else if (&j->start_interval == ident) {
4241 		job_log(j, LOG_DEBUG, "&j->start_interval == ident (%p)", ident);
4242 		j->start_pending = true;
4243 		job_dispatch(j, false);
4244 	} else if (&j->exit_timeout == ident) {
4245 		if (!job_assumes(j, j->p != 0)) {
4246 			return;
4247 		}
4248 
4249 		if (j->sent_sigkill) {
4250 			uint64_t td = runtime_get_nanoseconds_since(j->sent_signal_time);
4251 
4252 			td /= NSEC_PER_SEC;
4253 			td -= j->clean_kill ? 0 : j->exit_timeout;
4254 
4255 			job_log(j, LOG_WARNING | LOG_CONSOLE, "Job has not died after being %skilled %zu seconds ago. Simulating exit.", j->clean_kill ? "cleanly " : "", td);
4256 			j->workaround9359725 = true;
4257 
4258 			// This basically has to be done off the main thread. We have no
4259 			// mechanism for draining the main queue in our run loop (like CF
4260 			// does), and the kevent mechanism wants an object to be associated
4261 			// as the callback. So we just create a dispatch source and reap the
4262 			// errant PID whenever we can. Note that it is not safe for us to do
4263 			// any logging in this block, since logging requires exclusive
4264 			// access to global data structures that is only protected by the
4265 			// main thread.
4266 			dispatch_source_t hack_13570156 = dispatch_source_create(DISPATCH_SOURCE_TYPE_PROC, j->p, DISPATCH_PROC_EXIT, dispatch_get_global_queue(0, 0));
4267 			dispatch_source_set_event_handler(hack_13570156, ^{
4268 				pid_t pid = (pid_t)dispatch_source_get_handle(hack_13570156);
4269 
4270 				int status = 0;
4271 				(void)waitpid(pid, &status, 0);
4272 				dispatch_release(hack_13570156);
4273 			});
4274 
4275 			dispatch_resume(hack_13570156);
4276 
4277 			if (launchd_trap_sigkill_bugs) {
4278 				job_log(j, LOG_NOTICE | LOG_CONSOLE, "Trapping into kernel debugger. You can continue the machine after it has been debugged, and shutdown will proceed normally.");
4279 				(void)job_assumes_zero(j, host_reboot(mach_host_self(), HOST_REBOOT_DEBUGGER));
4280 			}
4281 
4282 			struct kevent bogus_exit;
4283 			EV_SET(&bogus_exit, j->p, EVFILT_PROC, 0, NOTE_EXIT, 0, 0);
4284 			jobmgr_callback(j->mgr, &bogus_exit);
4285 		} else {
4286 			if (unlikely(j->debug_before_kill)) {
4287 				job_log(j, LOG_NOTICE, "Exit timeout elapsed. Entering the kernel debugger");
4288 				(void)job_assumes_zero(j, host_reboot(mach_host_self(), HOST_REBOOT_DEBUGGER));
4289 			}
4290 
4291 			job_log(j, LOG_WARNING | LOG_CONSOLE, "Exit timeout elapsed (%u seconds). Killing", j->exit_timeout);
4292 			job_kill(j);
4293 		}
4294 	} else {
4295 		job_log(j, LOG_ERR, "Unrecognized job timer callback: %p", ident);
4296 	}
4297 }
4298 
4299 void
job_callback_read(job_t j,int ident)4300 job_callback_read(job_t j, int ident)
4301 {
4302 	if (ident == j->stdin_fd) {
4303 		job_dispatch(j, true);
4304 	} else {
4305 		socketgroup_callback(j);
4306 	}
4307 }
4308 
4309 void
jobmgr_reap_bulk(jobmgr_t jm,struct kevent * kev)4310 jobmgr_reap_bulk(jobmgr_t jm, struct kevent *kev)
4311 {
4312 	jobmgr_t jmi;
4313 	job_t j;
4314 
4315 	SLIST_FOREACH(jmi, &jm->submgrs, sle) {
4316 		jobmgr_reap_bulk(jmi, kev);
4317 	}
4318 
4319 	if ((j = jobmgr_find_by_pid(jm, (pid_t)kev->ident, false))) {
4320 		kev->udata = j;
4321 		job_callback(j, kev);
4322 	}
4323 }
4324 
4325 void
jobmgr_callback(void * obj,struct kevent * kev)4326 jobmgr_callback(void *obj, struct kevent *kev)
4327 {
4328 	jobmgr_t jm = obj;
4329 
4330 #if TARGET_OS_EMBEDDED
4331 	int flag2check = VQ_MOUNT;
4332 #else
4333 	int flag2check = VQ_UPDATE;
4334 #endif
4335 
4336 	switch (kev->filter) {
4337 	case EVFILT_PROC:
4338 		jobmgr_reap_bulk(jm, kev);
4339 		root_jobmgr = jobmgr_do_garbage_collection(root_jobmgr);
4340 		break;
4341 	case EVFILT_SIGNAL:
4342 		switch (kev->ident) {
4343 		case SIGTERM:
4344 			jobmgr_log(jm, LOG_DEBUG, "Got SIGTERM. Shutting down.");
4345 			return launchd_shutdown();
4346 		case SIGUSR1:
4347 			return calendarinterval_callback();
4348 		case SIGUSR2:
4349 			// Turn on all logging.
4350 			launchd_log_perf = true;
4351 			launchd_log_debug = true;
4352 			launchd_log_shutdown = true;
4353 			/* Hopefully /var is available by this point. If not, uh, oh well.
4354 			 * It's just a debugging facility.
4355 			 */
4356 			return jobmgr_log_perf_statistics(jm, false);
4357 		case SIGINFO:
4358 			return jobmgr_log_perf_statistics(jm, true);
4359 		default:
4360 			jobmgr_log(jm, LOG_ERR, "Unrecognized signal: %lu: %s", kev->ident, strsignal(kev->ident));
4361 		}
4362 		break;
4363 	case EVFILT_FS:
4364 		if (kev->fflags & flag2check) {
4365 			if (!launchd_var_available) {
4366 				struct stat sb;
4367 				if (stat("/var/log", &sb) == 0 && (sb.st_mode & S_IWUSR)) {
4368 					launchd_var_available = true;
4369 				}
4370 			}
4371 		} else if (kev->fflags & VQ_MOUNT) {
4372 			jobmgr_dispatch_all(jm, true);
4373 		}
4374 		jobmgr_dispatch_all_semaphores(jm);
4375 		break;
4376 	case EVFILT_TIMER:
4377 		if (kev->ident == (uintptr_t)&sorted_calendar_events) {
4378 			calendarinterval_callback();
4379 		} else if (kev->ident == (uintptr_t)jm) {
4380 			jobmgr_log(jm, LOG_DEBUG, "Shutdown timer firing.");
4381 			jobmgr_still_alive_with_check(jm);
4382 		} else if (kev->ident == (uintptr_t)&jm->reboot_flags) {
4383 			jobmgr_do_garbage_collection(jm);
4384 		}
4385 		else if (kev->ident == (uintptr_t)&launchd_runtime_busy_time) {
4386 #if 0
4387 			jobmgr_log(jm, LOG_DEBUG, "Idle exit timer fired. Shutting down.");
4388 			if (jobmgr_assumes_zero(jm, runtime_busy_cnt) == 0) {
4389 				return launchd_shutdown();
4390 			}
4391 #endif
4392 #if HAVE_SYSTEMSTATS
4393 		} else if (kev->ident == (uintptr_t)systemstats_timer_callback) {
4394 			systemstats_timer_callback();
4395 #endif
4396 		}
4397 		break;
4398 	case EVFILT_VNODE:
4399 		if (kev->ident == (uintptr_t)s_no_hang_fd) {
4400 			int _no_hang_fd = open("/dev/autofs_nowait", O_EVTONLY | O_NONBLOCK);
4401 			if (unlikely(_no_hang_fd != -1)) {
4402 				jobmgr_log(root_jobmgr, LOG_DEBUG, "/dev/autofs_nowait has appeared!");
4403 				(void)jobmgr_assumes_zero_p(root_jobmgr, kevent_mod((uintptr_t)s_no_hang_fd, EVFILT_VNODE, EV_DELETE, 0, 0, NULL));
4404 				(void)jobmgr_assumes_zero_p(root_jobmgr, runtime_close(s_no_hang_fd));
4405 				s_no_hang_fd = _fd(_no_hang_fd);
4406 			}
4407 		} else if (pid1_magic && launchd_console && kev->ident == (uintptr_t)fileno(launchd_console)) {
4408 			int cfd = -1;
4409 			if (jobmgr_assumes_zero_p(jm, cfd = open(_PATH_CONSOLE, O_WRONLY | O_NOCTTY)) != -1) {
4410 				_fd(cfd);
4411 				if (!(launchd_console = fdopen(cfd, "w"))) {
4412 					(void)jobmgr_assumes_zero(jm, errno);
4413 					(void)close(cfd);
4414 				}
4415 			}
4416 		}
4417 		break;
4418 	default:
4419 		jobmgr_log(jm, LOG_ERR, "Unrecognized kevent filter: %hd", kev->filter);
4420 	}
4421 }
4422 
4423 void
job_callback(void * obj,struct kevent * kev)4424 job_callback(void *obj, struct kevent *kev)
4425 {
4426 	job_t j = obj;
4427 
4428 	job_log(j, LOG_DEBUG, "Dispatching kevent callback.");
4429 
4430 	switch (kev->filter) {
4431 	case EVFILT_PROC:
4432 		return job_callback_proc(j, kev);
4433 	case EVFILT_TIMER:
4434 		return job_callback_timer(j, (void *) kev->ident);
4435 	case EVFILT_READ:
4436 		return job_callback_read(j, (int) kev->ident);
4437 	case EVFILT_MACHPORT:
4438 		return (void)job_dispatch(j, true);
4439 	default:
4440 		job_log(j, LOG_ERR, "Unrecognized job callback filter: %hd", kev->filter);
4441 	}
4442 }
4443 
4444 void
job_start(job_t j)4445 job_start(job_t j)
4446 {
4447 	uint64_t td;
4448 	int spair[2];
4449 	int execspair[2];
4450 	char nbuf[64];
4451 	pid_t c;
4452 	bool sipc = false;
4453 	u_int proc_fflags = NOTE_EXIT|NOTE_FORK|NOTE_EXEC|NOTE_EXIT_DETAIL|NOTE_EXITSTATUS;
4454 
4455 	if (!job_assumes(j, j->mgr != NULL)) {
4456 		return;
4457 	}
4458 
4459 	if (unlikely(job_active(j))) {
4460 		job_log(j, LOG_DEBUG, "Already started");
4461 		return;
4462 	}
4463 
4464 	if (!LIST_EMPTY(&j->mgr->attaches)) {
4465 		job_log(j, LOG_DEBUG, "Looking for attachments for job: %s", j->label);
4466 		(void)waiting4attach_find(j->mgr, j);
4467 	}
4468 
4469 	/*
4470 	 * Some users adjust the wall-clock and then expect software to not notice.
4471 	 * Therefore, launchd must use an absolute clock instead of the wall clock
4472 	 * wherever possible.
4473 	 */
4474 	td = runtime_get_nanoseconds_since(j->start_time);
4475 	td /= NSEC_PER_SEC;
4476 
4477 	if (j->start_time && (td < j->min_run_time) && !j->legacy_mach_job && !j->inetcompat && !j->unthrottle) {
4478 		time_t respawn_delta = j->min_run_time - (uint32_t)td;
4479 		/* We technically should ref-count throttled jobs to prevent idle exit,
4480 		 * but we're not directly tracking the 'throttled' state at the moment.
4481 		 */
4482 		job_log(j, LOG_NOTICE, "Throttling respawn: Will start in %ld seconds", respawn_delta);
4483 		(void)job_assumes_zero_p(j, kevent_mod((uintptr_t)j, EVFILT_TIMER, EV_ADD|EV_ONESHOT, NOTE_SECONDS, respawn_delta, j));
4484 		job_ignore(j);
4485 		return;
4486 	}
4487 
4488 	if (likely(!j->legacy_mach_job)) {
4489 		sipc = ((!SLIST_EMPTY(&j->sockets) || !SLIST_EMPTY(&j->machservices)) && !j->deny_job_creation) || j->embedded_god;
4490 	}
4491 
4492 	if (sipc) {
4493 		(void)job_assumes_zero_p(j, socketpair(AF_UNIX, SOCK_STREAM, 0, spair));
4494 	}
4495 
4496 	(void)job_assumes_zero_p(j, socketpair(AF_UNIX, SOCK_STREAM, 0, execspair));
4497 
4498 	switch (c = runtime_fork(j->weird_bootstrap ? j->j_port : j->mgr->jm_port)) {
4499 	case -1:
4500 		job_log_error(j, LOG_ERR, "fork() failed, will try again in one second");
4501 		(void)job_assumes_zero_p(j, kevent_mod((uintptr_t)j, EVFILT_TIMER, EV_ADD|EV_ONESHOT, NOTE_SECONDS, 1, j));
4502 		job_ignore(j);
4503 
4504 		(void)job_assumes_zero(j, runtime_close(execspair[0]));
4505 		(void)job_assumes_zero(j, runtime_close(execspair[1]));
4506 		if (sipc) {
4507 			(void)job_assumes_zero(j, runtime_close(spair[0]));
4508 			(void)job_assumes_zero(j, runtime_close(spair[1]));
4509 		}
4510 		break;
4511 	case 0:
4512 		if (unlikely(_vproc_post_fork_ping())) {
4513 			syslog(LOG_ERR, "_vproc_post_fork_ping() fail");
4514 			DEBUG_EXIT(EXIT_FAILURE);
4515 		}
4516 
4517 		(void)job_assumes_zero(j, runtime_close(execspair[0]));
4518 		// wait for our parent to say they've attached a kevent to us
4519 		read(_fd(execspair[1]), &c, sizeof(c));
4520 		if (sipc) {
4521 			(void)job_assumes_zero(j, runtime_close(spair[0]));
4522 			snprintf(nbuf, sizeof(nbuf), "%d", spair[1]);
4523 			setenv(LAUNCHD_TRUSTED_FD_ENV, nbuf, 1);
4524 		}
4525 		job_start_child(j);
4526 		break;
4527 	default:
4528 		j->start_time = runtime_get_opaque_time();
4529 
4530 		job_log(j, LOG_DEBUG, "Started as PID: %u", c);
4531 
4532 		j->did_exec = false;
4533 		j->fpfail = false;
4534 		j->jettisoned = false;
4535 		j->xpcproxy_did_exec = false;
4536 		j->checkedin = false;
4537 		j->start_pending = false;
4538 		j->reaped = false;
4539 		j->crashed = false;
4540 		j->stopped = false;
4541 		j->workaround9359725 = false;
4542 		j->implicit_reap = false;
4543 		j->unthrottle = false;
4544 		if (j->needs_kickoff) {
4545 			j->needs_kickoff = false;
4546 
4547 			if (SLIST_EMPTY(&j->semaphores)) {
4548 				j->ondemand = false;
4549 			}
4550 		}
4551 
4552 		if (j->has_console) {
4553 			launchd_wsp = c;
4554 		}
4555 
4556 		job_log(j, LOG_PERF, "Job started.");
4557 		runtime_add_ref();
4558 		total_children++;
4559 		LIST_INSERT_HEAD(&j->mgr->active_jobs[ACTIVE_JOB_HASH(c)], j, pid_hash_sle);
4560 		LIST_INSERT_HEAD(&managed_actives[ACTIVE_JOB_HASH(c)], j, global_pid_hash_sle);
4561 		j->p = c;
4562 
4563 		struct proc_uniqidentifierinfo info;
4564 		if (proc_pidinfo(c, PROC_PIDUNIQIDENTIFIERINFO, 0, &info, PROC_PIDUNIQIDENTIFIERINFO_SIZE) != 0) {
4565 			// ignore errors here, kevent_mod below will catch them and clean up
4566 			j->uniqueid = info.p_uniqueid;
4567 		}
4568 
4569 		j->mgr->normal_active_cnt++;
4570 		j->fork_fd = _fd(execspair[0]);
4571 		(void)job_assumes_zero(j, runtime_close(execspair[1]));
4572 		if (sipc) {
4573 			(void)job_assumes_zero(j, runtime_close(spair[1]));
4574 			ipc_open(_fd(spair[0]), j);
4575 		}
4576 		if (kevent_mod(c, EVFILT_PROC, EV_ADD, proc_fflags, 0, root_jobmgr ? root_jobmgr : j->mgr) != -1) {
4577 			job_ignore(j);
4578 		} else {
4579 			if (errno == ESRCH) {
4580 				job_log(j, LOG_ERR, "Child was killed before we could attach a kevent.");
4581 			} else {
4582 				(void)job_assumes(j, errno == ESRCH);
4583 			}
4584 			job_reap(j);
4585 
4586 			/* If we have reaped this job within this same run loop pass, then
4587 			 * it will be currently ignored. So if there's a failure to attach a
4588 			 * kevent, we need to make sure that we watch the job so that we can
4589 			 * respawn it.
4590 			 *
4591 			 * See <rdar://problem/10140809>.
4592 			 */
4593 			job_watch(j);
4594 		}
4595 
4596 #if HAVE_SYSTEMSTATS
4597 		if (systemstats_is_enabled()) {
4598 			/* We don't really *need* to make the full rusage call -- it
4599 			 * will be mostly 0s and very small numbers. We only need
4600 			 * ri_proc_start_abstime, because that's how we disambiguiate
4601 			 * PIDs when they wrap around; and the UUID.
4602 			 * In the future we should use the 64-bit process unique ID,
4603 			 * so there's nothing to disambiguiate, and skip the full
4604 			 * rusage call here.
4605 			 *
4606 			 * Well, the future is now.
4607 			 */
4608 			if (_systemstats_get_property(SYSTEMSTATS_API_VERSION, SYSTEMSTATS_WRITER_launchd, SYSTEMSTATS_PROPERTY_LAUNCHD_SHOULD_LOG_JOB_START)) {
4609 				job_log_perf_statistics(j, NULL, -3);
4610 			}
4611 		}
4612 #endif
4613 		j->wait4debugger_oneshot = false;
4614 		if (likely(!j->stall_before_exec)) {
4615 			job_uncork_fork(j);
4616 		}
4617 		break;
4618 	}
4619 }
4620 
4621 void
job_start_child(job_t j)4622 job_start_child(job_t j)
4623 {
4624 	typeof(posix_spawn) *psf;
4625 	const char *file2exec = "/usr/libexec/launchproxy";
4626 	const char **argv;
4627 	posix_spawnattr_t spattr;
4628 	int gflags = GLOB_NOSORT|GLOB_NOCHECK|GLOB_TILDE|GLOB_DOOFFS;
4629 	glob_t g;
4630 	short spflags = POSIX_SPAWN_SETEXEC;
4631 	int psproctype = POSIX_SPAWN_PROC_TYPE_DAEMON_BACKGROUND;
4632 	size_t binpref_out_cnt = 0;
4633 	size_t i;
4634 
4635 	(void)job_assumes_zero(j, posix_spawnattr_init(&spattr));
4636 
4637 	job_setup_attributes(j);
4638 
4639 	bool use_xpcproxy = false;
4640 	struct waiting4attach *w4a = waiting4attach_find(j->mgr, j);
4641 	if (w4a) {
4642 		(void)setenv(XPC_SERVICE_ENV_ATTACHED, "1", 1);
4643 		if (!j->xpc_service) {
4644 			use_xpcproxy = true;
4645 		}
4646 	}
4647 
4648 	if (use_xpcproxy) {
4649 		argv = alloca(3 * sizeof(char *));
4650 		argv[0] = "/usr/libexec/xpcproxy";
4651 		argv[1] = "-debug";
4652 		argv[2] = NULL;
4653 
4654 		file2exec = argv[0];
4655 	} else if (unlikely(j->argv && j->globargv)) {
4656 		g.gl_offs = 1;
4657 		for (i = 0; i < j->argc; i++) {
4658 			if (i > 0) {
4659 				gflags |= GLOB_APPEND;
4660 			}
4661 			if (glob(j->argv[i], gflags, NULL, &g) != 0) {
4662 				job_log_error(j, LOG_ERR, "glob(\"%s\")", j->argv[i]);
4663 				syslog(LOG_ERR, "glob error");
4664 				DEBUG_EXIT(EXIT_FAILURE);
4665 			}
4666 		}
4667 		g.gl_pathv[0] = (char *)file2exec;
4668 		argv = (const char **)g.gl_pathv;
4669 	} else if (likely(j->argv)) {
4670 		argv = alloca((j->argc + 2) * sizeof(char *));
4671 		argv[0] = file2exec;
4672 		for (i = 0; i < j->argc; i++) {
4673 			argv[i + 1] = j->argv[i];
4674 		}
4675 		argv[i + 1] = NULL;
4676 	} else {
4677 		argv = alloca(3 * sizeof(char *));
4678 		argv[0] = file2exec;
4679 		argv[1] = j->prog;
4680 		argv[2] = NULL;
4681 	}
4682 
4683 	if (likely(!(j->inetcompat || use_xpcproxy))) {
4684 		argv++;
4685 	}
4686 
4687 	if (unlikely(j->wait4debugger || j->wait4debugger_oneshot)) {
4688 		if (!j->app) {
4689 			job_log(j, LOG_WARNING, "Spawned and waiting for the debugger to attach before continuing...");
4690 		}
4691 		spflags |= POSIX_SPAWN_START_SUSPENDED;
4692 	}
4693 
4694 #if !TARGET_OS_EMBEDDED
4695 	if (unlikely(j->disable_aslr)) {
4696 		spflags |= _POSIX_SPAWN_DISABLE_ASLR;
4697 	}
4698 #endif
4699 	spflags |= j->pstype;
4700 
4701 	(void)job_assumes_zero(j, posix_spawnattr_setflags(&spattr, spflags));
4702 	if (unlikely(j->j_binpref_cnt)) {
4703 		(void)job_assumes_zero(j, posix_spawnattr_setbinpref_np(&spattr, j->j_binpref_cnt, j->j_binpref, &binpref_out_cnt));
4704 		(void)job_assumes(j, binpref_out_cnt == j->j_binpref_cnt);
4705 	}
4706 
4707 	psproctype = j->psproctype;
4708 	(void)job_assumes_zero(j, posix_spawnattr_setprocesstype_np(&spattr, psproctype));
4709 
4710 #if TARGET_OS_EMBEDDED
4711 	/* Set jetsam attributes. POSIX_SPAWN_JETSAM_USE_EFFECTIVE_PRIORITY guards
4712 	 * against a race which arises if, during spawn, an initial jetsam property
4713 	 * update occurs before the values below are applied. In this case, the flag
4714 	 * ensures that the subsequent change is ignored; the explicit update should
4715 	 * be given priority.
4716 	 */
4717 	(void)job_assumes_zero(j, posix_spawnattr_setjetsam(&spattr,
4718 	        POSIX_SPAWN_JETSAM_USE_EFFECTIVE_PRIORITY | (j->jetsam_memory_limit_background ? POSIX_SPAWN_JETSAM_HIWATER_BACKGROUND : 0),
4719 	        j->jetsam_priority, j->jetsam_memlimit));
4720 #endif
4721 
4722 #ifdef notyet
4723 	/* XXX: not yet: https://bugs.freenas.org/issues/10186 */
4724 	mach_port_array_t sports = NULL;
4725 	mach_msg_type_number_t sports_cnt = 0;
4726 	kern_return_t kr = vproc_mig_get_listener_port_rights(bootstrap_port, &sports, &sports_cnt);
4727 	if (kr == 0 && sports_cnt) {
4728 		/* For some reason, this SPI takes a count as a signed quantity. */
4729 		(void)posix_spawnattr_set_importancewatch_port_np(&spattr, (int)sports_cnt, sports);
4730 
4731 		/* All "count" parameters in MIG are counts of the array. So an array of
4732 		 * mach_port_t containing 10 elements will have a count of ten, but it
4733 		 * will occupy 40 bytes. So we must do the multiplication here to pass
4734 		 * the correct size.
4735 		 *
4736 		 * Note that we do NOT release the send rights. We need them to be valid
4737 		 * at the time they are passed to posix_spawn(2). When we exec(3) using
4738 		 * posix_spawn(2), they'll be cleaned up anyway.
4739 		 */
4740 		mig_deallocate((vm_address_t)sports, sports_cnt * sizeof(sports[0]));
4741 	} else if (kr != BOOTSTRAP_UNKNOWN_SERVICE) {
4742 		(void)job_assumes_zero(j, kr);
4743 	}
4744 #endif
4745 
4746 #if TARGET_OS_EMBEDDED
4747 	if (!j->app || j->system_app) {
4748 		(void)job_assumes_zero(j, posix_spawnattr_setcpumonitor_default(&spattr));
4749 	}
4750 #else
4751 	(void)job_assumes_zero(j, posix_spawnattr_setcpumonitor_default(&spattr));
4752 #endif
4753 
4754 #if 0
4755 #if !TARGET_OS_EMBEDDED
4756 	struct task_qos_policy qosinfo = {
4757 		.task_latency_qos_tier = LATENCY_QOS_LAUNCH_DEFAULT_TIER,
4758 		.task_throughput_qos_tier = THROUGHPUT_QOS_LAUNCH_DEFAULT_TIER,
4759 	};
4760 
4761 	if (!j->legacy_timers) {
4762 		kr = task_policy_set(mach_task_self(), TASK_BASE_QOS_POLICY, (task_policy_t)&qosinfo, TASK_QOS_POLICY_COUNT);
4763 		(void)job_assumes_zero_p(j, kr);
4764 	}
4765 #endif
4766 #endif
4767 
4768 #if HAVE_RESPONSIBILITY
4769 	/* Specify which process is responsible for the new job.  Per-app XPC
4770 	 * services are the responsibility of the app.  Other processes are
4771 	 * responsible for themselves.  This decision is final and also applies
4772 	 * to the process's children, so don't initialize responsibility when
4773 	 * starting a per-user launchd.
4774 	 */
4775 	if (j->mgr->req_pid) {
4776 		responsibility_init2(j->mgr->req_pid, NULL);
4777 	} else if (!j->per_user) {
4778 		responsibility_init2(getpid(), j->prog ? j->prog : j->argv[0]);
4779 	}
4780 #endif
4781 
4782 #if HAVE_QUARANTINE
4783 	if (j->quarantine_data) {
4784 		qtn_proc_t qp;
4785 
4786 		if (job_assumes(j, qp = qtn_proc_alloc())) {
4787 			if (job_assumes_zero(j, qtn_proc_init_with_data(qp, j->quarantine_data, j->quarantine_data_sz) == 0)) {
4788 				(void)job_assumes_zero(j, qtn_proc_apply_to_self(qp));
4789 			}
4790 		}
4791 	}
4792 #endif
4793 
4794 #if HAVE_SANDBOX
4795 #if TARGET_OS_EMBEDDED
4796 	struct sandbox_spawnattrs sbattrs;
4797 	if (j->seatbelt_profile || j->container_identifier) {
4798 		sandbox_spawnattrs_init(&sbattrs);
4799 		if (j->seatbelt_profile) {
4800 			sandbox_spawnattrs_setprofilename(&sbattrs, j->seatbelt_profile);
4801 		}
4802 		if (j->container_identifier) {
4803 			sandbox_spawnattrs_setcontainer(&sbattrs, j->container_identifier);
4804 		}
4805 		(void)job_assumes_zero(j, posix_spawnattr_setmacpolicyinfo_np(&spattr, "Sandbox", &sbattrs, sizeof(sbattrs)));
4806 	}
4807 #else
4808 	if (j->seatbelt_profile) {
4809 		char *seatbelt_err_buf = NULL;
4810 
4811 		if (job_assumes_zero_p(j, sandbox_init(j->seatbelt_profile, j->seatbelt_flags, &seatbelt_err_buf)) == -1) {
4812 			if (seatbelt_err_buf) {
4813 				job_log(j, LOG_ERR, "Sandbox failed to init: %s", seatbelt_err_buf);
4814 			}
4815 			goto out_bad;
4816 		}
4817 	}
4818 #endif
4819 #endif
4820 
4821 	psf = j->prog ? posix_spawn : posix_spawnp;
4822 
4823 	if (likely(!(j->inetcompat || use_xpcproxy))) {
4824 		file2exec = j->prog ? j->prog : argv[0];
4825 	}
4826 
4827 	errno = psf(NULL, file2exec, NULL, &spattr, (char *const *)argv, environ);
4828 	syslog(LOG_ERR, "job_start failed %s\n", strerror(errno));
4829 	sleep(20);
4830 
4831 #if HAVE_SANDBOX && !TARGET_OS_EMBEDDED
4832 out_bad:
4833 #endif
4834 	syslog(LOG_ERR, "errno=%d", errno);
4835 	DEBUG_EXIT(errno);
4836 }
4837 
4838 void
jobmgr_export_env_from_other_jobs(jobmgr_t jm,launch_data_t dict)4839 jobmgr_export_env_from_other_jobs(jobmgr_t jm, launch_data_t dict)
4840 {
4841 	launch_data_t tmp;
4842 	struct envitem *ei;
4843 	job_t ji;
4844 
4845 	if (jm->parentmgr) {
4846 		jobmgr_export_env_from_other_jobs(jm->parentmgr, dict);
4847 	} else {
4848 		char **tmpenviron = environ;
4849 		for (; *tmpenviron; tmpenviron++) {
4850 			char envkey[1024];
4851 			launch_data_t s = launch_data_alloc(LAUNCH_DATA_STRING);
4852 			launch_data_set_string(s, strchr(*tmpenviron, '=') + 1);
4853 			strncpy(envkey, *tmpenviron, sizeof(envkey));
4854 			*(strchr(envkey, '=')) = '\0';
4855 			launch_data_dict_insert(dict, s, envkey);
4856 		}
4857 	}
4858 
4859 	LIST_FOREACH(ji, &jm->jobs, sle) {
4860 		SLIST_FOREACH(ei, &ji->global_env, sle) {
4861 			if ((tmp = launch_data_new_string(ei->value))) {
4862 				launch_data_dict_insert(dict, tmp, ei->key);
4863 			}
4864 		}
4865 	}
4866 }
4867 
4868 void
jobmgr_setup_env_from_other_jobs(jobmgr_t jm)4869 jobmgr_setup_env_from_other_jobs(jobmgr_t jm)
4870 {
4871 	struct envitem *ei;
4872 	job_t ji;
4873 
4874 	if (jm->parentmgr) {
4875 		jobmgr_setup_env_from_other_jobs(jm->parentmgr);
4876 	}
4877 
4878 	LIST_FOREACH(ji, &jm->global_env_jobs, global_env_sle) {
4879 		SLIST_FOREACH(ei, &ji->global_env, sle) {
4880 			setenv(ei->key, ei->value, 1);
4881 		}
4882 	}
4883 }
4884 
4885 void
job_log_pids_with_weird_uids(job_t j)4886 job_log_pids_with_weird_uids(job_t j)
4887 {
4888 	size_t len = sizeof(pid_t) * get_kern_max_proc();
4889 	pid_t *pids = NULL;
4890 	uid_t u = j->mach_uid;
4891 	int i = 0, kp_cnt = 0;
4892 
4893 	if (!launchd_apple_internal) {
4894 		return;
4895 	}
4896 
4897 	pids = malloc(len);
4898 	if (!job_assumes(j, pids != NULL)) {
4899 		return;
4900 	}
4901 
4902 	runtime_ktrace(RTKT_LAUNCHD_FINDING_WEIRD_UIDS, j->p, u, 0);
4903 
4904 	/* libproc actually has some serious performance drawbacks when used over sysctl(3) in
4905 	 * scenarios like this. Whereas sysctl(3) can give us back all the kinfo_proc's in
4906 	 * one kernel call, libproc requires that we get a list of PIDs we're interested in
4907 	 * (in this case, all PIDs on the system) and then get a single proc_bsdshortinfo
4908 	 * struct back in a single call for each one.
4909 	 *
4910 	 * This kind of thing is also more inherently racy than sysctl(3). While sysctl(3)
4911 	 * returns a snapshot, it returns the whole shebang at once. Any PIDs given to us by
4912 	 * libproc could go stale before we call proc_pidinfo().
4913 	 *
4914 	 * Note that proc_list*() APIs return the number of PIDs given back, not the number
4915 	 * of bytes written to the buffer.
4916 	 */
4917 	if (job_assumes_zero_p(j, (kp_cnt = proc_listallpids(pids, len))) == -1) {
4918 		goto out;
4919 	}
4920 
4921 	for (i = 0; i < kp_cnt; i++) {
4922 		struct proc_bsdshortinfo proc;
4923 		/* We perhaps should not log a bug here if we get ESRCH back, due to the race
4924 		 * detailed above.
4925 		 */
4926 		if (proc_pidinfo(pids[i], PROC_PIDT_SHORTBSDINFO, 1, &proc, PROC_PIDT_SHORTBSDINFO_SIZE) == 0) {
4927 			if (errno != ESRCH) {
4928 				(void)job_assumes_zero(j, errno);
4929 			}
4930 			continue;
4931 		}
4932 
4933 		uid_t i_euid = proc.pbsi_uid;
4934 		uid_t i_uid = proc.pbsi_ruid;
4935 		uid_t i_svuid = proc.pbsi_svuid;
4936 		pid_t i_pid = pids[i];
4937 
4938 		if (i_euid != u && i_uid != u && i_svuid != u) {
4939 			continue;
4940 		}
4941 
4942 		job_log(j, LOG_ERR, "PID %u \"%s\" has no account to back it! Real/effective/saved UIDs: %u/%u/%u", i_pid, proc.pbsi_comm, i_uid, i_euid, i_svuid);
4943 
4944 // Temporarily disabled due to 5423935 and 4946119.
4945 #if 0
4946 		// Ask the accountless process to exit.
4947 		(void)job_assumes_zero_p(j, kill2(i_pid, SIGTERM));
4948 #endif
4949 	}
4950 
4951 out:
4952 	free(pids);
4953 }
4954 
4955 static struct passwd *
job_getpwnam(job_t j,const char * name)4956 job_getpwnam(job_t j, const char *name)
4957 {
4958 	/*
4959 	 * methodology for system daemons
4960 	 *
4961 	 * first lookup user record without any opendirectoryd interaction,
4962 	 * we don't know what interprocess dependencies might be in flight.
4963 	 * if that fails, we re-enable opendirectoryd interaction and
4964 	 * re-issue the lookup.  We have to disable the libinfo L1 cache
4965 	 * otherwise libinfo will return the negative cache entry on the retry
4966 	 */
4967 #if !TARGET_OS_EMBEDDED
4968 	struct passwd *pw = NULL;
4969 
4970 	if (pid1_magic && j->mgr == root_jobmgr) {
4971 		// 1 == SEARCH_MODULE_FLAG_DISABLED
4972 		si_search_module_set_flags("ds", 1);
4973 		gL1CacheEnabled = false;
4974 
4975 		pw = getpwnam(name);
4976 		si_search_module_set_flags("ds", 0);
4977 	}
4978 
4979 	if (pw == NULL) {
4980 		pw = getpwnam(name);
4981 	}
4982 
4983 	return pw;
4984 #else
4985 #pragma unused (j)
4986 	return getpwnam(name);
4987 #endif
4988 }
4989 
4990 static struct group *
job_getgrnam(job_t j,const char * name)4991 job_getgrnam(job_t j, const char *name)
4992 {
4993 #if !TARGET_OS_EMBEDDED
4994     struct group *gr = NULL;
4995 
4996     if (pid1_magic && j->mgr == root_jobmgr) {
4997         si_search_module_set_flags("ds", 1);
4998         gL1CacheEnabled = false;
4999 
5000         gr = getgrnam(name);
5001 
5002         si_search_module_set_flags("ds", 0);
5003     }
5004 
5005     if (gr == NULL) {
5006         gr = getgrnam(name);
5007     }
5008 
5009     return gr;
5010 #else
5011 #pragma unused (j)
5012     return getgrnam(name);
5013 #endif
5014 }
5015 
5016 void
job_postfork_test_user(job_t j)5017 job_postfork_test_user(job_t j)
5018 {
5019 	// This function is all about 5201578
5020 
5021 	const char *home_env_var = getenv("HOME");
5022 	const char *user_env_var = getenv("USER");
5023 	const char *logname_env_var = getenv("LOGNAME");
5024 	uid_t tmp_uid, local_uid = getuid();
5025 	gid_t tmp_gid, local_gid = getgid();
5026 	char shellpath[PATH_MAX];
5027 	char homedir[PATH_MAX];
5028 	char loginname[2000];
5029 	struct passwd *pwe;
5030 
5031 
5032 	if (!job_assumes(j, home_env_var && user_env_var && logname_env_var
5033 				&& strcmp(user_env_var, logname_env_var) == 0)) {
5034 		goto out_bad;
5035 	}
5036 
5037 	if ((pwe = job_getpwnam(j, user_env_var)) == NULL) {
5038 		job_log(j, LOG_ERR, "The account \"%s\" has been deleted out from under us!", user_env_var);
5039 		goto out_bad;
5040 	}
5041 
5042 	/*
5043 	 * We must copy the results of getpw*().
5044 	 *
5045 	 * Why? Because subsequent API calls may call getpw*() as a part of
5046 	 * their implementation. Since getpw*() returns a [now thread scoped]
5047 	 * global, we must therefore cache the results before continuing.
5048 	 */
5049 
5050 	tmp_uid = pwe->pw_uid;
5051 	tmp_gid = pwe->pw_gid;
5052 
5053 	strlcpy(shellpath, pwe->pw_shell, sizeof(shellpath));
5054 	strlcpy(loginname, pwe->pw_name, sizeof(loginname));
5055 	strlcpy(homedir, pwe->pw_dir, sizeof(homedir));
5056 
5057 	if (strcmp(loginname, logname_env_var) != 0) {
5058 		job_log(j, LOG_ERR, "The %s environmental variable changed out from under us!", "USER");
5059 		goto out_bad;
5060 	}
5061 	if (strcmp(homedir, home_env_var) != 0) {
5062 		job_log(j, LOG_ERR, "The %s environmental variable changed out from under us!", "HOME");
5063 		goto out_bad;
5064 	}
5065 	if (local_uid != tmp_uid) {
5066 		job_log(j, LOG_ERR, "The %cID of the account (%u) changed out from under us (%u)!",
5067 				'U', tmp_uid, local_uid);
5068 		goto out_bad;
5069 	}
5070 	if (local_gid != tmp_gid) {
5071 		job_log(j, LOG_ERR, "The %cID of the account (%u) changed out from under us (%u)!",
5072 				'G', tmp_gid, local_gid);
5073 		goto out_bad;
5074 	}
5075 
5076 	return;
5077 out_bad:
5078 #if 0
5079 	(void)job_assumes_zero_p(j, kill2(getppid(), SIGTERM));
5080 	DEBUG_EXIT(EXIT_FAILURE);
5081 #else
5082 	job_log(j, LOG_WARNING, "In a future build of the OS, this error will be fatal.");
5083 #endif
5084 }
5085 
5086 void
job_postfork_become_user(job_t j)5087 job_postfork_become_user(job_t j)
5088 {
5089 	char loginname[2000];
5090 	char tmpdirpath[PATH_MAX];
5091 	char shellpath[PATH_MAX];
5092 	char homedir[PATH_MAX];
5093 	struct passwd *pwe;
5094 	size_t r;
5095 	gid_t desired_gid = -1;
5096 	uid_t desired_uid = -1;
5097 
5098 	if (getuid() != 0) {
5099 		return job_postfork_test_user(j);
5100 	}
5101 
5102 	/*
5103 	 * I contend that having UID == 0 and GID != 0 is of dubious value.
5104 	 * Nevertheless, this used to work in Tiger. See: 5425348
5105 	 */
5106 	if (j->groupname && !j->username) {
5107 		j->username = strdup("root");
5108 	}
5109 
5110 	if (j->username) {
5111 		if ((pwe = job_getpwnam(j, j->username)) == NULL) {
5112 			job_log(j, LOG_ERR, "getpwnam(\"%s\") failed", j->username);
5113 			DEBUG_EXIT(ESRCH);
5114 		}
5115 	} else if (j->mach_uid) {
5116 		if ((pwe = getpwuid(j->mach_uid)) == NULL) {
5117 			job_log(j, LOG_ERR, "getpwuid(\"%u\") failed", j->mach_uid);
5118 			job_log_pids_with_weird_uids(j);
5119 			DEBUG_EXIT(ESRCH);
5120 		}
5121 	} else {
5122 		return;
5123 	}
5124 
5125 	/*
5126 	 * We must copy the results of getpw*().
5127 	 *
5128 	 * Why? Because subsequent API calls may call getpw*() as a part of
5129 	 * their implementation. Since getpw*() returns a [now thread scoped]
5130 	 * global, we must therefore cache the results before continuing.
5131 	 */
5132 
5133 	desired_uid = pwe->pw_uid;
5134 	desired_gid = pwe->pw_gid;
5135 
5136 	strlcpy(shellpath, pwe->pw_shell, sizeof(shellpath));
5137 	strlcpy(loginname, pwe->pw_name, sizeof(loginname));
5138 	strlcpy(homedir, pwe->pw_dir, sizeof(homedir));
5139 
5140 	if (unlikely(pwe->pw_expire && time(NULL) >= pwe->pw_expire)) {
5141 		job_log(j, LOG_ERR, "Expired account");
5142 		DEBUG_EXIT(EXIT_FAILURE);
5143 	}
5144 
5145 
5146 	if (unlikely(j->username && strcmp(j->username, loginname) != 0)) {
5147 		job_log(j, LOG_WARNING, "Suspicious setup: User \"%s\" maps to user: %s", j->username, loginname);
5148 	} else if (unlikely(j->mach_uid && (j->mach_uid != desired_uid))) {
5149 		job_log(j, LOG_WARNING, "Suspicious setup: UID %u maps to UID %u", j->mach_uid, desired_uid);
5150 	}
5151 
5152 	if (j->groupname) {
5153 		struct group *gre;
5154 
5155 		if (unlikely((gre = job_getgrnam(j, j->groupname)) == NULL)) {
5156 			job_log(j, LOG_ERR, "getgrnam(\"%s\") failed", j->groupname);
5157 			DEBUG_EXIT(ESRCH);
5158 		}
5159 
5160 		desired_gid = gre->gr_gid;
5161 	}
5162 
5163 	if (job_assumes_zero_p(j, setlogin(loginname)) == -1) {
5164 		DEBUG_EXIT(EXIT_FAILURE);
5165 	}
5166 
5167 	if (job_assumes_zero_p(j, setgid(desired_gid)) == -1) {
5168 		DEBUG_EXIT(EXIT_FAILURE);
5169 	}
5170 
5171 	/*
5172 	 * The kernel team and the DirectoryServices team want initgroups()
5173 	 * called after setgid(). See 4616864 for more information.
5174 	 */
5175 
5176 	if (likely(!j->no_init_groups)) {
5177 #if 1
5178 		if (job_assumes_zero_p(j, initgroups(loginname, desired_gid)) == -1) {
5179 			DEBUG_EXIT(EXIT_FAILURE);
5180 		}
5181 #else
5182 		/* Do our own little initgroups(). We do this to guarantee that we're
5183 		 * always opted into dynamic group resolution in the kernel. initgroups(3)
5184 		 * does not make this guarantee.
5185 		 */
5186 		int groups[NGROUPS], ngroups;
5187 
5188 		// A failure here isn't fatal, and we'll still get data we can use.
5189 		(void)job_assumes_zero_p(j, getgrouplist(j->username, desired_gid, groups, &ngroups));
5190 
5191 		if (job_assumes_zero_p(j, syscall(SYS_initgroups, ngroups, groups, desired_uid)) == -1) {
5192 			DEBUG_EXIT(EXIT_FAILURE);
5193 		}
5194 #endif
5195 	}
5196 
5197 	if (job_assumes_zero_p(j, setuid(desired_uid)) == -1) {
5198 		DEBUG_EXIT(EXIT_FAILURE);
5199 	}
5200 
5201 	r = confstr(_CS_DARWIN_USER_TEMP_DIR, tmpdirpath, sizeof(tmpdirpath));
5202 
5203 	if (likely(r > 0 && r < sizeof(tmpdirpath))) {
5204 		setenv("TMPDIR", tmpdirpath, 0);
5205 	}
5206 
5207 	setenv("SHELL", shellpath, 0);
5208 	setenv("HOME", homedir, 0);
5209 	setenv("USER", loginname, 0);
5210 	setenv("LOGNAME", loginname, 0);
5211 }
5212 
5213 void
job_setup_attributes(job_t j)5214 job_setup_attributes(job_t j)
5215 {
5216 	struct limititem *li;
5217 	struct envitem *ei;
5218 
5219 	if (unlikely(j->setnice)) {
5220 		(void)job_assumes_zero_p(j, setpriority(PRIO_PROCESS, 0, j->nice));
5221 	}
5222 
5223 	SLIST_FOREACH(li, &j->limits, sle) {
5224 		struct rlimit rl;
5225 
5226 		if (job_assumes_zero_p(j, getrlimit(li->which, &rl) == -1)) {
5227 			continue;
5228 		}
5229 
5230 		if (li->sethard) {
5231 			rl.rlim_max = li->lim.rlim_max;
5232 		}
5233 		if (li->setsoft) {
5234 			rl.rlim_cur = li->lim.rlim_cur;
5235 		}
5236 
5237 		if (setrlimit(li->which, &rl) == -1) {
5238 			job_log_error(j, LOG_WARNING, "setrlimit()");
5239 		}
5240 	}
5241 
5242 	if (unlikely(!j->inetcompat && j->session_create)) {
5243 		launchd_SessionCreate();
5244 	}
5245 
5246 	if (unlikely(j->low_pri_io)) {
5247 		(void)job_assumes_zero_p(j, setiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_PROCESS, IOPOL_THROTTLE));
5248 	}
5249 	if (j->low_priority_background_io) {
5250 		(void)job_assumes_zero_p(j, setiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_DARWIN_BG, IOPOL_THROTTLE));
5251 	}
5252 	if (unlikely(j->rootdir)) {
5253 		(void)job_assumes_zero_p(j, chroot(j->rootdir));
5254 		(void)job_assumes_zero_p(j, chdir("."));
5255 	}
5256 
5257 	job_postfork_become_user(j);
5258 
5259 	if (unlikely(j->workingdir)) {
5260 		if (chdir(j->workingdir) == -1) {
5261 			if (errno == ENOENT || errno == ENOTDIR) {
5262 				job_log(j, LOG_ERR, "Job specified non-existent working directory: %s", j->workingdir);
5263 			} else {
5264 				(void)job_assumes_zero(j, errno);
5265 			}
5266 		}
5267 	}
5268 
5269 	if (unlikely(j->setmask)) {
5270 		umask(j->mask);
5271 	}
5272 
5273 	if (j->stdin_fd) {
5274 		(void)job_assumes_zero_p(j, dup2(j->stdin_fd, STDIN_FILENO));
5275 	} else {
5276 		job_setup_fd(j, STDIN_FILENO, j->stdinpath, O_RDONLY|O_CREAT);
5277 	}
5278 	job_setup_fd(j, STDOUT_FILENO, j->stdoutpath, O_WRONLY|O_CREAT|O_APPEND);
5279 	job_setup_fd(j, STDERR_FILENO, j->stderrpath, O_WRONLY|O_CREAT|O_APPEND);
5280 
5281 	jobmgr_setup_env_from_other_jobs(j->mgr);
5282 
5283 	SLIST_FOREACH(ei, &j->env, sle) {
5284 		setenv(ei->key, ei->value, 1);
5285 	}
5286 
5287 #if !TARGET_OS_EMBEDDED
5288 	if (j->jetsam_properties) {
5289 		(void)job_assumes_zero(j, proc_setpcontrol(PROC_SETPC_TERMINATE));
5290 	}
5291 #endif
5292 
5293 #if TARGET_OS_EMBEDDED
5294 	if (j->main_thread_priority != 0) {
5295 		struct sched_param params;
5296 		bzero(&params, sizeof(params));
5297 		params.sched_priority = j->main_thread_priority;
5298 		(void)job_assumes_zero_p(j, pthread_setschedparam(pthread_self(), SCHED_OTHER, &params));
5299 	}
5300 #endif
5301 
5302 	/*
5303 	 * We'd like to call setsid() unconditionally, but we have reason to
5304 	 * believe that prevents launchd from being able to send signals to
5305 	 * setuid children. We'll settle for process-groups.
5306 	 */
5307 	if (getppid() != 1) {
5308 		(void)job_assumes_zero_p(j, setpgid(0, 0));
5309 	} else {
5310 		(void)job_assumes_zero_p(j, setsid());
5311 	}
5312 }
5313 
5314 void
job_setup_fd(job_t j,int target_fd,const char * path,int flags)5315 job_setup_fd(job_t j, int target_fd, const char *path, int flags)
5316 {
5317 	int fd;
5318 
5319 	if (!path) {
5320 		return;
5321 	}
5322 
5323 	if ((fd = open(path, flags|O_NOCTTY, DEFFILEMODE)) == -1) {
5324 		job_log_error(j, LOG_WARNING, "open(\"%s\", ...)", path);
5325 		return;
5326 	}
5327 
5328 	(void)job_assumes_zero_p(j, dup2(fd, target_fd));
5329 	(void)job_assumes_zero(j, runtime_close(fd));
5330 }
5331 
5332 void
calendarinterval_setalarm(job_t j,struct calendarinterval * ci)5333 calendarinterval_setalarm(job_t j, struct calendarinterval *ci)
5334 {
5335 	struct calendarinterval *ci_iter, *ci_prev = NULL;
5336 	time_t later, head_later;
5337 
5338 	later = cronemu(ci->when.tm_mon, ci->when.tm_mday, ci->when.tm_hour, ci->when.tm_min);
5339 
5340 	if (ci->when.tm_wday != -1) {
5341 		time_t otherlater = cronemu_wday(ci->when.tm_wday, ci->when.tm_hour, ci->when.tm_min);
5342 
5343 		if (ci->when.tm_mday == -1) {
5344 			later = otherlater;
5345 		} else {
5346 			later = later < otherlater ? later : otherlater;
5347 		}
5348 	}
5349 
5350 	ci->when_next = later;
5351 
5352 	LIST_FOREACH(ci_iter, &sorted_calendar_events, global_sle) {
5353 		if (ci->when_next < ci_iter->when_next) {
5354 			LIST_INSERT_BEFORE(ci_iter, ci, global_sle);
5355 			break;
5356 		}
5357 
5358 		ci_prev = ci_iter;
5359 	}
5360 
5361 	if (ci_iter == NULL) {
5362 		// ci must want to fire after every other timer, or there are no timers
5363 
5364 		if (LIST_EMPTY(&sorted_calendar_events)) {
5365 			LIST_INSERT_HEAD(&sorted_calendar_events, ci, global_sle);
5366 		} else {
5367 			LIST_INSERT_AFTER(ci_prev, ci, global_sle);
5368 		}
5369 	}
5370 
5371 	head_later = LIST_FIRST(&sorted_calendar_events)->when_next;
5372 
5373 	if (job_assumes_zero_p(j, kevent_mod((uintptr_t)&sorted_calendar_events, EVFILT_TIMER, EV_ADD, NOTE_ABSOLUTE|NOTE_SECONDS, head_later, root_jobmgr)) != -1) {
5374 		char time_string[100];
5375 		size_t time_string_len;
5376 
5377 		ctime_r(&later, time_string);
5378 		time_string_len = strlen(time_string);
5379 
5380 		if (likely(time_string_len && time_string[time_string_len - 1] == '\n')) {
5381 			time_string[time_string_len - 1] = '\0';
5382 		}
5383 
5384 		job_log(j, LOG_INFO, "Scheduled to run again at %s", time_string);
5385 	}
5386 }
5387 
5388 bool
jobmgr_log_bug(_SIMPLE_STRING asl_message,void * ctx,const char * message)5389 jobmgr_log_bug(_SIMPLE_STRING asl_message __attribute__((unused)), void *ctx, const char *message)
5390 {
5391 	jobmgr_t jm = ctx;
5392 	jobmgr_log(jm, LOG_ERR, "%s", message);
5393 
5394 	return true;
5395 }
5396 
5397 bool
job_log_bug(_SIMPLE_STRING asl_message,void * ctx,const char * message)5398 job_log_bug(_SIMPLE_STRING asl_message __attribute__((unused)), void *ctx, const char *message)
5399 {
5400 	job_t j = ctx;
5401 	job_log(j, LOG_ERR, "%s", message);
5402 
5403 	return true;
5404 }
5405 
5406 // ri: NULL = please sample j->p; non-NULL = use this sample
5407 void
job_log_perf_statistics(job_t j,struct rusage_info_v1 * ri,int64_t exit_status)5408 job_log_perf_statistics(job_t j, struct rusage_info_v1 *ri, int64_t exit_status)
5409 {
5410 #if HAVE_SYSTEMSTATS
5411 	if (j->anonymous || !j->p) {
5412 		return;
5413 	}
5414 	if (!systemstats_is_enabled()) {
5415 		return;
5416 	}
5417 	const char *name;
5418 	if (j->cfbundleidentifier) {
5419 		name = j->cfbundleidentifier;
5420 	} else {
5421 		name = j->label;
5422 	}
5423 	int r = 0;
5424 	struct rusage_info_v1 ris;
5425 	if (ri == NULL) {
5426 		ri = &ris;
5427 		r = proc_pid_rusage(j->p, RUSAGE_INFO_V1, (rusage_info_t)ri);
5428 	}
5429 	if (r == -1) {
5430 		return;
5431 	}
5432 	job_log_systemstats(j->p, j->uniqueid, runtime_get_uniqueid(), j->mgr->req_pid, j->mgr->req_uniqueid, name, ri, exit_status);
5433 #else
5434 #pragma unused (j, ri, exit_status)
5435 #endif
5436 }
5437 
5438 #if HAVE_SYSTEMSTATS
5439 // ri: NULL = don't write fields from ri; non-NULL = use this sample
5440 static
5441 void
job_log_systemstats(pid_t pid,uint64_t uniqueid,uint64_t parent_uniqueid,pid_t req_pid,uint64_t req_uniqueid,const char * name,struct rusage_info_v1 * ri,int64_t exit_status)5442 job_log_systemstats(pid_t pid, uint64_t uniqueid, uint64_t parent_uniqueid, pid_t req_pid, uint64_t req_uniqueid, const char *name, struct rusage_info_v1 *ri, int64_t exit_status)
5443 {
5444 	if (!systemstats_is_enabled()) {
5445 		return;
5446 	}
5447 
5448 	struct systemstats_process_usage_s info;
5449 	bzero(&info, sizeof(info));
5450 	info.name = name;
5451 	info.pid = pid;
5452 	info.exit_status = exit_status;
5453 	info.uid = getuid();
5454 	info.ppid = getpid();
5455 	info.responsible_pid = req_pid;
5456 
5457 	if (likely(ri)) {
5458 		info.macho_uuid = (const uint8_t *)&ri->ri_uuid;
5459 		info.user_time = ri->ri_user_time;
5460 		info.system_time = ri->ri_system_time;
5461 		info.pkg_idle_wkups = ri->ri_pkg_idle_wkups;
5462 		info.interrupt_wkups = ri->ri_interrupt_wkups;
5463 		info.proc_start_abstime = ri->ri_proc_start_abstime;
5464 		info.proc_exit_abstime = ri->ri_proc_exit_abstime;
5465 #if SYSTEMSTATS_API_VERSION >= 20130319
5466 		info.pageins = ri->ri_pageins;
5467 		info.wired_size = ri->ri_wired_size;
5468 		info.resident_size = ri->ri_resident_size;
5469 		info.phys_footprint = ri->ri_phys_footprint;
5470 		// info.purgeablesize = ???
5471 #endif
5472 #if SYSTEMSTATS_API_VERSION >= 20130328
5473 		info.child_user_time = ri->ri_child_user_time;
5474 		info.child_system_time = ri->ri_child_system_time;
5475 		info.child_pkg_idle_wkups = ri->ri_child_pkg_idle_wkups;
5476 		info.child_interrupt_wkups = ri->ri_child_interrupt_wkups;
5477 		info.child_pageins = ri->ri_child_pageins;
5478 		info.child_elapsed_abstime = ri->ri_child_elapsed_abstime;
5479 #endif
5480 	}
5481 #if SYSTEMSTATS_API_VERSION >= 20130410
5482 	info.uniqueid = uniqueid;
5483 	info.parent_uniqueid = parent_uniqueid;
5484 	info.responsible_uniqueid = req_uniqueid;
5485 #endif
5486 	systemstats_write_process_usage(&info);
5487 }
5488 #endif /* HAVE_SYSTEMSTATS */
5489 
5490 struct waiting4attach *
waiting4attach_new(jobmgr_t jm,const char * name,mach_port_t port,pid_t dest,xpc_service_type_t type)5491 waiting4attach_new(jobmgr_t jm, const char *name, mach_port_t port, pid_t dest, xpc_service_type_t type)
5492 {
5493 	size_t xtra = strlen(name) + 1;
5494 
5495 	struct waiting4attach *w4a = malloc(sizeof(*w4a) + xtra);
5496 	if (!w4a) {
5497 		return NULL;
5498 	}
5499 
5500 	w4a->port = port;
5501 	w4a->dest = dest;
5502 	w4a->type = type;
5503 	(void)strcpy(w4a->name, name);
5504 
5505 	if (dest) {
5506 		LIST_INSERT_HEAD(&_launchd_domain_waiters, w4a, le);
5507 	} else {
5508 		LIST_INSERT_HEAD(&jm->attaches, w4a, le);
5509 	}
5510 
5511 
5512 	(void)jobmgr_assumes_zero(jm, launchd_mport_notify_req(port, MACH_NOTIFY_DEAD_NAME));
5513 	return w4a;
5514 }
5515 
5516 void
waiting4attach_delete(jobmgr_t jm,struct waiting4attach * w4a)5517 waiting4attach_delete(jobmgr_t jm, struct waiting4attach *w4a)
5518 {
5519 	jobmgr_log(jm, LOG_DEBUG, "Canceling dead-name notification for waiter port: 0x%x", w4a->port);
5520 
5521 	LIST_REMOVE(w4a, le);
5522 
5523 	mach_port_t previous = MACH_PORT_NULL;
5524 	(void)jobmgr_assumes_zero(jm, mach_port_request_notification(mach_task_self(), w4a->port, MACH_NOTIFY_DEAD_NAME, 0, MACH_PORT_NULL, MACH_MSG_TYPE_MOVE_SEND_ONCE, &previous));
5525 	if (previous) {
5526 		(void)jobmgr_assumes_zero(jm, launchd_mport_deallocate(previous));
5527 	}
5528 
5529 	jobmgr_assumes_zero(jm, launchd_mport_deallocate(w4a->port));
5530 	free(w4a);
5531 }
5532 
5533 struct waiting4attach *
waiting4attach_find(jobmgr_t jm,job_t j)5534 waiting4attach_find(jobmgr_t jm, job_t j)
5535 {
5536 	char *name2use = (char *)j->label;
5537 	if (j->app) {
5538 		struct envitem *ei = NULL;
5539 		SLIST_FOREACH(ei, &j->env, sle) {
5540 			if (strcmp(ei->key, XPC_SERVICE_RENDEZVOUS_TOKEN) == 0) {
5541 				name2use = ei->value;
5542 				break;
5543 			}
5544 		}
5545 	}
5546 
5547 	struct waiting4attach *w4ai = NULL;
5548 	LIST_FOREACH(w4ai, &jm->attaches, le) {
5549 		if (strcmp(name2use, w4ai->name) == 0) {
5550 			job_log(j, LOG_DEBUG, "Found attachment: %s", name2use);
5551 			break;
5552 		}
5553 	}
5554 
5555 	return w4ai;
5556 }
5557 
5558 void
job_logv(job_t j,int pri,int err,const char * msg,va_list ap)5559 job_logv(job_t j, int pri, int err, const char *msg, va_list ap)
5560 {
5561 	const char *label2use = j ? j->label : "com.apple.launchd.job-unknown";
5562 	const char *mgr2use = j ? j->mgr->name : "com.apple.launchd.jobmanager-unknown";
5563 	char *newmsg;
5564 	int oldmask = 0;
5565 	size_t newmsgsz;
5566 
5567 	struct launchd_syslog_attr attr = {
5568 		.from_name = launchd_label,
5569 		.about_name = label2use,
5570 		.session_name = mgr2use,
5571 		.priority = pri,
5572 		.from_uid = getuid(),
5573 		.from_pid = getpid(),
5574 		.about_pid = j ? j->p : 0,
5575 	};
5576 
5577 	/* Hack: If bootstrap_port is set, we must be on the child side of a
5578 	 * fork(2), but before the exec*(3). Let's route the log message back to
5579 	 * launchd proper.
5580 	 */
5581 	if (bootstrap_port && uflag == false) {
5582 		return _vproc_logv(pri, err, msg, ap);
5583 	}
5584 
5585 	newmsgsz = strlen(msg) + 200;
5586 	newmsg = alloca(newmsgsz);
5587 
5588 	if (err) {
5589 #if !TARGET_OS_EMBEDDED
5590 		snprintf(newmsg, newmsgsz, "%s: %d: %s", msg, err, strerror(err));
5591 #else
5592 		snprintf(newmsg, newmsgsz, "(%s) %s: %d: %s", label2use, msg, err, strerror(err));
5593 #endif
5594 	} else {
5595 #if !TARGET_OS_EMBEDDED
5596 		snprintf(newmsg, newmsgsz, "%s", msg);
5597 #else
5598 		snprintf(newmsg, newmsgsz, "(%s) %s", label2use, msg);
5599 #endif
5600 	}
5601 
5602 	if (j && unlikely(j->debug)) {
5603 		oldmask = setlogmask(LOG_UPTO(LOG_DEBUG));
5604 	}
5605 
5606 	launchd_vsyslog(&attr, newmsg, ap);
5607 
5608 	if (j && unlikely(j->debug)) {
5609 		setlogmask(oldmask);
5610 	}
5611 }
5612 
5613 void
job_log_error(job_t j,int pri,const char * msg,...)5614 job_log_error(job_t j, int pri, const char *msg, ...)
5615 {
5616 	va_list ap;
5617 
5618 	va_start(ap, msg);
5619 	job_logv(j, pri, errno, msg, ap);
5620 	va_end(ap);
5621 }
5622 
5623 void
job_log(job_t j,int pri,const char * msg,...)5624 job_log(job_t j, int pri, const char *msg, ...)
5625 {
5626 	va_list ap;
5627 
5628 	va_start(ap, msg);
5629 	job_logv(j, pri, 0, msg, ap);
5630 	va_end(ap);
5631 }
5632 
5633 #if 0
5634 void
5635 jobmgr_log_error(jobmgr_t jm, int pri, const char *msg, ...)
5636 {
5637 	va_list ap;
5638 
5639 	va_start(ap, msg);
5640 	jobmgr_logv(jm, pri, errno, msg, ap);
5641 	va_end(ap);
5642 }
5643 #endif
5644 
5645 void
jobmgr_log_perf_statistics(jobmgr_t jm,bool signal_children)5646 jobmgr_log_perf_statistics(jobmgr_t jm, bool signal_children)
5647 {
5648 #if HAVE_SYSTEMSTATS
5649 	// Log information for kernel_task and pid 1 launchd.
5650 	if (systemstats_is_enabled() && pid1_magic && jm == root_jobmgr) {
5651 #if SYSTEMSTATS_API_VERSION >= 20130328
5652 		if (_systemstats_get_property(SYSTEMSTATS_API_VERSION, SYSTEMSTATS_WRITER_launchd, SYSTEMSTATS_PROPERTY_SHOULD_LOG_ENERGY_STATISTICS)) {
5653 			systemstats_write_intel_energy_statistics(NULL);
5654 		}
5655 #else
5656 		systemstats_write_intel_energy_statistics(NULL);
5657 #endif
5658 		job_log_systemstats(0, 0, 0, 0, 0, "com.apple.kernel", NULL, -1);
5659 		job_log_systemstats(1, 1, 0, 1, 1, "com.apple.launchd", NULL, -1);
5660 	}
5661 #endif
5662 	jobmgr_t jmi = NULL;
5663 	SLIST_FOREACH(jmi, &jm->submgrs, sle) {
5664 		jobmgr_log_perf_statistics(jmi, signal_children);
5665 	}
5666 
5667 	if (jm->xpc_singleton) {
5668 		jobmgr_log(jm, LOG_PERF, "XPC Singleton Domain: %s", jm->shortdesc);
5669 	} else if (jm->properties & BOOTSTRAP_PROPERTY_XPC_DOMAIN) {
5670 		jobmgr_log(jm, LOG_PERF, "XPC Private Domain: %s", jm->owner);
5671 	} else if (jm->properties & BOOTSTRAP_PROPERTY_EXPLICITSUBSET) {
5672 		jobmgr_log(jm, LOG_PERF, "Created via bootstrap_subset()");
5673 	}
5674 
5675 	jobmgr_log(jm, LOG_PERF, "Jobs in job manager:");
5676 
5677 	job_t ji = NULL;
5678 	LIST_FOREACH(ji, &jm->jobs, sle) {
5679 		job_log_perf_statistics(ji, NULL, -1);
5680 		if (unlikely(signal_children) && unlikely(strstr(ji->label, "com.apple.launchd.peruser.") == ji->label)) {
5681 			jobmgr_log(jm, LOG_PERF, "Sending SIGINFO to peruser launchd %d", ji->p);
5682 			kill(ji->p, SIGINFO);
5683 		}
5684 	}
5685 
5686 	jobmgr_log(jm, LOG_PERF, "End of job list.");
5687 }
5688 
5689 void
jobmgr_log(jobmgr_t jm,int pri,const char * msg,...)5690 jobmgr_log(jobmgr_t jm, int pri, const char *msg, ...)
5691 {
5692 	va_list ap;
5693 
5694 	va_start(ap, msg);
5695 	jobmgr_logv(jm, pri, 0, msg, ap);
5696 	va_end(ap);
5697 }
5698 
5699 void
jobmgr_logv(jobmgr_t jm,int pri,int err,const char * msg,va_list ap)5700 jobmgr_logv(jobmgr_t jm, int pri, int err, const char *msg, va_list ap)
5701 {
5702 	if (!jm) {
5703 		jm = root_jobmgr;
5704 	}
5705 
5706 	char *newmsg;
5707 	char *newname;
5708 	size_t i, o, jmname_len = strlen(jm->name), newmsgsz;
5709 
5710 	newname = alloca((jmname_len + 1) * 2);
5711 	newmsgsz = (jmname_len + 1) * 2 + strlen(msg) + 100;
5712 	newmsg = alloca(newmsgsz);
5713 
5714 	for (i = 0, o = 0; i < jmname_len; i++, o++) {
5715 		if (jm->name[i] == '%') {
5716 			newname[o] = '%';
5717 			o++;
5718 		}
5719 		newname[o] = jm->name[i];
5720 	}
5721 	newname[o] = '\0';
5722 
5723 	if (err) {
5724 		snprintf(newmsg, newmsgsz, "%s: %s: %s", newname, msg, strerror(err));
5725 	} else {
5726 		snprintf(newmsg, newmsgsz, "%s: %s", newname, msg);
5727 	}
5728 
5729 	if (jm->parentmgr) {
5730 		jobmgr_logv(jm->parentmgr, pri, 0, newmsg, ap);
5731 	} else {
5732 		struct launchd_syslog_attr attr = {
5733 			.from_name = launchd_label,
5734 			.about_name = launchd_label,
5735 			.session_name = jm->name,
5736 			.priority = pri,
5737 			.from_uid = getuid(),
5738 			.from_pid = getpid(),
5739 			.about_pid = getpid(),
5740 		};
5741 
5742 		launchd_vsyslog(&attr, newmsg, ap);
5743 	}
5744 }
5745 
5746 struct cal_dict_walk {
5747 	job_t j;
5748 	struct tm tmptm;
5749 };
5750 
5751 void
calendarinterval_new_from_obj_dict_walk(launch_data_t obj,const char * key,void * context)5752 calendarinterval_new_from_obj_dict_walk(launch_data_t obj, const char *key, void *context)
5753 {
5754 	struct cal_dict_walk *cdw = context;
5755 	struct tm *tmptm = &cdw->tmptm;
5756 	job_t j = cdw->j;
5757 	int64_t val;
5758 
5759 	if (unlikely(LAUNCH_DATA_INTEGER != launch_data_get_type(obj))) {
5760 		// hack to let caller know something went wrong
5761 		tmptm->tm_sec = -1;
5762 		return;
5763 	}
5764 
5765 	val = launch_data_get_integer(obj);
5766 
5767 	if (val < 0) {
5768 		job_log(j, LOG_WARNING, "The interval for key \"%s\" is less than zero.", key);
5769 	} else if (strcasecmp(key, LAUNCH_JOBKEY_CAL_MINUTE) == 0) {
5770 		if (val > 59) {
5771 			job_log(j, LOG_WARNING, "The interval for key \"%s\" is not between 0 and 59 (inclusive).", key);
5772 			tmptm->tm_sec = -1;
5773 		} else {
5774 			tmptm->tm_min = (typeof(tmptm->tm_min)) val;
5775 		}
5776 	} else if (strcasecmp(key, LAUNCH_JOBKEY_CAL_HOUR) == 0) {
5777 		if (val > 23) {
5778 			job_log(j, LOG_WARNING, "The interval for key \"%s\" is not between 0 and 23 (inclusive).", key);
5779 			tmptm->tm_sec = -1;
5780 		} else {
5781 			tmptm->tm_hour = (typeof(tmptm->tm_hour)) val;
5782 		}
5783 	} else if (strcasecmp(key, LAUNCH_JOBKEY_CAL_DAY) == 0) {
5784 		if (val < 1 || val > 31) {
5785 			job_log(j, LOG_WARNING, "The interval for key \"%s\" is not between 1 and 31 (inclusive).", key);
5786 			tmptm->tm_sec = -1;
5787 		} else {
5788 			tmptm->tm_mday = (typeof(tmptm->tm_mday)) val;
5789 		}
5790 	} else if (strcasecmp(key, LAUNCH_JOBKEY_CAL_WEEKDAY) == 0) {
5791 		if (val > 7) {
5792 			job_log(j, LOG_WARNING, "The interval for key \"%s\" is not between 0 and 7 (inclusive).", key);
5793 			tmptm->tm_sec = -1;
5794 		} else {
5795 			tmptm->tm_wday = (typeof(tmptm->tm_wday)) val;
5796 		}
5797 	} else if (strcasecmp(key, LAUNCH_JOBKEY_CAL_MONTH) == 0) {
5798 		if (val > 12) {
5799 			job_log(j, LOG_WARNING, "The interval for key \"%s\" is not between 0 and 12 (inclusive).", key);
5800 			tmptm->tm_sec = -1;
5801 		} else {
5802 			tmptm->tm_mon = (typeof(tmptm->tm_mon)) val;
5803 			tmptm->tm_mon -= 1; // 4798263 cron compatibility
5804 		}
5805 	}
5806 }
5807 
5808 bool
calendarinterval_new_from_obj(job_t j,launch_data_t obj)5809 calendarinterval_new_from_obj(job_t j, launch_data_t obj)
5810 {
5811 	struct cal_dict_walk cdw;
5812 
5813 	cdw.j = j;
5814 	memset(&cdw.tmptm, 0, sizeof(0));
5815 
5816 	cdw.tmptm.tm_min = -1;
5817 	cdw.tmptm.tm_hour = -1;
5818 	cdw.tmptm.tm_mday = -1;
5819 	cdw.tmptm.tm_wday = -1;
5820 	cdw.tmptm.tm_mon = -1;
5821 
5822 	if (!job_assumes(j, obj != NULL)) {
5823 		return false;
5824 	}
5825 
5826 	if (unlikely(LAUNCH_DATA_DICTIONARY != launch_data_get_type(obj))) {
5827 		return false;
5828 	}
5829 
5830 	launch_data_dict_iterate(obj, calendarinterval_new_from_obj_dict_walk, &cdw);
5831 
5832 	if (unlikely(cdw.tmptm.tm_sec == -1)) {
5833 		return false;
5834 	}
5835 
5836 	return calendarinterval_new(j, &cdw.tmptm);
5837 }
5838 
5839 bool
calendarinterval_new(job_t j,struct tm * w)5840 calendarinterval_new(job_t j, struct tm *w)
5841 {
5842 	struct calendarinterval *ci = calloc(1, sizeof(struct calendarinterval));
5843 
5844 	if (!job_assumes(j, ci != NULL)) {
5845 		return false;
5846 	}
5847 
5848 	ci->when = *w;
5849 	ci->job = j;
5850 
5851 	SLIST_INSERT_HEAD(&j->cal_intervals, ci, sle);
5852 
5853 	calendarinterval_setalarm(j, ci);
5854 
5855 	runtime_add_weak_ref();
5856 
5857 	return true;
5858 }
5859 
5860 void
calendarinterval_delete(job_t j,struct calendarinterval * ci)5861 calendarinterval_delete(job_t j, struct calendarinterval *ci)
5862 {
5863 	SLIST_REMOVE(&j->cal_intervals, ci, calendarinterval, sle);
5864 	LIST_REMOVE(ci, global_sle);
5865 
5866 	free(ci);
5867 
5868 	runtime_del_weak_ref();
5869 }
5870 
5871 void
calendarinterval_sanity_check(void)5872 calendarinterval_sanity_check(void)
5873 {
5874 	struct calendarinterval *ci = LIST_FIRST(&sorted_calendar_events);
5875 	time_t now = time(NULL);
5876 
5877 	if (unlikely(ci && (ci->when_next < now))) {
5878 		(void)jobmgr_assumes_zero_p(root_jobmgr, raise(SIGUSR1));
5879 	}
5880 }
5881 
5882 void
calendarinterval_callback(void)5883 calendarinterval_callback(void)
5884 {
5885 	struct calendarinterval *ci, *ci_next;
5886 	time_t now = time(NULL);
5887 
5888 	LIST_FOREACH_SAFE(ci, &sorted_calendar_events, global_sle, ci_next) {
5889 		job_t j = ci->job;
5890 
5891 		if (ci->when_next > now) {
5892 			break;
5893 		}
5894 
5895 		LIST_REMOVE(ci, global_sle);
5896 		calendarinterval_setalarm(j, ci);
5897 
5898 		j->start_pending = true;
5899 		job_dispatch(j, false);
5900 	}
5901 }
5902 
5903 bool
socketgroup_new(job_t j,const char * name,int * fds,size_t fd_cnt)5904 socketgroup_new(job_t j, const char *name, int *fds, size_t fd_cnt)
5905 {
5906 	struct socketgroup *sg = calloc(1, sizeof(struct socketgroup) + strlen(name) + 1);
5907 
5908 	if (!job_assumes(j, sg != NULL)) {
5909 		return false;
5910 	}
5911 
5912 	sg->fds = calloc(1, fd_cnt * sizeof(int));
5913 	sg->fd_cnt = fd_cnt;
5914 
5915 	if (!job_assumes(j, sg->fds != NULL)) {
5916 		free(sg);
5917 		return false;
5918 	}
5919 
5920 	memcpy(sg->fds, fds, fd_cnt * sizeof(int));
5921 	strcpy(sg->name_init, name);
5922 
5923 	SLIST_INSERT_HEAD(&j->sockets, sg, sle);
5924 
5925 	runtime_add_weak_ref();
5926 
5927 	return true;
5928 }
5929 
5930 void
socketgroup_delete(job_t j,struct socketgroup * sg)5931 socketgroup_delete(job_t j, struct socketgroup *sg)
5932 {
5933 	unsigned int i;
5934 
5935 	for (i = 0; i < sg->fd_cnt; i++) {
5936 #if 0
5937 		struct sockaddr_storage ss;
5938 		struct sockaddr_un *sun = (struct sockaddr_un *)&ss;
5939 		socklen_t ss_len = sizeof(ss);
5940 
5941 		// 5480306
5942 		if (job_assumes_zero(j, getsockname(sg->fds[i], (struct sockaddr *)&ss, &ss_len) != -1)
5943 				&& job_assumes(j, ss_len > 0) && (ss.ss_family == AF_UNIX)) {
5944 			(void)job_assumes(j, unlink(sun->sun_path) != -1);
5945 			// We might conditionally need to delete a directory here
5946 		}
5947 #endif
5948 		(void)job_assumes_zero_p(j, runtime_close(sg->fds[i]));
5949 	}
5950 
5951 	SLIST_REMOVE(&j->sockets, sg, socketgroup, sle);
5952 
5953 	free(sg->fds);
5954 	free(sg);
5955 
5956 	runtime_del_weak_ref();
5957 }
5958 
5959 void
socketgroup_kevent_mod(job_t j,struct socketgroup * sg,bool do_add)5960 socketgroup_kevent_mod(job_t j, struct socketgroup *sg, bool do_add)
5961 {
5962 	struct kevent kev[sg->fd_cnt];
5963 	char buf[10000];
5964 	unsigned int i, buf_off = 0;
5965 
5966 	for (i = 0; i < sg->fd_cnt; i++) {
5967 		EV_SET(&kev[i], sg->fds[i], EVFILT_READ, do_add ? EV_ADD : EV_DELETE, 0, 0, j);
5968 		buf_off += snprintf(buf + buf_off, sizeof(buf) - buf_off, " %d", sg->fds[i]);
5969 	}
5970 
5971 	job_log(j, LOG_DEBUG, "%s Sockets:%s", do_add ? "Watching" : "Ignoring", buf);
5972 
5973 	(void)job_assumes_zero_p(j, kevent_bulk_mod(kev, sg->fd_cnt));
5974 
5975 	for (i = 0; i < sg->fd_cnt; i++) {
5976 		(void)job_assumes(j, kev[i].flags & EV_ERROR);
5977 		errno = (typeof(errno)) kev[i].data;
5978 		(void)job_assumes_zero(j, kev[i].data);
5979 	}
5980 }
5981 
5982 void
socketgroup_ignore(job_t j,struct socketgroup * sg)5983 socketgroup_ignore(job_t j, struct socketgroup *sg)
5984 {
5985 	socketgroup_kevent_mod(j, sg, false);
5986 }
5987 
5988 void
socketgroup_watch(job_t j,struct socketgroup * sg)5989 socketgroup_watch(job_t j, struct socketgroup *sg)
5990 {
5991 	socketgroup_kevent_mod(j, sg, true);
5992 }
5993 
5994 void
socketgroup_callback(job_t j)5995 socketgroup_callback(job_t j)
5996 {
5997 	job_dispatch(j, true);
5998 }
5999 
6000 bool
envitem_new(job_t j,const char * k,const char * v,bool global)6001 envitem_new(job_t j, const char *k, const char *v, bool global)
6002 {
6003 	if (global && !launchd_allow_global_dyld_envvars) {
6004 		if (strncmp("DYLD_", k, sizeof("DYLD_") - 1) == 0) {
6005 			job_log(j, LOG_ERR, "Ignoring global environment variable submitted by job (variable=value): %s=%s", k, v);
6006 			return false;
6007 		}
6008 	}
6009 
6010 	struct envitem *ei = calloc(1, sizeof(struct envitem) + strlen(k) + 1 + strlen(v) + 1);
6011 
6012 	if (!job_assumes(j, ei != NULL)) {
6013 		return false;
6014 	}
6015 
6016 	strcpy(ei->key_init, k);
6017 	ei->value = ei->key_init + strlen(k) + 1;
6018 	strcpy(ei->value, v);
6019 
6020 	if (global) {
6021 		if (SLIST_EMPTY(&j->global_env)) {
6022 			LIST_INSERT_HEAD(&j->mgr->global_env_jobs, j, global_env_sle);
6023 		}
6024 		SLIST_INSERT_HEAD(&j->global_env, ei, sle);
6025 	} else {
6026 		SLIST_INSERT_HEAD(&j->env, ei, sle);
6027 	}
6028 
6029 	job_log(j, LOG_DEBUG, "Added environmental variable: %s=%s", k, v);
6030 
6031 	return true;
6032 }
6033 
6034 void
envitem_delete(job_t j,struct envitem * ei,bool global)6035 envitem_delete(job_t j, struct envitem *ei, bool global)
6036 {
6037 	if (global) {
6038 		SLIST_REMOVE(&j->global_env, ei, envitem, sle);
6039 		if (SLIST_EMPTY(&j->global_env)) {
6040 			LIST_REMOVE(j, global_env_sle);
6041 		}
6042 	} else {
6043 		SLIST_REMOVE(&j->env, ei, envitem, sle);
6044 	}
6045 
6046 	free(ei);
6047 }
6048 
6049 void
envitem_setup(launch_data_t obj,const char * key,void * context)6050 envitem_setup(launch_data_t obj, const char *key, void *context)
6051 {
6052 	job_t j = context;
6053 
6054 	if (launch_data_get_type(obj) != LAUNCH_DATA_STRING) {
6055 		return;
6056 	}
6057 
6058 	if (strncmp(LAUNCHD_TRUSTED_FD_ENV, key, sizeof(LAUNCHD_TRUSTED_FD_ENV) - 1) != 0) {
6059 		envitem_new(j, key, launch_data_get_string(obj), j->importing_global_env);
6060 	} else {
6061 		job_log(j, LOG_DEBUG, "Ignoring reserved environmental variable: %s", key);
6062 	}
6063 }
6064 
6065 bool
limititem_update(job_t j,int w,rlim_t r)6066 limititem_update(job_t j, int w, rlim_t r)
6067 {
6068 	struct limititem *li;
6069 
6070 	SLIST_FOREACH(li, &j->limits, sle) {
6071 		if (li->which == w) {
6072 			break;
6073 		}
6074 	}
6075 
6076 	if (li == NULL) {
6077 		li = calloc(1, sizeof(struct limititem));
6078 
6079 		if (!job_assumes(j, li != NULL)) {
6080 			return false;
6081 		}
6082 
6083 		SLIST_INSERT_HEAD(&j->limits, li, sle);
6084 
6085 		li->which = w;
6086 	}
6087 
6088 	if (j->importing_hard_limits) {
6089 		li->lim.rlim_max = r;
6090 		li->sethard = true;
6091 	} else {
6092 		li->lim.rlim_cur = r;
6093 		li->setsoft = true;
6094 	}
6095 
6096 	return true;
6097 }
6098 
6099 void
limititem_delete(job_t j,struct limititem * li)6100 limititem_delete(job_t j, struct limititem *li)
6101 {
6102 	SLIST_REMOVE(&j->limits, li, limititem, sle);
6103 
6104 	free(li);
6105 }
6106 
6107 #if HAVE_SANDBOX
6108 void
seatbelt_setup_flags(launch_data_t obj,const char * key,void * context)6109 seatbelt_setup_flags(launch_data_t obj, const char *key, void *context)
6110 {
6111 	job_t j = context;
6112 
6113 	if (launch_data_get_type(obj) != LAUNCH_DATA_BOOL) {
6114 		job_log(j, LOG_WARNING, "Sandbox flag value must be boolean: %s", key);
6115 		return;
6116 	}
6117 
6118 	if (launch_data_get_bool(obj) == false) {
6119 		return;
6120 	}
6121 
6122 	if (strcasecmp(key, LAUNCH_JOBKEY_SANDBOX_NAMED) == 0) {
6123 		j->seatbelt_flags |= SANDBOX_NAMED;
6124 	}
6125 }
6126 #endif
6127 
6128 void
limititem_setup(launch_data_t obj,const char * key,void * context)6129 limititem_setup(launch_data_t obj, const char *key, void *context)
6130 {
6131 	job_t j = context;
6132 	size_t i, limits_cnt = (sizeof(launchd_keys2limits) / sizeof(launchd_keys2limits[0]));
6133 	rlim_t rl;
6134 
6135 	if (launch_data_get_type(obj) != LAUNCH_DATA_INTEGER) {
6136 		return;
6137 	}
6138 
6139 	rl = launch_data_get_integer(obj);
6140 
6141 	for (i = 0; i < limits_cnt; i++) {
6142 		if (strcasecmp(launchd_keys2limits[i].key, key) == 0) {
6143 			break;
6144 		}
6145 	}
6146 
6147 	if (i == limits_cnt) {
6148 		return;
6149 	}
6150 
6151 	limititem_update(j, launchd_keys2limits[i].val, rl);
6152 }
6153 
6154 bool
job_useless(job_t j)6155 job_useless(job_t j)
6156 {
6157 	if ((j->legacy_LS_job || j->only_once) && j->start_time != 0) {
6158 		if (j->legacy_LS_job && j->j_port) {
6159 			return false;
6160 		}
6161 		job_log(j, LOG_INFO, "Exited. Was only configured to run once.");
6162 		return true;
6163 	} else if (j->removal_pending) {
6164 		job_log(j, LOG_DEBUG, "Exited while removal was pending.");
6165 		return true;
6166 	} else if (j->shutdown_monitor) {
6167 		return false;
6168 	} else if (j->mgr->shutting_down && !j->mgr->parentmgr) {
6169 		job_log(j, LOG_DEBUG, "Exited while shutdown in progress. Processes remaining: %lu/%lu", total_children, total_anon_children);
6170 		if (total_children == 0 && !j->anonymous) {
6171 			job_log(j, LOG_DEBUG | LOG_CONSOLE, "Job was last to exit during shutdown of: %s.", j->mgr->name);
6172 		}
6173 		return true;
6174 	} else if (j->legacy_mach_job) {
6175 		if (SLIST_EMPTY(&j->machservices)) {
6176 			job_log(j, LOG_INFO, "Garbage collecting");
6177 			return true;
6178 		} else if (!j->checkedin) {
6179 			job_log(j, LOG_WARNING, "Failed to check-in!");
6180 			return true;
6181 		}
6182 	} else {
6183 		/* If the job's executable does not have any valid architectures (for
6184 		 * example, if it's a PowerPC-only job), then we don't even bother
6185 		 * trying to relaunch it, as we have no reasonable expectation that
6186 		 * the situation will change.
6187 		 *
6188 		 * <rdar://problem/9106979>
6189 		 */
6190 		if (!j->did_exec && WEXITSTATUS(j->last_exit_status) == EBADARCH) {
6191 			job_log(j, LOG_ERR, "Job executable does not contain supported architectures. Unloading it. Its plist should be removed.");
6192 			return true;
6193 		}
6194 	}
6195 
6196 	return false;
6197 }
6198 
6199 bool
job_keepalive(job_t j)6200 job_keepalive(job_t j)
6201 {
6202 	mach_msg_type_number_t statusCnt;
6203 	mach_port_status_t status;
6204 	struct semaphoreitem *si;
6205 	struct machservice *ms;
6206 	bool good_exit = (WIFEXITED(j->last_exit_status) && WEXITSTATUS(j->last_exit_status) == 0);
6207 	bool is_not_kextd = (launchd_apple_internal || (strcmp(j->label, "com.apple.kextd") != 0));
6208 
6209 	if (unlikely(j->mgr->shutting_down)) {
6210 		return false;
6211 	}
6212 
6213 	/*
6214 	 * 5066316
6215 	 *
6216 	 * We definitely need to revisit this after Leopard ships. Please see
6217 	 * launchctl.c for the other half of this hack.
6218 	 */
6219 	if (unlikely((j->mgr->global_on_demand_cnt > 0) && is_not_kextd)) {
6220 		return false;
6221 	}
6222 
6223 	if (unlikely(j->needs_kickoff)) {
6224 		job_log(j, LOG_DEBUG, "KeepAlive check: Job needs to be kicked off on-demand before KeepAlive sets in.");
6225 		return false;
6226 	}
6227 
6228 	if (j->start_pending) {
6229 		job_log(j, LOG_DEBUG, "KeepAlive check: Pent-up non-IPC launch criteria.");
6230 		return true;
6231 	}
6232 
6233 	if (!j->ondemand) {
6234 		job_log(j, LOG_DEBUG, "KeepAlive check: job configured to run continuously.");
6235 		return true;
6236 	}
6237 
6238 	SLIST_FOREACH(ms, &j->machservices, sle) {
6239 		statusCnt = MACH_PORT_RECEIVE_STATUS_COUNT;
6240 		if (mach_port_get_attributes(mach_task_self(), ms->port, MACH_PORT_RECEIVE_STATUS,
6241 					(mach_port_info_t)&status, &statusCnt) != KERN_SUCCESS) {
6242 			continue;
6243 		}
6244 		if (status.mps_msgcount) {
6245 			job_log(j, LOG_DEBUG, "KeepAlive check: %d queued Mach messages on service: %s",
6246 					status.mps_msgcount, ms->name);
6247 			return true;
6248 		}
6249 	}
6250 
6251 	/* TODO: Coalesce external events and semaphore items, since they're basically
6252 	 * the same thing.
6253 	 */
6254 	struct externalevent *ei = NULL;
6255 	LIST_FOREACH(ei, &j->events, job_le) {
6256 		if (ei->state == ei->wanted_state) {
6257 			return true;
6258 		}
6259 	}
6260 
6261 	SLIST_FOREACH(si, &j->semaphores, sle) {
6262 		bool wanted_state = false;
6263 		job_t other_j;
6264 
6265 		switch (si->why) {
6266 		case NETWORK_UP:
6267 			wanted_state = true;
6268 		case NETWORK_DOWN:
6269 			if (network_up == wanted_state) {
6270 				job_log(j, LOG_DEBUG, "KeepAlive: The network is %s.", wanted_state ? "up" : "down");
6271 				return true;
6272 			}
6273 			break;
6274 		case SUCCESSFUL_EXIT:
6275 			wanted_state = true;
6276 		case FAILED_EXIT:
6277 			if (good_exit == wanted_state) {
6278 				job_log(j, LOG_DEBUG, "KeepAlive: The exit state was %s.", wanted_state ? "successful" : "failure");
6279 				return true;
6280 			}
6281 			break;
6282 		case CRASHED:
6283 			wanted_state = true;
6284 		case DID_NOT_CRASH:
6285 			if (j->crashed == wanted_state) {
6286 				return true;
6287 			}
6288 			break;
6289 		case OTHER_JOB_ENABLED:
6290 			wanted_state = true;
6291 		case OTHER_JOB_DISABLED:
6292 			if ((bool)job_find(NULL, si->what) == wanted_state) {
6293 				job_log(j, LOG_DEBUG, "KeepAlive: The following job is %s: %s", wanted_state ? "enabled" : "disabled", si->what);
6294 				return true;
6295 			}
6296 			break;
6297 		case OTHER_JOB_ACTIVE:
6298 			wanted_state = true;
6299 		case OTHER_JOB_INACTIVE:
6300 			if ((other_j = job_find(NULL, si->what))) {
6301 				if ((bool)other_j->p == wanted_state) {
6302 					job_log(j, LOG_DEBUG, "KeepAlive: The following job is %s: %s", wanted_state ? "active" : "inactive", si->what);
6303 					return true;
6304 				}
6305 			}
6306 			break;
6307 		}
6308 	}
6309 
6310 	return false;
6311 }
6312 
6313 const char *
job_active(job_t j)6314 job_active(job_t j)
6315 {
6316 	if (j->p && j->shutdown_monitor) {
6317 		return "Monitoring shutdown";
6318 	}
6319 	if (j->p) {
6320 		return "PID is still valid";
6321 	}
6322 
6323 	if (j->priv_port_has_senders) {
6324 		return "Privileged Port still has outstanding senders";
6325 	}
6326 
6327 	struct machservice *ms;
6328 	SLIST_FOREACH(ms, &j->machservices, sle) {
6329 		/* If we've simulated an exit, we mark the job as non-active, even
6330 		 * though doing so will leave it in an unsafe state. We do this so that
6331 		 * shutdown can proceed. See <rdar://problem/11126530>.
6332 		 */
6333 		if (!j->workaround9359725 && ms->recv && machservice_active(ms)) {
6334 			job_log(j, LOG_INFO, "Mach service is still active despite being killed: %s", ms->name);
6335 			/*
6336 			 * It is not at all clear to me why this returns a string.  The process
6337 			 * has been killed, and the loop at this point doesn't do anything other
6338 			 * than wait.  Which is probably not going to do anything useful.
6339 			 */
6340 			return NULL;
6341 			// return "Mach service is still active despite being killed";
6342 		}
6343 	}
6344 
6345 	return NULL;
6346 }
6347 
6348 void
machservice_watch(job_t j,struct machservice * ms)6349 machservice_watch(job_t j, struct machservice *ms)
6350 {
6351 	if (ms->recv) {
6352 		if (job_assumes_zero(j, runtime_add_mport(ms->port, NULL)) == KERN_INVALID_RIGHT) {
6353 			ms->recv_race_hack = true;
6354 		}
6355 	}
6356 }
6357 
6358 void
machservice_ignore(job_t j,struct machservice * ms)6359 machservice_ignore(job_t j, struct machservice *ms)
6360 {
6361 	/* We only add ports whose receive rights we control into the port set, so
6362 	 * don't attempt to remove te service from the port set if we didn't put it
6363 	 * there in the first place. Otherwise, we could wind up trying to access a
6364 	 * bogus index (like MACH_PORT_DEAD) or zeroing a valid one out.
6365 	 *
6366 	 * <rdar://problem/10898014>
6367 	 */
6368 	if (ms->recv) {
6369 		(void)job_assumes_zero(j, runtime_remove_mport(ms->port));
6370 	}
6371 }
6372 
6373 void
machservice_resetport(job_t j,struct machservice * ms)6374 machservice_resetport(job_t j, struct machservice *ms)
6375 {
6376 	LIST_REMOVE(ms, port_hash_sle);
6377 	(void)job_assumes_zero(j, launchd_mport_close_recv(ms->port));
6378 	(void)job_assumes_zero(j, launchd_mport_deallocate(ms->port));
6379 
6380 	ms->gen_num++;
6381 	(void)job_assumes_zero(j, launchd_mport_create_recv(&ms->port));
6382 	(void)job_assumes_zero(j, launchd_mport_make_send(ms->port));
6383 	LIST_INSERT_HEAD(&port_hash[HASH_PORT(ms->port)], ms, port_hash_sle);
6384 }
6385 
6386 void
machservice_stamp_port(job_t j,struct machservice * ms)6387 machservice_stamp_port(job_t j, struct machservice *ms)
6388 {
6389 	mach_port_context_t ctx = 0;
6390 	char *where2get = j->prog ? j->prog : j->argv[0];
6391 
6392 	char *prog = NULL;
6393 	if ((prog = strrchr(where2get, '/'))) {
6394 		prog++;
6395 	} else {
6396 		prog = where2get;
6397 	}
6398 
6399 	(void)strncpy((char *)&ctx, prog, sizeof(ctx));
6400 #if __LITTLE_ENDIAN__
6401 #if __LP64__
6402 	ctx = be64toh(ctx);
6403 #else
6404 	ctx = be32toh(ctx);
6405 #endif
6406 #endif
6407 
6408 	(void)job_assumes_zero(j, mach_port_set_context(mach_task_self(), ms->port, ctx));
6409 }
6410 
6411 struct machservice *
machservice_new(job_t j,const char * name,mach_port_t * serviceport,bool pid_local)6412 machservice_new(job_t j, const char *name, mach_port_t *serviceport, bool pid_local)
6413 {
6414 	/* Don't create new MachServices for dead ports. This is primarily for
6415 	 * clients who use bootstrap_register2(). They can pass in a send right, but
6416 	 * then that port can immediately go dead. Hilarity ensues.
6417 	 *
6418 	 * <rdar://problem/10898014>
6419 	 */
6420 	if (*serviceport == MACH_PORT_DEAD) {
6421 		return NULL;
6422 	}
6423 
6424 	struct machservice *ms = calloc(1, sizeof(struct machservice) + strlen(name) + 1);
6425 	if (!job_assumes(j, ms != NULL)) {
6426 		return NULL;
6427 	}
6428 
6429 	strcpy((char *)ms->name, name);
6430 	ms->job = j;
6431 	ms->gen_num = 1;
6432 	ms->per_pid = pid_local;
6433 
6434 	if (likely(*serviceport == MACH_PORT_NULL)) {
6435 		if (job_assumes_zero(j, launchd_mport_create_recv(&ms->port)) != KERN_SUCCESS) {
6436 			goto out_bad;
6437 		}
6438 
6439 		if (job_assumes_zero(j, launchd_mport_make_send(ms->port)) != KERN_SUCCESS) {
6440 			goto out_bad2;
6441 		}
6442 		*serviceport = ms->port;
6443 		ms->recv = true;
6444 	} else {
6445 		ms->port = *serviceport;
6446 		ms->isActive = true;
6447 	}
6448 
6449 	SLIST_INSERT_HEAD(&j->machservices, ms, sle);
6450 
6451 	jobmgr_t where2put = j->mgr;
6452 	// XPC domains are separate from Mach bootstraps.
6453 	if (!(j->mgr->properties & BOOTSTRAP_PROPERTY_XPC_DOMAIN)) {
6454 		if (launchd_flat_mach_namespace && !(j->mgr->properties & BOOTSTRAP_PROPERTY_EXPLICITSUBSET)) {
6455 			where2put = root_jobmgr;
6456 		}
6457 	}
6458 
6459 	/* Don't allow MachServices added by multiple-instance jobs to be looked up
6460 	 * by others. We could just do this with a simple bit, but then we'd have to
6461 	 * uniquify the names ourselves to avoid collisions. This is just easier.
6462 	 */
6463 	if (!j->dedicated_instance) {
6464 		LIST_INSERT_HEAD(&where2put->ms_hash[hash_ms(ms->name)], ms, name_hash_sle);
6465 	}
6466 	LIST_INSERT_HEAD(&port_hash[HASH_PORT(ms->port)], ms, port_hash_sle);
6467 
6468 	if (ms->recv) {
6469 		machservice_stamp_port(j, ms);
6470 	}
6471 
6472 	job_log(j, LOG_DEBUG, "Mach service added%s: %s", (j->mgr->properties & BOOTSTRAP_PROPERTY_EXPLICITSUBSET) ? " to private namespace" : "", name);
6473 
6474 	return ms;
6475 out_bad2:
6476 	(void)job_assumes_zero(j, launchd_mport_close_recv(ms->port));
6477 out_bad:
6478 	free(ms);
6479 	return NULL;
6480 }
6481 
6482 struct machservice *
machservice_new_alias(job_t j,struct machservice * orig)6483 machservice_new_alias(job_t j, struct machservice *orig)
6484 {
6485 	struct machservice *ms = calloc(1, sizeof(struct machservice) + strlen(orig->name) + 1);
6486 	if (job_assumes(j, ms != NULL)) {
6487 		strcpy((char *)ms->name, orig->name);
6488 		ms->alias = orig;
6489 		ms->job = j;
6490 
6491 		LIST_INSERT_HEAD(&j->mgr->ms_hash[hash_ms(ms->name)], ms, name_hash_sle);
6492 		SLIST_INSERT_HEAD(&j->machservices, ms, sle);
6493 		jobmgr_log(j->mgr, LOG_DEBUG, "Service aliased into job manager: %s", orig->name);
6494 	}
6495 
6496 	return ms;
6497 }
6498 
6499 bootstrap_status_t
machservice_status(struct machservice * ms)6500 machservice_status(struct machservice *ms)
6501 {
6502 	ms = ms->alias ? ms->alias : ms;
6503 	if (ms->isActive) {
6504 		return BOOTSTRAP_STATUS_ACTIVE;
6505 	} else if (ms->job->ondemand) {
6506 		return BOOTSTRAP_STATUS_ON_DEMAND;
6507 	} else {
6508 		return BOOTSTRAP_STATUS_INACTIVE;
6509 	}
6510 }
6511 
6512 #include <sys/mach/thread_status.h>
6513 void
job_setup_exception_port(job_t j,task_t target_task)6514 job_setup_exception_port(job_t j, task_t target_task)
6515 {
6516 	struct machservice *ms;
6517 	thread_state_flavor_t f = 0;
6518 	mach_port_t exc_port = the_exception_server;
6519 
6520 	if (unlikely(j->alt_exc_handler)) {
6521 		ms = jobmgr_lookup_service(j->mgr, j->alt_exc_handler, true, 0);
6522 		if (likely(ms)) {
6523 			exc_port = machservice_port(ms);
6524 		} else {
6525 			job_log(j, LOG_WARNING, "Falling back to default Mach exception handler. Could not find: %s", j->alt_exc_handler);
6526 		}
6527 	} else if (unlikely(j->internal_exc_handler)) {
6528 		exc_port = runtime_get_kernel_port();
6529 	} else if (unlikely(!exc_port)) {
6530 		return;
6531 	}
6532 
6533 #if defined (__ppc__) || defined(__ppc64__)
6534 	f = PPC_THREAD_STATE64;
6535 #elif defined(__i386__) || defined(__x86_64__)
6536 	f = x86_THREAD_STATE;
6537 #elif defined(__arm__)
6538 	f = ARM_THREAD_STATE;
6539 #else
6540 #error "unknown architecture"
6541 #endif
6542 
6543 	if (likely(target_task)) {
6544 		kern_return_t kr = task_set_exception_ports(target_task, EXC_MASK_CRASH | EXC_MASK_GUARD | EXC_MASK_RESOURCE, exc_port, EXCEPTION_STATE_IDENTITY | MACH_EXCEPTION_CODES, f);
6545 		if (kr) {
6546 			if (kr != MACH_SEND_INVALID_DEST) {
6547 				(void)job_assumes_zero(j, kr);
6548 			} else {
6549 				job_log(j, LOG_WARNING, "Task died before exception port could be set.");
6550 			}
6551 		}
6552 	} else if (pid1_magic && the_exception_server) {
6553 		mach_port_t mhp = mach_host_self();
6554 		(void)job_assumes_zero(j, host_set_exception_ports(mhp, EXC_MASK_CRASH | EXC_MASK_GUARD | EXC_MASK_RESOURCE, the_exception_server, EXCEPTION_STATE_IDENTITY | MACH_EXCEPTION_CODES, f));
6555 		(void)job_assumes_zero(j, launchd_mport_deallocate(mhp));
6556 	}
6557 }
6558 
6559 void
job_set_exception_port(job_t j,mach_port_t port)6560 job_set_exception_port(job_t j, mach_port_t port)
6561 {
6562 	if (unlikely(!the_exception_server)) {
6563 		the_exception_server = port;
6564 		job_setup_exception_port(j, 0);
6565 	} else {
6566 		job_log(j, LOG_WARNING, "The exception server is already claimed!");
6567 	}
6568 }
6569 
6570 void
machservice_setup_options(launch_data_t obj,const char * key,void * context)6571 machservice_setup_options(launch_data_t obj, const char *key, void *context)
6572 {
6573 	struct machservice *ms = context;
6574 	mach_port_t mhp = mach_host_self();
6575 	int which_port;
6576 	bool b;
6577 
6578 	if (!job_assumes(ms->job, mhp != MACH_PORT_NULL)) {
6579 		return;
6580 	}
6581 
6582 	switch (launch_data_get_type(obj)) {
6583 	case LAUNCH_DATA_INTEGER:
6584 		which_port = (int)launch_data_get_integer(obj); // XXX we should bound check this...
6585 		if (strcasecmp(key, LAUNCH_JOBKEY_MACH_TASKSPECIALPORT) == 0) {
6586 			switch (which_port) {
6587 			case TASK_KERNEL_PORT:
6588 			case TASK_HOST_PORT:
6589 			case TASK_NAME_PORT:
6590 			case TASK_BOOTSTRAP_PORT:
6591 			/* I find it a little odd that zero isn't reserved in the header.
6592 			 * Normally Mach is fairly good about this convention...
6593 			 */
6594 			case 0:
6595 				job_log(ms->job, LOG_WARNING, "Tried to set a reserved task special port: %d", which_port);
6596 				break;
6597 			default:
6598 				ms->special_port_num = which_port;
6599 				SLIST_INSERT_HEAD(&special_ports, ms, special_port_sle);
6600 				break;
6601 			}
6602 		} else if (strcasecmp(key, LAUNCH_JOBKEY_MACH_HOSTSPECIALPORT) == 0 && pid1_magic) {
6603 			if (which_port > HOST_MAX_SPECIAL_KERNEL_PORT) {
6604 				(void)job_assumes_zero(ms->job, (errno = host_set_special_port(mhp, which_port, ms->port)));
6605 			} else {
6606 				job_log(ms->job, LOG_WARNING, "Tried to set a reserved host special port: %d", which_port);
6607 			}
6608 		}
6609 	case LAUNCH_DATA_BOOL:
6610 		b = launch_data_get_bool(obj);
6611 		if (strcasecmp(key, LAUNCH_JOBKEY_MACH_ENTERKERNELDEBUGGERONCLOSE) == 0) {
6612 			ms->debug_on_close = b;
6613 		} else if (strcasecmp(key, LAUNCH_JOBKEY_MACH_RESETATCLOSE) == 0) {
6614 			ms->reset = b;
6615 		} else if (strcasecmp(key, LAUNCH_JOBKEY_MACH_HIDEUNTILCHECKIN) == 0) {
6616 			ms->hide = b;
6617 		} else if (strcasecmp(key, LAUNCH_JOBKEY_MACH_EXCEPTIONSERVER) == 0) {
6618 			job_set_exception_port(ms->job, ms->port);
6619 		} else if (strcasecmp(key, LAUNCH_JOBKEY_MACH_KUNCSERVER) == 0) {
6620 			ms->kUNCServer = b;
6621 			(void)job_assumes_zero(ms->job, host_set_UNDServer(mhp, ms->port));
6622 		}
6623 		break;
6624 	case LAUNCH_DATA_STRING:
6625 		if (strcasecmp(key, LAUNCH_JOBKEY_MACH_DRAINMESSAGESONCRASH) == 0) {
6626 			const char *option = launch_data_get_string(obj);
6627 			if (strcasecmp(option, "One") == 0) {
6628 				ms->drain_one_on_crash = true;
6629 			} else if (strcasecmp(option, "All") == 0) {
6630 				ms->drain_all_on_crash = true;
6631 			}
6632 		}
6633 		break;
6634 	case LAUNCH_DATA_DICTIONARY:
6635 		if (launch_data_dict_get_count(obj) == 0) {
6636 			job_set_exception_port(ms->job, ms->port);
6637 		}
6638 		break;
6639 	default:
6640 		break;
6641 	}
6642 
6643 	(void)job_assumes_zero(ms->job, launchd_mport_deallocate(mhp));
6644 }
6645 
6646 void
machservice_setup(launch_data_t obj,const char * key,void * context)6647 machservice_setup(launch_data_t obj, const char *key, void *context)
6648 {
6649 	job_t j = context;
6650 	struct machservice *ms;
6651 	mach_port_t p = MACH_PORT_NULL;
6652 
6653 	if (unlikely(ms = jobmgr_lookup_service(j->mgr, key, false, 0))) {
6654 		job_log(j, LOG_WARNING, "Conflict with job: %s over Mach service: %s", ms->job->label, key);
6655 		return;
6656 	}
6657 
6658 	if (!job_assumes(j, (ms = machservice_new(j, key, &p, false)) != NULL)) {
6659 		return;
6660 	}
6661 
6662 	ms->isActive = false;
6663 	ms->upfront = true;
6664 
6665 	if (launch_data_get_type(obj) == LAUNCH_DATA_DICTIONARY) {
6666 		launch_data_dict_iterate(obj, machservice_setup_options, ms);
6667 	}
6668 
6669 	kern_return_t kr = mach_port_set_attributes(mach_task_self(), ms->port, MACH_PORT_TEMPOWNER, NULL, 0);
6670 	(void)job_assumes_zero(j, kr);
6671 }
6672 
6673 jobmgr_t
jobmgr_do_garbage_collection(jobmgr_t jm)6674 jobmgr_do_garbage_collection(jobmgr_t jm)
6675 {
6676 	jobmgr_t jmi = NULL, jmn = NULL;
6677 	SLIST_FOREACH_SAFE(jmi, &jm->submgrs, sle, jmn) {
6678 		jobmgr_do_garbage_collection(jmi);
6679 	}
6680 
6681 	if (!jm->shutting_down) {
6682 		return jm;
6683 	}
6684 
6685 	if (SLIST_EMPTY(&jm->submgrs)) {
6686 		jobmgr_log(jm, LOG_DEBUG, "No submanagers left.");
6687 	} else {
6688 		jobmgr_log(jm, LOG_DEBUG, "Still have submanagers.");
6689 		SLIST_FOREACH(jmi, &jm->submgrs, sle) {
6690 			jobmgr_log(jm, LOG_DEBUG, "Submanager: %s", jmi->name);
6691 		}
6692 	}
6693 
6694 	size_t actives = 0;
6695 	job_t ji = NULL, jn = NULL;
6696 	LIST_FOREACH_SAFE(ji, &jm->jobs, sle, jn) {
6697 		if (ji->anonymous) {
6698 			continue;
6699 		}
6700 
6701 		// Let the shutdown monitor be up until the very end.
6702 		if (ji->shutdown_monitor) {
6703 			continue;
6704 		}
6705 
6706 		/* On our first pass through, open a transaction for all the jobs that
6707 		 * need to be dirty at shutdown. We'll close these transactions once the
6708 		 * jobs that do not need to be dirty at shutdown have all exited.
6709 		 */
6710 		if (ji->dirty_at_shutdown && !jm->shutdown_jobs_dirtied) {
6711 			job_open_shutdown_transaction(ji);
6712 		}
6713 
6714 		const char *active = job_active(ji);
6715 		if (!active) {
6716 			job_remove(ji);
6717 		} else {
6718 			job_log(ji, LOG_DEBUG, "Job is active: %s", active);
6719 			job_stop(ji);
6720 
6721 			if (!ji->dirty_at_shutdown) {
6722 				actives++;
6723 			}
6724 
6725 			if (ji->clean_kill) {
6726 				job_log(ji, LOG_DEBUG, "Job was killed cleanly.");
6727 			} else {
6728 				job_log(ji, LOG_DEBUG, "Job was sent SIGTERM%s.", ji->sent_sigkill ? " and SIGKILL" : "");
6729 			}
6730 		}
6731 	}
6732 
6733 	jm->shutdown_jobs_dirtied = true;
6734 	if (actives == 0) {
6735 		if (!jm->shutdown_jobs_cleaned) {
6736 			/* Once all normal jobs have exited, we clean the dirty-at-shutdown
6737 			 * jobs and make them into normal jobs so that the above loop will
6738 			 * handle them appropriately.
6739 			 */
6740 			LIST_FOREACH(ji, &jm->jobs, sle) {
6741 				if (ji->anonymous) {
6742 					continue;
6743 				}
6744 
6745 				if (!job_active(ji)) {
6746 					continue;
6747 				}
6748 
6749 				if (ji->shutdown_monitor) {
6750 					continue;
6751 				}
6752 
6753 				job_close_shutdown_transaction(ji);
6754 				actives++;
6755 			}
6756 
6757 			jm->shutdown_jobs_cleaned = true;
6758 		}
6759 
6760 		if (SLIST_EMPTY(&jm->submgrs) && actives == 0) {
6761 			/* We may be in a situation where the shutdown monitor is all that's
6762 			 * left, in which case we want to stop it. Like dirty-at-shutdown
6763 			 * jobs, we turn it back into a normal job so that the main loop
6764 			 * treats it appropriately.
6765 			 *
6766 			 * See:
6767 			 * <rdar://problem/10756306>
6768 			 * <rdar://problem/11034971>
6769 			 * <rdar://problem/11549541>
6770 			 */
6771 			if (jm->monitor_shutdown && _launchd_shutdown_monitor) {
6772 				/* The rest of shutdown has completed, so we can kill the shutdown
6773 				 * monitor now like it was any other job.
6774 				 */
6775 				_launchd_shutdown_monitor->shutdown_monitor = false;
6776 
6777 				job_log(_launchd_shutdown_monitor, LOG_NOTICE | LOG_CONSOLE, "Stopping shutdown monitor.");
6778 				job_stop(_launchd_shutdown_monitor);
6779 				_launchd_shutdown_monitor = NULL;
6780 			} else {
6781 				jobmgr_log(jm, LOG_DEBUG, "Removing.");
6782 				jobmgr_remove(jm);
6783 				return NULL;
6784 			}
6785 		}
6786 	}
6787 
6788 	return jm;
6789 }
6790 
6791 void
jobmgr_kill_stray_children(jobmgr_t jm,pid_t * p,size_t np)6792 jobmgr_kill_stray_children(jobmgr_t jm, pid_t *p, size_t np)
6793 {
6794 	/* I maintain that stray processes should be at the mercy of launchd during
6795 	 * shutdown, but nevertheless, things like diskimages-helper can stick
6796 	 * around, and SIGKILLing them can result in data loss. So we send SIGTERM
6797 	 * to all the strays and don't wait for them to exit before moving on.
6798 	 *
6799 	 * See rdar://problem/6562592
6800 	 */
6801 	size_t i = 0;
6802 	for (i = 0; i < np; i++) {
6803 		if (p[i] != 0) {
6804 			jobmgr_log(jm, LOG_DEBUG | LOG_CONSOLE, "Sending SIGTERM to PID %u and continuing...", p[i]);
6805 			(void)jobmgr_assumes_zero_p(jm, kill2(p[i], SIGTERM));
6806 		}
6807 	}
6808 }
6809 
6810 void
jobmgr_log_stray_children(jobmgr_t jm,bool kill_strays)6811 jobmgr_log_stray_children(jobmgr_t jm, bool kill_strays)
6812 {
6813 	size_t kp_skipped = 0, len = sizeof(pid_t) * get_kern_max_proc();
6814 	pid_t *pids = NULL;
6815 	int i = 0, kp_cnt = 0;
6816 
6817 	if (likely(jm->parentmgr || !pid1_magic)) {
6818 		return;
6819 	}
6820 
6821 	if (!jobmgr_assumes(jm, (pids = malloc(len)) != NULL)) {
6822 		return;
6823 	}
6824 
6825 	runtime_ktrace0(RTKT_LAUNCHD_FINDING_ALL_STRAYS);
6826 
6827 	if (jobmgr_assumes_zero_p(jm, (kp_cnt = proc_listallpids(pids, len))) == -1) {
6828 		goto out;
6829 	}
6830 
6831 	pid_t *ps = (pid_t *)calloc(sizeof(pid_t), kp_cnt);
6832 	for (i = 0; i < kp_cnt; i++) {
6833 		struct proc_bsdshortinfo proc;
6834 		if (proc_pidinfo(pids[i], PROC_PIDT_SHORTBSDINFO, 1, &proc, PROC_PIDT_SHORTBSDINFO_SIZE) == 0) {
6835 			if (errno != ESRCH) {
6836 				(void)jobmgr_assumes_zero(jm, errno);
6837 			}
6838 
6839 			kp_skipped++;
6840 			continue;
6841 		}
6842 
6843 		pid_t p_i = pids[i];
6844 		pid_t pp_i = proc.pbsi_ppid;
6845 		pid_t pg_i = proc.pbsi_pgid;
6846 		const char *z = (proc.pbsi_status == SZOMB) ? "zombie " : "";
6847 		const char *n = proc.pbsi_comm;
6848 
6849 		if (unlikely(p_i == 0 || p_i == 1)) {
6850 			kp_skipped++;
6851 			continue;
6852 		}
6853 
6854 		if (_launchd_shutdown_monitor && pp_i == _launchd_shutdown_monitor->p) {
6855 			kp_skipped++;
6856 			continue;
6857 		}
6858 
6859 		// We might have some jobs hanging around that we've decided to shut down in spite of.
6860 		job_t j = jobmgr_find_by_pid(jm, p_i, false);
6861 		if (!j || (j && j->anonymous)) {
6862 			jobmgr_log(jm, LOG_INFO | LOG_CONSOLE, "Stray %s%s at shutdown: PID %u PPID %u PGID %u %s", z, j ? "anonymous job" : "process", p_i, pp_i, pg_i, n);
6863 
6864 			int status = 0;
6865 			if (pp_i == getpid() && !jobmgr_assumes(jm, proc.pbsi_status != SZOMB)) {
6866 				if (jobmgr_assumes_zero(jm, waitpid(p_i, &status, WNOHANG)) == 0) {
6867 					jobmgr_log(jm, LOG_INFO | LOG_CONSOLE, "Unreaped zombie stray exited with status %i.", WEXITSTATUS(status));
6868 				}
6869 				kp_skipped++;
6870 			} else {
6871 				job_t leader = jobmgr_find_by_pid(jm, pg_i, false);
6872 				/* See rdar://problem/6745714. Some jobs have child processes that back kernel state,
6873 				 * so we don't want to terminate them. Long-term, I'd really like to provide shutdown
6874 				 * hints to the kernel along the way, so that it could shutdown certain subsystems when
6875 				 * their userspace emissaries go away, before the call to reboot(2).
6876 				 */
6877 				if (leader && leader->ignore_pg_at_shutdown) {
6878 					kp_skipped++;
6879 				} else {
6880 					ps[i] = p_i;
6881 				}
6882 			}
6883 		} else {
6884 			kp_skipped++;
6885 		}
6886 	}
6887 
6888 	if ((kp_cnt - kp_skipped > 0) && kill_strays) {
6889 		jobmgr_kill_stray_children(jm, ps, kp_cnt - kp_skipped);
6890 	}
6891 
6892 	free(ps);
6893 out:
6894 	free(pids);
6895 }
6896 
6897 jobmgr_t
jobmgr_parent(jobmgr_t jm)6898 jobmgr_parent(jobmgr_t jm)
6899 {
6900 	return jm->parentmgr;
6901 }
6902 
6903 void
job_uncork_fork(job_t j)6904 job_uncork_fork(job_t j)
6905 {
6906 	pid_t c = j->p;
6907 
6908 	job_log(j, LOG_DEBUG, "Uncorking the fork().");
6909 	/* this unblocks the child and avoids a race
6910 	 * between the above fork() and the kevent_mod() */
6911 	(void)job_assumes(j, write(j->fork_fd, &c, sizeof(c)) == sizeof(c));
6912 	(void)job_assumes_zero_p(j, runtime_close(j->fork_fd));
6913 	j->fork_fd = 0;
6914 }
6915 
6916 jobmgr_t
jobmgr_new(jobmgr_t jm,mach_port_t requestorport,mach_port_t transfer_port,bool sflag,const char * name,bool skip_init,mach_port_t asport)6917 jobmgr_new(jobmgr_t jm, mach_port_t requestorport, mach_port_t transfer_port, bool sflag, const char *name, bool skip_init, mach_port_t asport)
6918 {
6919 	job_t bootstrapper = NULL;
6920 	jobmgr_t jmr;
6921 
6922 	__OS_COMPILETIME_ASSERT__(offsetof(struct jobmgr_s, kqjobmgr_callback) == 0);
6923 
6924 	if (unlikely(jm && requestorport == MACH_PORT_NULL)) {
6925 		syslog(LOG_ERR, "no requester port!!!!");
6926 		jobmgr_log(jm, LOG_ERR, "Mach sub-bootstrap create request requires a requester port");
6927 		return NULL;
6928 	}
6929 
6930 	jmr = calloc(1, sizeof(struct jobmgr_s) + (name ? (strlen(name) + 1) : NAME_MAX + 1));
6931 
6932 	if (!jobmgr_assumes(jm, jmr != NULL)) {
6933 		return NULL;
6934 	}
6935 
6936 	if (jm == NULL) {
6937 		root_jobmgr = jmr;
6938 	}
6939 
6940 	jmr->kqjobmgr_callback = jobmgr_callback;
6941 	strcpy(jmr->name_init, name ? name : "Under construction");
6942 
6943 	jmr->req_port = requestorport;
6944 
6945 	if ((jmr->parentmgr = jm)) {
6946 		SLIST_INSERT_HEAD(&jm->submgrs, jmr, sle);
6947 	}
6948 	syslog(LOG_ERR, "if jm=%p then launchd_mport_notify_req transfer_port=%d", jm, transfer_port);
6949 	if (jm && jobmgr_assumes_zero(jmr, launchd_mport_notify_req(jmr->req_port, MACH_NOTIFY_DEAD_NAME)) != KERN_SUCCESS) {
6950 		syslog(LOG_ERR, "launchd_mport_notify_req failed!!!");
6951 		sleep(1);
6952 		goto out_bad;
6953 	}
6954 
6955 	if (transfer_port != MACH_PORT_NULL) {
6956 		syslog(LOG_ERR, "transfer_port=%d\n", transfer_port);
6957 		(void)jobmgr_assumes(jmr, jm != NULL);
6958 		jmr->jm_port = transfer_port;
6959 	} else if (!jm && !pid1_magic && uflag == false) {
6960 		char *trusted_fd = getenv(LAUNCHD_TRUSTED_FD_ENV);
6961 		name_t service_buf;
6962 
6963 		snprintf(service_buf, sizeof(service_buf), "com.apple.launchd.peruser.%u", getuid());
6964 
6965 		if (uflag == false && jobmgr_assumes_zero(jmr, bootstrap_check_in(bootstrap_port, service_buf, &jmr->jm_port)) != 0) {
6966 			goto out_bad;
6967 		}
6968 
6969 		if (trusted_fd) {
6970 			int dfd, lfd = (int) strtol(trusted_fd, NULL, 10);
6971 
6972 			if ((dfd = dup(lfd)) >= 0) {
6973 				(void)jobmgr_assumes_zero_p(jmr, runtime_close(dfd));
6974 				(void)jobmgr_assumes_zero_p(jmr, runtime_close(lfd));
6975 			}
6976 
6977 			unsetenv(LAUNCHD_TRUSTED_FD_ENV);
6978 		}
6979 
6980 		// cut off the Libc cache, we don't want to deadlock against ourself
6981 		inherited_bootstrap_port = bootstrap_port;
6982 		bootstrap_port = MACH_PORT_NULL;
6983 		os_assert_zero(launchd_mport_notify_req(inherited_bootstrap_port, MACH_NOTIFY_DEAD_NAME));
6984 
6985 		// We set this explicitly as we start each child
6986 		os_assert_zero(launchd_set_bport(MACH_PORT_NULL));
6987 	} else if (jobmgr_assumes_zero(jmr, launchd_mport_create_recv(&jmr->jm_port)) != KERN_SUCCESS) {
6988 		syslog(LOG_ERR, "launchd_mport_create_recv failed");
6989 		goto out_bad;
6990 	}
6991 		syslog(LOG_ERR, "launchd_mport_create_recv(=%d)\n", jmr->jm_port);
6992 	if (!name) {
6993 		sprintf(jmr->name_init, "%u", MACH_PORT_INDEX(jmr->jm_port));
6994 	}
6995 
6996 	if (!jm) {
6997 		syslog(LOG_ERR, "kevent_moddding");
6998 		(void)jobmgr_assumes_zero_p(jmr, kevent_mod(SIGTERM, EVFILT_SIGNAL, EV_ADD, 0, 0, jmr));
6999 		(void)jobmgr_assumes_zero_p(jmr, kevent_mod(SIGUSR1, EVFILT_SIGNAL, EV_ADD, 0, 0, jmr));
7000 		(void)jobmgr_assumes_zero_p(jmr, kevent_mod(SIGUSR2, EVFILT_SIGNAL, EV_ADD, 0, 0, jmr));
7001 		(void)jobmgr_assumes_zero_p(jmr, kevent_mod(SIGINFO, EVFILT_SIGNAL, EV_ADD, 0, 0, jmr));
7002 		(void)jobmgr_assumes_zero_p(jmr, kevent_mod(0, EVFILT_FS, EV_ADD, VQ_MOUNT|VQ_UNMOUNT|VQ_UPDATE, 0, jmr));
7003 	}
7004 
7005 	if (name && !skip_init) {
7006 		syslog(LOG_ERR, "jobmgr_init_session");
7007 		bootstrapper = jobmgr_init_session(jmr, name, sflag);
7008 	}
7009 
7010 	if (!bootstrapper || !bootstrapper->weird_bootstrap || uflag == true) {
7011 		if (jobmgr_assumes_zero(jmr, runtime_add_mport(jmr->jm_port, job_server)) != KERN_SUCCESS) {
7012 			goto out_bad;
7013 		}
7014 	}
7015 	syslog(LOG_ERR, "jobmgr created!!!!");
7016 	jobmgr_log(jmr, LOG_DEBUG, "Created job manager%s%s", jm ? " with parent: " : ".", jm ? jm->name : "");
7017 
7018 	if (bootstrapper) {
7019 		bootstrapper->asport = asport;
7020 
7021 		jobmgr_log(jmr, LOG_DEBUG, "Bootstrapping new job manager with audit session %u", asport);
7022 		(void)jobmgr_assumes(jmr, job_dispatch(bootstrapper, true) != NULL);
7023 	} else {
7024 		jmr->req_asport = asport;
7025 	}
7026 
7027 	if (asport != MACH_PORT_NULL) {
7028 		(void)jobmgr_assumes_zero(jmr, launchd_mport_copy_send(asport));
7029 	}
7030 
7031 	if (jmr->parentmgr) {
7032 		runtime_add_weak_ref();
7033 	}
7034 
7035 	return jmr;
7036 
7037 out_bad:
7038 	if (jmr) {
7039 		jobmgr_remove(jmr);
7040 		if (jm == NULL) {
7041 			root_jobmgr = NULL;
7042 		}
7043 	}
7044 	return NULL;
7045 }
7046 
7047 jobmgr_t
jobmgr_new_xpc_singleton_domain(jobmgr_t jm,name_t name)7048 jobmgr_new_xpc_singleton_domain(jobmgr_t jm, name_t name)
7049 {
7050 	jobmgr_t new = NULL;
7051 
7052 	/* These job managers are basically singletons, so we use the root Mach
7053 	 * bootstrap port as their requestor ports so they'll never go away.
7054 	 */
7055 	mach_port_t req_port = root_jobmgr->jm_port;
7056 	if (jobmgr_assumes_zero(jm, launchd_mport_make_send(req_port)) == KERN_SUCCESS) {
7057 		new = jobmgr_new(root_jobmgr, req_port, MACH_PORT_NULL, false, name, true, MACH_PORT_NULL);
7058 		if (new) {
7059 			new->properties |= BOOTSTRAP_PROPERTY_XPC_SINGLETON;
7060 			new->properties |= BOOTSTRAP_PROPERTY_XPC_DOMAIN;
7061 			new->xpc_singleton = true;
7062 		}
7063 	}
7064 
7065 	return new;
7066 }
7067 
7068 jobmgr_t
jobmgr_find_xpc_per_user_domain(jobmgr_t jm,uid_t uid)7069 jobmgr_find_xpc_per_user_domain(jobmgr_t jm, uid_t uid)
7070 {
7071 	jobmgr_t jmi = NULL;
7072 	LIST_FOREACH(jmi, &_s_xpc_user_domains, xpc_le) {
7073 		if (jmi->req_euid == uid) {
7074 			return jmi;
7075 		}
7076 	}
7077 
7078 	name_t name;
7079 	(void)snprintf(name, sizeof(name), "com.apple.xpc.domain.peruser.%u", uid);
7080 	jmi = jobmgr_new_xpc_singleton_domain(jm, name);
7081 	if (jobmgr_assumes(jm, jmi != NULL)) {
7082 		/* We need to create a per-user launchd for this UID if there isn't one
7083 		 * already so we can grab the bootstrap port.
7084 		 */
7085 		job_t puj = jobmgr_lookup_per_user_context_internal(NULL, uid, &jmi->req_bsport);
7086 		if (jobmgr_assumes(jmi, puj != NULL)) {
7087 			(void)jobmgr_assumes_zero(jmi, launchd_mport_copy_send(puj->asport));
7088 			(void)jobmgr_assumes_zero(jmi, launchd_mport_copy_send(jmi->req_bsport));
7089 			jmi->shortdesc = "per-user";
7090 			jmi->req_asport = puj->asport;
7091 			jmi->req_asid = puj->asid;
7092 			jmi->req_euid = uid;
7093 			jmi->req_egid = -1;
7094 
7095 			LIST_INSERT_HEAD(&_s_xpc_user_domains, jmi, xpc_le);
7096 		} else {
7097 			jobmgr_remove(jmi);
7098 		}
7099 	}
7100 
7101 	return jmi;
7102 }
7103 
7104 jobmgr_t
jobmgr_find_xpc_per_session_domain(jobmgr_t jm,au_asid_t asid)7105 jobmgr_find_xpc_per_session_domain(jobmgr_t jm, au_asid_t asid)
7106 {
7107 	jobmgr_t jmi = NULL;
7108 	LIST_FOREACH(jmi, &_s_xpc_session_domains, xpc_le) {
7109 		if (jmi->req_asid == asid) {
7110 			return jmi;
7111 		}
7112 	}
7113 
7114 	name_t name;
7115 	(void)snprintf(name, sizeof(name), "com.apple.xpc.domain.persession.%i", asid);
7116 	jmi = jobmgr_new_xpc_singleton_domain(jm, name);
7117 	if (jobmgr_assumes(jm, jmi != NULL)) {
7118 		(void)jobmgr_assumes_zero(jmi, launchd_mport_make_send(root_jobmgr->jm_port));
7119 		jmi->shortdesc = "per-session";
7120 		jmi->req_bsport = root_jobmgr->jm_port;
7121 #ifdef notyet
7122 		(void)jobmgr_assumes_zero(jmi, audit_session_port(asid, &jmi->req_asport));
7123 #endif
7124 		jmi->req_asid = asid;
7125 		jmi->req_euid = -1;
7126 		jmi->req_egid = -1;
7127 
7128 		LIST_INSERT_HEAD(&_s_xpc_session_domains, jmi, xpc_le);
7129 	} else {
7130 		jobmgr_remove(jmi);
7131 	}
7132 
7133 	return jmi;
7134 }
7135 
7136 job_t
jobmgr_init_session(jobmgr_t jm,const char * session_type,bool sflag)7137 jobmgr_init_session(jobmgr_t jm, const char *session_type, bool sflag)
7138 {
7139 	const char *bootstrap_tool[] = { "/bin/launchctl", "bootstrap", "-S", session_type, sflag ? "-s" : NULL, NULL };
7140 	char thelabel[1000];
7141 	job_t bootstrapper;
7142 
7143 	snprintf(thelabel, sizeof(thelabel), "com.apple.launchctl.%s", session_type);
7144 	bootstrapper = job_new(jm, thelabel, NULL, bootstrap_tool);
7145 
7146 	if (jobmgr_assumes(jm, bootstrapper != NULL) && (jm->parentmgr || !pid1_magic)) {
7147 		bootstrapper->is_bootstrapper = true;
7148 		char buf[100];
7149 
7150 		// <rdar://problem/5042202> launchd-201: can't ssh in with AFP OD account (hangs)
7151 		snprintf(buf, sizeof(buf), "0x%X:0:0", getuid());
7152 		envitem_new(bootstrapper, "__CF_USER_TEXT_ENCODING", buf, false);
7153 		bootstrapper->weird_bootstrap = true;
7154 		(void)jobmgr_assumes(jm, job_setup_machport(bootstrapper));
7155 	} else if (bootstrapper && strncmp(session_type, VPROCMGR_SESSION_SYSTEM, sizeof(VPROCMGR_SESSION_SYSTEM)) == 0) {
7156 #if TARGET_OS_EMBEDDED
7157 		bootstrapper->psproctype = POSIX_SPAWN_PROC_TYPE_DAEMON_INTERACTIVE;
7158 #endif
7159 		bootstrapper->is_bootstrapper = true;
7160 		if (jobmgr_assumes(jm, pid1_magic)) {
7161 			// Have our system bootstrapper print out to the console.
7162 			bootstrapper->stdoutpath = strdup(_PATH_CONSOLE);
7163 			bootstrapper->stderrpath = strdup(_PATH_CONSOLE);
7164 
7165 			if (launchd_console) {
7166 				(void)jobmgr_assumes_zero_p(jm, kevent_mod((uintptr_t)fileno(launchd_console), EVFILT_VNODE, EV_ADD | EV_ONESHOT, NOTE_REVOKE, 0, jm));
7167 			}
7168 		}
7169 	}
7170 
7171 	jm->session_initialized = true;
7172 	return bootstrapper;
7173 }
7174 
7175 jobmgr_t
jobmgr_delete_anything_with_port(jobmgr_t jm,mach_port_t port)7176 jobmgr_delete_anything_with_port(jobmgr_t jm, mach_port_t port)
7177 {
7178 	struct machservice *ms, *next_ms;
7179 	jobmgr_t jmi, jmn;
7180 
7181 	/* Mach ports, unlike Unix descriptors, are reference counted. In other
7182 	 * words, when some program hands us a second or subsequent send right to a
7183 	 * port we already have open, the Mach kernel gives us the same port number
7184 	 * back and increments an reference count associated with the port. This
7185 	 * This forces us, when discovering that a receive right at the other end
7186 	 * has been deleted, to wander all of our objects to see what weird places
7187 	 * clients might have handed us the same send right to use.
7188 	 */
7189 
7190 	if (jm == root_jobmgr) {
7191 		if (port == inherited_bootstrap_port) {
7192 			(void)jobmgr_assumes_zero(jm, launchd_mport_deallocate(port));
7193 			inherited_bootstrap_port = MACH_PORT_NULL;
7194 
7195 			return jobmgr_shutdown(jm);
7196 		}
7197 
7198 		LIST_FOREACH_SAFE(ms, &port_hash[HASH_PORT(port)], port_hash_sle, next_ms) {
7199 			if (ms->port == port && !ms->recv) {
7200 				machservice_delete(ms->job, ms, true);
7201 			}
7202 		}
7203 	}
7204 
7205 	SLIST_FOREACH_SAFE(jmi, &jm->submgrs, sle, jmn) {
7206 		jobmgr_delete_anything_with_port(jmi, port);
7207 	}
7208 
7209 	if (jm->req_port == port) {
7210 		jobmgr_log(jm, LOG_DEBUG, "Request port died: %i", MACH_PORT_INDEX(port));
7211 		return jobmgr_shutdown(jm);
7212 	}
7213 
7214 	struct waiting4attach *w4ai = NULL;
7215 	struct waiting4attach *w4ait = NULL;
7216 	LIST_FOREACH_SAFE(w4ai, &jm->attaches, le, w4ait) {
7217 		if (port == w4ai->port) {
7218 			waiting4attach_delete(jm, w4ai);
7219 			break;
7220 		}
7221 	}
7222 
7223 	return jm;
7224 }
7225 
7226 void
jobmgr_reap_pid(jobmgr_t jm,pid_t pid)7227 jobmgr_reap_pid(jobmgr_t jm, pid_t pid)
7228 {
7229 	if (jobmgr_find_by_pid_deep(jm, pid, true) != NULL)
7230 		return;
7231 
7232 	waitpid(pid, (int *) 0, 0);
7233 	jobmgr_log(jm, LOG_DEBUG, "Reaping PID %d", pid);
7234 }
7235 
7236 struct machservice *
jobmgr_lookup_service(jobmgr_t jm,const char * name,bool check_parent,pid_t target_pid)7237 jobmgr_lookup_service(jobmgr_t jm, const char *name, bool check_parent, pid_t target_pid)
7238 {
7239 	struct machservice *ms;
7240 	job_t target_j;
7241 
7242 	jobmgr_log(jm, LOG_DEBUG, "Looking up %sservice %s", target_pid ? "per-PID " : "", name);
7243 
7244 	if (target_pid) {
7245 		/* This is a hack to let FileSyncAgent look up per-PID Mach services from the Background
7246 		 * bootstrap in other bootstraps.
7247 		 */
7248 
7249 		// Start in the given bootstrap.
7250 		if (unlikely((target_j = jobmgr_find_by_pid(jm, target_pid, false)) == NULL)) {
7251 			// If we fail, do a deep traversal.
7252 			if (unlikely((target_j = jobmgr_find_by_pid_deep(root_jobmgr, target_pid, true)) == NULL)) {
7253 				jobmgr_log(jm, LOG_DEBUG, "Didn't find PID %i", target_pid);
7254 				return NULL;
7255 			}
7256 		}
7257 
7258 		SLIST_FOREACH(ms, &target_j->machservices, sle) {
7259 			if (ms->per_pid && strcmp(name, ms->name) == 0) {
7260 				return ms;
7261 			}
7262 		}
7263 
7264 		job_log(target_j, LOG_DEBUG, "Didn't find per-PID Mach service: %s", name);
7265 		return NULL;
7266 	}
7267 
7268 	jobmgr_t where2look = jm;
7269 	// XPC domains are separate from Mach bootstraps.
7270 	if (!(jm->properties & BOOTSTRAP_PROPERTY_XPC_DOMAIN)) {
7271 		if (launchd_flat_mach_namespace && !(jm->properties & BOOTSTRAP_PROPERTY_EXPLICITSUBSET)) {
7272 			where2look = root_jobmgr;
7273 		}
7274 	}
7275 
7276 	LIST_FOREACH(ms, &where2look->ms_hash[hash_ms(name)], name_hash_sle) {
7277 		if (!ms->per_pid && strcmp(name, ms->name) == 0) {
7278 			return ms;
7279 		}
7280 	}
7281 
7282 	if (jm->parentmgr == NULL || !check_parent) {
7283 		return NULL;
7284 	}
7285 
7286 	return jobmgr_lookup_service(jm->parentmgr, name, true, 0);
7287 }
7288 
7289 mach_port_t
machservice_port(struct machservice * ms)7290 machservice_port(struct machservice *ms)
7291 {
7292 	return ms->port;
7293 }
7294 
7295 job_t
machservice_job(struct machservice * ms)7296 machservice_job(struct machservice *ms)
7297 {
7298 	return ms->job;
7299 }
7300 
7301 bool
machservice_hidden(struct machservice * ms)7302 machservice_hidden(struct machservice *ms)
7303 {
7304 	return ms->hide;
7305 }
7306 
7307 bool
machservice_active(struct machservice * ms)7308 machservice_active(struct machservice *ms)
7309 {
7310 	return ms->isActive;
7311 }
7312 
7313 const char *
machservice_name(struct machservice * ms)7314 machservice_name(struct machservice *ms)
7315 {
7316 	return ms->name;
7317 }
7318 
7319 void
machservice_drain_port(struct machservice * ms)7320 machservice_drain_port(struct machservice *ms)
7321 {
7322 	bool drain_one = ms->drain_one_on_crash;
7323 	bool drain_all = ms->drain_all_on_crash;
7324 
7325 
7326 	if (!job_assumes(ms->job, (drain_one || drain_all) == true)) {
7327 		return;
7328 	}
7329 
7330 	job_log(ms->job, LOG_INFO, "Draining %s...", ms->name);
7331 	char *req_buff = calloc(2, sizeof(union __RequestUnion__catch_mach_exc_subsystem));
7332 	char *rep_buff = calloc(1, sizeof(union __ReplyUnion__catch_mach_exc_subsystem));
7333 	mig_reply_error_t *req_hdr = (mig_reply_error_t *)&req_buff;
7334 	mig_reply_error_t *rep_hdr = (mig_reply_error_t *)&rep_buff;
7335 
7336 	mach_msg_return_t mr = ~MACH_MSG_SUCCESS;
7337 
7338 	do {
7339 		/* This should be a direct check on the Mach service to see if it's an exception-handling
7340 		 * port, and it will break things if ReportCrash or SafetyNet start advertising other
7341 		 * Mach services. But for now, it should be okay.
7342 		 */
7343 		if (ms->job->alt_exc_handler || ms->job->internal_exc_handler) {
7344 			mr = launchd_exc_runtime_once(ms->port, sizeof(req_buff), sizeof(rep_buff), req_hdr, rep_hdr, 0);
7345 		} else {
7346 			mach_msg_options_t options =	MACH_RCV_MSG		|
7347 											MACH_RCV_TIMEOUT	;
7348 
7349 			mr = mach_msg((mach_msg_header_t *)req_hdr, options, 0, sizeof(req_buff), ms->port, 0, MACH_PORT_NULL);
7350 			switch (mr) {
7351 			case MACH_MSG_SUCCESS:
7352 				mach_msg_destroy((mach_msg_header_t *)req_hdr);
7353 				break;
7354 			case MACH_RCV_TIMED_OUT:
7355 				break;
7356 			case MACH_RCV_TOO_LARGE:
7357 				launchd_syslog(LOG_WARNING, "Tried to receive message that was larger than %lu bytes", sizeof(req_buff));
7358 				break;
7359 			default:
7360 				break;
7361 			}
7362 		}
7363 	} while (drain_all && mr != MACH_RCV_TIMED_OUT);
7364 }
7365 
7366 void
machservice_delete(job_t j,struct machservice * ms,bool port_died)7367 machservice_delete(job_t j, struct machservice *ms, bool port_died)
7368 {
7369 	if (ms->alias) {
7370 		/* HACK: Egregious code duplication. But dealing with aliases is a
7371 		 * pretty simple affair since they can't and shouldn't have any complex
7372 		 * behaviors associated with them.
7373 		 */
7374 		LIST_REMOVE(ms, name_hash_sle);
7375 		SLIST_REMOVE(&j->machservices, ms, machservice, sle);
7376 		free(ms);
7377 		return;
7378 	}
7379 
7380 	if (unlikely(ms->debug_on_close)) {
7381 		job_log(j, LOG_NOTICE, "About to enter kernel debugger because of Mach port: 0x%x", ms->port);
7382 		(void)job_assumes_zero(j, host_reboot(mach_host_self(), HOST_REBOOT_DEBUGGER));
7383 	}
7384 
7385 	if (ms->recv && job_assumes(j, !machservice_active(ms))) {
7386 		job_log(j, LOG_DEBUG, "Closing receive right for %s", ms->name);
7387 		(void)job_assumes_zero(j, launchd_mport_close_recv(ms->port));
7388 	}
7389 
7390 	(void)job_assumes_zero(j, launchd_mport_deallocate(ms->port));
7391 
7392 	if (unlikely(ms->port == the_exception_server)) {
7393 		the_exception_server = 0;
7394 	}
7395 
7396 	job_log(j, LOG_DEBUG, "Mach service deleted%s: %s", port_died ? " (port died)" : "", ms->name);
7397 
7398 	if (ms->special_port_num) {
7399 		SLIST_REMOVE(&special_ports, ms, machservice, special_port_sle);
7400 	}
7401 	SLIST_REMOVE(&j->machservices, ms, machservice, sle);
7402 
7403 	if (!(j->dedicated_instance || ms->event_channel)) {
7404 		LIST_REMOVE(ms, name_hash_sle);
7405 	}
7406 	LIST_REMOVE(ms, port_hash_sle);
7407 
7408 	free(ms);
7409 }
7410 
7411 void
machservice_request_notifications(struct machservice * ms)7412 machservice_request_notifications(struct machservice *ms)
7413 {
7414 	mach_msg_id_t which = MACH_NOTIFY_DEAD_NAME;
7415 
7416 	ms->isActive = true;
7417 
7418 	if (ms->recv) {
7419 		which = MACH_NOTIFY_PORT_DESTROYED;
7420 		job_checkin(ms->job);
7421 	}
7422 
7423 	(void)job_assumes_zero(ms->job, launchd_mport_notify_req(ms->port, which));
7424 }
7425 
7426 #define NELEM(x) (sizeof(x)/sizeof(x[0]))
7427 #define END_OF(x) (&(x)[NELEM(x)])
7428 
7429 char **
mach_cmd2argv(const char * string)7430 mach_cmd2argv(const char *string)
7431 {
7432 	char *argv[100], args[1000];
7433 	const char *cp;
7434 	char *argp = args, term, **argv_ret, *co;
7435 	unsigned int nargs = 0, i;
7436 
7437 	for (cp = string; *cp;) {
7438 		while (isspace(*cp))
7439 			cp++;
7440 		term = (*cp == '"') ? *cp++ : '\0';
7441 		if (nargs < NELEM(argv)) {
7442 			argv[nargs++] = argp;
7443 		}
7444 		while (*cp && (term ? *cp != term : !isspace(*cp)) && argp < END_OF(args)) {
7445 			if (*cp == '\\') {
7446 				cp++;
7447 			}
7448 			*argp++ = *cp;
7449 			if (*cp) {
7450 				cp++;
7451 			}
7452 		}
7453 		*argp++ = '\0';
7454 	}
7455 	argv[nargs] = NULL;
7456 
7457 	if (nargs == 0) {
7458 		return NULL;
7459 	}
7460 
7461 	argv_ret = malloc((nargs + 1) * sizeof(char *) + strlen(string) + 1);
7462 
7463 	if (!argv_ret) {
7464 		(void)os_assumes_zero(errno);
7465 		return NULL;
7466 	}
7467 
7468 	co = (char *)argv_ret + (nargs + 1) * sizeof(char *);
7469 
7470 	for (i = 0; i < nargs; i++) {
7471 		strcpy(co, argv[i]);
7472 		argv_ret[i] = co;
7473 		co += strlen(argv[i]) + 1;
7474 	}
7475 	argv_ret[i] = NULL;
7476 
7477 	return argv_ret;
7478 }
7479 
7480 void
job_checkin(job_t j)7481 job_checkin(job_t j)
7482 {
7483 	j->checkedin = true;
7484 }
7485 
job_is_god(job_t j)7486 bool job_is_god(job_t j)
7487 {
7488 	return j->embedded_god;
7489 }
7490 
7491 bool
job_ack_port_destruction(mach_port_t p)7492 job_ack_port_destruction(mach_port_t p)
7493 {
7494 	struct machservice *ms;
7495 	job_t j;
7496 
7497 	LIST_FOREACH(ms, &port_hash[HASH_PORT(p)], port_hash_sle) {
7498 		if (ms->recv && (ms->port == p)) {
7499 			break;
7500 		}
7501 	}
7502 
7503 	if (!ms) {
7504 		launchd_syslog(LOG_WARNING, "Could not find MachService to match receive right: 0x%x", p);
7505 		return false;
7506 	}
7507 
7508 	j = ms->job;
7509 
7510 	jobmgr_log(root_jobmgr, LOG_DEBUG, "Receive right returned to us: %s", ms->name);
7511 
7512 	/* Without being the exception handler, NOTE_EXIT is our only way to tell if
7513 	 * the job  crashed, and we can't rely on NOTE_EXIT always being processed
7514 	 * after all the job's receive rights have been returned.
7515 	 *
7516 	 * So when we get receive rights back, check to see if the job has been
7517 	 * reaped yet. If not, then we add this service to a list of services to be
7518 	 * drained on crash if it's requested that behavior. So, for a job with N
7519 	 * receive rights all requesting that they be drained on crash, we can
7520 	 * safely handle the following sequence of events.
7521 	 *
7522 	 * ReceiveRight0Returned
7523 	 * ReceiveRight1Returned
7524 	 * ReceiveRight2Returned
7525 	 * NOTE_EXIT (reap, get exit status)
7526 	 * ReceiveRight3Returned
7527 	 * .
7528 	 * .
7529 	 * .
7530 	 * ReceiveRight(N - 1)Returned
7531 	 */
7532 	if (ms->drain_one_on_crash || ms->drain_all_on_crash) {
7533 		if (j->crashed && j->reaped) {
7534 			job_log(j, LOG_DEBUG, "Job has crashed. Draining port...");
7535 			machservice_drain_port(ms);
7536 		} else if (!(j->crashed || j->reaped)) {
7537 			job_log(j, LOG_DEBUG, "Job's exit status is still unknown. Deferring drain.");
7538 		}
7539 	}
7540 
7541 	ms->isActive = false;
7542 	if (ms->delete_on_destruction) {
7543 		machservice_delete(j, ms, false);
7544 	} else if (ms->reset) {
7545 		machservice_resetport(j, ms);
7546 	}
7547 
7548 	kern_return_t kr = mach_port_set_attributes(mach_task_self(), ms->port, MACH_PORT_TEMPOWNER, NULL, 0);
7549 	(void)job_assumes_zero(j, kr);
7550 	machservice_stamp_port(j, ms);
7551 	job_dispatch(j, false);
7552 
7553 	if (ms->recv_race_hack) {
7554 		ms->recv_race_hack = false;
7555 		machservice_watch(ms->job, ms);
7556 	}
7557 
7558 	root_jobmgr = jobmgr_do_garbage_collection(root_jobmgr);
7559 
7560 	return true;
7561 }
7562 
7563 void
job_ack_no_senders(job_t j)7564 job_ack_no_senders(job_t j)
7565 {
7566 	j->priv_port_has_senders = false;
7567 
7568 	(void)job_assumes_zero(j, launchd_mport_close_recv(j->j_port));
7569 	j->j_port = 0;
7570 
7571 	job_log(j, LOG_DEBUG, "No more senders on privileged Mach bootstrap port");
7572 
7573 	job_dispatch(j, false);
7574 }
7575 
7576 bool
semaphoreitem_new(job_t j,semaphore_reason_t why,const char * what)7577 semaphoreitem_new(job_t j, semaphore_reason_t why, const char *what)
7578 {
7579 	struct semaphoreitem *si;
7580 	size_t alloc_sz = sizeof(struct semaphoreitem);
7581 
7582 	if (what) {
7583 		alloc_sz += strlen(what) + 1;
7584 	}
7585 
7586 	if (job_assumes(j, si = calloc(1, alloc_sz)) == NULL) {
7587 		return false;
7588 	}
7589 
7590 	si->why = why;
7591 
7592 	if (what) {
7593 		strcpy(si->what_init, what);
7594 	}
7595 
7596 	SLIST_INSERT_HEAD(&j->semaphores, si, sle);
7597 
7598 	if ((why == OTHER_JOB_ENABLED || why == OTHER_JOB_DISABLED) && !j->nosy) {
7599 		job_log(j, LOG_DEBUG, "Job is interested in \"%s\".", what);
7600 		SLIST_INSERT_HEAD(&s_curious_jobs, j, curious_jobs_sle);
7601 		j->nosy = true;
7602 	}
7603 
7604 	semaphoreitem_runtime_mod_ref(si, true);
7605 
7606 	return true;
7607 }
7608 
7609 void
semaphoreitem_runtime_mod_ref(struct semaphoreitem * si,bool add)7610 semaphoreitem_runtime_mod_ref(struct semaphoreitem *si, bool add)
7611 {
7612 	/*
7613 	 * External events need to be tracked.
7614 	 * Internal events do NOT need to be tracked.
7615 	 */
7616 
7617 	switch (si->why) {
7618 	case SUCCESSFUL_EXIT:
7619 	case FAILED_EXIT:
7620 	case OTHER_JOB_ENABLED:
7621 	case OTHER_JOB_DISABLED:
7622 	case OTHER_JOB_ACTIVE:
7623 	case OTHER_JOB_INACTIVE:
7624 		return;
7625 	default:
7626 		break;
7627 	}
7628 
7629 	if (add) {
7630 		runtime_add_weak_ref();
7631 	} else {
7632 		runtime_del_weak_ref();
7633 	}
7634 }
7635 
7636 void
semaphoreitem_delete(job_t j,struct semaphoreitem * si)7637 semaphoreitem_delete(job_t j, struct semaphoreitem *si)
7638 {
7639 	semaphoreitem_runtime_mod_ref(si, false);
7640 
7641 	SLIST_REMOVE(&j->semaphores, si, semaphoreitem, sle);
7642 
7643 	// We'll need to rethink this if it ever becomes possible to dynamically add or remove semaphores.
7644 	if ((si->why == OTHER_JOB_ENABLED || si->why == OTHER_JOB_DISABLED) && j->nosy) {
7645 		j->nosy = false;
7646 		SLIST_REMOVE(&s_curious_jobs, j, job_s, curious_jobs_sle);
7647 	}
7648 
7649 	free(si);
7650 }
7651 
7652 void
semaphoreitem_setup_dict_iter(launch_data_t obj,const char * key,void * context)7653 semaphoreitem_setup_dict_iter(launch_data_t obj, const char *key, void *context)
7654 {
7655 	struct semaphoreitem_dict_iter_context *sdic = context;
7656 	semaphore_reason_t why;
7657 
7658 	why = launch_data_get_bool(obj) ? sdic->why_true : sdic->why_false;
7659 
7660 	semaphoreitem_new(sdic->j, why, key);
7661 }
7662 
7663 void
semaphoreitem_setup(launch_data_t obj,const char * key,void * context)7664 semaphoreitem_setup(launch_data_t obj, const char *key, void *context)
7665 {
7666 	struct semaphoreitem_dict_iter_context sdic = { context, 0, 0 };
7667 	job_t j = context;
7668 	semaphore_reason_t why;
7669 
7670 	switch (launch_data_get_type(obj)) {
7671 	case LAUNCH_DATA_BOOL:
7672 		if (strcasecmp(key, LAUNCH_JOBKEY_KEEPALIVE_NETWORKSTATE) == 0) {
7673 			why = launch_data_get_bool(obj) ? NETWORK_UP : NETWORK_DOWN;
7674 			semaphoreitem_new(j, why, NULL);
7675 		} else if (strcasecmp(key, LAUNCH_JOBKEY_KEEPALIVE_SUCCESSFULEXIT) == 0) {
7676 			why = launch_data_get_bool(obj) ? SUCCESSFUL_EXIT : FAILED_EXIT;
7677 			semaphoreitem_new(j, why, NULL);
7678 			j->start_pending = true;
7679 		} else if (strcasecmp(key, LAUNCH_JOBKEY_KEEPALIVE_AFTERINITIALDEMAND) == 0) {
7680 			j->needs_kickoff = launch_data_get_bool(obj);
7681 		} else if (strcasecmp(key, LAUNCH_JOBKEY_KEEPALIVE_CRASHED) == 0) {
7682 			why = launch_data_get_bool(obj) ? CRASHED : DID_NOT_CRASH;
7683 			semaphoreitem_new(j, why, NULL);
7684 			j->start_pending = true;
7685 		} else {
7686 			job_log(j, LOG_ERR, "Unrecognized KeepAlive attribute: %s", key);
7687 		}
7688 		break;
7689 	case LAUNCH_DATA_DICTIONARY:
7690 		if (strcasecmp(key, LAUNCH_JOBKEY_KEEPALIVE_OTHERJOBACTIVE) == 0) {
7691 			sdic.why_true = OTHER_JOB_ACTIVE;
7692 			sdic.why_false = OTHER_JOB_INACTIVE;
7693 		} else if (strcasecmp(key, LAUNCH_JOBKEY_KEEPALIVE_OTHERJOBENABLED) == 0) {
7694 			sdic.why_true = OTHER_JOB_ENABLED;
7695 			sdic.why_false = OTHER_JOB_DISABLED;
7696 		} else {
7697 			job_log(j, LOG_ERR, "Unrecognized KeepAlive attribute: %s", key);
7698 			break;
7699 		}
7700 
7701 		launch_data_dict_iterate(obj, semaphoreitem_setup_dict_iter, &sdic);
7702 		break;
7703 	default:
7704 		job_log(j, LOG_ERR, "Unrecognized KeepAlive type: %u", launch_data_get_type(obj));
7705 		break;
7706 	}
7707 }
7708 
7709 bool
externalevent_new(job_t j,struct eventsystem * sys,const char * evname,xpc_object_t event,uint64_t flags __unused)7710 externalevent_new(job_t j, struct eventsystem *sys, const char *evname, xpc_object_t event, uint64_t flags __unused)
7711 {
7712 	if (j->event_monitor) {
7713 		job_log(j, LOG_ERR, "The event monitor job cannot use LaunchEvents or XPC Events.");
7714 		return false;
7715 	}
7716 
7717 	struct externalevent *ee = (struct externalevent *)calloc(1, sizeof(struct externalevent) + strlen(evname) + 1);
7718 	if (!ee) {
7719 		return false;
7720 	}
7721 
7722 	ee->event = xpc_retain(event);
7723 	(void)strcpy(ee->name, evname);
7724 	ee->job = j;
7725 	ee->id = sys->curid;
7726 	ee->sys = sys;
7727 	ee->state = false;
7728 	ee->wanted_state = true;
7729 	sys->curid++;
7730 
7731 #ifdef notyet
7732 	if (flags & XPC_EVENT_FLAG_ENTITLEMENTS) {
7733 		struct ldcred *ldc = runtime_get_caller_creds();
7734 		if (ldc) {
7735 			ee->entitlements = xpc_copy_entitlements_for_pid(ldc->pid);
7736 		}
7737 	}
7738 #endif
7739 	if (sys == _launchd_support_system) {
7740 		ee->internal = true;
7741 	}
7742 
7743 	LIST_INSERT_HEAD(&j->events, ee, job_le);
7744 	LIST_INSERT_HEAD(&sys->events, ee, sys_le);
7745 
7746 	job_log(j, LOG_DEBUG, "New event: %s/%s", sys->name, evname);
7747 
7748 	eventsystem_ping();
7749 	return true;
7750 }
7751 
7752 void
externalevent_delete(struct externalevent * ee)7753 externalevent_delete(struct externalevent *ee)
7754 {
7755 	xpc_release(ee->event);
7756 	if (ee->entitlements) {
7757 		xpc_release(ee->entitlements);
7758 	}
7759 	LIST_REMOVE(ee, job_le);
7760 	LIST_REMOVE(ee, sys_le);
7761 
7762 	free(ee);
7763 
7764 	eventsystem_ping();
7765 }
7766 
7767 void
externalevent_setup(launch_data_t obj,const char * key,void * context)7768 externalevent_setup(launch_data_t obj, const char *key, void *context)
7769 {
7770 	/* This method can ONLY be called on the job_import() path, as it assumes
7771 	 * the input is a launch_data_t.
7772 	 */
7773 	struct externalevent_iter_ctx *ctx = (struct externalevent_iter_ctx *)context;
7774 
7775 	xpc_object_t xobj = ld2xpc(obj);
7776 	if (xobj) {
7777 		job_log(ctx->j, LOG_DEBUG, "Importing stream/event: %s/%s", ctx->sys->name, key);
7778 		externalevent_new(ctx->j, ctx->sys, key, xobj, 0);
7779 		xpc_release(xobj);
7780 	} else {
7781 		job_log(ctx->j, LOG_ERR, "Could not import event for job: %s", key);
7782 	}
7783 }
7784 
7785 struct externalevent *
externalevent_find(const char * sysname,uint64_t id)7786 externalevent_find(const char *sysname, uint64_t id)
7787 {
7788 	struct externalevent *ei = NULL;
7789 
7790 	struct eventsystem *es = eventsystem_find(sysname);
7791 	if (es != NULL) {
7792 		LIST_FOREACH(ei, &es->events, sys_le) {
7793 			if (ei->id == id) {
7794 				break;
7795 			}
7796 		}
7797 	} else {
7798 		launchd_syslog(LOG_ERR, "Could not find event system: %s", sysname);
7799 	}
7800 
7801 	return ei;
7802 }
7803 
7804 struct eventsystem *
eventsystem_new(const char * name)7805 eventsystem_new(const char *name)
7806 {
7807 	struct eventsystem *es = (struct eventsystem *)calloc(1, sizeof(struct eventsystem) + strlen(name) + 1);
7808 	if (es != NULL) {
7809 		es->curid = 1;
7810 		(void)strcpy(es->name, name);
7811 		LIST_INSERT_HEAD(&_s_event_systems, es, global_le);
7812 	} else {
7813 		(void)os_assumes_zero(errno);
7814 	}
7815 
7816 	return es;
7817 }
7818 
7819 void
eventsystem_delete(struct eventsystem * es)7820 eventsystem_delete(struct eventsystem *es)
7821 {
7822 	struct externalevent *ei = NULL;
7823 	while ((ei = LIST_FIRST(&es->events))) {
7824 		externalevent_delete(ei);
7825 	}
7826 
7827 	LIST_REMOVE(es, global_le);
7828 
7829 	free(es);
7830 }
7831 
7832 void
eventsystem_setup(launch_data_t obj,const char * key,void * context)7833 eventsystem_setup(launch_data_t obj, const char *key, void *context)
7834 {
7835 	job_t j = (job_t)context;
7836 	if (!job_assumes(j, launch_data_get_type(obj) == LAUNCH_DATA_DICTIONARY)) {
7837 		return;
7838 	}
7839 
7840 	struct eventsystem *sys = eventsystem_find(key);
7841 	if (unlikely(sys == NULL)) {
7842 		sys = eventsystem_new(key);
7843 		job_log(j, LOG_DEBUG, "New event system: %s", key);
7844 	}
7845 
7846 	if (job_assumes(j, sys != NULL)) {
7847 		struct externalevent_iter_ctx ctx = {
7848 			.j = j,
7849 			.sys = sys,
7850 		};
7851 
7852 		job_log(j, LOG_DEBUG, "Importing events for stream: %s", key);
7853 		launch_data_dict_iterate(obj, externalevent_setup, &ctx);
7854 	}
7855 }
7856 
7857 struct eventsystem *
eventsystem_find(const char * name)7858 eventsystem_find(const char *name)
7859 {
7860 	struct eventsystem *esi = NULL;
7861 	LIST_FOREACH(esi, &_s_event_systems, global_le) {
7862 		if (strcmp(name, esi->name) == 0) {
7863 			break;
7864 		}
7865 	}
7866 
7867 	return esi;
7868 }
7869 
7870 void
eventsystem_ping(void)7871 eventsystem_ping(void)
7872 {
7873 	if (!_launchd_event_monitor) {
7874 		return;
7875 	}
7876 
7877 	if (!_launchd_event_monitor->p) {
7878 		(void)job_dispatch(_launchd_event_monitor, true);
7879 	} else {
7880 		if (_launchd_event_monitor->event_monitor_ready2signal) {
7881 			(void)job_assumes_zero_p(_launchd_event_monitor, kill(_launchd_event_monitor->p, SIGUSR1));
7882 		}
7883 	}
7884 }
7885 
7886 void
jobmgr_dispatch_all_semaphores(jobmgr_t jm)7887 jobmgr_dispatch_all_semaphores(jobmgr_t jm)
7888 {
7889 	jobmgr_t jmi, jmn;
7890 	job_t ji, jn;
7891 
7892 
7893 	SLIST_FOREACH_SAFE(jmi, &jm->submgrs, sle, jmn) {
7894 		jobmgr_dispatch_all_semaphores(jmi);
7895 	}
7896 
7897 	LIST_FOREACH_SAFE(ji, &jm->jobs, sle, jn) {
7898 		if (!SLIST_EMPTY(&ji->semaphores)) {
7899 			job_dispatch(ji, false);
7900 		}
7901 	}
7902 }
7903 
7904 time_t
cronemu(int mon,int mday,int hour,int min)7905 cronemu(int mon, int mday, int hour, int min)
7906 {
7907 	struct tm workingtm;
7908 	time_t now;
7909 
7910 	now = time(NULL);
7911 	workingtm = *localtime(&now);
7912 
7913 	workingtm.tm_isdst = -1;
7914 	workingtm.tm_sec = 0;
7915 	workingtm.tm_min++;
7916 
7917 	while (!cronemu_mon(&workingtm, mon, mday, hour, min)) {
7918 		workingtm.tm_year++;
7919 		workingtm.tm_mon = 0;
7920 		workingtm.tm_mday = 1;
7921 		workingtm.tm_hour = 0;
7922 		workingtm.tm_min = 0;
7923 		mktime(&workingtm);
7924 	}
7925 
7926 	return mktime(&workingtm);
7927 }
7928 
7929 time_t
cronemu_wday(int wday,int hour,int min)7930 cronemu_wday(int wday, int hour, int min)
7931 {
7932 	struct tm workingtm;
7933 	time_t now;
7934 
7935 	now = time(NULL);
7936 	workingtm = *localtime(&now);
7937 
7938 	workingtm.tm_isdst = -1;
7939 	workingtm.tm_sec = 0;
7940 	workingtm.tm_min++;
7941 
7942 	if (wday == 7) {
7943 		wday = 0;
7944 	}
7945 
7946 	while (!(workingtm.tm_wday == wday && cronemu_hour(&workingtm, hour, min))) {
7947 		workingtm.tm_mday++;
7948 		workingtm.tm_hour = 0;
7949 		workingtm.tm_min = 0;
7950 		mktime(&workingtm);
7951 	}
7952 
7953 	return mktime(&workingtm);
7954 }
7955 
7956 bool
cronemu_mon(struct tm * wtm,int mon,int mday,int hour,int min)7957 cronemu_mon(struct tm *wtm, int mon, int mday, int hour, int min)
7958 {
7959 	if (mon == -1) {
7960 		struct tm workingtm = *wtm;
7961 		int carrytest;
7962 
7963 		while (!cronemu_mday(&workingtm, mday, hour, min)) {
7964 			workingtm.tm_mon++;
7965 			workingtm.tm_mday = 1;
7966 			workingtm.tm_hour = 0;
7967 			workingtm.tm_min = 0;
7968 			carrytest = workingtm.tm_mon;
7969 			mktime(&workingtm);
7970 			if (carrytest != workingtm.tm_mon) {
7971 				return false;
7972 			}
7973 		}
7974 		*wtm = workingtm;
7975 		return true;
7976 	}
7977 
7978 	if (mon < wtm->tm_mon) {
7979 		return false;
7980 	}
7981 
7982 	if (mon > wtm->tm_mon) {
7983 		wtm->tm_mon = mon;
7984 		wtm->tm_mday = 1;
7985 		wtm->tm_hour = 0;
7986 		wtm->tm_min = 0;
7987 	}
7988 
7989 	return cronemu_mday(wtm, mday, hour, min);
7990 }
7991 
7992 bool
cronemu_mday(struct tm * wtm,int mday,int hour,int min)7993 cronemu_mday(struct tm *wtm, int mday, int hour, int min)
7994 {
7995 	if (mday == -1) {
7996 		struct tm workingtm = *wtm;
7997 		int carrytest;
7998 
7999 		while (!cronemu_hour(&workingtm, hour, min)) {
8000 			workingtm.tm_mday++;
8001 			workingtm.tm_hour = 0;
8002 			workingtm.tm_min = 0;
8003 			carrytest = workingtm.tm_mday;
8004 			mktime(&workingtm);
8005 			if (carrytest != workingtm.tm_mday) {
8006 				return false;
8007 			}
8008 		}
8009 		*wtm = workingtm;
8010 		return true;
8011 	}
8012 
8013 	if (mday < wtm->tm_mday) {
8014 		return false;
8015 	}
8016 
8017 	if (mday > wtm->tm_mday) {
8018 		wtm->tm_mday = mday;
8019 		wtm->tm_hour = 0;
8020 		wtm->tm_min = 0;
8021 	}
8022 
8023 	return cronemu_hour(wtm, hour, min);
8024 }
8025 
8026 bool
cronemu_hour(struct tm * wtm,int hour,int min)8027 cronemu_hour(struct tm *wtm, int hour, int min)
8028 {
8029 	if (hour == -1) {
8030 		struct tm workingtm = *wtm;
8031 		int carrytest;
8032 
8033 		while (!cronemu_min(&workingtm, min)) {
8034 			workingtm.tm_hour++;
8035 			workingtm.tm_min = 0;
8036 			carrytest = workingtm.tm_hour;
8037 			mktime(&workingtm);
8038 			if (carrytest != workingtm.tm_hour) {
8039 				return false;
8040 			}
8041 		}
8042 		*wtm = workingtm;
8043 		return true;
8044 	}
8045 
8046 	if (hour < wtm->tm_hour) {
8047 		return false;
8048 	}
8049 
8050 	if (hour > wtm->tm_hour) {
8051 		wtm->tm_hour = hour;
8052 		wtm->tm_min = 0;
8053 	}
8054 
8055 	return cronemu_min(wtm, min);
8056 }
8057 
8058 bool
cronemu_min(struct tm * wtm,int min)8059 cronemu_min(struct tm *wtm, int min)
8060 {
8061 	if (min == -1) {
8062 		return true;
8063 	}
8064 
8065 	if (min < wtm->tm_min) {
8066 		return false;
8067 	}
8068 
8069 	if (min > wtm->tm_min) {
8070 		wtm->tm_min = min;
8071 	}
8072 
8073 	return true;
8074 }
8075 
8076 kern_return_t
job_mig_create_server(job_t j,cmd_t server_cmd,uid_t server_uid,boolean_t on_demand,mach_port_t * server_portp)8077 job_mig_create_server(job_t j, cmd_t server_cmd, uid_t server_uid, boolean_t on_demand, mach_port_t *server_portp)
8078 {
8079 	struct ldcred *ldc = runtime_get_caller_creds();
8080 	job_t js;
8081 
8082 	if (!j) {
8083 		RETURN_NO_MEMORY();
8084 	}
8085 
8086 	if (unlikely(j->deny_job_creation)) {
8087 		return BOOTSTRAP_NOT_PRIVILEGED;
8088 	}
8089 
8090 #if HAVE_SANDBOX
8091 	const char **argv = (const char **)mach_cmd2argv(server_cmd);
8092 	if (unlikely(argv == NULL)) {
8093 		RETURN_NO_MEMORY();
8094 	}
8095 	if (unlikely(sandbox_check(ldc->pid, "job-creation", SANDBOX_FILTER_PATH, argv[0]) > 0)) {
8096 		free(argv);
8097 		return BOOTSTRAP_NOT_PRIVILEGED;
8098 	}
8099 	free(argv);
8100 #endif
8101 
8102 	job_log(j, LOG_DEBUG, "Server create attempt: %s", server_cmd);
8103 
8104 	if (pid1_magic) {
8105 		if (ldc->euid || ldc->uid) {
8106 			job_log(j, LOG_WARNING, "Server create attempt moved to per-user launchd: %s", server_cmd);
8107 			return VPROC_ERR_TRY_PER_USER;
8108 		}
8109 	} else {
8110 		if (unlikely(server_uid != getuid())) {
8111 			job_log(j, LOG_WARNING, "Server create: \"%s\": As UID %d, we will not be able to switch to UID %d",
8112 					server_cmd, getuid(), server_uid);
8113 		}
8114 		server_uid = 0; // zero means "do nothing"
8115 	}
8116 
8117 	js = job_new_via_mach_init(j, server_cmd, server_uid, on_demand);
8118 
8119 	if (unlikely(js == NULL)) {
8120 		RETURN_NO_MEMORY();
8121 	}
8122 
8123 	*server_portp = js->j_port;
8124 	return BOOTSTRAP_SUCCESS;
8125 }
8126 
8127 kern_return_t
job_mig_send_signal(job_t j,mach_port_t srp,name_t targetlabel,int sig)8128 job_mig_send_signal(job_t j, mach_port_t srp, name_t targetlabel, int sig)
8129 {
8130 	struct ldcred *ldc = runtime_get_caller_creds();
8131 	job_t otherj;
8132 
8133 	if (!j) {
8134 		RETURN_NO_MEMORY();
8135 	}
8136 
8137 	if (unlikely(ldc->euid != 0 && ldc->euid != getuid()) || j->deny_job_creation) {
8138 #if TARGET_OS_EMBEDDED
8139 		if (!j->embedded_god) {
8140 			return BOOTSTRAP_NOT_PRIVILEGED;
8141 		}
8142 #else
8143 		return BOOTSTRAP_NOT_PRIVILEGED;
8144 #endif
8145 	}
8146 
8147 #if HAVE_SANDBOX
8148 	if (unlikely(sandbox_check(ldc->pid, "job-creation", SANDBOX_FILTER_NONE) > 0)) {
8149 		return BOOTSTRAP_NOT_PRIVILEGED;
8150 	}
8151 #endif
8152 
8153 	if (unlikely(!(otherj = job_find(NULL, targetlabel)))) {
8154 		return BOOTSTRAP_UNKNOWN_SERVICE;
8155 	}
8156 
8157 #if TARGET_OS_EMBEDDED
8158 	if (j->embedded_god) {
8159 		if (j->username && otherj->username) {
8160 			if (strcmp(j->username, otherj->username) != 0) {
8161 				return BOOTSTRAP_NOT_PRIVILEGED;
8162 			}
8163 		} else {
8164 			return BOOTSTRAP_NOT_PRIVILEGED;
8165 		}
8166 	}
8167 #endif
8168 
8169 	if (sig == VPROC_MAGIC_UNLOAD_SIGNAL) {
8170 		bool do_block = otherj->p;
8171 
8172 		if (otherj->anonymous) {
8173 			return BOOTSTRAP_NOT_PRIVILEGED;
8174 		}
8175 
8176 		job_remove(otherj);
8177 
8178 		if (do_block) {
8179 			job_log(j, LOG_DEBUG, "Blocking MIG return of job_remove(): %s", otherj->label);
8180 			// this is messy. We shouldn't access 'otherj' after job_remove(), but we check otherj->p first...
8181 			(void)job_assumes(otherj, waiting4removal_new(otherj, srp));
8182 			return MIG_NO_REPLY;
8183 		} else {
8184 			return 0;
8185 		}
8186 	} else if (otherj->p) {
8187 		(void)job_assumes_zero_p(j, kill2(otherj->p, sig));
8188 	}
8189 
8190 	return 0;
8191 }
8192 
8193 kern_return_t
job_mig_log_forward(job_t j,vm_offset_t inval,mach_msg_type_number_t invalCnt)8194 job_mig_log_forward(job_t j, vm_offset_t inval, mach_msg_type_number_t invalCnt)
8195 {
8196 	struct ldcred *ldc = runtime_get_caller_creds();
8197 
8198 	if (!j) {
8199 		RETURN_NO_MEMORY();
8200 	}
8201 
8202 	if (!job_assumes(j, j->per_user)) {
8203 		return BOOTSTRAP_NOT_PRIVILEGED;
8204 	}
8205 
8206 	return launchd_log_forward(ldc->euid, ldc->egid, inval, invalCnt);
8207 }
8208 
8209 kern_return_t
job_mig_log_drain(job_t j,mach_port_t srp,vm_offset_t * outval,mach_msg_type_number_t * outvalCnt)8210 job_mig_log_drain(job_t j, mach_port_t srp, vm_offset_t *outval, mach_msg_type_number_t *outvalCnt)
8211 {
8212 	struct ldcred *ldc = runtime_get_caller_creds();
8213 
8214 	if (!j) {
8215 		RETURN_NO_MEMORY();
8216 	}
8217 
8218 	if (unlikely(ldc->euid)) {
8219 		return BOOTSTRAP_NOT_PRIVILEGED;
8220 	}
8221 
8222 	return launchd_log_drain(srp, outval, outvalCnt);
8223 }
8224 
8225 kern_return_t
job_mig_swap_complex(job_t j,vproc_gsk_t inkey,vproc_gsk_t outkey,vm_offset_t inval,mach_msg_type_number_t invalCnt,vm_offset_t * outval,mach_msg_type_number_t * outvalCnt)8226 job_mig_swap_complex(job_t j, vproc_gsk_t inkey, vproc_gsk_t outkey,
8227 	vm_offset_t inval, mach_msg_type_number_t invalCnt, vm_offset_t *outval,
8228 	mach_msg_type_number_t *outvalCnt)
8229 {
8230 	const char *action;
8231 	launch_data_t input_obj = NULL, output_obj = NULL;
8232 	size_t data_offset = 0;
8233 	size_t packed_size;
8234 	struct ldcred *ldc = runtime_get_caller_creds();
8235 
8236 	if (!j) {
8237 		RETURN_NO_MEMORY();
8238 	}
8239 
8240 	if (inkey && ldc->pid != j->p) {
8241 		if (ldc->euid && ldc->euid != getuid()) {
8242 			return BOOTSTRAP_NOT_PRIVILEGED;
8243 		}
8244  	}
8245 
8246 	if (unlikely(inkey && outkey && !job_assumes(j, inkey == outkey))) {
8247 		return 1;
8248 	}
8249 
8250 	if (inkey && outkey) {
8251 		action = "Swapping";
8252 	} else if (inkey) {
8253 		action = "Setting";
8254 	} else {
8255 		action = "Getting";
8256 	}
8257 
8258 	job_log(j, LOG_DEBUG, "%s key: %u", action, inkey ? inkey : outkey);
8259 
8260 	*outvalCnt = 20 * 1024 * 1024;
8261 	mig_allocate(outval, *outvalCnt);
8262 	if (!job_assumes(j, *outval != 0)) {
8263 		return 1;
8264 	}
8265 
8266 	/* Note to future maintainers: launch_data_unpack() does NOT return a heap
8267 	 * object. The data is decoded in-place. So do not call launch_data_free()
8268 	 * on input_obj.
8269 	 */
8270 	runtime_ktrace0(RTKT_LAUNCHD_DATA_UNPACK);
8271 	if (unlikely(invalCnt && !job_assumes(j, (input_obj = launch_data_unpack((void *)inval, invalCnt, NULL, 0, &data_offset, NULL)) != NULL))) {
8272 		goto out_bad;
8273 	}
8274 
8275 	char *store = NULL;
8276 	switch (outkey) {
8277 	case VPROC_GSK_ENVIRONMENT:
8278 		if (!job_assumes(j, (output_obj = launch_data_alloc(LAUNCH_DATA_DICTIONARY)))) {
8279 			goto out_bad;
8280 		}
8281 		jobmgr_export_env_from_other_jobs(j->mgr, output_obj);
8282 		runtime_ktrace0(RTKT_LAUNCHD_DATA_PACK);
8283 		if (!job_assumes(j, launch_data_pack(output_obj, (void *)*outval, *outvalCnt, NULL, NULL) != 0)) {
8284 			goto out_bad;
8285 		}
8286 		launch_data_free(output_obj);
8287 		break;
8288 	case VPROC_GSK_ALLJOBS:
8289 		if (!job_assumes(j, (output_obj = job_export_all()) != NULL)) {
8290 			goto out_bad;
8291 		}
8292 		ipc_revoke_fds(output_obj);
8293 		runtime_ktrace0(RTKT_LAUNCHD_DATA_PACK);
8294 		packed_size = launch_data_pack(output_obj, (void *)*outval, *outvalCnt, NULL, NULL);
8295 		if (!job_assumes(j, packed_size != 0)) {
8296 			goto out_bad;
8297 		}
8298 		launch_data_free(output_obj);
8299 		break;
8300 	case VPROC_GSK_MGR_NAME:
8301 		if (!job_assumes(j, (output_obj = launch_data_new_string(j->mgr->name)) != NULL)) {
8302 			goto out_bad;
8303 		}
8304 		packed_size = launch_data_pack(output_obj, (void *)*outval, *outvalCnt, NULL, NULL);
8305 		if (!job_assumes(j, packed_size != 0)) {
8306 			goto out_bad;
8307 		}
8308 
8309 		launch_data_free(output_obj);
8310 		break;
8311 	case VPROC_GSK_JOB_OVERRIDES_DB:
8312 		store = launchd_copy_persistent_store(LAUNCHD_PERSISTENT_STORE_DB, "overrides.plist");
8313 		if (!store || !job_assumes(j, (output_obj = launch_data_new_string(store)) != NULL)) {
8314 			free(store);
8315 			goto out_bad;
8316 		}
8317 
8318 		free(store);
8319 		packed_size = launch_data_pack(output_obj, (void *)*outval, *outvalCnt, NULL, NULL);
8320 		if (!job_assumes(j, packed_size != 0)) {
8321 			goto out_bad;
8322 		}
8323 
8324 		launch_data_free(output_obj);
8325 		break;
8326 	case VPROC_GSK_ZERO:
8327 		mig_deallocate(*outval, *outvalCnt);
8328 		*outval = 0;
8329 		*outvalCnt = 0;
8330 		break;
8331 	default:
8332 		goto out_bad;
8333 	}
8334 
8335 	mig_deallocate(inval, invalCnt);
8336 	return 0;
8337 
8338 out_bad:
8339 	mig_deallocate(inval, invalCnt);
8340 	if (*outval) {
8341 		mig_deallocate(*outval, *outvalCnt);
8342 	}
8343 	if (output_obj) {
8344 		launch_data_free(output_obj);
8345 	}
8346 
8347 	return 1;
8348 }
8349 
8350 kern_return_t
job_mig_swap_integer(job_t j,vproc_gsk_t inkey,vproc_gsk_t outkey,int64_t inval,int64_t * outval)8351 job_mig_swap_integer(job_t j, vproc_gsk_t inkey, vproc_gsk_t outkey, int64_t inval, int64_t *outval)
8352 {
8353 	const char *action;
8354 	kern_return_t kr = 0;
8355 	struct ldcred *ldc = runtime_get_caller_creds();
8356 	int oldmask;
8357 
8358 	if (!j) {
8359 		RETURN_NO_MEMORY();
8360 	}
8361 
8362 	if (inkey && ldc->pid != j->p) {
8363 		if (ldc->euid && ldc->euid != getuid()) {
8364 			return BOOTSTRAP_NOT_PRIVILEGED;
8365 		}
8366  	}
8367 
8368 	if (unlikely(inkey && outkey && !job_assumes(j, inkey == outkey))) {
8369 		return 1;
8370 	}
8371 
8372 	if (inkey && outkey) {
8373 		action = "Swapping";
8374 	} else if (inkey) {
8375 		action = "Setting";
8376 	} else {
8377 		action = "Getting";
8378 	}
8379 
8380 	job_log(j, LOG_DEBUG, "%s key: %u", action, inkey ? inkey : outkey);
8381 
8382 	switch (outkey) {
8383 	case VPROC_GSK_ABANDON_PROCESS_GROUP:
8384 		*outval = j->abandon_pg;
8385 		break;
8386 	case VPROC_GSK_LAST_EXIT_STATUS:
8387 		*outval = j->last_exit_status;
8388 		break;
8389 	case VPROC_GSK_MGR_UID:
8390 		*outval = getuid();
8391 		break;
8392 	case VPROC_GSK_MGR_PID:
8393 		*outval = getpid();
8394 		break;
8395 	case VPROC_GSK_IS_MANAGED:
8396 		*outval = j->anonymous ? 0 : 1;
8397 		break;
8398 	case VPROC_GSK_BASIC_KEEPALIVE:
8399 		*outval = !j->ondemand;
8400 		break;
8401 	case VPROC_GSK_START_INTERVAL:
8402 		*outval = j->start_interval;
8403 		break;
8404 	case VPROC_GSK_IDLE_TIMEOUT:
8405 		*outval = j->timeout;
8406 		break;
8407 	case VPROC_GSK_EXIT_TIMEOUT:
8408 		*outval = j->exit_timeout;
8409 		break;
8410 	case VPROC_GSK_GLOBAL_LOG_MASK:
8411 		oldmask = runtime_setlogmask(LOG_UPTO(LOG_DEBUG));
8412 		*outval = oldmask;
8413 		runtime_setlogmask(oldmask);
8414 		break;
8415 	case VPROC_GSK_GLOBAL_UMASK:
8416 		oldmask = umask(0);
8417 		*outval = oldmask;
8418 		umask(oldmask);
8419 		break;
8420 	case VPROC_GSK_TRANSACTIONS_ENABLED:
8421 		job_log(j, LOG_DEBUG, "Reading EnableTransactions value.");
8422 		*outval = j->enable_transactions;
8423 		break;
8424 	case VPROC_GSK_WAITFORDEBUGGER:
8425 		*outval = j->wait4debugger;
8426 		break;
8427 	case VPROC_GSK_EMBEDDEDROOTEQUIVALENT:
8428 		*outval = j->embedded_god;
8429 		break;
8430 	case VPROC_GSK_ZERO:
8431 		*outval = 0;
8432 		break;
8433 	default:
8434 		kr = 1;
8435 		break;
8436 	}
8437 
8438 	switch (inkey) {
8439 	case VPROC_GSK_ABANDON_PROCESS_GROUP:
8440 		j->abandon_pg = (bool)inval;
8441 		break;
8442 	case VPROC_GSK_GLOBAL_ON_DEMAND:
8443 		job_log(j, LOG_DEBUG, "Job has set global on-demand mode to: %s", inval ? "true" : "false");
8444 		kr = job_set_global_on_demand(j, inval);
8445 		break;
8446 	case VPROC_GSK_BASIC_KEEPALIVE:
8447 		j->ondemand = !inval;
8448 		break;
8449 	case VPROC_GSK_START_INTERVAL:
8450 		if (inval > UINT32_MAX || inval < 0) {
8451 			kr = 1;
8452 		} else if (inval) {
8453 			if (j->start_interval == 0) {
8454 				runtime_add_weak_ref();
8455 			}
8456 			j->start_interval = (typeof(j->start_interval)) inval;
8457 			(void)job_assumes_zero_p(j, kevent_mod((uintptr_t)&j->start_interval, EVFILT_TIMER, EV_ADD, NOTE_SECONDS, j->start_interval, j));
8458 		} else if (j->start_interval) {
8459 			(void)job_assumes_zero_p(j, kevent_mod((uintptr_t)&j->start_interval, EVFILT_TIMER, EV_DELETE, 0, 0, NULL));
8460 			if (j->start_interval != 0) {
8461 				runtime_del_weak_ref();
8462 			}
8463 			j->start_interval = 0;
8464 		}
8465 		break;
8466 	case VPROC_GSK_IDLE_TIMEOUT:
8467 		if (inval < 0 || inval > UINT32_MAX) {
8468 			kr = 1;
8469 		} else {
8470 			j->timeout = (typeof(j->timeout)) inval;
8471 		}
8472 		break;
8473 	case VPROC_GSK_EXIT_TIMEOUT:
8474 		if (inval < 0 || inval > UINT32_MAX) {
8475 			kr = 1;
8476 		} else {
8477 			j->exit_timeout = (typeof(j->exit_timeout)) inval;
8478 		}
8479 		break;
8480 	case VPROC_GSK_GLOBAL_LOG_MASK:
8481 		if (inval < 0 || inval > UINT32_MAX) {
8482 			kr = 1;
8483 		} else {
8484 			runtime_setlogmask((int) inval);
8485 		}
8486 		break;
8487 	case VPROC_GSK_GLOBAL_UMASK:
8488 		__OS_COMPILETIME_ASSERT__(sizeof (mode_t) == 2);
8489 		if (inval < 0 || inval > UINT16_MAX) {
8490 			kr = 1;
8491 		} else {
8492 #if HAVE_SANDBOX
8493 			if (unlikely(sandbox_check(ldc->pid, "job-creation", SANDBOX_FILTER_NONE) > 0)) {
8494 				kr = 1;
8495 			} else {
8496 				umask((mode_t) inval);
8497 			}
8498 #endif
8499 		}
8500 		break;
8501 	case VPROC_GSK_TRANSACTIONS_ENABLED:
8502 		/* No-op. */
8503 		break;
8504 	case VPROC_GSK_WEIRD_BOOTSTRAP:
8505 		if (job_assumes(j, j->weird_bootstrap)) {
8506 			job_log(j, LOG_DEBUG, "Unsetting weird bootstrap.");
8507 
8508 			mach_msg_size_t mxmsgsz = (typeof(mxmsgsz)) sizeof(union __RequestUnion__job_mig_job_subsystem);
8509 
8510 			if (job_mig_job_subsystem.maxsize > mxmsgsz) {
8511 				mxmsgsz = job_mig_job_subsystem.maxsize;
8512 			}
8513 
8514 			(void)job_assumes_zero(j, runtime_add_mport(j->mgr->jm_port, job_server));
8515 			j->weird_bootstrap = false;
8516 		}
8517 		break;
8518 	case VPROC_GSK_WAITFORDEBUGGER:
8519 		j->wait4debugger_oneshot = inval;
8520 		break;
8521 	case VPROC_GSK_PERUSER_SUSPEND:
8522 		if (job_assumes(j, pid1_magic && ldc->euid == 0)) {
8523 			mach_port_t junk = MACH_PORT_NULL;
8524 			job_t jpu = jobmgr_lookup_per_user_context_internal(j, (uid_t)inval, &junk);
8525 			if (job_assumes(j, jpu != NULL)) {
8526 				struct suspended_peruser *spi = NULL;
8527 				LIST_FOREACH(spi, &j->suspended_perusers, sle) {
8528 					if ((int64_t)(spi->j->mach_uid) == inval) {
8529 						job_log(j, LOG_WARNING, "Job tried to suspend per-user launchd for UID %zi twice.", inval);
8530 						break;
8531 					}
8532 				}
8533 
8534 				if (spi == NULL) {
8535 					job_log(j, LOG_INFO, "Job is suspending the per-user launchd for UID %zi.", inval);
8536 					spi = (struct suspended_peruser *)calloc(sizeof(struct suspended_peruser), 1);
8537 					if (job_assumes(j, spi != NULL)) {
8538 						/* Stop listening for events.
8539 						 *
8540 						 * See <rdar://problem/9014146>.
8541 						 */
8542 						if (jpu->peruser_suspend_count == 0) {
8543 							job_ignore(jpu);
8544 						}
8545 
8546 						spi->j = jpu;
8547 						spi->j->peruser_suspend_count++;
8548 						LIST_INSERT_HEAD(&j->suspended_perusers, spi, sle);
8549 						job_stop(spi->j);
8550 						*outval = jpu->p;
8551 					} else {
8552 						kr = BOOTSTRAP_NO_MEMORY;
8553 					}
8554 				}
8555 			}
8556 		} else {
8557 			kr = 1;
8558 		}
8559 		break;
8560 	case VPROC_GSK_PERUSER_RESUME:
8561 		if (job_assumes(j, pid1_magic == true)) {
8562 			struct suspended_peruser *spi = NULL, *spt = NULL;
8563 			LIST_FOREACH_SAFE(spi, &j->suspended_perusers, sle, spt) {
8564 				if ((int64_t)(spi->j->mach_uid) == inval) {
8565 					spi->j->peruser_suspend_count--;
8566 					LIST_REMOVE(spi, sle);
8567 					job_log(j, LOG_INFO, "Job is resuming the per-user launchd for UID %zi.", inval);
8568 					break;
8569 				}
8570 			}
8571 
8572 			if (!job_assumes(j, spi != NULL)) {
8573 				job_log(j, LOG_WARNING, "Job tried to resume per-user launchd for UID %zi that it did not suspend.", inval);
8574 				kr = BOOTSTRAP_NOT_PRIVILEGED;
8575 			} else if (spi->j->peruser_suspend_count == 0) {
8576 				job_watch(spi->j);
8577 				job_dispatch(spi->j, false);
8578 				free(spi);
8579 			}
8580 		} else {
8581 			kr = 1;
8582 		}
8583 		break;
8584 	case VPROC_GSK_ZERO:
8585 		break;
8586 	default:
8587 		kr = 1;
8588 		break;
8589 	}
8590 
8591 	return kr;
8592 }
8593 
8594 kern_return_t
job_mig_post_fork_ping(job_t j,task_t child_task,mach_port_t * asport)8595 job_mig_post_fork_ping(job_t j, task_t child_task, mach_port_t *asport)
8596 {
8597 	if (!j) {
8598 		RETURN_NO_MEMORY();
8599 	}
8600 
8601 	job_log(j, LOG_DEBUG, "Post fork ping.");
8602 
8603 	struct machservice *ms;
8604 	job_setup_exception_port(j, child_task);
8605 	SLIST_FOREACH(ms, &special_ports, special_port_sle) {
8606 		if (j->per_user && (ms->special_port_num != TASK_ACCESS_PORT)) {
8607 			// The TASK_ACCESS_PORT funny business is to workaround 5325399.
8608 			continue;
8609 		}
8610 
8611 		errno = task_set_special_port(child_task, ms->special_port_num, ms->port);
8612 		if (errno) {
8613 			if (errno == MACH_SEND_INVALID_DEST) {
8614 				job_log(j, LOG_WARNING, "Task died before special ports could be set.");
8615 				break;
8616 			}
8617 
8618 			int desired_log_level = LOG_ERR;
8619 			if (j->anonymous) {
8620 				// 5338127
8621 
8622 				desired_log_level = LOG_WARNING;
8623 
8624 				if (ms->special_port_num == TASK_SEATBELT_PORT) {
8625 					desired_log_level = LOG_DEBUG;
8626 				}
8627 			}
8628 
8629 			job_log(j, desired_log_level, "Could not setup Mach task special port %u: %s", ms->special_port_num, mach_error_string(errno));
8630 		}
8631 	}
8632 
8633 	/* MIG will not zero-initialize this pointer, so we must always do so.
8634 	 *
8635 	 * <rdar://problem/8562593>.
8636 	 */
8637 	*asport = MACH_PORT_NULL;
8638 #if !TARGET_OS_EMBEDDED
8639 	if (!j->anonymous) {
8640 		/* XPC services will spawn into the root security session by default.
8641 		 * xpcproxy will switch them away if needed.
8642 		 */
8643 		if (!(j->mgr->properties & BOOTSTRAP_PROPERTY_XPC_DOMAIN)) {
8644 			job_log(j, LOG_DEBUG, "Returning session port: 0x%x", j->asport);
8645 			*asport = j->asport;
8646 		}
8647 	}
8648 #endif
8649 	(void)job_assumes_zero(j, launchd_mport_deallocate(child_task));
8650 
8651 	return 0;
8652 }
8653 
8654 kern_return_t
job_mig_get_listener_port_rights(job_t j,mach_port_array_t * sports,mach_msg_type_number_t * sports_cnt)8655 job_mig_get_listener_port_rights(job_t j, mach_port_array_t *sports, mach_msg_type_number_t *sports_cnt)
8656 {
8657 	if (!j) {
8658 		RETURN_NO_MEMORY();
8659 	}
8660 
8661 	size_t cnt = 0;
8662 	struct machservice *msi = NULL;
8663 	SLIST_FOREACH(msi, &j->machservices, sle) {
8664 		if (msi->upfront && job_assumes(j, msi->recv)) {
8665 			cnt++;
8666 		}
8667 	}
8668 
8669 	if (cnt == 0) {
8670 		return BOOTSTRAP_UNKNOWN_SERVICE;
8671 	}
8672 
8673 	mach_port_array_t sports2 = NULL;
8674 	mig_allocate((vm_address_t *)&sports2, cnt * sizeof(sports2[0]));
8675 	if (!sports2) {
8676 		RETURN_NO_MEMORY();
8677 	}
8678 
8679 	size_t i = 0;
8680 	SLIST_FOREACH(msi, &j->machservices, sle) {
8681 		if (msi->upfront && msi->recv) {
8682 			sports2[i] = msi->port;
8683 			i++;
8684 		}
8685 	}
8686 
8687 	*sports = sports2;
8688 	*sports_cnt = cnt;
8689 
8690 	return KERN_SUCCESS;
8691 }
8692 
8693 kern_return_t
job_mig_register_gui_session(job_t j,mach_port_t asport)8694 job_mig_register_gui_session(job_t j, mach_port_t asport)
8695 {
8696 	if (!j->per_user) {
8697 		return BOOTSTRAP_NOT_PRIVILEGED;
8698 	}
8699 
8700 	jobmgr_t jm = jobmgr_find_xpc_per_user_domain(root_jobmgr, j->mach_uid);
8701 	if (!jm) {
8702 		return BOOTSTRAP_UNKNOWN_SERVICE;
8703 	}
8704 
8705 	if (jm->req_gui_asport) {
8706 		// This job manager persists, so we need to allow the per-user launchd
8707 		// to update the GUI session as it comes and goes.
8708 		jobmgr_assumes_zero(jm, launchd_mport_deallocate(jm->req_gui_asport));
8709 	}
8710 
8711 	jm->req_gui_asport = asport;
8712 	return KERN_SUCCESS;
8713 }
8714 
8715 kern_return_t
job_mig_reboot2(job_t j,uint64_t flags)8716 job_mig_reboot2(job_t j, uint64_t flags)
8717 {
8718 	char who_started_the_reboot[2048] = "";
8719 	struct proc_bsdshortinfo proc;
8720 	struct ldcred *ldc = runtime_get_caller_creds();
8721 	pid_t pid_to_log;
8722 
8723 	if (!j) {
8724 		RETURN_NO_MEMORY();
8725 	}
8726 
8727 	if (unlikely(!pid1_magic)) {
8728 		return BOOTSTRAP_NOT_PRIVILEGED;
8729 	}
8730 
8731 #if !TARGET_OS_EMBEDDED
8732 	if (unlikely(ldc->euid)) {
8733 #else
8734 	if (unlikely(ldc->euid) && !j->embedded_god) {
8735 #endif
8736 		return BOOTSTRAP_NOT_PRIVILEGED;
8737 	}
8738 
8739 	for (pid_to_log = ldc->pid; pid_to_log; pid_to_log = proc.pbsi_ppid) {
8740 		size_t who_offset;
8741 		if (proc_pidinfo(pid_to_log, PROC_PIDT_SHORTBSDINFO, 1, &proc, PROC_PIDT_SHORTBSDINFO_SIZE) == 0) {
8742 			if (errno != ESRCH) {
8743 				(void)job_assumes_zero(j, errno);
8744 			}
8745 			return 1;
8746 		}
8747 
8748 		if (!job_assumes(j, pid_to_log != (pid_t)proc.pbsi_ppid)) {
8749 			job_log(j, LOG_WARNING, "Job which is its own parent started reboot.");
8750 			snprintf(who_started_the_reboot, sizeof(who_started_the_reboot), "%s[%u]->%s[%u]->%s[%u]->...", proc.pbsi_comm, pid_to_log, proc.pbsi_comm, pid_to_log, proc.pbsi_comm, pid_to_log);
8751 			break;
8752 		}
8753 
8754 		who_offset = strlen(who_started_the_reboot);
8755 		snprintf(who_started_the_reboot + who_offset, sizeof(who_started_the_reboot) - who_offset,
8756 				" %s[%u]%s", proc.pbsi_comm, pid_to_log, proc.pbsi_ppid ? " ->" : "");
8757 	}
8758 
8759 	root_jobmgr->reboot_flags = (int)flags;
8760 
8761 	job_log(j, LOG_DEBUG, "reboot2() initiated by:%s", who_started_the_reboot);
8762 	launchd_shutdown();
8763 
8764 	return 0;
8765 }
8766 
8767 kern_return_t
8768 job_mig_getsocket(job_t j, name_t spr)
8769 {
8770 	if (!j) {
8771 		RETURN_NO_MEMORY();
8772 	}
8773 
8774 	if (j->deny_job_creation) {
8775 		return BOOTSTRAP_NOT_PRIVILEGED;
8776 	}
8777 
8778 #if HAVE_SANDBOX
8779 	struct ldcred *ldc = runtime_get_caller_creds();
8780 	if (unlikely(sandbox_check(ldc->pid, "job-creation", SANDBOX_FILTER_NONE) > 0)) {
8781 		return BOOTSTRAP_NOT_PRIVILEGED;
8782 	}
8783 #endif
8784 
8785 	ipc_server_init();
8786 
8787 	if (unlikely(!sockpath)) {
8788 		RETURN_NO_MEMORY();
8789 	}
8790 
8791 	strncpy(spr, sockpath, sizeof(name_t));
8792 
8793 	return BOOTSTRAP_SUCCESS;
8794 }
8795 
8796 kern_return_t
8797 job_mig_log(job_t j, int pri, int err, logmsg_t msg)
8798 {
8799 	if (!j) {
8800 		RETURN_NO_MEMORY();
8801 	}
8802 
8803 	if ((errno = err)) {
8804 		job_log_error(j, pri, "%s", msg);
8805 	} else {
8806 		job_log(j, pri, "%s", msg);
8807 	}
8808 
8809 	return 0;
8810 }
8811 
8812 void
8813 job_setup_per_user_directory(job_t j, uid_t uid, const char *path)
8814 {
8815 	struct stat sb;
8816 
8817 	bool created = false;
8818 	int r = stat(path, &sb);
8819 	if ((r == -1 && errno == ENOENT) || (r == 0 && !S_ISDIR(sb.st_mode))) {
8820 		if (r == 0) {
8821 			job_log(j, LOG_NOTICE, "File at location of per-user launchd directory is not a directory. Moving aside: %s", path);
8822 
8823 			char old[PATH_MAX];
8824 			snprintf(old, sizeof(old), "%s.movedaside", path);
8825 			(void)job_assumes_zero_p(j, rename(path, old));
8826 		}
8827 
8828 		(void)job_assumes_zero_p(j, mkdir(path, S_IRWXU));
8829 		(void)job_assumes_zero_p(j, chown(path, uid, 0));
8830 		created = true;
8831 	}
8832 
8833 	if (!created) {
8834 		if (sb.st_uid != uid) {
8835 			job_log(j, LOG_NOTICE, "Per-user launchd directory has improper user ownership. Repairing: %s", path);
8836 			(void)job_assumes_zero_p(j, chown(path, uid, 0));
8837 		}
8838 		if (sb.st_gid != 0) {
8839 			job_log(j, LOG_NOTICE, "Per-user launchd directory has improper group ownership. Repairing: %s", path);
8840 			(void)job_assumes_zero_p(j, chown(path, uid, 0));
8841 		}
8842 		if (sb.st_mode != (S_IRWXU | S_IFDIR)) {
8843 			job_log(j, LOG_NOTICE, "Per-user launchd directory has improper mode. Repairing: %s", path);
8844 			(void)job_assumes_zero_p(j, chmod(path, S_IRWXU));
8845 		}
8846 	}
8847 }
8848 
8849 void
8850 job_setup_per_user_directories(job_t j, uid_t uid, const char *label)
8851 {
8852 	char path[PATH_MAX];
8853 
8854 	(void)snprintf(path, sizeof(path), LAUNCHD_DB_PREFIX "/%s", label);
8855 	job_setup_per_user_directory(j, uid, path);
8856 
8857 	(void)snprintf(path, sizeof(path), LAUNCHD_LOG_PREFIX "/%s", label);
8858 	job_setup_per_user_directory(j, uid, path);
8859 }
8860 
8861 job_t
8862 jobmgr_lookup_per_user_context_internal(job_t j, uid_t which_user, mach_port_t *mp)
8863 {
8864 	job_t ji = NULL;
8865 	LIST_FOREACH(ji, &root_jobmgr->jobs, sle) {
8866 		if (!ji->per_user) {
8867 			continue;
8868 		}
8869 		if (ji->mach_uid != which_user) {
8870 			continue;
8871 		}
8872 		if (SLIST_EMPTY(&ji->machservices)) {
8873 			continue;
8874 		}
8875 		if (!SLIST_FIRST(&ji->machservices)->per_user_hack) {
8876 			continue;
8877 		}
8878 		break;
8879 	}
8880 
8881 	if (unlikely(ji == NULL)) {
8882 		struct machservice *ms;
8883 		char lbuf[1024];
8884 
8885 		job_log(j, LOG_DEBUG, "Creating per user launchd job for UID: %u", which_user);
8886 
8887 		sprintf(lbuf, "com.apple.launchd.peruser.%u", which_user);
8888 
8889 		ji = job_new(root_jobmgr, lbuf, "/sbin/launchd", NULL);
8890 
8891 		if (ji != NULL) {
8892 			auditinfo_addr_t auinfo = {
8893 				.ai_termid = {
8894 					.at_type = AU_IPv4
8895 				},
8896 				.ai_auid = which_user,
8897 				.ai_asid = AU_ASSIGN_ASID,
8898 			};
8899 
8900 			if (setaudit_addr(&auinfo, sizeof(auinfo)) == 0) {
8901 				job_log(ji, LOG_DEBUG, "Created new security session for per-user launchd: %u", auinfo.ai_asid);
8902 #ifdef notyet
8903 				(void)job_assumes(ji, (ji->asport = audit_session_self()) != MACH_PORT_NULL);
8904 
8905 				/* Kinda lame that we have to do this, but we can't create an
8906 				 * audit session without joining it.
8907 				 */
8908 				(void)job_assumes(ji, audit_session_join(launchd_audit_port));
8909 #endif
8910 				ji->asid = auinfo.ai_asid;
8911 			} else {
8912 				job_log(ji, LOG_WARNING, "Could not set audit session!");
8913 				job_remove(ji);
8914 				return NULL;
8915 			}
8916 
8917 			ji->mach_uid = which_user;
8918 			ji->per_user = true;
8919 			ji->enable_transactions = true;
8920 			job_setup_per_user_directories(ji, which_user, lbuf);
8921 
8922 			if ((ms = machservice_new(ji, lbuf, mp, false)) == NULL) {
8923 				job_remove(ji);
8924 				ji = NULL;
8925 			} else {
8926 				ms->upfront = true;
8927 				ms->per_user_hack = true;
8928 				ms->hide = true;
8929 
8930 				ji = job_dispatch(ji, false);
8931 			}
8932 		}
8933 	} else {
8934 		*mp = machservice_port(SLIST_FIRST(&ji->machservices));
8935 		job_log(j, LOG_DEBUG, "Per user launchd job found for UID: %u", which_user);
8936 	}
8937 
8938 	return ji;
8939 }
8940 
8941 kern_return_t
8942 job_mig_lookup_per_user_context(job_t j, uid_t which_user, mach_port_t *up_cont)
8943 {
8944 	struct ldcred *ldc = runtime_get_caller_creds();
8945 	job_t jpu;
8946 
8947 	if (!j) {
8948 		RETURN_NO_MEMORY();
8949 	}
8950 
8951 	if (launchd_osinstaller) {
8952 		return BOOTSTRAP_UNKNOWN_SERVICE;
8953 	}
8954 
8955 #if TARGET_OS_EMBEDDED
8956 	// There is no need for per-user launchd's on embedded.
8957 	job_log(j, LOG_ERR, "Per-user launchds are not supported on this platform.");
8958 	return BOOTSTRAP_UNKNOWN_SERVICE;
8959 #endif
8960 
8961 #if HAVE_SANDBOX
8962 	if (unlikely(sandbox_check(ldc->pid, "mach-per-user-lookup", SANDBOX_FILTER_NONE) > 0)) {
8963 		return BOOTSTRAP_NOT_PRIVILEGED;
8964 	}
8965 #endif
8966 
8967 	job_log(j, LOG_INFO, "Looking up per user launchd for UID: %u", which_user);
8968 
8969 	if (unlikely(!pid1_magic)) {
8970 		job_log(j, LOG_ERR, "Only PID 1 supports per user launchd lookups.");
8971 		return BOOTSTRAP_NOT_PRIVILEGED;
8972 	}
8973 
8974 	if (ldc->euid || ldc->uid) {
8975 		which_user = ldc->euid ?: ldc->uid;
8976 	}
8977 
8978 	*up_cont = MACH_PORT_NULL;
8979 
8980 	jpu = jobmgr_lookup_per_user_context_internal(j, which_user, up_cont);
8981 
8982 	return 0;
8983 }
8984 
8985 kern_return_t
8986 job_mig_check_in2(job_t j, name_t servicename, mach_port_t *serviceportp, uuid_t instance_id, uint64_t flags)
8987 {
8988 	bool per_pid_service = flags & BOOTSTRAP_PER_PID_SERVICE;
8989 	bool strict = flags & BOOTSTRAP_STRICT_CHECKIN;
8990 	struct ldcred *ldc = runtime_get_caller_creds();
8991 	struct machservice *ms = NULL;
8992 	job_t jo;
8993 
8994 	if (!j) {
8995 		RETURN_NO_MEMORY();
8996 	}
8997 
8998 	if (j->dedicated_instance) {
8999 		struct machservice *msi = NULL;
9000 		SLIST_FOREACH(msi, &j->machservices, sle) {
9001 			if (strncmp(servicename, msi->name, sizeof(name_t) - 1) == 0) {
9002 				uuid_copy(instance_id, j->instance_id);
9003 				ms = msi;
9004 				break;
9005 			}
9006 		}
9007 	} else {
9008 		ms = jobmgr_lookup_service(j->mgr, servicename, false, per_pid_service ? ldc->pid : 0);
9009 	}
9010 
9011 	if (strict) {
9012 		if (likely(ms != NULL)) {
9013 			if (ms->job != j) {
9014 				return BOOTSTRAP_NOT_PRIVILEGED;
9015 			} else if (ms->isActive) {
9016 				return BOOTSTRAP_SERVICE_ACTIVE;
9017 			}
9018 		} else {
9019 			return BOOTSTRAP_UNKNOWN_SERVICE;
9020 		}
9021 	} else if (ms == NULL) {
9022 		if (job_assumes(j, !j->dedicated_instance)) {
9023 			*serviceportp = MACH_PORT_NULL;
9024 
9025 #if HAVE_SANDBOX
9026 			if (unlikely(sandbox_check(ldc->pid, "mach-register", per_pid_service ? SANDBOX_FILTER_LOCAL_NAME : SANDBOX_FILTER_GLOBAL_NAME, servicename) > 0)) {
9027 				return BOOTSTRAP_NOT_PRIVILEGED;
9028 			}
9029 #endif
9030 			if (unlikely((ms = machservice_new(j, servicename, serviceportp, per_pid_service)) == NULL)) {
9031 				RETURN_NO_MEMORY();
9032 			}
9033 
9034 			// Treat this like a legacy job.
9035 			if (!j->legacy_mach_job) {
9036 				ms->isActive = true;
9037 				ms->recv = false;
9038 			}
9039 
9040 			if (!(j->anonymous || j->legacy_LS_job || j->legacy_mach_job)) {
9041 				job_log(j, LOG_APPLEONLY, "Please add the following service to the configuration file for this job: %s", servicename);
9042 			}
9043 		} else {
9044 			return BOOTSTRAP_UNKNOWN_SERVICE;
9045 		}
9046 	} else {
9047 		if (unlikely((jo = machservice_job(ms)) != j)) {
9048 			static pid_t last_warned_pid;
9049 
9050 			if (last_warned_pid != ldc->pid) {
9051 				job_log(jo, LOG_WARNING, "The following job tried to hijack the service \"%s\" from this job: %s", servicename, j->label);
9052 				last_warned_pid = ldc->pid;
9053 			}
9054 
9055 			return BOOTSTRAP_NOT_PRIVILEGED;
9056 		}
9057 		if (unlikely(machservice_active(ms))) {
9058 			job_log(j, LOG_WARNING, "Check-in of Mach service failed. Already active: %s", servicename);
9059 			return BOOTSTRAP_SERVICE_ACTIVE;
9060 		}
9061 	}
9062 
9063 	job_checkin(j);
9064 	machservice_request_notifications(ms);
9065 
9066 	job_log(j, LOG_INFO, "Check-in of service: %s", servicename);
9067 
9068 	*serviceportp = machservice_port(ms);
9069 	return BOOTSTRAP_SUCCESS;
9070 }
9071 
9072 kern_return_t
9073 job_mig_register2(job_t j, name_t servicename, mach_port_t serviceport, uint64_t flags)
9074 {
9075 	struct machservice *ms;
9076 	struct ldcred *ldc = runtime_get_caller_creds();
9077 	bool per_pid_service = flags & BOOTSTRAP_PER_PID_SERVICE;
9078 
9079 	if (!j) {
9080 		RETURN_NO_MEMORY();
9081 	}
9082 
9083 	if (!per_pid_service && !j->legacy_LS_job) {
9084 		job_log(j, LOG_APPLEONLY, "Performance: bootstrap_register() is deprecated. Service: %s", servicename);
9085 	}
9086 
9087 	job_log(j, LOG_DEBUG, "%sMach service registration attempt: %s", flags & BOOTSTRAP_PER_PID_SERVICE ? "Per PID " : "", servicename);
9088 
9089 #if HAVE_SANDBOX
9090 	if (unlikely(sandbox_check(ldc->pid, "mach-register", per_pid_service ? SANDBOX_FILTER_LOCAL_NAME : SANDBOX_FILTER_GLOBAL_NAME, servicename) > 0)) {
9091 		return BOOTSTRAP_NOT_PRIVILEGED;
9092 	}
9093 #endif
9094 
9095 	// 5641783 for the embedded hack
9096 #if !TARGET_OS_EMBEDDED
9097 	/*
9098 	 * From a per-user/session launchd's perspective, SecurityAgent (UID
9099 	 * 92) is a rogue application (not our UID, not root and not a child of
9100 	 * us). We'll have to reconcile this design friction at a later date.
9101 	 */
9102 	if (unlikely(j->anonymous && j->mgr->parentmgr == NULL && ldc->uid != 0 && ldc->uid != getuid() && ldc->uid != 92)) {
9103 		if (pid1_magic) {
9104 			return VPROC_ERR_TRY_PER_USER;
9105 		} else {
9106 			return BOOTSTRAP_NOT_PRIVILEGED;
9107 		}
9108 	}
9109 #endif
9110 
9111 	ms = jobmgr_lookup_service(j->mgr, servicename, false, flags & BOOTSTRAP_PER_PID_SERVICE ? ldc->pid : 0);
9112 
9113 	if (unlikely(ms)) {
9114 		if (machservice_job(ms) != j) {
9115 			return BOOTSTRAP_NOT_PRIVILEGED;
9116 		}
9117 		if (machservice_active(ms)) {
9118 			job_log(j, LOG_DEBUG, "Mach service registration failed. Already active: %s", servicename);
9119 			return BOOTSTRAP_SERVICE_ACTIVE;
9120 		}
9121 		if (ms->recv && (serviceport != MACH_PORT_NULL)) {
9122 			job_log(j, LOG_ERR, "bootstrap_register() erroneously called instead of bootstrap_check_in(). Mach service: %s", servicename);
9123 			return BOOTSTRAP_NOT_PRIVILEGED;
9124 		}
9125 		job_checkin(j);
9126 		machservice_delete(j, ms, false);
9127 	}
9128 
9129 	if (likely(serviceport != MACH_PORT_NULL)) {
9130 		if (likely(ms = machservice_new(j, servicename, &serviceport, flags & BOOTSTRAP_PER_PID_SERVICE ? true : false))) {
9131 			machservice_request_notifications(ms);
9132 		} else {
9133 			RETURN_NO_MEMORY();
9134 		}
9135 	}
9136 
9137 
9138 	return BOOTSTRAP_SUCCESS;
9139 }
9140 
9141 kern_return_t
9142 job_mig_look_up2(job_t j, mach_port_t srp, name_t servicename, mach_port_t *serviceportp, pid_t target_pid, uuid_t instance_id, uint64_t flags)
9143 {
9144 	struct machservice *ms = NULL;
9145 	struct ldcred *ldc = runtime_get_caller_creds();
9146 	kern_return_t kr;
9147 	bool per_pid_lookup = flags & BOOTSTRAP_PER_PID_SERVICE;
9148 	bool specific_instance = flags & BOOTSTRAP_SPECIFIC_INSTANCE;
9149 	bool strict_lookup = flags & BOOTSTRAP_STRICT_LOOKUP;
9150 	bool privileged = flags & BOOTSTRAP_PRIVILEGED_SERVER;
9151 
9152 	if (!j) {
9153 		RETURN_NO_MEMORY();
9154 	}
9155 
9156 	bool xpc_req = (j->mgr->properties & BOOTSTRAP_PROPERTY_XPC_DOMAIN);
9157 
9158 	// 5641783 for the embedded hack
9159 #if !TARGET_OS_EMBEDDED
9160 	if (unlikely(pid1_magic && j->anonymous && j->mgr->parentmgr == NULL && ldc->uid != 0 && ldc->euid != 0)) {
9161 		return VPROC_ERR_TRY_PER_USER;
9162 	}
9163 #endif
9164 
9165 #if HAVE_SANDBOX
9166 	/* We don't do sandbox checking for XPC domains because, by definition, all
9167 	 * the services within your domain should be accessible to you.
9168 	 */
9169 	if (!xpc_req && unlikely(sandbox_check(ldc->pid, "mach-lookup", per_pid_lookup ? SANDBOX_FILTER_LOCAL_NAME : SANDBOX_FILTER_GLOBAL_NAME, servicename) > 0)) {
9170 		return BOOTSTRAP_NOT_PRIVILEGED;
9171 	}
9172 #endif
9173 
9174 	if (per_pid_lookup) {
9175 		ms = jobmgr_lookup_service(j->mgr, servicename, false, target_pid);
9176 	} else {
9177 		if (xpc_req) {
9178 			// Requests from XPC domains stay local.
9179 			ms = jobmgr_lookup_service(j->mgr, servicename, false, 0);
9180 		} else {
9181 			/* A strict lookup which is privileged won't even bother trying to
9182 			 * find a service if we're not hosting the root Mach bootstrap.
9183 			 */
9184 			if (strict_lookup && privileged) {
9185 				if (inherited_bootstrap_port == MACH_PORT_NULL) {
9186 					ms = jobmgr_lookup_service(j->mgr, servicename, true, 0);
9187 				}
9188 			} else {
9189 				ms = jobmgr_lookup_service(j->mgr, servicename, true, 0);
9190 			}
9191 		}
9192 	}
9193 
9194 	if (likely(ms)) {
9195 		ms = ms->alias ? ms->alias : ms;
9196 		if (unlikely(specific_instance && ms->job->multiple_instances)) {
9197 			job_t ji = NULL;
9198 			job_t instance = NULL;
9199 			LIST_FOREACH(ji, &ms->job->subjobs, subjob_sle) {
9200 				if (uuid_compare(instance_id, ji->instance_id) == 0) {
9201 					instance = ji;
9202 					break;
9203 				}
9204 			}
9205 
9206 			if (unlikely(instance == NULL)) {
9207 				job_log(ms->job, LOG_DEBUG, "Creating new instance of job based on lookup of service %s", ms->name);
9208 				instance = job_new_subjob(ms->job, instance_id);
9209 				if (job_assumes(j, instance != NULL)) {
9210 					/* Disable this support for now. We only support having
9211 					 * multi-instance jobs within private XPC domains.
9212 					 */
9213 #if 0
9214 					/* If the job is multi-instance, in a singleton XPC domain
9215 					 * and the request is not coming from within that singleton
9216 					 * domain, we need to alias the new job into the requesting
9217 					 * domain.
9218 					 */
9219 					if (!j->mgr->xpc_singleton && xpc_req) {
9220 						(void)job_assumes(instance, job_new_alias(j->mgr, instance));
9221 					}
9222 #endif
9223 					job_dispatch(instance, false);
9224 				}
9225 			}
9226 
9227 			ms = NULL;
9228 			if (job_assumes(j, instance != NULL)) {
9229 				struct machservice *msi = NULL;
9230 				SLIST_FOREACH(msi, &instance->machservices, sle) {
9231 					/* sizeof(servicename) will return the size of a pointer,
9232 					 * even though it's an array type, because when passing
9233 					 * arrays as parameters in C, they implicitly degrade to
9234 					 * pointers.
9235 					 */
9236 					if (strncmp(servicename, msi->name, sizeof(name_t) - 1) == 0) {
9237 						ms = msi;
9238 						break;
9239 					}
9240 				}
9241 			}
9242 		} else {
9243 			if (machservice_hidden(ms) && !machservice_active(ms)) {
9244 				ms = NULL;
9245 			} else if (unlikely(ms->per_user_hack)) {
9246 				ms = NULL;
9247 			}
9248 		}
9249 	}
9250 
9251 	if (likely(ms)) {
9252 		(void)job_assumes(j, machservice_port(ms) != MACH_PORT_NULL);
9253 		job_log(j, LOG_DEBUG, "%sMach service lookup: %s", per_pid_lookup ? "Per PID " : "", servicename);
9254 		*serviceportp = machservice_port(ms);
9255 
9256 		job_log(j, LOG_DEBUG, "Service port: <%d>\n", *serviceportp);
9257 
9258 		kr = BOOTSTRAP_SUCCESS;
9259 	} else if (strict_lookup && !privileged) {
9260 		/* Hack: We need to simulate XPC's desire not to establish a hierarchy.
9261 		 * So if XPC is doing the lookup, and it's not a privileged lookup, we
9262 		 * won't forward. But if it is a privileged lookup, then we must
9263 		 * forward.
9264 		 */
9265 		return BOOTSTRAP_UNKNOWN_SERVICE;
9266 	} else if (inherited_bootstrap_port != MACH_PORT_NULL) {
9267 		// Requests from within an XPC domain don't get forwarded.
9268 		job_log(j, LOG_DEBUG, "Mach service lookup forwarded: %s", servicename);
9269 		/* Clients potentially check the audit token of the reply to verify that
9270 		 * the returned send right is trustworthy.
9271 		 */
9272 		(void)job_assumes_zero(j, vproc_mig_look_up2_forward(inherited_bootstrap_port, srp, servicename, target_pid, instance_id, flags));
9273 		return MIG_NO_REPLY;
9274 	} else if (pid1_magic && j->anonymous && ldc->euid >= 500 && strcasecmp(j->mgr->name, VPROCMGR_SESSION_LOGINWINDOW) == 0) {
9275 		/* 5240036 Should start background session when a lookup of CCacheServer
9276 		 * occurs
9277 		 *
9278 		 * This is a total hack. We sniff out loginwindow session, and attempt
9279 		 * to guess what it is up to. If we find a EUID that isn't root, we
9280 		 * force it over to the per-user context.
9281 		 */
9282 		return VPROC_ERR_TRY_PER_USER;
9283 	} else {
9284 		job_log(j, LOG_DEBUG, "%sMach service lookup failed: %s", per_pid_lookup ? "Per PID " : "", servicename);
9285 		kr = BOOTSTRAP_UNKNOWN_SERVICE;
9286 	}
9287 
9288 	return kr;
9289 }
9290 
9291 kern_return_t
9292 job_mig_parent(job_t j, mach_port_t srp, mach_port_t *parentport)
9293 {
9294 	if (!j) {
9295 		RETURN_NO_MEMORY();
9296 	}
9297 
9298 	job_log(j, LOG_DEBUG, "Requested parent bootstrap port");
9299 	jobmgr_t jm = j->mgr;
9300 
9301 	if (jobmgr_parent(jm)) {
9302 		*parentport = jobmgr_parent(jm)->jm_port;
9303 	} else if (MACH_PORT_NULL == inherited_bootstrap_port) {
9304 		*parentport = jm->jm_port;
9305 	} else {
9306 		(void)job_assumes_zero(j, vproc_mig_parent_forward(inherited_bootstrap_port, srp));
9307 		// The previous routine moved the reply port, we're forced to return MIG_NO_REPLY now
9308 		return MIG_NO_REPLY;
9309 	}
9310 	return BOOTSTRAP_SUCCESS;
9311 }
9312 
9313 kern_return_t
9314 job_mig_get_root_bootstrap(job_t j, mach_port_t *rootbsp)
9315 {
9316 	if (!j) {
9317 		RETURN_NO_MEMORY();
9318 	}
9319 
9320 	if (inherited_bootstrap_port == MACH_PORT_NULL) {
9321 		*rootbsp = root_jobmgr->jm_port;
9322 		(void)job_assumes_zero(j, launchd_mport_make_send(root_jobmgr->jm_port));
9323 	} else {
9324 		*rootbsp = inherited_bootstrap_port;
9325 		(void)job_assumes_zero(j, launchd_mport_copy_send(inherited_bootstrap_port));
9326 	}
9327 
9328 	return BOOTSTRAP_SUCCESS;
9329 }
9330 
9331 kern_return_t
9332 job_mig_info(job_t j, name_array_t *servicenamesp,
9333 	unsigned int *servicenames_cnt, name_array_t *servicejobsp,
9334 	unsigned int *servicejobs_cnt, bootstrap_status_array_t *serviceactivesp,
9335 	unsigned int *serviceactives_cnt, uint64_t flags)
9336 {
9337 	name_array_t service_names = NULL;
9338 	name_array_t service_jobs = NULL;
9339 	bootstrap_status_array_t service_actives = NULL;
9340 	unsigned int cnt = 0, cnt2 = 0;
9341 	jobmgr_t jm;
9342 
9343 	if (!j) {
9344 		RETURN_NO_MEMORY();
9345 	}
9346 
9347 #if TARGET_OS_EMBEDDED
9348 	struct ldcred *ldc = runtime_get_caller_creds();
9349 	if (ldc->euid) {
9350 		return EPERM;
9351 	}
9352 #endif // TARGET_OS_EMBEDDED
9353 
9354 	if (launchd_flat_mach_namespace) {
9355 		if ((j->mgr->properties & BOOTSTRAP_PROPERTY_EXPLICITSUBSET) || (flags & BOOTSTRAP_FORCE_LOCAL)) {
9356 			jm = j->mgr;
9357 		} else {
9358 			jm = root_jobmgr;
9359 		}
9360 	} else {
9361 		jm = j->mgr;
9362 	}
9363 
9364 	unsigned int i = 0;
9365 	struct machservice *msi = NULL;
9366 	for (i = 0; i < MACHSERVICE_HASH_SIZE; i++) {
9367 		LIST_FOREACH(msi, &jm->ms_hash[i], name_hash_sle) {
9368 			cnt += !msi->per_pid ? 1 : 0;
9369 		}
9370 	}
9371 
9372 	if (cnt == 0) {
9373 		goto out;
9374 	}
9375 
9376 	mig_allocate((vm_address_t *)&service_names, cnt * sizeof(service_names[0]));
9377 	if (!job_assumes(j, service_names != NULL)) {
9378 		goto out_bad;
9379 	}
9380 
9381 	mig_allocate((vm_address_t *)&service_jobs, cnt * sizeof(service_jobs[0]));
9382 	if (!job_assumes(j, service_jobs != NULL)) {
9383 		goto out_bad;
9384 	}
9385 
9386 	mig_allocate((vm_address_t *)&service_actives, cnt * sizeof(service_actives[0]));
9387 	if (!job_assumes(j, service_actives != NULL)) {
9388 		goto out_bad;
9389 	}
9390 
9391 	for (i = 0; i < MACHSERVICE_HASH_SIZE; i++) {
9392 		LIST_FOREACH(msi, &jm->ms_hash[i], name_hash_sle) {
9393 			if (!msi->per_pid) {
9394 				strlcpy(service_names[cnt2], machservice_name(msi), sizeof(service_names[0]));
9395 				msi = msi->alias ? msi->alias : msi;
9396 				if (msi->job->mgr->shortdesc) {
9397 					strlcpy(service_jobs[cnt2], msi->job->mgr->shortdesc, sizeof(service_jobs[0]));
9398 				} else {
9399 					strlcpy(service_jobs[cnt2], msi->job->label, sizeof(service_jobs[0]));
9400 				}
9401 				service_actives[cnt2] = machservice_status(msi);
9402 				cnt2++;
9403 			}
9404 		}
9405 	}
9406 
9407 	(void)job_assumes(j, cnt == cnt2);
9408 
9409 out:
9410 	*servicenamesp = service_names;
9411 	*servicejobsp = service_jobs;
9412 	*serviceactivesp = service_actives;
9413 	*servicenames_cnt = *servicejobs_cnt = *serviceactives_cnt = cnt;
9414 
9415 	return BOOTSTRAP_SUCCESS;
9416 
9417 out_bad:
9418 	if (service_names) {
9419 		mig_deallocate((vm_address_t)service_names, cnt * sizeof(service_names[0]));
9420 	}
9421 	if (service_jobs) {
9422 		mig_deallocate((vm_address_t)service_jobs, cnt * sizeof(service_jobs[0]));
9423 	}
9424 	if (service_actives) {
9425 		mig_deallocate((vm_address_t)service_actives, cnt * sizeof(service_actives[0]));
9426 	}
9427 
9428 	RETURN_NO_MEMORY();
9429 }
9430 
9431 kern_return_t
9432 job_mig_lookup_children(job_t j, mach_port_array_t *child_ports,
9433 	mach_msg_type_number_t *child_ports_cnt, name_array_t *child_names,
9434 	mach_msg_type_number_t *child_names_cnt,
9435 	bootstrap_property_array_t *child_properties,
9436 	mach_msg_type_number_t *child_properties_cnt)
9437 {
9438 	kern_return_t kr = BOOTSTRAP_NO_MEMORY;
9439 	if (!j) {
9440 		RETURN_NO_MEMORY();
9441 	}
9442 
9443 	struct ldcred *ldc = runtime_get_caller_creds();
9444 
9445 	/* Only allow root processes to look up children, even if we're in the per-user launchd.
9446 	 * Otherwise, this could be used to cross sessions, which counts as a security vulnerability
9447 	 * in a non-flat namespace.
9448 	 */
9449 	if (ldc->euid != 0) {
9450 		job_log(j, LOG_WARNING, "Attempt to look up children of bootstrap by unprivileged job.");
9451 		return BOOTSTRAP_NOT_PRIVILEGED;
9452 	}
9453 
9454 	unsigned int cnt = 0;
9455 
9456 	jobmgr_t jmr = j->mgr;
9457 	jobmgr_t jmi = NULL;
9458 	SLIST_FOREACH(jmi, &jmr->submgrs, sle) {
9459 		cnt++;
9460 	}
9461 
9462 	// Find our per-user launchds if we're PID 1.
9463 	job_t ji = NULL;
9464 	if (pid1_magic) {
9465 		LIST_FOREACH(ji, &jmr->jobs, sle) {
9466 			cnt += ji->per_user ? 1 : 0;
9467 		}
9468 	}
9469 
9470 	if (cnt == 0) {
9471 		return BOOTSTRAP_NO_CHILDREN;
9472 	}
9473 
9474 	mach_port_array_t _child_ports = NULL;
9475 	name_array_t _child_names = NULL;
9476 	bootstrap_property_array_t _child_properties = NULL;
9477 
9478 	mig_allocate((vm_address_t *)&_child_ports, cnt * sizeof(_child_ports[0]));
9479 	if (!job_assumes(j, _child_ports != NULL)) {
9480 		kr = BOOTSTRAP_NO_MEMORY;
9481 		goto out_bad;
9482 	}
9483 
9484 	mig_allocate((vm_address_t *)&_child_names, cnt * sizeof(_child_names[0]));
9485 	if (!job_assumes(j, _child_names != NULL)) {
9486 		kr = BOOTSTRAP_NO_MEMORY;
9487 		goto out_bad;
9488 	}
9489 
9490 	mig_allocate((vm_address_t *)&_child_properties, cnt * sizeof(_child_properties[0]));
9491 	if (!job_assumes(j, _child_properties != NULL)) {
9492 		kr = BOOTSTRAP_NO_MEMORY;
9493 		goto out_bad;
9494 	}
9495 
9496 	unsigned int cnt2 = 0;
9497 	SLIST_FOREACH(jmi, &jmr->submgrs, sle) {
9498 		if (jobmgr_assumes_zero(jmi, launchd_mport_make_send(jmi->jm_port)) == KERN_SUCCESS) {
9499 			_child_ports[cnt2] = jmi->jm_port;
9500 		} else {
9501 			_child_ports[cnt2] = MACH_PORT_NULL;
9502 		}
9503 
9504 		strlcpy(_child_names[cnt2], jmi->name, sizeof(_child_names[0]));
9505 		_child_properties[cnt2] = jmi->properties;
9506 
9507 		cnt2++;
9508 	}
9509 
9510 	if (pid1_magic) LIST_FOREACH(ji, &jmr->jobs, sle) {
9511 		if (ji->per_user) {
9512 			if (job_assumes(ji, SLIST_FIRST(&ji->machservices)->per_user_hack == true)) {
9513 				mach_port_t port = machservice_port(SLIST_FIRST(&ji->machservices));
9514 
9515 				if (job_assumes_zero(ji, launchd_mport_copy_send(port)) == KERN_SUCCESS) {
9516 					_child_ports[cnt2] = port;
9517 				} else {
9518 					_child_ports[cnt2] = MACH_PORT_NULL;
9519 				}
9520 			} else {
9521 				_child_ports[cnt2] = MACH_PORT_NULL;
9522 			}
9523 
9524 			strlcpy(_child_names[cnt2], ji->label, sizeof(_child_names[0]));
9525 			_child_properties[cnt2] |= BOOTSTRAP_PROPERTY_PERUSER;
9526 
9527 			cnt2++;
9528 		}
9529 	}
9530 
9531 	*child_names_cnt = cnt;
9532 	*child_ports_cnt = cnt;
9533 	*child_properties_cnt = cnt;
9534 
9535 	*child_names = _child_names;
9536 	*child_ports = _child_ports;
9537 	*child_properties = _child_properties;
9538 
9539 	unsigned int i = 0;
9540 	for (i = 0; i < cnt; i++) {
9541 		job_log(j, LOG_DEBUG, "child_names[%u] = %s", i, (char *)_child_names[i]);
9542 	}
9543 
9544 	return BOOTSTRAP_SUCCESS;
9545 out_bad:
9546 	if (_child_ports) {
9547 		mig_deallocate((vm_address_t)_child_ports, cnt * sizeof(_child_ports[0]));
9548 	}
9549 
9550 	if (_child_names) {
9551 		mig_deallocate((vm_address_t)_child_names, cnt * sizeof(_child_names[0]));
9552 	}
9553 
9554 	if (_child_properties) {
9555 		mig_deallocate((vm_address_t)_child_properties, cnt * sizeof(_child_properties[0]));
9556 	}
9557 
9558 	return kr;
9559 }
9560 
9561 kern_return_t
9562 job_mig_pid_is_managed(job_t j __attribute__((unused)), pid_t p, boolean_t *managed)
9563 {
9564 	struct ldcred *ldc = runtime_get_caller_creds();
9565 	if ((ldc->euid != geteuid()) && (ldc->euid != 0)) {
9566 		return BOOTSTRAP_NOT_PRIVILEGED;
9567 	}
9568 
9569 	/* This is so loginwindow doesn't try to quit GUI apps that have been launched
9570 	 * directly by launchd as agents.
9571 	 */
9572 	job_t j_for_pid = jobmgr_find_by_pid_deep(root_jobmgr, p, false);
9573 	if (j_for_pid && !j_for_pid->anonymous && !j_for_pid->legacy_LS_job) {
9574 		*managed = true;
9575 	}
9576 
9577 	return BOOTSTRAP_SUCCESS;
9578 }
9579 
9580 kern_return_t
9581 job_mig_port_for_label(job_t j __attribute__((unused)), name_t label, mach_port_t *mp)
9582 {
9583 	if (!j) {
9584 		RETURN_NO_MEMORY();
9585 	}
9586 
9587 	struct ldcred *ldc = runtime_get_caller_creds();
9588 	kern_return_t kr = BOOTSTRAP_NOT_PRIVILEGED;
9589 
9590 #if HAVE_SANDBOX
9591 	if (unlikely(sandbox_check(ldc->pid, "job-creation", SANDBOX_FILTER_NONE) > 0)) {
9592 		return BOOTSTRAP_NOT_PRIVILEGED;
9593 	}
9594 #endif
9595 
9596 	mach_port_t _mp = MACH_PORT_NULL;
9597 	if (!j->deny_job_creation && (ldc->euid == 0 || ldc->euid == geteuid())) {
9598 		job_t target_j = job_find(NULL, label);
9599 		if (jobmgr_assumes(root_jobmgr, target_j != NULL)) {
9600 			if (target_j->j_port == MACH_PORT_NULL) {
9601 				(void)job_assumes(target_j, job_setup_machport(target_j) == true);
9602 			}
9603 
9604 			_mp = target_j->j_port;
9605 			kr = _mp != MACH_PORT_NULL ? BOOTSTRAP_SUCCESS : BOOTSTRAP_NO_MEMORY;
9606 		} else {
9607 			kr = BOOTSTRAP_NO_MEMORY;
9608 		}
9609 	}
9610 
9611 	*mp = _mp;
9612 	return kr;
9613 }
9614 
9615 kern_return_t
9616 job_mig_set_security_session(job_t j, uuid_t uuid, mach_port_t asport)
9617 {
9618 #if TARGET_OS_EMBEDDED
9619 	return KERN_SUCCESS;
9620 #endif
9621 
9622 	if (!j) {
9623 		RETURN_NO_MEMORY();
9624 	}
9625 
9626 	uuid_string_t uuid_str;
9627 	uuid_unparse(uuid, uuid_str);
9628 	job_log(j, LOG_DEBUG, "Setting session %u for UUID %s...", asport, uuid_str);
9629 
9630 	job_t ji = NULL, jt = NULL;
9631 	LIST_FOREACH_SAFE(ji, &s_needing_sessions, sle, jt) {
9632 		uuid_string_t uuid_str2;
9633 		uuid_unparse(ji->expected_audit_uuid, uuid_str2);
9634 
9635 		if (uuid_compare(uuid, ji->expected_audit_uuid) == 0) {
9636 			uuid_clear(ji->expected_audit_uuid);
9637 			if (asport != MACH_PORT_NULL) {
9638 				job_log(ji, LOG_DEBUG, "Job should join session with port 0x%x", asport);
9639 				(void)job_assumes_zero(j, launchd_mport_copy_send(asport));
9640 			} else {
9641 				job_log(ji, LOG_DEBUG, "No session to set for job. Using our session.");
9642 			}
9643 
9644 			ji->asport = asport;
9645 			LIST_REMOVE(ji, needing_session_sle);
9646 
9647 			if (ji->event_monitor) {
9648 				eventsystem_ping();
9649 			} else {
9650 				job_dispatch(ji, false);
9651 			}
9652 		}
9653 	}
9654 
9655 	/* Each job that the session port was set for holds a reference. At the end of
9656 	 * the loop, there will be one extra reference belonging to this MiG protocol.
9657 	 * We need to release it so that the session goes away when all the jobs
9658 	 * referencing it are unloaded.
9659 	 */
9660 	(void)job_assumes_zero(j, launchd_mport_deallocate(asport));
9661 
9662 	return KERN_SUCCESS;
9663 }
9664 
9665 jobmgr_t
9666 jobmgr_find_by_name(jobmgr_t jm, const char *where)
9667 {
9668 	jobmgr_t jmi, jmi2;
9669 
9670 	// NULL is only passed for our custom API for LaunchServices. If that is the case, we do magic.
9671 	if (where == NULL) {
9672 		if (strcasecmp(jm->name, VPROCMGR_SESSION_LOGINWINDOW) == 0) {
9673 			where = VPROCMGR_SESSION_LOGINWINDOW;
9674 		} else {
9675 			where = VPROCMGR_SESSION_AQUA;
9676 		}
9677 	}
9678 
9679 	if (strcasecmp(jm->name, where) == 0) {
9680 		return jm;
9681 	}
9682 
9683 	if (strcasecmp(where, VPROCMGR_SESSION_BACKGROUND) == 0 && !pid1_magic) {
9684 		jmi = root_jobmgr;
9685 		goto jm_found;
9686 	}
9687 
9688 	SLIST_FOREACH(jmi, &root_jobmgr->submgrs, sle) {
9689 		if (unlikely(jmi->shutting_down)) {
9690 			continue;
9691 		} else if (jmi->properties & BOOTSTRAP_PROPERTY_XPC_DOMAIN) {
9692 			continue;
9693 		} else if (strcasecmp(jmi->name, where) == 0) {
9694 			goto jm_found;
9695 		} else if (strcasecmp(jmi->name, VPROCMGR_SESSION_BACKGROUND) == 0 && pid1_magic) {
9696 			SLIST_FOREACH(jmi2, &jmi->submgrs, sle) {
9697 				if (strcasecmp(jmi2->name, where) == 0) {
9698 					jmi = jmi2;
9699 					goto jm_found;
9700 				}
9701 			}
9702 		}
9703 	}
9704 
9705 jm_found:
9706 	return jmi;
9707 }
9708 
9709 kern_return_t
9710 job_mig_move_subset(job_t j, mach_port_t target_subset, name_t session_type, mach_port_t asport, uint64_t flags)
9711 {
9712 	mach_msg_type_number_t l2l_i, l2l_port_cnt = 0;
9713 	mach_port_array_t l2l_ports = NULL;
9714 	mach_port_t reqport, rcvright;
9715 	kern_return_t kr = 1;
9716 	launch_data_t out_obj_array = NULL;
9717 	struct ldcred *ldc = runtime_get_caller_creds();
9718 	jobmgr_t jmr = NULL;
9719 
9720 	if (!j) {
9721 		RETURN_NO_MEMORY();
9722 	}
9723 
9724 	if (job_mig_intran2(root_jobmgr, target_subset, ldc->pid)) {
9725 		job_log(j, LOG_ERR, "Moving a session to ourself is bogus.");
9726 
9727 		kr = BOOTSTRAP_NOT_PRIVILEGED;
9728 		goto out;
9729 	}
9730 
9731 	job_log(j, LOG_DEBUG, "Move subset attempt: 0x%x", target_subset);
9732 
9733 	kr = _vproc_grab_subset(target_subset, &reqport, &rcvright, &out_obj_array, &l2l_ports, &l2l_port_cnt);
9734 	if (job_assumes_zero(j, kr) != 0) {
9735 		goto out;
9736 	}
9737 
9738 	if (launch_data_array_get_count(out_obj_array) != l2l_port_cnt) {
9739 		os_assert_zero(l2l_port_cnt);
9740 	}
9741 
9742 	if (!job_assumes(j, (jmr = jobmgr_new(j->mgr, reqport, rcvright, false, session_type, false, asport)) != NULL)) {
9743 		kr = BOOTSTRAP_NO_MEMORY;
9744 		goto out;
9745 	}
9746 
9747 	if (strcmp(session_type, VPROCMGR_SESSION_AQUA) == 0) {
9748 		jobmgr_log(jmr, LOG_NOTICE, "Registering new GUI session.");
9749 		kr = vproc_mig_register_gui_session(inherited_bootstrap_port, asport);
9750 		if (kr) {
9751 			jobmgr_log(jmr, LOG_ERR, "Failed to register GUI session with PID 1: 0x%x/0x%x", inherited_bootstrap_port, kr);
9752 		}
9753 	}
9754 
9755 	jmr->properties |= BOOTSTRAP_PROPERTY_MOVEDSUBSET;
9756 
9757 	/* This is a hack. We should be doing this in jobmgr_new(), but since we're in the middle of
9758 	 * processing an IPC request, we'll do this action before the new job manager can get any IPC
9759 	 * requests. This serialization is guaranteed since we are single-threaded in that respect.
9760 	 */
9761 	if (flags & LAUNCH_GLOBAL_ON_DEMAND) {
9762 		// This is so awful.
9763 		// Remove the job from its current job manager.
9764 		LIST_REMOVE(j, sle);
9765 		LIST_REMOVE(j, pid_hash_sle);
9766 
9767 		// Put the job into the target job manager.
9768 		LIST_INSERT_HEAD(&jmr->jobs, j, sle);
9769 		LIST_INSERT_HEAD(&jmr->active_jobs[ACTIVE_JOB_HASH(j->p)], j, pid_hash_sle);
9770 
9771 		j->mgr = jmr;
9772 		job_set_global_on_demand(j, true);
9773 
9774 		if (!j->holds_ref) {
9775 			job_log(j, LOG_PERF, "Job moved subset into: %s", j->mgr->name);
9776 			j->holds_ref = true;
9777 			runtime_add_ref();
9778 		}
9779 	}
9780 
9781 	for (l2l_i = 0; l2l_i < l2l_port_cnt; l2l_i++) {
9782 		launch_data_t tmp, obj_at_idx;
9783 		struct machservice *ms;
9784 		job_t j_for_service;
9785 		const char *serv_name;
9786 		pid_t target_pid;
9787 		bool serv_perpid;
9788 
9789 		(void)job_assumes(j, obj_at_idx = launch_data_array_get_index(out_obj_array, l2l_i));
9790 		(void)job_assumes(j, tmp = launch_data_dict_lookup(obj_at_idx, TAKE_SUBSET_PID));
9791 		target_pid = (pid_t)launch_data_get_integer(tmp);
9792 		(void)job_assumes(j, tmp = launch_data_dict_lookup(obj_at_idx, TAKE_SUBSET_PERPID));
9793 		serv_perpid = launch_data_get_bool(tmp);
9794 		(void)job_assumes(j, tmp = launch_data_dict_lookup(obj_at_idx, TAKE_SUBSET_NAME));
9795 		serv_name = launch_data_get_string(tmp);
9796 
9797 		j_for_service = jobmgr_find_by_pid(jmr, target_pid, true);
9798 
9799 		if (unlikely(!j_for_service)) {
9800 			// The PID probably exited
9801 			(void)job_assumes_zero(j, launchd_mport_deallocate(l2l_ports[l2l_i]));
9802 			continue;
9803 		}
9804 
9805 		if (likely(ms = machservice_new(j_for_service, serv_name, &l2l_ports[l2l_i], serv_perpid))) {
9806 			job_log(j, LOG_DEBUG, "Importing %s into new bootstrap.", serv_name);
9807 			machservice_request_notifications(ms);
9808 		}
9809 	}
9810 
9811 	kr = 0;
9812 
9813 out:
9814 	if (out_obj_array) {
9815 		launch_data_free(out_obj_array);
9816 	}
9817 
9818 	if (l2l_ports) {
9819 		mig_deallocate((vm_address_t)l2l_ports, l2l_port_cnt * sizeof(l2l_ports[0]));
9820 	}
9821 
9822 	if (kr == 0) {
9823 		if (target_subset) {
9824 			(void)job_assumes_zero(j, launchd_mport_deallocate(target_subset));
9825 		}
9826 		if (asport) {
9827 			(void)job_assumes_zero(j, launchd_mport_deallocate(asport));
9828 		}
9829 	} else if (jmr) {
9830 		jobmgr_shutdown(jmr);
9831 	}
9832 
9833 	return kr;
9834 }
9835 
9836 kern_return_t
9837 job_mig_init_session(job_t j, name_t session_type, mach_port_t asport)
9838 {
9839 	if (!j) {
9840 		RETURN_NO_MEMORY();
9841 	}
9842 
9843 	job_t j2;
9844 
9845 	kern_return_t kr = BOOTSTRAP_NO_MEMORY;
9846 	if (j->mgr->session_initialized) {
9847 		job_log(j, LOG_ERR, "Tried to initialize an already setup session!");
9848 		kr = BOOTSTRAP_NOT_PRIVILEGED;
9849 		return kr;
9850 	} else if (strcmp(session_type, VPROCMGR_SESSION_LOGINWINDOW) == 0) {
9851 		jobmgr_t jmi;
9852 
9853 		/*
9854 		 * 5330262
9855 		 *
9856 		 * We're working around LoginWindow and the WindowServer.
9857 		 *
9858 		 * In practice, there is only one LoginWindow session. Unfortunately, for certain
9859 		 * scenarios, the WindowServer spawns loginwindow, and in those cases, it frequently
9860 		 * spawns a replacement loginwindow session before cleaning up the previous one.
9861 		 *
9862 		 * We're going to use the creation of a new LoginWindow context as a clue that the
9863 		 * previous LoginWindow context is on the way out and therefore we should just
9864 		 * kick-start the shutdown of it.
9865 		 */
9866 
9867 		SLIST_FOREACH(jmi, &root_jobmgr->submgrs, sle) {
9868 			if (unlikely(jmi->shutting_down)) {
9869 				continue;
9870 			} else if (strcasecmp(jmi->name, session_type) == 0) {
9871 				jobmgr_shutdown(jmi);
9872 				break;
9873 			}
9874 		}
9875 	} else if (strcmp(session_type, VPROCMGR_SESSION_AQUA) == 0) {
9876 		(void)job_assumes_zero(j, runtime_remove_mport(j->mgr->jm_port));
9877  	}
9878 
9879 	jobmgr_log(j->mgr, LOG_DEBUG, "Initializing as %s", session_type);
9880 	strcpy(j->mgr->name_init, session_type);
9881 
9882 	if (job_assumes(j, (j2 = jobmgr_init_session(j->mgr, session_type, false)))) {
9883 		j2->asport = asport;
9884 		(void)job_assumes(j, job_dispatch(j2, true));
9885 		kr = BOOTSTRAP_SUCCESS;
9886 	}
9887 
9888 	return kr;
9889 }
9890 
9891 kern_return_t
9892 job_mig_switch_to_session(job_t j, mach_port_t requestor_port, name_t session_name, mach_port_t asport, mach_port_t *new_bsport)
9893 {
9894 	struct ldcred *ldc = runtime_get_caller_creds();
9895 	if (!jobmgr_assumes(root_jobmgr, j != NULL)) {
9896 		jobmgr_log(root_jobmgr, LOG_ERR, "%s() called with NULL job: PID %d", __func__, ldc->pid);
9897 		RETURN_NO_MEMORY();
9898 	}
9899 
9900 	if (j->mgr->shutting_down) {
9901 		return BOOTSTRAP_UNKNOWN_SERVICE;
9902 	}
9903 
9904 	job_log(j, LOG_DEBUG, "Job wants to move to %s session.", session_name);
9905 
9906 	if (!job_assumes(j, pid1_magic == false)) {
9907 		job_log(j, LOG_WARNING, "Switching sessions is not allowed in the system Mach bootstrap.");
9908 		return BOOTSTRAP_NOT_PRIVILEGED;
9909 	}
9910 
9911 	if (!j->anonymous) {
9912 		job_log(j, LOG_NOTICE, "Non-anonymous job tried to switch sessions. Please use LimitLoadToSessionType instead.");
9913 		return BOOTSTRAP_NOT_PRIVILEGED;
9914 	}
9915 
9916 	jobmgr_t target_jm = jobmgr_find_by_name(root_jobmgr, session_name);
9917 	if (target_jm == j->mgr) {
9918 		job_log(j, LOG_DEBUG, "Job is already in its desired session (%s).", session_name);
9919 		(void)job_assumes_zero(j, launchd_mport_deallocate(asport));
9920 		(void)job_assumes_zero(j, launchd_mport_deallocate(requestor_port));
9921 		*new_bsport = target_jm->jm_port;
9922 		return BOOTSTRAP_SUCCESS;
9923 	}
9924 
9925 	if (!target_jm) {
9926 		target_jm = jobmgr_new(j->mgr, requestor_port, MACH_PORT_NULL, false, session_name, false, asport);
9927 		if (target_jm) {
9928 			target_jm->properties |= BOOTSTRAP_PROPERTY_IMPLICITSUBSET;
9929 			(void)job_assumes_zero(j, launchd_mport_deallocate(asport));
9930 		}
9931 	}
9932 
9933 	if (!job_assumes(j, target_jm != NULL)) {
9934 		job_log(j, LOG_WARNING, "Could not find %s session!", session_name);
9935 		RETURN_NO_MEMORY();
9936 	}
9937 
9938 	// Remove the job from it's current job manager.
9939 	LIST_REMOVE(j, sle);
9940 	LIST_REMOVE(j, pid_hash_sle);
9941 
9942 	job_t ji = NULL, jit = NULL;
9943 	LIST_FOREACH_SAFE(ji, &j->mgr->global_env_jobs, global_env_sle, jit) {
9944 		if (ji == j) {
9945 			LIST_REMOVE(ji, global_env_sle);
9946 			break;
9947 		}
9948 	}
9949 
9950 	// Put the job into the target job manager.
9951 	LIST_INSERT_HEAD(&target_jm->jobs, j, sle);
9952 	LIST_INSERT_HEAD(&target_jm->active_jobs[ACTIVE_JOB_HASH(j->p)], j, pid_hash_sle);
9953 
9954 	if (ji) {
9955 		LIST_INSERT_HEAD(&target_jm->global_env_jobs, j, global_env_sle);
9956 	}
9957 
9958 	// Move our Mach services over if we're not in a flat namespace.
9959 	if (!launchd_flat_mach_namespace && !SLIST_EMPTY(&j->machservices)) {
9960 		struct machservice *msi = NULL, *msit = NULL;
9961 		SLIST_FOREACH_SAFE(msi, &j->machservices, sle, msit) {
9962 			LIST_REMOVE(msi, name_hash_sle);
9963 			LIST_INSERT_HEAD(&target_jm->ms_hash[hash_ms(msi->name)], msi, name_hash_sle);
9964 		}
9965 	}
9966 
9967 	j->mgr = target_jm;
9968 
9969 	if (!j->holds_ref) {
9970 		/* Anonymous jobs which move around are particularly interesting to us, so we want to
9971 		 * stick around while they're still around.
9972 		 * For example, login calls into the PAM launchd module, which moves the process into
9973 		 * the StandardIO session by default. So we'll hold a reference on that job to prevent
9974 		 * ourselves from going away.
9975 		 */
9976 		j->holds_ref = true;
9977 		job_log(j, LOG_PERF, "Job switched into manager: %s", j->mgr->name);
9978 		runtime_add_ref();
9979 	}
9980 
9981 	*new_bsport = target_jm->jm_port;
9982 
9983 	return KERN_SUCCESS;
9984 }
9985 
9986 kern_return_t
9987 job_mig_take_subset(job_t j, mach_port_t *reqport, mach_port_t *rcvright,
9988 		vm_offset_t *outdata, mach_msg_type_number_t *outdataCnt,
9989 		mach_port_array_t *portsp, unsigned int *ports_cnt)
9990 {
9991 	launch_data_t tmp_obj, tmp_dict, outdata_obj_array = NULL;
9992 	mach_port_array_t ports = NULL;
9993 	unsigned int cnt = 0, cnt2 = 0;
9994 	size_t packed_size;
9995 	struct machservice *ms;
9996 	jobmgr_t jm;
9997 	job_t ji;
9998 
9999 	if (!j) {
10000 		RETURN_NO_MEMORY();
10001 	}
10002 
10003 	jm = j->mgr;
10004 
10005 	if (unlikely(!pid1_magic)) {
10006 		job_log(j, LOG_ERR, "Only the system launchd will transfer Mach sub-bootstraps.");
10007 		return BOOTSTRAP_NOT_PRIVILEGED;
10008 	}
10009 	if (unlikely(jobmgr_parent(jm) == NULL)) {
10010 		job_log(j, LOG_ERR, "Root Mach bootstrap cannot be transferred.");
10011 		return BOOTSTRAP_NOT_PRIVILEGED;
10012 	}
10013 	if (unlikely(strcasecmp(jm->name, VPROCMGR_SESSION_AQUA) == 0)) {
10014 		job_log(j, LOG_ERR, "Cannot transfer a setup GUI session.");
10015 		return BOOTSTRAP_NOT_PRIVILEGED;
10016 	}
10017 	if (unlikely(!j->anonymous)) {
10018 		job_log(j, LOG_ERR, "Only the anonymous job can transfer Mach sub-bootstraps.");
10019 		return BOOTSTRAP_NOT_PRIVILEGED;
10020 	}
10021 
10022 	job_log(j, LOG_DEBUG, "Transferring sub-bootstrap to the per session launchd.");
10023 
10024 	outdata_obj_array = launch_data_alloc(LAUNCH_DATA_ARRAY);
10025 	if (!job_assumes(j, outdata_obj_array)) {
10026 		goto out_bad;
10027 	}
10028 
10029 	*outdataCnt = 20 * 1024 * 1024;
10030 	mig_allocate(outdata, *outdataCnt);
10031 	if (!job_assumes(j, *outdata != 0)) {
10032 		return 1;
10033 	}
10034 
10035 	LIST_FOREACH(ji, &j->mgr->jobs, sle) {
10036 		if (!ji->anonymous) {
10037 			continue;
10038 		}
10039 		SLIST_FOREACH(ms, &ji->machservices, sle) {
10040 			cnt++;
10041 		}
10042 	}
10043 
10044 	mig_allocate((vm_address_t *)&ports, cnt * sizeof(ports[0]));
10045 	if (!job_assumes(j, ports != NULL)) {
10046 		goto out_bad;
10047 	}
10048 
10049 	LIST_FOREACH(ji, &j->mgr->jobs, sle) {
10050 		if (!ji->anonymous) {
10051 			continue;
10052 		}
10053 
10054 		SLIST_FOREACH(ms, &ji->machservices, sle) {
10055 			if (job_assumes(j, (tmp_dict = launch_data_alloc(LAUNCH_DATA_DICTIONARY)))) {
10056 				(void)job_assumes(j, launch_data_array_set_index(outdata_obj_array, tmp_dict, cnt2));
10057 			} else {
10058 				goto out_bad;
10059 			}
10060 
10061 			if (job_assumes(j, (tmp_obj = launch_data_new_string(machservice_name(ms))))) {
10062 				(void)job_assumes(j, launch_data_dict_insert(tmp_dict, tmp_obj, TAKE_SUBSET_NAME));
10063 			} else {
10064 				goto out_bad;
10065 			}
10066 
10067 			if (job_assumes(j, (tmp_obj = launch_data_new_integer((ms->job->p))))) {
10068 				(void)job_assumes(j, launch_data_dict_insert(tmp_dict, tmp_obj, TAKE_SUBSET_PID));
10069 			} else {
10070 				goto out_bad;
10071 			}
10072 
10073 			if (job_assumes(j, (tmp_obj = launch_data_new_bool((ms->per_pid))))) {
10074 				(void)job_assumes(j, launch_data_dict_insert(tmp_dict, tmp_obj, TAKE_SUBSET_PERPID));
10075 			} else {
10076 				goto out_bad;
10077 			}
10078 
10079 			ports[cnt2] = machservice_port(ms);
10080 
10081 			// Increment the send right by one so we can shutdown the jobmgr cleanly
10082 			(void)jobmgr_assumes_zero(jm, launchd_mport_copy_send(ports[cnt2]));
10083 			cnt2++;
10084 		}
10085 	}
10086 
10087 	(void)job_assumes(j, cnt == cnt2);
10088 
10089 	runtime_ktrace0(RTKT_LAUNCHD_DATA_PACK);
10090 	packed_size = launch_data_pack(outdata_obj_array, (void *)*outdata, *outdataCnt, NULL, NULL);
10091 	if (!job_assumes(j, packed_size != 0)) {
10092 		goto out_bad;
10093 	}
10094 
10095 	launch_data_free(outdata_obj_array);
10096 
10097 	*portsp = ports;
10098 	*ports_cnt = cnt;
10099 
10100 	*reqport = jm->req_port;
10101 	*rcvright = jm->jm_port;
10102 
10103 	jm->req_port = 0;
10104 	jm->jm_port = 0;
10105 
10106 	workaround_5477111 = j;
10107 
10108 	jobmgr_shutdown(jm);
10109 
10110 	return BOOTSTRAP_SUCCESS;
10111 
10112 out_bad:
10113 	if (outdata_obj_array) {
10114 		launch_data_free(outdata_obj_array);
10115 	}
10116 	if (*outdata) {
10117 		mig_deallocate(*outdata, *outdataCnt);
10118 	}
10119 	if (ports) {
10120 		mig_deallocate((vm_address_t)ports, cnt * sizeof(ports[0]));
10121 	}
10122 
10123 	RETURN_NO_MEMORY();
10124 }
10125 
10126 kern_return_t
10127 job_mig_subset(job_t j, mach_port_t requestorport, mach_port_t *subsetportp)
10128 {
10129 	int bsdepth = 0;
10130 	jobmgr_t jmr;
10131 
10132 	if (!j) {
10133 		RETURN_NO_MEMORY();
10134 	}
10135 	if (j->mgr->shutting_down) {
10136 		return BOOTSTRAP_UNKNOWN_SERVICE;
10137 	}
10138 
10139 	jmr = j->mgr;
10140 
10141 	while ((jmr = jobmgr_parent(jmr)) != NULL) {
10142 		bsdepth++;
10143 	}
10144 
10145 	// Since we use recursion, we need an artificial depth for subsets
10146 	if (unlikely(bsdepth > 100)) {
10147 		job_log(j, LOG_ERR, "Mach sub-bootstrap create request failed. Depth greater than: %d", bsdepth);
10148 		RETURN_NO_MEMORY();
10149 	}
10150 
10151 	char name[NAME_MAX];
10152 	snprintf(name, sizeof(name), "%s[%i].subset.%i", j->anonymous ? j->prog : j->label, j->p, MACH_PORT_INDEX(requestorport));
10153 
10154 	if (!job_assumes(j, (jmr = jobmgr_new(j->mgr, requestorport, MACH_PORT_NULL, false, name, true, j->asport)) != NULL)) {
10155 		if (unlikely(requestorport == MACH_PORT_NULL)) {
10156 			return BOOTSTRAP_NOT_PRIVILEGED;
10157 		}
10158 		RETURN_NO_MEMORY();
10159 	}
10160 
10161 	*subsetportp = jmr->jm_port;
10162 	jmr->properties |= BOOTSTRAP_PROPERTY_EXPLICITSUBSET;
10163 
10164 	/* A job could create multiple subsets, so only add a reference the first time
10165 	 * it does so we don't have to keep a count.
10166 	 */
10167 	if (j->anonymous && !j->holds_ref) {
10168 		job_log(j, LOG_PERF, "Job created subset: %s", jmr->name);
10169 		j->holds_ref = true;
10170 		runtime_add_ref();
10171 	}
10172 
10173 	job_log(j, LOG_DEBUG, "Job created a subset named \"%s\"", jmr->name);
10174 	return BOOTSTRAP_SUCCESS;
10175 }
10176 
10177 job_t
10178 _xpc_domain_import_service(jobmgr_t jm, launch_data_t pload)
10179 {
10180 	jobmgr_t where2put = NULL;
10181 
10182 	if (launch_data_get_type(pload) != LAUNCH_DATA_DICTIONARY) {
10183 		errno = EINVAL;
10184 		return NULL;
10185 	}
10186 
10187 	launch_data_t ldlabel = launch_data_dict_lookup(pload, LAUNCH_JOBKEY_LABEL);
10188 	if (!ldlabel || launch_data_get_type(ldlabel) != LAUNCH_DATA_STRING) {
10189 		errno = EINVAL;
10190 		return NULL;
10191 	}
10192 
10193 	const char *label = launch_data_get_string(ldlabel);
10194 	jobmgr_log(jm, LOG_DEBUG, "Importing service: %s", label);
10195 
10196 	launch_data_t destname = launch_data_dict_lookup(pload, LAUNCH_JOBKEY_XPCDOMAIN);
10197 	if (destname) {
10198 		bool supported_domain = false;
10199 
10200 		if (launch_data_get_type(destname) == LAUNCH_DATA_STRING) {
10201 			const char *str = launch_data_get_string(destname);
10202 			if (strcmp(str, XPC_DOMAIN_TYPE_SYSTEM) == 0) {
10203 				where2put = _s_xpc_system_domain;
10204 			} else if (strcmp(str, XPC_DOMAIN_TYPE_PERUSER) == 0) {
10205 				where2put = jobmgr_find_xpc_per_user_domain(jm, jm->req_euid);
10206 				supported_domain = true;
10207 			} else if (strcmp(str, XPC_DOMAIN_TYPE_PERSESSION) == 0) {
10208 				where2put = jobmgr_find_xpc_per_session_domain(jm, jm->req_asid);
10209 			} else {
10210 				jobmgr_log(jm, LOG_ERR, "Invalid XPC domain type: %s", str);
10211 				errno = EINVAL;
10212 			}
10213 		} else {
10214 			jobmgr_log(jm, LOG_ERR, "XPC domain type is not a string.");
10215 			errno = EINVAL;
10216 		}
10217 
10218 		if (where2put && !supported_domain) {
10219 			launch_data_t mi = NULL;
10220 			if ((mi = launch_data_dict_lookup(pload, LAUNCH_JOBKEY_MULTIPLEINSTANCES))) {
10221 				if (launch_data_get_type(mi) == LAUNCH_DATA_BOOL && launch_data_get_bool(mi)) {
10222 					jobmgr_log(where2put, LOG_ERR, "Multiple-instance services are not supported in this domain.");
10223 					where2put = NULL;
10224 					errno = EINVAL;
10225 				}
10226 			}
10227 		}
10228 	} else {
10229 		where2put = jm;
10230 	}
10231 
10232 	job_t j = NULL;
10233 	if (where2put) {
10234 		/* Gross. If the service already exists in a singleton domain, then
10235 		 * jobmgr_import2() will return the existing job. But if we fail to alias
10236 		 * this job, we will normally want to remove it. But if we did not create
10237 		 * it in the first place, then we need to avoid removing it. So check
10238 		 * errno against EEXIST in the success case and if it's EEXIST, then do
10239 		 * not remove the original job in the event of a failed alias.
10240 		 *
10241 		 * This really needs to be re-thought, but I think it'll require a larger
10242 		 * evaluation of launchd's data structures. Right now, once a job is
10243 		 * imported into a singleton domain, it won't be removed until the system
10244 		 * shuts down, but that may not always be true. If it ever changes, we'll
10245 		 * have a problem because we'll have to account for all existing aliases
10246 		 * and clean them up somehow. Or just start ref-counting. I knew this
10247 		 * aliasing stuff would be trouble...
10248 		 *
10249 		 * <rdar://problem/10646503>
10250 		 */
10251 		jobmgr_log(where2put, LOG_DEBUG, "Importing service...");
10252 
10253 		errno = 0;
10254 		if ((j = jobmgr_import2(where2put, pload))) {
10255 			bool created = (errno != EEXIST);
10256 			j->xpc_service = true;
10257 
10258 			if (where2put->xpc_singleton) {
10259 				/* If the service was destined for one of the global domains,
10260 				 * then we have to alias it into our local domain to reserve the
10261 				 * name.
10262 				 */
10263 				job_t ja = NULL;
10264 				if (!(ja = job_new_alias(jm, j))) {
10265 					/* If we failed to alias the job because of a conflict over
10266 					 * the label, then we remove it from the global domain. We
10267 					 * don't want to risk having imported a malicious job into
10268 					 * one of the global domains.
10269 					 */
10270 					if (errno != EEXIST) {
10271 						job_log(j, LOG_ERR, "Failed to alias job into: %s: %d: %s", where2put->name, errno, strerror(errno));
10272 					} else {
10273 						errno = 0;
10274 					}
10275 
10276 					if (created) {
10277 						jobmgr_log(jm, LOG_WARNING, "Singleton service already existed in job-local namespace. Removing: %s", j->label);
10278 						job_remove(j);
10279 					}
10280 
10281 					j = NULL;
10282 				} else {
10283 					jobmgr_log(jm, LOG_DEBUG, "Aliased service into local domain: %s", j->label);
10284 					(void)job_dispatch(j, false);
10285 					ja->xpc_service = true;
10286 					j = ja;
10287 				}
10288 			} else {
10289 				(void)job_dispatch(j, false);
10290 			}
10291 		}
10292 	} else {
10293 		jobmgr_log(jm, LOG_DEBUG, "Could not find destination for service: %s", label);
10294 	}
10295 
10296 	return j;
10297 }
10298 
10299 int
10300 _xpc_domain_import_services(job_t j, launch_data_t services)
10301 {
10302 	int error = EINVAL;
10303 	if (launch_data_get_type(services) != LAUNCH_DATA_ARRAY) {
10304 		return error;
10305 	}
10306 
10307 	size_t i = 0;
10308 	size_t c = launch_data_array_get_count(services);
10309 	jobmgr_log(j->mgr, LOG_DEBUG, "Importing new services: %lu", c);
10310 
10311 	for (i = 0; i < c; i++) {
10312 		jobmgr_log(j->mgr, LOG_DEBUG, "Importing service at index: %lu", i);
10313 
10314 		job_t nj = NULL;
10315 		launch_data_t ploadi = launch_data_array_get_index(services, i);
10316 		if (!(nj = _xpc_domain_import_service(j->mgr, ploadi))) {
10317 			if (!j->mgr->session_initialized && errno) {
10318 				/* Service import failures are only fatal if the domain is being
10319 				 * initialized. If we're extending the domain, we can run into
10320 				 * errors with services already existing, so we just ignore them.
10321 				 * In the case of a domain extension, we don't want to halt the
10322 				 * operation if we run into an error with one service.
10323 				 *
10324 				 * <rdar://problem/10842779>
10325 				 */
10326 				jobmgr_log(j->mgr, LOG_ERR, "Failed to import service at index: %lu: %d: %s", i, errno, strerror(errno));
10327 				error = errno;
10328 				break;
10329 			}
10330 		} else {
10331 			jobmgr_log(j->mgr, LOG_DEBUG, "Imported service: %s", nj->label);
10332 		}
10333 	}
10334 
10335 	if (i == c) {
10336 		error = 0;
10337 	}
10338 
10339 	return error;
10340 }
10341 
10342 kern_return_t
10343 xpc_domain_import2(job_t j, mach_port_t reqport, mach_port_t dport)
10344 {
10345 	if (unlikely(!pid1_magic)) {
10346 		job_log(j, LOG_ERR, "XPC domains may only reside in PID 1.");
10347 		return BOOTSTRAP_NOT_PRIVILEGED;
10348 	}
10349 	if (!j || !MACH_PORT_VALID(reqport)) {
10350 		return BOOTSTRAP_UNKNOWN_SERVICE;
10351 	}
10352 	if (root_jobmgr->shutting_down) {
10353 		jobmgr_log(root_jobmgr, LOG_ERR, "Attempt to create new domain while shutting down.");
10354 		return BOOTSTRAP_NOT_PRIVILEGED;
10355 	}
10356 	if (!j->xpc_bootstrapper) {
10357 		job_log(j, LOG_ERR, "Attempt to create new XPC domain by unprivileged job.");
10358 		return BOOTSTRAP_NOT_PRIVILEGED;
10359 	}
10360 
10361 	kern_return_t kr = BOOTSTRAP_NO_MEMORY;
10362 	/* All XPC domains are children of the root job manager. What we're creating
10363 	 * here is really just a skeleton. By creating it, we're adding reqp to our
10364 	 * port set. It will have two messages on it. The first specifies the
10365 	 * environment of the originator. This is so we can cache it and hand it to
10366 	 * xpcproxy to bootstrap our services. The second is the set of jobs that is
10367 	 * to be bootstrapped in.
10368 	 */
10369 	jobmgr_t jm = jobmgr_new(root_jobmgr, reqport, dport, false, NULL, true, MACH_PORT_NULL);
10370 	if (job_assumes(j, jm != NULL)) {
10371 		jm->properties |= BOOTSTRAP_PROPERTY_XPC_DOMAIN;
10372 		jm->shortdesc = "private";
10373 		kr = BOOTSTRAP_SUCCESS;
10374 	}
10375 
10376 	return kr;
10377 }
10378 
10379 kern_return_t
10380 xpc_domain_set_environment(job_t j, mach_port_t rp, mach_port_t bsport, mach_port_t excport, vm_offset_t ctx, mach_msg_type_number_t ctx_sz)
10381 {
10382 	if (!j) {
10383 		/* Due to the whacky nature of XPC service bootstrapping, we can end up
10384 		 * getting this message long after the requesting process has gone away.
10385 		 * See <rdar://problem/8593143>.
10386 		 */
10387 		return BOOTSTRAP_UNKNOWN_SERVICE;
10388 	}
10389 
10390 	jobmgr_t jm = j->mgr;
10391 	if (!(jm->properties & BOOTSTRAP_PROPERTY_XPC_DOMAIN)) {
10392 		return BOOTSTRAP_NOT_PRIVILEGED;
10393 	}
10394 
10395 	if (jm->req_asport != MACH_PORT_NULL) {
10396 		return BOOTSTRAP_NOT_PRIVILEGED;
10397 	}
10398 
10399 	struct ldcred *ldc = runtime_get_caller_creds();
10400 	struct proc_bsdinfowithuniqid proc;
10401 	if (proc_pidinfo(ldc->pid, PROC_PIDT_BSDINFOWITHUNIQID, 1, &proc, PROC_PIDT_BSDINFOWITHUNIQID_SIZE) == 0) {
10402 		if (errno != ESRCH) {
10403 			(void)jobmgr_assumes_zero(jm, errno);
10404 		}
10405 
10406 		jm->error = errno;
10407 		jobmgr_remove(jm);
10408 		RETURN_NO_MEMORY();
10409 	}
10410 #ifdef notyet
10411 #if !TARGET_OS_EMBEDDED
10412 	if (jobmgr_assumes_zero(jm, audit_session_port(ldc->asid, &jm->req_asport)) != 0) {
10413 		jm->error = EPERM;
10414 		jobmgr_remove(jm);
10415 		job_log(j, LOG_ERR, "Failed to get port for ASID: %u", ldc->asid);
10416 		return BOOTSTRAP_NOT_PRIVILEGED;
10417 	}
10418 #else
10419 	jm->req_asport = MACH_PORT_DEAD;
10420 #endif
10421 #endif
10422 	struct waiting4attach *w4ai = NULL;
10423 	struct waiting4attach *w4ait = NULL;
10424 	LIST_FOREACH_SAFE(w4ai, &_launchd_domain_waiters, le, w4ait) {
10425 		if (w4ai->dest == ldc->pid) {
10426 			jobmgr_log(jm, LOG_DEBUG, "Migrating attach for: %s", w4ai->name);
10427 			LIST_REMOVE(w4ai, le);
10428 			LIST_INSERT_HEAD(&jm->attaches, w4ai, le);
10429 			w4ai->dest = 0;
10430 		}
10431 	}
10432 
10433 	(void)snprintf(jm->name_init, NAME_MAX, "com.apple.xpc.domain.%s.%d", proc.pbsd.pbi_comm, ldc->pid);
10434 	strlcpy(jm->owner, proc.pbsd.pbi_comm, sizeof(jm->owner));
10435 	jm->req_bsport = bsport;
10436 	jm->req_excport = excport;
10437 	jm->req_rport = rp;
10438 	jm->req_ctx = ctx;
10439 	jm->req_ctx_sz = ctx_sz;
10440 	jm->req_pid = ldc->pid;
10441 	jm->req_euid = ldc->euid;
10442 	jm->req_egid = ldc->egid;
10443 	jm->req_asid = ldc->asid;
10444 	jm->req_uniqueid = proc.p_uniqidentifier.p_uniqueid;
10445 
10446 	return KERN_SUCCESS;
10447 }
10448 
10449 kern_return_t
10450 xpc_domain_load_services(job_t j, vm_offset_t services_buff, mach_msg_type_number_t services_sz)
10451 {
10452 	if (!j) {
10453 		return BOOTSTRAP_UNKNOWN_SERVICE;
10454 	}
10455 
10456  	job_t rootj = jobmgr_find_by_pid(root_jobmgr, j->p, false);
10457  	if (!(rootj && rootj->xpc_bootstrapper)) {
10458 		job_log(j, LOG_ERR, "Attempt to load services into XPC domain by unprivileged job.");
10459 		return BOOTSTRAP_NOT_PRIVILEGED;
10460 	}
10461 
10462 	// This is just for XPC domains (for now).
10463 	if (!(j->mgr->properties & BOOTSTRAP_PROPERTY_XPC_DOMAIN)) {
10464 		return BOOTSTRAP_NOT_PRIVILEGED;
10465 	}
10466 	if (j->mgr->session_initialized) {
10467 		jobmgr_log(j->mgr, LOG_ERR, "Attempt to initialize an already-initialized XPC domain.");
10468 		return BOOTSTRAP_NOT_PRIVILEGED;
10469 	}
10470 
10471 	size_t offset = 0;
10472 	launch_data_t services = launch_data_unpack((void *)services_buff, services_sz, NULL, 0, &offset, NULL);
10473 	if (!services) {
10474 		RETURN_NO_MEMORY();
10475 	}
10476 
10477 	int error = _xpc_domain_import_services(j, services);
10478 	if (error) {
10479 		j->mgr->error = error;
10480 		jobmgr_log(j->mgr, LOG_ERR, "Obliterating domain.");
10481 		jobmgr_remove(j->mgr);
10482 	} else {
10483 		j->mgr->session_initialized = true;
10484 		(void)jobmgr_assumes_zero(j->mgr, xpc_call_wakeup(j->mgr->req_rport, BOOTSTRAP_SUCCESS));
10485 		j->mgr->req_rport = MACH_PORT_NULL;
10486 
10487 		/* Returning a failure code will destroy the message, whereas returning
10488 		 * success will not, so we need to clean up here.
10489 		 */
10490 		mig_deallocate(services_buff, services_sz);
10491 		error = BOOTSTRAP_SUCCESS;
10492 	}
10493 
10494 	return error;
10495 }
10496 
10497 kern_return_t
10498 xpc_domain_check_in(job_t j, mach_port_t *bsport, mach_port_t *sbsport,
10499 	mach_port_t *excport, mach_port_t *asport, uint32_t *uid, uint32_t *gid,
10500 	int32_t *asid, vm_offset_t *ctx, mach_msg_type_number_t *ctx_sz)
10501 {
10502 	if (!jobmgr_assumes(root_jobmgr, j != NULL)) {
10503 		return BOOTSTRAP_UNKNOWN_SERVICE;
10504 	}
10505 	jobmgr_t jm = j->mgr;
10506 	if (!(jm->properties & BOOTSTRAP_PROPERTY_XPC_DOMAIN)) {
10507 		return BOOTSTRAP_NOT_PRIVILEGED;
10508 	}
10509 
10510 	if (jm->req_asport == MACH_PORT_NULL) {
10511 		return BOOTSTRAP_NOT_PRIVILEGED;
10512 	}
10513 
10514 	*bsport = jm->req_bsport;
10515 	*sbsport = root_jobmgr->jm_port;
10516 	*excport = jm->req_excport;
10517 	if (j->joins_gui_session) {
10518 		if (jm->req_gui_asport) {
10519 			*asport = jm->req_gui_asport;
10520 		} else {
10521 			job_log(j, LOG_NOTICE, "No GUI session set for UID of user service. This service may not act properly.");
10522 			*asport = jm->req_asport;
10523 		}
10524 	} else {
10525 		*asport = jm->req_asport;
10526 	}
10527 
10528 	*uid = jm->req_euid;
10529 	*gid = jm->req_egid;
10530 	*asid = jm->req_asid;
10531 
10532 	*ctx = jm->req_ctx;
10533 	*ctx_sz = jm->req_ctx_sz;
10534 
10535 	return KERN_SUCCESS;
10536 }
10537 
10538 kern_return_t
10539 xpc_domain_get_service_name(job_t j, event_name_t name)
10540 {
10541 	if (!j) {
10542 		RETURN_NO_MEMORY();
10543 	}
10544 
10545 	if (!j->xpc_service) {
10546 		jobmgr_log(j->mgr, LOG_ERR, "Attempt to get service name by non-XPC service: %s", j->label);
10547 		return BOOTSTRAP_NOT_PRIVILEGED;
10548 	}
10549 
10550 	const char *what2find = j->label;
10551 	if (j->dedicated_instance) {
10552 		what2find = j->original->label;
10553 	}
10554 
10555 	struct machservice *msi = NULL;
10556 	SLIST_FOREACH(msi, &j->machservices, sle) {
10557 		if (strcmp(msi->name, what2find) == 0) {
10558 			break;
10559 		}
10560 	}
10561 
10562 	if (!msi) {
10563 		jobmgr_log(j->mgr, LOG_ERR, "Attempt to get service name that does not exist: %s", j->label);
10564 		return BOOTSTRAP_UNKNOWN_SERVICE;
10565 	}
10566 
10567 	(void)strlcpy(name, msi->name, sizeof(event_name_t));
10568 	return BOOTSTRAP_SUCCESS;
10569 }
10570 
10571 #if XPC_LPI_VERSION >= 20111216
10572 kern_return_t
10573 xpc_domain_add_services(job_t j, vm_offset_t services_buff, mach_msg_type_number_t services_sz)
10574 {
10575 	if (!j) {
10576 		return BOOTSTRAP_UNKNOWN_SERVICE;
10577 	}
10578 
10579  	job_t rootj = jobmgr_find_by_pid(root_jobmgr, j->p, false);
10580  	if (!(rootj && rootj->xpc_bootstrapper)) {
10581 		job_log(j, LOG_ERR, "Attempt to add service to XPC domain by unprivileged job.");
10582 		return BOOTSTRAP_NOT_PRIVILEGED;
10583 	}
10584 
10585 	if (!(j->mgr->properties & BOOTSTRAP_PROPERTY_XPC_DOMAIN)) {
10586 		return BOOTSTRAP_NOT_PRIVILEGED;
10587 	}
10588 
10589 	size_t offset = 0;
10590 	launch_data_t services = launch_data_unpack((void *)services_buff, services_sz, NULL, 0, &offset, NULL);
10591 	if (!services) {
10592 		RETURN_NO_MEMORY();
10593 	}
10594 
10595 	int error = _xpc_domain_import_services(j, services);
10596 	if (!error) {
10597 		mig_deallocate(services_buff, services_sz);
10598 	}
10599 
10600 	return error;
10601 }
10602 #endif
10603 
10604 #pragma mark XPC Events
10605 int
10606 xpc_event_find_channel(job_t j, const char *stream, struct machservice **ms)
10607 {
10608 	int error = EXNOMEM;
10609 	struct machservice *msi = NULL;
10610 	SLIST_FOREACH(msi, &j->machservices, sle) {
10611 		if (strcmp(stream, msi->name) == 0) {
10612 			break;
10613 		}
10614 	}
10615 
10616 	if (!msi) {
10617 		mach_port_t sp = MACH_PORT_NULL;
10618 		msi = machservice_new(j, stream, &sp, false);
10619 		if (!msi) {
10620 			return EXNOMEM;
10621 		}
10622 
10623 		job_log(j, LOG_DEBUG, "Creating new MachService for stream: %s", stream);
10624 		/* Hack to keep this from being publicly accessible through
10625 		 * bootstrap_look_up().
10626 		 */
10627 		if (!j->dedicated_instance) {
10628 			LIST_REMOVE(msi, name_hash_sle);
10629 		}
10630 		msi->event_channel = true;
10631 
10632 		/* If we call job_dispatch() here before the audit session for the job
10633 		 * has been set, we'll end up not watching this service. But we also have
10634 		 * to take care not to watch the port if the job is active.
10635 		 *
10636 		 * See <rdar://problem/10357855>.
10637 		 */
10638 		if (!j->currently_ignored) {
10639 			machservice_watch(j, msi);
10640 		}
10641 
10642 		error = 0;
10643 		*ms = msi;
10644 	} else if (!msi->event_channel) {
10645 		job_log(j, LOG_ERR, "This job registered a MachService name identical to the requested event channel name: %s", stream);
10646 		error = EEXIST;
10647 	} else {
10648 		error = 0;
10649 		*ms = msi;
10650 	}
10651 
10652 	return error;
10653 }
10654 
10655 int
10656 xpc_event_get_event_name(job_t j, xpc_object_t request, xpc_object_t *reply)
10657 {
10658 	const char *stream = xpc_dictionary_get_string(request, XPC_EVENT_ROUTINE_KEY_STREAM);
10659 	if (!stream) {
10660 		return EXINVAL;
10661 	}
10662 
10663 	uint64_t token = xpc_dictionary_get_uint64(request, XPC_EVENT_ROUTINE_KEY_TOKEN);
10664 	if (!token) {
10665 		return EXINVAL;
10666 	}
10667 
10668 	job_log(j, LOG_DEBUG, "Getting event name for stream/token: %s/0x%zu", stream, token);
10669 
10670 	int result = ESRCH;
10671 	struct externalevent *event = externalevent_find(stream, token);
10672 	if (event && j->event_monitor) {
10673 		xpc_object_t reply2 = xpc_dictionary_create_reply(request);
10674 		xpc_dictionary_set_string(reply2, XPC_EVENT_ROUTINE_KEY_NAME, event->name);
10675 		*reply = reply2;
10676 
10677 		job_log(j, LOG_DEBUG, "Found: %s", event->name);
10678 		result = 0;
10679 	}
10680 
10681 	return result;
10682 }
10683 
10684 static int
10685 xpc_event_copy_entitlements(job_t j, xpc_object_t request, xpc_object_t *reply)
10686 {
10687 	const char *stream = xpc_dictionary_get_string(request, XPC_EVENT_ROUTINE_KEY_STREAM);
10688 	if (!stream) {
10689 		return EXINVAL;
10690 	}
10691 
10692 	uint64_t token = xpc_dictionary_get_uint64(request, XPC_EVENT_ROUTINE_KEY_TOKEN);
10693 	if (!token) {
10694 		return EXINVAL;
10695 	}
10696 
10697 	job_log(j, LOG_DEBUG, "Getting entitlements for stream/token: %s/0x%zu", stream, token);
10698 
10699 	int result = ESRCH;
10700 	struct externalevent *event = externalevent_find(stream, token);
10701 	if (event && j->event_monitor) {
10702 		xpc_object_t reply2 = xpc_dictionary_create_reply(request);
10703 		xpc_dictionary_set_value(reply2, XPC_EVENT_ROUTINE_KEY_ENTITLEMENTS, event->entitlements);
10704 		*reply = reply2;
10705 
10706 		job_log(j, LOG_DEBUG, "Found: %s", event->name);
10707 		result = 0;
10708 	}
10709 
10710 	return result;
10711 }
10712 
10713 // TODO - can be removed with rdar://problem/12666150
10714 #ifndef XPC_EVENT_FLAG_ALLOW_UNMANAGED
10715 #define XPC_EVENT_FLAG_ALLOW_UNMANAGED (1 << 1)
10716 #endif
10717 
10718 int
10719 xpc_event_set_event(job_t j, xpc_object_t request, xpc_object_t *reply)
10720 {
10721 	const char *stream = xpc_dictionary_get_string(request, XPC_EVENT_ROUTINE_KEY_STREAM);
10722 	if (!stream) {
10723 		return EXINVAL;
10724 	}
10725 
10726 	const char *key = xpc_dictionary_get_string(request, XPC_EVENT_ROUTINE_KEY_NAME);
10727 	if (!key) {
10728 		return EXINVAL;
10729 	}
10730 
10731 	xpc_object_t event = xpc_dictionary_get_value(request, XPC_EVENT_ROUTINE_KEY_EVENT);
10732 	if (event && xpc_get_type(event) != XPC_TYPE_DICTIONARY) {
10733 		return EXINVAL;
10734 	}
10735 
10736 	uint64_t flags = xpc_dictionary_get_uint64(request, XPC_EVENT_ROUTINE_KEY_FLAGS);
10737 
10738 	/* Don't allow events to be set for anonymous jobs unless specifically
10739 	 * requested in the flags. Only permit this for internal development.
10740 	 */
10741 	if (j->anonymous && ((flags & XPC_EVENT_FLAG_ALLOW_UNMANAGED) == 0 || !launchd_apple_internal)) {
10742 		job_log(j, LOG_ERR, "Unmanaged jobs may not make XPC Events requests.");
10743 		return EPERM;
10744 	}
10745 
10746 	job_log(j, LOG_DEBUG, "%s event for stream/key: %s/%s", event ? "Setting" : "Removing", stream, key);
10747 
10748 	struct externalevent *eei = NULL;
10749 	LIST_FOREACH(eei, &j->events, job_le) {
10750 		/* If the event for the given key already exists for the job, we need to
10751 		 * remove the old one first.
10752 		 */
10753 		if (strcmp(eei->name, key) == 0 && strcmp(eei->sys->name, stream) == 0) {
10754 			job_log(j, LOG_DEBUG, "Event exists. Removing.");
10755 			externalevent_delete(eei);
10756 			break;
10757 		}
10758 	}
10759 
10760 	int result = EXNOMEM;
10761 	if (event) {
10762 		struct eventsystem *es = eventsystem_find(stream);
10763 		if (!es) {
10764 			job_log(j, LOG_DEBUG, "Creating stream.");
10765 			es = eventsystem_new(stream);
10766 		}
10767 
10768 		if (es) {
10769 			job_log(j, LOG_DEBUG, "Adding event.");
10770 			if (externalevent_new(j, es, key, event, flags)) {
10771 				job_log(j, LOG_DEBUG, "Added new event for key: %s", key);
10772 				result = 0;
10773 			} else {
10774 				job_log(j, LOG_ERR, "Could not create event for key: %s", key);
10775 			}
10776 		} else {
10777 			job_log(j, LOG_ERR, "Event stream could not be created: %s", stream);
10778 		}
10779 	} else {
10780 		/* If the event was NULL, then we just remove it and return. */
10781 		result = 0;
10782 	}
10783 
10784 	if (result == 0) {
10785 		xpc_object_t reply2 = xpc_dictionary_create_reply(request);
10786 		*reply = reply2;
10787 	}
10788 
10789 	return result;
10790 }
10791 
10792 int
10793 xpc_event_copy_event(job_t j, xpc_object_t request, xpc_object_t *reply)
10794 {
10795 	const char *stream = xpc_dictionary_get_string(request, XPC_EVENT_ROUTINE_KEY_STREAM);
10796 	const char *key = xpc_dictionary_get_string(request, XPC_EVENT_ROUTINE_KEY_NAME);
10797 
10798 	bool all_streams = (stream == NULL);
10799 	bool all_events = (key == NULL || strcmp(key, "") == 0); // strcmp for libxpc compatibility
10800 	xpc_object_t events = NULL;
10801 
10802 	if (all_streams && !all_events) {
10803 		return EXINVAL;
10804 	}
10805 
10806 	if (all_streams || all_events) {
10807 		job_log(j, LOG_DEBUG, "Fetching all events%s%s", stream ? " for stream: " : "", stream ? stream : "");
10808 		events = xpc_dictionary_create(NULL, NULL, 0);
10809 	} else {
10810 		job_log(j, LOG_DEBUG, "Fetching stream/key: %s/%s", stream, key);
10811 	}
10812 
10813 	int result = ESRCH;
10814 	struct externalevent *eei = NULL;
10815 	LIST_FOREACH(eei, &j->events, job_le) {
10816 		if (all_streams) {
10817 			xpc_object_t sub = xpc_dictionary_get_value(events, eei->sys->name);
10818 			if (sub == NULL) {
10819 				sub = xpc_dictionary_create(NULL, NULL, 0);
10820 				xpc_dictionary_set_value(events, eei->sys->name, sub);
10821 				xpc_release(sub);
10822 			}
10823 			xpc_dictionary_set_value(sub, eei->name, eei->event);
10824 		} else if (strcmp(eei->sys->name, stream) == 0) {
10825 			if (all_events) {
10826 				xpc_dictionary_set_value(events, eei->name, eei->event);
10827 			} else if (strcmp(eei->name, key) == 0) {
10828 				job_log(j, LOG_DEBUG, "Found event.");
10829 				events = xpc_retain(eei->event);
10830 				break;
10831 			}
10832 		}
10833 	}
10834 
10835 	if (events) {
10836 		xpc_object_t reply2 = xpc_dictionary_create_reply(request);
10837 		xpc_dictionary_set_value(reply2, XPC_EVENT_ROUTINE_KEY_EVENT, events);
10838 		xpc_release(events);
10839 
10840 		*reply = reply2;
10841 		result = 0;
10842 	}
10843 
10844 	return result;
10845 }
10846 
10847 int
10848 xpc_event_channel_check_in(job_t j, xpc_object_t request, xpc_object_t *reply)
10849 {
10850 	const char *stream = xpc_dictionary_get_string(request, XPC_EVENT_ROUTINE_KEY_STREAM);
10851 	if (!stream) {
10852 		return EXINVAL;
10853 	}
10854 
10855 	job_log(j, LOG_DEBUG, "Checking in stream: %s", stream);
10856 
10857 	struct machservice *ms = NULL;
10858 	int error = xpc_event_find_channel(j, stream, &ms);
10859 	if (error) {
10860 		job_log(j, LOG_ERR, "Failed to check in: 0x%x: %s", error, xpc_strerror(error));
10861 	} else if (ms->isActive) {
10862 		job_log(j, LOG_ERR, "Attempt to check in on event channel multiple times: %s", stream);
10863 		error = EBUSY;
10864 	} else {
10865 		machservice_request_notifications(ms);
10866 
10867 		xpc_object_t reply2 = xpc_dictionary_create_reply(request);
10868 		xpc_dictionary_set_mach_recv(reply2, XPC_EVENT_ROUTINE_KEY_PORT, ms->port);
10869 		*reply = reply2;
10870 		error = 0;
10871 	}
10872 
10873 	return error;
10874 }
10875 
10876 int
10877 xpc_event_channel_look_up(job_t j, xpc_object_t request, xpc_object_t *reply)
10878 {
10879 	if (!j->event_monitor) {
10880 		return EPERM;
10881 	}
10882 
10883 	const char *stream = xpc_dictionary_get_string(request, XPC_EVENT_ROUTINE_KEY_STREAM);
10884 	if (!stream) {
10885 		return EXINVAL;
10886 	}
10887 
10888 	uint64_t token = xpc_dictionary_get_uint64(request, XPC_EVENT_ROUTINE_KEY_TOKEN);
10889 	if (!token) {
10890 		return EXINVAL;
10891 	}
10892 
10893 	job_log(j, LOG_DEBUG, "Looking up channel for stream/token: %s/%zu", stream, token);
10894 
10895 	struct externalevent *ee = externalevent_find(stream, token);
10896 	if (!ee) {
10897 		return ESRCH;
10898 	}
10899 
10900 	struct machservice *ms = NULL;
10901 	int error = xpc_event_find_channel(ee->job, stream, &ms);
10902 	if (!error) {
10903 		job_log(j, LOG_DEBUG, "Found event channel port: 0x%x", ms->port);
10904 		xpc_object_t reply2 = xpc_dictionary_create_reply(request);
10905 		xpc_dictionary_set_mach_send(reply2, XPC_EVENT_ROUTINE_KEY_PORT, ms->port);
10906 		*reply = reply2;
10907 		error = 0;
10908 	} else {
10909 		job_log(j, LOG_ERR, "Could not find event channel for stream/token: %s/%zu: 0x%x: %s", stream, token, error, xpc_strerror(error));
10910 	}
10911 
10912 	return error;
10913 }
10914 
10915 int
10916 xpc_event_provider_check_in(job_t j, xpc_object_t request, xpc_object_t *reply)
10917 {
10918 	if (!j->event_monitor) {
10919 		return EPERM;
10920 	}
10921 
10922 	/* This indicates that the event monitor is now safe to signal. This state
10923 	 * is independent of whether this operation actually succeeds; we just need
10924 	 * it to ignore SIGUSR1.
10925 	 */
10926 	j->event_monitor_ready2signal = true;
10927 
10928 	const char *stream = xpc_dictionary_get_string(request, XPC_EVENT_ROUTINE_KEY_STREAM);
10929 	if (!stream) {
10930 		return EXINVAL;
10931 	}
10932 
10933 	job_log(j, LOG_DEBUG, "Provider checking in for stream: %s", stream);
10934 
10935 	xpc_object_t events = xpc_array_create(NULL, 0);
10936 	struct eventsystem *es = eventsystem_find(stream);
10937 	if (!es) {
10938 		/* If we had to create the event stream, there were no events, so just
10939 		 * give back the empty array.
10940 		 */
10941 		job_log(j, LOG_DEBUG, "Creating event stream.");
10942 		es = eventsystem_new(stream);
10943 		if (!job_assumes(j, es)) {
10944 			xpc_release(events);
10945 			return EXNOMEM;
10946 		}
10947 
10948 		if (strcmp(stream, "com.apple.launchd.helper") == 0) {
10949 			_launchd_support_system = es;
10950 		}
10951 	} else {
10952 		job_log(j, LOG_DEBUG, "Filling event array.");
10953 
10954 		struct externalevent *ei = NULL;
10955 		LIST_FOREACH(ei, &es->events, sys_le) {
10956 			xpc_array_set_uint64(events, XPC_ARRAY_APPEND, ei->id);
10957 			xpc_array_append_value(events, ei->event);
10958 		}
10959 	}
10960 
10961 	xpc_object_t reply2 = xpc_dictionary_create_reply(request);
10962 	xpc_dictionary_set_value(reply2, XPC_EVENT_ROUTINE_KEY_EVENTS, events);
10963 	xpc_release(events);
10964 	*reply = reply2;
10965 
10966 	return 0;
10967 }
10968 
10969 int
10970 xpc_event_provider_set_state(job_t j, xpc_object_t request, xpc_object_t *reply)
10971 {
10972 	job_t other_j = NULL;
10973 
10974 	if (!j->event_monitor) {
10975 		return EPERM;
10976 	}
10977 
10978 	const char *stream = xpc_dictionary_get_string(request, XPC_EVENT_ROUTINE_KEY_STREAM);
10979 	if (!stream) {
10980 		return EXINVAL;
10981 	}
10982 
10983 	uint64_t token = xpc_dictionary_get_uint64(request, XPC_EVENT_ROUTINE_KEY_TOKEN);
10984 	if (!token) {
10985 		return EXINVAL;
10986 	}
10987 
10988 	bool state = false;
10989 	xpc_object_t xstate = xpc_dictionary_get_value(request, XPC_EVENT_ROUTINE_KEY_STATE);
10990 	if (!xstate || xpc_get_type(xstate) != XPC_TYPE_BOOL) {
10991 		return EXINVAL;
10992 	} else {
10993 		state = xpc_bool_get_value(xstate);
10994 	}
10995 
10996 	job_log(j, LOG_DEBUG, "Setting event state to %s for stream/token: %s/%zu", state ? "true" : "false", stream, token);
10997 
10998 	struct externalevent *ei = externalevent_find(stream, token);
10999 	if (!ei) {
11000 		job_log(j, LOG_ERR, "Could not find stream/token: %s/%zu", stream, token);
11001 		return ESRCH;
11002 	}
11003 
11004 	other_j = ei->job;
11005 	ei->state = state;
11006 
11007 	if (ei->internal) {
11008 		job_log(ei->job, LOG_NOTICE, "Job should be able to exec(3) now.");
11009 		ei->job->waiting4ok = false;
11010 		externalevent_delete(ei);
11011 	}
11012 
11013 	(void)job_dispatch(other_j, false);
11014 
11015 	xpc_object_t reply2 = xpc_dictionary_create_reply(request);
11016 	*reply = reply2;
11017 
11018 	return 0;
11019 }
11020 
11021 bool
11022 xpc_event_demux(mach_port_t p, xpc_object_t request, xpc_object_t *reply)
11023 {
11024 	uint64_t op = xpc_dictionary_get_uint64(request, XPC_EVENT_ROUTINE_KEY_OP);
11025 	if (!op) {
11026 		return false;
11027 	}
11028 
11029 	audit_token_t token;
11030 	xpc_dictionary_get_audit_token(request, &token);
11031 	runtime_record_caller_creds(&token);
11032 
11033 	struct ldcred *ldc = runtime_get_caller_creds();
11034 	job_t j = managed_job(ldc->pid);
11035 	if (!j) {
11036 		j = job_mig_intran(p);
11037 		if (!j) {
11038 			op = -1;
11039 		}
11040 	}
11041 
11042 	job_log(j, LOG_DEBUG, "Incoming XPC event request: %zu", op);
11043 
11044 	int error = -1;
11045 	switch (op) {
11046 	case XPC_EVENT_GET_NAME:
11047 		error = xpc_event_get_event_name(j, request, reply);
11048 		break;
11049 	case XPC_EVENT_SET:
11050 		error = xpc_event_set_event(j, request, reply);
11051 		break;
11052 	case XPC_EVENT_COPY:
11053 		error = xpc_event_copy_event(j, request, reply);
11054 		break;
11055 	case XPC_EVENT_CHECK_IN:
11056 		error = xpc_event_channel_check_in(j, request, reply);
11057 		break;
11058 	case XPC_EVENT_LOOK_UP:
11059 		error = xpc_event_channel_look_up(j, request, reply);
11060 		break;
11061 	case XPC_EVENT_PROVIDER_CHECK_IN:
11062 		error = xpc_event_provider_check_in(j, request, reply);
11063 		break;
11064 	case XPC_EVENT_PROVIDER_SET_STATE:
11065 		error = xpc_event_provider_set_state(j, request, reply);
11066 		break;
11067 	case XPC_EVENT_COPY_ENTITLEMENTS:
11068 		error = xpc_event_copy_entitlements(j, request, reply);
11069 		break;
11070 	case -1:
11071 		error = EINVAL;
11072 		break;
11073 	default:
11074 		job_log(j, LOG_ERR, "Bogus opcode.");
11075 		error = EDOM;
11076 	}
11077 
11078 	if (error) {
11079 		xpc_object_t reply2 = xpc_dictionary_create_reply(request);
11080 		xpc_dictionary_set_uint64(reply2, XPC_EVENT_ROUTINE_KEY_ERROR, error);
11081 		*reply = reply2;
11082 	}
11083 
11084 	return true;
11085 }
11086 
11087 static uint64_t
11088 xpc_get_jetsam_entitlement(const char *key)
11089 {
11090 	uint64_t entitlement = 0;
11091 
11092 	audit_token_t *token = runtime_get_caller_token();
11093 	xpc_object_t value = xpc_copy_entitlement_for_token(key, token);
11094 	if (value) {
11095 		if (xpc_get_type(value) == XPC_TYPE_UINT64) {
11096 			entitlement = xpc_uint64_get_value(value);
11097 		}
11098 
11099 		xpc_release(value);
11100 	}
11101 
11102 	return entitlement;
11103 }
11104 
11105 int
11106 xpc_process_set_jetsam_band(job_t j, xpc_object_t request, xpc_object_t *reply)
11107 {
11108 	if (!j) {
11109 		return EINVAL;
11110 	}
11111 
11112 	const char *label = xpc_dictionary_get_string(request, XPC_PROCESS_ROUTINE_KEY_LABEL);
11113 	if (!label) {
11114 		return EXINVAL;
11115 	}
11116 
11117 	xpc_jetsam_band_t entitled_band = -1;
11118 	xpc_jetsam_band_t requested_band = (xpc_jetsam_band_t)xpc_dictionary_get_uint64(request, XPC_PROCESS_ROUTINE_KEY_PRIORITY_BAND);
11119 	if (!requested_band) {
11120 		return EXINVAL;
11121 	}
11122 
11123 	if (!(requested_band >= XPC_JETSAM_BAND_SUSPENDED && requested_band < XPC_JETSAM_BAND_LAST)) {
11124 		return EXINVAL;
11125 	}
11126 
11127 	uint64_t rcdata = xpc_dictionary_get_uint64(request, XPC_PROCESS_ROUTINE_KEY_RCDATA);
11128 
11129 	job_t tj = job_find(root_jobmgr, label);
11130 	if (!tj) {
11131 		return EXSRCH;
11132 	}
11133 
11134 	boolean_t allow = false;
11135 	if (j->embedded_god) {
11136 		allow = true;
11137 	} else {
11138 		entitled_band = xpc_get_jetsam_entitlement("com.apple.private.jetsam.modify-priority");
11139 		if (entitled_band >= requested_band) {
11140 			allow = true;
11141 		}
11142 	}
11143 
11144 	if (!allow) {
11145 		if (launchd_no_jetsam_perm_check) {
11146 			job_log(j, LOG_NOTICE, "Jetsam priority checks disabled; allowing job to set priority: %d", requested_band);
11147 		} else {
11148 			job_log(j, LOG_ERR, "Job cannot decrease Jetsam priority band (requested/maximum): %d/%d", requested_band, entitled_band);
11149 			return EPERM;
11150 		}
11151 	}
11152 
11153 	job_log(j, LOG_INFO, "Setting Jetsam band: %d.", requested_band);
11154 	job_update_jetsam_properties(tj, requested_band, rcdata);
11155 
11156 	xpc_object_t reply2 = xpc_dictionary_create_reply(request);
11157 	*reply = reply2;
11158 
11159 	return 0;
11160 }
11161 
11162 int
11163 xpc_process_set_jetsam_memory_limit(job_t j, xpc_object_t request, xpc_object_t *reply)
11164 {
11165 	if (!j) {
11166 		return EINVAL;
11167 	}
11168 
11169 	const char *label = xpc_dictionary_get_string(request, XPC_PROCESS_ROUTINE_KEY_LABEL);
11170 	if (!label) {
11171 		return EXINVAL;
11172 	}
11173 
11174 	int32_t entitlement_limit = 0;
11175 	int32_t requested_limit = (int32_t)xpc_dictionary_get_uint64(request, XPC_PROCESS_ROUTINE_KEY_MEMORY_LIMIT);
11176 
11177 	job_t tj = job_find(root_jobmgr, label);
11178 	if (!tj) {
11179 		return EXSRCH;
11180 	}
11181 
11182 	boolean_t allow = false;
11183 	if (j->embedded_god) {
11184 		allow = true;
11185 	} else {
11186 		entitlement_limit = (int32_t)xpc_get_jetsam_entitlement("com.apple.private.jetsam.memory_limit");
11187 		if (entitlement_limit >= requested_limit) {
11188 			allow = true;
11189 		}
11190 	}
11191 
11192 	if (!allow) {
11193 		if (launchd_no_jetsam_perm_check) {
11194 			job_log(j, LOG_NOTICE, "Jetsam priority checks disabled; allowing job to set memory limit: %d", requested_limit);
11195 		} else {
11196 			job_log(j, LOG_ERR, "Job cannot set Jetsam memory limit (requested/maximum): %d/%d", requested_limit, entitlement_limit);
11197 			return EPERM;
11198 		}
11199 	}
11200 
11201 	job_log(j, LOG_INFO, "Setting Jetsam memory limit: %d.", requested_limit);
11202 	job_update_jetsam_memory_limit(tj, requested_limit);
11203 
11204 	xpc_object_t reply2 = xpc_dictionary_create_reply(request);
11205 	*reply = reply2;
11206 
11207 	return 0;
11208 }
11209 
11210 static jobmgr_t
11211 _xpc_process_find_target_manager(job_t j, xpc_service_type_t type, pid_t pid)
11212 {
11213 	jobmgr_t target = NULL;
11214 	if (type == XPC_SERVICE_TYPE_BUNDLED) {
11215 		job_log(j, LOG_DEBUG, "Bundled service. Searching for XPC domains for PID: %d", pid);
11216 
11217 		jobmgr_t jmi = NULL;
11218 		SLIST_FOREACH(jmi, &root_jobmgr->submgrs, sle) {
11219 			if (jmi->req_pid && jmi->req_pid == pid) {
11220 				jobmgr_log(jmi, LOG_DEBUG, "Found job manager for PID.");
11221 				target = jmi;
11222 				break;
11223 			}
11224 		}
11225 	} else if (type == XPC_SERVICE_TYPE_LAUNCHD || type == XPC_SERVICE_TYPE_APP) {
11226 		target = j->mgr;
11227 	}
11228 
11229 	return target;
11230 }
11231 
11232 static int
11233 xpc_process_attach(job_t j, xpc_object_t request, xpc_object_t *reply)
11234 {
11235 	if (!j) {
11236 		return EINVAL;
11237 	}
11238 
11239 	audit_token_t *token = runtime_get_caller_token();
11240 	xpc_object_t entitlement = xpc_copy_entitlement_for_token(XPC_SERVICE_ENTITLEMENT_ATTACH, token);
11241 	if (!entitlement) {
11242 		job_log(j, LOG_ERR, "Job does not have entitlement: %s", XPC_SERVICE_ENTITLEMENT_ATTACH);
11243 		return EPERM;
11244 	}
11245 
11246 	if (entitlement != XPC_BOOL_TRUE) {
11247 		char *desc = xpc_copy_description(entitlement);
11248 		job_log(j, LOG_ERR, "Job has bad value for entitlement: %s:\n%s", XPC_SERVICE_ENTITLEMENT_ATTACH, desc);
11249 		free(desc);
11250 
11251 		xpc_release(entitlement);
11252 		return EPERM;
11253 	}
11254 
11255 	const char *name = xpc_dictionary_get_string(request, XPC_PROCESS_ROUTINE_KEY_NAME);
11256 	if (!name) {
11257 		return EXINVAL;
11258 	}
11259 
11260 	xpc_service_type_t type = xpc_dictionary_get_int64(request, XPC_PROCESS_ROUTINE_KEY_TYPE);
11261 	if (!type) {
11262 		return EXINVAL;
11263 	}
11264 
11265 	mach_port_t port = xpc_dictionary_copy_mach_send(request, XPC_PROCESS_ROUTINE_KEY_NEW_INSTANCE_PORT);
11266 	if (!MACH_PORT_VALID(port)) {
11267 		return EXINVAL;
11268 	}
11269 
11270 	pid_t pid = xpc_dictionary_get_int64(request, XPC_PROCESS_ROUTINE_KEY_HANDLE);
11271 
11272 	job_log(j, LOG_DEBUG, "Attaching to service: %s", name);
11273 
11274 	xpc_object_t reply2 = xpc_dictionary_create_reply(request);
11275 	jobmgr_t target = _xpc_process_find_target_manager(j, type, pid);
11276 	if (target) {
11277 		jobmgr_log(target, LOG_DEBUG, "Found target job manager for service: %s", name);
11278 		(void)jobmgr_assumes(target, waiting4attach_new(target, name, port, 0, type));
11279 
11280 		/* HACK: This is awful. For legacy reasons, launchd job labels are all
11281 		 * stored in a global namespace, which is stored in the root job
11282 		 * manager. But XPC domains have a per-domain namespace. So if we're
11283 		 * looking for a legacy launchd job, we have to redirect any attachment
11284 		 * attempts to the root job manager to find existing instances.
11285 		 *
11286 		 * But because we store attachments on a per-job manager basis, we have
11287 		 * to create the new attachment in the actual target job manager, hence
11288 		 * why we change the target only after we've created the attachment.
11289 		 */
11290 		if (strcmp(target->name, VPROCMGR_SESSION_AQUA) == 0) {
11291 			target = root_jobmgr;
11292 		}
11293 
11294 		job_t existing = job_find(target, name);
11295 		if (existing && existing->p) {
11296 			job_log(existing, LOG_DEBUG, "Found existing instance of service.");
11297 			xpc_dictionary_set_int64(reply2, XPC_PROCESS_ROUTINE_KEY_PID, existing->p);
11298 		} else {
11299 			xpc_dictionary_set_uint64(reply2, XPC_PROCESS_ROUTINE_KEY_ERROR, ESRCH);
11300 		}
11301 	} else if (type == XPC_SERVICE_TYPE_BUNDLED) {
11302 		(void)job_assumes(j, waiting4attach_new(target, name, port, pid, type));
11303 		xpc_dictionary_set_uint64(reply2, XPC_PROCESS_ROUTINE_KEY_ERROR, ESRCH);
11304 	} else {
11305 		xpc_dictionary_set_uint64(reply2, XPC_PROCESS_ROUTINE_KEY_ERROR, EXSRCH);
11306 	}
11307 
11308 	*reply = reply2;
11309 	return 0;
11310 }
11311 
11312 static int
11313 xpc_process_detach(job_t j, xpc_object_t request, xpc_object_t *reply __unused)
11314 {
11315 	if (!j) {
11316 		return EINVAL;
11317 	}
11318 
11319 	const char *name = xpc_dictionary_get_string(request, XPC_PROCESS_ROUTINE_KEY_NAME);
11320 	if (!name) {
11321 		return EXINVAL;
11322 	}
11323 
11324 	xpc_service_type_t type = xpc_dictionary_get_int64(request, XPC_PROCESS_ROUTINE_KEY_TYPE);
11325 	if (!type) {
11326 		return EXINVAL;
11327 	}
11328 
11329 	job_log(j, LOG_DEBUG, "Deatching from service: %s", name);
11330 
11331 	pid_t pid = xpc_dictionary_get_int64(request, XPC_PROCESS_ROUTINE_KEY_PID);
11332 	jobmgr_t target = _xpc_process_find_target_manager(j, type, pid);
11333 	if (target) {
11334 		jobmgr_log(target, LOG_DEBUG, "Found target job manager for service: %s", name);
11335 
11336 		struct waiting4attach *w4ai = NULL;
11337 		struct waiting4attach *w4ait = NULL;
11338 		LIST_FOREACH_SAFE(w4ai, &target->attaches, le, w4ait) {
11339 			if (strcmp(name, w4ai->name) == 0) {
11340 				jobmgr_log(target, LOG_DEBUG, "Found attachment. Deleting.");
11341 				waiting4attach_delete(target, w4ai);
11342 				break;
11343 			}
11344 		}
11345 	}
11346 
11347 	return 0;
11348 }
11349 
11350 static int
11351 xpc_process_get_properties(job_t j, xpc_object_t request, xpc_object_t *reply)
11352 {
11353 	if (j->anonymous) {
11354 		/* Total hack. libxpc will send requests to the pipe created out of the
11355 		 * process' bootstrap port, so when job_mig_intran() tries to resolve
11356 		 * the process into a job, it'll wind up creating an anonymous job if
11357 		 * the requestor was an XPC service, whose job manager is an XPC domain.
11358 		 */
11359 		pid_t pid = j->p;
11360 		jobmgr_t jmi = NULL;
11361 		SLIST_FOREACH(jmi, &root_jobmgr->submgrs, sle) {
11362 			if ((j = jobmgr_find_by_pid(jmi, pid, false))) {
11363 				break;
11364 			}
11365 		}
11366 	}
11367 
11368 	if (!j || j->anonymous) {
11369 		return EXINVAL;
11370 	}
11371 
11372 	struct waiting4attach *w4a = waiting4attach_find(j->mgr, j);
11373 	if (!w4a) {
11374 		return EXINVAL;
11375 	}
11376 
11377 	xpc_object_t reply2 = xpc_dictionary_create_reply(request);
11378 	xpc_dictionary_set_uint64(reply2, XPC_PROCESS_ROUTINE_KEY_TYPE, w4a->type);
11379 	xpc_dictionary_set_mach_send(reply2, XPC_PROCESS_ROUTINE_KEY_NEW_INSTANCE_PORT, w4a->port);
11380 	if (j->prog) {
11381 		xpc_dictionary_set_string(reply2, XPC_PROCESS_ROUTINE_KEY_PATH, j->prog);
11382 	} else {
11383 		xpc_dictionary_set_string(reply2, XPC_PROCESS_ROUTINE_KEY_PATH, j->argv[0]);
11384 	}
11385 
11386 	if (j->argv) {
11387 		xpc_object_t xargv = xpc_array_create(NULL, 0);
11388 
11389 		size_t i = 0;
11390 		for (i = 0; i < j->argc; i++) {
11391 			if (j->argv[i]) {
11392 				xpc_array_set_string(xargv, XPC_ARRAY_APPEND, j->argv[i]);
11393 			}
11394 		}
11395 
11396 		xpc_dictionary_set_value(reply2, XPC_PROCESS_ROUTINE_KEY_ARGV, xargv);
11397 		xpc_release(xargv);
11398 	}
11399 
11400 	*reply = reply2;
11401 	return 0;
11402 }
11403 
11404 static int
11405 xpc_process_service_kill(job_t j, xpc_object_t request, xpc_object_t *reply)
11406 {
11407 #if XPC_LPI_VERSION >= 20130426
11408 	if (!j) {
11409 		return ESRCH;
11410 	}
11411 
11412 	jobmgr_t jm = _xpc_process_find_target_manager(j, XPC_SERVICE_TYPE_BUNDLED, j->p);
11413 	if (!jm) {
11414 		return ENOENT;
11415 	}
11416 
11417 	const char *name = xpc_dictionary_get_string(request, XPC_PROCESS_ROUTINE_KEY_NAME);
11418 	if (!name) {
11419 		return EINVAL;
11420 	}
11421 
11422 	int64_t whichsig = xpc_dictionary_get_int64(request, XPC_PROCESS_ROUTINE_KEY_SIGNAL);
11423 	if (!whichsig) {
11424 		return EINVAL;
11425 	}
11426 
11427 	job_t j2kill = job_find(jm, name);
11428 	if (!j2kill) {
11429 		return ESRCH;
11430 	}
11431 
11432 	if (j2kill->alias) {
11433 		// Only allow for private instances to be killed.
11434 		return EPERM;
11435 	}
11436 
11437 	struct proc_bsdshortinfo proc;
11438 	if (proc_pidinfo(j2kill->p, PROC_PIDT_SHORTBSDINFO, 1, &proc, PROC_PIDT_SHORTBSDINFO_SIZE) == 0) {
11439 		if (errno != ESRCH) {
11440 			(void)jobmgr_assumes_zero(root_jobmgr, errno);
11441 		}
11442 
11443 		return errno;
11444 	}
11445 
11446 	struct ldcred *ldc = runtime_get_caller_creds();
11447 	if (proc.pbsi_uid != ldc->euid) {
11448 		// Do not allow non-root to kill RoleAccount services running as a
11449 		// different user.
11450 		return EPERM;
11451 	}
11452 
11453 	if (!j2kill->p) {
11454 		return EALREADY;
11455 	}
11456 
11457 	xpc_object_t reply2 = xpc_dictionary_create_reply(request);
11458 	if (!reply2) {
11459 		return EINVAL;
11460 	}
11461 
11462 	int error = 0;
11463 	int ret = kill(j2kill->p, whichsig);
11464 	if (ret) {
11465 		error = errno;
11466 	}
11467 
11468 	xpc_dictionary_set_int64(reply2, XPC_PROCESS_ROUTINE_KEY_ERROR, error);
11469 	*reply = reply2;
11470 	return 0;
11471 #else
11472 	return ENOTSUP;
11473 #endif
11474 }
11475 
11476 bool
11477 xpc_process_demux(mach_port_t p, xpc_object_t request, xpc_object_t *reply)
11478 {
11479 	uint64_t op = xpc_dictionary_get_uint64(request, XPC_PROCESS_ROUTINE_KEY_OP);
11480 	if (!op) {
11481 		return false;
11482 	}
11483 
11484 	audit_token_t token;
11485 	xpc_dictionary_get_audit_token(request, &token);
11486 	runtime_record_caller_creds(&token);
11487 
11488 	job_t j = job_mig_intran(p);
11489 	job_log(j, LOG_DEBUG, "Incoming XPC process request: %zu", op);
11490 
11491 	int error = -1;
11492 	switch (op) {
11493 	case XPC_PROCESS_JETSAM_SET_BAND:
11494 		error = xpc_process_set_jetsam_band(j, request, reply);
11495 		break;
11496 	case XPC_PROCESS_JETSAM_SET_MEMORY_LIMIT:
11497 		error = xpc_process_set_jetsam_memory_limit(j, request, reply);
11498 		break;
11499 	case XPC_PROCESS_SERVICE_ATTACH:
11500 		error = xpc_process_attach(j, request, reply);
11501 		break;
11502 	case XPC_PROCESS_SERVICE_DETACH:
11503 		error = xpc_process_detach(j, request, reply);
11504 		break;
11505 	case XPC_PROCESS_SERVICE_GET_PROPERTIES:
11506 		error = xpc_process_get_properties(j, request, reply);
11507 		break;
11508 	case XPC_PROCESS_SERVICE_KILL:
11509 		error = xpc_process_service_kill(j, request, reply);
11510 		break;
11511 	default:
11512 		job_log(j, LOG_ERR, "Bogus process opcode.");
11513 		error = EDOM;
11514 	}
11515 
11516 	if (error) {
11517 		xpc_object_t reply2 = xpc_dictionary_create_reply(request);
11518 		if (reply2) {
11519 			xpc_dictionary_set_uint64(reply2, XPC_PROCESS_ROUTINE_KEY_ERROR, error);
11520 		}
11521 
11522 		*reply = reply2;
11523 	}
11524 
11525 	return true;
11526 }
11527 
11528 kern_return_t
11529 job_mig_kickstart(job_t j, name_t targetlabel, pid_t *out_pid, unsigned int flags)
11530 {
11531 	struct ldcred *ldc = runtime_get_caller_creds();
11532 	job_t otherj;
11533 
11534 	if (!j) {
11535 		RETURN_NO_MEMORY();
11536 	}
11537 
11538 	if (unlikely(!(otherj = job_find(NULL, targetlabel)))) {
11539 		return BOOTSTRAP_UNKNOWN_SERVICE;
11540 	}
11541 
11542 #if TARGET_OS_EMBEDDED
11543 	bool allow_non_root_kickstart = j->username && otherj->username && (strcmp(j->username, otherj->username) == 0);
11544 #else
11545 	bool allow_non_root_kickstart = false;
11546 #endif
11547 
11548 	if (ldc->euid != 0 && ldc->euid != geteuid() && !allow_non_root_kickstart) {
11549 		return BOOTSTRAP_NOT_PRIVILEGED;
11550 	}
11551 
11552 #if HAVE_SANDBOX
11553 	if (unlikely(sandbox_check(ldc->pid, "job-creation", SANDBOX_FILTER_NONE) > 0)) {
11554 		return BOOTSTRAP_NOT_PRIVILEGED;
11555 	}
11556 #endif
11557 
11558 	if (otherj->p && (flags & VPROCFLAG_STALL_JOB_EXEC)) {
11559 		return BOOTSTRAP_SERVICE_ACTIVE;
11560 	}
11561 
11562 	otherj->stall_before_exec = (flags & VPROCFLAG_STALL_JOB_EXEC);
11563 	otherj = job_dispatch(otherj, true);
11564 
11565 	if (!job_assumes(j, otherj && otherj->p)) {
11566 		// <rdar://problem/6787083> Clear this flag if we failed to start the job.
11567 		otherj->stall_before_exec = false;
11568 		RETURN_NO_MEMORY();
11569 	}
11570 
11571 	*out_pid = otherj->p;
11572 
11573 	return 0;
11574 }
11575 
11576 kern_return_t
11577 job_mig_spawn_internal(job_t j, vm_offset_t indata, mach_msg_type_number_t indataCnt, mach_port_t asport, job_t *outj)
11578 {
11579 	launch_data_t jobdata = NULL;
11580 	size_t data_offset = 0;
11581 	struct ldcred *ldc = runtime_get_caller_creds();
11582 	job_t jr;
11583 
11584 	if (!j) {
11585 		RETURN_NO_MEMORY();
11586 	}
11587 
11588 	if (unlikely(j->deny_job_creation)) {
11589 		return BOOTSTRAP_NOT_PRIVILEGED;
11590 	}
11591 
11592 #if HAVE_SANDBOX
11593 	if (unlikely(sandbox_check(ldc->pid, "job-creation", SANDBOX_FILTER_NONE) > 0)) {
11594 		return BOOTSTRAP_NOT_PRIVILEGED;
11595 	}
11596 #endif
11597 
11598 	if (unlikely(pid1_magic && ldc->euid && ldc->uid)) {
11599 		job_log(j, LOG_DEBUG, "Punting spawn to per-user-context");
11600 		return VPROC_ERR_TRY_PER_USER;
11601 	}
11602 
11603 	if (!job_assumes(j, indataCnt != 0)) {
11604 		return 1;
11605 	}
11606 
11607 	runtime_ktrace0(RTKT_LAUNCHD_DATA_UNPACK);
11608 	if (!job_assumes(j, (jobdata = launch_data_unpack((void *)indata, indataCnt, NULL, 0, &data_offset, NULL)) != NULL)) {
11609 		return 1;
11610 	}
11611 
11612 	jobmgr_t target_jm = jobmgr_find_by_name(j->mgr, NULL);
11613 	if (!jobmgr_assumes(j->mgr, target_jm != NULL)) {
11614 		jobmgr_log(j->mgr, LOG_ERR, "This API can only be used by a process running within an Aqua session.");
11615 		return 1;
11616 	}
11617 
11618 	jr = jobmgr_import2(target_jm ?: j->mgr, jobdata);
11619 
11620 	launch_data_t label = NULL;
11621 	launch_data_t wait4debugger = NULL;
11622 	if (!jr) {
11623 		switch (errno) {
11624 		case EEXIST:
11625 			/* If EEXIST was returned, we know that there is a label string in
11626 			 * the dictionary. So we don't need to check the types here; that
11627 			 * has already been done.
11628 			 */
11629 			label = launch_data_dict_lookup(jobdata, LAUNCH_JOBKEY_LABEL);
11630 			jr = job_find(NULL, launch_data_get_string(label));
11631 			if (job_assumes(j, jr != NULL) && !jr->p) {
11632 				wait4debugger = launch_data_dict_lookup(jobdata, LAUNCH_JOBKEY_WAITFORDEBUGGER);
11633 				if (wait4debugger && launch_data_get_type(wait4debugger) == LAUNCH_DATA_BOOL) {
11634 					if (launch_data_get_bool(wait4debugger)) {
11635 						/* If the job exists, we're going to kick-start it, but
11636 						 * we need to give the caller the opportunity to start
11637 						 * it suspended if it so desires. But this will only
11638 						 * take effect if the job isn't running.
11639 						 */
11640 						jr->wait4debugger_oneshot = true;
11641 					}
11642 				}
11643 			}
11644 
11645 			*outj = jr;
11646 			return BOOTSTRAP_NAME_IN_USE;
11647 		default:
11648 			RETURN_NO_MEMORY();
11649 		}
11650 	}
11651 
11652 	if (pid1_magic) {
11653 		jr->mach_uid = ldc->uid;
11654 	}
11655 
11656 	// TODO: Consolidate the app and legacy_LS_job bits.
11657 	jr->legacy_LS_job = true;
11658 	jr->abandon_pg = true;
11659 	jr->asport = asport;
11660 	jr->app = true;
11661 	uuid_clear(jr->expected_audit_uuid);
11662 	jr = job_dispatch(jr, true);
11663 
11664 	if (!job_assumes(j, jr != NULL)) {
11665 		job_remove(jr);
11666 		RETURN_NO_MEMORY();
11667 	}
11668 
11669 	if (!job_assumes(jr, jr->p)) {
11670 		job_remove(jr);
11671 		RETURN_NO_MEMORY();
11672 	}
11673 
11674 	job_log(jr, LOG_DEBUG, "Spawned by PID %u: %s", j->p, j->label);
11675 	*outj = jr;
11676 
11677 	return BOOTSTRAP_SUCCESS;
11678 }
11679 
11680 kern_return_t
11681 job_mig_spawn2(job_t j, mach_port_t rp, vm_offset_t indata, mach_msg_type_number_t indataCnt, mach_port_t asport, pid_t *child_pid, mach_port_t *obsvr_port)
11682 {
11683 	job_t nj = NULL;
11684 	kern_return_t kr = job_mig_spawn_internal(j, indata, indataCnt, asport, &nj);
11685 	if (likely(kr == KERN_SUCCESS)) {
11686 		if (job_setup_exit_port(nj) != KERN_SUCCESS) {
11687 			job_remove(nj);
11688 			kr = BOOTSTRAP_NO_MEMORY;
11689 		} else {
11690 			/* Do not return until the job has called exec(3), thereby making it
11691 			 * safe for the caller to send it SIGCONT.
11692 			 *
11693 			 * <rdar://problem/9042798>
11694 			 */
11695 			nj->spawn_reply_port = rp;
11696 			kr = MIG_NO_REPLY;
11697 		}
11698 	} else if (kr == BOOTSTRAP_NAME_IN_USE) {
11699 		bool was_running = nj->p;
11700 		if (job_dispatch(nj, true)) {
11701 			if (!was_running) {
11702 				job_log(nj, LOG_DEBUG, "Job exists but is not running. Kick-starting.");
11703 
11704 				if (job_setup_exit_port(nj) == KERN_SUCCESS) {
11705 					nj->spawn_reply_port = rp;
11706 					kr = MIG_NO_REPLY;
11707 				} else {
11708 					kr = BOOTSTRAP_NO_MEMORY;
11709 				}
11710 			} else {
11711 				*obsvr_port = MACH_PORT_NULL;
11712 				*child_pid = nj->p;
11713 				kr = KERN_SUCCESS;
11714 			}
11715 		} else {
11716 			job_log(nj, LOG_ERR, "Failed to dispatch job, requestor: %s", j->label);
11717 			kr = BOOTSTRAP_UNKNOWN_SERVICE;
11718 		}
11719 	}
11720 
11721 	mig_deallocate(indata, indataCnt);
11722 	return kr;
11723 }
11724 
11725 launch_data_t
11726 job_do_ipc_request(job_t j, launch_data_t request, mach_port_t asport __attribute__((unused)))
11727 {
11728 	return (ipc_process_msg(j, request));
11729 }
11730 
11731 #define LAUNCHD_MAX_LEGACY_FDS 128
11732 #define countof(x) (sizeof((x)) / sizeof((x[0])))
11733 #define LOG_USER_FAIL()											\
11734 do {															\
11735 		if (uflag)												\
11736 			printf("launchd ipc_request failed on line: %d\n", __LINE__);	\
11737 		goto out_bad;											\
11738 } while (0)
11739 
11740 kern_return_t
11741 job_mig_ipc_request(job_t j, vm_offset_t request,
11742 	mach_msg_type_number_t requestCnt, mach_port_array_t request_fds,
11743 	mach_msg_type_number_t request_fdsCnt, vm_offset_t *reply,
11744 	mach_msg_type_number_t *replyCnt, mach_port_array_t *reply_fdps,
11745 	mach_msg_type_number_t *reply_fdsCnt, mach_port_t asport)
11746 {
11747 	if (!j) {
11748 		RETURN_NO_MEMORY();
11749 	}
11750 
11751 	/* TODO: Once we support actions other than checking in, we must check the
11752 	 * sandbox capabilities and EUID of the requestort.
11753 	 */
11754 	size_t nout_fdps = 0;
11755 	size_t nfds = request_fdsCnt / sizeof(request_fds[0]);
11756 	if (nfds > LAUNCHD_MAX_LEGACY_FDS) {
11757 		job_log(j, LOG_ERR, "Too many incoming descriptors: %lu", nfds);
11758 		RETURN_NO_MEMORY();
11759 	}
11760 
11761 	int in_fds[LAUNCHD_MAX_LEGACY_FDS];
11762 	size_t i = 0;
11763 	for (i = 0; i < nfds; i++) {
11764 		in_fds[i] = _fd(fileport_makefd(request_fds[i]));
11765 		if (in_fds[i] == -1) {
11766 			job_log(j, LOG_ERR, "Bad descriptor passed in legacy IPC request at index: %lu", i);
11767 		}
11768 	}
11769 
11770 	// DON'T goto outbad before this point.
11771 	*reply = 0;
11772 	*reply_fdps = NULL;
11773 	launch_data_t ldreply = NULL;
11774 
11775 	size_t dataoff = 0;
11776 	size_t fdoff = 0;
11777 	launch_data_t ldrequest = launch_data_unpack((void *)request, requestCnt, in_fds, nfds, &dataoff, &fdoff);
11778 	if (!ldrequest) {
11779 		job_log(j, LOG_ERR, "Invalid legacy IPC request passed.");
11780 		LOG_USER_FAIL();
11781 	}
11782 
11783 	ldreply = job_do_ipc_request(j, ldrequest, asport);
11784 	if (!ldreply) {
11785 		ldreply = launch_data_new_errno(errno);
11786 		if (!ldreply) {
11787 			LOG_USER_FAIL();
11788 		}
11789 	}
11790 
11791 	*replyCnt = 10 * 1024 * 1024;
11792 	mig_allocate(reply, *replyCnt);
11793 	if (!*reply) {
11794 		LOG_USER_FAIL();
11795 	}
11796 
11797 	int out_fds[LAUNCHD_MAX_LEGACY_FDS];
11798 	size_t nout_fds = 0;
11799 	size_t sz = launch_data_pack(ldreply, (void *)*reply, *replyCnt, out_fds, &nout_fds);
11800 	if (!sz) {
11801 		job_log(j, LOG_ERR, "Could not pack legacy IPC reply.");
11802 		LOG_USER_FAIL();
11803 	}
11804 
11805 	if (nout_fds) {
11806 		if (nout_fds > 128) {
11807 			job_log(j, LOG_ERR, "Too many outgoing descriptors: %lu", nout_fds);
11808 			LOG_USER_FAIL();
11809 		}
11810 
11811 		*reply_fdsCnt = nout_fds * sizeof((*reply_fdps)[0]);
11812 		mig_allocate((vm_address_t *)reply_fdps, *reply_fdsCnt);
11813 		if (!*reply_fdps) {
11814 			LOG_USER_FAIL();
11815 		}
11816 
11817 		for (i = 0; i < nout_fds; i++) {
11818 			mach_port_t fp = MACH_PORT_NULL;
11819 			/* Whatever. Worst case is that we insert MACH_PORT_NULL. Not a big
11820 			 * deal. Note, these get stuffed into an array whose disposition is
11821 			 * mach_port_move_send_t, so we don't have to worry about them after
11822 			 * returning.
11823 			 */
11824 			if (fileport_makeport(out_fds[i], &fp) != 0) {
11825 				job_log(j, LOG_ERR, "Could not pack response descriptor at index: %lu: %d: %s", i, errno, strerror(errno));
11826 			}
11827 			(*reply_fdps)[i] = fp;
11828 		}
11829 
11830 		nout_fdps = nout_fds;
11831 	} else {
11832 		*reply_fdsCnt = 0;
11833 	}
11834 
11835 	mig_deallocate(request, requestCnt);
11836 	launch_data_free(ldreply);
11837 	ldreply = NULL;
11838 
11839 	// Unused for now.
11840 	(void)launchd_mport_deallocate(asport);
11841 
11842 	return BOOTSTRAP_SUCCESS;
11843 
11844 out_bad:
11845 	for (i = 0; i < nfds; i++) {
11846 		(void)close(in_fds[i]);
11847 	}
11848 
11849 	for (i = 0; i < nout_fds; i++) {
11850 		(void)launchd_mport_deallocate((*reply_fdps)[i]);
11851 	}
11852 
11853 	if (*reply) {
11854 		mig_deallocate(*reply, *replyCnt);
11855 	}
11856 
11857 	/* We should never hit this since the last goto out is in the case that
11858 	 * allocating this fails.
11859 	 */
11860 	if (*reply_fdps) {
11861 		mig_deallocate((vm_address_t)*reply_fdps, *reply_fdsCnt);
11862 	}
11863 
11864 	if (ldreply) {
11865 		launch_data_free(ldreply);
11866 	}
11867 
11868 	RETURN_NO_MEMORY();
11869 }
11870 
11871 void
11872 jobmgr_init(bool sflag)
11873 {
11874 	const char *root_session_type = pid1_magic ? VPROCMGR_SESSION_SYSTEM : VPROCMGR_SESSION_BACKGROUND;
11875 	SLIST_INIT(&s_curious_jobs);
11876 	LIST_INIT(&s_needing_sessions);
11877 	syslog(LOG_ERR, "starting root_jobmgr");
11878 	os_assert((root_jobmgr = jobmgr_new(NULL, MACH_PORT_NULL, MACH_PORT_NULL, sflag, root_session_type, false, MACH_PORT_NULL)) != NULL);
11879 #if 0
11880 	os_assert((_s_xpc_system_domain = jobmgr_new_xpc_singleton_domain(root_jobmgr, strdup("com.apple.xpc.system"))) != NULL);
11881 	_s_xpc_system_domain->req_asid = launchd_audit_session;
11882 	_s_xpc_system_domain->req_asport = launchd_audit_port;
11883 	_s_xpc_system_domain->shortdesc = "system";
11884 #endif
11885 	if (pid1_magic) {
11886 		root_jobmgr->monitor_shutdown = true;
11887 	}
11888 
11889 	uint32_t fflags = NOTE_ATTRIB | NOTE_LINK | NOTE_REVOKE | NOTE_EXTEND | NOTE_WRITE;
11890 	s_no_hang_fd = open("/dev/autofs_nowait", O_EVTONLY | O_NONBLOCK);
11891 	if (likely(s_no_hang_fd == -1)) {
11892 		if (jobmgr_assumes_zero_p(root_jobmgr, (s_no_hang_fd = open("/dev", O_EVTONLY | O_NONBLOCK))) != -1) {
11893 			(void)jobmgr_assumes_zero_p(root_jobmgr, kevent_mod((uintptr_t)s_no_hang_fd, EVFILT_VNODE, EV_ADD, fflags, 0, root_jobmgr));
11894 		}
11895 	}
11896 	s_no_hang_fd = _fd(s_no_hang_fd);
11897 }
11898 
11899 size_t
11900 our_strhash(const char *s)
11901 {
11902 	size_t c, r = 5381;
11903 
11904 	/* djb2
11905 	 * This algorithm was first reported by Dan Bernstein many years ago in comp.lang.c
11906 	 */
11907 
11908 	while ((c = *s++)) {
11909 		r = ((r << 5) + r) + c; // hash*33 + c
11910 	}
11911 
11912 	return r;
11913 }
11914 
11915 size_t
11916 hash_label(const char *label)
11917 {
11918 	return our_strhash(label) % LABEL_HASH_SIZE;
11919 }
11920 
11921 size_t
11922 hash_ms(const char *msstr)
11923 {
11924 	return our_strhash(msstr) % MACHSERVICE_HASH_SIZE;
11925 }
11926 
11927 bool
11928 waiting4removal_new(job_t j, mach_port_t rp)
11929 {
11930 	struct waiting_for_removal *w4r;
11931 
11932 	if (!job_assumes(j, (w4r = malloc(sizeof(struct waiting_for_removal))) != NULL)) {
11933 		return false;
11934 	}
11935 
11936 	w4r->reply_port = rp;
11937 
11938 	SLIST_INSERT_HEAD(&j->removal_watchers, w4r, sle);
11939 
11940 	return true;
11941 }
11942 
11943 void
11944 waiting4removal_delete(job_t j, struct waiting_for_removal *w4r)
11945 {
11946 	(void)job_assumes_zero(j, job_mig_send_signal_reply(w4r->reply_port, 0));
11947 
11948 	SLIST_REMOVE(&j->removal_watchers, w4r, waiting_for_removal, sle);
11949 
11950 	free(w4r);
11951 }
11952 
11953 size_t
11954 get_kern_max_proc(void)
11955 {
11956 	int mib[] = { CTL_KERN, KERN_MAXPROC };
11957 	int max = 100;
11958 	size_t max_sz = sizeof(max);
11959 
11960 	(void)posix_assumes_zero(sysctl(mib, 2, &max, &max_sz, NULL, 0));
11961 
11962 	return max;
11963 }
11964 
11965 // See rdar://problem/6271234
11966 void
11967 eliminate_double_reboot(void)
11968 {
11969 	if (unlikely(!pid1_magic)) {
11970 		return;
11971 	}
11972 
11973 	struct stat sb;
11974 	const char *argv[] = { _PATH_BSHELL, "/etc/rc.deferred_install", NULL };
11975 	int result = -1;
11976 
11977 	if (unlikely(stat(argv[1], &sb) != -1)) {
11978 		jobmgr_log(root_jobmgr, LOG_DEBUG | LOG_CONSOLE, "Going to run deferred install script.");
11979 
11980 		pid_t p = 0;
11981 		result = posix_spawnp(&p, argv[0], NULL, NULL, (char **)argv, environ);
11982 		if (result == -1) {
11983 			jobmgr_log(root_jobmgr, LOG_WARNING | LOG_CONSOLE, "Couldn't run deferred install script: %d: %s", result, strerror(result));
11984 			goto out;
11985 		}
11986 
11987 		int wstatus = 0;
11988 		result = waitpid(p, &wstatus, 0);
11989 		if (result == -1) {
11990 			jobmgr_log(root_jobmgr, LOG_WARNING | LOG_CONSOLE, "Failed to reap deferred install script: %d: %s", errno, strerror(errno));
11991 			goto out;
11992 		}
11993 
11994 		if (WIFEXITED(wstatus)) {
11995 			if ((result = WEXITSTATUS(wstatus)) == 0) {
11996 				jobmgr_log(root_jobmgr, LOG_DEBUG | LOG_CONSOLE, "Deferred install script completed successfully.");
11997 			} else {
11998 				jobmgr_log(root_jobmgr, LOG_WARNING | LOG_CONSOLE, "Deferred install script failed with status: %d", WEXITSTATUS(wstatus));
11999 			}
12000 		} else {
12001 			jobmgr_log(root_jobmgr, LOG_WARNING | LOG_CONSOLE, "Weirdness with install script: %d", wstatus);
12002 		}
12003 	}
12004 out:
12005 	if (result == 0) {
12006 		/* If the unlink(2) was to fail, it would be most likely fail with
12007 		 * EBUSY. All the other failure cases for unlink(2) don't apply when
12008 		 * we're running under PID 1 and have verified that the file exists.
12009 		 * Outside of someone deliberately messing with us (like if
12010 		 * /etc/rc.deferredinstall is actually a looping sym-link or a mount
12011 		 * point for a filesystem) and I/O errors, we should be good.
12012 		 */
12013 		if (unlink(argv[1]) == -1) {
12014 			jobmgr_log(root_jobmgr, LOG_WARNING | LOG_CONSOLE, "Failed to remove deferred install script: %d: %s", errno, strerror(errno));
12015 		}
12016 	}
12017 }
12018 
12019 void
12020 jetsam_property_setup(launch_data_t obj, const char *key, job_t j)
12021 {
12022 	job_log(j, LOG_DEBUG, "Setting Jetsam properties for job...");
12023 	if (strcasecmp(key, LAUNCH_JOBKEY_JETSAMPRIORITY) == 0 && launch_data_get_type(obj) == LAUNCH_DATA_INTEGER) {
12024 		j->jetsam_priority = (typeof(j->jetsam_priority))launch_data_get_integer(obj);
12025 
12026 #if XPC_LPI_VERSION >= 20120810
12027 		if (j->jetsam_priority > XPC_JETSAM_PRIORITY_RESERVED && j->jetsam_priority < XPC_JETSAM_PRIORITY_RESERVED + XPC_JETSAM_BAND_LAST) {
12028 			size_t band = j->jetsam_priority - XPC_JETSAM_PRIORITY_RESERVED;
12029 			j->jetsam_priority = _launchd_priority_map[band - 1].priority;
12030 		}
12031 #endif
12032 		job_log(j, LOG_DEBUG, "Priority: %d", j->jetsam_priority);
12033 	} else if (strcasecmp(key, LAUNCH_JOBKEY_JETSAMMEMORYLIMIT) == 0 && launch_data_get_type(obj) == LAUNCH_DATA_INTEGER) {
12034 		j->jetsam_memlimit = (typeof(j->jetsam_memlimit))launch_data_get_integer(obj);
12035 		job_log(j, LOG_DEBUG, "Memory limit: %d", j->jetsam_memlimit);
12036 	} else if (strcasecmp(key, LAUNCH_JOBKEY_JETSAMMEMORYLIMITBACKGROUND) == 0) {
12037 		j->jetsam_memory_limit_background = true;
12038 		job_log(j, LOG_DEBUG, "Memory limit is for background state only");
12039 	} else if (strcasecmp(key, LAUNCH_KEY_JETSAMFRONTMOST) == 0) {
12040 		/* Ignore. We only recognize this key so we don't complain when we get SpringBoard's request.
12041 		 * You can't set this in a plist.
12042 		 */
12043 	} else if (strcasecmp(key, LAUNCH_KEY_JETSAMACTIVE) == 0) {
12044 		// Ignore.
12045 	} else if (strcasecmp(key, LAUNCH_KEY_JETSAMLABEL) == 0) {
12046 		/* Ignore. This key is present in SpringBoard's request dictionary, so we don't want to
12047 		 * complain about it.
12048 		 */
12049 	} else {
12050 		job_log(j, LOG_ERR, "Unknown Jetsam key: %s", key);
12051 	}
12052 
12053 	if (unlikely(!j->jetsam_properties)) {
12054 		j->jetsam_properties = true;
12055 	}
12056 }
12057 
12058 void
12059 job_update_jetsam_properties(job_t j, xpc_jetsam_band_t band, uint64_t user_data)
12060 {
12061 #if TARGET_OS_EMBEDDED
12062 	j->jetsam_priority = _launchd_priority_map[band - 1].priority;
12063 	j->jetsam_properties = true;
12064 
12065 	memorystatus_priority_properties_t mjp;
12066 	mjp.priority = j->jetsam_priority;
12067 	mjp.user_data = user_data;
12068 
12069 	size_t size = sizeof(mjp);
12070 	int r = memorystatus_control(MEMORYSTATUS_CMD_SET_PRIORITY_PROPERTIES, j->p, 0, &mjp, size);
12071 	if (r == -1 && errno != ESRCH) {
12072 		(void)job_assumes_zero(j, errno);
12073 	}
12074 #else
12075 #pragma unused(j, band, user_data)
12076 #endif
12077 }
12078 
12079 void
12080 job_update_jetsam_memory_limit(job_t j, int32_t limit)
12081 {
12082 #if TARGET_OS_EMBEDDED
12083 	j->jetsam_memlimit = limit;
12084 	j->jetsam_properties = true;
12085 
12086 	int r = memorystatus_control(MEMORYSTATUS_CMD_SET_JETSAM_HIGH_WATER_MARK, j->p, limit, NULL, 0);
12087 	if (r == -1 && errno != ESRCH) {
12088 		(void)job_assumes_zero(j, errno);
12089 	}
12090 #else
12091 #pragma unused(j, limit)
12092 #endif
12093 }
12094 
12095 void
12096 _log_launchd_bug(const char *rcs_rev, const char *path, unsigned int line, const char *test)
12097 {
12098         int saved_errno = errno;
12099         char buf[100];
12100         const char *file = strrchr(path, '/');
12101         char *rcs_rev_tmp = strchr(rcs_rev, ' ');
12102 
12103         if (!file) {
12104                 file = path;
12105         } else {
12106                 file += 1;
12107         }
12108 
12109         if (!rcs_rev_tmp) {
12110                 strlcpy(buf, rcs_rev, sizeof(buf));
12111         } else {
12112                 strlcpy(buf, rcs_rev_tmp + 1, sizeof(buf));
12113                 rcs_rev_tmp = strchr(buf, ' ');
12114                 if (rcs_rev_tmp)
12115                         *rcs_rev_tmp = '\0';
12116         }
12117 
12118         syslog(LOG_NOTICE, "Bug: %s:%u (%s):%u: %s", file, line, buf, saved_errno, test);
12119 }
12120 
12121 pid_t
12122 launchd_fork(void)
12123 {
12124 
12125 	return (runtime_fork(root_jobmgr->jm_port));
12126 }
12127