xref: /xnu-8020.121.3/bsd/kern/kern_ktrace.c (revision fdd8201d7b966f0c3ea610489d29bd841d358941)
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 
63 #include <kern/locks.h>
64 #include <kern/assert.h>
65 
66 #include <sys/kdebug.h>
67 #include <kperf/kperf.h>
68 
69 #include <kern/host.h>
70 
71 kern_return_t ktrace_background_available_notify_user(void);
72 
73 static LCK_GRP_DECLARE(ktrace_grp, "ktrace");
74 static LCK_MTX_DECLARE(ktrace_mtx, &ktrace_grp);
75 
76 /*
77  * The overall state of ktrace, whether it is unconfigured, in foreground mode,
78  * or in background mode.  The state determines which processes can configure
79  * ktrace.
80  */
81 static enum ktrace_state ktrace_state = KTRACE_STATE_OFF;
82 
83 /* The true owner of ktrace, checked by ktrace_access_check(). */
84 static uint64_t ktrace_owning_unique_id = 0;
85 static pid_t ktrace_owning_pid = 0;
86 
87 /*
88  * The background pid of ktrace, automatically made the owner when
89  * transitioning to background mode.
90  */
91 static uint64_t ktrace_bg_unique_id = 0;
92 static pid_t ktrace_bg_pid = 0;
93 
94 /* The name of the last process to configure ktrace. */
95 static char ktrace_last_owner_execname[MAXCOMLEN + 1] = { 0 };
96 
97 /*
98  * Which subsystems of ktrace (currently kdebug and kperf) are active.
99  */
100 static uint32_t ktrace_active_mask = 0;
101 
102 /*
103  * At boot or when a daemon has been newly loaded, it's necessary to bootstrap
104  * user space background tools by sending a background available notification
105  * when the init_background sysctl is made.
106  *
107  * Background tools must be RunAtLoad daemons.
108  */
109 static bool should_notify_on_init = true;
110 
111 /* Set the owning process of ktrace. */
112 static void ktrace_set_owning_proc(proc_t p);
113 
114 /* Reset ktrace ownership back to unowned. */
115 static void ktrace_release_ownership(void);
116 
117 /* Make the background tool the owner of ktrace. */
118 static void ktrace_promote_background(void);
119 
120 /*
121  * If user space sets a pid manually (through kperf "blessing"), ktrace should
122  * not treat resets as releasing ownership.  At that point, ownership is only
123  * released when the owner is set to an invalid pid.
124  *
125  * This is managed by the user space-oriented function ktrace_set_owning_pid
126  * and ktrace_unset_owning_pid.
127  */
128 bool ktrace_keep_ownership_on_reset = false;
129 
130 /* Whether the kernel is the owner of ktrace. */
131 bool ktrace_owner_kernel = false;
132 
133 /* Allow user space to unset the owning pid and potentially reset ktrace. */
134 static void ktrace_set_invalid_owning_pid(void);
135 
136 /*
137  * This flag allows any root process to set a new ktrace owner.  It is
138  * currently used by Instruments.
139  */
140 int ktrace_root_set_owner_allowed = 0;
141 
142 /*
143  * If ktrace is guaranteed that it's the only thread running on the system
144  * (e.g., during boot or wake) this flag disables locking requirements.
145  */
146 static bool ktrace_single_threaded = false;
147 
148 void
ktrace_lock(void)149 ktrace_lock(void)
150 {
151 	if (!ktrace_single_threaded) {
152 		lck_mtx_lock(&ktrace_mtx);
153 	}
154 }
155 
156 void
ktrace_unlock(void)157 ktrace_unlock(void)
158 {
159 	if (!ktrace_single_threaded) {
160 		lck_mtx_unlock(&ktrace_mtx);
161 	}
162 }
163 
164 void
ktrace_assert_lock_held(void)165 ktrace_assert_lock_held(void)
166 {
167 	if (!ktrace_single_threaded) {
168 		lck_mtx_assert(&ktrace_mtx, LCK_MTX_ASSERT_OWNED);
169 	}
170 }
171 
172 void
ktrace_start_single_threaded(void)173 ktrace_start_single_threaded(void)
174 {
175 	ktrace_single_threaded = true;
176 }
177 
178 void
ktrace_end_single_threaded(void)179 ktrace_end_single_threaded(void)
180 {
181 	ktrace_single_threaded = false;
182 }
183 
184 static void
ktrace_reset_internal(uint32_t reset_mask)185 ktrace_reset_internal(uint32_t reset_mask)
186 {
187 	if (!ktrace_keep_ownership_on_reset) {
188 		ktrace_active_mask &= ~reset_mask;
189 	}
190 
191 	if (reset_mask & KTRACE_KPERF) {
192 		kperf_reset();
193 	}
194 	if (reset_mask & KTRACE_KDEBUG) {
195 		kdebug_reset();
196 	}
197 
198 	if (ktrace_active_mask == 0) {
199 		if (ktrace_state == KTRACE_STATE_FG) {
200 			/* transition from foreground to background */
201 			ktrace_promote_background();
202 		} else if (ktrace_state == KTRACE_STATE_BG) {
203 			/* background tool is resetting ktrace */
204 			should_notify_on_init = true;
205 			ktrace_release_ownership();
206 			ktrace_state = KTRACE_STATE_OFF;
207 		}
208 	}
209 }
210 
211 void
ktrace_reset(uint32_t reset_mask)212 ktrace_reset(uint32_t reset_mask)
213 {
214 	ktrace_assert_lock_held();
215 
216 	if (ktrace_active_mask == 0) {
217 		if (!ktrace_keep_ownership_on_reset) {
218 			assert(ktrace_state == KTRACE_STATE_OFF);
219 		}
220 		return;
221 	}
222 
223 	ktrace_reset_internal(reset_mask);
224 }
225 
226 static void
ktrace_promote_background(void)227 ktrace_promote_background(void)
228 {
229 	assert(ktrace_state != KTRACE_STATE_BG);
230 
231 	/*
232 	 * Remember to send a background available notification on the next init
233 	 * if the notification failed (meaning no task holds the receive right
234 	 * for the host special port).
235 	 */
236 	if (ktrace_background_available_notify_user() == KERN_FAILURE) {
237 		should_notify_on_init = true;
238 	} else {
239 		should_notify_on_init = false;
240 	}
241 
242 	ktrace_release_ownership();
243 	ktrace_state = KTRACE_STATE_OFF;
244 }
245 
246 bool
ktrace_background_active(void)247 ktrace_background_active(void)
248 {
249 	return ktrace_state == KTRACE_STATE_BG;
250 }
251 
252 int
ktrace_read_check(void)253 ktrace_read_check(void)
254 {
255 	ktrace_assert_lock_held();
256 
257 	if (proc_uniqueid(current_proc()) == ktrace_owning_unique_id) {
258 		return 0;
259 	}
260 
261 	return kauth_cred_issuser(kauth_cred_get()) ? 0 : EPERM;
262 }
263 
264 /* If an owning process has exited, reset the ownership. */
265 static void
ktrace_ownership_maintenance(void)266 ktrace_ownership_maintenance(void)
267 {
268 	ktrace_assert_lock_held();
269 
270 	/* do nothing if ktrace is not owned */
271 	if (ktrace_owning_unique_id == 0) {
272 		return;
273 	}
274 
275 	/* reset ownership if process cannot be found */
276 
277 	proc_t owning_proc = proc_find(ktrace_owning_pid);
278 
279 	if (owning_proc != NULL) {
280 		/* make sure the pid was not recycled */
281 		if (proc_uniqueid(owning_proc) != ktrace_owning_unique_id) {
282 			ktrace_release_ownership();
283 		}
284 
285 		proc_rele(owning_proc);
286 	} else {
287 		ktrace_release_ownership();
288 	}
289 }
290 
291 int
ktrace_configure(uint32_t config_mask)292 ktrace_configure(uint32_t config_mask)
293 {
294 	ktrace_assert_lock_held();
295 	assert(config_mask != 0);
296 
297 	proc_t p = current_proc();
298 
299 	/* if process clearly owns ktrace, allow */
300 	if (proc_uniqueid(p) == ktrace_owning_unique_id) {
301 		ktrace_active_mask |= config_mask;
302 		return 0;
303 	}
304 
305 	/* background configure while foreground is active is not allowed */
306 	if (proc_uniqueid(p) == ktrace_bg_unique_id &&
307 	    ktrace_state == KTRACE_STATE_FG) {
308 		return EBUSY;
309 	}
310 
311 	ktrace_ownership_maintenance();
312 
313 	/* allow process to gain control when unowned or background */
314 	if (ktrace_owning_unique_id == 0 || ktrace_state == KTRACE_STATE_BG) {
315 		if (!kauth_cred_issuser(kauth_cred_get())) {
316 			return EPERM;
317 		}
318 
319 		ktrace_owner_kernel = false;
320 		ktrace_set_owning_proc(p);
321 		ktrace_active_mask |= config_mask;
322 		return 0;
323 	}
324 
325 	/* owned by an existing, different process */
326 	return EBUSY;
327 }
328 
329 void
ktrace_disable(enum ktrace_state state_to_match)330 ktrace_disable(enum ktrace_state state_to_match)
331 {
332 	if (ktrace_state == state_to_match) {
333 		kernel_debug_disable();
334 		kperf_disable_sampling();
335 	}
336 }
337 
338 int
ktrace_get_owning_pid(void)339 ktrace_get_owning_pid(void)
340 {
341 	ktrace_assert_lock_held();
342 
343 	ktrace_ownership_maintenance();
344 	return ktrace_owning_pid;
345 }
346 
347 void
ktrace_kernel_configure(uint32_t config_mask)348 ktrace_kernel_configure(uint32_t config_mask)
349 {
350 	assert(ktrace_single_threaded == true);
351 
352 	if (ktrace_owner_kernel) {
353 		ktrace_active_mask |= config_mask;
354 		return;
355 	}
356 
357 	if (ktrace_state != KTRACE_STATE_OFF) {
358 		if (ktrace_active_mask & config_mask & KTRACE_KPERF) {
359 			kperf_reset();
360 		}
361 		if (ktrace_active_mask & config_mask & KTRACE_KDEBUG) {
362 			kdebug_reset();
363 		}
364 	}
365 
366 	ktrace_owner_kernel = true;
367 	ktrace_active_mask |= config_mask;
368 	ktrace_state = KTRACE_STATE_FG;
369 
370 	ktrace_release_ownership();
371 	strlcpy(ktrace_last_owner_execname, "kernel_task",
372 	    sizeof(ktrace_last_owner_execname));
373 }
374 
375 static errno_t
ktrace_init_background(void)376 ktrace_init_background(void)
377 {
378 	int err = 0;
379 
380 	ktrace_assert_lock_held();
381 
382 	if ((err = priv_check_cred(kauth_cred_get(), PRIV_KTRACE_BACKGROUND, 0))) {
383 		return err;
384 	}
385 
386 	/*
387 	 * When a background tool first checks in, send a notification if ktrace
388 	 * is available.
389 	 */
390 	if (should_notify_on_init) {
391 		if (ktrace_state == KTRACE_STATE_OFF) {
392 			/*
393 			 * This notification can only fail if a process does not
394 			 * hold the receive right for the host special port.
395 			 * Return an error and don't make the current process
396 			 * the background tool.
397 			 */
398 			if (ktrace_background_available_notify_user() == KERN_FAILURE) {
399 				return EINVAL;
400 			}
401 		}
402 		should_notify_on_init = false;
403 	}
404 
405 	proc_t p = current_proc();
406 
407 	ktrace_bg_unique_id = proc_uniqueid(p);
408 	ktrace_bg_pid = proc_pid(p);
409 
410 	if (ktrace_state == KTRACE_STATE_BG) {
411 		ktrace_set_owning_proc(p);
412 	}
413 
414 	return 0;
415 }
416 
417 void
ktrace_set_invalid_owning_pid(void)418 ktrace_set_invalid_owning_pid(void)
419 {
420 	if (ktrace_keep_ownership_on_reset) {
421 		ktrace_keep_ownership_on_reset = false;
422 		ktrace_reset_internal(ktrace_active_mask);
423 	}
424 }
425 
426 int
ktrace_set_owning_pid(int pid)427 ktrace_set_owning_pid(int pid)
428 {
429 	ktrace_assert_lock_held();
430 
431 	/* allow user space to successfully unset owning pid */
432 	if (pid == -1) {
433 		ktrace_set_invalid_owning_pid();
434 		return 0;
435 	}
436 
437 	/* use ktrace_reset or ktrace_release_ownership, not this */
438 	if (pid == 0) {
439 		ktrace_set_invalid_owning_pid();
440 		return EINVAL;
441 	}
442 
443 	proc_t p = proc_find(pid);
444 	if (!p) {
445 		ktrace_set_invalid_owning_pid();
446 		return ESRCH;
447 	}
448 
449 	ktrace_keep_ownership_on_reset = true;
450 	ktrace_set_owning_proc(p);
451 
452 	proc_rele(p);
453 	return 0;
454 }
455 
456 static void
ktrace_set_owning_proc(proc_t p)457 ktrace_set_owning_proc(proc_t p)
458 {
459 	ktrace_assert_lock_held();
460 	assert(p != NULL);
461 
462 	if (ktrace_state != KTRACE_STATE_FG) {
463 		if (proc_uniqueid(p) == ktrace_bg_unique_id) {
464 			ktrace_state = KTRACE_STATE_BG;
465 		} else {
466 			if (ktrace_state == KTRACE_STATE_BG) {
467 				if (ktrace_active_mask & KTRACE_KPERF) {
468 					kperf_reset();
469 				}
470 				if (ktrace_active_mask & KTRACE_KDEBUG) {
471 					kdebug_reset();
472 				}
473 
474 				ktrace_active_mask = 0;
475 			}
476 			ktrace_state = KTRACE_STATE_FG;
477 			should_notify_on_init = false;
478 		}
479 	}
480 
481 	ktrace_owner_kernel = false;
482 	ktrace_owning_unique_id = proc_uniqueid(p);
483 	ktrace_owning_pid = proc_pid(p);
484 	strlcpy(ktrace_last_owner_execname, proc_name_address(p),
485 	    sizeof(ktrace_last_owner_execname));
486 }
487 
488 static void
ktrace_release_ownership(void)489 ktrace_release_ownership(void)
490 {
491 	ktrace_owning_unique_id = 0;
492 	ktrace_owning_pid = 0;
493 }
494 
495 #define SYSCTL_INIT_BACKGROUND (1)
496 
497 static int ktrace_sysctl SYSCTL_HANDLER_ARGS;
498 
499 SYSCTL_NODE(, OID_AUTO, ktrace, CTLFLAG_RW | CTLFLAG_LOCKED, 0, "ktrace");
500 
501 SYSCTL_UINT(_ktrace, OID_AUTO, state, CTLFLAG_RD | CTLFLAG_LOCKED,
502     &ktrace_state, 0,
503     "");
504 
505 SYSCTL_INT(_ktrace, OID_AUTO, owning_pid, CTLFLAG_RD | CTLFLAG_LOCKED,
506     &ktrace_owning_pid, 0,
507     "pid of the process that owns ktrace");
508 
509 SYSCTL_INT(_ktrace, OID_AUTO, background_pid, CTLFLAG_RD | CTLFLAG_LOCKED,
510     &ktrace_bg_pid, 0,
511     "pid of the background ktrace tool");
512 
513 SYSCTL_STRING(_ktrace, OID_AUTO, configured_by, CTLFLAG_RD | CTLFLAG_LOCKED,
514     ktrace_last_owner_execname, 0,
515     "execname of process that last configured ktrace");
516 
517 SYSCTL_PROC(_ktrace, OID_AUTO, init_background, CTLFLAG_RW | CTLFLAG_LOCKED,
518     (void *)SYSCTL_INIT_BACKGROUND, sizeof(int),
519     ktrace_sysctl, "I", "initialize calling process as background");
520 
521 static int
522 ktrace_sysctl SYSCTL_HANDLER_ARGS
523 {
524 #pragma unused(oidp, arg2)
525 	int ret = 0;
526 	uintptr_t type = (uintptr_t)arg1;
527 
528 	ktrace_lock();
529 
530 	if (!kauth_cred_issuser(kauth_cred_get())) {
531 		ret = EPERM;
532 		goto out;
533 	}
534 
535 	if (type == SYSCTL_INIT_BACKGROUND) {
536 		if (req->newptr != USER_ADDR_NULL) {
537 			ret = ktrace_init_background();
538 			goto out;
539 		} else {
540 			ret = EINVAL;
541 			goto out;
542 		}
543 	} else {
544 		ret = EINVAL;
545 		goto out;
546 	}
547 
548 out:
549 	ktrace_unlock();
550 	return ret;
551 }
552