OLD | NEW |
(Empty) | |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 // This is the version of the Android-specific Chromium linker that uses |
| 6 // the Android M and later system linker to load libraries. |
| 7 |
| 8 // This source code *cannot* depend on anything from base/ or the C++ |
| 9 // STL, to keep the final library small, and avoid ugly dependency issues. |
| 10 |
| 11 #include "modern_linker_jni.h" |
| 12 |
| 13 #include <sys/mman.h> |
| 14 #include <sys/stat.h> |
| 15 #include <sys/types.h> |
| 16 #include <dlfcn.h> |
| 17 #include <errno.h> |
| 18 #include <fcntl.h> |
| 19 #include <jni.h> |
| 20 #include <limits.h> |
| 21 #include <link.h> |
| 22 #include <string.h> |
| 23 |
| 24 #include "android_dlext.h" |
| 25 #include "linker_jni.h" |
| 26 |
| 27 #define PAGE_START(x) ((x)&PAGE_MASK) |
| 28 #define PAGE_END(x) PAGE_START((x) + (PAGE_SIZE - 1)) |
| 29 |
| 30 namespace chromium_android_linker { |
| 31 namespace { |
| 32 |
| 33 // Record of the Java VM passed to JNI_OnLoad(). |
| 34 static JavaVM* s_java_vm = nullptr; |
| 35 |
| 36 // Get the CPU ABI string for which the linker is running. |
| 37 // |
| 38 // The returned string is used to construct the path to libchrome.so when |
| 39 // loading directly from APK. |
| 40 // |
| 41 // |env| is the current JNI environment handle. |
| 42 // |clazz| is the static class handle for org.chromium.base.Linker, |
| 43 // and is ignored here. |
| 44 // Returns the CPU ABI string for which the linker is running. |
| 45 jstring GetCpuAbi(JNIEnv* env, jclass clazz) { |
| 46 #if defined(__arm__) && defined(__ARM_ARCH_7A__) |
| 47 static const char* kCurrentABI = "armeabi-v7a"; |
| 48 #elif defined(__arm__) |
| 49 static const char* kCurrentABI = "armeabi"; |
| 50 #elif defined(__i386__) |
| 51 static const char* kCurrentABI = "x86"; |
| 52 #elif defined(__mips__) |
| 53 static const char* kCurrentABI = "mips"; |
| 54 #elif defined(__x86_64__) |
| 55 static const char* kCurrentABI = "x86_64"; |
| 56 #elif defined(__aarch64__) |
| 57 static const char* kCurrentABI = "arm64-v8a"; |
| 58 #else |
| 59 #error "Unsupported target abi" |
| 60 #endif |
| 61 return env->NewStringUTF(kCurrentABI); |
| 62 } |
| 63 |
| 64 // Convenience wrapper around dlsym() on the main executable. Returns |
| 65 // the address of the requested symbol, or nullptr if not found. Status |
| 66 // is available from dlerror(). |
| 67 void* Dlsym(const char* symbol_name) { |
| 68 static void* handle = nullptr; |
| 69 |
| 70 if (!handle) |
| 71 handle = dlopen(nullptr, RTLD_NOW); |
| 72 |
| 73 void* result = dlsym(handle, symbol_name); |
| 74 return result; |
| 75 } |
| 76 |
| 77 // dl_iterate_phdr() wrapper, accessed via dlsym lookup. Done this way. |
| 78 // so that this code compiles for Android versions that are too early to |
| 79 // offer it. Checks in LibraryLoader.java should ensure that we |
| 80 // never reach here at runtime on Android versions that are too old to |
| 81 // supply dl_iterate_phdr; that is, earlier than Android M. Returns |
| 82 // false if no dl_iterate_phdr() is available, otherwise true with the |
| 83 // return value from dl_iterate_phdr() in |status|. |
| 84 bool DlIteratePhdr(int (*callback)(dl_phdr_info*, size_t, void*), |
| 85 void* data, |
| 86 int* status) { |
| 87 using DlIteratePhdrCallback = int (*)(dl_phdr_info*, size_t, void*); |
| 88 using DlIteratePhdrFunctionPtr = int (*)(DlIteratePhdrCallback, void*); |
| 89 static DlIteratePhdrFunctionPtr function_ptr = nullptr; |
| 90 |
| 91 if (!function_ptr) { |
| 92 function_ptr = |
| 93 reinterpret_cast<DlIteratePhdrFunctionPtr>(Dlsym("dl_iterate_phdr")); |
| 94 if (!function_ptr) { |
| 95 LOG_ERROR("dlsym: dl_iterate_phdr: %s", dlerror()); |
| 96 return false; |
| 97 } |
| 98 } |
| 99 |
| 100 *status = (*function_ptr)(callback, data); |
| 101 return true; |
| 102 } |
| 103 |
| 104 // Convenience struct wrapper round android_dlextinfo. |
| 105 struct AndroidDlextinfo { |
| 106 AndroidDlextinfo(int flags, |
| 107 void* reserved_addr, |
| 108 size_t reserved_size, |
| 109 int relro_fd) { |
| 110 memset(&extinfo, 0, sizeof(extinfo)); |
| 111 extinfo.flags = flags; |
| 112 extinfo.reserved_addr = reserved_addr; |
| 113 extinfo.reserved_size = reserved_size; |
| 114 extinfo.relro_fd = relro_fd; |
| 115 } |
| 116 |
| 117 android_dlextinfo extinfo; |
| 118 }; |
| 119 |
| 120 // android_dlopen_ext() wrapper, accessed via dlsym lookup. Returns false |
| 121 // if no android_dlopen_ext() is available, otherwise true with the return |
| 122 // value from android_dlopen_ext() in |status|. |
| 123 bool AndroidDlopenExt(const char* filename, |
| 124 int flag, |
| 125 const AndroidDlextinfo* dlextinfo, |
| 126 void** status) { |
| 127 using DlopenExtFunctionPtr = |
| 128 void* (*)(const char*, int, const android_dlextinfo*); |
| 129 static DlopenExtFunctionPtr function_ptr = nullptr; |
| 130 |
| 131 if (!function_ptr) { |
| 132 function_ptr = |
| 133 reinterpret_cast<DlopenExtFunctionPtr>(Dlsym("android_dlopen_ext")); |
| 134 if (!function_ptr) { |
| 135 LOG_ERROR("dlsym: android_dlopen_ext: %s", dlerror()); |
| 136 return false; |
| 137 } |
| 138 } |
| 139 |
| 140 const android_dlextinfo* extinfo = &dlextinfo->extinfo; |
| 141 LOG_INFO( |
| 142 "android_dlopen_ext:" |
| 143 " flags=0x%llx, reserved_addr=%p, reserved_size=%d, relro_fd=%d", |
| 144 extinfo->flags, extinfo->reserved_addr, extinfo->reserved_size, |
| 145 extinfo->relro_fd); |
| 146 |
| 147 *status = (*function_ptr)(filename, flag, extinfo); |
| 148 return true; |
| 149 } |
| 150 |
| 151 // Callback data for FindLoadedLibrarySize(). |
| 152 struct CallbackData { |
| 153 explicit CallbackData(void* address) : load_address(address), load_size(0) {} |
| 154 |
| 155 const void* load_address; |
| 156 size_t load_size; |
| 157 }; |
| 158 |
| 159 // Callback for dl_iterate_phdr(). Read phdrs to identify whether or not |
| 160 // this library's load address matches the |load_address| passed in |
| 161 // |data|. If yes, pass back load size via |data|. A non-zero return value |
| 162 // terminates iteration. |
| 163 int FindLoadedLibrarySize(dl_phdr_info* info, size_t size UNUSED, void* data) { |
| 164 CallbackData* callback_data = reinterpret_cast<CallbackData*>(data); |
| 165 |
| 166 // Use max and min vaddr to compute the library's load size. |
| 167 ElfW(Addr) min_vaddr = ~0; |
| 168 ElfW(Addr) max_vaddr = 0; |
| 169 |
| 170 bool is_matching = false; |
| 171 for (size_t i = 0; i < info->dlpi_phnum; ++i) { |
| 172 const ElfW(Phdr)* phdr = &info->dlpi_phdr[i]; |
| 173 if (phdr->p_type != PT_LOAD) |
| 174 continue; |
| 175 |
| 176 // See if this segment's load address matches what we passed to |
| 177 // android_dlopen_ext as extinfo.reserved_addr. |
| 178 void* load_addr = reinterpret_cast<void*>(info->dlpi_addr + phdr->p_vaddr); |
| 179 if (load_addr == callback_data->load_address) |
| 180 is_matching = true; |
| 181 |
| 182 if (phdr->p_vaddr < min_vaddr) |
| 183 min_vaddr = phdr->p_vaddr; |
| 184 if (phdr->p_vaddr + phdr->p_memsz > max_vaddr) |
| 185 max_vaddr = phdr->p_vaddr + phdr->p_memsz; |
| 186 } |
| 187 |
| 188 // If this library matches what we seek, return its load size. |
| 189 if (is_matching) { |
| 190 callback_data->load_size = PAGE_END(max_vaddr) - PAGE_START(min_vaddr); |
| 191 return true; |
| 192 } |
| 193 |
| 194 return false; |
| 195 } |
| 196 |
| 197 // Helper class for anonymous memory mapping. |
| 198 class ScopedAnonymousMmap { |
| 199 public: |
| 200 ScopedAnonymousMmap(void* addr, size_t size); |
| 201 |
| 202 ~ScopedAnonymousMmap() { munmap(addr_, size_); } |
| 203 |
| 204 void* GetAddr() const { return effective_addr_; } |
| 205 void Release() { |
| 206 addr_ = nullptr; |
| 207 size_ = 0; |
| 208 effective_addr_ = nullptr; |
| 209 } |
| 210 |
| 211 private: |
| 212 void* addr_; |
| 213 size_t size_; |
| 214 |
| 215 // The effective_addr_ is the address seen by client code. It may or may |
| 216 // not be the same as addr_, the real start of the anonymous mapping. |
| 217 void* effective_addr_; |
| 218 }; |
| 219 |
| 220 // ScopedAnonymousMmap constructor. |addr| is a requested mapping address, or |
| 221 // zero if any address will do, and |size| is the size of mapping required. |
| 222 ScopedAnonymousMmap::ScopedAnonymousMmap(void* addr, size_t size) { |
| 223 #if RESERVE_BREAKPAD_GUARD_REGION |
| 224 // Increase size to extend the address reservation mapping so that it will |
| 225 // also include a guard region from load_bias_ to start_addr. If loading |
| 226 // at a fixed address, move our requested address back by the guard region |
| 227 // size. |
| 228 size += kBreakpadGuardRegionBytes; |
| 229 if (addr) { |
| 230 if (addr < reinterpret_cast<void*>(kBreakpadGuardRegionBytes)) { |
| 231 LOG_ERROR("Fixed address %p is too low to accommodate Breakpad guard", |
| 232 addr); |
| 233 addr_ = MAP_FAILED; |
| 234 size_ = 0; |
| 235 return; |
| 236 } |
| 237 addr = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(addr) - |
| 238 kBreakpadGuardRegionBytes); |
| 239 } |
| 240 LOG_INFO("Added %d to size, for Breakpad guard", kBreakpadGuardRegionBytes); |
| 241 #endif |
| 242 |
| 243 addr_ = mmap(addr, size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); |
| 244 if (addr_ != MAP_FAILED) { |
| 245 size_ = size; |
| 246 } else { |
| 247 LOG_INFO("mmap failed: %s", strerror(errno)); |
| 248 size_ = 0; |
| 249 } |
| 250 effective_addr_ = addr_; |
| 251 |
| 252 #if RESERVE_BREAKPAD_GUARD_REGION |
| 253 // If we increased size to accommodate a Breakpad guard region, move |
| 254 // the effective address, if valid, upwards by the size of the guard region. |
| 255 if (addr_ == MAP_FAILED) |
| 256 return; |
| 257 if (addr_ < reinterpret_cast<void*>(kBreakpadGuardRegionBytes)) { |
| 258 LOG_ERROR("Map address %p is too low to accommodate Breakpad guard", addr_); |
| 259 effective_addr_ = MAP_FAILED; |
| 260 } else { |
| 261 effective_addr_ = reinterpret_cast<void*>( |
| 262 reinterpret_cast<uintptr_t>(addr_) + kBreakpadGuardRegionBytes); |
| 263 } |
| 264 #endif |
| 265 } |
| 266 |
| 267 // Helper for LoadLibrary(). Return the actual size of the library loaded |
| 268 // at |addr| in |load_size|. Returns false if the library appears not to |
| 269 // be loaded. |
| 270 bool GetLibraryLoadSize(void* addr, size_t* load_size) { |
| 271 LOG_INFO("Called for %p", addr); |
| 272 |
| 273 // Find the real load size for the library loaded at |addr|. |
| 274 CallbackData callback_data(addr); |
| 275 int status = 0; |
| 276 if (!DlIteratePhdr(&FindLoadedLibrarySize, &callback_data, &status)) { |
| 277 LOG_ERROR("No dl_iterate_phdr function found"); |
| 278 return false; |
| 279 } |
| 280 if (!status) { |
| 281 LOG_ERROR("Failed to find library at address %p", addr); |
| 282 return false; |
| 283 } |
| 284 |
| 285 *load_size = callback_data.load_size; |
| 286 return true; |
| 287 } |
| 288 |
| 289 // Helper for LoadLibrary(). We reserve an address space larger than |
| 290 // needed. After library loading we want to trim that reservation to only |
| 291 // what is needed. |
| 292 bool ResizeReservedAddressSpace(void* addr, |
| 293 size_t reserved_size, |
| 294 size_t load_size) { |
| 295 LOG_INFO("Called for %p, reserved %d, loaded %d", addr, reserved_size, |
| 296 load_size); |
| 297 |
| 298 if (reserved_size < load_size) { |
| 299 LOG_ERROR("WARNING: library reservation was too small"); |
| 300 return true; |
| 301 } |
| 302 |
| 303 // Unmap the part of the reserved address space that is beyond the end of |
| 304 // the loaded library data. |
| 305 void* unmap = |
| 306 reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(addr) + load_size); |
| 307 size_t length = reserved_size - load_size; |
| 308 if (munmap(unmap, length) == -1) { |
| 309 LOG_ERROR("Failed to unmap %d at %p", static_cast<int>(length), unmap); |
| 310 return false; |
| 311 } |
| 312 |
| 313 return true; |
| 314 } |
| 315 |
| 316 // Load a library with the chromium linker, using android_dlopen_ext(). |
| 317 // |
| 318 // android_dlopen_ext() understands how to directly load from a zipfile, |
| 319 // based on the format of |dlopen_ext_path|. If it contains a "!/" separator |
| 320 // then the string indicates <zip_path>!/<file_path> and indicates the |
| 321 // file_path element within the zip file at zip_path. A library in a |
| 322 // zipfile must be uncompressed and page aligned. The library is expected |
| 323 // to be lib/<abi_tag>/crazy.<basename>. The <abi_tag> used will be the |
| 324 // same as the abi for this linker. The "crazy." prefix is included |
| 325 // so that the Android Package Manager doesn't extract the library into |
| 326 // /data/app-lib. |
| 327 // |
| 328 // If |dlopen_ext_path| contains no "!/" separator then android_dlopen_ext() |
| 329 // assumes that it is a normal path to a standalone library file. |
| 330 // |
| 331 // Loading the library will also call its JNI_OnLoad() method, which |
| 332 // shall register its methods. Note that lazy native method resolution |
| 333 // will _not_ work after this, because Dalvik uses the system's dlsym() |
| 334 // which won't see the new library, so explicit registration is mandatory. |
| 335 // Load a library with the chromium linker. This will also call its |
| 336 // JNI_OnLoad() method, which shall register its methods. Note that |
| 337 // lazy native method resolution will _not_ work after this, because |
| 338 // Dalvik uses the system's dlsym() which won't see the new library, |
| 339 // so explicit registration is mandatory. |
| 340 // |
| 341 // |env| is the current JNI environment handle. |
| 342 // |clazz| is the static class handle for org.chromium.base.Linker, |
| 343 // and is ignored here. |
| 344 // |dlopen_ext_path| is the library identifier (e.g. libfoo.so). |
| 345 // |load_address| is an explicit load address. |
| 346 // |relro_path| is the path to the file into which RELRO data is held. |
| 347 // |lib_info_obj| is a LibInfo handle used to communicate information |
| 348 // with the Java side. |
| 349 // Return true on success. |
| 350 jboolean LoadLibrary(JNIEnv* env, |
| 351 jclass clazz, |
| 352 jstring dlopen_ext_path, |
| 353 jlong load_address, |
| 354 jobject lib_info_obj) { |
| 355 String dlopen_library_path(env, dlopen_ext_path); |
| 356 LOG_INFO("Called for %s, at address 0x%llx", dlopen_library_path.c_str(), |
| 357 load_address); |
| 358 |
| 359 if (!IsValidAddress(load_address)) { |
| 360 LOG_ERROR("Invalid address 0x%llx", load_address); |
| 361 return false; |
| 362 } |
| 363 |
| 364 const size_t size = kAddressSpaceReservationSize; |
| 365 void* wanted_addr = reinterpret_cast<void*>(load_address); |
| 366 |
| 367 // Reserve the address space into which we load the library. |
| 368 ScopedAnonymousMmap mapping(wanted_addr, size); |
| 369 void* addr = mapping.GetAddr(); |
| 370 if (addr == MAP_FAILED) { |
| 371 LOG_ERROR("Failed to reserve space for load"); |
| 372 return false; |
| 373 } |
| 374 if (wanted_addr && addr != wanted_addr) { |
| 375 LOG_ERROR("Failed to obtain fixed address for load"); |
| 376 return false; |
| 377 } |
| 378 |
| 379 // Build dlextinfo to load the library into the reserved space, using |
| 380 // the shared RELRO if supplied and if its start address matches addr. |
| 381 int relro_fd = -1; |
| 382 int flags = ANDROID_DLEXT_RESERVED_ADDRESS; |
| 383 if (wanted_addr && lib_info_obj) { |
| 384 void* relro_start; |
| 385 s_lib_info_fields.GetRelroInfo(env, lib_info_obj, |
| 386 reinterpret_cast<size_t*>(&relro_start), |
| 387 nullptr, &relro_fd); |
| 388 if (relro_fd != -1 && relro_start == addr) { |
| 389 flags |= ANDROID_DLEXT_USE_RELRO; |
| 390 } |
| 391 } |
| 392 AndroidDlextinfo dlextinfo(flags, addr, size, relro_fd); |
| 393 |
| 394 // Load the library into the reserved space. |
| 395 const char* path = dlopen_library_path.c_str(); |
| 396 void* handle = nullptr; |
| 397 if (!AndroidDlopenExt(path, RTLD_NOW, &dlextinfo, &handle)) { |
| 398 LOG_ERROR("No android_dlopen_ext function found"); |
| 399 return false; |
| 400 } |
| 401 if (handle == nullptr) { |
| 402 LOG_ERROR("android_dlopen_ext: %s", dlerror()); |
| 403 return false; |
| 404 } |
| 405 |
| 406 // After loading, trim the mapping to match the library's actual size. |
| 407 size_t load_size = 0; |
| 408 if (!GetLibraryLoadSize(addr, &load_size)) { |
| 409 LOG_ERROR("Unable to find size for load at %p", addr); |
| 410 return false; |
| 411 } |
| 412 if (!ResizeReservedAddressSpace(addr, size, load_size)) { |
| 413 LOG_ERROR("Unable to resize reserved address mapping"); |
| 414 return false; |
| 415 } |
| 416 |
| 417 // Locate and then call the loaded library's JNI_OnLoad() function. Check |
| 418 // that it returns a usable JNI version. |
| 419 using JNI_OnLoadFunctionPtr = int (*)(void* vm, void* reserved); |
| 420 auto jni_onload = |
| 421 reinterpret_cast<JNI_OnLoadFunctionPtr>(dlsym(handle, "JNI_OnLoad")); |
| 422 if (jni_onload == nullptr) { |
| 423 LOG_ERROR("dlsym: JNI_OnLoad: %s", dlerror()); |
| 424 return false; |
| 425 } |
| 426 |
| 427 int jni_version = (*jni_onload)(s_java_vm, nullptr); |
| 428 if (jni_version < JNI_VERSION_1_4) { |
| 429 LOG_ERROR("JNI version is invalid: %d", jni_version); |
| 430 return false; |
| 431 } |
| 432 |
| 433 // Release mapping before returning so that we do not unmap reserved space. |
| 434 mapping.Release(); |
| 435 |
| 436 // Note the load address and load size in the supplied libinfo object. |
| 437 const size_t cast_addr = reinterpret_cast<size_t>(addr); |
| 438 s_lib_info_fields.SetLoadInfo(env, lib_info_obj, cast_addr, load_size); |
| 439 |
| 440 LOG_INFO("Success loading library %s", dlopen_library_path.c_str()); |
| 441 return true; |
| 442 } |
| 443 |
| 444 // Create a shared RELRO file for a library, using android_dlopen_ext(). |
| 445 // |
| 446 // Loads the library similarly to LoadLibrary() above, by reserving address |
| 447 // space and then using android_dlopen_ext() to load into the reserved |
| 448 // area. Adds flags to android_dlopen_ext() to saved the library's RELRO |
| 449 // memory into the given file path, then unload the library and returns. |
| 450 // |
| 451 // Does not call JNI_OnLoad() or otherwise execute any code from the library. |
| 452 // |
| 453 // |env| is the current JNI environment handle. |
| 454 // |clazz| is the static class handle for org.chromium.base.Linker, |
| 455 // and is ignored here. |
| 456 // |dlopen_ext_path| is the library identifier (e.g. libfoo.so). |
| 457 // |load_address| is an explicit load address. |
| 458 // |relro_path| is the path to the file into which RELRO data is written. |
| 459 // |lib_info_obj| is a LibInfo handle used to communicate information |
| 460 // with the Java side. |
| 461 // Return true on success. |
| 462 jboolean CreateSharedRelro(JNIEnv* env, |
| 463 jclass clazz, |
| 464 jstring dlopen_ext_path, |
| 465 jlong load_address, |
| 466 jstring relro_path, |
| 467 jobject lib_info_obj) { |
| 468 String dlopen_library_path(env, dlopen_ext_path); |
| 469 LOG_INFO("Called for %s, at address 0x%llx", dlopen_library_path.c_str(), |
| 470 load_address); |
| 471 |
| 472 if (!IsValidAddress(load_address) || load_address == 0) { |
| 473 LOG_ERROR("Invalid address 0x%llx", load_address); |
| 474 return false; |
| 475 } |
| 476 |
| 477 const size_t size = kAddressSpaceReservationSize; |
| 478 void* wanted_addr = reinterpret_cast<void*>(load_address); |
| 479 |
| 480 // Reserve the address space into which we load the library. |
| 481 ScopedAnonymousMmap mapping(wanted_addr, size); |
| 482 void* addr = mapping.GetAddr(); |
| 483 if (addr == MAP_FAILED) { |
| 484 LOG_ERROR("Failed to reserve space for load"); |
| 485 return false; |
| 486 } |
| 487 if (addr != wanted_addr) { |
| 488 LOG_ERROR("Failed to obtain fixed address for load"); |
| 489 return false; |
| 490 } |
| 491 |
| 492 // Open the shared RELRO file for write. Overwrites any prior content. |
| 493 String shared_relro_path(env, relro_path); |
| 494 const char* filepath = shared_relro_path.c_str(); |
| 495 unlink(filepath); |
| 496 int relro_fd = open(filepath, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); |
| 497 if (relro_fd == -1) { |
| 498 LOG_ERROR("open: %s: %s", filepath, strerror(errno)); |
| 499 return false; |
| 500 } |
| 501 |
| 502 // Use android_dlopen_ext() to create the shared RELRO. |
| 503 const int flags = ANDROID_DLEXT_RESERVED_ADDRESS | ANDROID_DLEXT_WRITE_RELRO; |
| 504 AndroidDlextinfo dlextinfo(flags, addr, size, relro_fd); |
| 505 |
| 506 const char* path = dlopen_library_path.c_str(); |
| 507 void* handle = nullptr; |
| 508 if (!AndroidDlopenExt(path, RTLD_NOW, &dlextinfo, &handle)) { |
| 509 LOG_ERROR("No android_dlopen_ext function found"); |
| 510 close(relro_fd); |
| 511 return false; |
| 512 } |
| 513 if (handle == nullptr) { |
| 514 LOG_ERROR("android_dlopen_ext: %s", dlerror()); |
| 515 close(relro_fd); |
| 516 return false; |
| 517 } |
| 518 |
| 519 // Unload the library from this address. The reserved space is |
| 520 // automatically unmapped on exit from this function. |
| 521 dlclose(handle); |
| 522 |
| 523 // Reopen the shared RELFO fd in read-only mode. This ensures that nothing |
| 524 // can write to it through the RELRO fd that we return in libinfo. |
| 525 close(relro_fd); |
| 526 relro_fd = open(filepath, O_RDONLY); |
| 527 if (relro_fd == -1) { |
| 528 LOG_ERROR("open: %s: %s", filepath, strerror(errno)); |
| 529 return false; |
| 530 } |
| 531 |
| 532 // Delete the directory entry for the RELRO file. The fd we hold ensures |
| 533 // that its data remains intact. |
| 534 if (unlink(filepath) == -1) { |
| 535 LOG_ERROR("unlink: %s: %s", filepath, strerror(errno)); |
| 536 return false; |
| 537 } |
| 538 |
| 539 // Note the shared RELRO fd in the supplied libinfo object. In this |
| 540 // implementation the RELRO start is set to the library's load address, |
| 541 // and the RELRO size is unused. |
| 542 const size_t cast_addr = reinterpret_cast<size_t>(addr); |
| 543 s_lib_info_fields.SetRelroInfo(env, lib_info_obj, cast_addr, 0, relro_fd); |
| 544 |
| 545 LOG_INFO("Success creating shared RELRO %s", shared_relro_path.c_str()); |
| 546 return true; |
| 547 } |
| 548 |
| 549 const JNINativeMethod kNativeMethods[] = { |
| 550 {"nativeGetCpuAbi", |
| 551 "(" |
| 552 ")" |
| 553 "Ljava/lang/String;", |
| 554 reinterpret_cast<void*>(&GetCpuAbi)}, |
| 555 {"nativeLoadLibrary", |
| 556 "(" |
| 557 "Ljava/lang/String;" |
| 558 "J" |
| 559 "Lorg/chromium/base/library_loader/Linker$LibInfo;" |
| 560 ")" |
| 561 "Z", |
| 562 reinterpret_cast<void*>(&LoadLibrary)}, |
| 563 {"nativeCreateSharedRelro", |
| 564 "(" |
| 565 "Ljava/lang/String;" |
| 566 "J" |
| 567 "Ljava/lang/String;" |
| 568 "Lorg/chromium/base/library_loader/Linker$LibInfo;" |
| 569 ")" |
| 570 "Z", |
| 571 reinterpret_cast<void*>(&CreateSharedRelro)}, |
| 572 }; |
| 573 |
| 574 } // namespace |
| 575 |
| 576 bool ModernLinkerJNIInit(JavaVM* vm, JNIEnv* env) { |
| 577 LOG_INFO("Entering"); |
| 578 |
| 579 // Register native methods. |
| 580 jclass linker_class; |
| 581 if (!InitClassReference(env, "org/chromium/base/library_loader/ModernLinker", |
| 582 &linker_class)) |
| 583 return false; |
| 584 |
| 585 LOG_INFO("Registering native methods"); |
| 586 env->RegisterNatives(linker_class, kNativeMethods, |
| 587 sizeof(kNativeMethods) / sizeof(kNativeMethods[0])); |
| 588 |
| 589 // Record the Java VM handle. |
| 590 s_java_vm = vm; |
| 591 |
| 592 return true; |
| 593 } |
| 594 |
| 595 } // namespace chromium_android_linker |
OLD | NEW |