• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <android-base/thread_annotations.h>
34 #include <nativebridge/native_bridge.h>
35 #include <nativehelper/scoped_utf_chars.h>
36 
37 #ifdef ART_TARGET_ANDROID
38 #include <log/log.h>
39 #include "library_namespaces.h"
40 #include "nativeloader/dlext_namespaces.h"
41 #endif
42 
43 namespace android {
44 
45 namespace {
46 
47 #if defined(ART_TARGET_ANDROID)
48 
49 // NATIVELOADER_DEFAULT_NAMESPACE_LIBS is an environment variable that can be
50 // used to list extra libraries (separated by ":") that libnativeloader will
51 // load from the default namespace. The libraries must be listed without paths,
52 // and then LD_LIBRARY_PATH is typically set to the directories to load them
53 // from. The libraries will be available in all classloader namespaces, and also
54 // in the fallback namespace used when no classloader is given.
55 //
56 // kNativeloaderExtraLibs is the name of that fallback namespace.
57 //
58 // NATIVELOADER_DEFAULT_NAMESPACE_LIBS is intended to be used for testing only,
59 // and in particular in the ART run tests that are executed through dalvikvm in
60 // the APEX. In that case the default namespace links to the ART namespace
61 // (com_android_art) for all libraries, which means this can be used to load
62 // test libraries that depend on ART internal libraries.
63 constexpr const char* kNativeloaderExtraLibs = "nativeloader-extra-libs";
64 
65 using android::nativeloader::LibraryNamespaces;
66 
67 std::mutex g_namespaces_mutex;
68 LibraryNamespaces* g_namespaces = new LibraryNamespaces;
69 NativeLoaderNamespace* g_nativeloader_extra_libs_namespace = nullptr;
70 
FindExportedNamespace(const char * caller_location)71 android_namespace_t* FindExportedNamespace(const char* caller_location) {
72   auto name = nativeloader::FindApexNamespaceName(caller_location);
73   if (name.ok()) {
74     android_namespace_t* boot_namespace = android_get_exported_namespace(name->c_str());
75     LOG_ALWAYS_FATAL_IF((boot_namespace == nullptr),
76                         "Error finding namespace of apex: no namespace called %s", name->c_str());
77     return boot_namespace;
78   }
79   return nullptr;
80 }
81 
CreateNativeloaderDefaultNamespaceLibsLink(NativeLoaderNamespace & ns)82 Result<void> CreateNativeloaderDefaultNamespaceLibsLink(NativeLoaderNamespace& ns)
83     REQUIRES(g_namespaces_mutex) {
84   const char* links = getenv("NATIVELOADER_DEFAULT_NAMESPACE_LIBS");
85   if (links == nullptr || *links == 0) {
86     return {};
87   }
88   // Pass nullptr to Link() to create a link to the default namespace without
89   // requiring it to be visible.
90   return ns.Link(nullptr, links);
91 }
92 
GetNativeloaderExtraLibsNamespace()93 Result<NativeLoaderNamespace*> GetNativeloaderExtraLibsNamespace() REQUIRES(g_namespaces_mutex) {
94   if (g_nativeloader_extra_libs_namespace != nullptr) {
95     return g_nativeloader_extra_libs_namespace;
96   }
97 
98   Result<NativeLoaderNamespace> ns =
99       NativeLoaderNamespace::Create(kNativeloaderExtraLibs,
100                                     /*search_paths=*/"",
101                                     /*permitted_paths=*/"",
102                                     /*parent=*/nullptr,
103                                     /*is_shared=*/false,
104                                     /*is_exempt_list_enabled=*/false,
105                                     /*also_used_as_anonymous=*/false);
106   if (!ns.ok()) {
107     return ns.error();
108   }
109   g_nativeloader_extra_libs_namespace = new NativeLoaderNamespace(std::move(ns.value()));
110   Result<void> linked =
111       CreateNativeloaderDefaultNamespaceLibsLink(*g_nativeloader_extra_libs_namespace);
112   if (!linked.ok()) {
113     return linked.error();
114   }
115   return g_nativeloader_extra_libs_namespace;
116 }
117 
118 // If the given path matches a library in NATIVELOADER_DEFAULT_NAMESPACE_LIBS
119 // then load it in the nativeloader-extra-libs namespace, otherwise return
120 // nullptr without error.
TryLoadNativeloaderExtraLib(const char * path)121 Result<void*> TryLoadNativeloaderExtraLib(const char* path) {
122   const char* links = getenv("NATIVELOADER_DEFAULT_NAMESPACE_LIBS");
123   if (links == nullptr || *links == 0) {
124     return nullptr;
125   }
126   std::vector<std::string> lib_list = base::Split(links, ":");
127   if (std::find(lib_list.begin(), lib_list.end(), path) == lib_list.end()) {
128     return nullptr;
129   }
130 
131   std::lock_guard<std::mutex> guard(g_namespaces_mutex);
132   Result<NativeLoaderNamespace*> ns = GetNativeloaderExtraLibsNamespace();
133   if (!ns.ok()) {
134     return ns.error();
135   }
136   return ns.value()->Load(path);
137 }
138 
CreateClassLoaderNamespaceLocked(JNIEnv * env,int32_t target_sdk_version,jobject class_loader,bool is_shared,jstring dex_path,jstring library_path,jstring permitted_path,jstring uses_library_list)139 Result<NativeLoaderNamespace*> CreateClassLoaderNamespaceLocked(JNIEnv* env,
140                                                                 int32_t target_sdk_version,
141                                                                 jobject class_loader,
142                                                                 bool is_shared,
143                                                                 jstring dex_path,
144                                                                 jstring library_path,
145                                                                 jstring permitted_path,
146                                                                 jstring uses_library_list)
147     REQUIRES(g_namespaces_mutex) {
148   Result<NativeLoaderNamespace*> ns = g_namespaces->Create(env,
149                                                            target_sdk_version,
150                                                            class_loader,
151                                                            is_shared,
152                                                            dex_path,
153                                                            library_path,
154                                                            permitted_path,
155                                                            uses_library_list);
156   if (!ns.ok()) {
157     return ns;
158   }
159   Result<void> linked = CreateNativeloaderDefaultNamespaceLibsLink(*ns.value());
160   if (!linked.ok()) {
161     return linked.error();
162   }
163   return ns;
164 }
165 
166 #endif  // #if defined(ART_TARGET_ANDROID)
167 
168 }  // namespace
169 
InitializeNativeLoader()170 void InitializeNativeLoader() {
171 #if defined(ART_TARGET_ANDROID)
172   std::lock_guard<std::mutex> guard(g_namespaces_mutex);
173   g_namespaces->Initialize();
174 #endif
175 }
176 
ResetNativeLoader()177 void ResetNativeLoader() {
178 #if defined(ART_TARGET_ANDROID)
179   std::lock_guard<std::mutex> guard(g_namespaces_mutex);
180   g_namespaces->Reset();
181   delete g_nativeloader_extra_libs_namespace;
182   g_nativeloader_extra_libs_namespace = nullptr;
183 #endif
184 }
185 
CreateClassLoaderNamespace(JNIEnv * env,int32_t target_sdk_version,jobject class_loader,bool is_shared,jstring dex_path,jstring library_path,jstring permitted_path,jstring uses_library_list)186 jstring CreateClassLoaderNamespace(JNIEnv* env, int32_t target_sdk_version, jobject class_loader,
187                                    bool is_shared, jstring dex_path, jstring library_path,
188                                    jstring permitted_path, jstring uses_library_list) {
189 #if defined(ART_TARGET_ANDROID)
190   std::lock_guard<std::mutex> guard(g_namespaces_mutex);
191   Result<NativeLoaderNamespace*> ns = CreateClassLoaderNamespaceLocked(env,
192                                                                        target_sdk_version,
193                                                                        class_loader,
194                                                                        is_shared,
195                                                                        dex_path,
196                                                                        library_path,
197                                                                        permitted_path,
198                                                                        uses_library_list);
199   if (!ns.ok()) {
200     return env->NewStringUTF(ns.error().message().c_str());
201   }
202 #else
203   UNUSED(env, target_sdk_version, class_loader, is_shared, dex_path, library_path, permitted_path,
204          uses_library_list);
205 #endif
206   return nullptr;
207 }
208 
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)209 void* OpenNativeLibrary(JNIEnv* env, int32_t target_sdk_version, const char* path,
210                         jobject class_loader, const char* caller_location, jstring library_path,
211                         bool* needs_native_bridge, char** error_msg) {
212 #if defined(ART_TARGET_ANDROID)
213   UNUSED(target_sdk_version);
214 
215   if (class_loader == nullptr) {
216     *needs_native_bridge = false;
217     if (caller_location != nullptr) {
218       android_namespace_t* boot_namespace = FindExportedNamespace(caller_location);
219       if (boot_namespace != nullptr) {
220         const android_dlextinfo dlextinfo = {
221             .flags = ANDROID_DLEXT_USE_NAMESPACE,
222             .library_namespace = boot_namespace,
223         };
224         void* handle = android_dlopen_ext(path, RTLD_NOW, &dlextinfo);
225         if (handle == nullptr) {
226           *error_msg = strdup(dlerror());
227         }
228         return handle;
229       }
230     }
231 
232     // Check if the library is in NATIVELOADER_DEFAULT_NAMESPACE_LIBS and should
233     // be loaded from the kNativeloaderExtraLibs namespace.
234     {
235       Result<void*> handle = TryLoadNativeloaderExtraLib(path);
236       if (!handle.ok()) {
237         *error_msg = strdup(handle.error().message().c_str());
238         return nullptr;
239       }
240       if (handle.value() != nullptr) {
241         return handle.value();
242       }
243     }
244 
245     // Fall back to the system namespace. This happens for preloaded JNI
246     // libraries in the zygote.
247     // TODO(b/185833744): Investigate if this should fall back to the app main
248     // namespace (aka anonymous namespace) instead.
249     void* handle = OpenSystemLibrary(path, RTLD_NOW);
250     if (handle == nullptr) {
251       *error_msg = strdup(dlerror());
252     }
253     return handle;
254   }
255 
256   std::lock_guard<std::mutex> guard(g_namespaces_mutex);
257   NativeLoaderNamespace* ns;
258 
259   if ((ns = g_namespaces->FindNamespaceByClassLoader(env, class_loader)) == nullptr) {
260     // This is the case where the classloader was not created by ApplicationLoaders
261     // In this case we create an isolated not-shared namespace for it.
262     Result<NativeLoaderNamespace*> isolated_ns =
263         CreateClassLoaderNamespaceLocked(env,
264                                          target_sdk_version,
265                                          class_loader,
266                                          /*is_shared=*/false,
267                                          /*dex_path=*/nullptr,
268                                          library_path,
269                                          /*permitted_path=*/nullptr,
270                                          /*uses_library_list=*/nullptr);
271     if (!isolated_ns.ok()) {
272       *error_msg = strdup(isolated_ns.error().message().c_str());
273       return nullptr;
274     } else {
275       ns = *isolated_ns;
276     }
277   }
278 
279   return OpenNativeLibraryInNamespace(ns, path, needs_native_bridge, error_msg);
280 #else
281   UNUSED(env, target_sdk_version, class_loader, caller_location);
282 
283   // Do some best effort to emulate library-path support. It will not
284   // work for dependencies.
285   //
286   // Note: null has a special meaning and must be preserved.
287   std::string c_library_path;  // Empty string by default.
288   if (library_path != nullptr && path != nullptr && path[0] != '/') {
289     ScopedUtfChars library_path_utf_chars(env, library_path);
290     c_library_path = library_path_utf_chars.c_str();
291   }
292 
293   std::vector<std::string> library_paths = base::Split(c_library_path, ":");
294 
295   for (const std::string& lib_path : library_paths) {
296     *needs_native_bridge = false;
297     const char* path_arg;
298     std::string complete_path;
299     if (path == nullptr) {
300       // Preserve null.
301       path_arg = nullptr;
302     } else {
303       complete_path = lib_path;
304       if (!complete_path.empty()) {
305         complete_path.append("/");
306       }
307       complete_path.append(path);
308       path_arg = complete_path.c_str();
309     }
310     void* handle = dlopen(path_arg, RTLD_NOW);
311     if (handle != nullptr) {
312       return handle;
313     }
314     if (NativeBridgeIsSupported(path_arg)) {
315       *needs_native_bridge = true;
316       handle = NativeBridgeLoadLibrary(path_arg, RTLD_NOW);
317       if (handle != nullptr) {
318         return handle;
319       }
320       *error_msg = strdup(NativeBridgeGetError());
321     } else {
322       *error_msg = strdup(dlerror());
323     }
324   }
325   return nullptr;
326 #endif
327 }
328 
CloseNativeLibrary(void * handle,const bool needs_native_bridge,char ** error_msg)329 bool CloseNativeLibrary(void* handle, const bool needs_native_bridge, char** error_msg) {
330   bool success;
331   if (needs_native_bridge) {
332     success = (NativeBridgeUnloadLibrary(handle) == 0);
333     if (!success) {
334       *error_msg = strdup(NativeBridgeGetError());
335     }
336   } else {
337     success = (dlclose(handle) == 0);
338     if (!success) {
339       *error_msg = strdup(dlerror());
340     }
341   }
342 
343   return success;
344 }
345 
NativeLoaderFreeErrorMessage(char * msg)346 void NativeLoaderFreeErrorMessage(char* msg) {
347   // The error messages get allocated through strdup, so we must call free on them.
348   free(msg);
349 }
350 
351 #if defined(ART_TARGET_ANDROID)
OpenNativeLibraryInNamespace(NativeLoaderNamespace * ns,const char * path,bool * needs_native_bridge,char ** error_msg)352 void* OpenNativeLibraryInNamespace(NativeLoaderNamespace* ns, const char* path,
353                                    bool* needs_native_bridge, char** error_msg) {
354   auto handle = ns->Load(path);
355   if (!handle.ok() && error_msg != nullptr) {
356     *error_msg = strdup(handle.error().message().c_str());
357   }
358   if (needs_native_bridge != nullptr) {
359     *needs_native_bridge = ns->IsBridged();
360   }
361   return handle.ok() ? *handle : nullptr;
362 }
363 
364 // native_bridge_namespaces are not supported for callers of this function.
365 // This function will return nullptr in the case when application is running
366 // on native bridge.
FindNamespaceByClassLoader(JNIEnv * env,jobject class_loader)367 android_namespace_t* FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader) {
368   std::lock_guard<std::mutex> guard(g_namespaces_mutex);
369   NativeLoaderNamespace* ns = g_namespaces->FindNamespaceByClassLoader(env, class_loader);
370   if (ns != nullptr && !ns->IsBridged()) {
371     return ns->ToRawAndroidNamespace();
372   }
373   return nullptr;
374 }
375 
FindNativeLoaderNamespaceByClassLoader(JNIEnv * env,jobject class_loader)376 NativeLoaderNamespace* FindNativeLoaderNamespaceByClassLoader(JNIEnv* env, jobject class_loader) {
377   std::lock_guard<std::mutex> guard(g_namespaces_mutex);
378   return g_namespaces->FindNamespaceByClassLoader(env, class_loader);
379 }
380 
LinkNativeLoaderNamespaceToExportedNamespaceLibrary(struct NativeLoaderNamespace * ns,const char * exported_ns_name,const char * library_name,char ** error_msg)381 void LinkNativeLoaderNamespaceToExportedNamespaceLibrary(struct NativeLoaderNamespace* ns,
382                                                          const char* exported_ns_name,
383                                                          const char* library_name,
384                                                          char** error_msg) {
385   Result<NativeLoaderNamespace> exported_ns =
386       NativeLoaderNamespace::GetExportedNamespace(exported_ns_name, ns->IsBridged());
387   if (!exported_ns.ok()) {
388     *error_msg = strdup(exported_ns.error().message().c_str());
389     return;
390   }
391 
392   Result<void> linked = ns->Link(&exported_ns.value(), std::string(library_name));
393   if (!linked.ok()) {
394     *error_msg = strdup(linked.error().message().c_str());
395   }
396 }
397 
398 #endif  // ART_TARGET_ANDROID
399 
400 };  // namespace android
401