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