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

Unified 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: Update for review feedback. 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: base/android/linker/modern_linker_jni.cc
diff --git a/base/android/linker/modern_linker_jni.cc b/base/android/linker/modern_linker_jni.cc
index 1cd18dbfb3c12700f98aff409be014132f982181..53ae405c2deca5522f491589f6f068a93b51f9fc 100644
--- a/base/android/linker/modern_linker_jni.cc
+++ b/base/android/linker/modern_linker_jni.cc
@@ -290,8 +290,10 @@ bool GetLibraryLoadSize(void* addr, size_t* load_size, size_t* min_vaddr) {
// Helper for LoadLibrary(). We reserve an address space larger than
// needed. After library loading we want to trim that reservation to only
-// what is needed.
-bool ResizeReservedAddressSpace(void* addr,
+// what is needed. Failure to trim should not occur, but if it does then
+// everything will still run, so we treat it as a warning rather than
+// an error.
+void ResizeReservedAddressSpace(void* addr,
size_t reserved_size,
size_t load_size,
size_t min_vaddr) {
@@ -301,38 +303,35 @@ bool ResizeReservedAddressSpace(void* addr,
const uintptr_t uintptr_addr = reinterpret_cast<uintptr_t>(addr);
- if (reserved_size < load_size) {
+ if (reserved_size > load_size) {
+ // Unmap the part of the reserved address space that is beyond the end of
+ // the loaded library data.
+ void* unmap = reinterpret_cast<void*>(uintptr_addr + load_size);
+ const size_t length = reserved_size - load_size;
+ if (munmap(unmap, length) == -1) {
dimitry 2016/01/15 22:18:10 what is going to happen here once bionic linker st
+ LOG_ERROR("WARNING: unmap of %d bytes at %p failed: %s",
+ static_cast<int>(length), unmap, strerror(errno));
+ }
+ } else {
LOG_ERROR("WARNING: library reservation was too small");
- return true;
- }
-
- // Unmap the part of the reserved address space that is beyond the end of
- // the loaded library data.
- void* unmap = reinterpret_cast<void*>(uintptr_addr + load_size);
- size_t length = reserved_size - load_size;
- if (munmap(unmap, length) == -1) {
- LOG_ERROR("Failed to unmap %d at %p", static_cast<int>(length), unmap);
- return false;
}
#if RESERVE_BREAKPAD_GUARD_REGION
- if (min_vaddr > kBreakpadGuardRegionBytes) {
+ if (kBreakpadGuardRegionBytes > min_vaddr) {
+ // Unmap the part of the reserved address space that is ahead of where we
+ // actually need the guard region to start. Resizes the guard region to
+ // min_vaddr bytes.
+ void* unmap =
+ reinterpret_cast<void*>(uintptr_addr - kBreakpadGuardRegionBytes);
+ const size_t length = kBreakpadGuardRegionBytes - min_vaddr;
+ if (munmap(unmap, length) == -1) {
+ LOG_ERROR("WARNING: unmap of %d bytes at %p failed: %s",
+ static_cast<int>(length), unmap, strerror(errno));
+ }
+ } else {
LOG_ERROR("WARNING: breakpad guard region reservation was too small");
- return true;
- }
-
- // Unmap the part of the reserved address space that is ahead of where we
- // actually need the guard region to start. Resizes the guard region to
- // min_vaddr bytes.
- unmap = reinterpret_cast<void*>(uintptr_addr - kBreakpadGuardRegionBytes);
- length = kBreakpadGuardRegionBytes - min_vaddr;
- if (munmap(unmap, length) == -1) {
- LOG_ERROR("Failed to unmap %d at %p", static_cast<int>(length), unmap);
- return false;
}
#endif
-
- return true;
}
// Load a library with the chromium linker, using android_dlopen_ext().
@@ -420,17 +419,29 @@ jboolean LoadLibrary(JNIEnv* env,
return false;
}
- // After loading, trim the mapping to match the library's actual size.
+ // For https://crbug.com/568880.
+ //
+ // Release the scoped mapping. Now that the library has loaded we can no
+ // longer assume we have control of all of this area. libdl knows addr and
+ // has loaded the library into some portion of the reservation. It will
+ // not expect that portion of memory to be arbitrarily unmapped.
+ mapping.Release();
+
+ // After loading we can find the actual size of the library. It should
+ // be less than the space we reserved for it.
size_t load_size = 0;
size_t min_vaddr = 0;
if (!GetLibraryLoadSize(addr, &load_size, &min_vaddr)) {
LOG_ERROR("Unable to find size for load at %p", addr);
return false;
}
- if (!ResizeReservedAddressSpace(addr, size, load_size, min_vaddr)) {
- LOG_ERROR("Unable to resize reserved address mapping");
- return false;
- }
+
+ // Trim the reservation mapping to match the library's actual size. Failure
+ // to resize is not a fatal error. At worst we lose a portion of virtual
+ // address space that we might otherwise have recovered. Note that trimming
+ // the mapping here requires that we have already released the scoped
+ // mapping.
+ ResizeReservedAddressSpace(addr, size, load_size, min_vaddr);
// Locate and if found then call the loaded library's JNI_OnLoad() function.
using JNI_OnLoadFunctionPtr = int (*)(void* vm, void* reserved);
@@ -445,9 +456,6 @@ jboolean LoadLibrary(JNIEnv* env,
}
}
- // Release mapping before returning so that we do not unmap reserved space.
- mapping.Release();
-
// Note the load address and load size in the supplied libinfo object.
const size_t cast_addr = reinterpret_cast<size_t>(addr);
s_lib_info_fields.SetLoadInfo(env, lib_info_obj, cast_addr, load_size);
@@ -532,11 +540,31 @@ jboolean CreateSharedRelro(JNIEnv* env,
return false;
}
- // Unload the library from this address. The reserved space is
- // automatically unmapped on exit from this function.
+ // For https://crbug.com/568880.
+ //
+ // Release the scoped mapping. See comment in LoadLibrary() above for more.
+ mapping.Release();
+
+ // For https://crbug.com/568880.
+ //
+ // Unload the library from this address. Calling dlclose() will unmap the
+ // part of the reservation occupied by the libary, but will leave the
+ // remainder of the reservation mapped, and we have no effective way of
+ // unmapping the leftover portions because we don't know where dlclose's
+ // unmap ended.
+ //
+ // For now we live with this. It is a loss of some virtual address space
+ // (but not actual memory), and because it occurs only once and only in
+ // the browser process, and never in renderer processes, it is not a
+ // significant issue.
+ //
+ // TODO(simonb): Between mapping.Release() and here, consider calling the
+ // functions that trim the reservation down to the size of the loaded
+ // library. This may help recover some or all of the virtual address space
+ // that is otherwise lost.
dlclose(handle);
- // Reopen the shared RELFO fd in read-only mode. This ensures that nothing
+ // Reopen the shared RELRO fd in read-only mode. This ensures that nothing
// can write to it through the RELRO fd that we return in libinfo.
close(relro_fd);
relro_fd = open(filepath, O_RDONLY);
« 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