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