1 /* 2 * Copyright (C) 2015 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 #define LOG_NDEBUG 0 18 #define LOG_TAG "AslrMallocTest" 19 20 #include <android-base/file.h> 21 #include <android-base/parseint.h> 22 #include <android-base/stringprintf.h> 23 #include <android-base/strings.h> 24 #include <linux/limits.h> 25 #include <math.h> 26 #include <stdint.h> 27 #include <stdio.h> 28 #include <sys/types.h> 29 #include <sys/wait.h> 30 #include <unistd.h> 31 #include <unordered_set> 32 33 #include <gtest/gtest.h> 34 #include <string> 35 #include <utils/Log.h> 36 37 /* minimum entropy for malloc return addresses */ 38 const size_t minEntropyBits = 8; 39 40 /* test using the following allocation sizes */ 41 const size_t allocSizes[] = { 42 1 << 8, // small 43 1 << 16, // large 44 1 << 23 // huge 45 }; 46 47 /* when started using this argument followed by the allocation size, 48 * performs malloc(size) and prints out the address */ 49 static const std::string argPrint = "--print-malloc-address"; 50 51 class AslrMallocTest : public ::testing::Test 52 { 53 protected: 54 std::string self_; 55 56 AslrMallocTest() {} 57 virtual ~AslrMallocTest() {} 58 59 virtual void SetUp() 60 { 61 /* path to self for exec */ 62 char path[PATH_MAX]; 63 auto size = readlink("/proc/self/exe", path, sizeof(path)); 64 ASSERT_TRUE(size > 0 && size < PATH_MAX); 65 path[size] = '\0'; 66 self_ = path; 67 } 68 69 void GetAddress(size_t allocSize, uintptr_t& address) 70 { 71 int fds[2]; 72 ASSERT_TRUE(pipe(fds) != -1); 73 74 auto pid = fork(); 75 ASSERT_TRUE(pid != -1); 76 77 if (pid == 0) { 78 /* child process */ 79 ASSERT_TRUE(TEMP_FAILURE_RETRY(dup2(fds[1], STDOUT_FILENO)) != -1); 80 81 for (auto fd : fds) { 82 TEMP_FAILURE_RETRY(close(fd)); 83 } 84 85 /* exec self to print malloc output */ 86 ASSERT_TRUE(execl(self_.c_str(), self_.c_str(), argPrint.c_str(), 87 android::base::StringPrintf("%zu", allocSize).c_str(), 88 nullptr) != -1); 89 } 90 91 /* parent process */ 92 TEMP_FAILURE_RETRY(close(fds[1])); 93 94 std::string output; 95 ASSERT_TRUE(android::base::ReadFdToString(fds[0], &output)); 96 TEMP_FAILURE_RETRY(close(fds[0])); 97 98 int status; 99 ASSERT_TRUE(waitpid(pid, &status, 0) != -1); 100 ASSERT_TRUE(WEXITSTATUS(status) == EXIT_SUCCESS); 101 102 ASSERT_TRUE(android::base::ParseUint(output.c_str(), &address)); 103 } 104 105 void TestRandomization() 106 { 107 /* should be sufficient to see minEntropyBits when rounded up */ 108 size_t iterations = 2 * (1 << minEntropyBits); 109 110 for (auto size : allocSizes) { 111 ALOGV("running %zu iterations for allocation size %zu", 112 iterations, size); 113 114 /* collect unique return addresses */ 115 std::unordered_set<uintptr_t> addresses; 116 117 for (size_t i = 0; i < iterations; ++i) { 118 uintptr_t address; 119 GetAddress(size, address); 120 121 addresses.emplace(address); 122 } 123 124 size_t entropy = static_cast<size_t>(0.5 + 125 log2(static_cast<double>(addresses.size()))); 126 127 ALOGV("%zu bits of entropy for allocation size %zu (minimum %zu)", 128 entropy, size, minEntropyBits); 129 ALOGE_IF(entropy < minEntropyBits, 130 "insufficient entropy for malloc(%zu)", size); 131 ASSERT_TRUE(entropy >= minEntropyBits); 132 } 133 } 134 }; 135 136 TEST_F(AslrMallocTest, testMallocRandomization) { 137 TestRandomization(); 138 } 139 140 int main(int argc, char **argv) 141 { 142 if (argc == 3 && argPrint == argv[1]) { 143 size_t size; 144 145 if (!android::base::ParseUint(argv[2], &size)) { 146 return EXIT_FAILURE; 147 } 148 149 void* p = malloc(size); 150 printf("%p", p); 151 free(p); 152 return EXIT_SUCCESS; 153 } 154 155 testing::InitGoogleTest(&argc, argv); 156 return RUN_ALL_TESTS(); 157 } 158