Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(94)

Side by Side Diff: runtime/szrt_asan.c

Issue 2227353002: Subzero: Added ASan quarantine for recently freed objects (Closed) Base URL: https://chromium.googlesource.com/native_client/pnacl-subzero.git@master
Patch Set: Added check for double free errors Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | tests_lit/asan_tests/doublefree.ll » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
11 /// \brief Provides the AddressSanitizer runtime. 11 /// \brief Provides the AddressSanitizer runtime.
12 /// 12 ///
13 /// Exposes functions for initializing the shadow memory region and managing it 13 /// Exposes functions for initializing the shadow memory region and managing it
14 /// on loads, stores, and allocations. 14 /// on loads, stores, and allocations.
15 /// 15 ///
16 //===----------------------------------------------------------------------===// 16 //===----------------------------------------------------------------------===//
17 17
18 #include <assert.h> 18 #include <assert.h>
19 #include <errno.h> 19 #include <errno.h>
20 #include <limits.h> 20 #include <limits.h>
21 #include <sched.h>
21 #include <stdbool.h> 22 #include <stdbool.h>
22 #include <stddef.h> 23 #include <stddef.h>
23 #include <stdint.h> 24 #include <stdint.h>
24 #include <stdio.h> 25 #include <stdio.h>
25 #include <stdlib.h> 26 #include <stdlib.h>
26 #include <string.h> 27 #include <string.h>
27 #include <sys/mman.h> 28 #include <sys/mman.h>
28 29
30 #if _POSIX_THREADS
31
32 #include <pthread.h>
33 typedef pthread_mutex_t mutex_t;
34 #define MUTEX_INITIALIZER (PTHREAD_MUTEX_INITIALIZER)
35 #define MUTEX_LOCK(mutex) (pthread_mutex_lock(&(mutex)))
36 #define MUTEX_UNLOCK(mutex) (pthread_mutex_unlock(&(mutex)))
37
38 #else // !_POSIX_THREADS
39
40 typedef uint32_t mutex_t;
41 #define MUTEX_INITIALIZER (0)
42 #define MUTEX_LOCK(mutex) \
43 while (__sync_swap((mutex), 1) != 0) { \
44 sched_yield(); \
45 }
46 #define MUTEX_UNLOCK(mutex) (__sync_swap((mutex), 0))
47
48 #endif // _POSIX_THREADS
49
29 #define RZ_SIZE (32) 50 #define RZ_SIZE (32)
30 #define SHADOW_SCALE_LOG2 (3) 51 #define SHADOW_SCALE_LOG2 (3)
31 #define SHADOW_SCALE ((size_t)1 << SHADOW_SCALE_LOG2) 52 #define SHADOW_SCALE ((size_t)1 << SHADOW_SCALE_LOG2)
32 #define DEBUG (0) 53 #define DEBUG (1)
33 54
34 // Assuming 48 bit address space on 64 bit systems 55 // Assuming 48 bit address space on 64 bit systems
35 #define SHADOW_LENGTH_64 (1u << (48 - SHADOW_SCALE_LOG2)) 56 #define SHADOW_LENGTH_64 (1u << (48 - SHADOW_SCALE_LOG2))
36 #define SHADOW_LENGTH_32 (1u << (32 - SHADOW_SCALE_LOG2)) 57 #define SHADOW_LENGTH_32 (1u << (32 - SHADOW_SCALE_LOG2))
37 #define WORD_SIZE (sizeof(uint32_t)) 58 #define WORD_SIZE (sizeof(uint32_t))
38 #define IS_32_BIT (sizeof(void *) == WORD_SIZE) 59 #define IS_32_BIT (sizeof(void *) == WORD_SIZE)
39 60
40 #define SHADOW_OFFSET(p) ((uintptr_t)(p) % SHADOW_SCALE) 61 #define SHADOW_OFFSET(p) ((uintptr_t)(p) % SHADOW_SCALE)
41 #define IS_SHADOW_ALIGNED(p) (SHADOW_OFFSET(p) == 0) 62 #define IS_SHADOW_ALIGNED(p) (SHADOW_OFFSET(p) == 0)
42 63
43 #define MEM2SHADOW(p) (((uintptr_t)(p) >> SHADOW_SCALE_LOG2) + shadow_offset) 64 #define MEM2SHADOW(p) (((uintptr_t)(p) >> SHADOW_SCALE_LOG2) + shadow_offset)
44 #define SHADOW2MEM(p) \ 65 #define SHADOW2MEM(p) \
45 ((uintptr_t)((char *)(p)-shadow_offset) << SHADOW_SCALE_LOG2) 66 ((uintptr_t)((char *)(p)-shadow_offset) << SHADOW_SCALE_LOG2)
46 67
68 #define QUARANTINE_MAX_SIZE ((size_t)1 << 28) // 256 MB
69
47 #define STACK_POISON_VAL ((char)-1) 70 #define STACK_POISON_VAL ((char)-1)
48 #define HEAP_POISON_VAL ((char)-2) 71 #define HEAP_POISON_VAL ((char)-2)
49 #define GLOBAL_POISON_VAL ((char)-3) 72 #define GLOBAL_POISON_VAL ((char)-3)
73 #define FREED_POISON_VAL ((char)-4)
50 #define MEMTYPE_INDEX(x) (-1 - (x)) 74 #define MEMTYPE_INDEX(x) (-1 - (x))
51 static const char *memtype_names[] = {"stack", "heap", "global"}; 75 static const char *memtype_names[] = {"stack", "heap", "global", "freed"};
52 76
53 #define ACCESS_LOAD (0) 77 #define ACCESS_LOAD (0)
54 #define ACCESS_STORE (1) 78 #define ACCESS_STORE (1)
55 static const char *access_names[] = {"load from", "store to"}; 79 static const char *access_names[] = {"load from", "store to"};
56 80
57 #if DEBUG 81 #if DEBUG
58 #define DUMP(args...) \ 82 #define DUMP(args...) \
59 do { \ 83 do { \
60 printf(args); \ 84 printf(args); \
61 } while (false); 85 } while (false);
(...skipping 10 matching lines...) Expand all
72 void __asan_init(int, void **, int *); 96 void __asan_init(int, void **, int *);
73 void __asan_check_load(char *, int); 97 void __asan_check_load(char *, int);
74 void __asan_check_store(char *, int); 98 void __asan_check_store(char *, int);
75 void *__asan_malloc(size_t); 99 void *__asan_malloc(size_t);
76 void *__asan_calloc(size_t, size_t); 100 void *__asan_calloc(size_t, size_t);
77 void *__asan_realloc(char *, size_t); 101 void *__asan_realloc(char *, size_t);
78 void __asan_free(char *); 102 void __asan_free(char *);
79 void __asan_poison(char *, int, char); 103 void __asan_poison(char *, int, char);
80 void __asan_unpoison(char *, int); 104 void __asan_unpoison(char *, int);
81 105
106 struct quarantine_entry {
107 struct quarantine_entry *next;
108 size_t size;
109 };
110
111 mutex_t quarantine_lock = MUTEX_INITIALIZER;
112 uint64_t quarantine_size = 0;
113 struct quarantine_entry *quarantine_head = NULL;
114 struct quarantine_entry *quarantine_tail = NULL;
115
82 static void __asan_error(char *ptr, int size, int access) { 116 static void __asan_error(char *ptr, int size, int access) {
83 char *shadow_addr = MEM2SHADOW(ptr); 117 char *shadow_addr = MEM2SHADOW(ptr);
84 char shadow_val = *shadow_addr; 118 char shadow_val = *shadow_addr;
85 if (shadow_val > 0) 119 if (shadow_val > 0)
86 shadow_val = *(shadow_addr + 1); 120 shadow_val = *(shadow_addr + 1);
87 assert(access == ACCESS_LOAD || access == ACCESS_STORE); 121 assert(access == ACCESS_LOAD || access == ACCESS_STORE);
88 const char *access_name = access_names[access]; 122 const char *access_name = access_names[access];
89 assert(shadow_val == STACK_POISON_VAL || shadow_val == HEAP_POISON_VAL || 123 assert(shadow_val == STACK_POISON_VAL || shadow_val == HEAP_POISON_VAL ||
90 shadow_val == GLOBAL_POISON_VAL); 124 shadow_val == GLOBAL_POISON_VAL || shadow_val == FREED_POISON_VAL);
91 const char *memtype = memtype_names[MEMTYPE_INDEX(shadow_val)]; 125 const char *memtype = memtype_names[MEMTYPE_INDEX(shadow_val)];
92 fprintf(stderr, "Illegal %d byte %s %s object at %p\n", size, access_name, 126 fprintf(stderr, "Illegal %d byte %s %s object at %p\n", size, access_name,
93 memtype, ptr); 127 memtype, ptr);
94 abort(); 128 abort();
95 } 129 }
96 130
97 // check only the first byte of each word unless strict 131 // check only the first byte of each word unless strict
98 static bool __asan_check(char *ptr, int size) { 132 static bool __asan_check(char *ptr, int size) {
99 assert(size == 1 || size == 2 || size == 4 || size == 8); 133 assert(size == 1 || size == 2 || size == 4 || size == 8);
100 char *shadow_addr = (char *)MEM2SHADOW(ptr); 134 char *shadow_addr = (char *)MEM2SHADOW(ptr);
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after
206 if (new_alloc == NULL) 240 if (new_alloc == NULL)
207 return NULL; 241 return NULL;
208 size_t copyable = (size < old_size) ? size : old_size; 242 size_t copyable = (size < old_size) ? size : old_size;
209 memcpy(new_alloc, ptr, copyable); 243 memcpy(new_alloc, ptr, copyable);
210 __asan_free(ptr); 244 __asan_free(ptr);
211 return new_alloc; 245 return new_alloc;
212 } 246 }
213 247
214 void __asan_free(char *ptr) { 248 void __asan_free(char *ptr) {
215 DUMP("free() called on %p\n", ptr); 249 DUMP("free() called on %p\n", ptr);
250 if (ptr == NULL)
251 return;
252 if (*(char *)MEM2SHADOW(ptr) == FREED_POISON_VAL) {
253 fprintf(stderr, "Double free of object at %p\n", ptr);
254 abort();
255 }
216 char *rz_left, *rz_right; 256 char *rz_left, *rz_right;
217 __asan_get_redzones(ptr, &rz_left, &rz_right); 257 __asan_get_redzones(ptr, &rz_left, &rz_right);
218 size_t rz_right_size = *(size_t *)rz_right; 258 size_t rz_right_size = *(size_t *)rz_right;
219 __asan_unpoison(rz_left, RZ_SIZE); 259 size_t total_size = rz_right_size + (rz_right - rz_left);
220 __asan_unpoison(rz_right, rz_right_size); 260 __asan_poison(rz_left, total_size, FREED_POISON_VAL);
221 free(rz_left); 261
262 // place allocation in quarantine
263 struct quarantine_entry *entry = (struct quarantine_entry *)rz_left;
264 assert(entry != NULL);
265 entry->next = NULL;
266 entry->size = total_size;
267
268 DUMP("Placing %d bytes at %p in quarantine\n", entry->size, entry);
269 MUTEX_LOCK(&quarantine_lock);
270 if (quarantine_tail != NULL)
271 quarantine_tail->next = entry;
272 quarantine_tail = entry;
273 if (quarantine_head == NULL)
274 quarantine_head = entry;
275 quarantine_size += total_size;
276 DUMP("Quarantine size is %llu\n", quarantine_size);
277
278 // free old objects as necessary
279 while (quarantine_size > QUARANTINE_MAX_SIZE) {
280 struct quarantine_entry *freed = quarantine_head;
281 assert(freed != NULL);
282 __asan_unpoison((char *)freed, freed->size);
283 quarantine_size -= freed->size;
284 quarantine_head = freed->next;
285 DUMP("Releasing %d bytes at %p from quarantine\n", freed->size, freed);
286 DUMP("Quarantine size is %llu\n", quarantine_size);
287 free(freed);
288 }
289 MUTEX_UNLOCK(&quarantine_lock);
222 } 290 }
223 291
224 void __asan_poison(char *ptr, int size, char poison_val) { 292 void __asan_poison(char *ptr, int size, char poison_val) {
225 char *end = ptr + size; 293 char *end = ptr + size;
226 assert(IS_SHADOW_ALIGNED(end)); 294 assert(IS_SHADOW_ALIGNED(end));
227 // redzones should be no greater than RZ_SIZE + RZ_SIZE-1 for alignment
228 assert(size < 2 * RZ_SIZE);
229 DUMP("poison %d bytes at %p: %p - %p\n", size, ptr, MEM2SHADOW(ptr), 295 DUMP("poison %d bytes at %p: %p - %p\n", size, ptr, MEM2SHADOW(ptr),
230 MEM2SHADOW(end)); 296 MEM2SHADOW(end));
231 size_t offset = SHADOW_OFFSET(ptr); 297 size_t offset = SHADOW_OFFSET(ptr);
232 *(char *)MEM2SHADOW(ptr) = (offset == 0) ? poison_val : offset; 298 *(char *)MEM2SHADOW(ptr) = (offset == 0) ? poison_val : offset;
233 ptr += SHADOW_OFFSET(size); 299 ptr += SHADOW_OFFSET(size);
234 assert(IS_SHADOW_ALIGNED(ptr)); 300 assert(IS_SHADOW_ALIGNED(ptr));
235 int len = (end - ptr) >> SHADOW_SCALE_LOG2; 301 int len = (end - ptr) >> SHADOW_SCALE_LOG2;
236 memset(MEM2SHADOW(ptr), poison_val, len); 302 memset(MEM2SHADOW(ptr), poison_val, len);
237 } 303 }
238 304
239 void __asan_unpoison(char *ptr, int size) { 305 void __asan_unpoison(char *ptr, int size) {
240 char *end = ptr + size; 306 char *end = ptr + size;
241 assert(IS_SHADOW_ALIGNED(end)); 307 assert(IS_SHADOW_ALIGNED(end));
242 assert(size < 2 * RZ_SIZE);
243 DUMP("unpoison %d bytes at %p: %p - %p\n", size, ptr, MEM2SHADOW(ptr), 308 DUMP("unpoison %d bytes at %p: %p - %p\n", size, ptr, MEM2SHADOW(ptr),
244 MEM2SHADOW(end)); 309 MEM2SHADOW(end));
245 *(char *)MEM2SHADOW(ptr) = 0; 310 *(char *)MEM2SHADOW(ptr) = 0;
246 ptr += SHADOW_OFFSET(size); 311 ptr += SHADOW_OFFSET(size);
247 assert(IS_SHADOW_ALIGNED(ptr)); 312 assert(IS_SHADOW_ALIGNED(ptr));
248 memset(MEM2SHADOW(ptr), 0, (end - ptr) >> SHADOW_SCALE_LOG2); 313 memset(MEM2SHADOW(ptr), 0, (end - ptr) >> SHADOW_SCALE_LOG2);
249 } 314 }
OLDNEW
« no previous file with comments | « no previous file | tests_lit/asan_tests/doublefree.ll » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698