xref: /xnu-11215.41.3/san/memory/kasan-test.c (revision 33de042d024d46de5ff4e89f2471de6608e37fa4)
1 /*
2  * Copyright (c) 2016 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 #include <stdint.h>
30 #include <string.h>
31 #include <vm/vm_map.h>
32 #include <kern/assert.h>
33 #include <kern/locks.h>
34 #include <kern/kalloc.h>
35 #include <kern/simple_lock.h>
36 #include <kern/debug.h>
37 #include <kern/thread.h>
38 #include <mach/mach_vm.h>
39 #include <mach/vm_param.h>
40 #include <libkern/libkern.h>
41 #include <libkern/kernel_mach_header.h>
42 #include <sys/queue.h>
43 #include "kasan.h"
44 #include "kasan_internal.h"
45 #include "memintrinsics.h"
46 
47 /* move to kasan-test.h */
48 typedef int jmp_buf[_JBLEN];
49 void _longjmp(jmp_buf env, int val) OS_NORETURN;
50 int _setjmp(jmp_buf env) __attribute__((returns_twice));
51 
52 
53 #define STATIC_ARRAY_SZ 66
54 #define STACK_ARRAY_SZ 9
55 #define BUFSZ 34
56 #define LBUFSZ 255
57 
58 enum {
59 	TEST_PASS,
60 	TEST_FAIL_NOFAULT,
61 	TEST_FAIL_BADFAULT,
62 	TEST_SETUP_FAIL = 1,
63 	TEST_INVALID,
64 	TEST_UNKNOWN
65 };
66 
67 unsigned long static_array[STATIC_ARRAY_SZ];
68 
69 static jmp_buf jbuf;
70 static volatile int in_test = 0;
71 
72 #define TEST_BARRIER()    do { __asm__ __volatile__ ("" ::: "memory"); } while(0)
73 #define TEST_START(t)     do { t->result = 1; TEST_BARRIER(); } while (0)
74 #define TEST_FAULT(t)     do { TEST_BARRIER(); t->result = 0; TEST_BARRIER(); } while (0)
75 #define TEST_NOFAULT(t)   do { TEST_BARRIER(); t->result = 1; TEST_BARRIER(); } while (0)
76 #define TEST_DONE(t, res)  do { t->result = (res); kasan_handle_test(); } while (0)
77 #define DECLARE_TEST(f, s)    { .func = f, .name = s }
78 #define DECLARE_TEST3(f, c, s) { .func = f, .cleanup = c, .name = s }
79 
80 static void
heap_cleanup(struct kasan_test * t)81 heap_cleanup(struct kasan_test *t)
82 {
83 	if (t->data) {
84 		kfree_data(t->data, t->datasz);
85 		t->data = NULL;
86 	}
87 }
88 
89 static int
test_global_overflow(struct kasan_test __unused * t)90 test_global_overflow(struct kasan_test __unused *t)
91 {
92 	int i;
93 	/* rookie error */
94 	for (i = 0; i <= STATIC_ARRAY_SZ; i++) {
95 		static_array[i] = i;
96 	}
97 	return 0;
98 }
99 
100 static int
test_heap_underflow(struct kasan_test __unused * t)101 test_heap_underflow(struct kasan_test __unused *t)
102 {
103 	uint8_t *x = kalloc_data(BUFSZ, Z_WAITOK);
104 	if (!x) {
105 		return 1;
106 	}
107 	t->datasz = BUFSZ;
108 	t->data = x;
109 	x[-1] = 0x12;
110 	return 0;
111 }
112 
113 static int
test_heap_overflow(struct kasan_test __unused * t)114 test_heap_overflow(struct kasan_test __unused *t)
115 {
116 	uint8_t *x = kalloc_data(BUFSZ, Z_WAITOK);
117 	if (!x) {
118 		return 1;
119 	}
120 	t->datasz = BUFSZ;
121 	t->data = x;
122 	x[BUFSZ] = 0x11;
123 	return 0;
124 }
125 
126 static int
test_heap_uaf(struct kasan_test __unused * t)127 test_heap_uaf(struct kasan_test __unused *t)
128 {
129 	uint8_t *x = kalloc_data(LBUFSZ, Z_WAITOK);
130 	if (!x) {
131 		return 1;
132 	}
133 	kfree_data(x, LBUFSZ);
134 	x[0] = 0x10;
135 	return 0;
136 }
137 
138 static int
test_heap_inval_free(struct kasan_test __unused * t)139 test_heap_inval_free(struct kasan_test __unused *t)
140 {
141 	int x;
142 	int *ptr = &x;
143 	kfree_data(ptr, BUFSZ);
144 	return 0;
145 }
146 
147 static int
test_heap_double_free(struct kasan_test * t)148 test_heap_double_free(struct kasan_test *t)
149 {
150 	TEST_START(t);
151 
152 	uint8_t *x = kalloc_data(BUFSZ, Z_WAITOK);
153 	if (!x) {
154 		return 1;
155 	}
156 	kfree_data(x, BUFSZ);
157 
158 	TEST_FAULT(t);
159 	kfree_data(x, BUFSZ);
160 
161 	return 0;
162 }
163 
164 static int
test_heap_small_free(struct kasan_test * t)165 test_heap_small_free(struct kasan_test *t)
166 {
167 	TEST_START(t);
168 
169 	uint8_t *x = kalloc_data(BUFSZ, Z_WAITOK);
170 	if (!x) {
171 		return 1;
172 	}
173 	t->datasz = BUFSZ;
174 	t->data = x;
175 
176 	TEST_FAULT(t);
177 	kfree_data(x, BUFSZ - 2);
178 	t->data = NULL;
179 	t->datasz = 0;
180 
181 	return 0;
182 }
183 
184 static int
test_stack_overflow(struct kasan_test * t)185 test_stack_overflow(struct kasan_test *t)
186 {
187 	TEST_START(t);
188 
189 	uint8_t i;
190 	volatile uint8_t a[STACK_ARRAY_SZ];
191 
192 	for (i = 0; i < STACK_ARRAY_SZ; i++) {
193 		a[i] = i;
194 	}
195 
196 	TEST_FAULT(t);
197 	a[i] = i; /* rookie error */
198 	TEST_NOFAULT(t);
199 
200 	TEST_BARRIER();
201 
202 	return !(a[0] == 0);
203 }
204 
205 static int
test_stack_underflow(struct kasan_test * t)206 test_stack_underflow(struct kasan_test *t)
207 {
208 	TEST_START(t);
209 
210 	long idx;
211 	uint8_t a[STACK_ARRAY_SZ];
212 
213 	__nosan_memset(a, 0, STACK_ARRAY_SZ);
214 
215 	/* generate a negative index without the compiler noticing */
216 #if __x86_64__
217 	__asm__ __volatile__ ("movq $-1, %0" : "=r"(idx) :: "memory");
218 #else
219 	__asm__ __volatile__ ("mov %0, #-1" : "=r"(idx) :: "memory");
220 #endif
221 
222 	TEST_FAULT(t);
223 	a[idx] = 0xbd;
224 	TEST_NOFAULT(t);
225 
226 	TEST_BARRIER();
227 	return a[0] == 0;
228 }
229 
230 static int
test_memcpy(struct kasan_test * t)231 test_memcpy(struct kasan_test *t)
232 {
233 	TEST_START(t);
234 	uint8_t a1[STACK_ARRAY_SZ];
235 	uint8_t a2[STACK_ARRAY_SZ];
236 
237 	/* should work */
238 	memcpy(a1, a2, STACK_ARRAY_SZ);
239 
240 	TEST_BARRIER();
241 
242 	/* should fail */
243 	TEST_FAULT(t);
244 	memcpy(a2, a1, STACK_ARRAY_SZ + 1);
245 	TEST_NOFAULT(t);
246 
247 	return 0;
248 }
249 
250 static int
test_memmove(struct kasan_test * t)251 test_memmove(struct kasan_test *t)
252 {
253 	TEST_START(t);
254 	uint8_t a1[STACK_ARRAY_SZ];
255 	uint8_t a2[STACK_ARRAY_SZ];
256 
257 	/* should work */
258 	memmove(a1, a2, STACK_ARRAY_SZ);
259 
260 	TEST_BARRIER();
261 
262 	/* should fail */
263 	TEST_FAULT(t);
264 	memmove(a2, a1, STACK_ARRAY_SZ + 1);
265 	TEST_NOFAULT(t);
266 
267 	return 0;
268 }
269 
270 static int
test_bcopy(struct kasan_test * t)271 test_bcopy(struct kasan_test *t)
272 {
273 	TEST_START(t);
274 	uint8_t a1[STACK_ARRAY_SZ];
275 	uint8_t a2[STACK_ARRAY_SZ];
276 
277 	/* should work */
278 	bcopy(a1, a2, STACK_ARRAY_SZ);
279 
280 	TEST_BARRIER();
281 
282 	/* should fail */
283 	TEST_FAULT(t);
284 	bcopy(a2, a1, STACK_ARRAY_SZ + 1);
285 	TEST_NOFAULT(t);
286 
287 	return 0;
288 }
289 
290 static int
test_memset(struct kasan_test * t)291 test_memset(struct kasan_test *t)
292 {
293 	TEST_START(t);
294 	uint8_t a1[STACK_ARRAY_SZ];
295 
296 	/* should work */
297 	memset(a1, 'e', STACK_ARRAY_SZ);
298 
299 	TEST_BARRIER();
300 
301 	/* should fail */
302 	TEST_FAULT(t);
303 	memset(a1, 'f', STACK_ARRAY_SZ + 1);
304 	TEST_NOFAULT(t);
305 
306 	return 0;
307 }
308 
309 static int
test_memcmp(struct kasan_test * t)310 test_memcmp(struct kasan_test *t)
311 {
312 	TEST_START(t);
313 	uint8_t *a1;
314 	uint8_t *a2;
315 
316 	a1 = kalloc_data(STACK_ARRAY_SZ, Z_WAITOK);
317 	if (!a1) {
318 		return 1;
319 	}
320 	a2 = kalloc_data(STACK_ARRAY_SZ + 1, Z_WAITOK);
321 	if (!a2) {
322 		return 1;
323 	}
324 
325 	/* should work */
326 	memcmp(a1, a2, STACK_ARRAY_SZ);
327 	memcmp(a1, a2 + 1, STACK_ARRAY_SZ);
328 
329 	TEST_BARRIER();
330 
331 	/* should fail */
332 	TEST_FAULT(t);
333 	memcmp(a1, a2, STACK_ARRAY_SZ + 1);
334 	TEST_NOFAULT(t);
335 
336 	return 0;
337 }
338 
339 static int
test_bcmp(struct kasan_test * t)340 test_bcmp(struct kasan_test *t)
341 {
342 	TEST_START(t);
343 	uint8_t *a1;
344 	uint8_t *a2;
345 
346 	a1 = kalloc_data(STACK_ARRAY_SZ, Z_WAITOK);
347 	if (!a1) {
348 		return 1;
349 	}
350 	a2 = kalloc_data(STACK_ARRAY_SZ + 1, Z_WAITOK);
351 	if (!a2) {
352 		return 1;
353 	}
354 
355 	/* should work */
356 	bcmp(a1, a2, STACK_ARRAY_SZ);
357 	bcmp(a1, a2 + 1, STACK_ARRAY_SZ);
358 
359 	TEST_BARRIER();
360 
361 	/* should fail */
362 	TEST_FAULT(t);
363 	bcmp(a1, a2, STACK_ARRAY_SZ + 1);
364 	TEST_NOFAULT(t);
365 
366 	return 0;
367 }
368 
369 static int
test_bzero(struct kasan_test * t)370 test_bzero(struct kasan_test *t)
371 {
372 	TEST_START(t);
373 	uint8_t a1[STACK_ARRAY_SZ];
374 
375 	/* should work */
376 	bzero(a1, STACK_ARRAY_SZ);
377 
378 	TEST_BARRIER();
379 
380 	/* should fail */
381 	TEST_FAULT(t);
382 	bzero(a1, STACK_ARRAY_SZ + 1);
383 	TEST_NOFAULT(t);
384 
385 	return 0;
386 }
387 
388 static int
test_strlcpy(struct kasan_test * t)389 test_strlcpy(struct kasan_test *t)
390 {
391 	TEST_START(t);
392 	char a1[8];
393 
394 	/* should not fault */
395 	strlcpy(a1, "small", 8);
396 	strlcpy(a1, "looooonnnnggg", 8);
397 
398 	TEST_FAULT(t);
399 	strlcpy(a1, "looooooooonnnnggg", 9);
400 	TEST_NOFAULT(t);
401 
402 	return 0;
403 }
404 
405 static int
test_strncpy(struct kasan_test * t)406 test_strncpy(struct kasan_test *t)
407 {
408 	TEST_START(t);
409 	char a1[9];
410 
411 	/* should not fault */
412 	strncpy(a1, "small", 9);
413 	strncpy(a1, "looooonnnnggg", 9);
414 
415 	TEST_FAULT(t);
416 	strncpy(a1, "looooonnnnggg", 10);
417 	TEST_NOFAULT(t);
418 
419 	return a1[0] != 'l';
420 }
421 
422 static int
test_strlcat(struct kasan_test * t)423 test_strlcat(struct kasan_test *t)
424 {
425 	TEST_START(t);
426 	char a1[9] = {};
427 
428 	/* should not fault */
429 	strlcat(a1, "abcd", 9);
430 	strlcat(a1, "efgh", 9);
431 	strlcat(a1, "ijkl", 9);
432 	a1[0] = '\0';
433 	strlcat(a1, "looooonnnnggg", 9);
434 
435 	a1[0] = '\0';
436 	TEST_FAULT(t);
437 	strlcat(a1, "looooonnnnggg", 10);
438 	TEST_NOFAULT(t);
439 
440 	return a1[0] != 'l';
441 }
442 
443 static int
test_strncat(struct kasan_test * t)444 test_strncat(struct kasan_test *t)
445 {
446 	TEST_START(t);
447 	char a1[9] = {};
448 
449 	/* should not fault */
450 	strncat(a1, "abcd", 4);
451 	strncat(a1, "efgh", 4);
452 
453 	TEST_FAULT(t);
454 	strncat(a1, "i", 1);
455 	TEST_NOFAULT(t);
456 
457 	return a1[0] != 'a';
458 }
459 
460 /* we ignore the top *two* frames in backtrace - so add an extra one */
461 static int OS_NOINLINE
test_blacklist_helper(void)462 test_blacklist_helper(void)
463 {
464 	return kasan_is_blacklisted(TYPE_TEST);
465 }
466 
467 static int OS_NOINLINE
test_blacklist(struct kasan_test * t)468 test_blacklist(struct kasan_test *t)
469 {
470 	TEST_START(t);
471 	int res = (int)!test_blacklist_helper();
472 	TEST_DONE(t, res);
473 	return 0;
474 }
475 
476 static int OS_NOINLINE
test_blacklist_str(struct kasan_test * t)477 test_blacklist_str(struct kasan_test *t)
478 {
479 	TEST_START(t);
480 	char a1[8];
481 
482 	bcopy("123456", a1, 8);
483 
484 	TEST_DONE(t, 0); /* success */
485 	return 0;
486 }
487 
488 static void OS_NOINLINE
force_fakestack(char * x)489 force_fakestack(char *x)
490 {
491 	__asm__ __volatile__ ("" :: "r" (x) : "memory");
492 }
493 
494 OS_NOINLINE
495 static int
test_fakestack_helper(struct kasan_test * t,char * x)496 test_fakestack_helper(struct kasan_test *t, char *x)
497 {
498 	TEST_START(t);
499 
500 	x[0] = 0x55;
501 
502 	/* ensure that 'x' is on the fakestack */
503 	uintptr_t base = dtrace_get_kernel_stack(current_thread());
504 	uintptr_t p = (uintptr_t)x;
505 	if (p >= base && p < base + kernel_stack_size) {
506 		return 1;
507 	}
508 
509 	__asan_handle_no_return();
510 
511 	/* x better still be accessible */
512 	TEST_NOFAULT(t);
513 	if (x[0] != 0x55) {
514 		TEST_DONE(t, 1);
515 	}
516 
517 	TEST_DONE(t, 0);
518 	return 0;
519 }
520 
521 static int
test_fakestack(struct kasan_test * t)522 test_fakestack(struct kasan_test *t)
523 {
524 	char x[8];
525 	if (!fakestack_enabled) {
526 		return 1;
527 	}
528 	force_fakestack(x);
529 	return test_fakestack_helper(t, x);
530 }
531 
532 int *uaf_ptr;
533 static int * NOINLINE
stack_uaf_helper(void)534 stack_uaf_helper(void)
535 {
536 	int x;
537 	uaf_ptr = &x;
538 	return uaf_ptr;
539 }
540 
541 static int
test_stack_uaf(struct kasan_test __unused * t)542 test_stack_uaf(struct kasan_test __unused *t)
543 {
544 	int *x = stack_uaf_helper();
545 	*x = 0xb4d;
546 	TEST_BARRIER();
547 	return !(*x == 0xb4d);
548 }
549 
550 static struct kasan_test xnu_tests[] = {
551 	DECLARE_TEST(NULL, NULL),
552 	DECLARE_TEST(test_global_overflow, "Global overflow"),
553 	DECLARE_TEST3(test_heap_underflow, heap_cleanup, "Heap underflow"),
554 	DECLARE_TEST3(test_heap_overflow, heap_cleanup, "Heap overflow"),
555 	DECLARE_TEST(test_heap_uaf, "Heap use-after-free"),
556 	DECLARE_TEST(test_heap_inval_free, "Heap invalid free"),
557 	DECLARE_TEST(test_heap_double_free, "Heap double free"),
558 	DECLARE_TEST3(test_heap_small_free, heap_cleanup, "Heap small free"),
559 	DECLARE_TEST(test_stack_overflow, "Stack overflow"),
560 	DECLARE_TEST(test_stack_underflow, "Stack underflow"),
561 	DECLARE_TEST(test_stack_uaf, "Stack use-after-return"),
562 	DECLARE_TEST(test_memcpy, "memcpy"),
563 	DECLARE_TEST(test_memmove, "memmmove"),
564 	DECLARE_TEST(test_bcopy, "bcopy"),
565 	DECLARE_TEST(test_memset, "memset"),
566 	DECLARE_TEST(test_memcmp, "memcmp"),
567 	DECLARE_TEST(test_bcmp, "bcmp"),
568 	DECLARE_TEST(test_bzero, "bzero"),
569 	DECLARE_TEST(test_strlcpy, "strlcpy"),
570 	DECLARE_TEST(test_strlcat, "strlcat"),
571 	DECLARE_TEST(test_strncpy, "strncpy"),
572 	DECLARE_TEST(test_strncat, "strncat"),
573 	DECLARE_TEST(test_blacklist, "blacklist"),
574 	DECLARE_TEST(test_blacklist_str, "blacklist_str"),
575 	DECLARE_TEST(test_fakestack, "fakestack"),
576 };
577 static int num_xnutests = sizeof(xnu_tests) / sizeof(xnu_tests[0]);
578 
579 static int
kasan_run_test(struct kasan_test * test_list,int testno,int fail)580 kasan_run_test(struct kasan_test *test_list, int testno, int fail)
581 {
582 	int status = TEST_UNKNOWN;
583 	struct kasan_test *t = &test_list[testno];
584 
585 	if (testno < 0 || testno >= num_xnutests || !t->func) {
586 		printf("KASan: test.%02d INVALID\n", testno);
587 		return TEST_INVALID;
588 	}
589 
590 	if (!fail) {
591 		in_test = 1;
592 	}
593 
594 	if (_setjmp(jbuf) == 0) {
595 		t->result = 0;
596 		int ret = t->func(t);
597 		if (ret) {
598 			printf("KASan: test.%02d SETUP FAIL (%s)\n", testno, t->name);
599 			status = ret;
600 		} else {
601 			/* did not fault when it should have */
602 			printf("KASan: test.%02d FAIL (%s)\n", testno, t->name);
603 			status = TEST_FAIL_NOFAULT;
604 		}
605 	} else {
606 		if (t->result) {
607 			/* faulted, but at the wrong place */
608 			printf("KASan: test.%02d FAIL %d (%s)\n", testno, t->result, t->name);
609 			status = TEST_FAIL_BADFAULT;
610 		} else {
611 			printf("KASan: test.%02d PASS (%s)\n", testno, t->name);
612 			status = TEST_PASS;
613 		}
614 	}
615 	in_test = 0;
616 	if (t->cleanup) {
617 		t->cleanup(t);
618 	}
619 
620 	return status;
621 }
622 
623 static void
kasan_test(int testno,int fail)624 kasan_test(int testno, int fail)
625 {
626 	int i = 1;
627 	int pass = 0, total = 0;
628 	int ret;
629 
630 	if (testno == -1) {
631 		/* shorthand for all tests */
632 		testno = (1U << (num_xnutests - 1)) - 1;
633 	}
634 
635 	while (testno) {
636 		if (testno & 0x1) {
637 			ret = kasan_run_test(xnu_tests, i, fail);
638 			if (ret == TEST_PASS) {
639 				pass++;
640 			}
641 			if (ret != TEST_INVALID) {
642 				total++;
643 			}
644 		}
645 
646 		i++;
647 		testno >>= 1;
648 	}
649 	printf("KASan: TEST SUMMARY %d/%d passed\n", pass, total);
650 }
651 
652 void
kasan_handle_test(void)653 kasan_handle_test(void)
654 {
655 	if (in_test) {
656 		_longjmp(jbuf, 1);
657 		/* NOTREACHED */
658 	}
659 }
660 
661 void
__kasan_runtests(struct kasan_test * kext_tests,int numtests)662 __kasan_runtests(struct kasan_test *kext_tests, int numtests)
663 {
664 	int i;
665 	for (i = 0; i < numtests; i++) {
666 		kasan_run_test(kext_tests, i, 0);
667 	}
668 }
669 
670 static int
sysctl_kasan_test(__unused struct sysctl_oid * oidp,__unused void * arg1,int arg2,struct sysctl_req * req)671 sysctl_kasan_test(__unused struct sysctl_oid *oidp, __unused void *arg1, int arg2, struct sysctl_req *req)
672 {
673 	int ch, err, mask = 0;
674 	err = sysctl_io_number(req, 0, sizeof(int), &mask, &ch);
675 
676 	if (!err && mask) {
677 		kasan_test(mask, arg2);
678 	}
679 
680 	return err;
681 }
682 
683 SYSCTL_PROC(_kern_kasan, OID_AUTO, test,
684     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
685     0, 0, sysctl_kasan_test, "I", "");
686 
687 SYSCTL_PROC(_kern_kasan, OID_AUTO, fail,
688     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
689     0, 1, sysctl_kasan_test, "I", "");
690