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