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