xref: /xnu-10002.61.3/san/memory/ubsan_minimal.c (revision 0f4c859e951fba394238ab619495c4e1d54d0f34)
1*0f4c859eSApple OSS Distributions /*
2*0f4c859eSApple OSS Distributions  * Copyright (c) 2021 Apple Inc. All rights reserved.
3*0f4c859eSApple OSS Distributions  *
4*0f4c859eSApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5*0f4c859eSApple OSS Distributions  *
6*0f4c859eSApple OSS Distributions  * This file contains Original Code and/or Modifications of Original Code
7*0f4c859eSApple OSS Distributions  * as defined in and that are subject to the Apple Public Source License
8*0f4c859eSApple OSS Distributions  * Version 2.0 (the 'License'). You may not use this file except in
9*0f4c859eSApple OSS Distributions  * compliance with the License. The rights granted to you under the License
10*0f4c859eSApple OSS Distributions  * may not be used to create, or enable the creation or redistribution of,
11*0f4c859eSApple OSS Distributions  * unlawful or unlicensed copies of an Apple operating system, or to
12*0f4c859eSApple OSS Distributions  * circumvent, violate, or enable the circumvention or violation of, any
13*0f4c859eSApple OSS Distributions  * terms of an Apple operating system software license agreement.
14*0f4c859eSApple OSS Distributions  *
15*0f4c859eSApple OSS Distributions  * Please obtain a copy of the License at
16*0f4c859eSApple OSS Distributions  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17*0f4c859eSApple OSS Distributions  *
18*0f4c859eSApple OSS Distributions  * The Original Code and all software distributed under the License are
19*0f4c859eSApple OSS Distributions  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20*0f4c859eSApple OSS Distributions  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21*0f4c859eSApple OSS Distributions  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22*0f4c859eSApple OSS Distributions  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23*0f4c859eSApple OSS Distributions  * Please see the License for the specific language governing rights and
24*0f4c859eSApple OSS Distributions  * limitations under the License.
25*0f4c859eSApple OSS Distributions  *
26*0f4c859eSApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27*0f4c859eSApple OSS Distributions  */
28*0f4c859eSApple OSS Distributions 
29*0f4c859eSApple OSS Distributions /*
30*0f4c859eSApple OSS Distributions  * UBSan minimal runtime for production environments
31*0f4c859eSApple OSS Distributions  * This runtime emulates an inlined trap model, but gated through the
32*0f4c859eSApple OSS Distributions  * logging functions, so that fix and continue is always possible just by
33*0f4c859eSApple OSS Distributions  * advancing the program counter.
34*0f4c859eSApple OSS Distributions  * NOTE: this file is regularly instrumented, since all helpers must inline
35*0f4c859eSApple OSS Distributions  * correctly to a trap.
36*0f4c859eSApple OSS Distributions  */
37*0f4c859eSApple OSS Distributions #include <sys/sysctl.h>
38*0f4c859eSApple OSS Distributions #include <kern/kalloc.h>
39*0f4c859eSApple OSS Distributions #include <kern/telemetry.h>
40*0f4c859eSApple OSS Distributions #include <machine/machine_routines.h>
41*0f4c859eSApple OSS Distributions #include <san/ubsan_minimal.h>
42*0f4c859eSApple OSS Distributions 
43*0f4c859eSApple OSS Distributions #define UBSAN_M_NONE            (0x0000)
44*0f4c859eSApple OSS Distributions #define UBSAN_M_PANIC           (0x0001)
45*0f4c859eSApple OSS Distributions 
46*0f4c859eSApple OSS Distributions #define UBSAN_MINIMAL_TRAPS_START       UBSAN_SIGNED_OVERFLOW_TRAP
47*0f4c859eSApple OSS Distributions #define UBSAN_MINIMAL_TRAPS_END         UBSAN_SIGNED_OVERFLOW_TRAP
48*0f4c859eSApple OSS Distributions 
49*0f4c859eSApple OSS Distributions struct ubsan_minimal_trap_desc {
50*0f4c859eSApple OSS Distributions 	uint16_t        id;
51*0f4c859eSApple OSS Distributions 	uint32_t        flags;
52*0f4c859eSApple OSS Distributions 	char            str[16];
53*0f4c859eSApple OSS Distributions };
54*0f4c859eSApple OSS Distributions 
55*0f4c859eSApple OSS Distributions #if RELEASE
56*0f4c859eSApple OSS Distributions static __security_const_late
57*0f4c859eSApple OSS Distributions #endif /* RELEASE */
58*0f4c859eSApple OSS Distributions struct ubsan_minimal_trap_desc ubsan_traps[] = {
59*0f4c859eSApple OSS Distributions 	{ UBSAN_SIGNED_OVERFLOW_TRAP, UBSAN_M_NONE, "signed-overflow" },
60*0f4c859eSApple OSS Distributions };
61*0f4c859eSApple OSS Distributions 
62*0f4c859eSApple OSS Distributions static SECURITY_READ_ONLY_LATE(bool) ubsan_minimal_enabled = false;
63*0f4c859eSApple OSS Distributions 
64*0f4c859eSApple OSS Distributions /* Helper counters for fixup/drop operations */
65*0f4c859eSApple OSS Distributions static uint32_t ubsan_minimal_fixup_events;
66*0f4c859eSApple OSS Distributions 
67*0f4c859eSApple OSS Distributions static char *
ubsan_minimal_trap_to_str(uint16_t trap)68*0f4c859eSApple OSS Distributions ubsan_minimal_trap_to_str(uint16_t trap)
69*0f4c859eSApple OSS Distributions {
70*0f4c859eSApple OSS Distributions 	return ubsan_traps[trap - UBSAN_MINIMAL_TRAPS_START].str;
71*0f4c859eSApple OSS Distributions }
72*0f4c859eSApple OSS Distributions 
73*0f4c859eSApple OSS Distributions void
ubsan_handle_brk_trap(__unused void * state,uint16_t trap)74*0f4c859eSApple OSS Distributions ubsan_handle_brk_trap(
75*0f4c859eSApple OSS Distributions 	__unused void     *state,
76*0f4c859eSApple OSS Distributions 	uint16_t          trap)
77*0f4c859eSApple OSS Distributions {
78*0f4c859eSApple OSS Distributions 	if (!ubsan_minimal_enabled) {
79*0f4c859eSApple OSS Distributions #if DEVELOPMENT
80*0f4c859eSApple OSS Distributions 		/* We want to know about those sooner than later... */
81*0f4c859eSApple OSS Distributions 		panic("UBSAN trap taken in early startup code");
82*0f4c859eSApple OSS Distributions #endif /* DEVELOPMENT */
83*0f4c859eSApple OSS Distributions 		return;
84*0f4c859eSApple OSS Distributions 	}
85*0f4c859eSApple OSS Distributions 
86*0f4c859eSApple OSS Distributions 	uint32_t trap_idx = trap - UBSAN_MINIMAL_TRAPS_START;
87*0f4c859eSApple OSS Distributions 
88*0f4c859eSApple OSS Distributions 	if (ubsan_traps[trap_idx].flags & UBSAN_M_PANIC) {
89*0f4c859eSApple OSS Distributions 		panic("UBSAN trap for %s detected\n", ubsan_minimal_trap_to_str(trap));
90*0f4c859eSApple OSS Distributions 		__builtin_unreachable();
91*0f4c859eSApple OSS Distributions 	}
92*0f4c859eSApple OSS Distributions 
93*0f4c859eSApple OSS Distributions 	ubsan_minimal_fixup_events++;
94*0f4c859eSApple OSS Distributions }
95*0f4c859eSApple OSS Distributions 
96*0f4c859eSApple OSS Distributions __startup_func
97*0f4c859eSApple OSS Distributions void
ubsan_minimal_init(void)98*0f4c859eSApple OSS Distributions ubsan_minimal_init(void)
99*0f4c859eSApple OSS Distributions {
100*0f4c859eSApple OSS Distributions #if DEVELOPMENT || DEBUG
101*0f4c859eSApple OSS Distributions 	bool force_panic = false;
102*0f4c859eSApple OSS Distributions 	PE_parse_boot_argn("-ubsan_force_panic", &force_panic, sizeof(force_panic));
103*0f4c859eSApple OSS Distributions 	if (force_panic) {
104*0f4c859eSApple OSS Distributions 		for (int i = UBSAN_MINIMAL_TRAPS_START; i <= UBSAN_MINIMAL_TRAPS_END; i++) {
105*0f4c859eSApple OSS Distributions 			size_t idx = i - UBSAN_MINIMAL_TRAPS_START;
106*0f4c859eSApple OSS Distributions 			ubsan_traps[idx].flags |= UBSAN_M_PANIC;
107*0f4c859eSApple OSS Distributions 		}
108*0f4c859eSApple OSS Distributions 	}
109*0f4c859eSApple OSS Distributions #endif /* DEVELOPMENT || DEBUG */
110*0f4c859eSApple OSS Distributions 
111*0f4c859eSApple OSS Distributions 	ubsan_minimal_enabled = true;
112*0f4c859eSApple OSS Distributions }
113*0f4c859eSApple OSS Distributions 
114*0f4c859eSApple OSS Distributions #if DEVELOPMENT || DEBUG
115*0f4c859eSApple OSS Distributions 
116*0f4c859eSApple OSS Distributions /* Add a simple testing path that explicitly triggers a signed int overflow */
117*0f4c859eSApple OSS Distributions static int
118*0f4c859eSApple OSS Distributions sysctl_ubsan_test SYSCTL_HANDLER_ARGS
119*0f4c859eSApple OSS Distributions {
120*0f4c859eSApple OSS Distributions #pragma unused(oidp, arg1, arg2)
121*0f4c859eSApple OSS Distributions 	int err, incr = 0;
122*0f4c859eSApple OSS Distributions 	err = sysctl_io_number(req, 0, sizeof(int), &incr, NULL);
123*0f4c859eSApple OSS Distributions 
124*0f4c859eSApple OSS Distributions 	int k = 0x7fffffff;
125*0f4c859eSApple OSS Distributions 
126*0f4c859eSApple OSS Distributions 	for (int i = 0; i < 3; i++) {
127*0f4c859eSApple OSS Distributions 		int a = k;
128*0f4c859eSApple OSS Distributions 		if (incr != 0) {
129*0f4c859eSApple OSS Distributions 			k += incr;
130*0f4c859eSApple OSS Distributions 		}
131*0f4c859eSApple OSS Distributions 
132*0f4c859eSApple OSS Distributions 		k = a;
133*0f4c859eSApple OSS Distributions 	}
134*0f4c859eSApple OSS Distributions 
135*0f4c859eSApple OSS Distributions 	return err;
136*0f4c859eSApple OSS Distributions }
137*0f4c859eSApple OSS Distributions 
138*0f4c859eSApple OSS Distributions SYSCTL_DECL(kern_ubsan);
139*0f4c859eSApple OSS Distributions SYSCTL_NODE(_kern, OID_AUTO, ubsan, CTLFLAG_RW | CTLFLAG_LOCKED, 0, "ubsan");
140*0f4c859eSApple OSS Distributions SYSCTL_NODE(_kern_ubsan, OID_AUTO, minimal, CTLFLAG_RW | CTLFLAG_LOCKED, 0, "minimal runtime");
141*0f4c859eSApple OSS Distributions SYSCTL_INT(_kern_ubsan_minimal, OID_AUTO, fixups, CTLFLAG_RW | CTLFLAG_LOCKED, &ubsan_minimal_fixup_events, 0, "");
142*0f4c859eSApple OSS Distributions SYSCTL_INT(_kern_ubsan_minimal, OID_AUTO, signed_ovf_flags, CTLFLAG_RW | CTLFLAG_LOCKED, &(ubsan_traps[0].flags), 0, "");
143*0f4c859eSApple OSS Distributions SYSCTL_PROC(_kern_ubsan_minimal, OID_AUTO, test, CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
144*0f4c859eSApple OSS Distributions     0, 0, sysctl_ubsan_test, "I", "Test signed overflow detection");
145*0f4c859eSApple OSS Distributions 
146*0f4c859eSApple OSS Distributions #endif /* DEVELOPMENT || DEBUG */
147*0f4c859eSApple OSS Distributions 
148*0f4c859eSApple OSS Distributions #define UBSAN_M_ATTR    __attribute__((always_inline, cold))
149*0f4c859eSApple OSS Distributions 
150*0f4c859eSApple OSS Distributions UBSAN_M_ATTR void
__ubsan_handle_divrem_overflow_minimal(void)151*0f4c859eSApple OSS Distributions __ubsan_handle_divrem_overflow_minimal(void)
152*0f4c859eSApple OSS Distributions {
153*0f4c859eSApple OSS Distributions 	asm volatile ("brk #%0" : : "i"(UBSAN_SIGNED_OVERFLOW_TRAP));
154*0f4c859eSApple OSS Distributions }
155*0f4c859eSApple OSS Distributions 
156*0f4c859eSApple OSS Distributions UBSAN_M_ATTR void
__ubsan_handle_negate_overflow_minimal(void)157*0f4c859eSApple OSS Distributions __ubsan_handle_negate_overflow_minimal(void)
158*0f4c859eSApple OSS Distributions {
159*0f4c859eSApple OSS Distributions 	asm volatile ("brk #%0" : : "i"(UBSAN_SIGNED_OVERFLOW_TRAP));
160*0f4c859eSApple OSS Distributions }
161*0f4c859eSApple OSS Distributions 
162*0f4c859eSApple OSS Distributions UBSAN_M_ATTR void
__ubsan_handle_mul_overflow_minimal(void)163*0f4c859eSApple OSS Distributions __ubsan_handle_mul_overflow_minimal(void)
164*0f4c859eSApple OSS Distributions {
165*0f4c859eSApple OSS Distributions 	asm volatile ("brk #%0" : : "i"(UBSAN_SIGNED_OVERFLOW_TRAP));
166*0f4c859eSApple OSS Distributions }
167*0f4c859eSApple OSS Distributions 
168*0f4c859eSApple OSS Distributions UBSAN_M_ATTR void
__ubsan_handle_sub_overflow_minimal(void)169*0f4c859eSApple OSS Distributions __ubsan_handle_sub_overflow_minimal(void)
170*0f4c859eSApple OSS Distributions {
171*0f4c859eSApple OSS Distributions 	asm volatile ("brk #%0" : : "i"(UBSAN_SIGNED_OVERFLOW_TRAP));
172*0f4c859eSApple OSS Distributions }
173*0f4c859eSApple OSS Distributions 
174*0f4c859eSApple OSS Distributions UBSAN_M_ATTR void
__ubsan_handle_add_overflow_minimal(void)175*0f4c859eSApple OSS Distributions __ubsan_handle_add_overflow_minimal(void)
176*0f4c859eSApple OSS Distributions {
177*0f4c859eSApple OSS Distributions 	asm volatile ("brk #%0" : : "i"(UBSAN_SIGNED_OVERFLOW_TRAP));
178*0f4c859eSApple OSS Distributions }
179