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