blob: 00eea589ee3d61f287b5099df2bab3f3e87e48d8 [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>
Yabin Cui16f7f8d2014-11-04 11:08:05 -080020#include <elf.h>
Torne (Richard Coles)183ad9d2014-02-27 13:18:00 +000021#include <errno.h>
22#include <fcntl.h>
Yabin Cui16f7f8d2014-11-04 11:08:05 -080023#include <inttypes.h>
Torne (Richard Coles)183ad9d2014-02-27 13:18:00 +000024#include <stdio.h>
25#include <string.h>
26#include <unistd.h>
Torne (Richard Coles)12bbb912014-02-06 14:34:21 +000027#include <android/dlext.h>
28#include <sys/mman.h>
Torne (Richard Coles)26052612014-05-02 14:57:42 +010029#include <sys/types.h>
Torne (Richard Coles)183ad9d2014-02-27 13:18:00 +000030#include <sys/wait.h>
Torne (Richard Coles)12bbb912014-02-06 14:34:21 +000031
Torne (Richard Coles)26052612014-05-02 14:57:42 +010032#include <pagemap/pagemap.h>
Christopher Ferrisc0ffcec2016-01-19 20:32:37 -080033#include <ziparchive/zip_archive.h>
Torne (Richard Coles)26052612014-05-02 14:57:42 +010034
Yabin Cui294d1e22014-12-07 20:43:37 -080035#include "TemporaryFile.h"
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -080036#include "utils.h"
Torne (Richard Coles)12bbb912014-02-06 14:34:21 +000037
38#define ASSERT_DL_NOTNULL(ptr) \
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -070039 ASSERT_TRUE(ptr != nullptr) << "dlerror: " << dlerror()
Torne (Richard Coles)12bbb912014-02-06 14:34:21 +000040
41#define ASSERT_DL_ZERO(i) \
42 ASSERT_EQ(0, i) << "dlerror: " << dlerror()
43
Torne (Richard Coles)183ad9d2014-02-27 13:18:00 +000044#define ASSERT_NOERROR(i) \
45 ASSERT_NE(-1, i) << "errno: " << strerror(errno)
46
Yabin Cui16f7f8d2014-11-04 11:08:05 -080047#define ASSERT_SUBSTR(needle, haystack) \
48 ASSERT_PRED_FORMAT2(::testing::IsSubstring, needle, haystack)
49
Torne (Richard Coles)12bbb912014-02-06 14:34:21 +000050
51typedef int (*fn)(void);
52#define LIBNAME "libdlext_test.so"
Torne (Richard Coles)26ec9672014-04-30 15:48:40 +010053#define LIBNAME_NORELRO "libdlext_test_norelro.so"
Torne (Richard Coles)12bbb912014-02-06 14:34:21 +000054#define LIBSIZE 1024*1024 // how much address space to reserve for it
55
Dmitriy Ivanov04dc91a2014-07-01 14:10:16 -070056#if defined(__LP64__)
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -070057#define NATIVE_TESTS_PATH "/nativetest64"
Dmitriy Ivanov04dc91a2014-07-01 14:10:16 -070058#else
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -070059#define NATIVE_TESTS_PATH "/nativetest"
Dmitriy Ivanov04dc91a2014-07-01 14:10:16 -070060#endif
Torne (Richard Coles)12bbb912014-02-06 14:34:21 +000061
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -070062#define LIBPATH NATIVE_TESTS_PATH "/libdlext_test_fd/libdlext_test_fd.so"
63#define LIBZIPPATH NATIVE_TESTS_PATH "/libdlext_test_zip/libdlext_test_zip_zipaligned.zip"
64#define LIBZIPPATH_WITH_RUNPATH NATIVE_TESTS_PATH "/libdlext_test_runpath_zip/libdlext_test_runpath_zip_zipaligned.zip"
Christopher Ferrisc0ffcec2016-01-19 20:32:37 -080065#define LIBZIP_SIMPLE_ZIP "libdir/libatest_simple_zip.so"
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -070066
Torne (Richard Coles)12bbb912014-02-06 14:34:21 +000067class DlExtTest : public ::testing::Test {
68protected:
69 virtual void SetUp() {
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -070070 handle_ = nullptr;
Torne (Richard Coles)12bbb912014-02-06 14:34:21 +000071 // verify that we don't have the library loaded already
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -070072 void* h = dlopen(LIBNAME, RTLD_NOW | RTLD_NOLOAD);
73 ASSERT_TRUE(h == nullptr);
74 h = dlopen(LIBNAME_NORELRO, RTLD_NOW | RTLD_NOLOAD);
75 ASSERT_TRUE(h == nullptr);
Torne (Richard Coles)12bbb912014-02-06 14:34:21 +000076 // call dlerror() to swallow the error, and check it was the one we wanted
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -070077 ASSERT_STREQ("dlopen failed: library \"" LIBNAME_NORELRO "\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror());
Torne (Richard Coles)12bbb912014-02-06 14:34:21 +000078 }
79
80 virtual void TearDown() {
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -070081 if (handle_ != nullptr) {
Torne (Richard Coles)12bbb912014-02-06 14:34:21 +000082 ASSERT_DL_ZERO(dlclose(handle_));
83 }
84 }
85
86 void* handle_;
87};
88
89TEST_F(DlExtTest, ExtInfoNull) {
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -070090 handle_ = android_dlopen_ext(LIBNAME, RTLD_NOW, nullptr);
Torne (Richard Coles)12bbb912014-02-06 14:34:21 +000091 ASSERT_DL_NOTNULL(handle_);
92 fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber"));
93 ASSERT_DL_NOTNULL(f);
94 EXPECT_EQ(4, f());
95}
96
97TEST_F(DlExtTest, ExtInfoNoFlags) {
98 android_dlextinfo extinfo;
99 extinfo.flags = 0;
100 handle_ = android_dlopen_ext(LIBNAME, RTLD_NOW, &extinfo);
101 ASSERT_DL_NOTNULL(handle_);
102 fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber"));
103 ASSERT_DL_NOTNULL(f);
104 EXPECT_EQ(4, f());
105}
106
Dmitriy Ivanov04dc91a2014-07-01 14:10:16 -0700107TEST_F(DlExtTest, ExtInfoUseFd) {
Dmitriy Ivanov52393a52015-03-18 22:50:01 -0700108 const std::string lib_path = std::string(getenv("ANDROID_DATA")) + LIBPATH;
Dmitriy Ivanov04dc91a2014-07-01 14:10:16 -0700109
110 android_dlextinfo extinfo;
111 extinfo.flags = ANDROID_DLEXT_USE_LIBRARY_FD;
Dmitriy Ivanov52393a52015-03-18 22:50:01 -0700112 extinfo.library_fd = TEMP_FAILURE_RETRY(open(lib_path.c_str(), O_RDONLY | O_CLOEXEC));
Dmitriy Ivanov04dc91a2014-07-01 14:10:16 -0700113 ASSERT_TRUE(extinfo.library_fd != -1);
Dmitriy Ivanov52393a52015-03-18 22:50:01 -0700114 handle_ = android_dlopen_ext(lib_path.c_str(), RTLD_NOW, &extinfo);
Dmitriy Ivanov04dc91a2014-07-01 14:10:16 -0700115 ASSERT_DL_NOTNULL(handle_);
116 fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber"));
117 ASSERT_DL_NOTNULL(f);
118 EXPECT_EQ(4, f());
Dmitriy Ivanovedfc9f62015-09-02 16:32:02 -0700119
120 uint32_t* taxicab_number = reinterpret_cast<uint32_t*>(dlsym(handle_, "dlopen_testlib_taxicab_number"));
121 ASSERT_DL_NOTNULL(taxicab_number);
122 EXPECT_EQ(1729U, *taxicab_number);
Dmitriy Ivanov04dc91a2014-07-01 14:10:16 -0700123}
124
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -0700125TEST_F(DlExtTest, ExtInfoUseFdWithOffset) {
Dmitriy Ivanov52393a52015-03-18 22:50:01 -0700126 const std::string lib_path = std::string(getenv("ANDROID_DATA")) + LIBZIPPATH;
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -0700127
128 android_dlextinfo extinfo;
Dmitriy Ivanova6c12792014-10-21 12:09:18 -0700129 extinfo.flags = ANDROID_DLEXT_USE_LIBRARY_FD | ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET;
Dmitriy Ivanov52393a52015-03-18 22:50:01 -0700130 extinfo.library_fd = TEMP_FAILURE_RETRY(open(lib_path.c_str(), O_RDONLY | O_CLOEXEC));
Christopher Ferrisc0ffcec2016-01-19 20:32:37 -0800131
132 // Find the offset of the shared library in the zip.
133 ZipArchiveHandle handle;
134 ASSERT_EQ(0, OpenArchive(lib_path.c_str(), &handle));
135 ZipEntry zip_entry;
136 ZipString zip_name;
137 zip_name.name = reinterpret_cast<const uint8_t*>(LIBZIP_SIMPLE_ZIP);
138 zip_name.name_length = sizeof(LIBZIP_SIMPLE_ZIP) - 1;
139 ASSERT_EQ(0, FindEntry(handle, zip_name, &zip_entry));
140 extinfo.library_fd_offset = zip_entry.offset;
141 CloseArchive(handle);
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -0700142
Dmitriy Ivanov52393a52015-03-18 22:50:01 -0700143 handle_ = android_dlopen_ext(lib_path.c_str(), RTLD_NOW, &extinfo);
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -0700144 ASSERT_DL_NOTNULL(handle_);
145
Dmitriy Ivanovb4827502015-09-28 16:38:31 -0700146 uint32_t* taxicab_number = reinterpret_cast<uint32_t*>(dlsym(handle_, "dlopen_testlib_taxicab_number"));
147 ASSERT_DL_NOTNULL(taxicab_number);
148 EXPECT_EQ(1729U, *taxicab_number);
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -0700149}
150
151TEST_F(DlExtTest, ExtInfoUseFdWithInvalidOffset) {
Dmitriy Ivanov52393a52015-03-18 22:50:01 -0700152 const std::string lib_path = std::string(getenv("ANDROID_DATA")) + LIBZIPPATH;
Dmitriy Ivanovef255922015-04-08 11:53:08 -0700153 // lib_path is relative when $ANDROID_DATA is relative
154 char lib_realpath_buf[PATH_MAX];
155 ASSERT_TRUE(realpath(lib_path.c_str(), lib_realpath_buf) == lib_realpath_buf);
156 const std::string lib_realpath = std::string(lib_realpath_buf);
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -0700157
158 android_dlextinfo extinfo;
Dmitriy Ivanova6c12792014-10-21 12:09:18 -0700159 extinfo.flags = ANDROID_DLEXT_USE_LIBRARY_FD | ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET;
Dmitriy Ivanov52393a52015-03-18 22:50:01 -0700160 extinfo.library_fd = TEMP_FAILURE_RETRY(open(lib_path.c_str(), O_RDONLY | O_CLOEXEC));
Dmitriy Ivanova6c12792014-10-21 12:09:18 -0700161 extinfo.library_fd_offset = 17;
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -0700162
163 handle_ = android_dlopen_ext("libname_placeholder", RTLD_NOW, &extinfo);
164 ASSERT_TRUE(handle_ == nullptr);
Dmitriy Ivanova6c12792014-10-21 12:09:18 -0700165 ASSERT_STREQ("dlopen failed: file offset for the library \"libname_placeholder\" is not page-aligned: 17", dlerror());
166
Yabin Cui16f7f8d2014-11-04 11:08:05 -0800167 // Test an address above 2^44, for http://b/18178121 .
168 extinfo.library_fd_offset = (5LL<<48) + PAGE_SIZE;
Dmitriy Ivanova6c12792014-10-21 12:09:18 -0700169 handle_ = android_dlopen_ext("libname_placeholder", RTLD_NOW, &extinfo);
Dmitriy Ivanova6c12792014-10-21 12:09:18 -0700170 ASSERT_TRUE(handle_ == nullptr);
Yabin Cui16f7f8d2014-11-04 11:08:05 -0800171 ASSERT_SUBSTR("dlopen failed: file offset for the library \"libname_placeholder\" >= file size", dlerror());
172
173 extinfo.library_fd_offset = 0LL - PAGE_SIZE;
174 handle_ = android_dlopen_ext("libname_placeholder", RTLD_NOW, &extinfo);
175 ASSERT_TRUE(handle_ == nullptr);
176 ASSERT_SUBSTR("dlopen failed: file offset for the library \"libname_placeholder\" is negative", dlerror());
177
Dmitriy Ivanovb4827502015-09-28 16:38:31 -0700178 extinfo.library_fd_offset = 0;
Dmitriy Ivanovaae859c2015-03-31 11:14:03 -0700179 handle_ = android_dlopen_ext("libname_ignored", RTLD_NOW, &extinfo);
Yabin Cui16f7f8d2014-11-04 11:08:05 -0800180 ASSERT_TRUE(handle_ == nullptr);
Dmitriy Ivanovef255922015-04-08 11:53:08 -0700181 ASSERT_EQ("dlopen failed: \"" + lib_realpath + "\" has bad ELF magic", dlerror());
Dmitriy Ivanova6c12792014-10-21 12:09:18 -0700182
Dmitriy Ivanovfd7a91e2015-11-06 10:44:37 -0800183 // Check if dlsym works after unsuccessful dlopen().
184 // Supply non-exiting one to make linker visit every soinfo.
185 void* sym = dlsym(RTLD_DEFAULT, "this_symbol_does_not_exist___");
186 ASSERT_TRUE(sym == nullptr);
187
Dmitriy Ivanova6c12792014-10-21 12:09:18 -0700188 close(extinfo.library_fd);
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -0700189}
190
Christopher Ferrisc0ffcec2016-01-19 20:32:37 -0800191TEST_F(DlExtTest, ExtInfoUseOffsetWithoutFd) {
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -0700192 android_dlextinfo extinfo;
Dmitriy Ivanova6c12792014-10-21 12:09:18 -0700193 extinfo.flags = ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET;
Christopher Ferrisc0ffcec2016-01-19 20:32:37 -0800194 // This offset will not be used, so it doesn't matter.
195 extinfo.library_fd_offset = 0;
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -0700196
197 handle_ = android_dlopen_ext("/some/lib/that/does_not_exist", RTLD_NOW, &extinfo);
198 ASSERT_TRUE(handle_ == nullptr);
Dmitriy Ivanova6c12792014-10-21 12:09:18 -0700199 ASSERT_STREQ("dlopen failed: invalid extended flag combination (ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET without ANDROID_DLEXT_USE_LIBRARY_FD): 0x20", dlerror());
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -0700200}
201
Dmitriy Ivanov9b821362015-04-02 16:03:56 -0700202TEST(dlext, android_dlopen_ext_force_load_smoke) {
203 // 1. Open actual file
204 void* handle = dlopen("libdlext_test.so", RTLD_NOW);
205 ASSERT_DL_NOTNULL(handle);
206 // 2. Open link with force_load flag set
207 android_dlextinfo extinfo;
208 extinfo.flags = ANDROID_DLEXT_FORCE_LOAD;
209 void* handle2 = android_dlopen_ext("libdlext_test_v2.so", RTLD_NOW, &extinfo);
210 ASSERT_DL_NOTNULL(handle2);
211 ASSERT_TRUE(handle != handle2);
212
213 dlclose(handle2);
214 dlclose(handle);
215}
216
217TEST(dlext, android_dlopen_ext_force_load_soname_exception) {
218 // Check if soname lookup still returns already loaded library
219 // when ANDROID_DLEXT_FORCE_LOAD flag is specified.
220 void* handle = dlopen("libdlext_test_v2.so", RTLD_NOW);
221 ASSERT_DL_NOTNULL(handle);
222
223 android_dlextinfo extinfo;
224 extinfo.flags = ANDROID_DLEXT_FORCE_LOAD;
225
226 // Note that 'libdlext_test.so' is dt_soname for libdlext_test_v2.so
227 void* handle2 = android_dlopen_ext("libdlext_test.so", RTLD_NOW, &extinfo);
228
229 ASSERT_DL_NOTNULL(handle2);
230 ASSERT_TRUE(handle == handle2);
231
232 dlclose(handle2);
233 dlclose(handle);
234}
235
Dmitriy Ivanov52393a52015-03-18 22:50:01 -0700236TEST(dlfcn, dlopen_from_zip_absolute_path) {
237 const std::string lib_path = std::string(getenv("ANDROID_DATA")) + LIBZIPPATH;
238
Dmitriy Ivanovb4827502015-09-28 16:38:31 -0700239 void* handle = dlopen((lib_path + "!/libdir/libatest_simple_zip.so").c_str(), RTLD_NOW);
Dmitriy Ivanov52393a52015-03-18 22:50:01 -0700240 ASSERT_TRUE(handle != nullptr) << dlerror();
241
Dmitriy Ivanovb4827502015-09-28 16:38:31 -0700242 uint32_t* taxicab_number = reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_testlib_taxicab_number"));
243 ASSERT_DL_NOTNULL(taxicab_number);
244 EXPECT_EQ(1729U, *taxicab_number);
Dmitriy Ivanov52393a52015-03-18 22:50:01 -0700245
246 dlclose(handle);
247}
248
Dmitriy Ivanova1feb112015-10-01 18:41:57 -0700249TEST(dlfcn, dlopen_from_zip_with_dt_runpath) {
250 const std::string lib_path = std::string(getenv("ANDROID_DATA")) + LIBZIPPATH_WITH_RUNPATH;
251
252 void* handle = dlopen((lib_path + "!/libdir/libtest_dt_runpath_d_zip.so").c_str(), RTLD_NOW);
253
254 ASSERT_TRUE(handle != nullptr) << dlerror();
255
256 typedef void *(* dlopen_b_fn)();
257 dlopen_b_fn fn = (dlopen_b_fn)dlsym(handle, "dlopen_b");
258 ASSERT_TRUE(fn != nullptr) << dlerror();
259
260 void *p = fn();
261 ASSERT_TRUE(p != nullptr) << dlerror();
262
263 dlclose(p);
264 dlclose(handle);
265}
266
Dmitriy Ivanov52393a52015-03-18 22:50:01 -0700267TEST(dlfcn, dlopen_from_zip_ld_library_path) {
Dmitriy Ivanov402a7502015-06-09 13:46:51 -0700268 const std::string lib_path = std::string(getenv("ANDROID_DATA")) + LIBZIPPATH + "!/libdir";
Dmitriy Ivanov52393a52015-03-18 22:50:01 -0700269
270 typedef void (*fn_t)(const char*);
271 fn_t android_update_LD_LIBRARY_PATH =
272 reinterpret_cast<fn_t>(dlsym(RTLD_DEFAULT, "android_update_LD_LIBRARY_PATH"));
273
274 ASSERT_TRUE(android_update_LD_LIBRARY_PATH != nullptr) << dlerror();
275
Dmitriy Ivanovb4827502015-09-28 16:38:31 -0700276 void* handle = dlopen("libdlext_test_zip.so", RTLD_NOW);
Dmitriy Ivanov52393a52015-03-18 22:50:01 -0700277 ASSERT_TRUE(handle == nullptr);
278
279 android_update_LD_LIBRARY_PATH(lib_path.c_str());
280
Dmitriy Ivanovb4827502015-09-28 16:38:31 -0700281 handle = dlopen("libdlext_test_zip.so", RTLD_NOW);
Dmitriy Ivanov52393a52015-03-18 22:50:01 -0700282 ASSERT_TRUE(handle != nullptr) << dlerror();
283
284 int (*fn)(void);
285 fn = reinterpret_cast<int (*)(void)>(dlsym(handle, "getRandomNumber"));
286 ASSERT_TRUE(fn != nullptr);
287 EXPECT_EQ(4, fn());
288
Dmitriy Ivanovb4827502015-09-28 16:38:31 -0700289 uint32_t* taxicab_number = reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_testlib_taxicab_number"));
290 ASSERT_DL_NOTNULL(taxicab_number);
291 EXPECT_EQ(1729U, *taxicab_number);
292
Dmitriy Ivanov52393a52015-03-18 22:50:01 -0700293 dlclose(handle);
294}
295
296
Torne (Richard Coles)12bbb912014-02-06 14:34:21 +0000297TEST_F(DlExtTest, Reserved) {
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -0700298 void* start = mmap(nullptr, LIBSIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS,
Torne (Richard Coles)12bbb912014-02-06 14:34:21 +0000299 -1, 0);
300 ASSERT_TRUE(start != MAP_FAILED);
301 android_dlextinfo extinfo;
302 extinfo.flags = ANDROID_DLEXT_RESERVED_ADDRESS;
303 extinfo.reserved_addr = start;
304 extinfo.reserved_size = LIBSIZE;
305 handle_ = android_dlopen_ext(LIBNAME, RTLD_NOW, &extinfo);
306 ASSERT_DL_NOTNULL(handle_);
307 fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber"));
308 ASSERT_DL_NOTNULL(f);
Chih-Hung Hsieha2c6ae62014-08-27 13:45:37 -0700309 EXPECT_GE(reinterpret_cast<void*>(f), start);
Torne (Richard Coles)12bbb912014-02-06 14:34:21 +0000310 EXPECT_LT(reinterpret_cast<void*>(f),
311 reinterpret_cast<char*>(start) + LIBSIZE);
312 EXPECT_EQ(4, f());
313}
314
315TEST_F(DlExtTest, ReservedTooSmall) {
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -0700316 void* start = mmap(nullptr, PAGE_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS,
Torne (Richard Coles)12bbb912014-02-06 14:34:21 +0000317 -1, 0);
318 ASSERT_TRUE(start != MAP_FAILED);
319 android_dlextinfo extinfo;
320 extinfo.flags = ANDROID_DLEXT_RESERVED_ADDRESS;
321 extinfo.reserved_addr = start;
322 extinfo.reserved_size = PAGE_SIZE;
323 handle_ = android_dlopen_ext(LIBNAME, RTLD_NOW, &extinfo);
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -0700324 EXPECT_EQ(nullptr, handle_);
Torne (Richard Coles)12bbb912014-02-06 14:34:21 +0000325}
326
327TEST_F(DlExtTest, ReservedHint) {
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -0700328 void* start = mmap(nullptr, LIBSIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS,
Torne (Richard Coles)12bbb912014-02-06 14:34:21 +0000329 -1, 0);
330 ASSERT_TRUE(start != MAP_FAILED);
331 android_dlextinfo extinfo;
332 extinfo.flags = ANDROID_DLEXT_RESERVED_ADDRESS_HINT;
333 extinfo.reserved_addr = start;
334 extinfo.reserved_size = LIBSIZE;
335 handle_ = android_dlopen_ext(LIBNAME, RTLD_NOW, &extinfo);
336 ASSERT_DL_NOTNULL(handle_);
337 fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber"));
338 ASSERT_DL_NOTNULL(f);
Chih-Hung Hsieha2c6ae62014-08-27 13:45:37 -0700339 EXPECT_GE(reinterpret_cast<void*>(f), start);
Torne (Richard Coles)12bbb912014-02-06 14:34:21 +0000340 EXPECT_LT(reinterpret_cast<void*>(f),
341 reinterpret_cast<char*>(start) + LIBSIZE);
342 EXPECT_EQ(4, f());
343}
344
345TEST_F(DlExtTest, ReservedHintTooSmall) {
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -0700346 void* start = mmap(nullptr, PAGE_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS,
Torne (Richard Coles)12bbb912014-02-06 14:34:21 +0000347 -1, 0);
348 ASSERT_TRUE(start != MAP_FAILED);
349 android_dlextinfo extinfo;
350 extinfo.flags = ANDROID_DLEXT_RESERVED_ADDRESS_HINT;
351 extinfo.reserved_addr = start;
352 extinfo.reserved_size = PAGE_SIZE;
353 handle_ = android_dlopen_ext(LIBNAME, RTLD_NOW, &extinfo);
354 ASSERT_DL_NOTNULL(handle_);
355 fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber"));
356 ASSERT_DL_NOTNULL(f);
Chih-Hung Hsieha2c6ae62014-08-27 13:45:37 -0700357 EXPECT_TRUE(reinterpret_cast<void*>(f) < start ||
358 (reinterpret_cast<void*>(f) >=
359 reinterpret_cast<char*>(start) + PAGE_SIZE));
Torne (Richard Coles)12bbb912014-02-06 14:34:21 +0000360 EXPECT_EQ(4, f());
361}
Torne (Richard Coles)183ad9d2014-02-27 13:18:00 +0000362
Dmitriy Ivanov126af752015-10-07 16:34:20 -0700363TEST_F(DlExtTest, LoadAtFixedAddress) {
364 void* start = mmap(nullptr, LIBSIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS,
365 -1, 0);
366 ASSERT_TRUE(start != MAP_FAILED);
367 munmap(start, LIBSIZE);
368
369 android_dlextinfo extinfo;
370 extinfo.flags = ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS;
371 extinfo.reserved_addr = start;
372
373 handle_ = android_dlopen_ext(LIBNAME, RTLD_NOW, &extinfo);
374 ASSERT_DL_NOTNULL(handle_);
375 fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber"));
376 ASSERT_DL_NOTNULL(f);
377 EXPECT_GE(reinterpret_cast<void*>(f), start);
378 EXPECT_LT(reinterpret_cast<void*>(f), reinterpret_cast<char*>(start) + LIBSIZE);
379
380 EXPECT_EQ(4, f());
381}
382
383TEST_F(DlExtTest, LoadAtFixedAddressTooSmall) {
384 void* start = mmap(nullptr, LIBSIZE + PAGE_SIZE, PROT_NONE,
385 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
386 ASSERT_TRUE(start != MAP_FAILED);
387 munmap(start, LIBSIZE + PAGE_SIZE);
388 void* new_addr = mmap(reinterpret_cast<uint8_t*>(start) + PAGE_SIZE, LIBSIZE, PROT_NONE,
389 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
390 ASSERT_TRUE(new_addr != MAP_FAILED);
391
392 android_dlextinfo extinfo;
393 extinfo.flags = ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS;
394 extinfo.reserved_addr = start;
395
396 handle_ = android_dlopen_ext(LIBNAME, RTLD_NOW, &extinfo);
397 ASSERT_TRUE(handle_ == nullptr);
398}
399
Torne (Richard Coles)26ec9672014-04-30 15:48:40 +0100400class DlExtRelroSharingTest : public DlExtTest {
401protected:
402 virtual void SetUp() {
403 DlExtTest::SetUp();
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -0700404 void* start = mmap(nullptr, LIBSIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS,
Torne (Richard Coles)26ec9672014-04-30 15:48:40 +0100405 -1, 0);
406 ASSERT_TRUE(start != MAP_FAILED);
407 extinfo_.flags = ANDROID_DLEXT_RESERVED_ADDRESS;
408 extinfo_.reserved_addr = start;
409 extinfo_.reserved_size = LIBSIZE;
410 extinfo_.relro_fd = -1;
Torne (Richard Coles)183ad9d2014-02-27 13:18:00 +0000411 }
412
Torne (Richard Coles)26ec9672014-04-30 15:48:40 +0100413 virtual void TearDown() {
414 DlExtTest::TearDown();
Torne (Richard Coles)26ec9672014-04-30 15:48:40 +0100415 }
Torne (Richard Coles)183ad9d2014-02-27 13:18:00 +0000416
Yabin Cui294d1e22014-12-07 20:43:37 -0800417 void CreateRelroFile(const char* lib, const char* relro_file) {
418 int relro_fd = open(relro_file, O_RDWR | O_TRUNC);
Torne (Richard Coles)26ec9672014-04-30 15:48:40 +0100419 ASSERT_NOERROR(relro_fd);
420
421 pid_t pid = fork();
422 if (pid == 0) {
423 // child process
424 extinfo_.flags |= ANDROID_DLEXT_WRITE_RELRO;
425 extinfo_.relro_fd = relro_fd;
426 void* handle = android_dlopen_ext(lib, RTLD_NOW, &extinfo_);
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -0700427 if (handle == nullptr) {
Torne (Richard Coles)26ec9672014-04-30 15:48:40 +0100428 fprintf(stderr, "in child: %s\n", dlerror());
429 exit(1);
430 }
431 exit(0);
432 }
433
434 // continuing in parent
435 ASSERT_NOERROR(close(relro_fd));
436 ASSERT_NOERROR(pid);
437 int status;
438 ASSERT_EQ(pid, waitpid(pid, &status, 0));
439 ASSERT_TRUE(WIFEXITED(status));
440 ASSERT_EQ(0, WEXITSTATUS(status));
441
442 // reopen file for reading so it can be used
Yabin Cui294d1e22014-12-07 20:43:37 -0800443 relro_fd = open(relro_file, O_RDONLY);
Torne (Richard Coles)26ec9672014-04-30 15:48:40 +0100444 ASSERT_NOERROR(relro_fd);
445 extinfo_.flags |= ANDROID_DLEXT_USE_RELRO;
446 extinfo_.relro_fd = relro_fd;
447 }
448
449 void TryUsingRelro(const char* lib) {
450 handle_ = android_dlopen_ext(lib, RTLD_NOW, &extinfo_);
451 ASSERT_DL_NOTNULL(handle_);
452 fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber"));
453 ASSERT_DL_NOTNULL(f);
454 EXPECT_EQ(4, f());
Dmitriy Ivanovedfc9f62015-09-02 16:32:02 -0700455
456 uint32_t* taxicab_number = reinterpret_cast<uint32_t*>(dlsym(handle_, "dlopen_testlib_taxicab_number"));
457 ASSERT_DL_NOTNULL(taxicab_number);
458 EXPECT_EQ(1729U, *taxicab_number);
Torne (Richard Coles)26ec9672014-04-30 15:48:40 +0100459 }
460
Torne (Richard Coles)26052612014-05-02 14:57:42 +0100461 void SpawnChildrenAndMeasurePss(const char* lib, bool share_relro, size_t* pss_out);
462
Torne (Richard Coles)26ec9672014-04-30 15:48:40 +0100463 android_dlextinfo extinfo_;
Torne (Richard Coles)26ec9672014-04-30 15:48:40 +0100464};
465
466TEST_F(DlExtRelroSharingTest, ChildWritesGoodData) {
Yabin Cui294d1e22014-12-07 20:43:37 -0800467 TemporaryFile tf; // Use tf to get an unique filename.
468 ASSERT_NOERROR(close(tf.fd));
469
470 ASSERT_NO_FATAL_FAILURE(CreateRelroFile(LIBNAME, tf.filename));
Torne (Richard Coles)26ec9672014-04-30 15:48:40 +0100471 ASSERT_NO_FATAL_FAILURE(TryUsingRelro(LIBNAME));
Yabin Cui294d1e22014-12-07 20:43:37 -0800472
473 // Use destructor of tf to close and unlink the file.
474 tf.fd = extinfo_.relro_fd;
Torne (Richard Coles)26ec9672014-04-30 15:48:40 +0100475}
476
477TEST_F(DlExtRelroSharingTest, ChildWritesNoRelro) {
Yabin Cui294d1e22014-12-07 20:43:37 -0800478 TemporaryFile tf; // // Use tf to get an unique filename.
479 ASSERT_NOERROR(close(tf.fd));
480
481 ASSERT_NO_FATAL_FAILURE(CreateRelroFile(LIBNAME_NORELRO, tf.filename));
Torne (Richard Coles)26ec9672014-04-30 15:48:40 +0100482 ASSERT_NO_FATAL_FAILURE(TryUsingRelro(LIBNAME_NORELRO));
Yabin Cui294d1e22014-12-07 20:43:37 -0800483
484 // Use destructor of tf to close and unlink the file.
485 tf.fd = extinfo_.relro_fd;
Torne (Richard Coles)26ec9672014-04-30 15:48:40 +0100486}
487
488TEST_F(DlExtRelroSharingTest, RelroFileEmpty) {
Torne (Richard Coles)26ec9672014-04-30 15:48:40 +0100489 ASSERT_NO_FATAL_FAILURE(TryUsingRelro(LIBNAME));
Torne (Richard Coles)183ad9d2014-02-27 13:18:00 +0000490}
Torne (Richard Coles)26052612014-05-02 14:57:42 +0100491
492TEST_F(DlExtRelroSharingTest, VerifyMemorySaving) {
Dan Albert69fb9f32014-09-03 11:30:21 -0700493 if (geteuid() != 0) {
494 GTEST_LOG_(INFO) << "This test must be run as root.\n";
495 return;
496 }
497
Yabin Cui294d1e22014-12-07 20:43:37 -0800498 TemporaryFile tf; // Use tf to get an unique filename.
499 ASSERT_NOERROR(close(tf.fd));
500
501 ASSERT_NO_FATAL_FAILURE(CreateRelroFile(LIBNAME, tf.filename));
502
Torne (Richard Coles)26052612014-05-02 14:57:42 +0100503 int pipefd[2];
504 ASSERT_NOERROR(pipe(pipefd));
505
506 size_t without_sharing, with_sharing;
507 ASSERT_NO_FATAL_FAILURE(SpawnChildrenAndMeasurePss(LIBNAME, false, &without_sharing));
508 ASSERT_NO_FATAL_FAILURE(SpawnChildrenAndMeasurePss(LIBNAME, true, &with_sharing));
509
510 // We expect the sharing to save at least 10% of the total PSS. In practice
511 // it saves 40%+ for this test.
512 size_t expected_size = without_sharing - (without_sharing/10);
513 EXPECT_LT(with_sharing, expected_size);
Yabin Cui294d1e22014-12-07 20:43:37 -0800514
515 // Use destructor of tf to close and unlink the file.
516 tf.fd = extinfo_.relro_fd;
Torne (Richard Coles)26052612014-05-02 14:57:42 +0100517}
518
519void getPss(pid_t pid, size_t* pss_out) {
520 pm_kernel_t* kernel;
521 ASSERT_EQ(0, pm_kernel_create(&kernel));
522
523 pm_process_t* process;
524 ASSERT_EQ(0, pm_process_create(kernel, pid, &process));
525
526 pm_map_t** maps;
527 size_t num_maps;
528 ASSERT_EQ(0, pm_process_maps(process, &maps, &num_maps));
529
530 size_t total_pss = 0;
531 for (size_t i = 0; i < num_maps; i++) {
532 pm_memusage_t usage;
533 ASSERT_EQ(0, pm_map_usage(maps[i], &usage));
534 total_pss += usage.pss;
535 }
536 *pss_out = total_pss;
537
538 free(maps);
539 pm_process_destroy(process);
540 pm_kernel_destroy(kernel);
541}
542
543void DlExtRelroSharingTest::SpawnChildrenAndMeasurePss(const char* lib, bool share_relro,
544 size_t* pss_out) {
545 const int CHILDREN = 20;
546
547 // Create children
548 pid_t childpid[CHILDREN];
549 int childpipe[CHILDREN];
550 for (int i=0; i<CHILDREN; ++i) {
551 char read_buf;
552 int child_done_pipe[2], parent_done_pipe[2];
553 ASSERT_NOERROR(pipe(child_done_pipe));
554 ASSERT_NOERROR(pipe(parent_done_pipe));
555
556 pid_t child = fork();
557 if (child == 0) {
558 // close the 'wrong' ends of the pipes in the child
559 close(child_done_pipe[0]);
560 close(parent_done_pipe[1]);
561
562 // open the library
563 void* handle;
564 if (share_relro) {
565 handle = android_dlopen_ext(lib, RTLD_NOW, &extinfo_);
566 } else {
567 handle = dlopen(lib, RTLD_NOW);
568 }
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -0700569 if (handle == nullptr) {
Torne (Richard Coles)26052612014-05-02 14:57:42 +0100570 fprintf(stderr, "in child: %s\n", dlerror());
571 exit(1);
572 }
573
574 // close write end of child_done_pipe to signal the parent that we're done.
575 close(child_done_pipe[1]);
576
577 // wait for the parent to close parent_done_pipe, then exit
578 read(parent_done_pipe[0], &read_buf, 1);
579 exit(0);
580 }
581
582 ASSERT_NOERROR(child);
583
584 // close the 'wrong' ends of the pipes in the parent
585 close(child_done_pipe[1]);
586 close(parent_done_pipe[0]);
587
588 // wait for the child to be done
589 read(child_done_pipe[0], &read_buf, 1);
590 close(child_done_pipe[0]);
591
592 // save the child's pid and the parent_done_pipe
593 childpid[i] = child;
594 childpipe[i] = parent_done_pipe[1];
595 }
596
597 // Sum the PSS of all the children
598 size_t total_pss = 0;
599 for (int i=0; i<CHILDREN; ++i) {
600 size_t child_pss;
601 ASSERT_NO_FATAL_FAILURE(getPss(childpid[i], &child_pss));
602 total_pss += child_pss;
603 }
604 *pss_out = total_pss;
605
606 // Close pipes and wait for children to exit
607 for (int i=0; i<CHILDREN; ++i) {
608 ASSERT_NOERROR(close(childpipe[i]));
609 }
610 for (int i=0; i<CHILDREN; ++i) {
611 int status;
612 ASSERT_EQ(childpid[i], waitpid(childpid[i], &status, 0));
613 ASSERT_TRUE(WIFEXITED(status));
614 ASSERT_EQ(0, WEXITSTATUS(status));
615 }
616}
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700617
618// Testing namespaces
619static const char* g_public_lib = "libnstest_public.so";
620
621TEST(dlext, ns_smoke) {
622 static const char* root_lib = "libnstest_root.so";
623 std::string path = std::string("libc.so:libc++.so:libdl.so:libm.so:") + g_public_lib;
624
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -0800625 ASSERT_FALSE(android_init_namespaces(path.c_str(), nullptr));
626 ASSERT_STREQ("android_init_namespaces failed: error initializing public namespace: "
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700627 "\"libnstest_public.so\" was not found in the default namespace", dlerror());
628
629 const std::string lib_path = std::string(getenv("ANDROID_DATA")) + NATIVE_TESTS_PATH;
630
Dimitry Ivanov22840aa2015-12-04 18:28:49 -0800631 const std::string lib_public_path = lib_path + "/public_namespace_libs/" + g_public_lib;
632 void* handle_public = dlopen(lib_public_path.c_str(), RTLD_NOW);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700633 ASSERT_TRUE(handle_public != nullptr) << dlerror();
634
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -0800635 ASSERT_TRUE(android_init_namespaces(path.c_str(), nullptr)) << dlerror();
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700636
637 // Check that libraries added to public namespace are NODELETE
638 dlclose(handle_public);
Dimitry Ivanov7331fe12015-12-14 14:11:17 -0800639 handle_public = dlopen((lib_path + "/public_namespace_libs/" + g_public_lib).c_str(),
640 RTLD_NOW | RTLD_NOLOAD);
641
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700642 ASSERT_TRUE(handle_public != nullptr) << dlerror();
643
Dimitry Ivanov7331fe12015-12-14 14:11:17 -0800644 android_namespace_t* ns1 =
645 android_create_namespace("private", nullptr,
646 (lib_path + "/private_namespace_libs").c_str(),
647 ANDROID_NAMESPACE_TYPE_REGULAR, nullptr);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700648 ASSERT_TRUE(ns1 != nullptr) << dlerror();
649
Dimitry Ivanov7331fe12015-12-14 14:11:17 -0800650 android_namespace_t* ns2 =
651 android_create_namespace("private_isolated", nullptr,
652 (lib_path + "/private_namespace_libs").c_str(),
653 ANDROID_NAMESPACE_TYPE_ISOLATED, nullptr);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700654 ASSERT_TRUE(ns2 != nullptr) << dlerror();
655
656 // This should not have affect search path for default namespace:
657 ASSERT_TRUE(dlopen(root_lib, RTLD_NOW) == nullptr);
658 void* handle = dlopen(g_public_lib, RTLD_NOW);
659 ASSERT_TRUE(handle != nullptr) << dlerror();
660 dlclose(handle);
661
662 android_dlextinfo extinfo;
663 extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
664 extinfo.library_namespace = ns1;
665
666 void* handle1 = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo);
667 ASSERT_TRUE(handle1 != nullptr) << dlerror();
668
669 extinfo.library_namespace = ns2;
670 void* handle2 = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo);
671 ASSERT_TRUE(handle2 != nullptr) << dlerror();
672
673 ASSERT_TRUE(handle1 != handle2);
674
Dimitry Ivanov22840aa2015-12-04 18:28:49 -0800675 // dlopen for a public library using an absolute path should work for isolated namespaces
676 extinfo.library_namespace = ns2;
677 handle = android_dlopen_ext(lib_public_path.c_str(), RTLD_NOW, &extinfo);
678 ASSERT_TRUE(handle != nullptr) << dlerror();
679 ASSERT_TRUE(handle == handle_public);
680
681 dlclose(handle);
682
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700683 typedef const char* (*fn_t)();
684
685 fn_t ns_get_local_string1 = reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_local_string"));
686 ASSERT_TRUE(ns_get_local_string1 != nullptr) << dlerror();
687 fn_t ns_get_local_string2 = reinterpret_cast<fn_t>(dlsym(handle2, "ns_get_local_string"));
688 ASSERT_TRUE(ns_get_local_string2 != nullptr) << dlerror();
689
690 EXPECT_STREQ("This string is local to root library", ns_get_local_string1());
691 EXPECT_STREQ("This string is local to root library", ns_get_local_string2());
692
693 ASSERT_TRUE(ns_get_local_string1() != ns_get_local_string2());
694
695 fn_t ns_get_private_extern_string1 =
696 reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_private_extern_string"));
697 ASSERT_TRUE(ns_get_private_extern_string1 != nullptr) << dlerror();
698 fn_t ns_get_private_extern_string2 =
699 reinterpret_cast<fn_t>(dlsym(handle2, "ns_get_private_extern_string"));
700 ASSERT_TRUE(ns_get_private_extern_string2 != nullptr) << dlerror();
701
702 EXPECT_STREQ("This string is from private namespace", ns_get_private_extern_string1());
703 EXPECT_STREQ("This string is from private namespace", ns_get_private_extern_string2());
704
705 ASSERT_TRUE(ns_get_private_extern_string1() != ns_get_private_extern_string2());
706
707 fn_t ns_get_public_extern_string1 =
708 reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_public_extern_string"));
709 ASSERT_TRUE(ns_get_public_extern_string1 != nullptr) << dlerror();
710 fn_t ns_get_public_extern_string2 =
711 reinterpret_cast<fn_t>(dlsym(handle2, "ns_get_public_extern_string"));
712 ASSERT_TRUE(ns_get_public_extern_string2 != nullptr) << dlerror();
713
714 EXPECT_STREQ("This string is from public namespace", ns_get_public_extern_string1());
715 ASSERT_TRUE(ns_get_public_extern_string1() == ns_get_public_extern_string2());
716
717 // and now check that dlopen() does the right thing in terms of preserving namespace
718 fn_t ns_get_dlopened_string1 = reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_dlopened_string"));
719 ASSERT_TRUE(ns_get_dlopened_string1 != nullptr) << dlerror();
720 fn_t ns_get_dlopened_string2 = reinterpret_cast<fn_t>(dlsym(handle2, "ns_get_dlopened_string"));
721 ASSERT_TRUE(ns_get_dlopened_string2 != nullptr) << dlerror();
722
723 EXPECT_STREQ("This string is from private namespace (dlopened library)", ns_get_dlopened_string1());
724 EXPECT_STREQ("This string is from private namespace (dlopened library)", ns_get_dlopened_string2());
725
726 ASSERT_TRUE(ns_get_dlopened_string1() != ns_get_dlopened_string2());
727
728 dlclose(handle1);
729
730 // Check if handle2 is still alive (and well)
731 ASSERT_STREQ("This string is local to root library", ns_get_local_string2());
732 ASSERT_STREQ("This string is from private namespace", ns_get_private_extern_string2());
733 ASSERT_STREQ("This string is from public namespace", ns_get_public_extern_string2());
734 ASSERT_STREQ("This string is from private namespace (dlopened library)", ns_get_dlopened_string2());
735
736 dlclose(handle2);
737}
738
Dmitriy Ivanov3cc35e22015-11-17 18:36:50 -0800739extern "C" void android_set_application_target_sdk_version(uint32_t target);
740
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700741TEST(dlext, ns_isolated) {
742 static const char* root_lib = "libnstest_root_not_isolated.so";
743 std::string path = std::string("libc.so:libc++.so:libdl.so:libm.so:") + g_public_lib;
744
745 const std::string lib_path = std::string(getenv("ANDROID_DATA")) + NATIVE_TESTS_PATH;
Dimitry Ivanov22840aa2015-12-04 18:28:49 -0800746 const std::string lib_public_path = lib_path + "/public_namespace_libs/" + g_public_lib;
747 void* handle_public = dlopen(lib_public_path.c_str(), RTLD_NOW);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700748 ASSERT_TRUE(handle_public != nullptr) << dlerror();
749
Dmitriy Ivanov3cc35e22015-11-17 18:36:50 -0800750 android_set_application_target_sdk_version(42U); // something > 23
751
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -0800752 ASSERT_TRUE(android_init_namespaces(path.c_str(), nullptr)) << dlerror();
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700753
Dimitry Ivanov7331fe12015-12-14 14:11:17 -0800754 android_namespace_t* ns_not_isolated =
755 android_create_namespace("private", nullptr,
756 (lib_path + "/private_namespace_libs").c_str(),
757 ANDROID_NAMESPACE_TYPE_REGULAR, nullptr);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700758 ASSERT_TRUE(ns_not_isolated != nullptr) << dlerror();
759
Dimitry Ivanov7331fe12015-12-14 14:11:17 -0800760 android_namespace_t* ns_isolated =
761 android_create_namespace("private_isolated1", nullptr,
762 (lib_path + "/private_namespace_libs").c_str(),
763 ANDROID_NAMESPACE_TYPE_ISOLATED, nullptr);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700764 ASSERT_TRUE(ns_isolated != nullptr) << dlerror();
765
Dimitry Ivanov7331fe12015-12-14 14:11:17 -0800766 android_namespace_t* ns_isolated2 =
767 android_create_namespace("private_isolated2",
768 (lib_path + "/private_namespace_libs").c_str(),
769 nullptr, ANDROID_NAMESPACE_TYPE_ISOLATED, lib_path.c_str());
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700770 ASSERT_TRUE(ns_isolated2 != nullptr) << dlerror();
771
772 ASSERT_TRUE(dlopen(root_lib, RTLD_NOW) == nullptr);
773 ASSERT_STREQ("dlopen failed: library \"libnstest_root_not_isolated.so\" not found", dlerror());
774
775 std::string lib_private_external_path =
776 lib_path + "/private_namespace_libs_external/libnstest_private_external.so";
777
778 // Load lib_private_external_path to default namespace
779 // (it should remain invisible for the isolated namespaces after this)
780 void* handle = dlopen(lib_private_external_path.c_str(), RTLD_NOW);
781 ASSERT_TRUE(handle != nullptr) << dlerror();
782
783 android_dlextinfo extinfo;
784 extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
785 extinfo.library_namespace = ns_not_isolated;
786
787 void* handle1 = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo);
788 ASSERT_TRUE(handle1 != nullptr) << dlerror();
789
790 extinfo.library_namespace = ns_isolated;
791
792 void* handle2 = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo);
793 ASSERT_TRUE(handle2 == nullptr);
794 ASSERT_STREQ("dlopen failed: library \"libnstest_private_external.so\" not found", dlerror());
795
796 // Check dlopen by absolute path
797 handle2 = android_dlopen_ext(lib_private_external_path.c_str(), RTLD_NOW, &extinfo);
798 ASSERT_TRUE(handle2 == nullptr);
Dimitry Ivanov22840aa2015-12-04 18:28:49 -0800799 ASSERT_EQ("dlopen failed: library \"" + lib_private_external_path + "\" is not accessible for the namespace \"private_isolated1\"", dlerror());
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700800
801 extinfo.library_namespace = ns_isolated2;
802
Dimitry Ivanov284ae352015-12-08 10:47:13 -0800803 // this should work because isolation_path for private_isolated2 includes lib_path
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700804 handle2 = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo);
Dimitry Ivanov284ae352015-12-08 10:47:13 -0800805 ASSERT_TRUE(handle2 != nullptr) << dlerror();
806 dlclose(handle2);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700807
808 // Check dlopen by absolute path
809 handle2 = android_dlopen_ext(lib_private_external_path.c_str(), RTLD_NOW, &extinfo);
Dimitry Ivanov284ae352015-12-08 10:47:13 -0800810 ASSERT_TRUE(handle2 != nullptr) << dlerror();
811 dlclose(handle2);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700812
813 typedef const char* (*fn_t)();
814 fn_t ns_get_local_string = reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_local_string"));
815 ASSERT_TRUE(ns_get_local_string != nullptr) << dlerror();
816
817 ASSERT_STREQ("This string is local to root library", ns_get_local_string());
818
819 fn_t ns_get_private_extern_string =
820 reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_private_extern_string"));
821 ASSERT_TRUE(ns_get_private_extern_string != nullptr) << dlerror();
822
823 ASSERT_STREQ("This string is from private namespace", ns_get_private_extern_string());
824
825 fn_t ns_get_public_extern_string =
826 reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_public_extern_string"));
827 ASSERT_TRUE(ns_get_public_extern_string != nullptr) << dlerror();
828
829 ASSERT_STREQ("This string is from public namespace", ns_get_public_extern_string());
830
831 fn_t ns_get_dlopened_string = reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_dlopened_string"));
832 ASSERT_TRUE(ns_get_dlopened_string != nullptr) << dlerror();
833
834 ASSERT_STREQ("This string is from private namespace (dlopened library)", ns_get_dlopened_string());
835
836 dlclose(handle1);
837}
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -0800838
Dimitry Ivanov7331fe12015-12-14 14:11:17 -0800839TEST(dlext, ns_shared) {
840 static const char* root_lib = "libnstest_root_not_isolated.so";
841 static const char* root_lib_isolated = "libnstest_root.so";
842 std::string path = std::string("libc.so:libc++.so:libdl.so:libm.so:") + g_public_lib;
843
844 const std::string lib_path = std::string(getenv("ANDROID_DATA")) + NATIVE_TESTS_PATH;
845 const std::string lib_public_path = lib_path + "/public_namespace_libs/" + g_public_lib;
846 void* handle_public = dlopen(lib_public_path.c_str(), RTLD_NOW);
847 ASSERT_TRUE(handle_public != nullptr) << dlerror();
848
849 android_set_application_target_sdk_version(42U); // something > 23
850
851 ASSERT_TRUE(android_init_namespaces(path.c_str(), nullptr)) << dlerror();
852
853 // preload this library to the default namespace to check if it
854 // is shared later on.
855 void* handle_dlopened =
856 dlopen((lib_path + "/private_namespace_libs/libnstest_dlopened.so").c_str(), RTLD_NOW);
857 ASSERT_TRUE(handle_dlopened != nullptr) << dlerror();
858
859 android_namespace_t* ns_not_isolated =
860 android_create_namespace("private", nullptr,
861 (lib_path + "/private_namespace_libs").c_str(),
862 ANDROID_NAMESPACE_TYPE_REGULAR, nullptr);
863 ASSERT_TRUE(ns_not_isolated != nullptr) << dlerror();
864
865 android_namespace_t* ns_isolated_shared =
866 android_create_namespace("private_isolated_shared", nullptr,
867 (lib_path + "/private_namespace_libs").c_str(),
868 ANDROID_NAMESPACE_TYPE_ISOLATED | ANDROID_NAMESPACE_TYPE_SHARED,
869 nullptr);
870 ASSERT_TRUE(ns_isolated_shared != nullptr) << dlerror();
871
872 ASSERT_TRUE(dlopen(root_lib, RTLD_NOW) == nullptr);
873 ASSERT_STREQ("dlopen failed: library \"libnstest_root_not_isolated.so\" not found", dlerror());
874
875 std::string lib_private_external_path =
876 lib_path + "/private_namespace_libs_external/libnstest_private_external.so";
877
878 // Load lib_private_external_path to default namespace
879 // (it should remain invisible for the isolated namespaces after this)
880 void* handle = dlopen(lib_private_external_path.c_str(), RTLD_NOW);
881 ASSERT_TRUE(handle != nullptr) << dlerror();
882
883 android_dlextinfo extinfo;
884 extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
885 extinfo.library_namespace = ns_not_isolated;
886
887 void* handle1 = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo);
888 ASSERT_TRUE(handle1 != nullptr) << dlerror();
889
890 extinfo.library_namespace = ns_isolated_shared;
891
892 void* handle2 = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo);
893 ASSERT_TRUE(handle2 == nullptr);
894 ASSERT_STREQ("dlopen failed: library \"libnstest_private_external.so\" not found", dlerror());
895
896 // Check dlopen by absolute path
897 handle2 = android_dlopen_ext(lib_private_external_path.c_str(), RTLD_NOW, &extinfo);
898 ASSERT_TRUE(handle2 == nullptr);
899 ASSERT_EQ("dlopen failed: library \"" + lib_private_external_path + "\" is not accessible for the namespace \"private_isolated_shared\"", dlerror());
900
901 // load libnstest_root.so to shared namespace in order to check that everything is different
902 // except shared libnstest_dlopened.so
903
904 handle2 = android_dlopen_ext(root_lib_isolated, RTLD_NOW, &extinfo);
905
906 typedef const char* (*fn_t)();
907 fn_t ns_get_local_string = reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_local_string"));
908 ASSERT_TRUE(ns_get_local_string != nullptr) << dlerror();
909 fn_t ns_get_local_string_shared = reinterpret_cast<fn_t>(dlsym(handle2, "ns_get_local_string"));
910 ASSERT_TRUE(ns_get_local_string_shared != nullptr) << dlerror();
911
912 ASSERT_STREQ("This string is local to root library", ns_get_local_string());
913 ASSERT_STREQ("This string is local to root library", ns_get_local_string_shared());
914 ASSERT_TRUE(ns_get_local_string() != ns_get_local_string_shared());
915
916 fn_t ns_get_private_extern_string =
917 reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_private_extern_string"));
918 ASSERT_TRUE(ns_get_private_extern_string != nullptr) << dlerror();
919 fn_t ns_get_private_extern_string_shared =
920 reinterpret_cast<fn_t>(dlsym(handle2, "ns_get_private_extern_string"));
921 ASSERT_TRUE(ns_get_private_extern_string_shared() != nullptr) << dlerror();
922
923 ASSERT_STREQ("This string is from private namespace", ns_get_private_extern_string());
924 ASSERT_STREQ("This string is from private namespace", ns_get_private_extern_string_shared());
925 ASSERT_TRUE(ns_get_private_extern_string() != ns_get_private_extern_string_shared());
926
927 fn_t ns_get_public_extern_string =
928 reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_public_extern_string"));
929 ASSERT_TRUE(ns_get_public_extern_string != nullptr) << dlerror();
930 fn_t ns_get_public_extern_string_shared =
931 reinterpret_cast<fn_t>(dlsym(handle2, "ns_get_public_extern_string"));
932 ASSERT_TRUE(ns_get_public_extern_string_shared != nullptr) << dlerror();
933
934 ASSERT_STREQ("This string is from public namespace", ns_get_public_extern_string());
935 ASSERT_STREQ("This string is from public namespace", ns_get_public_extern_string_shared());
936 ASSERT_TRUE(ns_get_public_extern_string() == ns_get_public_extern_string_shared());
937
938 fn_t ns_get_dlopened_string = reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_dlopened_string"));
939 ASSERT_TRUE(ns_get_dlopened_string != nullptr) << dlerror();
940 fn_t ns_get_dlopened_string_shared = reinterpret_cast<fn_t>(dlsym(handle2, "ns_get_dlopened_string"));
941 ASSERT_TRUE(ns_get_dlopened_string_shared != nullptr) << dlerror();
942 const char** ns_dlopened_string = static_cast<const char**>(dlsym(handle_dlopened, "g_private_dlopened_string"));
943 ASSERT_TRUE(ns_dlopened_string != nullptr) << dlerror();
944
945 ASSERT_STREQ("This string is from private namespace (dlopened library)", ns_get_dlopened_string());
946 ASSERT_STREQ("This string is from private namespace (dlopened library)", *ns_dlopened_string);
947 ASSERT_STREQ("This string is from private namespace (dlopened library)", ns_get_dlopened_string_shared());
948 ASSERT_TRUE(ns_get_dlopened_string() != ns_get_dlopened_string_shared());
949 ASSERT_TRUE(*ns_dlopened_string == ns_get_dlopened_string_shared());
950
951 dlclose(handle1);
952 dlclose(handle2);
953}
954
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -0800955TEST(dlext, ns_anonymous) {
956 static const char* root_lib = "libnstest_root.so";
957 std::string path = std::string("libc.so:libc++.so:libdl.so:libm.so:") + g_public_lib;
958
959 const std::string lib_path = std::string(getenv("ANDROID_DATA")) + NATIVE_TESTS_PATH;
960
Dimitry Ivanov22840aa2015-12-04 18:28:49 -0800961 const std::string lib_public_path = lib_path + "/public_namespace_libs/" + g_public_lib;
962 void* handle_public = dlopen(lib_public_path.c_str(), RTLD_NOW);
963
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -0800964 ASSERT_TRUE(handle_public != nullptr) << dlerror();
965
966 ASSERT_TRUE(android_init_namespaces(path.c_str(), (lib_path + "/private_namespace_libs").c_str()))
967 << dlerror();
968
969 android_namespace_t* ns = android_create_namespace(
970 "private", nullptr,
971 (lib_path + "/private_namespace_libs").c_str(),
Dimitry Ivanov7331fe12015-12-14 14:11:17 -0800972 ANDROID_NAMESPACE_TYPE_REGULAR, nullptr);
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -0800973
974 ASSERT_TRUE(ns != nullptr) << dlerror();
975
976 std::string private_library_absolute_path = lib_path + "/private_namespace_libs/" + root_lib;
977
978 android_dlextinfo extinfo;
979 extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
980 extinfo.library_namespace = ns;
981
982 // we are going to copy this library to anonymous mmap and call the copy of ns_get_dlopened_string
983 void* handle = android_dlopen_ext(private_library_absolute_path.c_str(), RTLD_NOW, &extinfo);
984 ASSERT_TRUE(handle != nullptr) << dlerror();
985
986 uintptr_t ns_get_dlopened_string_addr =
987 reinterpret_cast<uintptr_t>(dlsym(handle, "ns_get_dlopened_string"));
988 ASSERT_TRUE(ns_get_dlopened_string_addr != 0) << dlerror();
989 typedef const char* (*fn_t)();
990 fn_t ns_get_dlopened_string_private = reinterpret_cast<fn_t>(ns_get_dlopened_string_addr);
991
992 std::vector<map_record> maps;
993 Maps::parse_maps(&maps);
994
995 uintptr_t addr_start = 0;
996 uintptr_t addr_end = 0;
997 std::vector<map_record> maps_to_copy;
998
999 for (const auto& rec : maps) {
1000 if (rec.pathname == private_library_absolute_path) {
1001 if (addr_start == 0) {
1002 addr_start = rec.addr_start;
1003 }
1004 addr_end = rec.addr_end;
1005
1006 maps_to_copy.push_back(rec);
1007 }
1008 }
1009
1010 // some sanity checks..
1011 ASSERT_TRUE(addr_start > 0);
1012 ASSERT_TRUE(addr_end > 0);
1013 ASSERT_EQ(3U, maps_to_copy.size());
1014 ASSERT_TRUE(ns_get_dlopened_string_addr > addr_start);
1015 ASSERT_TRUE(ns_get_dlopened_string_addr < addr_end);
1016
1017 // copy
1018 uintptr_t reserved_addr = reinterpret_cast<uintptr_t>(mmap(nullptr, addr_end - addr_start,
1019 PROT_NONE, MAP_ANON | MAP_PRIVATE,
1020 -1, 0));
1021 ASSERT_TRUE(reinterpret_cast<void*>(reserved_addr) != MAP_FAILED);
1022
1023 for (const auto& rec : maps_to_copy) {
1024 uintptr_t offset = rec.addr_start - addr_start;
1025 size_t size = rec.addr_end - rec.addr_start;
1026 void* addr = reinterpret_cast<void*>(reserved_addr + offset);
1027 void* map = mmap(addr, size, PROT_READ | PROT_WRITE,
1028 MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, 0);
1029 ASSERT_TRUE(map != MAP_FAILED);
1030 memcpy(map, reinterpret_cast<void*>(rec.addr_start), size);
1031 mprotect(map, size, rec.perms);
1032 }
1033
1034 // call the function copy
1035 uintptr_t ns_get_dlopened_string_offset = ns_get_dlopened_string_addr - addr_start;
1036 fn_t ns_get_dlopened_string_anon = reinterpret_cast<fn_t>(reserved_addr + ns_get_dlopened_string_offset);
1037 ASSERT_STREQ("This string is from private namespace (dlopened library)",
1038 ns_get_dlopened_string_anon());
1039
1040 // They should belong to different namespaces (private and anonymous)
1041 ASSERT_STREQ("This string is from private namespace (dlopened library)",
1042 ns_get_dlopened_string_private());
1043
1044 ASSERT_TRUE(ns_get_dlopened_string_anon() != ns_get_dlopened_string_private());
1045}