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