]> git.saurik.com Git - apple/xnu.git/blob - bsd/kern/kern_ktrace.c
3f2a7ef0f9b28f940ba85ed97de02f3dac91f686
[apple/xnu.git] / bsd / kern / kern_ktrace.c
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
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
71 kern_return_t ktrace_background_available_notify_user(void);
72
73 static LCK_GRP_DECLARE(ktrace_grp, "ktrace");
74 static LCK_MTX_DECLARE(ktrace_mtx, &ktrace_grp);
75
76 /*
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
79 * ktrace.
80 */
81 static enum ktrace_state ktrace_state = KTRACE_STATE_OFF;
82
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;
86
87 /*
88 * The background pid of ktrace, automatically made the owner when
89 * transitioning to background mode.
90 */
91 static uint64_t ktrace_bg_unique_id = 0;
92 static pid_t ktrace_bg_pid = 0;
93
94 /* The name of the last process to configure ktrace. */
95 static char ktrace_last_owner_execname[MAXCOMLEN + 1] = { 0 };
96
97 /*
98 * Which subsystems of ktrace (currently kdebug and kperf) are active.
99 */
100 static uint32_t ktrace_active_mask = 0;
101
102 /*
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.
106 *
107 * Background tools must be RunAtLoad daemons.
108 */
109 static bool should_notify_on_init = true;
110
111 /* Set the owning process of ktrace. */
112 static void ktrace_set_owning_proc(proc_t p);
113
114 /* Reset ktrace ownership back to unowned. */
115 static void ktrace_release_ownership(void);
116
117 /* Make the background tool the owner of ktrace. */
118 static void ktrace_promote_background(void);
119
120 /*
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.
124 *
125 * This is managed by the user space-oriented function ktrace_set_owning_pid
126 * and ktrace_unset_owning_pid.
127 */
128 bool ktrace_keep_ownership_on_reset = false;
129
130 /* Whether the kernel is the owner of ktrace. */
131 bool ktrace_owner_kernel = false;
132
133 /* Allow user space to unset the owning pid and potentially reset ktrace. */
134 static void ktrace_set_invalid_owning_pid(void);
135
136 /*
137 * This flag allows any root process to set a new ktrace owner. It is
138 * currently used by Instruments.
139 */
140 int ktrace_root_set_owner_allowed = 0;
141
142 /*
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.
145 */
146 static bool ktrace_single_threaded = false;
147
148 void
149 ktrace_lock(void)
150 {
151 if (!ktrace_single_threaded) {
152 lck_mtx_lock(&ktrace_mtx);
153 }
154 }
155
156 void
157 ktrace_unlock(void)
158 {
159 if (!ktrace_single_threaded) {
160 lck_mtx_unlock(&ktrace_mtx);
161 }
162 }
163
164 void
165 ktrace_assert_lock_held(void)
166 {
167 if (!ktrace_single_threaded) {
168 lck_mtx_assert(&ktrace_mtx, LCK_MTX_ASSERT_OWNED);
169 }
170 }
171
172 void
173 ktrace_start_single_threaded(void)
174 {
175 ktrace_single_threaded = true;
176 }
177
178 void
179 ktrace_end_single_threaded(void)
180 {
181 ktrace_single_threaded = false;
182 }
183
184 static void
185 ktrace_reset_internal(uint32_t reset_mask)
186 {
187 if (!ktrace_keep_ownership_on_reset) {
188 ktrace_active_mask &= ~reset_mask;
189 }
190
191 if (reset_mask & KTRACE_KPERF) {
192 kperf_reset();
193 }
194 if (reset_mask & KTRACE_KDEBUG) {
195 kdebug_reset();
196 }
197
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;
207 }
208 }
209 }
210
211 void
212 ktrace_reset(uint32_t reset_mask)
213 {
214 ktrace_assert_lock_held();
215
216 if (ktrace_active_mask == 0) {
217 if (!ktrace_keep_ownership_on_reset) {
218 assert(ktrace_state == KTRACE_STATE_OFF);
219 }
220 return;
221 }
222
223 ktrace_reset_internal(reset_mask);
224 }
225
226 static void
227 ktrace_promote_background(void)
228 {
229 assert(ktrace_state != KTRACE_STATE_BG);
230
231 /*
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).
235 */
236 if (ktrace_background_available_notify_user() == KERN_FAILURE) {
237 should_notify_on_init = true;
238 } else {
239 should_notify_on_init = false;
240 }
241
242 ktrace_release_ownership();
243 ktrace_state = KTRACE_STATE_OFF;
244 }
245
246 bool
247 ktrace_background_active(void)
248 {
249 return ktrace_state == KTRACE_STATE_BG;
250 }
251
252 int
253 ktrace_read_check(void)
254 {
255 ktrace_assert_lock_held();
256
257 if (proc_uniqueid(current_proc()) == ktrace_owning_unique_id) {
258 return 0;
259 }
260
261 return kauth_cred_issuser(kauth_cred_get()) ? 0 : EPERM;
262 }
263
264 /* If an owning process has exited, reset the ownership. */
265 static void
266 ktrace_ownership_maintenance(void)
267 {
268 ktrace_assert_lock_held();
269
270 /* do nothing if ktrace is not owned */
271 if (ktrace_owning_unique_id == 0) {
272 return;
273 }
274
275 /* reset ownership if process cannot be found */
276
277 proc_t owning_proc = proc_find(ktrace_owning_pid);
278
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();
283 }
284
285 proc_rele(owning_proc);
286 } else {
287 ktrace_release_ownership();
288 }
289 }
290
291 int
292 ktrace_configure(uint32_t config_mask)
293 {
294 ktrace_assert_lock_held();
295 assert(config_mask != 0);
296
297 proc_t p = current_proc();
298
299 /* if process clearly owns ktrace, allow */
300 if (proc_uniqueid(p) == ktrace_owning_unique_id) {
301 ktrace_active_mask |= config_mask;
302 return 0;
303 }
304
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) {
308 return EBUSY;
309 }
310
311 ktrace_ownership_maintenance();
312
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())) {
316 return EPERM;
317 }
318
319 ktrace_owner_kernel = false;
320 ktrace_set_owning_proc(p);
321 ktrace_active_mask |= config_mask;
322 return 0;
323 }
324
325 /* owned by an existing, different process */
326 return EBUSY;
327 }
328
329 void
330 ktrace_disable(enum ktrace_state state_to_match)
331 {
332 if (ktrace_state == state_to_match) {
333 kernel_debug_disable();
334 kperf_disable_sampling();
335 }
336 }
337
338 int
339 ktrace_get_owning_pid(void)
340 {
341 ktrace_assert_lock_held();
342
343 ktrace_ownership_maintenance();
344 return ktrace_owning_pid;
345 }
346
347 void
348 ktrace_kernel_configure(uint32_t config_mask)
349 {
350 assert(ktrace_single_threaded == true);
351
352 if (ktrace_owner_kernel) {
353 ktrace_active_mask |= config_mask;
354 return;
355 }
356
357 if (ktrace_state != KTRACE_STATE_OFF) {
358 if (ktrace_active_mask & config_mask & KTRACE_KPERF) {
359 kperf_reset();
360 }
361 if (ktrace_active_mask & config_mask & KTRACE_KDEBUG) {
362 kdebug_reset();
363 }
364 }
365
366 ktrace_owner_kernel = true;
367 ktrace_active_mask |= config_mask;
368 ktrace_state = KTRACE_STATE_FG;
369
370 ktrace_release_ownership();
371 strlcpy(ktrace_last_owner_execname, "kernel_task",
372 sizeof(ktrace_last_owner_execname));
373 }
374
375 static errno_t
376 ktrace_init_background(void)
377 {
378 int err = 0;
379
380 ktrace_assert_lock_held();
381
382 if ((err = priv_check_cred(kauth_cred_get(), PRIV_KTRACE_BACKGROUND, 0))) {
383 return err;
384 }
385
386 /*
387 * When a background tool first checks in, send a notification if ktrace
388 * is available.
389 */
390 if (should_notify_on_init) {
391 if (ktrace_state == KTRACE_STATE_OFF) {
392 /*
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.
397 */
398 if (ktrace_background_available_notify_user() == KERN_FAILURE) {
399 return EINVAL;
400 }
401 }
402 should_notify_on_init = false;
403 }
404
405 proc_t p = current_proc();
406
407 ktrace_bg_unique_id = proc_uniqueid(p);
408 ktrace_bg_pid = proc_pid(p);
409
410 if (ktrace_state == KTRACE_STATE_BG) {
411 ktrace_set_owning_proc(p);
412 }
413
414 return 0;
415 }
416
417 void
418 ktrace_set_invalid_owning_pid(void)
419 {
420 if (ktrace_keep_ownership_on_reset) {
421 ktrace_keep_ownership_on_reset = false;
422 ktrace_reset_internal(ktrace_active_mask);
423 }
424 }
425
426 int
427 ktrace_set_owning_pid(int pid)
428 {
429 ktrace_assert_lock_held();
430
431 /* allow user space to successfully unset owning pid */
432 if (pid == -1) {
433 ktrace_set_invalid_owning_pid();
434 return 0;
435 }
436
437 /* use ktrace_reset or ktrace_release_ownership, not this */
438 if (pid == 0) {
439 ktrace_set_invalid_owning_pid();
440 return EINVAL;
441 }
442
443 proc_t p = proc_find(pid);
444 if (!p) {
445 ktrace_set_invalid_owning_pid();
446 return ESRCH;
447 }
448
449 ktrace_keep_ownership_on_reset = true;
450 ktrace_set_owning_proc(p);
451
452 proc_rele(p);
453 return 0;
454 }
455
456 static void
457 ktrace_set_owning_proc(proc_t p)
458 {
459 ktrace_assert_lock_held();
460 assert(p != NULL);
461
462 if (ktrace_state != KTRACE_STATE_FG) {
463 if (proc_uniqueid(p) == ktrace_bg_unique_id) {
464 ktrace_state = KTRACE_STATE_BG;
465 } else {
466 if (ktrace_state == KTRACE_STATE_BG) {
467 if (ktrace_active_mask & KTRACE_KPERF) {
468 kperf_reset();
469 }
470 if (ktrace_active_mask & KTRACE_KDEBUG) {
471 kdebug_reset();
472 }
473
474 ktrace_active_mask = 0;
475 }
476 ktrace_state = KTRACE_STATE_FG;
477 should_notify_on_init = false;
478 }
479 }
480
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));
486 }
487
488 static void
489 ktrace_release_ownership(void)
490 {
491 ktrace_owning_unique_id = 0;
492 ktrace_owning_pid = 0;
493 }
494
495 #define SYSCTL_INIT_BACKGROUND (1)
496
497 static int ktrace_sysctl SYSCTL_HANDLER_ARGS;
498
499 SYSCTL_NODE(, OID_AUTO, ktrace, CTLFLAG_RW | CTLFLAG_LOCKED, 0, "ktrace");
500
501 SYSCTL_UINT(_ktrace, OID_AUTO, state, CTLFLAG_RD | CTLFLAG_LOCKED,
502 &ktrace_state, 0,
503 "");
504
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");
508
509 SYSCTL_INT(_ktrace, OID_AUTO, background_pid, CTLFLAG_RD | CTLFLAG_LOCKED,
510 &ktrace_bg_pid, 0,
511 "pid of the background ktrace tool");
512
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");
516
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");
520
521 static int
522 ktrace_sysctl SYSCTL_HANDLER_ARGS
523 {
524 #pragma unused(oidp, arg2)
525 int ret = 0;
526 uintptr_t type = (uintptr_t)arg1;
527
528 ktrace_lock();
529
530 if (!kauth_cred_issuser(kauth_cred_get())) {
531 ret = EPERM;
532 goto out;
533 }
534
535 if (type == SYSCTL_INIT_BACKGROUND) {
536 if (req->newptr != USER_ADDR_NULL) {
537 ret = ktrace_init_background();
538 goto out;
539 } else {
540 ret = EINVAL;
541 goto out;
542 }
543 } else {
544 ret = EINVAL;
545 goto out;
546 }
547
548 out:
549 ktrace_unlock();
550 return ret;
551 }