native_loader.cpp revision 39da84b06cf53f87ae535a685b315c1584bba7cb
1/* 2 * Copyright (C) 2015 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 "nativeloader/native_loader.h" 18#include "ScopedUtfChars.h" 19 20#include <dlfcn.h> 21#ifdef __ANDROID__ 22#include "dlext_namespaces.h" 23#include "cutils/properties.h" 24#include "log/log.h" 25#endif 26 27#include <algorithm> 28#include <vector> 29#include <string> 30#include <mutex> 31 32#include "android-base/file.h" 33#include "android-base/macros.h" 34#include "android-base/strings.h" 35 36namespace android { 37 38#if defined(__ANDROID__) 39static constexpr const char* kPublicNativeLibrariesSystemConfigPathFromRoot = "/etc/public.libraries.txt"; 40static constexpr const char* kPublicNativeLibrariesVendorConfig = "/vendor/etc/public.libraries.txt"; 41 42// (http://b/27588281) This is a workaround for apps using custom classloaders and calling 43// System.load() with an absolute path which is outside of the classloader library search path. 44// This list includes all directories app is allowed to access this way. 45static constexpr const char* kWhitelistedDirectories = "/data:/mnt/expand"; 46 47static bool is_debuggable() { 48 char debuggable[PROP_VALUE_MAX]; 49 property_get("ro.debuggable", debuggable, "0"); 50 return std::string(debuggable) == "1"; 51} 52 53class LibraryNamespaces { 54 public: 55 LibraryNamespaces() : initialized_(false) { } 56 57 android_namespace_t* Create(JNIEnv* env, 58 jobject class_loader, 59 bool is_shared, 60 jstring java_library_path, 61 jstring java_permitted_path) { 62 std::string library_path; // empty string by default. 63 64 if (java_library_path != nullptr) { 65 ScopedUtfChars library_path_utf_chars(env, java_library_path); 66 library_path = library_path_utf_chars.c_str(); 67 } 68 69 // (http://b/27588281) This is a workaround for apps using custom 70 // classloaders and calling System.load() with an absolute path which 71 // is outside of the classloader library search path. 72 // 73 // This part effectively allows such a classloader to access anything 74 // under /data and /mnt/expand 75 std::string permitted_path = kWhitelistedDirectories; 76 77 if (java_permitted_path != nullptr) { 78 ScopedUtfChars path(env, java_permitted_path); 79 if (path.c_str() != nullptr && path.size() > 0) { 80 permitted_path = permitted_path + ":" + path.c_str(); 81 } 82 } 83 84 if (!initialized_ && !InitPublicNamespace(library_path.c_str())) { 85 return nullptr; 86 } 87 88 android_namespace_t* ns = FindNamespaceByClassLoader(env, class_loader); 89 90 LOG_ALWAYS_FATAL_IF(ns != nullptr, 91 "There is already a namespace associated with this classloader"); 92 93 uint64_t namespace_type = ANDROID_NAMESPACE_TYPE_ISOLATED; 94 if (is_shared) { 95 namespace_type |= ANDROID_NAMESPACE_TYPE_SHARED; 96 } 97 98 android_namespace_t* parent_ns = FindParentNamespaceByClassLoader(env, class_loader); 99 100 ns = android_create_namespace("classloader-namespace", 101 nullptr, 102 library_path.c_str(), 103 namespace_type, 104 permitted_path.c_str(), 105 parent_ns); 106 107 if (ns != nullptr) { 108 namespaces_.push_back(std::make_pair(env->NewWeakGlobalRef(class_loader), ns)); 109 } 110 111 return ns; 112 } 113 114 android_namespace_t* FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader) { 115 auto it = std::find_if(namespaces_.begin(), namespaces_.end(), 116 [&](const std::pair<jweak, android_namespace_t*>& value) { 117 return env->IsSameObject(value.first, class_loader); 118 }); 119 return it != namespaces_.end() ? it->second : nullptr; 120 } 121 122 void Initialize() { 123 // Once public namespace is initialized there is no 124 // point in running this code - it will have no effect 125 // on the current list of public libraries. 126 if (initialized_) { 127 return; 128 } 129 130 std::vector<std::string> sonames; 131 const char* android_root_env = getenv("ANDROID_ROOT"); 132 std::string root_dir = android_root_env != nullptr ? android_root_env : "/system"; 133 std::string public_native_libraries_system_config = 134 root_dir + kPublicNativeLibrariesSystemConfigPathFromRoot; 135 136 std::string error_msg; 137 LOG_ALWAYS_FATAL_IF(!ReadConfig(public_native_libraries_system_config, &sonames, &error_msg), 138 "Error reading public native library list from \"%s\": %s", 139 public_native_libraries_system_config.c_str(), error_msg.c_str()); 140 141 // For debuggable platform builds use ANDROID_ADDITIONAL_PUBLIC_LIBRARIES environment 142 // variable to add libraries to the list. This is intended for platform tests only. 143 if (is_debuggable()) { 144 const char* additional_libs = getenv("ANDROID_ADDITIONAL_PUBLIC_LIBRARIES"); 145 if (additional_libs != nullptr && additional_libs[0] != '\0') { 146 std::vector<std::string> additional_libs_vector = base::Split(additional_libs, ":"); 147 std::copy(additional_libs_vector.begin(), 148 additional_libs_vector.end(), 149 std::back_inserter(sonames)); 150 } 151 } 152 153 // This file is optional, quietly ignore if the file does not exist. 154 ReadConfig(kPublicNativeLibrariesVendorConfig, &sonames); 155 156 // android_init_namespaces() expects all the public libraries 157 // to be loaded so that they can be found by soname alone. 158 // 159 // TODO(dimitry): this is a bit misleading since we do not know 160 // if the vendor public library is going to be opened from /vendor/lib 161 // we might as well end up loading them from /system/lib 162 // For now we rely on CTS test to catch things like this but 163 // it should probably be addressed in the future. 164 for (const auto& soname : sonames) { 165 dlopen(soname.c_str(), RTLD_NOW | RTLD_NODELETE); 166 } 167 168 public_libraries_ = base::Join(sonames, ':'); 169 } 170 171 void Reset() { 172 namespaces_.clear(); 173 } 174 175 private: 176 bool ReadConfig(const std::string& configFile, std::vector<std::string>* sonames, 177 std::string* error_msg = nullptr) { 178 // Read list of public native libraries from the config file. 179 std::string file_content; 180 if(!base::ReadFileToString(configFile, &file_content)) { 181 if (error_msg) *error_msg = strerror(errno); 182 return false; 183 } 184 185 std::vector<std::string> lines = base::Split(file_content, "\n"); 186 187 for (auto& line : lines) { 188 auto trimmed_line = base::Trim(line); 189 if (trimmed_line[0] == '#' || trimmed_line.empty()) { 190 continue; 191 } 192 size_t space_pos = trimmed_line.rfind(' '); 193 if (space_pos != std::string::npos) { 194 std::string type = trimmed_line.substr(space_pos + 1); 195 if (type != "32" && type != "64") { 196 if (error_msg) *error_msg = "Malformed line: " + line; 197 return false; 198 } 199#if defined(__LP64__) 200 // Skip 32 bit public library. 201 if (type == "32") { 202 continue; 203 } 204#else 205 // Skip 64 bit public library. 206 if (type == "64") { 207 continue; 208 } 209#endif 210 trimmed_line.resize(space_pos); 211 } 212 213 sonames->push_back(trimmed_line); 214 } 215 216 return true; 217 } 218 219 bool InitPublicNamespace(const char* library_path) { 220 // (http://b/25844435) - Some apps call dlopen from generated code (mono jited 221 // code is one example) unknown to linker in which case linker uses anonymous 222 // namespace. The second argument specifies the search path for the anonymous 223 // namespace which is the library_path of the classloader. 224 initialized_ = android_init_namespaces(public_libraries_.c_str(), library_path); 225 226 return initialized_; 227 } 228 229 jobject GetParentClassLoader(JNIEnv* env, jobject class_loader) { 230 jclass class_loader_class = env->FindClass("java/lang/ClassLoader"); 231 jmethodID get_parent = env->GetMethodID(class_loader_class, 232 "getParent", 233 "()Ljava/lang/ClassLoader;"); 234 235 return env->CallObjectMethod(class_loader, get_parent); 236 } 237 238 android_namespace_t* FindParentNamespaceByClassLoader(JNIEnv* env, jobject class_loader) { 239 jobject parent_class_loader = GetParentClassLoader(env, class_loader); 240 241 while (parent_class_loader != nullptr) { 242 android_namespace_t* ns = FindNamespaceByClassLoader(env, parent_class_loader); 243 if (ns != nullptr) { 244 return ns; 245 } 246 247 parent_class_loader = GetParentClassLoader(env, parent_class_loader); 248 } 249 return nullptr; 250 } 251 252 bool initialized_; 253 std::vector<std::pair<jweak, android_namespace_t*>> namespaces_; 254 std::string public_libraries_; 255 256 257 DISALLOW_COPY_AND_ASSIGN(LibraryNamespaces); 258}; 259 260static std::mutex g_namespaces_mutex; 261static LibraryNamespaces* g_namespaces = new LibraryNamespaces; 262#endif 263 264void InitializeNativeLoader() { 265#if defined(__ANDROID__) 266 std::lock_guard<std::mutex> guard(g_namespaces_mutex); 267 g_namespaces->Initialize(); 268#endif 269} 270 271void ResetNativeLoader() { 272#if defined(__ANDROID__) 273 std::lock_guard<std::mutex> guard(g_namespaces_mutex); 274 g_namespaces->Reset(); 275#endif 276} 277 278jstring CreateClassLoaderNamespace(JNIEnv* env, 279 int32_t target_sdk_version, 280 jobject class_loader, 281 bool is_shared, 282 jstring library_path, 283 jstring permitted_path) { 284#if defined(__ANDROID__) 285 UNUSED(target_sdk_version); 286 std::lock_guard<std::mutex> guard(g_namespaces_mutex); 287 android_namespace_t* ns = g_namespaces->Create(env, 288 class_loader, 289 is_shared, 290 library_path, 291 permitted_path); 292 if (ns == nullptr) { 293 return env->NewStringUTF(dlerror()); 294 } 295#else 296 UNUSED(env, target_sdk_version, class_loader, is_shared, 297 library_path, permitted_path); 298#endif 299 return nullptr; 300} 301 302void* OpenNativeLibrary(JNIEnv* env, 303 int32_t target_sdk_version, 304 const char* path, 305 jobject class_loader, 306 jstring library_path) { 307#if defined(__ANDROID__) 308 UNUSED(target_sdk_version); 309 if (class_loader == nullptr) { 310 return dlopen(path, RTLD_NOW); 311 } 312 313 std::lock_guard<std::mutex> guard(g_namespaces_mutex); 314 android_namespace_t* ns = g_namespaces->FindNamespaceByClassLoader(env, class_loader); 315 316 if (ns == nullptr) { 317 // This is the case where the classloader was not created by ApplicationLoaders 318 // In this case we create an isolated not-shared namespace for it. 319 ns = g_namespaces->Create(env, class_loader, false, library_path, nullptr); 320 if (ns == nullptr) { 321 return nullptr; 322 } 323 } 324 325 android_dlextinfo extinfo; 326 extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE; 327 extinfo.library_namespace = ns; 328 329 return android_dlopen_ext(path, RTLD_NOW, &extinfo); 330#else 331 UNUSED(env, target_sdk_version, class_loader, library_path); 332 return dlopen(path, RTLD_NOW); 333#endif 334} 335 336bool CloseNativeLibrary(void* handle) { 337 return dlclose(handle) == 0; 338} 339 340#if defined(__ANDROID__) 341android_namespace_t* FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader) { 342 std::lock_guard<std::mutex> guard(g_namespaces_mutex); 343 return g_namespaces->FindNamespaceByClassLoader(env, class_loader); 344} 345#endif 346 347}; // android namespace 348