xref: /xnu-10063.121.3/san/memory/kasan-classic.c (revision 2c2f96dc2b9a4408a43d3150ae9c105355ca3daa)
1*2c2f96dcSApple OSS Distributions /*
2*2c2f96dcSApple OSS Distributions  * Copyright (c) 2016-2021 Apple Inc. All rights reserved.
3*2c2f96dcSApple OSS Distributions  *
4*2c2f96dcSApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5*2c2f96dcSApple OSS Distributions  *
6*2c2f96dcSApple OSS Distributions  * This file contains Original Code and/or Modifications of Original Code
7*2c2f96dcSApple OSS Distributions  * as defined in and that are subject to the Apple Public Source License
8*2c2f96dcSApple OSS Distributions  * Version 2.0 (the 'License'). You may not use this file except in
9*2c2f96dcSApple OSS Distributions  * compliance with the License. The rights granted to you under the License
10*2c2f96dcSApple OSS Distributions  * may not be used to create, or enable the creation or redistribution of,
11*2c2f96dcSApple OSS Distributions  * unlawful or unlicensed copies of an Apple operating system, or to
12*2c2f96dcSApple OSS Distributions  * circumvent, violate, or enable the circumvention or violation of, any
13*2c2f96dcSApple OSS Distributions  * terms of an Apple operating system software license agreement.
14*2c2f96dcSApple OSS Distributions  *
15*2c2f96dcSApple OSS Distributions  * Please obtain a copy of the License at
16*2c2f96dcSApple OSS Distributions  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17*2c2f96dcSApple OSS Distributions  *
18*2c2f96dcSApple OSS Distributions  * The Original Code and all software distributed under the License are
19*2c2f96dcSApple OSS Distributions  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20*2c2f96dcSApple OSS Distributions  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21*2c2f96dcSApple OSS Distributions  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22*2c2f96dcSApple OSS Distributions  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23*2c2f96dcSApple OSS Distributions  * Please see the License for the specific language governing rights and
24*2c2f96dcSApple OSS Distributions  * limitations under the License.
25*2c2f96dcSApple OSS Distributions  *
26*2c2f96dcSApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27*2c2f96dcSApple OSS Distributions  */
28*2c2f96dcSApple OSS Distributions 
29*2c2f96dcSApple OSS Distributions #include <string.h>
30*2c2f96dcSApple OSS Distributions #include <stdint.h>
31*2c2f96dcSApple OSS Distributions #include <stdbool.h>
32*2c2f96dcSApple OSS Distributions #include <vm/vm_map.h>
33*2c2f96dcSApple OSS Distributions #include <kern/assert.h>
34*2c2f96dcSApple OSS Distributions #include <kern/cpu_data.h>
35*2c2f96dcSApple OSS Distributions #include <machine/machine_routines.h>
36*2c2f96dcSApple OSS Distributions #include <kern/locks.h>
37*2c2f96dcSApple OSS Distributions #include <kern/simple_lock.h>
38*2c2f96dcSApple OSS Distributions #include <kern/debug.h>
39*2c2f96dcSApple OSS Distributions #include <kern/backtrace.h>
40*2c2f96dcSApple OSS Distributions #include <kern/thread.h>
41*2c2f96dcSApple OSS Distributions #include <kern/btlog.h>
42*2c2f96dcSApple OSS Distributions #include <libkern/libkern.h>
43*2c2f96dcSApple OSS Distributions #include <mach/mach_vm.h>
44*2c2f96dcSApple OSS Distributions #include <mach/mach_types.h>
45*2c2f96dcSApple OSS Distributions #include <mach/vm_param.h>
46*2c2f96dcSApple OSS Distributions #include <mach/machine/vm_param.h>
47*2c2f96dcSApple OSS Distributions #include <mach/sdt.h>
48*2c2f96dcSApple OSS Distributions #include <machine/atomic.h>
49*2c2f96dcSApple OSS Distributions #include <sys/sysctl.h>
50*2c2f96dcSApple OSS Distributions 
51*2c2f96dcSApple OSS Distributions #include "kasan.h"
52*2c2f96dcSApple OSS Distributions #include "kasan_internal.h"
53*2c2f96dcSApple OSS Distributions #include "memintrinsics.h"
54*2c2f96dcSApple OSS Distributions #include "kasan-classic.h"
55*2c2f96dcSApple OSS Distributions 
56*2c2f96dcSApple OSS Distributions 
57*2c2f96dcSApple OSS Distributions /*
58*2c2f96dcSApple OSS Distributions  * KASAN-CLASSIC
59*2c2f96dcSApple OSS Distributions  *
60*2c2f96dcSApple OSS Distributions  * This implementation relies on a shadow table that matches each
61*2c2f96dcSApple OSS Distributions  * byte with 8 bytes of the kernel virtual address space. The value of this
62*2c2f96dcSApple OSS Distributions  * byte is either:
63*2c2f96dcSApple OSS Distributions  *
64*2c2f96dcSApple OSS Distributions  *  - 0:                the full 8 bytes are addressable
65*2c2f96dcSApple OSS Distributions  *  - [1,7]:            the byte is partially addressable (as many valid bytes
66*2c2f96dcSApple OSS Distributions  *                      as specified)
67*2c2f96dcSApple OSS Distributions  *  - 0xFx, 0xAC, 0xE9: byte is not addressable and poisoned somehow (for a
68*2c2f96dcSApple OSS Distributions  *                      complete list, check kasan-classic.h)
69*2c2f96dcSApple OSS Distributions  *
70*2c2f96dcSApple OSS Distributions  * Through instrumentation of every load and store and through modifications
71*2c2f96dcSApple OSS Distributions  * to the kernel to properly record and/or quarantine memory regions as a
72*2c2f96dcSApple OSS Distributions  * consequence of memory management operations, KASAN can detect nearly any
73*2c2f96dcSApple OSS Distributions  * type of memory corruption, with two big caveats: linear overflows and
74*2c2f96dcSApple OSS Distributions  * use-after-free. These are solved by redzoning and quarantines.
75*2c2f96dcSApple OSS Distributions  *
76*2c2f96dcSApple OSS Distributions  * For linear overflows, if the adjacent memory is valid (as it is common on
77*2c2f96dcSApple OSS Distributions  * both stack and heap), KASAN must add redzones next to each buffer.
78*2c2f96dcSApple OSS Distributions  * For use-after-free, free'd buffers are not returned immediately on subsequent
79*2c2f96dcSApple OSS Distributions  * memory allocation calls, but are 'stored' in a quarantined region, de-facto
80*2c2f96dcSApple OSS Distributions  * delaying reallocation.
81*2c2f96dcSApple OSS Distributions  *
82*2c2f96dcSApple OSS Distributions  * KASAN-CLASSIC has significant memory cost:
83*2c2f96dcSApple OSS Distributions  *  1) ~13% of available memory for the shadow table (4G phone -> ~512MB)
84*2c2f96dcSApple OSS Distributions  *  2) ~20-30MB of quarantine space
85*2c2f96dcSApple OSS Distributions  *  3) extra padding introduced to support redzones
86*2c2f96dcSApple OSS Distributions  *
87*2c2f96dcSApple OSS Distributions  * (1) and (2) is backed by stealing memory at boot. (3) is instead added at
88*2c2f96dcSApple OSS Distributions  * runtime on top of each allocation.
89*2c2f96dcSApple OSS Distributions  */
90*2c2f96dcSApple OSS Distributions 
91*2c2f96dcSApple OSS Distributions _Static_assert(!KASAN_LIGHT, "Light mode not supported by KASan Classic.");
92*2c2f96dcSApple OSS Distributions 
93*2c2f96dcSApple OSS Distributions /* Configuration options */
94*2c2f96dcSApple OSS Distributions static unsigned quarantine_enabled = 1;               /* Quarantine on/off */
95*2c2f96dcSApple OSS Distributions static bool checks_enabled = false;                   /* Poision checking on/off */
96*2c2f96dcSApple OSS Distributions 
97*2c2f96dcSApple OSS Distributions /*
98*2c2f96dcSApple OSS Distributions  * LLVM contains enough logic to inline check operations against the shadow
99*2c2f96dcSApple OSS Distributions  * table and uses this symbol as an anchor to find it in memory.
100*2c2f96dcSApple OSS Distributions  */
101*2c2f96dcSApple OSS Distributions const uintptr_t __asan_shadow_memory_dynamic_address = KASAN_OFFSET;
102*2c2f96dcSApple OSS Distributions 
103*2c2f96dcSApple OSS Distributions void
kasan_impl_init(void)104*2c2f96dcSApple OSS Distributions kasan_impl_init(void)
105*2c2f96dcSApple OSS Distributions {
106*2c2f96dcSApple OSS Distributions 	/* Quarantine is enabled by default */
107*2c2f96dcSApple OSS Distributions 	quarantine_enabled = 1;
108*2c2f96dcSApple OSS Distributions 
109*2c2f96dcSApple OSS Distributions 	/* Enable shadow checking early on. */
110*2c2f96dcSApple OSS Distributions 	checks_enabled = true;
111*2c2f96dcSApple OSS Distributions }
112*2c2f96dcSApple OSS Distributions 
113*2c2f96dcSApple OSS Distributions void
kasan_impl_kdp_disable(void)114*2c2f96dcSApple OSS Distributions kasan_impl_kdp_disable(void)
115*2c2f96dcSApple OSS Distributions {
116*2c2f96dcSApple OSS Distributions 	quarantine_enabled = 0;
117*2c2f96dcSApple OSS Distributions 	__asan_option_detect_stack_use_after_return = 0;
118*2c2f96dcSApple OSS Distributions 	fakestack_enabled = 0;
119*2c2f96dcSApple OSS Distributions 	checks_enabled = false;
120*2c2f96dcSApple OSS Distributions }
121*2c2f96dcSApple OSS Distributions 
122*2c2f96dcSApple OSS Distributions void NOINLINE
kasan_impl_late_init(void)123*2c2f96dcSApple OSS Distributions kasan_impl_late_init(void)
124*2c2f96dcSApple OSS Distributions {
125*2c2f96dcSApple OSS Distributions 	kasan_init_fakestack();
126*2c2f96dcSApple OSS Distributions }
127*2c2f96dcSApple OSS Distributions 
128*2c2f96dcSApple OSS Distributions /* Describes the source location where a global is defined. */
129*2c2f96dcSApple OSS Distributions struct asan_global_source_location {
130*2c2f96dcSApple OSS Distributions 	const char *filename;
131*2c2f96dcSApple OSS Distributions 	int line_no;
132*2c2f96dcSApple OSS Distributions 	int column_no;
133*2c2f96dcSApple OSS Distributions };
134*2c2f96dcSApple OSS Distributions 
135*2c2f96dcSApple OSS Distributions /* Describes an instrumented global variable. */
136*2c2f96dcSApple OSS Distributions struct asan_global {
137*2c2f96dcSApple OSS Distributions 	uptr addr;
138*2c2f96dcSApple OSS Distributions 	uptr size;
139*2c2f96dcSApple OSS Distributions 	uptr size_with_redzone;
140*2c2f96dcSApple OSS Distributions 	const char *name;
141*2c2f96dcSApple OSS Distributions 	const char *module;
142*2c2f96dcSApple OSS Distributions 	uptr has_dynamic_init;
143*2c2f96dcSApple OSS Distributions 	struct asan_global_source_location *location;
144*2c2f96dcSApple OSS Distributions #if CLANG_MIN_VERSION(8020000)
145*2c2f96dcSApple OSS Distributions 	uptr odr_indicator;
146*2c2f96dcSApple OSS Distributions #endif
147*2c2f96dcSApple OSS Distributions };
148*2c2f96dcSApple OSS Distributions 
149*2c2f96dcSApple OSS Distributions /* Walk through the globals section and set them up at boot */
150*2c2f96dcSApple OSS Distributions void NOINLINE
kasan_init_globals(vm_offset_t base,vm_size_t size)151*2c2f96dcSApple OSS Distributions kasan_init_globals(vm_offset_t base, vm_size_t size)
152*2c2f96dcSApple OSS Distributions {
153*2c2f96dcSApple OSS Distributions 	struct asan_global *glob = (struct asan_global *)base;
154*2c2f96dcSApple OSS Distributions 	struct asan_global *glob_end = (struct asan_global *)(base + size);
155*2c2f96dcSApple OSS Distributions 	for (; glob < glob_end; glob++) {
156*2c2f96dcSApple OSS Distributions 		/*
157*2c2f96dcSApple OSS Distributions 		 * Add a redzone after each global variable.
158*2c2f96dcSApple OSS Distributions 		 * size=variable size, leftsz=0, rightsz=redzone
159*2c2f96dcSApple OSS Distributions 		 */
160*2c2f96dcSApple OSS Distributions 		kasan_poison(glob->addr, glob->size, 0, glob->size_with_redzone - glob->size, ASAN_GLOBAL_RZ);
161*2c2f96dcSApple OSS Distributions 	}
162*2c2f96dcSApple OSS Distributions }
163*2c2f96dcSApple OSS Distributions 
164*2c2f96dcSApple OSS Distributions /* Reporting */
165*2c2f96dcSApple OSS Distributions static const char *
kasan_classic_access_to_str(access_t type)166*2c2f96dcSApple OSS Distributions kasan_classic_access_to_str(access_t type)
167*2c2f96dcSApple OSS Distributions {
168*2c2f96dcSApple OSS Distributions 	if (type & TYPE_READ) {
169*2c2f96dcSApple OSS Distributions 		return "load from";
170*2c2f96dcSApple OSS Distributions 	} else if (type & TYPE_WRITE) {
171*2c2f96dcSApple OSS Distributions 		return "store to";
172*2c2f96dcSApple OSS Distributions 	} else if (type & TYPE_FREE) {
173*2c2f96dcSApple OSS Distributions 		return "free of";
174*2c2f96dcSApple OSS Distributions 	} else {
175*2c2f96dcSApple OSS Distributions 		return "access of";
176*2c2f96dcSApple OSS Distributions 	}
177*2c2f96dcSApple OSS Distributions }
178*2c2f96dcSApple OSS Distributions 
179*2c2f96dcSApple OSS Distributions static const char *kasan_classic_shadow_strings[] = {
180*2c2f96dcSApple OSS Distributions 	[ASAN_VALID] =          "VALID",
181*2c2f96dcSApple OSS Distributions 	[ASAN_PARTIAL1] =       "PARTIAL1",
182*2c2f96dcSApple OSS Distributions 	[ASAN_PARTIAL2] =       "PARTIAL2",
183*2c2f96dcSApple OSS Distributions 	[ASAN_PARTIAL3] =       "PARTIAL3",
184*2c2f96dcSApple OSS Distributions 	[ASAN_PARTIAL4] =       "PARTIAL4",
185*2c2f96dcSApple OSS Distributions 	[ASAN_PARTIAL5] =       "PARTIAL5",
186*2c2f96dcSApple OSS Distributions 	[ASAN_PARTIAL6] =       "PARTIAL6",
187*2c2f96dcSApple OSS Distributions 	[ASAN_PARTIAL7] =       "PARTIAL7",
188*2c2f96dcSApple OSS Distributions 	[ASAN_STACK_LEFT_RZ] =  "STACK_LEFT_RZ",
189*2c2f96dcSApple OSS Distributions 	[ASAN_STACK_MID_RZ] =   "STACK_MID_RZ",
190*2c2f96dcSApple OSS Distributions 	[ASAN_STACK_RIGHT_RZ] = "STACK_RIGHT_RZ",
191*2c2f96dcSApple OSS Distributions 	[ASAN_STACK_FREED] =    "STACK_FREED",
192*2c2f96dcSApple OSS Distributions 	[ASAN_STACK_OOSCOPE] =  "STACK_OOSCOPE",
193*2c2f96dcSApple OSS Distributions 	[ASAN_GLOBAL_RZ] =      "GLOBAL_RZ",
194*2c2f96dcSApple OSS Distributions 	[ASAN_HEAP_LEFT_RZ] =   "HEAP_LEFT_RZ",
195*2c2f96dcSApple OSS Distributions 	[ASAN_HEAP_RIGHT_RZ] =  "HEAP_RIGHT_RZ",
196*2c2f96dcSApple OSS Distributions 	[ASAN_HEAP_FREED] =     "HEAP_FREED",
197*2c2f96dcSApple OSS Distributions 	[0xff] =                NULL
198*2c2f96dcSApple OSS Distributions };
199*2c2f96dcSApple OSS Distributions 
200*2c2f96dcSApple OSS Distributions size_t
kasan_impl_decode_issue(char * logbuf,size_t bufsize,uptr p,uptr width,access_t access,violation_t reason)201*2c2f96dcSApple OSS Distributions kasan_impl_decode_issue(char *logbuf, size_t bufsize, uptr p, uptr width, access_t access, violation_t reason)
202*2c2f96dcSApple OSS Distributions {
203*2c2f96dcSApple OSS Distributions 	uint8_t *shadow_ptr = SHADOW_FOR_ADDRESS(p);
204*2c2f96dcSApple OSS Distributions 	uint8_t shadow_type = *shadow_ptr;
205*2c2f96dcSApple OSS Distributions 	size_t n = 0;
206*2c2f96dcSApple OSS Distributions 
207*2c2f96dcSApple OSS Distributions 	const char *shadow_str = kasan_classic_shadow_strings[shadow_type];
208*2c2f96dcSApple OSS Distributions 	if (!shadow_str) {
209*2c2f96dcSApple OSS Distributions 		shadow_str = "<invalid>";
210*2c2f96dcSApple OSS Distributions 	}
211*2c2f96dcSApple OSS Distributions 
212*2c2f96dcSApple OSS Distributions 	if (reason == REASON_MOD_OOB || reason == REASON_BAD_METADATA) {
213*2c2f96dcSApple OSS Distributions 		n += scnprintf(logbuf, bufsize, "KASan: free of corrupted/invalid object %#lx\n", p);
214*2c2f96dcSApple OSS Distributions 	} else if (reason == REASON_MOD_AFTER_FREE) {
215*2c2f96dcSApple OSS Distributions 		n += scnprintf(logbuf, bufsize, "KASan: UaF of quarantined object %#lx\n", p);
216*2c2f96dcSApple OSS Distributions 	} else {
217*2c2f96dcSApple OSS Distributions 		n += scnprintf(logbuf, bufsize, "KASan: invalid %lu-byte %s %#lx [%s]\n",
218*2c2f96dcSApple OSS Distributions 		    width, kasan_classic_access_to_str(access), p, shadow_str);
219*2c2f96dcSApple OSS Distributions 	}
220*2c2f96dcSApple OSS Distributions 
221*2c2f96dcSApple OSS Distributions 	return n;
222*2c2f96dcSApple OSS Distributions }
223*2c2f96dcSApple OSS Distributions 
224*2c2f96dcSApple OSS Distributions static inline bool
kasan_poison_active(uint8_t flags)225*2c2f96dcSApple OSS Distributions kasan_poison_active(uint8_t flags)
226*2c2f96dcSApple OSS Distributions {
227*2c2f96dcSApple OSS Distributions 	switch (flags) {
228*2c2f96dcSApple OSS Distributions 	case ASAN_GLOBAL_RZ:
229*2c2f96dcSApple OSS Distributions 		return kasan_check_enabled(TYPE_POISON_GLOBAL);
230*2c2f96dcSApple OSS Distributions 	case ASAN_HEAP_RZ:
231*2c2f96dcSApple OSS Distributions 	case ASAN_HEAP_LEFT_RZ:
232*2c2f96dcSApple OSS Distributions 	case ASAN_HEAP_RIGHT_RZ:
233*2c2f96dcSApple OSS Distributions 	case ASAN_HEAP_FREED:
234*2c2f96dcSApple OSS Distributions 		return kasan_check_enabled(TYPE_POISON_HEAP);
235*2c2f96dcSApple OSS Distributions 	default:
236*2c2f96dcSApple OSS Distributions 		return true;
237*2c2f96dcSApple OSS Distributions 	}
238*2c2f96dcSApple OSS Distributions }
239*2c2f96dcSApple OSS Distributions 
240*2c2f96dcSApple OSS Distributions /*
241*2c2f96dcSApple OSS Distributions  * Create a poisoned redzone at the top and at the end of a (marked) valid range.
242*2c2f96dcSApple OSS Distributions  * Parameters:
243*2c2f96dcSApple OSS Distributions  *    base: starting address (including the eventual left red zone)
244*2c2f96dcSApple OSS Distributions  *    size: size of the valid range
245*2c2f96dcSApple OSS Distributions  *    leftrz: size (multiple of KASAN_GRANULE) of the left redzone
246*2c2f96dcSApple OSS Distributions  *    rightrz: size (multiple of KASAN_GRANULE) of the right redzone
247*2c2f96dcSApple OSS Distributions  *    flags: select between different poisoning options (e.g. stack vs heap)
248*2c2f96dcSApple OSS Distributions  */
249*2c2f96dcSApple OSS Distributions void NOINLINE
kasan_poison(vm_offset_t base,vm_size_t size,vm_size_t leftrz,vm_size_t rightrz,uint8_t flags)250*2c2f96dcSApple OSS Distributions kasan_poison(vm_offset_t base, vm_size_t size, vm_size_t leftrz,
251*2c2f96dcSApple OSS Distributions     vm_size_t rightrz, uint8_t flags)
252*2c2f96dcSApple OSS Distributions {
253*2c2f96dcSApple OSS Distributions 	uint8_t *shadow = SHADOW_FOR_ADDRESS(base);
254*2c2f96dcSApple OSS Distributions 	/*
255*2c2f96dcSApple OSS Distributions 	 * Buffer size is allowed to not be a multiple of 8. Create a partial
256*2c2f96dcSApple OSS Distributions 	 * entry in the shadow table if so.
257*2c2f96dcSApple OSS Distributions 	 */
258*2c2f96dcSApple OSS Distributions 	uint8_t partial = (uint8_t)kasan_granule_partial(size);
259*2c2f96dcSApple OSS Distributions 	vm_size_t total = leftrz + size + rightrz;
260*2c2f96dcSApple OSS Distributions 	vm_size_t pos = 0;
261*2c2f96dcSApple OSS Distributions 
262*2c2f96dcSApple OSS Distributions 	/* ensure base, leftrz and total allocation size are granule-aligned */
263*2c2f96dcSApple OSS Distributions 	assert(kasan_granule_partial(base) == 0);
264*2c2f96dcSApple OSS Distributions 	assert(kasan_granule_partial(leftrz) == 0);
265*2c2f96dcSApple OSS Distributions 	assert(kasan_granule_partial(total) == 0);
266*2c2f96dcSApple OSS Distributions 
267*2c2f96dcSApple OSS Distributions 	if (!kasan_enabled || !kasan_poison_active(flags)) {
268*2c2f96dcSApple OSS Distributions 		return;
269*2c2f96dcSApple OSS Distributions 	}
270*2c2f96dcSApple OSS Distributions 
271*2c2f96dcSApple OSS Distributions 	leftrz >>= KASAN_SCALE;
272*2c2f96dcSApple OSS Distributions 	size >>= KASAN_SCALE;
273*2c2f96dcSApple OSS Distributions 	total >>= KASAN_SCALE;
274*2c2f96dcSApple OSS Distributions 
275*2c2f96dcSApple OSS Distributions 	uint8_t l_flags = flags;
276*2c2f96dcSApple OSS Distributions 	uint8_t r_flags = flags;
277*2c2f96dcSApple OSS Distributions 
278*2c2f96dcSApple OSS Distributions 	if (flags == ASAN_STACK_RZ) {
279*2c2f96dcSApple OSS Distributions 		l_flags = ASAN_STACK_LEFT_RZ;
280*2c2f96dcSApple OSS Distributions 		r_flags = ASAN_STACK_RIGHT_RZ;
281*2c2f96dcSApple OSS Distributions 	} else if (flags == ASAN_HEAP_RZ) {
282*2c2f96dcSApple OSS Distributions 		l_flags = ASAN_HEAP_LEFT_RZ;
283*2c2f96dcSApple OSS Distributions 		r_flags = ASAN_HEAP_RIGHT_RZ;
284*2c2f96dcSApple OSS Distributions 	}
285*2c2f96dcSApple OSS Distributions 
286*2c2f96dcSApple OSS Distributions 	/*
287*2c2f96dcSApple OSS Distributions 	 * poison the redzones and unpoison the valid bytes
288*2c2f96dcSApple OSS Distributions 	 */
289*2c2f96dcSApple OSS Distributions 	__nosan_memset(shadow + pos, l_flags, leftrz);
290*2c2f96dcSApple OSS Distributions 	pos += leftrz;
291*2c2f96dcSApple OSS Distributions 
292*2c2f96dcSApple OSS Distributions 	__nosan_memset(shadow + pos, ASAN_VALID, size);
293*2c2f96dcSApple OSS Distributions 	pos += size;
294*2c2f96dcSApple OSS Distributions 
295*2c2f96dcSApple OSS Distributions 	/* Do we have any leftover valid byte? */
296*2c2f96dcSApple OSS Distributions 	if (partial && pos < total) {
297*2c2f96dcSApple OSS Distributions 		shadow[pos++] = partial;
298*2c2f96dcSApple OSS Distributions 	}
299*2c2f96dcSApple OSS Distributions 
300*2c2f96dcSApple OSS Distributions 	__nosan_memset(shadow + pos, r_flags, total - pos);
301*2c2f96dcSApple OSS Distributions }
302*2c2f96dcSApple OSS Distributions 
303*2c2f96dcSApple OSS Distributions /*
304*2c2f96dcSApple OSS Distributions  * Check the shadow table to determine whether [base, base+size) is valid or
305*2c2f96dcSApple OSS Distributions  * is poisoned.
306*2c2f96dcSApple OSS Distributions  */
307*2c2f96dcSApple OSS Distributions static bool NOINLINE
kasan_range_poisoned(vm_offset_t base,vm_size_t size,vm_offset_t * first_invalid)308*2c2f96dcSApple OSS Distributions kasan_range_poisoned(vm_offset_t base, vm_size_t size, vm_offset_t *first_invalid)
309*2c2f96dcSApple OSS Distributions {
310*2c2f96dcSApple OSS Distributions 	uint8_t         *shadow;
311*2c2f96dcSApple OSS Distributions 	vm_size_t       i;
312*2c2f96dcSApple OSS Distributions 
313*2c2f96dcSApple OSS Distributions 	if (!kasan_enabled) {
314*2c2f96dcSApple OSS Distributions 		return false;
315*2c2f96dcSApple OSS Distributions 	}
316*2c2f96dcSApple OSS Distributions 
317*2c2f96dcSApple OSS Distributions 	size += kasan_granule_partial(base);
318*2c2f96dcSApple OSS Distributions 	base = kasan_granule_trunc(base);
319*2c2f96dcSApple OSS Distributions 
320*2c2f96dcSApple OSS Distributions 	shadow = SHADOW_FOR_ADDRESS(base);
321*2c2f96dcSApple OSS Distributions 	size_t limit = (size + KASAN_GRANULE - 1) / KASAN_GRANULE;
322*2c2f96dcSApple OSS Distributions 
323*2c2f96dcSApple OSS Distributions 	/* Walk the shadow table, fail on any non-valid value */
324*2c2f96dcSApple OSS Distributions 	for (i = 0; i < limit; i++, size -= KASAN_GRANULE) {
325*2c2f96dcSApple OSS Distributions 		assert(size > 0);
326*2c2f96dcSApple OSS Distributions 		uint8_t s = shadow[i];
327*2c2f96dcSApple OSS Distributions 		if (s == 0 || (size < KASAN_GRANULE && s >= size && s < KASAN_GRANULE)) {
328*2c2f96dcSApple OSS Distributions 			/* valid */
329*2c2f96dcSApple OSS Distributions 			continue;
330*2c2f96dcSApple OSS Distributions 		} else {
331*2c2f96dcSApple OSS Distributions 			goto fail;
332*2c2f96dcSApple OSS Distributions 		}
333*2c2f96dcSApple OSS Distributions 	}
334*2c2f96dcSApple OSS Distributions 
335*2c2f96dcSApple OSS Distributions 	return false;
336*2c2f96dcSApple OSS Distributions 
337*2c2f96dcSApple OSS Distributions fail:
338*2c2f96dcSApple OSS Distributions 	if (first_invalid) {
339*2c2f96dcSApple OSS Distributions 		/* XXX: calculate the exact first byte that failed */
340*2c2f96dcSApple OSS Distributions 		*first_invalid = base + i * 8;
341*2c2f96dcSApple OSS Distributions 	}
342*2c2f96dcSApple OSS Distributions 	return true;
343*2c2f96dcSApple OSS Distributions }
344*2c2f96dcSApple OSS Distributions 
345*2c2f96dcSApple OSS Distributions /* An 8-byte valid range is indetified by 0 in kasan classic shadow table */
346*2c2f96dcSApple OSS Distributions void
kasan_impl_fill_valid_range(uintptr_t page,size_t size)347*2c2f96dcSApple OSS Distributions kasan_impl_fill_valid_range(uintptr_t page, size_t size)
348*2c2f96dcSApple OSS Distributions {
349*2c2f96dcSApple OSS Distributions 	__nosan_bzero((void *)page, size);
350*2c2f96dcSApple OSS Distributions }
351*2c2f96dcSApple OSS Distributions 
352*2c2f96dcSApple OSS Distributions /*
353*2c2f96dcSApple OSS Distributions  * Verify whether an access to memory is valid. A valid access is one that
354*2c2f96dcSApple OSS Distributions  * doesn't touch any region marked as a poisoned redzone or invalid.
355*2c2f96dcSApple OSS Distributions  * 'access' records whether the attempted access is a read or a write.
356*2c2f96dcSApple OSS Distributions  */
357*2c2f96dcSApple OSS Distributions void NOINLINE
kasan_check_range(const void * x,size_t sz,access_t access)358*2c2f96dcSApple OSS Distributions kasan_check_range(const void *x, size_t sz, access_t access)
359*2c2f96dcSApple OSS Distributions {
360*2c2f96dcSApple OSS Distributions 	uintptr_t invalid;
361*2c2f96dcSApple OSS Distributions 	uintptr_t ptr = (uintptr_t)x;
362*2c2f96dcSApple OSS Distributions 
363*2c2f96dcSApple OSS Distributions 	if (!checks_enabled) {
364*2c2f96dcSApple OSS Distributions 		return;
365*2c2f96dcSApple OSS Distributions 	}
366*2c2f96dcSApple OSS Distributions 
367*2c2f96dcSApple OSS Distributions 	if (kasan_range_poisoned(ptr, sz, &invalid)) {
368*2c2f96dcSApple OSS Distributions 		size_t remaining = sz - (invalid - ptr);
369*2c2f96dcSApple OSS Distributions 		kasan_violation(invalid, remaining, access, REASON_POISONED);
370*2c2f96dcSApple OSS Distributions 	}
371*2c2f96dcSApple OSS Distributions }
372*2c2f96dcSApple OSS Distributions 
373*2c2f96dcSApple OSS Distributions /*
374*2c2f96dcSApple OSS Distributions  * Return true if [base, base+sz) is unpoisoned or matches the passed in
375*2c2f96dcSApple OSS Distributions  * shadow value.
376*2c2f96dcSApple OSS Distributions  */
377*2c2f96dcSApple OSS Distributions bool
kasan_check_shadow(vm_address_t addr,vm_size_t sz,uint8_t shadow_match_value)378*2c2f96dcSApple OSS Distributions kasan_check_shadow(vm_address_t addr, vm_size_t sz, uint8_t shadow_match_value)
379*2c2f96dcSApple OSS Distributions {
380*2c2f96dcSApple OSS Distributions 	/* round 'base' up to skip any partial, which won't match 'shadow' */
381*2c2f96dcSApple OSS Distributions 	uintptr_t base = kasan_granule_round(addr);
382*2c2f96dcSApple OSS Distributions 	sz -= base - addr;
383*2c2f96dcSApple OSS Distributions 
384*2c2f96dcSApple OSS Distributions 	uintptr_t end = base + sz;
385*2c2f96dcSApple OSS Distributions 
386*2c2f96dcSApple OSS Distributions 	while (base < end) {
387*2c2f96dcSApple OSS Distributions 		uint8_t *sh = SHADOW_FOR_ADDRESS(base);
388*2c2f96dcSApple OSS Distributions 		if (*sh && *sh != shadow_match_value) {
389*2c2f96dcSApple OSS Distributions 			return false;
390*2c2f96dcSApple OSS Distributions 		}
391*2c2f96dcSApple OSS Distributions 		base += KASAN_GRANULE;
392*2c2f96dcSApple OSS Distributions 	}
393*2c2f96dcSApple OSS Distributions 	return true;
394*2c2f96dcSApple OSS Distributions }
395*2c2f96dcSApple OSS Distributions 
396*2c2f96dcSApple OSS Distributions /*
397*2c2f96dcSApple OSS Distributions  * KASAN zalloc hooks
398*2c2f96dcSApple OSS Distributions  *
399*2c2f96dcSApple OSS Distributions  * KASAN can only distinguish between valid and unvalid memory accesses.
400*2c2f96dcSApple OSS Distributions  * This property severely limits its applicability to zalloc (and any other
401*2c2f96dcSApple OSS Distributions  * memory allocator), whereby linear overflows are generally to valid
402*2c2f96dcSApple OSS Distributions  * memory and non-simple use-after-free can hit an already reallocated buffer.
403*2c2f96dcSApple OSS Distributions  *
404*2c2f96dcSApple OSS Distributions  * To overcome these limitations, KASAN requires a bunch of fairly invasive
405*2c2f96dcSApple OSS Distributions  * changes to zalloc to add both red-zoning and quarantines.
406*2c2f96dcSApple OSS Distributions  */
407*2c2f96dcSApple OSS Distributions 
408*2c2f96dcSApple OSS Distributions __enum_decl(kasan_alloc_state_t, uint16_t, {
409*2c2f96dcSApple OSS Distributions 	KASAN_STATE_FREED,
410*2c2f96dcSApple OSS Distributions 	KASAN_STATE_ALLOCATED,
411*2c2f96dcSApple OSS Distributions 	KASAN_STATE_QUARANTINED,
412*2c2f96dcSApple OSS Distributions });
413*2c2f96dcSApple OSS Distributions 
414*2c2f96dcSApple OSS Distributions typedef struct kasan_alloc_header {
415*2c2f96dcSApple OSS Distributions 	union {
416*2c2f96dcSApple OSS Distributions 		struct {
417*2c2f96dcSApple OSS Distributions 			kasan_alloc_state_t state;
418*2c2f96dcSApple OSS Distributions 			uint16_t left_rz;
419*2c2f96dcSApple OSS Distributions 			uint32_t user_size;
420*2c2f96dcSApple OSS Distributions 		};
421*2c2f96dcSApple OSS Distributions 		struct {
422*2c2f96dcSApple OSS Distributions 			kasan_alloc_state_t state2;
423*2c2f96dcSApple OSS Distributions 			intptr_t next : 48;
424*2c2f96dcSApple OSS Distributions 		};
425*2c2f96dcSApple OSS Distributions 	};
426*2c2f96dcSApple OSS Distributions 	btref_t  alloc_btref;
427*2c2f96dcSApple OSS Distributions 	btref_t  free_btref;
428*2c2f96dcSApple OSS Distributions } *kasan_alloc_header_t;
429*2c2f96dcSApple OSS Distributions static_assert(sizeof(struct kasan_alloc_header) == KASAN_GUARD_SIZE);
430*2c2f96dcSApple OSS Distributions 
431*2c2f96dcSApple OSS Distributions static kasan_alloc_header_t
header_for_user_addr(vm_offset_t addr)432*2c2f96dcSApple OSS Distributions header_for_user_addr(vm_offset_t addr)
433*2c2f96dcSApple OSS Distributions {
434*2c2f96dcSApple OSS Distributions 	return (void *)(addr - sizeof(struct kasan_alloc_header));
435*2c2f96dcSApple OSS Distributions }
436*2c2f96dcSApple OSS Distributions 
437*2c2f96dcSApple OSS Distributions void
kasan_zmem_add(vm_address_t addr,vm_size_t size,vm_offset_t esize,vm_offset_t offs,vm_offset_t rzsize)438*2c2f96dcSApple OSS Distributions kasan_zmem_add(
439*2c2f96dcSApple OSS Distributions 	vm_address_t            addr,
440*2c2f96dcSApple OSS Distributions 	vm_size_t               size,
441*2c2f96dcSApple OSS Distributions 	vm_offset_t             esize,
442*2c2f96dcSApple OSS Distributions 	vm_offset_t             offs,
443*2c2f96dcSApple OSS Distributions 	vm_offset_t             rzsize)
444*2c2f96dcSApple OSS Distributions {
445*2c2f96dcSApple OSS Distributions 	uint8_t *shadow = SHADOW_FOR_ADDRESS(addr);
446*2c2f96dcSApple OSS Distributions 
447*2c2f96dcSApple OSS Distributions 	assert(kasan_granule_partial(esize) == 0);
448*2c2f96dcSApple OSS Distributions 	assert(kasan_granule_partial(offs) == 0);
449*2c2f96dcSApple OSS Distributions 	assert(kasan_granule_partial(rzsize) == 0);
450*2c2f96dcSApple OSS Distributions 	assert((size - offs) % esize == 0);
451*2c2f96dcSApple OSS Distributions 
452*2c2f96dcSApple OSS Distributions 	size   >>= KASAN_SCALE;
453*2c2f96dcSApple OSS Distributions 	esize  >>= KASAN_SCALE;
454*2c2f96dcSApple OSS Distributions 	offs   >>= KASAN_SCALE;
455*2c2f96dcSApple OSS Distributions 	rzsize >>= KASAN_SCALE;
456*2c2f96dcSApple OSS Distributions 
457*2c2f96dcSApple OSS Distributions 	__nosan_memset(shadow, ASAN_HEAP_FREED, size);
458*2c2f96dcSApple OSS Distributions 
459*2c2f96dcSApple OSS Distributions 	__nosan_memset(shadow, ASAN_HEAP_LEFT_RZ, offs);
460*2c2f96dcSApple OSS Distributions 
461*2c2f96dcSApple OSS Distributions 	for (vm_offset_t pos = offs; pos < size; pos += esize) {
462*2c2f96dcSApple OSS Distributions 		__nosan_memset(shadow + pos, ASAN_HEAP_LEFT_RZ, rzsize);
463*2c2f96dcSApple OSS Distributions 	}
464*2c2f96dcSApple OSS Distributions }
465*2c2f96dcSApple OSS Distributions 
466*2c2f96dcSApple OSS Distributions void
kasan_zmem_remove(vm_address_t addr,vm_size_t size,vm_offset_t esize,vm_offset_t offs,vm_offset_t rzsize)467*2c2f96dcSApple OSS Distributions kasan_zmem_remove(
468*2c2f96dcSApple OSS Distributions 	vm_address_t            addr,
469*2c2f96dcSApple OSS Distributions 	vm_size_t               size,
470*2c2f96dcSApple OSS Distributions 	vm_offset_t             esize,
471*2c2f96dcSApple OSS Distributions 	vm_offset_t             offs,
472*2c2f96dcSApple OSS Distributions 	vm_offset_t             rzsize)
473*2c2f96dcSApple OSS Distributions {
474*2c2f96dcSApple OSS Distributions 	uint8_t *shadow = SHADOW_FOR_ADDRESS(addr);
475*2c2f96dcSApple OSS Distributions 
476*2c2f96dcSApple OSS Distributions 	assert(kasan_granule_partial(esize) == 0);
477*2c2f96dcSApple OSS Distributions 	assert(kasan_granule_partial(offs) == 0);
478*2c2f96dcSApple OSS Distributions 	assert(kasan_granule_partial(rzsize) == 0);
479*2c2f96dcSApple OSS Distributions 	assert((size - offs) % esize == 0);
480*2c2f96dcSApple OSS Distributions 
481*2c2f96dcSApple OSS Distributions 	if (rzsize) {
482*2c2f96dcSApple OSS Distributions 		for (vm_offset_t pos = offs + rzsize; pos < size; pos += esize) {
483*2c2f96dcSApple OSS Distributions 			kasan_alloc_header_t h;
484*2c2f96dcSApple OSS Distributions 
485*2c2f96dcSApple OSS Distributions 			h = header_for_user_addr(addr + pos);
486*2c2f96dcSApple OSS Distributions 
487*2c2f96dcSApple OSS Distributions 			assert(h->state == KASAN_STATE_FREED);
488*2c2f96dcSApple OSS Distributions 			btref_put(h->alloc_btref);
489*2c2f96dcSApple OSS Distributions 			btref_put(h->free_btref);
490*2c2f96dcSApple OSS Distributions 		}
491*2c2f96dcSApple OSS Distributions 	}
492*2c2f96dcSApple OSS Distributions 
493*2c2f96dcSApple OSS Distributions 	__nosan_memset(shadow, ASAN_VALID, size >> KASAN_SCALE);
494*2c2f96dcSApple OSS Distributions }
495*2c2f96dcSApple OSS Distributions 
496*2c2f96dcSApple OSS Distributions void
kasan_alloc(vm_address_t addr,vm_size_t size,vm_size_t req,vm_size_t rzsize,bool percpu,void * fp)497*2c2f96dcSApple OSS Distributions kasan_alloc(
498*2c2f96dcSApple OSS Distributions 	vm_address_t            addr,
499*2c2f96dcSApple OSS Distributions 	vm_size_t               size,
500*2c2f96dcSApple OSS Distributions 	vm_size_t               req,
501*2c2f96dcSApple OSS Distributions 	vm_size_t               rzsize,
502*2c2f96dcSApple OSS Distributions 	bool                    percpu,
503*2c2f96dcSApple OSS Distributions 	void                   *fp)
504*2c2f96dcSApple OSS Distributions {
505*2c2f96dcSApple OSS Distributions 	assert(kasan_granule_partial(addr) == 0);
506*2c2f96dcSApple OSS Distributions 	assert(kasan_granule_partial(size) == 0);
507*2c2f96dcSApple OSS Distributions 	assert(kasan_granule_partial(rzsize) == 0);
508*2c2f96dcSApple OSS Distributions 
509*2c2f96dcSApple OSS Distributions 	if (rzsize) {
510*2c2f96dcSApple OSS Distributions 		/* stash the allocation sizes in the left redzone */
511*2c2f96dcSApple OSS Distributions 		kasan_alloc_header_t h = header_for_user_addr(addr);
512*2c2f96dcSApple OSS Distributions 
513*2c2f96dcSApple OSS Distributions 		btref_put(h->free_btref);
514*2c2f96dcSApple OSS Distributions 		btref_put(h->alloc_btref);
515*2c2f96dcSApple OSS Distributions 
516*2c2f96dcSApple OSS Distributions 		h->state       = KASAN_STATE_ALLOCATED;
517*2c2f96dcSApple OSS Distributions 		h->left_rz     = (uint16_t)rzsize;
518*2c2f96dcSApple OSS Distributions 		h->user_size   = (uint32_t)req;
519*2c2f96dcSApple OSS Distributions 		h->alloc_btref = btref_get(fp, BTREF_GET_NOWAIT);
520*2c2f96dcSApple OSS Distributions 		h->free_btref  = 0;
521*2c2f96dcSApple OSS Distributions 	}
522*2c2f96dcSApple OSS Distributions 
523*2c2f96dcSApple OSS Distributions 	kasan_poison(addr, req, 0, size - req, ASAN_HEAP_RZ);
524*2c2f96dcSApple OSS Distributions 	if (percpu) {
525*2c2f96dcSApple OSS Distributions 		for (uint32_t i = 1; i < zpercpu_count(); i++) {
526*2c2f96dcSApple OSS Distributions 			addr += PAGE_SIZE;
527*2c2f96dcSApple OSS Distributions 			kasan_poison(addr, req, 0, size - req, ASAN_HEAP_RZ);
528*2c2f96dcSApple OSS Distributions 		}
529*2c2f96dcSApple OSS Distributions 	}
530*2c2f96dcSApple OSS Distributions }
531*2c2f96dcSApple OSS Distributions 
532*2c2f96dcSApple OSS Distributions void
kasan_free(vm_address_t addr,vm_size_t size,vm_size_t req,vm_size_t rzsize,bool percpu,void * fp)533*2c2f96dcSApple OSS Distributions kasan_free(
534*2c2f96dcSApple OSS Distributions 	vm_address_t            addr,
535*2c2f96dcSApple OSS Distributions 	vm_size_t               size,
536*2c2f96dcSApple OSS Distributions 	vm_size_t               req,
537*2c2f96dcSApple OSS Distributions 	vm_size_t               rzsize,
538*2c2f96dcSApple OSS Distributions 	bool                    percpu,
539*2c2f96dcSApple OSS Distributions 	void                   *fp)
540*2c2f96dcSApple OSS Distributions {
541*2c2f96dcSApple OSS Distributions 	uint8_t *shadow = SHADOW_FOR_ADDRESS(addr);
542*2c2f96dcSApple OSS Distributions 
543*2c2f96dcSApple OSS Distributions 	if (rzsize) {
544*2c2f96dcSApple OSS Distributions 		kasan_alloc_header_t h = header_for_user_addr(addr);
545*2c2f96dcSApple OSS Distributions 
546*2c2f96dcSApple OSS Distributions 		kasan_check_alloc(addr, size, req);
547*2c2f96dcSApple OSS Distributions 		assert(h->free_btref == 0);
548*2c2f96dcSApple OSS Distributions 		h->state      = KASAN_STATE_FREED;
549*2c2f96dcSApple OSS Distributions 		h->next       = 0;
550*2c2f96dcSApple OSS Distributions 		h->free_btref = btref_get(fp, BTREF_GET_NOWAIT);
551*2c2f96dcSApple OSS Distributions 	}
552*2c2f96dcSApple OSS Distributions 
553*2c2f96dcSApple OSS Distributions 	__nosan_memset(shadow, ASAN_HEAP_FREED, size >> KASAN_SCALE);
554*2c2f96dcSApple OSS Distributions 	if (percpu) {
555*2c2f96dcSApple OSS Distributions 		for (uint32_t i = 1; i < zpercpu_count(); i++) {
556*2c2f96dcSApple OSS Distributions 			shadow += PAGE_SIZE >> KASAN_SCALE;
557*2c2f96dcSApple OSS Distributions 			__nosan_memset(shadow, ASAN_HEAP_FREED,
558*2c2f96dcSApple OSS Distributions 			    size >> KASAN_SCALE);
559*2c2f96dcSApple OSS Distributions 		}
560*2c2f96dcSApple OSS Distributions 	}
561*2c2f96dcSApple OSS Distributions }
562*2c2f96dcSApple OSS Distributions 
563*2c2f96dcSApple OSS Distributions void
kasan_alloc_large(vm_address_t addr,vm_size_t req_size)564*2c2f96dcSApple OSS Distributions kasan_alloc_large(vm_address_t addr, vm_size_t req_size)
565*2c2f96dcSApple OSS Distributions {
566*2c2f96dcSApple OSS Distributions 	vm_size_t l_rz = PAGE_SIZE;
567*2c2f96dcSApple OSS Distributions 	vm_size_t r_rz = round_page(req_size) - req_size + PAGE_SIZE;
568*2c2f96dcSApple OSS Distributions 
569*2c2f96dcSApple OSS Distributions 	kasan_poison(addr - l_rz, req_size, l_rz, r_rz, ASAN_HEAP_RZ);
570*2c2f96dcSApple OSS Distributions }
571*2c2f96dcSApple OSS Distributions 
572*2c2f96dcSApple OSS Distributions /*
573*2c2f96dcSApple OSS Distributions  * return the original user-requested allocation size
574*2c2f96dcSApple OSS Distributions  * addr: user alloc pointer
575*2c2f96dcSApple OSS Distributions  */
576*2c2f96dcSApple OSS Distributions vm_size_t
kasan_user_size(vm_offset_t addr)577*2c2f96dcSApple OSS Distributions kasan_user_size(vm_offset_t addr)
578*2c2f96dcSApple OSS Distributions {
579*2c2f96dcSApple OSS Distributions 	kasan_alloc_header_t h = header_for_user_addr(addr);
580*2c2f96dcSApple OSS Distributions 
581*2c2f96dcSApple OSS Distributions 	assert(h->state == KASAN_STATE_ALLOCATED);
582*2c2f96dcSApple OSS Distributions 	return h->user_size;
583*2c2f96dcSApple OSS Distributions }
584*2c2f96dcSApple OSS Distributions 
585*2c2f96dcSApple OSS Distributions /*
586*2c2f96dcSApple OSS Distributions  * Verify that `addr' (user pointer) is a valid allocation
587*2c2f96dcSApple OSS Distributions  */
588*2c2f96dcSApple OSS Distributions void
kasan_check_alloc(vm_offset_t addr,vm_size_t size,vm_size_t req)589*2c2f96dcSApple OSS Distributions kasan_check_alloc(vm_offset_t addr, vm_size_t size, vm_size_t req)
590*2c2f96dcSApple OSS Distributions {
591*2c2f96dcSApple OSS Distributions 	kasan_alloc_header_t h = header_for_user_addr(addr);
592*2c2f96dcSApple OSS Distributions 
593*2c2f96dcSApple OSS Distributions 	if (!checks_enabled) {
594*2c2f96dcSApple OSS Distributions 		return;
595*2c2f96dcSApple OSS Distributions 	}
596*2c2f96dcSApple OSS Distributions 
597*2c2f96dcSApple OSS Distributions 	if (h->state != KASAN_STATE_ALLOCATED) {
598*2c2f96dcSApple OSS Distributions 		kasan_violation(addr, req, TYPE_ZFREE, REASON_BAD_METADATA);
599*2c2f96dcSApple OSS Distributions 	}
600*2c2f96dcSApple OSS Distributions 
601*2c2f96dcSApple OSS Distributions 	/* check the freed size matches what we recorded at alloc time */
602*2c2f96dcSApple OSS Distributions 	if (h->user_size != req) {
603*2c2f96dcSApple OSS Distributions 		kasan_violation(addr, req, TYPE_ZFREE, REASON_INVALID_SIZE);
604*2c2f96dcSApple OSS Distributions 	}
605*2c2f96dcSApple OSS Distributions 
606*2c2f96dcSApple OSS Distributions 	vm_size_t rightrz_sz = size - h->user_size;
607*2c2f96dcSApple OSS Distributions 
608*2c2f96dcSApple OSS Distributions 	/* Check that the redzones are valid */
609*2c2f96dcSApple OSS Distributions 	if (!kasan_check_shadow(addr - h->left_rz, h->left_rz, ASAN_HEAP_LEFT_RZ) ||
610*2c2f96dcSApple OSS Distributions 	    !kasan_check_shadow(addr + h->user_size, rightrz_sz, ASAN_HEAP_RIGHT_RZ)) {
611*2c2f96dcSApple OSS Distributions 		kasan_violation(addr, req, TYPE_ZFREE, REASON_BAD_METADATA);
612*2c2f96dcSApple OSS Distributions 	}
613*2c2f96dcSApple OSS Distributions 
614*2c2f96dcSApple OSS Distributions 	/* Check the allocated range is not poisoned */
615*2c2f96dcSApple OSS Distributions 	kasan_check_range((void *)addr, req, TYPE_ZFREE);
616*2c2f96dcSApple OSS Distributions }
617*2c2f96dcSApple OSS Distributions 
618*2c2f96dcSApple OSS Distributions /*
619*2c2f96dcSApple OSS Distributions  * KASAN Quarantine
620*2c2f96dcSApple OSS Distributions  */
621*2c2f96dcSApple OSS Distributions 
622*2c2f96dcSApple OSS Distributions typedef struct kasan_quarantine {
623*2c2f96dcSApple OSS Distributions 	kasan_alloc_header_t  head;
624*2c2f96dcSApple OSS Distributions 	kasan_alloc_header_t  tail;
625*2c2f96dcSApple OSS Distributions 	uint32_t              size;
626*2c2f96dcSApple OSS Distributions 	uint32_t              count;
627*2c2f96dcSApple OSS Distributions } *kasan_quarantine_t;
628*2c2f96dcSApple OSS Distributions 
629*2c2f96dcSApple OSS Distributions static struct kasan_quarantine PERCPU_DATA(kasan_quarantine);
630*2c2f96dcSApple OSS Distributions 
631*2c2f96dcSApple OSS Distributions extern int get_preemption_level(void);
632*2c2f96dcSApple OSS Distributions 
633*2c2f96dcSApple OSS Distributions struct kasan_quarantine_result
kasan_quarantine(vm_address_t addr,vm_size_t size)634*2c2f96dcSApple OSS Distributions kasan_quarantine(vm_address_t addr, vm_size_t size)
635*2c2f96dcSApple OSS Distributions {
636*2c2f96dcSApple OSS Distributions 	kasan_alloc_header_t h = header_for_user_addr(addr);
637*2c2f96dcSApple OSS Distributions 	kasan_quarantine_t   q = PERCPU_GET(kasan_quarantine);
638*2c2f96dcSApple OSS Distributions 	struct kasan_quarantine_result kqr = { };
639*2c2f96dcSApple OSS Distributions 
640*2c2f96dcSApple OSS Distributions 	assert(h->state == KASAN_STATE_FREED && h->next == 0);
641*2c2f96dcSApple OSS Distributions 
642*2c2f96dcSApple OSS Distributions 	h->state = KASAN_STATE_QUARANTINED;
643*2c2f96dcSApple OSS Distributions 
644*2c2f96dcSApple OSS Distributions 	q->size += size;
645*2c2f96dcSApple OSS Distributions 	q->count++;
646*2c2f96dcSApple OSS Distributions 	if (q->tail == NULL) {
647*2c2f96dcSApple OSS Distributions 		q->head = h;
648*2c2f96dcSApple OSS Distributions 	} else {
649*2c2f96dcSApple OSS Distributions 		q->tail->next = (intptr_t)h;
650*2c2f96dcSApple OSS Distributions 	}
651*2c2f96dcSApple OSS Distributions 	q->tail = h;
652*2c2f96dcSApple OSS Distributions 
653*2c2f96dcSApple OSS Distributions 	if (q->size >= QUARANTINE_MAXSIZE || q->count > QUARANTINE_ENTRIES) {
654*2c2f96dcSApple OSS Distributions 		h = q->head;
655*2c2f96dcSApple OSS Distributions 		assert(h->state == KASAN_STATE_QUARANTINED);
656*2c2f96dcSApple OSS Distributions 
657*2c2f96dcSApple OSS Distributions 		q->head  = (kasan_alloc_header_t)(intptr_t)h->next;
658*2c2f96dcSApple OSS Distributions 		h->state = KASAN_STATE_FREED;
659*2c2f96dcSApple OSS Distributions 		h->next  = 0;
660*2c2f96dcSApple OSS Distributions 
661*2c2f96dcSApple OSS Distributions 		kqr.addr = (vm_address_t)(h + 1);
662*2c2f96dcSApple OSS Distributions 		q->size -= kasan_quarantine_resolve(kqr.addr, &kqr.zone);
663*2c2f96dcSApple OSS Distributions 		q->count--;
664*2c2f96dcSApple OSS Distributions 	}
665*2c2f96dcSApple OSS Distributions 
666*2c2f96dcSApple OSS Distributions 	return kqr;
667*2c2f96dcSApple OSS Distributions }
668*2c2f96dcSApple OSS Distributions 
669*2c2f96dcSApple OSS Distributions /*
670*2c2f96dcSApple OSS Distributions  * Unpoison the C++ array cookie (if it exists). We don't know exactly where it
671*2c2f96dcSApple OSS Distributions  * lives relative to the start of the buffer, but it's always the word immediately
672*2c2f96dcSApple OSS Distributions  * before the start of the array data, so for naturally-aligned objects we need to
673*2c2f96dcSApple OSS Distributions  * search at most 2 shadow bytes.
674*2c2f96dcSApple OSS Distributions  */
675*2c2f96dcSApple OSS Distributions void
kasan_unpoison_cxx_array_cookie(void * ptr)676*2c2f96dcSApple OSS Distributions kasan_unpoison_cxx_array_cookie(void *ptr)
677*2c2f96dcSApple OSS Distributions {
678*2c2f96dcSApple OSS Distributions 	uint8_t *shadow = SHADOW_FOR_ADDRESS((uptr)ptr);
679*2c2f96dcSApple OSS Distributions 	for (size_t i = 0; i < 2; i++) {
680*2c2f96dcSApple OSS Distributions 		if (shadow[i] == ASAN_ARRAY_COOKIE) {
681*2c2f96dcSApple OSS Distributions 			shadow[i] = ASAN_VALID;
682*2c2f96dcSApple OSS Distributions 			return;
683*2c2f96dcSApple OSS Distributions 		} else if (shadow[i] != ASAN_VALID) {
684*2c2f96dcSApple OSS Distributions 			/* must have seen the cookie by now */
685*2c2f96dcSApple OSS Distributions 			return;
686*2c2f96dcSApple OSS Distributions 		}
687*2c2f96dcSApple OSS Distributions 	}
688*2c2f96dcSApple OSS Distributions }
689*2c2f96dcSApple OSS Distributions 
690*2c2f96dcSApple OSS Distributions SYSCTL_UINT(_kern_kasan, OID_AUTO, quarantine, CTLFLAG_RW, &quarantine_enabled, 0, "");
691