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