Bug 1455662 - Guard against mprotect() failure when manipulating link map r=jchen

MozReview-Commit-ID: 7orhBmf4j5j
This commit is contained in:
James Willcox 2018-04-11 16:49:11 -05:00
Родитель 9b0a00e563
Коммит 624417af1d
1 изменённых файлов: 47 добавлений и 15 удалений

Просмотреть файл

@ -904,16 +904,28 @@ public:
if (prot == -1 || (start + length) > end) if (prot == -1 || (start + length) > end)
MOZ_CRASH(); MOZ_CRASH();
if (prot & PROT_WRITE) if (prot & PROT_WRITE) {
success = true;
return; return;
}
page = firstPage; 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() ~EnsureWritable()
{ {
if (page != MAP_FAILED) { if (success && page != MAP_FAILED) {
mprotect(page, length, prot); mprotect(page, length, prot);
} }
} }
@ -953,6 +965,7 @@ private:
int prot; int prot;
void *page; void *page;
size_t length; size_t length;
bool success;
}; };
/** /**
@ -976,18 +989,28 @@ ElfLoader::DebuggerHelper::Add(ElfLoader::link_map *map)
{ {
if (!dbg->r_brk) if (!dbg->r_brk)
return; return;
dbg->r_state = r_debug::RT_ADD; dbg->r_state = r_debug::RT_ADD;
dbg->r_brk(); dbg->r_brk();
map->l_prev = nullptr;
map->l_next = dbg->r_map;
if (!firstAdded) { if (!firstAdded) {
firstAdded = map;
/* When adding a library for the first time, r_map points to data /* 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 */ * handled by the system linker, and that data may be read-only */
EnsureWritable w(&dbg->r_map->l_prev); 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; dbg->r_map->l_prev = map;
} else } else
dbg->r_map->l_prev = map; dbg->r_map->l_prev = map;
map->l_prev = nullptr;
map->l_next = dbg->r_map;
dbg->r_map = map; dbg->r_map = map;
dbg->r_state = r_debug::RT_CONSISTENT; dbg->r_state = r_debug::RT_CONSISTENT;
dbg->r_brk(); dbg->r_brk();
@ -998,22 +1021,31 @@ ElfLoader::DebuggerHelper::Remove(ElfLoader::link_map *map)
{ {
if (!dbg->r_brk) if (!dbg->r_brk)
return; return;
dbg->r_state = r_debug::RT_DELETE; dbg->r_state = r_debug::RT_DELETE;
dbg->r_brk(); dbg->r_brk();
if (map == firstAdded) {
/* 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) if (dbg->r_map == map)
dbg->r_map = map->l_next; dbg->r_map = map->l_next;
else if (map->l_prev) { else if (map->l_prev) {
map->l_prev->l_next = map->l_next; 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);
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_state = r_debug::RT_CONSISTENT;
dbg->r_brk(); dbg->r_brk();
} }