Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 // This is the version of the Android-specific Chromium linker that uses | 5 // This is the version of the Android-specific Chromium linker that uses |
| 6 // the Android M and later system linker to load libraries. | 6 // the Android M and later system linker to load libraries. |
| 7 | 7 |
| 8 // This source code *cannot* depend on anything from base/ or the C++ | 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. | 9 // STL, to keep the final library small, and avoid ugly dependency issues. |
| 10 | 10 |
| (...skipping 272 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 283 return false; | 283 return false; |
| 284 } | 284 } |
| 285 | 285 |
| 286 *load_size = callback_data.load_size; | 286 *load_size = callback_data.load_size; |
| 287 *min_vaddr = callback_data.min_vaddr; | 287 *min_vaddr = callback_data.min_vaddr; |
| 288 return true; | 288 return true; |
| 289 } | 289 } |
| 290 | 290 |
| 291 // Helper for LoadLibrary(). We reserve an address space larger than | 291 // Helper for LoadLibrary(). We reserve an address space larger than |
| 292 // needed. After library loading we want to trim that reservation to only | 292 // needed. After library loading we want to trim that reservation to only |
| 293 // what is needed. | 293 // what is needed. Failure to trim should not occur, but if it does then |
| 294 bool ResizeReservedAddressSpace(void* addr, | 294 // everything will still run, so we treat it as a warning rather than |
| 295 // an error. | |
| 296 void ResizeReservedAddressSpace(void* addr, | |
| 295 size_t reserved_size, | 297 size_t reserved_size, |
| 296 size_t load_size, | 298 size_t load_size, |
| 297 size_t min_vaddr) { | 299 size_t min_vaddr) { |
| 298 LOG_INFO("Called for %p, reserved %d, loaded %d, min_vaddr %d", | 300 LOG_INFO("Called for %p, reserved %d, loaded %d, min_vaddr %d", |
| 299 addr, static_cast<int>(reserved_size), | 301 addr, static_cast<int>(reserved_size), |
| 300 static_cast<int>(load_size), static_cast<int>(min_vaddr)); | 302 static_cast<int>(load_size), static_cast<int>(min_vaddr)); |
| 301 | 303 |
| 302 const uintptr_t uintptr_addr = reinterpret_cast<uintptr_t>(addr); | 304 const uintptr_t uintptr_addr = reinterpret_cast<uintptr_t>(addr); |
| 303 | 305 |
| 304 if (reserved_size < load_size) { | 306 if (reserved_size > load_size) { |
| 307 // Unmap the part of the reserved address space that is beyond the end of | |
| 308 // the loaded library data. | |
| 309 void* unmap = reinterpret_cast<void*>(uintptr_addr + load_size); | |
| 310 const size_t length = reserved_size - load_size; | |
| 311 if (munmap(unmap, length) == -1) { | |
| 312 LOG_ERROR("WARNING: unmap of %d bytes at %p failed: %s", | |
| 313 static_cast<int>(length), unmap, strerror(errno)); | |
| 314 } | |
| 315 } else { | |
| 305 LOG_ERROR("WARNING: library reservation was too small"); | 316 LOG_ERROR("WARNING: library reservation was too small"); |
|
rmcilroy
2016/01/15 15:56:00
LOG_WARN ?
simonb (inactive)
2016/01/15 16:18:18
Doesn't exist, unfortunately. The linker JNI code
| |
| 306 return true; | |
| 307 } | |
| 308 | |
| 309 // Unmap the part of the reserved address space that is beyond the end of | |
| 310 // the loaded library data. | |
| 311 void* unmap = reinterpret_cast<void*>(uintptr_addr + load_size); | |
| 312 size_t length = reserved_size - load_size; | |
| 313 if (munmap(unmap, length) == -1) { | |
| 314 LOG_ERROR("Failed to unmap %d at %p", static_cast<int>(length), unmap); | |
| 315 return false; | |
| 316 } | 317 } |
| 317 | 318 |
| 318 #if RESERVE_BREAKPAD_GUARD_REGION | 319 #if RESERVE_BREAKPAD_GUARD_REGION |
| 319 if (min_vaddr > kBreakpadGuardRegionBytes) { | 320 if (kBreakpadGuardRegionBytes > min_vaddr) { |
| 321 // Unmap the part of the reserved address space that is ahead of where we | |
| 322 // actually need the guard region to start. Resizes the guard region to | |
| 323 // min_vaddr bytes. | |
| 324 void* unmap = | |
| 325 reinterpret_cast<void*>(uintptr_addr - kBreakpadGuardRegionBytes); | |
| 326 const size_t length = kBreakpadGuardRegionBytes - min_vaddr; | |
| 327 if (munmap(unmap, length) == -1) { | |
| 328 LOG_ERROR("WARNING: unmap of %d bytes at %p failed: %s", | |
| 329 static_cast<int>(length), unmap, strerror(errno)); | |
| 330 } | |
| 331 } else { | |
| 320 LOG_ERROR("WARNING: breakpad guard region reservation was too small"); | 332 LOG_ERROR("WARNING: breakpad guard region reservation was too small"); |
| 321 return true; | |
| 322 } | |
| 323 | |
| 324 // Unmap the part of the reserved address space that is ahead of where we | |
| 325 // actually need the guard region to start. Resizes the guard region to | |
| 326 // min_vaddr bytes. | |
| 327 unmap = reinterpret_cast<void*>(uintptr_addr - kBreakpadGuardRegionBytes); | |
| 328 length = kBreakpadGuardRegionBytes - min_vaddr; | |
| 329 if (munmap(unmap, length) == -1) { | |
| 330 LOG_ERROR("Failed to unmap %d at %p", static_cast<int>(length), unmap); | |
| 331 return false; | |
| 332 } | 333 } |
| 333 #endif | 334 #endif |
| 334 | |
| 335 return true; | |
| 336 } | 335 } |
| 337 | 336 |
| 338 // Load a library with the chromium linker, using android_dlopen_ext(). | 337 // Load a library with the chromium linker, using android_dlopen_ext(). |
| 339 // | 338 // |
| 340 // android_dlopen_ext() understands how to directly load from a zipfile, | 339 // android_dlopen_ext() understands how to directly load from a zipfile, |
| 341 // based on the format of |dlopen_ext_path|. If it contains a "!/" separator | 340 // based on the format of |dlopen_ext_path|. If it contains a "!/" separator |
| 342 // then the string indicates <zip_path>!/<file_path> and indicates the | 341 // then the string indicates <zip_path>!/<file_path> and indicates the |
| 343 // file_path element within the zip file at zip_path. A library in a | 342 // file_path element within the zip file at zip_path. A library in a |
| 344 // zipfile must be uncompressed and page aligned. The library is expected | 343 // zipfile must be uncompressed and page aligned. The library is expected |
| 345 // to be lib/<abi_tag>/crazy.<basename>. The <abi_tag> used will be the | 344 // to be lib/<abi_tag>/crazy.<basename>. The <abi_tag> used will be the |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 413 void* handle = nullptr; | 412 void* handle = nullptr; |
| 414 if (!AndroidDlopenExt(path, RTLD_NOW, &dlextinfo, &handle)) { | 413 if (!AndroidDlopenExt(path, RTLD_NOW, &dlextinfo, &handle)) { |
| 415 LOG_ERROR("No android_dlopen_ext function found"); | 414 LOG_ERROR("No android_dlopen_ext function found"); |
| 416 return false; | 415 return false; |
| 417 } | 416 } |
| 418 if (handle == nullptr) { | 417 if (handle == nullptr) { |
| 419 LOG_ERROR("android_dlopen_ext: %s", dlerror()); | 418 LOG_ERROR("android_dlopen_ext: %s", dlerror()); |
| 420 return false; | 419 return false; |
| 421 } | 420 } |
| 422 | 421 |
| 423 // After loading, trim the mapping to match the library's actual size. | 422 // For https://crbug.com/568880. |
| 423 // | |
| 424 // Release the scoped mapping. Now that the library has loaded we can no | |
| 425 // longer assume we have control of all of this area. libdl knows addr and | |
| 426 // has loaded the library into some portion of the reservation. It will | |
| 427 // not expect that portion of memory to be arbitrarily unmapped. | |
| 428 mapping.Release(); | |
| 429 | |
| 430 // After loading we can find the actual size of the library. It should | |
| 431 // be less than the space we reserved for it. | |
| 424 size_t load_size = 0; | 432 size_t load_size = 0; |
| 425 size_t min_vaddr = 0; | 433 size_t min_vaddr = 0; |
| 426 if (!GetLibraryLoadSize(addr, &load_size, &min_vaddr)) { | 434 if (!GetLibraryLoadSize(addr, &load_size, &min_vaddr)) { |
| 427 LOG_ERROR("Unable to find size for load at %p", addr); | 435 LOG_ERROR("Unable to find size for load at %p", addr); |
| 428 return false; | 436 return false; |
| 429 } | 437 } |
| 430 if (!ResizeReservedAddressSpace(addr, size, load_size, min_vaddr)) { | 438 |
| 431 LOG_ERROR("Unable to resize reserved address mapping"); | 439 // Trim the reservation mapping to match the library's actual size. Failure |
| 432 return false; | 440 // to resize is not a fatal error. At worst we lose a portion of virtual |
| 433 } | 441 // address space that we might otherwise have recovered. Note that trimming |
| 442 // the mapping here requires that we have already released the scoped | |
| 443 // mapping. | |
| 444 ResizeReservedAddressSpace(addr, size, load_size, min_vaddr); | |
| 434 | 445 |
| 435 // Locate and if found then call the loaded library's JNI_OnLoad() function. | 446 // Locate and if found then call the loaded library's JNI_OnLoad() function. |
| 436 using JNI_OnLoadFunctionPtr = int (*)(void* vm, void* reserved); | 447 using JNI_OnLoadFunctionPtr = int (*)(void* vm, void* reserved); |
| 437 auto jni_onload = | 448 auto jni_onload = |
| 438 reinterpret_cast<JNI_OnLoadFunctionPtr>(dlsym(handle, "JNI_OnLoad")); | 449 reinterpret_cast<JNI_OnLoadFunctionPtr>(dlsym(handle, "JNI_OnLoad")); |
| 439 if (jni_onload != nullptr) { | 450 if (jni_onload != nullptr) { |
| 440 // Check that JNI_OnLoad returns a usable JNI version. | 451 // Check that JNI_OnLoad returns a usable JNI version. |
| 441 int jni_version = (*jni_onload)(s_java_vm, nullptr); | 452 int jni_version = (*jni_onload)(s_java_vm, nullptr); |
| 442 if (jni_version < JNI_VERSION_1_4) { | 453 if (jni_version < JNI_VERSION_1_4) { |
| 443 LOG_ERROR("JNI version is invalid: %d", jni_version); | 454 LOG_ERROR("JNI version is invalid: %d", jni_version); |
| 444 return false; | 455 return false; |
| 445 } | 456 } |
| 446 } | 457 } |
| 447 | 458 |
| 448 // Release mapping before returning so that we do not unmap reserved space. | |
| 449 mapping.Release(); | |
| 450 | |
| 451 // Note the load address and load size in the supplied libinfo object. | 459 // Note the load address and load size in the supplied libinfo object. |
| 452 const size_t cast_addr = reinterpret_cast<size_t>(addr); | 460 const size_t cast_addr = reinterpret_cast<size_t>(addr); |
| 453 s_lib_info_fields.SetLoadInfo(env, lib_info_obj, cast_addr, load_size); | 461 s_lib_info_fields.SetLoadInfo(env, lib_info_obj, cast_addr, load_size); |
| 454 | 462 |
| 455 LOG_INFO("Success loading library %s", dlopen_library_path.c_str()); | 463 LOG_INFO("Success loading library %s", dlopen_library_path.c_str()); |
| 456 return true; | 464 return true; |
| 457 } | 465 } |
| 458 | 466 |
| 459 // Create a shared RELRO file for a library, using android_dlopen_ext(). | 467 // Create a shared RELRO file for a library, using android_dlopen_ext(). |
| 460 // | 468 // |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 525 LOG_ERROR("No android_dlopen_ext function found"); | 533 LOG_ERROR("No android_dlopen_ext function found"); |
| 526 close(relro_fd); | 534 close(relro_fd); |
| 527 return false; | 535 return false; |
| 528 } | 536 } |
| 529 if (handle == nullptr) { | 537 if (handle == nullptr) { |
| 530 LOG_ERROR("android_dlopen_ext: %s", dlerror()); | 538 LOG_ERROR("android_dlopen_ext: %s", dlerror()); |
| 531 close(relro_fd); | 539 close(relro_fd); |
| 532 return false; | 540 return false; |
| 533 } | 541 } |
| 534 | 542 |
| 535 // Unload the library from this address. The reserved space is | 543 // For https://crbug.com/568880. |
| 536 // automatically unmapped on exit from this function. | 544 // |
| 545 // Release the scoped mapping. See comment in LoadLibrary() above for more. | |
|
rmcilroy
2016/01/15 15:56:00
Isn't this covered by the comment below on dlclose
simonb (inactive)
2016/01/15 16:18:18
Sort of, but also for reasons in LoadLibrary(), wh
| |
| 546 mapping.Release(); | |
| 547 | |
| 548 // For https://crbug.com/568880. | |
| 549 // | |
| 550 // Unload the library from this address. Calling dlclose() will unmap the | |
| 551 // part of the reservation occupied by the libary, but will leave the | |
| 552 // remainder of the reservation mapped, and we have no effective way of | |
| 553 // unmapping the leftover portions because we don't know where dlclose's | |
| 554 // unmap ended. | |
| 555 // | |
| 556 // For now we live with this. It is a loss of some virtual address space | |
| 557 // (but not actual memory), and because it occurs only once and only in | |
| 558 // the browser process, and never in renderer processes, it is not a | |
| 559 // significant issue. | |
|
rmcilroy
2016/01/15 15:56:00
Please add the TODO here as discussed.
simonb (inactive)
2016/01/15 16:18:18
Done.
| |
| 537 dlclose(handle); | 560 dlclose(handle); |
| 538 | 561 |
| 539 // Reopen the shared RELFO fd in read-only mode. This ensures that nothing | 562 // Reopen the shared RELRO fd in read-only mode. This ensures that nothing |
| 540 // can write to it through the RELRO fd that we return in libinfo. | 563 // can write to it through the RELRO fd that we return in libinfo. |
| 541 close(relro_fd); | 564 close(relro_fd); |
| 542 relro_fd = open(filepath, O_RDONLY); | 565 relro_fd = open(filepath, O_RDONLY); |
| 543 if (relro_fd == -1) { | 566 if (relro_fd == -1) { |
| 544 LOG_ERROR("open: %s: %s", filepath, strerror(errno)); | 567 LOG_ERROR("open: %s: %s", filepath, strerror(errno)); |
| 545 return false; | 568 return false; |
| 546 } | 569 } |
| 547 | 570 |
| 548 // Delete the directory entry for the RELRO file. The fd we hold ensures | 571 // Delete the directory entry for the RELRO file. The fd we hold ensures |
| 549 // that its data remains intact. | 572 // that its data remains intact. |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 604 kNativeMethods, | 627 kNativeMethods, |
| 605 sizeof(kNativeMethods) / sizeof(kNativeMethods[0])); | 628 sizeof(kNativeMethods) / sizeof(kNativeMethods[0])); |
| 606 | 629 |
| 607 // Record the Java VM handle. | 630 // Record the Java VM handle. |
| 608 s_java_vm = vm; | 631 s_java_vm = vm; |
| 609 | 632 |
| 610 return true; | 633 return true; |
| 611 } | 634 } |
| 612 | 635 |
| 613 } // namespace chromium_android_linker | 636 } // namespace chromium_android_linker |
| OLD | NEW |