xref: /aosp_15_r20/cts/tests/aslr/src/AslrMallocTest.cpp (revision b7c941bb3fa97aba169d73cee0bed2de8ac964bf)
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