]>
Commit | Line | Data |
---|---|---|
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 | #define STATIC_ARRAY_SZ 66 | |
48 | #define STACK_ARRAY_SZ 9 | |
49 | #define BUFSZ 34 | |
50 | #define LBUFSZ 255 | |
51 | ||
52 | enum { | |
53 | TEST_PASS, | |
54 | TEST_FAIL_NOFAULT, | |
55 | TEST_FAIL_BADFAULT, | |
56 | TEST_SETUP_FAIL = 1, | |
57 | TEST_INVALID, | |
58 | TEST_UNKNOWN | |
59 | }; | |
60 | ||
61 | unsigned long static_array[STATIC_ARRAY_SZ]; | |
62 | ||
63 | static jmp_buf jbuf; | |
64 | static volatile int in_test = 0; | |
65 | ||
66 | struct 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 | ||
83 | static 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 | ||
91 | static 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 | ||
101 | static 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 | ||
113 | static 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 | ||
125 | static 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 | ||
136 | static int test_heap_inval_free(struct kasan_test __unused *t) | |
137 | { | |
138 | int x; | |
139 | kfree(&x, BUFSZ); | |
140 | return 0; | |
141 | } | |
142 | ||
143 | static 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 | ||
159 | static 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 | ||
178 | static 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 | ||
198 | static 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 | ||
222 | static 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 | ||
241 | static 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 | ||
260 | static 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 | ||
279 | static 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 | ||
297 | static 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 | ||
324 | static 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 | ||
351 | static 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 | ||
369 | static 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 | ||
385 | static 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 | ||
401 | static 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 | ||
421 | static 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 */ | |
438 | static int OS_NOINLINE | |
439 | test_blacklist_helper(void) | |
440 | { | |
441 | return kasan_is_blacklisted(TYPE_TEST); | |
442 | } | |
443 | ||
444 | static int OS_NOINLINE | |
445 | test_blacklist(struct kasan_test *t) | |
446 | { | |
447 | TEST_START(t); | |
448 | int res = (int)!test_blacklist_helper(); | |
449 | TEST_DONE(t, res); | |
450 | return 0; | |
451 | } | |
452 | ||
453 | static int OS_NOINLINE | |
454 | test_blacklist_str(struct kasan_test *t) | |
455 | { | |
456 | TEST_START(t); | |
457 | char a1[8]; | |
458 | ||
459 | bcopy("123456", a1, 8); | |
460 | ||
461 | TEST_DONE(t, 0); /* success */ | |
462 | return 0; | |
463 | } | |
464 | ||
465 | #if 0 | |
466 | static 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 | ||
486 | static void OS_NOINLINE | |
487 | force_fakestack(char *x) | |
488 | { | |
489 | __asm__ __volatile__("" :: "r" (x) : "memory"); | |
490 | } | |
491 | ||
492 | OS_NOINLINE | |
493 | static int | |
494 | test_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 | ||
519 | static int | |
520 | test_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 | ||
530 | int *uaf_ptr; | |
531 | static int * NOINLINE | |
532 | stack_uaf_helper(void) | |
533 | { | |
534 | int x; | |
535 | uaf_ptr = &x; | |
536 | return uaf_ptr; | |
537 | } | |
538 | ||
539 | static 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 | ||
547 | static 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"), | |
572 | DECLARE_TEST(test_fakestack, "fakestack"), | |
573 | // DECLARE_TEST(test_strnlen, "strnlen"), | |
574 | }; | |
575 | static int num_xnutests = sizeof(xnu_tests)/sizeof(xnu_tests[0]); | |
576 | ||
577 | static int | |
578 | kasan_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 { | |
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 | void | |
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 | |
653 | kasan_handle_test(void) | |
654 | { | |
655 | if (in_test) { | |
656 | _longjmp(jbuf, 1); | |
657 | /* NOTREACHED */ | |
658 | } | |
659 | } | |
660 | ||
661 | void | |
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 | } |