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 #define LOG_TAG "nativeloader"
18 
19 #include "nativeloader/native_loader.h"
20 
21 #include <dlfcn.h>
22 #include <sys/types.h>
23 
24 #include <algorithm>
25 #include <memory>
26 #include <mutex>
27 #include <string>
28 #include <vector>
29 
30 #include <android-base/file.h>
31 #include <android-base/macros.h>
32 #include <android-base/strings.h>
33 #include <nativebridge/native_bridge.h>
34 #include <nativehelper/scoped_utf_chars.h>
35 
36 #ifdef __ANDROID__
37 #include <log/log.h>
38 #include "library_namespaces.h"
39 #include "nativeloader/dlext_namespaces.h"
40 #endif
41 
42 namespace android {
43 
44 namespace {
45 #if defined(__ANDROID__)
46 using android::nativeloader::LibraryNamespaces;
47 
48 constexpr const char* kApexPath = "/apex/";
49 
50 std::mutex g_namespaces_mutex;
51 LibraryNamespaces* g_namespaces = new LibraryNamespaces;
52 
FindExportedNamespace(const char * caller_location)53 android_namespace_t* FindExportedNamespace(const char* caller_location) {
54   std::string location = caller_location;
55   // Lots of implicit assumptions here: we expect `caller_location` to be of the form:
56   // /apex/modulename/...
57   //
58   // And we extract from it 'modulename', which is the name of the linker namespace.
59   if (android::base::StartsWith(location, kApexPath)) {
60     size_t start_index = strlen(kApexPath);
61     size_t slash_index = location.find_first_of('/', start_index);
62     LOG_ALWAYS_FATAL_IF((slash_index == std::string::npos),
63                         "Error finding namespace of apex: no slash in path %s", caller_location);
64     std::string name = location.substr(start_index, slash_index - start_index);
65     std::replace(name.begin(), name.end(), '.', '_');
66     android_namespace_t* boot_namespace = android_get_exported_namespace(name.c_str());
67     LOG_ALWAYS_FATAL_IF((boot_namespace == nullptr),
68                         "Error finding namespace of apex: no namespace called %s", name.c_str());
69     return boot_namespace;
70   }
71   return nullptr;
72 }
73 #endif  // #if defined(__ANDROID__)
74 }  // namespace
75 
InitializeNativeLoader()76 void InitializeNativeLoader() {
77 #if defined(__ANDROID__)
78   std::lock_guard<std::mutex> guard(g_namespaces_mutex);
79   g_namespaces->Initialize();
80 #endif
81 }
82 
ResetNativeLoader()83 void ResetNativeLoader() {
84 #if defined(__ANDROID__)
85   std::lock_guard<std::mutex> guard(g_namespaces_mutex);
86   g_namespaces->Reset();
87 #endif
88 }
89 
CreateClassLoaderNamespace(JNIEnv * env,int32_t target_sdk_version,jobject class_loader,bool is_shared,jstring dex_path,jstring library_path,jstring permitted_path)90 jstring CreateClassLoaderNamespace(JNIEnv* env, int32_t target_sdk_version, jobject class_loader,
91                                    bool is_shared, jstring dex_path, jstring library_path,
92                                    jstring permitted_path) {
93 #if defined(__ANDROID__)
94   std::lock_guard<std::mutex> guard(g_namespaces_mutex);
95   auto ns = g_namespaces->Create(env, target_sdk_version, class_loader, is_shared, dex_path,
96                                  library_path, permitted_path);
97   if (!ns.ok()) {
98     return env->NewStringUTF(ns.error().message().c_str());
99   }
100 #else
101   UNUSED(env, target_sdk_version, class_loader, is_shared, dex_path, library_path, permitted_path);
102 #endif
103   return nullptr;
104 }
105 
OpenNativeLibrary(JNIEnv * env,int32_t target_sdk_version,const char * path,jobject class_loader,const char * caller_location,jstring library_path,bool * needs_native_bridge,char ** error_msg)106 void* OpenNativeLibrary(JNIEnv* env, int32_t target_sdk_version, const char* path,
107                         jobject class_loader, const char* caller_location, jstring library_path,
108                         bool* needs_native_bridge, char** error_msg) {
109 #if defined(__ANDROID__)
110   UNUSED(target_sdk_version);
111   if (class_loader == nullptr) {
112     *needs_native_bridge = false;
113     if (caller_location != nullptr) {
114       android_namespace_t* boot_namespace = FindExportedNamespace(caller_location);
115       if (boot_namespace != nullptr) {
116         const android_dlextinfo dlextinfo = {
117             .flags = ANDROID_DLEXT_USE_NAMESPACE,
118             .library_namespace = boot_namespace,
119         };
120         void* handle = android_dlopen_ext(path, RTLD_NOW, &dlextinfo);
121         if (handle == nullptr) {
122           *error_msg = strdup(dlerror());
123         }
124         return handle;
125       }
126     }
127     void* handle = dlopen(path, RTLD_NOW);
128     if (handle == nullptr) {
129       *error_msg = strdup(dlerror());
130     }
131     return handle;
132   }
133 
134   std::lock_guard<std::mutex> guard(g_namespaces_mutex);
135   NativeLoaderNamespace* ns;
136 
137   if ((ns = g_namespaces->FindNamespaceByClassLoader(env, class_loader)) == nullptr) {
138     // This is the case where the classloader was not created by ApplicationLoaders
139     // In this case we create an isolated not-shared namespace for it.
140     Result<NativeLoaderNamespace*> isolated_ns =
141         g_namespaces->Create(env, target_sdk_version, class_loader, false /* is_shared */, nullptr,
142                              library_path, nullptr);
143     if (!isolated_ns.ok()) {
144       *error_msg = strdup(isolated_ns.error().message().c_str());
145       return nullptr;
146     } else {
147       ns = *isolated_ns;
148     }
149   }
150 
151   return OpenNativeLibraryInNamespace(ns, path, needs_native_bridge, error_msg);
152 #else
153   UNUSED(env, target_sdk_version, class_loader, caller_location);
154 
155   // Do some best effort to emulate library-path support. It will not
156   // work for dependencies.
157   //
158   // Note: null has a special meaning and must be preserved.
159   std::string c_library_path;  // Empty string by default.
160   if (library_path != nullptr && path != nullptr && path[0] != '/') {
161     ScopedUtfChars library_path_utf_chars(env, library_path);
162     c_library_path = library_path_utf_chars.c_str();
163   }
164 
165   std::vector<std::string> library_paths = base::Split(c_library_path, ":");
166 
167   for (const std::string& lib_path : library_paths) {
168     *needs_native_bridge = false;
169     const char* path_arg;
170     std::string complete_path;
171     if (path == nullptr) {
172       // Preserve null.
173       path_arg = nullptr;
174     } else {
175       complete_path = lib_path;
176       if (!complete_path.empty()) {
177         complete_path.append("/");
178       }
179       complete_path.append(path);
180       path_arg = complete_path.c_str();
181     }
182     void* handle = dlopen(path_arg, RTLD_NOW);
183     if (handle != nullptr) {
184       return handle;
185     }
186     if (NativeBridgeIsSupported(path_arg)) {
187       *needs_native_bridge = true;
188       handle = NativeBridgeLoadLibrary(path_arg, RTLD_NOW);
189       if (handle != nullptr) {
190         return handle;
191       }
192       *error_msg = strdup(NativeBridgeGetError());
193     } else {
194       *error_msg = strdup(dlerror());
195     }
196   }
197   return nullptr;
198 #endif
199 }
200 
CloseNativeLibrary(void * handle,const bool needs_native_bridge,char ** error_msg)201 bool CloseNativeLibrary(void* handle, const bool needs_native_bridge, char** error_msg) {
202   bool success;
203   if (needs_native_bridge) {
204     success = (NativeBridgeUnloadLibrary(handle) == 0);
205     if (!success) {
206       *error_msg = strdup(NativeBridgeGetError());
207     }
208   } else {
209     success = (dlclose(handle) == 0);
210     if (!success) {
211       *error_msg = strdup(dlerror());
212     }
213   }
214 
215   return success;
216 }
217 
NativeLoaderFreeErrorMessage(char * msg)218 void NativeLoaderFreeErrorMessage(char* msg) {
219   // The error messages get allocated through strdup, so we must call free on them.
220   free(msg);
221 }
222 
223 #if defined(__ANDROID__)
OpenNativeLibraryInNamespace(NativeLoaderNamespace * ns,const char * path,bool * needs_native_bridge,char ** error_msg)224 void* OpenNativeLibraryInNamespace(NativeLoaderNamespace* ns, const char* path,
225                                    bool* needs_native_bridge, char** error_msg) {
226   auto handle = ns->Load(path);
227   if (!handle.ok() && error_msg != nullptr) {
228     *error_msg = strdup(handle.error().message().c_str());
229   }
230   if (needs_native_bridge != nullptr) {
231     *needs_native_bridge = ns->IsBridged();
232   }
233   return handle.ok() ? *handle : nullptr;
234 }
235 
236 // native_bridge_namespaces are not supported for callers of this function.
237 // This function will return nullptr in the case when application is running
238 // on native bridge.
FindNamespaceByClassLoader(JNIEnv * env,jobject class_loader)239 android_namespace_t* FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader) {
240   std::lock_guard<std::mutex> guard(g_namespaces_mutex);
241   NativeLoaderNamespace* ns = g_namespaces->FindNamespaceByClassLoader(env, class_loader);
242   if (ns != nullptr && !ns->IsBridged()) {
243     return ns->ToRawAndroidNamespace();
244   }
245   return nullptr;
246 }
247 
FindNativeLoaderNamespaceByClassLoader(JNIEnv * env,jobject class_loader)248 NativeLoaderNamespace* FindNativeLoaderNamespaceByClassLoader(JNIEnv* env, jobject class_loader) {
249   std::lock_guard<std::mutex> guard(g_namespaces_mutex);
250   return g_namespaces->FindNamespaceByClassLoader(env, class_loader);
251 }
252 #endif
253 
254 };  // namespace android
255