1 /*
2    american fuzzy lop - error-checking, memory-zeroing alloc routines
3    ------------------------------------------------------------------
4 
5    Written and maintained by Michal Zalewski <lcamtuf@google.com>
6 
7    Copyright 2013, 2014, 2015 Google Inc. All rights reserved.
8 
9    Licensed under the Apache License, Version 2.0 (the "License");
10    you may not use this file except in compliance with the License.
11    You may obtain a copy of the License at:
12 
13      http://www.apache.org/licenses/LICENSE-2.0
14 
15    This allocator is not designed to resist malicious attackers (the canaries
16    are small and predictable), but provides a robust and portable way to detect
17    use-after-free, off-by-one writes, stale pointers, and so on.
18 
19  */
20 
21 #ifndef _HAVE_ALLOC_INL_H
22 #define _HAVE_ALLOC_INL_H
23 
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 
28 #include "config.h"
29 #include "types.h"
30 #include "debug.h"
31 
32 /* User-facing macro to sprintf() to a dynamically allocated buffer. */
33 
34 #define alloc_printf(_str...) ({ \
35     u8* _tmp; \
36     s32 _len = snprintf(NULL, 0, _str); \
37     if (_len < 0) FATAL("Whoa, snprintf() fails?!"); \
38     _tmp = ck_alloc(_len + 1); \
39     snprintf((char*)_tmp, _len + 1, _str); \
40     _tmp; \
41   })
42 
43 /* Macro to enforce allocation limits as a last-resort defense against
44    integer overflows. */
45 
46 #define ALLOC_CHECK_SIZE(_s) do { \
47     if ((_s) > MAX_ALLOC) \
48       ABORT("Bad alloc request: %u bytes", (_s)); \
49   } while (0)
50 
51 /* Macro to check malloc() failures and the like. */
52 
53 #define ALLOC_CHECK_RESULT(_r, _s) do { \
54     if (!(_r)) \
55       ABORT("Out of memory: can't allocate %u bytes", (_s)); \
56   } while (0)
57 
58 /* Magic tokens used to mark used / freed chunks. */
59 
60 #define ALLOC_MAGIC_C1  0xFF00FF00 /* Used head (dword)  */
61 #define ALLOC_MAGIC_F   0xFE00FE00 /* Freed head (dword) */
62 #define ALLOC_MAGIC_C2  0xF0       /* Used tail (byte)   */
63 
64 /* Positions of guard tokens in relation to the user-visible pointer. */
65 
66 #define ALLOC_C1(_ptr)  (((u32*)(_ptr))[-2])
67 #define ALLOC_S(_ptr)   (((u32*)(_ptr))[-1])
68 #define ALLOC_C2(_ptr)  (((u8*)(_ptr))[ALLOC_S(_ptr)])
69 
70 #define ALLOC_OFF_HEAD  8
71 #define ALLOC_OFF_TOTAL (ALLOC_OFF_HEAD + 1)
72 
73 /* Allocator increments for ck_realloc_block(). */
74 
75 #define ALLOC_BLK_INC    256
76 
77 /* Sanity-checking macros for pointers. */
78 
79 #define CHECK_PTR(_p) do { \
80     if (_p) { \
81       if (ALLOC_C1(_p) ^ ALLOC_MAGIC_C1) {\
82         if (ALLOC_C1(_p) == ALLOC_MAGIC_F) \
83           ABORT("Use after free."); \
84         else ABORT("Corrupted head alloc canary."); \
85       } \
86       if (ALLOC_C2(_p) ^ ALLOC_MAGIC_C2) \
87         ABORT("Corrupted tail alloc canary."); \
88     } \
89   } while (0)
90 
91 #define CHECK_PTR_EXPR(_p) ({ \
92     typeof (_p) _tmp = (_p); \
93     CHECK_PTR(_tmp); \
94     _tmp; \
95   })
96 
97 
98 /* Allocate a buffer, explicitly not zeroing it. Returns NULL for zero-sized
99    requests. */
100 
DFL_ck_alloc_nozero(u32 size)101 static inline void* DFL_ck_alloc_nozero(u32 size) {
102 
103   void* ret;
104 
105   if (!size) return NULL;
106 
107   ALLOC_CHECK_SIZE(size);
108   ret = malloc(size + ALLOC_OFF_TOTAL);
109   ALLOC_CHECK_RESULT(ret, size);
110 
111   ret += ALLOC_OFF_HEAD;
112 
113   ALLOC_C1(ret) = ALLOC_MAGIC_C1;
114   ALLOC_S(ret)  = size;
115   ALLOC_C2(ret) = ALLOC_MAGIC_C2;
116 
117   return ret;
118 
119 }
120 
121 
122 /* Allocate a buffer, returning zeroed memory. */
123 
DFL_ck_alloc(u32 size)124 static inline void* DFL_ck_alloc(u32 size) {
125 
126   void* mem;
127 
128   if (!size) return NULL;
129   mem = DFL_ck_alloc_nozero(size);
130 
131   return memset(mem, 0, size);
132 
133 }
134 
135 
136 /* Free memory, checking for double free and corrupted heap. When DEBUG_BUILD
137    is set, the old memory will be also clobbered with 0xFF. */
138 
DFL_ck_free(void * mem)139 static inline void DFL_ck_free(void* mem) {
140 
141   if (!mem) return;
142 
143   CHECK_PTR(mem);
144 
145 #ifdef DEBUG_BUILD
146 
147   /* Catch pointer issues sooner. */
148   memset(mem, 0xFF, ALLOC_S(mem));
149 
150 #endif /* DEBUG_BUILD */
151 
152   ALLOC_C1(mem) = ALLOC_MAGIC_F;
153 
154   free(mem - ALLOC_OFF_HEAD);
155 
156 }
157 
158 
159 /* Re-allocate a buffer, checking for issues and zeroing any newly-added tail.
160    With DEBUG_BUILD, the buffer is always reallocated to a new addresses and the
161    old memory is clobbered with 0xFF. */
162 
DFL_ck_realloc(void * orig,u32 size)163 static inline void* DFL_ck_realloc(void* orig, u32 size) {
164 
165   void* ret;
166   u32   old_size = 0;
167 
168   if (!size) {
169 
170     DFL_ck_free(orig);
171     return NULL;
172 
173   }
174 
175   if (orig) {
176 
177     CHECK_PTR(orig);
178 
179 #ifndef DEBUG_BUILD
180     ALLOC_C1(orig) = ALLOC_MAGIC_F;
181 #endif /* !DEBUG_BUILD */
182 
183     old_size  = ALLOC_S(orig);
184     orig     -= ALLOC_OFF_HEAD;
185 
186     ALLOC_CHECK_SIZE(old_size);
187 
188   }
189 
190   ALLOC_CHECK_SIZE(size);
191 
192 #ifndef DEBUG_BUILD
193 
194   ret = realloc(orig, size + ALLOC_OFF_TOTAL);
195   ALLOC_CHECK_RESULT(ret, size);
196 
197 #else
198 
199   /* Catch pointer issues sooner: force relocation and make sure that the
200      original buffer is wiped. */
201 
202   ret = malloc(size + ALLOC_OFF_TOTAL);
203   ALLOC_CHECK_RESULT(ret, size);
204 
205   if (orig) {
206 
207     memcpy(ret + ALLOC_OFF_HEAD, orig + ALLOC_OFF_HEAD, MIN(size, old_size));
208     memset(orig + ALLOC_OFF_HEAD, 0xFF, old_size);
209 
210     ALLOC_C1(orig + ALLOC_OFF_HEAD) = ALLOC_MAGIC_F;
211 
212     free(orig);
213 
214   }
215 
216 #endif /* ^!DEBUG_BUILD */
217 
218   ret += ALLOC_OFF_HEAD;
219 
220   ALLOC_C1(ret) = ALLOC_MAGIC_C1;
221   ALLOC_S(ret)  = size;
222   ALLOC_C2(ret) = ALLOC_MAGIC_C2;
223 
224   if (size > old_size)
225     memset(ret + old_size, 0, size - old_size);
226 
227   return ret;
228 
229 }
230 
231 
232 /* Re-allocate a buffer with ALLOC_BLK_INC increments (used to speed up
233    repeated small reallocs without complicating the user code). */
234 
DFL_ck_realloc_block(void * orig,u32 size)235 static inline void* DFL_ck_realloc_block(void* orig, u32 size) {
236 
237 #ifndef DEBUG_BUILD
238 
239   if (orig) {
240 
241     CHECK_PTR(orig);
242 
243     if (ALLOC_S(orig) >= size) return orig;
244 
245     size += ALLOC_BLK_INC;
246 
247   }
248 
249 #endif /* !DEBUG_BUILD */
250 
251   return DFL_ck_realloc(orig, size);
252 
253 }
254 
255 
256 /* Create a buffer with a copy of a string. Returns NULL for NULL inputs. */
257 
DFL_ck_strdup(u8 * str)258 static inline u8* DFL_ck_strdup(u8* str) {
259 
260   void* ret;
261   u32   size;
262 
263   if (!str) return NULL;
264 
265   size = strlen((char*)str) + 1;
266 
267   ALLOC_CHECK_SIZE(size);
268   ret = malloc(size + ALLOC_OFF_TOTAL);
269   ALLOC_CHECK_RESULT(ret, size);
270 
271   ret += ALLOC_OFF_HEAD;
272 
273   ALLOC_C1(ret) = ALLOC_MAGIC_C1;
274   ALLOC_S(ret)  = size;
275   ALLOC_C2(ret) = ALLOC_MAGIC_C2;
276 
277   return memcpy(ret, str, size);
278 
279 }
280 
281 
282 /* Create a buffer with a copy of a memory block. Returns NULL for zero-sized
283    or NULL inputs. */
284 
DFL_ck_memdup(void * mem,u32 size)285 static inline void* DFL_ck_memdup(void* mem, u32 size) {
286 
287   void* ret;
288 
289   if (!mem || !size) return NULL;
290 
291   ALLOC_CHECK_SIZE(size);
292   ret = malloc(size + ALLOC_OFF_TOTAL);
293   ALLOC_CHECK_RESULT(ret, size);
294 
295   ret += ALLOC_OFF_HEAD;
296 
297   ALLOC_C1(ret) = ALLOC_MAGIC_C1;
298   ALLOC_S(ret)  = size;
299   ALLOC_C2(ret) = ALLOC_MAGIC_C2;
300 
301   return memcpy(ret, mem, size);
302 
303 }
304 
305 
306 /* Create a buffer with a block of text, appending a NUL terminator at the end.
307    Returns NULL for zero-sized or NULL inputs. */
308 
DFL_ck_memdup_str(u8 * mem,u32 size)309 static inline u8* DFL_ck_memdup_str(u8* mem, u32 size) {
310 
311   u8* ret;
312 
313   if (!mem || !size) return NULL;
314 
315   ALLOC_CHECK_SIZE(size);
316   ret = malloc(size + ALLOC_OFF_TOTAL + 1);
317   ALLOC_CHECK_RESULT(ret, size);
318 
319   ret += ALLOC_OFF_HEAD;
320 
321   ALLOC_C1(ret) = ALLOC_MAGIC_C1;
322   ALLOC_S(ret)  = size;
323   ALLOC_C2(ret) = ALLOC_MAGIC_C2;
324 
325   memcpy(ret, mem, size);
326   ret[size] = 0;
327 
328   return ret;
329 
330 }
331 
332 
333 #ifndef DEBUG_BUILD
334 
335 /* In non-debug mode, we just do straightforward aliasing of the above functions
336    to user-visible names such as ck_alloc(). */
337 
338 #define ck_alloc          DFL_ck_alloc
339 #define ck_alloc_nozero   DFL_ck_alloc_nozero
340 #define ck_realloc        DFL_ck_realloc
341 #define ck_realloc_block  DFL_ck_realloc_block
342 #define ck_strdup         DFL_ck_strdup
343 #define ck_memdup         DFL_ck_memdup
344 #define ck_memdup_str     DFL_ck_memdup_str
345 #define ck_free           DFL_ck_free
346 
347 #define alloc_report()
348 
349 #else
350 
351 /* In debugging mode, we also track allocations to detect memory leaks, and the
352    flow goes through one more layer of indirection. */
353 
354 /* Alloc tracking data structures: */
355 
356 #define ALLOC_BUCKETS     4096
357 
358 struct TRK_obj {
359   void *ptr;
360   char *file, *func;
361   u32  line;
362 };
363 
364 #ifdef AFL_MAIN
365 
366 struct TRK_obj* TRK[ALLOC_BUCKETS];
367 u32 TRK_cnt[ALLOC_BUCKETS];
368 
369 #  define alloc_report() TRK_report()
370 
371 #else
372 
373 extern struct TRK_obj* TRK[ALLOC_BUCKETS];
374 extern u32 TRK_cnt[ALLOC_BUCKETS];
375 
376 #  define alloc_report()
377 
378 #endif /* ^AFL_MAIN */
379 
380 /* Bucket-assigning function for a given pointer: */
381 
382 #define TRKH(_ptr) (((((u32)(_ptr)) >> 16) ^ ((u32)(_ptr))) % ALLOC_BUCKETS)
383 
384 
385 /* Add a new entry to the list of allocated objects. */
386 
TRK_alloc_buf(void * ptr,const char * file,const char * func,u32 line)387 static inline void TRK_alloc_buf(void* ptr, const char* file, const char* func,
388                                  u32 line) {
389 
390   u32 i, bucket;
391 
392   if (!ptr) return;
393 
394   bucket = TRKH(ptr);
395 
396   /* Find a free slot in the list of entries for that bucket. */
397 
398   for (i = 0; i < TRK_cnt[bucket]; i++)
399 
400     if (!TRK[bucket][i].ptr) {
401 
402       TRK[bucket][i].ptr  = ptr;
403       TRK[bucket][i].file = (char*)file;
404       TRK[bucket][i].func = (char*)func;
405       TRK[bucket][i].line = line;
406       return;
407 
408     }
409 
410   /* No space available - allocate more. */
411 
412   TRK[bucket] = DFL_ck_realloc_block(TRK[bucket],
413     (TRK_cnt[bucket] + 1) * sizeof(struct TRK_obj));
414 
415   TRK[bucket][i].ptr  = ptr;
416   TRK[bucket][i].file = (char*)file;
417   TRK[bucket][i].func = (char*)func;
418   TRK[bucket][i].line = line;
419 
420   TRK_cnt[bucket]++;
421 
422 }
423 
424 
425 /* Remove entry from the list of allocated objects. */
426 
TRK_free_buf(void * ptr,const char * file,const char * func,u32 line)427 static inline void TRK_free_buf(void* ptr, const char* file, const char* func,
428                                 u32 line) {
429 
430   u32 i, bucket;
431 
432   if (!ptr) return;
433 
434   bucket = TRKH(ptr);
435 
436   /* Find the element on the list... */
437 
438   for (i = 0; i < TRK_cnt[bucket]; i++)
439 
440     if (TRK[bucket][i].ptr == ptr) {
441 
442       TRK[bucket][i].ptr = 0;
443       return;
444 
445     }
446 
447   WARNF("ALLOC: Attempt to free non-allocated memory in %s (%s:%u)",
448         func, file, line);
449 
450 }
451 
452 
453 /* Do a final report on all non-deallocated objects. */
454 
TRK_report(void)455 static inline void TRK_report(void) {
456 
457   u32 i, bucket;
458 
459   fflush(0);
460 
461   for (bucket = 0; bucket < ALLOC_BUCKETS; bucket++)
462     for (i = 0; i < TRK_cnt[bucket]; i++)
463       if (TRK[bucket][i].ptr)
464         WARNF("ALLOC: Memory never freed, created in %s (%s:%u)",
465               TRK[bucket][i].func, TRK[bucket][i].file, TRK[bucket][i].line);
466 
467 }
468 
469 
470 /* Simple wrappers for non-debugging functions: */
471 
TRK_ck_alloc(u32 size,const char * file,const char * func,u32 line)472 static inline void* TRK_ck_alloc(u32 size, const char* file, const char* func,
473                                  u32 line) {
474 
475   void* ret = DFL_ck_alloc(size);
476   TRK_alloc_buf(ret, file, func, line);
477   return ret;
478 
479 }
480 
481 
TRK_ck_realloc(void * orig,u32 size,const char * file,const char * func,u32 line)482 static inline void* TRK_ck_realloc(void* orig, u32 size, const char* file,
483                                    const char* func, u32 line) {
484 
485   void* ret = DFL_ck_realloc(orig, size);
486   TRK_free_buf(orig, file, func, line);
487   TRK_alloc_buf(ret, file, func, line);
488   return ret;
489 
490 }
491 
492 
TRK_ck_realloc_block(void * orig,u32 size,const char * file,const char * func,u32 line)493 static inline void* TRK_ck_realloc_block(void* orig, u32 size, const char* file,
494                                          const char* func, u32 line) {
495 
496   void* ret = DFL_ck_realloc_block(orig, size);
497   TRK_free_buf(orig, file, func, line);
498   TRK_alloc_buf(ret, file, func, line);
499   return ret;
500 
501 }
502 
503 
TRK_ck_strdup(u8 * str,const char * file,const char * func,u32 line)504 static inline void* TRK_ck_strdup(u8* str, const char* file, const char* func,
505                                   u32 line) {
506 
507   void* ret = DFL_ck_strdup(str);
508   TRK_alloc_buf(ret, file, func, line);
509   return ret;
510 
511 }
512 
513 
TRK_ck_memdup(void * mem,u32 size,const char * file,const char * func,u32 line)514 static inline void* TRK_ck_memdup(void* mem, u32 size, const char* file,
515                                   const char* func, u32 line) {
516 
517   void* ret = DFL_ck_memdup(mem, size);
518   TRK_alloc_buf(ret, file, func, line);
519   return ret;
520 
521 }
522 
523 
TRK_ck_memdup_str(void * mem,u32 size,const char * file,const char * func,u32 line)524 static inline void* TRK_ck_memdup_str(void* mem, u32 size, const char* file,
525                                       const char* func, u32 line) {
526 
527   void* ret = DFL_ck_memdup_str(mem, size);
528   TRK_alloc_buf(ret, file, func, line);
529   return ret;
530 
531 }
532 
533 
TRK_ck_free(void * ptr,const char * file,const char * func,u32 line)534 static inline void TRK_ck_free(void* ptr, const char* file,
535                                 const char* func, u32 line) {
536 
537   TRK_free_buf(ptr, file, func, line);
538   DFL_ck_free(ptr);
539 
540 }
541 
542 /* Aliasing user-facing names to tracking functions: */
543 
544 #define ck_alloc(_p1) \
545   TRK_ck_alloc(_p1, __FILE__, __FUNCTION__, __LINE__)
546 
547 #define ck_alloc_nozero(_p1) \
548   TRK_ck_alloc(_p1, __FILE__, __FUNCTION__, __LINE__)
549 
550 #define ck_realloc(_p1, _p2) \
551   TRK_ck_realloc(_p1, _p2, __FILE__, __FUNCTION__, __LINE__)
552 
553 #define ck_realloc_block(_p1, _p2) \
554   TRK_ck_realloc_block(_p1, _p2, __FILE__, __FUNCTION__, __LINE__)
555 
556 #define ck_strdup(_p1) \
557   TRK_ck_strdup(_p1, __FILE__, __FUNCTION__, __LINE__)
558 
559 #define ck_memdup(_p1, _p2) \
560   TRK_ck_memdup(_p1, _p2, __FILE__, __FUNCTION__, __LINE__)
561 
562 #define ck_memdup_str(_p1, _p2) \
563   TRK_ck_memdup_str(_p1, _p2, __FILE__, __FUNCTION__, __LINE__)
564 
565 #define ck_free(_p1) \
566   TRK_ck_free(_p1, __FILE__, __FUNCTION__, __LINE__)
567 
568 #endif /* ^!DEBUG_BUILD */
569 
570 #endif /* ! _HAVE_ALLOC_INL_H */
571