1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in 12 * the documentation and/or other materials provided with the 13 * distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 18 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 19 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 22 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 25 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <stdlib.h> 30 #include <string.h> 31 #include <sys/mman.h> 32 33 #include <gtest/gtest.h> 34 35 #include "../linker_config.h" 36 #include "../linker_utils.h" 37 38 #include <unistd.h> 39 40 #include <android-base/scopeguard.h> 41 #include <android-base/stringprintf.h> 42 #include <android-base/file.h> 43 #include <android-base/test_utils.h> 44 45 #if defined(__LP64__) 46 #define ARCH_SUFFIX "64" 47 #else 48 #define ARCH_SUFFIX "" 49 #endif 50 51 static const char* config_str = 52 "# comment \n" 53 "dir.test = /data/local/tmp\n" 54 "\n" 55 "[test]\n" 56 "\n" 57 "enable.target.sdk.version = true\n" 58 "additional.namespaces=system\n" 59 "additional.namespaces+=vndk\n" 60 "namespace.default.isolated = true\n" 61 "namespace.default.search.paths = /vendor/${LIB}\n" 62 "namespace.default.permitted.paths = /vendor/${LIB}\n" 63 "namespace.default.asan.search.paths = /data\n" 64 "namespace.default.asan.search.paths += /vendor/${LIB}\n" 65 "namespace.default.asan.permitted.paths = /data:/vendor\n" 66 "namespace.default.links = system\n" 67 "namespace.default.links += vndk\n" 68 // irregular whitespaces are added intentionally for testing purpose 69 "namespace.default.link.system.shared_libs= libc.so\n" 70 "namespace.default.link.system.shared_libs += libm.so:libdl.so\n" 71 "namespace.default.link.system.shared_libs +=libstdc++.so\n" 72 "namespace.default.link.vndk.shared_libs = libcutils.so:libbase.so\n" 73 "namespace.system.isolated = true\n" 74 "namespace.system.visible = true\n" 75 "namespace.system.search.paths = /system/${LIB}\n" 76 "namespace.system.permitted.paths = /system/${LIB}\n" 77 "namespace.system.asan.search.paths = /data:/system/${LIB}\n" 78 "namespace.system.asan.permitted.paths = /data:/system\n" 79 "namespace.vndk.isolated = tr\n" 80 "namespace.vndk.isolated += ue\n" // should be ignored and return as 'false'. 81 "namespace.vndk.search.paths = /system/${LIB}/vndk\n" 82 "namespace.vndk.asan.search.paths = /data\n" 83 "namespace.vndk.asan.search.paths += /system/${LIB}/vndk\n" 84 "namespace.vndk.links = default\n" 85 "namespace.vndk.link.default.allow_all_shared_libs = true\n" 86 "\n"; 87 88 static bool write_version(const std::string& path, uint32_t version) { 89 std::string content = android::base::StringPrintf("%d", version); 90 return android::base::WriteStringToFile(content, path); 91 } 92 93 static std::vector<std::string> resolve_paths(std::vector<std::string> paths) { 94 std::vector<std::string> resolved_paths; 95 resolve_paths(paths, &resolved_paths); 96 return resolved_paths; 97 } 98 99 static void run_linker_config_smoke_test(bool is_asan) { 100 const std::vector<std::string> kExpectedDefaultSearchPath = 101 resolve_paths(is_asan ? std::vector<std::string>({ "/data", "/vendor/lib" ARCH_SUFFIX }) : 102 std::vector<std::string>({ "/vendor/lib" ARCH_SUFFIX })); 103 104 const std::vector<std::string> kExpectedDefaultPermittedPath = 105 resolve_paths(is_asan ? std::vector<std::string>({ "/data", "/vendor" }) : 106 std::vector<std::string>({ "/vendor/lib" ARCH_SUFFIX })); 107 108 const std::vector<std::string> kExpectedSystemSearchPath = 109 resolve_paths(is_asan ? std::vector<std::string>({ "/data", "/system/lib" ARCH_SUFFIX }) : 110 std::vector<std::string>({ "/system/lib" ARCH_SUFFIX })); 111 112 const std::vector<std::string> kExpectedSystemPermittedPath = 113 resolve_paths(is_asan ? std::vector<std::string>({ "/data", "/system" }) : 114 std::vector<std::string>({ "/system/lib" ARCH_SUFFIX })); 115 116 const std::vector<std::string> kExpectedVndkSearchPath = 117 resolve_paths(is_asan ? std::vector<std::string>({ "/data", "/system/lib" ARCH_SUFFIX "/vndk"}) : 118 std::vector<std::string>({ "/system/lib" ARCH_SUFFIX "/vndk"})); 119 120 TemporaryFile tmp_file; 121 close(tmp_file.fd); 122 tmp_file.fd = -1; 123 124 android::base::WriteStringToFile(config_str, tmp_file.path); 125 126 TemporaryDir tmp_dir; 127 128 std::string executable_path = std::string(tmp_dir.path) + "/some-binary"; 129 std::string version_file = std::string(tmp_dir.path) + "/.version"; 130 131 auto file_guard = 132 android::base::make_scope_guard([&version_file] { unlink(version_file.c_str()); }); 133 134 ASSERT_TRUE(write_version(version_file, 113U)) << strerror(errno); 135 136 // read config 137 const Config* config = nullptr; 138 std::string error_msg; 139 ASSERT_TRUE(Config::read_binary_config(tmp_file.path, 140 executable_path.c_str(), 141 is_asan, 142 &config, 143 &error_msg)) << error_msg; 144 ASSERT_TRUE(config != nullptr); 145 ASSERT_TRUE(error_msg.empty()); 146 147 ASSERT_EQ(113U, config->target_sdk_version()); 148 149 const NamespaceConfig* default_ns_config = config->default_namespace_config(); 150 ASSERT_TRUE(default_ns_config != nullptr); 151 152 ASSERT_TRUE(default_ns_config->isolated()); 153 ASSERT_FALSE(default_ns_config->visible()); 154 ASSERT_EQ(kExpectedDefaultSearchPath, default_ns_config->search_paths()); 155 ASSERT_EQ(kExpectedDefaultPermittedPath, default_ns_config->permitted_paths()); 156 157 const auto& default_ns_links = default_ns_config->links(); 158 ASSERT_EQ(2U, default_ns_links.size()); 159 160 ASSERT_EQ("system", default_ns_links[0].ns_name()); 161 ASSERT_EQ("libc.so:libm.so:libdl.so:libstdc++.so", default_ns_links[0].shared_libs()); 162 ASSERT_FALSE(default_ns_links[0].allow_all_shared_libs()); 163 164 ASSERT_EQ("vndk", default_ns_links[1].ns_name()); 165 ASSERT_EQ("libcutils.so:libbase.so", default_ns_links[1].shared_libs()); 166 ASSERT_FALSE(default_ns_links[1].allow_all_shared_libs()); 167 168 auto& ns_configs = config->namespace_configs(); 169 ASSERT_EQ(3U, ns_configs.size()); 170 171 // find second namespace 172 const NamespaceConfig* ns_system = nullptr; 173 const NamespaceConfig* ns_vndk = nullptr; 174 for (auto& ns : ns_configs) { 175 std::string ns_name = ns->name(); 176 ASSERT_TRUE(ns_name == "system" || ns_name == "default" || ns_name == "vndk") 177 << "unexpected ns name: " << ns->name(); 178 179 if (ns_name == "system") { 180 ns_system = ns.get(); 181 } else if (ns_name == "vndk") { 182 ns_vndk = ns.get(); 183 } 184 } 185 186 ASSERT_TRUE(ns_system != nullptr) << "system namespace was not found"; 187 188 ASSERT_TRUE(ns_system->isolated()); 189 ASSERT_TRUE(ns_system->visible()); 190 ASSERT_EQ(kExpectedSystemSearchPath, ns_system->search_paths()); 191 ASSERT_EQ(kExpectedSystemPermittedPath, ns_system->permitted_paths()); 192 193 ASSERT_TRUE(ns_vndk != nullptr) << "vndk namespace was not found"; 194 195 ASSERT_FALSE(ns_vndk->isolated()); // malformed bool property 196 ASSERT_FALSE(ns_vndk->visible()); // undefined bool property 197 ASSERT_EQ(kExpectedVndkSearchPath, ns_vndk->search_paths()); 198 199 const auto& ns_vndk_links = ns_vndk->links(); 200 ASSERT_EQ(1U, ns_vndk_links.size()); 201 ASSERT_EQ("default", ns_vndk_links[0].ns_name()); 202 ASSERT_TRUE(ns_vndk_links[0].allow_all_shared_libs()); 203 } 204 205 TEST(linker_config, smoke) { 206 run_linker_config_smoke_test(false); 207 } 208 209 TEST(linker_config, asan_smoke) { 210 run_linker_config_smoke_test(true); 211 } 212 213 TEST(linker_config, ns_link_shared_libs_invalid_settings) { 214 // This unit test ensures an error is emitted when a namespace link in ld.config.txt specifies 215 // both shared_libs and allow_all_shared_libs. 216 217 static const char config_str[] = 218 "dir.test = /data/local/tmp\n" 219 "\n" 220 "[test]\n" 221 "additional.namespaces = system\n" 222 "namespace.default.links = system\n" 223 "namespace.default.link.system.shared_libs = libc.so:libm.so\n" 224 "namespace.default.link.system.allow_all_shared_libs = true\n" 225 "\n"; 226 227 TemporaryFile tmp_file; 228 close(tmp_file.fd); 229 tmp_file.fd = -1; 230 231 android::base::WriteStringToFile(config_str, tmp_file.path); 232 233 TemporaryDir tmp_dir; 234 235 std::string executable_path = std::string(tmp_dir.path) + "/some-binary"; 236 237 const Config* config = nullptr; 238 std::string error_msg; 239 ASSERT_FALSE(Config::read_binary_config(tmp_file.path, 240 executable_path.c_str(), 241 false, 242 &config, 243 &error_msg)); 244 ASSERT_TRUE(config == nullptr); 245 ASSERT_EQ(std::string(tmp_file.path) + ":6: " 246 "error: both shared_libs and allow_all_shared_libs are set for default->system link.", 247 error_msg); 248 } 249