OLD | NEW |
1 //===- subzero/runtime/szrt_asan.c - AddressSanitizer Runtime -----*- C -*-===// | 1 //===- subzero/runtime/szrt_asan.c - AddressSanitizer Runtime -----*- C -*-===// |
2 // | 2 // |
3 // The Subzero Code Generator | 3 // The Subzero Code Generator |
4 // | 4 // |
5 // This file is distributed under the University of Illinois Open Source | 5 // This file is distributed under the University of Illinois Open Source |
6 // License. See LICENSE.TXT for details. | 6 // License. See LICENSE.TXT for details. |
7 // | 7 // |
8 //===----------------------------------------------------------------------===// | 8 //===----------------------------------------------------------------------===// |
9 /// | 9 /// |
10 /// \file | 10 /// \file |
(...skipping 26 matching lines...) Expand all Loading... |
37 #define WORD_SIZE (sizeof(uint32_t)) | 37 #define WORD_SIZE (sizeof(uint32_t)) |
38 #define IS_32_BIT (sizeof(void *) == WORD_SIZE) | 38 #define IS_32_BIT (sizeof(void *) == WORD_SIZE) |
39 | 39 |
40 #define SHADOW_OFFSET(p) ((uintptr_t)(p) % SHADOW_SCALE) | 40 #define SHADOW_OFFSET(p) ((uintptr_t)(p) % SHADOW_SCALE) |
41 #define IS_SHADOW_ALIGNED(p) (SHADOW_OFFSET(p) == 0) | 41 #define IS_SHADOW_ALIGNED(p) (SHADOW_OFFSET(p) == 0) |
42 | 42 |
43 #define MEM2SHADOW(p) (((uintptr_t)(p) >> SHADOW_SCALE_LOG2) + shadow_offset) | 43 #define MEM2SHADOW(p) (((uintptr_t)(p) >> SHADOW_SCALE_LOG2) + shadow_offset) |
44 #define SHADOW2MEM(p) \ | 44 #define SHADOW2MEM(p) \ |
45 ((uintptr_t)((char *)(p)-shadow_offset) << SHADOW_SCALE_LOG2) | 45 ((uintptr_t)((char *)(p)-shadow_offset) << SHADOW_SCALE_LOG2) |
46 | 46 |
47 #define POISON_VAL (-1) | 47 #define STACK_POISON_VAL ((char)-1) |
| 48 #define HEAP_POISON_VAL ((char)-2) |
| 49 #define GLOBAL_POISON_VAL ((char)-3) |
| 50 #define MEMTYPE_INDEX(x) (-1 - (x)) |
| 51 static const char *memtype_names[] = {"stack", "heap", "global"}; |
| 52 |
| 53 #define ACCESS_LOAD (0) |
| 54 #define ACCESS_STORE (1) |
| 55 static const char *access_names[] = {"load from", "store to"}; |
48 | 56 |
49 #if DEBUG | 57 #if DEBUG |
50 #define DUMP(args...) \ | 58 #define DUMP(args...) \ |
51 do { \ | 59 do { \ |
52 printf(args); \ | 60 printf(args); \ |
53 } while (false); | 61 } while (false); |
54 #else // !DEBUG | 62 #else // !DEBUG |
55 #define DUMP(args...) | 63 #define DUMP(args...) |
56 #endif // DEBUG | 64 #endif // DEBUG |
57 | 65 |
58 static char *shadow_offset = NULL; | 66 static char *shadow_offset = NULL; |
59 | 67 |
60 static void __asan_error(char *, int); | 68 static bool __asan_check(char *, int); |
61 static void __asan_check(char *, int); | 69 static void __asan_error(char *, int, int); |
62 static void __asan_get_redzones(char *, char **, char **); | 70 static void __asan_get_redzones(char *, char **, char **); |
63 | 71 |
64 void __asan_init(int, void **, int *); | 72 void __asan_init(int, void **, int *); |
65 void __asan_check_load(char *, int); | 73 void __asan_check_load(char *, int); |
66 void __asan_check_store(char *, int); | 74 void __asan_check_store(char *, int); |
67 void *__asan_malloc(size_t); | 75 void *__asan_malloc(size_t); |
68 void *__asan_calloc(size_t, size_t); | 76 void *__asan_calloc(size_t, size_t); |
69 void *__asan_realloc(char *, size_t); | 77 void *__asan_realloc(char *, size_t); |
70 void __asan_free(char *); | 78 void __asan_free(char *); |
71 void __asan_poison(char *, int); | 79 void __asan_poison(char *, int, char); |
72 void __asan_unpoison(char *, int); | 80 void __asan_unpoison(char *, int); |
73 | 81 |
74 static void __asan_error(char *ptr, int size) { | 82 static void __asan_error(char *ptr, int size, int access) { |
75 fprintf(stderr, "Illegal access of %d bytes at %p\n", size, ptr); | 83 char *shadow_addr = MEM2SHADOW(ptr); |
| 84 char shadow_val = *shadow_addr; |
| 85 if (shadow_val > 0) |
| 86 shadow_val = *(shadow_addr + 1); |
| 87 assert(access == ACCESS_LOAD || access == ACCESS_STORE); |
| 88 const char *access_name = access_names[access]; |
| 89 assert(shadow_val == STACK_POISON_VAL || shadow_val == HEAP_POISON_VAL || |
| 90 shadow_val == GLOBAL_POISON_VAL); |
| 91 const char *memtype = memtype_names[MEMTYPE_INDEX(shadow_val)]; |
| 92 fprintf(stderr, "Illegal %d byte %s %s object at %p\n", size, access_name, |
| 93 memtype, ptr); |
76 abort(); | 94 abort(); |
77 } | 95 } |
78 | 96 |
79 // check only the first byte of each word unless strict | 97 // check only the first byte of each word unless strict |
80 static void __asan_check(char *ptr, int size) { | 98 static bool __asan_check(char *ptr, int size) { |
81 assert(size == 1 || size == 2 || size == 4 || size == 8); | 99 assert(size == 1 || size == 2 || size == 4 || size == 8); |
82 char *shadow_addr = (char *)MEM2SHADOW(ptr); | 100 char *shadow_addr = (char *)MEM2SHADOW(ptr); |
| 101 char shadow_val = *shadow_addr; |
83 DUMP("check %d bytes at %p: %p + %d (%d)\n", size, ptr, shadow_addr, | 102 DUMP("check %d bytes at %p: %p + %d (%d)\n", size, ptr, shadow_addr, |
84 (uintptr_t)ptr % SHADOW_SCALE, *shadow_addr); | 103 (uintptr_t)ptr % SHADOW_SCALE, shadow_val); |
85 if (size == SHADOW_SCALE) { | 104 if (size == SHADOW_SCALE) { |
86 if (*shadow_addr != 0) | 105 return shadow_val == 0; |
87 __asan_error(ptr, size); | |
88 return; | |
89 } | 106 } |
90 if (*shadow_addr != 0 && (char)SHADOW_OFFSET(ptr) + size > *shadow_addr) | 107 return shadow_val == 0 || (char)SHADOW_OFFSET(ptr) + size <= shadow_val; |
91 __asan_error(ptr, size); | |
92 } | 108 } |
93 | 109 |
94 static void __asan_get_redzones(char *ptr, char **left, char **right) { | 110 static void __asan_get_redzones(char *ptr, char **left, char **right) { |
95 char *rz_left = ptr - RZ_SIZE; | 111 char *rz_left = ptr - RZ_SIZE; |
96 char *rz_right = *(char **)rz_left; | 112 char *rz_right = *(char **)rz_left; |
97 if (left != NULL) | 113 if (left != NULL) |
98 *left = rz_left; | 114 *left = rz_left; |
99 if (right != NULL) | 115 if (right != NULL) |
100 *right = rz_right; | 116 *right = rz_right; |
101 } | 117 } |
102 | 118 |
103 void __asan_check_load(char *ptr, int size) { | 119 void __asan_check_load(char *ptr, int size) { |
104 // aligned single word accesses may be widened single byte accesses, but for | 120 // aligned single word accesses may be widened single byte accesses, but for |
105 // all else use strict check | 121 // all else use strict check |
106 if (size == WORD_SIZE && (uintptr_t)ptr % WORD_SIZE == 0) | 122 int check_size = |
107 size = 1; | 123 (size == WORD_SIZE && (uintptr_t)ptr % WORD_SIZE == 0) ? 1 : size; |
108 __asan_check(ptr, size); | 124 if (!__asan_check(ptr, check_size)) |
| 125 __asan_error(ptr, size, ACCESS_LOAD); |
109 } | 126 } |
110 | 127 |
111 void __asan_check_store(char *ptr, int size) { | 128 void __asan_check_store(char *ptr, int size) { |
112 // stores may never be partially out of bounds so use strict check | 129 // stores may never be partially out of bounds so use strict check |
113 bool strict = true; | 130 if (!__asan_check(ptr, size)) |
114 __asan_check(ptr, size); | 131 __asan_error(ptr, size, ACCESS_STORE); |
115 } | 132 } |
116 | 133 |
117 void __asan_init(int n_rzs, void **rzs, int *rz_sizes) { | 134 void __asan_init(int n_rzs, void **rzs, int *rz_sizes) { |
118 // ensure the redzones are large enough to hold metadata | 135 // ensure the redzones are large enough to hold metadata |
119 assert(RZ_SIZE >= sizeof(void *) && RZ_SIZE >= sizeof(size_t)); | 136 assert(RZ_SIZE >= sizeof(void *) && RZ_SIZE >= sizeof(size_t)); |
120 assert(shadow_offset == NULL); | 137 assert(shadow_offset == NULL); |
121 size_t length = (IS_32_BIT) ? SHADOW_LENGTH_32 : SHADOW_LENGTH_64; | 138 size_t length = (IS_32_BIT) ? SHADOW_LENGTH_32 : SHADOW_LENGTH_64; |
122 int prot = PROT_READ | PROT_WRITE; | 139 int prot = PROT_READ | PROT_WRITE; |
123 int flags = MAP_PRIVATE | MAP_ANONYMOUS; | 140 int flags = MAP_PRIVATE | MAP_ANONYMOUS; |
124 int fd = -1; | 141 int fd = -1; |
125 off_t offset = 0; | 142 off_t offset = 0; |
126 shadow_offset = mmap((void *)length, length, prot, flags, fd, offset); | 143 shadow_offset = mmap((void *)length, length, prot, flags, fd, offset); |
127 if (shadow_offset == NULL) | 144 if (shadow_offset == NULL) |
128 fprintf(stderr, "unable to allocate shadow memory\n"); | 145 fprintf(stderr, "unable to allocate shadow memory\n"); |
129 else | 146 else |
130 DUMP("set up shadow memory at %p\n", shadow_offset); | 147 DUMP("set up shadow memory at %p\n", shadow_offset); |
131 if (mprotect(MEM2SHADOW(shadow_offset), length >> SHADOW_SCALE_LOG2, | 148 if (mprotect(MEM2SHADOW(shadow_offset), length >> SHADOW_SCALE_LOG2, |
132 PROT_NONE)) | 149 PROT_NONE)) |
133 fprintf(stderr, "could not protect bad region\n"); | 150 fprintf(stderr, "could not protect bad region\n"); |
134 else | 151 else |
135 DUMP("protected bad region\n"); | 152 DUMP("protected bad region\n"); |
136 | 153 |
137 // poison global redzones | 154 // poison global redzones |
138 DUMP("poisioning %d global redzones\n", n_rzs); | 155 DUMP("poisioning %d global redzones\n", n_rzs); |
139 for (int i = 0; i < n_rzs; i++) { | 156 for (int i = 0; i < n_rzs; i++) { |
140 DUMP("(%d) poisoning redzone of size %d at %p\n", i, rz_sizes[i], rzs[i]); | 157 DUMP("(%d) poisoning redzone of size %d at %p\n", i, rz_sizes[i], rzs[i]); |
141 __asan_poison(rzs[i], rz_sizes[i]); | 158 __asan_poison(rzs[i], rz_sizes[i], GLOBAL_POISON_VAL); |
142 } | 159 } |
143 } | 160 } |
144 | 161 |
145 void *__asan_malloc(size_t size) { | 162 void *__asan_malloc(size_t size) { |
146 DUMP("malloc() called with size %d\n", size); | 163 DUMP("malloc() called with size %d\n", size); |
147 size_t padding = | 164 size_t padding = |
148 (IS_SHADOW_ALIGNED(size)) ? 0 : SHADOW_SCALE - SHADOW_OFFSET(size); | 165 (IS_SHADOW_ALIGNED(size)) ? 0 : SHADOW_SCALE - SHADOW_OFFSET(size); |
149 size_t rz_left_size = RZ_SIZE; | 166 size_t rz_left_size = RZ_SIZE; |
150 size_t rz_right_size = RZ_SIZE + padding; | 167 size_t rz_right_size = RZ_SIZE + padding; |
151 void *rz_left; | 168 void *rz_left; |
152 int err = posix_memalign(&rz_left, SHADOW_SCALE, | 169 int err = posix_memalign(&rz_left, SHADOW_SCALE, |
153 rz_left_size + size + rz_right_size); | 170 rz_left_size + size + rz_right_size); |
154 if (err != 0) { | 171 if (err != 0) { |
155 assert(err == ENOMEM); | 172 assert(err == ENOMEM); |
156 return NULL; | 173 return NULL; |
157 } | 174 } |
158 void *ret = rz_left + rz_left_size; | 175 void *ret = rz_left + rz_left_size; |
159 void *rz_right = ret + size; | 176 void *rz_right = ret + size; |
160 __asan_poison(rz_left, rz_left_size); | 177 __asan_poison(rz_left, rz_left_size, HEAP_POISON_VAL); |
161 __asan_poison(rz_right, rz_right_size); | 178 __asan_poison(rz_right, rz_right_size, HEAP_POISON_VAL); |
162 // record size and location data so we can find it again | 179 // record size and location data so we can find it again |
163 *(void **)rz_left = rz_right; | 180 *(void **)rz_left = rz_right; |
164 *(size_t *)rz_right = rz_right_size; | 181 *(size_t *)rz_right = rz_right_size; |
165 assert((uintptr_t)ret % 8 == 0); | 182 assert((uintptr_t)ret % 8 == 0); |
166 return ret; | 183 return ret; |
167 } | 184 } |
168 | 185 |
169 void *__asan_calloc(size_t nmemb, size_t size) { | 186 void *__asan_calloc(size_t nmemb, size_t size) { |
170 size_t alloc_size = nmemb * size; | 187 size_t alloc_size = nmemb * size; |
171 void *ret = __asan_malloc(alloc_size); | 188 void *ret = __asan_malloc(alloc_size); |
(...skipping 25 matching lines...) Expand all Loading... |
197 void __asan_free(char *ptr) { | 214 void __asan_free(char *ptr) { |
198 DUMP("free() called on %p\n", ptr); | 215 DUMP("free() called on %p\n", ptr); |
199 char *rz_left, *rz_right; | 216 char *rz_left, *rz_right; |
200 __asan_get_redzones(ptr, &rz_left, &rz_right); | 217 __asan_get_redzones(ptr, &rz_left, &rz_right); |
201 size_t rz_right_size = *(size_t *)rz_right; | 218 size_t rz_right_size = *(size_t *)rz_right; |
202 __asan_unpoison(rz_left, RZ_SIZE); | 219 __asan_unpoison(rz_left, RZ_SIZE); |
203 __asan_unpoison(rz_right, rz_right_size); | 220 __asan_unpoison(rz_right, rz_right_size); |
204 free(rz_left); | 221 free(rz_left); |
205 } | 222 } |
206 | 223 |
207 void __asan_poison(char *ptr, int size) { | 224 void __asan_poison(char *ptr, int size, char poison_val) { |
208 char *end = ptr + size; | 225 char *end = ptr + size; |
209 assert(IS_SHADOW_ALIGNED(end)); | 226 assert(IS_SHADOW_ALIGNED(end)); |
210 // redzones should be no greater than RZ_SIZE + RZ_SIZE-1 for alignment | 227 // redzones should be no greater than RZ_SIZE + RZ_SIZE-1 for alignment |
211 assert(size < 2 * RZ_SIZE); | 228 assert(size < 2 * RZ_SIZE); |
212 DUMP("poison %d bytes at %p: %p - %p\n", size, ptr, MEM2SHADOW(ptr), | 229 DUMP("poison %d bytes at %p: %p - %p\n", size, ptr, MEM2SHADOW(ptr), |
213 MEM2SHADOW(end)); | 230 MEM2SHADOW(end)); |
214 size_t offset = SHADOW_OFFSET(ptr); | 231 size_t offset = SHADOW_OFFSET(ptr); |
215 *(char *)MEM2SHADOW(ptr) = (offset == 0) ? POISON_VAL : offset; | 232 *(char *)MEM2SHADOW(ptr) = (offset == 0) ? poison_val : offset; |
216 ptr += SHADOW_OFFSET(size); | 233 ptr += SHADOW_OFFSET(size); |
217 assert(IS_SHADOW_ALIGNED(ptr)); | 234 assert(IS_SHADOW_ALIGNED(ptr)); |
218 for (; ptr != end; ptr += SHADOW_SCALE) { | 235 int len = (end - ptr) >> SHADOW_SCALE_LOG2; |
219 *(char *)MEM2SHADOW(ptr) = POISON_VAL; | 236 memset(MEM2SHADOW(ptr), poison_val, len); |
220 } | |
221 } | 237 } |
222 | 238 |
223 void __asan_unpoison(char *ptr, int size) { | 239 void __asan_unpoison(char *ptr, int size) { |
224 char *end = ptr + size; | 240 char *end = ptr + size; |
225 assert(IS_SHADOW_ALIGNED(end)); | 241 assert(IS_SHADOW_ALIGNED(end)); |
226 assert(size < 2 * RZ_SIZE); | 242 assert(size < 2 * RZ_SIZE); |
227 DUMP("unpoison %d bytes at %p: %p - %p\n", size, ptr, MEM2SHADOW(ptr), | 243 DUMP("unpoison %d bytes at %p: %p - %p\n", size, ptr, MEM2SHADOW(ptr), |
228 MEM2SHADOW(end)); | 244 MEM2SHADOW(end)); |
229 *(char *)MEM2SHADOW(ptr) = 0; | 245 *(char *)MEM2SHADOW(ptr) = 0; |
230 ptr += SHADOW_OFFSET(size); | 246 ptr += SHADOW_OFFSET(size); |
231 assert(IS_SHADOW_ALIGNED(ptr)); | 247 assert(IS_SHADOW_ALIGNED(ptr)); |
232 for (; ptr != end; ptr += SHADOW_SCALE) { | 248 memset(MEM2SHADOW(ptr), 0, (end - ptr) >> SHADOW_SCALE_LOG2); |
233 *(char *)MEM2SHADOW(ptr) = 0; | |
234 } | |
235 } | 249 } |
OLD | NEW |