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 <pthread.h>
24 #include <pwd.h>
25 #include <stdbool.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <unistd.h>
30 #include <sys/types.h>
31 #include <sys/wait.h>
32 
33 // crashes if built with -fsanitize=address
test_crash_malloc()34 void test_crash_malloc() {
35   volatile char* heap = malloc(32);
36   heap[32] = heap[32];
37   printf("(HW)ASAN: Heap Test Failed\n");
38 }
39 
40 // crashes if built with -fsanitize=address
test_crash_stack()41 void test_crash_stack() {
42   volatile char stack[32];
43   volatile char* p_stack = stack;
44   p_stack[32] = p_stack[32];
45   printf("(HW)ASAN: Stack Test Failed\n");
46 }
47 
test_crash_pthread_mutex_unlock()48 void test_crash_pthread_mutex_unlock() {
49   volatile char* heap = malloc(32);
50   pthread_mutex_unlock((void*)&heap[32]);
51   printf("HWASAN: Libc Test Failed\n");
52 }
53 
data_asan_exists()54 int data_asan_exists() {
55   int fd = open("/data/asan", O_DIRECTORY | O_PATH | O_CLOEXEC, 0);
56   if(fd < 0) {
57     printf("ASAN: Missing /data/asan\n");
58     return 1;
59   }
60   close(fd);
61   return 0;
62 }
63 
64 // crashes if built with -fsanitize=memory
test_msan_crash_stack()65 void test_msan_crash_stack() {
66   volatile int stack[10];
67   stack[5] = 0;
68   if (stack[0]) {
69     stack[0] = 1;
70   }
71   printf("MSAN: Stack Test Failed\n");
72 }
73 
74 // crashes if built with -fsanitize=integer
test_integer_overflow()75 void test_integer_overflow() {
76   size_t max = (size_t)-1;
77   max++;
78   printf("UBSAN: Integer Overflow Test Failed\n");
79 }
80 
81 // returns 0 if kcov is enabled
test_kcov()82 int test_kcov() {
83   const char* kcov_file = "/sys/kernel/debug/kcov";
84   int fd = open(kcov_file, O_RDWR);
85   if (fd == -1) {
86     printf("KCOV: Could not open %s\n", kcov_file);
87     return 1;
88   }
89   close(fd);
90   return 0;
91 }
92 
93 // returns 0 if kasan was compiled in
test_kasan()94 int test_kasan() {
95   // rely on the exit status of grep to propagate
96   if (system("gzip -d < /proc/config.gz | grep CONFIG_KASAN=y >/dev/null")) {
97     printf("KASAN: CONFIG_KASAN not in /proc/config.gz\n");
98     return 1;
99   }
100   return 0;
101 }
102 
103 // Number of iterations required to reliably guarantee a GWP-ASan crash.
104 // GWP-ASan's sample rate is not truly nondeterministic, it initialises a
105 // thread-local counter at 2*SampleRate, and decrements on each malloc(). Once
106 // the counter reaches zero, we provide a sampled allocation. GWP-ASan's current
107 // default sample rate is 1/5000.
108 #define GWP_ASAN_ITERATIONS_TO_ENSURE_CRASH (0x10000)
109 
110 // crashes with GWP-ASan
test_crash_gwp_asan()111 void test_crash_gwp_asan() {
112   for (unsigned i = 0; i < GWP_ASAN_ITERATIONS_TO_ENSURE_CRASH; ++i ) {
113     volatile char *x = malloc(1);
114     free((void*) x);
115     *x = 0;
116   }
117   printf("GWP-ASan: Use after Free Failed\n");
118 }
119 
120 // executes a test that is expected to crash
121 // returns 0 if the test crashes
test(void (* function)())122 int test(void (*function)()) {
123   fflush(stdout);
124 
125   pid_t child = fork();
126   int status = 0;
127 
128   if (child == -1) {
129     perror("fork");
130     exit(1);
131   }
132 
133   if (child == 0) {
134     // Silence the ASAN report that is generated
135     close(2);
136 
137     // Invoke the target function.  If it does not crash, terminate the process.
138     function();
139     exit(EXIT_SUCCESS);
140   }
141 
142   // Wait for the child to either crash, or exit cleanly
143   while (child == waitpid(child, &status, 0)) {
144     if (!WIFEXITED(status))
145       continue;
146     if (WEXITSTATUS(status) == EXIT_SUCCESS)
147       return 1;
148     break;
149   }
150   return 0;
151 }
152 
have_option(const char * option,const char ** argv,const int argc)153 int have_option(const char* option, const char** argv, const int argc) {
154   for (int i = 1; i < argc; i++)
155     if (!strcmp(option, argv[i]))
156       return 1;
157   return 0;
158 }
159 
sanitizer_status(int argc,const char ** argv)160 int sanitizer_status(int argc, const char** argv) {
161   int test_everything = 0;
162   int failures = 0;
163 
164   if (argc <= 1)
165     test_everything = 1;
166 
167   if (test_everything || have_option("asan", argv, argc)) {
168     int asan_failures = 0;
169 
170 #if !defined(ANDROID_SANITIZE_ADDRESS)
171     asan_failures += 1;
172     printf("ASAN: Compiler flags failed!\n");
173 #endif
174 
175     asan_failures += test(test_crash_malloc);
176     asan_failures += test(test_crash_stack);
177     asan_failures += data_asan_exists();
178 
179     if (!asan_failures)
180       printf("ASAN: OK\n");
181 
182     failures += asan_failures;
183   }
184 
185   if (test_everything || have_option("hwasan", argv, argc)) {
186     int hwasan_failures = 0;
187 
188 #if !defined(ANDROID_SANITIZE_HWADDRESS)
189     hwasan_failures += 1;
190     printf("HWASAN: Compiler flags failed!\n");
191 #endif
192 
193     hwasan_failures += test(test_crash_malloc);
194     hwasan_failures += test(test_crash_stack);
195     hwasan_failures += test(test_crash_pthread_mutex_unlock);
196 
197     if (!hwasan_failures)
198       printf("HWASAN: OK\n");
199 
200     failures += hwasan_failures;
201   }
202 
203   if(test_everything || have_option("cov", argv, argc)) {
204     int cov_failures = 0;
205 
206 #ifndef ANDROID_SANITIZE_COVERAGE
207     printf("COV: Compiler flags failed!\n");
208     cov_failures += 1;
209 #endif
210 
211     if (!cov_failures)
212       printf("COV: OK\n");
213 
214     failures += cov_failures;
215   }
216 
217   if (test_everything || have_option("msan", argv, argc)) {
218     int msan_failures = 0;
219 
220     msan_failures += test(test_msan_crash_stack);
221 
222     if (!msan_failures)
223       printf("MSAN: OK\n");
224 
225     failures += msan_failures;
226   }
227 
228   if (test_everything || have_option("kasan", argv, argc)) {
229     int kasan_failures = 0;
230 
231     kasan_failures += test_kasan();
232 
233     if(!kasan_failures)
234       printf("KASAN: OK\n");
235 
236     failures += kasan_failures;
237   }
238 
239   if (test_everything || have_option("kcov", argv, argc)) {
240     int kcov_failures = 0;
241 
242     kcov_failures += test_kcov();
243 
244     if (!kcov_failures)
245       printf("KCOV: OK\n");
246 
247     failures += kcov_failures;
248   }
249 
250   if (test_everything || have_option("ubsan", argv, argc)) {
251     int ubsan_failures = 0;
252 
253     ubsan_failures += test(test_integer_overflow);
254 
255     if (!ubsan_failures)
256       printf("UBSAN: OK\n");
257 
258     failures += ubsan_failures;
259   }
260 
261   if (test_everything || have_option("gwp_asan", argv, argc)) {
262     int gwp_asan_failures = 0;
263 
264     gwp_asan_failures += test(test_crash_gwp_asan);
265 
266     if (!gwp_asan_failures)
267       printf("GWP-ASan: OK\n");
268 
269     failures += gwp_asan_failures;
270   }
271 
272   return failures > 0 ? EXIT_FAILURE : EXIT_SUCCESS;
273 }
274