Skip to content

Commit

Permalink
Bug 1455662 - Guard against mprotect() failure when manipulating link…
Browse files Browse the repository at this point in the history
… map r=jchen

MozReview-Commit-ID: 7orhBmf4j5j
  • Loading branch information
snorp committed Apr 25, 2018
1 parent e8ec56d commit 5b9c290
Showing 1 changed file with 44 additions and 12 deletions.
56 changes: 44 additions & 12 deletions mozglue/linker/ElfLoader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -904,16 +904,28 @@ class EnsureWritable
if (prot == -1 || (start + length) > end)
MOZ_CRASH();

if (prot & PROT_WRITE)
if (prot & PROT_WRITE) {
success = true;
return;
}

page = firstPage;
mprotect(page, length, prot | PROT_WRITE);
int ret = mprotect(page, length, prot | PROT_WRITE);
success = ret == 0;
if (!success) {
ERROR("mprotect(%p, %zu, %d) = %d (errno=%d; %s)",
page, length, prot | PROT_WRITE, ret,
errno, strerror(errno));
}
}

bool IsWritable() const {
return success;
}

~EnsureWritable()
{
if (page != MAP_FAILED) {
if (success && page != MAP_FAILED) {
mprotect(page, length, prot);
}
}
Expand Down Expand Up @@ -953,6 +965,7 @@ class EnsureWritable
int prot;
void *page;
size_t length;
bool success;
};

/**
Expand All @@ -976,18 +989,28 @@ ElfLoader::DebuggerHelper::Add(ElfLoader::link_map *map)
{
if (!dbg->r_brk)
return;

dbg->r_state = r_debug::RT_ADD;
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()) {
dbg->r_state = r_debug::RT_CONSISTENT;
dbg->r_brk();
return;
}

firstAdded = map;
dbg->r_map->l_prev = map;
} else
dbg->r_map->l_prev = map;

map->l_prev = nullptr;
map->l_next = dbg->r_map;

dbg->r_map = map;
dbg->r_state = r_debug::RT_CONSISTENT;
dbg->r_brk();
Expand All @@ -998,22 +1021,31 @@ ElfLoader::DebuggerHelper::Remove(ElfLoader::link_map *map)
{
if (!dbg->r_brk)
return;

dbg->r_state = r_debug::RT_DELETE;
dbg->r_brk();
if (dbg->r_map == map)
dbg->r_map = map->l_next;
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()) {
dbg->r_state = r_debug::RT_CONSISTENT;
dbg->r_brk();
return;
}

firstAdded = map->l_prev;
map->l_next->l_prev = map->l_prev;
} else if (map->l_next) {
map->l_next->l_prev = map->l_prev;
}

if (dbg->r_map == map)
dbg->r_map = map->l_next;
else if (map->l_prev) {
map->l_prev->l_next = map->l_next;
}
dbg->r_state = r_debug::RT_CONSISTENT;
dbg->r_brk();
}
Expand Down

0 comments on commit 5b9c290

Please sign in to comment.