Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(115)

Side by Side Diff: base/android/linker/modern_linker_jni.cc

Issue 1583093007: Never unmap memory reserved for RELRO file creation. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698