2 * Copyright (c) 2015 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 lck_mtx_t
*ktrace_lock
;
76 * The overall state of ktrace, whether it is unconfigured, in foreground mode,
77 * or in background mode. The state determines which processes can configure
80 static enum ktrace_state ktrace_state
= KTRACE_STATE_OFF
;
82 /* The true owner of ktrace, checked by ktrace_access_check(). */
83 static uint64_t ktrace_owning_unique_id
= 0;
84 static pid_t ktrace_owning_pid
= 0;
87 * The background pid of ktrace, automatically made the owner when
88 * transitioning to background mode.
90 static uint64_t ktrace_bg_unique_id
= 0;
91 static pid_t ktrace_bg_pid
= 0;
93 /* The name of the last process to configure ktrace. */
94 static char ktrace_last_owner_execname
[MAXCOMLEN
+ 1] = { 0 };
97 * Which subsystems of ktrace (currently kdebug and kperf) are active.
99 static uint32_t ktrace_active_mask
= 0;
102 * At boot or when a daemon has been newly loaded, it's necessary to bootstrap
103 * user space background tools by sending a background available notification
104 * when the init_background sysctl is made.
106 * Background tools must be RunAtLoad daemons.
108 static boolean_t should_notify_on_init
= TRUE
;
110 /* Set the owning process of ktrace. */
111 static void ktrace_set_owning_proc(proc_t p
);
113 /* Reset ktrace ownership back to unowned. */
114 static void ktrace_release_ownership(void);
116 /* Make the background tool the owner of ktrace. */
117 static void ktrace_promote_background(void);
120 * If user space sets a pid manually (through kperf "blessing"), ktrace should
121 * not treat resets as releasing ownership. At that point, ownership is only
122 * released when the owner is set to an invalid pid.
124 * This is managed by the user space-oriented function ktrace_set_owning_pid
125 * and ktrace_unset_owning_pid.
127 boolean_t ktrace_keep_ownership_on_reset
= FALSE
;
129 /* Allow user space to unset the owning pid and potentially reset ktrace. */
130 static void ktrace_set_invalid_owning_pid(void);
133 * This flag allows any root process to set a new ktrace owner. It is
134 * currently used by Instruments.
136 int ktrace_root_set_owner_allowed
= 0;
139 ktrace_reset(uint32_t reset_mask
)
141 lck_mtx_assert(ktrace_lock
, LCK_MTX_ASSERT_OWNED
);
142 assert(reset_mask
!= 0);
144 if (ktrace_active_mask
== 0) {
145 if (!ktrace_keep_ownership_on_reset
) {
146 assert(ktrace_state
== KTRACE_STATE_OFF
);
151 if (!ktrace_keep_ownership_on_reset
) {
152 ktrace_active_mask
&= ~reset_mask
;
155 if (reset_mask
& KTRACE_KPERF
) {
158 if (reset_mask
& KTRACE_KDEBUG
) {
162 if (ktrace_active_mask
== 0) {
163 if (ktrace_state
== KTRACE_STATE_FG
) {
164 /* transition from foreground to background */
165 ktrace_promote_background();
166 } else if (ktrace_state
== KTRACE_STATE_BG
) {
167 /* background tool is resetting ktrace */
168 should_notify_on_init
= TRUE
;
169 ktrace_release_ownership();
170 ktrace_state
= KTRACE_STATE_OFF
;
176 ktrace_promote_background(void)
178 lck_mtx_assert(ktrace_lock
, LCK_MTX_ASSERT_OWNED
);
179 assert(ktrace_state
!= KTRACE_STATE_BG
);
182 * Remember to send a background available notification on the next init
183 * if the notification failed (meaning no task holds the receive right
184 * for the host special port).
186 if (ktrace_background_available_notify_user() == KERN_FAILURE
) {
187 should_notify_on_init
= TRUE
;
189 should_notify_on_init
= FALSE
;
192 ktrace_release_ownership();
193 ktrace_state
= KTRACE_STATE_OFF
;
197 ktrace_background_active(void)
199 lck_mtx_assert(ktrace_lock
, LCK_MTX_ASSERT_OWNED
);
200 return (ktrace_state
== KTRACE_STATE_BG
);
204 ktrace_read_check(void)
206 lck_mtx_assert(ktrace_lock
, LCK_MTX_ASSERT_OWNED
);
208 if (proc_uniqueid(current_proc()) == ktrace_owning_unique_id
)
213 return kauth_cred_issuser(kauth_cred_get()) ? 0 : EPERM
;
216 /* If an owning process has exited, reset the ownership. */
218 ktrace_ownership_maintenance(void)
220 lck_mtx_assert(ktrace_lock
, LCK_MTX_ASSERT_OWNED
);
222 /* do nothing if ktrace is not owned */
223 if (ktrace_owning_unique_id
== 0) {
227 /* reset ownership if process cannot be found */
229 proc_t owning_proc
= proc_find(ktrace_owning_pid
);
231 if (owning_proc
!= NULL
) {
232 /* make sure the pid was not recycled */
233 if (proc_uniqueid(owning_proc
) != ktrace_owning_unique_id
) {
234 ktrace_release_ownership();
237 proc_rele(owning_proc
);
239 ktrace_release_ownership();
244 ktrace_configure(uint32_t config_mask
)
246 lck_mtx_assert(ktrace_lock
, LCK_MTX_ASSERT_OWNED
);
247 assert(config_mask
!= 0);
249 proc_t p
= current_proc();
251 /* if process clearly owns ktrace, allow */
252 if (proc_uniqueid(p
) == ktrace_owning_unique_id
) {
253 ktrace_active_mask
|= config_mask
;
257 /* background configure while foreground is active is not allowed */
258 if (proc_uniqueid(p
) == ktrace_bg_unique_id
&&
259 ktrace_state
== KTRACE_STATE_FG
)
264 ktrace_ownership_maintenance();
266 /* allow process to gain control when unowned or background */
267 if (ktrace_owning_unique_id
== 0 || ktrace_state
== KTRACE_STATE_BG
) {
268 if (!kauth_cred_issuser(kauth_cred_get())) {
272 ktrace_set_owning_proc(p
);
273 ktrace_active_mask
|= config_mask
;
277 /* owned by an existing, different process */
282 ktrace_disable(enum ktrace_state state_to_match
)
284 if (ktrace_state
== state_to_match
) {
285 kernel_debug_disable();
286 kperf_sampling_disable();
291 ktrace_get_owning_pid(void)
293 lck_mtx_assert(ktrace_lock
, LCK_MTX_ASSERT_OWNED
);
295 ktrace_ownership_maintenance();
296 return ktrace_owning_pid
;
300 ktrace_kernel_configure(uint32_t config_mask
)
302 lck_mtx_assert(ktrace_lock
, LCK_MTX_ASSERT_OWNED
);
304 if (ktrace_state
!= KTRACE_STATE_OFF
) {
305 if (ktrace_active_mask
& KTRACE_KPERF
) {
308 if (ktrace_active_mask
& KTRACE_KDEBUG
) {
313 ktrace_active_mask
= config_mask
;
314 ktrace_state
= KTRACE_STATE_FG
;
316 ktrace_release_ownership();
317 strlcpy(ktrace_last_owner_execname
, "kernel_task",
318 sizeof(ktrace_last_owner_execname
));
322 ktrace_init_background(void)
326 lck_mtx_assert(ktrace_lock
, LCK_MTX_ASSERT_OWNED
);
328 if ((err
= priv_check_cred(kauth_cred_get(), PRIV_KTRACE_BACKGROUND
, 0))) {
333 * When a background tool first checks in, send a notification if ktrace
336 if (should_notify_on_init
) {
337 if (ktrace_state
== KTRACE_STATE_OFF
) {
339 * This notification can only fail if a process does not
340 * hold the receive right for the host special port.
341 * Return an error and don't make the current process
342 * the background tool.
344 if (ktrace_background_available_notify_user() == KERN_FAILURE
) {
348 should_notify_on_init
= FALSE
;
351 proc_t p
= current_proc();
353 ktrace_bg_unique_id
= proc_uniqueid(p
);
354 ktrace_bg_pid
= proc_pid(p
);
356 if (ktrace_state
== KTRACE_STATE_BG
) {
357 ktrace_set_owning_proc(p
);
364 ktrace_set_invalid_owning_pid(void)
366 if (ktrace_keep_ownership_on_reset
) {
367 ktrace_reset(ktrace_active_mask
);
368 ktrace_keep_ownership_on_reset
= FALSE
;
373 ktrace_set_owning_pid(int pid
)
375 lck_mtx_assert(ktrace_lock
, LCK_MTX_ASSERT_OWNED
);
377 /* allow user space to successfully unset owning pid */
379 ktrace_set_invalid_owning_pid();
383 /* use ktrace_reset or ktrace_release_ownership, not this */
385 ktrace_set_invalid_owning_pid();
389 proc_t p
= proc_find(pid
);
391 ktrace_set_invalid_owning_pid();
395 ktrace_keep_ownership_on_reset
= TRUE
;
396 ktrace_set_owning_proc(p
);
403 ktrace_set_owning_proc(proc_t p
)
405 lck_mtx_assert(ktrace_lock
, LCK_MTX_ASSERT_OWNED
);
408 if (ktrace_state
!= KTRACE_STATE_FG
) {
409 if (proc_uniqueid(p
) == ktrace_bg_unique_id
) {
410 ktrace_state
= KTRACE_STATE_BG
;
412 if (ktrace_state
== KTRACE_STATE_BG
) {
413 if (ktrace_active_mask
& KTRACE_KPERF
) {
416 if (ktrace_active_mask
& KTRACE_KDEBUG
) {
420 ktrace_active_mask
= 0;
422 ktrace_state
= KTRACE_STATE_FG
;
423 should_notify_on_init
= FALSE
;
427 ktrace_owning_unique_id
= proc_uniqueid(p
);
428 ktrace_owning_pid
= proc_pid(p
);
429 strlcpy(ktrace_last_owner_execname
, proc_name_address(p
),
430 sizeof(ktrace_last_owner_execname
));
434 ktrace_release_ownership(void)
436 lck_mtx_assert(ktrace_lock
, LCK_MTX_ASSERT_OWNED
);
438 ktrace_owning_unique_id
= 0;
439 ktrace_owning_pid
= 0;
442 #define SYSCTL_INIT_BACKGROUND (1)
444 static int ktrace_sysctl SYSCTL_HANDLER_ARGS
;
446 SYSCTL_NODE(, OID_AUTO
, ktrace
, CTLFLAG_RW
| CTLFLAG_LOCKED
, 0, "ktrace");
448 SYSCTL_UINT(_ktrace
, OID_AUTO
, state
, CTLFLAG_RD
| CTLFLAG_LOCKED
,
452 SYSCTL_INT(_ktrace
, OID_AUTO
, owning_pid
, CTLFLAG_RD
| CTLFLAG_LOCKED
,
453 &ktrace_owning_pid
, 0,
454 "pid of the process that owns ktrace");
456 SYSCTL_INT(_ktrace
, OID_AUTO
, background_pid
, CTLFLAG_RD
| CTLFLAG_LOCKED
,
458 "pid of the background ktrace tool");
460 SYSCTL_STRING(_ktrace
, OID_AUTO
, configured_by
, CTLFLAG_RD
| CTLFLAG_LOCKED
,
461 ktrace_last_owner_execname
, 0,
462 "execname of process that last configured ktrace");
464 SYSCTL_PROC(_ktrace
, OID_AUTO
, init_background
, CTLFLAG_RW
| CTLFLAG_LOCKED
,
465 (void *)SYSCTL_INIT_BACKGROUND
, sizeof(int),
466 ktrace_sysctl
, "I", "initialize calling process as background");
469 ktrace_sysctl SYSCTL_HANDLER_ARGS
471 #pragma unused(oidp, arg2)
473 uintptr_t type
= (uintptr_t)arg1
;
475 lck_mtx_lock(ktrace_lock
);
477 if (!kauth_cred_issuser(kauth_cred_get())) {
482 if (type
== SYSCTL_INIT_BACKGROUND
) {
483 if (req
->newptr
!= USER_ADDR_NULL
) {
484 ret
= ktrace_init_background();
496 lck_mtx_unlock(ktrace_lock
);
500 /* This should only be called from the bootstrap thread. */
504 static lck_grp_attr_t
*lock_grp_attr
= NULL
;
505 static lck_grp_t
*lock_grp
= NULL
;
506 static boolean_t initialized
= FALSE
;
512 lock_grp_attr
= lck_grp_attr_alloc_init();
513 lock_grp
= lck_grp_alloc_init("ktrace", lock_grp_attr
);
514 lck_grp_attr_free(lock_grp_attr
);
516 ktrace_lock
= lck_mtx_alloc_init(lock_grp
, LCK_ATTR_NULL
);