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 char global[32] = {};
38
39 // crashes if built with -fsanitize={address,hwaddress}
test_crash_malloc_overflow()40 void test_crash_malloc_overflow() {
41 volatile char* heap = reinterpret_cast<volatile char *>(malloc(32));
42 heap[32] = heap[32];
43 printf("Heap Overflow Test Failed\n");
44 }
45
46 // crashes if built with -fsanitize={address,hwaddresss}
test_crash_malloc_uaf()47 void test_crash_malloc_uaf() {
48 volatile char* heap = reinterpret_cast<volatile char *>(malloc(32));
49 free((void *)heap);
50 heap[0] = heap[0];
51 printf("Heap UAF Test Failed\n");
52 }
53
54 // crashes if built with -fsanitize={address,hwaddress,memtag-stack}
test_crash_stack()55 void test_crash_stack() {
56 volatile char stack[32];
57 volatile char* p_stack = stack;
58 p_stack[32] = p_stack[32];
59 printf("(HW)ASAN / Stack MTE: Stack Test Failed\n");
60 }
61
62 // crashes if built with -fsanitize={address,hwaddress,memtag-globals}
test_crash_globals()63 void test_crash_globals() {
64 volatile char* p_global = global;
65 p_global[32] = p_global[32];
66 printf("(HW)ASAN / Globals MTE: Globals Test Failed\n");
67 }
68
test_crash_pthread_mutex_unlock()69 void test_crash_pthread_mutex_unlock() {
70 volatile char* heap = reinterpret_cast<volatile char *>(malloc(32));
71 pthread_mutex_unlock((pthread_mutex_t*)&heap[32]);
72 printf("HWASAN: Libc Test Failed\n");
73 }
74
data_asan_exists()75 int data_asan_exists() {
76 int fd = open("/data/asan", O_DIRECTORY | O_PATH | O_CLOEXEC, 0);
77 if(fd < 0) {
78 printf("ASAN: Missing /data/asan\n");
79 return 1;
80 }
81 close(fd);
82 return 0;
83 }
84
85 // crashes if built with -fsanitize=memory
test_msan_crash_stack()86 void test_msan_crash_stack() {
87 volatile int stack[10];
88 stack[5] = 0;
89 if (stack[0]) { // NOLINT
90 stack[0] = 1;
91 }
92 printf("MSAN: Stack Test Failed\n");
93 }
94
95 // crashes if built with -fsanitize=integer
test_integer_overflow()96 void test_integer_overflow() {
97 size_t max = (size_t)-1;
98 max++;
99 printf("UBSAN: Integer Overflow Test Failed\n");
100 }
101
102 // returns 0 if kcov is enabled
test_kcov()103 int test_kcov() {
104 const char* kcov_file = "/sys/kernel/debug/kcov";
105 int fd = open(kcov_file, O_RDWR);
106 if (fd == -1) {
107 printf("KCOV: Could not open %s\n", kcov_file);
108 return 1;
109 }
110 close(fd);
111 return 0;
112 }
113
114 // returns 0 if kasan was compiled in
test_kasan()115 int test_kasan() {
116 // rely on the exit status of grep to propagate
117 if (system("gzip -d < /proc/config.gz | grep CONFIG_KASAN=y >/dev/null")) {
118 printf("KASAN: CONFIG_KASAN not in /proc/config.gz\n");
119 return 1;
120 }
121 return 0;
122 }
123
124 // Number of iterations required to reliably guarantee a GWP-ASan crash.
125 // GWP-ASan's sample rate is not truly nondeterministic, it initialises a
126 // thread-local counter at 2*SampleRate, and decrements on each malloc(). Once
127 // the counter reaches zero, we provide a sampled allocation. GWP-ASan's current
128 // default sample rate is 1/5000.
129 #define GWP_ASAN_ITERATIONS_TO_ENSURE_CRASH (0x10000)
130
131 // crashes with GWP-ASan
test_crash_gwp_asan()132 void test_crash_gwp_asan() {
133 for (unsigned i = 0; i < GWP_ASAN_ITERATIONS_TO_ENSURE_CRASH; ++i ) {
134 volatile char* x = reinterpret_cast<volatile char *>(malloc(1));
135 free((void*) x);
136 *x = 0;
137 }
138 printf("GWP-ASan: Use after Free Failed\n");
139 }
140
141 // executes a test that is expected to crash
142 // returns 0 if the test crashes
test(void (* function)())143 int test(void (*function)()) {
144 fflush(stdout);
145
146 pid_t child = fork();
147 int status = 0;
148
149 if (child == -1) {
150 perror("fork");
151 exit(1);
152 }
153
154 if (child == 0) {
155 // Silence the ASAN report that is generated
156 close(2);
157
158 // Invoke the target function. If it does not crash, terminate the process.
159 function();
160 exit(EXIT_SUCCESS);
161 }
162
163 // Wait for the child to either crash, or exit cleanly
164 while (child == waitpid(child, &status, 0)) {
165 if (!WIFEXITED(status))
166 continue;
167 if (WEXITSTATUS(status) == EXIT_SUCCESS)
168 return 1;
169 break;
170 }
171 return 0;
172 }
173
have_option(const char * option,const char ** argv,const int argc)174 int have_option(const char* option, const char** argv, const int argc) {
175 for (int i = 1; i < argc; i++)
176 if (!strcmp(option, argv[i]))
177 return 1;
178 return 0;
179 }
180
main(int argc,const char ** argv)181 int main(int argc, const char** argv) {
182 int test_everything = 0;
183 int failures = 0;
184
185 if (argc <= 1)
186 test_everything = 1;
187
188 if (test_everything || have_option("asan", argv, argc)) {
189 int asan_failures = 0;
190
191 #if !__has_feature(address_sanitizer)
192 asan_failures += 1;
193 printf("ASAN: Compiler flags failed!\n");
194 #endif
195
196 asan_failures += test(test_crash_malloc_overflow);
197 asan_failures += test(test_crash_malloc_uaf);
198 asan_failures += test(test_crash_stack);
199 asan_failures += data_asan_exists();
200
201 if (!asan_failures)
202 printf("ASAN: OK\n");
203
204 failures += asan_failures;
205 }
206
207 if (test_everything || have_option("hwasan", argv, argc)) {
208 int hwasan_failures = 0;
209
210 #if !__has_feature(hwaddress_sanitizer)
211 hwasan_failures += 1;
212 printf("HWASAN: Compiler flags failed!\n");
213 #endif
214
215 hwasan_failures += test(test_crash_malloc_overflow);
216 hwasan_failures += test(test_crash_malloc_uaf);
217 hwasan_failures += test(test_crash_stack);
218 hwasan_failures += test(test_crash_pthread_mutex_unlock);
219 hwasan_failures += test(test_crash_globals);
220
221 if (!hwasan_failures)
222 printf("HWASAN: OK\n");
223
224 failures += hwasan_failures;
225 }
226
227 if (test_everything || have_option("msan", argv, argc)) {
228 int msan_failures = 0;
229
230 msan_failures += test(test_msan_crash_stack);
231
232 if (!msan_failures)
233 printf("MSAN: OK\n");
234
235 failures += msan_failures;
236 }
237
238 if (test_everything || have_option("kasan", argv, argc)) {
239 int kasan_failures = 0;
240
241 kasan_failures += test_kasan();
242
243 if(!kasan_failures)
244 printf("KASAN: OK\n");
245
246 failures += kasan_failures;
247 }
248
249 if (test_everything || have_option("kcov", argv, argc)) {
250 int kcov_failures = 0;
251
252 kcov_failures += test_kcov();
253
254 if (!kcov_failures)
255 printf("KCOV: OK\n");
256
257 failures += kcov_failures;
258 }
259
260 if (test_everything || have_option("ubsan", argv, argc)) {
261 int ubsan_failures = 0;
262
263 ubsan_failures += test(test_integer_overflow);
264
265 if (!ubsan_failures)
266 printf("UBSAN: OK\n");
267
268 failures += ubsan_failures;
269 }
270
271 if (test_everything || have_option("gwp_asan", argv, argc)) {
272 int gwp_asan_failures = 0;
273
274 gwp_asan_failures += test(test_crash_gwp_asan);
275
276 if (!gwp_asan_failures)
277 printf("GWP-ASan: OK\n");
278
279 failures += gwp_asan_failures;
280 }
281
282 if (test_everything || have_option("mte", argv, argc)) {
283 int mte_failures = 0;
284
285 if (!(mte_supported() && !__has_feature(address_sanitizer) &&
286 !__has_feature(hwaddress_sanitizer))) {
287 mte_failures += 1;
288 printf("MTE: Not supported\n");
289 }
290
291 mte_failures += test(test_crash_malloc_overflow);
292 mte_failures += test(test_crash_malloc_uaf);
293
294 int tagged_addr_ctrl = prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0);
295 if (tagged_addr_ctrl < 0) {
296 mte_failures += 1;
297 printf("MTE: PR_GET_TAGGED_ADDR_CTRL failed\n");
298 }
299
300 HeapTaggingLevel heap_tagging_level = M_HEAP_TAGGING_LEVEL_SYNC;
301 if (mallopt(M_BIONIC_SET_HEAP_TAGGING_LEVEL, heap_tagging_level) == 0) {
302 mte_failures += 1;
303 printf("MTE: mallopt failed\n");
304 }
305
306 mte_failures += test(test_crash_malloc_overflow);
307 mte_failures += test(test_crash_malloc_uaf);
308
309 if (!mte_failures)
310 printf("MTE: OK\n");
311
312 failures += mte_failures;
313 }
314
315 if (test_everything || have_option("stack_mte", argv, argc)) {
316 int stack_mte_failures = 0;
317
318 if (!(mte_supported() && !__has_feature(address_sanitizer) &&
319 !__has_feature(hwaddress_sanitizer))) {
320 stack_mte_failures += 1;
321 printf("MTE: Not supported\n");
322 }
323
324 stack_mte_failures += test(test_crash_stack);
325
326 if (!stack_mte_failures)
327 printf("Stack MTE: OK\n");
328
329 failures += stack_mte_failures;
330 }
331
332 if (test_everything || have_option("globals_mte", argv, argc)) {
333 int globals_mte_failures = 0;
334
335 if (!(mte_supported() && !__has_feature(address_sanitizer) &&
336 !__has_feature(hwaddress_sanitizer))) {
337 globals_mte_failures += 1;
338 printf("MTE: Not supported\n");
339 }
340
341 globals_mte_failures += test(test_crash_globals);
342
343 if (!globals_mte_failures)
344 printf("Globals MTE: OK\n");
345
346 failures += globals_mte_failures;
347 }
348
349 return failures > 0 ? EXIT_FAILURE : EXIT_SUCCESS;
350 }
351