1 //===-- asan_mem_test.cc --------------------------------------------------===//
2 //
3 // This file is distributed under the University of Illinois Open Source
4 // License. See LICENSE.TXT for details.
5 //
6 //===----------------------------------------------------------------------===//
7 //
8 // This file is a part of AddressSanitizer, an address sanity checker.
9 //
10 //===----------------------------------------------------------------------===//
11 #include "asan_test_utils.h"
12 
13 template<typename T>
MemSetOOBTestTemplate(size_t length)14 void MemSetOOBTestTemplate(size_t length) {
15   if (length == 0) return;
16   size_t size = Ident(sizeof(T) * length);
17   T *array = Ident((T*)malloc(size));
18   int element = Ident(42);
19   int zero = Ident(0);
20   void *(*MEMSET)(void *s, int c, size_t n) = Ident(memset);
21   // memset interval inside array
22   MEMSET(array, element, size);
23   MEMSET(array, element, size - 1);
24   MEMSET(array + length - 1, element, sizeof(T));
25   MEMSET(array, element, 1);
26 
27   // memset 0 bytes
28   MEMSET(array - 10, element, zero);
29   MEMSET(array - 1, element, zero);
30   MEMSET(array, element, zero);
31   MEMSET(array + length, 0, zero);
32   MEMSET(array + length + 1, 0, zero);
33 
34   // try to memset bytes to the right of array
35   EXPECT_DEATH(MEMSET(array, 0, size + 1),
36                RightOOBWriteMessage(0));
37   EXPECT_DEATH(MEMSET((char*)(array + length) - 1, element, 6),
38                RightOOBWriteMessage(0));
39   EXPECT_DEATH(MEMSET(array + 1, element, size + sizeof(T)),
40                RightOOBWriteMessage(0));
41   // whole interval is to the right
42   EXPECT_DEATH(MEMSET(array + length + 1, 0, 10),
43                RightOOBWriteMessage(sizeof(T)));
44 
45   // try to memset bytes to the left of array
46   EXPECT_DEATH(MEMSET((char*)array - 1, element, size),
47                LeftOOBWriteMessage(1));
48   EXPECT_DEATH(MEMSET((char*)array - 5, 0, 6),
49                LeftOOBWriteMessage(5));
50   if (length >= 100) {
51     // Large OOB, we find it only if the redzone is large enough.
52     EXPECT_DEATH(memset(array - 5, element, size + 5 * sizeof(T)),
53                  LeftOOBWriteMessage(5 * sizeof(T)));
54   }
55   // whole interval is to the left
56   EXPECT_DEATH(MEMSET(array - 2, 0, sizeof(T)),
57                LeftOOBWriteMessage(2 * sizeof(T)));
58 
59   // try to memset bytes both to the left & to the right
60   EXPECT_DEATH(MEMSET((char*)array - 2, element, size + 4),
61                LeftOOBWriteMessage(2));
62 
63   free(array);
64 }
65 
TEST(AddressSanitizer,MemSetOOBTest)66 TEST(AddressSanitizer, MemSetOOBTest) {
67   MemSetOOBTestTemplate<char>(100);
68   MemSetOOBTestTemplate<int>(5);
69   MemSetOOBTestTemplate<double>(256);
70   // We can test arrays of structres/classes here, but what for?
71 }
72 
73 // Try to allocate two arrays of 'size' bytes that are near each other.
74 // Strictly speaking we are not guaranteed to find such two pointers,
75 // but given the structure of asan's allocator we will.
AllocateTwoAdjacentArrays(char ** x1,char ** x2,size_t size)76 static bool AllocateTwoAdjacentArrays(char **x1, char **x2, size_t size) {
77   vector<uintptr_t> v;
78   bool res = false;
79   for (size_t i = 0; i < 1000U && !res; i++) {
80     v.push_back(reinterpret_cast<uintptr_t>(new char[size]));
81     if (i == 0) continue;
82     sort(v.begin(), v.end());
83     for (size_t j = 1; j < v.size(); j++) {
84       assert(v[j] > v[j-1]);
85       if ((size_t)(v[j] - v[j-1]) < size * 2) {
86         *x2 = reinterpret_cast<char*>(v[j]);
87         *x1 = reinterpret_cast<char*>(v[j-1]);
88         res = true;
89         break;
90       }
91     }
92   }
93 
94   for (size_t i = 0; i < v.size(); i++) {
95     char *p = reinterpret_cast<char *>(v[i]);
96     if (res && p == *x1) continue;
97     if (res && p == *x2) continue;
98     delete [] p;
99   }
100   return res;
101 }
102 
TEST(AddressSanitizer,LargeOOBInMemset)103 TEST(AddressSanitizer, LargeOOBInMemset) {
104   for (size_t size = 200; size < 100000; size += size / 2) {
105     char *x1, *x2;
106     if (!Ident(AllocateTwoAdjacentArrays)(&x1, &x2, size))
107       continue;
108     // fprintf(stderr, "  large oob memset: %p %p %zd\n", x1, x2, size);
109     // Do a memset on x1 with huge out-of-bound access that will end up in x2.
110     EXPECT_DEATH(Ident(memset)(x1, 0, size * 2),
111                  "is located 0 bytes to the right");
112     delete [] x1;
113     delete [] x2;
114     return;
115   }
116   assert(0 && "Did not find two adjacent malloc-ed pointers");
117 }
118 
119 // Same test for memcpy and memmove functions
120 template <typename T, class M>
MemTransferOOBTestTemplate(size_t length)121 void MemTransferOOBTestTemplate(size_t length) {
122   if (length == 0) return;
123   size_t size = Ident(sizeof(T) * length);
124   T *src = Ident((T*)malloc(size));
125   T *dest = Ident((T*)malloc(size));
126   int zero = Ident(0);
127 
128   // valid transfer of bytes between arrays
129   M::transfer(dest, src, size);
130   M::transfer(dest + 1, src, size - sizeof(T));
131   M::transfer(dest, src + length - 1, sizeof(T));
132   M::transfer(dest, src, 1);
133 
134   // transfer zero bytes
135   M::transfer(dest - 1, src, 0);
136   M::transfer(dest + length, src, zero);
137   M::transfer(dest, src - 1, zero);
138   M::transfer(dest, src, zero);
139 
140   // try to change mem to the right of dest
141   EXPECT_DEATH(M::transfer(dest + 1, src, size),
142                RightOOBWriteMessage(0));
143   EXPECT_DEATH(M::transfer((char*)(dest + length) - 1, src, 5),
144                RightOOBWriteMessage(0));
145 
146   // try to change mem to the left of dest
147   EXPECT_DEATH(M::transfer(dest - 2, src, size),
148                LeftOOBWriteMessage(2 * sizeof(T)));
149   EXPECT_DEATH(M::transfer((char*)dest - 3, src, 4),
150                LeftOOBWriteMessage(3));
151 
152   // try to access mem to the right of src
153   EXPECT_DEATH(M::transfer(dest, src + 2, size),
154                RightOOBReadMessage(0));
155   EXPECT_DEATH(M::transfer(dest, (char*)(src + length) - 3, 6),
156                RightOOBReadMessage(0));
157 
158   // try to access mem to the left of src
159   EXPECT_DEATH(M::transfer(dest, src - 1, size),
160                LeftOOBReadMessage(sizeof(T)));
161   EXPECT_DEATH(M::transfer(dest, (char*)src - 6, 7),
162                LeftOOBReadMessage(6));
163 
164   // Generally we don't need to test cases where both accessing src and writing
165   // to dest address to poisoned memory.
166 
167   T *big_src = Ident((T*)malloc(size * 2));
168   T *big_dest = Ident((T*)malloc(size * 2));
169   // try to change mem to both sides of dest
170   EXPECT_DEATH(M::transfer(dest - 1, big_src, size * 2),
171                LeftOOBWriteMessage(sizeof(T)));
172   // try to access mem to both sides of src
173   EXPECT_DEATH(M::transfer(big_dest, src - 2, size * 2),
174                LeftOOBReadMessage(2 * sizeof(T)));
175 
176   free(src);
177   free(dest);
178   free(big_src);
179   free(big_dest);
180 }
181 
182 class MemCpyWrapper {
183  public:
transfer(void * to,const void * from,size_t size)184   static void* transfer(void *to, const void *from, size_t size) {
185     return Ident(memcpy)(to, from, size);
186   }
187 };
188 
TEST(AddressSanitizer,MemCpyOOBTest)189 TEST(AddressSanitizer, MemCpyOOBTest) {
190   MemTransferOOBTestTemplate<char, MemCpyWrapper>(100);
191   MemTransferOOBTestTemplate<int, MemCpyWrapper>(1024);
192 }
193 
194 class MemMoveWrapper {
195  public:
transfer(void * to,const void * from,size_t size)196   static void* transfer(void *to, const void *from, size_t size) {
197     return Ident(memmove)(to, from, size);
198   }
199 };
200 
TEST(AddressSanitizer,MemMoveOOBTest)201 TEST(AddressSanitizer, MemMoveOOBTest) {
202   MemTransferOOBTestTemplate<char, MemMoveWrapper>(100);
203   MemTransferOOBTestTemplate<int, MemMoveWrapper>(1024);
204 }
205 
206 
TEST(AddressSanitizer,MemCmpOOBTest)207 TEST(AddressSanitizer, MemCmpOOBTest) {
208   size_t size = Ident(100);
209   char *s1 = MallocAndMemsetString(size);
210   char *s2 = MallocAndMemsetString(size);
211   // Normal memcmp calls.
212   Ident(memcmp(s1, s2, size));
213   Ident(memcmp(s1 + size - 1, s2 + size - 1, 1));
214   Ident(memcmp(s1 - 1, s2 - 1, 0));
215   // One of arguments points to not allocated memory.
216   EXPECT_DEATH(Ident(memcmp)(s1 - 1, s2, 1), LeftOOBReadMessage(1));
217   EXPECT_DEATH(Ident(memcmp)(s1, s2 - 1, 1), LeftOOBReadMessage(1));
218   EXPECT_DEATH(Ident(memcmp)(s1 + size, s2, 1), RightOOBReadMessage(0));
219   EXPECT_DEATH(Ident(memcmp)(s1, s2 + size, 1), RightOOBReadMessage(0));
220   // Hit unallocated memory and die.
221   EXPECT_DEATH(Ident(memcmp)(s1 + 1, s2 + 1, size), RightOOBReadMessage(0));
222   EXPECT_DEATH(Ident(memcmp)(s1 + size - 1, s2, 2), RightOOBReadMessage(0));
223   // Zero bytes are not terminators and don't prevent from OOB.
224   s1[size - 1] = '\0';
225   s2[size - 1] = '\0';
226   EXPECT_DEATH(Ident(memcmp)(s1, s2, size + 1), RightOOBReadMessage(0));
227 
228   // Even if the buffers differ in the first byte, we still assume that
229   // memcmp may access the whole buffer and thus reporting the overflow here:
230   s1[0] = 1;
231   s2[0] = 123;
232   EXPECT_DEATH(Ident(memcmp)(s1, s2, size + 1), RightOOBReadMessage(0));
233 
234   free(s1);
235   free(s2);
236 }
237 
238 
239 
240