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