[cfi] Handle large libraries correctly.
Fallback to unchecked if the shadow offset overflows int16_t.
This may happen when a library's data segment is larger than 256MB.
Also updated some comments.
Bug: 22033465
Test: bionic device tests
Change-Id: I8eef42f75099f24aed566499ff1731a0bbf01ff3
diff --git a/linker/linker_cfi.cpp b/linker/linker_cfi.cpp
index f788c16..e9cdab6 100644
--- a/linker/linker_cfi.cpp
+++ b/linker/linker_cfi.cpp
@@ -96,14 +96,21 @@
uint16_t* shadow_end = MemToShadow(end - 1) + 1;
ShadowWrite sw(shadow_begin, shadow_end);
- uint16_t sv = ((begin + kShadowAlign - cfi_check) >> kCfiCheckGranularity) + kRegularShadowMin;
+ uint16_t sv_begin = ((begin + kShadowAlign - cfi_check) >> kCfiCheckGranularity) + kRegularShadowMin;
// With each step of the loop below, __cfi_check address computation base is increased by
// 2**ShadowGranularity.
// To compensate for that, each next shadow value must be increased by 2**ShadowGranularity /
// 2**CfiCheckGranularity.
uint16_t sv_step = 1 << (kShadowGranularity - kCfiCheckGranularity);
+ uint16_t sv = sv_begin;
for (uint16_t& s : sw) {
+ if (sv < sv_begin) {
+ // If shadow value wraps around, also fall back to unchecked. This means the binary is too
+ // large. FIXME: consider using a (slow) resolution function instead.
+ s = kUncheckedShadow;
+ continue;
+ }
// If there is something there already, fall back to unchecked. This may happen in rare cases
// with MAP_FIXED libraries. FIXME: consider using a (slow) resolution function instead.
s = (s == kInvalidShadow) ? sv : kUncheckedShadow;
@@ -191,6 +198,7 @@
bool CFIShadowWriter::MaybeInit(soinfo* new_si, soinfo* solist) {
CHECK(initial_link_done);
+ CHECK(shadow_start == nullptr);
// Check if CFI shadow must be initialized at this time.
bool found = false;
if (new_si == nullptr) {
@@ -250,7 +258,7 @@
}
bool CFIShadowWriter::InitialLinkDone(soinfo* solist) {
- CHECK(!initial_link_done)
+ CHECK(!initial_link_done);
initial_link_done = true;
return MaybeInit(nullptr, solist);
}