Make stack sanitization elide pointers to non-executable mappings.

The address space of every Android Java process is approximately 50%
mapped, which means that sanitization tends to be ineffective because
most string fragments are plausibly pointers into some mapping.

For example, the zygote on 32 bit devices has the following mappings
made by dalvik and this covers all 4 byte strings starting with a
character between 0x13 and 0x52 (which includes all uppercase characters
up to and including 'R').

12c00000-12d16000
12d16000-32c00000
32c00000-32c01000
32c01000-52c00000

In order to perform stack unwinding we only need pointers into the stack
of the thread in question, and pointers to executable mappings. If we
reduce the set of considered mappings to those mappings alone, then only
~2% of the address space is left unelided.

BUG=664460

Change-Id: I1cc27821659acfb91d658f42a83a24c176505a88
Reviewed-on: https://chromium-review.googlesource.com/446500
Reviewed-by: Robert Sesek <rsesek@chromium.org>
This commit is contained in:
Tobias Sargeant 2017-02-23 14:22:36 +00:00 committed by Tobias Sargeant
parent 4af8174278
commit 4a7e088a27

View File

@ -752,6 +752,7 @@ void LinuxDumper::SanitizeStackCopy(uint8_t* stack_copy, size_t stack_len,
// bit, modulo the bitfield size, is not set then there does not
// exist a mapping in mappings_ that would contain that pointer.
for (size_t i = 0; i < mappings_.size(); ++i) {
if (!mappings_[i]->exec) continue;
// For each mapping, work out the (unmodulo'ed) range of bits to
// set.
uintptr_t start = mappings_[i]->start_addr;
@ -791,7 +792,8 @@ void LinuxDumper::SanitizeStackCopy(uint8_t* stack_copy, size_t stack_len,
}
uintptr_t test = addr >> shift;
if (could_hit_mapping[(test >> 3) & array_mask] & (1 << (test & 7)) &&
(hit_mapping = FindMappingNoBias(addr)) != nullptr) {
(hit_mapping = FindMappingNoBias(addr)) != nullptr &&
hit_mapping->exec) {
last_hit_mapping = hit_mapping;
continue;
}