blob: b56fc4102960191d9d1c3e5ac3d3f50eeb884f58 [file] [log] [blame]
Torne (Richard Coles)12bbb912014-02-06 14:34:21 +00001/*
2 * Copyright (C) 2014 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#include <gtest/gtest.h>
18
19#include <dlfcn.h>
Torne (Richard Coles)183ad9d2014-02-27 13:18:00 +000020#include <errno.h>
21#include <fcntl.h>
22#include <stdio.h>
23#include <string.h>
24#include <unistd.h>
Torne (Richard Coles)12bbb912014-02-06 14:34:21 +000025#include <android/dlext.h>
26#include <sys/mman.h>
Torne (Richard Coles)26052612014-05-02 14:57:42 +010027#include <sys/types.h>
Torne (Richard Coles)183ad9d2014-02-27 13:18:00 +000028#include <sys/wait.h>
Torne (Richard Coles)12bbb912014-02-06 14:34:21 +000029
Torne (Richard Coles)26052612014-05-02 14:57:42 +010030#include <pagemap/pagemap.h>
31
Torne (Richard Coles)12bbb912014-02-06 14:34:21 +000032
33#define ASSERT_DL_NOTNULL(ptr) \
34 ASSERT_TRUE(ptr != NULL) << "dlerror: " << dlerror()
35
36#define ASSERT_DL_ZERO(i) \
37 ASSERT_EQ(0, i) << "dlerror: " << dlerror()
38
Torne (Richard Coles)183ad9d2014-02-27 13:18:00 +000039#define ASSERT_NOERROR(i) \
40 ASSERT_NE(-1, i) << "errno: " << strerror(errno)
41
Torne (Richard Coles)12bbb912014-02-06 14:34:21 +000042
43typedef int (*fn)(void);
44#define LIBNAME "libdlext_test.so"
Torne (Richard Coles)26ec9672014-04-30 15:48:40 +010045#define LIBNAME_NORELRO "libdlext_test_norelro.so"
Torne (Richard Coles)12bbb912014-02-06 14:34:21 +000046#define LIBSIZE 1024*1024 // how much address space to reserve for it
47
48
49class DlExtTest : public ::testing::Test {
50protected:
51 virtual void SetUp() {
52 handle_ = NULL;
53 // verify that we don't have the library loaded already
54 ASSERT_EQ(NULL, dlsym(RTLD_DEFAULT, "getRandomNumber"));
55 // call dlerror() to swallow the error, and check it was the one we wanted
56 ASSERT_STREQ("undefined symbol: getRandomNumber", dlerror());
57 }
58
59 virtual void TearDown() {
60 if (handle_ != NULL) {
61 ASSERT_DL_ZERO(dlclose(handle_));
62 }
63 }
64
65 void* handle_;
66};
67
68TEST_F(DlExtTest, ExtInfoNull) {
69 handle_ = android_dlopen_ext(LIBNAME, RTLD_NOW, NULL);
70 ASSERT_DL_NOTNULL(handle_);
71 fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber"));
72 ASSERT_DL_NOTNULL(f);
73 EXPECT_EQ(4, f());
74}
75
76TEST_F(DlExtTest, ExtInfoNoFlags) {
77 android_dlextinfo extinfo;
78 extinfo.flags = 0;
79 handle_ = android_dlopen_ext(LIBNAME, RTLD_NOW, &extinfo);
80 ASSERT_DL_NOTNULL(handle_);
81 fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber"));
82 ASSERT_DL_NOTNULL(f);
83 EXPECT_EQ(4, f());
84}
85
86TEST_F(DlExtTest, Reserved) {
87 void* start = mmap(NULL, LIBSIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS,
88 -1, 0);
89 ASSERT_TRUE(start != MAP_FAILED);
90 android_dlextinfo extinfo;
91 extinfo.flags = ANDROID_DLEXT_RESERVED_ADDRESS;
92 extinfo.reserved_addr = start;
93 extinfo.reserved_size = LIBSIZE;
94 handle_ = android_dlopen_ext(LIBNAME, RTLD_NOW, &extinfo);
95 ASSERT_DL_NOTNULL(handle_);
96 fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber"));
97 ASSERT_DL_NOTNULL(f);
98 EXPECT_GE(f, start);
99 EXPECT_LT(reinterpret_cast<void*>(f),
100 reinterpret_cast<char*>(start) + LIBSIZE);
101 EXPECT_EQ(4, f());
102}
103
104TEST_F(DlExtTest, ReservedTooSmall) {
105 void* start = mmap(NULL, PAGE_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS,
106 -1, 0);
107 ASSERT_TRUE(start != MAP_FAILED);
108 android_dlextinfo extinfo;
109 extinfo.flags = ANDROID_DLEXT_RESERVED_ADDRESS;
110 extinfo.reserved_addr = start;
111 extinfo.reserved_size = PAGE_SIZE;
112 handle_ = android_dlopen_ext(LIBNAME, RTLD_NOW, &extinfo);
113 EXPECT_EQ(NULL, handle_);
114}
115
116TEST_F(DlExtTest, ReservedHint) {
117 void* start = mmap(NULL, LIBSIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS,
118 -1, 0);
119 ASSERT_TRUE(start != MAP_FAILED);
120 android_dlextinfo extinfo;
121 extinfo.flags = ANDROID_DLEXT_RESERVED_ADDRESS_HINT;
122 extinfo.reserved_addr = start;
123 extinfo.reserved_size = LIBSIZE;
124 handle_ = android_dlopen_ext(LIBNAME, RTLD_NOW, &extinfo);
125 ASSERT_DL_NOTNULL(handle_);
126 fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber"));
127 ASSERT_DL_NOTNULL(f);
128 EXPECT_GE(f, start);
129 EXPECT_LT(reinterpret_cast<void*>(f),
130 reinterpret_cast<char*>(start) + LIBSIZE);
131 EXPECT_EQ(4, f());
132}
133
134TEST_F(DlExtTest, ReservedHintTooSmall) {
135 void* start = mmap(NULL, PAGE_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS,
136 -1, 0);
137 ASSERT_TRUE(start != MAP_FAILED);
138 android_dlextinfo extinfo;
139 extinfo.flags = ANDROID_DLEXT_RESERVED_ADDRESS_HINT;
140 extinfo.reserved_addr = start;
141 extinfo.reserved_size = PAGE_SIZE;
142 handle_ = android_dlopen_ext(LIBNAME, RTLD_NOW, &extinfo);
143 ASSERT_DL_NOTNULL(handle_);
144 fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber"));
145 ASSERT_DL_NOTNULL(f);
146 EXPECT_TRUE(f < start || (reinterpret_cast<void*>(f) >=
147 reinterpret_cast<char*>(start) + PAGE_SIZE));
148 EXPECT_EQ(4, f());
149}
Torne (Richard Coles)183ad9d2014-02-27 13:18:00 +0000150
Torne (Richard Coles)26ec9672014-04-30 15:48:40 +0100151class DlExtRelroSharingTest : public DlExtTest {
152protected:
153 virtual void SetUp() {
154 DlExtTest::SetUp();
155 void* start = mmap(NULL, LIBSIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS,
156 -1, 0);
157 ASSERT_TRUE(start != MAP_FAILED);
158 extinfo_.flags = ANDROID_DLEXT_RESERVED_ADDRESS;
159 extinfo_.reserved_addr = start;
160 extinfo_.reserved_size = LIBSIZE;
161 extinfo_.relro_fd = -1;
Torne (Richard Coles)183ad9d2014-02-27 13:18:00 +0000162
Torne (Richard Coles)26ec9672014-04-30 15:48:40 +0100163 const char* android_data = getenv("ANDROID_DATA");
164 ASSERT_TRUE(android_data != NULL);
165 snprintf(relro_file_, sizeof(relro_file_), "%s/local/tmp/libdlext_test.relro", android_data);
Torne (Richard Coles)183ad9d2014-02-27 13:18:00 +0000166 }
167
Torne (Richard Coles)26ec9672014-04-30 15:48:40 +0100168 virtual void TearDown() {
169 DlExtTest::TearDown();
170 if (extinfo_.relro_fd != -1) {
171 ASSERT_NOERROR(close(extinfo_.relro_fd));
172 }
173 }
Torne (Richard Coles)183ad9d2014-02-27 13:18:00 +0000174
Torne (Richard Coles)26ec9672014-04-30 15:48:40 +0100175 void CreateRelroFile(const char* lib) {
176 int relro_fd = open(relro_file_, O_CREAT | O_RDWR | O_TRUNC, 0644);
177 ASSERT_NOERROR(relro_fd);
178
179 pid_t pid = fork();
180 if (pid == 0) {
181 // child process
182 extinfo_.flags |= ANDROID_DLEXT_WRITE_RELRO;
183 extinfo_.relro_fd = relro_fd;
184 void* handle = android_dlopen_ext(lib, RTLD_NOW, &extinfo_);
185 if (handle == NULL) {
186 fprintf(stderr, "in child: %s\n", dlerror());
187 exit(1);
188 }
189 exit(0);
190 }
191
192 // continuing in parent
193 ASSERT_NOERROR(close(relro_fd));
194 ASSERT_NOERROR(pid);
195 int status;
196 ASSERT_EQ(pid, waitpid(pid, &status, 0));
197 ASSERT_TRUE(WIFEXITED(status));
198 ASSERT_EQ(0, WEXITSTATUS(status));
199
200 // reopen file for reading so it can be used
201 relro_fd = open(relro_file_, O_RDONLY);
202 ASSERT_NOERROR(relro_fd);
203 extinfo_.flags |= ANDROID_DLEXT_USE_RELRO;
204 extinfo_.relro_fd = relro_fd;
205 }
206
207 void TryUsingRelro(const char* lib) {
208 handle_ = android_dlopen_ext(lib, RTLD_NOW, &extinfo_);
209 ASSERT_DL_NOTNULL(handle_);
210 fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber"));
211 ASSERT_DL_NOTNULL(f);
212 EXPECT_EQ(4, f());
213 }
214
Torne (Richard Coles)26052612014-05-02 14:57:42 +0100215 void SpawnChildrenAndMeasurePss(const char* lib, bool share_relro, size_t* pss_out);
216
Torne (Richard Coles)26ec9672014-04-30 15:48:40 +0100217 android_dlextinfo extinfo_;
218 char relro_file_[PATH_MAX];
219};
220
221TEST_F(DlExtRelroSharingTest, ChildWritesGoodData) {
222 ASSERT_NO_FATAL_FAILURE(CreateRelroFile(LIBNAME));
223 ASSERT_NO_FATAL_FAILURE(TryUsingRelro(LIBNAME));
224}
225
226TEST_F(DlExtRelroSharingTest, ChildWritesNoRelro) {
227 ASSERT_NO_FATAL_FAILURE(CreateRelroFile(LIBNAME_NORELRO));
228 ASSERT_NO_FATAL_FAILURE(TryUsingRelro(LIBNAME_NORELRO));
229}
230
231TEST_F(DlExtRelroSharingTest, RelroFileEmpty) {
232 int relro_fd = open(relro_file_, O_CREAT | O_RDWR | O_TRUNC, 0644);
Torne (Richard Coles)183ad9d2014-02-27 13:18:00 +0000233 ASSERT_NOERROR(relro_fd);
Torne (Richard Coles)183ad9d2014-02-27 13:18:00 +0000234 ASSERT_NOERROR(close(relro_fd));
235
Torne (Richard Coles)26ec9672014-04-30 15:48:40 +0100236 ASSERT_NO_FATAL_FAILURE(TryUsingRelro(LIBNAME));
Torne (Richard Coles)183ad9d2014-02-27 13:18:00 +0000237}
Torne (Richard Coles)26052612014-05-02 14:57:42 +0100238
239TEST_F(DlExtRelroSharingTest, VerifyMemorySaving) {
240 ASSERT_NO_FATAL_FAILURE(CreateRelroFile(LIBNAME));
241 int relro_fd = open(relro_file_, O_RDONLY);
242 ASSERT_NOERROR(relro_fd);
243 extinfo_.flags |= ANDROID_DLEXT_USE_RELRO;
244 extinfo_.relro_fd = relro_fd;
245 int pipefd[2];
246 ASSERT_NOERROR(pipe(pipefd));
247
248 size_t without_sharing, with_sharing;
249 ASSERT_NO_FATAL_FAILURE(SpawnChildrenAndMeasurePss(LIBNAME, false, &without_sharing));
250 ASSERT_NO_FATAL_FAILURE(SpawnChildrenAndMeasurePss(LIBNAME, true, &with_sharing));
251
252 // We expect the sharing to save at least 10% of the total PSS. In practice
253 // it saves 40%+ for this test.
254 size_t expected_size = without_sharing - (without_sharing/10);
255 EXPECT_LT(with_sharing, expected_size);
256}
257
258void getPss(pid_t pid, size_t* pss_out) {
259 pm_kernel_t* kernel;
260 ASSERT_EQ(0, pm_kernel_create(&kernel));
261
262 pm_process_t* process;
263 ASSERT_EQ(0, pm_process_create(kernel, pid, &process));
264
265 pm_map_t** maps;
266 size_t num_maps;
267 ASSERT_EQ(0, pm_process_maps(process, &maps, &num_maps));
268
269 size_t total_pss = 0;
270 for (size_t i = 0; i < num_maps; i++) {
271 pm_memusage_t usage;
272 ASSERT_EQ(0, pm_map_usage(maps[i], &usage));
273 total_pss += usage.pss;
274 }
275 *pss_out = total_pss;
276
277 free(maps);
278 pm_process_destroy(process);
279 pm_kernel_destroy(kernel);
280}
281
282void DlExtRelroSharingTest::SpawnChildrenAndMeasurePss(const char* lib, bool share_relro,
283 size_t* pss_out) {
284 const int CHILDREN = 20;
285
286 // Create children
287 pid_t childpid[CHILDREN];
288 int childpipe[CHILDREN];
289 for (int i=0; i<CHILDREN; ++i) {
290 char read_buf;
291 int child_done_pipe[2], parent_done_pipe[2];
292 ASSERT_NOERROR(pipe(child_done_pipe));
293 ASSERT_NOERROR(pipe(parent_done_pipe));
294
295 pid_t child = fork();
296 if (child == 0) {
297 // close the 'wrong' ends of the pipes in the child
298 close(child_done_pipe[0]);
299 close(parent_done_pipe[1]);
300
301 // open the library
302 void* handle;
303 if (share_relro) {
304 handle = android_dlopen_ext(lib, RTLD_NOW, &extinfo_);
305 } else {
306 handle = dlopen(lib, RTLD_NOW);
307 }
308 if (handle == NULL) {
309 fprintf(stderr, "in child: %s\n", dlerror());
310 exit(1);
311 }
312
313 // close write end of child_done_pipe to signal the parent that we're done.
314 close(child_done_pipe[1]);
315
316 // wait for the parent to close parent_done_pipe, then exit
317 read(parent_done_pipe[0], &read_buf, 1);
318 exit(0);
319 }
320
321 ASSERT_NOERROR(child);
322
323 // close the 'wrong' ends of the pipes in the parent
324 close(child_done_pipe[1]);
325 close(parent_done_pipe[0]);
326
327 // wait for the child to be done
328 read(child_done_pipe[0], &read_buf, 1);
329 close(child_done_pipe[0]);
330
331 // save the child's pid and the parent_done_pipe
332 childpid[i] = child;
333 childpipe[i] = parent_done_pipe[1];
334 }
335
336 // Sum the PSS of all the children
337 size_t total_pss = 0;
338 for (int i=0; i<CHILDREN; ++i) {
339 size_t child_pss;
340 ASSERT_NO_FATAL_FAILURE(getPss(childpid[i], &child_pss));
341 total_pss += child_pss;
342 }
343 *pss_out = total_pss;
344
345 // Close pipes and wait for children to exit
346 for (int i=0; i<CHILDREN; ++i) {
347 ASSERT_NOERROR(close(childpipe[i]));
348 }
349 for (int i=0; i<CHILDREN; ++i) {
350 int status;
351 ASSERT_EQ(childpid[i], waitpid(childpid[i], &status, 0));
352 ASSERT_TRUE(WIFEXITED(status));
353 ASSERT_EQ(0, WEXITSTATUS(status));
354 }
355}