• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "base/android/bundle_utils.h"
6 
7 #include <android/dlext.h>
8 #include <dlfcn.h>
9 
10 #include "base/android/jni_android.h"
11 #include "base/android/jni_string.h"
12 #include "base/base_jni/BundleUtils_jni.h"
13 #include "base/check.h"
14 #include "base/compiler_specific.h"
15 #include "base/containers/span.h"
16 #include "base/files/file_path.h"
17 #include "base/notreached.h"
18 
19 // These symbols are added by the lld linker when creating a partitioned shared
20 // library. The symbols live in the base library, and are used to properly load
21 // the other partitions (feature libraries) when needed.
22 struct PartitionIndexEntry {
23   int32_t name_relptr;
24   int32_t addr_relptr;
25   uint32_t size;
26 };
27 static_assert(sizeof(PartitionIndexEntry) == 12U,
28               "Unexpected PartitionIndexEntry size");
29 
30 // Marked as weak_import because these symbols are lld-specific. The method that
31 // uses them will only be invoked in builds that have lld-generated partitions.
32 extern PartitionIndexEntry __part_index_begin[] __attribute__((weak_import));
33 extern PartitionIndexEntry __part_index_end[] __attribute__((weak_import));
34 
35 namespace base {
36 namespace android {
37 
38 namespace {
39 
40 // Takes as input a "rel pointer", which is a pointer to a 32-bit integer that
41 // contains the offset to add to the pointer, in order to find the actual
42 // desired pointer address.
43 //
44 // # Safety
45 // If the value in the pointer does not provide an offset from the pointer that
46 // stays inside the same allocation, Undefined Behaviour can result.
ReadRelPtr(int32_t * relptr)47 UNSAFE_BUFFER_USAGE void* ReadRelPtr(int32_t* relptr) {
48   // SAFETY: This relies on the caller to provide a valid pointer + value.
49   return UNSAFE_BUFFERS(reinterpret_cast<char*>(relptr) + *relptr);
50 }
51 
52 }  // namespace
53 
54 // static
ResolveLibraryPath(const std::string & library_name,const std::string & split_name)55 std::string BundleUtils::ResolveLibraryPath(const std::string& library_name,
56                                             const std::string& split_name) {
57   JNIEnv* env = AttachCurrentThread();
58   ScopedJavaLocalRef<jstring> java_path = Java_BundleUtils_getNativeLibraryPath(
59       env, ConvertUTF8ToJavaString(env, library_name),
60       ConvertUTF8ToJavaString(env, split_name));
61   // TODO(crbug.com/40656179): Remove this tolerance.
62   if (!java_path) {
63     return std::string();
64   }
65   return ConvertJavaStringToUTF8(env, java_path);
66 }
67 
68 // static
IsBundle()69 bool BundleUtils::IsBundle() {
70   return Java_BundleUtils_isBundleForNative(AttachCurrentThread());
71 }
72 
73 // static
DlOpenModuleLibraryPartition(const std::string & library_name,const std::string & partition,const std::string & split_name)74 void* BundleUtils::DlOpenModuleLibraryPartition(const std::string& library_name,
75                                                 const std::string& partition,
76                                                 const std::string& split_name) {
77   // TODO(crbug.com/40656179): Remove this tolerance.
78   std::string library_path = ResolveLibraryPath(library_name, split_name);
79   if (library_path.empty()) {
80     return nullptr;
81   }
82 
83   // Linear search is required here because the partition descriptors are not
84   // ordered. If a large number of partitions come into existence, lld could be
85   // modified to sort the partitions.
86   DCHECK(__part_index_begin != nullptr);
87   DCHECK(__part_index_end != nullptr);
88   // SAFETY: `__part_index_begin` and `__part_index_end` are provided by the
89   // linker (https://lld.llvm.org/Partitions.html) and we rely on the linker to
90   // provide pointers that are part of the same allocation with
91   // `__part_index_begin <= __part_index_end`.
92   auto parts = UNSAFE_BUFFERS(
93       span<PartitionIndexEntry>(__part_index_begin, __part_index_end));
94   for (PartitionIndexEntry& part : parts) {
95     std::string name(static_cast<const char*>(
96         // SAFETY: `name_relptr` plus its value points to a nul-terminated
97         // string containing the soname of the partition. This pointer and
98         // offset is provided by the linker and thus assumed to always be
99         // correct. https://lld.llvm.org/Partitions.html
100         UNSAFE_BUFFERS(ReadRelPtr(&part.name_relptr))));
101     if (name == partition) {
102       android_dlextinfo info = {};
103       info.flags = ANDROID_DLEXT_RESERVED_ADDRESS;
104       info.reserved_addr =
105           // SAFETY: `addr_offset` field is a relative pointer to the
106           // partition's load address. This pointer and offset is provided by
107           // the linker and thus assumed to always be correct.
108           // https://lld.llvm.org/Partitions.html
109           UNSAFE_BUFFERS(ReadRelPtr(&part.addr_relptr));
110       info.reserved_size = part.size;
111 
112 #if __ANDROID_API__ >= 24
113       return android_dlopen_ext(library_path.c_str(), RTLD_LOCAL, &info);
114 #else
115       // When targeting pre-N, such as for Cronet, android_dlopen_ext() might
116       // not be available on the system.
117       NOTREACHED() << "android_dlopen_ext not available";
118 #endif
119     }
120   }
121 
122   NOTREACHED();
123 }
124 
125 }  // namespace android
126 }  // namespace base
127