dlext_test.cpp revision 350bdad61cc6551db649fcaeb8642f4a1d6b139a
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#include <android/dlext.h> 28#include <sys/mman.h> 29#include <sys/types.h> 30#include <sys/wait.h> 31 32#include <pagemap/pagemap.h> 33#include <ziparchive/zip_archive.h> 34 35#include "TemporaryFile.h" 36#include "utils.h" 37 38#define ASSERT_DL_NOTNULL(ptr) \ 39 ASSERT_TRUE(ptr != nullptr) << "dlerror: " << dlerror() 40 41#define ASSERT_DL_ZERO(i) \ 42 ASSERT_EQ(0, i) << "dlerror: " << dlerror() 43 44#define ASSERT_NOERROR(i) \ 45 ASSERT_NE(-1, i) << "errno: " << strerror(errno) 46 47#define ASSERT_SUBSTR(needle, haystack) \ 48 ASSERT_PRED_FORMAT2(::testing::IsSubstring, needle, haystack) 49 50 51typedef int (*fn)(void); 52#define LIBNAME "libdlext_test.so" 53#define LIBNAME_NORELRO "libdlext_test_norelro.so" 54#define LIBSIZE 1024*1024 // how much address space to reserve for it 55 56#if defined(__LP64__) 57#define NATIVE_TESTS_PATH "/nativetest64" 58#else 59#define NATIVE_TESTS_PATH "/nativetest" 60#endif 61 62#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" 65#define LIBZIP_SIMPLE_ZIP "libdir/libatest_simple_zip.so" 66 67class DlExtTest : public ::testing::Test { 68protected: 69 virtual void SetUp() { 70 handle_ = nullptr; 71 // verify that we don't have the library loaded already 72 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); 76 // call dlerror() to swallow the error, and check it was the one we wanted 77 ASSERT_STREQ("dlopen failed: library \"" LIBNAME_NORELRO "\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror()); 78 } 79 80 virtual void TearDown() { 81 if (handle_ != nullptr) { 82 ASSERT_DL_ZERO(dlclose(handle_)); 83 } 84 } 85 86 void* handle_; 87}; 88 89TEST_F(DlExtTest, ExtInfoNull) { 90 handle_ = android_dlopen_ext(LIBNAME, RTLD_NOW, nullptr); 91 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 107TEST_F(DlExtTest, ExtInfoUseFd) { 108 const std::string lib_path = std::string(getenv("ANDROID_DATA")) + LIBPATH; 109 110 android_dlextinfo extinfo; 111 extinfo.flags = ANDROID_DLEXT_USE_LIBRARY_FD; 112 extinfo.library_fd = TEMP_FAILURE_RETRY(open(lib_path.c_str(), O_RDONLY | O_CLOEXEC)); 113 ASSERT_TRUE(extinfo.library_fd != -1); 114 handle_ = android_dlopen_ext(lib_path.c_str(), RTLD_NOW, &extinfo); 115 ASSERT_DL_NOTNULL(handle_); 116 fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber")); 117 ASSERT_DL_NOTNULL(f); 118 EXPECT_EQ(4, f()); 119 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); 123} 124 125TEST_F(DlExtTest, ExtInfoUseFdWithOffset) { 126 const std::string lib_path = std::string(getenv("ANDROID_DATA")) + LIBZIPPATH; 127 128 android_dlextinfo extinfo; 129 extinfo.flags = ANDROID_DLEXT_USE_LIBRARY_FD | ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET; 130 extinfo.library_fd = TEMP_FAILURE_RETRY(open(lib_path.c_str(), O_RDONLY | O_CLOEXEC)); 131 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); 142 143 handle_ = android_dlopen_ext(lib_path.c_str(), RTLD_NOW, &extinfo); 144 ASSERT_DL_NOTNULL(handle_); 145 146 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); 149} 150 151TEST_F(DlExtTest, ExtInfoUseFdWithInvalidOffset) { 152 const std::string lib_path = std::string(getenv("ANDROID_DATA")) + LIBZIPPATH; 153 // 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); 157 158 android_dlextinfo extinfo; 159 extinfo.flags = ANDROID_DLEXT_USE_LIBRARY_FD | ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET; 160 extinfo.library_fd = TEMP_FAILURE_RETRY(open(lib_path.c_str(), O_RDONLY | O_CLOEXEC)); 161 extinfo.library_fd_offset = 17; 162 163 handle_ = android_dlopen_ext("libname_placeholder", RTLD_NOW, &extinfo); 164 ASSERT_TRUE(handle_ == nullptr); 165 ASSERT_STREQ("dlopen failed: file offset for the library \"libname_placeholder\" is not page-aligned: 17", dlerror()); 166 167 // Test an address above 2^44, for http://b/18178121 . 168 extinfo.library_fd_offset = (5LL<<48) + PAGE_SIZE; 169 handle_ = android_dlopen_ext("libname_placeholder", RTLD_NOW, &extinfo); 170 ASSERT_TRUE(handle_ == nullptr); 171 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 178 extinfo.library_fd_offset = 0; 179 handle_ = android_dlopen_ext("libname_ignored", RTLD_NOW, &extinfo); 180 ASSERT_TRUE(handle_ == nullptr); 181 ASSERT_EQ("dlopen failed: \"" + lib_realpath + "\" has bad ELF magic", dlerror()); 182 183 // 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 188 close(extinfo.library_fd); 189} 190 191TEST_F(DlExtTest, ExtInfoUseOffsetWithoutFd) { 192 android_dlextinfo extinfo; 193 extinfo.flags = ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET; 194 // This offset will not be used, so it doesn't matter. 195 extinfo.library_fd_offset = 0; 196 197 handle_ = android_dlopen_ext("/some/lib/that/does_not_exist", RTLD_NOW, &extinfo); 198 ASSERT_TRUE(handle_ == nullptr); 199 ASSERT_STREQ("dlopen failed: invalid extended flag combination (ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET without ANDROID_DLEXT_USE_LIBRARY_FD): 0x20", dlerror()); 200} 201 202TEST(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 236TEST(dlfcn, dlopen_from_zip_absolute_path) { 237 const std::string lib_path = std::string(getenv("ANDROID_DATA")) + LIBZIPPATH; 238 239 void* handle = dlopen((lib_path + "!/libdir/libatest_simple_zip.so").c_str(), RTLD_NOW); 240 ASSERT_TRUE(handle != nullptr) << dlerror(); 241 242 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); 245 246 dlclose(handle); 247} 248 249TEST(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 267TEST(dlfcn, dlopen_from_zip_ld_library_path) { 268 const std::string lib_path = std::string(getenv("ANDROID_DATA")) + LIBZIPPATH + "!/libdir"; 269 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 276 void* handle = dlopen("libdlext_test_zip.so", RTLD_NOW); 277 ASSERT_TRUE(handle == nullptr); 278 279 android_update_LD_LIBRARY_PATH(lib_path.c_str()); 280 281 handle = dlopen("libdlext_test_zip.so", RTLD_NOW); 282 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 289 uint32_t* taxicab_number = 290 reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_testlib_taxicab_number")); 291 ASSERT_DL_NOTNULL(taxicab_number); 292 EXPECT_EQ(1729U, *taxicab_number); 293 294 dlclose(handle); 295} 296 297 298TEST_F(DlExtTest, Reserved) { 299 void* start = mmap(nullptr, LIBSIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 300 ASSERT_TRUE(start != MAP_FAILED); 301 android_dlextinfo extinfo; 302 extinfo.flags = ANDROID_DLEXT_RESERVED_ADDRESS; 303 extinfo.reserved_addr = start; 304 extinfo.reserved_size = LIBSIZE; 305 handle_ = android_dlopen_ext(LIBNAME, RTLD_NOW, &extinfo); 306 ASSERT_DL_NOTNULL(handle_); 307 fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber")); 308 ASSERT_DL_NOTNULL(f); 309 EXPECT_GE(reinterpret_cast<void*>(f), start); 310 EXPECT_LT(reinterpret_cast<void*>(f), 311 reinterpret_cast<char*>(start) + LIBSIZE); 312 EXPECT_EQ(4, f()); 313 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"; 320} 321 322TEST_F(DlExtTest, ReservedTooSmall) { 323 void* start = mmap(nullptr, PAGE_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 324 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); 330 EXPECT_EQ(nullptr, handle_); 331} 332 333TEST_F(DlExtTest, ReservedHint) { 334 void* start = mmap(nullptr, LIBSIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 335 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); 344 EXPECT_GE(reinterpret_cast<void*>(f), start); 345 EXPECT_LT(reinterpret_cast<void*>(f), 346 reinterpret_cast<char*>(start) + LIBSIZE); 347 EXPECT_EQ(4, f()); 348} 349 350TEST_F(DlExtTest, ReservedHintTooSmall) { 351 void* start = mmap(nullptr, PAGE_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 352 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); 361 EXPECT_TRUE(reinterpret_cast<void*>(f) < start || 362 (reinterpret_cast<void*>(f) >= 363 reinterpret_cast<char*>(start) + PAGE_SIZE)); 364 EXPECT_EQ(4, f()); 365} 366 367TEST_F(DlExtTest, LoadAtFixedAddress) { 368 void* start = mmap(nullptr, LIBSIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 369 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()); 384 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"; 390} 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 409class DlExtRelroSharingTest : public DlExtTest { 410protected: 411 virtual void SetUp() { 412 DlExtTest::SetUp(); 413 void* start = mmap(nullptr, LIBSIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 414 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; 419 } 420 421 virtual void TearDown() { 422 DlExtTest::TearDown(); 423 } 424 425 void CreateRelroFile(const char* lib, const char* relro_file) { 426 int relro_fd = open(relro_file, O_RDWR | O_TRUNC); 427 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_); 435 if (handle == nullptr) { 436 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 AssertChildExited(pid, 0); 446 447 // reopen file for reading so it can be used 448 relro_fd = open(relro_file, O_RDONLY); 449 ASSERT_NOERROR(relro_fd); 450 extinfo_.flags |= ANDROID_DLEXT_USE_RELRO; 451 extinfo_.relro_fd = relro_fd; 452 } 453 454 void TryUsingRelro(const char* lib) { 455 handle_ = android_dlopen_ext(lib, RTLD_NOW, &extinfo_); 456 ASSERT_DL_NOTNULL(handle_); 457 fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber")); 458 ASSERT_DL_NOTNULL(f); 459 EXPECT_EQ(4, f()); 460 461 uint32_t* taxicab_number = 462 reinterpret_cast<uint32_t*>(dlsym(handle_, "dlopen_testlib_taxicab_number")); 463 ASSERT_DL_NOTNULL(taxicab_number); 464 EXPECT_EQ(1729U, *taxicab_number); 465 } 466 467 void SpawnChildrenAndMeasurePss(const char* lib, bool share_relro, size_t* pss_out); 468 469 android_dlextinfo extinfo_; 470}; 471 472TEST_F(DlExtRelroSharingTest, ChildWritesGoodData) { 473 TemporaryFile tf; // Use tf to get an unique filename. 474 ASSERT_NOERROR(close(tf.fd)); 475 476 ASSERT_NO_FATAL_FAILURE(CreateRelroFile(LIBNAME, tf.filename)); 477 ASSERT_NO_FATAL_FAILURE(TryUsingRelro(LIBNAME)); 478 479 // Use destructor of tf to close and unlink the file. 480 tf.fd = extinfo_.relro_fd; 481} 482 483TEST_F(DlExtRelroSharingTest, ChildWritesNoRelro) { 484 TemporaryFile tf; // // Use tf to get an unique filename. 485 ASSERT_NOERROR(close(tf.fd)); 486 487 ASSERT_NO_FATAL_FAILURE(CreateRelroFile(LIBNAME_NORELRO, tf.filename)); 488 ASSERT_NO_FATAL_FAILURE(TryUsingRelro(LIBNAME_NORELRO)); 489 490 // Use destructor of tf to close and unlink the file. 491 tf.fd = extinfo_.relro_fd; 492} 493 494TEST_F(DlExtRelroSharingTest, RelroFileEmpty) { 495 ASSERT_NO_FATAL_FAILURE(TryUsingRelro(LIBNAME)); 496} 497 498TEST_F(DlExtRelroSharingTest, VerifyMemorySaving) { 499 if (geteuid() != 0) { 500 GTEST_LOG_(INFO) << "This test must be run as root.\n"; 501 return; 502 } 503 504 TemporaryFile tf; // Use tf to get an unique filename. 505 ASSERT_NOERROR(close(tf.fd)); 506 507 ASSERT_NO_FATAL_FAILURE(CreateRelroFile(LIBNAME, tf.filename)); 508 509 int pipefd[2]; 510 ASSERT_NOERROR(pipe(pipefd)); 511 512 size_t without_sharing, with_sharing; 513 ASSERT_NO_FATAL_FAILURE(SpawnChildrenAndMeasurePss(LIBNAME, false, &without_sharing)); 514 ASSERT_NO_FATAL_FAILURE(SpawnChildrenAndMeasurePss(LIBNAME, true, &with_sharing)); 515 516 // We expect the sharing to save at least 10% of the total PSS. In practice 517 // it saves 40%+ for this test. 518 size_t expected_size = without_sharing - (without_sharing/10); 519 EXPECT_LT(with_sharing, expected_size); 520 521 // Use destructor of tf to close and unlink the file. 522 tf.fd = extinfo_.relro_fd; 523} 524 525void getPss(pid_t pid, size_t* pss_out) { 526 pm_kernel_t* kernel; 527 ASSERT_EQ(0, pm_kernel_create(&kernel)); 528 529 pm_process_t* process; 530 ASSERT_EQ(0, pm_process_create(kernel, pid, &process)); 531 532 pm_map_t** maps; 533 size_t num_maps; 534 ASSERT_EQ(0, pm_process_maps(process, &maps, &num_maps)); 535 536 size_t total_pss = 0; 537 for (size_t i = 0; i < num_maps; i++) { 538 pm_memusage_t usage; 539 ASSERT_EQ(0, pm_map_usage(maps[i], &usage)); 540 total_pss += usage.pss; 541 } 542 *pss_out = total_pss; 543 544 free(maps); 545 pm_process_destroy(process); 546 pm_kernel_destroy(kernel); 547} 548 549void DlExtRelroSharingTest::SpawnChildrenAndMeasurePss(const char* lib, bool share_relro, 550 size_t* pss_out) { 551 const int CHILDREN = 20; 552 553 // Create children 554 pid_t child_pids[CHILDREN]; 555 int childpipe[CHILDREN]; 556 for (int i=0; i<CHILDREN; ++i) { 557 char read_buf; 558 int child_done_pipe[2], parent_done_pipe[2]; 559 ASSERT_NOERROR(pipe(child_done_pipe)); 560 ASSERT_NOERROR(pipe(parent_done_pipe)); 561 562 pid_t child = fork(); 563 if (child == 0) { 564 // close the 'wrong' ends of the pipes in the child 565 close(child_done_pipe[0]); 566 close(parent_done_pipe[1]); 567 568 // open the library 569 void* handle; 570 if (share_relro) { 571 handle = android_dlopen_ext(lib, RTLD_NOW, &extinfo_); 572 } else { 573 handle = dlopen(lib, RTLD_NOW); 574 } 575 if (handle == nullptr) { 576 fprintf(stderr, "in child: %s\n", dlerror()); 577 exit(1); 578 } 579 580 // close write end of child_done_pipe to signal the parent that we're done. 581 close(child_done_pipe[1]); 582 583 // wait for the parent to close parent_done_pipe, then exit 584 read(parent_done_pipe[0], &read_buf, 1); 585 exit(0); 586 } 587 588 ASSERT_NOERROR(child); 589 590 // close the 'wrong' ends of the pipes in the parent 591 close(child_done_pipe[1]); 592 close(parent_done_pipe[0]); 593 594 // wait for the child to be done 595 read(child_done_pipe[0], &read_buf, 1); 596 close(child_done_pipe[0]); 597 598 // save the child's pid and the parent_done_pipe 599 child_pids[i] = child; 600 childpipe[i] = parent_done_pipe[1]; 601 } 602 603 // Sum the PSS of all the children 604 size_t total_pss = 0; 605 for (int i=0; i<CHILDREN; ++i) { 606 size_t child_pss; 607 ASSERT_NO_FATAL_FAILURE(getPss(child_pids[i], &child_pss)); 608 total_pss += child_pss; 609 } 610 *pss_out = total_pss; 611 612 // Close pipes and wait for children to exit 613 for (int i=0; i<CHILDREN; ++i) { 614 ASSERT_NOERROR(close(childpipe[i])); 615 } 616 for (int i = 0; i < CHILDREN; ++i) { 617 AssertChildExited(child_pids[i], 0); 618 } 619} 620 621// Testing namespaces 622static const char* g_public_lib = "libnstest_public.so"; 623 624TEST(dlext, ns_smoke) { 625 static const char* root_lib = "libnstest_root.so"; 626 std::string path = std::string("libc.so:libc++.so:libdl.so:libm.so:") + g_public_lib; 627 628 ASSERT_FALSE(android_init_namespaces(path.c_str(), nullptr)); 629 ASSERT_STREQ("android_init_namespaces failed: error initializing public namespace: " 630 "\"libnstest_public.so\" was not found in the default namespace", dlerror()); 631 632 const std::string lib_path = std::string(getenv("ANDROID_DATA")) + NATIVE_TESTS_PATH; 633 634 const std::string lib_public_path = lib_path + "/public_namespace_libs/" + g_public_lib; 635 void* handle_public = dlopen(lib_public_path.c_str(), RTLD_NOW); 636 ASSERT_TRUE(handle_public != nullptr) << dlerror(); 637 638 ASSERT_TRUE(android_init_namespaces(path.c_str(), nullptr)) << dlerror(); 639 640 // Check that libraries added to public namespace are NODELETE 641 dlclose(handle_public); 642 handle_public = dlopen((lib_path + "/public_namespace_libs/" + g_public_lib).c_str(), 643 RTLD_NOW | RTLD_NOLOAD); 644 645 ASSERT_TRUE(handle_public != nullptr) << dlerror(); 646 647 android_namespace_t* ns1 = 648 android_create_namespace("private", nullptr, 649 (lib_path + "/private_namespace_libs").c_str(), 650 ANDROID_NAMESPACE_TYPE_REGULAR, nullptr); 651 ASSERT_TRUE(ns1 != nullptr) << dlerror(); 652 653 android_namespace_t* ns2 = 654 android_create_namespace("private_isolated", nullptr, 655 (lib_path + "/private_namespace_libs").c_str(), 656 ANDROID_NAMESPACE_TYPE_ISOLATED, nullptr); 657 ASSERT_TRUE(ns2 != nullptr) << dlerror(); 658 659 // This should not have affect search path for default namespace: 660 ASSERT_TRUE(dlopen(root_lib, RTLD_NOW) == nullptr); 661 void* handle = dlopen(g_public_lib, RTLD_NOW); 662 ASSERT_TRUE(handle != nullptr) << dlerror(); 663 dlclose(handle); 664 665 android_dlextinfo extinfo; 666 extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE; 667 extinfo.library_namespace = ns1; 668 669 void* handle1 = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo); 670 ASSERT_TRUE(handle1 != nullptr) << dlerror(); 671 672 extinfo.library_namespace = ns2; 673 void* handle2 = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo); 674 ASSERT_TRUE(handle2 != nullptr) << dlerror(); 675 676 ASSERT_TRUE(handle1 != handle2); 677 678 // dlopen for a public library using an absolute path should work for isolated namespaces 679 extinfo.library_namespace = ns2; 680 handle = android_dlopen_ext(lib_public_path.c_str(), RTLD_NOW, &extinfo); 681 ASSERT_TRUE(handle != nullptr) << dlerror(); 682 ASSERT_TRUE(handle == handle_public); 683 684 dlclose(handle); 685 686 typedef const char* (*fn_t)(); 687 688 fn_t ns_get_local_string1 = reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_local_string")); 689 ASSERT_TRUE(ns_get_local_string1 != nullptr) << dlerror(); 690 fn_t ns_get_local_string2 = reinterpret_cast<fn_t>(dlsym(handle2, "ns_get_local_string")); 691 ASSERT_TRUE(ns_get_local_string2 != nullptr) << dlerror(); 692 693 EXPECT_STREQ("This string is local to root library", ns_get_local_string1()); 694 EXPECT_STREQ("This string is local to root library", ns_get_local_string2()); 695 696 ASSERT_TRUE(ns_get_local_string1() != ns_get_local_string2()); 697 698 fn_t ns_get_private_extern_string1 = 699 reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_private_extern_string")); 700 ASSERT_TRUE(ns_get_private_extern_string1 != nullptr) << dlerror(); 701 fn_t ns_get_private_extern_string2 = 702 reinterpret_cast<fn_t>(dlsym(handle2, "ns_get_private_extern_string")); 703 ASSERT_TRUE(ns_get_private_extern_string2 != nullptr) << dlerror(); 704 705 EXPECT_STREQ("This string is from private namespace", ns_get_private_extern_string1()); 706 EXPECT_STREQ("This string is from private namespace", ns_get_private_extern_string2()); 707 708 ASSERT_TRUE(ns_get_private_extern_string1() != ns_get_private_extern_string2()); 709 710 fn_t ns_get_public_extern_string1 = 711 reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_public_extern_string")); 712 ASSERT_TRUE(ns_get_public_extern_string1 != nullptr) << dlerror(); 713 fn_t ns_get_public_extern_string2 = 714 reinterpret_cast<fn_t>(dlsym(handle2, "ns_get_public_extern_string")); 715 ASSERT_TRUE(ns_get_public_extern_string2 != nullptr) << dlerror(); 716 717 EXPECT_STREQ("This string is from public namespace", ns_get_public_extern_string1()); 718 ASSERT_TRUE(ns_get_public_extern_string1() == ns_get_public_extern_string2()); 719 720 // and now check that dlopen() does the right thing in terms of preserving namespace 721 fn_t ns_get_dlopened_string1 = reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_dlopened_string")); 722 ASSERT_TRUE(ns_get_dlopened_string1 != nullptr) << dlerror(); 723 fn_t ns_get_dlopened_string2 = reinterpret_cast<fn_t>(dlsym(handle2, "ns_get_dlopened_string")); 724 ASSERT_TRUE(ns_get_dlopened_string2 != nullptr) << dlerror(); 725 726 EXPECT_STREQ("This string is from private namespace (dlopened library)", ns_get_dlopened_string1()); 727 EXPECT_STREQ("This string is from private namespace (dlopened library)", ns_get_dlopened_string2()); 728 729 ASSERT_TRUE(ns_get_dlopened_string1() != ns_get_dlopened_string2()); 730 731 dlclose(handle1); 732 733 // Check if handle2 is still alive (and well) 734 ASSERT_STREQ("This string is local to root library", ns_get_local_string2()); 735 ASSERT_STREQ("This string is from private namespace", ns_get_private_extern_string2()); 736 ASSERT_STREQ("This string is from public namespace", ns_get_public_extern_string2()); 737 ASSERT_STREQ("This string is from private namespace (dlopened library)", ns_get_dlopened_string2()); 738 739 dlclose(handle2); 740} 741 742extern "C" void android_set_application_target_sdk_version(uint32_t target); 743 744TEST(dlext, ns_isolated) { 745 static const char* root_lib = "libnstest_root_not_isolated.so"; 746 std::string path = std::string("libc.so:libc++.so:libdl.so:libm.so:") + g_public_lib; 747 748 const std::string lib_path = std::string(getenv("ANDROID_DATA")) + NATIVE_TESTS_PATH; 749 const std::string lib_public_path = lib_path + "/public_namespace_libs/" + g_public_lib; 750 void* handle_public = dlopen(lib_public_path.c_str(), RTLD_NOW); 751 ASSERT_TRUE(handle_public != nullptr) << dlerror(); 752 753 android_set_application_target_sdk_version(42U); // something > 23 754 755 ASSERT_TRUE(android_init_namespaces(path.c_str(), nullptr)) << dlerror(); 756 757 android_namespace_t* ns_not_isolated = 758 android_create_namespace("private", nullptr, 759 (lib_path + "/private_namespace_libs").c_str(), 760 ANDROID_NAMESPACE_TYPE_REGULAR, nullptr); 761 ASSERT_TRUE(ns_not_isolated != nullptr) << dlerror(); 762 763 android_namespace_t* ns_isolated = 764 android_create_namespace("private_isolated1", nullptr, 765 (lib_path + "/private_namespace_libs").c_str(), 766 ANDROID_NAMESPACE_TYPE_ISOLATED, nullptr); 767 ASSERT_TRUE(ns_isolated != nullptr) << dlerror(); 768 769 android_namespace_t* ns_isolated2 = 770 android_create_namespace("private_isolated2", 771 (lib_path + "/private_namespace_libs").c_str(), 772 nullptr, ANDROID_NAMESPACE_TYPE_ISOLATED, lib_path.c_str()); 773 ASSERT_TRUE(ns_isolated2 != nullptr) << dlerror(); 774 775 ASSERT_TRUE(dlopen(root_lib, RTLD_NOW) == nullptr); 776 ASSERT_STREQ("dlopen failed: library \"libnstest_root_not_isolated.so\" not found", dlerror()); 777 778 std::string lib_private_external_path = 779 lib_path + "/private_namespace_libs_external/libnstest_private_external.so"; 780 781 // Load lib_private_external_path to default namespace 782 // (it should remain invisible for the isolated namespaces after this) 783 void* handle = dlopen(lib_private_external_path.c_str(), RTLD_NOW); 784 ASSERT_TRUE(handle != nullptr) << dlerror(); 785 786 android_dlextinfo extinfo; 787 extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE; 788 extinfo.library_namespace = ns_not_isolated; 789 790 void* handle1 = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo); 791 ASSERT_TRUE(handle1 != nullptr) << dlerror(); 792 793 extinfo.library_namespace = ns_isolated; 794 795 void* handle2 = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo); 796 ASSERT_TRUE(handle2 == nullptr); 797 ASSERT_STREQ("dlopen failed: library \"libnstest_private_external.so\" not found", dlerror()); 798 799 // Check dlopen by absolute path 800 handle2 = android_dlopen_ext(lib_private_external_path.c_str(), RTLD_NOW, &extinfo); 801 ASSERT_TRUE(handle2 == nullptr); 802 ASSERT_EQ("dlopen failed: library \"" + lib_private_external_path + "\" needed" 803 " or dlopened by \"" + get_executable_name() + "\" is not accessible" 804 " for the namespace \"private_isolated1\"", dlerror()); 805 806 extinfo.library_namespace = ns_isolated2; 807 808 // this should work because isolation_path for private_isolated2 includes lib_path 809 handle2 = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo); 810 ASSERT_TRUE(handle2 != nullptr) << dlerror(); 811 dlclose(handle2); 812 813 // Check dlopen by absolute path 814 handle2 = android_dlopen_ext(lib_private_external_path.c_str(), RTLD_NOW, &extinfo); 815 ASSERT_TRUE(handle2 != nullptr) << dlerror(); 816 dlclose(handle2); 817 818 typedef const char* (*fn_t)(); 819 fn_t ns_get_local_string = reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_local_string")); 820 ASSERT_TRUE(ns_get_local_string != nullptr) << dlerror(); 821 822 ASSERT_STREQ("This string is local to root library", ns_get_local_string()); 823 824 fn_t ns_get_private_extern_string = 825 reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_private_extern_string")); 826 ASSERT_TRUE(ns_get_private_extern_string != nullptr) << dlerror(); 827 828 ASSERT_STREQ("This string is from private namespace", ns_get_private_extern_string()); 829 830 fn_t ns_get_public_extern_string = 831 reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_public_extern_string")); 832 ASSERT_TRUE(ns_get_public_extern_string != nullptr) << dlerror(); 833 834 ASSERT_STREQ("This string is from public namespace", ns_get_public_extern_string()); 835 836 fn_t ns_get_dlopened_string = reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_dlopened_string")); 837 ASSERT_TRUE(ns_get_dlopened_string != nullptr) << dlerror(); 838 839 ASSERT_STREQ("This string is from private namespace (dlopened library)", ns_get_dlopened_string()); 840 841 dlclose(handle1); 842} 843 844TEST(dlext, ns_shared) { 845 static const char* root_lib = "libnstest_root_not_isolated.so"; 846 static const char* root_lib_isolated = "libnstest_root.so"; 847 std::string path = std::string("libc.so:libc++.so:libdl.so:libm.so:") + g_public_lib; 848 849 const std::string lib_path = std::string(getenv("ANDROID_DATA")) + NATIVE_TESTS_PATH; 850 const std::string lib_public_path = lib_path + "/public_namespace_libs/" + g_public_lib; 851 void* handle_public = dlopen(lib_public_path.c_str(), RTLD_NOW); 852 ASSERT_TRUE(handle_public != nullptr) << dlerror(); 853 854 android_set_application_target_sdk_version(42U); // something > 23 855 856 ASSERT_TRUE(android_init_namespaces(path.c_str(), nullptr)) << dlerror(); 857 858 // preload this library to the default namespace to check if it 859 // is shared later on. 860 void* handle_dlopened = 861 dlopen((lib_path + "/private_namespace_libs/libnstest_dlopened.so").c_str(), RTLD_NOW); 862 ASSERT_TRUE(handle_dlopened != nullptr) << dlerror(); 863 864 android_namespace_t* ns_not_isolated = 865 android_create_namespace("private", nullptr, 866 (lib_path + "/private_namespace_libs").c_str(), 867 ANDROID_NAMESPACE_TYPE_REGULAR, nullptr); 868 ASSERT_TRUE(ns_not_isolated != nullptr) << dlerror(); 869 870 android_namespace_t* ns_isolated_shared = 871 android_create_namespace("private_isolated_shared", nullptr, 872 (lib_path + "/private_namespace_libs").c_str(), 873 ANDROID_NAMESPACE_TYPE_ISOLATED | ANDROID_NAMESPACE_TYPE_SHARED, 874 nullptr); 875 ASSERT_TRUE(ns_isolated_shared != nullptr) << dlerror(); 876 877 ASSERT_TRUE(dlopen(root_lib, RTLD_NOW) == nullptr); 878 ASSERT_STREQ("dlopen failed: library \"libnstest_root_not_isolated.so\" not found", dlerror()); 879 880 std::string lib_private_external_path = 881 lib_path + "/private_namespace_libs_external/libnstest_private_external.so"; 882 883 // Load lib_private_external_path to default namespace 884 // (it should remain invisible for the isolated namespaces after this) 885 void* handle = dlopen(lib_private_external_path.c_str(), RTLD_NOW); 886 ASSERT_TRUE(handle != nullptr) << dlerror(); 887 888 android_dlextinfo extinfo; 889 extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE; 890 extinfo.library_namespace = ns_not_isolated; 891 892 void* handle1 = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo); 893 ASSERT_TRUE(handle1 != nullptr) << dlerror(); 894 895 extinfo.library_namespace = ns_isolated_shared; 896 897 void* handle2 = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo); 898 ASSERT_TRUE(handle2 == nullptr); 899 ASSERT_STREQ("dlopen failed: library \"libnstest_private_external.so\" not found", dlerror()); 900 901 // Check dlopen by absolute path 902 handle2 = android_dlopen_ext(lib_private_external_path.c_str(), RTLD_NOW, &extinfo); 903 ASSERT_TRUE(handle2 == nullptr); 904 ASSERT_EQ("dlopen failed: library \"" + lib_private_external_path + "\" needed" 905 " or dlopened by \"" + get_executable_name() + "\" is not accessible" 906 " for the namespace \"private_isolated_shared\"", dlerror()); 907 908 // load libnstest_root.so to shared namespace in order to check that everything is different 909 // except shared libnstest_dlopened.so 910 911 handle2 = android_dlopen_ext(root_lib_isolated, RTLD_NOW, &extinfo); 912 913 typedef const char* (*fn_t)(); 914 fn_t ns_get_local_string = reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_local_string")); 915 ASSERT_TRUE(ns_get_local_string != nullptr) << dlerror(); 916 fn_t ns_get_local_string_shared = reinterpret_cast<fn_t>(dlsym(handle2, "ns_get_local_string")); 917 ASSERT_TRUE(ns_get_local_string_shared != nullptr) << dlerror(); 918 919 ASSERT_STREQ("This string is local to root library", ns_get_local_string()); 920 ASSERT_STREQ("This string is local to root library", ns_get_local_string_shared()); 921 ASSERT_TRUE(ns_get_local_string() != ns_get_local_string_shared()); 922 923 fn_t ns_get_private_extern_string = 924 reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_private_extern_string")); 925 ASSERT_TRUE(ns_get_private_extern_string != nullptr) << dlerror(); 926 fn_t ns_get_private_extern_string_shared = 927 reinterpret_cast<fn_t>(dlsym(handle2, "ns_get_private_extern_string")); 928 ASSERT_TRUE(ns_get_private_extern_string_shared() != nullptr) << dlerror(); 929 930 ASSERT_STREQ("This string is from private namespace", ns_get_private_extern_string()); 931 ASSERT_STREQ("This string is from private namespace", ns_get_private_extern_string_shared()); 932 ASSERT_TRUE(ns_get_private_extern_string() != ns_get_private_extern_string_shared()); 933 934 fn_t ns_get_public_extern_string = 935 reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_public_extern_string")); 936 ASSERT_TRUE(ns_get_public_extern_string != nullptr) << dlerror(); 937 fn_t ns_get_public_extern_string_shared = 938 reinterpret_cast<fn_t>(dlsym(handle2, "ns_get_public_extern_string")); 939 ASSERT_TRUE(ns_get_public_extern_string_shared != nullptr) << dlerror(); 940 941 ASSERT_STREQ("This string is from public namespace", ns_get_public_extern_string()); 942 ASSERT_STREQ("This string is from public namespace", ns_get_public_extern_string_shared()); 943 ASSERT_TRUE(ns_get_public_extern_string() == ns_get_public_extern_string_shared()); 944 945 fn_t ns_get_dlopened_string = reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_dlopened_string")); 946 ASSERT_TRUE(ns_get_dlopened_string != nullptr) << dlerror(); 947 fn_t ns_get_dlopened_string_shared = reinterpret_cast<fn_t>(dlsym(handle2, "ns_get_dlopened_string")); 948 ASSERT_TRUE(ns_get_dlopened_string_shared != nullptr) << dlerror(); 949 const char** ns_dlopened_string = static_cast<const char**>(dlsym(handle_dlopened, "g_private_dlopened_string")); 950 ASSERT_TRUE(ns_dlopened_string != nullptr) << dlerror(); 951 952 ASSERT_STREQ("This string is from private namespace (dlopened library)", ns_get_dlopened_string()); 953 ASSERT_STREQ("This string is from private namespace (dlopened library)", *ns_dlopened_string); 954 ASSERT_STREQ("This string is from private namespace (dlopened library)", ns_get_dlopened_string_shared()); 955 ASSERT_TRUE(ns_get_dlopened_string() != ns_get_dlopened_string_shared()); 956 ASSERT_TRUE(*ns_dlopened_string == ns_get_dlopened_string_shared()); 957 958 dlclose(handle1); 959 dlclose(handle2); 960} 961 962TEST(dlext, ns_anonymous) { 963 static const char* root_lib = "libnstest_root.so"; 964 std::string path = std::string("libc.so:libc++.so:libdl.so:libm.so:") + g_public_lib; 965 966 const std::string lib_path = std::string(getenv("ANDROID_DATA")) + NATIVE_TESTS_PATH; 967 968 const std::string lib_public_path = lib_path + "/public_namespace_libs/" + g_public_lib; 969 void* handle_public = dlopen(lib_public_path.c_str(), RTLD_NOW); 970 971 ASSERT_TRUE(handle_public != nullptr) << dlerror(); 972 973 ASSERT_TRUE(android_init_namespaces(path.c_str(), (lib_path + "/private_namespace_libs").c_str())) 974 << dlerror(); 975 976 android_namespace_t* ns = android_create_namespace( 977 "private", nullptr, 978 (lib_path + "/private_namespace_libs").c_str(), 979 ANDROID_NAMESPACE_TYPE_REGULAR, nullptr); 980 981 ASSERT_TRUE(ns != nullptr) << dlerror(); 982 983 std::string private_library_absolute_path = lib_path + "/private_namespace_libs/" + root_lib; 984 985 android_dlextinfo extinfo; 986 extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE; 987 extinfo.library_namespace = ns; 988 989 // we are going to copy this library to anonymous mmap and call the copy of ns_get_dlopened_string 990 void* handle = android_dlopen_ext(private_library_absolute_path.c_str(), RTLD_NOW, &extinfo); 991 ASSERT_TRUE(handle != nullptr) << dlerror(); 992 993 uintptr_t ns_get_dlopened_string_addr = 994 reinterpret_cast<uintptr_t>(dlsym(handle, "ns_get_dlopened_string")); 995 ASSERT_TRUE(ns_get_dlopened_string_addr != 0) << dlerror(); 996 typedef const char* (*fn_t)(); 997 fn_t ns_get_dlopened_string_private = reinterpret_cast<fn_t>(ns_get_dlopened_string_addr); 998 999 std::vector<map_record> maps; 1000 Maps::parse_maps(&maps); 1001 1002 uintptr_t addr_start = 0; 1003 uintptr_t addr_end = 0; 1004 std::vector<map_record> maps_to_copy; 1005 1006 for (const auto& rec : maps) { 1007 if (rec.pathname == private_library_absolute_path) { 1008 if (addr_start == 0) { 1009 addr_start = rec.addr_start; 1010 } 1011 addr_end = rec.addr_end; 1012 1013 maps_to_copy.push_back(rec); 1014 } 1015 } 1016 1017 // some sanity checks.. 1018 ASSERT_TRUE(addr_start > 0); 1019 ASSERT_TRUE(addr_end > 0); 1020 ASSERT_EQ(3U, maps_to_copy.size()); 1021 ASSERT_TRUE(ns_get_dlopened_string_addr > addr_start); 1022 ASSERT_TRUE(ns_get_dlopened_string_addr < addr_end); 1023 1024 // copy 1025 uintptr_t reserved_addr = reinterpret_cast<uintptr_t>(mmap(nullptr, addr_end - addr_start, 1026 PROT_NONE, MAP_ANON | MAP_PRIVATE, 1027 -1, 0)); 1028 ASSERT_TRUE(reinterpret_cast<void*>(reserved_addr) != MAP_FAILED); 1029 1030 for (const auto& rec : maps_to_copy) { 1031 uintptr_t offset = rec.addr_start - addr_start; 1032 size_t size = rec.addr_end - rec.addr_start; 1033 void* addr = reinterpret_cast<void*>(reserved_addr + offset); 1034 void* map = mmap(addr, size, PROT_READ | PROT_WRITE, 1035 MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, 0); 1036 ASSERT_TRUE(map != MAP_FAILED); 1037 memcpy(map, reinterpret_cast<void*>(rec.addr_start), size); 1038 mprotect(map, size, rec.perms); 1039 } 1040 1041 // call the function copy 1042 uintptr_t ns_get_dlopened_string_offset = ns_get_dlopened_string_addr - addr_start; 1043 fn_t ns_get_dlopened_string_anon = reinterpret_cast<fn_t>(reserved_addr + ns_get_dlopened_string_offset); 1044 ASSERT_STREQ("This string is from private namespace (dlopened library)", 1045 ns_get_dlopened_string_anon()); 1046 1047 // They should belong to different namespaces (private and anonymous) 1048 ASSERT_STREQ("This string is from private namespace (dlopened library)", 1049 ns_get_dlopened_string_private()); 1050 1051 ASSERT_TRUE(ns_get_dlopened_string_anon() != ns_get_dlopened_string_private()); 1052} 1053