| Torne (Richard Coles) | 12bbb91 | 2014-02-06 14:34:21 +0000 | [diff] [blame] | 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> | 
| Yabin Cui | 16f7f8d | 2014-11-04 11:08:05 -0800 | [diff] [blame] | 20 | #include <elf.h> | 
| Torne (Richard Coles) | 183ad9d | 2014-02-27 13:18:00 +0000 | [diff] [blame] | 21 | #include <errno.h> | 
|  | 22 | #include <fcntl.h> | 
| Yabin Cui | 16f7f8d | 2014-11-04 11:08:05 -0800 | [diff] [blame] | 23 | #include <inttypes.h> | 
| Torne (Richard Coles) | 183ad9d | 2014-02-27 13:18:00 +0000 | [diff] [blame] | 24 | #include <stdio.h> | 
|  | 25 | #include <string.h> | 
|  | 26 | #include <unistd.h> | 
| Dimitry Ivanov | bf34ba3 | 2017-04-21 13:12:05 -0700 | [diff] [blame] | 27 |  | 
| Torne (Richard Coles) | 12bbb91 | 2014-02-06 14:34:21 +0000 | [diff] [blame] | 28 | #include <android/dlext.h> | 
| Christopher Ferris | 6d2c0bd | 2018-08-21 18:13:10 -0700 | [diff] [blame] | 29 | #include <android-base/file.h> | 
| Zhenhua WANG | 81aad00 | 2017-04-25 11:07:19 +0800 | [diff] [blame] | 30 | #include <android-base/strings.h> | 
| Josh Gao | 1626957 | 2019-10-29 13:41:00 -0700 | [diff] [blame] | 31 | #include <android-base/test_utils.h> | 
| Dimitry Ivanov | bf34ba3 | 2017-04-21 13:12:05 -0700 | [diff] [blame] | 32 |  | 
| Torne (Richard Coles) | 12bbb91 | 2014-02-06 14:34:21 +0000 | [diff] [blame] | 33 | #include <sys/mman.h> | 
| Kalesh Singh | 4084b55 | 2024-03-13 13:35:49 -0700 | [diff] [blame] | 34 | #include <sys/stat.h> | 
| Torne (Richard Coles) | 2605261 | 2014-05-02 14:57:42 +0100 | [diff] [blame] | 35 | #include <sys/types.h> | 
| Dimitry Ivanov | bf34ba3 | 2017-04-21 13:12:05 -0700 | [diff] [blame] | 36 | #include <sys/vfs.h> | 
| Torne (Richard Coles) | 183ad9d | 2014-02-27 13:18:00 +0000 | [diff] [blame] | 37 | #include <sys/wait.h> | 
| Torne (Richard Coles) | 12bbb91 | 2014-02-06 14:34:21 +0000 | [diff] [blame] | 38 |  | 
| Sandeep Patil | 4e02cc1 | 2019-01-21 14:22:05 -0800 | [diff] [blame] | 39 | #include <meminfo/procmeminfo.h> | 
| Torne (Richard Coles) | efbe9a5 | 2018-10-17 15:59:38 -0400 | [diff] [blame] | 40 | #include <procinfo/process_map.h> | 
| Christopher Ferris | c0ffcec | 2016-01-19 20:32:37 -0800 | [diff] [blame] | 41 | #include <ziparchive/zip_archive.h> | 
| Torne (Richard Coles) | 2605261 | 2014-05-02 14:57:42 +0100 | [diff] [blame] | 42 |  | 
| Ryan Prichard | 22fa3dd | 2020-01-31 14:47:48 -0800 | [diff] [blame] | 43 | #include "core_shared_libs.h" | 
| Dimitry Ivanov | 927877c | 2016-09-21 11:17:13 -0700 | [diff] [blame] | 44 | #include "gtest_globals.h" | 
| Dmitriy Ivanov | 1ffec1c | 2015-11-23 11:26:35 -0800 | [diff] [blame] | 45 | #include "utils.h" | 
| Dimitry Ivanov | 41fd295 | 2016-05-09 17:37:39 -0700 | [diff] [blame] | 46 | #include "dlext_private.h" | 
| Dimitry Ivanov | 708589f | 2016-09-19 10:50:28 -0700 | [diff] [blame] | 47 | #include "dlfcn_symlink_support.h" | 
| Torne (Richard Coles) | 12bbb91 | 2014-02-06 14:34:21 +0000 | [diff] [blame] | 48 |  | 
|  | 49 | #define ASSERT_DL_NOTNULL(ptr) \ | 
| Chih-Hung Hsieh | d61ca37 | 2016-06-03 10:18:07 -0700 | [diff] [blame] | 50 | ASSERT_TRUE((ptr) != nullptr) << "dlerror: " << dlerror() | 
| Torne (Richard Coles) | 12bbb91 | 2014-02-06 14:34:21 +0000 | [diff] [blame] | 51 |  | 
|  | 52 | #define ASSERT_DL_ZERO(i) \ | 
|  | 53 | ASSERT_EQ(0, i) << "dlerror: " << dlerror() | 
|  | 54 |  | 
| Torne (Richard Coles) | 183ad9d | 2014-02-27 13:18:00 +0000 | [diff] [blame] | 55 | #define ASSERT_NOERROR(i) \ | 
|  | 56 | ASSERT_NE(-1, i) << "errno: " << strerror(errno) | 
|  | 57 |  | 
| Yabin Cui | 16f7f8d | 2014-11-04 11:08:05 -0800 | [diff] [blame] | 58 | #define ASSERT_SUBSTR(needle, haystack) \ | 
|  | 59 | ASSERT_PRED_FORMAT2(::testing::IsSubstring, needle, haystack) | 
|  | 60 |  | 
| Torne (Richard Coles) | 12bbb91 | 2014-02-06 14:34:21 +0000 | [diff] [blame] | 61 |  | 
|  | 62 | typedef int (*fn)(void); | 
| Dimitry Ivanov | 927877c | 2016-09-21 11:17:13 -0700 | [diff] [blame] | 63 | constexpr const char* kLibName = "libdlext_test.so"; | 
| Torne (Richard Coles) | efbe9a5 | 2018-10-17 15:59:38 -0400 | [diff] [blame] | 64 | constexpr const char* kLibNameRecursive = "libdlext_test_recursive.so"; | 
| Dimitry Ivanov | 927877c | 2016-09-21 11:17:13 -0700 | [diff] [blame] | 65 | constexpr const char* kLibNameNoRelro = "libdlext_test_norelro.so"; | 
|  | 66 | constexpr const char* kLibZipSimpleZip = "libdir/libatest_simple_zip.so"; | 
|  | 67 | constexpr auto kLibSize = 1024 * 1024; // how much address space to reserve for it | 
| Dmitriy Ivanov | 07e5bc1 | 2014-10-03 17:52:44 -0700 | [diff] [blame] | 68 |  | 
| Torne (Richard Coles) | 12bbb91 | 2014-02-06 14:34:21 +0000 | [diff] [blame] | 69 | class DlExtTest : public ::testing::Test { | 
|  | 70 | protected: | 
| Yi Kong | 358603a | 2019-03-29 14:25:16 -0700 | [diff] [blame] | 71 | void SetUp() override { | 
| Dmitriy Ivanov | 07e5bc1 | 2014-10-03 17:52:44 -0700 | [diff] [blame] | 72 | handle_ = nullptr; | 
| Torne (Richard Coles) | 12bbb91 | 2014-02-06 14:34:21 +0000 | [diff] [blame] | 73 | // verify that we don't have the library loaded already | 
| Dimitry Ivanov | 927877c | 2016-09-21 11:17:13 -0700 | [diff] [blame] | 74 | void* h = dlopen(kLibName, RTLD_NOW | RTLD_NOLOAD); | 
| Dmitriy Ivanov | 07e5bc1 | 2014-10-03 17:52:44 -0700 | [diff] [blame] | 75 | ASSERT_TRUE(h == nullptr); | 
| Dimitry Ivanov | 927877c | 2016-09-21 11:17:13 -0700 | [diff] [blame] | 76 | h = dlopen(kLibNameNoRelro, RTLD_NOW | RTLD_NOLOAD); | 
| Dmitriy Ivanov | 07e5bc1 | 2014-10-03 17:52:44 -0700 | [diff] [blame] | 77 | ASSERT_TRUE(h == nullptr); | 
| Torne (Richard Coles) | 12bbb91 | 2014-02-06 14:34:21 +0000 | [diff] [blame] | 78 | // call dlerror() to swallow the error, and check it was the one we wanted | 
| Dimitry Ivanov | 927877c | 2016-09-21 11:17:13 -0700 | [diff] [blame] | 79 | ASSERT_EQ(std::string("dlopen failed: library \"") + kLibNameNoRelro + "\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror()); | 
| Torne (Richard Coles) | 12bbb91 | 2014-02-06 14:34:21 +0000 | [diff] [blame] | 80 | } | 
|  | 81 |  | 
| Yi Kong | 358603a | 2019-03-29 14:25:16 -0700 | [diff] [blame] | 82 | void TearDown() override { | 
| Dmitriy Ivanov | 07e5bc1 | 2014-10-03 17:52:44 -0700 | [diff] [blame] | 83 | if (handle_ != nullptr) { | 
| Torne (Richard Coles) | 12bbb91 | 2014-02-06 14:34:21 +0000 | [diff] [blame] | 84 | ASSERT_DL_ZERO(dlclose(handle_)); | 
|  | 85 | } | 
|  | 86 | } | 
|  | 87 |  | 
|  | 88 | void* handle_; | 
| Kalesh Singh | 41c8951 | 2023-10-19 14:10:31 -0700 | [diff] [blame] | 89 | const size_t kPageSize = getpagesize(); | 
| Torne (Richard Coles) | 12bbb91 | 2014-02-06 14:34:21 +0000 | [diff] [blame] | 90 | }; | 
|  | 91 |  | 
|  | 92 | TEST_F(DlExtTest, ExtInfoNull) { | 
| Dimitry Ivanov | 927877c | 2016-09-21 11:17:13 -0700 | [diff] [blame] | 93 | handle_ = android_dlopen_ext(kLibName, RTLD_NOW, nullptr); | 
| Torne (Richard Coles) | 12bbb91 | 2014-02-06 14:34:21 +0000 | [diff] [blame] | 94 | ASSERT_DL_NOTNULL(handle_); | 
|  | 95 | fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber")); | 
|  | 96 | ASSERT_DL_NOTNULL(f); | 
|  | 97 | EXPECT_EQ(4, f()); | 
|  | 98 | } | 
|  | 99 |  | 
|  | 100 | TEST_F(DlExtTest, ExtInfoNoFlags) { | 
|  | 101 | android_dlextinfo extinfo; | 
|  | 102 | extinfo.flags = 0; | 
| Dimitry Ivanov | 927877c | 2016-09-21 11:17:13 -0700 | [diff] [blame] | 103 | handle_ = android_dlopen_ext(kLibName, RTLD_NOW, &extinfo); | 
| Torne (Richard Coles) | 12bbb91 | 2014-02-06 14:34:21 +0000 | [diff] [blame] | 104 | ASSERT_DL_NOTNULL(handle_); | 
|  | 105 | fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber")); | 
|  | 106 | ASSERT_DL_NOTNULL(f); | 
|  | 107 | EXPECT_EQ(4, f()); | 
|  | 108 | } | 
|  | 109 |  | 
| Dmitriy Ivanov | 04dc91a | 2014-07-01 14:10:16 -0700 | [diff] [blame] | 110 | TEST_F(DlExtTest, ExtInfoUseFd) { | 
| Elliott Hughes | 8d8138a | 2024-03-12 22:37:13 +0000 | [diff] [blame] | 111 | const std::string lib_path = GetTestLibRoot() + "/libdlext_test_fd/libdlext_test_fd.so"; | 
| Dmitriy Ivanov | 04dc91a | 2014-07-01 14:10:16 -0700 | [diff] [blame] | 112 |  | 
|  | 113 | android_dlextinfo extinfo; | 
|  | 114 | extinfo.flags = ANDROID_DLEXT_USE_LIBRARY_FD; | 
| Dmitriy Ivanov | 52393a5 | 2015-03-18 22:50:01 -0700 | [diff] [blame] | 115 | extinfo.library_fd = TEMP_FAILURE_RETRY(open(lib_path.c_str(), O_RDONLY | O_CLOEXEC)); | 
| Dmitriy Ivanov | 04dc91a | 2014-07-01 14:10:16 -0700 | [diff] [blame] | 116 | ASSERT_TRUE(extinfo.library_fd != -1); | 
| Dmitriy Ivanov | 52393a5 | 2015-03-18 22:50:01 -0700 | [diff] [blame] | 117 | handle_ = android_dlopen_ext(lib_path.c_str(), RTLD_NOW, &extinfo); | 
| Dmitriy Ivanov | 04dc91a | 2014-07-01 14:10:16 -0700 | [diff] [blame] | 118 | ASSERT_DL_NOTNULL(handle_); | 
|  | 119 | fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber")); | 
|  | 120 | ASSERT_DL_NOTNULL(f); | 
|  | 121 | EXPECT_EQ(4, f()); | 
| Dmitriy Ivanov | edfc9f6 | 2015-09-02 16:32:02 -0700 | [diff] [blame] | 122 |  | 
|  | 123 | uint32_t* taxicab_number = reinterpret_cast<uint32_t*>(dlsym(handle_, "dlopen_testlib_taxicab_number")); | 
|  | 124 | ASSERT_DL_NOTNULL(taxicab_number); | 
|  | 125 | EXPECT_EQ(1729U, *taxicab_number); | 
| Dmitriy Ivanov | 04dc91a | 2014-07-01 14:10:16 -0700 | [diff] [blame] | 126 | } | 
|  | 127 |  | 
| Dmitriy Ivanov | 07e5bc1 | 2014-10-03 17:52:44 -0700 | [diff] [blame] | 128 | TEST_F(DlExtTest, ExtInfoUseFdWithOffset) { | 
| Elliott Hughes | 8d8138a | 2024-03-12 22:37:13 +0000 | [diff] [blame] | 129 | const std::string lib_path = GetTestLibRoot() + "/libdlext_test_zip/libdlext_test_zip_zipaligned.zip"; | 
| Dmitriy Ivanov | 07e5bc1 | 2014-10-03 17:52:44 -0700 | [diff] [blame] | 130 |  | 
|  | 131 | android_dlextinfo extinfo; | 
| Dmitriy Ivanov | a6c1279 | 2014-10-21 12:09:18 -0700 | [diff] [blame] | 132 | extinfo.flags = ANDROID_DLEXT_USE_LIBRARY_FD | ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET; | 
| Dmitriy Ivanov | 52393a5 | 2015-03-18 22:50:01 -0700 | [diff] [blame] | 133 | extinfo.library_fd = TEMP_FAILURE_RETRY(open(lib_path.c_str(), O_RDONLY | O_CLOEXEC)); | 
| Christopher Ferris | c0ffcec | 2016-01-19 20:32:37 -0800 | [diff] [blame] | 134 |  | 
|  | 135 | // Find the offset of the shared library in the zip. | 
|  | 136 | ZipArchiveHandle handle; | 
|  | 137 | ASSERT_EQ(0, OpenArchive(lib_path.c_str(), &handle)); | 
|  | 138 | ZipEntry zip_entry; | 
| Elliott Hughes | b51bb50 | 2019-05-03 22:45:41 -0700 | [diff] [blame] | 139 | ASSERT_EQ(0, FindEntry(handle, kLibZipSimpleZip, &zip_entry)); | 
| Christopher Ferris | c0ffcec | 2016-01-19 20:32:37 -0800 | [diff] [blame] | 140 | extinfo.library_fd_offset = zip_entry.offset; | 
|  | 141 | CloseArchive(handle); | 
| Dmitriy Ivanov | 07e5bc1 | 2014-10-03 17:52:44 -0700 | [diff] [blame] | 142 |  | 
| Dmitriy Ivanov | 52393a5 | 2015-03-18 22:50:01 -0700 | [diff] [blame] | 143 | handle_ = android_dlopen_ext(lib_path.c_str(), RTLD_NOW, &extinfo); | 
| Dmitriy Ivanov | 07e5bc1 | 2014-10-03 17:52:44 -0700 | [diff] [blame] | 144 | ASSERT_DL_NOTNULL(handle_); | 
|  | 145 |  | 
| Dmitriy Ivanov | b482750 | 2015-09-28 16:38:31 -0700 | [diff] [blame] | 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); | 
| Dmitriy Ivanov | 07e5bc1 | 2014-10-03 17:52:44 -0700 | [diff] [blame] | 149 | } | 
|  | 150 |  | 
|  | 151 | TEST_F(DlExtTest, ExtInfoUseFdWithInvalidOffset) { | 
| Elliott Hughes | 8d8138a | 2024-03-12 22:37:13 +0000 | [diff] [blame] | 152 | const std::string lib_path = GetTestLibRoot() + "/libdlext_test_zip/libdlext_test_zip_zipaligned.zip"; | 
| Dmitriy Ivanov | 07e5bc1 | 2014-10-03 17:52:44 -0700 | [diff] [blame] | 153 |  | 
|  | 154 | android_dlextinfo extinfo; | 
| Dmitriy Ivanov | a6c1279 | 2014-10-21 12:09:18 -0700 | [diff] [blame] | 155 | extinfo.flags = ANDROID_DLEXT_USE_LIBRARY_FD | ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET; | 
| Dmitriy Ivanov | 52393a5 | 2015-03-18 22:50:01 -0700 | [diff] [blame] | 156 | extinfo.library_fd = TEMP_FAILURE_RETRY(open(lib_path.c_str(), O_RDONLY | O_CLOEXEC)); | 
| Dmitriy Ivanov | a6c1279 | 2014-10-21 12:09:18 -0700 | [diff] [blame] | 157 | extinfo.library_fd_offset = 17; | 
| Dmitriy Ivanov | 07e5bc1 | 2014-10-03 17:52:44 -0700 | [diff] [blame] | 158 |  | 
|  | 159 | handle_ = android_dlopen_ext("libname_placeholder", RTLD_NOW, &extinfo); | 
|  | 160 | ASSERT_TRUE(handle_ == nullptr); | 
| Dmitriy Ivanov | a6c1279 | 2014-10-21 12:09:18 -0700 | [diff] [blame] | 161 | ASSERT_STREQ("dlopen failed: file offset for the library \"libname_placeholder\" is not page-aligned: 17", dlerror()); | 
|  | 162 |  | 
| Yabin Cui | 16f7f8d | 2014-11-04 11:08:05 -0800 | [diff] [blame] | 163 | // Test an address above 2^44, for http://b/18178121 . | 
| Kalesh Singh | 41c8951 | 2023-10-19 14:10:31 -0700 | [diff] [blame] | 164 | extinfo.library_fd_offset = (5LL << 48) + kPageSize; | 
| Dmitriy Ivanov | a6c1279 | 2014-10-21 12:09:18 -0700 | [diff] [blame] | 165 | handle_ = android_dlopen_ext("libname_placeholder", RTLD_NOW, &extinfo); | 
| Dmitriy Ivanov | a6c1279 | 2014-10-21 12:09:18 -0700 | [diff] [blame] | 166 | ASSERT_TRUE(handle_ == nullptr); | 
| Yabin Cui | 16f7f8d | 2014-11-04 11:08:05 -0800 | [diff] [blame] | 167 | ASSERT_SUBSTR("dlopen failed: file offset for the library \"libname_placeholder\" >= file size", dlerror()); | 
|  | 168 |  | 
| Kalesh Singh | 41c8951 | 2023-10-19 14:10:31 -0700 | [diff] [blame] | 169 | extinfo.library_fd_offset = 0LL - kPageSize; | 
| Yabin Cui | 16f7f8d | 2014-11-04 11:08:05 -0800 | [diff] [blame] | 170 | handle_ = android_dlopen_ext("libname_placeholder", RTLD_NOW, &extinfo); | 
|  | 171 | ASSERT_TRUE(handle_ == nullptr); | 
|  | 172 | ASSERT_SUBSTR("dlopen failed: file offset for the library \"libname_placeholder\" is negative", dlerror()); | 
|  | 173 |  | 
| Dmitriy Ivanov | b482750 | 2015-09-28 16:38:31 -0700 | [diff] [blame] | 174 | extinfo.library_fd_offset = 0; | 
| Dmitriy Ivanov | aae859c | 2015-03-31 11:14:03 -0700 | [diff] [blame] | 175 | handle_ = android_dlopen_ext("libname_ignored", RTLD_NOW, &extinfo); | 
| Yabin Cui | 16f7f8d | 2014-11-04 11:08:05 -0800 | [diff] [blame] | 176 | ASSERT_TRUE(handle_ == nullptr); | 
| Elliott Hughes | a897151 | 2018-06-27 14:39:06 -0700 | [diff] [blame] | 177 | ASSERT_EQ("dlopen failed: \"" + lib_path + "\" has bad ELF magic: 504b0304", dlerror()); | 
| Dmitriy Ivanov | a6c1279 | 2014-10-21 12:09:18 -0700 | [diff] [blame] | 178 |  | 
| Dmitriy Ivanov | fd7a91e | 2015-11-06 10:44:37 -0800 | [diff] [blame] | 179 | // Check if dlsym works after unsuccessful dlopen(). | 
|  | 180 | // Supply non-exiting one to make linker visit every soinfo. | 
|  | 181 | void* sym = dlsym(RTLD_DEFAULT, "this_symbol_does_not_exist___"); | 
|  | 182 | ASSERT_TRUE(sym == nullptr); | 
|  | 183 |  | 
| Dmitriy Ivanov | a6c1279 | 2014-10-21 12:09:18 -0700 | [diff] [blame] | 184 | close(extinfo.library_fd); | 
| Dmitriy Ivanov | 07e5bc1 | 2014-10-03 17:52:44 -0700 | [diff] [blame] | 185 | } | 
|  | 186 |  | 
| Christopher Ferris | c0ffcec | 2016-01-19 20:32:37 -0800 | [diff] [blame] | 187 | TEST_F(DlExtTest, ExtInfoUseOffsetWithoutFd) { | 
| Dmitriy Ivanov | 07e5bc1 | 2014-10-03 17:52:44 -0700 | [diff] [blame] | 188 | android_dlextinfo extinfo; | 
| Dmitriy Ivanov | a6c1279 | 2014-10-21 12:09:18 -0700 | [diff] [blame] | 189 | extinfo.flags = ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET; | 
| Christopher Ferris | c0ffcec | 2016-01-19 20:32:37 -0800 | [diff] [blame] | 190 | // This offset will not be used, so it doesn't matter. | 
|  | 191 | extinfo.library_fd_offset = 0; | 
| Dmitriy Ivanov | 07e5bc1 | 2014-10-03 17:52:44 -0700 | [diff] [blame] | 192 |  | 
|  | 193 | handle_ = android_dlopen_ext("/some/lib/that/does_not_exist", RTLD_NOW, &extinfo); | 
|  | 194 | ASSERT_TRUE(handle_ == nullptr); | 
| Dmitriy Ivanov | a6c1279 | 2014-10-21 12:09:18 -0700 | [diff] [blame] | 195 | ASSERT_STREQ("dlopen failed: invalid extended flag combination (ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET without ANDROID_DLEXT_USE_LIBRARY_FD): 0x20", dlerror()); | 
| Dmitriy Ivanov | 07e5bc1 | 2014-10-03 17:52:44 -0700 | [diff] [blame] | 196 | } | 
|  | 197 |  | 
| Dmitriy Ivanov | 9b82136 | 2015-04-02 16:03:56 -0700 | [diff] [blame] | 198 | TEST(dlext, android_dlopen_ext_force_load_smoke) { | 
| Dimitry Ivanov | 708589f | 2016-09-19 10:50:28 -0700 | [diff] [blame] | 199 | DlfcnSymlink symlink("android_dlopen_ext_force_load_smoke"); | 
|  | 200 | const std::string symlink_name = basename(symlink.get_symlink_path().c_str()); | 
| Dmitriy Ivanov | 9b82136 | 2015-04-02 16:03:56 -0700 | [diff] [blame] | 201 | // 1. Open actual file | 
|  | 202 | void* handle = dlopen("libdlext_test.so", RTLD_NOW); | 
|  | 203 | ASSERT_DL_NOTNULL(handle); | 
|  | 204 | // 2. Open link with force_load flag set | 
|  | 205 | android_dlextinfo extinfo; | 
|  | 206 | extinfo.flags = ANDROID_DLEXT_FORCE_LOAD; | 
| Dimitry Ivanov | 708589f | 2016-09-19 10:50:28 -0700 | [diff] [blame] | 207 | void* handle2 = android_dlopen_ext(symlink_name.c_str(), RTLD_NOW, &extinfo); | 
| Dmitriy Ivanov | 9b82136 | 2015-04-02 16:03:56 -0700 | [diff] [blame] | 208 | ASSERT_DL_NOTNULL(handle2); | 
|  | 209 | ASSERT_TRUE(handle != handle2); | 
|  | 210 |  | 
|  | 211 | dlclose(handle2); | 
|  | 212 | dlclose(handle); | 
|  | 213 | } | 
|  | 214 |  | 
|  | 215 | TEST(dlext, android_dlopen_ext_force_load_soname_exception) { | 
| Dimitry Ivanov | 708589f | 2016-09-19 10:50:28 -0700 | [diff] [blame] | 216 | DlfcnSymlink symlink("android_dlopen_ext_force_load_soname_exception"); | 
|  | 217 | const std::string symlink_name = basename(symlink.get_symlink_path().c_str()); | 
| Dmitriy Ivanov | 9b82136 | 2015-04-02 16:03:56 -0700 | [diff] [blame] | 218 | // Check if soname lookup still returns already loaded library | 
|  | 219 | // when ANDROID_DLEXT_FORCE_LOAD flag is specified. | 
| Dimitry Ivanov | 708589f | 2016-09-19 10:50:28 -0700 | [diff] [blame] | 220 | void* handle = dlopen(symlink_name.c_str(), RTLD_NOW); | 
| Dmitriy Ivanov | 9b82136 | 2015-04-02 16:03:56 -0700 | [diff] [blame] | 221 | ASSERT_DL_NOTNULL(handle); | 
|  | 222 |  | 
|  | 223 | android_dlextinfo extinfo; | 
|  | 224 | extinfo.flags = ANDROID_DLEXT_FORCE_LOAD; | 
|  | 225 |  | 
| Dimitry Ivanov | 708589f | 2016-09-19 10:50:28 -0700 | [diff] [blame] | 226 | // Note that 'libdlext_test.so' is dt_soname for the symlink_name | 
| Dmitriy Ivanov | 9b82136 | 2015-04-02 16:03:56 -0700 | [diff] [blame] | 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 |  | 
| Elliott Hughes | 95c6cd7 | 2019-12-20 13:26:14 -0800 | [diff] [blame] | 236 | TEST(dlfcn, dlopen_from_nullptr_android_api_level_28) { | 
| Victor Chang | 6cb719f | 2019-02-06 17:19:10 +0000 | [diff] [blame] | 237 | // Regression test for http://b/123972211. Testing dlopen(nullptr) when target sdk is P | 
| Elliott Hughes | 95c6cd7 | 2019-12-20 13:26:14 -0800 | [diff] [blame] | 238 | android_set_application_target_sdk_version(28); | 
| Victor Chang | 6cb719f | 2019-02-06 17:19:10 +0000 | [diff] [blame] | 239 | ASSERT_TRUE(dlopen(nullptr, RTLD_NOW) != nullptr); | 
|  | 240 | } | 
|  | 241 |  | 
| Victor Chang | f248d2d | 2020-05-06 21:05:03 +0100 | [diff] [blame] | 242 | // Test system path translation for backward compatibility. http://b/130219528 | 
|  | 243 | TEST(dlfcn, dlopen_system_libicuuc_android_api_level_28) { | 
|  | 244 | android_set_application_target_sdk_version(28); | 
|  | 245 | ASSERT_TRUE(dlopen(PATH_TO_SYSTEM_LIB "libicuuc.so", RTLD_NOW) != nullptr); | 
|  | 246 | ASSERT_TRUE(dlopen(PATH_TO_SYSTEM_LIB "libicui18n.so", RTLD_NOW) != nullptr); | 
|  | 247 | } | 
|  | 248 |  | 
|  | 249 | TEST(dlfcn, dlopen_system_libicuuc_android_api_level_29) { | 
|  | 250 | android_set_application_target_sdk_version(29); | 
|  | 251 | ASSERT_TRUE(dlopen(PATH_TO_SYSTEM_LIB "libicuuc.so", RTLD_NOW) == nullptr); | 
|  | 252 | ASSERT_TRUE(dlopen(PATH_TO_SYSTEM_LIB "libicui18n.so", RTLD_NOW) == nullptr); | 
|  | 253 | } | 
|  | 254 |  | 
|  | 255 | TEST(dlfcn, dlopen_system_libicuuc_android_api_level_current) { | 
|  | 256 | ASSERT_TRUE(dlopen(PATH_TO_SYSTEM_LIB "libicuuc.so", RTLD_NOW) == nullptr); | 
|  | 257 | ASSERT_TRUE(dlopen(PATH_TO_SYSTEM_LIB "libicui18n.so", RTLD_NOW) == nullptr); | 
|  | 258 | } | 
|  | 259 |  | 
| Dmitriy Ivanov | 52393a5 | 2015-03-18 22:50:01 -0700 | [diff] [blame] | 260 | TEST(dlfcn, dlopen_from_zip_absolute_path) { | 
| Dimitry Ivanov | 927877c | 2016-09-21 11:17:13 -0700 | [diff] [blame] | 261 | const std::string lib_zip_path = "/libdlext_test_zip/libdlext_test_zip_zipaligned.zip"; | 
| Elliott Hughes | 8d8138a | 2024-03-12 22:37:13 +0000 | [diff] [blame] | 262 | const std::string lib_path = GetTestLibRoot() + lib_zip_path; | 
| Dmitriy Ivanov | 52393a5 | 2015-03-18 22:50:01 -0700 | [diff] [blame] | 263 |  | 
| Dmitriy Ivanov | b482750 | 2015-09-28 16:38:31 -0700 | [diff] [blame] | 264 | void* handle = dlopen((lib_path + "!/libdir/libatest_simple_zip.so").c_str(), RTLD_NOW); | 
| Dmitriy Ivanov | 52393a5 | 2015-03-18 22:50:01 -0700 | [diff] [blame] | 265 | ASSERT_TRUE(handle != nullptr) << dlerror(); | 
|  | 266 |  | 
| Dmitriy Ivanov | b482750 | 2015-09-28 16:38:31 -0700 | [diff] [blame] | 267 | uint32_t* taxicab_number = reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_testlib_taxicab_number")); | 
|  | 268 | ASSERT_DL_NOTNULL(taxicab_number); | 
|  | 269 | EXPECT_EQ(1729U, *taxicab_number); | 
| Dmitriy Ivanov | 52393a5 | 2015-03-18 22:50:01 -0700 | [diff] [blame] | 270 |  | 
|  | 271 | dlclose(handle); | 
|  | 272 | } | 
|  | 273 |  | 
| Dmitriy Ivanov | a1feb11 | 2015-10-01 18:41:57 -0700 | [diff] [blame] | 274 | TEST(dlfcn, dlopen_from_zip_with_dt_runpath) { | 
| Dimitry Ivanov | 927877c | 2016-09-21 11:17:13 -0700 | [diff] [blame] | 275 | const std::string lib_zip_path = "/libdlext_test_runpath_zip/libdlext_test_runpath_zip_zipaligned.zip"; | 
| Elliott Hughes | 8d8138a | 2024-03-12 22:37:13 +0000 | [diff] [blame] | 276 | const std::string lib_path = GetTestLibRoot() + lib_zip_path; | 
| Dmitriy Ivanov | a1feb11 | 2015-10-01 18:41:57 -0700 | [diff] [blame] | 277 |  | 
|  | 278 | void* handle = dlopen((lib_path + "!/libdir/libtest_dt_runpath_d_zip.so").c_str(), RTLD_NOW); | 
|  | 279 |  | 
|  | 280 | ASSERT_TRUE(handle != nullptr) << dlerror(); | 
|  | 281 |  | 
|  | 282 | typedef void *(* dlopen_b_fn)(); | 
|  | 283 | dlopen_b_fn fn = (dlopen_b_fn)dlsym(handle, "dlopen_b"); | 
|  | 284 | ASSERT_TRUE(fn != nullptr) << dlerror(); | 
|  | 285 |  | 
|  | 286 | void *p = fn(); | 
|  | 287 | ASSERT_TRUE(p != nullptr) << dlerror(); | 
|  | 288 |  | 
|  | 289 | dlclose(p); | 
|  | 290 | dlclose(handle); | 
|  | 291 | } | 
|  | 292 |  | 
| Dmitriy Ivanov | 52393a5 | 2015-03-18 22:50:01 -0700 | [diff] [blame] | 293 | TEST(dlfcn, dlopen_from_zip_ld_library_path) { | 
| Dimitry Ivanov | 927877c | 2016-09-21 11:17:13 -0700 | [diff] [blame] | 294 | const std::string lib_zip_path = "/libdlext_test_zip/libdlext_test_zip_zipaligned.zip"; | 
| Elliott Hughes | 8d8138a | 2024-03-12 22:37:13 +0000 | [diff] [blame] | 295 | const std::string lib_path = GetTestLibRoot() + lib_zip_path + "!/libdir"; | 
| Dmitriy Ivanov | 52393a5 | 2015-03-18 22:50:01 -0700 | [diff] [blame] | 296 |  | 
|  | 297 | typedef void (*fn_t)(const char*); | 
|  | 298 | fn_t android_update_LD_LIBRARY_PATH = | 
|  | 299 | reinterpret_cast<fn_t>(dlsym(RTLD_DEFAULT, "android_update_LD_LIBRARY_PATH")); | 
|  | 300 |  | 
|  | 301 | ASSERT_TRUE(android_update_LD_LIBRARY_PATH != nullptr) << dlerror(); | 
|  | 302 |  | 
| Dmitriy Ivanov | b482750 | 2015-09-28 16:38:31 -0700 | [diff] [blame] | 303 | void* handle = dlopen("libdlext_test_zip.so", RTLD_NOW); | 
| Dmitriy Ivanov | 52393a5 | 2015-03-18 22:50:01 -0700 | [diff] [blame] | 304 | ASSERT_TRUE(handle == nullptr); | 
|  | 305 |  | 
|  | 306 | android_update_LD_LIBRARY_PATH(lib_path.c_str()); | 
|  | 307 |  | 
| Dmitriy Ivanov | b482750 | 2015-09-28 16:38:31 -0700 | [diff] [blame] | 308 | handle = dlopen("libdlext_test_zip.so", RTLD_NOW); | 
| Dmitriy Ivanov | 52393a5 | 2015-03-18 22:50:01 -0700 | [diff] [blame] | 309 | ASSERT_TRUE(handle != nullptr) << dlerror(); | 
|  | 310 |  | 
|  | 311 | int (*fn)(void); | 
|  | 312 | fn = reinterpret_cast<int (*)(void)>(dlsym(handle, "getRandomNumber")); | 
|  | 313 | ASSERT_TRUE(fn != nullptr); | 
|  | 314 | EXPECT_EQ(4, fn()); | 
|  | 315 |  | 
| Dimitry Ivanov | f45b0e9 | 2016-01-15 11:13:35 -0800 | [diff] [blame] | 316 | uint32_t* taxicab_number = | 
|  | 317 | reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_testlib_taxicab_number")); | 
| Dmitriy Ivanov | b482750 | 2015-09-28 16:38:31 -0700 | [diff] [blame] | 318 | ASSERT_DL_NOTNULL(taxicab_number); | 
|  | 319 | EXPECT_EQ(1729U, *taxicab_number); | 
|  | 320 |  | 
| Dmitriy Ivanov | 52393a5 | 2015-03-18 22:50:01 -0700 | [diff] [blame] | 321 | dlclose(handle); | 
|  | 322 | } | 
|  | 323 |  | 
|  | 324 |  | 
| Torne (Richard Coles) | 12bbb91 | 2014-02-06 14:34:21 +0000 | [diff] [blame] | 325 | TEST_F(DlExtTest, Reserved) { | 
| Dimitry Ivanov | 927877c | 2016-09-21 11:17:13 -0700 | [diff] [blame] | 326 | void* start = mmap(nullptr, kLibSize, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); | 
| Torne (Richard Coles) | 12bbb91 | 2014-02-06 14:34:21 +0000 | [diff] [blame] | 327 | ASSERT_TRUE(start != MAP_FAILED); | 
|  | 328 | android_dlextinfo extinfo; | 
|  | 329 | extinfo.flags = ANDROID_DLEXT_RESERVED_ADDRESS; | 
|  | 330 | extinfo.reserved_addr = start; | 
| Dimitry Ivanov | 927877c | 2016-09-21 11:17:13 -0700 | [diff] [blame] | 331 | extinfo.reserved_size = kLibSize; | 
|  | 332 | handle_ = android_dlopen_ext(kLibName, RTLD_NOW, &extinfo); | 
| Torne (Richard Coles) | 12bbb91 | 2014-02-06 14:34:21 +0000 | [diff] [blame] | 333 | ASSERT_DL_NOTNULL(handle_); | 
|  | 334 | fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber")); | 
|  | 335 | ASSERT_DL_NOTNULL(f); | 
| Chih-Hung Hsieh | a2c6ae6 | 2014-08-27 13:45:37 -0700 | [diff] [blame] | 336 | EXPECT_GE(reinterpret_cast<void*>(f), start); | 
| Torne (Richard Coles) | 12bbb91 | 2014-02-06 14:34:21 +0000 | [diff] [blame] | 337 | EXPECT_LT(reinterpret_cast<void*>(f), | 
| Dimitry Ivanov | 927877c | 2016-09-21 11:17:13 -0700 | [diff] [blame] | 338 | reinterpret_cast<char*>(start) + kLibSize); | 
| Torne (Richard Coles) | 12bbb91 | 2014-02-06 14:34:21 +0000 | [diff] [blame] | 339 | EXPECT_EQ(4, f()); | 
| Dimitry Ivanov | f45b0e9 | 2016-01-15 11:13:35 -0800 | [diff] [blame] | 340 |  | 
|  | 341 | // Check that after dlclose reserved address space is unmapped (and can be reused) | 
|  | 342 | dlclose(handle_); | 
|  | 343 | handle_ = nullptr; | 
|  | 344 |  | 
| Kalesh Singh | 41c8951 | 2023-10-19 14:10:31 -0700 | [diff] [blame] | 345 | void* new_start = mmap(start, kPageSize, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); | 
| Dimitry Ivanov | f45b0e9 | 2016-01-15 11:13:35 -0800 | [diff] [blame] | 346 | ASSERT_NE(start, new_start) << "dlclose unmapped reserved space"; | 
| Torne (Richard Coles) | 12bbb91 | 2014-02-06 14:34:21 +0000 | [diff] [blame] | 347 | } | 
|  | 348 |  | 
|  | 349 | TEST_F(DlExtTest, ReservedTooSmall) { | 
| Kalesh Singh | 41c8951 | 2023-10-19 14:10:31 -0700 | [diff] [blame] | 350 | void* start = mmap(nullptr, kPageSize, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); | 
| Torne (Richard Coles) | 12bbb91 | 2014-02-06 14:34:21 +0000 | [diff] [blame] | 351 | ASSERT_TRUE(start != MAP_FAILED); | 
|  | 352 | android_dlextinfo extinfo; | 
|  | 353 | extinfo.flags = ANDROID_DLEXT_RESERVED_ADDRESS; | 
|  | 354 | extinfo.reserved_addr = start; | 
| Kalesh Singh | 41c8951 | 2023-10-19 14:10:31 -0700 | [diff] [blame] | 355 | extinfo.reserved_size = kPageSize; | 
| Dimitry Ivanov | 927877c | 2016-09-21 11:17:13 -0700 | [diff] [blame] | 356 | handle_ = android_dlopen_ext(kLibName, RTLD_NOW, &extinfo); | 
| Dmitriy Ivanov | 07e5bc1 | 2014-10-03 17:52:44 -0700 | [diff] [blame] | 357 | EXPECT_EQ(nullptr, handle_); | 
| Torne (Richard Coles) | 12bbb91 | 2014-02-06 14:34:21 +0000 | [diff] [blame] | 358 | } | 
|  | 359 |  | 
| Torne (Richard Coles) | efbe9a5 | 2018-10-17 15:59:38 -0400 | [diff] [blame] | 360 | TEST_F(DlExtTest, ReservedRecursive) { | 
|  | 361 | void* start = mmap(nullptr, kLibSize, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); | 
|  | 362 | ASSERT_TRUE(start != MAP_FAILED); | 
|  | 363 | android_dlextinfo extinfo; | 
|  | 364 | extinfo.flags = ANDROID_DLEXT_RESERVED_ADDRESS | ANDROID_DLEXT_RESERVED_ADDRESS_RECURSIVE; | 
|  | 365 | extinfo.reserved_addr = start; | 
|  | 366 | extinfo.reserved_size = kLibSize; | 
|  | 367 | handle_ = android_dlopen_ext(kLibNameRecursive, RTLD_NOW, &extinfo); | 
|  | 368 | ASSERT_DL_NOTNULL(handle_); | 
|  | 369 |  | 
|  | 370 | fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber")); | 
|  | 371 | ASSERT_DL_NOTNULL(f); | 
|  | 372 | EXPECT_GE(reinterpret_cast<void*>(f), start); | 
|  | 373 | EXPECT_LT(reinterpret_cast<void*>(f), | 
|  | 374 | reinterpret_cast<char*>(start) + kLibSize); | 
|  | 375 | EXPECT_EQ(4, f()); | 
|  | 376 |  | 
|  | 377 | f = reinterpret_cast<fn>(dlsym(handle_, "getBiggerRandomNumber")); | 
|  | 378 | ASSERT_DL_NOTNULL(f); | 
|  | 379 | EXPECT_GE(reinterpret_cast<void*>(f), start); | 
|  | 380 | EXPECT_LT(reinterpret_cast<void*>(f), | 
|  | 381 | reinterpret_cast<char*>(start) + kLibSize); | 
|  | 382 | EXPECT_EQ(8, f()); | 
|  | 383 |  | 
|  | 384 | uint32_t* taxicab_number = reinterpret_cast<uint32_t*>(dlsym(handle_, "dlopen_testlib_taxicab_number")); | 
|  | 385 | ASSERT_DL_NOTNULL(taxicab_number); | 
| Peter Collingbourne | 191ecdc | 2019-08-07 19:06:00 -0700 | [diff] [blame] | 386 | // Untag the pointer so that it can be compared with start, which will be untagged. | 
|  | 387 | void* addr = reinterpret_cast<void*>(untag_address(taxicab_number)); | 
|  | 388 | EXPECT_GE(addr, start); | 
|  | 389 | EXPECT_LT(addr, reinterpret_cast<char*>(start) + kLibSize); | 
| Torne (Richard Coles) | efbe9a5 | 2018-10-17 15:59:38 -0400 | [diff] [blame] | 390 | EXPECT_EQ(1729U, *taxicab_number); | 
|  | 391 | } | 
|  | 392 |  | 
|  | 393 | TEST_F(DlExtTest, ReservedRecursiveTooSmall) { | 
| Kalesh Singh | 41c8951 | 2023-10-19 14:10:31 -0700 | [diff] [blame] | 394 | void* start = mmap(nullptr, kPageSize, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); | 
| Torne (Richard Coles) | efbe9a5 | 2018-10-17 15:59:38 -0400 | [diff] [blame] | 395 | ASSERT_TRUE(start != MAP_FAILED); | 
|  | 396 | android_dlextinfo extinfo; | 
|  | 397 | extinfo.flags = ANDROID_DLEXT_RESERVED_ADDRESS | ANDROID_DLEXT_RESERVED_ADDRESS_RECURSIVE; | 
|  | 398 | extinfo.reserved_addr = start; | 
| Kalesh Singh | 41c8951 | 2023-10-19 14:10:31 -0700 | [diff] [blame] | 399 | extinfo.reserved_size = kPageSize; | 
| Torne (Richard Coles) | efbe9a5 | 2018-10-17 15:59:38 -0400 | [diff] [blame] | 400 | handle_ = android_dlopen_ext(kLibNameRecursive, RTLD_NOW, &extinfo); | 
|  | 401 | EXPECT_EQ(nullptr, handle_); | 
|  | 402 | } | 
|  | 403 |  | 
| Torne (Richard Coles) | 12bbb91 | 2014-02-06 14:34:21 +0000 | [diff] [blame] | 404 | TEST_F(DlExtTest, ReservedHint) { | 
| Dimitry Ivanov | 927877c | 2016-09-21 11:17:13 -0700 | [diff] [blame] | 405 | void* start = mmap(nullptr, kLibSize, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); | 
| Torne (Richard Coles) | 12bbb91 | 2014-02-06 14:34:21 +0000 | [diff] [blame] | 406 | ASSERT_TRUE(start != MAP_FAILED); | 
|  | 407 | android_dlextinfo extinfo; | 
|  | 408 | extinfo.flags = ANDROID_DLEXT_RESERVED_ADDRESS_HINT; | 
|  | 409 | extinfo.reserved_addr = start; | 
| Dimitry Ivanov | 927877c | 2016-09-21 11:17:13 -0700 | [diff] [blame] | 410 | extinfo.reserved_size = kLibSize; | 
|  | 411 | handle_ = android_dlopen_ext(kLibName, RTLD_NOW, &extinfo); | 
| Torne (Richard Coles) | 12bbb91 | 2014-02-06 14:34:21 +0000 | [diff] [blame] | 412 | ASSERT_DL_NOTNULL(handle_); | 
|  | 413 | fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber")); | 
|  | 414 | ASSERT_DL_NOTNULL(f); | 
| Chih-Hung Hsieh | a2c6ae6 | 2014-08-27 13:45:37 -0700 | [diff] [blame] | 415 | EXPECT_GE(reinterpret_cast<void*>(f), start); | 
| Torne (Richard Coles) | 12bbb91 | 2014-02-06 14:34:21 +0000 | [diff] [blame] | 416 | EXPECT_LT(reinterpret_cast<void*>(f), | 
| Dimitry Ivanov | 927877c | 2016-09-21 11:17:13 -0700 | [diff] [blame] | 417 | reinterpret_cast<char*>(start) + kLibSize); | 
| Torne (Richard Coles) | 12bbb91 | 2014-02-06 14:34:21 +0000 | [diff] [blame] | 418 | EXPECT_EQ(4, f()); | 
|  | 419 | } | 
|  | 420 |  | 
|  | 421 | TEST_F(DlExtTest, ReservedHintTooSmall) { | 
| Kalesh Singh | 41c8951 | 2023-10-19 14:10:31 -0700 | [diff] [blame] | 422 | void* start = mmap(nullptr, kPageSize, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); | 
| Torne (Richard Coles) | 12bbb91 | 2014-02-06 14:34:21 +0000 | [diff] [blame] | 423 | ASSERT_TRUE(start != MAP_FAILED); | 
|  | 424 | android_dlextinfo extinfo; | 
|  | 425 | extinfo.flags = ANDROID_DLEXT_RESERVED_ADDRESS_HINT; | 
|  | 426 | extinfo.reserved_addr = start; | 
| Kalesh Singh | 41c8951 | 2023-10-19 14:10:31 -0700 | [diff] [blame] | 427 | extinfo.reserved_size = kPageSize; | 
| Dimitry Ivanov | 927877c | 2016-09-21 11:17:13 -0700 | [diff] [blame] | 428 | handle_ = android_dlopen_ext(kLibName, RTLD_NOW, &extinfo); | 
| Torne (Richard Coles) | 12bbb91 | 2014-02-06 14:34:21 +0000 | [diff] [blame] | 429 | ASSERT_DL_NOTNULL(handle_); | 
|  | 430 | fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber")); | 
|  | 431 | ASSERT_DL_NOTNULL(f); | 
| Chih-Hung Hsieh | a2c6ae6 | 2014-08-27 13:45:37 -0700 | [diff] [blame] | 432 | EXPECT_TRUE(reinterpret_cast<void*>(f) < start || | 
| Kalesh Singh | 41c8951 | 2023-10-19 14:10:31 -0700 | [diff] [blame] | 433 | (reinterpret_cast<void*>(f) >= reinterpret_cast<char*>(start) + kPageSize)); | 
| Torne (Richard Coles) | 12bbb91 | 2014-02-06 14:34:21 +0000 | [diff] [blame] | 434 | EXPECT_EQ(4, f()); | 
|  | 435 | } | 
| Torne (Richard Coles) | 183ad9d | 2014-02-27 13:18:00 +0000 | [diff] [blame] | 436 |  | 
| Torne (Richard Coles) | 26ec967 | 2014-04-30 15:48:40 +0100 | [diff] [blame] | 437 | class DlExtRelroSharingTest : public DlExtTest { | 
|  | 438 | protected: | 
| Yi Kong | 358603a | 2019-03-29 14:25:16 -0700 | [diff] [blame] | 439 | void SetUp() override { | 
| Torne (Richard Coles) | 26ec967 | 2014-04-30 15:48:40 +0100 | [diff] [blame] | 440 | DlExtTest::SetUp(); | 
| Dimitry Ivanov | 927877c | 2016-09-21 11:17:13 -0700 | [diff] [blame] | 441 | void* start = mmap(nullptr, kLibSize, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); | 
| Torne (Richard Coles) | 26ec967 | 2014-04-30 15:48:40 +0100 | [diff] [blame] | 442 | ASSERT_TRUE(start != MAP_FAILED); | 
|  | 443 | extinfo_.flags = ANDROID_DLEXT_RESERVED_ADDRESS; | 
|  | 444 | extinfo_.reserved_addr = start; | 
| Dimitry Ivanov | 927877c | 2016-09-21 11:17:13 -0700 | [diff] [blame] | 445 | extinfo_.reserved_size = kLibSize; | 
| Torne (Richard Coles) | 26ec967 | 2014-04-30 15:48:40 +0100 | [diff] [blame] | 446 | extinfo_.relro_fd = -1; | 
| Torne (Richard Coles) | 183ad9d | 2014-02-27 13:18:00 +0000 | [diff] [blame] | 447 | } | 
|  | 448 |  | 
| Yi Kong | 358603a | 2019-03-29 14:25:16 -0700 | [diff] [blame] | 449 | void TearDown() override { | 
| Torne (Richard Coles) | 26ec967 | 2014-04-30 15:48:40 +0100 | [diff] [blame] | 450 | DlExtTest::TearDown(); | 
| Torne (Richard Coles) | 26ec967 | 2014-04-30 15:48:40 +0100 | [diff] [blame] | 451 | } | 
| Torne (Richard Coles) | 183ad9d | 2014-02-27 13:18:00 +0000 | [diff] [blame] | 452 |  | 
| Torne (Richard Coles) | efbe9a5 | 2018-10-17 15:59:38 -0400 | [diff] [blame] | 453 | void CreateRelroFile(const char* lib, const char* relro_file, bool recursive) { | 
| Elliott Hughes | 5cec377 | 2018-01-19 15:45:23 -0800 | [diff] [blame] | 454 | int relro_fd = open(relro_file, O_RDWR | O_TRUNC | O_CLOEXEC); | 
| Torne (Richard Coles) | 26ec967 | 2014-04-30 15:48:40 +0100 | [diff] [blame] | 455 | ASSERT_NOERROR(relro_fd); | 
|  | 456 |  | 
| Torne (Richard Coles) | efbe9a5 | 2018-10-17 15:59:38 -0400 | [diff] [blame] | 457 | if (recursive) { | 
|  | 458 | extinfo_.flags |= ANDROID_DLEXT_RESERVED_ADDRESS_RECURSIVE; | 
|  | 459 | } | 
|  | 460 |  | 
| Torne (Richard Coles) | 26ec967 | 2014-04-30 15:48:40 +0100 | [diff] [blame] | 461 | pid_t pid = fork(); | 
|  | 462 | if (pid == 0) { | 
|  | 463 | // child process | 
|  | 464 | extinfo_.flags |= ANDROID_DLEXT_WRITE_RELRO; | 
|  | 465 | extinfo_.relro_fd = relro_fd; | 
|  | 466 | void* handle = android_dlopen_ext(lib, RTLD_NOW, &extinfo_); | 
| Dmitriy Ivanov | 07e5bc1 | 2014-10-03 17:52:44 -0700 | [diff] [blame] | 467 | if (handle == nullptr) { | 
| Torne (Richard Coles) | 26ec967 | 2014-04-30 15:48:40 +0100 | [diff] [blame] | 468 | fprintf(stderr, "in child: %s\n", dlerror()); | 
|  | 469 | exit(1); | 
|  | 470 | } | 
| Torne (Richard Coles) | fa9f7f2 | 2019-04-02 17:04:42 -0400 | [diff] [blame] | 471 | fn f = reinterpret_cast<fn>(dlsym(handle, "getRandomNumber")); | 
|  | 472 | ASSERT_DL_NOTNULL(f); | 
|  | 473 | EXPECT_EQ(4, f()); | 
|  | 474 |  | 
|  | 475 | if (recursive) { | 
|  | 476 | fn f = reinterpret_cast<fn>(dlsym(handle, "getBiggerRandomNumber")); | 
|  | 477 | ASSERT_DL_NOTNULL(f); | 
|  | 478 | EXPECT_EQ(8, f()); | 
|  | 479 | } | 
|  | 480 |  | 
|  | 481 | uint32_t* taxicab_number = | 
|  | 482 | reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_testlib_taxicab_number")); | 
|  | 483 | ASSERT_DL_NOTNULL(taxicab_number); | 
|  | 484 | EXPECT_EQ(1729U, *taxicab_number); | 
|  | 485 | exit(testing::Test::HasFailure()); | 
| Torne (Richard Coles) | 26ec967 | 2014-04-30 15:48:40 +0100 | [diff] [blame] | 486 | } | 
|  | 487 |  | 
|  | 488 | // continuing in parent | 
|  | 489 | ASSERT_NOERROR(close(relro_fd)); | 
|  | 490 | ASSERT_NOERROR(pid); | 
| Elliott Hughes | 33697a0 | 2016-01-26 13:04:57 -0800 | [diff] [blame] | 491 | AssertChildExited(pid, 0); | 
| Torne (Richard Coles) | 26ec967 | 2014-04-30 15:48:40 +0100 | [diff] [blame] | 492 |  | 
|  | 493 | // reopen file for reading so it can be used | 
| Elliott Hughes | 5cec377 | 2018-01-19 15:45:23 -0800 | [diff] [blame] | 494 | relro_fd = open(relro_file, O_RDONLY | O_CLOEXEC); | 
| Torne (Richard Coles) | 26ec967 | 2014-04-30 15:48:40 +0100 | [diff] [blame] | 495 | ASSERT_NOERROR(relro_fd); | 
|  | 496 | extinfo_.flags |= ANDROID_DLEXT_USE_RELRO; | 
|  | 497 | extinfo_.relro_fd = relro_fd; | 
|  | 498 | } | 
|  | 499 |  | 
| Torne (Richard Coles) | efbe9a5 | 2018-10-17 15:59:38 -0400 | [diff] [blame] | 500 | void TryUsingRelro(const char* lib, bool recursive) { | 
| Torne (Richard Coles) | 26ec967 | 2014-04-30 15:48:40 +0100 | [diff] [blame] | 501 | handle_ = android_dlopen_ext(lib, RTLD_NOW, &extinfo_); | 
|  | 502 | ASSERT_DL_NOTNULL(handle_); | 
|  | 503 | fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber")); | 
|  | 504 | ASSERT_DL_NOTNULL(f); | 
|  | 505 | EXPECT_EQ(4, f()); | 
| Dmitriy Ivanov | edfc9f6 | 2015-09-02 16:32:02 -0700 | [diff] [blame] | 506 |  | 
| Torne (Richard Coles) | efbe9a5 | 2018-10-17 15:59:38 -0400 | [diff] [blame] | 507 | if (recursive) { | 
|  | 508 | fn f = reinterpret_cast<fn>(dlsym(handle_, "getBiggerRandomNumber")); | 
|  | 509 | ASSERT_DL_NOTNULL(f); | 
|  | 510 | EXPECT_EQ(8, f()); | 
|  | 511 | } | 
|  | 512 |  | 
| Dimitry Ivanov | f45b0e9 | 2016-01-15 11:13:35 -0800 | [diff] [blame] | 513 | uint32_t* taxicab_number = | 
|  | 514 | reinterpret_cast<uint32_t*>(dlsym(handle_, "dlopen_testlib_taxicab_number")); | 
| Dmitriy Ivanov | edfc9f6 | 2015-09-02 16:32:02 -0700 | [diff] [blame] | 515 | ASSERT_DL_NOTNULL(taxicab_number); | 
|  | 516 | EXPECT_EQ(1729U, *taxicab_number); | 
| Torne (Richard Coles) | 26ec967 | 2014-04-30 15:48:40 +0100 | [diff] [blame] | 517 | } | 
|  | 518 |  | 
| Zhenhua WANG | 81aad00 | 2017-04-25 11:07:19 +0800 | [diff] [blame] | 519 | void SpawnChildrenAndMeasurePss(const char* lib, const char* relro_file, bool share_relro, | 
|  | 520 | size_t* pss_out); | 
| Torne (Richard Coles) | 2605261 | 2014-05-02 14:57:42 +0100 | [diff] [blame] | 521 |  | 
| Torne (Richard Coles) | efbe9a5 | 2018-10-17 15:59:38 -0400 | [diff] [blame] | 522 | std::string FindMappingName(void* ptr); | 
|  | 523 |  | 
| Torne (Richard Coles) | 26ec967 | 2014-04-30 15:48:40 +0100 | [diff] [blame] | 524 | android_dlextinfo extinfo_; | 
| Torne (Richard Coles) | 26ec967 | 2014-04-30 15:48:40 +0100 | [diff] [blame] | 525 | }; | 
|  | 526 |  | 
|  | 527 | TEST_F(DlExtRelroSharingTest, ChildWritesGoodData) { | 
| Yabin Cui | 294d1e2 | 2014-12-07 20:43:37 -0800 | [diff] [blame] | 528 | TemporaryFile tf; // Use tf to get an unique filename. | 
|  | 529 | ASSERT_NOERROR(close(tf.fd)); | 
|  | 530 |  | 
| Torne (Richard Coles) | efbe9a5 | 2018-10-17 15:59:38 -0400 | [diff] [blame] | 531 | ASSERT_NO_FATAL_FAILURE(CreateRelroFile(kLibName, tf.path, false)); | 
|  | 532 | ASSERT_NO_FATAL_FAILURE(TryUsingRelro(kLibName, false)); | 
|  | 533 | void* relro_data = dlsym(handle_, "lots_of_relro"); | 
|  | 534 | ASSERT_DL_NOTNULL(relro_data); | 
|  | 535 | EXPECT_EQ(tf.path, FindMappingName(relro_data)); | 
|  | 536 |  | 
|  | 537 | // Use destructor of tf to close and unlink the file. | 
|  | 538 | tf.fd = extinfo_.relro_fd; | 
|  | 539 | } | 
|  | 540 |  | 
|  | 541 | TEST_F(DlExtRelroSharingTest, ChildWritesGoodDataRecursive) { | 
|  | 542 | TemporaryFile tf; // Use tf to get an unique filename. | 
|  | 543 | ASSERT_NOERROR(close(tf.fd)); | 
|  | 544 |  | 
|  | 545 | ASSERT_NO_FATAL_FAILURE(CreateRelroFile(kLibNameRecursive, tf.path, true)); | 
|  | 546 | ASSERT_NO_FATAL_FAILURE(TryUsingRelro(kLibNameRecursive, true)); | 
|  | 547 | void* relro_data = dlsym(handle_, "lots_of_relro"); | 
|  | 548 | ASSERT_DL_NOTNULL(relro_data); | 
|  | 549 | EXPECT_EQ(tf.path, FindMappingName(relro_data)); | 
|  | 550 | void* recursive_relro_data = dlsym(handle_, "lots_more_relro"); | 
|  | 551 | ASSERT_DL_NOTNULL(recursive_relro_data); | 
|  | 552 | EXPECT_EQ(tf.path, FindMappingName(recursive_relro_data)); | 
|  | 553 |  | 
| Yabin Cui | 294d1e2 | 2014-12-07 20:43:37 -0800 | [diff] [blame] | 554 |  | 
|  | 555 | // Use destructor of tf to close and unlink the file. | 
|  | 556 | tf.fd = extinfo_.relro_fd; | 
| Torne (Richard Coles) | 26ec967 | 2014-04-30 15:48:40 +0100 | [diff] [blame] | 557 | } | 
|  | 558 |  | 
| Torne (Richard Coles) | 5d10374 | 2019-04-11 12:25:06 -0400 | [diff] [blame] | 559 | TEST_F(DlExtRelroSharingTest, CheckRelroSizes) { | 
|  | 560 | TemporaryFile tf1, tf2; | 
|  | 561 | ASSERT_NOERROR(close(tf1.fd)); | 
|  | 562 | ASSERT_NOERROR(close(tf2.fd)); | 
|  | 563 |  | 
|  | 564 | ASSERT_NO_FATAL_FAILURE(CreateRelroFile(kLibNameRecursive, tf1.path, false)); | 
|  | 565 | struct stat no_recursive; | 
|  | 566 | ASSERT_NOERROR(fstat(extinfo_.relro_fd, &no_recursive)); | 
|  | 567 | tf1.fd = extinfo_.relro_fd; | 
|  | 568 |  | 
|  | 569 | ASSERT_NO_FATAL_FAILURE(CreateRelroFile(kLibNameRecursive, tf2.path, true)); | 
|  | 570 | struct stat with_recursive; | 
|  | 571 | ASSERT_NOERROR(fstat(extinfo_.relro_fd, &with_recursive)); | 
|  | 572 | tf2.fd = extinfo_.relro_fd; | 
|  | 573 |  | 
|  | 574 | // RELRO file should end up bigger when we use the recursive flag, since it | 
|  | 575 | // includes data for more than one library. | 
|  | 576 | ASSERT_GT(with_recursive.st_size, no_recursive.st_size); | 
|  | 577 | } | 
|  | 578 |  | 
| Torne (Richard Coles) | 26ec967 | 2014-04-30 15:48:40 +0100 | [diff] [blame] | 579 | TEST_F(DlExtRelroSharingTest, ChildWritesNoRelro) { | 
| Yabin Cui | 294d1e2 | 2014-12-07 20:43:37 -0800 | [diff] [blame] | 580 | TemporaryFile tf; // // Use tf to get an unique filename. | 
|  | 581 | ASSERT_NOERROR(close(tf.fd)); | 
|  | 582 |  | 
| Torne (Richard Coles) | efbe9a5 | 2018-10-17 15:59:38 -0400 | [diff] [blame] | 583 | ASSERT_NO_FATAL_FAILURE(CreateRelroFile(kLibNameNoRelro, tf.path, false)); | 
|  | 584 | ASSERT_NO_FATAL_FAILURE(TryUsingRelro(kLibNameNoRelro, false)); | 
| Yabin Cui | 294d1e2 | 2014-12-07 20:43:37 -0800 | [diff] [blame] | 585 |  | 
|  | 586 | // Use destructor of tf to close and unlink the file. | 
|  | 587 | tf.fd = extinfo_.relro_fd; | 
| Torne (Richard Coles) | 26ec967 | 2014-04-30 15:48:40 +0100 | [diff] [blame] | 588 | } | 
|  | 589 |  | 
|  | 590 | TEST_F(DlExtRelroSharingTest, RelroFileEmpty) { | 
| Torne (Richard Coles) | efbe9a5 | 2018-10-17 15:59:38 -0400 | [diff] [blame] | 591 | ASSERT_NO_FATAL_FAILURE(TryUsingRelro(kLibName, false)); | 
| Torne (Richard Coles) | 183ad9d | 2014-02-27 13:18:00 +0000 | [diff] [blame] | 592 | } | 
| Torne (Richard Coles) | 2605261 | 2014-05-02 14:57:42 +0100 | [diff] [blame] | 593 |  | 
|  | 594 | TEST_F(DlExtRelroSharingTest, VerifyMemorySaving) { | 
| Elliott Hughes | bcaa454 | 2019-03-08 15:20:23 -0800 | [diff] [blame] | 595 | if (geteuid() != 0) GTEST_SKIP() << "This test must be run as root"; | 
| Dan Albert | 69fb9f3 | 2014-09-03 11:30:21 -0700 | [diff] [blame] | 596 |  | 
| Yabin Cui | 294d1e2 | 2014-12-07 20:43:37 -0800 | [diff] [blame] | 597 | TemporaryFile tf; // Use tf to get an unique filename. | 
|  | 598 | ASSERT_NOERROR(close(tf.fd)); | 
|  | 599 |  | 
| Torne (Richard Coles) | efbe9a5 | 2018-10-17 15:59:38 -0400 | [diff] [blame] | 600 | ASSERT_NO_FATAL_FAILURE(CreateRelroFile(kLibName, tf.path, false)); | 
| Yabin Cui | 294d1e2 | 2014-12-07 20:43:37 -0800 | [diff] [blame] | 601 |  | 
| Torne (Richard Coles) | 2605261 | 2014-05-02 14:57:42 +0100 | [diff] [blame] | 602 | int pipefd[2]; | 
|  | 603 | ASSERT_NOERROR(pipe(pipefd)); | 
|  | 604 |  | 
|  | 605 | size_t without_sharing, with_sharing; | 
| Mark Salyzyn | 68a3bcc | 2018-11-13 07:35:21 -0800 | [diff] [blame] | 606 | ASSERT_NO_FATAL_FAILURE(SpawnChildrenAndMeasurePss(kLibName, tf.path, false, &without_sharing)); | 
|  | 607 | ASSERT_NO_FATAL_FAILURE(SpawnChildrenAndMeasurePss(kLibName, tf.path, true, &with_sharing)); | 
| Zhenhua WANG | 81aad00 | 2017-04-25 11:07:19 +0800 | [diff] [blame] | 608 | ASSERT_LT(with_sharing, without_sharing); | 
| Torne (Richard Coles) | 2605261 | 2014-05-02 14:57:42 +0100 | [diff] [blame] | 609 |  | 
| Zhenhua WANG | 81aad00 | 2017-04-25 11:07:19 +0800 | [diff] [blame] | 610 | // We expect the sharing to save at least 50% of the library's total PSS. | 
|  | 611 | // In practice it saves 80%+ for this library in the test. | 
|  | 612 | size_t pss_saved = without_sharing - with_sharing; | 
|  | 613 | size_t expected_min_saved = without_sharing / 2; | 
|  | 614 |  | 
|  | 615 | EXPECT_LT(expected_min_saved, pss_saved); | 
| Yabin Cui | 294d1e2 | 2014-12-07 20:43:37 -0800 | [diff] [blame] | 616 |  | 
|  | 617 | // Use destructor of tf to close and unlink the file. | 
|  | 618 | tf.fd = extinfo_.relro_fd; | 
| Torne (Richard Coles) | 2605261 | 2014-05-02 14:57:42 +0100 | [diff] [blame] | 619 | } | 
|  | 620 |  | 
| Zhenhua WANG | 81aad00 | 2017-04-25 11:07:19 +0800 | [diff] [blame] | 621 | void GetPss(bool shared_relro, const char* lib, const char* relro_file, pid_t pid, | 
|  | 622 | size_t* total_pss) { | 
| Sandeep Patil | 4e02cc1 | 2019-01-21 14:22:05 -0800 | [diff] [blame] | 623 | android::meminfo::ProcMemInfo proc_mem(pid); | 
| Christopher Ferris | 89b658c | 2019-10-10 13:27:54 -0700 | [diff] [blame] | 624 | const std::vector<android::meminfo::Vma>& maps = proc_mem.MapsWithoutUsageStats(); | 
| Sandeep Patil | 4e02cc1 | 2019-01-21 14:22:05 -0800 | [diff] [blame] | 625 | ASSERT_GT(maps.size(), 0UL); | 
| Torne (Richard Coles) | 2605261 | 2014-05-02 14:57:42 +0100 | [diff] [blame] | 626 |  | 
| Zhenhua WANG | 81aad00 | 2017-04-25 11:07:19 +0800 | [diff] [blame] | 627 | // Calculate total PSS of the library. | 
|  | 628 | *total_pss = 0; | 
|  | 629 | bool saw_relro_file = false; | 
| Sandeep Patil | 4e02cc1 | 2019-01-21 14:22:05 -0800 | [diff] [blame] | 630 | for (auto& vma : maps) { | 
|  | 631 | if (android::base::EndsWith(vma.name, lib) || (vma.name == relro_file)) { | 
|  | 632 | if (vma.name == relro_file) { | 
|  | 633 | saw_relro_file = true; | 
|  | 634 | } | 
| Zhenhua WANG | 81aad00 | 2017-04-25 11:07:19 +0800 | [diff] [blame] | 635 |  | 
| Christopher Ferris | 89b658c | 2019-10-10 13:27:54 -0700 | [diff] [blame] | 636 | android::meminfo::Vma update_vma(vma); | 
|  | 637 | ASSERT_TRUE(proc_mem.FillInVmaStats(update_vma)); | 
|  | 638 | *total_pss += update_vma.usage.pss; | 
| Zhenhua WANG | 81aad00 | 2017-04-25 11:07:19 +0800 | [diff] [blame] | 639 | } | 
| Torne (Richard Coles) | 2605261 | 2014-05-02 14:57:42 +0100 | [diff] [blame] | 640 | } | 
| Torne (Richard Coles) | 2605261 | 2014-05-02 14:57:42 +0100 | [diff] [blame] | 641 |  | 
| Zhenhua WANG | 81aad00 | 2017-04-25 11:07:19 +0800 | [diff] [blame] | 642 | if (shared_relro) ASSERT_TRUE(saw_relro_file); | 
| Torne (Richard Coles) | 2605261 | 2014-05-02 14:57:42 +0100 | [diff] [blame] | 643 | } | 
|  | 644 |  | 
| Zhenhua WANG | 81aad00 | 2017-04-25 11:07:19 +0800 | [diff] [blame] | 645 | void DlExtRelroSharingTest::SpawnChildrenAndMeasurePss(const char* lib, const char* relro_file, | 
|  | 646 | bool share_relro, size_t* pss_out) { | 
| Torne (Richard Coles) | 2605261 | 2014-05-02 14:57:42 +0100 | [diff] [blame] | 647 | const int CHILDREN = 20; | 
|  | 648 |  | 
|  | 649 | // Create children | 
| Elliott Hughes | 33697a0 | 2016-01-26 13:04:57 -0800 | [diff] [blame] | 650 | pid_t child_pids[CHILDREN]; | 
| Torne (Richard Coles) | 2605261 | 2014-05-02 14:57:42 +0100 | [diff] [blame] | 651 | int childpipe[CHILDREN]; | 
|  | 652 | for (int i=0; i<CHILDREN; ++i) { | 
|  | 653 | char read_buf; | 
|  | 654 | int child_done_pipe[2], parent_done_pipe[2]; | 
|  | 655 | ASSERT_NOERROR(pipe(child_done_pipe)); | 
|  | 656 | ASSERT_NOERROR(pipe(parent_done_pipe)); | 
|  | 657 |  | 
|  | 658 | pid_t child = fork(); | 
|  | 659 | if (child == 0) { | 
|  | 660 | // close the 'wrong' ends of the pipes in the child | 
|  | 661 | close(child_done_pipe[0]); | 
|  | 662 | close(parent_done_pipe[1]); | 
|  | 663 |  | 
|  | 664 | // open the library | 
|  | 665 | void* handle; | 
|  | 666 | if (share_relro) { | 
|  | 667 | handle = android_dlopen_ext(lib, RTLD_NOW, &extinfo_); | 
|  | 668 | } else { | 
|  | 669 | handle = dlopen(lib, RTLD_NOW); | 
|  | 670 | } | 
| Dmitriy Ivanov | 07e5bc1 | 2014-10-03 17:52:44 -0700 | [diff] [blame] | 671 | if (handle == nullptr) { | 
| Torne (Richard Coles) | 2605261 | 2014-05-02 14:57:42 +0100 | [diff] [blame] | 672 | fprintf(stderr, "in child: %s\n", dlerror()); | 
|  | 673 | exit(1); | 
|  | 674 | } | 
|  | 675 |  | 
|  | 676 | // close write end of child_done_pipe to signal the parent that we're done. | 
|  | 677 | close(child_done_pipe[1]); | 
|  | 678 |  | 
|  | 679 | // wait for the parent to close parent_done_pipe, then exit | 
|  | 680 | read(parent_done_pipe[0], &read_buf, 1); | 
|  | 681 | exit(0); | 
|  | 682 | } | 
|  | 683 |  | 
|  | 684 | ASSERT_NOERROR(child); | 
|  | 685 |  | 
|  | 686 | // close the 'wrong' ends of the pipes in the parent | 
|  | 687 | close(child_done_pipe[1]); | 
|  | 688 | close(parent_done_pipe[0]); | 
|  | 689 |  | 
|  | 690 | // wait for the child to be done | 
|  | 691 | read(child_done_pipe[0], &read_buf, 1); | 
|  | 692 | close(child_done_pipe[0]); | 
|  | 693 |  | 
|  | 694 | // save the child's pid and the parent_done_pipe | 
| Elliott Hughes | 33697a0 | 2016-01-26 13:04:57 -0800 | [diff] [blame] | 695 | child_pids[i] = child; | 
| Torne (Richard Coles) | 2605261 | 2014-05-02 14:57:42 +0100 | [diff] [blame] | 696 | childpipe[i] = parent_done_pipe[1]; | 
|  | 697 | } | 
|  | 698 |  | 
| Zhenhua WANG | 81aad00 | 2017-04-25 11:07:19 +0800 | [diff] [blame] | 699 | // Sum the PSS of tested library of all the children | 
| Torne (Richard Coles) | 2605261 | 2014-05-02 14:57:42 +0100 | [diff] [blame] | 700 | size_t total_pss = 0; | 
|  | 701 | for (int i=0; i<CHILDREN; ++i) { | 
|  | 702 | size_t child_pss; | 
| Zhenhua WANG | 81aad00 | 2017-04-25 11:07:19 +0800 | [diff] [blame] | 703 | ASSERT_NO_FATAL_FAILURE(GetPss(share_relro, lib, relro_file, child_pids[i], &child_pss)); | 
| Torne (Richard Coles) | 2605261 | 2014-05-02 14:57:42 +0100 | [diff] [blame] | 704 | total_pss += child_pss; | 
|  | 705 | } | 
|  | 706 | *pss_out = total_pss; | 
|  | 707 |  | 
|  | 708 | // Close pipes and wait for children to exit | 
|  | 709 | for (int i=0; i<CHILDREN; ++i) { | 
|  | 710 | ASSERT_NOERROR(close(childpipe[i])); | 
|  | 711 | } | 
| Elliott Hughes | 33697a0 | 2016-01-26 13:04:57 -0800 | [diff] [blame] | 712 | for (int i = 0; i < CHILDREN; ++i) { | 
|  | 713 | AssertChildExited(child_pids[i], 0); | 
| Torne (Richard Coles) | 2605261 | 2014-05-02 14:57:42 +0100 | [diff] [blame] | 714 | } | 
|  | 715 | } | 
| Dmitriy Ivanov | 42d5fcb | 2015-10-29 17:01:24 -0700 | [diff] [blame] | 716 |  | 
| Torne (Richard Coles) | efbe9a5 | 2018-10-17 15:59:38 -0400 | [diff] [blame] | 717 | std::string DlExtRelroSharingTest::FindMappingName(void* ptr) { | 
| Evgenii Stepanov | 4edbcee | 2021-09-17 14:59:15 -0700 | [diff] [blame] | 718 | uint64_t addr = reinterpret_cast<uint64_t>(untag_address(ptr)); | 
| Torne (Richard Coles) | efbe9a5 | 2018-10-17 15:59:38 -0400 | [diff] [blame] | 719 | std::string found_name = "<not found>"; | 
|  | 720 |  | 
| Edgar Arriaga | d02148c | 2020-11-23 18:11:02 -0800 | [diff] [blame] | 721 | EXPECT_TRUE(android::procinfo::ReadMapFile("/proc/self/maps", | 
|  | 722 | [&](const android::procinfo::MapInfo& mapinfo) { | 
|  | 723 | if (addr >= mapinfo.start && addr < mapinfo.end) { | 
|  | 724 | found_name = mapinfo.name; | 
|  | 725 | } | 
|  | 726 | })); | 
| Torne (Richard Coles) | efbe9a5 | 2018-10-17 15:59:38 -0400 | [diff] [blame] | 727 |  | 
|  | 728 | return found_name; | 
|  | 729 | } | 
|  | 730 |  | 
| Dmitriy Ivanov | 42d5fcb | 2015-10-29 17:01:24 -0700 | [diff] [blame] | 731 | // Testing namespaces | 
|  | 732 | static const char* g_public_lib = "libnstest_public.so"; | 
|  | 733 |  | 
| Dimitry Ivanov | 7a34b9d | 2017-02-03 14:07:34 -0800 | [diff] [blame] | 734 | // These are libs shared with default namespace | 
| Ryan Prichard | 22fa3dd | 2020-01-31 14:47:48 -0800 | [diff] [blame] | 735 | static const std::string g_core_shared_libs = kCoreSharedLibs; | 
| Dimitry Ivanov | 7a34b9d | 2017-02-03 14:07:34 -0800 | [diff] [blame] | 736 |  | 
| Dmitriy Ivanov | 42d5fcb | 2015-10-29 17:01:24 -0700 | [diff] [blame] | 737 | TEST(dlext, ns_smoke) { | 
|  | 738 | static const char* root_lib = "libnstest_root.so"; | 
| Dimitry Ivanov | 7a34b9d | 2017-02-03 14:07:34 -0800 | [diff] [blame] | 739 | std::string shared_libs = g_core_shared_libs + ":" + g_public_lib; | 
| Dmitriy Ivanov | 42d5fcb | 2015-10-29 17:01:24 -0700 | [diff] [blame] | 740 |  | 
| Dimitry Ivanov | 7a34b9d | 2017-02-03 14:07:34 -0800 | [diff] [blame] | 741 | ASSERT_FALSE(android_init_anonymous_namespace("", nullptr)); | 
|  | 742 | ASSERT_STREQ("android_init_anonymous_namespace failed: error linking namespaces" | 
|  | 743 | " \"(anonymous)\"->\"(default)\": the list of shared libraries is empty.", | 
|  | 744 | dlerror()); | 
| Dimitry Ivanov | 5480761 | 2016-04-21 14:57:38 -0700 | [diff] [blame] | 745 |  | 
| Elliott Hughes | 8d8138a | 2024-03-12 22:37:13 +0000 | [diff] [blame] | 746 | const std::string lib_public_path = GetTestLibRoot() + "/public_namespace_libs/" + g_public_lib; | 
| Dimitry Ivanov | 22840aa | 2015-12-04 18:28:49 -0800 | [diff] [blame] | 747 | void* handle_public = dlopen(lib_public_path.c_str(), RTLD_NOW); | 
| Dmitriy Ivanov | 42d5fcb | 2015-10-29 17:01:24 -0700 | [diff] [blame] | 748 | ASSERT_TRUE(handle_public != nullptr) << dlerror(); | 
|  | 749 |  | 
| Dimitry Ivanov | 7a34b9d | 2017-02-03 14:07:34 -0800 | [diff] [blame] | 750 | ASSERT_TRUE(android_init_anonymous_namespace(shared_libs.c_str(), nullptr)) << dlerror(); | 
| Dmitriy Ivanov | 42d5fcb | 2015-10-29 17:01:24 -0700 | [diff] [blame] | 751 |  | 
| Dimitry Ivanov | 7d429d3 | 2017-02-01 15:28:52 -0800 | [diff] [blame] | 752 | // Check that libraries added to public namespace are not NODELETE | 
| Dmitriy Ivanov | 42d5fcb | 2015-10-29 17:01:24 -0700 | [diff] [blame] | 753 | dlclose(handle_public); | 
| Dimitry Ivanov | 7d429d3 | 2017-02-01 15:28:52 -0800 | [diff] [blame] | 754 | handle_public = dlopen(lib_public_path.c_str(), RTLD_NOW | RTLD_NOLOAD); | 
| Dimitry Ivanov | 7d429d3 | 2017-02-01 15:28:52 -0800 | [diff] [blame] | 755 | ASSERT_TRUE(handle_public == nullptr); | 
|  | 756 | ASSERT_EQ(std::string("dlopen failed: library \"") + lib_public_path + | 
|  | 757 | "\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror()); | 
|  | 758 |  | 
|  | 759 | handle_public = dlopen(lib_public_path.c_str(), RTLD_NOW); | 
| Dmitriy Ivanov | 42d5fcb | 2015-10-29 17:01:24 -0700 | [diff] [blame] | 760 |  | 
| Dimitry Ivanov | 7a34b9d | 2017-02-03 14:07:34 -0800 | [diff] [blame] | 761 | // create "public namespace", share limited set of public libraries with | 
|  | 762 |  | 
| Dimitry Ivanov | 7331fe1 | 2015-12-14 14:11:17 -0800 | [diff] [blame] | 763 | android_namespace_t* ns1 = | 
| Dimitry Ivanov | 7a34b9d | 2017-02-03 14:07:34 -0800 | [diff] [blame] | 764 | android_create_namespace("private", | 
|  | 765 | nullptr, | 
| Elliott Hughes | 8d8138a | 2024-03-12 22:37:13 +0000 | [diff] [blame] | 766 | (GetTestLibRoot() + "/private_namespace_libs").c_str(), | 
| Dimitry Ivanov | 7a34b9d | 2017-02-03 14:07:34 -0800 | [diff] [blame] | 767 | ANDROID_NAMESPACE_TYPE_REGULAR, | 
|  | 768 | nullptr, | 
|  | 769 | nullptr); | 
| Dmitriy Ivanov | 42d5fcb | 2015-10-29 17:01:24 -0700 | [diff] [blame] | 770 | ASSERT_TRUE(ns1 != nullptr) << dlerror(); | 
| Dimitry Ivanov | 7a34b9d | 2017-02-03 14:07:34 -0800 | [diff] [blame] | 771 | ASSERT_TRUE(android_link_namespaces(ns1, nullptr, shared_libs.c_str())) << dlerror(); | 
| Dmitriy Ivanov | 42d5fcb | 2015-10-29 17:01:24 -0700 | [diff] [blame] | 772 |  | 
| Dimitry Ivanov | 7331fe1 | 2015-12-14 14:11:17 -0800 | [diff] [blame] | 773 | android_namespace_t* ns2 = | 
| Dimitry Ivanov | 7a34b9d | 2017-02-03 14:07:34 -0800 | [diff] [blame] | 774 | android_create_namespace("private_isolated", | 
|  | 775 | nullptr, | 
| Elliott Hughes | 8d8138a | 2024-03-12 22:37:13 +0000 | [diff] [blame] | 776 | (GetTestLibRoot() + "/private_namespace_libs").c_str(), | 
| Dimitry Ivanov | 7a34b9d | 2017-02-03 14:07:34 -0800 | [diff] [blame] | 777 | ANDROID_NAMESPACE_TYPE_ISOLATED, | 
|  | 778 | nullptr, | 
|  | 779 | nullptr); | 
| Dmitriy Ivanov | 42d5fcb | 2015-10-29 17:01:24 -0700 | [diff] [blame] | 780 | ASSERT_TRUE(ns2 != nullptr) << dlerror(); | 
| Dimitry Ivanov | 7a34b9d | 2017-02-03 14:07:34 -0800 | [diff] [blame] | 781 | ASSERT_TRUE(android_link_namespaces(ns2, nullptr, shared_libs.c_str())) << dlerror(); | 
| Dmitriy Ivanov | 42d5fcb | 2015-10-29 17:01:24 -0700 | [diff] [blame] | 782 |  | 
|  | 783 | // This should not have affect search path for default namespace: | 
|  | 784 | ASSERT_TRUE(dlopen(root_lib, RTLD_NOW) == nullptr); | 
|  | 785 | void* handle = dlopen(g_public_lib, RTLD_NOW); | 
|  | 786 | ASSERT_TRUE(handle != nullptr) << dlerror(); | 
|  | 787 | dlclose(handle); | 
|  | 788 |  | 
| Dimitry Ivanov | d3e7d08 | 2017-03-27 14:11:02 -0700 | [diff] [blame] | 789 | // dlopen for a public library using an absolute path should work | 
|  | 790 | // 1. For isolated namespaces | 
| Dmitriy Ivanov | 42d5fcb | 2015-10-29 17:01:24 -0700 | [diff] [blame] | 791 | android_dlextinfo extinfo; | 
|  | 792 | extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE; | 
| Dimitry Ivanov | d3e7d08 | 2017-03-27 14:11:02 -0700 | [diff] [blame] | 793 | extinfo.library_namespace = ns2; | 
|  | 794 | handle = android_dlopen_ext(lib_public_path.c_str(), RTLD_NOW, &extinfo); | 
|  | 795 | ASSERT_TRUE(handle != nullptr) << dlerror(); | 
|  | 796 | ASSERT_TRUE(handle == handle_public); | 
|  | 797 |  | 
|  | 798 | dlclose(handle); | 
|  | 799 |  | 
|  | 800 | // 1.1 even if it wasn't loaded before | 
|  | 801 | dlclose(handle_public); | 
|  | 802 |  | 
|  | 803 | handle_public = dlopen(lib_public_path.c_str(), RTLD_NOW | RTLD_NOLOAD); | 
|  | 804 | ASSERT_TRUE(handle_public == nullptr); | 
|  | 805 | ASSERT_EQ(std::string("dlopen failed: library \"") + lib_public_path + | 
|  | 806 | "\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror()); | 
|  | 807 |  | 
|  | 808 | handle = android_dlopen_ext(lib_public_path.c_str(), RTLD_NOW, &extinfo); | 
|  | 809 | ASSERT_TRUE(handle != nullptr) << dlerror(); | 
|  | 810 |  | 
|  | 811 | handle_public = dlopen(lib_public_path.c_str(), RTLD_NOW); | 
|  | 812 | ASSERT_TRUE(handle == handle_public); | 
|  | 813 |  | 
|  | 814 | dlclose(handle); | 
|  | 815 |  | 
|  | 816 | // 2. And for regular namespaces (make sure it does not load second copy of the library) | 
|  | 817 | extinfo.library_namespace = ns1; | 
|  | 818 | handle = android_dlopen_ext(lib_public_path.c_str(), RTLD_NOW, &extinfo); | 
|  | 819 | ASSERT_TRUE(handle != nullptr) << dlerror(); | 
|  | 820 | ASSERT_TRUE(handle == handle_public); | 
|  | 821 |  | 
|  | 822 | dlclose(handle); | 
|  | 823 |  | 
|  | 824 | // 2.1 Unless it was not loaded before - in which case it will load a duplicate. | 
|  | 825 | // TODO(dimitry): This is broken. Maybe we need to deprecate non-isolated namespaces? | 
|  | 826 | dlclose(handle_public); | 
|  | 827 |  | 
|  | 828 | handle_public = dlopen(lib_public_path.c_str(), RTLD_NOW | RTLD_NOLOAD); | 
|  | 829 | ASSERT_TRUE(handle_public == nullptr); | 
|  | 830 | ASSERT_EQ(std::string("dlopen failed: library \"") + lib_public_path + | 
|  | 831 | "\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror()); | 
|  | 832 |  | 
|  | 833 | handle = android_dlopen_ext(lib_public_path.c_str(), RTLD_NOW, &extinfo); | 
|  | 834 | ASSERT_TRUE(handle != nullptr) << dlerror(); | 
|  | 835 |  | 
|  | 836 | handle_public = dlopen(lib_public_path.c_str(), RTLD_NOW); | 
|  | 837 |  | 
|  | 838 | ASSERT_TRUE(handle != handle_public); | 
|  | 839 |  | 
|  | 840 | dlclose(handle); | 
|  | 841 |  | 
| Dmitriy Ivanov | 42d5fcb | 2015-10-29 17:01:24 -0700 | [diff] [blame] | 842 | extinfo.library_namespace = ns1; | 
|  | 843 |  | 
|  | 844 | void* handle1 = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo); | 
|  | 845 | ASSERT_TRUE(handle1 != nullptr) << dlerror(); | 
|  | 846 |  | 
|  | 847 | extinfo.library_namespace = ns2; | 
|  | 848 | void* handle2 = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo); | 
|  | 849 | ASSERT_TRUE(handle2 != nullptr) << dlerror(); | 
|  | 850 |  | 
|  | 851 | ASSERT_TRUE(handle1 != handle2); | 
|  | 852 |  | 
|  | 853 | typedef const char* (*fn_t)(); | 
|  | 854 |  | 
|  | 855 | fn_t ns_get_local_string1 = reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_local_string")); | 
|  | 856 | ASSERT_TRUE(ns_get_local_string1 != nullptr) << dlerror(); | 
|  | 857 | fn_t ns_get_local_string2 = reinterpret_cast<fn_t>(dlsym(handle2, "ns_get_local_string")); | 
|  | 858 | ASSERT_TRUE(ns_get_local_string2 != nullptr) << dlerror(); | 
|  | 859 |  | 
|  | 860 | EXPECT_STREQ("This string is local to root library", ns_get_local_string1()); | 
|  | 861 | EXPECT_STREQ("This string is local to root library", ns_get_local_string2()); | 
|  | 862 |  | 
|  | 863 | ASSERT_TRUE(ns_get_local_string1() != ns_get_local_string2()); | 
|  | 864 |  | 
|  | 865 | fn_t ns_get_private_extern_string1 = | 
|  | 866 | reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_private_extern_string")); | 
|  | 867 | ASSERT_TRUE(ns_get_private_extern_string1 != nullptr) << dlerror(); | 
|  | 868 | fn_t ns_get_private_extern_string2 = | 
|  | 869 | reinterpret_cast<fn_t>(dlsym(handle2, "ns_get_private_extern_string")); | 
|  | 870 | ASSERT_TRUE(ns_get_private_extern_string2 != nullptr) << dlerror(); | 
|  | 871 |  | 
|  | 872 | EXPECT_STREQ("This string is from private namespace", ns_get_private_extern_string1()); | 
|  | 873 | EXPECT_STREQ("This string is from private namespace", ns_get_private_extern_string2()); | 
|  | 874 |  | 
|  | 875 | ASSERT_TRUE(ns_get_private_extern_string1() != ns_get_private_extern_string2()); | 
|  | 876 |  | 
|  | 877 | fn_t ns_get_public_extern_string1 = | 
|  | 878 | reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_public_extern_string")); | 
|  | 879 | ASSERT_TRUE(ns_get_public_extern_string1 != nullptr) << dlerror(); | 
|  | 880 | fn_t ns_get_public_extern_string2 = | 
|  | 881 | reinterpret_cast<fn_t>(dlsym(handle2, "ns_get_public_extern_string")); | 
|  | 882 | ASSERT_TRUE(ns_get_public_extern_string2 != nullptr) << dlerror(); | 
|  | 883 |  | 
|  | 884 | EXPECT_STREQ("This string is from public namespace", ns_get_public_extern_string1()); | 
|  | 885 | ASSERT_TRUE(ns_get_public_extern_string1() == ns_get_public_extern_string2()); | 
|  | 886 |  | 
|  | 887 | // and now check that dlopen() does the right thing in terms of preserving namespace | 
|  | 888 | fn_t ns_get_dlopened_string1 = reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_dlopened_string")); | 
|  | 889 | ASSERT_TRUE(ns_get_dlopened_string1 != nullptr) << dlerror(); | 
|  | 890 | fn_t ns_get_dlopened_string2 = reinterpret_cast<fn_t>(dlsym(handle2, "ns_get_dlopened_string")); | 
|  | 891 | ASSERT_TRUE(ns_get_dlopened_string2 != nullptr) << dlerror(); | 
|  | 892 |  | 
|  | 893 | EXPECT_STREQ("This string is from private namespace (dlopened library)", ns_get_dlopened_string1()); | 
|  | 894 | EXPECT_STREQ("This string is from private namespace (dlopened library)", ns_get_dlopened_string2()); | 
|  | 895 |  | 
|  | 896 | ASSERT_TRUE(ns_get_dlopened_string1() != ns_get_dlopened_string2()); | 
|  | 897 |  | 
| Dimitry Ivanov | 7a34b9d | 2017-02-03 14:07:34 -0800 | [diff] [blame] | 898 | // Check that symbols from non-shared libraries a shared library depends on are not visible | 
|  | 899 | // from original namespace. | 
|  | 900 |  | 
|  | 901 | fn_t ns_get_internal_extern_string = | 
|  | 902 | reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_internal_extern_string")); | 
|  | 903 | ASSERT_TRUE(ns_get_internal_extern_string != nullptr) << dlerror(); | 
|  | 904 | ASSERT_TRUE(ns_get_internal_extern_string() == nullptr) << | 
|  | 905 | "ns_get_internal_extern_string() expected to return null but returns \"" << | 
|  | 906 | ns_get_internal_extern_string() << "\""; | 
|  | 907 |  | 
| Dmitriy Ivanov | 42d5fcb | 2015-10-29 17:01:24 -0700 | [diff] [blame] | 908 | dlclose(handle1); | 
|  | 909 |  | 
|  | 910 | // Check if handle2 is still alive (and well) | 
|  | 911 | ASSERT_STREQ("This string is local to root library", ns_get_local_string2()); | 
|  | 912 | ASSERT_STREQ("This string is from private namespace", ns_get_private_extern_string2()); | 
|  | 913 | ASSERT_STREQ("This string is from public namespace", ns_get_public_extern_string2()); | 
|  | 914 | ASSERT_STREQ("This string is from private namespace (dlopened library)", ns_get_dlopened_string2()); | 
|  | 915 |  | 
|  | 916 | dlclose(handle2); | 
|  | 917 | } | 
|  | 918 |  | 
| Dimitry Ivanov | bf34ba3 | 2017-04-21 13:12:05 -0700 | [diff] [blame] | 919 | TEST(dlext, dlopen_ext_use_o_tmpfile_fd) { | 
| Elliott Hughes | 8d8138a | 2024-03-12 22:37:13 +0000 | [diff] [blame] | 920 | const std::string lib_path = GetTestLibRoot() + "/libtest_simple.so"; | 
| Dimitry Ivanov | bf34ba3 | 2017-04-21 13:12:05 -0700 | [diff] [blame] | 921 |  | 
|  | 922 | int tmpfd = TEMP_FAILURE_RETRY( | 
| Elliott Hughes | 8d8138a | 2024-03-12 22:37:13 +0000 | [diff] [blame] | 923 | open(GetTestLibRoot().c_str(), O_TMPFILE | O_CLOEXEC | O_RDWR | O_EXCL, 0)); | 
| Dimitry Ivanov | bf34ba3 | 2017-04-21 13:12:05 -0700 | [diff] [blame] | 924 |  | 
|  | 925 | // Ignore kernels without O_TMPFILE flag support | 
|  | 926 | if (tmpfd == -1 && (errno == EISDIR || errno == EINVAL || errno == EOPNOTSUPP)) { | 
|  | 927 | return; | 
|  | 928 | } | 
|  | 929 |  | 
|  | 930 | ASSERT_TRUE(tmpfd != -1) << strerror(errno); | 
|  | 931 |  | 
|  | 932 | android_namespace_t* ns = | 
|  | 933 | android_create_namespace("testing-o_tmpfile", | 
|  | 934 | nullptr, | 
| Elliott Hughes | 8d8138a | 2024-03-12 22:37:13 +0000 | [diff] [blame] | 935 | GetTestLibRoot().c_str(), | 
| Dimitry Ivanov | bf34ba3 | 2017-04-21 13:12:05 -0700 | [diff] [blame] | 936 | ANDROID_NAMESPACE_TYPE_ISOLATED, | 
|  | 937 | nullptr, | 
|  | 938 | nullptr); | 
|  | 939 |  | 
|  | 940 | ASSERT_DL_NOTNULL(ns); | 
|  | 941 |  | 
|  | 942 | ASSERT_TRUE(android_link_namespaces(ns, nullptr, g_core_shared_libs.c_str())) << dlerror(); | 
|  | 943 |  | 
|  | 944 | std::string content; | 
|  | 945 | ASSERT_TRUE(android::base::ReadFileToString(lib_path, &content)) << strerror(errno); | 
|  | 946 | ASSERT_TRUE(android::base::WriteStringToFd(content, tmpfd)) << strerror(errno); | 
|  | 947 |  | 
|  | 948 | android_dlextinfo extinfo; | 
|  | 949 | extinfo.flags = ANDROID_DLEXT_USE_LIBRARY_FD | ANDROID_DLEXT_USE_NAMESPACE; | 
|  | 950 | extinfo.library_fd = tmpfd; | 
|  | 951 | extinfo.library_namespace = ns; | 
|  | 952 |  | 
|  | 953 | void* handle = android_dlopen_ext("foobar", RTLD_NOW, &extinfo); | 
|  | 954 |  | 
|  | 955 | ASSERT_DL_NOTNULL(handle); | 
|  | 956 |  | 
|  | 957 | uint32_t* taxicab_number = reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_testlib_taxicab_number")); | 
|  | 958 | ASSERT_DL_NOTNULL(taxicab_number); | 
|  | 959 | EXPECT_EQ(1729U, *taxicab_number); | 
|  | 960 | dlclose(handle); | 
|  | 961 | } | 
|  | 962 |  | 
|  | 963 | TEST(dlext, dlopen_ext_use_memfd) { | 
| Elliott Hughes | 8d8138a | 2024-03-12 22:37:13 +0000 | [diff] [blame] | 964 | const std::string lib_path = GetTestLibRoot() + "/libtest_simple.so"; | 
| Dimitry Ivanov | bf34ba3 | 2017-04-21 13:12:05 -0700 | [diff] [blame] | 965 |  | 
|  | 966 | // create memfd | 
| Elliott Hughes | 3d24d2b | 2019-08-05 13:53:01 -0700 | [diff] [blame] | 967 | int memfd = memfd_create("foobar", MFD_CLOEXEC); | 
| Elliott Hughes | 4ae4be9 | 2023-09-22 17:15:25 -0700 | [diff] [blame] | 968 | if (memfd == -1 && errno == ENOSYS) GTEST_SKIP() << "no memfd_create() in this kernel"; | 
| Dimitry Ivanov | bf34ba3 | 2017-04-21 13:12:05 -0700 | [diff] [blame] | 969 | ASSERT_TRUE(memfd != -1) << strerror(errno); | 
|  | 970 |  | 
|  | 971 | // Check st.f_type is TMPFS_MAGIC for memfd | 
|  | 972 | struct statfs st; | 
|  | 973 | ASSERT_TRUE(TEMP_FAILURE_RETRY(fstatfs(memfd, &st)) == 0) << strerror(errno); | 
|  | 974 | ASSERT_EQ(static_cast<decltype(st.f_type)>(TMPFS_MAGIC), st.f_type); | 
|  | 975 |  | 
|  | 976 | android_namespace_t* ns = | 
|  | 977 | android_create_namespace("testing-memfd", | 
|  | 978 | nullptr, | 
| Elliott Hughes | 8d8138a | 2024-03-12 22:37:13 +0000 | [diff] [blame] | 979 | GetTestLibRoot().c_str(), | 
| Dimitry Ivanov | bf34ba3 | 2017-04-21 13:12:05 -0700 | [diff] [blame] | 980 | ANDROID_NAMESPACE_TYPE_ISOLATED, | 
|  | 981 | nullptr, | 
|  | 982 | nullptr); | 
|  | 983 |  | 
|  | 984 | ASSERT_DL_NOTNULL(ns); | 
|  | 985 |  | 
|  | 986 | ASSERT_TRUE(android_link_namespaces(ns, nullptr, g_core_shared_libs.c_str())) << dlerror(); | 
|  | 987 |  | 
|  | 988 | // read file into memfd backed one. | 
|  | 989 | std::string content; | 
|  | 990 | ASSERT_TRUE(android::base::ReadFileToString(lib_path, &content)) << strerror(errno); | 
|  | 991 | ASSERT_TRUE(android::base::WriteStringToFd(content, memfd)) << strerror(errno); | 
|  | 992 |  | 
|  | 993 | android_dlextinfo extinfo; | 
|  | 994 | extinfo.flags = ANDROID_DLEXT_USE_LIBRARY_FD | ANDROID_DLEXT_USE_NAMESPACE; | 
|  | 995 | extinfo.library_fd = memfd; | 
|  | 996 | extinfo.library_namespace = ns; | 
|  | 997 |  | 
|  | 998 | void* handle = android_dlopen_ext("foobar", RTLD_NOW, &extinfo); | 
|  | 999 |  | 
|  | 1000 | ASSERT_DL_NOTNULL(handle); | 
|  | 1001 |  | 
|  | 1002 | uint32_t* taxicab_number = reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_testlib_taxicab_number")); | 
|  | 1003 | ASSERT_DL_NOTNULL(taxicab_number); | 
|  | 1004 | EXPECT_EQ(1729U, *taxicab_number); | 
|  | 1005 | dlclose(handle); | 
|  | 1006 | } | 
|  | 1007 |  | 
| Dimitry Ivanov | 7a34b9d | 2017-02-03 14:07:34 -0800 | [diff] [blame] | 1008 | TEST(dlext, ns_symbol_visibilty_one_namespace) { | 
|  | 1009 | static const char* root_lib = "libnstest_root.so"; | 
|  | 1010 | ASSERT_TRUE(android_init_anonymous_namespace(g_core_shared_libs.c_str(), nullptr)); | 
|  | 1011 |  | 
| Elliott Hughes | 8d8138a | 2024-03-12 22:37:13 +0000 | [diff] [blame] | 1012 | const std::string ns_search_path = GetTestLibRoot() + "/public_namespace_libs:" + | 
|  | 1013 | GetTestLibRoot() + "/private_namespace_libs"; | 
| Dimitry Ivanov | 7a34b9d | 2017-02-03 14:07:34 -0800 | [diff] [blame] | 1014 |  | 
|  | 1015 | android_namespace_t* ns = | 
|  | 1016 | android_create_namespace("one", | 
|  | 1017 | nullptr, | 
|  | 1018 | ns_search_path.c_str(), | 
|  | 1019 | ANDROID_NAMESPACE_TYPE_ISOLATED, | 
|  | 1020 | nullptr, | 
|  | 1021 | nullptr); | 
|  | 1022 |  | 
|  | 1023 | ASSERT_TRUE(android_link_namespaces(ns, nullptr, g_core_shared_libs.c_str())) << dlerror(); | 
|  | 1024 |  | 
|  | 1025 | android_dlextinfo extinfo; | 
|  | 1026 | extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE; | 
|  | 1027 | extinfo.library_namespace = ns; | 
|  | 1028 |  | 
|  | 1029 | void* handle = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo); | 
|  | 1030 | ASSERT_TRUE(handle != nullptr) << dlerror(); | 
|  | 1031 |  | 
|  | 1032 | typedef const char* (*fn_t)(); | 
|  | 1033 |  | 
|  | 1034 | // Check that relocation worked correctly | 
|  | 1035 | fn_t ns_get_internal_extern_string = | 
|  | 1036 | reinterpret_cast<fn_t>(dlsym(handle, "ns_get_internal_extern_string")); | 
|  | 1037 | ASSERT_TRUE(ns_get_internal_extern_string != nullptr) << dlerror(); | 
|  | 1038 | ASSERT_STREQ("This string is from a library a shared library depends on", ns_get_internal_extern_string()); | 
|  | 1039 |  | 
|  | 1040 | fn_t internal_extern_string_fn = | 
|  | 1041 | reinterpret_cast<fn_t>(dlsym(handle, "internal_extern_string")); | 
|  | 1042 | ASSERT_TRUE(internal_extern_string_fn != nullptr) << dlerror(); | 
|  | 1043 | ASSERT_STREQ("This string is from a library a shared library depends on", internal_extern_string_fn()); | 
|  | 1044 | } | 
|  | 1045 |  | 
|  | 1046 | TEST(dlext, ns_symbol_visibilty_between_namespaces) { | 
|  | 1047 | static const char* root_lib = "libnstest_root.so"; | 
|  | 1048 | ASSERT_TRUE(android_init_anonymous_namespace(g_core_shared_libs.c_str(), nullptr)); | 
|  | 1049 |  | 
| Elliott Hughes | 8d8138a | 2024-03-12 22:37:13 +0000 | [diff] [blame] | 1050 | const std::string public_ns_search_path =  GetTestLibRoot() + "/public_namespace_libs"; | 
|  | 1051 | const std::string private_ns_search_path = GetTestLibRoot() + "/private_namespace_libs"; | 
| Dimitry Ivanov | 7a34b9d | 2017-02-03 14:07:34 -0800 | [diff] [blame] | 1052 |  | 
|  | 1053 | android_namespace_t* ns_public = | 
|  | 1054 | android_create_namespace("public", | 
|  | 1055 | nullptr, | 
|  | 1056 | public_ns_search_path.c_str(), | 
|  | 1057 | ANDROID_NAMESPACE_TYPE_ISOLATED, | 
|  | 1058 | nullptr, | 
|  | 1059 | nullptr); | 
|  | 1060 |  | 
|  | 1061 | ASSERT_TRUE(android_link_namespaces(ns_public, nullptr, g_core_shared_libs.c_str())) << dlerror(); | 
|  | 1062 |  | 
|  | 1063 | android_namespace_t* ns_private = | 
|  | 1064 | android_create_namespace("private", | 
|  | 1065 | nullptr, | 
|  | 1066 | private_ns_search_path.c_str(), | 
|  | 1067 | ANDROID_NAMESPACE_TYPE_ISOLATED, | 
|  | 1068 | nullptr, | 
|  | 1069 | nullptr); | 
|  | 1070 |  | 
|  | 1071 | ASSERT_TRUE(android_link_namespaces(ns_private, ns_public, g_public_lib)) << dlerror(); | 
|  | 1072 | ASSERT_TRUE(android_link_namespaces(ns_private, nullptr, g_core_shared_libs.c_str())) << dlerror(); | 
|  | 1073 |  | 
|  | 1074 | android_dlextinfo extinfo; | 
|  | 1075 | extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE; | 
|  | 1076 | extinfo.library_namespace = ns_private; | 
|  | 1077 |  | 
|  | 1078 | void* handle = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo); | 
|  | 1079 | ASSERT_TRUE(handle != nullptr) << dlerror(); | 
|  | 1080 |  | 
|  | 1081 | typedef const char* (*fn_t)(); | 
|  | 1082 |  | 
|  | 1083 | // Check that relocation worked correctly | 
|  | 1084 | fn_t ns_get_internal_extern_string = | 
|  | 1085 | reinterpret_cast<fn_t>(dlsym(handle, "ns_get_internal_extern_string")); | 
|  | 1086 | ASSERT_TRUE(ns_get_internal_extern_string != nullptr) << dlerror(); | 
|  | 1087 | ASSERT_TRUE(ns_get_internal_extern_string() == nullptr) << | 
|  | 1088 | "ns_get_internal_extern_string() expected to return null but returns \"" << | 
|  | 1089 | ns_get_internal_extern_string() << "\""; | 
|  | 1090 |  | 
|  | 1091 | fn_t internal_extern_string_fn = | 
|  | 1092 | reinterpret_cast<fn_t>(dlsym(handle, "internal_extern_string")); | 
|  | 1093 | ASSERT_TRUE(internal_extern_string_fn == nullptr); | 
|  | 1094 | ASSERT_STREQ("undefined symbol: internal_extern_string", dlerror()); | 
|  | 1095 | } | 
|  | 1096 |  | 
|  | 1097 | TEST(dlext, ns_unload_between_namespaces) { | 
|  | 1098 | static const char* root_lib = "libnstest_root.so"; | 
|  | 1099 | ASSERT_TRUE(android_init_anonymous_namespace(g_core_shared_libs.c_str(), nullptr)); | 
|  | 1100 |  | 
| Elliott Hughes | 8d8138a | 2024-03-12 22:37:13 +0000 | [diff] [blame] | 1101 | const std::string public_ns_search_path =  GetTestLibRoot() + "/public_namespace_libs"; | 
|  | 1102 | const std::string private_ns_search_path = GetTestLibRoot() + "/private_namespace_libs"; | 
| Dimitry Ivanov | 7a34b9d | 2017-02-03 14:07:34 -0800 | [diff] [blame] | 1103 |  | 
|  | 1104 | android_namespace_t* ns_public = | 
|  | 1105 | android_create_namespace("public", | 
|  | 1106 | nullptr, | 
|  | 1107 | public_ns_search_path.c_str(), | 
|  | 1108 | ANDROID_NAMESPACE_TYPE_ISOLATED, | 
|  | 1109 | nullptr, | 
|  | 1110 | nullptr); | 
|  | 1111 |  | 
|  | 1112 | ASSERT_TRUE(android_link_namespaces(ns_public, nullptr, g_core_shared_libs.c_str())) << dlerror(); | 
|  | 1113 |  | 
|  | 1114 | android_namespace_t* ns_private = | 
|  | 1115 | android_create_namespace("private", | 
|  | 1116 | nullptr, | 
|  | 1117 | private_ns_search_path.c_str(), | 
|  | 1118 | ANDROID_NAMESPACE_TYPE_ISOLATED, | 
|  | 1119 | nullptr, | 
|  | 1120 | nullptr); | 
|  | 1121 |  | 
|  | 1122 | ASSERT_TRUE(android_link_namespaces(ns_private, ns_public, g_public_lib)) << dlerror(); | 
|  | 1123 | ASSERT_TRUE(android_link_namespaces(ns_private, nullptr, g_core_shared_libs.c_str())) << dlerror(); | 
|  | 1124 |  | 
|  | 1125 | android_dlextinfo extinfo; | 
|  | 1126 | extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE; | 
|  | 1127 | extinfo.library_namespace = ns_private; | 
|  | 1128 |  | 
|  | 1129 | void* handle = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo); | 
|  | 1130 | ASSERT_TRUE(handle != nullptr) << dlerror(); | 
|  | 1131 |  | 
|  | 1132 | dlclose(handle); | 
|  | 1133 | // Check that root_lib was unloaded | 
|  | 1134 | handle = android_dlopen_ext(root_lib, RTLD_NOW | RTLD_NOLOAD, &extinfo); | 
|  | 1135 | ASSERT_TRUE(handle == nullptr); | 
|  | 1136 | ASSERT_EQ(std::string("dlopen failed: library \"") + root_lib + | 
|  | 1137 | "\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror()); | 
|  | 1138 |  | 
|  | 1139 | // Check that shared library was unloaded in public ns | 
|  | 1140 | extinfo.library_namespace = ns_public; | 
|  | 1141 | handle = android_dlopen_ext(g_public_lib, RTLD_NOW | RTLD_NOLOAD, &extinfo); | 
|  | 1142 | ASSERT_TRUE(handle == nullptr); | 
|  | 1143 | ASSERT_EQ(std::string("dlopen failed: library \"") + g_public_lib + | 
|  | 1144 | "\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror()); | 
|  | 1145 | } | 
|  | 1146 |  | 
| dimitry | 965d06d | 2017-11-28 16:03:07 +0100 | [diff] [blame] | 1147 | TEST(dlext, ns_unload_between_namespaces_missing_symbol_direct) { | 
|  | 1148 | ASSERT_TRUE(android_init_anonymous_namespace(g_core_shared_libs.c_str(), nullptr)); | 
|  | 1149 |  | 
| Elliott Hughes | 8d8138a | 2024-03-12 22:37:13 +0000 | [diff] [blame] | 1150 | const std::string public_ns_search_path =  GetTestLibRoot() + "/public_namespace_libs"; | 
|  | 1151 | const std::string private_ns_search_path = GetTestLibRoot() + "/private_namespace_libs"; | 
| dimitry | 965d06d | 2017-11-28 16:03:07 +0100 | [diff] [blame] | 1152 |  | 
|  | 1153 | android_namespace_t* ns_public = | 
|  | 1154 | android_create_namespace("public", | 
|  | 1155 | nullptr, | 
|  | 1156 | public_ns_search_path.c_str(), | 
|  | 1157 | ANDROID_NAMESPACE_TYPE_ISOLATED, | 
|  | 1158 | nullptr, | 
|  | 1159 | nullptr); | 
|  | 1160 |  | 
|  | 1161 | ASSERT_TRUE(android_link_namespaces(ns_public, nullptr, g_core_shared_libs.c_str())) << dlerror(); | 
|  | 1162 |  | 
|  | 1163 | android_namespace_t* ns_private = | 
|  | 1164 | android_create_namespace("private", | 
|  | 1165 | nullptr, | 
|  | 1166 | private_ns_search_path.c_str(), | 
|  | 1167 | ANDROID_NAMESPACE_TYPE_ISOLATED, | 
|  | 1168 | nullptr, | 
|  | 1169 | nullptr); | 
|  | 1170 |  | 
|  | 1171 | ASSERT_TRUE(android_link_namespaces(ns_private, ns_public, "libtest_missing_symbol.so")) << dlerror(); | 
|  | 1172 | ASSERT_TRUE(android_link_namespaces(ns_private, nullptr, g_core_shared_libs.c_str())) << dlerror(); | 
|  | 1173 |  | 
|  | 1174 | android_dlextinfo extinfo; | 
|  | 1175 | extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE; | 
|  | 1176 | extinfo.library_namespace = ns_private; | 
|  | 1177 |  | 
|  | 1178 | void* handle = android_dlopen_ext((public_ns_search_path + "/libtest_missing_symbol.so").c_str(), | 
|  | 1179 | RTLD_NOW, | 
|  | 1180 | &extinfo); | 
|  | 1181 | ASSERT_TRUE(handle == nullptr); | 
|  | 1182 | ASSERT_EQ(std::string("dlopen failed: cannot locate symbol \"dlopen_testlib_missing_symbol\" referenced by \"") + | 
|  | 1183 | public_ns_search_path + "/libtest_missing_symbol.so\"...", | 
|  | 1184 | dlerror()); | 
|  | 1185 | } | 
|  | 1186 |  | 
|  | 1187 | TEST(dlext, ns_unload_between_namespaces_missing_symbol_indirect) { | 
|  | 1188 | ASSERT_TRUE(android_init_anonymous_namespace(g_core_shared_libs.c_str(), nullptr)); | 
|  | 1189 |  | 
| Elliott Hughes | 8d8138a | 2024-03-12 22:37:13 +0000 | [diff] [blame] | 1190 | const std::string public_ns_search_path =  GetTestLibRoot() + "/public_namespace_libs"; | 
|  | 1191 | const std::string private_ns_search_path = GetTestLibRoot() + "/private_namespace_libs"; | 
| dimitry | 965d06d | 2017-11-28 16:03:07 +0100 | [diff] [blame] | 1192 |  | 
|  | 1193 | android_namespace_t* ns_public = | 
|  | 1194 | android_create_namespace("public", | 
|  | 1195 | nullptr, | 
|  | 1196 | public_ns_search_path.c_str(), | 
|  | 1197 | ANDROID_NAMESPACE_TYPE_ISOLATED, | 
|  | 1198 | nullptr, | 
|  | 1199 | nullptr); | 
|  | 1200 |  | 
|  | 1201 | ASSERT_TRUE(android_link_namespaces(ns_public, nullptr, g_core_shared_libs.c_str())) << dlerror(); | 
|  | 1202 |  | 
|  | 1203 | android_namespace_t* ns_private = | 
|  | 1204 | android_create_namespace("private", | 
|  | 1205 | nullptr, | 
|  | 1206 | private_ns_search_path.c_str(), | 
|  | 1207 | ANDROID_NAMESPACE_TYPE_ISOLATED, | 
|  | 1208 | nullptr, | 
|  | 1209 | nullptr); | 
|  | 1210 |  | 
|  | 1211 | ASSERT_TRUE(android_link_namespaces(ns_private, | 
|  | 1212 | ns_public, | 
|  | 1213 | "libnstest_public.so:libtest_missing_symbol_child_public.so") | 
|  | 1214 | ) << dlerror(); | 
|  | 1215 | ASSERT_TRUE(android_link_namespaces(ns_private, nullptr, g_core_shared_libs.c_str())) << dlerror(); | 
|  | 1216 |  | 
|  | 1217 | android_dlextinfo extinfo; | 
|  | 1218 | extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE; | 
|  | 1219 | extinfo.library_namespace = ns_private; | 
|  | 1220 |  | 
|  | 1221 | void* handle = android_dlopen_ext("libtest_missing_symbol_root.so", RTLD_NOW, &extinfo); | 
|  | 1222 | ASSERT_TRUE(handle == nullptr); | 
|  | 1223 | ASSERT_EQ(std::string("dlopen failed: cannot locate symbol \"dlopen_testlib_missing_symbol\" referenced by \"") + | 
|  | 1224 | private_ns_search_path + "/libtest_missing_symbol_root.so\"...", | 
|  | 1225 | dlerror()); | 
|  | 1226 | } | 
|  | 1227 |  | 
| Ryan Prichard | aff9a34 | 2020-08-03 15:29:12 -0700 | [diff] [blame] | 1228 | TEST(dlext, ns_exempt_list_enabled) { | 
| Dimitry Ivanov | 1862314 | 2017-02-21 13:41:08 -0800 | [diff] [blame] | 1229 | ASSERT_TRUE(android_init_anonymous_namespace(g_core_shared_libs.c_str(), nullptr)); | 
|  | 1230 |  | 
| Elliott Hughes | 8d8138a | 2024-03-12 22:37:13 +0000 | [diff] [blame] | 1231 | const std::string ns_search_path = GetTestLibRoot() + "/private_namespace_libs"; | 
| Dimitry Ivanov | 1862314 | 2017-02-21 13:41:08 -0800 | [diff] [blame] | 1232 |  | 
|  | 1233 | android_namespace_t* ns = | 
|  | 1234 | android_create_namespace("namespace", | 
|  | 1235 | nullptr, | 
|  | 1236 | ns_search_path.c_str(), | 
| Ryan Prichard | aff9a34 | 2020-08-03 15:29:12 -0700 | [diff] [blame] | 1237 | ANDROID_NAMESPACE_TYPE_ISOLATED | ANDROID_NAMESPACE_TYPE_EXEMPT_LIST_ENABLED, | 
| Dimitry Ivanov | 1862314 | 2017-02-21 13:41:08 -0800 | [diff] [blame] | 1238 | nullptr, | 
|  | 1239 | nullptr); | 
|  | 1240 |  | 
|  | 1241 | ASSERT_TRUE(android_link_namespaces(ns, nullptr, g_core_shared_libs.c_str())) << dlerror(); | 
|  | 1242 |  | 
|  | 1243 | android_dlextinfo extinfo; | 
|  | 1244 | extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE; | 
|  | 1245 | extinfo.library_namespace = ns; | 
|  | 1246 |  | 
| Ryan Prichard | aff9a34 | 2020-08-03 15:29:12 -0700 | [diff] [blame] | 1247 | // An app targeting M can open libnativehelper.so because it's on the exempt-list. | 
| Elliott Hughes | 95c6cd7 | 2019-12-20 13:26:14 -0800 | [diff] [blame] | 1248 | android_set_application_target_sdk_version(23); | 
| Dimitry Ivanov | 1862314 | 2017-02-21 13:41:08 -0800 | [diff] [blame] | 1249 | void* handle = android_dlopen_ext("libnativehelper.so", RTLD_NOW, &extinfo); | 
|  | 1250 | ASSERT_TRUE(handle != nullptr) << dlerror(); | 
|  | 1251 |  | 
| Ryan Prichard | aff9a34 | 2020-08-03 15:29:12 -0700 | [diff] [blame] | 1252 | // Check that loader did not load another copy of libdl.so while loading exempted library. | 
| Dimitry Ivanov | 35c8e3b | 2017-02-27 12:17:47 -0800 | [diff] [blame] | 1253 | void* dlsym_ptr = dlsym(handle, "dlsym"); | 
|  | 1254 | ASSERT_TRUE(dlsym_ptr != nullptr) << dlerror(); | 
|  | 1255 | ASSERT_EQ(&dlsym, dlsym_ptr); | 
|  | 1256 |  | 
| Dimitry Ivanov | 1862314 | 2017-02-21 13:41:08 -0800 | [diff] [blame] | 1257 | dlclose(handle); | 
|  | 1258 |  | 
| Ryan Prichard | aff9a34 | 2020-08-03 15:29:12 -0700 | [diff] [blame] | 1259 | // An app targeting N no longer has the exempt-list. | 
| Elliott Hughes | 95c6cd7 | 2019-12-20 13:26:14 -0800 | [diff] [blame] | 1260 | android_set_application_target_sdk_version(24); | 
| Dimitry Ivanov | 1862314 | 2017-02-21 13:41:08 -0800 | [diff] [blame] | 1261 | handle = android_dlopen_ext("libnativehelper.so", RTLD_NOW, &extinfo); | 
|  | 1262 | ASSERT_TRUE(handle == nullptr); | 
|  | 1263 | ASSERT_STREQ("dlopen failed: library \"libnativehelper.so\" not found", dlerror()); | 
|  | 1264 | } | 
|  | 1265 |  | 
| Ryan Prichard | aff9a34 | 2020-08-03 15:29:12 -0700 | [diff] [blame] | 1266 | TEST(dlext, ns_exempt_list_disabled_by_default) { | 
| Jiyong Park | 37b91af | 2017-05-05 22:07:05 +0900 | [diff] [blame] | 1267 | ASSERT_TRUE(android_init_anonymous_namespace(g_core_shared_libs.c_str(), nullptr)); | 
|  | 1268 |  | 
| Elliott Hughes | 8d8138a | 2024-03-12 22:37:13 +0000 | [diff] [blame] | 1269 | const std::string ns_search_path = GetTestLibRoot() + "/private_namespace_libs"; | 
| Jiyong Park | 37b91af | 2017-05-05 22:07:05 +0900 | [diff] [blame] | 1270 |  | 
|  | 1271 | android_namespace_t* ns = | 
|  | 1272 | android_create_namespace("namespace", | 
|  | 1273 | nullptr, | 
|  | 1274 | ns_search_path.c_str(), | 
|  | 1275 | ANDROID_NAMESPACE_TYPE_ISOLATED, | 
|  | 1276 | nullptr, | 
|  | 1277 | nullptr); | 
|  | 1278 |  | 
|  | 1279 | ASSERT_TRUE(android_link_namespaces(ns, nullptr, g_core_shared_libs.c_str())) << dlerror(); | 
|  | 1280 |  | 
|  | 1281 | android_dlextinfo extinfo; | 
|  | 1282 | extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE; | 
|  | 1283 | extinfo.library_namespace = ns; | 
|  | 1284 |  | 
| Elliott Hughes | 95c6cd7 | 2019-12-20 13:26:14 -0800 | [diff] [blame] | 1285 | android_set_application_target_sdk_version(23); | 
| Jiyong Park | 37b91af | 2017-05-05 22:07:05 +0900 | [diff] [blame] | 1286 | void* handle = android_dlopen_ext("libnativehelper.so", RTLD_NOW, &extinfo); | 
|  | 1287 | ASSERT_TRUE(handle == nullptr); | 
|  | 1288 | ASSERT_STREQ("dlopen failed: library \"libnativehelper.so\" not found", dlerror()); | 
|  | 1289 | } | 
|  | 1290 |  | 
| Dimitry Ivanov | 7a34b9d | 2017-02-03 14:07:34 -0800 | [diff] [blame] | 1291 | TEST(dlext, ns_cyclic_namespaces) { | 
|  | 1292 | // Test that ns1->ns2->ns1 link does not break the loader | 
|  | 1293 | ASSERT_TRUE(android_init_anonymous_namespace(g_core_shared_libs.c_str(), nullptr)); | 
|  | 1294 | std::string shared_libs = g_core_shared_libs + ":libthatdoesnotexist.so"; | 
|  | 1295 |  | 
| Elliott Hughes | 8d8138a | 2024-03-12 22:37:13 +0000 | [diff] [blame] | 1296 | const std::string ns_search_path =  GetTestLibRoot() + "/public_namespace_libs"; | 
| Dimitry Ivanov | 7a34b9d | 2017-02-03 14:07:34 -0800 | [diff] [blame] | 1297 |  | 
|  | 1298 | android_namespace_t* ns1 = | 
|  | 1299 | android_create_namespace("ns1", | 
|  | 1300 | nullptr, | 
|  | 1301 | ns_search_path.c_str(), | 
|  | 1302 | ANDROID_NAMESPACE_TYPE_ISOLATED, | 
|  | 1303 | nullptr, | 
|  | 1304 | nullptr); | 
|  | 1305 |  | 
|  | 1306 | ASSERT_TRUE(android_link_namespaces(ns1, nullptr, g_core_shared_libs.c_str())) << dlerror(); | 
|  | 1307 |  | 
|  | 1308 | android_namespace_t* ns2 = | 
|  | 1309 | android_create_namespace("ns1", | 
|  | 1310 | nullptr, | 
|  | 1311 | ns_search_path.c_str(), | 
|  | 1312 | ANDROID_NAMESPACE_TYPE_ISOLATED, | 
|  | 1313 | nullptr, | 
|  | 1314 | nullptr); | 
|  | 1315 |  | 
|  | 1316 | ASSERT_TRUE(android_link_namespaces(ns2, nullptr, g_core_shared_libs.c_str())) << dlerror(); | 
|  | 1317 |  | 
|  | 1318 | ASSERT_TRUE(android_link_namespaces(ns2, ns1, shared_libs.c_str())) << dlerror(); | 
|  | 1319 | ASSERT_TRUE(android_link_namespaces(ns1, ns2, shared_libs.c_str())) << dlerror(); | 
|  | 1320 |  | 
|  | 1321 | android_dlextinfo extinfo; | 
|  | 1322 | extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE; | 
|  | 1323 | extinfo.library_namespace = ns1; | 
|  | 1324 |  | 
|  | 1325 | void* handle = android_dlopen_ext("libthatdoesnotexist.so", RTLD_NOW, &extinfo); | 
|  | 1326 | ASSERT_TRUE(handle == nullptr); | 
|  | 1327 | ASSERT_STREQ("dlopen failed: library \"libthatdoesnotexist.so\" not found", dlerror()); | 
|  | 1328 | } | 
|  | 1329 |  | 
| Dmitriy Ivanov | 42d5fcb | 2015-10-29 17:01:24 -0700 | [diff] [blame] | 1330 | TEST(dlext, ns_isolated) { | 
|  | 1331 | static const char* root_lib = "libnstest_root_not_isolated.so"; | 
| Dimitry Ivanov | 7a34b9d | 2017-02-03 14:07:34 -0800 | [diff] [blame] | 1332 | std::string shared_libs = g_core_shared_libs + ":" + g_public_lib; | 
| Dmitriy Ivanov | 42d5fcb | 2015-10-29 17:01:24 -0700 | [diff] [blame] | 1333 |  | 
| Elliott Hughes | 8d8138a | 2024-03-12 22:37:13 +0000 | [diff] [blame] | 1334 | const std::string lib_public_path = GetTestLibRoot() + "/public_namespace_libs/" + g_public_lib; | 
| Dimitry Ivanov | 22840aa | 2015-12-04 18:28:49 -0800 | [diff] [blame] | 1335 | void* handle_public = dlopen(lib_public_path.c_str(), RTLD_NOW); | 
| Dmitriy Ivanov | 42d5fcb | 2015-10-29 17:01:24 -0700 | [diff] [blame] | 1336 | ASSERT_TRUE(handle_public != nullptr) << dlerror(); | 
|  | 1337 |  | 
| Dmitriy Ivanov | 3cc35e2 | 2015-11-17 18:36:50 -0800 | [diff] [blame] | 1338 | android_set_application_target_sdk_version(42U); // something > 23 | 
|  | 1339 |  | 
| Dimitry Ivanov | 7a34b9d | 2017-02-03 14:07:34 -0800 | [diff] [blame] | 1340 | ASSERT_TRUE(android_init_anonymous_namespace(shared_libs.c_str(), nullptr)) << dlerror(); | 
| Dmitriy Ivanov | 42d5fcb | 2015-10-29 17:01:24 -0700 | [diff] [blame] | 1341 |  | 
| Dimitry Ivanov | 7331fe1 | 2015-12-14 14:11:17 -0800 | [diff] [blame] | 1342 | android_namespace_t* ns_not_isolated = | 
| Dimitry Ivanov | 7a34b9d | 2017-02-03 14:07:34 -0800 | [diff] [blame] | 1343 | android_create_namespace("private", | 
|  | 1344 | nullptr, | 
| Elliott Hughes | 8d8138a | 2024-03-12 22:37:13 +0000 | [diff] [blame] | 1345 | (GetTestLibRoot() + "/private_namespace_libs").c_str(), | 
| Dimitry Ivanov | 7a34b9d | 2017-02-03 14:07:34 -0800 | [diff] [blame] | 1346 | ANDROID_NAMESPACE_TYPE_REGULAR, | 
|  | 1347 | nullptr, | 
|  | 1348 | nullptr); | 
| Dmitriy Ivanov | 42d5fcb | 2015-10-29 17:01:24 -0700 | [diff] [blame] | 1349 | ASSERT_TRUE(ns_not_isolated != nullptr) << dlerror(); | 
| Dimitry Ivanov | 7a34b9d | 2017-02-03 14:07:34 -0800 | [diff] [blame] | 1350 | ASSERT_TRUE(android_link_namespaces(ns_not_isolated, nullptr, shared_libs.c_str())) << dlerror(); | 
| Dmitriy Ivanov | 42d5fcb | 2015-10-29 17:01:24 -0700 | [diff] [blame] | 1351 |  | 
| Dimitry Ivanov | 7331fe1 | 2015-12-14 14:11:17 -0800 | [diff] [blame] | 1352 | android_namespace_t* ns_isolated = | 
| Dimitry Ivanov | fc2da53 | 2016-05-12 15:20:21 -0700 | [diff] [blame] | 1353 | android_create_namespace("private_isolated1", | 
|  | 1354 | nullptr, | 
| Elliott Hughes | 8d8138a | 2024-03-12 22:37:13 +0000 | [diff] [blame] | 1355 | (GetTestLibRoot() + "/private_namespace_libs").c_str(), | 
| Dimitry Ivanov | fc2da53 | 2016-05-12 15:20:21 -0700 | [diff] [blame] | 1356 | ANDROID_NAMESPACE_TYPE_ISOLATED, | 
|  | 1357 | nullptr, | 
|  | 1358 | nullptr); | 
| Dmitriy Ivanov | 42d5fcb | 2015-10-29 17:01:24 -0700 | [diff] [blame] | 1359 | ASSERT_TRUE(ns_isolated != nullptr) << dlerror(); | 
| Dimitry Ivanov | 7a34b9d | 2017-02-03 14:07:34 -0800 | [diff] [blame] | 1360 | ASSERT_TRUE(android_link_namespaces(ns_isolated, nullptr, shared_libs.c_str())) << dlerror(); | 
| Dmitriy Ivanov | 42d5fcb | 2015-10-29 17:01:24 -0700 | [diff] [blame] | 1361 |  | 
| Dimitry Ivanov | 7331fe1 | 2015-12-14 14:11:17 -0800 | [diff] [blame] | 1362 | android_namespace_t* ns_isolated2 = | 
|  | 1363 | android_create_namespace("private_isolated2", | 
| Elliott Hughes | 8d8138a | 2024-03-12 22:37:13 +0000 | [diff] [blame] | 1364 | (GetTestLibRoot() + "/private_namespace_libs").c_str(), | 
| Dimitry Ivanov | fc2da53 | 2016-05-12 15:20:21 -0700 | [diff] [blame] | 1365 | nullptr, | 
|  | 1366 | ANDROID_NAMESPACE_TYPE_ISOLATED, | 
| Elliott Hughes | 8d8138a | 2024-03-12 22:37:13 +0000 | [diff] [blame] | 1367 | GetTestLibRoot().c_str(), | 
| Dimitry Ivanov | fc2da53 | 2016-05-12 15:20:21 -0700 | [diff] [blame] | 1368 | nullptr); | 
| Dmitriy Ivanov | 42d5fcb | 2015-10-29 17:01:24 -0700 | [diff] [blame] | 1369 | ASSERT_TRUE(ns_isolated2 != nullptr) << dlerror(); | 
| Dimitry Ivanov | 7a34b9d | 2017-02-03 14:07:34 -0800 | [diff] [blame] | 1370 | ASSERT_TRUE(android_link_namespaces(ns_isolated2, nullptr, shared_libs.c_str())) << dlerror(); | 
| Dmitriy Ivanov | 42d5fcb | 2015-10-29 17:01:24 -0700 | [diff] [blame] | 1371 |  | 
|  | 1372 | ASSERT_TRUE(dlopen(root_lib, RTLD_NOW) == nullptr); | 
|  | 1373 | ASSERT_STREQ("dlopen failed: library \"libnstest_root_not_isolated.so\" not found", dlerror()); | 
|  | 1374 |  | 
|  | 1375 | std::string lib_private_external_path = | 
| Elliott Hughes | 8d8138a | 2024-03-12 22:37:13 +0000 | [diff] [blame] | 1376 | GetTestLibRoot() + "/private_namespace_libs_external/libnstest_private_external.so"; | 
| Dmitriy Ivanov | 42d5fcb | 2015-10-29 17:01:24 -0700 | [diff] [blame] | 1377 |  | 
|  | 1378 | // Load lib_private_external_path to default namespace | 
|  | 1379 | // (it should remain invisible for the isolated namespaces after this) | 
|  | 1380 | void* handle = dlopen(lib_private_external_path.c_str(), RTLD_NOW); | 
|  | 1381 | ASSERT_TRUE(handle != nullptr) << dlerror(); | 
|  | 1382 |  | 
|  | 1383 | android_dlextinfo extinfo; | 
|  | 1384 | extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE; | 
|  | 1385 | extinfo.library_namespace = ns_not_isolated; | 
|  | 1386 |  | 
|  | 1387 | void* handle1 = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo); | 
|  | 1388 | ASSERT_TRUE(handle1 != nullptr) << dlerror(); | 
|  | 1389 |  | 
|  | 1390 | extinfo.library_namespace = ns_isolated; | 
|  | 1391 |  | 
|  | 1392 | void* handle2 = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo); | 
|  | 1393 | ASSERT_TRUE(handle2 == nullptr); | 
| Josh Gao | 1626957 | 2019-10-29 13:41:00 -0700 | [diff] [blame] | 1394 | const char* error = dlerror(); | 
|  | 1395 | ASSERT_MATCH(error, | 
|  | 1396 | R"(dlopen failed: library "libnstest_private_external.so" not found: needed by )" | 
|  | 1397 | R"(\S+libnstest_root_not_isolated.so in namespace private_isolated1)"); | 
| Dmitriy Ivanov | 42d5fcb | 2015-10-29 17:01:24 -0700 | [diff] [blame] | 1398 |  | 
|  | 1399 | // Check dlopen by absolute path | 
|  | 1400 | handle2 = android_dlopen_ext(lib_private_external_path.c_str(), RTLD_NOW, &extinfo); | 
|  | 1401 | ASSERT_TRUE(handle2 == nullptr); | 
| Dimitry Ivanov | d17a377 | 2016-03-01 13:11:28 -0800 | [diff] [blame] | 1402 | ASSERT_EQ("dlopen failed: library \"" + lib_private_external_path + "\" needed" | 
| Christopher Ferris | 6d2c0bd | 2018-08-21 18:13:10 -0700 | [diff] [blame] | 1403 | " or dlopened by \"" + android::base::GetExecutablePath() +  "\" is not accessible" | 
| Dimitry Ivanov | d17a377 | 2016-03-01 13:11:28 -0800 | [diff] [blame] | 1404 | " for the namespace \"private_isolated1\"", dlerror()); | 
| Dmitriy Ivanov | 42d5fcb | 2015-10-29 17:01:24 -0700 | [diff] [blame] | 1405 |  | 
|  | 1406 | extinfo.library_namespace = ns_isolated2; | 
|  | 1407 |  | 
| Elliott Hughes | 8d8138a | 2024-03-12 22:37:13 +0000 | [diff] [blame] | 1408 | // this should work because isolation_path for private_isolated2 includes GetTestLibRoot() | 
| Dmitriy Ivanov | 42d5fcb | 2015-10-29 17:01:24 -0700 | [diff] [blame] | 1409 | handle2 = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo); | 
| Dimitry Ivanov | 284ae35 | 2015-12-08 10:47:13 -0800 | [diff] [blame] | 1410 | ASSERT_TRUE(handle2 != nullptr) << dlerror(); | 
|  | 1411 | dlclose(handle2); | 
| Dmitriy Ivanov | 42d5fcb | 2015-10-29 17:01:24 -0700 | [diff] [blame] | 1412 |  | 
|  | 1413 | // Check dlopen by absolute path | 
|  | 1414 | handle2 = android_dlopen_ext(lib_private_external_path.c_str(), RTLD_NOW, &extinfo); | 
| Dimitry Ivanov | 284ae35 | 2015-12-08 10:47:13 -0800 | [diff] [blame] | 1415 | ASSERT_TRUE(handle2 != nullptr) << dlerror(); | 
|  | 1416 | dlclose(handle2); | 
| Dmitriy Ivanov | 42d5fcb | 2015-10-29 17:01:24 -0700 | [diff] [blame] | 1417 |  | 
|  | 1418 | typedef const char* (*fn_t)(); | 
|  | 1419 | fn_t ns_get_local_string = reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_local_string")); | 
|  | 1420 | ASSERT_TRUE(ns_get_local_string != nullptr) << dlerror(); | 
|  | 1421 |  | 
|  | 1422 | ASSERT_STREQ("This string is local to root library", ns_get_local_string()); | 
|  | 1423 |  | 
|  | 1424 | fn_t ns_get_private_extern_string = | 
|  | 1425 | reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_private_extern_string")); | 
|  | 1426 | ASSERT_TRUE(ns_get_private_extern_string != nullptr) << dlerror(); | 
|  | 1427 |  | 
|  | 1428 | ASSERT_STREQ("This string is from private namespace", ns_get_private_extern_string()); | 
|  | 1429 |  | 
|  | 1430 | fn_t ns_get_public_extern_string = | 
|  | 1431 | reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_public_extern_string")); | 
|  | 1432 | ASSERT_TRUE(ns_get_public_extern_string != nullptr) << dlerror(); | 
|  | 1433 |  | 
|  | 1434 | ASSERT_STREQ("This string is from public namespace", ns_get_public_extern_string()); | 
|  | 1435 |  | 
|  | 1436 | fn_t ns_get_dlopened_string = reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_dlopened_string")); | 
|  | 1437 | ASSERT_TRUE(ns_get_dlopened_string != nullptr) << dlerror(); | 
|  | 1438 |  | 
|  | 1439 | ASSERT_STREQ("This string is from private namespace (dlopened library)", ns_get_dlopened_string()); | 
|  | 1440 |  | 
|  | 1441 | dlclose(handle1); | 
|  | 1442 | } | 
| Dmitriy Ivanov | 1ffec1c | 2015-11-23 11:26:35 -0800 | [diff] [blame] | 1443 |  | 
| Dimitry Ivanov | 7331fe1 | 2015-12-14 14:11:17 -0800 | [diff] [blame] | 1444 | TEST(dlext, ns_shared) { | 
|  | 1445 | static const char* root_lib = "libnstest_root_not_isolated.so"; | 
|  | 1446 | static const char* root_lib_isolated = "libnstest_root.so"; | 
| Dimitry Ivanov | 7a34b9d | 2017-02-03 14:07:34 -0800 | [diff] [blame] | 1447 |  | 
|  | 1448 | std::string shared_libs = g_core_shared_libs + ":" + g_public_lib; | 
| Dimitry Ivanov | 7331fe1 | 2015-12-14 14:11:17 -0800 | [diff] [blame] | 1449 |  | 
| Jiyong Park | 917d34a | 2017-08-31 14:07:13 +0900 | [diff] [blame] | 1450 | // create a parent namespace to use instead of the default namespace. This is | 
|  | 1451 | // to make this test be independent from the configuration of the default | 
|  | 1452 | // namespace. | 
|  | 1453 | android_namespace_t* ns_parent = | 
|  | 1454 | android_create_namespace("parent", | 
|  | 1455 | nullptr, | 
|  | 1456 | nullptr, | 
|  | 1457 | ANDROID_NAMESPACE_TYPE_REGULAR, | 
|  | 1458 | nullptr, | 
|  | 1459 | nullptr); | 
|  | 1460 | ASSERT_TRUE(ns_parent != nullptr) << dlerror(); | 
|  | 1461 | ASSERT_TRUE(android_link_namespaces(ns_parent, nullptr, g_core_shared_libs.c_str())) << dlerror(); | 
|  | 1462 |  | 
|  | 1463 | android_dlextinfo extinfo; | 
|  | 1464 | extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE; | 
|  | 1465 | extinfo.library_namespace = ns_parent; | 
|  | 1466 |  | 
| Elliott Hughes | 8d8138a | 2024-03-12 22:37:13 +0000 | [diff] [blame] | 1467 | const std::string lib_public_path = GetTestLibRoot() + "/public_namespace_libs/" + g_public_lib; | 
| Jiyong Park | 917d34a | 2017-08-31 14:07:13 +0900 | [diff] [blame] | 1468 | void* handle_public = android_dlopen_ext(lib_public_path.c_str(), RTLD_NOW, &extinfo); | 
| Dimitry Ivanov | 7331fe1 | 2015-12-14 14:11:17 -0800 | [diff] [blame] | 1469 | ASSERT_TRUE(handle_public != nullptr) << dlerror(); | 
|  | 1470 |  | 
|  | 1471 | android_set_application_target_sdk_version(42U); // something > 23 | 
|  | 1472 |  | 
| Dimitry Ivanov | 7a34b9d | 2017-02-03 14:07:34 -0800 | [diff] [blame] | 1473 | ASSERT_TRUE(android_init_anonymous_namespace(shared_libs.c_str(), nullptr)) << dlerror(); | 
| Dimitry Ivanov | 7331fe1 | 2015-12-14 14:11:17 -0800 | [diff] [blame] | 1474 |  | 
| Jiyong Park | 917d34a | 2017-08-31 14:07:13 +0900 | [diff] [blame] | 1475 | // preload this library to the parent namespace to check if it | 
| Dimitry Ivanov | 7331fe1 | 2015-12-14 14:11:17 -0800 | [diff] [blame] | 1476 | // is shared later on. | 
|  | 1477 | void* handle_dlopened = | 
| Elliott Hughes | 8d8138a | 2024-03-12 22:37:13 +0000 | [diff] [blame] | 1478 | android_dlopen_ext((GetTestLibRoot() + "/private_namespace_libs/libnstest_dlopened.so").c_str(), RTLD_NOW, &extinfo); | 
| Dimitry Ivanov | 7331fe1 | 2015-12-14 14:11:17 -0800 | [diff] [blame] | 1479 | ASSERT_TRUE(handle_dlopened != nullptr) << dlerror(); | 
|  | 1480 |  | 
| Jiyong Park | 917d34a | 2017-08-31 14:07:13 +0900 | [diff] [blame] | 1481 | // create two child namespaces of 'ns_parent'. One with regular, the other | 
|  | 1482 | // with isolated & shared. | 
| Dimitry Ivanov | 7331fe1 | 2015-12-14 14:11:17 -0800 | [diff] [blame] | 1483 | android_namespace_t* ns_not_isolated = | 
| Dimitry Ivanov | 7a34b9d | 2017-02-03 14:07:34 -0800 | [diff] [blame] | 1484 | android_create_namespace("private", | 
|  | 1485 | nullptr, | 
| Elliott Hughes | 8d8138a | 2024-03-12 22:37:13 +0000 | [diff] [blame] | 1486 | (GetTestLibRoot() + "/private_namespace_libs").c_str(), | 
| Dimitry Ivanov | 7a34b9d | 2017-02-03 14:07:34 -0800 | [diff] [blame] | 1487 | ANDROID_NAMESPACE_TYPE_REGULAR, | 
|  | 1488 | nullptr, | 
| Jiyong Park | 917d34a | 2017-08-31 14:07:13 +0900 | [diff] [blame] | 1489 | ns_parent); | 
| Dimitry Ivanov | 7331fe1 | 2015-12-14 14:11:17 -0800 | [diff] [blame] | 1490 | ASSERT_TRUE(ns_not_isolated != nullptr) << dlerror(); | 
| Jiyong Park | 917d34a | 2017-08-31 14:07:13 +0900 | [diff] [blame] | 1491 | ASSERT_TRUE(android_link_namespaces(ns_not_isolated, ns_parent, g_public_lib)) << dlerror(); | 
|  | 1492 | ASSERT_TRUE(android_link_namespaces(ns_not_isolated, nullptr, g_core_shared_libs.c_str())) << dlerror(); | 
| Dimitry Ivanov | 7331fe1 | 2015-12-14 14:11:17 -0800 | [diff] [blame] | 1493 |  | 
|  | 1494 | android_namespace_t* ns_isolated_shared = | 
| Dimitry Ivanov | 7a34b9d | 2017-02-03 14:07:34 -0800 | [diff] [blame] | 1495 | android_create_namespace("private_isolated_shared", | 
|  | 1496 | nullptr, | 
| Elliott Hughes | 8d8138a | 2024-03-12 22:37:13 +0000 | [diff] [blame] | 1497 | (GetTestLibRoot() + "/private_namespace_libs").c_str(), | 
| Dimitry Ivanov | 7331fe1 | 2015-12-14 14:11:17 -0800 | [diff] [blame] | 1498 | ANDROID_NAMESPACE_TYPE_ISOLATED | ANDROID_NAMESPACE_TYPE_SHARED, | 
| Dimitry Ivanov | 7a34b9d | 2017-02-03 14:07:34 -0800 | [diff] [blame] | 1499 | nullptr, | 
| Jiyong Park | 917d34a | 2017-08-31 14:07:13 +0900 | [diff] [blame] | 1500 | ns_parent); | 
| Dimitry Ivanov | 7331fe1 | 2015-12-14 14:11:17 -0800 | [diff] [blame] | 1501 | ASSERT_TRUE(ns_isolated_shared != nullptr) << dlerror(); | 
| Jiyong Park | 917d34a | 2017-08-31 14:07:13 +0900 | [diff] [blame] | 1502 | ASSERT_TRUE(android_link_namespaces(ns_isolated_shared, ns_parent, g_public_lib)) << dlerror(); | 
|  | 1503 | ASSERT_TRUE(android_link_namespaces(ns_isolated_shared, nullptr, g_core_shared_libs.c_str())) << dlerror(); | 
| Dimitry Ivanov | 7331fe1 | 2015-12-14 14:11:17 -0800 | [diff] [blame] | 1504 |  | 
| Jiyong Park | 917d34a | 2017-08-31 14:07:13 +0900 | [diff] [blame] | 1505 | ASSERT_TRUE(android_dlopen_ext(root_lib, RTLD_NOW, &extinfo) == nullptr); | 
| Dimitry Ivanov | 7331fe1 | 2015-12-14 14:11:17 -0800 | [diff] [blame] | 1506 | ASSERT_STREQ("dlopen failed: library \"libnstest_root_not_isolated.so\" not found", dlerror()); | 
|  | 1507 |  | 
|  | 1508 | std::string lib_private_external_path = | 
| Elliott Hughes | 8d8138a | 2024-03-12 22:37:13 +0000 | [diff] [blame] | 1509 | GetTestLibRoot() + "/private_namespace_libs_external/libnstest_private_external.so"; | 
| Dimitry Ivanov | 7331fe1 | 2015-12-14 14:11:17 -0800 | [diff] [blame] | 1510 |  | 
| Jiyong Park | 917d34a | 2017-08-31 14:07:13 +0900 | [diff] [blame] | 1511 | // Load lib_private_external_path to the parent namespace | 
| Dimitry Ivanov | 7331fe1 | 2015-12-14 14:11:17 -0800 | [diff] [blame] | 1512 | // (it should remain invisible for the isolated namespaces after this) | 
| Jiyong Park | 917d34a | 2017-08-31 14:07:13 +0900 | [diff] [blame] | 1513 | void* handle = android_dlopen_ext(lib_private_external_path.c_str(), RTLD_NOW, &extinfo); | 
| Dimitry Ivanov | 7331fe1 | 2015-12-14 14:11:17 -0800 | [diff] [blame] | 1514 | ASSERT_TRUE(handle != nullptr) << dlerror(); | 
|  | 1515 |  | 
| Dimitry Ivanov | 7331fe1 | 2015-12-14 14:11:17 -0800 | [diff] [blame] | 1516 | extinfo.library_namespace = ns_not_isolated; | 
|  | 1517 |  | 
|  | 1518 | void* handle1 = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo); | 
|  | 1519 | ASSERT_TRUE(handle1 != nullptr) << dlerror(); | 
|  | 1520 |  | 
|  | 1521 | extinfo.library_namespace = ns_isolated_shared; | 
|  | 1522 |  | 
|  | 1523 | void* handle2 = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo); | 
|  | 1524 | ASSERT_TRUE(handle2 == nullptr); | 
| Josh Gao | 1626957 | 2019-10-29 13:41:00 -0700 | [diff] [blame] | 1525 | ASSERT_MATCH(dlerror(), | 
|  | 1526 | R"(dlopen failed: library "libnstest_private_external.so" not found: needed by )" | 
|  | 1527 | R"(\S+libnstest_root_not_isolated.so in namespace private_isolated_shared)"); | 
| Dimitry Ivanov | 7331fe1 | 2015-12-14 14:11:17 -0800 | [diff] [blame] | 1528 |  | 
|  | 1529 | // Check dlopen by absolute path | 
|  | 1530 | handle2 = android_dlopen_ext(lib_private_external_path.c_str(), RTLD_NOW, &extinfo); | 
|  | 1531 | ASSERT_TRUE(handle2 == nullptr); | 
| Dimitry Ivanov | d17a377 | 2016-03-01 13:11:28 -0800 | [diff] [blame] | 1532 | ASSERT_EQ("dlopen failed: library \"" + lib_private_external_path + "\" needed" | 
| Christopher Ferris | 6d2c0bd | 2018-08-21 18:13:10 -0700 | [diff] [blame] | 1533 | " or dlopened by \"" + android::base::GetExecutablePath() + "\" is not accessible" | 
| Dimitry Ivanov | d17a377 | 2016-03-01 13:11:28 -0800 | [diff] [blame] | 1534 | " for the namespace \"private_isolated_shared\"", dlerror()); | 
| Dimitry Ivanov | 7331fe1 | 2015-12-14 14:11:17 -0800 | [diff] [blame] | 1535 |  | 
|  | 1536 | // load libnstest_root.so to shared namespace in order to check that everything is different | 
|  | 1537 | // except shared libnstest_dlopened.so | 
|  | 1538 |  | 
|  | 1539 | handle2 = android_dlopen_ext(root_lib_isolated, RTLD_NOW, &extinfo); | 
|  | 1540 |  | 
|  | 1541 | typedef const char* (*fn_t)(); | 
|  | 1542 | fn_t ns_get_local_string = reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_local_string")); | 
|  | 1543 | ASSERT_TRUE(ns_get_local_string != nullptr) << dlerror(); | 
|  | 1544 | fn_t ns_get_local_string_shared = reinterpret_cast<fn_t>(dlsym(handle2, "ns_get_local_string")); | 
|  | 1545 | ASSERT_TRUE(ns_get_local_string_shared != nullptr) << dlerror(); | 
|  | 1546 |  | 
|  | 1547 | ASSERT_STREQ("This string is local to root library", ns_get_local_string()); | 
|  | 1548 | ASSERT_STREQ("This string is local to root library", ns_get_local_string_shared()); | 
|  | 1549 | ASSERT_TRUE(ns_get_local_string() != ns_get_local_string_shared()); | 
|  | 1550 |  | 
|  | 1551 | fn_t ns_get_private_extern_string = | 
|  | 1552 | reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_private_extern_string")); | 
|  | 1553 | ASSERT_TRUE(ns_get_private_extern_string != nullptr) << dlerror(); | 
|  | 1554 | fn_t ns_get_private_extern_string_shared = | 
|  | 1555 | reinterpret_cast<fn_t>(dlsym(handle2, "ns_get_private_extern_string")); | 
|  | 1556 | ASSERT_TRUE(ns_get_private_extern_string_shared() != nullptr) << dlerror(); | 
|  | 1557 |  | 
|  | 1558 | ASSERT_STREQ("This string is from private namespace", ns_get_private_extern_string()); | 
|  | 1559 | ASSERT_STREQ("This string is from private namespace", ns_get_private_extern_string_shared()); | 
|  | 1560 | ASSERT_TRUE(ns_get_private_extern_string() != ns_get_private_extern_string_shared()); | 
|  | 1561 |  | 
|  | 1562 | fn_t ns_get_public_extern_string = | 
|  | 1563 | reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_public_extern_string")); | 
|  | 1564 | ASSERT_TRUE(ns_get_public_extern_string != nullptr) << dlerror(); | 
|  | 1565 | fn_t ns_get_public_extern_string_shared = | 
|  | 1566 | reinterpret_cast<fn_t>(dlsym(handle2, "ns_get_public_extern_string")); | 
|  | 1567 | ASSERT_TRUE(ns_get_public_extern_string_shared != nullptr) << dlerror(); | 
|  | 1568 |  | 
|  | 1569 | ASSERT_STREQ("This string is from public namespace", ns_get_public_extern_string()); | 
|  | 1570 | ASSERT_STREQ("This string is from public namespace", ns_get_public_extern_string_shared()); | 
|  | 1571 | ASSERT_TRUE(ns_get_public_extern_string() == ns_get_public_extern_string_shared()); | 
|  | 1572 |  | 
|  | 1573 | fn_t ns_get_dlopened_string = reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_dlopened_string")); | 
|  | 1574 | ASSERT_TRUE(ns_get_dlopened_string != nullptr) << dlerror(); | 
|  | 1575 | fn_t ns_get_dlopened_string_shared = reinterpret_cast<fn_t>(dlsym(handle2, "ns_get_dlopened_string")); | 
|  | 1576 | ASSERT_TRUE(ns_get_dlopened_string_shared != nullptr) << dlerror(); | 
|  | 1577 | const char** ns_dlopened_string = static_cast<const char**>(dlsym(handle_dlopened, "g_private_dlopened_string")); | 
|  | 1578 | ASSERT_TRUE(ns_dlopened_string != nullptr) << dlerror(); | 
|  | 1579 |  | 
|  | 1580 | ASSERT_STREQ("This string is from private namespace (dlopened library)", ns_get_dlopened_string()); | 
|  | 1581 | ASSERT_STREQ("This string is from private namespace (dlopened library)", *ns_dlopened_string); | 
|  | 1582 | ASSERT_STREQ("This string is from private namespace (dlopened library)", ns_get_dlopened_string_shared()); | 
|  | 1583 | ASSERT_TRUE(ns_get_dlopened_string() != ns_get_dlopened_string_shared()); | 
|  | 1584 | ASSERT_TRUE(*ns_dlopened_string == ns_get_dlopened_string_shared()); | 
|  | 1585 |  | 
|  | 1586 | dlclose(handle1); | 
|  | 1587 | dlclose(handle2); | 
|  | 1588 | } | 
|  | 1589 |  | 
| Dimitry Ivanov | f1cb669 | 2017-05-01 17:45:38 -0700 | [diff] [blame] | 1590 | TEST(dlext, ns_shared_links_and_paths) { | 
|  | 1591 | // Create parent namespace (isolated, not shared) | 
|  | 1592 | android_namespace_t* ns_isolated = | 
|  | 1593 | android_create_namespace("private_isolated", | 
|  | 1594 | nullptr, | 
| Elliott Hughes | 8d8138a | 2024-03-12 22:37:13 +0000 | [diff] [blame] | 1595 | (GetTestLibRoot() + "/private_namespace_libs").c_str(), | 
| Dimitry Ivanov | f1cb669 | 2017-05-01 17:45:38 -0700 | [diff] [blame] | 1596 | ANDROID_NAMESPACE_TYPE_ISOLATED, | 
| Elliott Hughes | 8d8138a | 2024-03-12 22:37:13 +0000 | [diff] [blame] | 1597 | (GetTestLibRoot() + "/public_namespace_libs").c_str(), | 
| Dimitry Ivanov | f1cb669 | 2017-05-01 17:45:38 -0700 | [diff] [blame] | 1598 | nullptr); | 
|  | 1599 | ASSERT_TRUE(ns_isolated != nullptr) << dlerror(); | 
|  | 1600 | ASSERT_TRUE(android_link_namespaces(ns_isolated, nullptr, g_core_shared_libs.c_str())) << dlerror(); | 
|  | 1601 |  | 
|  | 1602 | // Create shared namespace with ns_isolated parent | 
|  | 1603 | android_namespace_t* ns_shared = | 
|  | 1604 | android_create_namespace("private_shared", | 
|  | 1605 | nullptr, | 
|  | 1606 | nullptr, | 
|  | 1607 | ANDROID_NAMESPACE_TYPE_SHARED | ANDROID_NAMESPACE_TYPE_ISOLATED, | 
|  | 1608 | nullptr, | 
|  | 1609 | ns_isolated); | 
|  | 1610 | ASSERT_TRUE(ns_shared != nullptr) << dlerror(); | 
|  | 1611 |  | 
|  | 1612 | // 1. Load a library in ns_shared to check that it has inherited | 
|  | 1613 | // search path and the link to the default namespace. | 
|  | 1614 | android_dlextinfo extinfo; | 
|  | 1615 | extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE; | 
|  | 1616 | extinfo.library_namespace = ns_shared; | 
|  | 1617 |  | 
|  | 1618 | { | 
|  | 1619 | void* handle = android_dlopen_ext("libnstest_private.so", RTLD_NOW, &extinfo); | 
|  | 1620 | ASSERT_TRUE(handle != nullptr) << dlerror(); | 
|  | 1621 | const char** ns_private_extern_string = static_cast<const char**>(dlsym(handle, "g_private_extern_string")); | 
|  | 1622 | ASSERT_TRUE(ns_private_extern_string != nullptr) << dlerror(); | 
|  | 1623 | ASSERT_STREQ("This string is from private namespace", *ns_private_extern_string); | 
|  | 1624 |  | 
|  | 1625 | dlclose(handle); | 
|  | 1626 | } | 
|  | 1627 | // 2. Load another test library by absolute path to check that | 
|  | 1628 | // it has inherited permitted_when_isolated_path | 
|  | 1629 | { | 
|  | 1630 | void* handle = android_dlopen_ext( | 
| Elliott Hughes | 8d8138a | 2024-03-12 22:37:13 +0000 | [diff] [blame] | 1631 | (GetTestLibRoot() + "/public_namespace_libs/libnstest_public.so").c_str(), | 
| Dimitry Ivanov | f1cb669 | 2017-05-01 17:45:38 -0700 | [diff] [blame] | 1632 | RTLD_NOW, | 
|  | 1633 | &extinfo); | 
|  | 1634 |  | 
|  | 1635 | ASSERT_TRUE(handle != nullptr) << dlerror(); | 
|  | 1636 | const char** ns_public_extern_string = static_cast<const char**>(dlsym(handle, "g_public_extern_string")); | 
|  | 1637 | ASSERT_TRUE(ns_public_extern_string != nullptr) << dlerror(); | 
|  | 1638 | ASSERT_STREQ("This string is from public namespace", *ns_public_extern_string); | 
|  | 1639 |  | 
|  | 1640 | dlclose(handle); | 
|  | 1641 | } | 
|  | 1642 |  | 
|  | 1643 | // 3. Check that it is still isolated. | 
|  | 1644 | { | 
|  | 1645 | void* handle = android_dlopen_ext( | 
| Elliott Hughes | 8d8138a | 2024-03-12 22:37:13 +0000 | [diff] [blame] | 1646 | (GetTestLibRoot() + "/libtest_empty.so").c_str(), | 
| Dimitry Ivanov | f1cb669 | 2017-05-01 17:45:38 -0700 | [diff] [blame] | 1647 | RTLD_NOW, | 
|  | 1648 | &extinfo); | 
|  | 1649 |  | 
|  | 1650 | ASSERT_TRUE(handle == nullptr); | 
|  | 1651 | } | 
|  | 1652 | } | 
|  | 1653 |  | 
| Dimitry Ivanov | aca299a | 2016-04-11 12:42:58 -0700 | [diff] [blame] | 1654 | TEST(dlext, ns_shared_dlclose) { | 
| Dimitry Ivanov | aca299a | 2016-04-11 12:42:58 -0700 | [diff] [blame] | 1655 | android_set_application_target_sdk_version(42U); // something > 23 | 
|  | 1656 |  | 
| Dimitry Ivanov | 7a34b9d | 2017-02-03 14:07:34 -0800 | [diff] [blame] | 1657 | ASSERT_TRUE(android_init_anonymous_namespace(g_core_shared_libs.c_str(), nullptr)) << dlerror(); | 
| Dimitry Ivanov | aca299a | 2016-04-11 12:42:58 -0700 | [diff] [blame] | 1658 |  | 
|  | 1659 | // preload this library to the default namespace to check if it | 
|  | 1660 | // is shared later on. | 
|  | 1661 | void* handle_dlopened = | 
| Elliott Hughes | 8d8138a | 2024-03-12 22:37:13 +0000 | [diff] [blame] | 1662 | dlopen((GetTestLibRoot() + "/private_namespace_libs/libnstest_dlopened.so").c_str(), RTLD_NOW); | 
| Dimitry Ivanov | aca299a | 2016-04-11 12:42:58 -0700 | [diff] [blame] | 1663 | ASSERT_TRUE(handle_dlopened != nullptr) << dlerror(); | 
|  | 1664 |  | 
|  | 1665 | android_namespace_t* ns_isolated_shared = | 
| Dimitry Ivanov | 7a34b9d | 2017-02-03 14:07:34 -0800 | [diff] [blame] | 1666 | android_create_namespace("private_isolated_shared", | 
|  | 1667 | nullptr, | 
| Elliott Hughes | 8d8138a | 2024-03-12 22:37:13 +0000 | [diff] [blame] | 1668 | (GetTestLibRoot() + "/private_namespace_libs").c_str(), | 
| Dimitry Ivanov | aca299a | 2016-04-11 12:42:58 -0700 | [diff] [blame] | 1669 | ANDROID_NAMESPACE_TYPE_ISOLATED | ANDROID_NAMESPACE_TYPE_SHARED, | 
| Dimitry Ivanov | 7a34b9d | 2017-02-03 14:07:34 -0800 | [diff] [blame] | 1670 | nullptr, | 
|  | 1671 | nullptr); | 
| Dimitry Ivanov | aca299a | 2016-04-11 12:42:58 -0700 | [diff] [blame] | 1672 | ASSERT_TRUE(ns_isolated_shared != nullptr) << dlerror(); | 
| Dimitry Ivanov | 7a34b9d | 2017-02-03 14:07:34 -0800 | [diff] [blame] | 1673 | ASSERT_TRUE(android_link_namespaces(ns_isolated_shared, nullptr, g_core_shared_libs.c_str())) << dlerror(); | 
| Dimitry Ivanov | aca299a | 2016-04-11 12:42:58 -0700 | [diff] [blame] | 1674 |  | 
|  | 1675 | // Check if "libnstest_dlopened.so" is loaded (and the same) | 
|  | 1676 | android_dlextinfo extinfo; | 
|  | 1677 | extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE; | 
|  | 1678 | extinfo.library_namespace = ns_isolated_shared; | 
|  | 1679 |  | 
|  | 1680 | void* handle = android_dlopen_ext("libnstest_dlopened.so", RTLD_NOW | RTLD_NOLOAD, &extinfo); | 
|  | 1681 | ASSERT_TRUE(handle != nullptr) << dlerror(); | 
|  | 1682 | ASSERT_TRUE(handle == handle_dlopened); | 
|  | 1683 | dlclose(handle); | 
|  | 1684 | dlclose(handle_dlopened); | 
|  | 1685 |  | 
|  | 1686 | // And now check that the library cannot be found by soname (and is no longer loaded) | 
|  | 1687 | handle = android_dlopen_ext("libnstest_dlopened.so", RTLD_NOW | RTLD_NOLOAD, &extinfo); | 
|  | 1688 | ASSERT_TRUE(handle == nullptr) | 
|  | 1689 | << "Error: libnstest_dlopened.so is still accessible in shared namespace"; | 
|  | 1690 |  | 
| Elliott Hughes | 8d8138a | 2024-03-12 22:37:13 +0000 | [diff] [blame] | 1691 | handle = android_dlopen_ext((GetTestLibRoot() + "/private_namespace_libs/libnstest_dlopened.so").c_str(), | 
| Dimitry Ivanov | aca299a | 2016-04-11 12:42:58 -0700 | [diff] [blame] | 1692 | RTLD_NOW | RTLD_NOLOAD, &extinfo); | 
|  | 1693 | ASSERT_TRUE(handle == nullptr) | 
|  | 1694 | << "Error: libnstest_dlopened.so is still accessible in shared namespace"; | 
|  | 1695 |  | 
|  | 1696 | handle = dlopen("libnstest_dlopened.so", RTLD_NOW | RTLD_NOLOAD); | 
|  | 1697 | ASSERT_TRUE(handle == nullptr) | 
|  | 1698 | << "Error: libnstest_dlopened.so is still accessible in default namespace"; | 
|  | 1699 |  | 
| Elliott Hughes | 8d8138a | 2024-03-12 22:37:13 +0000 | [diff] [blame] | 1700 | handle = dlopen((GetTestLibRoot() + "/private_namespace_libs/libnstest_dlopened.so").c_str(), | 
| Dimitry Ivanov | aca299a | 2016-04-11 12:42:58 -0700 | [diff] [blame] | 1701 | RTLD_NOW | RTLD_NOLOAD); | 
|  | 1702 | ASSERT_TRUE(handle == nullptr) | 
|  | 1703 | << "Error: libnstest_dlopened.so is still accessible in default namespace"; | 
|  | 1704 |  | 
|  | 1705 | // Now lets see if the soinfo area gets reused in the wrong way: | 
|  | 1706 | // load a library to default namespace. | 
| Elliott Hughes | 8d8138a | 2024-03-12 22:37:13 +0000 | [diff] [blame] | 1707 | const std::string lib_public_path = GetTestLibRoot() + "/public_namespace_libs/" + g_public_lib; | 
| Dimitry Ivanov | aca299a | 2016-04-11 12:42:58 -0700 | [diff] [blame] | 1708 | void* handle_public = dlopen(lib_public_path.c_str(), RTLD_NOW); | 
|  | 1709 | ASSERT_TRUE(handle_public != nullptr) << dlerror(); | 
|  | 1710 |  | 
|  | 1711 | // try to find it in shared namespace | 
|  | 1712 | handle = android_dlopen_ext(g_public_lib, RTLD_NOW | RTLD_NOLOAD, &extinfo); | 
|  | 1713 | ASSERT_TRUE(handle == nullptr) | 
|  | 1714 | << "Error: " << g_public_lib << " is accessible in shared namespace"; | 
|  | 1715 | } | 
|  | 1716 |  | 
| Dimitry Ivanov | fc2da53 | 2016-05-12 15:20:21 -0700 | [diff] [blame] | 1717 | TEST(dlext, ns_isolated_rtld_global) { | 
|  | 1718 | static const char* root_lib = "libnstest_root.so"; | 
| Dimitry Ivanov | 7a34b9d | 2017-02-03 14:07:34 -0800 | [diff] [blame] | 1719 | ASSERT_TRUE(android_init_anonymous_namespace(g_core_shared_libs.c_str(), nullptr)); | 
| Dimitry Ivanov | fc2da53 | 2016-05-12 15:20:21 -0700 | [diff] [blame] | 1720 |  | 
| Elliott Hughes | 8d8138a | 2024-03-12 22:37:13 +0000 | [diff] [blame] | 1721 | const std::string lib_public_path = GetTestLibRoot() + "/public_namespace_libs"; | 
| Dimitry Ivanov | fc2da53 | 2016-05-12 15:20:21 -0700 | [diff] [blame] | 1722 |  | 
|  | 1723 | android_namespace_t* ns1 = | 
|  | 1724 | android_create_namespace("isolated1", | 
|  | 1725 | nullptr, | 
| Elliott Hughes | 8d8138a | 2024-03-12 22:37:13 +0000 | [diff] [blame] | 1726 | (GetTestLibRoot() + "/private_namespace_libs").c_str(), | 
| Dimitry Ivanov | fc2da53 | 2016-05-12 15:20:21 -0700 | [diff] [blame] | 1727 | ANDROID_NAMESPACE_TYPE_ISOLATED, | 
|  | 1728 | lib_public_path.c_str(), | 
|  | 1729 | nullptr); | 
|  | 1730 | ASSERT_TRUE(ns1 != nullptr) << dlerror(); | 
| Dimitry Ivanov | 7a34b9d | 2017-02-03 14:07:34 -0800 | [diff] [blame] | 1731 | ASSERT_TRUE(android_link_namespaces(ns1, nullptr, g_core_shared_libs.c_str())) << dlerror(); | 
| Dimitry Ivanov | fc2da53 | 2016-05-12 15:20:21 -0700 | [diff] [blame] | 1732 |  | 
|  | 1733 | android_namespace_t* ns2 = | 
|  | 1734 | android_create_namespace("isolated2", | 
|  | 1735 | nullptr, | 
| Elliott Hughes | 8d8138a | 2024-03-12 22:37:13 +0000 | [diff] [blame] | 1736 | (GetTestLibRoot() + "/private_namespace_libs").c_str(), | 
| Dimitry Ivanov | fc2da53 | 2016-05-12 15:20:21 -0700 | [diff] [blame] | 1737 | ANDROID_NAMESPACE_TYPE_ISOLATED, | 
|  | 1738 | lib_public_path.c_str(), | 
|  | 1739 | nullptr); | 
|  | 1740 | ASSERT_TRUE(ns2 != nullptr) << dlerror(); | 
| Dimitry Ivanov | 7a34b9d | 2017-02-03 14:07:34 -0800 | [diff] [blame] | 1741 | ASSERT_TRUE(android_link_namespaces(ns2, nullptr, g_core_shared_libs.c_str())) << dlerror(); | 
| Dimitry Ivanov | fc2da53 | 2016-05-12 15:20:21 -0700 | [diff] [blame] | 1742 |  | 
|  | 1743 | android_dlextinfo extinfo; | 
|  | 1744 | extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE; | 
|  | 1745 | extinfo.library_namespace = ns1; | 
|  | 1746 |  | 
|  | 1747 | void* handle_global = android_dlopen_ext((lib_public_path + "/" + g_public_lib).c_str(), | 
|  | 1748 | RTLD_GLOBAL, | 
|  | 1749 | &extinfo); | 
|  | 1750 |  | 
|  | 1751 | ASSERT_TRUE(handle_global != nullptr) << dlerror(); | 
|  | 1752 |  | 
|  | 1753 | android_namespace_t* ns1_child = | 
| Dimitry Ivanov | 7a34b9d | 2017-02-03 14:07:34 -0800 | [diff] [blame] | 1754 | android_create_namespace("isolated1_child", | 
|  | 1755 | nullptr, | 
| Elliott Hughes | 8d8138a | 2024-03-12 22:37:13 +0000 | [diff] [blame] | 1756 | (GetTestLibRoot() + "/private_namespace_libs").c_str(), | 
| Dimitry Ivanov | 7a34b9d | 2017-02-03 14:07:34 -0800 | [diff] [blame] | 1757 | ANDROID_NAMESPACE_TYPE_ISOLATED, | 
|  | 1758 | nullptr, | 
|  | 1759 | ns1); | 
|  | 1760 |  | 
|  | 1761 | ASSERT_TRUE(ns1_child != nullptr) << dlerror(); | 
|  | 1762 | ASSERT_TRUE(android_link_namespaces(ns1_child, nullptr, g_core_shared_libs.c_str())) << dlerror(); | 
| Dimitry Ivanov | fc2da53 | 2016-05-12 15:20:21 -0700 | [diff] [blame] | 1763 |  | 
|  | 1764 | // Now - only ns1 and ns1 child should be able to dlopen root_lib | 
|  | 1765 | // attempt to use ns2 should result in dlerror() | 
|  | 1766 |  | 
|  | 1767 | // Check ns1_child first. | 
|  | 1768 | extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE; | 
|  | 1769 | extinfo.library_namespace = ns1_child; | 
|  | 1770 |  | 
|  | 1771 | void* handle1 = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo); | 
|  | 1772 | ASSERT_TRUE(handle1 != nullptr) << dlerror(); | 
|  | 1773 |  | 
|  | 1774 | // now ns1 | 
|  | 1775 | extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE; | 
|  | 1776 | extinfo.library_namespace = ns1; | 
|  | 1777 |  | 
|  | 1778 | handle1 = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo); | 
|  | 1779 | ASSERT_TRUE(handle1 != nullptr) << dlerror(); | 
|  | 1780 |  | 
|  | 1781 | // and ns2 should fail | 
|  | 1782 | extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE; | 
|  | 1783 | extinfo.library_namespace = ns2; | 
|  | 1784 |  | 
|  | 1785 | handle1 = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo); | 
|  | 1786 | ASSERT_TRUE(handle1 == nullptr); | 
| Josh Gao | 1626957 | 2019-10-29 13:41:00 -0700 | [diff] [blame] | 1787 | ASSERT_MATCH( | 
|  | 1788 | dlerror(), | 
|  | 1789 | R"(dlopen failed: library "libnstest_public.so" not found: needed by \S+libnstest_root.so)" | 
|  | 1790 | R"( in namespace isolated2)"); | 
| Dimitry Ivanov | fc2da53 | 2016-05-12 15:20:21 -0700 | [diff] [blame] | 1791 | } | 
|  | 1792 |  | 
| dimitry | 8db36a5 | 2017-10-23 15:10:10 +0200 | [diff] [blame] | 1793 | TEST(dlext, ns_inaccessible_error_message) { | 
|  | 1794 | // We set up 2 namespaces (a and b) and link a->b with a shared library | 
|  | 1795 | // libtestshared.so. Then try to dlopen different library with the same | 
|  | 1796 | // name from in namespace a. Note that library should not be accessible | 
|  | 1797 | // in either namespace but since it's soname is in the list of shared libs | 
|  | 1798 | // the linker will attempt to find it in linked namespace. | 
|  | 1799 | // | 
|  | 1800 | // Check the error message and make sure it mentions correct namespace name. | 
|  | 1801 | ASSERT_TRUE(android_init_anonymous_namespace(g_core_shared_libs.c_str(), nullptr)); | 
|  | 1802 |  | 
|  | 1803 | android_namespace_t* ns_a = | 
|  | 1804 | android_create_namespace("ns_a", | 
|  | 1805 | nullptr, | 
| Elliott Hughes | 8d8138a | 2024-03-12 22:37:13 +0000 | [diff] [blame] | 1806 | (GetTestLibRoot() + "/private_namespace_libs").c_str(), | 
| dimitry | 8db36a5 | 2017-10-23 15:10:10 +0200 | [diff] [blame] | 1807 | ANDROID_NAMESPACE_TYPE_ISOLATED, | 
|  | 1808 | nullptr, | 
|  | 1809 | nullptr); | 
|  | 1810 | ASSERT_TRUE(ns_a != nullptr) << dlerror(); | 
|  | 1811 | ASSERT_TRUE(android_link_namespaces(ns_a, nullptr, g_core_shared_libs.c_str())) << dlerror(); | 
|  | 1812 |  | 
|  | 1813 | android_namespace_t* ns_b = | 
|  | 1814 | android_create_namespace("ns_b", | 
|  | 1815 | nullptr, | 
| Elliott Hughes | 8d8138a | 2024-03-12 22:37:13 +0000 | [diff] [blame] | 1816 | GetTestLibRoot().c_str(), | 
| dimitry | 8db36a5 | 2017-10-23 15:10:10 +0200 | [diff] [blame] | 1817 | ANDROID_NAMESPACE_TYPE_ISOLATED, | 
|  | 1818 | nullptr, | 
|  | 1819 | nullptr); | 
|  | 1820 | ASSERT_TRUE(ns_b != nullptr) << dlerror(); | 
|  | 1821 | ASSERT_TRUE(android_link_namespaces(ns_b, nullptr, g_core_shared_libs.c_str())) << dlerror(); | 
|  | 1822 |  | 
|  | 1823 | ASSERT_TRUE(android_link_namespaces(ns_a, ns_b, "libtestshared.so")) << dlerror(); | 
|  | 1824 |  | 
|  | 1825 | android_dlextinfo extinfo; | 
|  | 1826 | extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE; | 
|  | 1827 | extinfo.library_namespace = ns_a; | 
|  | 1828 |  | 
| Elliott Hughes | 8d8138a | 2024-03-12 22:37:13 +0000 | [diff] [blame] | 1829 | std::string library_path = GetTestLibRoot() + "/inaccessible_libs/libtestshared.so"; | 
| dimitry | 8db36a5 | 2017-10-23 15:10:10 +0200 | [diff] [blame] | 1830 |  | 
|  | 1831 | void* handle = android_dlopen_ext(library_path.c_str(), RTLD_NOW, &extinfo); | 
|  | 1832 | ASSERT_TRUE(handle == nullptr); | 
|  | 1833 | std::string expected_dlerror = | 
|  | 1834 | android::base::StringPrintf("dlopen failed: library \"%s\" needed or dlopened by \"%s\"" | 
|  | 1835 | " is not accessible for the namespace \"ns_a\"", | 
|  | 1836 | library_path.c_str(), | 
| Christopher Ferris | 6d2c0bd | 2018-08-21 18:13:10 -0700 | [diff] [blame] | 1837 | android::base::GetExecutablePath().c_str()); | 
| dimitry | 8db36a5 | 2017-10-23 15:10:10 +0200 | [diff] [blame] | 1838 | ASSERT_EQ(expected_dlerror, dlerror()); | 
|  | 1839 | } | 
|  | 1840 |  | 
| dimitry | 321476a | 2018-01-29 15:32:37 +0100 | [diff] [blame] | 1841 | extern "C" bool __loader_android_link_namespaces_all_libs(android_namespace_t* namespace_from, | 
|  | 1842 | android_namespace_t* namespace_to); | 
|  | 1843 |  | 
| Logan Chien | 9ee4591 | 2018-01-18 12:05:09 +0800 | [diff] [blame] | 1844 | TEST(dlext, ns_link_namespaces_invalid_arguments) { | 
|  | 1845 | ASSERT_TRUE(android_init_anonymous_namespace(g_core_shared_libs.c_str(), nullptr)); | 
|  | 1846 |  | 
|  | 1847 | android_namespace_t* ns = | 
|  | 1848 | android_create_namespace("private", | 
|  | 1849 | nullptr, | 
| Elliott Hughes | 8d8138a | 2024-03-12 22:37:13 +0000 | [diff] [blame] | 1850 | (GetTestLibRoot() + "/private_namespace_libs").c_str(), | 
| Logan Chien | 9ee4591 | 2018-01-18 12:05:09 +0800 | [diff] [blame] | 1851 | ANDROID_NAMESPACE_TYPE_REGULAR, | 
|  | 1852 | nullptr, | 
|  | 1853 | nullptr); | 
|  | 1854 | ASSERT_TRUE(ns != nullptr) << dlerror(); | 
|  | 1855 |  | 
|  | 1856 | // Test android_link_namespaces() | 
|  | 1857 | ASSERT_FALSE(android_link_namespaces(nullptr, nullptr, "libc.so")); | 
|  | 1858 | ASSERT_STREQ("android_link_namespaces failed: error linking namespaces: namespace_from is null.", | 
|  | 1859 | dlerror()); | 
|  | 1860 |  | 
|  | 1861 | ASSERT_FALSE(android_link_namespaces(ns, nullptr, nullptr)); | 
|  | 1862 | ASSERT_STREQ("android_link_namespaces failed: " | 
|  | 1863 | "error linking namespaces \"private\"->\"(default)\": " | 
|  | 1864 | "the list of shared libraries is empty.", dlerror()); | 
|  | 1865 |  | 
|  | 1866 | ASSERT_FALSE(android_link_namespaces(ns, nullptr, "")); | 
|  | 1867 | ASSERT_STREQ("android_link_namespaces failed: " | 
|  | 1868 | "error linking namespaces \"private\"->\"(default)\": " | 
|  | 1869 | "the list of shared libraries is empty.", dlerror()); | 
|  | 1870 |  | 
| dimitry | 321476a | 2018-01-29 15:32:37 +0100 | [diff] [blame] | 1871 | // Test __loader_android_link_namespaces_all_libs() | 
|  | 1872 | ASSERT_FALSE(__loader_android_link_namespaces_all_libs(nullptr, nullptr)); | 
| Logan Chien | 9ee4591 | 2018-01-18 12:05:09 +0800 | [diff] [blame] | 1873 | ASSERT_STREQ("android_link_namespaces_all_libs failed: " | 
|  | 1874 | "error linking namespaces: namespace_from is null.", dlerror()); | 
|  | 1875 |  | 
| dimitry | 321476a | 2018-01-29 15:32:37 +0100 | [diff] [blame] | 1876 | ASSERT_FALSE(__loader_android_link_namespaces_all_libs(nullptr, ns)); | 
| Logan Chien | 9ee4591 | 2018-01-18 12:05:09 +0800 | [diff] [blame] | 1877 | ASSERT_STREQ("android_link_namespaces_all_libs failed: " | 
|  | 1878 | "error linking namespaces: namespace_from is null.", dlerror()); | 
|  | 1879 |  | 
| dimitry | 321476a | 2018-01-29 15:32:37 +0100 | [diff] [blame] | 1880 | ASSERT_FALSE(__loader_android_link_namespaces_all_libs(ns, nullptr)); | 
| Logan Chien | 9ee4591 | 2018-01-18 12:05:09 +0800 | [diff] [blame] | 1881 | ASSERT_STREQ("android_link_namespaces_all_libs failed: " | 
|  | 1882 | "error linking namespaces: namespace_to is null.", dlerror()); | 
|  | 1883 | } | 
|  | 1884 |  | 
|  | 1885 | TEST(dlext, ns_allow_all_shared_libs) { | 
|  | 1886 | ASSERT_TRUE(android_init_anonymous_namespace(g_core_shared_libs.c_str(), nullptr)); | 
|  | 1887 |  | 
|  | 1888 | android_namespace_t* ns_a = | 
|  | 1889 | android_create_namespace("ns_a", | 
|  | 1890 | nullptr, | 
| Elliott Hughes | 8d8138a | 2024-03-12 22:37:13 +0000 | [diff] [blame] | 1891 | (GetTestLibRoot() + "/ns_a").c_str(), | 
| Logan Chien | 9ee4591 | 2018-01-18 12:05:09 +0800 | [diff] [blame] | 1892 | ANDROID_NAMESPACE_TYPE_ISOLATED, | 
|  | 1893 | nullptr, | 
|  | 1894 | nullptr); | 
|  | 1895 | ASSERT_TRUE(ns_a != nullptr) << dlerror(); | 
|  | 1896 | ASSERT_TRUE(android_link_namespaces(ns_a, nullptr, g_core_shared_libs.c_str())) << dlerror(); | 
|  | 1897 |  | 
|  | 1898 | android_namespace_t* ns_b = | 
|  | 1899 | android_create_namespace("ns_b", | 
|  | 1900 | nullptr, | 
| Elliott Hughes | 8d8138a | 2024-03-12 22:37:13 +0000 | [diff] [blame] | 1901 | (GetTestLibRoot() + "/ns_b").c_str(), | 
| Logan Chien | 9ee4591 | 2018-01-18 12:05:09 +0800 | [diff] [blame] | 1902 | ANDROID_NAMESPACE_TYPE_ISOLATED, | 
|  | 1903 | nullptr, | 
|  | 1904 | nullptr); | 
|  | 1905 | ASSERT_TRUE(ns_b != nullptr) << dlerror(); | 
|  | 1906 | ASSERT_TRUE(android_link_namespaces(ns_b, nullptr, g_core_shared_libs.c_str())) << dlerror(); | 
|  | 1907 |  | 
|  | 1908 | ASSERT_TRUE(android_link_namespaces(ns_b, ns_a, "libnstest_ns_a_public1.so")) << dlerror(); | 
| dimitry | 321476a | 2018-01-29 15:32:37 +0100 | [diff] [blame] | 1909 | ASSERT_TRUE(__loader_android_link_namespaces_all_libs(ns_a, ns_b)) << dlerror(); | 
| Logan Chien | 9ee4591 | 2018-01-18 12:05:09 +0800 | [diff] [blame] | 1910 |  | 
|  | 1911 | // Load libs with android_dlopen_ext() from namespace b | 
|  | 1912 | android_dlextinfo extinfo; | 
|  | 1913 | extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE; | 
|  | 1914 | extinfo.library_namespace = ns_b; | 
|  | 1915 |  | 
|  | 1916 | void* ns_b_handle1 = android_dlopen_ext("libnstest_ns_a_public1.so", RTLD_NOW, &extinfo); | 
|  | 1917 | ASSERT_TRUE(ns_b_handle1 != nullptr) << dlerror(); | 
|  | 1918 |  | 
|  | 1919 | void* ns_b_handle1_internal = | 
|  | 1920 | android_dlopen_ext("libnstest_ns_a_public1_internal.so", RTLD_NOW, &extinfo); | 
|  | 1921 | ASSERT_TRUE(ns_b_handle1_internal == nullptr); | 
|  | 1922 |  | 
|  | 1923 | void* ns_b_handle2 = android_dlopen_ext("libnstest_ns_b_public2.so", RTLD_NOW, &extinfo); | 
|  | 1924 | ASSERT_TRUE(ns_b_handle2 != nullptr) << dlerror(); | 
|  | 1925 |  | 
|  | 1926 | void* ns_b_handle3 = android_dlopen_ext("libnstest_ns_b_public3.so", RTLD_NOW, &extinfo); | 
|  | 1927 | ASSERT_TRUE(ns_b_handle3 != nullptr) << dlerror(); | 
|  | 1928 |  | 
|  | 1929 | // Load libs with android_dlopen_ext() from namespace a | 
|  | 1930 | extinfo.library_namespace = ns_a; | 
|  | 1931 |  | 
|  | 1932 | void* ns_a_handle1 = android_dlopen_ext("libnstest_ns_a_public1.so", RTLD_NOW, &extinfo); | 
|  | 1933 | ASSERT_TRUE(ns_a_handle1 != nullptr) << dlerror(); | 
|  | 1934 |  | 
|  | 1935 | void* ns_a_handle1_internal = | 
|  | 1936 | android_dlopen_ext("libnstest_ns_a_public1_internal.so", RTLD_NOW, &extinfo); | 
|  | 1937 | ASSERT_TRUE(ns_a_handle1_internal != nullptr) << dlerror(); | 
|  | 1938 |  | 
|  | 1939 | void* ns_a_handle2 = android_dlopen_ext("libnstest_ns_b_public2.so", RTLD_NOW, &extinfo); | 
|  | 1940 | ASSERT_TRUE(ns_a_handle2 != nullptr) << dlerror(); | 
|  | 1941 |  | 
|  | 1942 | void* ns_a_handle3 = android_dlopen_ext("libnstest_ns_b_public3.so", RTLD_NOW, &extinfo); | 
|  | 1943 | ASSERT_TRUE(ns_a_handle3 != nullptr) << dlerror(); | 
|  | 1944 |  | 
|  | 1945 | // Compare the dlopen handle | 
|  | 1946 | ASSERT_EQ(ns_b_handle1, ns_a_handle1); | 
|  | 1947 | ASSERT_EQ(ns_b_handle2, ns_a_handle2); | 
|  | 1948 | ASSERT_EQ(ns_b_handle3, ns_a_handle3); | 
|  | 1949 |  | 
|  | 1950 | // Close libs | 
|  | 1951 | dlclose(ns_b_handle1); | 
|  | 1952 | dlclose(ns_b_handle2); | 
|  | 1953 | dlclose(ns_b_handle3); | 
|  | 1954 |  | 
|  | 1955 | dlclose(ns_a_handle1); | 
|  | 1956 | dlclose(ns_a_handle1_internal); | 
|  | 1957 | dlclose(ns_a_handle2); | 
|  | 1958 | dlclose(ns_a_handle3); | 
|  | 1959 | } | 
|  | 1960 |  | 
| Dmitriy Ivanov | 1ffec1c | 2015-11-23 11:26:35 -0800 | [diff] [blame] | 1961 | TEST(dlext, ns_anonymous) { | 
|  | 1962 | static const char* root_lib = "libnstest_root.so"; | 
| Dimitry Ivanov | 7a34b9d | 2017-02-03 14:07:34 -0800 | [diff] [blame] | 1963 | std::string shared_libs = g_core_shared_libs + ":" + g_public_lib; | 
| Dmitriy Ivanov | 1ffec1c | 2015-11-23 11:26:35 -0800 | [diff] [blame] | 1964 |  | 
| Elliott Hughes | 8d8138a | 2024-03-12 22:37:13 +0000 | [diff] [blame] | 1965 | const std::string lib_public_path = GetTestLibRoot() + "/public_namespace_libs/" + g_public_lib; | 
| Dimitry Ivanov | 22840aa | 2015-12-04 18:28:49 -0800 | [diff] [blame] | 1966 | void* handle_public = dlopen(lib_public_path.c_str(), RTLD_NOW); | 
|  | 1967 |  | 
| Dmitriy Ivanov | 1ffec1c | 2015-11-23 11:26:35 -0800 | [diff] [blame] | 1968 | ASSERT_TRUE(handle_public != nullptr) << dlerror(); | 
|  | 1969 |  | 
| Dimitry Ivanov | 7a34b9d | 2017-02-03 14:07:34 -0800 | [diff] [blame] | 1970 | ASSERT_TRUE( | 
|  | 1971 | android_init_anonymous_namespace(shared_libs.c_str(), | 
| Elliott Hughes | 8d8138a | 2024-03-12 22:37:13 +0000 | [diff] [blame] | 1972 | (GetTestLibRoot() + "/private_namespace_libs").c_str()) | 
| Dimitry Ivanov | 7a34b9d | 2017-02-03 14:07:34 -0800 | [diff] [blame] | 1973 | ) << dlerror(); | 
| Dmitriy Ivanov | 1ffec1c | 2015-11-23 11:26:35 -0800 | [diff] [blame] | 1974 |  | 
| Dimitry Ivanov | 7a34b9d | 2017-02-03 14:07:34 -0800 | [diff] [blame] | 1975 | android_namespace_t* ns = | 
|  | 1976 | android_create_namespace("private", | 
|  | 1977 | nullptr, | 
| Elliott Hughes | 8d8138a | 2024-03-12 22:37:13 +0000 | [diff] [blame] | 1978 | (GetTestLibRoot() + "/private_namespace_libs").c_str(), | 
| Dimitry Ivanov | 7a34b9d | 2017-02-03 14:07:34 -0800 | [diff] [blame] | 1979 | ANDROID_NAMESPACE_TYPE_REGULAR, | 
|  | 1980 | nullptr, | 
|  | 1981 | nullptr); | 
| Dmitriy Ivanov | 1ffec1c | 2015-11-23 11:26:35 -0800 | [diff] [blame] | 1982 |  | 
|  | 1983 | ASSERT_TRUE(ns != nullptr) << dlerror(); | 
| Dimitry Ivanov | 7a34b9d | 2017-02-03 14:07:34 -0800 | [diff] [blame] | 1984 | ASSERT_TRUE(android_link_namespaces(ns, nullptr, shared_libs.c_str())) << dlerror(); | 
| Dmitriy Ivanov | 1ffec1c | 2015-11-23 11:26:35 -0800 | [diff] [blame] | 1985 |  | 
| Elliott Hughes | 8d8138a | 2024-03-12 22:37:13 +0000 | [diff] [blame] | 1986 | std::string private_library_absolute_path = GetTestLibRoot() + "/private_namespace_libs/" + root_lib; | 
| Dmitriy Ivanov | 1ffec1c | 2015-11-23 11:26:35 -0800 | [diff] [blame] | 1987 |  | 
|  | 1988 | android_dlextinfo extinfo; | 
|  | 1989 | extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE; | 
|  | 1990 | extinfo.library_namespace = ns; | 
|  | 1991 |  | 
|  | 1992 | // we are going to copy this library to anonymous mmap and call the copy of ns_get_dlopened_string | 
|  | 1993 | void* handle = android_dlopen_ext(private_library_absolute_path.c_str(), RTLD_NOW, &extinfo); | 
|  | 1994 | ASSERT_TRUE(handle != nullptr) << dlerror(); | 
|  | 1995 |  | 
|  | 1996 | uintptr_t ns_get_dlopened_string_addr = | 
|  | 1997 | reinterpret_cast<uintptr_t>(dlsym(handle, "ns_get_dlopened_string")); | 
|  | 1998 | ASSERT_TRUE(ns_get_dlopened_string_addr != 0) << dlerror(); | 
|  | 1999 | typedef const char* (*fn_t)(); | 
|  | 2000 | fn_t ns_get_dlopened_string_private = reinterpret_cast<fn_t>(ns_get_dlopened_string_addr); | 
|  | 2001 |  | 
|  | 2002 | std::vector<map_record> maps; | 
|  | 2003 | Maps::parse_maps(&maps); | 
|  | 2004 |  | 
|  | 2005 | uintptr_t addr_start = 0; | 
|  | 2006 | uintptr_t addr_end = 0; | 
| dimitry | 8eaf28d | 2017-10-11 10:04:14 +0200 | [diff] [blame] | 2007 | bool has_executable_segment = false; | 
| Dmitriy Ivanov | 1ffec1c | 2015-11-23 11:26:35 -0800 | [diff] [blame] | 2008 | std::vector<map_record> maps_to_copy; | 
|  | 2009 |  | 
|  | 2010 | for (const auto& rec : maps) { | 
|  | 2011 | if (rec.pathname == private_library_absolute_path) { | 
|  | 2012 | if (addr_start == 0) { | 
|  | 2013 | addr_start = rec.addr_start; | 
|  | 2014 | } | 
|  | 2015 | addr_end = rec.addr_end; | 
| dimitry | 8eaf28d | 2017-10-11 10:04:14 +0200 | [diff] [blame] | 2016 | has_executable_segment = has_executable_segment || (rec.perms & PROT_EXEC) != 0; | 
| Dmitriy Ivanov | 1ffec1c | 2015-11-23 11:26:35 -0800 | [diff] [blame] | 2017 |  | 
|  | 2018 | maps_to_copy.push_back(rec); | 
|  | 2019 | } | 
|  | 2020 | } | 
|  | 2021 |  | 
| Elliott Hughes | 68ae6ad | 2020-07-21 16:11:30 -0700 | [diff] [blame] | 2022 | // Some validity checks. | 
| Dmitriy Ivanov | 1ffec1c | 2015-11-23 11:26:35 -0800 | [diff] [blame] | 2023 | ASSERT_TRUE(addr_start > 0); | 
|  | 2024 | ASSERT_TRUE(addr_end > 0); | 
| dimitry | 3b0a5b7 | 2018-06-06 11:11:25 +0200 | [diff] [blame] | 2025 | ASSERT_TRUE(maps_to_copy.size() > 0); | 
| Dmitriy Ivanov | 1ffec1c | 2015-11-23 11:26:35 -0800 | [diff] [blame] | 2026 | ASSERT_TRUE(ns_get_dlopened_string_addr > addr_start); | 
|  | 2027 | ASSERT_TRUE(ns_get_dlopened_string_addr < addr_end); | 
|  | 2028 |  | 
| dimitry | 8eaf28d | 2017-10-11 10:04:14 +0200 | [diff] [blame] | 2029 | if (!has_executable_segment) { | 
|  | 2030 | // For some natively bridged environments this code might be missing | 
|  | 2031 | // the executable flag. This is because the guest code is not supposed | 
|  | 2032 | // to be executed directly and making it non-executable is more secure. | 
| Evgeny Eltsin | ad865d7 | 2019-12-17 18:54:17 +0100 | [diff] [blame] | 2033 | // In this case we assume the segment with the function is executable. | 
|  | 2034 | for (auto& rec : maps_to_copy) { | 
|  | 2035 | if (ns_get_dlopened_string_addr >= rec.addr_start && | 
|  | 2036 | ns_get_dlopened_string_addr < rec.addr_end) { | 
|  | 2037 | ASSERT_TRUE((rec.perms & PROT_WRITE) == 0); | 
|  | 2038 | rec.perms |= PROT_EXEC; | 
|  | 2039 | break; | 
|  | 2040 | } | 
|  | 2041 | } | 
| dimitry | 8eaf28d | 2017-10-11 10:04:14 +0200 | [diff] [blame] | 2042 | } | 
|  | 2043 |  | 
| Dmitriy Ivanov | 1ffec1c | 2015-11-23 11:26:35 -0800 | [diff] [blame] | 2044 | // copy | 
|  | 2045 | uintptr_t reserved_addr = reinterpret_cast<uintptr_t>(mmap(nullptr, addr_end - addr_start, | 
|  | 2046 | PROT_NONE, MAP_ANON | MAP_PRIVATE, | 
|  | 2047 | -1, 0)); | 
|  | 2048 | ASSERT_TRUE(reinterpret_cast<void*>(reserved_addr) != MAP_FAILED); | 
|  | 2049 |  | 
| Kalesh Singh | 4084b55 | 2024-03-13 13:35:49 -0700 | [diff] [blame] | 2050 | struct stat file_stat; | 
|  | 2051 | int ret = TEMP_FAILURE_RETRY(stat(private_library_absolute_path.c_str(), &file_stat)); | 
|  | 2052 | ASSERT_EQ(ret, 0) << "Failed to stat library"; | 
|  | 2053 | size_t file_size = file_stat.st_size; | 
|  | 2054 |  | 
| Dmitriy Ivanov | 1ffec1c | 2015-11-23 11:26:35 -0800 | [diff] [blame] | 2055 | for (const auto& rec : maps_to_copy) { | 
|  | 2056 | uintptr_t offset = rec.addr_start - addr_start; | 
|  | 2057 | size_t size = rec.addr_end - rec.addr_start; | 
|  | 2058 | void* addr = reinterpret_cast<void*>(reserved_addr + offset); | 
|  | 2059 | void* map = mmap(addr, size, PROT_READ | PROT_WRITE, | 
|  | 2060 | MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, 0); | 
|  | 2061 | ASSERT_TRUE(map != MAP_FAILED); | 
| Kalesh Singh | 4084b55 | 2024-03-13 13:35:49 -0700 | [diff] [blame] | 2062 | // Attempting the below memcpy from a portion of the map that is off the end of | 
|  | 2063 | // the backing file will cause the kernel to throw a SIGBUS | 
|  | 2064 | size_t _size = ::android::procinfo::MappedFileSize(rec.addr_start, rec.addr_end, | 
|  | 2065 | rec.offset, file_size); | 
|  | 2066 | memcpy(map, reinterpret_cast<void*>(rec.addr_start), _size); | 
| Dmitriy Ivanov | 1ffec1c | 2015-11-23 11:26:35 -0800 | [diff] [blame] | 2067 | mprotect(map, size, rec.perms); | 
|  | 2068 | } | 
|  | 2069 |  | 
|  | 2070 | // call the function copy | 
|  | 2071 | uintptr_t ns_get_dlopened_string_offset  = ns_get_dlopened_string_addr - addr_start; | 
|  | 2072 | fn_t ns_get_dlopened_string_anon = reinterpret_cast<fn_t>(reserved_addr + ns_get_dlopened_string_offset); | 
|  | 2073 | ASSERT_STREQ("This string is from private namespace (dlopened library)", | 
|  | 2074 | ns_get_dlopened_string_anon()); | 
|  | 2075 |  | 
|  | 2076 | // They should belong to different namespaces (private and anonymous) | 
|  | 2077 | ASSERT_STREQ("This string is from private namespace (dlopened library)", | 
|  | 2078 | ns_get_dlopened_string_private()); | 
|  | 2079 |  | 
|  | 2080 | ASSERT_TRUE(ns_get_dlopened_string_anon() != ns_get_dlopened_string_private()); | 
|  | 2081 | } | 
| Dimitry Ivanov | d88e1f3 | 2016-03-24 15:30:30 -0700 | [diff] [blame] | 2082 |  | 
| Ryan Prichard | 22fa3dd | 2020-01-31 14:47:48 -0800 | [diff] [blame] | 2083 | TEST(dlext, ns_hidden_child) { | 
|  | 2084 | ExecTestHelper eth; | 
|  | 2085 |  | 
| Elliott Hughes | 8d8138a | 2024-03-12 22:37:13 +0000 | [diff] [blame] | 2086 | std::string helper = GetTestLibRoot() + "/ns_hidden_child_helper"; | 
| Elliott Hughes | 8d8138a | 2024-03-12 22:37:13 +0000 | [diff] [blame] | 2087 | std::string app_ns_dir = GetTestLibRoot() + "/ns_hidden_child_app"; | 
| Ryan Prichard | 22fa3dd | 2020-01-31 14:47:48 -0800 | [diff] [blame] | 2088 | eth.SetArgs({ helper.c_str(), app_ns_dir.c_str(), nullptr }); | 
|  | 2089 |  | 
|  | 2090 | // Add the main libns_hidden_child_*.so libraries to the search path of the default namespace. | 
| Elliott Hughes | 8d8138a | 2024-03-12 22:37:13 +0000 | [diff] [blame] | 2091 | std::string env = "LD_LIBRARY_PATH=" + GetTestLibRoot(); | 
| Ryan Prichard | 22fa3dd | 2020-01-31 14:47:48 -0800 | [diff] [blame] | 2092 | eth.SetEnv({ env.c_str(), nullptr }); | 
|  | 2093 |  | 
|  | 2094 | eth.Run([&]() { execve(helper.c_str(), eth.GetArgs(), eth.GetEnv()); }, 0, | 
|  | 2095 | "public_function is non-null\n" | 
|  | 2096 | "internal_function is null\n"); | 
|  | 2097 | } | 
|  | 2098 |  | 
| Dimitry Ivanov | d88e1f3 | 2016-03-24 15:30:30 -0700 | [diff] [blame] | 2099 | TEST(dlext, dlopen_handle_value_platform) { | 
|  | 2100 | void* handle = dlopen("libtest_dlsym_from_this.so", RTLD_NOW | RTLD_LOCAL); | 
|  | 2101 | ASSERT_TRUE((reinterpret_cast<uintptr_t>(handle) & 1) != 0) | 
|  | 2102 | << "dlopen should return odd value for the handle"; | 
|  | 2103 | dlclose(handle); | 
|  | 2104 | } | 
|  | 2105 |  | 
|  | 2106 | TEST(dlext, dlopen_handle_value_app_compat) { | 
| Elliott Hughes | 95c6cd7 | 2019-12-20 13:26:14 -0800 | [diff] [blame] | 2107 | android_set_application_target_sdk_version(23); | 
| Dimitry Ivanov | d88e1f3 | 2016-03-24 15:30:30 -0700 | [diff] [blame] | 2108 | void* handle = dlopen("libtest_dlsym_from_this.so", RTLD_NOW | RTLD_LOCAL); | 
|  | 2109 | ASSERT_TRUE(reinterpret_cast<uintptr_t>(handle) % sizeof(uintptr_t) == 0) | 
|  | 2110 | << "dlopen should return valid pointer"; | 
|  | 2111 | dlclose(handle); | 
|  | 2112 | } |