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 |