xref: /aosp_15_r20/external/cronet/base/android/linker/linker_jni.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker // Copyright 2015 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker 
5*6777b538SAndroid Build Coastguard Worker #include "base/android/linker/linker_jni.h"
6*6777b538SAndroid Build Coastguard Worker 
7*6777b538SAndroid Build Coastguard Worker #include <android/dlext.h>
8*6777b538SAndroid Build Coastguard Worker #include <dlfcn.h>
9*6777b538SAndroid Build Coastguard Worker #include <errno.h>
10*6777b538SAndroid Build Coastguard Worker #include <fcntl.h>
11*6777b538SAndroid Build Coastguard Worker #include <inttypes.h>
12*6777b538SAndroid Build Coastguard Worker #include <jni.h>
13*6777b538SAndroid Build Coastguard Worker #include <link.h>
14*6777b538SAndroid Build Coastguard Worker #include <stdlib.h>
15*6777b538SAndroid Build Coastguard Worker #include <string.h>
16*6777b538SAndroid Build Coastguard Worker #include <sys/mman.h>
17*6777b538SAndroid Build Coastguard Worker #include <sys/stat.h>
18*6777b538SAndroid Build Coastguard Worker #include <unistd.h>
19*6777b538SAndroid Build Coastguard Worker 
20*6777b538SAndroid Build Coastguard Worker #include <memory>
21*6777b538SAndroid Build Coastguard Worker 
22*6777b538SAndroid Build Coastguard Worker namespace chromium_android_linker {
23*6777b538SAndroid Build Coastguard Worker 
24*6777b538SAndroid Build Coastguard Worker namespace {
25*6777b538SAndroid Build Coastguard Worker 
26*6777b538SAndroid Build Coastguard Worker // Variable containing LibInfo for the loaded library.
27*6777b538SAndroid Build Coastguard Worker LibInfo_class s_lib_info_fields;
28*6777b538SAndroid Build Coastguard Worker 
29*6777b538SAndroid Build Coastguard Worker // Guarded by |mLock| in Linker.java.
30*6777b538SAndroid Build Coastguard Worker RelroSharingStatus s_relro_sharing_status = RelroSharingStatus::NOT_ATTEMPTED;
31*6777b538SAndroid Build Coastguard Worker 
32*6777b538SAndroid Build Coastguard Worker // Saved JavaVM passed to JNI_OnLoad().
33*6777b538SAndroid Build Coastguard Worker JavaVM* s_java_vm = nullptr;
34*6777b538SAndroid Build Coastguard Worker 
GetPageSize()35*6777b538SAndroid Build Coastguard Worker size_t GetPageSize() {
36*6777b538SAndroid Build Coastguard Worker   return sysconf(_SC_PAGESIZE);
37*6777b538SAndroid Build Coastguard Worker }
38*6777b538SAndroid Build Coastguard Worker 
39*6777b538SAndroid Build Coastguard Worker // With mmap(2) reserves a range of virtual addresses.
40*6777b538SAndroid Build Coastguard Worker //
41*6777b538SAndroid Build Coastguard Worker // The range must start with |hint| and be of size |size|. The |hint==0|
42*6777b538SAndroid Build Coastguard Worker // indicates that the address of the mapping should be chosen at random,
43*6777b538SAndroid Build Coastguard Worker // utilizing ASLR built into mmap(2).
44*6777b538SAndroid Build Coastguard Worker //
45*6777b538SAndroid Build Coastguard Worker // The start of the resulting region is returned in |address|.
46*6777b538SAndroid Build Coastguard Worker //
47*6777b538SAndroid Build Coastguard Worker // The value 0 returned iff the attempt failed (a part of the address range is
48*6777b538SAndroid Build Coastguard Worker // already reserved by some other subsystem).
ReserveAddressWithHint(uintptr_t hint,uintptr_t * address,size_t * size)49*6777b538SAndroid Build Coastguard Worker void ReserveAddressWithHint(uintptr_t hint, uintptr_t* address, size_t* size) {
50*6777b538SAndroid Build Coastguard Worker   void* ptr = reinterpret_cast<void*>(hint);
51*6777b538SAndroid Build Coastguard Worker   void* new_ptr = mmap(ptr, kAddressSpaceReservationSize, PROT_NONE,
52*6777b538SAndroid Build Coastguard Worker                        MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
53*6777b538SAndroid Build Coastguard Worker   if (new_ptr == MAP_FAILED) {
54*6777b538SAndroid Build Coastguard Worker     PLOG_ERROR("mmap");
55*6777b538SAndroid Build Coastguard Worker     *address = 0;
56*6777b538SAndroid Build Coastguard Worker   } else if ((hint != 0) && (new_ptr != ptr)) {
57*6777b538SAndroid Build Coastguard Worker     // Something grabbed the address range before the early phase of the
58*6777b538SAndroid Build Coastguard Worker     // linker had a chance, this should be uncommon.
59*6777b538SAndroid Build Coastguard Worker     LOG_ERROR("Address range starting at 0x%" PRIxPTR " was not free to use",
60*6777b538SAndroid Build Coastguard Worker               hint);
61*6777b538SAndroid Build Coastguard Worker     munmap(new_ptr, kAddressSpaceReservationSize);
62*6777b538SAndroid Build Coastguard Worker     *address = 0;
63*6777b538SAndroid Build Coastguard Worker   } else {
64*6777b538SAndroid Build Coastguard Worker     *address = reinterpret_cast<uintptr_t>(new_ptr);
65*6777b538SAndroid Build Coastguard Worker     *size = kAddressSpaceReservationSize;
66*6777b538SAndroid Build Coastguard Worker     LOG_INFO("Reserved region at address: 0x%" PRIxPTR ", size: 0x%zu",
67*6777b538SAndroid Build Coastguard Worker              *address, *size);
68*6777b538SAndroid Build Coastguard Worker   }
69*6777b538SAndroid Build Coastguard Worker }
70*6777b538SAndroid Build Coastguard Worker 
ScanRegionInBuffer(const char * buf,size_t length,uintptr_t * out_address,size_t * out_size)71*6777b538SAndroid Build Coastguard Worker bool ScanRegionInBuffer(const char* buf,
72*6777b538SAndroid Build Coastguard Worker                         size_t length,
73*6777b538SAndroid Build Coastguard Worker                         uintptr_t* out_address,
74*6777b538SAndroid Build Coastguard Worker                         size_t* out_size) {
75*6777b538SAndroid Build Coastguard Worker   const char* position = strstr(buf, "[anon:libwebview reservation]");
76*6777b538SAndroid Build Coastguard Worker   if (!position)
77*6777b538SAndroid Build Coastguard Worker     return false;
78*6777b538SAndroid Build Coastguard Worker 
79*6777b538SAndroid Build Coastguard Worker   const char* line_start = position;
80*6777b538SAndroid Build Coastguard Worker   while (line_start > buf) {
81*6777b538SAndroid Build Coastguard Worker     line_start--;
82*6777b538SAndroid Build Coastguard Worker     if (*line_start == '\n') {
83*6777b538SAndroid Build Coastguard Worker       line_start++;
84*6777b538SAndroid Build Coastguard Worker       break;
85*6777b538SAndroid Build Coastguard Worker     }
86*6777b538SAndroid Build Coastguard Worker   }
87*6777b538SAndroid Build Coastguard Worker 
88*6777b538SAndroid Build Coastguard Worker   // Extract the region start and end. The failures below should not happen as
89*6777b538SAndroid Build Coastguard Worker   // long as the reservation is made the same way in
90*6777b538SAndroid Build Coastguard Worker   // frameworks/base/native/webview/loader/loader.cpp.
91*6777b538SAndroid Build Coastguard Worker   uintptr_t vma_start, vma_end;
92*6777b538SAndroid Build Coastguard Worker   char permissions[5] = {'\0'};  // Ensure a null-terminated string.
93*6777b538SAndroid Build Coastguard Worker   // Example line from proc(5):
94*6777b538SAndroid Build Coastguard Worker   // address           perms offset  dev   inode   pathname
95*6777b538SAndroid Build Coastguard Worker   // 00400000-00452000 r-xp 00000000 08:02 173521  /usr/bin/dbus-daemon
96*6777b538SAndroid Build Coastguard Worker   if (sscanf(line_start, "%" SCNxPTR "-%" SCNxPTR " %4c", &vma_start, &vma_end,
97*6777b538SAndroid Build Coastguard Worker              permissions) < 3) {
98*6777b538SAndroid Build Coastguard Worker     return false;
99*6777b538SAndroid Build Coastguard Worker   }
100*6777b538SAndroid Build Coastguard Worker 
101*6777b538SAndroid Build Coastguard Worker   if (strcmp(permissions, "---p"))
102*6777b538SAndroid Build Coastguard Worker     return false;
103*6777b538SAndroid Build Coastguard Worker 
104*6777b538SAndroid Build Coastguard Worker   const size_t kPageSize = GetPageSize();
105*6777b538SAndroid Build Coastguard Worker   if (vma_start % kPageSize || vma_end % kPageSize) {
106*6777b538SAndroid Build Coastguard Worker     return false;
107*6777b538SAndroid Build Coastguard Worker   }
108*6777b538SAndroid Build Coastguard Worker 
109*6777b538SAndroid Build Coastguard Worker   *out_address = static_cast<uintptr_t>(vma_start);
110*6777b538SAndroid Build Coastguard Worker   *out_size = vma_end - vma_start;
111*6777b538SAndroid Build Coastguard Worker 
112*6777b538SAndroid Build Coastguard Worker   return true;
113*6777b538SAndroid Build Coastguard Worker }
114*6777b538SAndroid Build Coastguard Worker 
FindRegionInOpenFile(int fd,uintptr_t * out_address,size_t * out_size)115*6777b538SAndroid Build Coastguard Worker bool FindRegionInOpenFile(int fd, uintptr_t* out_address, size_t* out_size) {
116*6777b538SAndroid Build Coastguard Worker   constexpr size_t kMaxLineLength = 256;
117*6777b538SAndroid Build Coastguard Worker   const size_t kPageSize = GetPageSize();
118*6777b538SAndroid Build Coastguard Worker   const size_t kReadSize = kPageSize;
119*6777b538SAndroid Build Coastguard Worker 
120*6777b538SAndroid Build Coastguard Worker   // Loop until no bytes left to scan. On every iteration except the last, fill
121*6777b538SAndroid Build Coastguard Worker   // the buffer till the end. On every iteration except the first, the buffer
122*6777b538SAndroid Build Coastguard Worker   // begins with kMaxLineLength bytes from the end of the previous fill.
123*6777b538SAndroid Build Coastguard Worker   char buf[kReadSize + kMaxLineLength + 1];
124*6777b538SAndroid Build Coastguard Worker   buf[kReadSize + kMaxLineLength] = '\0';  // Stop strstr().
125*6777b538SAndroid Build Coastguard Worker   size_t pos = 0;
126*6777b538SAndroid Build Coastguard Worker   size_t bytes_requested = kReadSize + kMaxLineLength;
127*6777b538SAndroid Build Coastguard Worker   bool reached_end = false;
128*6777b538SAndroid Build Coastguard Worker   while (true) {
129*6777b538SAndroid Build Coastguard Worker     // Fill the |buf| to the maximum and determine whether reading reached the
130*6777b538SAndroid Build Coastguard Worker     // end.
131*6777b538SAndroid Build Coastguard Worker     size_t bytes_read = 0;
132*6777b538SAndroid Build Coastguard Worker     do {
133*6777b538SAndroid Build Coastguard Worker       ssize_t rv = HANDLE_EINTR(
134*6777b538SAndroid Build Coastguard Worker           read(fd, buf + pos + bytes_read, bytes_requested - bytes_read));
135*6777b538SAndroid Build Coastguard Worker       if (rv == 0) {
136*6777b538SAndroid Build Coastguard Worker         reached_end = true;
137*6777b538SAndroid Build Coastguard Worker       } else if (rv < 0) {
138*6777b538SAndroid Build Coastguard Worker         PLOG_ERROR("read to find webview reservation");
139*6777b538SAndroid Build Coastguard Worker         return false;
140*6777b538SAndroid Build Coastguard Worker       }
141*6777b538SAndroid Build Coastguard Worker       bytes_read += rv;
142*6777b538SAndroid Build Coastguard Worker     } while (!reached_end && (bytes_read < bytes_requested));
143*6777b538SAndroid Build Coastguard Worker 
144*6777b538SAndroid Build Coastguard Worker     // Return results if the buffer contains the pattern.
145*6777b538SAndroid Build Coastguard Worker     if (ScanRegionInBuffer(buf, pos + bytes_read, out_address, out_size))
146*6777b538SAndroid Build Coastguard Worker       return true;
147*6777b538SAndroid Build Coastguard Worker 
148*6777b538SAndroid Build Coastguard Worker     // Did not find the pattern.
149*6777b538SAndroid Build Coastguard Worker     if (reached_end)
150*6777b538SAndroid Build Coastguard Worker       return false;
151*6777b538SAndroid Build Coastguard Worker 
152*6777b538SAndroid Build Coastguard Worker     // The buffer is filled to the end. Copy the end bytes to the beginning,
153*6777b538SAndroid Build Coastguard Worker     // allowing to scan these bytes on the next iteration.
154*6777b538SAndroid Build Coastguard Worker     memcpy(buf, buf + kReadSize, kMaxLineLength);
155*6777b538SAndroid Build Coastguard Worker     pos = kMaxLineLength;
156*6777b538SAndroid Build Coastguard Worker     bytes_requested = kReadSize;
157*6777b538SAndroid Build Coastguard Worker   }
158*6777b538SAndroid Build Coastguard Worker }
159*6777b538SAndroid Build Coastguard Worker 
160*6777b538SAndroid Build Coastguard Worker // Invokes android_dlopen_ext() to load the library into a given address range.
161*6777b538SAndroid Build Coastguard Worker // Assumes that the address range is already reserved with mmap(2). On success,
162*6777b538SAndroid Build Coastguard Worker // the |handle| of the loaded library is returned.
163*6777b538SAndroid Build Coastguard Worker //
164*6777b538SAndroid Build Coastguard Worker // Returns true iff this operation succeeds.
AndroidDlopenExt(void * mapping_start,size_t mapping_size,const char * filename,void ** handle)165*6777b538SAndroid Build Coastguard Worker bool AndroidDlopenExt(void* mapping_start,
166*6777b538SAndroid Build Coastguard Worker                       size_t mapping_size,
167*6777b538SAndroid Build Coastguard Worker                       const char* filename,
168*6777b538SAndroid Build Coastguard Worker                       void** handle) {
169*6777b538SAndroid Build Coastguard Worker   android_dlextinfo dlextinfo = {};
170*6777b538SAndroid Build Coastguard Worker   dlextinfo.flags = ANDROID_DLEXT_RESERVED_ADDRESS;
171*6777b538SAndroid Build Coastguard Worker   dlextinfo.reserved_addr = mapping_start;
172*6777b538SAndroid Build Coastguard Worker   dlextinfo.reserved_size = mapping_size;
173*6777b538SAndroid Build Coastguard Worker 
174*6777b538SAndroid Build Coastguard Worker   LOG_INFO(
175*6777b538SAndroid Build Coastguard Worker       "android_dlopen_ext:"
176*6777b538SAndroid Build Coastguard Worker       " flags=0x%" PRIx64 ", reserved_addr=%p, reserved_size=%zu",
177*6777b538SAndroid Build Coastguard Worker       dlextinfo.flags, dlextinfo.reserved_addr, dlextinfo.reserved_size);
178*6777b538SAndroid Build Coastguard Worker 
179*6777b538SAndroid Build Coastguard Worker   void* rv = android_dlopen_ext(filename, RTLD_NOW, &dlextinfo);
180*6777b538SAndroid Build Coastguard Worker   if (rv == nullptr) {
181*6777b538SAndroid Build Coastguard Worker     LOG_ERROR("android_dlopen_ext: %s", dlerror());
182*6777b538SAndroid Build Coastguard Worker     return false;
183*6777b538SAndroid Build Coastguard Worker   }
184*6777b538SAndroid Build Coastguard Worker 
185*6777b538SAndroid Build Coastguard Worker   *handle = rv;
186*6777b538SAndroid Build Coastguard Worker   return true;
187*6777b538SAndroid Build Coastguard Worker }
188*6777b538SAndroid Build Coastguard Worker 
189*6777b538SAndroid Build Coastguard Worker // With munmap(2) unmaps the tail of the given contiguous range of virtual
190*6777b538SAndroid Build Coastguard Worker // memory. Ignores errors.
TrimMapping(uintptr_t address,size_t old_size,size_t new_size)191*6777b538SAndroid Build Coastguard Worker void TrimMapping(uintptr_t address, size_t old_size, size_t new_size) {
192*6777b538SAndroid Build Coastguard Worker   if (old_size <= new_size) {
193*6777b538SAndroid Build Coastguard Worker     LOG_ERROR("WARNING: library reservation was too small");
194*6777b538SAndroid Build Coastguard Worker   } else {
195*6777b538SAndroid Build Coastguard Worker     // Unmap the part of the reserved address space that is beyond the end of
196*6777b538SAndroid Build Coastguard Worker     // the loaded library data.
197*6777b538SAndroid Build Coastguard Worker     const uintptr_t unmap = address + new_size;
198*6777b538SAndroid Build Coastguard Worker     const size_t length = old_size - new_size;
199*6777b538SAndroid Build Coastguard Worker     munmap(reinterpret_cast<void*>(unmap), length);
200*6777b538SAndroid Build Coastguard Worker   }
201*6777b538SAndroid Build Coastguard Worker }
202*6777b538SAndroid Build Coastguard Worker 
203*6777b538SAndroid Build Coastguard Worker // Calls JNI_OnLoad() in the library referenced by |handle|.
204*6777b538SAndroid Build Coastguard Worker // Returns true for success.
CallJniOnLoad(void * handle)205*6777b538SAndroid Build Coastguard Worker bool CallJniOnLoad(void* handle) {
206*6777b538SAndroid Build Coastguard Worker   LOG_INFO("Entering");
207*6777b538SAndroid Build Coastguard Worker   // Locate and if found then call the loaded library's JNI_OnLoad() function.
208*6777b538SAndroid Build Coastguard Worker   using JNI_OnLoadFunctionPtr = int (*)(void* vm, void* reserved);
209*6777b538SAndroid Build Coastguard Worker   auto jni_onload =
210*6777b538SAndroid Build Coastguard Worker       reinterpret_cast<JNI_OnLoadFunctionPtr>(dlsym(handle, "JNI_OnLoad"));
211*6777b538SAndroid Build Coastguard Worker   if (jni_onload != nullptr) {
212*6777b538SAndroid Build Coastguard Worker     // Check that JNI_OnLoad returns a usable JNI version.
213*6777b538SAndroid Build Coastguard Worker     int jni_version = (*jni_onload)(s_java_vm, nullptr);
214*6777b538SAndroid Build Coastguard Worker     if (jni_version < JNI_VERSION_1_4) {
215*6777b538SAndroid Build Coastguard Worker       LOG_ERROR("JNI version is invalid: %d", jni_version);
216*6777b538SAndroid Build Coastguard Worker       return false;
217*6777b538SAndroid Build Coastguard Worker     }
218*6777b538SAndroid Build Coastguard Worker   }
219*6777b538SAndroid Build Coastguard Worker 
220*6777b538SAndroid Build Coastguard Worker   LOG_INFO("Done");
221*6777b538SAndroid Build Coastguard Worker   return true;
222*6777b538SAndroid Build Coastguard Worker }
223*6777b538SAndroid Build Coastguard Worker 
224*6777b538SAndroid Build Coastguard Worker }  // namespace
225*6777b538SAndroid Build Coastguard Worker 
String(JNIEnv * env,jstring str)226*6777b538SAndroid Build Coastguard Worker String::String(JNIEnv* env, jstring str) {
227*6777b538SAndroid Build Coastguard Worker   size_ = env->GetStringUTFLength(str);
228*6777b538SAndroid Build Coastguard Worker   ptr_ = static_cast<char*>(::malloc(size_ + 1));
229*6777b538SAndroid Build Coastguard Worker 
230*6777b538SAndroid Build Coastguard Worker   // Note: This runs before browser native code is loaded, and so cannot
231*6777b538SAndroid Build Coastguard Worker   // rely on anything from base/. This means that we must use
232*6777b538SAndroid Build Coastguard Worker   // GetStringUTFChars() and not base::android::ConvertJavaStringToUTF8().
233*6777b538SAndroid Build Coastguard Worker   //
234*6777b538SAndroid Build Coastguard Worker   // GetStringUTFChars() suffices because the only strings used here are
235*6777b538SAndroid Build Coastguard Worker   // paths to APK files or names of shared libraries, all of which are
236*6777b538SAndroid Build Coastguard Worker   // plain ASCII, defined and hard-coded by the Chromium Android build.
237*6777b538SAndroid Build Coastguard Worker   //
238*6777b538SAndroid Build Coastguard Worker   // For more: see
239*6777b538SAndroid Build Coastguard Worker   //   https://crbug.com/508876
240*6777b538SAndroid Build Coastguard Worker   //
241*6777b538SAndroid Build Coastguard Worker   // Note: GetStringUTFChars() returns Java UTF-8 bytes. This is good
242*6777b538SAndroid Build Coastguard Worker   // enough for the linker though.
243*6777b538SAndroid Build Coastguard Worker   const char* bytes = env->GetStringUTFChars(str, nullptr);
244*6777b538SAndroid Build Coastguard Worker   ::memcpy(ptr_, bytes, size_);
245*6777b538SAndroid Build Coastguard Worker   ptr_[size_] = '\0';
246*6777b538SAndroid Build Coastguard Worker 
247*6777b538SAndroid Build Coastguard Worker   env->ReleaseStringUTFChars(str, bytes);
248*6777b538SAndroid Build Coastguard Worker }
249*6777b538SAndroid Build Coastguard Worker 
IsValidAddress(jlong address)250*6777b538SAndroid Build Coastguard Worker bool IsValidAddress(jlong address) {
251*6777b538SAndroid Build Coastguard Worker   bool result = static_cast<jlong>(static_cast<uintptr_t>(address)) == address;
252*6777b538SAndroid Build Coastguard Worker   if (!result) {
253*6777b538SAndroid Build Coastguard Worker     LOG_ERROR("Invalid address 0x%" PRIx64, static_cast<uint64_t>(address));
254*6777b538SAndroid Build Coastguard Worker   }
255*6777b538SAndroid Build Coastguard Worker   return result;
256*6777b538SAndroid Build Coastguard Worker }
257*6777b538SAndroid Build Coastguard Worker 
258*6777b538SAndroid Build Coastguard Worker // Finds the jclass JNI reference corresponding to a given |class_name|.
259*6777b538SAndroid Build Coastguard Worker // |env| is the current JNI environment handle.
260*6777b538SAndroid Build Coastguard Worker // On success, return true and set |*clazz|.
InitClassReference(JNIEnv * env,const char * class_name,jclass * clazz)261*6777b538SAndroid Build Coastguard Worker bool InitClassReference(JNIEnv* env, const char* class_name, jclass* clazz) {
262*6777b538SAndroid Build Coastguard Worker   *clazz = env->FindClass(class_name);
263*6777b538SAndroid Build Coastguard Worker   if (!*clazz) {
264*6777b538SAndroid Build Coastguard Worker     LOG_ERROR("Could not find class for %s", class_name);
265*6777b538SAndroid Build Coastguard Worker     return false;
266*6777b538SAndroid Build Coastguard Worker   }
267*6777b538SAndroid Build Coastguard Worker   return true;
268*6777b538SAndroid Build Coastguard Worker }
269*6777b538SAndroid Build Coastguard Worker 
270*6777b538SAndroid Build Coastguard Worker // Initializes a jfieldID corresponding to the field of a given |clazz|,
271*6777b538SAndroid Build Coastguard Worker // with name |field_name| and signature |field_sig|.
272*6777b538SAndroid Build Coastguard Worker // |env| is the current JNI environment handle.
273*6777b538SAndroid Build Coastguard Worker // On success, return true and set |*field_id|.
InitFieldId(JNIEnv * env,jclass clazz,const char * field_name,const char * field_sig,jfieldID * field_id)274*6777b538SAndroid Build Coastguard Worker bool InitFieldId(JNIEnv* env,
275*6777b538SAndroid Build Coastguard Worker                  jclass clazz,
276*6777b538SAndroid Build Coastguard Worker                  const char* field_name,
277*6777b538SAndroid Build Coastguard Worker                  const char* field_sig,
278*6777b538SAndroid Build Coastguard Worker                  jfieldID* field_id) {
279*6777b538SAndroid Build Coastguard Worker   *field_id = env->GetFieldID(clazz, field_name, field_sig);
280*6777b538SAndroid Build Coastguard Worker   if (!*field_id) {
281*6777b538SAndroid Build Coastguard Worker     LOG_ERROR("Could not find ID for field '%s'", field_name);
282*6777b538SAndroid Build Coastguard Worker     return false;
283*6777b538SAndroid Build Coastguard Worker   }
284*6777b538SAndroid Build Coastguard Worker   LOG_INFO("Found ID %p for field '%s'", *field_id, field_name);
285*6777b538SAndroid Build Coastguard Worker   return true;
286*6777b538SAndroid Build Coastguard Worker }
287*6777b538SAndroid Build Coastguard Worker 
FindWebViewReservation(uintptr_t * out_address,size_t * out_size)288*6777b538SAndroid Build Coastguard Worker bool FindWebViewReservation(uintptr_t* out_address, size_t* out_size) {
289*6777b538SAndroid Build Coastguard Worker   // Note: reading /proc/PID/maps or /proc/PID/smaps is inherently racy. Among
290*6777b538SAndroid Build Coastguard Worker   // other things, the kernel provides these guarantees:
291*6777b538SAndroid Build Coastguard Worker   // * Each region record (line) is well formed
292*6777b538SAndroid Build Coastguard Worker   // * If there is something at a given vaddr during the entirety of the life of
293*6777b538SAndroid Build Coastguard Worker   //   the smaps/maps walk, there will be some output for it.
294*6777b538SAndroid Build Coastguard Worker   //
295*6777b538SAndroid Build Coastguard Worker   // In order for the address/size extraction to be safe, these precausions are
296*6777b538SAndroid Build Coastguard Worker   // made in base/android/linker:
297*6777b538SAndroid Build Coastguard Worker   // * Modification of the range is done only after this function exits
298*6777b538SAndroid Build Coastguard Worker   // * The use of the range is avoided if it is not sufficient in size, which
299*6777b538SAndroid Build Coastguard Worker   //   might happen if it gets split
300*6777b538SAndroid Build Coastguard Worker   const char kFileName[] = "/proc/self/maps";
301*6777b538SAndroid Build Coastguard Worker   int fd = HANDLE_EINTR(open(kFileName, O_RDONLY));
302*6777b538SAndroid Build Coastguard Worker   if (fd == -1) {
303*6777b538SAndroid Build Coastguard Worker     PLOG_ERROR("open %s", kFileName);
304*6777b538SAndroid Build Coastguard Worker     return false;
305*6777b538SAndroid Build Coastguard Worker   }
306*6777b538SAndroid Build Coastguard Worker 
307*6777b538SAndroid Build Coastguard Worker   bool result = FindRegionInOpenFile(fd, out_address, out_size);
308*6777b538SAndroid Build Coastguard Worker   close(fd);
309*6777b538SAndroid Build Coastguard Worker   return result;
310*6777b538SAndroid Build Coastguard Worker }
311*6777b538SAndroid Build Coastguard Worker 
312*6777b538SAndroid Build Coastguard Worker // Starting with API level 26 (Android O) the following functions from
313*6777b538SAndroid Build Coastguard Worker // libandroid.so should be used to create shared memory regions to ensure
314*6777b538SAndroid Build Coastguard Worker // compatibility with the future versions:
315*6777b538SAndroid Build Coastguard Worker // * ASharedMemory_create()
316*6777b538SAndroid Build Coastguard Worker // * ASharedMemory_setProt()
317*6777b538SAndroid Build Coastguard Worker //
318*6777b538SAndroid Build Coastguard Worker // This is inspired by //third_party/ashmem/ashmem-dev.c, which cannot be
319*6777b538SAndroid Build Coastguard Worker // referenced from the linker library to avoid increasing binary size.
320*6777b538SAndroid Build Coastguard Worker //
321*6777b538SAndroid Build Coastguard Worker // *Not* threadsafe.
322*6777b538SAndroid Build Coastguard Worker struct SharedMemoryFunctions {
SharedMemoryFunctionschromium_android_linker::SharedMemoryFunctions323*6777b538SAndroid Build Coastguard Worker   SharedMemoryFunctions() {
324*6777b538SAndroid Build Coastguard Worker     library_handle = dlopen("libandroid.so", RTLD_NOW);
325*6777b538SAndroid Build Coastguard Worker     create = reinterpret_cast<CreateFunction>(
326*6777b538SAndroid Build Coastguard Worker         dlsym(library_handle, "ASharedMemory_create"));
327*6777b538SAndroid Build Coastguard Worker     set_protection = reinterpret_cast<SetProtectionFunction>(
328*6777b538SAndroid Build Coastguard Worker         dlsym(library_handle, "ASharedMemory_setProt"));
329*6777b538SAndroid Build Coastguard Worker   }
330*6777b538SAndroid Build Coastguard Worker 
IsWorkingchromium_android_linker::SharedMemoryFunctions331*6777b538SAndroid Build Coastguard Worker   bool IsWorking() const {
332*6777b538SAndroid Build Coastguard Worker     if (!create || !set_protection) {
333*6777b538SAndroid Build Coastguard Worker       LOG_ERROR("Cannot get the shared memory functions from libandroid");
334*6777b538SAndroid Build Coastguard Worker       return false;
335*6777b538SAndroid Build Coastguard Worker     }
336*6777b538SAndroid Build Coastguard Worker     return true;
337*6777b538SAndroid Build Coastguard Worker   }
338*6777b538SAndroid Build Coastguard Worker 
~SharedMemoryFunctionschromium_android_linker::SharedMemoryFunctions339*6777b538SAndroid Build Coastguard Worker   ~SharedMemoryFunctions() {
340*6777b538SAndroid Build Coastguard Worker     if (library_handle)
341*6777b538SAndroid Build Coastguard Worker       dlclose(library_handle);
342*6777b538SAndroid Build Coastguard Worker   }
343*6777b538SAndroid Build Coastguard Worker 
344*6777b538SAndroid Build Coastguard Worker   typedef int (*CreateFunction)(const char*, size_t);
345*6777b538SAndroid Build Coastguard Worker   typedef int (*SetProtectionFunction)(int fd, int prot);
346*6777b538SAndroid Build Coastguard Worker 
347*6777b538SAndroid Build Coastguard Worker   CreateFunction create;
348*6777b538SAndroid Build Coastguard Worker   SetProtectionFunction set_protection;
349*6777b538SAndroid Build Coastguard Worker 
350*6777b538SAndroid Build Coastguard Worker   void* library_handle = nullptr;
351*6777b538SAndroid Build Coastguard Worker };
352*6777b538SAndroid Build Coastguard Worker 
ExportLoadInfoToJava() const353*6777b538SAndroid Build Coastguard Worker void NativeLibInfo::ExportLoadInfoToJava() const {
354*6777b538SAndroid Build Coastguard Worker   if (!env_)
355*6777b538SAndroid Build Coastguard Worker     return;
356*6777b538SAndroid Build Coastguard Worker   s_lib_info_fields.SetLoadInfo(env_, java_object_, load_address_, load_size_);
357*6777b538SAndroid Build Coastguard Worker }
358*6777b538SAndroid Build Coastguard Worker 
ExportRelroInfoToJava() const359*6777b538SAndroid Build Coastguard Worker void NativeLibInfo::ExportRelroInfoToJava() const {
360*6777b538SAndroid Build Coastguard Worker   if (!env_)
361*6777b538SAndroid Build Coastguard Worker     return;
362*6777b538SAndroid Build Coastguard Worker   s_lib_info_fields.SetRelroInfo(env_, java_object_, relro_start_, relro_size_,
363*6777b538SAndroid Build Coastguard Worker                                  relro_fd_);
364*6777b538SAndroid Build Coastguard Worker }
365*6777b538SAndroid Build Coastguard Worker 
CloseRelroFd()366*6777b538SAndroid Build Coastguard Worker void NativeLibInfo::CloseRelroFd() {
367*6777b538SAndroid Build Coastguard Worker   if (relro_fd_ == kInvalidFd)
368*6777b538SAndroid Build Coastguard Worker     return;
369*6777b538SAndroid Build Coastguard Worker   close(relro_fd_);
370*6777b538SAndroid Build Coastguard Worker   relro_fd_ = kInvalidFd;
371*6777b538SAndroid Build Coastguard Worker }
372*6777b538SAndroid Build Coastguard Worker 
FindRelroAndLibraryRangesInElf()373*6777b538SAndroid Build Coastguard Worker bool NativeLibInfo::FindRelroAndLibraryRangesInElf() {
374*6777b538SAndroid Build Coastguard Worker   LOG_INFO("Called for 0x%" PRIxPTR, load_address_);
375*6777b538SAndroid Build Coastguard Worker 
376*6777b538SAndroid Build Coastguard Worker   // Check that an ELF library starts at the |load_address_|.
377*6777b538SAndroid Build Coastguard Worker   if (memcmp(reinterpret_cast<void*>(load_address_), ELFMAG, SELFMAG) != 0) {
378*6777b538SAndroid Build Coastguard Worker     LOG_ERROR("Wrong magic number");
379*6777b538SAndroid Build Coastguard Worker     return false;
380*6777b538SAndroid Build Coastguard Worker   }
381*6777b538SAndroid Build Coastguard Worker   auto class_type = *reinterpret_cast<uint8_t*>(load_address_ + EI_CLASS);
382*6777b538SAndroid Build Coastguard Worker   if (class_type == ELFCLASS32) {
383*6777b538SAndroid Build Coastguard Worker     LOG_INFO("ELFCLASS32");
384*6777b538SAndroid Build Coastguard Worker   } else if (class_type == ELFCLASS64) {
385*6777b538SAndroid Build Coastguard Worker     LOG_INFO("ELFCLASS64");
386*6777b538SAndroid Build Coastguard Worker   } else {
387*6777b538SAndroid Build Coastguard Worker     LOG_ERROR("Could not determine ELF class");
388*6777b538SAndroid Build Coastguard Worker     return false;
389*6777b538SAndroid Build Coastguard Worker   }
390*6777b538SAndroid Build Coastguard Worker 
391*6777b538SAndroid Build Coastguard Worker   // Compute the ranges of PT_LOAD segments and the PT_GNU_RELRO. It is possible
392*6777b538SAndroid Build Coastguard Worker   // to reach for the same information by iterating over all loaded libraries
393*6777b538SAndroid Build Coastguard Worker   // and their program headers using dl_iterate_phdr(3). Instead here the
394*6777b538SAndroid Build Coastguard Worker   // iteration goes through the array |e_phoff[e_phnum]| to avoid acquisition of
395*6777b538SAndroid Build Coastguard Worker   // the global lock in Bionic (dlfcn.cpp).
396*6777b538SAndroid Build Coastguard Worker   //
397*6777b538SAndroid Build Coastguard Worker   // The code relies on (1) having RELRO in the PT_GNU_RELRO segment, and (2)
398*6777b538SAndroid Build Coastguard Worker   // the fact that the address *range* occupied by the library is the minimal
399*6777b538SAndroid Build Coastguard Worker   // address range containing all of the PT_LOAD and PT_GNU_RELRO segments.
400*6777b538SAndroid Build Coastguard Worker   // This is a contract between the static linker and the dynamic linker which
401*6777b538SAndroid Build Coastguard Worker   // seems unlikely to get broken. It might break though as a result of
402*6777b538SAndroid Build Coastguard Worker   // post-processing the DSO, which has historically happened for a few
403*6777b538SAndroid Build Coastguard Worker   // occasions (eliminating the unwind tables and splitting the library into
404*6777b538SAndroid Build Coastguard Worker   // DFMs).
405*6777b538SAndroid Build Coastguard Worker   auto min_vaddr = std::numeric_limits<ElfW(Addr)>::max();
406*6777b538SAndroid Build Coastguard Worker   auto min_relro_vaddr = min_vaddr;
407*6777b538SAndroid Build Coastguard Worker   ElfW(Addr) max_vaddr = 0;
408*6777b538SAndroid Build Coastguard Worker   ElfW(Addr) max_relro_vaddr = 0;
409*6777b538SAndroid Build Coastguard Worker   const auto* ehdr = reinterpret_cast<const ElfW(Ehdr)*>(load_address_);
410*6777b538SAndroid Build Coastguard Worker   const auto* phdrs =
411*6777b538SAndroid Build Coastguard Worker       reinterpret_cast<const ElfW(Phdr)*>(load_address_ + ehdr->e_phoff);
412*6777b538SAndroid Build Coastguard Worker   const size_t kPageSize = GetPageSize();
413*6777b538SAndroid Build Coastguard Worker   for (int i = 0; i < ehdr->e_phnum; i++) {
414*6777b538SAndroid Build Coastguard Worker     const ElfW(Phdr)* phdr = &phdrs[i];
415*6777b538SAndroid Build Coastguard Worker     switch (phdr->p_type) {
416*6777b538SAndroid Build Coastguard Worker       case PT_LOAD:
417*6777b538SAndroid Build Coastguard Worker         if (phdr->p_vaddr < min_vaddr)
418*6777b538SAndroid Build Coastguard Worker           min_vaddr = phdr->p_vaddr;
419*6777b538SAndroid Build Coastguard Worker         if (phdr->p_vaddr + phdr->p_memsz > max_vaddr)
420*6777b538SAndroid Build Coastguard Worker           max_vaddr = phdr->p_vaddr + phdr->p_memsz;
421*6777b538SAndroid Build Coastguard Worker         break;
422*6777b538SAndroid Build Coastguard Worker       case PT_GNU_RELRO:
423*6777b538SAndroid Build Coastguard Worker         min_relro_vaddr = PageStart(kPageSize, phdr->p_vaddr);
424*6777b538SAndroid Build Coastguard Worker         max_relro_vaddr = phdr->p_vaddr + phdr->p_memsz;
425*6777b538SAndroid Build Coastguard Worker 
426*6777b538SAndroid Build Coastguard Worker         // As of 2020-11 in libmonochrome.so RELRO is covered by a LOAD segment.
427*6777b538SAndroid Build Coastguard Worker         // It is not clear whether this property is going to be guaranteed in
428*6777b538SAndroid Build Coastguard Worker         // the future. Include the RELRO segment as part of the 'load size'.
429*6777b538SAndroid Build Coastguard Worker         // This way a potential future change in layout of LOAD segments would
430*6777b538SAndroid Build Coastguard Worker         // not open address space for racy mmap(MAP_FIXED).
431*6777b538SAndroid Build Coastguard Worker         if (min_relro_vaddr < min_vaddr)
432*6777b538SAndroid Build Coastguard Worker           min_vaddr = min_relro_vaddr;
433*6777b538SAndroid Build Coastguard Worker         if (max_vaddr < max_relro_vaddr)
434*6777b538SAndroid Build Coastguard Worker           max_vaddr = max_relro_vaddr;
435*6777b538SAndroid Build Coastguard Worker         break;
436*6777b538SAndroid Build Coastguard Worker       default:
437*6777b538SAndroid Build Coastguard Worker         break;
438*6777b538SAndroid Build Coastguard Worker     }
439*6777b538SAndroid Build Coastguard Worker   }
440*6777b538SAndroid Build Coastguard Worker 
441*6777b538SAndroid Build Coastguard Worker   // Fill out size and RELRO information.
442*6777b538SAndroid Build Coastguard Worker   load_size_ = PageEnd(kPageSize, max_vaddr) - PageStart(kPageSize, min_vaddr);
443*6777b538SAndroid Build Coastguard Worker   relro_size_ = PageEnd(kPageSize, max_relro_vaddr) -
444*6777b538SAndroid Build Coastguard Worker                 PageStart(kPageSize, min_relro_vaddr);
445*6777b538SAndroid Build Coastguard Worker   relro_start_ = load_address_ + PageStart(kPageSize, min_relro_vaddr);
446*6777b538SAndroid Build Coastguard Worker   return true;
447*6777b538SAndroid Build Coastguard Worker }
448*6777b538SAndroid Build Coastguard Worker 
LoadWithDlopenExt(const String & path,void ** handle)449*6777b538SAndroid Build Coastguard Worker bool NativeLibInfo::LoadWithDlopenExt(const String& path, void** handle) {
450*6777b538SAndroid Build Coastguard Worker   LOG_INFO("Entering");
451*6777b538SAndroid Build Coastguard Worker 
452*6777b538SAndroid Build Coastguard Worker   // The address range must be reserved during initialization in Linker.java.
453*6777b538SAndroid Build Coastguard Worker   if (!load_address_) {
454*6777b538SAndroid Build Coastguard Worker     // TODO(pasko): measure how often this happens.
455*6777b538SAndroid Build Coastguard Worker     return false;
456*6777b538SAndroid Build Coastguard Worker   }
457*6777b538SAndroid Build Coastguard Worker 
458*6777b538SAndroid Build Coastguard Worker   // Remember the memory reservation size. Starting from this point load_size_
459*6777b538SAndroid Build Coastguard Worker   // changes the meaning to reflect the size of the loaded library.
460*6777b538SAndroid Build Coastguard Worker   size_t reservation_size = load_size_;
461*6777b538SAndroid Build Coastguard Worker   auto* address = reinterpret_cast<void*>(load_address_);
462*6777b538SAndroid Build Coastguard Worker 
463*6777b538SAndroid Build Coastguard Worker   // Invoke android_dlopen_ext.
464*6777b538SAndroid Build Coastguard Worker   void* local_handle = nullptr;
465*6777b538SAndroid Build Coastguard Worker   if (!AndroidDlopenExt(address, reservation_size, path.c_str(),
466*6777b538SAndroid Build Coastguard Worker                         &local_handle)) {
467*6777b538SAndroid Build Coastguard Worker     LOG_ERROR("android_dlopen_ext() error");
468*6777b538SAndroid Build Coastguard Worker     munmap(address, load_size_);
469*6777b538SAndroid Build Coastguard Worker     return false;
470*6777b538SAndroid Build Coastguard Worker   }
471*6777b538SAndroid Build Coastguard Worker 
472*6777b538SAndroid Build Coastguard Worker   // Histogram ChromiumAndroidLinker.ModernLinkerDlopenExtTime that measured the
473*6777b538SAndroid Build Coastguard Worker   // amount of time the ModernLinker spends to run android_dlopen_ext() was
474*6777b538SAndroid Build Coastguard Worker   // removed in July 2023.
475*6777b538SAndroid Build Coastguard Worker 
476*6777b538SAndroid Build Coastguard Worker   // Determine the library address ranges and the RELRO region.
477*6777b538SAndroid Build Coastguard Worker   if (!FindRelroAndLibraryRangesInElf()) {
478*6777b538SAndroid Build Coastguard Worker     // Fail early if PT_GNU_RELRO is not found. It likely indicates a
479*6777b538SAndroid Build Coastguard Worker     // build misconfiguration.
480*6777b538SAndroid Build Coastguard Worker     LOG_ERROR("Could not find RELRO in the loaded library: %s", path.c_str());
481*6777b538SAndroid Build Coastguard Worker     abort();
482*6777b538SAndroid Build Coastguard Worker   }
483*6777b538SAndroid Build Coastguard Worker 
484*6777b538SAndroid Build Coastguard Worker   // Histogram ChromiumAndroidLinker.ModernLinkerIteratePhdrTime that measured
485*6777b538SAndroid Build Coastguard Worker   // the amount of time the ModernLinker spends to find the RELRO region using
486*6777b538SAndroid Build Coastguard Worker   // dl_iterate_phdr() was removed in July 2023.
487*6777b538SAndroid Build Coastguard Worker 
488*6777b538SAndroid Build Coastguard Worker   // Release the unused parts of the memory reservation.
489*6777b538SAndroid Build Coastguard Worker   TrimMapping(load_address_, reservation_size, load_size_);
490*6777b538SAndroid Build Coastguard Worker 
491*6777b538SAndroid Build Coastguard Worker   *handle = local_handle;
492*6777b538SAndroid Build Coastguard Worker   return true;
493*6777b538SAndroid Build Coastguard Worker }
494*6777b538SAndroid Build Coastguard Worker 
CreateSharedRelroFd(const SharedMemoryFunctions & functions)495*6777b538SAndroid Build Coastguard Worker bool NativeLibInfo::CreateSharedRelroFd(
496*6777b538SAndroid Build Coastguard Worker     const SharedMemoryFunctions& functions) {
497*6777b538SAndroid Build Coastguard Worker   LOG_INFO("Entering");
498*6777b538SAndroid Build Coastguard Worker   if (!relro_start_ || !relro_size_) {
499*6777b538SAndroid Build Coastguard Worker     LOG_ERROR("RELRO region is not populated");
500*6777b538SAndroid Build Coastguard Worker     return false;
501*6777b538SAndroid Build Coastguard Worker   }
502*6777b538SAndroid Build Coastguard Worker 
503*6777b538SAndroid Build Coastguard Worker   // Create a writable shared memory region.
504*6777b538SAndroid Build Coastguard Worker   int shared_mem_fd = functions.create("cr_relro", relro_size_);
505*6777b538SAndroid Build Coastguard Worker   if (shared_mem_fd == -1) {
506*6777b538SAndroid Build Coastguard Worker     LOG_ERROR("Cannot create the shared memory file");
507*6777b538SAndroid Build Coastguard Worker     return false;
508*6777b538SAndroid Build Coastguard Worker   }
509*6777b538SAndroid Build Coastguard Worker   int rw_flags = PROT_READ | PROT_WRITE;
510*6777b538SAndroid Build Coastguard Worker   functions.set_protection(shared_mem_fd, rw_flags);
511*6777b538SAndroid Build Coastguard Worker 
512*6777b538SAndroid Build Coastguard Worker   // Map the region as writable.
513*6777b538SAndroid Build Coastguard Worker   void* relro_copy_addr =
514*6777b538SAndroid Build Coastguard Worker       mmap(nullptr, relro_size_, rw_flags, MAP_SHARED, shared_mem_fd, 0);
515*6777b538SAndroid Build Coastguard Worker   if (relro_copy_addr == MAP_FAILED) {
516*6777b538SAndroid Build Coastguard Worker     PLOG_ERROR("failed to allocate space for copying RELRO");
517*6777b538SAndroid Build Coastguard Worker     close(shared_mem_fd);
518*6777b538SAndroid Build Coastguard Worker     return false;
519*6777b538SAndroid Build Coastguard Worker   }
520*6777b538SAndroid Build Coastguard Worker 
521*6777b538SAndroid Build Coastguard Worker   // Populate the shared memory region with the contents of RELRO.
522*6777b538SAndroid Build Coastguard Worker   void* relro_addr = reinterpret_cast<void*>(relro_start_);
523*6777b538SAndroid Build Coastguard Worker   memcpy(relro_copy_addr, relro_addr, relro_size_);
524*6777b538SAndroid Build Coastguard Worker 
525*6777b538SAndroid Build Coastguard Worker   // Protect the underlying physical pages from further modifications from all
526*6777b538SAndroid Build Coastguard Worker   // processes including the forked ones.
527*6777b538SAndroid Build Coastguard Worker   //
528*6777b538SAndroid Build Coastguard Worker   // Setting protection flags on the region to read-only guarantees that the
529*6777b538SAndroid Build Coastguard Worker   // memory can no longer get mapped as writable, for any FD pointing to the
530*6777b538SAndroid Build Coastguard Worker   // region, for any process. It is necessary to also munmap(2) the existing
531*6777b538SAndroid Build Coastguard Worker   // writable memory mappings, since they are not directly affected by the
532*6777b538SAndroid Build Coastguard Worker   // change of region's protection flags.
533*6777b538SAndroid Build Coastguard Worker   munmap(relro_copy_addr, relro_size_);
534*6777b538SAndroid Build Coastguard Worker   if (functions.set_protection(shared_mem_fd, PROT_READ) == -1) {
535*6777b538SAndroid Build Coastguard Worker     LOG_ERROR("Failed to set the RELRO FD as read-only.");
536*6777b538SAndroid Build Coastguard Worker     close(shared_mem_fd);
537*6777b538SAndroid Build Coastguard Worker     return false;
538*6777b538SAndroid Build Coastguard Worker   }
539*6777b538SAndroid Build Coastguard Worker 
540*6777b538SAndroid Build Coastguard Worker   relro_fd_ = shared_mem_fd;
541*6777b538SAndroid Build Coastguard Worker   return true;
542*6777b538SAndroid Build Coastguard Worker }
543*6777b538SAndroid Build Coastguard Worker 
ReplaceRelroWithSharedOne(const SharedMemoryFunctions & functions) const544*6777b538SAndroid Build Coastguard Worker bool NativeLibInfo::ReplaceRelroWithSharedOne(
545*6777b538SAndroid Build Coastguard Worker     const SharedMemoryFunctions& functions) const {
546*6777b538SAndroid Build Coastguard Worker   LOG_INFO("Entering");
547*6777b538SAndroid Build Coastguard Worker   if (relro_fd_ == -1 || !relro_start_ || !relro_size_) {
548*6777b538SAndroid Build Coastguard Worker     LOG_ERROR("Replacement RELRO not ready");
549*6777b538SAndroid Build Coastguard Worker     return false;
550*6777b538SAndroid Build Coastguard Worker   }
551*6777b538SAndroid Build Coastguard Worker 
552*6777b538SAndroid Build Coastguard Worker   // Map as read-only to *atomically* replace the RELRO region provided by the
553*6777b538SAndroid Build Coastguard Worker   // dynamic linker. To avoid memory corruption it is important that the
554*6777b538SAndroid Build Coastguard Worker   // contents of both memory regions is identical.
555*6777b538SAndroid Build Coastguard Worker   void* new_addr = mmap(reinterpret_cast<void*>(relro_start_), relro_size_,
556*6777b538SAndroid Build Coastguard Worker                         PROT_READ, MAP_FIXED | MAP_SHARED, relro_fd_, 0);
557*6777b538SAndroid Build Coastguard Worker   if (new_addr == MAP_FAILED) {
558*6777b538SAndroid Build Coastguard Worker     PLOG_ERROR("mmap: replace RELRO");
559*6777b538SAndroid Build Coastguard Worker     return false;
560*6777b538SAndroid Build Coastguard Worker   }
561*6777b538SAndroid Build Coastguard Worker 
562*6777b538SAndroid Build Coastguard Worker   LOG_INFO("Replaced RELRO at 0x%" PRIxPTR, relro_start_);
563*6777b538SAndroid Build Coastguard Worker   return true;
564*6777b538SAndroid Build Coastguard Worker }
565*6777b538SAndroid Build Coastguard Worker 
NativeLibInfo(JNIEnv * env,jobject java_object)566*6777b538SAndroid Build Coastguard Worker NativeLibInfo::NativeLibInfo(JNIEnv* env, jobject java_object)
567*6777b538SAndroid Build Coastguard Worker     : env_(env), java_object_(java_object) {}
568*6777b538SAndroid Build Coastguard Worker 
CopyFromJavaObject()569*6777b538SAndroid Build Coastguard Worker bool NativeLibInfo::CopyFromJavaObject() {
570*6777b538SAndroid Build Coastguard Worker   if (!env_)
571*6777b538SAndroid Build Coastguard Worker     return false;
572*6777b538SAndroid Build Coastguard Worker 
573*6777b538SAndroid Build Coastguard Worker   if (!s_lib_info_fields.GetLoadInfo(env_, java_object_, &load_address_,
574*6777b538SAndroid Build Coastguard Worker                                      &load_size_)) {
575*6777b538SAndroid Build Coastguard Worker     return false;
576*6777b538SAndroid Build Coastguard Worker   }
577*6777b538SAndroid Build Coastguard Worker   s_lib_info_fields.GetRelroInfo(env_, java_object_, &relro_start_,
578*6777b538SAndroid Build Coastguard Worker                                  &relro_size_, &relro_fd_);
579*6777b538SAndroid Build Coastguard Worker   return true;
580*6777b538SAndroid Build Coastguard Worker }
581*6777b538SAndroid Build Coastguard Worker 
LoadLibrary(const String & library_path,bool spawn_relro_region)582*6777b538SAndroid Build Coastguard Worker bool NativeLibInfo::LoadLibrary(const String& library_path,
583*6777b538SAndroid Build Coastguard Worker                                 bool spawn_relro_region) {
584*6777b538SAndroid Build Coastguard Worker   // Load the library.
585*6777b538SAndroid Build Coastguard Worker   void* handle = nullptr;
586*6777b538SAndroid Build Coastguard Worker   if (!LoadWithDlopenExt(library_path, &handle)) {
587*6777b538SAndroid Build Coastguard Worker     LOG_ERROR("Failed to load native library: %s", library_path.c_str());
588*6777b538SAndroid Build Coastguard Worker     return false;
589*6777b538SAndroid Build Coastguard Worker   }
590*6777b538SAndroid Build Coastguard Worker   if (!CallJniOnLoad(handle))
591*6777b538SAndroid Build Coastguard Worker     return false;
592*6777b538SAndroid Build Coastguard Worker 
593*6777b538SAndroid Build Coastguard Worker   // Publish the library size and load address back to LibInfo in Java.
594*6777b538SAndroid Build Coastguard Worker   ExportLoadInfoToJava();
595*6777b538SAndroid Build Coastguard Worker 
596*6777b538SAndroid Build Coastguard Worker   if (!spawn_relro_region)
597*6777b538SAndroid Build Coastguard Worker     return true;
598*6777b538SAndroid Build Coastguard Worker 
599*6777b538SAndroid Build Coastguard Worker   // Spawn RELRO to a shared memory region by copying and remapping on top of
600*6777b538SAndroid Build Coastguard Worker   // itself.
601*6777b538SAndroid Build Coastguard Worker   SharedMemoryFunctions functions;
602*6777b538SAndroid Build Coastguard Worker   if (!functions.IsWorking())
603*6777b538SAndroid Build Coastguard Worker     return false;
604*6777b538SAndroid Build Coastguard Worker   if (!CreateSharedRelroFd(functions)) {
605*6777b538SAndroid Build Coastguard Worker     LOG_ERROR("Failed to create shared RELRO");
606*6777b538SAndroid Build Coastguard Worker     return false;
607*6777b538SAndroid Build Coastguard Worker   }
608*6777b538SAndroid Build Coastguard Worker   if (!ReplaceRelroWithSharedOne(functions)) {
609*6777b538SAndroid Build Coastguard Worker     LOG_ERROR("Failed to convert RELRO to shared memory");
610*6777b538SAndroid Build Coastguard Worker     CloseRelroFd();
611*6777b538SAndroid Build Coastguard Worker     return false;
612*6777b538SAndroid Build Coastguard Worker   }
613*6777b538SAndroid Build Coastguard Worker 
614*6777b538SAndroid Build Coastguard Worker   LOG_INFO(
615*6777b538SAndroid Build Coastguard Worker       "Created and converted RELRO to shared memory: relro_fd=%d, "
616*6777b538SAndroid Build Coastguard Worker       "relro_start=0x%" PRIxPTR,
617*6777b538SAndroid Build Coastguard Worker       relro_fd_, relro_start_);
618*6777b538SAndroid Build Coastguard Worker   ExportRelroInfoToJava();
619*6777b538SAndroid Build Coastguard Worker   return true;
620*6777b538SAndroid Build Coastguard Worker }
621*6777b538SAndroid Build Coastguard Worker 
RelroIsIdentical(const NativeLibInfo & other_lib_info,const SharedMemoryFunctions & functions) const622*6777b538SAndroid Build Coastguard Worker bool NativeLibInfo::RelroIsIdentical(
623*6777b538SAndroid Build Coastguard Worker     const NativeLibInfo& other_lib_info,
624*6777b538SAndroid Build Coastguard Worker     const SharedMemoryFunctions& functions) const {
625*6777b538SAndroid Build Coastguard Worker   // Abandon sharing if contents of the incoming RELRO region does not match the
626*6777b538SAndroid Build Coastguard Worker   // current one. This can be useful for debugging, but should never happen in
627*6777b538SAndroid Build Coastguard Worker   // the field.
628*6777b538SAndroid Build Coastguard Worker   if (other_lib_info.relro_start_ != relro_start_ ||
629*6777b538SAndroid Build Coastguard Worker       other_lib_info.relro_size_ != relro_size_ ||
630*6777b538SAndroid Build Coastguard Worker       other_lib_info.load_size_ != load_size_) {
631*6777b538SAndroid Build Coastguard Worker     LOG_ERROR("Incoming RELRO size does not match RELRO of the loaded library");
632*6777b538SAndroid Build Coastguard Worker     return false;
633*6777b538SAndroid Build Coastguard Worker   }
634*6777b538SAndroid Build Coastguard Worker   void* shared_relro_address =
635*6777b538SAndroid Build Coastguard Worker       mmap(nullptr, other_lib_info.relro_size_, PROT_READ, MAP_SHARED,
636*6777b538SAndroid Build Coastguard Worker            other_lib_info.relro_fd_, 0);
637*6777b538SAndroid Build Coastguard Worker   if (shared_relro_address == MAP_FAILED) {
638*6777b538SAndroid Build Coastguard Worker     PLOG_ERROR("mmap: check RELRO is identical");
639*6777b538SAndroid Build Coastguard Worker     return false;
640*6777b538SAndroid Build Coastguard Worker   }
641*6777b538SAndroid Build Coastguard Worker   void* current_relro_address = reinterpret_cast<void*>(relro_start_);
642*6777b538SAndroid Build Coastguard Worker   int not_equal =
643*6777b538SAndroid Build Coastguard Worker       memcmp(shared_relro_address, current_relro_address, relro_size_);
644*6777b538SAndroid Build Coastguard Worker   munmap(shared_relro_address, relro_size_);
645*6777b538SAndroid Build Coastguard Worker   if (not_equal) {
646*6777b538SAndroid Build Coastguard Worker     LOG_ERROR("Relocations are not identical, giving up.");
647*6777b538SAndroid Build Coastguard Worker     return false;
648*6777b538SAndroid Build Coastguard Worker   }
649*6777b538SAndroid Build Coastguard Worker   return true;
650*6777b538SAndroid Build Coastguard Worker }
651*6777b538SAndroid Build Coastguard Worker 
CompareRelroAndReplaceItBy(const NativeLibInfo & other_lib_info)652*6777b538SAndroid Build Coastguard Worker bool NativeLibInfo::CompareRelroAndReplaceItBy(
653*6777b538SAndroid Build Coastguard Worker     const NativeLibInfo& other_lib_info) {
654*6777b538SAndroid Build Coastguard Worker   if (other_lib_info.relro_fd_ == -1) {
655*6777b538SAndroid Build Coastguard Worker     LOG_ERROR("No shared region to use");
656*6777b538SAndroid Build Coastguard Worker     s_relro_sharing_status = RelroSharingStatus::EXTERNAL_RELRO_FD_NOT_PROVIDED;
657*6777b538SAndroid Build Coastguard Worker     return false;
658*6777b538SAndroid Build Coastguard Worker   }
659*6777b538SAndroid Build Coastguard Worker 
660*6777b538SAndroid Build Coastguard Worker   if (load_address_ == 0) {
661*6777b538SAndroid Build Coastguard Worker     LOG_ERROR("Load address reset. Second attempt to load the library?");
662*6777b538SAndroid Build Coastguard Worker     s_relro_sharing_status = RelroSharingStatus::EXTERNAL_LOAD_ADDRESS_RESET;
663*6777b538SAndroid Build Coastguard Worker     return false;
664*6777b538SAndroid Build Coastguard Worker   }
665*6777b538SAndroid Build Coastguard Worker 
666*6777b538SAndroid Build Coastguard Worker   if (!FindRelroAndLibraryRangesInElf()) {
667*6777b538SAndroid Build Coastguard Worker     LOG_ERROR("Could not find RELRO from externally provided address: 0x%p",
668*6777b538SAndroid Build Coastguard Worker               reinterpret_cast<void*>(other_lib_info.load_address_));
669*6777b538SAndroid Build Coastguard Worker     s_relro_sharing_status = RelroSharingStatus::EXTERNAL_RELRO_NOT_FOUND;
670*6777b538SAndroid Build Coastguard Worker     return false;
671*6777b538SAndroid Build Coastguard Worker   }
672*6777b538SAndroid Build Coastguard Worker 
673*6777b538SAndroid Build Coastguard Worker   SharedMemoryFunctions functions;
674*6777b538SAndroid Build Coastguard Worker   if (!functions.IsWorking()) {
675*6777b538SAndroid Build Coastguard Worker     s_relro_sharing_status = RelroSharingStatus::NO_SHMEM_FUNCTIONS;
676*6777b538SAndroid Build Coastguard Worker     return false;
677*6777b538SAndroid Build Coastguard Worker   }
678*6777b538SAndroid Build Coastguard Worker   if (!RelroIsIdentical(other_lib_info, functions)) {
679*6777b538SAndroid Build Coastguard Worker     LOG_ERROR("RELRO is not identical");
680*6777b538SAndroid Build Coastguard Worker     s_relro_sharing_status = RelroSharingStatus::NOT_IDENTICAL;
681*6777b538SAndroid Build Coastguard Worker     return false;
682*6777b538SAndroid Build Coastguard Worker   }
683*6777b538SAndroid Build Coastguard Worker 
684*6777b538SAndroid Build Coastguard Worker   // Make it shared.
685*6777b538SAndroid Build Coastguard Worker   //
686*6777b538SAndroid Build Coastguard Worker   // The alternative approach to invoke mprotect+mremap is probably faster than
687*6777b538SAndroid Build Coastguard Worker   // munmap+mmap here. The advantage of the latter is that it removes all
688*6777b538SAndroid Build Coastguard Worker   // formerly writable mappings, so:
689*6777b538SAndroid Build Coastguard Worker   //  * It does not rely on disallowing mprotect(PROT_WRITE)
690*6777b538SAndroid Build Coastguard Worker   //  * This way |ReplaceRelroWithSharedOne()| is reused across spawning RELRO
691*6777b538SAndroid Build Coastguard Worker   //    and receiving it
692*6777b538SAndroid Build Coastguard Worker   if (!other_lib_info.ReplaceRelroWithSharedOne(functions)) {
693*6777b538SAndroid Build Coastguard Worker     LOG_ERROR("Failed to use relro_fd");
694*6777b538SAndroid Build Coastguard Worker     s_relro_sharing_status = RelroSharingStatus::REMAP_FAILED;
695*6777b538SAndroid Build Coastguard Worker     return false;
696*6777b538SAndroid Build Coastguard Worker   }
697*6777b538SAndroid Build Coastguard Worker 
698*6777b538SAndroid Build Coastguard Worker   s_relro_sharing_status = RelroSharingStatus::SHARED;
699*6777b538SAndroid Build Coastguard Worker   return true;
700*6777b538SAndroid Build Coastguard Worker }
701*6777b538SAndroid Build Coastguard Worker 
CreateSharedRelroFdForTesting()702*6777b538SAndroid Build Coastguard Worker bool NativeLibInfo::CreateSharedRelroFdForTesting() {
703*6777b538SAndroid Build Coastguard Worker   // The library providing these functions will be dlclose()-ed after returning
704*6777b538SAndroid Build Coastguard Worker   // from this context. The extra overhead of dlopen() is OK for testing.
705*6777b538SAndroid Build Coastguard Worker   SharedMemoryFunctions functions;
706*6777b538SAndroid Build Coastguard Worker   if (!functions.IsWorking())
707*6777b538SAndroid Build Coastguard Worker     abort();
708*6777b538SAndroid Build Coastguard Worker   return CreateSharedRelroFd(functions);
709*6777b538SAndroid Build Coastguard Worker }
710*6777b538SAndroid Build Coastguard Worker 
711*6777b538SAndroid Build Coastguard Worker // static
SharedMemoryFunctionsSupportedForTesting()712*6777b538SAndroid Build Coastguard Worker bool NativeLibInfo::SharedMemoryFunctionsSupportedForTesting() {
713*6777b538SAndroid Build Coastguard Worker   SharedMemoryFunctions functions;
714*6777b538SAndroid Build Coastguard Worker   return functions.IsWorking();
715*6777b538SAndroid Build Coastguard Worker }
716*6777b538SAndroid Build Coastguard Worker 
717*6777b538SAndroid Build Coastguard Worker JNI_BOUNDARY_EXPORT void
Java_org_chromium_base_library_1loader_LinkerJni_nativeFindMemoryRegionAtRandomAddress(JNIEnv * env,jclass clazz,jobject lib_info_obj)718*6777b538SAndroid Build Coastguard Worker Java_org_chromium_base_library_1loader_LinkerJni_nativeFindMemoryRegionAtRandomAddress(
719*6777b538SAndroid Build Coastguard Worker     JNIEnv* env,
720*6777b538SAndroid Build Coastguard Worker     jclass clazz,
721*6777b538SAndroid Build Coastguard Worker     jobject lib_info_obj) {
722*6777b538SAndroid Build Coastguard Worker   LOG_INFO("Entering");
723*6777b538SAndroid Build Coastguard Worker   uintptr_t address;
724*6777b538SAndroid Build Coastguard Worker   size_t size;
725*6777b538SAndroid Build Coastguard Worker   ReserveAddressWithHint(0, &address, &size);
726*6777b538SAndroid Build Coastguard Worker   s_lib_info_fields.SetLoadInfo(env, lib_info_obj, address, size);
727*6777b538SAndroid Build Coastguard Worker }
728*6777b538SAndroid Build Coastguard Worker 
729*6777b538SAndroid Build Coastguard Worker JNI_BOUNDARY_EXPORT void
Java_org_chromium_base_library_1loader_LinkerJni_nativeReserveMemoryForLibrary(JNIEnv * env,jclass clazz,jobject lib_info_obj)730*6777b538SAndroid Build Coastguard Worker Java_org_chromium_base_library_1loader_LinkerJni_nativeReserveMemoryForLibrary(
731*6777b538SAndroid Build Coastguard Worker     JNIEnv* env,
732*6777b538SAndroid Build Coastguard Worker     jclass clazz,
733*6777b538SAndroid Build Coastguard Worker     jobject lib_info_obj) {
734*6777b538SAndroid Build Coastguard Worker   LOG_INFO("Entering");
735*6777b538SAndroid Build Coastguard Worker   uintptr_t address;
736*6777b538SAndroid Build Coastguard Worker   size_t size;
737*6777b538SAndroid Build Coastguard Worker   s_lib_info_fields.GetLoadInfo(env, lib_info_obj, &address, &size);
738*6777b538SAndroid Build Coastguard Worker   ReserveAddressWithHint(address, &address, &size);
739*6777b538SAndroid Build Coastguard Worker   s_lib_info_fields.SetLoadInfo(env, lib_info_obj, address, size);
740*6777b538SAndroid Build Coastguard Worker }
741*6777b538SAndroid Build Coastguard Worker 
742*6777b538SAndroid Build Coastguard Worker JNI_BOUNDARY_EXPORT jboolean
Java_org_chromium_base_library_1loader_LinkerJni_nativeFindRegionReservedByWebViewZygote(JNIEnv * env,jclass clazz,jobject lib_info_obj)743*6777b538SAndroid Build Coastguard Worker Java_org_chromium_base_library_1loader_LinkerJni_nativeFindRegionReservedByWebViewZygote(
744*6777b538SAndroid Build Coastguard Worker     JNIEnv* env,
745*6777b538SAndroid Build Coastguard Worker     jclass clazz,
746*6777b538SAndroid Build Coastguard Worker     jobject lib_info_obj) {
747*6777b538SAndroid Build Coastguard Worker   LOG_INFO("Entering");
748*6777b538SAndroid Build Coastguard Worker   uintptr_t address;
749*6777b538SAndroid Build Coastguard Worker   size_t size;
750*6777b538SAndroid Build Coastguard Worker   if (!FindWebViewReservation(&address, &size))
751*6777b538SAndroid Build Coastguard Worker     return false;
752*6777b538SAndroid Build Coastguard Worker   s_lib_info_fields.SetLoadInfo(env, lib_info_obj, address, size);
753*6777b538SAndroid Build Coastguard Worker   return true;
754*6777b538SAndroid Build Coastguard Worker }
755*6777b538SAndroid Build Coastguard Worker 
756*6777b538SAndroid Build Coastguard Worker JNI_BOUNDARY_EXPORT jboolean
Java_org_chromium_base_library_1loader_LinkerJni_nativeLoadLibrary(JNIEnv * env,jclass clazz,jstring jdlopen_ext_path,jobject lib_info_obj,jboolean spawn_relro_region)757*6777b538SAndroid Build Coastguard Worker Java_org_chromium_base_library_1loader_LinkerJni_nativeLoadLibrary(
758*6777b538SAndroid Build Coastguard Worker     JNIEnv* env,
759*6777b538SAndroid Build Coastguard Worker     jclass clazz,
760*6777b538SAndroid Build Coastguard Worker     jstring jdlopen_ext_path,
761*6777b538SAndroid Build Coastguard Worker     jobject lib_info_obj,
762*6777b538SAndroid Build Coastguard Worker     jboolean spawn_relro_region) {
763*6777b538SAndroid Build Coastguard Worker   LOG_INFO("Entering");
764*6777b538SAndroid Build Coastguard Worker 
765*6777b538SAndroid Build Coastguard Worker   // Copy the contents from the Java-side LibInfo object.
766*6777b538SAndroid Build Coastguard Worker   NativeLibInfo lib_info = {env, lib_info_obj};
767*6777b538SAndroid Build Coastguard Worker   if (!lib_info.CopyFromJavaObject())
768*6777b538SAndroid Build Coastguard Worker     return false;
769*6777b538SAndroid Build Coastguard Worker 
770*6777b538SAndroid Build Coastguard Worker   String library_path(env, jdlopen_ext_path);
771*6777b538SAndroid Build Coastguard Worker   if (!lib_info.LoadLibrary(library_path, spawn_relro_region)) {
772*6777b538SAndroid Build Coastguard Worker     return false;
773*6777b538SAndroid Build Coastguard Worker   }
774*6777b538SAndroid Build Coastguard Worker   return true;
775*6777b538SAndroid Build Coastguard Worker }
776*6777b538SAndroid Build Coastguard Worker 
777*6777b538SAndroid Build Coastguard Worker JNI_BOUNDARY_EXPORT jboolean
Java_org_chromium_base_library_1loader_LinkerJni_nativeUseRelros(JNIEnv * env,jclass clazz,jlong local_load_address,jobject remote_lib_info_obj)778*6777b538SAndroid Build Coastguard Worker Java_org_chromium_base_library_1loader_LinkerJni_nativeUseRelros(
779*6777b538SAndroid Build Coastguard Worker     JNIEnv* env,
780*6777b538SAndroid Build Coastguard Worker     jclass clazz,
781*6777b538SAndroid Build Coastguard Worker     jlong local_load_address,
782*6777b538SAndroid Build Coastguard Worker     jobject remote_lib_info_obj) {
783*6777b538SAndroid Build Coastguard Worker   LOG_INFO("Entering");
784*6777b538SAndroid Build Coastguard Worker   // Copy the contents from the Java-side LibInfo object.
785*6777b538SAndroid Build Coastguard Worker   NativeLibInfo incoming_lib_info = {env, remote_lib_info_obj};
786*6777b538SAndroid Build Coastguard Worker   if (!incoming_lib_info.CopyFromJavaObject()) {
787*6777b538SAndroid Build Coastguard Worker     s_relro_sharing_status = RelroSharingStatus::CORRUPTED_IN_JAVA;
788*6777b538SAndroid Build Coastguard Worker     return false;
789*6777b538SAndroid Build Coastguard Worker   }
790*6777b538SAndroid Build Coastguard Worker 
791*6777b538SAndroid Build Coastguard Worker   // Create an empty NativeLibInfo to extract the current information about the
792*6777b538SAndroid Build Coastguard Worker   // loaded library and later compare with the contents of the
793*6777b538SAndroid Build Coastguard Worker   // |incoming_lib_info|.
794*6777b538SAndroid Build Coastguard Worker   NativeLibInfo lib_info = {nullptr, nullptr};
795*6777b538SAndroid Build Coastguard Worker   lib_info.set_load_address(static_cast<uintptr_t>(local_load_address));
796*6777b538SAndroid Build Coastguard Worker 
797*6777b538SAndroid Build Coastguard Worker   if (!lib_info.CompareRelroAndReplaceItBy(incoming_lib_info)) {
798*6777b538SAndroid Build Coastguard Worker     return false;
799*6777b538SAndroid Build Coastguard Worker   }
800*6777b538SAndroid Build Coastguard Worker   return true;
801*6777b538SAndroid Build Coastguard Worker }
802*6777b538SAndroid Build Coastguard Worker 
803*6777b538SAndroid Build Coastguard Worker JNI_BOUNDARY_EXPORT jint
Java_org_chromium_base_library_1loader_LinkerJni_nativeGetRelroSharingResult(JNIEnv * env,jclass clazz)804*6777b538SAndroid Build Coastguard Worker Java_org_chromium_base_library_1loader_LinkerJni_nativeGetRelroSharingResult(
805*6777b538SAndroid Build Coastguard Worker     JNIEnv* env,
806*6777b538SAndroid Build Coastguard Worker     jclass clazz) {
807*6777b538SAndroid Build Coastguard Worker   return static_cast<jint>(s_relro_sharing_status);
808*6777b538SAndroid Build Coastguard Worker }
809*6777b538SAndroid Build Coastguard Worker 
LinkerJNIInit(JavaVM * vm,JNIEnv * env)810*6777b538SAndroid Build Coastguard Worker bool LinkerJNIInit(JavaVM* vm, JNIEnv* env) {
811*6777b538SAndroid Build Coastguard Worker   // Find LibInfo field ids.
812*6777b538SAndroid Build Coastguard Worker   if (!s_lib_info_fields.Init(env)) {
813*6777b538SAndroid Build Coastguard Worker     return false;
814*6777b538SAndroid Build Coastguard Worker   }
815*6777b538SAndroid Build Coastguard Worker 
816*6777b538SAndroid Build Coastguard Worker   s_java_vm = vm;
817*6777b538SAndroid Build Coastguard Worker   return true;
818*6777b538SAndroid Build Coastguard Worker }
819*6777b538SAndroid Build Coastguard Worker 
820*6777b538SAndroid Build Coastguard Worker }  // namespace chromium_android_linker
821