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