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