• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <malloc.h>
23 #include <paths.h>
24 #include <pthread.h>
25 #include <pwd.h>
26 #include <stdbool.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <unistd.h>
31 #include <sys/prctl.h>
32 #include <sys/types.h>
33 #include <sys/wait.h>
34 
35 #include <bionic/mte.h>
36 
37 // crashes if built with -fsanitize={address,hwaddress}
test_crash_malloc_overflow()38 void test_crash_malloc_overflow() {
39   volatile char* heap = reinterpret_cast<volatile char *>(malloc(32));
40   heap[32] = heap[32];
41   printf("Heap Overflow Test Failed\n");
42 }
43 
44 // crashes if built with -fsanitize={address,hwaddresss}
test_crash_malloc_uaf()45 void test_crash_malloc_uaf() {
46   volatile char* heap = reinterpret_cast<volatile char *>(malloc(32));
47   free((void *)heap);
48   heap[0] = heap[0];
49   printf("Heap UAF Test Failed\n");
50 }
51 
52 // crashes if built with -fsanitize=address
test_crash_stack()53 void test_crash_stack() {
54   volatile char stack[32];
55   volatile char* p_stack = stack;
56   p_stack[32] = p_stack[32];
57   printf("(HW)ASAN: Stack Test Failed\n");
58 }
59 
test_crash_pthread_mutex_unlock()60 void test_crash_pthread_mutex_unlock() {
61   volatile char* heap = reinterpret_cast<volatile char *>(malloc(32));
62   pthread_mutex_unlock((pthread_mutex_t*)&heap[32]);
63   printf("HWASAN: Libc Test Failed\n");
64 }
65 
data_asan_exists()66 int data_asan_exists() {
67   int fd = open("/data/asan", O_DIRECTORY | O_PATH | O_CLOEXEC, 0);
68   if(fd < 0) {
69     printf("ASAN: Missing /data/asan\n");
70     return 1;
71   }
72   close(fd);
73   return 0;
74 }
75 
76 // crashes if built with -fsanitize=memory
test_msan_crash_stack()77 void test_msan_crash_stack() {
78   volatile int stack[10];
79   stack[5] = 0;
80   if (stack[0]) { // NOLINT
81     stack[0] = 1;
82   }
83   printf("MSAN: Stack Test Failed\n");
84 }
85 
86 // crashes if built with -fsanitize=integer
test_integer_overflow()87 void test_integer_overflow() {
88   size_t max = (size_t)-1;
89   max++;
90   printf("UBSAN: Integer Overflow Test Failed\n");
91 }
92 
93 // returns 0 if kcov is enabled
test_kcov()94 int test_kcov() {
95   const char* kcov_file = "/sys/kernel/debug/kcov";
96   int fd = open(kcov_file, O_RDWR);
97   if (fd == -1) {
98     printf("KCOV: Could not open %s\n", kcov_file);
99     return 1;
100   }
101   close(fd);
102   return 0;
103 }
104 
105 // returns 0 if kasan was compiled in
test_kasan()106 int test_kasan() {
107   // rely on the exit status of grep to propagate
108   if (system("gzip -d < /proc/config.gz | grep CONFIG_KASAN=y >/dev/null")) {
109     printf("KASAN: CONFIG_KASAN not in /proc/config.gz\n");
110     return 1;
111   }
112   return 0;
113 }
114 
115 // Number of iterations required to reliably guarantee a GWP-ASan crash.
116 // GWP-ASan's sample rate is not truly nondeterministic, it initialises a
117 // thread-local counter at 2*SampleRate, and decrements on each malloc(). Once
118 // the counter reaches zero, we provide a sampled allocation. GWP-ASan's current
119 // default sample rate is 1/5000.
120 #define GWP_ASAN_ITERATIONS_TO_ENSURE_CRASH (0x10000)
121 
122 // crashes with GWP-ASan
test_crash_gwp_asan()123 void test_crash_gwp_asan() {
124   for (unsigned i = 0; i < GWP_ASAN_ITERATIONS_TO_ENSURE_CRASH; ++i ) {
125     volatile char* x = reinterpret_cast<volatile char *>(malloc(1));
126     free((void*) x);
127     *x = 0;
128   }
129   printf("GWP-ASan: Use after Free Failed\n");
130 }
131 
132 // executes a test that is expected to crash
133 // returns 0 if the test crashes
test(void (* function)())134 int test(void (*function)()) {
135   fflush(stdout);
136 
137   pid_t child = fork();
138   int status = 0;
139 
140   if (child == -1) {
141     perror("fork");
142     exit(1);
143   }
144 
145   if (child == 0) {
146     // Silence the ASAN report that is generated
147     close(2);
148 
149     // Invoke the target function.  If it does not crash, terminate the process.
150     function();
151     exit(EXIT_SUCCESS);
152   }
153 
154   // Wait for the child to either crash, or exit cleanly
155   while (child == waitpid(child, &status, 0)) {
156     if (!WIFEXITED(status))
157       continue;
158     if (WEXITSTATUS(status) == EXIT_SUCCESS)
159       return 1;
160     break;
161   }
162   return 0;
163 }
164 
have_option(const char * option,const char ** argv,const int argc)165 int have_option(const char* option, const char** argv, const int argc) {
166   for (int i = 1; i < argc; i++)
167     if (!strcmp(option, argv[i]))
168       return 1;
169   return 0;
170 }
171 
main(int argc,const char ** argv)172 int main(int argc, const char** argv) {
173   int test_everything = 0;
174   int failures = 0;
175 
176   if (argc <= 1)
177     test_everything = 1;
178 
179   if (test_everything || have_option("asan", argv, argc)) {
180     int asan_failures = 0;
181 
182 #if !__has_feature(address_sanitizer)
183     asan_failures += 1;
184     printf("ASAN: Compiler flags failed!\n");
185 #endif
186 
187     asan_failures += test(test_crash_malloc_overflow);
188     asan_failures += test(test_crash_malloc_uaf);
189     asan_failures += test(test_crash_stack);
190     asan_failures += data_asan_exists();
191 
192     if (!asan_failures)
193       printf("ASAN: OK\n");
194 
195     failures += asan_failures;
196   }
197 
198   if (test_everything || have_option("hwasan", argv, argc)) {
199     int hwasan_failures = 0;
200 
201 #if !__has_feature(hwaddress_sanitizer)
202     hwasan_failures += 1;
203     printf("HWASAN: Compiler flags failed!\n");
204 #endif
205 
206     hwasan_failures += test(test_crash_malloc_overflow);
207     hwasan_failures += test(test_crash_malloc_uaf);
208     hwasan_failures += test(test_crash_stack);
209     hwasan_failures += test(test_crash_pthread_mutex_unlock);
210 
211     if (!hwasan_failures)
212       printf("HWASAN: OK\n");
213 
214     failures += hwasan_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   if (test_everything || have_option("mte", argv, argc)) {
273     int mte_failures = 0;
274 
275     if (!(mte_supported() && !__has_feature(address_sanitizer) &&
276           !__has_feature(hwaddress_sanitizer))) {
277       mte_failures += 1;
278       printf("MTE: Not supported\n");
279     }
280 
281     mte_failures += test(test_crash_malloc_overflow);
282     mte_failures += test(test_crash_malloc_uaf);
283 
284     int tagged_addr_ctrl = prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0);
285     if (tagged_addr_ctrl < 0) {
286       mte_failures += 1;
287       printf("MTE: PR_GET_TAGGED_ADDR_CTRL failed\n");
288     }
289 
290     HeapTaggingLevel heap_tagging_level = M_HEAP_TAGGING_LEVEL_SYNC;
291     if (mallopt(M_BIONIC_SET_HEAP_TAGGING_LEVEL, heap_tagging_level) == 0) {
292       mte_failures += 1;
293       printf("MTE: mallopt failed\n");
294     }
295 
296     mte_failures += test(test_crash_malloc_overflow);
297     mte_failures += test(test_crash_malloc_uaf);
298 
299     if (!mte_failures)
300       printf("MTE: OK\n");
301 
302     failures += mte_failures;
303   }
304 
305   return failures > 0 ? EXIT_FAILURE : EXIT_SUCCESS;
306 }
307