xref: /xnu-11417.140.69/osfmk/kern/trap_telemetry.h (revision 43a90889846e00bfb5cf1d255cdc0a701a1e05a4)
1 /*
2  * Copyright (c) 2012-2024 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 #ifndef _TRAP_TELEMETRY_H_
30 #define _TRAP_TELEMETRY_H_
31 
32 #include <stdint.h>
33 #include <stdbool.h>
34 #include <sys/cdefs.h>
35 #include <mach/mach_types.h>
36 #include <kern/thread.h>
37 
38 __BEGIN_DECLS
39 #if XNU_KERNEL_PRIVATE
40 __enum_decl(trap_telemetry_ca_event_t, uint8_t, {
41 	/** Do not report this event to CoreAnalytics. */
42 	TRAP_TELEMETRY_CA_EVENT_NONE = 0,
43 
44 	TRAP_TELEMETRY_CA_EVENT_KERNEL_BRK = 1,
45 
46 	TRAP_TELEMETRY_CA_EVENT_INTERNAL = 2,
47 
48 	/** Used for validation, keep this value last. */
49 	TRAP_TELEMETRY_CA_EVENT_COUNT,
50 });
51 
52 typedef struct {
53 	uint8_t
54 	/**
55 	 * The event to use when reporting to CoreAnalytics.
56 	 * Encodings specified by trap_telemetry_ca_event_t.
57 	 */
58 	    telemetry_ca_event:2,
59 
60 	/**
61 	 * Should the trap only be reported once per fault PC, per boot?
62 	 *
63 	 * This should be set for traps which may fire very often in order to avoid
64 	 * overwhelming Core Analytics.
65 	 *
66 	 * Note, however, that unsetting this option does not guarantee all traps
67 	 * will be reported. Repeated traps at the same location within quick
68 	 * succession will, for example, only be reported once for performance
69 	 * reasons. Additionally, trap telemetry events may be dropped/fail at any
70 	 * time due to internal conditions.
71 	 */
72 	    report_once_per_site:1;
73 } trap_telemetry_options_s;
74 
75 __enum_decl(trap_telemetry_type_t, uint32_t, {
76 	/* These show up in telemetry, do not renumber */
77 	TRAP_TELEMETRY_TYPE_KERNEL_BRK_KASAN     = 0,     /* <unrecoverable> KASan violation traps */
78 	TRAP_TELEMETRY_TYPE_KERNEL_BRK_PTRAUTH   = 1,     /* <unrecoverable> Pointer Auth failure traps */
79 	TRAP_TELEMETRY_TYPE_KERNEL_BRK_CLANG     = 2,     /* <unrecoverable> Clang sanitizer traps */
80 	TRAP_TELEMETRY_TYPE_KERNEL_BRK_LIBCXX    = 3,     /* <unrecoverable> Libc++ abort trap*/
81 	TRAP_TELEMETRY_TYPE_KERNEL_BRK_TELEMETRY = 4,     /* <  recoverable> Soft telemetry collection traps */
82 	TRAP_TELEMETRY_TYPE_KERNEL_BRK_XNU       = 5,     /* <??recoverable> XNU defined traps */
83 
84 	/* Failure conditions which may eventually turn into hard errors */
85 	TRAP_TELEMETRY_TYPE_KERNEL_SOFT_ERROR    = 6,
86 	TRAP_TELEMETRY_TYPE_SPTM_SOFT_ERROR      = 7,
87 
88 	TRAP_TELEMETRY_TYPE_KERNEL_BRK_TEST      = ~0u,   /* Development only */
89 });
90 
91 /**
92  * Report a trap with a given type and code originating from the fault location
93  * in SAVED_STATE.
94  *
95  * Returns true if the event was submitted (or duped) and false on error.
96  */
97 extern bool
98 trap_telemetry_report_exception(
99 	trap_telemetry_type_t trap_type,
100 	uint64_t trap_code,
101 	trap_telemetry_options_s options,
102 	void *saved_state);
103 
104 /**
105  * Perform a simulated trap of a given type and code.
106  * Fault PC and backtrace will begin at the call site of this function.
107  *
108  * Returns true if the event was submitted (or duped) and false on error.
109  */
110 extern bool
111 trap_telemetry_report_simulated_trap(
112 	trap_telemetry_type_t trap_type,
113 	uint64_t trap_code,
114 	trap_telemetry_options_s options);
115 
116 /**
117  * Perform a simulated trap of a given type and code, with given fault PC and
118  * backtrace.
119  *
120  * Only up to TRAP_TELEMETRY_BT_FRAMES frames of backtrace will be used.
121  *
122  * Returns true if the event was submitted (or duped) and false on error.
123  */
124 extern bool
125 trap_telemetry_report_simulated_trap_with_backtrace(
126 	trap_telemetry_type_t trap_type,
127 	uint64_t trap_code,
128 	trap_telemetry_options_s options,
129 	uintptr_t fault_pc,
130 	uintptr_t *frames,
131 	size_t frames_valid_count);
132 
133 /** Initialize the trap telemetry module */
134 extern void
135 trap_telemetry_init(void);
136 
137 /* ~* Breakpoint Telemetry Helpers *~ */
138 
139 enum kernel_brk_trap_comment {
140 	/* CLANG (reserved)       : [0x0000 ~ 0x00FF] <Intel only> */
141 	CLANG_X86_TRAP_START           = 0x0000,
142 	CLANG_X86_TRAP_BOUND_CHK       = 0x0019, /* bound check fatal trap */
143 	CLANG_X86_TRAP_END             = 0x00FF,
144 
145 	/* LIBCXX                 : [0x0800 ~ 0x0800] */
146 	LIBCXX_TRAP_START              = 0x0800,
147 	LIBCXX_TRAP_ABORT              = 0x0800, /* libcxx abort() in libcxx_support/stdlib.h */
148 	LIBCXX_TRAP_END                = 0x0800,
149 
150 	/* KASAN (kasan-tbi.h)    : [0x0900 ~ 0x093F] <ARM only> */
151 
152 	/* CLANG (reserved)       : [0x5500 ~ 0x55FF] <ARM only> */
153 	CLANG_ARM_TRAP_START           = 0x5500,
154 	CLANG_ARM_TRAP_BOUND_CHK       = 0x5519, /* bound check fatal trap */
155 	CLANG_ARM_TRAP_END             = 0x55FF,
156 
157 	/* Software defined       : [0xB000 ~ 0xBFFF] */
158 	XNU_HARD_TRAP_START            = 0xB000,
159 	XNU_HARD_TRAP_ASSERT_FAILURE   = 0xBFFC, /* backend for assert() */
160 	XNU_HARD_TRAP_SAFE_UNLINK      = 0xBFFD, /* queue safe unlinking traps */
161 	XNU_HARD_TRAP_STRING_CHK       = 0xBFFE, /* read traps in string.h */
162 	XNU_HARD_TRAP_END              = 0xBFFF,
163 
164 	/* PTRAUTH (sleh.c)       : [0xC470 ~ 0xC473] <ARM only> */
165 	PTRAUTH_TRAP_START             = 0xC470,
166 	PTRAUTH_TRAP_END               = 0xC473,
167 
168 	/* TELEMETRY              : [0xFF00 ~ 0xFFFE] */
169 	XNU_SOFT_TRAP_START            = 0xFF00,
170 	UBSAN_SOFT_TRAP_SIGNED_OF      = 0xFF00, /* ubsan minimal signed overflow*/
171 	CLANG_SOFT_TRAP_BOUND_CHK      = 0xFF19, /* ml_bound_chk_soft_trap */
172 	XNU_SOFT_TRAP_STRING_CHK       = 0xFFFE, /* read traps in string.h */
173 	XNU_SOFT_TRAP_END              = 0xFFFE,
174 
175 	/* TEST */
176 	TEST_RECOVERABLE_SOFT_TRAP     = 0xFFFF, /* development only */
177 };
178 
179 typedef struct {
180 	uint8_t
181 	/** Can this breakpoint be recovered from? */
182 	    recoverable : 1,
183 	/** Should this breakpoint be reported to trap telemetry? */
184 	    enable_trap_telemetry : 1;
185 	/** If recoverable, the telemetry options  */
186 	trap_telemetry_options_s telemetry_options;
187 } brk_telemetry_options_s;
188 
189 /** Default configuration for fatal breakpoints */
190 #define BRK_TELEMETRY_OPTIONS_FATAL_DEFAULT \
191 	(brk_telemetry_options_s) { \
192 	    .recoverable = false, \
193 	    .enable_trap_telemetry = false, \
194 	/* ignored when trap telemetry disabled, but zero init anyways */ \
195 	    .telemetry_options = {0}, \
196 	}
197 
198 /** Default configuration for recoverable breakpoints */
199 #define BRK_TELEMETRY_OPTIONS_RECOVERABLE_DEFAULT(enable_telemetry) \
200 	(brk_telemetry_options_s) { \
201 	    .recoverable = true, \
202 	    .enable_trap_telemetry = (enable_telemetry), \
203 	    .telemetry_options = { \
204 	        .telemetry_ca_event = TRAP_TELEMETRY_CA_EVENT_KERNEL_BRK, \
205 	/* Different backtraces may be useful, so report all */ \
206 	        .report_once_per_site = false, \
207 	    }, \
208 	}
209 
210 typedef struct kernel_brk_descriptor {
211 	trap_telemetry_type_t    type;
212 	uint16_t                 base;
213 	uint16_t                 max;
214 	brk_telemetry_options_s  options;
215 
216 	const char *(*handle_breakpoint)(void *states, uint16_t comment);
217 } *kernel_brk_descriptor_t;
218 
219 extern struct kernel_brk_descriptor kernel_brk_descriptors[]
220 __SECTION_START_SYM("__DATA_CONST", "__kern_brk_desc");
221 
222 extern struct kernel_brk_descriptor kernel_brk_descriptors_end[]
223 __SECTION_END_SYM("__DATA_CONST", "__kern_brk_desc");
224 
225 #define KERNEL_BRK_DESCRIPTOR_DEFINE(name, ...) \
226 __PLACE_IN_SECTION("__DATA_CONST,__kern_brk_desc") \
227 static const struct kernel_brk_descriptor name = { __VA_ARGS__ };
228 
229 const static inline struct kernel_brk_descriptor *
find_kernel_brk_descriptor_by_comment(uint16_t comment)230 find_kernel_brk_descriptor_by_comment(uint16_t comment)
231 {
232 	for (kernel_brk_descriptor_t des = kernel_brk_descriptors; des < kernel_brk_descriptors_end; des++) {
233 		if (comment >= des->base && comment <= des->max) {
234 			return des;
235 		}
236 	}
237 
238 	return NULL;
239 }
240 
241 /* ~* Kernel Soft Error Telemetry Helpers *~ */
242 
243 __enum_decl(trap_telemetry_kernel_soft_error_code_t, uint64_t, {
244 	/* Do not renumber entries -- IDs are used in telemetry */
245 	TRAP_TELEMETRY_KERNEL_SOFT_ERROR_VM_KERNEL_MAX_ALLOC_SIZE = 0,
246 });
247 
248 /**
249  * Report a kernel soft error CODE with a backtrace originating at this
250  * function's call site.
251  *
252  * If REPORT_ONCE_PER_SITE is true, events will be deduplicated by call site
253  * address and only the first instance at a given site will be reported. For the
254  * call site address to be meaningful, this function must be inlined (hence the
255  * always_inline attribute).
256  */
257 __unused
258 __attribute__((always_inline))
259 static void
trap_telemetry_report_kernel_soft_error(trap_telemetry_kernel_soft_error_code_t code,bool report_once_per_site)260 trap_telemetry_report_kernel_soft_error(
261 	trap_telemetry_kernel_soft_error_code_t code,
262 	bool report_once_per_site)
263 {
264 	trap_telemetry_report_simulated_trap(
265 		TRAP_TELEMETRY_TYPE_KERNEL_SOFT_ERROR,
266 		(uint64_t)code,
267 		(trap_telemetry_options_s) {
268 		.telemetry_ca_event = TRAP_TELEMETRY_CA_EVENT_INTERNAL,
269 		.report_once_per_site = report_once_per_site
270 	});
271 }
272 
273 #endif /* XNU_KERNEL_PRIVATE */
274 
275 __END_DECLS
276 
277 #endif /* _TRAP_TELEMETRY_H_  */
278