1 /*
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>
20 #include <elf.h>
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <inttypes.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <unistd.h>
27
28 #include <android/dlext.h>
29 #include <android-base/strings.h>
30
31 #include <linux/memfd.h>
32 #include <sys/mman.h>
33 #include <sys/types.h>
34 #include <sys/vfs.h>
35 #include <sys/wait.h>
36
37 #include <pagemap/pagemap.h>
38 #include <ziparchive/zip_archive.h>
39
40 #include "gtest_globals.h"
41 #include "TemporaryFile.h"
42 #include "utils.h"
43 #include "dlext_private.h"
44 #include "dlfcn_symlink_support.h"
45
46 #define ASSERT_DL_NOTNULL(ptr) \
47 ASSERT_TRUE((ptr) != nullptr) << "dlerror: " << dlerror()
48
49 #define ASSERT_DL_ZERO(i) \
50 ASSERT_EQ(0, i) << "dlerror: " << dlerror()
51
52 #define ASSERT_NOERROR(i) \
53 ASSERT_NE(-1, i) << "errno: " << strerror(errno)
54
55 #define ASSERT_SUBSTR(needle, haystack) \
56 ASSERT_PRED_FORMAT2(::testing::IsSubstring, needle, haystack)
57
58
59 typedef int (*fn)(void);
60 constexpr const char* kLibName = "libdlext_test.so";
61 constexpr const char* kLibNameNoRelro = "libdlext_test_norelro.so";
62 constexpr const char* kLibZipSimpleZip = "libdir/libatest_simple_zip.so";
63 constexpr auto kLibSize = 1024 * 1024; // how much address space to reserve for it
64
65 class DlExtTest : public ::testing::Test {
66 protected:
SetUp()67 virtual void SetUp() {
68 handle_ = nullptr;
69 // verify that we don't have the library loaded already
70 void* h = dlopen(kLibName, RTLD_NOW | RTLD_NOLOAD);
71 ASSERT_TRUE(h == nullptr);
72 h = dlopen(kLibNameNoRelro, RTLD_NOW | RTLD_NOLOAD);
73 ASSERT_TRUE(h == nullptr);
74 // call dlerror() to swallow the error, and check it was the one we wanted
75 ASSERT_EQ(std::string("dlopen failed: library \"") + kLibNameNoRelro + "\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror());
76 }
77
TearDown()78 virtual void TearDown() {
79 if (handle_ != nullptr) {
80 ASSERT_DL_ZERO(dlclose(handle_));
81 }
82 }
83
84 void* handle_;
85 };
86
TEST_F(DlExtTest,ExtInfoNull)87 TEST_F(DlExtTest, ExtInfoNull) {
88 handle_ = android_dlopen_ext(kLibName, RTLD_NOW, nullptr);
89 ASSERT_DL_NOTNULL(handle_);
90 fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber"));
91 ASSERT_DL_NOTNULL(f);
92 EXPECT_EQ(4, f());
93 }
94
TEST_F(DlExtTest,ExtInfoNoFlags)95 TEST_F(DlExtTest, ExtInfoNoFlags) {
96 android_dlextinfo extinfo;
97 extinfo.flags = 0;
98 handle_ = android_dlopen_ext(kLibName, RTLD_NOW, &extinfo);
99 ASSERT_DL_NOTNULL(handle_);
100 fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber"));
101 ASSERT_DL_NOTNULL(f);
102 EXPECT_EQ(4, f());
103 }
104
TEST_F(DlExtTest,ExtInfoUseFd)105 TEST_F(DlExtTest, ExtInfoUseFd) {
106 const std::string lib_path = get_testlib_root() + "/libdlext_test_fd/libdlext_test_fd.so";
107
108 android_dlextinfo extinfo;
109 extinfo.flags = ANDROID_DLEXT_USE_LIBRARY_FD;
110 extinfo.library_fd = TEMP_FAILURE_RETRY(open(lib_path.c_str(), O_RDONLY | O_CLOEXEC));
111 ASSERT_TRUE(extinfo.library_fd != -1);
112 handle_ = android_dlopen_ext(lib_path.c_str(), RTLD_NOW, &extinfo);
113 ASSERT_DL_NOTNULL(handle_);
114 fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber"));
115 ASSERT_DL_NOTNULL(f);
116 EXPECT_EQ(4, f());
117
118 uint32_t* taxicab_number = reinterpret_cast<uint32_t*>(dlsym(handle_, "dlopen_testlib_taxicab_number"));
119 ASSERT_DL_NOTNULL(taxicab_number);
120 EXPECT_EQ(1729U, *taxicab_number);
121 }
122
TEST_F(DlExtTest,ExtInfoUseFdWithOffset)123 TEST_F(DlExtTest, ExtInfoUseFdWithOffset) {
124 const std::string lib_path = get_testlib_root() + "/libdlext_test_zip/libdlext_test_zip_zipaligned.zip";
125
126 android_dlextinfo extinfo;
127 extinfo.flags = ANDROID_DLEXT_USE_LIBRARY_FD | ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET;
128 extinfo.library_fd = TEMP_FAILURE_RETRY(open(lib_path.c_str(), O_RDONLY | O_CLOEXEC));
129
130 // Find the offset of the shared library in the zip.
131 ZipArchiveHandle handle;
132 ASSERT_EQ(0, OpenArchive(lib_path.c_str(), &handle));
133 ZipEntry zip_entry;
134 ZipString zip_name;
135 zip_name.name = reinterpret_cast<const uint8_t*>(kLibZipSimpleZip);
136 zip_name.name_length = strlen(kLibZipSimpleZip);
137 ASSERT_EQ(0, FindEntry(handle, zip_name, &zip_entry));
138 extinfo.library_fd_offset = zip_entry.offset;
139 CloseArchive(handle);
140
141 handle_ = android_dlopen_ext(lib_path.c_str(), RTLD_NOW, &extinfo);
142 ASSERT_DL_NOTNULL(handle_);
143
144 uint32_t* taxicab_number = reinterpret_cast<uint32_t*>(dlsym(handle_, "dlopen_testlib_taxicab_number"));
145 ASSERT_DL_NOTNULL(taxicab_number);
146 EXPECT_EQ(1729U, *taxicab_number);
147 }
148
TEST_F(DlExtTest,ExtInfoUseFdWithInvalidOffset)149 TEST_F(DlExtTest, ExtInfoUseFdWithInvalidOffset) {
150 const std::string lib_path = get_testlib_root() + "/libdlext_test_zip/libdlext_test_zip_zipaligned.zip";
151
152 android_dlextinfo extinfo;
153 extinfo.flags = ANDROID_DLEXT_USE_LIBRARY_FD | ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET;
154 extinfo.library_fd = TEMP_FAILURE_RETRY(open(lib_path.c_str(), O_RDONLY | O_CLOEXEC));
155 extinfo.library_fd_offset = 17;
156
157 handle_ = android_dlopen_ext("libname_placeholder", RTLD_NOW, &extinfo);
158 ASSERT_TRUE(handle_ == nullptr);
159 ASSERT_STREQ("dlopen failed: file offset for the library \"libname_placeholder\" is not page-aligned: 17", dlerror());
160
161 // Test an address above 2^44, for http://b/18178121 .
162 extinfo.library_fd_offset = (5LL<<48) + PAGE_SIZE;
163 handle_ = android_dlopen_ext("libname_placeholder", RTLD_NOW, &extinfo);
164 ASSERT_TRUE(handle_ == nullptr);
165 ASSERT_SUBSTR("dlopen failed: file offset for the library \"libname_placeholder\" >= file size", dlerror());
166
167 extinfo.library_fd_offset = 0LL - PAGE_SIZE;
168 handle_ = android_dlopen_ext("libname_placeholder", RTLD_NOW, &extinfo);
169 ASSERT_TRUE(handle_ == nullptr);
170 ASSERT_SUBSTR("dlopen failed: file offset for the library \"libname_placeholder\" is negative", dlerror());
171
172 extinfo.library_fd_offset = 0;
173 handle_ = android_dlopen_ext("libname_ignored", RTLD_NOW, &extinfo);
174 ASSERT_TRUE(handle_ == nullptr);
175 ASSERT_EQ("dlopen failed: \"" + lib_path + "\" has bad ELF magic", dlerror());
176
177 // Check if dlsym works after unsuccessful dlopen().
178 // Supply non-exiting one to make linker visit every soinfo.
179 void* sym = dlsym(RTLD_DEFAULT, "this_symbol_does_not_exist___");
180 ASSERT_TRUE(sym == nullptr);
181
182 close(extinfo.library_fd);
183 }
184
TEST_F(DlExtTest,ExtInfoUseOffsetWithoutFd)185 TEST_F(DlExtTest, ExtInfoUseOffsetWithoutFd) {
186 android_dlextinfo extinfo;
187 extinfo.flags = ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET;
188 // This offset will not be used, so it doesn't matter.
189 extinfo.library_fd_offset = 0;
190
191 handle_ = android_dlopen_ext("/some/lib/that/does_not_exist", RTLD_NOW, &extinfo);
192 ASSERT_TRUE(handle_ == nullptr);
193 ASSERT_STREQ("dlopen failed: invalid extended flag combination (ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET without ANDROID_DLEXT_USE_LIBRARY_FD): 0x20", dlerror());
194 }
195
TEST(dlext,android_dlopen_ext_force_load_smoke)196 TEST(dlext, android_dlopen_ext_force_load_smoke) {
197 DlfcnSymlink symlink("android_dlopen_ext_force_load_smoke");
198 const std::string symlink_name = basename(symlink.get_symlink_path().c_str());
199 // 1. Open actual file
200 void* handle = dlopen("libdlext_test.so", RTLD_NOW);
201 ASSERT_DL_NOTNULL(handle);
202 // 2. Open link with force_load flag set
203 android_dlextinfo extinfo;
204 extinfo.flags = ANDROID_DLEXT_FORCE_LOAD;
205 void* handle2 = android_dlopen_ext(symlink_name.c_str(), RTLD_NOW, &extinfo);
206 ASSERT_DL_NOTNULL(handle2);
207 ASSERT_TRUE(handle != handle2);
208
209 dlclose(handle2);
210 dlclose(handle);
211 }
212
TEST(dlext,android_dlopen_ext_force_load_soname_exception)213 TEST(dlext, android_dlopen_ext_force_load_soname_exception) {
214 DlfcnSymlink symlink("android_dlopen_ext_force_load_soname_exception");
215 const std::string symlink_name = basename(symlink.get_symlink_path().c_str());
216 // Check if soname lookup still returns already loaded library
217 // when ANDROID_DLEXT_FORCE_LOAD flag is specified.
218 void* handle = dlopen(symlink_name.c_str(), RTLD_NOW);
219 ASSERT_DL_NOTNULL(handle);
220
221 android_dlextinfo extinfo;
222 extinfo.flags = ANDROID_DLEXT_FORCE_LOAD;
223
224 // Note that 'libdlext_test.so' is dt_soname for the symlink_name
225 void* handle2 = android_dlopen_ext("libdlext_test.so", RTLD_NOW, &extinfo);
226
227 ASSERT_DL_NOTNULL(handle2);
228 ASSERT_TRUE(handle == handle2);
229
230 dlclose(handle2);
231 dlclose(handle);
232 }
233
TEST(dlfcn,dlopen_from_zip_absolute_path)234 TEST(dlfcn, dlopen_from_zip_absolute_path) {
235 const std::string lib_zip_path = "/libdlext_test_zip/libdlext_test_zip_zipaligned.zip";
236 const std::string lib_path = get_testlib_root() + lib_zip_path;
237
238 void* handle = dlopen((lib_path + "!/libdir/libatest_simple_zip.so").c_str(), RTLD_NOW);
239 ASSERT_TRUE(handle != nullptr) << dlerror();
240
241 uint32_t* taxicab_number = reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_testlib_taxicab_number"));
242 ASSERT_DL_NOTNULL(taxicab_number);
243 EXPECT_EQ(1729U, *taxicab_number);
244
245 dlclose(handle);
246 }
247
TEST(dlfcn,dlopen_from_zip_with_dt_runpath)248 TEST(dlfcn, dlopen_from_zip_with_dt_runpath) {
249 const std::string lib_zip_path = "/libdlext_test_runpath_zip/libdlext_test_runpath_zip_zipaligned.zip";
250 const std::string lib_path = get_testlib_root() + lib_zip_path;
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
TEST(dlfcn,dlopen_from_zip_ld_library_path)267 TEST(dlfcn, dlopen_from_zip_ld_library_path) {
268 const std::string lib_zip_path = "/libdlext_test_zip/libdlext_test_zip_zipaligned.zip";
269 const std::string lib_path = get_testlib_root() + lib_zip_path + "!/libdir";
270
271 typedef void (*fn_t)(const char*);
272 fn_t android_update_LD_LIBRARY_PATH =
273 reinterpret_cast<fn_t>(dlsym(RTLD_DEFAULT, "android_update_LD_LIBRARY_PATH"));
274
275 ASSERT_TRUE(android_update_LD_LIBRARY_PATH != nullptr) << dlerror();
276
277 void* handle = dlopen("libdlext_test_zip.so", RTLD_NOW);
278 ASSERT_TRUE(handle == nullptr);
279
280 android_update_LD_LIBRARY_PATH(lib_path.c_str());
281
282 handle = dlopen("libdlext_test_zip.so", RTLD_NOW);
283 ASSERT_TRUE(handle != nullptr) << dlerror();
284
285 int (*fn)(void);
286 fn = reinterpret_cast<int (*)(void)>(dlsym(handle, "getRandomNumber"));
287 ASSERT_TRUE(fn != nullptr);
288 EXPECT_EQ(4, fn());
289
290 uint32_t* taxicab_number =
291 reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_testlib_taxicab_number"));
292 ASSERT_DL_NOTNULL(taxicab_number);
293 EXPECT_EQ(1729U, *taxicab_number);
294
295 dlclose(handle);
296 }
297
298
TEST_F(DlExtTest,Reserved)299 TEST_F(DlExtTest, Reserved) {
300 void* start = mmap(nullptr, kLibSize, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
301 ASSERT_TRUE(start != MAP_FAILED);
302 android_dlextinfo extinfo;
303 extinfo.flags = ANDROID_DLEXT_RESERVED_ADDRESS;
304 extinfo.reserved_addr = start;
305 extinfo.reserved_size = kLibSize;
306 handle_ = android_dlopen_ext(kLibName, RTLD_NOW, &extinfo);
307 ASSERT_DL_NOTNULL(handle_);
308 fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber"));
309 ASSERT_DL_NOTNULL(f);
310 EXPECT_GE(reinterpret_cast<void*>(f), start);
311 EXPECT_LT(reinterpret_cast<void*>(f),
312 reinterpret_cast<char*>(start) + kLibSize);
313 EXPECT_EQ(4, f());
314
315 // Check that after dlclose reserved address space is unmapped (and can be reused)
316 dlclose(handle_);
317 handle_ = nullptr;
318
319 void* new_start = mmap(start, PAGE_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
320 ASSERT_NE(start, new_start) << "dlclose unmapped reserved space";
321 }
322
TEST_F(DlExtTest,ReservedTooSmall)323 TEST_F(DlExtTest, ReservedTooSmall) {
324 void* start = mmap(nullptr, PAGE_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
325 ASSERT_TRUE(start != MAP_FAILED);
326 android_dlextinfo extinfo;
327 extinfo.flags = ANDROID_DLEXT_RESERVED_ADDRESS;
328 extinfo.reserved_addr = start;
329 extinfo.reserved_size = PAGE_SIZE;
330 handle_ = android_dlopen_ext(kLibName, RTLD_NOW, &extinfo);
331 EXPECT_EQ(nullptr, handle_);
332 }
333
TEST_F(DlExtTest,ReservedHint)334 TEST_F(DlExtTest, ReservedHint) {
335 void* start = mmap(nullptr, kLibSize, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
336 ASSERT_TRUE(start != MAP_FAILED);
337 android_dlextinfo extinfo;
338 extinfo.flags = ANDROID_DLEXT_RESERVED_ADDRESS_HINT;
339 extinfo.reserved_addr = start;
340 extinfo.reserved_size = kLibSize;
341 handle_ = android_dlopen_ext(kLibName, RTLD_NOW, &extinfo);
342 ASSERT_DL_NOTNULL(handle_);
343 fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber"));
344 ASSERT_DL_NOTNULL(f);
345 EXPECT_GE(reinterpret_cast<void*>(f), start);
346 EXPECT_LT(reinterpret_cast<void*>(f),
347 reinterpret_cast<char*>(start) + kLibSize);
348 EXPECT_EQ(4, f());
349 }
350
TEST_F(DlExtTest,ReservedHintTooSmall)351 TEST_F(DlExtTest, ReservedHintTooSmall) {
352 void* start = mmap(nullptr, PAGE_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
353 ASSERT_TRUE(start != MAP_FAILED);
354 android_dlextinfo extinfo;
355 extinfo.flags = ANDROID_DLEXT_RESERVED_ADDRESS_HINT;
356 extinfo.reserved_addr = start;
357 extinfo.reserved_size = PAGE_SIZE;
358 handle_ = android_dlopen_ext(kLibName, RTLD_NOW, &extinfo);
359 ASSERT_DL_NOTNULL(handle_);
360 fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber"));
361 ASSERT_DL_NOTNULL(f);
362 EXPECT_TRUE(reinterpret_cast<void*>(f) < start ||
363 (reinterpret_cast<void*>(f) >=
364 reinterpret_cast<char*>(start) + PAGE_SIZE));
365 EXPECT_EQ(4, f());
366 }
367
TEST_F(DlExtTest,LoadAtFixedAddress)368 TEST_F(DlExtTest, LoadAtFixedAddress) {
369 void* start = mmap(nullptr, kLibSize, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
370 ASSERT_TRUE(start != MAP_FAILED);
371 munmap(start, kLibSize);
372
373 android_dlextinfo extinfo;
374 extinfo.flags = ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS;
375 extinfo.reserved_addr = start;
376
377 handle_ = android_dlopen_ext(kLibName, RTLD_NOW, &extinfo);
378 ASSERT_DL_NOTNULL(handle_);
379 fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber"));
380 ASSERT_DL_NOTNULL(f);
381 EXPECT_GE(reinterpret_cast<void*>(f), start);
382 EXPECT_LT(reinterpret_cast<void*>(f), reinterpret_cast<char*>(start) + kLibSize);
383
384 EXPECT_EQ(4, f());
385 dlclose(handle_);
386 handle_ = nullptr;
387
388 // Check that dlclose unmapped the file
389 void* addr = mmap(start, kLibSize, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
390 ASSERT_EQ(start, addr) << "dlclose did not unmap the memory";
391 }
392
TEST_F(DlExtTest,LoadAtFixedAddressTooSmall)393 TEST_F(DlExtTest, LoadAtFixedAddressTooSmall) {
394 void* start = mmap(nullptr, kLibSize + PAGE_SIZE, PROT_NONE,
395 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
396 ASSERT_TRUE(start != MAP_FAILED);
397 munmap(start, kLibSize + PAGE_SIZE);
398 void* new_addr = mmap(reinterpret_cast<uint8_t*>(start) + PAGE_SIZE, kLibSize, PROT_NONE,
399 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
400 ASSERT_TRUE(new_addr != MAP_FAILED);
401
402 android_dlextinfo extinfo;
403 extinfo.flags = ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS;
404 extinfo.reserved_addr = start;
405
406 handle_ = android_dlopen_ext(kLibName, RTLD_NOW, &extinfo);
407 ASSERT_TRUE(handle_ == nullptr);
408 }
409
410 class DlExtRelroSharingTest : public DlExtTest {
411 protected:
SetUp()412 virtual void SetUp() {
413 DlExtTest::SetUp();
414 void* start = mmap(nullptr, kLibSize, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
415 ASSERT_TRUE(start != MAP_FAILED);
416 extinfo_.flags = ANDROID_DLEXT_RESERVED_ADDRESS;
417 extinfo_.reserved_addr = start;
418 extinfo_.reserved_size = kLibSize;
419 extinfo_.relro_fd = -1;
420 }
421
TearDown()422 virtual void TearDown() {
423 DlExtTest::TearDown();
424 }
425
CreateRelroFile(const char * lib,const char * relro_file)426 void CreateRelroFile(const char* lib, const char* relro_file) {
427 int relro_fd = open(relro_file, O_RDWR | O_TRUNC);
428 ASSERT_NOERROR(relro_fd);
429
430 pid_t pid = fork();
431 if (pid == 0) {
432 // child process
433 extinfo_.flags |= ANDROID_DLEXT_WRITE_RELRO;
434 extinfo_.relro_fd = relro_fd;
435 void* handle = android_dlopen_ext(lib, RTLD_NOW, &extinfo_);
436 if (handle == nullptr) {
437 fprintf(stderr, "in child: %s\n", dlerror());
438 exit(1);
439 }
440 exit(0);
441 }
442
443 // continuing in parent
444 ASSERT_NOERROR(close(relro_fd));
445 ASSERT_NOERROR(pid);
446 AssertChildExited(pid, 0);
447
448 // reopen file for reading so it can be used
449 relro_fd = open(relro_file, O_RDONLY);
450 ASSERT_NOERROR(relro_fd);
451 extinfo_.flags |= ANDROID_DLEXT_USE_RELRO;
452 extinfo_.relro_fd = relro_fd;
453 }
454
TryUsingRelro(const char * lib)455 void TryUsingRelro(const char* lib) {
456 handle_ = android_dlopen_ext(lib, RTLD_NOW, &extinfo_);
457 ASSERT_DL_NOTNULL(handle_);
458 fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber"));
459 ASSERT_DL_NOTNULL(f);
460 EXPECT_EQ(4, f());
461
462 uint32_t* taxicab_number =
463 reinterpret_cast<uint32_t*>(dlsym(handle_, "dlopen_testlib_taxicab_number"));
464 ASSERT_DL_NOTNULL(taxicab_number);
465 EXPECT_EQ(1729U, *taxicab_number);
466 }
467
468 void SpawnChildrenAndMeasurePss(const char* lib, const char* relro_file, bool share_relro,
469 size_t* pss_out);
470
471 android_dlextinfo extinfo_;
472 };
473
TEST_F(DlExtRelroSharingTest,ChildWritesGoodData)474 TEST_F(DlExtRelroSharingTest, ChildWritesGoodData) {
475 TemporaryFile tf; // Use tf to get an unique filename.
476 ASSERT_NOERROR(close(tf.fd));
477
478 ASSERT_NO_FATAL_FAILURE(CreateRelroFile(kLibName, tf.filename));
479 ASSERT_NO_FATAL_FAILURE(TryUsingRelro(kLibName));
480
481 // Use destructor of tf to close and unlink the file.
482 tf.fd = extinfo_.relro_fd;
483 }
484
TEST_F(DlExtRelroSharingTest,ChildWritesNoRelro)485 TEST_F(DlExtRelroSharingTest, ChildWritesNoRelro) {
486 TemporaryFile tf; // // Use tf to get an unique filename.
487 ASSERT_NOERROR(close(tf.fd));
488
489 ASSERT_NO_FATAL_FAILURE(CreateRelroFile(kLibNameNoRelro, tf.filename));
490 ASSERT_NO_FATAL_FAILURE(TryUsingRelro(kLibNameNoRelro));
491
492 // Use destructor of tf to close and unlink the file.
493 tf.fd = extinfo_.relro_fd;
494 }
495
TEST_F(DlExtRelroSharingTest,RelroFileEmpty)496 TEST_F(DlExtRelroSharingTest, RelroFileEmpty) {
497 ASSERT_NO_FATAL_FAILURE(TryUsingRelro(kLibName));
498 }
499
TEST_F(DlExtRelroSharingTest,VerifyMemorySaving)500 TEST_F(DlExtRelroSharingTest, VerifyMemorySaving) {
501 if (geteuid() != 0) {
502 GTEST_LOG_(INFO) << "This test must be run as root.\n";
503 return;
504 }
505
506 TemporaryFile tf; // Use tf to get an unique filename.
507 ASSERT_NOERROR(close(tf.fd));
508
509 ASSERT_NO_FATAL_FAILURE(CreateRelroFile(kLibName, tf.filename));
510
511 int pipefd[2];
512 ASSERT_NOERROR(pipe(pipefd));
513
514 size_t without_sharing, with_sharing;
515 ASSERT_NO_FATAL_FAILURE(SpawnChildrenAndMeasurePss(kLibName, tf.filename, false, &without_sharing));
516 ASSERT_NO_FATAL_FAILURE(SpawnChildrenAndMeasurePss(kLibName, tf.filename, true, &with_sharing));
517 ASSERT_LT(with_sharing, without_sharing);
518
519 // We expect the sharing to save at least 50% of the library's total PSS.
520 // In practice it saves 80%+ for this library in the test.
521 size_t pss_saved = without_sharing - with_sharing;
522 size_t expected_min_saved = without_sharing / 2;
523
524 EXPECT_LT(expected_min_saved, pss_saved);
525
526 // Use destructor of tf to close and unlink the file.
527 tf.fd = extinfo_.relro_fd;
528 }
529
GetPss(bool shared_relro,const char * lib,const char * relro_file,pid_t pid,size_t * total_pss)530 void GetPss(bool shared_relro, const char* lib, const char* relro_file, pid_t pid,
531 size_t* total_pss) {
532 pm_kernel_t* kernel;
533 ASSERT_EQ(0, pm_kernel_create(&kernel));
534
535 pm_process_t* process;
536 ASSERT_EQ(0, pm_process_create(kernel, pid, &process));
537
538 pm_map_t** maps;
539 size_t num_maps;
540 ASSERT_EQ(0, pm_process_maps(process, &maps, &num_maps));
541
542 // Calculate total PSS of the library.
543 *total_pss = 0;
544 bool saw_relro_file = false;
545 for (size_t i = 0; i < num_maps; ++i) {
546 if (android::base::EndsWith(maps[i]->name, lib) || strcmp(maps[i]->name, relro_file) == 0) {
547 if (strcmp(maps[i]->name, relro_file) == 0) saw_relro_file = true;
548
549 pm_memusage_t usage;
550 ASSERT_EQ(0, pm_map_usage(maps[i], &usage));
551 *total_pss += usage.pss;
552 }
553 }
554
555 free(maps);
556 pm_process_destroy(process);
557 pm_kernel_destroy(kernel);
558
559 if (shared_relro) ASSERT_TRUE(saw_relro_file);
560 }
561
SpawnChildrenAndMeasurePss(const char * lib,const char * relro_file,bool share_relro,size_t * pss_out)562 void DlExtRelroSharingTest::SpawnChildrenAndMeasurePss(const char* lib, const char* relro_file,
563 bool share_relro, size_t* pss_out) {
564 const int CHILDREN = 20;
565
566 // Create children
567 pid_t child_pids[CHILDREN];
568 int childpipe[CHILDREN];
569 for (int i=0; i<CHILDREN; ++i) {
570 char read_buf;
571 int child_done_pipe[2], parent_done_pipe[2];
572 ASSERT_NOERROR(pipe(child_done_pipe));
573 ASSERT_NOERROR(pipe(parent_done_pipe));
574
575 pid_t child = fork();
576 if (child == 0) {
577 // close the 'wrong' ends of the pipes in the child
578 close(child_done_pipe[0]);
579 close(parent_done_pipe[1]);
580
581 // open the library
582 void* handle;
583 if (share_relro) {
584 handle = android_dlopen_ext(lib, RTLD_NOW, &extinfo_);
585 } else {
586 handle = dlopen(lib, RTLD_NOW);
587 }
588 if (handle == nullptr) {
589 fprintf(stderr, "in child: %s\n", dlerror());
590 exit(1);
591 }
592
593 // close write end of child_done_pipe to signal the parent that we're done.
594 close(child_done_pipe[1]);
595
596 // wait for the parent to close parent_done_pipe, then exit
597 read(parent_done_pipe[0], &read_buf, 1);
598 exit(0);
599 }
600
601 ASSERT_NOERROR(child);
602
603 // close the 'wrong' ends of the pipes in the parent
604 close(child_done_pipe[1]);
605 close(parent_done_pipe[0]);
606
607 // wait for the child to be done
608 read(child_done_pipe[0], &read_buf, 1);
609 close(child_done_pipe[0]);
610
611 // save the child's pid and the parent_done_pipe
612 child_pids[i] = child;
613 childpipe[i] = parent_done_pipe[1];
614 }
615
616 // Sum the PSS of tested library of all the children
617 size_t total_pss = 0;
618 for (int i=0; i<CHILDREN; ++i) {
619 size_t child_pss;
620 ASSERT_NO_FATAL_FAILURE(GetPss(share_relro, lib, relro_file, child_pids[i], &child_pss));
621 total_pss += child_pss;
622 }
623 *pss_out = total_pss;
624
625 // Close pipes and wait for children to exit
626 for (int i=0; i<CHILDREN; ++i) {
627 ASSERT_NOERROR(close(childpipe[i]));
628 }
629 for (int i = 0; i < CHILDREN; ++i) {
630 AssertChildExited(child_pids[i], 0);
631 }
632 }
633
634 // Testing namespaces
635 static const char* g_public_lib = "libnstest_public.so";
636
637 // These are libs shared with default namespace
638 static const std::string g_core_shared_libs = "libc.so:libc++.so:libdl.so:libm.so";
639
TEST(dlext,ns_smoke)640 TEST(dlext, ns_smoke) {
641 static const char* root_lib = "libnstest_root.so";
642 std::string shared_libs = g_core_shared_libs + ":" + g_public_lib;
643
644 ASSERT_FALSE(android_init_anonymous_namespace("", nullptr));
645 ASSERT_STREQ("android_init_anonymous_namespace failed: error linking namespaces"
646 " \"(anonymous)\"->\"(default)\": the list of shared libraries is empty.",
647 dlerror());
648
649 const std::string lib_public_path = get_testlib_root() + "/public_namespace_libs/" + g_public_lib;
650 void* handle_public = dlopen(lib_public_path.c_str(), RTLD_NOW);
651 ASSERT_TRUE(handle_public != nullptr) << dlerror();
652
653 ASSERT_TRUE(android_init_anonymous_namespace(shared_libs.c_str(), nullptr)) << dlerror();
654
655 // Check that libraries added to public namespace are not NODELETE
656 dlclose(handle_public);
657 handle_public = dlopen(lib_public_path.c_str(), RTLD_NOW | RTLD_NOLOAD);
658 ASSERT_TRUE(handle_public == nullptr);
659 ASSERT_EQ(std::string("dlopen failed: library \"") + lib_public_path +
660 "\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror());
661
662 handle_public = dlopen(lib_public_path.c_str(), RTLD_NOW);
663
664 // create "public namespace", share limited set of public libraries with
665
666 android_namespace_t* ns1 =
667 android_create_namespace("private",
668 nullptr,
669 (get_testlib_root() + "/private_namespace_libs").c_str(),
670 ANDROID_NAMESPACE_TYPE_REGULAR,
671 nullptr,
672 nullptr);
673 ASSERT_TRUE(ns1 != nullptr) << dlerror();
674 ASSERT_TRUE(android_link_namespaces(ns1, nullptr, shared_libs.c_str())) << dlerror();
675
676 android_namespace_t* ns2 =
677 android_create_namespace("private_isolated",
678 nullptr,
679 (get_testlib_root() + "/private_namespace_libs").c_str(),
680 ANDROID_NAMESPACE_TYPE_ISOLATED,
681 nullptr,
682 nullptr);
683 ASSERT_TRUE(ns2 != nullptr) << dlerror();
684 ASSERT_TRUE(android_link_namespaces(ns2, nullptr, shared_libs.c_str())) << dlerror();
685
686 // This should not have affect search path for default namespace:
687 ASSERT_TRUE(dlopen(root_lib, RTLD_NOW) == nullptr);
688 void* handle = dlopen(g_public_lib, RTLD_NOW);
689 ASSERT_TRUE(handle != nullptr) << dlerror();
690 dlclose(handle);
691
692 // dlopen for a public library using an absolute path should work
693 // 1. For isolated namespaces
694 android_dlextinfo extinfo;
695 extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
696 extinfo.library_namespace = ns2;
697 handle = android_dlopen_ext(lib_public_path.c_str(), RTLD_NOW, &extinfo);
698 ASSERT_TRUE(handle != nullptr) << dlerror();
699 ASSERT_TRUE(handle == handle_public);
700
701 dlclose(handle);
702
703 // 1.1 even if it wasn't loaded before
704 dlclose(handle_public);
705
706 handle_public = dlopen(lib_public_path.c_str(), RTLD_NOW | RTLD_NOLOAD);
707 ASSERT_TRUE(handle_public == nullptr);
708 ASSERT_EQ(std::string("dlopen failed: library \"") + lib_public_path +
709 "\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror());
710
711 handle = android_dlopen_ext(lib_public_path.c_str(), RTLD_NOW, &extinfo);
712 ASSERT_TRUE(handle != nullptr) << dlerror();
713
714 handle_public = dlopen(lib_public_path.c_str(), RTLD_NOW);
715 ASSERT_TRUE(handle == handle_public);
716
717 dlclose(handle);
718
719 // 2. And for regular namespaces (make sure it does not load second copy of the library)
720 extinfo.library_namespace = ns1;
721 handle = android_dlopen_ext(lib_public_path.c_str(), RTLD_NOW, &extinfo);
722 ASSERT_TRUE(handle != nullptr) << dlerror();
723 ASSERT_TRUE(handle == handle_public);
724
725 dlclose(handle);
726
727 // 2.1 Unless it was not loaded before - in which case it will load a duplicate.
728 // TODO(dimitry): This is broken. Maybe we need to deprecate non-isolated namespaces?
729 dlclose(handle_public);
730
731 handle_public = dlopen(lib_public_path.c_str(), RTLD_NOW | RTLD_NOLOAD);
732 ASSERT_TRUE(handle_public == nullptr);
733 ASSERT_EQ(std::string("dlopen failed: library \"") + lib_public_path +
734 "\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror());
735
736 handle = android_dlopen_ext(lib_public_path.c_str(), RTLD_NOW, &extinfo);
737 ASSERT_TRUE(handle != nullptr) << dlerror();
738
739 handle_public = dlopen(lib_public_path.c_str(), RTLD_NOW);
740
741 ASSERT_TRUE(handle != handle_public);
742
743 dlclose(handle);
744
745 extinfo.library_namespace = ns1;
746
747 void* handle1 = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo);
748 ASSERT_TRUE(handle1 != nullptr) << dlerror();
749
750 extinfo.library_namespace = ns2;
751 void* handle2 = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo);
752 ASSERT_TRUE(handle2 != nullptr) << dlerror();
753
754 ASSERT_TRUE(handle1 != handle2);
755
756 typedef const char* (*fn_t)();
757
758 fn_t ns_get_local_string1 = reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_local_string"));
759 ASSERT_TRUE(ns_get_local_string1 != nullptr) << dlerror();
760 fn_t ns_get_local_string2 = reinterpret_cast<fn_t>(dlsym(handle2, "ns_get_local_string"));
761 ASSERT_TRUE(ns_get_local_string2 != nullptr) << dlerror();
762
763 EXPECT_STREQ("This string is local to root library", ns_get_local_string1());
764 EXPECT_STREQ("This string is local to root library", ns_get_local_string2());
765
766 ASSERT_TRUE(ns_get_local_string1() != ns_get_local_string2());
767
768 fn_t ns_get_private_extern_string1 =
769 reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_private_extern_string"));
770 ASSERT_TRUE(ns_get_private_extern_string1 != nullptr) << dlerror();
771 fn_t ns_get_private_extern_string2 =
772 reinterpret_cast<fn_t>(dlsym(handle2, "ns_get_private_extern_string"));
773 ASSERT_TRUE(ns_get_private_extern_string2 != nullptr) << dlerror();
774
775 EXPECT_STREQ("This string is from private namespace", ns_get_private_extern_string1());
776 EXPECT_STREQ("This string is from private namespace", ns_get_private_extern_string2());
777
778 ASSERT_TRUE(ns_get_private_extern_string1() != ns_get_private_extern_string2());
779
780 fn_t ns_get_public_extern_string1 =
781 reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_public_extern_string"));
782 ASSERT_TRUE(ns_get_public_extern_string1 != nullptr) << dlerror();
783 fn_t ns_get_public_extern_string2 =
784 reinterpret_cast<fn_t>(dlsym(handle2, "ns_get_public_extern_string"));
785 ASSERT_TRUE(ns_get_public_extern_string2 != nullptr) << dlerror();
786
787 EXPECT_STREQ("This string is from public namespace", ns_get_public_extern_string1());
788 ASSERT_TRUE(ns_get_public_extern_string1() == ns_get_public_extern_string2());
789
790 // and now check that dlopen() does the right thing in terms of preserving namespace
791 fn_t ns_get_dlopened_string1 = reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_dlopened_string"));
792 ASSERT_TRUE(ns_get_dlopened_string1 != nullptr) << dlerror();
793 fn_t ns_get_dlopened_string2 = reinterpret_cast<fn_t>(dlsym(handle2, "ns_get_dlopened_string"));
794 ASSERT_TRUE(ns_get_dlopened_string2 != nullptr) << dlerror();
795
796 EXPECT_STREQ("This string is from private namespace (dlopened library)", ns_get_dlopened_string1());
797 EXPECT_STREQ("This string is from private namespace (dlopened library)", ns_get_dlopened_string2());
798
799 ASSERT_TRUE(ns_get_dlopened_string1() != ns_get_dlopened_string2());
800
801 // Check that symbols from non-shared libraries a shared library depends on are not visible
802 // from original namespace.
803
804 fn_t ns_get_internal_extern_string =
805 reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_internal_extern_string"));
806 ASSERT_TRUE(ns_get_internal_extern_string != nullptr) << dlerror();
807 ASSERT_TRUE(ns_get_internal_extern_string() == nullptr) <<
808 "ns_get_internal_extern_string() expected to return null but returns \"" <<
809 ns_get_internal_extern_string() << "\"";
810
811 dlclose(handle1);
812
813 // Check if handle2 is still alive (and well)
814 ASSERT_STREQ("This string is local to root library", ns_get_local_string2());
815 ASSERT_STREQ("This string is from private namespace", ns_get_private_extern_string2());
816 ASSERT_STREQ("This string is from public namespace", ns_get_public_extern_string2());
817 ASSERT_STREQ("This string is from private namespace (dlopened library)", ns_get_dlopened_string2());
818
819 dlclose(handle2);
820 }
821
TEST(dlext,dlopen_ext_use_o_tmpfile_fd)822 TEST(dlext, dlopen_ext_use_o_tmpfile_fd) {
823 const std::string lib_path = get_testlib_root() + "/libtest_simple.so";
824
825 int tmpfd = TEMP_FAILURE_RETRY(
826 open(get_testlib_root().c_str(), O_TMPFILE | O_CLOEXEC | O_RDWR | O_EXCL));
827
828 // Ignore kernels without O_TMPFILE flag support
829 if (tmpfd == -1 && (errno == EISDIR || errno == EINVAL || errno == EOPNOTSUPP)) {
830 return;
831 }
832
833 ASSERT_TRUE(tmpfd != -1) << strerror(errno);
834
835 android_namespace_t* ns =
836 android_create_namespace("testing-o_tmpfile",
837 nullptr,
838 get_testlib_root().c_str(),
839 ANDROID_NAMESPACE_TYPE_ISOLATED,
840 nullptr,
841 nullptr);
842
843 ASSERT_DL_NOTNULL(ns);
844
845 ASSERT_TRUE(android_link_namespaces(ns, nullptr, g_core_shared_libs.c_str())) << dlerror();
846
847 std::string content;
848 ASSERT_TRUE(android::base::ReadFileToString(lib_path, &content)) << strerror(errno);
849 ASSERT_TRUE(android::base::WriteStringToFd(content, tmpfd)) << strerror(errno);
850
851 android_dlextinfo extinfo;
852 extinfo.flags = ANDROID_DLEXT_USE_LIBRARY_FD | ANDROID_DLEXT_USE_NAMESPACE;
853 extinfo.library_fd = tmpfd;
854 extinfo.library_namespace = ns;
855
856 void* handle = android_dlopen_ext("foobar", RTLD_NOW, &extinfo);
857
858 ASSERT_DL_NOTNULL(handle);
859
860 uint32_t* taxicab_number = reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_testlib_taxicab_number"));
861 ASSERT_DL_NOTNULL(taxicab_number);
862 EXPECT_EQ(1729U, *taxicab_number);
863 dlclose(handle);
864 }
865
TEST(dlext,dlopen_ext_use_memfd)866 TEST(dlext, dlopen_ext_use_memfd) {
867 const std::string lib_path = get_testlib_root() + "/libtest_simple.so";
868
869 // create memfd
870 int memfd = syscall(__NR_memfd_create, "foobar", MFD_CLOEXEC);
871 if (memfd == -1 && errno == ENOSYS) {
872 return;
873 }
874
875 ASSERT_TRUE(memfd != -1) << strerror(errno);
876
877 // Check st.f_type is TMPFS_MAGIC for memfd
878 struct statfs st;
879 ASSERT_TRUE(TEMP_FAILURE_RETRY(fstatfs(memfd, &st)) == 0) << strerror(errno);
880 ASSERT_EQ(static_cast<decltype(st.f_type)>(TMPFS_MAGIC), st.f_type);
881
882 android_namespace_t* ns =
883 android_create_namespace("testing-memfd",
884 nullptr,
885 get_testlib_root().c_str(),
886 ANDROID_NAMESPACE_TYPE_ISOLATED,
887 nullptr,
888 nullptr);
889
890 ASSERT_DL_NOTNULL(ns);
891
892 ASSERT_TRUE(android_link_namespaces(ns, nullptr, g_core_shared_libs.c_str())) << dlerror();
893
894 // read file into memfd backed one.
895 std::string content;
896 ASSERT_TRUE(android::base::ReadFileToString(lib_path, &content)) << strerror(errno);
897 ASSERT_TRUE(android::base::WriteStringToFd(content, memfd)) << strerror(errno);
898
899 android_dlextinfo extinfo;
900 extinfo.flags = ANDROID_DLEXT_USE_LIBRARY_FD | ANDROID_DLEXT_USE_NAMESPACE;
901 extinfo.library_fd = memfd;
902 extinfo.library_namespace = ns;
903
904 void* handle = android_dlopen_ext("foobar", RTLD_NOW, &extinfo);
905
906 ASSERT_DL_NOTNULL(handle);
907
908 uint32_t* taxicab_number = reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_testlib_taxicab_number"));
909 ASSERT_DL_NOTNULL(taxicab_number);
910 EXPECT_EQ(1729U, *taxicab_number);
911 dlclose(handle);
912 }
913
TEST(dlext,ns_symbol_visibilty_one_namespace)914 TEST(dlext, ns_symbol_visibilty_one_namespace) {
915 static const char* root_lib = "libnstest_root.so";
916 ASSERT_TRUE(android_init_anonymous_namespace(g_core_shared_libs.c_str(), nullptr));
917
918 const std::string ns_search_path = get_testlib_root() + "/public_namespace_libs:" +
919 get_testlib_root() + "/private_namespace_libs";
920
921 android_namespace_t* ns =
922 android_create_namespace("one",
923 nullptr,
924 ns_search_path.c_str(),
925 ANDROID_NAMESPACE_TYPE_ISOLATED,
926 nullptr,
927 nullptr);
928
929 ASSERT_TRUE(android_link_namespaces(ns, nullptr, g_core_shared_libs.c_str())) << dlerror();
930
931 android_dlextinfo extinfo;
932 extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
933 extinfo.library_namespace = ns;
934
935 void* handle = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo);
936 ASSERT_TRUE(handle != nullptr) << dlerror();
937
938 typedef const char* (*fn_t)();
939
940 // Check that relocation worked correctly
941 fn_t ns_get_internal_extern_string =
942 reinterpret_cast<fn_t>(dlsym(handle, "ns_get_internal_extern_string"));
943 ASSERT_TRUE(ns_get_internal_extern_string != nullptr) << dlerror();
944 ASSERT_STREQ("This string is from a library a shared library depends on", ns_get_internal_extern_string());
945
946 fn_t internal_extern_string_fn =
947 reinterpret_cast<fn_t>(dlsym(handle, "internal_extern_string"));
948 ASSERT_TRUE(internal_extern_string_fn != nullptr) << dlerror();
949 ASSERT_STREQ("This string is from a library a shared library depends on", internal_extern_string_fn());
950 }
951
TEST(dlext,ns_symbol_visibilty_between_namespaces)952 TEST(dlext, ns_symbol_visibilty_between_namespaces) {
953 static const char* root_lib = "libnstest_root.so";
954 ASSERT_TRUE(android_init_anonymous_namespace(g_core_shared_libs.c_str(), nullptr));
955
956 const std::string public_ns_search_path = get_testlib_root() + "/public_namespace_libs";
957 const std::string private_ns_search_path = get_testlib_root() + "/private_namespace_libs";
958
959 android_namespace_t* ns_public =
960 android_create_namespace("public",
961 nullptr,
962 public_ns_search_path.c_str(),
963 ANDROID_NAMESPACE_TYPE_ISOLATED,
964 nullptr,
965 nullptr);
966
967 ASSERT_TRUE(android_link_namespaces(ns_public, nullptr, g_core_shared_libs.c_str())) << dlerror();
968
969 android_namespace_t* ns_private =
970 android_create_namespace("private",
971 nullptr,
972 private_ns_search_path.c_str(),
973 ANDROID_NAMESPACE_TYPE_ISOLATED,
974 nullptr,
975 nullptr);
976
977 ASSERT_TRUE(android_link_namespaces(ns_private, ns_public, g_public_lib)) << dlerror();
978 ASSERT_TRUE(android_link_namespaces(ns_private, nullptr, g_core_shared_libs.c_str())) << dlerror();
979
980 android_dlextinfo extinfo;
981 extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
982 extinfo.library_namespace = ns_private;
983
984 void* handle = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo);
985 ASSERT_TRUE(handle != nullptr) << dlerror();
986
987 typedef const char* (*fn_t)();
988
989 // Check that relocation worked correctly
990 fn_t ns_get_internal_extern_string =
991 reinterpret_cast<fn_t>(dlsym(handle, "ns_get_internal_extern_string"));
992 ASSERT_TRUE(ns_get_internal_extern_string != nullptr) << dlerror();
993 ASSERT_TRUE(ns_get_internal_extern_string() == nullptr) <<
994 "ns_get_internal_extern_string() expected to return null but returns \"" <<
995 ns_get_internal_extern_string() << "\"";
996
997 fn_t internal_extern_string_fn =
998 reinterpret_cast<fn_t>(dlsym(handle, "internal_extern_string"));
999 ASSERT_TRUE(internal_extern_string_fn == nullptr);
1000 ASSERT_STREQ("undefined symbol: internal_extern_string", dlerror());
1001 }
1002
TEST(dlext,ns_unload_between_namespaces)1003 TEST(dlext, ns_unload_between_namespaces) {
1004 static const char* root_lib = "libnstest_root.so";
1005 ASSERT_TRUE(android_init_anonymous_namespace(g_core_shared_libs.c_str(), nullptr));
1006
1007 const std::string public_ns_search_path = get_testlib_root() + "/public_namespace_libs";
1008 const std::string private_ns_search_path = get_testlib_root() + "/private_namespace_libs";
1009
1010 android_namespace_t* ns_public =
1011 android_create_namespace("public",
1012 nullptr,
1013 public_ns_search_path.c_str(),
1014 ANDROID_NAMESPACE_TYPE_ISOLATED,
1015 nullptr,
1016 nullptr);
1017
1018 ASSERT_TRUE(android_link_namespaces(ns_public, nullptr, g_core_shared_libs.c_str())) << dlerror();
1019
1020 android_namespace_t* ns_private =
1021 android_create_namespace("private",
1022 nullptr,
1023 private_ns_search_path.c_str(),
1024 ANDROID_NAMESPACE_TYPE_ISOLATED,
1025 nullptr,
1026 nullptr);
1027
1028 ASSERT_TRUE(android_link_namespaces(ns_private, ns_public, g_public_lib)) << dlerror();
1029 ASSERT_TRUE(android_link_namespaces(ns_private, nullptr, g_core_shared_libs.c_str())) << dlerror();
1030
1031 android_dlextinfo extinfo;
1032 extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
1033 extinfo.library_namespace = ns_private;
1034
1035 void* handle = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo);
1036 ASSERT_TRUE(handle != nullptr) << dlerror();
1037
1038 dlclose(handle);
1039 // Check that root_lib was unloaded
1040 handle = android_dlopen_ext(root_lib, RTLD_NOW | RTLD_NOLOAD, &extinfo);
1041 ASSERT_TRUE(handle == nullptr);
1042 ASSERT_EQ(std::string("dlopen failed: library \"") + root_lib +
1043 "\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror());
1044
1045 // Check that shared library was unloaded in public ns
1046 extinfo.library_namespace = ns_public;
1047 handle = android_dlopen_ext(g_public_lib, RTLD_NOW | RTLD_NOLOAD, &extinfo);
1048 ASSERT_TRUE(handle == nullptr);
1049 ASSERT_EQ(std::string("dlopen failed: library \"") + g_public_lib +
1050 "\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror());
1051 }
1052
TEST(dlext,ns_greylist_enabled)1053 TEST(dlext, ns_greylist_enabled) {
1054 ASSERT_TRUE(android_init_anonymous_namespace(g_core_shared_libs.c_str(), nullptr));
1055
1056 const std::string ns_search_path = get_testlib_root() + "/private_namespace_libs";
1057
1058 android_namespace_t* ns =
1059 android_create_namespace("namespace",
1060 nullptr,
1061 ns_search_path.c_str(),
1062 ANDROID_NAMESPACE_TYPE_ISOLATED | ANDROID_NAMESPACE_TYPE_GREYLIST_ENABLED,
1063 nullptr,
1064 nullptr);
1065
1066 ASSERT_TRUE(android_link_namespaces(ns, nullptr, g_core_shared_libs.c_str())) << dlerror();
1067
1068 android_dlextinfo extinfo;
1069 extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
1070 extinfo.library_namespace = ns;
1071
1072 // An app targeting M can open libnativehelper.so because it's on the greylist.
1073 android_set_application_target_sdk_version(__ANDROID_API_M__);
1074 void* handle = android_dlopen_ext("libnativehelper.so", RTLD_NOW, &extinfo);
1075 ASSERT_TRUE(handle != nullptr) << dlerror();
1076
1077 // Check that loader did not load another copy of libdl.so while loading greylisted library.
1078 void* dlsym_ptr = dlsym(handle, "dlsym");
1079 ASSERT_TRUE(dlsym_ptr != nullptr) << dlerror();
1080 ASSERT_EQ(&dlsym, dlsym_ptr);
1081
1082 dlclose(handle);
1083
1084 // An app targeting N no longer has the greylist.
1085 android_set_application_target_sdk_version(__ANDROID_API_N__);
1086 handle = android_dlopen_ext("libnativehelper.so", RTLD_NOW, &extinfo);
1087 ASSERT_TRUE(handle == nullptr);
1088 ASSERT_STREQ("dlopen failed: library \"libnativehelper.so\" not found", dlerror());
1089 }
1090
TEST(dlext,ns_greylist_disabled_by_default)1091 TEST(dlext, ns_greylist_disabled_by_default) {
1092 ASSERT_TRUE(android_init_anonymous_namespace(g_core_shared_libs.c_str(), nullptr));
1093
1094 const std::string ns_search_path = get_testlib_root() + "/private_namespace_libs";
1095
1096 android_namespace_t* ns =
1097 android_create_namespace("namespace",
1098 nullptr,
1099 ns_search_path.c_str(),
1100 ANDROID_NAMESPACE_TYPE_ISOLATED,
1101 nullptr,
1102 nullptr);
1103
1104 ASSERT_TRUE(android_link_namespaces(ns, nullptr, g_core_shared_libs.c_str())) << dlerror();
1105
1106 android_dlextinfo extinfo;
1107 extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
1108 extinfo.library_namespace = ns;
1109
1110 android_set_application_target_sdk_version(__ANDROID_API_M__);
1111 void* handle = android_dlopen_ext("libnativehelper.so", RTLD_NOW, &extinfo);
1112 ASSERT_TRUE(handle == nullptr);
1113 ASSERT_STREQ("dlopen failed: library \"libnativehelper.so\" not found", dlerror());
1114 }
1115
TEST(dlext,ns_cyclic_namespaces)1116 TEST(dlext, ns_cyclic_namespaces) {
1117 // Test that ns1->ns2->ns1 link does not break the loader
1118 ASSERT_TRUE(android_init_anonymous_namespace(g_core_shared_libs.c_str(), nullptr));
1119 std::string shared_libs = g_core_shared_libs + ":libthatdoesnotexist.so";
1120
1121 const std::string ns_search_path = get_testlib_root() + "/public_namespace_libs";
1122
1123 android_namespace_t* ns1 =
1124 android_create_namespace("ns1",
1125 nullptr,
1126 ns_search_path.c_str(),
1127 ANDROID_NAMESPACE_TYPE_ISOLATED,
1128 nullptr,
1129 nullptr);
1130
1131 ASSERT_TRUE(android_link_namespaces(ns1, nullptr, g_core_shared_libs.c_str())) << dlerror();
1132
1133 android_namespace_t* ns2 =
1134 android_create_namespace("ns1",
1135 nullptr,
1136 ns_search_path.c_str(),
1137 ANDROID_NAMESPACE_TYPE_ISOLATED,
1138 nullptr,
1139 nullptr);
1140
1141 ASSERT_TRUE(android_link_namespaces(ns2, nullptr, g_core_shared_libs.c_str())) << dlerror();
1142
1143 ASSERT_TRUE(android_link_namespaces(ns2, ns1, shared_libs.c_str())) << dlerror();
1144 ASSERT_TRUE(android_link_namespaces(ns1, ns2, shared_libs.c_str())) << dlerror();
1145
1146 android_dlextinfo extinfo;
1147 extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
1148 extinfo.library_namespace = ns1;
1149
1150 void* handle = android_dlopen_ext("libthatdoesnotexist.so", RTLD_NOW, &extinfo);
1151 ASSERT_TRUE(handle == nullptr);
1152 ASSERT_STREQ("dlopen failed: library \"libthatdoesnotexist.so\" not found", dlerror());
1153 }
1154
TEST(dlext,ns_isolated)1155 TEST(dlext, ns_isolated) {
1156 static const char* root_lib = "libnstest_root_not_isolated.so";
1157 std::string shared_libs = g_core_shared_libs + ":" + g_public_lib;
1158
1159 const std::string lib_public_path = get_testlib_root() + "/public_namespace_libs/" + g_public_lib;
1160 void* handle_public = dlopen(lib_public_path.c_str(), RTLD_NOW);
1161 ASSERT_TRUE(handle_public != nullptr) << dlerror();
1162
1163 android_set_application_target_sdk_version(42U); // something > 23
1164
1165 ASSERT_TRUE(android_init_anonymous_namespace(shared_libs.c_str(), nullptr)) << dlerror();
1166
1167 android_namespace_t* ns_not_isolated =
1168 android_create_namespace("private",
1169 nullptr,
1170 (get_testlib_root() + "/private_namespace_libs").c_str(),
1171 ANDROID_NAMESPACE_TYPE_REGULAR,
1172 nullptr,
1173 nullptr);
1174 ASSERT_TRUE(ns_not_isolated != nullptr) << dlerror();
1175 ASSERT_TRUE(android_link_namespaces(ns_not_isolated, nullptr, shared_libs.c_str())) << dlerror();
1176
1177 android_namespace_t* ns_isolated =
1178 android_create_namespace("private_isolated1",
1179 nullptr,
1180 (get_testlib_root() + "/private_namespace_libs").c_str(),
1181 ANDROID_NAMESPACE_TYPE_ISOLATED,
1182 nullptr,
1183 nullptr);
1184 ASSERT_TRUE(ns_isolated != nullptr) << dlerror();
1185 ASSERT_TRUE(android_link_namespaces(ns_isolated, nullptr, shared_libs.c_str())) << dlerror();
1186
1187 android_namespace_t* ns_isolated2 =
1188 android_create_namespace("private_isolated2",
1189 (get_testlib_root() + "/private_namespace_libs").c_str(),
1190 nullptr,
1191 ANDROID_NAMESPACE_TYPE_ISOLATED,
1192 get_testlib_root().c_str(),
1193 nullptr);
1194 ASSERT_TRUE(ns_isolated2 != nullptr) << dlerror();
1195 ASSERT_TRUE(android_link_namespaces(ns_isolated2, nullptr, shared_libs.c_str())) << dlerror();
1196
1197 ASSERT_TRUE(dlopen(root_lib, RTLD_NOW) == nullptr);
1198 ASSERT_STREQ("dlopen failed: library \"libnstest_root_not_isolated.so\" not found", dlerror());
1199
1200 std::string lib_private_external_path =
1201 get_testlib_root() + "/private_namespace_libs_external/libnstest_private_external.so";
1202
1203 // Load lib_private_external_path to default namespace
1204 // (it should remain invisible for the isolated namespaces after this)
1205 void* handle = dlopen(lib_private_external_path.c_str(), RTLD_NOW);
1206 ASSERT_TRUE(handle != nullptr) << dlerror();
1207
1208 android_dlextinfo extinfo;
1209 extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
1210 extinfo.library_namespace = ns_not_isolated;
1211
1212 void* handle1 = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo);
1213 ASSERT_TRUE(handle1 != nullptr) << dlerror();
1214
1215 extinfo.library_namespace = ns_isolated;
1216
1217 void* handle2 = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo);
1218 ASSERT_TRUE(handle2 == nullptr);
1219 ASSERT_STREQ("dlopen failed: library \"libnstest_private_external.so\" not found", dlerror());
1220
1221 // Check dlopen by absolute path
1222 handle2 = android_dlopen_ext(lib_private_external_path.c_str(), RTLD_NOW, &extinfo);
1223 ASSERT_TRUE(handle2 == nullptr);
1224 ASSERT_EQ("dlopen failed: library \"" + lib_private_external_path + "\" needed"
1225 " or dlopened by \"" + get_executable_path() + "\" is not accessible"
1226 " for the namespace \"private_isolated1\"", dlerror());
1227
1228 extinfo.library_namespace = ns_isolated2;
1229
1230 // this should work because isolation_path for private_isolated2 includes get_testlib_root()
1231 handle2 = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo);
1232 ASSERT_TRUE(handle2 != nullptr) << dlerror();
1233 dlclose(handle2);
1234
1235 // Check dlopen by absolute path
1236 handle2 = android_dlopen_ext(lib_private_external_path.c_str(), RTLD_NOW, &extinfo);
1237 ASSERT_TRUE(handle2 != nullptr) << dlerror();
1238 dlclose(handle2);
1239
1240 typedef const char* (*fn_t)();
1241 fn_t ns_get_local_string = reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_local_string"));
1242 ASSERT_TRUE(ns_get_local_string != nullptr) << dlerror();
1243
1244 ASSERT_STREQ("This string is local to root library", ns_get_local_string());
1245
1246 fn_t ns_get_private_extern_string =
1247 reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_private_extern_string"));
1248 ASSERT_TRUE(ns_get_private_extern_string != nullptr) << dlerror();
1249
1250 ASSERT_STREQ("This string is from private namespace", ns_get_private_extern_string());
1251
1252 fn_t ns_get_public_extern_string =
1253 reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_public_extern_string"));
1254 ASSERT_TRUE(ns_get_public_extern_string != nullptr) << dlerror();
1255
1256 ASSERT_STREQ("This string is from public namespace", ns_get_public_extern_string());
1257
1258 fn_t ns_get_dlopened_string = reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_dlopened_string"));
1259 ASSERT_TRUE(ns_get_dlopened_string != nullptr) << dlerror();
1260
1261 ASSERT_STREQ("This string is from private namespace (dlopened library)", ns_get_dlopened_string());
1262
1263 dlclose(handle1);
1264 }
1265
TEST(dlext,ns_shared)1266 TEST(dlext, ns_shared) {
1267 static const char* root_lib = "libnstest_root_not_isolated.so";
1268 static const char* root_lib_isolated = "libnstest_root.so";
1269
1270 std::string shared_libs = g_core_shared_libs + ":" + g_public_lib;
1271
1272 const std::string lib_public_path = get_testlib_root() + "/public_namespace_libs/" + g_public_lib;
1273 void* handle_public = dlopen(lib_public_path.c_str(), RTLD_NOW);
1274 ASSERT_TRUE(handle_public != nullptr) << dlerror();
1275
1276 android_set_application_target_sdk_version(42U); // something > 23
1277
1278 ASSERT_TRUE(android_init_anonymous_namespace(shared_libs.c_str(), nullptr)) << dlerror();
1279
1280 // preload this library to the default namespace to check if it
1281 // is shared later on.
1282 void* handle_dlopened =
1283 dlopen((get_testlib_root() + "/private_namespace_libs/libnstest_dlopened.so").c_str(), RTLD_NOW);
1284 ASSERT_TRUE(handle_dlopened != nullptr) << dlerror();
1285
1286 android_namespace_t* ns_not_isolated =
1287 android_create_namespace("private",
1288 nullptr,
1289 (get_testlib_root() + "/private_namespace_libs").c_str(),
1290 ANDROID_NAMESPACE_TYPE_REGULAR,
1291 nullptr,
1292 nullptr);
1293 ASSERT_TRUE(ns_not_isolated != nullptr) << dlerror();
1294 ASSERT_TRUE(android_link_namespaces(ns_not_isolated, nullptr, shared_libs.c_str())) << dlerror();
1295
1296 android_namespace_t* ns_isolated_shared =
1297 android_create_namespace("private_isolated_shared",
1298 nullptr,
1299 (get_testlib_root() + "/private_namespace_libs").c_str(),
1300 ANDROID_NAMESPACE_TYPE_ISOLATED | ANDROID_NAMESPACE_TYPE_SHARED,
1301 nullptr,
1302 nullptr);
1303 ASSERT_TRUE(ns_isolated_shared != nullptr) << dlerror();
1304 ASSERT_TRUE(android_link_namespaces(ns_isolated_shared, nullptr, shared_libs.c_str())) << dlerror();
1305
1306 ASSERT_TRUE(dlopen(root_lib, RTLD_NOW) == nullptr);
1307 ASSERT_STREQ("dlopen failed: library \"libnstest_root_not_isolated.so\" not found", dlerror());
1308
1309 std::string lib_private_external_path =
1310 get_testlib_root() + "/private_namespace_libs_external/libnstest_private_external.so";
1311
1312 // Load lib_private_external_path to default namespace
1313 // (it should remain invisible for the isolated namespaces after this)
1314 void* handle = dlopen(lib_private_external_path.c_str(), RTLD_NOW);
1315 ASSERT_TRUE(handle != nullptr) << dlerror();
1316
1317 android_dlextinfo extinfo;
1318 extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
1319 extinfo.library_namespace = ns_not_isolated;
1320
1321 void* handle1 = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo);
1322 ASSERT_TRUE(handle1 != nullptr) << dlerror();
1323
1324 extinfo.library_namespace = ns_isolated_shared;
1325
1326 void* handle2 = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo);
1327 ASSERT_TRUE(handle2 == nullptr);
1328 ASSERT_STREQ("dlopen failed: library \"libnstest_private_external.so\" not found", dlerror());
1329
1330 // Check dlopen by absolute path
1331 handle2 = android_dlopen_ext(lib_private_external_path.c_str(), RTLD_NOW, &extinfo);
1332 ASSERT_TRUE(handle2 == nullptr);
1333 ASSERT_EQ("dlopen failed: library \"" + lib_private_external_path + "\" needed"
1334 " or dlopened by \"" + get_executable_path() + "\" is not accessible"
1335 " for the namespace \"private_isolated_shared\"", dlerror());
1336
1337 // load libnstest_root.so to shared namespace in order to check that everything is different
1338 // except shared libnstest_dlopened.so
1339
1340 handle2 = android_dlopen_ext(root_lib_isolated, RTLD_NOW, &extinfo);
1341
1342 typedef const char* (*fn_t)();
1343 fn_t ns_get_local_string = reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_local_string"));
1344 ASSERT_TRUE(ns_get_local_string != nullptr) << dlerror();
1345 fn_t ns_get_local_string_shared = reinterpret_cast<fn_t>(dlsym(handle2, "ns_get_local_string"));
1346 ASSERT_TRUE(ns_get_local_string_shared != nullptr) << dlerror();
1347
1348 ASSERT_STREQ("This string is local to root library", ns_get_local_string());
1349 ASSERT_STREQ("This string is local to root library", ns_get_local_string_shared());
1350 ASSERT_TRUE(ns_get_local_string() != ns_get_local_string_shared());
1351
1352 fn_t ns_get_private_extern_string =
1353 reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_private_extern_string"));
1354 ASSERT_TRUE(ns_get_private_extern_string != nullptr) << dlerror();
1355 fn_t ns_get_private_extern_string_shared =
1356 reinterpret_cast<fn_t>(dlsym(handle2, "ns_get_private_extern_string"));
1357 ASSERT_TRUE(ns_get_private_extern_string_shared() != nullptr) << dlerror();
1358
1359 ASSERT_STREQ("This string is from private namespace", ns_get_private_extern_string());
1360 ASSERT_STREQ("This string is from private namespace", ns_get_private_extern_string_shared());
1361 ASSERT_TRUE(ns_get_private_extern_string() != ns_get_private_extern_string_shared());
1362
1363 fn_t ns_get_public_extern_string =
1364 reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_public_extern_string"));
1365 ASSERT_TRUE(ns_get_public_extern_string != nullptr) << dlerror();
1366 fn_t ns_get_public_extern_string_shared =
1367 reinterpret_cast<fn_t>(dlsym(handle2, "ns_get_public_extern_string"));
1368 ASSERT_TRUE(ns_get_public_extern_string_shared != nullptr) << dlerror();
1369
1370 ASSERT_STREQ("This string is from public namespace", ns_get_public_extern_string());
1371 ASSERT_STREQ("This string is from public namespace", ns_get_public_extern_string_shared());
1372 ASSERT_TRUE(ns_get_public_extern_string() == ns_get_public_extern_string_shared());
1373
1374 fn_t ns_get_dlopened_string = reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_dlopened_string"));
1375 ASSERT_TRUE(ns_get_dlopened_string != nullptr) << dlerror();
1376 fn_t ns_get_dlopened_string_shared = reinterpret_cast<fn_t>(dlsym(handle2, "ns_get_dlopened_string"));
1377 ASSERT_TRUE(ns_get_dlopened_string_shared != nullptr) << dlerror();
1378 const char** ns_dlopened_string = static_cast<const char**>(dlsym(handle_dlopened, "g_private_dlopened_string"));
1379 ASSERT_TRUE(ns_dlopened_string != nullptr) << dlerror();
1380
1381 ASSERT_STREQ("This string is from private namespace (dlopened library)", ns_get_dlopened_string());
1382 ASSERT_STREQ("This string is from private namespace (dlopened library)", *ns_dlopened_string);
1383 ASSERT_STREQ("This string is from private namespace (dlopened library)", ns_get_dlopened_string_shared());
1384 ASSERT_TRUE(ns_get_dlopened_string() != ns_get_dlopened_string_shared());
1385 ASSERT_TRUE(*ns_dlopened_string == ns_get_dlopened_string_shared());
1386
1387 dlclose(handle1);
1388 dlclose(handle2);
1389 }
1390
TEST(dlext,ns_shared_links_and_paths)1391 TEST(dlext, ns_shared_links_and_paths) {
1392 // Create parent namespace (isolated, not shared)
1393 android_namespace_t* ns_isolated =
1394 android_create_namespace("private_isolated",
1395 nullptr,
1396 (get_testlib_root() + "/private_namespace_libs").c_str(),
1397 ANDROID_NAMESPACE_TYPE_ISOLATED,
1398 (get_testlib_root() + "/public_namespace_libs").c_str(),
1399 nullptr);
1400 ASSERT_TRUE(ns_isolated != nullptr) << dlerror();
1401 ASSERT_TRUE(android_link_namespaces(ns_isolated, nullptr, g_core_shared_libs.c_str())) << dlerror();
1402
1403 // Create shared namespace with ns_isolated parent
1404 android_namespace_t* ns_shared =
1405 android_create_namespace("private_shared",
1406 nullptr,
1407 nullptr,
1408 ANDROID_NAMESPACE_TYPE_SHARED | ANDROID_NAMESPACE_TYPE_ISOLATED,
1409 nullptr,
1410 ns_isolated);
1411 ASSERT_TRUE(ns_shared != nullptr) << dlerror();
1412
1413 // 1. Load a library in ns_shared to check that it has inherited
1414 // search path and the link to the default namespace.
1415 android_dlextinfo extinfo;
1416 extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
1417 extinfo.library_namespace = ns_shared;
1418
1419 {
1420 void* handle = android_dlopen_ext("libnstest_private.so", RTLD_NOW, &extinfo);
1421 ASSERT_TRUE(handle != nullptr) << dlerror();
1422 const char** ns_private_extern_string = static_cast<const char**>(dlsym(handle, "g_private_extern_string"));
1423 ASSERT_TRUE(ns_private_extern_string != nullptr) << dlerror();
1424 ASSERT_STREQ("This string is from private namespace", *ns_private_extern_string);
1425
1426 dlclose(handle);
1427 }
1428 // 2. Load another test library by absolute path to check that
1429 // it has inherited permitted_when_isolated_path
1430 {
1431 void* handle = android_dlopen_ext(
1432 (get_testlib_root() + "/public_namespace_libs/libnstest_public.so").c_str(),
1433 RTLD_NOW,
1434 &extinfo);
1435
1436 ASSERT_TRUE(handle != nullptr) << dlerror();
1437 const char** ns_public_extern_string = static_cast<const char**>(dlsym(handle, "g_public_extern_string"));
1438 ASSERT_TRUE(ns_public_extern_string != nullptr) << dlerror();
1439 ASSERT_STREQ("This string is from public namespace", *ns_public_extern_string);
1440
1441 dlclose(handle);
1442 }
1443
1444 // 3. Check that it is still isolated.
1445 {
1446 void* handle = android_dlopen_ext(
1447 (get_testlib_root() + "/libtest_empty.so").c_str(),
1448 RTLD_NOW,
1449 &extinfo);
1450
1451 ASSERT_TRUE(handle == nullptr);
1452 }
1453 }
1454
TEST(dlext,ns_shared_dlclose)1455 TEST(dlext, ns_shared_dlclose) {
1456 android_set_application_target_sdk_version(42U); // something > 23
1457
1458 ASSERT_TRUE(android_init_anonymous_namespace(g_core_shared_libs.c_str(), nullptr)) << dlerror();
1459
1460 // preload this library to the default namespace to check if it
1461 // is shared later on.
1462 void* handle_dlopened =
1463 dlopen((get_testlib_root() + "/private_namespace_libs/libnstest_dlopened.so").c_str(), RTLD_NOW);
1464 ASSERT_TRUE(handle_dlopened != nullptr) << dlerror();
1465
1466 android_namespace_t* ns_isolated_shared =
1467 android_create_namespace("private_isolated_shared",
1468 nullptr,
1469 (get_testlib_root() + "/private_namespace_libs").c_str(),
1470 ANDROID_NAMESPACE_TYPE_ISOLATED | ANDROID_NAMESPACE_TYPE_SHARED,
1471 nullptr,
1472 nullptr);
1473 ASSERT_TRUE(ns_isolated_shared != nullptr) << dlerror();
1474 ASSERT_TRUE(android_link_namespaces(ns_isolated_shared, nullptr, g_core_shared_libs.c_str())) << dlerror();
1475
1476 // Check if "libnstest_dlopened.so" is loaded (and the same)
1477 android_dlextinfo extinfo;
1478 extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
1479 extinfo.library_namespace = ns_isolated_shared;
1480
1481 void* handle = android_dlopen_ext("libnstest_dlopened.so", RTLD_NOW | RTLD_NOLOAD, &extinfo);
1482 ASSERT_TRUE(handle != nullptr) << dlerror();
1483 ASSERT_TRUE(handle == handle_dlopened);
1484 dlclose(handle);
1485 dlclose(handle_dlopened);
1486
1487 // And now check that the library cannot be found by soname (and is no longer loaded)
1488 handle = android_dlopen_ext("libnstest_dlopened.so", RTLD_NOW | RTLD_NOLOAD, &extinfo);
1489 ASSERT_TRUE(handle == nullptr)
1490 << "Error: libnstest_dlopened.so is still accessible in shared namespace";
1491
1492 handle = android_dlopen_ext((get_testlib_root() + "/private_namespace_libs/libnstest_dlopened.so").c_str(),
1493 RTLD_NOW | RTLD_NOLOAD, &extinfo);
1494 ASSERT_TRUE(handle == nullptr)
1495 << "Error: libnstest_dlopened.so is still accessible in shared namespace";
1496
1497 handle = dlopen("libnstest_dlopened.so", RTLD_NOW | RTLD_NOLOAD);
1498 ASSERT_TRUE(handle == nullptr)
1499 << "Error: libnstest_dlopened.so is still accessible in default namespace";
1500
1501 handle = dlopen((get_testlib_root() + "/private_namespace_libs/libnstest_dlopened.so").c_str(),
1502 RTLD_NOW | RTLD_NOLOAD);
1503 ASSERT_TRUE(handle == nullptr)
1504 << "Error: libnstest_dlopened.so is still accessible in default namespace";
1505
1506 // Now lets see if the soinfo area gets reused in the wrong way:
1507 // load a library to default namespace.
1508 const std::string lib_public_path = get_testlib_root() + "/public_namespace_libs/" + g_public_lib;
1509 void* handle_public = dlopen(lib_public_path.c_str(), RTLD_NOW);
1510 ASSERT_TRUE(handle_public != nullptr) << dlerror();
1511
1512 // try to find it in shared namespace
1513 handle = android_dlopen_ext(g_public_lib, RTLD_NOW | RTLD_NOLOAD, &extinfo);
1514 ASSERT_TRUE(handle == nullptr)
1515 << "Error: " << g_public_lib << " is accessible in shared namespace";
1516 }
1517
TEST(dlext,ns_isolated_rtld_global)1518 TEST(dlext, ns_isolated_rtld_global) {
1519 static const char* root_lib = "libnstest_root.so";
1520 ASSERT_TRUE(android_init_anonymous_namespace(g_core_shared_libs.c_str(), nullptr));
1521
1522 const std::string lib_public_path = get_testlib_root() + "/public_namespace_libs";
1523
1524 android_namespace_t* ns1 =
1525 android_create_namespace("isolated1",
1526 nullptr,
1527 (get_testlib_root() + "/private_namespace_libs").c_str(),
1528 ANDROID_NAMESPACE_TYPE_ISOLATED,
1529 lib_public_path.c_str(),
1530 nullptr);
1531 ASSERT_TRUE(ns1 != nullptr) << dlerror();
1532 ASSERT_TRUE(android_link_namespaces(ns1, nullptr, g_core_shared_libs.c_str())) << dlerror();
1533
1534 android_namespace_t* ns2 =
1535 android_create_namespace("isolated2",
1536 nullptr,
1537 (get_testlib_root() + "/private_namespace_libs").c_str(),
1538 ANDROID_NAMESPACE_TYPE_ISOLATED,
1539 lib_public_path.c_str(),
1540 nullptr);
1541 ASSERT_TRUE(ns2 != nullptr) << dlerror();
1542 ASSERT_TRUE(android_link_namespaces(ns2, nullptr, g_core_shared_libs.c_str())) << dlerror();
1543
1544 android_dlextinfo extinfo;
1545 extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
1546 extinfo.library_namespace = ns1;
1547
1548 void* handle_global = android_dlopen_ext((lib_public_path + "/" + g_public_lib).c_str(),
1549 RTLD_GLOBAL,
1550 &extinfo);
1551
1552 ASSERT_TRUE(handle_global != nullptr) << dlerror();
1553
1554 android_namespace_t* ns1_child =
1555 android_create_namespace("isolated1_child",
1556 nullptr,
1557 (get_testlib_root() + "/private_namespace_libs").c_str(),
1558 ANDROID_NAMESPACE_TYPE_ISOLATED,
1559 nullptr,
1560 ns1);
1561
1562 ASSERT_TRUE(ns1_child != nullptr) << dlerror();
1563 ASSERT_TRUE(android_link_namespaces(ns1_child, nullptr, g_core_shared_libs.c_str())) << dlerror();
1564
1565 // Now - only ns1 and ns1 child should be able to dlopen root_lib
1566 // attempt to use ns2 should result in dlerror()
1567
1568 // Check ns1_child first.
1569 extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
1570 extinfo.library_namespace = ns1_child;
1571
1572 void* handle1 = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo);
1573 ASSERT_TRUE(handle1 != nullptr) << dlerror();
1574
1575 // now ns1
1576 extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
1577 extinfo.library_namespace = ns1;
1578
1579 handle1 = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo);
1580 ASSERT_TRUE(handle1 != nullptr) << dlerror();
1581
1582 // and ns2 should fail
1583 extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
1584 extinfo.library_namespace = ns2;
1585
1586 handle1 = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo);
1587 ASSERT_TRUE(handle1 == nullptr);
1588 ASSERT_STREQ("dlopen failed: library \"libnstest_public.so\" not found", dlerror());
1589 }
1590
TEST(dlext,ns_anonymous)1591 TEST(dlext, ns_anonymous) {
1592 static const char* root_lib = "libnstest_root.so";
1593 std::string shared_libs = g_core_shared_libs + ":" + g_public_lib;
1594
1595 const std::string lib_public_path = get_testlib_root() + "/public_namespace_libs/" + g_public_lib;
1596 void* handle_public = dlopen(lib_public_path.c_str(), RTLD_NOW);
1597
1598 ASSERT_TRUE(handle_public != nullptr) << dlerror();
1599
1600 ASSERT_TRUE(
1601 android_init_anonymous_namespace(shared_libs.c_str(),
1602 (get_testlib_root() + "/private_namespace_libs").c_str())
1603 ) << dlerror();
1604
1605 android_namespace_t* ns =
1606 android_create_namespace("private",
1607 nullptr,
1608 (get_testlib_root() + "/private_namespace_libs").c_str(),
1609 ANDROID_NAMESPACE_TYPE_REGULAR,
1610 nullptr,
1611 nullptr);
1612
1613 ASSERT_TRUE(ns != nullptr) << dlerror();
1614 ASSERT_TRUE(android_link_namespaces(ns, nullptr, shared_libs.c_str())) << dlerror();
1615
1616 std::string private_library_absolute_path = get_testlib_root() + "/private_namespace_libs/" + root_lib;
1617
1618 android_dlextinfo extinfo;
1619 extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
1620 extinfo.library_namespace = ns;
1621
1622 // we are going to copy this library to anonymous mmap and call the copy of ns_get_dlopened_string
1623 void* handle = android_dlopen_ext(private_library_absolute_path.c_str(), RTLD_NOW, &extinfo);
1624 ASSERT_TRUE(handle != nullptr) << dlerror();
1625
1626 uintptr_t ns_get_dlopened_string_addr =
1627 reinterpret_cast<uintptr_t>(dlsym(handle, "ns_get_dlopened_string"));
1628 ASSERT_TRUE(ns_get_dlopened_string_addr != 0) << dlerror();
1629 typedef const char* (*fn_t)();
1630 fn_t ns_get_dlopened_string_private = reinterpret_cast<fn_t>(ns_get_dlopened_string_addr);
1631
1632 std::vector<map_record> maps;
1633 Maps::parse_maps(&maps);
1634
1635 uintptr_t addr_start = 0;
1636 uintptr_t addr_end = 0;
1637 std::vector<map_record> maps_to_copy;
1638
1639 for (const auto& rec : maps) {
1640 if (rec.pathname == private_library_absolute_path) {
1641 if (addr_start == 0) {
1642 addr_start = rec.addr_start;
1643 }
1644 addr_end = rec.addr_end;
1645
1646 maps_to_copy.push_back(rec);
1647 }
1648 }
1649
1650 // some sanity checks..
1651 ASSERT_TRUE(addr_start > 0);
1652 ASSERT_TRUE(addr_end > 0);
1653 ASSERT_EQ(3U, maps_to_copy.size());
1654 ASSERT_TRUE(ns_get_dlopened_string_addr > addr_start);
1655 ASSERT_TRUE(ns_get_dlopened_string_addr < addr_end);
1656
1657 // copy
1658 uintptr_t reserved_addr = reinterpret_cast<uintptr_t>(mmap(nullptr, addr_end - addr_start,
1659 PROT_NONE, MAP_ANON | MAP_PRIVATE,
1660 -1, 0));
1661 ASSERT_TRUE(reinterpret_cast<void*>(reserved_addr) != MAP_FAILED);
1662
1663 for (const auto& rec : maps_to_copy) {
1664 uintptr_t offset = rec.addr_start - addr_start;
1665 size_t size = rec.addr_end - rec.addr_start;
1666 void* addr = reinterpret_cast<void*>(reserved_addr + offset);
1667 void* map = mmap(addr, size, PROT_READ | PROT_WRITE,
1668 MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, 0);
1669 ASSERT_TRUE(map != MAP_FAILED);
1670 memcpy(map, reinterpret_cast<void*>(rec.addr_start), size);
1671 mprotect(map, size, rec.perms);
1672 }
1673
1674 // call the function copy
1675 uintptr_t ns_get_dlopened_string_offset = ns_get_dlopened_string_addr - addr_start;
1676 fn_t ns_get_dlopened_string_anon = reinterpret_cast<fn_t>(reserved_addr + ns_get_dlopened_string_offset);
1677 ASSERT_STREQ("This string is from private namespace (dlopened library)",
1678 ns_get_dlopened_string_anon());
1679
1680 // They should belong to different namespaces (private and anonymous)
1681 ASSERT_STREQ("This string is from private namespace (dlopened library)",
1682 ns_get_dlopened_string_private());
1683
1684 ASSERT_TRUE(ns_get_dlopened_string_anon() != ns_get_dlopened_string_private());
1685 }
1686
TEST(dlext,dlopen_handle_value_platform)1687 TEST(dlext, dlopen_handle_value_platform) {
1688 void* handle = dlopen("libtest_dlsym_from_this.so", RTLD_NOW | RTLD_LOCAL);
1689 ASSERT_TRUE((reinterpret_cast<uintptr_t>(handle) & 1) != 0)
1690 << "dlopen should return odd value for the handle";
1691 dlclose(handle);
1692 }
1693
TEST(dlext,dlopen_handle_value_app_compat)1694 TEST(dlext, dlopen_handle_value_app_compat) {
1695 android_set_application_target_sdk_version(__ANDROID_API_M__);
1696 void* handle = dlopen("libtest_dlsym_from_this.so", RTLD_NOW | RTLD_LOCAL);
1697 ASSERT_TRUE(reinterpret_cast<uintptr_t>(handle) % sizeof(uintptr_t) == 0)
1698 << "dlopen should return valid pointer";
1699 dlclose(handle);
1700 }
1701