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

Unified Diff: third_party/android_crazy_linker/src/src/crazy_linker_rdebug.cpp

Issue 937813002: Close a window for a race with the system linker (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Update for more review comments Created 5 years, 10 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 | « third_party/android_crazy_linker/src/src/crazy_linker_rdebug.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: third_party/android_crazy_linker/src/src/crazy_linker_rdebug.cpp
diff --git a/third_party/android_crazy_linker/src/src/crazy_linker_rdebug.cpp b/third_party/android_crazy_linker/src/src/crazy_linker_rdebug.cpp
index 60ff8904f5f03009328d89ad58ec4fc1badd3f32..fd410c46f41182c151bebff73171bc9640261848 100644
--- a/third_party/android_crazy_linker/src/src/crazy_linker_rdebug.cpp
+++ b/third_party/android_crazy_linker/src/src/crazy_linker_rdebug.cpp
@@ -11,6 +11,7 @@
#include <unistd.h>
#include "crazy_linker_debug.h"
+#include "crazy_linker_globals.h"
#include "crazy_linker_proc_maps.h"
#include "crazy_linker_util.h"
#include "crazy_linker_system.h"
@@ -155,11 +156,13 @@ bool FindElfDynamicSection(const char* path,
// Helper class to temporarily remap a page to readable+writable until
// scope exit.
-class ScopedPageMapper {
+class ScopedPageReadWriteRemapper {
public:
- ScopedPageMapper() : page_address_(0), page_prot_(0) {}
- void MapReadWrite(void* address);
- ~ScopedPageMapper();
+ ScopedPageReadWriteRemapper(void* address);
+ ~ScopedPageReadWriteRemapper();
+
+ // Releases the page so that the destructor does not undo the remapping.
+ void Release();
private:
static const uintptr_t kPageSize = 4096;
@@ -167,16 +170,20 @@ class ScopedPageMapper {
int page_prot_;
};
-void ScopedPageMapper::MapReadWrite(void* address) {
+ScopedPageReadWriteRemapper::ScopedPageReadWriteRemapper(void* address) {
page_address_ = reinterpret_cast<uintptr_t>(address) & ~(kPageSize - 1);
page_prot_ = 0;
- if (!FindProtectionFlagsForAddress(address, &page_prot_) ||
- (page_prot_ & (PROT_READ | PROT_WRITE)) == (PROT_READ | PROT_WRITE)) {
- // If the address is invalid, or if the page is already read+write,
- // no need to do anything here.
+ if (!FindProtectionFlagsForAddress(address, &page_prot_)) {
+ LOG("Could not find protection flags for %p\n", address);
page_address_ = 0;
return;
}
+
+ // Note: page_prot_ may already indicate read/write, but because of
+ // possible races with the system linker we cannot be confident that
+ // this is reliable. So we always set read/write here.
+ //
+ // See commentary in WriteLinkMapField for more.
int new_page_prot = page_prot_ | PROT_READ | PROT_WRITE;
int ret = mprotect(
reinterpret_cast<void*>(page_address_), kPageSize, new_page_prot);
@@ -186,7 +193,7 @@ void ScopedPageMapper::MapReadWrite(void* address) {
}
}
-ScopedPageMapper::~ScopedPageMapper() {
+ScopedPageReadWriteRemapper::~ScopedPageReadWriteRemapper() {
if (page_address_) {
int ret =
mprotect(reinterpret_cast<void*>(page_address_), kPageSize, page_prot_);
@@ -195,6 +202,11 @@ ScopedPageMapper::~ScopedPageMapper() {
}
}
+void ScopedPageReadWriteRemapper::Release() {
+ page_address_ = 0;
+ page_prot_ = 0;
+}
+
} // namespace
bool RDebug::Init() {
@@ -382,7 +394,38 @@ bool RDebug::PostCallback(rdebug_callback_handler_t handler,
return true;
}
+// Helper function for AddEntryImpl and DelEntryImpl.
+// Sets *link_pointer to entry. link_pointer is either an 'l_prev' or an
+// 'l_next' field in a neighbouring linkmap_t. If link_pointer is in a
+// page that is mapped readonly, the page is remapped to be writable before
+// assignment.
+void RDebug::WriteLinkMapField(link_map_t** link_pointer, link_map_t* entry) {
+ ScopedPageReadWriteRemapper mapper(link_pointer);
+ LOG("%s: Remapped page for %p for read/write\n", __FUNCTION__, link_pointer);
+
+ *link_pointer = entry;
+
+ // We always mprotect the page containing link_pointer to read/write,
+ // then write the entry. The page may already be read/write, but on
+ // recent Android release is most likely readonly. Because of the way
+ // the system linker operates we cannot tell with certainty what its
+ // correct setting should be.
+ //
+ // Now, we always leave the page read/write. Here is why. If we set it
+ // back to readonly at the point between where the system linker sets
+ // it to read/write and where it writes to the address, this will cause
+ // the system linker to crash. Clearly that is undesirable. From
+ // observations this occurs most frequently on the gpu process.
+ //
+ // TODO(simonb): Revisit this, details in:
+ // https://code.google.com/p/chromium/issues/detail?id=450659
+ // https://code.google.com/p/chromium/issues/detail?id=458346
+ mapper.Release();
+ LOG("%s: Released mapper, leaving page read/write\n", __FUNCTION__);
+}
+
void RDebug::AddEntryImpl(link_map_t* entry) {
+ ScopedGlobalLock lock;
LOG("%s: Adding: %s\n", __FUNCTION__, entry->l_name);
if (!init_)
Init();
@@ -433,19 +476,8 @@ void RDebug::AddEntryImpl(link_map_t* entry) {
// list, ensure that they are writable. This avoids crashing when
// updating the 'l_prev' or 'l_next' fields of a system linker entry,
// which are mapped read-only.
- {
- ScopedPageMapper mapper;
- if (readonly_entries_)
- mapper.MapReadWrite(before);
- before->l_next = entry;
- }
-
- {
- ScopedPageMapper mapper;
- if (readonly_entries_)
- mapper.MapReadWrite(after);
- after->l_prev = entry;
- }
+ WriteLinkMapField(&before->l_next, entry);
+ WriteLinkMapField(&after->l_prev, entry);
// Tell GDB that the list modification has completed.
r_debug_->r_state = RT_CONSISTENT;
@@ -453,6 +485,7 @@ void RDebug::AddEntryImpl(link_map_t* entry) {
}
void RDebug::DelEntryImpl(link_map_t* entry) {
+ ScopedGlobalLock lock;
LOG("%s: Deleting: %s\n", __FUNCTION__, entry->l_name);
if (!r_debug_)
return;
@@ -464,19 +497,10 @@ void RDebug::DelEntryImpl(link_map_t* entry) {
// IMPORTANT: Before modifying the previous and next entries in the
// list, ensure that they are writable. See comment above for more
// details.
- if (entry->l_prev) {
- ScopedPageMapper mapper;
- if (readonly_entries_)
- mapper.MapReadWrite(entry->l_prev);
- entry->l_prev->l_next = entry->l_next;
- }
-
- if (entry->l_next) {
- ScopedPageMapper mapper;
- if (readonly_entries_)
- mapper.MapReadWrite(entry->l_next);
- entry->l_next->l_prev = entry->l_prev;
- }
+ if (entry->l_prev)
+ WriteLinkMapField(&entry->l_prev->l_next, entry->l_next);
+ if (entry->l_next)
+ WriteLinkMapField(&entry->l_next->l_prev, entry->l_prev);
if (r_debug_->r_map == entry)
r_debug_->r_map = entry->l_next;
« no previous file with comments | « third_party/android_crazy_linker/src/src/crazy_linker_rdebug.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698