xref: /aosp_15_r20/system/extras/tests/kernel.config/aslr_test.cpp (revision 288bf5226967eb3dac5cce6c939ccc2a7f2b4fe5)
1*288bf522SAndroid Build Coastguard Worker /*
2*288bf522SAndroid Build Coastguard Worker  * Copyright (C) 2016 The Android Open Source Project
3*288bf522SAndroid Build Coastguard Worker  *
4*288bf522SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*288bf522SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*288bf522SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*288bf522SAndroid Build Coastguard Worker  *
8*288bf522SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*288bf522SAndroid Build Coastguard Worker  *
10*288bf522SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*288bf522SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*288bf522SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*288bf522SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*288bf522SAndroid Build Coastguard Worker  * limitations under the License.
15*288bf522SAndroid Build Coastguard Worker  */
16*288bf522SAndroid Build Coastguard Worker 
17*288bf522SAndroid Build Coastguard Worker #include <ctype.h>
18*288bf522SAndroid Build Coastguard Worker 
19*288bf522SAndroid Build Coastguard Worker #include "aslr_test.h"
20*288bf522SAndroid Build Coastguard Worker 
get_mmap_rnd_bits(bool compat)21*288bf522SAndroid Build Coastguard Worker unsigned int get_mmap_rnd_bits(bool compat) {
22*288bf522SAndroid Build Coastguard Worker     std::string path;
23*288bf522SAndroid Build Coastguard Worker 
24*288bf522SAndroid Build Coastguard Worker     if (compat)
25*288bf522SAndroid Build Coastguard Worker         path = PROCFS_COMPAT_PATH;
26*288bf522SAndroid Build Coastguard Worker     else
27*288bf522SAndroid Build Coastguard Worker         path = PROCFS_PATH;
28*288bf522SAndroid Build Coastguard Worker 
29*288bf522SAndroid Build Coastguard Worker     std::ifstream bi_file(path);
30*288bf522SAndroid Build Coastguard Worker     if (!bi_file)
31*288bf522SAndroid Build Coastguard Worker         return false;
32*288bf522SAndroid Build Coastguard Worker     std::string str_rec;
33*288bf522SAndroid Build Coastguard Worker     bi_file >> str_rec;
34*288bf522SAndroid Build Coastguard Worker 
35*288bf522SAndroid Build Coastguard Worker     return stoi(str_rec);
36*288bf522SAndroid Build Coastguard Worker }
37*288bf522SAndroid Build Coastguard Worker 
set_mmap_rnd_bits(unsigned int new_val,bool compat)38*288bf522SAndroid Build Coastguard Worker bool set_mmap_rnd_bits(unsigned int new_val, bool compat) {
39*288bf522SAndroid Build Coastguard Worker     std::string path;
40*288bf522SAndroid Build Coastguard Worker 
41*288bf522SAndroid Build Coastguard Worker     if (compat)
42*288bf522SAndroid Build Coastguard Worker         path = "/proc/sys/vm/mmap_rnd_compat_bits";
43*288bf522SAndroid Build Coastguard Worker     else
44*288bf522SAndroid Build Coastguard Worker         path = "/proc/sys/vm/mmap_rnd_bits";
45*288bf522SAndroid Build Coastguard Worker 
46*288bf522SAndroid Build Coastguard Worker     std::ofstream bo_file(path, std::ios::out);
47*288bf522SAndroid Build Coastguard Worker     if (!bo_file)
48*288bf522SAndroid Build Coastguard Worker         return false;
49*288bf522SAndroid Build Coastguard Worker 
50*288bf522SAndroid Build Coastguard Worker     std::string str_val = std::to_string(new_val);
51*288bf522SAndroid Build Coastguard Worker     bo_file << str_val << std::flush;
52*288bf522SAndroid Build Coastguard Worker     bo_file.close();
53*288bf522SAndroid Build Coastguard Worker 
54*288bf522SAndroid Build Coastguard Worker     // check to make sure it was recorded
55*288bf522SAndroid Build Coastguard Worker     std::ifstream bi_file(path);
56*288bf522SAndroid Build Coastguard Worker     if (!bi_file)
57*288bf522SAndroid Build Coastguard Worker         return false;
58*288bf522SAndroid Build Coastguard Worker     std::string str_rec;
59*288bf522SAndroid Build Coastguard Worker     bi_file >> str_rec;
60*288bf522SAndroid Build Coastguard Worker     bi_file.close();
61*288bf522SAndroid Build Coastguard Worker     if (str_val.compare(str_rec) != 0)
62*288bf522SAndroid Build Coastguard Worker         return false;
63*288bf522SAndroid Build Coastguard Worker     return true;
64*288bf522SAndroid Build Coastguard Worker }
65*288bf522SAndroid Build Coastguard Worker 
scrape_addr(const char * exec_name,const char * lib_match)66*288bf522SAndroid Build Coastguard Worker std::string scrape_addr(const char *exec_name, const char *lib_match) {
67*288bf522SAndroid Build Coastguard Worker     pid_t pid;
68*288bf522SAndroid Build Coastguard Worker     int fd[2];
69*288bf522SAndroid Build Coastguard Worker     char buff[MAX_ADDR_LEN];
70*288bf522SAndroid Build Coastguard Worker     int len, status;
71*288bf522SAndroid Build Coastguard Worker     if(pipe(fd)) {
72*288bf522SAndroid Build Coastguard Worker         std::cerr << "Error creating pipe:" << strerror(errno) << "\n";
73*288bf522SAndroid Build Coastguard Worker         return std::string();
74*288bf522SAndroid Build Coastguard Worker     }
75*288bf522SAndroid Build Coastguard Worker 
76*288bf522SAndroid Build Coastguard Worker     if ((pid = fork()) < 0) {
77*288bf522SAndroid Build Coastguard Worker         std::cerr << "Error creating new process: " << strerror(errno) << "\n";
78*288bf522SAndroid Build Coastguard Worker         close(fd[0]);
79*288bf522SAndroid Build Coastguard Worker         close(fd[1]);
80*288bf522SAndroid Build Coastguard Worker         return std::string();
81*288bf522SAndroid Build Coastguard Worker     } else if (pid > 0) {
82*288bf522SAndroid Build Coastguard Worker         // parent
83*288bf522SAndroid Build Coastguard Worker         close(fd[1]);
84*288bf522SAndroid Build Coastguard Worker         wait(&status);
85*288bf522SAndroid Build Coastguard Worker         if (status == -1) {
86*288bf522SAndroid Build Coastguard Worker             std::cerr << "Unable to find starting address of mmapp'd libc. Aborting.\n";
87*288bf522SAndroid Build Coastguard Worker             close(fd[0]);
88*288bf522SAndroid Build Coastguard Worker             return std::string();
89*288bf522SAndroid Build Coastguard Worker         }
90*288bf522SAndroid Build Coastguard Worker         len = read(fd[0], buff, MAX_ADDR_LEN - 1);
91*288bf522SAndroid Build Coastguard Worker         if (len < 0) {
92*288bf522SAndroid Build Coastguard Worker             std::cerr << "Error reading pipe from child: " << strerror(errno) << "\n";
93*288bf522SAndroid Build Coastguard Worker             close(fd[0]);
94*288bf522SAndroid Build Coastguard Worker             return std::string();
95*288bf522SAndroid Build Coastguard Worker         }
96*288bf522SAndroid Build Coastguard Worker         buff[len] = '\0';
97*288bf522SAndroid Build Coastguard Worker         close(fd[0]);
98*288bf522SAndroid Build Coastguard Worker     } else {
99*288bf522SAndroid Build Coastguard Worker         // child, dup 'n' exec
100*288bf522SAndroid Build Coastguard Worker         close(fd[0]);
101*288bf522SAndroid Build Coastguard Worker         if(dup2(fd[1], STDOUT_FILENO) != STDOUT_FILENO) {
102*288bf522SAndroid Build Coastguard Worker             std::cerr << "Error dup'n pipe to STDOUT of child: " << strerror(errno) << "\n";
103*288bf522SAndroid Build Coastguard Worker             close(fd[1]);
104*288bf522SAndroid Build Coastguard Worker             return std::string();
105*288bf522SAndroid Build Coastguard Worker         }
106*288bf522SAndroid Build Coastguard Worker         if(execlp(exec_name, exec_name, lib_match, (char *) NULL)) {
107*288bf522SAndroid Build Coastguard Worker             std::cerr << "Error exec'ing mmap_scraper: " << strerror(errno) << "\n";
108*288bf522SAndroid Build Coastguard Worker             close(fd[1]);
109*288bf522SAndroid Build Coastguard Worker             return std::string();
110*288bf522SAndroid Build Coastguard Worker         }
111*288bf522SAndroid Build Coastguard Worker     }
112*288bf522SAndroid Build Coastguard Worker     return std::string(buff, strlen(buff));
113*288bf522SAndroid Build Coastguard Worker }
114*288bf522SAndroid Build Coastguard Worker 
calc_mmap_entropy(const char * exec_name,const char * lib_match,size_t samp_sz)115*288bf522SAndroid Build Coastguard Worker unsigned int calc_mmap_entropy(const char *exec_name, const char *lib_match, size_t samp_sz) {
116*288bf522SAndroid Build Coastguard Worker     uint64_t addr, min_addr, max_addr;
117*288bf522SAndroid Build Coastguard Worker 
118*288bf522SAndroid Build Coastguard Worker     std::unordered_set<uint64_t> addrs = { };
119*288bf522SAndroid Build Coastguard Worker 
120*288bf522SAndroid Build Coastguard Worker     // get our first value
121*288bf522SAndroid Build Coastguard Worker     std::string addr_str = scrape_addr(exec_name, lib_match);
122*288bf522SAndroid Build Coastguard Worker     if (addr_str.empty()) {
123*288bf522SAndroid Build Coastguard Worker         std::cerr << "empty first address";
124*288bf522SAndroid Build Coastguard Worker         return 0;
125*288bf522SAndroid Build Coastguard Worker     }
126*288bf522SAndroid Build Coastguard Worker     if (!isxdigit(addr_str[0])) {
127*288bf522SAndroid Build Coastguard Worker         std::cerr << "invalid address: " << addr_str;
128*288bf522SAndroid Build Coastguard Worker         return 0;
129*288bf522SAndroid Build Coastguard Worker     }
130*288bf522SAndroid Build Coastguard Worker     addr = min_addr = max_addr = std::stoll(addr_str, 0, 16);
131*288bf522SAndroid Build Coastguard Worker     addrs.insert(addr);
132*288bf522SAndroid Build Coastguard Worker     for (unsigned int i = 0; i < samp_sz - 1; ++i) {
133*288bf522SAndroid Build Coastguard Worker         addr_str = scrape_addr(exec_name, lib_match);
134*288bf522SAndroid Build Coastguard Worker         if (addr_str.empty()) {
135*288bf522SAndroid Build Coastguard Worker             std::cerr << "empty address";
136*288bf522SAndroid Build Coastguard Worker             return 0;
137*288bf522SAndroid Build Coastguard Worker         }
138*288bf522SAndroid Build Coastguard Worker         if (!isxdigit(addr_str[0])) {
139*288bf522SAndroid Build Coastguard Worker             std::cerr << "invalid address: " << addr_str;
140*288bf522SAndroid Build Coastguard Worker             return 0;
141*288bf522SAndroid Build Coastguard Worker         }
142*288bf522SAndroid Build Coastguard Worker         addr = std::stoll(addr_str, 0, 16);
143*288bf522SAndroid Build Coastguard Worker         if (addr < min_addr)
144*288bf522SAndroid Build Coastguard Worker             min_addr = addr;
145*288bf522SAndroid Build Coastguard Worker         if (addr >= max_addr)
146*288bf522SAndroid Build Coastguard Worker             max_addr = addr;
147*288bf522SAndroid Build Coastguard Worker         addrs.insert(addr);
148*288bf522SAndroid Build Coastguard Worker     }
149*288bf522SAndroid Build Coastguard Worker     if (addrs.size() < (samp_sz >> 1)) {
150*288bf522SAndroid Build Coastguard Worker         std::cerr << "> 50% collisions in mmap addresses, entropy appears to be rigged!";
151*288bf522SAndroid Build Coastguard Worker         return 0;
152*288bf522SAndroid Build Coastguard Worker     }
153*288bf522SAndroid Build Coastguard Worker     unsigned int e_bits = (int) (std::ceil(std::log2(max_addr - min_addr)) - std::log2(getpagesize()));
154*288bf522SAndroid Build Coastguard Worker     return e_bits;
155*288bf522SAndroid Build Coastguard Worker }
156*288bf522SAndroid Build Coastguard Worker 
157*288bf522SAndroid Build Coastguard Worker const char *AslrMmapTest::path;
158*288bf522SAndroid Build Coastguard Worker const char *AslrMmapTest::lib;
159*288bf522SAndroid Build Coastguard Worker unsigned int AslrMmapTest::def, AslrMmapTest::min, AslrMmapTest::max;
160*288bf522SAndroid Build Coastguard Worker bool AslrMmapTest::compat = false, AslrMmapTest::user32 = false;
161*288bf522SAndroid Build Coastguard Worker unsigned int AslrMmapTest::def_cmpt, AslrMmapTest::min_cmpt, AslrMmapTest::max_cmpt;
162*288bf522SAndroid Build Coastguard Worker 
SetUpTestCase()163*288bf522SAndroid Build Coastguard Worker void AslrMmapTest::SetUpTestCase() {
164*288bf522SAndroid Build Coastguard Worker     /* set up per-arch values */
165*288bf522SAndroid Build Coastguard Worker #if defined(__x86_64__)
166*288bf522SAndroid Build Coastguard Worker     def = 32;
167*288bf522SAndroid Build Coastguard Worker     min = 28;
168*288bf522SAndroid Build Coastguard Worker     max = 32;
169*288bf522SAndroid Build Coastguard Worker     path = SCRAPE_PATH_64;
170*288bf522SAndroid Build Coastguard Worker     lib = SCRAPE_LIB_64;
171*288bf522SAndroid Build Coastguard Worker 
172*288bf522SAndroid Build Coastguard Worker     compat = true;
173*288bf522SAndroid Build Coastguard Worker     def_cmpt = 16;
174*288bf522SAndroid Build Coastguard Worker     min_cmpt = 8;
175*288bf522SAndroid Build Coastguard Worker     max_cmpt = 16;
176*288bf522SAndroid Build Coastguard Worker 
177*288bf522SAndroid Build Coastguard Worker #elif defined(__i386__)
178*288bf522SAndroid Build Coastguard Worker     def = 16;
179*288bf522SAndroid Build Coastguard Worker     min = 8;
180*288bf522SAndroid Build Coastguard Worker     max = 16;
181*288bf522SAndroid Build Coastguard Worker     path = SCRAPE_PATH_32;
182*288bf522SAndroid Build Coastguard Worker     lib = SCRAPE_LIB_32;
183*288bf522SAndroid Build Coastguard Worker 
184*288bf522SAndroid Build Coastguard Worker     if (!access(PROCFS_COMPAT_PATH, F_OK)) {
185*288bf522SAndroid Build Coastguard Worker         // running 32 bit userspace over 64-bit kernel
186*288bf522SAndroid Build Coastguard Worker         user32 = true;
187*288bf522SAndroid Build Coastguard Worker         def_cmpt = 16;
188*288bf522SAndroid Build Coastguard Worker         min_cmpt = 8;
189*288bf522SAndroid Build Coastguard Worker         max_cmpt = 16;
190*288bf522SAndroid Build Coastguard Worker     }
191*288bf522SAndroid Build Coastguard Worker 
192*288bf522SAndroid Build Coastguard Worker #elif defined(__aarch64__)
193*288bf522SAndroid Build Coastguard Worker     unsigned int pgbits = std::log2(getpagesize());
194*288bf522SAndroid Build Coastguard Worker     def = 24;
195*288bf522SAndroid Build Coastguard Worker     min = 18 - (pgbits - 12);
196*288bf522SAndroid Build Coastguard Worker     max = 24;
197*288bf522SAndroid Build Coastguard Worker     path = SCRAPE_PATH_64;
198*288bf522SAndroid Build Coastguard Worker     lib = SCRAPE_LIB_64;
199*288bf522SAndroid Build Coastguard Worker 
200*288bf522SAndroid Build Coastguard Worker     compat = true;
201*288bf522SAndroid Build Coastguard Worker     def_cmpt = 16;
202*288bf522SAndroid Build Coastguard Worker     min_cmpt = 11 - (pgbits - 12);
203*288bf522SAndroid Build Coastguard Worker     max_cmpt = 16;
204*288bf522SAndroid Build Coastguard Worker 
205*288bf522SAndroid Build Coastguard Worker #elif defined(__arm__)
206*288bf522SAndroid Build Coastguard Worker     unsigned int pgbits = std::log2(getpagesize());
207*288bf522SAndroid Build Coastguard Worker     def = 16;
208*288bf522SAndroid Build Coastguard Worker     min = 8;
209*288bf522SAndroid Build Coastguard Worker     max = 16;
210*288bf522SAndroid Build Coastguard Worker     path = SCRAPE_PATH_32;
211*288bf522SAndroid Build Coastguard Worker     lib = SCRAPE_LIB_32;
212*288bf522SAndroid Build Coastguard Worker 
213*288bf522SAndroid Build Coastguard Worker     if (!access(PROCFS_COMPAT_PATH, F_OK)) {
214*288bf522SAndroid Build Coastguard Worker         // running 32 bit userspace over 64-bit kernel
215*288bf522SAndroid Build Coastguard Worker         user32 = true;
216*288bf522SAndroid Build Coastguard Worker         def_cmpt = 16;
217*288bf522SAndroid Build Coastguard Worker         min_cmpt = 11 - (pgbits - 12);;
218*288bf522SAndroid Build Coastguard Worker         max_cmpt = 16;
219*288bf522SAndroid Build Coastguard Worker     }
220*288bf522SAndroid Build Coastguard Worker #endif
221*288bf522SAndroid Build Coastguard Worker }
222*288bf522SAndroid Build Coastguard Worker 
TearDown()223*288bf522SAndroid Build Coastguard Worker void AslrMmapTest::TearDown() {
224*288bf522SAndroid Build Coastguard Worker     if (!user32)
225*288bf522SAndroid Build Coastguard Worker         set_mmap_rnd_bits(def, false);
226*288bf522SAndroid Build Coastguard Worker     if (user32 || compat)
227*288bf522SAndroid Build Coastguard Worker         set_mmap_rnd_bits(def_cmpt, true);
228*288bf522SAndroid Build Coastguard Worker }
229*288bf522SAndroid Build Coastguard Worker 
230*288bf522SAndroid Build Coastguard Worker /* run tests only if on supported arch */
231*288bf522SAndroid Build Coastguard Worker #if defined(__x86_64__) || defined(__i386__) || defined(__aarch64__) || defined(__arm__)
232*288bf522SAndroid Build Coastguard Worker 
TEST_F(AslrMmapTest,entropy_min_def)233*288bf522SAndroid Build Coastguard Worker TEST_F(AslrMmapTest, entropy_min_def) {
234*288bf522SAndroid Build Coastguard Worker     if (user32) {
235*288bf522SAndroid Build Coastguard Worker         // running 32-bit userspace on 64-bit kernel, only compat used.
236*288bf522SAndroid Build Coastguard Worker         return;
237*288bf522SAndroid Build Coastguard Worker     } else {
238*288bf522SAndroid Build Coastguard Worker         EXPECT_GE(def, calc_mmap_entropy(path, lib, 16));
239*288bf522SAndroid Build Coastguard Worker     }
240*288bf522SAndroid Build Coastguard Worker }
241*288bf522SAndroid Build Coastguard Worker 
TEST_F(AslrMmapTest,entropy_min_cmpt_def)242*288bf522SAndroid Build Coastguard Worker TEST_F(AslrMmapTest, entropy_min_cmpt_def) {
243*288bf522SAndroid Build Coastguard Worker     if (compat || user32) {
244*288bf522SAndroid Build Coastguard Worker         EXPECT_GE(def_cmpt, calc_mmap_entropy(SCRAPE_PATH_32, SCRAPE_LIB_32, 16));
245*288bf522SAndroid Build Coastguard Worker     }
246*288bf522SAndroid Build Coastguard Worker }
247*288bf522SAndroid Build Coastguard Worker 
248*288bf522SAndroid Build Coastguard Worker #endif /* supported arch */
249