2 * Copyright (c) 2015-2017 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
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.
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.
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
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.
50 #include <sys/ktrace.h>
52 #include <mach/host_priv.h>
53 #include <mach/mach_types.h>
54 #include <mach/ktrace_background.h>
56 #include <sys/kauth.h>
59 char *proc_name_address(void *p
);
60 #include <sys/sysctl.h>
63 #include <kern/locks.h>
64 #include <kern/assert.h>
66 #include <sys/kdebug.h>
67 #include <kperf/kperf.h>
69 #include <kern/host.h>
71 kern_return_t
ktrace_background_available_notify_user(void);
73 static LCK_GRP_DECLARE(ktrace_grp
, "ktrace");
74 static LCK_MTX_DECLARE(ktrace_mtx
, &ktrace_grp
);
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
81 static enum ktrace_state ktrace_state
= KTRACE_STATE_OFF
;
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;
88 * The background pid of ktrace, automatically made the owner when
89 * transitioning to background mode.
91 static uint64_t ktrace_bg_unique_id
= 0;
92 static pid_t ktrace_bg_pid
= 0;
94 /* The name of the last process to configure ktrace. */
95 static char ktrace_last_owner_execname
[MAXCOMLEN
+ 1] = { 0 };
98 * Which subsystems of ktrace (currently kdebug and kperf) are active.
100 static uint32_t ktrace_active_mask
= 0;
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.
107 * Background tools must be RunAtLoad daemons.
109 static bool should_notify_on_init
= true;
111 /* Set the owning process of ktrace. */
112 static void ktrace_set_owning_proc(proc_t p
);
114 /* Reset ktrace ownership back to unowned. */
115 static void ktrace_release_ownership(void);
117 /* Make the background tool the owner of ktrace. */
118 static void ktrace_promote_background(void);
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.
125 * This is managed by the user space-oriented function ktrace_set_owning_pid
126 * and ktrace_unset_owning_pid.
128 bool ktrace_keep_ownership_on_reset
= false;
130 /* Whether the kernel is the owner of ktrace. */
131 bool ktrace_owner_kernel
= false;
133 /* Allow user space to unset the owning pid and potentially reset ktrace. */
134 static void ktrace_set_invalid_owning_pid(void);
137 * This flag allows any root process to set a new ktrace owner. It is
138 * currently used by Instruments.
140 int ktrace_root_set_owner_allowed
= 0;
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.
146 static bool ktrace_single_threaded
= false;
151 if (!ktrace_single_threaded
) {
152 lck_mtx_lock(&ktrace_mtx
);
159 if (!ktrace_single_threaded
) {
160 lck_mtx_unlock(&ktrace_mtx
);
165 ktrace_assert_lock_held(void)
167 if (!ktrace_single_threaded
) {
168 lck_mtx_assert(&ktrace_mtx
, LCK_MTX_ASSERT_OWNED
);
173 ktrace_start_single_threaded(void)
175 ktrace_single_threaded
= true;
179 ktrace_end_single_threaded(void)
181 ktrace_single_threaded
= false;
185 ktrace_reset_internal(uint32_t reset_mask
)
187 if (!ktrace_keep_ownership_on_reset
) {
188 ktrace_active_mask
&= ~reset_mask
;
191 if (reset_mask
& KTRACE_KPERF
) {
194 if (reset_mask
& KTRACE_KDEBUG
) {
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
;
212 ktrace_reset(uint32_t reset_mask
)
214 ktrace_assert_lock_held();
216 if (ktrace_active_mask
== 0) {
217 if (!ktrace_keep_ownership_on_reset
) {
218 assert(ktrace_state
== KTRACE_STATE_OFF
);
223 ktrace_reset_internal(reset_mask
);
227 ktrace_promote_background(void)
229 assert(ktrace_state
!= KTRACE_STATE_BG
);
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).
236 if (ktrace_background_available_notify_user() == KERN_FAILURE
) {
237 should_notify_on_init
= true;
239 should_notify_on_init
= false;
242 ktrace_release_ownership();
243 ktrace_state
= KTRACE_STATE_OFF
;
247 ktrace_background_active(void)
249 return ktrace_state
== KTRACE_STATE_BG
;
253 ktrace_read_check(void)
255 ktrace_assert_lock_held();
257 if (proc_uniqueid(current_proc()) == ktrace_owning_unique_id
) {
261 return kauth_cred_issuser(kauth_cred_get()) ? 0 : EPERM
;
264 /* If an owning process has exited, reset the ownership. */
266 ktrace_ownership_maintenance(void)
268 ktrace_assert_lock_held();
270 /* do nothing if ktrace is not owned */
271 if (ktrace_owning_unique_id
== 0) {
275 /* reset ownership if process cannot be found */
277 proc_t owning_proc
= proc_find(ktrace_owning_pid
);
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();
285 proc_rele(owning_proc
);
287 ktrace_release_ownership();
292 ktrace_configure(uint32_t config_mask
)
294 ktrace_assert_lock_held();
295 assert(config_mask
!= 0);
297 proc_t p
= current_proc();
299 /* if process clearly owns ktrace, allow */
300 if (proc_uniqueid(p
) == ktrace_owning_unique_id
) {
301 ktrace_active_mask
|= config_mask
;
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
) {
311 ktrace_ownership_maintenance();
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())) {
319 ktrace_owner_kernel
= false;
320 ktrace_set_owning_proc(p
);
321 ktrace_active_mask
|= config_mask
;
325 /* owned by an existing, different process */
330 ktrace_disable(enum ktrace_state state_to_match
)
332 if (ktrace_state
== state_to_match
) {
333 kernel_debug_disable();
334 kperf_disable_sampling();
339 ktrace_get_owning_pid(void)
341 ktrace_assert_lock_held();
343 ktrace_ownership_maintenance();
344 return ktrace_owning_pid
;
348 ktrace_kernel_configure(uint32_t config_mask
)
350 assert(ktrace_single_threaded
== true);
352 if (ktrace_owner_kernel
) {
353 ktrace_active_mask
|= config_mask
;
357 if (ktrace_state
!= KTRACE_STATE_OFF
) {
358 if (ktrace_active_mask
& config_mask
& KTRACE_KPERF
) {
361 if (ktrace_active_mask
& config_mask
& KTRACE_KDEBUG
) {
366 ktrace_owner_kernel
= true;
367 ktrace_active_mask
|= config_mask
;
368 ktrace_state
= KTRACE_STATE_FG
;
370 ktrace_release_ownership();
371 strlcpy(ktrace_last_owner_execname
, "kernel_task",
372 sizeof(ktrace_last_owner_execname
));
376 ktrace_init_background(void)
380 ktrace_assert_lock_held();
382 if ((err
= priv_check_cred(kauth_cred_get(), PRIV_KTRACE_BACKGROUND
, 0))) {
387 * When a background tool first checks in, send a notification if ktrace
390 if (should_notify_on_init
) {
391 if (ktrace_state
== KTRACE_STATE_OFF
) {
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.
398 if (ktrace_background_available_notify_user() == KERN_FAILURE
) {
402 should_notify_on_init
= false;
405 proc_t p
= current_proc();
407 ktrace_bg_unique_id
= proc_uniqueid(p
);
408 ktrace_bg_pid
= proc_pid(p
);
410 if (ktrace_state
== KTRACE_STATE_BG
) {
411 ktrace_set_owning_proc(p
);
418 ktrace_set_invalid_owning_pid(void)
420 if (ktrace_keep_ownership_on_reset
) {
421 ktrace_keep_ownership_on_reset
= false;
422 ktrace_reset_internal(ktrace_active_mask
);
427 ktrace_set_owning_pid(int pid
)
429 ktrace_assert_lock_held();
431 /* allow user space to successfully unset owning pid */
433 ktrace_set_invalid_owning_pid();
437 /* use ktrace_reset or ktrace_release_ownership, not this */
439 ktrace_set_invalid_owning_pid();
443 proc_t p
= proc_find(pid
);
445 ktrace_set_invalid_owning_pid();
449 ktrace_keep_ownership_on_reset
= true;
450 ktrace_set_owning_proc(p
);
457 ktrace_set_owning_proc(proc_t p
)
459 ktrace_assert_lock_held();
462 if (ktrace_state
!= KTRACE_STATE_FG
) {
463 if (proc_uniqueid(p
) == ktrace_bg_unique_id
) {
464 ktrace_state
= KTRACE_STATE_BG
;
466 if (ktrace_state
== KTRACE_STATE_BG
) {
467 if (ktrace_active_mask
& KTRACE_KPERF
) {
470 if (ktrace_active_mask
& KTRACE_KDEBUG
) {
474 ktrace_active_mask
= 0;
476 ktrace_state
= KTRACE_STATE_FG
;
477 should_notify_on_init
= false;
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
));
489 ktrace_release_ownership(void)
491 ktrace_owning_unique_id
= 0;
492 ktrace_owning_pid
= 0;
495 #define SYSCTL_INIT_BACKGROUND (1)
497 static int ktrace_sysctl SYSCTL_HANDLER_ARGS
;
499 SYSCTL_NODE(, OID_AUTO
, ktrace
, CTLFLAG_RW
| CTLFLAG_LOCKED
, 0, "ktrace");
501 SYSCTL_UINT(_ktrace
, OID_AUTO
, state
, CTLFLAG_RD
| CTLFLAG_LOCKED
,
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");
509 SYSCTL_INT(_ktrace
, OID_AUTO
, background_pid
, CTLFLAG_RD
| CTLFLAG_LOCKED
,
511 "pid of the background ktrace tool");
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");
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");
522 ktrace_sysctl SYSCTL_HANDLER_ARGS
524 #pragma unused(oidp, arg2)
526 uintptr_t type
= (uintptr_t)arg1
;
530 if (!kauth_cred_issuser(kauth_cred_get())) {
535 if (type
== SYSCTL_INIT_BACKGROUND
) {
536 if (req
->newptr
!= USER_ADDR_NULL
) {
537 ret
= ktrace_init_background();