1 /*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <errno.h>
18 #include <error.h>
19 #include <fcntl.h>
20 #include <getopt.h>
21 #include <limits.h>
22 #include <paths.h>
23 #include <pwd.h>
24 #include <stdbool.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <unistd.h>
29 #include <sys/types.h>
30 #include <sys/wait.h>
31
32 // crashes if built with -fsanitize=address
test_crash_malloc()33 void test_crash_malloc() {
34 volatile char* heap = malloc(32);
35 heap[32] = heap[32];
36 printf("ASAN: Heap Test Failed\n");
37 }
38
39 // crashes if built with -fsanitize=address
test_crash_stack()40 void test_crash_stack() {
41 volatile char stack[32];
42 volatile char* p_stack = stack;
43 p_stack[32] = p_stack[32];
44 printf("ASAN: Stack Test Failed\n");
45 }
46
data_asan_exists()47 int data_asan_exists() {
48 int fd = open("/data/asan", O_DIRECTORY | O_PATH | O_CLOEXEC, 0);
49 if(fd < 0) {
50 printf("ASAN: Missing /data/asan\n");
51 return 1;
52 }
53 close(fd);
54 return 0;
55 }
56
57 // crashes if built with -fsanitize=memory
test_msan_crash_stack()58 void test_msan_crash_stack() {
59 volatile int stack[10];
60 stack[5] = 0;
61 if (stack[0]) {
62 stack[0] = 1;
63 }
64 printf("MSAN: Stack Test Failed\n");
65 }
66
67 // crashes if built with -fsanitize=integer
test_integer_overflow()68 void test_integer_overflow() {
69 size_t max = (size_t)-1;
70 max++;
71 printf("UBSAN: Integer Overflow Test Failed\n");
72 }
73
74 // returns 0 if kcov is enabled
test_kcov()75 int test_kcov() {
76 const char* kcov_file = "/sys/kernel/debug/kcov";
77 int fd = open(kcov_file, O_RDWR);
78 if (fd == -1) {
79 printf("KCOV: Could not open %s\n", kcov_file);
80 return 1;
81 }
82 close(fd);
83 return 0;
84 }
85
86 // returns 0 if kasan was compiled in
test_kasan()87 int test_kasan() {
88 // rely on the exit status of grep to propagate
89 if (system("gzip -d < /proc/config.gz | grep CONFIG_KASAN=y >/dev/null")) {
90 printf("KASAN: CONFIG_KASAN not in /proc/config.gz\n");
91 return 1;
92 }
93 return 0;
94 }
95
96 // executes a test that is expected to crash
97 // returns 0 if the test crashes
test(void (* function)())98 int test(void (*function)()) {
99 fflush(stdout);
100
101 pid_t child = fork();
102 int status = 0;
103
104 if (child == -1) {
105 perror("fork");
106 exit(1);
107 }
108
109 if (child == 0) {
110 // Silence the ASAN report that is generated
111 close(2);
112
113 // Invoke the target function. If it does not crash, terminate the process.
114 function();
115 exit(EXIT_SUCCESS);
116 }
117
118 // Wait for the child to either crash, or exit cleanly
119 while (child == waitpid(child, &status, 0)) {
120 if (!WIFEXITED(status))
121 continue;
122 if (WEXITSTATUS(status) == EXIT_SUCCESS)
123 return 1;
124 break;
125 }
126 return 0;
127 }
128
have_option(const char * option,const char ** argv,const int argc)129 int have_option(const char* option, const char** argv, const int argc) {
130 for (int i = 1; i < argc; i++)
131 if (!strcmp(option, argv[i]))
132 return 1;
133 return 0;
134 }
135
sanitizer_status(int argc,const char ** argv)136 int sanitizer_status(int argc, const char** argv) {
137 int test_everything = 0;
138 int failures = 0;
139
140 if (argc <= 1)
141 test_everything = 1;
142
143 if (test_everything || have_option("asan", argv, argc)) {
144 int asan_failures = 0;
145
146 #if !defined(ANDROID_SANITIZE_ADDRESS) && !defined(ANDROID_SANITIZE_HWADDRESS)
147 asan_failures += 1;
148 printf("ASAN: Compiler flags failed!\n");
149 #endif
150
151 asan_failures += test(test_crash_malloc);
152 asan_failures += test(test_crash_stack);
153 asan_failures += data_asan_exists();
154
155 if (!asan_failures)
156 printf("ASAN: OK\n");
157
158 failures += asan_failures;
159 }
160
161 if(test_everything || have_option("cov", argv, argc)) {
162 int cov_failures = 0;
163
164 #ifndef ANDROID_SANITIZE_COVERAGE
165 printf("COV: Compiler flags failed!\n");
166 cov_failures += 1;
167 #endif
168
169 if (!cov_failures)
170 printf("COV: OK\n");
171
172 failures += cov_failures;
173 }
174
175 if (test_everything || have_option("msan", argv, argc)) {
176 int msan_failures = 0;
177
178 msan_failures += test(test_msan_crash_stack);
179
180 if (!msan_failures)
181 printf("MSAN: OK\n");
182
183 failures += msan_failures;
184 }
185
186 if (test_everything || have_option("kasan", argv, argc)) {
187 int kasan_failures = 0;
188
189 kasan_failures += test_kasan();
190
191 if(!kasan_failures)
192 printf("KASAN: OK\n");
193
194 failures += kasan_failures;
195 }
196
197 if (test_everything || have_option("kcov", argv, argc)) {
198 int kcov_failures = 0;
199
200 kcov_failures += test_kcov();
201
202 if (!kcov_failures)
203 printf("KCOV: OK\n");
204
205 failures += kcov_failures;
206 }
207
208 if (test_everything || have_option("ubsan", argv, argc)) {
209 int ubsan_failures = 0;
210
211 ubsan_failures += test(test_integer_overflow);
212
213 if (!ubsan_failures)
214 printf("UBSAN: OK\n");
215
216 failures += ubsan_failures;
217 }
218
219 return failures > 0 ? EXIT_FAILURE : EXIT_SUCCESS;
220 }
221