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