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 <optional>
28 #include <regex>
29 #include <string>
30 #include <vector>
31 
32 #include "android-base/file.h"
33 #include "android-base/macros.h"
34 #include "android-base/strings.h"
35 #include "android-base/thread_annotations.h"
36 #include "base/macros.h"
37 #include "nativebridge/native_bridge.h"
38 #include "nativehelper/scoped_utf_chars.h"
39 #include "public_libraries.h"
40 
41 #ifdef ART_TARGET_ANDROID
42 #include "android-modules-utils/sdk_level.h"
43 #include "library_namespaces.h"
44 #include "log/log.h"
45 #include "nativeloader/dlext_namespaces.h"
46 #endif
47 
48 namespace android {
49 
50 namespace {
51 
52 #if defined(ART_TARGET_ANDROID)
53 
54 using ::android::base::Result;
55 using ::android::nativeloader::LibraryNamespaces;
56 
57 const std::regex kPartitionNativeLibPathRegex(
58     "/(system(_ext)?|(system/)?(vendor|product))/lib(64)?/.*");
59 
60 // NATIVELOADER_DEFAULT_NAMESPACE_LIBS is an environment variable that can be
61 // used to list extra libraries (separated by ":") that libnativeloader will
62 // load from the default namespace. The libraries must be listed without paths,
63 // and then LD_LIBRARY_PATH is typically set to the directories to load them
64 // from. The libraries will be available in all classloader namespaces, and also
65 // in the fallback namespace used when no classloader is given.
66 //
67 // kNativeloaderExtraLibs is the name of that fallback namespace.
68 //
69 // NATIVELOADER_DEFAULT_NAMESPACE_LIBS is intended to be used for testing only,
70 // and in particular in the ART run tests that are executed through dalvikvm in
71 // the APEX. In that case the default namespace links to the ART namespace
72 // (com_android_art) for all libraries, which means this can be used to load
73 // test libraries that depend on ART internal libraries.
74 constexpr const char* kNativeloaderExtraLibs = "nativeloader-extra-libs";
75 
76 std::mutex g_namespaces_mutex;
77 LibraryNamespaces* g_namespaces GUARDED_BY(g_namespaces_mutex) = new LibraryNamespaces;
78 NativeLoaderNamespace* g_nativeloader_extra_libs_namespace GUARDED_BY(g_namespaces_mutex) = nullptr;
79 
FindApexNamespace(const char * caller_location)80 std::optional<NativeLoaderNamespace> FindApexNamespace(const char* caller_location) {
81   std::optional<std::string> name = nativeloader::FindApexNamespaceName(caller_location);
82   if (name.has_value()) {
83     // Native Bridge is never used for APEXes.
84     Result<NativeLoaderNamespace> ns =
85         NativeLoaderNamespace::GetExportedNamespace(name.value(), /*is_bridged=*/false);
86     LOG_ALWAYS_FATAL_IF(!ns.ok(),
87                         "Error finding ns %s for APEX location %s: %s",
88                         name.value().c_str(),
89                         caller_location,
90                         ns.error().message().c_str());
91     return ns.value();
92   }
93   return std::nullopt;
94 }
95 
GetNamespaceForApiDomain(nativeloader::ApiDomain api_domain,bool is_bridged)96 Result<NativeLoaderNamespace> GetNamespaceForApiDomain(nativeloader::ApiDomain api_domain,
97                                                        bool is_bridged) {
98   switch (api_domain) {
99     case nativeloader::API_DOMAIN_VENDOR:
100       return NativeLoaderNamespace::GetExportedNamespace(nativeloader::kVendorNamespaceName,
101                                                          is_bridged);
102     case nativeloader::API_DOMAIN_PRODUCT:
103       return NativeLoaderNamespace::GetExportedNamespace(nativeloader::kProductNamespaceName,
104                                                          is_bridged);
105     case nativeloader::API_DOMAIN_SYSTEM:
106       return NativeLoaderNamespace::GetSystemNamespace(is_bridged);
107     default:
108       LOG_FATAL("Invalid API domain %d", api_domain);
109       UNREACHABLE();
110   }
111 }
112 
CreateNativeloaderDefaultNamespaceLibsLink(NativeLoaderNamespace & ns)113 Result<void> CreateNativeloaderDefaultNamespaceLibsLink(NativeLoaderNamespace& ns)
114     REQUIRES(g_namespaces_mutex) {
115   const char* links = getenv("NATIVELOADER_DEFAULT_NAMESPACE_LIBS");
116   if (links == nullptr || *links == 0) {
117     return {};
118   }
119   // Pass nullptr to Link() to create a link to the default namespace without
120   // requiring it to be visible.
121   return ns.Link(nullptr, links);
122 }
123 
GetNativeloaderExtraLibsNamespace()124 Result<NativeLoaderNamespace*> GetNativeloaderExtraLibsNamespace() REQUIRES(g_namespaces_mutex) {
125   if (g_nativeloader_extra_libs_namespace != nullptr) {
126     return g_nativeloader_extra_libs_namespace;
127   }
128 
129   Result<NativeLoaderNamespace> ns =
130       NativeLoaderNamespace::Create(kNativeloaderExtraLibs,
131                                     /*search_paths=*/"",
132                                     /*permitted_paths=*/"",
133                                     /*parent=*/nullptr,
134                                     /*is_shared=*/false,
135                                     /*is_exempt_list_enabled=*/false,
136                                     /*also_used_as_anonymous=*/false);
137   if (!ns.ok()) {
138     return ns.error();
139   }
140   g_nativeloader_extra_libs_namespace = new NativeLoaderNamespace(std::move(ns.value()));
141   Result<void> linked =
142       CreateNativeloaderDefaultNamespaceLibsLink(*g_nativeloader_extra_libs_namespace);
143   if (!linked.ok()) {
144     return linked.error();
145   }
146   return g_nativeloader_extra_libs_namespace;
147 }
148 
149 // If the given path matches a library in NATIVELOADER_DEFAULT_NAMESPACE_LIBS
150 // then load it in the nativeloader-extra-libs namespace, otherwise return
151 // nullptr without error.
TryLoadNativeloaderExtraLib(const char * path)152 Result<void*> TryLoadNativeloaderExtraLib(const char* path) {
153   const char* links = getenv("NATIVELOADER_DEFAULT_NAMESPACE_LIBS");
154   if (links == nullptr || *links == 0) {
155     return nullptr;
156   }
157   std::vector<std::string> lib_list = base::Split(links, ":");
158   if (std::find(lib_list.begin(), lib_list.end(), path) == lib_list.end()) {
159     return nullptr;
160   }
161 
162   std::lock_guard<std::mutex> guard(g_namespaces_mutex);
163   Result<NativeLoaderNamespace*> ns = GetNativeloaderExtraLibsNamespace();
164   if (!ns.ok()) {
165     return ns.error();
166   }
167 
168   Result<void*> res = ns.value()->Load(path);
169   ALOGD("Load %s using ns %s from NATIVELOADER_DEFAULT_NAMESPACE_LIBS match: %s",
170         path,
171         ns.value()->name().c_str(),
172         res.ok() ? "ok" : res.error().message().c_str());
173   return res;
174 }
175 
CreateClassLoaderNamespaceLocked(JNIEnv * env,int32_t target_sdk_version,jobject class_loader,nativeloader::ApiDomain api_domain,bool is_shared,const std::string & dex_path,jstring library_path_j,jstring permitted_path_j,jstring uses_library_list_j)176 Result<NativeLoaderNamespace*> CreateClassLoaderNamespaceLocked(JNIEnv* env,
177                                                                 int32_t target_sdk_version,
178                                                                 jobject class_loader,
179                                                                 nativeloader::ApiDomain api_domain,
180                                                                 bool is_shared,
181                                                                 const std::string& dex_path,
182                                                                 jstring library_path_j,
183                                                                 jstring permitted_path_j,
184                                                                 jstring uses_library_list_j)
185     REQUIRES(g_namespaces_mutex) {
186   Result<NativeLoaderNamespace*> ns = g_namespaces->Create(env,
187                                                            target_sdk_version,
188                                                            class_loader,
189                                                            api_domain,
190                                                            is_shared,
191                                                            dex_path,
192                                                            library_path_j,
193                                                            permitted_path_j,
194                                                            uses_library_list_j);
195   if (!ns.ok()) {
196     return ns;
197   }
198   Result<void> linked = CreateNativeloaderDefaultNamespaceLibsLink(*ns.value());
199   if (!linked.ok()) {
200     return linked.error();
201   }
202   return ns;
203 }
204 
205 #endif  // ART_TARGET_ANDROID
206 
207 }  // namespace
208 
InitializeNativeLoader()209 void InitializeNativeLoader() {
210 #if defined(ART_TARGET_ANDROID)
211   std::lock_guard<std::mutex> guard(g_namespaces_mutex);
212   g_namespaces->Initialize();
213 #endif
214 }
215 
ResetNativeLoader()216 void ResetNativeLoader() {
217 #if defined(ART_TARGET_ANDROID)
218   std::lock_guard<std::mutex> guard(g_namespaces_mutex);
219   g_namespaces->Reset();
220   delete g_nativeloader_extra_libs_namespace;
221   g_nativeloader_extra_libs_namespace = nullptr;
222 #endif
223 }
224 
225 // dex_path_j may be a ':'-separated list of paths, e.g. when creating a shared
226 // library loader - cf. mCodePaths in android.content.pm.SharedLibraryInfo.
CreateClassLoaderNamespace(JNIEnv * env,int32_t target_sdk_version,jobject class_loader,bool is_shared,jstring dex_path_j,jstring library_path_j,jstring permitted_path_j,jstring uses_library_list_j)227 jstring CreateClassLoaderNamespace(JNIEnv* env,
228                                    int32_t target_sdk_version,
229                                    jobject class_loader,
230                                    bool is_shared,
231                                    jstring dex_path_j,
232                                    jstring library_path_j,
233                                    jstring permitted_path_j,
234                                    jstring uses_library_list_j) {
235 #if defined(ART_TARGET_ANDROID)
236   std::string dex_path;
237   if (dex_path_j != nullptr) {
238     ScopedUtfChars dex_path_chars(env, dex_path_j);
239     dex_path = dex_path_chars.c_str();
240   }
241 
242   Result<nativeloader::ApiDomain> api_domain = nativeloader::GetApiDomainFromPathList(dex_path);
243   if (!api_domain.ok()) {
244     return env->NewStringUTF(api_domain.error().message().c_str());
245   }
246 
247   std::lock_guard<std::mutex> guard(g_namespaces_mutex);
248   Result<NativeLoaderNamespace*> ns = CreateClassLoaderNamespaceLocked(env,
249                                                                        target_sdk_version,
250                                                                        class_loader,
251                                                                        api_domain.value(),
252                                                                        is_shared,
253                                                                        dex_path,
254                                                                        library_path_j,
255                                                                        permitted_path_j,
256                                                                        uses_library_list_j);
257   if (!ns.ok()) {
258     return env->NewStringUTF(ns.error().message().c_str());
259   }
260 
261 #else
262   UNUSED(env,
263          target_sdk_version,
264          class_loader,
265          is_shared,
266          dex_path_j,
267          library_path_j,
268          permitted_path_j,
269          uses_library_list_j);
270 #endif
271 
272   return nullptr;
273 }
274 
OpenNativeLibrary(JNIEnv * env,int32_t target_sdk_version,const char * path,jobject class_loader,const char * caller_location,jstring library_path_j,bool * needs_native_bridge,char ** error_msg)275 void* OpenNativeLibrary(JNIEnv* env,
276                         int32_t target_sdk_version,
277                         const char* path,
278                         jobject class_loader,
279                         const char* caller_location,
280                         jstring library_path_j,
281                         bool* needs_native_bridge,
282                         char** error_msg) {
283 #if defined(ART_TARGET_ANDROID)
284   if (class_loader == nullptr) {
285     // class_loader is null only for the boot class loader (see
286     // IsBootClassLoader call in JavaVMExt::LoadNativeLibrary), i.e. the caller
287     // is in the boot classpath.
288     *needs_native_bridge = false;
289     if (caller_location != nullptr) {
290       std::optional<NativeLoaderNamespace> ns = FindApexNamespace(caller_location);
291       if (ns.has_value()) {
292         const android_dlextinfo dlextinfo = {
293             .flags = ANDROID_DLEXT_USE_NAMESPACE,
294             .library_namespace = ns.value().ToRawAndroidNamespace(),
295         };
296         void* handle = android_dlopen_ext(path, RTLD_NOW, &dlextinfo);
297         char* dlerror_msg = handle == nullptr ? strdup(dlerror()) : nullptr;
298         ALOGD("Load %s using APEX ns %s for caller %s: %s",
299               path,
300               ns.value().name().c_str(),
301               caller_location,
302               dlerror_msg == nullptr ? "ok" : dlerror_msg);
303         if (dlerror_msg != nullptr) {
304           *error_msg = dlerror_msg;
305         }
306         return handle;
307       }
308     }
309 
310     // Check if the library is in NATIVELOADER_DEFAULT_NAMESPACE_LIBS and should
311     // be loaded from the kNativeloaderExtraLibs namespace.
312     {
313       Result<void*> handle = TryLoadNativeloaderExtraLib(path);
314       if (!handle.ok()) {
315         *error_msg = strdup(handle.error().message().c_str());
316         return nullptr;
317       }
318       if (handle.value() != nullptr) {
319         return handle.value();
320       }
321     }
322 
323     // Fall back to the system namespace. This happens for preloaded JNI
324     // libraries in the zygote.
325     void* handle = OpenSystemLibrary(path, RTLD_NOW);
326     char* dlerror_msg = handle == nullptr ? strdup(dlerror()) : nullptr;
327     ALOGD("Load %s using system ns (caller=%s): %s",
328           path,
329           caller_location == nullptr ? "<unknown>" : caller_location,
330           dlerror_msg == nullptr ? "ok" : dlerror_msg);
331     if (dlerror_msg != nullptr) {
332       *error_msg = dlerror_msg;
333     }
334     return handle;
335   }
336 
337   // If the caller is in any of the system image partitions and the library is
338   // in the same partition then load it without regards to public library
339   // restrictions. This is only done if the library is specified by an absolute
340   // path, so we don't affect the lookup process for libraries specified by name
341   // only.
342   if (caller_location != nullptr &&
343       // Check that the library is in the partition-wide native library
344       // location. Apps in the partition may have their own native libraries,
345       // and those should still be loaded with the app's classloader namespace.
346       std::regex_match(path, kPartitionNativeLibPathRegex) &&
347       // Don't do this if the system image is older than V, to avoid any compat
348       // issues with apps and shared libs in them.
349       android::modules::sdklevel::IsAtLeastV()) {
350     nativeloader::ApiDomain caller_api_domain = nativeloader::GetApiDomainFromPath(caller_location);
351     if (caller_api_domain != nativeloader::API_DOMAIN_DEFAULT) {
352       nativeloader::ApiDomain library_api_domain = nativeloader::GetApiDomainFromPath(path);
353 
354       if (library_api_domain == caller_api_domain) {
355         bool is_bridged = false;
356         if (library_path_j != nullptr) {
357           ScopedUtfChars library_path_utf_chars(env, library_path_j);
358           if (library_path_utf_chars[0] != '\0') {
359             is_bridged = NativeBridgeIsPathSupported(library_path_utf_chars.c_str());
360           }
361         }
362 
363         Result<NativeLoaderNamespace> ns = GetNamespaceForApiDomain(caller_api_domain, is_bridged);
364         if (!ns.ok()) {
365           ALOGD("Failed to find ns for caller %s in API domain %d to load %s (is_bridged=%b): %s",
366                 caller_location,
367                 caller_api_domain,
368                 path,
369                 is_bridged,
370                 ns.error().message().c_str());
371           *error_msg = strdup(ns.error().message().c_str());
372           return nullptr;
373         }
374 
375         *needs_native_bridge = ns.value().IsBridged();
376         Result<void*> handle = ns.value().Load(path);
377         ALOGD("Load %s using ns %s for caller %s in same partition (is_bridged=%b): %s",
378               path,
379               ns.value().name().c_str(),
380               caller_location,
381               is_bridged,
382               handle.ok() ? "ok" : handle.error().message().c_str());
383         if (!handle.ok()) {
384           *error_msg = strdup(handle.error().message().c_str());
385           return nullptr;
386         }
387         return handle.value();
388       }
389     }
390   }
391 
392   std::lock_guard<std::mutex> guard(g_namespaces_mutex);
393 
394   {
395     NativeLoaderNamespace* ns = g_namespaces->FindNamespaceByClassLoader(env, class_loader);
396     if (ns != nullptr) {
397       *needs_native_bridge = ns->IsBridged();
398       Result<void*> handle = ns->Load(path);
399       ALOGD("Load %s using ns %s from class loader (caller=%s): %s",
400             path,
401             ns->name().c_str(),
402             caller_location == nullptr ? "<unknown>" : caller_location,
403             handle.ok() ? "ok" : handle.error().message().c_str());
404       if (!handle.ok()) {
405         *error_msg = strdup(handle.error().message().c_str());
406         return nullptr;
407       }
408       return handle.value();
409     }
410   }
411 
412   // This is the case where the classloader was not created by ApplicationLoaders
413   // In this case we create an isolated not-shared namespace for it.
414   const std::string empty_dex_path;
415   Result<NativeLoaderNamespace*> isolated_ns =
416       CreateClassLoaderNamespaceLocked(env,
417                                        target_sdk_version,
418                                        class_loader,
419                                        nativeloader::API_DOMAIN_DEFAULT,
420                                        /*is_shared=*/false,
421                                        empty_dex_path,
422                                        library_path_j,
423                                        /*permitted_path_j=*/nullptr,
424                                        /*uses_library_list_j=*/nullptr);
425   if (!isolated_ns.ok()) {
426     ALOGD("Failed to create isolated ns for %s (caller=%s)",
427           path,
428           caller_location == nullptr ? "<unknown>" : caller_location);
429     *error_msg = strdup(isolated_ns.error().message().c_str());
430     return nullptr;
431   }
432 
433   *needs_native_bridge = isolated_ns.value()->IsBridged();
434   Result<void*> handle = isolated_ns.value()->Load(path);
435   ALOGD("Load %s using isolated ns %s (caller=%s): %s",
436         path,
437         isolated_ns.value()->name().c_str(),
438         caller_location == nullptr ? "<unknown>" : caller_location,
439         handle.ok() ? "ok" : handle.error().message().c_str());
440   if (!handle.ok()) {
441     *error_msg = strdup(handle.error().message().c_str());
442     return nullptr;
443   }
444   return handle.value();
445 
446 #else   // !ART_TARGET_ANDROID
447   UNUSED(env, target_sdk_version, class_loader, caller_location);
448 
449   // Do some best effort to emulate library-path support. It will not
450   // work for dependencies.
451   //
452   // Note: null has a special meaning and must be preserved.
453   std::string library_path;  // Empty string by default.
454   if (library_path_j != nullptr && path != nullptr && path[0] != '/') {
455     ScopedUtfChars library_path_utf_chars(env, library_path_j);
456     library_path = library_path_utf_chars.c_str();
457   }
458 
459   std::vector<std::string> library_paths = base::Split(library_path, ":");
460 
461   for (const std::string& lib_path : library_paths) {
462     *needs_native_bridge = false;
463     const char* path_arg;
464     std::string complete_path;
465     if (path == nullptr) {
466       // Preserve null.
467       path_arg = nullptr;
468     } else {
469       complete_path = lib_path;
470       if (!complete_path.empty()) {
471         complete_path.append("/");
472       }
473       complete_path.append(path);
474       path_arg = complete_path.c_str();
475     }
476     void* handle = dlopen(path_arg, RTLD_NOW);
477     if (handle != nullptr) {
478       return handle;
479     }
480     if (NativeBridgeIsSupported(path_arg)) {
481       *needs_native_bridge = true;
482       handle = NativeBridgeLoadLibrary(path_arg, RTLD_NOW);
483       if (handle != nullptr) {
484         return handle;
485       }
486       *error_msg = strdup(NativeBridgeGetError());
487     } else {
488       *error_msg = strdup(dlerror());
489     }
490   }
491   return nullptr;
492 #endif  // !ART_TARGET_ANDROID
493 }
494 
CloseNativeLibrary(void * handle,const bool needs_native_bridge,char ** error_msg)495 bool CloseNativeLibrary(void* handle, const bool needs_native_bridge, char** error_msg) {
496   bool success;
497   if (needs_native_bridge) {
498     success = (NativeBridgeUnloadLibrary(handle) == 0);
499     if (!success) {
500       *error_msg = strdup(NativeBridgeGetError());
501     }
502   } else {
503     success = (dlclose(handle) == 0);
504     if (!success) {
505       *error_msg = strdup(dlerror());
506     }
507   }
508 
509   return success;
510 }
511 
NativeLoaderFreeErrorMessage(char * msg)512 void NativeLoaderFreeErrorMessage(char* msg) {
513   // The error messages get allocated through strdup, so we must call free on them.
514   free(msg);
515 }
516 
517 #if defined(ART_TARGET_ANDROID)
OpenNativeLibraryInNamespace(NativeLoaderNamespace * ns,const char * path,bool * needs_native_bridge,char ** error_msg)518 void* OpenNativeLibraryInNamespace(NativeLoaderNamespace* ns, const char* path,
519                                    bool* needs_native_bridge, char** error_msg) {
520   Result<void*> handle = ns->Load(path);
521   if (!handle.ok() && error_msg != nullptr) {
522     *error_msg = strdup(handle.error().message().c_str());
523   }
524   if (needs_native_bridge != nullptr) {
525     *needs_native_bridge = ns->IsBridged();
526   }
527   return handle.ok() ? *handle : nullptr;
528 }
529 
IsNamespaceNativeBridged(const struct NativeLoaderNamespace * ns)530 bool IsNamespaceNativeBridged(const struct NativeLoaderNamespace* ns) { return ns->IsBridged(); }
531 
532 // native_bridge_namespaces are not supported for callers of this function.
533 // This function will return nullptr in the case when application is running
534 // on native bridge.
FindNamespaceByClassLoader(JNIEnv * env,jobject class_loader)535 android_namespace_t* FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader) {
536   std::lock_guard<std::mutex> guard(g_namespaces_mutex);
537   NativeLoaderNamespace* ns = g_namespaces->FindNamespaceByClassLoader(env, class_loader);
538   if (ns != nullptr && !ns->IsBridged()) {
539     return ns->ToRawAndroidNamespace();
540   }
541   return nullptr;
542 }
543 
FindNativeLoaderNamespaceByClassLoader(JNIEnv * env,jobject class_loader)544 NativeLoaderNamespace* FindNativeLoaderNamespaceByClassLoader(JNIEnv* env, jobject class_loader) {
545   std::lock_guard<std::mutex> guard(g_namespaces_mutex);
546   return g_namespaces->FindNamespaceByClassLoader(env, class_loader);
547 }
548 
LinkNativeLoaderNamespaceToExportedNamespaceLibrary(struct NativeLoaderNamespace * ns,const char * exported_ns_name,const char * library_name,char ** error_msg)549 void LinkNativeLoaderNamespaceToExportedNamespaceLibrary(struct NativeLoaderNamespace* ns,
550                                                          const char* exported_ns_name,
551                                                          const char* library_name,
552                                                          char** error_msg) {
553   Result<NativeLoaderNamespace> exported_ns =
554       NativeLoaderNamespace::GetExportedNamespace(exported_ns_name, ns->IsBridged());
555   if (!exported_ns.ok()) {
556     *error_msg = strdup(exported_ns.error().message().c_str());
557     return;
558   }
559 
560   Result<void> linked = ns->Link(&exported_ns.value(), std::string(library_name));
561   if (!linked.ok()) {
562     *error_msg = strdup(linked.error().message().c_str());
563   }
564 }
565 
566 #endif  // ART_TARGET_ANDROID
567 
568 }  // namespace android
569