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