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 #define TLOG_TAG "hwasan-rt"
18 
19 #include "hwasan.h"
20 #include <lib/hwasan/hwasan_shadow.h>
21 
22 #include <assert.h>
23 #include <lk/compiler.h>
24 #include <lk/macros.h>
25 #include <stdbool.h>
26 #include <stdint.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <sys/auxv.h>
31 #include <trusty_log.h>
32 #include <uapi/err.h>
33 
34 uintptr_t __hwasan_shadow_memory_dynamic_address = 0;
35 
get_tag(uintptr_t ptr)36 static inline uint8_t get_tag(uintptr_t ptr) {
37     return (uint64_t)ptr >> hwasan_addr_tag_shift;
38 }
39 
remove_ptr_tag(uintptr_t ptr)40 static inline uintptr_t remove_ptr_tag(uintptr_t ptr) {
41     return ptr & ~hwasan_addr_tag_mask;
42 }
43 
tag_ptr(uintptr_t ptr,uint8_t tag)44 static inline uintptr_t tag_ptr(uintptr_t ptr, uint8_t tag) {
45     uint64_t tag_mask = (uint64_t)tag << hwasan_addr_tag_shift;
46     return remove_ptr_tag(ptr) | tag_mask;
47 }
48 
49 /* Tagging granularity is 1 tag per 16 bytes */
mem_to_shadow(uintptr_t ptr)50 static inline uintptr_t mem_to_shadow(uintptr_t ptr) {
51     ptr = remove_ptr_tag(ptr);
52     return (ptr >> HWASAN_SHADOW_SCALE) +
53            __hwasan_shadow_memory_dynamic_address;
54 }
55 
is_valid_user_ptr(uintptr_t ptr)56 static inline bool is_valid_user_ptr(uintptr_t ptr) {
57     ptr = remove_ptr_tag(ptr);
58     return !ptr || (ptr >= USER_ASPACE_BASE &&
59                     ptr < USER_ASPACE_BASE + USER_ASPACE_SIZE);
60 }
61 
__hwasan_report_error(uintptr_t far)62 __WEAK void __hwasan_report_error(uintptr_t far) {
63     /* TODO(b/149918767): unwind stack, analyze, and report error */
64     uint8_t ptr_tag = get_tag(far);
65     uint8_t* shadow_tag = (uint8_t*)mem_to_shadow(far);
66 
67     TLOGE("Failed address check. Fault address: 0x%16lx, pointer tag: 0x%x, "
68           "expected tag: 0x%x\n",
69           far, ptr_tag, *shadow_tag);
70 
71     abort();
72 }
73 
check_address(uintptr_t ptr,size_t size)74 static void check_address(uintptr_t ptr, size_t size) {
75     assert(is_valid_user_ptr(ptr));
76 
77     if (!ptr || size == 0) {
78         /* Pass the address check since NULL pointer dereference segfaults
79          * anyways */
80         return;
81     }
82 
83     uint8_t ptr_tag = get_tag(ptr);
84     uint8_t* first_tag = (uint8_t*)mem_to_shadow(ptr);
85     uint8_t* last_tag = (uint8_t*)mem_to_shadow(ptr + size - 1);
86     for (uint8_t* tag = first_tag; tag <= last_tag; tag++) {
87         if (ptr_tag != *tag) {
88             uintptr_t far =
89                     ptr + ((uintptr_t)(tag - first_tag) << HWASAN_SHADOW_SCALE);
90             __hwasan_report_error(far);
91         }
92     }
93 }
94 
__hwasan_init(void)95 void __hwasan_init(void) {
96     if (!__hwasan_shadow_memory_dynamic_address) {
97         __hwasan_shadow_memory_dynamic_address =
98                 getauxval(TRUSTY_AT_HWASAN_SHADOW);
99         assert(__hwasan_shadow_memory_dynamic_address);
100     }
101 }
102 
__hwasan_memset(uintptr_t ptr,int val,size_t size)103 void* __hwasan_memset(uintptr_t ptr, int val, size_t size) {
104     check_address(ptr, size);
105     return memset((void*)ptr, val, size);
106 }
107 
__hwasan_memcpy(uintptr_t dst,const uintptr_t src,size_t size)108 void* __hwasan_memcpy(uintptr_t dst, const uintptr_t src, size_t size) {
109     check_address(dst, size);
110     check_address(src, size);
111     return memcpy((void*)dst, (void*)src, size);
112 }
113 
__hwasan_memmove(uintptr_t dst,const uintptr_t src,size_t size)114 void* __hwasan_memmove(uintptr_t dst, const uintptr_t src, size_t size) {
115     check_address(dst, size);
116     check_address(src, size);
117     return memmove((void*)dst, (void*)src, size);
118 }
119 
__hwasan_loadN(uintptr_t ptr,size_t size)120 void __hwasan_loadN(uintptr_t ptr, size_t size) {
121     check_address(ptr, size);
122 }
123 
__hwasan_storeN(uintptr_t ptr,size_t size)124 void __hwasan_storeN(uintptr_t ptr, size_t size) {
125     check_address(ptr, size);
126 }
127 
hwasan_generate_tag()128 static uint8_t hwasan_generate_tag() {
129     static uint8_t tag = 0;
130     /* 0 tag corresponds to untagged memory, so avoid generating it */
131     if (__builtin_add_overflow(tag, 1, &tag)) {
132         tag = 1;
133     }
134     return tag;
135 }
136 
hwasan_tag_memory_etc(uintptr_t ptr,size_t size,uint8_t tag)137 static uintptr_t hwasan_tag_memory_etc(uintptr_t ptr,
138                                        size_t size,
139                                        uint8_t tag) {
140     assert(IS_ALIGNED(ptr, 1U << HWASAN_SHADOW_SCALE));
141     assert(is_valid_user_ptr(ptr));
142 
143     /*
144      * It's possible that dlmalloc() fails to allocate memory, in which case it
145      * passes NULL here.
146      */
147     if (!ptr || !size) {
148         return ptr;
149     }
150 
151     uint8_t* first_tag = (uint8_t*)mem_to_shadow(ptr);
152     uint8_t* last_tag = (uint8_t*)mem_to_shadow(ptr + size - 1);
153     for (uint8_t* i = first_tag; i <= last_tag; i++) {
154         *i = tag;
155     }
156     return tag_ptr(ptr, tag);
157 }
158 
hwasan_tag_memory(void * ptr,size_t size)159 void* hwasan_tag_memory(void* ptr, size_t size) {
160     return (void*)hwasan_tag_memory_etc((uintptr_t)ptr, size,
161                                         hwasan_generate_tag());
162 }
163 
hwasan_untag_memory(void * ptr,size_t size)164 void hwasan_untag_memory(void* ptr, size_t size) {
165     hwasan_tag_memory_etc((uintptr_t)ptr, size, 0);
166 }
167 
hwasan_remove_ptr_tag(void * ptr)168 void* hwasan_remove_ptr_tag(void* ptr) {
169     return (void*)remove_ptr_tag((uintptr_t)ptr);
170 }
171