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 
is_debuggable()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:
LibraryNamespaces()56   LibraryNamespaces() : initialized_(false) { }
57 
Create(JNIEnv * env,jobject class_loader,bool is_shared,jstring java_library_path,jstring java_permitted_path)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 
FindNamespaceByClassLoader(JNIEnv * env,jobject class_loader)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 
Initialize()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     LOG_ALWAYS_FATAL_IF(!ReadConfig(public_native_libraries_system_config, &sonames),
131                         "Error reading public native library list from \"%s\": %s",
132                         public_native_libraries_system_config.c_str(), strerror(errno));
133 
134     // For debuggable platform builds use ANDROID_ADDITIONAL_PUBLIC_LIBRARIES environment
135     // variable to add libraries to the list. This is intended for platform tests only.
136     if (is_debuggable()) {
137       const char* additional_libs = getenv("ANDROID_ADDITIONAL_PUBLIC_LIBRARIES");
138       if (additional_libs != nullptr && additional_libs[0] != '\0') {
139         std::vector<std::string> additional_libs_vector = base::Split(additional_libs, ":");
140         std::copy(additional_libs_vector.begin(),
141                   additional_libs_vector.end(),
142                   std::back_inserter(sonames));
143       }
144     }
145 
146     // This file is optional, quietly ignore if the file does not exist.
147     ReadConfig(kPublicNativeLibrariesVendorConfig, &sonames);
148 
149     // android_init_namespaces() expects all the public libraries
150     // to be loaded so that they can be found by soname alone.
151     //
152     // TODO(dimitry): this is a bit misleading since we do not know
153     // if the vendor public library is going to be opened from /vendor/lib
154     // we might as well end up loading them from /system/lib
155     // For now we rely on CTS test to catch things like this but
156     // it should probably be addressed in the future.
157     for (const auto& soname : sonames) {
158       dlopen(soname.c_str(), RTLD_NOW | RTLD_NODELETE);
159     }
160 
161     public_libraries_ = base::Join(sonames, ':');
162   }
163 
Reset()164   void Reset() {
165     namespaces_.clear();
166   }
167 
168  private:
ReadConfig(const std::string & configFile,std::vector<std::string> * sonames)169   bool ReadConfig(const std::string& configFile, std::vector<std::string>* sonames) {
170     // Read list of public native libraries from the config file.
171     std::string file_content;
172     if(!base::ReadFileToString(configFile, &file_content)) {
173       return false;
174     }
175 
176     std::vector<std::string> lines = base::Split(file_content, "\n");
177 
178     for (const auto& line : lines) {
179       auto trimmed_line = base::Trim(line);
180       if (trimmed_line[0] == '#' || trimmed_line.empty()) {
181         continue;
182       }
183 
184       sonames->push_back(trimmed_line);
185     }
186 
187     return true;
188   }
189 
InitPublicNamespace(const char * library_path)190   bool InitPublicNamespace(const char* library_path) {
191     // (http://b/25844435) - Some apps call dlopen from generated code (mono jited
192     // code is one example) unknown to linker in which  case linker uses anonymous
193     // namespace. The second argument specifies the search path for the anonymous
194     // namespace which is the library_path of the classloader.
195     initialized_ = android_init_namespaces(public_libraries_.c_str(), library_path);
196 
197     return initialized_;
198   }
199 
GetParentClassLoader(JNIEnv * env,jobject class_loader)200   jobject GetParentClassLoader(JNIEnv* env, jobject class_loader) {
201     jclass class_loader_class = env->FindClass("java/lang/ClassLoader");
202     jmethodID get_parent = env->GetMethodID(class_loader_class,
203                                             "getParent",
204                                             "()Ljava/lang/ClassLoader;");
205 
206     return env->CallObjectMethod(class_loader, get_parent);
207   }
208 
FindParentNamespaceByClassLoader(JNIEnv * env,jobject class_loader)209   android_namespace_t* FindParentNamespaceByClassLoader(JNIEnv* env, jobject class_loader) {
210     jobject parent_class_loader = GetParentClassLoader(env, class_loader);
211 
212     while (parent_class_loader != nullptr) {
213       android_namespace_t* ns = FindNamespaceByClassLoader(env, parent_class_loader);
214       if (ns != nullptr) {
215         return ns;
216       }
217 
218       parent_class_loader = GetParentClassLoader(env, parent_class_loader);
219     }
220     return nullptr;
221   }
222 
223   bool initialized_;
224   std::vector<std::pair<jweak, android_namespace_t*>> namespaces_;
225   std::string public_libraries_;
226 
227 
228   DISALLOW_COPY_AND_ASSIGN(LibraryNamespaces);
229 };
230 
231 static std::mutex g_namespaces_mutex;
232 static LibraryNamespaces* g_namespaces = new LibraryNamespaces;
233 #endif
234 
InitializeNativeLoader()235 void InitializeNativeLoader() {
236 #if defined(__ANDROID__)
237   std::lock_guard<std::mutex> guard(g_namespaces_mutex);
238   g_namespaces->Initialize();
239 #endif
240 }
241 
ResetNativeLoader()242 void ResetNativeLoader() {
243 #if defined(__ANDROID__)
244   std::lock_guard<std::mutex> guard(g_namespaces_mutex);
245   g_namespaces->Reset();
246 #endif
247 }
248 
CreateClassLoaderNamespace(JNIEnv * env,int32_t target_sdk_version,jobject class_loader,bool is_shared,jstring library_path,jstring permitted_path)249 jstring CreateClassLoaderNamespace(JNIEnv* env,
250                                    int32_t target_sdk_version,
251                                    jobject class_loader,
252                                    bool is_shared,
253                                    jstring library_path,
254                                    jstring permitted_path) {
255 #if defined(__ANDROID__)
256   UNUSED(target_sdk_version);
257   std::lock_guard<std::mutex> guard(g_namespaces_mutex);
258   android_namespace_t* ns = g_namespaces->Create(env,
259                                                  class_loader,
260                                                  is_shared,
261                                                  library_path,
262                                                  permitted_path);
263   if (ns == nullptr) {
264     return env->NewStringUTF(dlerror());
265   }
266 #else
267   UNUSED(env, target_sdk_version, class_loader, is_shared,
268          library_path, permitted_path);
269 #endif
270   return nullptr;
271 }
272 
OpenNativeLibrary(JNIEnv * env,int32_t target_sdk_version,const char * path,jobject class_loader,jstring library_path)273 void* OpenNativeLibrary(JNIEnv* env,
274                         int32_t target_sdk_version,
275                         const char* path,
276                         jobject class_loader,
277                         jstring library_path) {
278 #if defined(__ANDROID__)
279   UNUSED(target_sdk_version);
280   if (class_loader == nullptr) {
281     return dlopen(path, RTLD_NOW);
282   }
283 
284   std::lock_guard<std::mutex> guard(g_namespaces_mutex);
285   android_namespace_t* ns = g_namespaces->FindNamespaceByClassLoader(env, class_loader);
286 
287   if (ns == nullptr) {
288     // This is the case where the classloader was not created by ApplicationLoaders
289     // In this case we create an isolated not-shared namespace for it.
290     ns = g_namespaces->Create(env, class_loader, false, library_path, nullptr);
291     if (ns == nullptr) {
292       return nullptr;
293     }
294   }
295 
296   android_dlextinfo extinfo;
297   extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
298   extinfo.library_namespace = ns;
299 
300   return android_dlopen_ext(path, RTLD_NOW, &extinfo);
301 #else
302   UNUSED(env, target_sdk_version, class_loader, library_path);
303   return dlopen(path, RTLD_NOW);
304 #endif
305 }
306 
CloseNativeLibrary(void * handle)307 bool CloseNativeLibrary(void* handle) {
308   return dlclose(handle) == 0;
309 }
310 
311 #if defined(__ANDROID__)
FindNamespaceByClassLoader(JNIEnv * env,jobject class_loader)312 android_namespace_t* FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader) {
313   std::lock_guard<std::mutex> guard(g_namespaces_mutex);
314   return g_namespaces->FindNamespaceByClassLoader(env, class_loader);
315 }
316 #endif
317 
318 }; //  android namespace
319