asan_interceptors.cc revision de496f451bce322b6cde100456591f1f50ab3477
1//===-- asan_interceptors.cc ------------------------------------*- C++ -*-===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file is a part of AddressSanitizer, an address sanity checker.
11//
12// Intercept various libc functions to catch buggy memory accesses there.
13//===----------------------------------------------------------------------===//
14#include "asan_interceptors.h"
15
16#include "asan_allocator.h"
17#include "asan_interface.h"
18#include "asan_internal.h"
19#include "asan_mapping.h"
20#include "asan_stack.h"
21#include "asan_stats.h"
22
23#include <ctype.h>
24#include <dlfcn.h>
25#include <string.h>
26#include <strings.h>
27
28namespace __asan {
29
30index_f       real_index;
31memcmp_f      real_memcmp;
32memcpy_f      real_memcpy;
33memmove_f     real_memmove;
34memset_f      real_memset;
35strcasecmp_f  real_strcasecmp;
36strcat_f      real_strcat;
37strchr_f      real_strchr;
38strcmp_f      real_strcmp;
39strcpy_f      real_strcpy;
40strdup_f      real_strdup;
41strlen_f      real_strlen;
42strncasecmp_f real_strncasecmp;
43strncmp_f     real_strncmp;
44strncpy_f     real_strncpy;
45strnlen_f     real_strnlen;
46
47// Instruments read/write access to a single byte in memory.
48// On error calls __asan_report_error, which aborts the program.
49__attribute__((noinline))
50static void AccessAddress(uintptr_t address, bool isWrite) {
51  if (__asan_address_is_poisoned((void*)address)) {
52    GET_BP_PC_SP;
53    __asan_report_error(pc, bp, sp, address, isWrite, /* access_size */ 1);
54  }
55}
56
57// We implement ACCESS_MEMORY_RANGE, ASAN_READ_RANGE,
58// and ASAN_WRITE_RANGE as macro instead of function so
59// that no extra frames are created, and stack trace contains
60// relevant information only.
61
62// Instruments read/write access to a memory range.
63// More complex implementation is possible, for now just
64// checking the first and the last byte of a range.
65#define ACCESS_MEMORY_RANGE(offset, size, isWrite) do { \
66  if (size > 0) { \
67    uintptr_t ptr = (uintptr_t)(offset); \
68    AccessAddress(ptr, isWrite); \
69    AccessAddress(ptr + (size) - 1, isWrite); \
70  } \
71} while (0)
72
73#define ASAN_READ_RANGE(offset, size) do { \
74  ACCESS_MEMORY_RANGE(offset, size, false); \
75} while (0)
76
77#define ASAN_WRITE_RANGE(offset, size) do { \
78  ACCESS_MEMORY_RANGE(offset, size, true); \
79} while (0)
80
81// Behavior of functions like "memcpy" or "strcpy" is undefined
82// if memory intervals overlap. We report error in this case.
83// Macro is used to avoid creation of new frames.
84static inline bool RangesOverlap(const char *offset1, size_t length1,
85                                 const char *offset2, size_t length2) {
86  return !((offset1 + length1 <= offset2) || (offset2 + length2 <= offset1));
87}
88#define CHECK_RANGES_OVERLAP(name, _offset1, length1, _offset2, length2) do { \
89  const char *offset1 = (const char*)_offset1; \
90  const char *offset2 = (const char*)_offset2; \
91  if (RangesOverlap(offset1, length1, offset2, length2)) { \
92    Report("ERROR: AddressSanitizer %s-param-overlap: " \
93           "memory ranges [%p,%p) and [%p, %p) overlap\n", \
94           name, offset1, offset1 + length1, offset2, offset2 + length2); \
95    PRINT_CURRENT_STACK(); \
96    ShowStatsAndAbort(); \
97  } \
98} while (0)
99
100#define ENSURE_ASAN_INITED() do { \
101  CHECK(!asan_init_is_running); \
102  if (!asan_inited) { \
103    __asan_init(); \
104  } \
105} while (0)
106
107size_t internal_strlen(const char *s) {
108  size_t i = 0;
109  while (s[i]) i++;
110  return i;
111}
112
113size_t internal_strnlen(const char *s, size_t maxlen) {
114  if (real_strnlen != NULL) {
115    return real_strnlen(s, maxlen);
116  }
117  size_t i = 0;
118  while (i < maxlen && s[i]) i++;
119  return i;
120}
121
122void* internal_memchr(const void* s, int c, size_t n) {
123  const char* t = (char*)s;
124  for (size_t i = 0; i < n; ++i, ++t)
125    if (*t == c)
126      return (void*)t;
127  return NULL;
128}
129
130int internal_memcmp(const void* s1, const void* s2, size_t n) {
131  const char* t1 = (char*)s1;
132  const char* t2 = (char*)s2;
133  for (size_t i = 0; i < n; ++i, ++t1, ++t2)
134    if (*t1 != *t2)
135      return *t1 < *t2 ? -1 : 1;
136  return 0;
137}
138
139void InitializeAsanInterceptors() {
140#ifndef __APPLE__
141  INTERCEPT_FUNCTION(index);
142#else
143  OVERRIDE_FUNCTION(index, WRAP(strchr));
144#endif
145  INTERCEPT_FUNCTION(memcmp);
146  INTERCEPT_FUNCTION(memcpy);
147  INTERCEPT_FUNCTION(memmove);
148  INTERCEPT_FUNCTION(memset);
149  INTERCEPT_FUNCTION(strcasecmp);
150  INTERCEPT_FUNCTION(strcat);  // NOLINT
151  INTERCEPT_FUNCTION(strchr);
152  INTERCEPT_FUNCTION(strcmp);
153  INTERCEPT_FUNCTION(strcpy);  // NOLINT
154  INTERCEPT_FUNCTION(strdup);
155  INTERCEPT_FUNCTION(strlen);
156  INTERCEPT_FUNCTION(strncasecmp);
157  INTERCEPT_FUNCTION(strncmp);
158  INTERCEPT_FUNCTION(strncpy);
159#ifndef __APPLE__
160  INTERCEPT_FUNCTION(strnlen);
161#endif
162  if (FLAG_v > 0) {
163    Printf("AddressSanitizer: libc interceptors initialized\n");
164  }
165}
166
167}  // namespace __asan
168
169// ---------------------- Wrappers ---------------- {{{1
170using namespace __asan;  // NOLINT
171
172static inline int CharCmp(unsigned char c1, unsigned char c2) {
173  return (c1 == c2) ? 0 : (c1 < c2) ? -1 : 1;
174}
175
176static inline int CharCaseCmp(unsigned char c1, unsigned char c2) {
177  int c1_low = tolower(c1);
178  int c2_low = tolower(c2);
179  return c1_low - c2_low;
180}
181
182int WRAP(memcmp)(const void *a1, const void *a2, size_t size) {
183  ENSURE_ASAN_INITED();
184  unsigned char c1 = 0, c2 = 0;
185  const unsigned char *s1 = (const unsigned char*)a1;
186  const unsigned char *s2 = (const unsigned char*)a2;
187  size_t i;
188  for (i = 0; i < size; i++) {
189    c1 = s1[i];
190    c2 = s2[i];
191    if (c1 != c2) break;
192  }
193  ASAN_READ_RANGE(s1, Min(i + 1, size));
194  ASAN_READ_RANGE(s2, Min(i + 1, size));
195  return CharCmp(c1, c2);
196}
197
198void *WRAP(memcpy)(void *to, const void *from, size_t size) {
199  // memcpy is called during __asan_init() from the internals
200  // of printf(...).
201  if (asan_init_is_running) {
202    return real_memcpy(to, from, size);
203  }
204  ENSURE_ASAN_INITED();
205  if (FLAG_replace_intrin) {
206    CHECK_RANGES_OVERLAP("memcpy", to, size, from, size);
207    ASAN_WRITE_RANGE(from, size);
208    ASAN_READ_RANGE(to, size);
209  }
210  return real_memcpy(to, from, size);
211}
212
213void *WRAP(memmove)(void *to, const void *from, size_t size) {
214  ENSURE_ASAN_INITED();
215  if (FLAG_replace_intrin) {
216    ASAN_WRITE_RANGE(from, size);
217    ASAN_READ_RANGE(to, size);
218  }
219  return real_memmove(to, from, size);
220}
221
222void *WRAP(memset)(void *block, int c, size_t size) {
223  // memset is called inside INTERCEPT_FUNCTION on Mac.
224  if (asan_init_is_running) {
225    return real_memset(block, c, size);
226  }
227  ENSURE_ASAN_INITED();
228  if (FLAG_replace_intrin) {
229    ASAN_WRITE_RANGE(block, size);
230  }
231  return real_memset(block, c, size);
232}
233
234// Note that on Linux index and strchr are definined differently depending on
235// the compiler (gcc vs clang).
236// see __CORRECT_ISO_CPP_STRING_H_PROTO in /usr/include/string.h
237
238#ifndef __APPLE__
239char *WRAP(index)(const char *str, int c)
240  __attribute__((alias(WRAPPER_NAME(strchr))));
241#endif
242
243char *WRAP(strchr)(const char *str, int c) {
244  ENSURE_ASAN_INITED();
245  char *result = real_strchr(str, c);
246  if (FLAG_replace_str) {
247    size_t bytes_read = (result ? result - str : real_strlen(str)) + 1;
248    ASAN_READ_RANGE(str, bytes_read);
249  }
250  return result;
251}
252
253int WRAP(strcasecmp)(const char *s1, const char *s2) {
254  ENSURE_ASAN_INITED();
255  unsigned char c1, c2;
256  size_t i;
257  for (i = 0; ; i++) {
258    c1 = (unsigned char)s1[i];
259    c2 = (unsigned char)s2[i];
260    if (CharCaseCmp(c1, c2) != 0 || c1 == '\0') break;
261  }
262  ASAN_READ_RANGE(s1, i + 1);
263  ASAN_READ_RANGE(s2, i + 1);
264  return CharCaseCmp(c1, c2);
265}
266
267char *WRAP(strcat)(char *to, const char *from) {  // NOLINT
268  ENSURE_ASAN_INITED();
269  if (FLAG_replace_str) {
270    size_t from_length = real_strlen(from);
271    ASAN_READ_RANGE(from, from_length + 1);
272    if (from_length > 0) {
273      size_t to_length = real_strlen(to);
274      ASAN_READ_RANGE(to, to_length);
275      ASAN_WRITE_RANGE(to + to_length, from_length + 1);
276      CHECK_RANGES_OVERLAP("strcat", to, to_length + 1, from, from_length + 1);
277    }
278  }
279  return real_strcat(to, from);
280}
281
282int WRAP(strcmp)(const char *s1, const char *s2) {
283  // strcmp is called from malloc_default_purgeable_zone()
284  // in __asan::ReplaceSystemAlloc() on Mac.
285  if (asan_init_is_running) {
286    return real_strcmp(s1, s2);
287  }
288  unsigned char c1, c2;
289  size_t i;
290  for (i = 0; ; i++) {
291    c1 = (unsigned char)s1[i];
292    c2 = (unsigned char)s2[i];
293    if (c1 != c2 || c1 == '\0') break;
294  }
295  ASAN_READ_RANGE(s1, i + 1);
296  ASAN_READ_RANGE(s2, i + 1);
297  return CharCmp(c1, c2);
298}
299
300char *WRAP(strcpy)(char *to, const char *from) {  // NOLINT
301  // strcpy is called from malloc_default_purgeable_zone()
302  // in __asan::ReplaceSystemAlloc() on Mac.
303  if (asan_init_is_running) {
304    return real_strcpy(to, from);
305  }
306  ENSURE_ASAN_INITED();
307  if (FLAG_replace_str) {
308    size_t from_size = real_strlen(from) + 1;
309    CHECK_RANGES_OVERLAP("strcpy", to, from_size, from, from_size);
310    ASAN_READ_RANGE(from, from_size);
311    ASAN_WRITE_RANGE(to, from_size);
312  }
313  return real_strcpy(to, from);
314}
315
316char *WRAP(strdup)(const char *s) {
317  ENSURE_ASAN_INITED();
318  if (FLAG_replace_str) {
319    size_t length = real_strlen(s);
320    ASAN_READ_RANGE(s, length + 1);
321  }
322  return real_strdup(s);
323}
324
325size_t WRAP(strlen)(const char *s) {
326  // strlen is called from malloc_default_purgeable_zone()
327  // in __asan::ReplaceSystemAlloc() on Mac.
328  if (asan_init_is_running) {
329    return real_strlen(s);
330  }
331  ENSURE_ASAN_INITED();
332  size_t length = real_strlen(s);
333  if (FLAG_replace_str) {
334    ASAN_READ_RANGE(s, length + 1);
335  }
336  return length;
337}
338
339int WRAP(strncasecmp)(const char *s1, const char *s2, size_t size) {
340  ENSURE_ASAN_INITED();
341  unsigned char c1 = 0, c2 = 0;
342  size_t i;
343  for (i = 0; i < size; i++) {
344    c1 = (unsigned char)s1[i];
345    c2 = (unsigned char)s2[i];
346    if (CharCaseCmp(c1, c2) != 0 || c1 == '\0') break;
347  }
348  ASAN_READ_RANGE(s1, Min(i + 1, size));
349  ASAN_READ_RANGE(s2, Min(i + 1, size));
350  return CharCaseCmp(c1, c2);
351}
352
353int WRAP(strncmp)(const char *s1, const char *s2, size_t size) {
354  // strncmp is called from malloc_default_purgeable_zone()
355  // in __asan::ReplaceSystemAlloc() on Mac.
356  if (asan_init_is_running) {
357    return real_strncmp(s1, s2, size);
358  }
359  unsigned char c1 = 0, c2 = 0;
360  size_t i;
361  for (i = 0; i < size; i++) {
362    c1 = (unsigned char)s1[i];
363    c2 = (unsigned char)s2[i];
364    if (c1 != c2 || c1 == '\0') break;
365  }
366  ASAN_READ_RANGE(s1, Min(i + 1, size));
367  ASAN_READ_RANGE(s2, Min(i + 1, size));
368  return CharCmp(c1, c2);
369}
370
371char *WRAP(strncpy)(char *to, const char *from, size_t size) {
372  ENSURE_ASAN_INITED();
373  if (FLAG_replace_str) {
374    size_t from_size = Min(size, internal_strnlen(from, size) + 1);
375    CHECK_RANGES_OVERLAP("strncpy", to, from_size, from, from_size);
376    ASAN_READ_RANGE(from, from_size);
377    ASAN_WRITE_RANGE(to, size);
378  }
379  return real_strncpy(to, from, size);
380}
381
382#ifndef __APPLE__
383size_t WRAP(strnlen)(const char *s, size_t maxlen) {
384  ENSURE_ASAN_INITED();
385  size_t length = real_strnlen(s, maxlen);
386  if (FLAG_replace_str) {
387    ASAN_READ_RANGE(s, Min(length + 1, maxlen));
388  }
389  return length;
390}
391#endif
392