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/file.h> 41 #include <android-base/scopeguard.h> 42 #include <android-base/stringprintf.h> 43 44 #if defined(__LP64__) 45 #define ARCH_SUFFIX "64" 46 #else 47 #define ARCH_SUFFIX "" 48 #endif 49 50 static const char* config_str = 51 "# comment \n" 52 "dir.test = /data/local/tmp\n" 53 "\n" 54 "[test]\n" 55 "\n" 56 "enable.target.sdk.version = true\n" 57 "additional.namespaces=system\n" 58 "additional.namespaces+=vndk\n" 59 "additional.namespaces+=vndk_in_system\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 "namespace.vndk.link.vndk_in_system.allow_all_shared_libs = true\n" 87 "namespace.vndk_in_system.isolated = true\n" 88 "namespace.vndk_in_system.visible = true\n" 89 "namespace.vndk_in_system.search.paths = /system/${LIB}\n" 90 "namespace.vndk_in_system.permitted.paths = /system/${LIB}\n" 91 "namespace.vndk_in_system.whitelisted = libz.so:libyuv.so:libtinyxml2.so\n" 92 "\n"; 93 94 static bool write_version(const std::string& path, uint32_t version) { 95 std::string content = android::base::StringPrintf("%d", version); 96 return android::base::WriteStringToFile(content, path); 97 } 98 99 static std::vector<std::string> resolve_paths(std::vector<std::string> paths) { 100 std::vector<std::string> resolved_paths; 101 resolve_paths(paths, &resolved_paths); 102 return resolved_paths; 103 } 104 105 static void run_linker_config_smoke_test(bool is_asan) { 106 const std::vector<std::string> kExpectedDefaultSearchPath = 107 resolve_paths(is_asan ? std::vector<std::string>({ "/data", "/vendor/lib" ARCH_SUFFIX }) : 108 std::vector<std::string>({ "/vendor/lib" ARCH_SUFFIX })); 109 110 const std::vector<std::string> kExpectedDefaultPermittedPath = 111 resolve_paths(is_asan ? std::vector<std::string>({ "/data", "/vendor" }) : 112 std::vector<std::string>({ "/vendor/lib" ARCH_SUFFIX })); 113 114 const std::vector<std::string> kExpectedSystemSearchPath = 115 resolve_paths(is_asan ? std::vector<std::string>({ "/data", "/system/lib" ARCH_SUFFIX }) : 116 std::vector<std::string>({ "/system/lib" ARCH_SUFFIX })); 117 118 const std::vector<std::string> kExpectedSystemPermittedPath = 119 resolve_paths(is_asan ? std::vector<std::string>({ "/data", "/system" }) : 120 std::vector<std::string>({ "/system/lib" ARCH_SUFFIX })); 121 122 const std::vector<std::string> kExpectedVndkSearchPath = 123 resolve_paths(is_asan ? std::vector<std::string>({ "/data", "/system/lib" ARCH_SUFFIX "/vndk"}) : 124 std::vector<std::string>({ "/system/lib" ARCH_SUFFIX "/vndk"})); 125 126 TemporaryFile tmp_file; 127 close(tmp_file.fd); 128 tmp_file.fd = -1; 129 130 android::base::WriteStringToFile(config_str, tmp_file.path); 131 132 TemporaryDir tmp_dir; 133 134 std::string executable_path = std::string(tmp_dir.path) + "/some-binary"; 135 std::string version_file = std::string(tmp_dir.path) + "/.version"; 136 137 auto file_guard = 138 android::base::make_scope_guard([&version_file] { unlink(version_file.c_str()); }); 139 140 ASSERT_TRUE(write_version(version_file, 113U)) << strerror(errno); 141 142 // read config 143 const Config* config = nullptr; 144 std::string error_msg; 145 ASSERT_TRUE(Config::read_binary_config(tmp_file.path, 146 executable_path.c_str(), 147 is_asan, 148 &config, 149 &error_msg)) << error_msg; 150 ASSERT_TRUE(config != nullptr); 151 ASSERT_TRUE(error_msg.empty()); 152 153 ASSERT_EQ(113, config->target_sdk_version()); 154 155 const NamespaceConfig* default_ns_config = config->default_namespace_config(); 156 ASSERT_TRUE(default_ns_config != nullptr); 157 158 ASSERT_TRUE(default_ns_config->isolated()); 159 ASSERT_FALSE(default_ns_config->visible()); 160 ASSERT_EQ(kExpectedDefaultSearchPath, default_ns_config->search_paths()); 161 ASSERT_EQ(kExpectedDefaultPermittedPath, default_ns_config->permitted_paths()); 162 163 const auto& default_ns_links = default_ns_config->links(); 164 ASSERT_EQ(2U, default_ns_links.size()); 165 166 ASSERT_EQ("system", default_ns_links[0].ns_name()); 167 ASSERT_EQ("libc.so:libm.so:libdl.so:libstdc++.so", default_ns_links[0].shared_libs()); 168 ASSERT_FALSE(default_ns_links[0].allow_all_shared_libs()); 169 170 ASSERT_EQ("vndk", default_ns_links[1].ns_name()); 171 ASSERT_EQ("libcutils.so:libbase.so", default_ns_links[1].shared_libs()); 172 ASSERT_FALSE(default_ns_links[1].allow_all_shared_libs()); 173 174 auto& ns_configs = config->namespace_configs(); 175 ASSERT_EQ(4U, ns_configs.size()); 176 177 // find second namespace 178 const NamespaceConfig* ns_system = nullptr; 179 const NamespaceConfig* ns_vndk = nullptr; 180 const NamespaceConfig* ns_vndk_in_system = nullptr; 181 for (auto& ns : ns_configs) { 182 std::string ns_name = ns->name(); 183 ASSERT_TRUE(ns_name == "system" || ns_name == "default" || 184 ns_name == "vndk" || ns_name == "vndk_in_system") 185 << "unexpected ns name: " << ns->name(); 186 187 if (ns_name == "system") { 188 ns_system = ns.get(); 189 } else if (ns_name == "vndk") { 190 ns_vndk = ns.get(); 191 } else if (ns_name == "vndk_in_system") { 192 ns_vndk_in_system = ns.get(); 193 } 194 } 195 196 ASSERT_TRUE(ns_system != nullptr) << "system namespace was not found"; 197 198 ASSERT_TRUE(ns_system->isolated()); 199 ASSERT_TRUE(ns_system->visible()); 200 ASSERT_EQ(kExpectedSystemSearchPath, ns_system->search_paths()); 201 ASSERT_EQ(kExpectedSystemPermittedPath, ns_system->permitted_paths()); 202 203 ASSERT_TRUE(ns_vndk != nullptr) << "vndk namespace was not found"; 204 205 ASSERT_FALSE(ns_vndk->isolated()); // malformed bool property 206 ASSERT_FALSE(ns_vndk->visible()); // undefined bool property 207 ASSERT_EQ(kExpectedVndkSearchPath, ns_vndk->search_paths()); 208 209 const auto& ns_vndk_links = ns_vndk->links(); 210 ASSERT_EQ(1U, ns_vndk_links.size()); 211 ASSERT_EQ("default", ns_vndk_links[0].ns_name()); 212 ASSERT_TRUE(ns_vndk_links[0].allow_all_shared_libs()); 213 214 ASSERT_TRUE(ns_vndk_in_system != nullptr) << "vndk_in_system namespace was not found"; 215 ASSERT_EQ( 216 std::vector<std::string>({"libz.so", "libyuv.so", "libtinyxml2.so"}), 217 ns_vndk_in_system->whitelisted_libs()); 218 } 219 220 TEST(linker_config, smoke) { 221 run_linker_config_smoke_test(false); 222 } 223 224 TEST(linker_config, asan_smoke) { 225 run_linker_config_smoke_test(true); 226 } 227 228 TEST(linker_config, ns_link_shared_libs_invalid_settings) { 229 // This unit test ensures an error is emitted when a namespace link in ld.config.txt specifies 230 // both shared_libs and allow_all_shared_libs. 231 232 static const char config_str[] = 233 "dir.test = /data/local/tmp\n" 234 "\n" 235 "[test]\n" 236 "additional.namespaces = system\n" 237 "namespace.default.links = system\n" 238 "namespace.default.link.system.shared_libs = libc.so:libm.so\n" 239 "namespace.default.link.system.allow_all_shared_libs = true\n" 240 "\n"; 241 242 TemporaryFile tmp_file; 243 close(tmp_file.fd); 244 tmp_file.fd = -1; 245 246 android::base::WriteStringToFile(config_str, tmp_file.path); 247 248 TemporaryDir tmp_dir; 249 250 std::string executable_path = std::string(tmp_dir.path) + "/some-binary"; 251 252 const Config* config = nullptr; 253 std::string error_msg; 254 ASSERT_FALSE(Config::read_binary_config(tmp_file.path, 255 executable_path.c_str(), 256 false, 257 &config, 258 &error_msg)); 259 ASSERT_TRUE(config == nullptr); 260 ASSERT_EQ(std::string(tmp_file.path) + ":6: " 261 "error: both shared_libs and allow_all_shared_libs are set for default->system link.", 262 error_msg); 263 } 264 265 TEST(linker_config, dir_path_resolve) { 266 // This unit test ensures the linker resolves paths of dir.${section} 267 // properties to real path. 268 269 TemporaryDir tmp_dir; 270 271 std::string sub_dir = std::string(tmp_dir.path) + "/subdir"; 272 mkdir(sub_dir.c_str(), 0755); 273 274 auto subdir_guard = 275 android::base::make_scope_guard([&sub_dir] { rmdir(sub_dir.c_str()); }); 276 277 std::string symlink_path = std::string(tmp_dir.path) + "/symlink"; 278 symlink(sub_dir.c_str(), symlink_path.c_str()); 279 280 auto symlink_guard = 281 android::base::make_scope_guard([&symlink_path] { unlink(symlink_path.c_str()); }); 282 283 std::string config_str = 284 "dir.test = " + symlink_path + "\n" 285 "\n" 286 "[test]\n"; 287 288 TemporaryFile tmp_file; 289 close(tmp_file.fd); 290 tmp_file.fd = -1; 291 292 android::base::WriteStringToFile(config_str, tmp_file.path); 293 294 std::string executable_path = sub_dir + "/some-binary"; 295 296 const Config* config = nullptr; 297 std::string error_msg; 298 299 ASSERT_TRUE(Config::read_binary_config(tmp_file.path, 300 executable_path.c_str(), 301 false, 302 &config, 303 &error_msg)) << error_msg; 304 305 ASSERT_TRUE(config != nullptr) << error_msg; 306 ASSERT_TRUE(error_msg.empty()) << error_msg; 307 } 308