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