Bug 1450793 - Guard against mprotect() failure when manipulating link map r=glandium
MozReview-Commit-ID: 7orhBmf4j5j
--- a/mozglue/linker/ElfLoader.cpp
+++ b/mozglue/linker/ElfLoader.cpp
@@ -898,22 +898,30 @@ public:
prot = getProt(start, &end);
if (prot == -1 || (start + length) > end)
MOZ_CRASH();
if (prot & PROT_WRITE)
return;
page = firstPage;
- mprotect(page, length, prot | PROT_WRITE);
+ success = (mprotect(page, length, prot | PROT_WRITE) == 0);
+ if (!success) {
+ ERROR("Failed to make %p - 0x%x writable: %s\n", ptr,
+ intptr_t(ptr) + length, strerror(errno));
+ }
+ }
+
+ bool IsWritable() {
+ return success;
}
~EnsureWritable()
{
- if (page != MAP_FAILED) {
+ if (success && page != MAP_FAILED) {
mprotect(page, length, prot);
}
}
private:
int getProt(uintptr_t addr, uintptr_t *end)
{
/* The interesting part of the /proc/self/maps format looks like:
@@ -943,16 +951,17 @@ private:
return result;
}
return -1;
}
int prot;
void *page;
size_t length;
+ bool success;
};
/**
* The system linker maintains a doubly linked list of library it loads
* for use by the debugger. Unfortunately, it also uses the list pointers
* in a lot of operations and adding our data in the list is likely to
* trigger crashes when the linker tries to use data we don't provide or
* that fall off the amount data we allocated. Fortunately, the linker only
@@ -975,16 +984,20 @@ ElfLoader::DebuggerHelper::Add(ElfLoader
dbg->r_brk();
map->l_prev = nullptr;
map->l_next = dbg->r_map;
if (!firstAdded) {
firstAdded = map;
/* When adding a library for the first time, r_map points to data
* handled by the system linker, and that data may be read-only */
EnsureWritable w(&dbg->r_map->l_prev);
+ if (!w.IsWritable()) {
+ return;
+ }
+
dbg->r_map->l_prev = map;
} else
dbg->r_map->l_prev = map;
dbg->r_map = map;
dbg->r_state = r_debug::RT_CONSISTENT;
dbg->r_brk();
}
@@ -1000,16 +1013,20 @@ ElfLoader::DebuggerHelper::Remove(ElfLoa
else if (map->l_prev) {
map->l_prev->l_next = map->l_next;
}
if (map == firstAdded) {
firstAdded = map->l_prev;
/* When removing the first added library, its l_next is going to be
* data handled by the system linker, and that data may be read-only */
EnsureWritable w(&map->l_next->l_prev);
+ if (!w.IsWritable()) {
+ return;
+ }
+
map->l_next->l_prev = map->l_prev;
} else if (map->l_next) {
map->l_next->l_prev = map->l_prev;
}
dbg->r_state = r_debug::RT_CONSISTENT;
dbg->r_brk();
}