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