dlext_test.cpp revision 284ae3559ed909613b189b98bdc3efab94373a30
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 34#include "TemporaryFile.h" 35#include "utils.h" 36 37#define ASSERT_DL_NOTNULL(ptr) \ 38 ASSERT_TRUE(ptr != nullptr) << "dlerror: " << dlerror() 39 40#define ASSERT_DL_ZERO(i) \ 41 ASSERT_EQ(0, i) << "dlerror: " << dlerror() 42 43#define ASSERT_NOERROR(i) \ 44 ASSERT_NE(-1, i) << "errno: " << strerror(errno) 45 46#define ASSERT_SUBSTR(needle, haystack) \ 47 ASSERT_PRED_FORMAT2(::testing::IsSubstring, needle, haystack) 48 49 50typedef int (*fn)(void); 51#define LIBNAME "libdlext_test.so" 52#define LIBNAME_NORELRO "libdlext_test_norelro.so" 53#define LIBSIZE 1024*1024 // how much address space to reserve for it 54 55#if defined(__LP64__) 56#define NATIVE_TESTS_PATH "/nativetest64" 57#else 58#define NATIVE_TESTS_PATH "/nativetest" 59#endif 60 61#define LIBPATH NATIVE_TESTS_PATH "/libdlext_test_fd/libdlext_test_fd.so" 62#define LIBZIPPATH NATIVE_TESTS_PATH "/libdlext_test_zip/libdlext_test_zip_zipaligned.zip" 63#define LIBZIPPATH_WITH_RUNPATH NATIVE_TESTS_PATH "/libdlext_test_runpath_zip/libdlext_test_runpath_zip_zipaligned.zip" 64 65#define LIBZIP_OFFSET PAGE_SIZE 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 extinfo.library_fd_offset = LIBZIP_OFFSET; 132 133 handle_ = android_dlopen_ext(lib_path.c_str(), RTLD_NOW, &extinfo); 134 ASSERT_DL_NOTNULL(handle_); 135 136 uint32_t* taxicab_number = reinterpret_cast<uint32_t*>(dlsym(handle_, "dlopen_testlib_taxicab_number")); 137 ASSERT_DL_NOTNULL(taxicab_number); 138 EXPECT_EQ(1729U, *taxicab_number); 139} 140 141TEST_F(DlExtTest, ExtInfoUseFdWithInvalidOffset) { 142 const std::string lib_path = std::string(getenv("ANDROID_DATA")) + LIBZIPPATH; 143 // lib_path is relative when $ANDROID_DATA is relative 144 char lib_realpath_buf[PATH_MAX]; 145 ASSERT_TRUE(realpath(lib_path.c_str(), lib_realpath_buf) == lib_realpath_buf); 146 const std::string lib_realpath = std::string(lib_realpath_buf); 147 148 android_dlextinfo extinfo; 149 extinfo.flags = ANDROID_DLEXT_USE_LIBRARY_FD | ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET; 150 extinfo.library_fd = TEMP_FAILURE_RETRY(open(lib_path.c_str(), O_RDONLY | O_CLOEXEC)); 151 extinfo.library_fd_offset = 17; 152 153 handle_ = android_dlopen_ext("libname_placeholder", RTLD_NOW, &extinfo); 154 ASSERT_TRUE(handle_ == nullptr); 155 ASSERT_STREQ("dlopen failed: file offset for the library \"libname_placeholder\" is not page-aligned: 17", dlerror()); 156 157 // Test an address above 2^44, for http://b/18178121 . 158 extinfo.library_fd_offset = (5LL<<48) + PAGE_SIZE; 159 handle_ = android_dlopen_ext("libname_placeholder", RTLD_NOW, &extinfo); 160 ASSERT_TRUE(handle_ == nullptr); 161 ASSERT_SUBSTR("dlopen failed: file offset for the library \"libname_placeholder\" >= file size", dlerror()); 162 163 extinfo.library_fd_offset = 0LL - PAGE_SIZE; 164 handle_ = android_dlopen_ext("libname_placeholder", RTLD_NOW, &extinfo); 165 ASSERT_TRUE(handle_ == nullptr); 166 ASSERT_SUBSTR("dlopen failed: file offset for the library \"libname_placeholder\" is negative", dlerror()); 167 168 extinfo.library_fd_offset = 0; 169 handle_ = android_dlopen_ext("libname_ignored", RTLD_NOW, &extinfo); 170 ASSERT_TRUE(handle_ == nullptr); 171 ASSERT_EQ("dlopen failed: \"" + lib_realpath + "\" has bad ELF magic", dlerror()); 172 173 // Check if dlsym works after unsuccessful dlopen(). 174 // Supply non-exiting one to make linker visit every soinfo. 175 void* sym = dlsym(RTLD_DEFAULT, "this_symbol_does_not_exist___"); 176 ASSERT_TRUE(sym == nullptr); 177 178 close(extinfo.library_fd); 179} 180 181TEST_F(DlExtTest, ExtInfoUseOffsetWihtoutFd) { 182 android_dlextinfo extinfo; 183 extinfo.flags = ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET; 184 extinfo.library_fd_offset = LIBZIP_OFFSET; 185 186 handle_ = android_dlopen_ext("/some/lib/that/does_not_exist", RTLD_NOW, &extinfo); 187 ASSERT_TRUE(handle_ == nullptr); 188 ASSERT_STREQ("dlopen failed: invalid extended flag combination (ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET without ANDROID_DLEXT_USE_LIBRARY_FD): 0x20", dlerror()); 189} 190 191TEST(dlext, android_dlopen_ext_force_load_smoke) { 192 // 1. Open actual file 193 void* handle = dlopen("libdlext_test.so", RTLD_NOW); 194 ASSERT_DL_NOTNULL(handle); 195 // 2. Open link with force_load flag set 196 android_dlextinfo extinfo; 197 extinfo.flags = ANDROID_DLEXT_FORCE_LOAD; 198 void* handle2 = android_dlopen_ext("libdlext_test_v2.so", RTLD_NOW, &extinfo); 199 ASSERT_DL_NOTNULL(handle2); 200 ASSERT_TRUE(handle != handle2); 201 202 dlclose(handle2); 203 dlclose(handle); 204} 205 206TEST(dlext, android_dlopen_ext_force_load_soname_exception) { 207 // Check if soname lookup still returns already loaded library 208 // when ANDROID_DLEXT_FORCE_LOAD flag is specified. 209 void* handle = dlopen("libdlext_test_v2.so", RTLD_NOW); 210 ASSERT_DL_NOTNULL(handle); 211 212 android_dlextinfo extinfo; 213 extinfo.flags = ANDROID_DLEXT_FORCE_LOAD; 214 215 // Note that 'libdlext_test.so' is dt_soname for libdlext_test_v2.so 216 void* handle2 = android_dlopen_ext("libdlext_test.so", RTLD_NOW, &extinfo); 217 218 ASSERT_DL_NOTNULL(handle2); 219 ASSERT_TRUE(handle == handle2); 220 221 dlclose(handle2); 222 dlclose(handle); 223} 224 225TEST(dlfcn, dlopen_from_zip_absolute_path) { 226 const std::string lib_path = std::string(getenv("ANDROID_DATA")) + LIBZIPPATH; 227 228 void* handle = dlopen((lib_path + "!/libdir/libatest_simple_zip.so").c_str(), RTLD_NOW); 229 ASSERT_TRUE(handle != nullptr) << dlerror(); 230 231 uint32_t* taxicab_number = reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_testlib_taxicab_number")); 232 ASSERT_DL_NOTNULL(taxicab_number); 233 EXPECT_EQ(1729U, *taxicab_number); 234 235 dlclose(handle); 236} 237 238TEST(dlfcn, dlopen_from_zip_with_dt_runpath) { 239 const std::string lib_path = std::string(getenv("ANDROID_DATA")) + LIBZIPPATH_WITH_RUNPATH; 240 241 void* handle = dlopen((lib_path + "!/libdir/libtest_dt_runpath_d_zip.so").c_str(), RTLD_NOW); 242 243 ASSERT_TRUE(handle != nullptr) << dlerror(); 244 245 typedef void *(* dlopen_b_fn)(); 246 dlopen_b_fn fn = (dlopen_b_fn)dlsym(handle, "dlopen_b"); 247 ASSERT_TRUE(fn != nullptr) << dlerror(); 248 249 void *p = fn(); 250 ASSERT_TRUE(p != nullptr) << dlerror(); 251 252 dlclose(p); 253 dlclose(handle); 254} 255 256TEST(dlfcn, dlopen_from_zip_ld_library_path) { 257 const std::string lib_path = std::string(getenv("ANDROID_DATA")) + LIBZIPPATH + "!/libdir"; 258 259 typedef void (*fn_t)(const char*); 260 fn_t android_update_LD_LIBRARY_PATH = 261 reinterpret_cast<fn_t>(dlsym(RTLD_DEFAULT, "android_update_LD_LIBRARY_PATH")); 262 263 ASSERT_TRUE(android_update_LD_LIBRARY_PATH != nullptr) << dlerror(); 264 265 void* handle = dlopen("libdlext_test_zip.so", RTLD_NOW); 266 ASSERT_TRUE(handle == nullptr); 267 268 android_update_LD_LIBRARY_PATH(lib_path.c_str()); 269 270 handle = dlopen("libdlext_test_zip.so", RTLD_NOW); 271 ASSERT_TRUE(handle != nullptr) << dlerror(); 272 273 int (*fn)(void); 274 fn = reinterpret_cast<int (*)(void)>(dlsym(handle, "getRandomNumber")); 275 ASSERT_TRUE(fn != nullptr); 276 EXPECT_EQ(4, fn()); 277 278 uint32_t* taxicab_number = reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_testlib_taxicab_number")); 279 ASSERT_DL_NOTNULL(taxicab_number); 280 EXPECT_EQ(1729U, *taxicab_number); 281 282 dlclose(handle); 283} 284 285 286TEST_F(DlExtTest, Reserved) { 287 void* start = mmap(nullptr, LIBSIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, 288 -1, 0); 289 ASSERT_TRUE(start != MAP_FAILED); 290 android_dlextinfo extinfo; 291 extinfo.flags = ANDROID_DLEXT_RESERVED_ADDRESS; 292 extinfo.reserved_addr = start; 293 extinfo.reserved_size = LIBSIZE; 294 handle_ = android_dlopen_ext(LIBNAME, RTLD_NOW, &extinfo); 295 ASSERT_DL_NOTNULL(handle_); 296 fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber")); 297 ASSERT_DL_NOTNULL(f); 298 EXPECT_GE(reinterpret_cast<void*>(f), start); 299 EXPECT_LT(reinterpret_cast<void*>(f), 300 reinterpret_cast<char*>(start) + LIBSIZE); 301 EXPECT_EQ(4, f()); 302} 303 304TEST_F(DlExtTest, ReservedTooSmall) { 305 void* start = mmap(nullptr, PAGE_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, 306 -1, 0); 307 ASSERT_TRUE(start != MAP_FAILED); 308 android_dlextinfo extinfo; 309 extinfo.flags = ANDROID_DLEXT_RESERVED_ADDRESS; 310 extinfo.reserved_addr = start; 311 extinfo.reserved_size = PAGE_SIZE; 312 handle_ = android_dlopen_ext(LIBNAME, RTLD_NOW, &extinfo); 313 EXPECT_EQ(nullptr, handle_); 314} 315 316TEST_F(DlExtTest, ReservedHint) { 317 void* start = mmap(nullptr, LIBSIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, 318 -1, 0); 319 ASSERT_TRUE(start != MAP_FAILED); 320 android_dlextinfo extinfo; 321 extinfo.flags = ANDROID_DLEXT_RESERVED_ADDRESS_HINT; 322 extinfo.reserved_addr = start; 323 extinfo.reserved_size = LIBSIZE; 324 handle_ = android_dlopen_ext(LIBNAME, RTLD_NOW, &extinfo); 325 ASSERT_DL_NOTNULL(handle_); 326 fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber")); 327 ASSERT_DL_NOTNULL(f); 328 EXPECT_GE(reinterpret_cast<void*>(f), start); 329 EXPECT_LT(reinterpret_cast<void*>(f), 330 reinterpret_cast<char*>(start) + LIBSIZE); 331 EXPECT_EQ(4, f()); 332} 333 334TEST_F(DlExtTest, ReservedHintTooSmall) { 335 void* start = mmap(nullptr, PAGE_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, 336 -1, 0); 337 ASSERT_TRUE(start != MAP_FAILED); 338 android_dlextinfo extinfo; 339 extinfo.flags = ANDROID_DLEXT_RESERVED_ADDRESS_HINT; 340 extinfo.reserved_addr = start; 341 extinfo.reserved_size = PAGE_SIZE; 342 handle_ = android_dlopen_ext(LIBNAME, RTLD_NOW, &extinfo); 343 ASSERT_DL_NOTNULL(handle_); 344 fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber")); 345 ASSERT_DL_NOTNULL(f); 346 EXPECT_TRUE(reinterpret_cast<void*>(f) < start || 347 (reinterpret_cast<void*>(f) >= 348 reinterpret_cast<char*>(start) + PAGE_SIZE)); 349 EXPECT_EQ(4, f()); 350} 351 352TEST_F(DlExtTest, LoadAtFixedAddress) { 353 void* start = mmap(nullptr, LIBSIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, 354 -1, 0); 355 ASSERT_TRUE(start != MAP_FAILED); 356 munmap(start, LIBSIZE); 357 358 android_dlextinfo extinfo; 359 extinfo.flags = ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS; 360 extinfo.reserved_addr = start; 361 362 handle_ = android_dlopen_ext(LIBNAME, RTLD_NOW, &extinfo); 363 ASSERT_DL_NOTNULL(handle_); 364 fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber")); 365 ASSERT_DL_NOTNULL(f); 366 EXPECT_GE(reinterpret_cast<void*>(f), start); 367 EXPECT_LT(reinterpret_cast<void*>(f), reinterpret_cast<char*>(start) + LIBSIZE); 368 369 EXPECT_EQ(4, f()); 370} 371 372TEST_F(DlExtTest, LoadAtFixedAddressTooSmall) { 373 void* start = mmap(nullptr, LIBSIZE + PAGE_SIZE, PROT_NONE, 374 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 375 ASSERT_TRUE(start != MAP_FAILED); 376 munmap(start, LIBSIZE + PAGE_SIZE); 377 void* new_addr = mmap(reinterpret_cast<uint8_t*>(start) + PAGE_SIZE, LIBSIZE, PROT_NONE, 378 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 379 ASSERT_TRUE(new_addr != MAP_FAILED); 380 381 android_dlextinfo extinfo; 382 extinfo.flags = ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS; 383 extinfo.reserved_addr = start; 384 385 handle_ = android_dlopen_ext(LIBNAME, RTLD_NOW, &extinfo); 386 ASSERT_TRUE(handle_ == nullptr); 387} 388 389class DlExtRelroSharingTest : public DlExtTest { 390protected: 391 virtual void SetUp() { 392 DlExtTest::SetUp(); 393 void* start = mmap(nullptr, LIBSIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, 394 -1, 0); 395 ASSERT_TRUE(start != MAP_FAILED); 396 extinfo_.flags = ANDROID_DLEXT_RESERVED_ADDRESS; 397 extinfo_.reserved_addr = start; 398 extinfo_.reserved_size = LIBSIZE; 399 extinfo_.relro_fd = -1; 400 } 401 402 virtual void TearDown() { 403 DlExtTest::TearDown(); 404 } 405 406 void CreateRelroFile(const char* lib, const char* relro_file) { 407 int relro_fd = open(relro_file, O_RDWR | O_TRUNC); 408 ASSERT_NOERROR(relro_fd); 409 410 pid_t pid = fork(); 411 if (pid == 0) { 412 // child process 413 extinfo_.flags |= ANDROID_DLEXT_WRITE_RELRO; 414 extinfo_.relro_fd = relro_fd; 415 void* handle = android_dlopen_ext(lib, RTLD_NOW, &extinfo_); 416 if (handle == nullptr) { 417 fprintf(stderr, "in child: %s\n", dlerror()); 418 exit(1); 419 } 420 exit(0); 421 } 422 423 // continuing in parent 424 ASSERT_NOERROR(close(relro_fd)); 425 ASSERT_NOERROR(pid); 426 int status; 427 ASSERT_EQ(pid, waitpid(pid, &status, 0)); 428 ASSERT_TRUE(WIFEXITED(status)); 429 ASSERT_EQ(0, WEXITSTATUS(status)); 430 431 // reopen file for reading so it can be used 432 relro_fd = open(relro_file, O_RDONLY); 433 ASSERT_NOERROR(relro_fd); 434 extinfo_.flags |= ANDROID_DLEXT_USE_RELRO; 435 extinfo_.relro_fd = relro_fd; 436 } 437 438 void TryUsingRelro(const char* lib) { 439 handle_ = android_dlopen_ext(lib, RTLD_NOW, &extinfo_); 440 ASSERT_DL_NOTNULL(handle_); 441 fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber")); 442 ASSERT_DL_NOTNULL(f); 443 EXPECT_EQ(4, f()); 444 445 uint32_t* taxicab_number = reinterpret_cast<uint32_t*>(dlsym(handle_, "dlopen_testlib_taxicab_number")); 446 ASSERT_DL_NOTNULL(taxicab_number); 447 EXPECT_EQ(1729U, *taxicab_number); 448 } 449 450 void SpawnChildrenAndMeasurePss(const char* lib, bool share_relro, size_t* pss_out); 451 452 android_dlextinfo extinfo_; 453}; 454 455TEST_F(DlExtRelroSharingTest, ChildWritesGoodData) { 456 TemporaryFile tf; // Use tf to get an unique filename. 457 ASSERT_NOERROR(close(tf.fd)); 458 459 ASSERT_NO_FATAL_FAILURE(CreateRelroFile(LIBNAME, tf.filename)); 460 ASSERT_NO_FATAL_FAILURE(TryUsingRelro(LIBNAME)); 461 462 // Use destructor of tf to close and unlink the file. 463 tf.fd = extinfo_.relro_fd; 464} 465 466TEST_F(DlExtRelroSharingTest, ChildWritesNoRelro) { 467 TemporaryFile tf; // // Use tf to get an unique filename. 468 ASSERT_NOERROR(close(tf.fd)); 469 470 ASSERT_NO_FATAL_FAILURE(CreateRelroFile(LIBNAME_NORELRO, tf.filename)); 471 ASSERT_NO_FATAL_FAILURE(TryUsingRelro(LIBNAME_NORELRO)); 472 473 // Use destructor of tf to close and unlink the file. 474 tf.fd = extinfo_.relro_fd; 475} 476 477TEST_F(DlExtRelroSharingTest, RelroFileEmpty) { 478 ASSERT_NO_FATAL_FAILURE(TryUsingRelro(LIBNAME)); 479} 480 481TEST_F(DlExtRelroSharingTest, VerifyMemorySaving) { 482 if (geteuid() != 0) { 483 GTEST_LOG_(INFO) << "This test must be run as root.\n"; 484 return; 485 } 486 487 TemporaryFile tf; // Use tf to get an unique filename. 488 ASSERT_NOERROR(close(tf.fd)); 489 490 ASSERT_NO_FATAL_FAILURE(CreateRelroFile(LIBNAME, tf.filename)); 491 492 int pipefd[2]; 493 ASSERT_NOERROR(pipe(pipefd)); 494 495 size_t without_sharing, with_sharing; 496 ASSERT_NO_FATAL_FAILURE(SpawnChildrenAndMeasurePss(LIBNAME, false, &without_sharing)); 497 ASSERT_NO_FATAL_FAILURE(SpawnChildrenAndMeasurePss(LIBNAME, true, &with_sharing)); 498 499 // We expect the sharing to save at least 10% of the total PSS. In practice 500 // it saves 40%+ for this test. 501 size_t expected_size = without_sharing - (without_sharing/10); 502 EXPECT_LT(with_sharing, expected_size); 503 504 // Use destructor of tf to close and unlink the file. 505 tf.fd = extinfo_.relro_fd; 506} 507 508void getPss(pid_t pid, size_t* pss_out) { 509 pm_kernel_t* kernel; 510 ASSERT_EQ(0, pm_kernel_create(&kernel)); 511 512 pm_process_t* process; 513 ASSERT_EQ(0, pm_process_create(kernel, pid, &process)); 514 515 pm_map_t** maps; 516 size_t num_maps; 517 ASSERT_EQ(0, pm_process_maps(process, &maps, &num_maps)); 518 519 size_t total_pss = 0; 520 for (size_t i = 0; i < num_maps; i++) { 521 pm_memusage_t usage; 522 ASSERT_EQ(0, pm_map_usage(maps[i], &usage)); 523 total_pss += usage.pss; 524 } 525 *pss_out = total_pss; 526 527 free(maps); 528 pm_process_destroy(process); 529 pm_kernel_destroy(kernel); 530} 531 532void DlExtRelroSharingTest::SpawnChildrenAndMeasurePss(const char* lib, bool share_relro, 533 size_t* pss_out) { 534 const int CHILDREN = 20; 535 536 // Create children 537 pid_t childpid[CHILDREN]; 538 int childpipe[CHILDREN]; 539 for (int i=0; i<CHILDREN; ++i) { 540 char read_buf; 541 int child_done_pipe[2], parent_done_pipe[2]; 542 ASSERT_NOERROR(pipe(child_done_pipe)); 543 ASSERT_NOERROR(pipe(parent_done_pipe)); 544 545 pid_t child = fork(); 546 if (child == 0) { 547 // close the 'wrong' ends of the pipes in the child 548 close(child_done_pipe[0]); 549 close(parent_done_pipe[1]); 550 551 // open the library 552 void* handle; 553 if (share_relro) { 554 handle = android_dlopen_ext(lib, RTLD_NOW, &extinfo_); 555 } else { 556 handle = dlopen(lib, RTLD_NOW); 557 } 558 if (handle == nullptr) { 559 fprintf(stderr, "in child: %s\n", dlerror()); 560 exit(1); 561 } 562 563 // close write end of child_done_pipe to signal the parent that we're done. 564 close(child_done_pipe[1]); 565 566 // wait for the parent to close parent_done_pipe, then exit 567 read(parent_done_pipe[0], &read_buf, 1); 568 exit(0); 569 } 570 571 ASSERT_NOERROR(child); 572 573 // close the 'wrong' ends of the pipes in the parent 574 close(child_done_pipe[1]); 575 close(parent_done_pipe[0]); 576 577 // wait for the child to be done 578 read(child_done_pipe[0], &read_buf, 1); 579 close(child_done_pipe[0]); 580 581 // save the child's pid and the parent_done_pipe 582 childpid[i] = child; 583 childpipe[i] = parent_done_pipe[1]; 584 } 585 586 // Sum the PSS of all the children 587 size_t total_pss = 0; 588 for (int i=0; i<CHILDREN; ++i) { 589 size_t child_pss; 590 ASSERT_NO_FATAL_FAILURE(getPss(childpid[i], &child_pss)); 591 total_pss += child_pss; 592 } 593 *pss_out = total_pss; 594 595 // Close pipes and wait for children to exit 596 for (int i=0; i<CHILDREN; ++i) { 597 ASSERT_NOERROR(close(childpipe[i])); 598 } 599 for (int i=0; i<CHILDREN; ++i) { 600 int status; 601 ASSERT_EQ(childpid[i], waitpid(childpid[i], &status, 0)); 602 ASSERT_TRUE(WIFEXITED(status)); 603 ASSERT_EQ(0, WEXITSTATUS(status)); 604 } 605} 606 607// Testing namespaces 608static const char* g_public_lib = "libnstest_public.so"; 609 610TEST(dlext, ns_smoke) { 611 static const char* root_lib = "libnstest_root.so"; 612 std::string path = std::string("libc.so:libc++.so:libdl.so:libm.so:") + g_public_lib; 613 614 ASSERT_FALSE(android_init_namespaces(path.c_str(), nullptr)); 615 ASSERT_STREQ("android_init_namespaces failed: error initializing public namespace: " 616 "\"libnstest_public.so\" was not found in the default namespace", dlerror()); 617 618 const std::string lib_path = std::string(getenv("ANDROID_DATA")) + NATIVE_TESTS_PATH; 619 620 const std::string lib_public_path = lib_path + "/public_namespace_libs/" + g_public_lib; 621 void* handle_public = dlopen(lib_public_path.c_str(), RTLD_NOW); 622 ASSERT_TRUE(handle_public != nullptr) << dlerror(); 623 624 ASSERT_TRUE(android_init_namespaces(path.c_str(), nullptr)) << dlerror(); 625 626 // Check that libraries added to public namespace are NODELETE 627 dlclose(handle_public); 628 handle_public = dlopen((lib_path + "/public_namespace_libs/" + g_public_lib).c_str(), RTLD_NOW | RTLD_NOLOAD); 629 ASSERT_TRUE(handle_public != nullptr) << dlerror(); 630 631 android_namespace_t* ns1 = android_create_namespace("private", nullptr, (lib_path + "/private_namespace_libs").c_str(), false, nullptr); 632 ASSERT_TRUE(ns1 != nullptr) << dlerror(); 633 634 android_namespace_t* ns2 = android_create_namespace("private_isolated", nullptr, (lib_path + "/private_namespace_libs").c_str(), true, nullptr); 635 ASSERT_TRUE(ns2 != nullptr) << dlerror(); 636 637 // This should not have affect search path for default namespace: 638 ASSERT_TRUE(dlopen(root_lib, RTLD_NOW) == nullptr); 639 void* handle = dlopen(g_public_lib, RTLD_NOW); 640 ASSERT_TRUE(handle != nullptr) << dlerror(); 641 dlclose(handle); 642 643 android_dlextinfo extinfo; 644 extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE; 645 extinfo.library_namespace = ns1; 646 647 void* handle1 = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo); 648 ASSERT_TRUE(handle1 != nullptr) << dlerror(); 649 650 extinfo.library_namespace = ns2; 651 void* handle2 = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo); 652 ASSERT_TRUE(handle2 != nullptr) << dlerror(); 653 654 ASSERT_TRUE(handle1 != handle2); 655 656 // dlopen for a public library using an absolute path should work for isolated namespaces 657 extinfo.library_namespace = ns2; 658 handle = android_dlopen_ext(lib_public_path.c_str(), RTLD_NOW, &extinfo); 659 ASSERT_TRUE(handle != nullptr) << dlerror(); 660 ASSERT_TRUE(handle == handle_public); 661 662 dlclose(handle); 663 664 typedef const char* (*fn_t)(); 665 666 fn_t ns_get_local_string1 = reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_local_string")); 667 ASSERT_TRUE(ns_get_local_string1 != nullptr) << dlerror(); 668 fn_t ns_get_local_string2 = reinterpret_cast<fn_t>(dlsym(handle2, "ns_get_local_string")); 669 ASSERT_TRUE(ns_get_local_string2 != nullptr) << dlerror(); 670 671 EXPECT_STREQ("This string is local to root library", ns_get_local_string1()); 672 EXPECT_STREQ("This string is local to root library", ns_get_local_string2()); 673 674 ASSERT_TRUE(ns_get_local_string1() != ns_get_local_string2()); 675 676 fn_t ns_get_private_extern_string1 = 677 reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_private_extern_string")); 678 ASSERT_TRUE(ns_get_private_extern_string1 != nullptr) << dlerror(); 679 fn_t ns_get_private_extern_string2 = 680 reinterpret_cast<fn_t>(dlsym(handle2, "ns_get_private_extern_string")); 681 ASSERT_TRUE(ns_get_private_extern_string2 != nullptr) << dlerror(); 682 683 EXPECT_STREQ("This string is from private namespace", ns_get_private_extern_string1()); 684 EXPECT_STREQ("This string is from private namespace", ns_get_private_extern_string2()); 685 686 ASSERT_TRUE(ns_get_private_extern_string1() != ns_get_private_extern_string2()); 687 688 fn_t ns_get_public_extern_string1 = 689 reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_public_extern_string")); 690 ASSERT_TRUE(ns_get_public_extern_string1 != nullptr) << dlerror(); 691 fn_t ns_get_public_extern_string2 = 692 reinterpret_cast<fn_t>(dlsym(handle2, "ns_get_public_extern_string")); 693 ASSERT_TRUE(ns_get_public_extern_string2 != nullptr) << dlerror(); 694 695 EXPECT_STREQ("This string is from public namespace", ns_get_public_extern_string1()); 696 ASSERT_TRUE(ns_get_public_extern_string1() == ns_get_public_extern_string2()); 697 698 // and now check that dlopen() does the right thing in terms of preserving namespace 699 fn_t ns_get_dlopened_string1 = reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_dlopened_string")); 700 ASSERT_TRUE(ns_get_dlopened_string1 != nullptr) << dlerror(); 701 fn_t ns_get_dlopened_string2 = reinterpret_cast<fn_t>(dlsym(handle2, "ns_get_dlopened_string")); 702 ASSERT_TRUE(ns_get_dlopened_string2 != nullptr) << dlerror(); 703 704 EXPECT_STREQ("This string is from private namespace (dlopened library)", ns_get_dlopened_string1()); 705 EXPECT_STREQ("This string is from private namespace (dlopened library)", ns_get_dlopened_string2()); 706 707 ASSERT_TRUE(ns_get_dlopened_string1() != ns_get_dlopened_string2()); 708 709 dlclose(handle1); 710 711 // Check if handle2 is still alive (and well) 712 ASSERT_STREQ("This string is local to root library", ns_get_local_string2()); 713 ASSERT_STREQ("This string is from private namespace", ns_get_private_extern_string2()); 714 ASSERT_STREQ("This string is from public namespace", ns_get_public_extern_string2()); 715 ASSERT_STREQ("This string is from private namespace (dlopened library)", ns_get_dlopened_string2()); 716 717 dlclose(handle2); 718} 719 720extern "C" void android_set_application_target_sdk_version(uint32_t target); 721 722TEST(dlext, ns_isolated) { 723 static const char* root_lib = "libnstest_root_not_isolated.so"; 724 std::string path = std::string("libc.so:libc++.so:libdl.so:libm.so:") + g_public_lib; 725 726 const std::string lib_path = std::string(getenv("ANDROID_DATA")) + NATIVE_TESTS_PATH; 727 const std::string lib_public_path = lib_path + "/public_namespace_libs/" + g_public_lib; 728 void* handle_public = dlopen(lib_public_path.c_str(), RTLD_NOW); 729 ASSERT_TRUE(handle_public != nullptr) << dlerror(); 730 731 android_set_application_target_sdk_version(42U); // something > 23 732 733 ASSERT_TRUE(android_init_namespaces(path.c_str(), nullptr)) << dlerror(); 734 735 android_namespace_t* ns_not_isolated = android_create_namespace("private", nullptr, (lib_path + "/private_namespace_libs").c_str(), false, nullptr); 736 ASSERT_TRUE(ns_not_isolated != nullptr) << dlerror(); 737 738 android_namespace_t* ns_isolated = android_create_namespace("private_isolated1", nullptr, (lib_path + "/private_namespace_libs").c_str(), true, nullptr); 739 ASSERT_TRUE(ns_isolated != nullptr) << dlerror(); 740 741 android_namespace_t* ns_isolated2 = android_create_namespace("private_isolated2", (lib_path + "/private_namespace_libs").c_str(), nullptr, true, lib_path.c_str()); 742 ASSERT_TRUE(ns_isolated2 != nullptr) << dlerror(); 743 744 ASSERT_TRUE(dlopen(root_lib, RTLD_NOW) == nullptr); 745 ASSERT_STREQ("dlopen failed: library \"libnstest_root_not_isolated.so\" not found", dlerror()); 746 747 std::string lib_private_external_path = 748 lib_path + "/private_namespace_libs_external/libnstest_private_external.so"; 749 750 // Load lib_private_external_path to default namespace 751 // (it should remain invisible for the isolated namespaces after this) 752 void* handle = dlopen(lib_private_external_path.c_str(), RTLD_NOW); 753 ASSERT_TRUE(handle != nullptr) << dlerror(); 754 755 android_dlextinfo extinfo; 756 extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE; 757 extinfo.library_namespace = ns_not_isolated; 758 759 void* handle1 = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo); 760 ASSERT_TRUE(handle1 != nullptr) << dlerror(); 761 762 extinfo.library_namespace = ns_isolated; 763 764 void* handle2 = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo); 765 ASSERT_TRUE(handle2 == nullptr); 766 ASSERT_STREQ("dlopen failed: library \"libnstest_private_external.so\" not found", dlerror()); 767 768 // Check dlopen by absolute path 769 handle2 = android_dlopen_ext(lib_private_external_path.c_str(), RTLD_NOW, &extinfo); 770 ASSERT_TRUE(handle2 == nullptr); 771 ASSERT_EQ("dlopen failed: library \"" + lib_private_external_path + "\" is not accessible for the namespace \"private_isolated1\"", dlerror()); 772 773 extinfo.library_namespace = ns_isolated2; 774 775 // this should work because isolation_path for private_isolated2 includes lib_path 776 handle2 = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo); 777 ASSERT_TRUE(handle2 != nullptr) << dlerror(); 778 dlclose(handle2); 779 780 // Check dlopen by absolute path 781 handle2 = android_dlopen_ext(lib_private_external_path.c_str(), RTLD_NOW, &extinfo); 782 ASSERT_TRUE(handle2 != nullptr) << dlerror(); 783 dlclose(handle2); 784 785 typedef const char* (*fn_t)(); 786 fn_t ns_get_local_string = reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_local_string")); 787 ASSERT_TRUE(ns_get_local_string != nullptr) << dlerror(); 788 789 ASSERT_STREQ("This string is local to root library", ns_get_local_string()); 790 791 fn_t ns_get_private_extern_string = 792 reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_private_extern_string")); 793 ASSERT_TRUE(ns_get_private_extern_string != nullptr) << dlerror(); 794 795 ASSERT_STREQ("This string is from private namespace", ns_get_private_extern_string()); 796 797 fn_t ns_get_public_extern_string = 798 reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_public_extern_string")); 799 ASSERT_TRUE(ns_get_public_extern_string != nullptr) << dlerror(); 800 801 ASSERT_STREQ("This string is from public namespace", ns_get_public_extern_string()); 802 803 fn_t ns_get_dlopened_string = reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_dlopened_string")); 804 ASSERT_TRUE(ns_get_dlopened_string != nullptr) << dlerror(); 805 806 ASSERT_STREQ("This string is from private namespace (dlopened library)", ns_get_dlopened_string()); 807 808 dlclose(handle1); 809} 810 811TEST(dlext, ns_anonymous) { 812 static const char* root_lib = "libnstest_root.so"; 813 std::string path = std::string("libc.so:libc++.so:libdl.so:libm.so:") + g_public_lib; 814 815 const std::string lib_path = std::string(getenv("ANDROID_DATA")) + NATIVE_TESTS_PATH; 816 817 const std::string lib_public_path = lib_path + "/public_namespace_libs/" + g_public_lib; 818 void* handle_public = dlopen(lib_public_path.c_str(), RTLD_NOW); 819 820 ASSERT_TRUE(handle_public != nullptr) << dlerror(); 821 822 ASSERT_TRUE(android_init_namespaces(path.c_str(), (lib_path + "/private_namespace_libs").c_str())) 823 << dlerror(); 824 825 android_namespace_t* ns = android_create_namespace( 826 "private", nullptr, 827 (lib_path + "/private_namespace_libs").c_str(), 828 false, nullptr); 829 830 ASSERT_TRUE(ns != nullptr) << dlerror(); 831 832 std::string private_library_absolute_path = lib_path + "/private_namespace_libs/" + root_lib; 833 834 android_dlextinfo extinfo; 835 extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE; 836 extinfo.library_namespace = ns; 837 838 // we are going to copy this library to anonymous mmap and call the copy of ns_get_dlopened_string 839 void* handle = android_dlopen_ext(private_library_absolute_path.c_str(), RTLD_NOW, &extinfo); 840 ASSERT_TRUE(handle != nullptr) << dlerror(); 841 842 uintptr_t ns_get_dlopened_string_addr = 843 reinterpret_cast<uintptr_t>(dlsym(handle, "ns_get_dlopened_string")); 844 ASSERT_TRUE(ns_get_dlopened_string_addr != 0) << dlerror(); 845 typedef const char* (*fn_t)(); 846 fn_t ns_get_dlopened_string_private = reinterpret_cast<fn_t>(ns_get_dlopened_string_addr); 847 848 std::vector<map_record> maps; 849 Maps::parse_maps(&maps); 850 851 uintptr_t addr_start = 0; 852 uintptr_t addr_end = 0; 853 std::vector<map_record> maps_to_copy; 854 855 for (const auto& rec : maps) { 856 if (rec.pathname == private_library_absolute_path) { 857 if (addr_start == 0) { 858 addr_start = rec.addr_start; 859 } 860 addr_end = rec.addr_end; 861 862 maps_to_copy.push_back(rec); 863 } 864 } 865 866 // some sanity checks.. 867 ASSERT_TRUE(addr_start > 0); 868 ASSERT_TRUE(addr_end > 0); 869 ASSERT_EQ(3U, maps_to_copy.size()); 870 ASSERT_TRUE(ns_get_dlopened_string_addr > addr_start); 871 ASSERT_TRUE(ns_get_dlopened_string_addr < addr_end); 872 873 // copy 874 uintptr_t reserved_addr = reinterpret_cast<uintptr_t>(mmap(nullptr, addr_end - addr_start, 875 PROT_NONE, MAP_ANON | MAP_PRIVATE, 876 -1, 0)); 877 ASSERT_TRUE(reinterpret_cast<void*>(reserved_addr) != MAP_FAILED); 878 879 for (const auto& rec : maps_to_copy) { 880 uintptr_t offset = rec.addr_start - addr_start; 881 size_t size = rec.addr_end - rec.addr_start; 882 void* addr = reinterpret_cast<void*>(reserved_addr + offset); 883 void* map = mmap(addr, size, PROT_READ | PROT_WRITE, 884 MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, 0); 885 ASSERT_TRUE(map != MAP_FAILED); 886 memcpy(map, reinterpret_cast<void*>(rec.addr_start), size); 887 mprotect(map, size, rec.perms); 888 } 889 890 // call the function copy 891 uintptr_t ns_get_dlopened_string_offset = ns_get_dlopened_string_addr - addr_start; 892 fn_t ns_get_dlopened_string_anon = reinterpret_cast<fn_t>(reserved_addr + ns_get_dlopened_string_offset); 893 ASSERT_STREQ("This string is from private namespace (dlopened library)", 894 ns_get_dlopened_string_anon()); 895 896 // They should belong to different namespaces (private and anonymous) 897 ASSERT_STREQ("This string is from private namespace (dlopened library)", 898 ns_get_dlopened_string_private()); 899 900 ASSERT_TRUE(ns_get_dlopened_string_anon() != ns_get_dlopened_string_private()); 901} 902