• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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 <stdint.h>
18 #define TLOG_TAG "hwasan-test"
19 
20 #include <memref.h>
21 #include <stdlib.h>
22 #include <trusty_unittest.h>
23 
24 #include <lib/hwasan/hwasan_shadow.h>
25 #include <lk/compiler.h>
26 #include <sys/auxv.h>
27 #include <sys/mman.h>
28 
29 #ifndef ARCH_ARM64
30 #error Trusty only supports HWAsan on arm64
31 #endif
32 
33 #define PAGE_SIZE getauxval(AT_PAGESZ)
34 
35 /* Magic number, only true for Aarch64 */
36 #define TAGGING_GRANULARITY 16
37 
38 #define OK 0
39 #define ERR 1
40 
41 static int hwasan_error = OK;
__hwasan_report_error(void)42 void __hwasan_report_error(void) {
43     WRITE_ONCE(hwasan_error, ERR);
44 }
45 
46 /*
47  * This symbol is branched into when HWASan error is detected. Trusty HWASan
48  * runtime defines it as a weak symbol. Override it for testing.
49  */
hwasan_get_error(void)50 static int hwasan_get_error(void) {
51     int ret = READ_ONCE(hwasan_error);
52     WRITE_ONCE(hwasan_error, OK);
53     return ret;
54 }
55 
56 /* To make sure variable isn't optimized away */
touch(volatile void * a)57 static void touch(volatile void* a) {
58     *((volatile uint8_t*)a) = *((volatile uint8_t*)a);
59 }
60 
TEST(hwasan,hello_world)61 TEST(hwasan, hello_world) {
62     TLOGI("Hello World!\n");
63     ASSERT_EQ(hwasan_get_error(), OK);
64 test_abort:;
65 }
66 
TEST(hwasan,stack_ok)67 TEST(hwasan, stack_ok) {
68     int a = 0;
69 
70     WRITE_ONCE(a, 5);
71     ASSERT_EQ(hwasan_get_error(), OK);
72 
73     ASSERT_EQ(READ_ONCE(a), 5);
74     ASSERT_EQ(hwasan_get_error(), OK);
75 
76 test_abort:;
77 }
78 
TEST(hwasan,stack_err)79 TEST(hwasan, stack_err) {
80     int a = 0;
81     int* b = (int*)hwasan_remove_ptr_tag((void*)(&a));
82 
83     WRITE_ONCE(*b, 5);
84     ASSERT_EQ(hwasan_get_error(), ERR);
85 
86     ASSERT_EQ(READ_ONCE(*b), 5);
87     ASSERT_EQ(hwasan_get_error(), ERR);
88 
89 test_abort:;
90 }
91 
TEST(hwasan,heap_ok)92 TEST(hwasan, heap_ok) {
93     int* a = malloc(sizeof(int));
94 
95     WRITE_ONCE(*a, 5);
96     ASSERT_EQ(hwasan_get_error(), OK);
97 
98     ASSERT_EQ(READ_ONCE(*a), 5);
99     ASSERT_EQ(hwasan_get_error(), OK);
100 
101 test_abort:
102     free(a);
103 }
104 
TEST(hwasan,heap_err)105 TEST(hwasan, heap_err) {
106     int* a = malloc(sizeof(int));
107     int* b = (int*)hwasan_remove_ptr_tag((void*)a);
108 
109     WRITE_ONCE(*b, 5);
110     ASSERT_EQ(hwasan_get_error(), ERR);
111 
112     ASSERT_EQ(READ_ONCE(*b), 5);
113     ASSERT_EQ(hwasan_get_error(), ERR);
114 
115 test_abort:
116     free(a);
117 }
118 
TEST(hwasan,heap_use_after_free)119 TEST(hwasan, heap_use_after_free) {
120     int* a = malloc(sizeof(int));
121 
122     WRITE_ONCE(*a, 5);
123     ASSERT_EQ(*a, 5);
124 
125     free(a);
126     ASSERT_EQ(READ_ONCE(*a), 5); /* heap use after free */
127     ASSERT_EQ(hwasan_get_error(), ERR);
128 
129 test_abort:;
130 }
131 
TEST(hwasan,memintrinsics_ok)132 TEST(hwasan, memintrinsics_ok) {
133     static const size_t size = TAGGING_GRANULARITY;
134     int8_t* a = malloc(size);
135 
136     touch(a);
137     memset(a, 'a', size);
138     touch(a);
139     ASSERT_EQ(hwasan_get_error(), OK);
140 
141 test_abort:
142     free(a);
143 }
144 
TEST(hwasan,memintrinsics_err)145 TEST(hwasan, memintrinsics_err) {
146     static const size_t size = TAGGING_GRANULARITY;
147     int8_t* a = malloc(size);
148 
149     touch(a);
150     memset(a, 'a', size + 1); /* heap buffer overflow */
151     touch(a);
152     ASSERT_EQ(hwasan_get_error(), ERR);
153 
154 test_abort:
155     free(a);
156 }
157 
TEST(hwasan,realloc_tag_new)158 TEST(hwasan, realloc_tag_new) {
159     static const size_t size = TAGGING_GRANULARITY;
160     int8_t* a = malloc(size);
161     int8_t* b = realloc(a, size + 1);
162     ASSERT_NE(b, NULL);
163 
164     touch(b);
165     memset(b, 'b', size + 1);
166     touch(b);
167     ASSERT_EQ(hwasan_get_error(), OK);
168 
169 test_abort:
170     free(b);
171 }
172 
173 /* Test that realloc()'ing to new memory makes old memory inaccessible */
TEST(hwasan,realloc_untag_old)174 TEST(hwasan, realloc_untag_old) {
175     static const size_t old_size = TAGGING_GRANULARITY;
176     static const size_t new_size = 128 * TAGGING_GRANULARITY;
177     static const size_t num_tries = 100;
178 
179     int8_t* a;
180     int8_t* unused;
181     int8_t* b;
182     void* a_notag;
183     void* b_notag;
184 
185     /* Try getting a new memory location from realloc() */
186     for (size_t i = 0; i < num_tries; i++) {
187         a = malloc(old_size);
188         unused = malloc(old_size);
189         b = realloc(a, new_size); /* hopefully we get a new address */
190 
191         a_notag = hwasan_remove_ptr_tag(a);
192         b_notag = hwasan_remove_ptr_tag(b);
193 
194         if (a_notag != b_notag) {
195             break;
196         }
197 
198         touch(unused);
199         touch(b);
200         free(unused);
201         free(b);
202     }
203 
204     /* Might not be true, but better to not ignore this. */
205     ASSERT_NE(a_notag, b_notag);
206 
207     /*
208      * "a" should have been freed and untagged by this point. Writing to &a
209      * may corrupt the heap, so avoid doing that.
210      */
211     WRITE_ONCE(*b, READ_ONCE(*a));
212     ASSERT_EQ(hwasan_get_error(), ERR);
213 
214 test_abort:
215     free(unused);
216     free(b);
217 }
218 
219 /* Test that realloc()'ing to same memory location retags that memory */
TEST(hwasan,realloc_retag)220 TEST(hwasan, realloc_retag) {
221     static const size_t num_tries = 100;
222 
223     int8_t* a;
224     int8_t* b;
225     void* a_notag;
226     void* b_notag;
227 
228     /* Try getting the same memory location from realloc() */
229     for (size_t i = 0; i < num_tries; i++) {
230         a = malloc(sizeof(*a));
231         b = realloc(a, sizeof(*a)); /* hopefully we get a new address */
232 
233         a_notag = hwasan_remove_ptr_tag(a);
234         b_notag = hwasan_remove_ptr_tag(b);
235 
236         if (a_notag == b_notag) {
237             break;
238         }
239 
240         free(b);
241     }
242 
243     /* Might not be true, but better to not ignore this. */
244     ASSERT_EQ(a_notag, b_notag);
245 
246     /*
247      * Since there are no allocations between a and b, their tags can't collide
248      * (even if they point to same memory).
249      */
250     ASSERT_NE(a, b);
251 
252 test_abort:
253     free(b);
254 }
255 
TEST(hwasan,memalign)256 TEST(hwasan, memalign) {
257     int* a = memalign(PAGE_SIZE, PAGE_SIZE);
258     WRITE_ONCE(*a, 5);
259     ASSERT_EQ(READ_ONCE(*a), 5);
260     ASSERT_EQ(hwasan_get_error(), OK);
261 
262 test_abort:
263     free(a);
264 }
265 
TEST(hwasan,memref_create)266 TEST(hwasan, memref_create) {
267     void* a = memalign(PAGE_SIZE, PAGE_SIZE);
268     int handle = memref_create(a, PAGE_SIZE,
269                                MMAP_FLAG_PROT_READ | MMAP_FLAG_PROT_WRITE);
270 
271     ASSERT_GE(handle, 0);
272     ASSERT_EQ(hwasan_get_error(), OK);
273 
274 test_abort:
275     close(handle);
276     free(a);
277 }
278 
279 #define MEM_MAP_ID 1
280 #define MEM_MAP_ADDR 0x70000000U
281 #define MEM_MAP_SIZE 0x1000U
282 
TEST(hwasan,mmap)283 TEST(hwasan, mmap) {
284     int ret;
285     struct dma_pmem pmem;
286     int* a;
287     uint32_t dma_flags = DMA_FLAG_FROM_DEVICE | DMA_FLAG_ALLOW_PARTIAL;
288 
289     for (size_t i = 0; i < 10; i++) {
290         a = mmap(NULL, MEM_MAP_SIZE, PROT_READ | PROT_WRITE,
291                  MMAP_FLAG_IO_HANDLE, MEM_MAP_ID, 0);
292         ASSERT_NE(a, MAP_FAILED);
293 
294         ret = prepare_dma(a, MEM_MAP_SIZE, dma_flags, &pmem);
295         ASSERT_EQ(ret, 1);
296         ASSERT_EQ(pmem.paddr, MEM_MAP_ADDR);
297         ASSERT_EQ(pmem.size, MEM_MAP_SIZE);
298 
299         touch(a);
300         finish_dma(a, MEM_MAP_SIZE, dma_flags);
301         munmap(a, MEM_MAP_SIZE);
302     }
303 
304     return;
305 
306 test_abort:
307     finish_dma(a, MEM_MAP_SIZE, dma_flags);
308     munmap(a, MEM_MAP_SIZE);
309 }
310 
TEST(hwasan,mmap_ok)311 TEST(hwasan, mmap_ok) {
312     int* a = mmap(NULL, MEM_MAP_SIZE, PROT_READ | PROT_WRITE,
313                   MMAP_FLAG_IO_HANDLE, MEM_MAP_ID, 0);
314     ASSERT_NE(a, MAP_FAILED);
315 
316     WRITE_ONCE(*a, 5);
317     ASSERT_EQ(hwasan_get_error(), OK);
318 
319     ASSERT_EQ(READ_ONCE(*a), 5);
320     ASSERT_EQ(hwasan_get_error(), OK);
321 
322 test_abort:;
323     munmap(a, MEM_MAP_SIZE);
324 }
325 
TEST(hwasan,mmap_err)326 TEST(hwasan, mmap_err) {
327     int* a = mmap(NULL, MEM_MAP_SIZE, PROT_READ | PROT_WRITE,
328                   MMAP_FLAG_IO_HANDLE, MEM_MAP_ID, 0);
329     ASSERT_NE(a, MAP_FAILED);
330     int* b = (int*)hwasan_remove_ptr_tag((void*)a);
331 
332     WRITE_ONCE(*b, 5);
333     ASSERT_EQ(hwasan_get_error(), ERR);
334 
335     ASSERT_EQ(READ_ONCE(*b), 5);
336     ASSERT_EQ(hwasan_get_error(), ERR);
337 
338 test_abort:;
339     munmap(a, MEM_MAP_SIZE);
340 }
341 
342 static int bss_int;
343 
TEST(hwasan,bss_ok)344 TEST(hwasan, bss_ok) {
345     WRITE_ONCE(bss_int, 5);
346     ASSERT_EQ(bss_int, 5);
347     ASSERT_EQ(hwasan_get_error(), OK);
348 test_abort:;
349 }
350 
TEST(hwasan,bss_err)351 TEST(hwasan, bss_err) {
352     int* a = (int*)hwasan_remove_ptr_tag((void*)(&bss_int));
353     WRITE_ONCE(*a, 6);
354     ASSERT_EQ(READ_ONCE(*a), 6);
355 
356     /* TODO(b/148877030): Sanitize globals */
357     ASSERT_EQ(hwasan_get_error(), OK);
358 test_abort:;
359 }
360 
361 PORT_TEST(hwcrypto, "com.android.trusty.hwasan.user.test")
362