xref: /xnu-8792.61.2/bsd/kern/kern_ktrace.c (revision 42e220869062b56f8d7d0726fd4c88954f87902c)
1 /*
2  * Copyright (c) 2015-2017 Apple Inc. All rights reserved.
3  *
4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5  *
6  * This file contains Original Code and/or Modifications of Original Code
7  * as defined in and that are subject to the Apple Public Source License
8  * Version 2.0 (the 'License'). You may not use this file except in
9  * compliance with the License. The rights granted to you under the License
10  * may not be used to create, or enable the creation or redistribution of,
11  * unlawful or unlicensed copies of an Apple operating system, or to
12  * circumvent, violate, or enable the circumvention or violation of, any
13  * terms of an Apple operating system software license agreement.
14  *
15  * Please obtain a copy of the License at
16  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17  *
18  * The Original Code and all software distributed under the License are
19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23  * Please see the License for the specific language governing rights and
24  * limitations under the License.
25  *
26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27  */
28 
29 /*
30  * This file manages the ownership of ktrace and its subsystems, like kdebug
31  * and kperf, as well as the overall state of the system, whether it is in
32  * foreground or background mode.
33  *
34  * When unconfigured or in background mode, any root process can take ownership
35  * of ktrace and configure it, changing the state to foreground and, in the case
36  * of a transition out of background, resetting the background configuration.
37  *
38  * When in foreground mode, if the owning process is still running, only it may
39  * configure ktrace.  If it exits, ktrace keeps running but any root process can
40  * change the configuration.  When ktrace is reset, the state changes back to
41  * unconfigured and a notification is sent on the ktrace_background host special
42  * port.
43  *
44  * If a process has set itself as the background tool, using the init_background
45  * sysctl, it can configure ktrace only when ktrace is off or already in
46  * background mode.  The first attempt to configure ktrace by the background pid
47  * when it is off results in the transition to background mode.
48  */
49 
50 #include <sys/ktrace.h>
51 
52 #include <mach/host_priv.h>
53 #include <mach/mach_types.h>
54 #include <mach/ktrace_background.h>
55 
56 #include <sys/kauth.h>
57 #include <sys/priv.h>
58 #include <sys/proc.h>
59 char *proc_name_address(void *p);
60 #include <sys/sysctl.h>
61 #include <sys/vm.h>
62 #include <os/log.h>
63 
64 #include <kern/locks.h>
65 #include <kern/assert.h>
66 
67 #include <sys/kdebug.h>
68 #include <kperf/kperf.h>
69 
70 #include <kern/host.h>
71 
72 kern_return_t ktrace_background_available_notify_user(void);
73 
74 static LCK_GRP_DECLARE(ktrace_grp, "ktrace");
75 static LCK_MTX_DECLARE(ktrace_mtx, &ktrace_grp);
76 
77 /*
78  * The overall state of ktrace, whether it is unconfigured, in foreground mode,
79  * or in background mode.  The state determines which processes can configure
80  * ktrace.
81  */
82 static ktrace_state_t ktrace_state = KTRACE_STATE_OFF;
83 
84 /* The true owner of ktrace, checked by ktrace_access_check(). */
85 static uint64_t ktrace_owning_unique_id = 0;
86 static pid_t ktrace_owning_pid = 0;
87 
88 /*
89  * The background pid of ktrace, automatically made the owner when
90  * transitioning to background mode.
91  */
92 static uint64_t ktrace_bg_unique_id = 0;
93 static pid_t ktrace_bg_pid = 0;
94 
95 /* The name of the last process to configure ktrace. */
96 static char ktrace_last_owner_execname[MAXCOMLEN + 1] = { 0 };
97 
98 /*
99  * Which subsystems of ktrace (currently kdebug and kperf) are active.
100  */
101 static uint32_t ktrace_active_mask = 0;
102 
103 /*
104  * At boot or when a daemon has been newly loaded, it's necessary to bootstrap
105  * user space background tools by sending a background available notification
106  * when the init_background sysctl is made.
107  *
108  * Background tools must be RunAtLoad daemons.
109  */
110 static bool should_notify_on_init = true;
111 
112 /* Set the owning process of ktrace. */
113 static void ktrace_set_owning_proc(proc_t p);
114 
115 /* Reset ktrace ownership back to unowned. */
116 static void ktrace_release_ownership(void);
117 
118 /* Make the background tool the owner of ktrace. */
119 static void ktrace_promote_background(void);
120 
121 /*
122  * If user space sets a pid manually (through kperf "blessing"), ktrace should
123  * not treat resets as releasing ownership.  At that point, ownership is only
124  * released when the owner is set to an invalid pid.
125  *
126  * This is managed by the user space-oriented function ktrace_set_owning_pid
127  * and ktrace_unset_owning_pid.
128  */
129 bool ktrace_keep_ownership_on_reset = false;
130 
131 /* Whether the kernel is the owner of ktrace. */
132 bool ktrace_owner_kernel = false;
133 
134 /* Allow user space to unset the owning pid and potentially reset ktrace. */
135 static void ktrace_set_invalid_owning_pid(void);
136 
137 /*
138  * This flag allows any root process to set a new ktrace owner.  It is
139  * currently used by Instruments.
140  */
141 int ktrace_root_set_owner_allowed = 0;
142 
143 /*
144  * If ktrace is guaranteed that it's the only thread running on the system
145  * (e.g., during boot or wake) this flag disables locking requirements.
146  */
147 static bool ktrace_single_threaded = false;
148 
149 __startup_func
150 static void
ktrace_startup(void)151 ktrace_startup(void)
152 {
153 	extern void kpc_init(void);
154 #if KPC
155 	kpc_init();
156 #endif /* KPC */
157 #if KPERF
158 	kperf_init();
159 #endif /* KPERF */
160 	kdebug_startup();
161 }
162 STARTUP(KTRACE, STARTUP_RANK_FIRST, ktrace_startup);
163 
164 void
ktrace_lock(void)165 ktrace_lock(void)
166 {
167 	if (!ktrace_single_threaded) {
168 		lck_mtx_lock(&ktrace_mtx);
169 	}
170 }
171 
172 void
ktrace_unlock(void)173 ktrace_unlock(void)
174 {
175 	if (!ktrace_single_threaded) {
176 		lck_mtx_unlock(&ktrace_mtx);
177 	}
178 }
179 
180 void
ktrace_assert_lock_held(void)181 ktrace_assert_lock_held(void)
182 {
183 	if (!ktrace_single_threaded) {
184 		lck_mtx_assert(&ktrace_mtx, LCK_MTX_ASSERT_OWNED);
185 	}
186 }
187 
188 void
ktrace_start_single_threaded(void)189 ktrace_start_single_threaded(void)
190 {
191 	ktrace_single_threaded = true;
192 }
193 
194 void
ktrace_end_single_threaded(void)195 ktrace_end_single_threaded(void)
196 {
197 	ktrace_single_threaded = false;
198 }
199 
200 static void
ktrace_reset_internal(uint32_t reset_mask)201 ktrace_reset_internal(uint32_t reset_mask)
202 {
203 	if (!ktrace_keep_ownership_on_reset) {
204 		ktrace_active_mask &= ~reset_mask;
205 	}
206 
207 	if (reset_mask & KTRACE_KPERF) {
208 		kperf_reset();
209 	}
210 	if (reset_mask & KTRACE_KDEBUG) {
211 		kdebug_reset();
212 	}
213 
214 	if (ktrace_active_mask == 0) {
215 		if (ktrace_state == KTRACE_STATE_FG) {
216 			/* transition from foreground to background */
217 			ktrace_promote_background();
218 		} else if (ktrace_state == KTRACE_STATE_BG) {
219 			/* background tool is resetting ktrace */
220 			should_notify_on_init = true;
221 			ktrace_release_ownership();
222 			ktrace_state = KTRACE_STATE_OFF;
223 		}
224 	}
225 }
226 
227 void
ktrace_reset(uint32_t reset_mask)228 ktrace_reset(uint32_t reset_mask)
229 {
230 	ktrace_assert_lock_held();
231 
232 	if (ktrace_active_mask == 0) {
233 		if (!ktrace_keep_ownership_on_reset) {
234 			assert(ktrace_state == KTRACE_STATE_OFF);
235 		}
236 		return;
237 	}
238 
239 	ktrace_reset_internal(reset_mask);
240 }
241 
242 static void
ktrace_promote_background(void)243 ktrace_promote_background(void)
244 {
245 	assert(ktrace_state != KTRACE_STATE_BG);
246 
247 	os_log(OS_LOG_DEFAULT, "ktrace: promoting background tool");
248 
249 	/*
250 	 * Remember to send a background available notification on the next init
251 	 * if the notification failed (meaning no task holds the receive right
252 	 * for the host special port).
253 	 */
254 	if (ktrace_background_available_notify_user() == KERN_FAILURE) {
255 		should_notify_on_init = true;
256 	} else {
257 		should_notify_on_init = false;
258 	}
259 
260 	ktrace_release_ownership();
261 	ktrace_state = KTRACE_STATE_OFF;
262 }
263 
264 bool
ktrace_background_active(void)265 ktrace_background_active(void)
266 {
267 	return ktrace_state == KTRACE_STATE_BG;
268 }
269 
270 int
ktrace_read_check(void)271 ktrace_read_check(void)
272 {
273 	ktrace_assert_lock_held();
274 
275 	if (proc_uniqueid(current_proc()) == ktrace_owning_unique_id) {
276 		return 0;
277 	}
278 
279 	return kauth_cred_issuser(kauth_cred_get()) ? 0 : EPERM;
280 }
281 
282 /* If an owning process has exited, reset the ownership. */
283 static void
ktrace_ownership_maintenance(void)284 ktrace_ownership_maintenance(void)
285 {
286 	ktrace_assert_lock_held();
287 
288 	/* do nothing if ktrace is not owned */
289 	if (ktrace_owning_unique_id == 0) {
290 		return;
291 	}
292 
293 	/* reset ownership if process cannot be found */
294 
295 	proc_t owning_proc = proc_find(ktrace_owning_pid);
296 
297 	if (owning_proc != NULL) {
298 		/* make sure the pid was not recycled */
299 		if (proc_uniqueid(owning_proc) != ktrace_owning_unique_id) {
300 			ktrace_release_ownership();
301 		}
302 
303 		proc_rele(owning_proc);
304 	} else {
305 		ktrace_release_ownership();
306 	}
307 }
308 
309 int
ktrace_configure(uint32_t config_mask)310 ktrace_configure(uint32_t config_mask)
311 {
312 	ktrace_assert_lock_held();
313 	assert(config_mask != 0);
314 
315 	proc_t p = current_proc();
316 
317 	/* if process clearly owns ktrace, allow */
318 	if (proc_uniqueid(p) == ktrace_owning_unique_id) {
319 		ktrace_active_mask |= config_mask;
320 		return 0;
321 	}
322 
323 	/* background configure while foreground is active is not allowed */
324 	if (proc_uniqueid(p) == ktrace_bg_unique_id &&
325 	    ktrace_state == KTRACE_STATE_FG) {
326 		return EBUSY;
327 	}
328 
329 	ktrace_ownership_maintenance();
330 
331 	/* allow process to gain control when unowned or background */
332 	if (ktrace_owning_unique_id == 0 || ktrace_state == KTRACE_STATE_BG) {
333 		if (!kauth_cred_issuser(kauth_cred_get())) {
334 			return EPERM;
335 		}
336 
337 		ktrace_owner_kernel = false;
338 		ktrace_set_owning_proc(p);
339 		ktrace_active_mask |= config_mask;
340 		return 0;
341 	}
342 
343 	/* owned by an existing, different process */
344 	return EBUSY;
345 }
346 
347 void
ktrace_disable(ktrace_state_t state_to_match)348 ktrace_disable(ktrace_state_t state_to_match)
349 {
350 	if (ktrace_state == state_to_match) {
351 		kernel_debug_disable();
352 		kperf_disable_sampling();
353 	}
354 }
355 
356 int
ktrace_get_owning_pid(void)357 ktrace_get_owning_pid(void)
358 {
359 	ktrace_assert_lock_held();
360 
361 	ktrace_ownership_maintenance();
362 	return ktrace_owning_pid;
363 }
364 
365 void
ktrace_kernel_configure(uint32_t config_mask)366 ktrace_kernel_configure(uint32_t config_mask)
367 {
368 	assert(ktrace_single_threaded == true);
369 
370 	if (ktrace_owner_kernel) {
371 		ktrace_active_mask |= config_mask;
372 		return;
373 	}
374 
375 	if (ktrace_state != KTRACE_STATE_OFF) {
376 		if (ktrace_active_mask & config_mask & KTRACE_KPERF) {
377 			kperf_reset();
378 		}
379 		if (ktrace_active_mask & config_mask & KTRACE_KDEBUG) {
380 			kdebug_reset();
381 		}
382 	}
383 
384 	ktrace_owner_kernel = true;
385 	ktrace_active_mask |= config_mask;
386 	ktrace_state = KTRACE_STATE_FG;
387 
388 	ktrace_release_ownership();
389 	strlcpy(ktrace_last_owner_execname, "kernel_task",
390 	    sizeof(ktrace_last_owner_execname));
391 }
392 
393 static errno_t
ktrace_init_background(void)394 ktrace_init_background(void)
395 {
396 	int err = 0;
397 
398 	ktrace_assert_lock_held();
399 
400 	if ((err = priv_check_cred(kauth_cred_get(), PRIV_KTRACE_BACKGROUND, 0))) {
401 		return err;
402 	}
403 
404 	/*
405 	 * When a background tool first checks in, send a notification if ktrace
406 	 * is available.
407 	 */
408 	if (should_notify_on_init) {
409 		if (ktrace_state == KTRACE_STATE_OFF) {
410 			/*
411 			 * This notification can only fail if a process does not
412 			 * hold the receive right for the host special port.
413 			 * Return an error and don't make the current process
414 			 * the background tool.
415 			 */
416 			if (ktrace_background_available_notify_user() == KERN_FAILURE) {
417 				return EINVAL;
418 			}
419 		}
420 		should_notify_on_init = false;
421 	}
422 
423 	proc_t p = current_proc();
424 
425 	ktrace_bg_unique_id = proc_uniqueid(p);
426 	ktrace_bg_pid = proc_pid(p);
427 
428 	if (ktrace_state == KTRACE_STATE_BG) {
429 		ktrace_set_owning_proc(p);
430 	}
431 
432 	return 0;
433 }
434 
435 void
ktrace_set_invalid_owning_pid(void)436 ktrace_set_invalid_owning_pid(void)
437 {
438 	os_log(OS_LOG_DEFAULT, "ktrace: manually invalidating owning process");
439 	if (ktrace_keep_ownership_on_reset) {
440 		ktrace_keep_ownership_on_reset = false;
441 		ktrace_reset_internal(ktrace_active_mask);
442 	}
443 }
444 
445 int
ktrace_set_owning_pid(int pid)446 ktrace_set_owning_pid(int pid)
447 {
448 	ktrace_assert_lock_held();
449 
450 	/* allow user space to successfully unset owning pid */
451 	if (pid == -1) {
452 		ktrace_set_invalid_owning_pid();
453 		return 0;
454 	}
455 
456 	/* use ktrace_reset or ktrace_release_ownership, not this */
457 	if (pid == 0) {
458 		ktrace_set_invalid_owning_pid();
459 		return EINVAL;
460 	}
461 
462 	proc_t p = proc_find(pid);
463 	if (!p) {
464 		ktrace_set_invalid_owning_pid();
465 		return ESRCH;
466 	}
467 
468 	ktrace_keep_ownership_on_reset = true;
469 	os_log(OS_LOG_DEFAULT, "ktrace: manually setting owning process");
470 	ktrace_set_owning_proc(p);
471 
472 	proc_rele(p);
473 	return 0;
474 }
475 
476 static void
ktrace_set_owning_proc(proc_t p)477 ktrace_set_owning_proc(proc_t p)
478 {
479 	ktrace_assert_lock_held();
480 	assert(p != NULL);
481 	ktrace_state_t old_state = ktrace_state;
482 
483 	if (ktrace_state != KTRACE_STATE_FG) {
484 		if (proc_uniqueid(p) == ktrace_bg_unique_id) {
485 			ktrace_state = KTRACE_STATE_BG;
486 		} else {
487 			if (ktrace_state == KTRACE_STATE_BG) {
488 				if (ktrace_active_mask & KTRACE_KPERF) {
489 					kperf_reset();
490 				}
491 				if (ktrace_active_mask & KTRACE_KDEBUG) {
492 					kdebug_reset();
493 				}
494 
495 				ktrace_active_mask = 0;
496 			}
497 			ktrace_state = KTRACE_STATE_FG;
498 			should_notify_on_init = false;
499 		}
500 	}
501 
502 	ktrace_owner_kernel = false;
503 	ktrace_owning_unique_id = proc_uniqueid(p);
504 	ktrace_owning_pid = proc_pid(p);
505 	strlcpy(ktrace_last_owner_execname, proc_name_address(p),
506 	    sizeof(ktrace_last_owner_execname));
507 	os_log(OS_LOG_DEFAULT, "ktrace: changing state from %d to %d, owned by "
508 	    "%s[%d]", old_state, ktrace_state, ktrace_last_owner_execname,
509 	    ktrace_owning_pid);
510 }
511 
512 static void
ktrace_release_ownership(void)513 ktrace_release_ownership(void)
514 {
515 	ktrace_owning_unique_id = 0;
516 	ktrace_owning_pid = 0;
517 }
518 
519 #define SYSCTL_INIT_BACKGROUND (1)
520 
521 static int ktrace_sysctl SYSCTL_HANDLER_ARGS;
522 
523 SYSCTL_NODE(, OID_AUTO, ktrace, CTLFLAG_RW | CTLFLAG_LOCKED, 0, "ktrace");
524 
525 SYSCTL_UINT(_ktrace, OID_AUTO, state, CTLFLAG_RD | CTLFLAG_LOCKED,
526     &ktrace_state, 0,
527     "");
528 
529 SYSCTL_UINT(_ktrace, OID_AUTO, active_mask, CTLFLAG_RD | CTLFLAG_LOCKED,
530     &ktrace_active_mask, 0,
531     "");
532 
533 SYSCTL_INT(_ktrace, OID_AUTO, owning_pid, CTLFLAG_RD | CTLFLAG_LOCKED,
534     &ktrace_owning_pid, 0,
535     "pid of the process that owns ktrace");
536 
537 SYSCTL_INT(_ktrace, OID_AUTO, background_pid, CTLFLAG_RD | CTLFLAG_LOCKED,
538     &ktrace_bg_pid, 0,
539     "pid of the background ktrace tool");
540 
541 SYSCTL_STRING(_ktrace, OID_AUTO, configured_by, CTLFLAG_RD | CTLFLAG_LOCKED,
542     ktrace_last_owner_execname, 0,
543     "execname of process that last configured ktrace");
544 
545 SYSCTL_PROC(_ktrace, OID_AUTO, init_background, CTLFLAG_RW | CTLFLAG_LOCKED,
546     (void *)SYSCTL_INIT_BACKGROUND, sizeof(int),
547     ktrace_sysctl, "I", "initialize calling process as background");
548 
549 static int
550 ktrace_sysctl SYSCTL_HANDLER_ARGS
551 {
552 #pragma unused(oidp, arg2)
553 	int ret = 0;
554 	uintptr_t type = (uintptr_t)arg1;
555 
556 	ktrace_lock();
557 
558 	if (!kauth_cred_issuser(kauth_cred_get())) {
559 		ret = EPERM;
560 		goto out;
561 	}
562 
563 	if (type == SYSCTL_INIT_BACKGROUND) {
564 		if (req->newptr != USER_ADDR_NULL) {
565 			ret = ktrace_init_background();
566 			goto out;
567 		} else {
568 			ret = EINVAL;
569 			goto out;
570 		}
571 	} else {
572 		ret = EINVAL;
573 		goto out;
574 	}
575 
576 out:
577 	ktrace_unlock();
578 	return ret;
579 }
580