1 /* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include <stdlib.h> 18 #include <string.h> 19 #include <sys/mman.h> 20 21 #include <gtest/gtest.h> 22 #include "buffer_tests.h" 23 #include "utils.h" 24 25 // For the comparison buffer tests, the maximum length to test for the 26 // miscompare checks. 27 #define MISCMP_MAX_LENGTH 512 28 29 #define FENCEPOST_LENGTH 8 30 31 static int g_single_aligns[][2] = { 32 // Both buffers at same alignment. 33 { 1, 0 }, 34 { 2, 0 }, 35 { 4, 0 }, 36 { 8, 0 }, 37 { 16, 0 }, 38 { 32, 0 }, 39 { 64, 0 }, 40 { 128, 0 }, 41 42 // General unaligned cases. 43 { 4, 1 }, 44 { 4, 2 }, 45 { 4, 3 }, 46 47 { 8, 1 }, 48 { 8, 2 }, 49 { 8, 3 }, 50 { 8, 4 }, 51 { 8, 5 }, 52 { 8, 6 }, 53 { 8, 7 }, 54 55 { 128, 1 }, 56 { 128, 4 }, 57 { 128, 8 }, 58 { 128, 12 }, 59 { 128, 16 }, 60 }; 61 62 static const size_t g_single_aligns_len = sizeof(g_single_aligns)/sizeof(int[2]); 63 64 // Set of multiple buffer alignment combinations to be used for string/memory 65 // testing routines. 66 static int g_double_aligns[][4] = { 67 // Both buffers at same alignment. 68 { 1, 0, 1, 0 }, 69 { 2, 0, 2, 0 }, 70 { 4, 0, 4, 0 }, 71 { 8, 0, 8, 0 }, 72 { 16, 0, 16, 0 }, 73 { 32, 0, 32, 0 }, 74 { 64, 0, 64, 0 }, 75 { 128, 0, 128, 0 }, 76 77 // Different word alignments between buffers. 78 { 8, 0, 4, 0 }, 79 { 4, 0, 8, 0 }, 80 { 16, 0, 4, 0 }, 81 { 4, 0, 16, 0 }, 82 83 // General unaligned cases. 84 { 4, 0, 4, 1 }, 85 { 4, 0, 4, 2 }, 86 { 4, 0, 4, 3 }, 87 88 { 4, 1, 4, 0 }, 89 { 4, 1, 4, 1 }, 90 { 4, 1, 4, 2 }, 91 { 4, 1, 4, 3 }, 92 93 { 4, 2, 4, 0 }, 94 { 4, 2, 4, 1 }, 95 { 4, 2, 4, 2 }, 96 { 4, 2, 4, 3 }, 97 98 { 4, 3, 4, 0 }, 99 { 4, 3, 4, 1 }, 100 { 4, 3, 4, 2 }, 101 { 4, 3, 4, 3 }, 102 103 { 8, 0, 8, 1 }, 104 { 8, 0, 8, 2 }, 105 { 8, 0, 8, 3 }, 106 { 8, 0, 8, 4 }, 107 { 8, 0, 8, 5 }, 108 { 8, 0, 8, 6 }, 109 { 8, 0, 8, 7 }, 110 111 { 8, 1, 8, 0 }, 112 { 8, 1, 8, 1 }, 113 { 8, 1, 8, 2 }, 114 { 8, 1, 8, 3 }, 115 { 8, 1, 8, 4 }, 116 { 8, 1, 8, 5 }, 117 { 8, 1, 8, 6 }, 118 { 8, 1, 8, 7 }, 119 120 { 8, 2, 8, 0 }, 121 { 8, 2, 8, 1 }, 122 { 8, 2, 8, 2 }, 123 { 8, 2, 8, 3 }, 124 { 8, 2, 8, 4 }, 125 { 8, 2, 8, 5 }, 126 { 8, 2, 8, 6 }, 127 { 8, 2, 8, 7 }, 128 129 { 8, 3, 8, 0 }, 130 { 8, 3, 8, 1 }, 131 { 8, 3, 8, 2 }, 132 { 8, 3, 8, 3 }, 133 { 8, 3, 8, 4 }, 134 { 8, 3, 8, 5 }, 135 { 8, 3, 8, 6 }, 136 { 8, 3, 8, 7 }, 137 138 { 8, 4, 8, 0 }, 139 { 8, 4, 8, 1 }, 140 { 8, 4, 8, 2 }, 141 { 8, 4, 8, 3 }, 142 { 8, 4, 8, 4 }, 143 { 8, 4, 8, 5 }, 144 { 8, 4, 8, 6 }, 145 { 8, 4, 8, 7 }, 146 147 { 8, 5, 8, 0 }, 148 { 8, 5, 8, 1 }, 149 { 8, 5, 8, 2 }, 150 { 8, 5, 8, 3 }, 151 { 8, 5, 8, 4 }, 152 { 8, 5, 8, 5 }, 153 { 8, 5, 8, 6 }, 154 { 8, 5, 8, 7 }, 155 156 { 8, 6, 8, 0 }, 157 { 8, 6, 8, 1 }, 158 { 8, 6, 8, 2 }, 159 { 8, 6, 8, 3 }, 160 { 8, 6, 8, 4 }, 161 { 8, 6, 8, 5 }, 162 { 8, 6, 8, 6 }, 163 { 8, 6, 8, 7 }, 164 165 { 8, 7, 8, 0 }, 166 { 8, 7, 8, 1 }, 167 { 8, 7, 8, 2 }, 168 { 8, 7, 8, 3 }, 169 { 8, 7, 8, 4 }, 170 { 8, 7, 8, 5 }, 171 { 8, 7, 8, 6 }, 172 { 8, 7, 8, 7 }, 173 174 { 128, 1, 128, 4 }, 175 { 128, 1, 128, 8 }, 176 { 128, 1, 128, 12 }, 177 { 128, 1, 128, 16 }, 178 { 128, 4, 128, 1 }, 179 { 128, 8, 128, 1 }, 180 { 128, 12, 128, 1 }, 181 { 128, 16, 128, 1 }, 182 }; 183 184 static const size_t g_double_aligns_len = sizeof(g_double_aligns)/sizeof(int[4]); 185 186 static size_t SetIncrement(size_t len) { 187 if (len >= 4096) { 188 return 1024; 189 } else if (len >= 1024) { 190 return 256; 191 } 192 return 1; 193 } 194 195 // Return a pointer into the current buffer with the specified alignment. 196 static void *GetAlignedPtr(void *orig_ptr, int alignment, int or_mask) { 197 uint64_t ptr = reinterpret_cast<uint64_t>(orig_ptr); 198 if (alignment > 0) { 199 // When setting the alignment, set it to exactly the alignment chosen. 200 // The pointer returned will be guaranteed not to be aligned to anything 201 // more than that. 202 ptr += alignment - (ptr & (alignment - 1)); 203 ptr |= alignment | or_mask; 204 } 205 206 return reinterpret_cast<void*>(ptr); 207 } 208 209 static void SetFencepost(uint8_t *buffer) { 210 for (int i = 0; i < FENCEPOST_LENGTH; i += 2) { 211 buffer[i] = 0xde; 212 buffer[i+1] = 0xad; 213 } 214 } 215 216 static void VerifyFencepost(uint8_t *buffer) { 217 for (int i = 0; i < FENCEPOST_LENGTH; i += 2) { 218 if (buffer[i] != 0xde || buffer[i+1] != 0xad) { 219 uint8_t expected_value; 220 if (buffer[i] == 0xde) { 221 i++; 222 expected_value = 0xad; 223 } else { 224 expected_value = 0xde; 225 } 226 ASSERT_EQ(expected_value, buffer[i]); 227 } 228 } 229 } 230 231 // Malloc can return a tagged pointer, which is not accepted in mm system calls like mprotect 232 // in the preliminary version of the syscall tagging support in the current Pixel 2 kernel. 233 // Note: the final version of the kernel patchset may relax this requirement. 234 static int MprotectHeap(void* addr, size_t len, int prot) { 235 return mprotect(untag_address(addr), len, prot); 236 } 237 238 void RunSingleBufferAlignTest( 239 size_t max_test_size, void (*test_func)(uint8_t*, size_t), 240 size_t (*set_incr)(size_t)) { 241 if (!set_incr) { 242 set_incr = SetIncrement; 243 } 244 245 // Allocate one large buffer with lots of extra space so that we can 246 // guarantee that the all possible alignments will fit. 247 uint8_t *buf = new uint8_t[3*max_test_size]; 248 249 uint8_t *buf_align; 250 for (size_t i = 0; i < g_single_aligns_len; i++) { 251 size_t incr = 1; 252 for (size_t len = 0; len <= max_test_size; len += incr) { 253 incr = set_incr(len); 254 255 buf_align = reinterpret_cast<uint8_t*>(GetAlignedPtr( 256 buf+FENCEPOST_LENGTH, g_single_aligns[i][0], g_single_aligns[i][1])); 257 258 SetFencepost(&buf_align[-FENCEPOST_LENGTH]); 259 SetFencepost(&buf_align[len]); 260 261 test_func(buf_align, len); 262 263 VerifyFencepost(&buf_align[-FENCEPOST_LENGTH]); 264 VerifyFencepost(&buf_align[len]); 265 } 266 } 267 delete[] buf; 268 } 269 270 void RunSrcDstBufferAlignTest( 271 size_t max_test_size, void (*test_func)(uint8_t*, uint8_t*, size_t), 272 size_t (*set_incr)(size_t)) { 273 if (!set_incr) { 274 set_incr = SetIncrement; 275 } 276 277 // Allocate two large buffers for all of the testing. 278 uint8_t* src = new uint8_t[3*max_test_size]; 279 uint8_t* dst = new uint8_t[3*max_test_size]; 280 281 uint8_t* src_align; 282 uint8_t* dst_align; 283 for (size_t i = 0; i < g_double_aligns_len; i++) { 284 size_t incr = 1; 285 for (size_t len = 0; len <= max_test_size; len += incr) { 286 incr = set_incr(len); 287 288 src_align = 289 reinterpret_cast<uint8_t*>(GetAlignedPtr( 290 src+FENCEPOST_LENGTH, g_double_aligns[i][0], g_double_aligns[i][1])); 291 dst_align = 292 reinterpret_cast<uint8_t*>(GetAlignedPtr( 293 dst+FENCEPOST_LENGTH, g_double_aligns[i][2], g_double_aligns[i][3])); 294 SetFencepost(&dst_align[-FENCEPOST_LENGTH]); 295 SetFencepost(&dst_align[len]); 296 297 test_func(src_align, dst_align, len); 298 299 VerifyFencepost(&dst_align[-FENCEPOST_LENGTH]); 300 VerifyFencepost(&dst_align[len]); 301 } 302 } 303 delete[] src; 304 delete[] dst; 305 } 306 307 void RunCmpBufferAlignTest( 308 size_t max_test_size, void (*test_cmp_func)(uint8_t*, uint8_t*, size_t), 309 void (*test_miscmp_func)(uint8_t*, uint8_t*, size_t, size_t), 310 size_t (*set_incr)(size_t)) { 311 if (!set_incr) { 312 set_incr = SetIncrement; 313 } 314 315 // Allocate two large buffers for all of the testing. 316 uint8_t* buf1 = new uint8_t[3*max_test_size]; 317 uint8_t* buf2 = new uint8_t[3*max_test_size]; 318 319 uint8_t* buf1_align; 320 uint8_t* buf2_align; 321 for (size_t i = 0; i < g_double_aligns_len; i++) { 322 size_t incr = 1; 323 for (size_t len = 0; len <= max_test_size; len += incr) { 324 incr = set_incr(len); 325 326 buf1_align = 327 reinterpret_cast<uint8_t*>(GetAlignedPtr( 328 buf1, g_double_aligns[i][0], g_double_aligns[i][1])); 329 buf2_align = 330 reinterpret_cast<uint8_t*>(GetAlignedPtr( 331 buf2, g_double_aligns[i][2], g_double_aligns[i][3])); 332 333 // Check by putting all zeroes after both buffers. 334 memset(buf1_align+len, 0, 32); 335 memset(buf2_align+len, 0, 32); 336 test_cmp_func(buf1_align, buf2_align, len); 337 338 // Check by putting different values after both buffers. 339 for (size_t j = 0; j < 32; j++) { 340 buf1_align[len+j] = j; 341 buf2_align[len+j] = j+1; 342 } 343 test_cmp_func(buf1_align, buf2_align, len); 344 345 if (len > 0) { 346 // Change the lengths of the buffers and verify that there are 347 // miscompares. 348 for (size_t len2 = len+1; len2 < len+32; len2++) { 349 test_miscmp_func(buf1_align, buf2_align, len, len2); 350 test_miscmp_func(buf1_align, buf2_align, len2, len); 351 } 352 } 353 } 354 } 355 delete[] buf1; 356 delete[] buf2; 357 } 358 359 void RunSingleBufferOverreadTest(void (*test_func)(uint8_t*, size_t)) { 360 // In order to verify that functions are not reading past the end of the 361 // src, create data that ends exactly at an unreadable memory boundary. 362 size_t pagesize = static_cast<size_t>(sysconf(_SC_PAGE_SIZE)); 363 uint8_t* memory; 364 ASSERT_TRUE(posix_memalign(reinterpret_cast<void**>(&memory), pagesize, 365 2*pagesize) == 0); 366 memset(memory, 0x23, 2*pagesize); 367 368 // Make the second page unreadable and unwritable. 369 ASSERT_TRUE(MprotectHeap(&memory[pagesize], pagesize, PROT_NONE) == 0); 370 371 for (size_t i = 0; i < pagesize; i++) { 372 uint8_t* buf = &memory[pagesize-i]; 373 374 test_func(buf, i); 375 } 376 ASSERT_TRUE(MprotectHeap(&memory[pagesize], pagesize, PROT_READ | PROT_WRITE) == 0); 377 free(memory); 378 } 379 380 void RunSrcDstBufferOverreadTest(void (*test_func)(uint8_t*, uint8_t*, size_t)) { 381 // In order to verify that functions are not reading past the end of the 382 // src, create data that ends exactly at an unreadable memory boundary. 383 size_t pagesize = static_cast<size_t>(sysconf(_SC_PAGE_SIZE)); 384 uint8_t* memory; 385 ASSERT_TRUE(posix_memalign(reinterpret_cast<void**>(&memory), pagesize, 386 2*pagesize) == 0); 387 memset(memory, 0x23, 2*pagesize); 388 389 // Make the second page unreadable and unwritable. 390 ASSERT_TRUE(MprotectHeap(&memory[pagesize], pagesize, PROT_NONE) == 0); 391 392 uint8_t* dst_buffer = new uint8_t[2*pagesize]; 393 // Change the dst alignment as we change the source. 394 for (size_t i = 0; i < 16; i++) { 395 uint8_t* dst = &dst_buffer[i]; 396 for (size_t j = 0; j < pagesize; j++) { 397 uint8_t* src = &memory[pagesize-j]; 398 399 test_func(src, dst, j); 400 } 401 } 402 ASSERT_TRUE(MprotectHeap(&memory[pagesize], pagesize, PROT_READ | PROT_WRITE) == 0); 403 free(memory); 404 delete[] dst_buffer; 405 } 406 407 void RunCmpBufferOverreadTest( 408 void (*test_cmp_func)(uint8_t*, uint8_t*, size_t), 409 void (*test_miscmp_func)(uint8_t*, uint8_t*, size_t, size_t)) { 410 // In order to verify that functions are not reading past the end of either 411 // of the bufs, create both buffers that end exactly at an unreadable memory 412 // boundary. 413 size_t pagesize = static_cast<size_t>(sysconf(_SC_PAGE_SIZE)); 414 uint8_t* memory1; 415 ASSERT_TRUE(posix_memalign(reinterpret_cast<void**>(&memory1), pagesize, 416 2*pagesize) == 0); 417 memset(memory1, 0x23, 2*pagesize); 418 419 // Make the second page unreadable and unwritable. 420 ASSERT_TRUE(MprotectHeap(&memory1[pagesize], pagesize, PROT_NONE) == 0); 421 422 uint8_t* memory2; 423 ASSERT_TRUE(posix_memalign(reinterpret_cast<void**>(&memory2), pagesize, 424 2*pagesize) == 0); 425 memset(memory2, 0x23, 2*pagesize); 426 427 // Make the second page unreadable and unwritable. 428 ASSERT_TRUE(MprotectHeap(&memory2[pagesize], pagesize, PROT_NONE) == 0); 429 430 for (size_t i = 0; i < pagesize; i++) { 431 uint8_t* buf1 = &memory1[pagesize-i]; 432 uint8_t* buf2 = &memory2[pagesize-i]; 433 434 test_cmp_func(buf1, buf2, i); 435 } 436 437 // Don't cycle through pagesize, MISCMP_MAX_LENGTH bytes should be good. 438 size_t miscmp_len; 439 if (pagesize > MISCMP_MAX_LENGTH) { 440 miscmp_len = MISCMP_MAX_LENGTH; 441 } else { 442 miscmp_len = pagesize; 443 } 444 for (size_t i = 1; i < miscmp_len; i++) { 445 uint8_t* buf1 = &memory1[pagesize-i]; 446 for (size_t j = 1; j < miscmp_len; j++) { 447 if (j == i) 448 continue; 449 450 uint8_t* buf2 = &memory2[pagesize-j]; 451 452 test_miscmp_func(buf1, buf2, i, j); 453 } 454 } 455 456 ASSERT_TRUE(MprotectHeap(&memory1[pagesize], pagesize, PROT_READ | PROT_WRITE) == 0); 457 ASSERT_TRUE(MprotectHeap(&memory2[pagesize], pagesize, PROT_READ | PROT_WRITE) == 0); 458 free(memory1); 459 free(memory2); 460 } 461