blob: c221402a7bc7c3c2ca1c95943467d4033a82d5e0 [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
Dimitry Ivanovf45b0e92016-01-15 11:13:35 -0800289 uint32_t* taxicab_number =
290 reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_testlib_taxicab_number"));
Dmitriy Ivanovb4827502015-09-28 16:38:31 -0700291 ASSERT_DL_NOTNULL(taxicab_number);
292 EXPECT_EQ(1729U, *taxicab_number);
293
Dmitriy Ivanov52393a52015-03-18 22:50:01 -0700294 dlclose(handle);
295}
296
297
Torne (Richard Coles)12bbb912014-02-06 14:34:21 +0000298TEST_F(DlExtTest, Reserved) {
Dimitry Ivanovf45b0e92016-01-15 11:13:35 -0800299 void* start = mmap(nullptr, LIBSIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
Torne (Richard Coles)12bbb912014-02-06 14:34:21 +0000300 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());
Dimitry Ivanovf45b0e92016-01-15 11:13:35 -0800313
314 // Check that after dlclose reserved address space is unmapped (and can be reused)
315 dlclose(handle_);
316 handle_ = nullptr;
317
318 void* new_start = mmap(start, PAGE_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
319 ASSERT_NE(start, new_start) << "dlclose unmapped reserved space";
Torne (Richard Coles)12bbb912014-02-06 14:34:21 +0000320}
321
322TEST_F(DlExtTest, ReservedTooSmall) {
Dimitry Ivanovf45b0e92016-01-15 11:13:35 -0800323 void* start = mmap(nullptr, PAGE_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
Torne (Richard Coles)12bbb912014-02-06 14:34:21 +0000324 ASSERT_TRUE(start != MAP_FAILED);
325 android_dlextinfo extinfo;
326 extinfo.flags = ANDROID_DLEXT_RESERVED_ADDRESS;
327 extinfo.reserved_addr = start;
328 extinfo.reserved_size = PAGE_SIZE;
329 handle_ = android_dlopen_ext(LIBNAME, RTLD_NOW, &extinfo);
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -0700330 EXPECT_EQ(nullptr, handle_);
Torne (Richard Coles)12bbb912014-02-06 14:34:21 +0000331}
332
333TEST_F(DlExtTest, ReservedHint) {
Dimitry Ivanovf45b0e92016-01-15 11:13:35 -0800334 void* start = mmap(nullptr, LIBSIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
Torne (Richard Coles)12bbb912014-02-06 14:34:21 +0000335 ASSERT_TRUE(start != MAP_FAILED);
336 android_dlextinfo extinfo;
337 extinfo.flags = ANDROID_DLEXT_RESERVED_ADDRESS_HINT;
338 extinfo.reserved_addr = start;
339 extinfo.reserved_size = LIBSIZE;
340 handle_ = android_dlopen_ext(LIBNAME, RTLD_NOW, &extinfo);
341 ASSERT_DL_NOTNULL(handle_);
342 fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber"));
343 ASSERT_DL_NOTNULL(f);
Chih-Hung Hsieha2c6ae62014-08-27 13:45:37 -0700344 EXPECT_GE(reinterpret_cast<void*>(f), start);
Torne (Richard Coles)12bbb912014-02-06 14:34:21 +0000345 EXPECT_LT(reinterpret_cast<void*>(f),
346 reinterpret_cast<char*>(start) + LIBSIZE);
347 EXPECT_EQ(4, f());
348}
349
350TEST_F(DlExtTest, ReservedHintTooSmall) {
Dimitry Ivanovf45b0e92016-01-15 11:13:35 -0800351 void* start = mmap(nullptr, PAGE_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
Torne (Richard Coles)12bbb912014-02-06 14:34:21 +0000352 ASSERT_TRUE(start != MAP_FAILED);
353 android_dlextinfo extinfo;
354 extinfo.flags = ANDROID_DLEXT_RESERVED_ADDRESS_HINT;
355 extinfo.reserved_addr = start;
356 extinfo.reserved_size = PAGE_SIZE;
357 handle_ = android_dlopen_ext(LIBNAME, RTLD_NOW, &extinfo);
358 ASSERT_DL_NOTNULL(handle_);
359 fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber"));
360 ASSERT_DL_NOTNULL(f);
Chih-Hung Hsieha2c6ae62014-08-27 13:45:37 -0700361 EXPECT_TRUE(reinterpret_cast<void*>(f) < start ||
362 (reinterpret_cast<void*>(f) >=
363 reinterpret_cast<char*>(start) + PAGE_SIZE));
Torne (Richard Coles)12bbb912014-02-06 14:34:21 +0000364 EXPECT_EQ(4, f());
365}
Torne (Richard Coles)183ad9d2014-02-27 13:18:00 +0000366
Dmitriy Ivanov126af752015-10-07 16:34:20 -0700367TEST_F(DlExtTest, LoadAtFixedAddress) {
Dimitry Ivanovf45b0e92016-01-15 11:13:35 -0800368 void* start = mmap(nullptr, LIBSIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
Dmitriy Ivanov126af752015-10-07 16:34:20 -0700369 ASSERT_TRUE(start != MAP_FAILED);
370 munmap(start, LIBSIZE);
371
372 android_dlextinfo extinfo;
373 extinfo.flags = ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS;
374 extinfo.reserved_addr = start;
375
376 handle_ = android_dlopen_ext(LIBNAME, RTLD_NOW, &extinfo);
377 ASSERT_DL_NOTNULL(handle_);
378 fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber"));
379 ASSERT_DL_NOTNULL(f);
380 EXPECT_GE(reinterpret_cast<void*>(f), start);
381 EXPECT_LT(reinterpret_cast<void*>(f), reinterpret_cast<char*>(start) + LIBSIZE);
382
383 EXPECT_EQ(4, f());
Dimitry Ivanovf45b0e92016-01-15 11:13:35 -0800384 dlclose(handle_);
385 handle_ = nullptr;
386
387 // Check that dlclose unmapped the file
388 void* addr = mmap(start, LIBSIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
389 ASSERT_EQ(start, addr) << "dlclose did not unmap the memory";
Dmitriy Ivanov126af752015-10-07 16:34:20 -0700390}
391
392TEST_F(DlExtTest, LoadAtFixedAddressTooSmall) {
393 void* start = mmap(nullptr, LIBSIZE + PAGE_SIZE, PROT_NONE,
394 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
395 ASSERT_TRUE(start != MAP_FAILED);
396 munmap(start, LIBSIZE + PAGE_SIZE);
397 void* new_addr = mmap(reinterpret_cast<uint8_t*>(start) + PAGE_SIZE, LIBSIZE, PROT_NONE,
398 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
399 ASSERT_TRUE(new_addr != MAP_FAILED);
400
401 android_dlextinfo extinfo;
402 extinfo.flags = ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS;
403 extinfo.reserved_addr = start;
404
405 handle_ = android_dlopen_ext(LIBNAME, RTLD_NOW, &extinfo);
406 ASSERT_TRUE(handle_ == nullptr);
407}
408
Torne (Richard Coles)26ec9672014-04-30 15:48:40 +0100409class DlExtRelroSharingTest : public DlExtTest {
410protected:
411 virtual void SetUp() {
412 DlExtTest::SetUp();
Dimitry Ivanovf45b0e92016-01-15 11:13:35 -0800413 void* start = mmap(nullptr, LIBSIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
Torne (Richard Coles)26ec9672014-04-30 15:48:40 +0100414 ASSERT_TRUE(start != MAP_FAILED);
415 extinfo_.flags = ANDROID_DLEXT_RESERVED_ADDRESS;
416 extinfo_.reserved_addr = start;
417 extinfo_.reserved_size = LIBSIZE;
418 extinfo_.relro_fd = -1;
Torne (Richard Coles)183ad9d2014-02-27 13:18:00 +0000419 }
420
Torne (Richard Coles)26ec9672014-04-30 15:48:40 +0100421 virtual void TearDown() {
422 DlExtTest::TearDown();
Torne (Richard Coles)26ec9672014-04-30 15:48:40 +0100423 }
Torne (Richard Coles)183ad9d2014-02-27 13:18:00 +0000424
Yabin Cui294d1e22014-12-07 20:43:37 -0800425 void CreateRelroFile(const char* lib, const char* relro_file) {
426 int relro_fd = open(relro_file, O_RDWR | O_TRUNC);
Torne (Richard Coles)26ec9672014-04-30 15:48:40 +0100427 ASSERT_NOERROR(relro_fd);
428
429 pid_t pid = fork();
430 if (pid == 0) {
431 // child process
432 extinfo_.flags |= ANDROID_DLEXT_WRITE_RELRO;
433 extinfo_.relro_fd = relro_fd;
434 void* handle = android_dlopen_ext(lib, RTLD_NOW, &extinfo_);
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -0700435 if (handle == nullptr) {
Torne (Richard Coles)26ec9672014-04-30 15:48:40 +0100436 fprintf(stderr, "in child: %s\n", dlerror());
437 exit(1);
438 }
439 exit(0);
440 }
441
442 // continuing in parent
443 ASSERT_NOERROR(close(relro_fd));
444 ASSERT_NOERROR(pid);
445 int status;
446 ASSERT_EQ(pid, waitpid(pid, &status, 0));
447 ASSERT_TRUE(WIFEXITED(status));
448 ASSERT_EQ(0, WEXITSTATUS(status));
449
450 // reopen file for reading so it can be used
Yabin Cui294d1e22014-12-07 20:43:37 -0800451 relro_fd = open(relro_file, O_RDONLY);
Torne (Richard Coles)26ec9672014-04-30 15:48:40 +0100452 ASSERT_NOERROR(relro_fd);
453 extinfo_.flags |= ANDROID_DLEXT_USE_RELRO;
454 extinfo_.relro_fd = relro_fd;
455 }
456
457 void TryUsingRelro(const char* lib) {
458 handle_ = android_dlopen_ext(lib, RTLD_NOW, &extinfo_);
459 ASSERT_DL_NOTNULL(handle_);
460 fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber"));
461 ASSERT_DL_NOTNULL(f);
462 EXPECT_EQ(4, f());
Dmitriy Ivanovedfc9f62015-09-02 16:32:02 -0700463
Dimitry Ivanovf45b0e92016-01-15 11:13:35 -0800464 uint32_t* taxicab_number =
465 reinterpret_cast<uint32_t*>(dlsym(handle_, "dlopen_testlib_taxicab_number"));
Dmitriy Ivanovedfc9f62015-09-02 16:32:02 -0700466 ASSERT_DL_NOTNULL(taxicab_number);
467 EXPECT_EQ(1729U, *taxicab_number);
Torne (Richard Coles)26ec9672014-04-30 15:48:40 +0100468 }
469
Torne (Richard Coles)26052612014-05-02 14:57:42 +0100470 void SpawnChildrenAndMeasurePss(const char* lib, bool share_relro, size_t* pss_out);
471
Torne (Richard Coles)26ec9672014-04-30 15:48:40 +0100472 android_dlextinfo extinfo_;
Torne (Richard Coles)26ec9672014-04-30 15:48:40 +0100473};
474
475TEST_F(DlExtRelroSharingTest, ChildWritesGoodData) {
Yabin Cui294d1e22014-12-07 20:43:37 -0800476 TemporaryFile tf; // Use tf to get an unique filename.
477 ASSERT_NOERROR(close(tf.fd));
478
479 ASSERT_NO_FATAL_FAILURE(CreateRelroFile(LIBNAME, tf.filename));
Torne (Richard Coles)26ec9672014-04-30 15:48:40 +0100480 ASSERT_NO_FATAL_FAILURE(TryUsingRelro(LIBNAME));
Yabin Cui294d1e22014-12-07 20:43:37 -0800481
482 // Use destructor of tf to close and unlink the file.
483 tf.fd = extinfo_.relro_fd;
Torne (Richard Coles)26ec9672014-04-30 15:48:40 +0100484}
485
486TEST_F(DlExtRelroSharingTest, ChildWritesNoRelro) {
Yabin Cui294d1e22014-12-07 20:43:37 -0800487 TemporaryFile tf; // // Use tf to get an unique filename.
488 ASSERT_NOERROR(close(tf.fd));
489
490 ASSERT_NO_FATAL_FAILURE(CreateRelroFile(LIBNAME_NORELRO, tf.filename));
Torne (Richard Coles)26ec9672014-04-30 15:48:40 +0100491 ASSERT_NO_FATAL_FAILURE(TryUsingRelro(LIBNAME_NORELRO));
Yabin Cui294d1e22014-12-07 20:43:37 -0800492
493 // Use destructor of tf to close and unlink the file.
494 tf.fd = extinfo_.relro_fd;
Torne (Richard Coles)26ec9672014-04-30 15:48:40 +0100495}
496
497TEST_F(DlExtRelroSharingTest, RelroFileEmpty) {
Torne (Richard Coles)26ec9672014-04-30 15:48:40 +0100498 ASSERT_NO_FATAL_FAILURE(TryUsingRelro(LIBNAME));
Torne (Richard Coles)183ad9d2014-02-27 13:18:00 +0000499}
Torne (Richard Coles)26052612014-05-02 14:57:42 +0100500
501TEST_F(DlExtRelroSharingTest, VerifyMemorySaving) {
Dan Albert69fb9f32014-09-03 11:30:21 -0700502 if (geteuid() != 0) {
503 GTEST_LOG_(INFO) << "This test must be run as root.\n";
504 return;
505 }
506
Yabin Cui294d1e22014-12-07 20:43:37 -0800507 TemporaryFile tf; // Use tf to get an unique filename.
508 ASSERT_NOERROR(close(tf.fd));
509
510 ASSERT_NO_FATAL_FAILURE(CreateRelroFile(LIBNAME, tf.filename));
511
Torne (Richard Coles)26052612014-05-02 14:57:42 +0100512 int pipefd[2];
513 ASSERT_NOERROR(pipe(pipefd));
514
515 size_t without_sharing, with_sharing;
516 ASSERT_NO_FATAL_FAILURE(SpawnChildrenAndMeasurePss(LIBNAME, false, &without_sharing));
517 ASSERT_NO_FATAL_FAILURE(SpawnChildrenAndMeasurePss(LIBNAME, true, &with_sharing));
518
519 // We expect the sharing to save at least 10% of the total PSS. In practice
520 // it saves 40%+ for this test.
521 size_t expected_size = without_sharing - (without_sharing/10);
522 EXPECT_LT(with_sharing, expected_size);
Yabin Cui294d1e22014-12-07 20:43:37 -0800523
524 // Use destructor of tf to close and unlink the file.
525 tf.fd = extinfo_.relro_fd;
Torne (Richard Coles)26052612014-05-02 14:57:42 +0100526}
527
528void getPss(pid_t pid, size_t* pss_out) {
529 pm_kernel_t* kernel;
530 ASSERT_EQ(0, pm_kernel_create(&kernel));
531
532 pm_process_t* process;
533 ASSERT_EQ(0, pm_process_create(kernel, pid, &process));
534
535 pm_map_t** maps;
536 size_t num_maps;
537 ASSERT_EQ(0, pm_process_maps(process, &maps, &num_maps));
538
539 size_t total_pss = 0;
540 for (size_t i = 0; i < num_maps; i++) {
541 pm_memusage_t usage;
542 ASSERT_EQ(0, pm_map_usage(maps[i], &usage));
543 total_pss += usage.pss;
544 }
545 *pss_out = total_pss;
546
547 free(maps);
548 pm_process_destroy(process);
549 pm_kernel_destroy(kernel);
550}
551
552void DlExtRelroSharingTest::SpawnChildrenAndMeasurePss(const char* lib, bool share_relro,
553 size_t* pss_out) {
554 const int CHILDREN = 20;
555
556 // Create children
557 pid_t childpid[CHILDREN];
558 int childpipe[CHILDREN];
559 for (int i=0; i<CHILDREN; ++i) {
560 char read_buf;
561 int child_done_pipe[2], parent_done_pipe[2];
562 ASSERT_NOERROR(pipe(child_done_pipe));
563 ASSERT_NOERROR(pipe(parent_done_pipe));
564
565 pid_t child = fork();
566 if (child == 0) {
567 // close the 'wrong' ends of the pipes in the child
568 close(child_done_pipe[0]);
569 close(parent_done_pipe[1]);
570
571 // open the library
572 void* handle;
573 if (share_relro) {
574 handle = android_dlopen_ext(lib, RTLD_NOW, &extinfo_);
575 } else {
576 handle = dlopen(lib, RTLD_NOW);
577 }
Dmitriy Ivanov07e5bc12014-10-03 17:52:44 -0700578 if (handle == nullptr) {
Torne (Richard Coles)26052612014-05-02 14:57:42 +0100579 fprintf(stderr, "in child: %s\n", dlerror());
580 exit(1);
581 }
582
583 // close write end of child_done_pipe to signal the parent that we're done.
584 close(child_done_pipe[1]);
585
586 // wait for the parent to close parent_done_pipe, then exit
587 read(parent_done_pipe[0], &read_buf, 1);
588 exit(0);
589 }
590
591 ASSERT_NOERROR(child);
592
593 // close the 'wrong' ends of the pipes in the parent
594 close(child_done_pipe[1]);
595 close(parent_done_pipe[0]);
596
597 // wait for the child to be done
598 read(child_done_pipe[0], &read_buf, 1);
599 close(child_done_pipe[0]);
600
601 // save the child's pid and the parent_done_pipe
602 childpid[i] = child;
603 childpipe[i] = parent_done_pipe[1];
604 }
605
606 // Sum the PSS of all the children
607 size_t total_pss = 0;
608 for (int i=0; i<CHILDREN; ++i) {
609 size_t child_pss;
610 ASSERT_NO_FATAL_FAILURE(getPss(childpid[i], &child_pss));
611 total_pss += child_pss;
612 }
613 *pss_out = total_pss;
614
615 // Close pipes and wait for children to exit
616 for (int i=0; i<CHILDREN; ++i) {
617 ASSERT_NOERROR(close(childpipe[i]));
618 }
619 for (int i=0; i<CHILDREN; ++i) {
620 int status;
621 ASSERT_EQ(childpid[i], waitpid(childpid[i], &status, 0));
622 ASSERT_TRUE(WIFEXITED(status));
623 ASSERT_EQ(0, WEXITSTATUS(status));
624 }
625}
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700626
627// Testing namespaces
628static const char* g_public_lib = "libnstest_public.so";
629
630TEST(dlext, ns_smoke) {
631 static const char* root_lib = "libnstest_root.so";
632 std::string path = std::string("libc.so:libc++.so:libdl.so:libm.so:") + g_public_lib;
633
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -0800634 ASSERT_FALSE(android_init_namespaces(path.c_str(), nullptr));
635 ASSERT_STREQ("android_init_namespaces failed: error initializing public namespace: "
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700636 "\"libnstest_public.so\" was not found in the default namespace", dlerror());
637
638 const std::string lib_path = std::string(getenv("ANDROID_DATA")) + NATIVE_TESTS_PATH;
639
Dimitry Ivanov22840aa2015-12-04 18:28:49 -0800640 const std::string lib_public_path = lib_path + "/public_namespace_libs/" + g_public_lib;
641 void* handle_public = dlopen(lib_public_path.c_str(), RTLD_NOW);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700642 ASSERT_TRUE(handle_public != nullptr) << dlerror();
643
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -0800644 ASSERT_TRUE(android_init_namespaces(path.c_str(), nullptr)) << dlerror();
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700645
646 // Check that libraries added to public namespace are NODELETE
647 dlclose(handle_public);
Dimitry Ivanov7331fe12015-12-14 14:11:17 -0800648 handle_public = dlopen((lib_path + "/public_namespace_libs/" + g_public_lib).c_str(),
649 RTLD_NOW | RTLD_NOLOAD);
650
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700651 ASSERT_TRUE(handle_public != nullptr) << dlerror();
652
Dimitry Ivanov7331fe12015-12-14 14:11:17 -0800653 android_namespace_t* ns1 =
654 android_create_namespace("private", nullptr,
655 (lib_path + "/private_namespace_libs").c_str(),
656 ANDROID_NAMESPACE_TYPE_REGULAR, nullptr);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700657 ASSERT_TRUE(ns1 != nullptr) << dlerror();
658
Dimitry Ivanov7331fe12015-12-14 14:11:17 -0800659 android_namespace_t* ns2 =
660 android_create_namespace("private_isolated", nullptr,
661 (lib_path + "/private_namespace_libs").c_str(),
662 ANDROID_NAMESPACE_TYPE_ISOLATED, nullptr);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700663 ASSERT_TRUE(ns2 != nullptr) << dlerror();
664
665 // This should not have affect search path for default namespace:
666 ASSERT_TRUE(dlopen(root_lib, RTLD_NOW) == nullptr);
667 void* handle = dlopen(g_public_lib, RTLD_NOW);
668 ASSERT_TRUE(handle != nullptr) << dlerror();
669 dlclose(handle);
670
671 android_dlextinfo extinfo;
672 extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
673 extinfo.library_namespace = ns1;
674
675 void* handle1 = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo);
676 ASSERT_TRUE(handle1 != nullptr) << dlerror();
677
678 extinfo.library_namespace = ns2;
679 void* handle2 = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo);
680 ASSERT_TRUE(handle2 != nullptr) << dlerror();
681
682 ASSERT_TRUE(handle1 != handle2);
683
Dimitry Ivanov22840aa2015-12-04 18:28:49 -0800684 // dlopen for a public library using an absolute path should work for isolated namespaces
685 extinfo.library_namespace = ns2;
686 handle = android_dlopen_ext(lib_public_path.c_str(), RTLD_NOW, &extinfo);
687 ASSERT_TRUE(handle != nullptr) << dlerror();
688 ASSERT_TRUE(handle == handle_public);
689
690 dlclose(handle);
691
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700692 typedef const char* (*fn_t)();
693
694 fn_t ns_get_local_string1 = reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_local_string"));
695 ASSERT_TRUE(ns_get_local_string1 != nullptr) << dlerror();
696 fn_t ns_get_local_string2 = reinterpret_cast<fn_t>(dlsym(handle2, "ns_get_local_string"));
697 ASSERT_TRUE(ns_get_local_string2 != nullptr) << dlerror();
698
699 EXPECT_STREQ("This string is local to root library", ns_get_local_string1());
700 EXPECT_STREQ("This string is local to root library", ns_get_local_string2());
701
702 ASSERT_TRUE(ns_get_local_string1() != ns_get_local_string2());
703
704 fn_t ns_get_private_extern_string1 =
705 reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_private_extern_string"));
706 ASSERT_TRUE(ns_get_private_extern_string1 != nullptr) << dlerror();
707 fn_t ns_get_private_extern_string2 =
708 reinterpret_cast<fn_t>(dlsym(handle2, "ns_get_private_extern_string"));
709 ASSERT_TRUE(ns_get_private_extern_string2 != nullptr) << dlerror();
710
711 EXPECT_STREQ("This string is from private namespace", ns_get_private_extern_string1());
712 EXPECT_STREQ("This string is from private namespace", ns_get_private_extern_string2());
713
714 ASSERT_TRUE(ns_get_private_extern_string1() != ns_get_private_extern_string2());
715
716 fn_t ns_get_public_extern_string1 =
717 reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_public_extern_string"));
718 ASSERT_TRUE(ns_get_public_extern_string1 != nullptr) << dlerror();
719 fn_t ns_get_public_extern_string2 =
720 reinterpret_cast<fn_t>(dlsym(handle2, "ns_get_public_extern_string"));
721 ASSERT_TRUE(ns_get_public_extern_string2 != nullptr) << dlerror();
722
723 EXPECT_STREQ("This string is from public namespace", ns_get_public_extern_string1());
724 ASSERT_TRUE(ns_get_public_extern_string1() == ns_get_public_extern_string2());
725
726 // and now check that dlopen() does the right thing in terms of preserving namespace
727 fn_t ns_get_dlopened_string1 = reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_dlopened_string"));
728 ASSERT_TRUE(ns_get_dlopened_string1 != nullptr) << dlerror();
729 fn_t ns_get_dlopened_string2 = reinterpret_cast<fn_t>(dlsym(handle2, "ns_get_dlopened_string"));
730 ASSERT_TRUE(ns_get_dlopened_string2 != nullptr) << dlerror();
731
732 EXPECT_STREQ("This string is from private namespace (dlopened library)", ns_get_dlopened_string1());
733 EXPECT_STREQ("This string is from private namespace (dlopened library)", ns_get_dlopened_string2());
734
735 ASSERT_TRUE(ns_get_dlopened_string1() != ns_get_dlopened_string2());
736
737 dlclose(handle1);
738
739 // Check if handle2 is still alive (and well)
740 ASSERT_STREQ("This string is local to root library", ns_get_local_string2());
741 ASSERT_STREQ("This string is from private namespace", ns_get_private_extern_string2());
742 ASSERT_STREQ("This string is from public namespace", ns_get_public_extern_string2());
743 ASSERT_STREQ("This string is from private namespace (dlopened library)", ns_get_dlopened_string2());
744
745 dlclose(handle2);
746}
747
Dmitriy Ivanov3cc35e22015-11-17 18:36:50 -0800748extern "C" void android_set_application_target_sdk_version(uint32_t target);
749
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700750TEST(dlext, ns_isolated) {
751 static const char* root_lib = "libnstest_root_not_isolated.so";
752 std::string path = std::string("libc.so:libc++.so:libdl.so:libm.so:") + g_public_lib;
753
754 const std::string lib_path = std::string(getenv("ANDROID_DATA")) + NATIVE_TESTS_PATH;
Dimitry Ivanov22840aa2015-12-04 18:28:49 -0800755 const std::string lib_public_path = lib_path + "/public_namespace_libs/" + g_public_lib;
756 void* handle_public = dlopen(lib_public_path.c_str(), RTLD_NOW);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700757 ASSERT_TRUE(handle_public != nullptr) << dlerror();
758
Dmitriy Ivanov3cc35e22015-11-17 18:36:50 -0800759 android_set_application_target_sdk_version(42U); // something > 23
760
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -0800761 ASSERT_TRUE(android_init_namespaces(path.c_str(), nullptr)) << dlerror();
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700762
Dimitry Ivanov7331fe12015-12-14 14:11:17 -0800763 android_namespace_t* ns_not_isolated =
764 android_create_namespace("private", nullptr,
765 (lib_path + "/private_namespace_libs").c_str(),
766 ANDROID_NAMESPACE_TYPE_REGULAR, nullptr);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700767 ASSERT_TRUE(ns_not_isolated != nullptr) << dlerror();
768
Dimitry Ivanov7331fe12015-12-14 14:11:17 -0800769 android_namespace_t* ns_isolated =
770 android_create_namespace("private_isolated1", nullptr,
771 (lib_path + "/private_namespace_libs").c_str(),
772 ANDROID_NAMESPACE_TYPE_ISOLATED, nullptr);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700773 ASSERT_TRUE(ns_isolated != nullptr) << dlerror();
774
Dimitry Ivanov7331fe12015-12-14 14:11:17 -0800775 android_namespace_t* ns_isolated2 =
776 android_create_namespace("private_isolated2",
777 (lib_path + "/private_namespace_libs").c_str(),
778 nullptr, ANDROID_NAMESPACE_TYPE_ISOLATED, lib_path.c_str());
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700779 ASSERT_TRUE(ns_isolated2 != nullptr) << dlerror();
780
781 ASSERT_TRUE(dlopen(root_lib, RTLD_NOW) == nullptr);
782 ASSERT_STREQ("dlopen failed: library \"libnstest_root_not_isolated.so\" not found", dlerror());
783
784 std::string lib_private_external_path =
785 lib_path + "/private_namespace_libs_external/libnstest_private_external.so";
786
787 // Load lib_private_external_path to default namespace
788 // (it should remain invisible for the isolated namespaces after this)
789 void* handle = dlopen(lib_private_external_path.c_str(), RTLD_NOW);
790 ASSERT_TRUE(handle != nullptr) << dlerror();
791
792 android_dlextinfo extinfo;
793 extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
794 extinfo.library_namespace = ns_not_isolated;
795
796 void* handle1 = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo);
797 ASSERT_TRUE(handle1 != nullptr) << dlerror();
798
799 extinfo.library_namespace = ns_isolated;
800
801 void* handle2 = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo);
802 ASSERT_TRUE(handle2 == nullptr);
803 ASSERT_STREQ("dlopen failed: library \"libnstest_private_external.so\" not found", dlerror());
804
805 // Check dlopen by absolute path
806 handle2 = android_dlopen_ext(lib_private_external_path.c_str(), RTLD_NOW, &extinfo);
807 ASSERT_TRUE(handle2 == nullptr);
Dimitry Ivanov22840aa2015-12-04 18:28:49 -0800808 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 -0700809
810 extinfo.library_namespace = ns_isolated2;
811
Dimitry Ivanov284ae352015-12-08 10:47:13 -0800812 // this should work because isolation_path for private_isolated2 includes lib_path
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700813 handle2 = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo);
Dimitry Ivanov284ae352015-12-08 10:47:13 -0800814 ASSERT_TRUE(handle2 != nullptr) << dlerror();
815 dlclose(handle2);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700816
817 // Check dlopen by absolute path
818 handle2 = android_dlopen_ext(lib_private_external_path.c_str(), RTLD_NOW, &extinfo);
Dimitry Ivanov284ae352015-12-08 10:47:13 -0800819 ASSERT_TRUE(handle2 != nullptr) << dlerror();
820 dlclose(handle2);
Dmitriy Ivanov42d5fcb2015-10-29 17:01:24 -0700821
822 typedef const char* (*fn_t)();
823 fn_t ns_get_local_string = reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_local_string"));
824 ASSERT_TRUE(ns_get_local_string != nullptr) << dlerror();
825
826 ASSERT_STREQ("This string is local to root library", ns_get_local_string());
827
828 fn_t ns_get_private_extern_string =
829 reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_private_extern_string"));
830 ASSERT_TRUE(ns_get_private_extern_string != nullptr) << dlerror();
831
832 ASSERT_STREQ("This string is from private namespace", ns_get_private_extern_string());
833
834 fn_t ns_get_public_extern_string =
835 reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_public_extern_string"));
836 ASSERT_TRUE(ns_get_public_extern_string != nullptr) << dlerror();
837
838 ASSERT_STREQ("This string is from public namespace", ns_get_public_extern_string());
839
840 fn_t ns_get_dlopened_string = reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_dlopened_string"));
841 ASSERT_TRUE(ns_get_dlopened_string != nullptr) << dlerror();
842
843 ASSERT_STREQ("This string is from private namespace (dlopened library)", ns_get_dlopened_string());
844
845 dlclose(handle1);
846}
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -0800847
Dimitry Ivanov7331fe12015-12-14 14:11:17 -0800848TEST(dlext, ns_shared) {
849 static const char* root_lib = "libnstest_root_not_isolated.so";
850 static const char* root_lib_isolated = "libnstest_root.so";
851 std::string path = std::string("libc.so:libc++.so:libdl.so:libm.so:") + g_public_lib;
852
853 const std::string lib_path = std::string(getenv("ANDROID_DATA")) + NATIVE_TESTS_PATH;
854 const std::string lib_public_path = lib_path + "/public_namespace_libs/" + g_public_lib;
855 void* handle_public = dlopen(lib_public_path.c_str(), RTLD_NOW);
856 ASSERT_TRUE(handle_public != nullptr) << dlerror();
857
858 android_set_application_target_sdk_version(42U); // something > 23
859
860 ASSERT_TRUE(android_init_namespaces(path.c_str(), nullptr)) << dlerror();
861
862 // preload this library to the default namespace to check if it
863 // is shared later on.
864 void* handle_dlopened =
865 dlopen((lib_path + "/private_namespace_libs/libnstest_dlopened.so").c_str(), RTLD_NOW);
866 ASSERT_TRUE(handle_dlopened != nullptr) << dlerror();
867
868 android_namespace_t* ns_not_isolated =
869 android_create_namespace("private", nullptr,
870 (lib_path + "/private_namespace_libs").c_str(),
871 ANDROID_NAMESPACE_TYPE_REGULAR, nullptr);
872 ASSERT_TRUE(ns_not_isolated != nullptr) << dlerror();
873
874 android_namespace_t* ns_isolated_shared =
875 android_create_namespace("private_isolated_shared", nullptr,
876 (lib_path + "/private_namespace_libs").c_str(),
877 ANDROID_NAMESPACE_TYPE_ISOLATED | ANDROID_NAMESPACE_TYPE_SHARED,
878 nullptr);
879 ASSERT_TRUE(ns_isolated_shared != nullptr) << dlerror();
880
881 ASSERT_TRUE(dlopen(root_lib, RTLD_NOW) == nullptr);
882 ASSERT_STREQ("dlopen failed: library \"libnstest_root_not_isolated.so\" not found", dlerror());
883
884 std::string lib_private_external_path =
885 lib_path + "/private_namespace_libs_external/libnstest_private_external.so";
886
887 // Load lib_private_external_path to default namespace
888 // (it should remain invisible for the isolated namespaces after this)
889 void* handle = dlopen(lib_private_external_path.c_str(), RTLD_NOW);
890 ASSERT_TRUE(handle != nullptr) << dlerror();
891
892 android_dlextinfo extinfo;
893 extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
894 extinfo.library_namespace = ns_not_isolated;
895
896 void* handle1 = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo);
897 ASSERT_TRUE(handle1 != nullptr) << dlerror();
898
899 extinfo.library_namespace = ns_isolated_shared;
900
901 void* handle2 = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo);
902 ASSERT_TRUE(handle2 == nullptr);
903 ASSERT_STREQ("dlopen failed: library \"libnstest_private_external.so\" not found", dlerror());
904
905 // Check dlopen by absolute path
906 handle2 = android_dlopen_ext(lib_private_external_path.c_str(), RTLD_NOW, &extinfo);
907 ASSERT_TRUE(handle2 == nullptr);
908 ASSERT_EQ("dlopen failed: library \"" + lib_private_external_path + "\" is not accessible for the namespace \"private_isolated_shared\"", dlerror());
909
910 // load libnstest_root.so to shared namespace in order to check that everything is different
911 // except shared libnstest_dlopened.so
912
913 handle2 = android_dlopen_ext(root_lib_isolated, RTLD_NOW, &extinfo);
914
915 typedef const char* (*fn_t)();
916 fn_t ns_get_local_string = reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_local_string"));
917 ASSERT_TRUE(ns_get_local_string != nullptr) << dlerror();
918 fn_t ns_get_local_string_shared = reinterpret_cast<fn_t>(dlsym(handle2, "ns_get_local_string"));
919 ASSERT_TRUE(ns_get_local_string_shared != nullptr) << dlerror();
920
921 ASSERT_STREQ("This string is local to root library", ns_get_local_string());
922 ASSERT_STREQ("This string is local to root library", ns_get_local_string_shared());
923 ASSERT_TRUE(ns_get_local_string() != ns_get_local_string_shared());
924
925 fn_t ns_get_private_extern_string =
926 reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_private_extern_string"));
927 ASSERT_TRUE(ns_get_private_extern_string != nullptr) << dlerror();
928 fn_t ns_get_private_extern_string_shared =
929 reinterpret_cast<fn_t>(dlsym(handle2, "ns_get_private_extern_string"));
930 ASSERT_TRUE(ns_get_private_extern_string_shared() != nullptr) << dlerror();
931
932 ASSERT_STREQ("This string is from private namespace", ns_get_private_extern_string());
933 ASSERT_STREQ("This string is from private namespace", ns_get_private_extern_string_shared());
934 ASSERT_TRUE(ns_get_private_extern_string() != ns_get_private_extern_string_shared());
935
936 fn_t ns_get_public_extern_string =
937 reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_public_extern_string"));
938 ASSERT_TRUE(ns_get_public_extern_string != nullptr) << dlerror();
939 fn_t ns_get_public_extern_string_shared =
940 reinterpret_cast<fn_t>(dlsym(handle2, "ns_get_public_extern_string"));
941 ASSERT_TRUE(ns_get_public_extern_string_shared != nullptr) << dlerror();
942
943 ASSERT_STREQ("This string is from public namespace", ns_get_public_extern_string());
944 ASSERT_STREQ("This string is from public namespace", ns_get_public_extern_string_shared());
945 ASSERT_TRUE(ns_get_public_extern_string() == ns_get_public_extern_string_shared());
946
947 fn_t ns_get_dlopened_string = reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_dlopened_string"));
948 ASSERT_TRUE(ns_get_dlopened_string != nullptr) << dlerror();
949 fn_t ns_get_dlopened_string_shared = reinterpret_cast<fn_t>(dlsym(handle2, "ns_get_dlopened_string"));
950 ASSERT_TRUE(ns_get_dlopened_string_shared != nullptr) << dlerror();
951 const char** ns_dlopened_string = static_cast<const char**>(dlsym(handle_dlopened, "g_private_dlopened_string"));
952 ASSERT_TRUE(ns_dlopened_string != nullptr) << dlerror();
953
954 ASSERT_STREQ("This string is from private namespace (dlopened library)", ns_get_dlopened_string());
955 ASSERT_STREQ("This string is from private namespace (dlopened library)", *ns_dlopened_string);
956 ASSERT_STREQ("This string is from private namespace (dlopened library)", ns_get_dlopened_string_shared());
957 ASSERT_TRUE(ns_get_dlopened_string() != ns_get_dlopened_string_shared());
958 ASSERT_TRUE(*ns_dlopened_string == ns_get_dlopened_string_shared());
959
960 dlclose(handle1);
961 dlclose(handle2);
962}
963
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -0800964TEST(dlext, ns_anonymous) {
965 static const char* root_lib = "libnstest_root.so";
966 std::string path = std::string("libc.so:libc++.so:libdl.so:libm.so:") + g_public_lib;
967
968 const std::string lib_path = std::string(getenv("ANDROID_DATA")) + NATIVE_TESTS_PATH;
969
Dimitry Ivanov22840aa2015-12-04 18:28:49 -0800970 const std::string lib_public_path = lib_path + "/public_namespace_libs/" + g_public_lib;
971 void* handle_public = dlopen(lib_public_path.c_str(), RTLD_NOW);
972
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -0800973 ASSERT_TRUE(handle_public != nullptr) << dlerror();
974
975 ASSERT_TRUE(android_init_namespaces(path.c_str(), (lib_path + "/private_namespace_libs").c_str()))
976 << dlerror();
977
978 android_namespace_t* ns = android_create_namespace(
979 "private", nullptr,
980 (lib_path + "/private_namespace_libs").c_str(),
Dimitry Ivanov7331fe12015-12-14 14:11:17 -0800981 ANDROID_NAMESPACE_TYPE_REGULAR, nullptr);
Dmitriy Ivanov1ffec1c2015-11-23 11:26:35 -0800982
983 ASSERT_TRUE(ns != nullptr) << dlerror();
984
985 std::string private_library_absolute_path = lib_path + "/private_namespace_libs/" + root_lib;
986
987 android_dlextinfo extinfo;
988 extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
989 extinfo.library_namespace = ns;
990
991 // we are going to copy this library to anonymous mmap and call the copy of ns_get_dlopened_string
992 void* handle = android_dlopen_ext(private_library_absolute_path.c_str(), RTLD_NOW, &extinfo);
993 ASSERT_TRUE(handle != nullptr) << dlerror();
994
995 uintptr_t ns_get_dlopened_string_addr =
996 reinterpret_cast<uintptr_t>(dlsym(handle, "ns_get_dlopened_string"));
997 ASSERT_TRUE(ns_get_dlopened_string_addr != 0) << dlerror();
998 typedef const char* (*fn_t)();
999 fn_t ns_get_dlopened_string_private = reinterpret_cast<fn_t>(ns_get_dlopened_string_addr);
1000
1001 std::vector<map_record> maps;
1002 Maps::parse_maps(&maps);
1003
1004 uintptr_t addr_start = 0;
1005 uintptr_t addr_end = 0;
1006 std::vector<map_record> maps_to_copy;
1007
1008 for (const auto& rec : maps) {
1009 if (rec.pathname == private_library_absolute_path) {
1010 if (addr_start == 0) {
1011 addr_start = rec.addr_start;
1012 }
1013 addr_end = rec.addr_end;
1014
1015 maps_to_copy.push_back(rec);
1016 }
1017 }
1018
1019 // some sanity checks..
1020 ASSERT_TRUE(addr_start > 0);
1021 ASSERT_TRUE(addr_end > 0);
1022 ASSERT_EQ(3U, maps_to_copy.size());
1023 ASSERT_TRUE(ns_get_dlopened_string_addr > addr_start);
1024 ASSERT_TRUE(ns_get_dlopened_string_addr < addr_end);
1025
1026 // copy
1027 uintptr_t reserved_addr = reinterpret_cast<uintptr_t>(mmap(nullptr, addr_end - addr_start,
1028 PROT_NONE, MAP_ANON | MAP_PRIVATE,
1029 -1, 0));
1030 ASSERT_TRUE(reinterpret_cast<void*>(reserved_addr) != MAP_FAILED);
1031
1032 for (const auto& rec : maps_to_copy) {
1033 uintptr_t offset = rec.addr_start - addr_start;
1034 size_t size = rec.addr_end - rec.addr_start;
1035 void* addr = reinterpret_cast<void*>(reserved_addr + offset);
1036 void* map = mmap(addr, size, PROT_READ | PROT_WRITE,
1037 MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, 0);
1038 ASSERT_TRUE(map != MAP_FAILED);
1039 memcpy(map, reinterpret_cast<void*>(rec.addr_start), size);
1040 mprotect(map, size, rec.perms);
1041 }
1042
1043 // call the function copy
1044 uintptr_t ns_get_dlopened_string_offset = ns_get_dlopened_string_addr - addr_start;
1045 fn_t ns_get_dlopened_string_anon = reinterpret_cast<fn_t>(reserved_addr + ns_get_dlopened_string_offset);
1046 ASSERT_STREQ("This string is from private namespace (dlopened library)",
1047 ns_get_dlopened_string_anon());
1048
1049 // They should belong to different namespaces (private and anonymous)
1050 ASSERT_STREQ("This string is from private namespace (dlopened library)",
1051 ns_get_dlopened_string_private());
1052
1053 ASSERT_TRUE(ns_get_dlopened_string_anon() != ns_get_dlopened_string_private());
1054}