1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in 12 * the documentation and/or other materials provided with the 13 * distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 18 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 19 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 22 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 25 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include "linker_cfi.h" 30 31 #include "linker_debug.h" 32 #include "linker_globals.h" 33 #include "private/bionic_page.h" 34 35 #include <sys/mman.h> 36 #include <sys/prctl.h> 37 #include <sys/types.h> 38 #include <cstdint> 39 40 // Update shadow without making it writable by preparing the data on the side and mremap-ing it in 41 // place. 42 class ShadowWrite { 43 char* shadow_start; 44 char* shadow_end; 45 char* aligned_start; 46 char* aligned_end; 47 char* tmp_start; 48 49 public: 50 ShadowWrite(uint16_t* s, uint16_t* e) { 51 shadow_start = reinterpret_cast<char*>(s); 52 shadow_end = reinterpret_cast<char*>(e); 53 aligned_start = reinterpret_cast<char*>(PAGE_START(reinterpret_cast<uintptr_t>(shadow_start))); 54 aligned_end = reinterpret_cast<char*>(PAGE_END(reinterpret_cast<uintptr_t>(shadow_end))); 55 tmp_start = 56 reinterpret_cast<char*>(mmap(nullptr, aligned_end - aligned_start, PROT_READ | PROT_WRITE, 57 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)); 58 CHECK(tmp_start != MAP_FAILED); 59 memcpy(tmp_start, aligned_start, shadow_start - aligned_start); 60 memcpy(tmp_start + (shadow_end - aligned_start), shadow_end, aligned_end - shadow_end); 61 } 62 63 uint16_t* begin() { 64 return reinterpret_cast<uint16_t*>(tmp_start + (shadow_start - aligned_start)); 65 } 66 67 uint16_t* end() { 68 return reinterpret_cast<uint16_t*>(tmp_start + (shadow_end - aligned_start)); 69 } 70 71 ~ShadowWrite() { 72 size_t size = aligned_end - aligned_start; 73 mprotect(tmp_start, size, PROT_READ); 74 void* res = mremap(tmp_start, size, size, MREMAP_MAYMOVE | MREMAP_FIXED, 75 reinterpret_cast<void*>(aligned_start)); 76 CHECK(res != MAP_FAILED); 77 } 78 }; 79 80 void CFIShadowWriter::FixupVmaName() { 81 prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, *shadow_start, kShadowSize, "cfi shadow"); 82 } 83 84 void CFIShadowWriter::AddConstant(uintptr_t begin, uintptr_t end, uint16_t v) { 85 uint16_t* shadow_begin = MemToShadow(begin); 86 uint16_t* shadow_end = MemToShadow(end - 1) + 1; 87 88 ShadowWrite sw(shadow_begin, shadow_end); 89 std::fill(sw.begin(), sw.end(), v); 90 } 91 92 void CFIShadowWriter::AddUnchecked(uintptr_t begin, uintptr_t end) { 93 AddConstant(begin, end, kUncheckedShadow); 94 } 95 96 void CFIShadowWriter::AddInvalid(uintptr_t begin, uintptr_t end) { 97 AddConstant(begin, end, kInvalidShadow); 98 } 99 100 void CFIShadowWriter::Add(uintptr_t begin, uintptr_t end, uintptr_t cfi_check) { 101 CHECK((cfi_check & (kCfiCheckAlign - 1)) == 0); 102 103 // Don't fill anything below cfi_check. We can not represent those addresses 104 // in the shadow, and must make sure at codegen to place all valid call 105 // targets above cfi_check. 106 begin = std::max(begin, cfi_check) & ~(kShadowAlign - 1); 107 uint16_t* shadow_begin = MemToShadow(begin); 108 uint16_t* shadow_end = MemToShadow(end - 1) + 1; 109 110 ShadowWrite sw(shadow_begin, shadow_end); 111 uint16_t sv_begin = ((begin + kShadowAlign - cfi_check) >> kCfiCheckGranularity) + kRegularShadowMin; 112 113 // With each step of the loop below, __cfi_check address computation base is increased by 114 // 2**ShadowGranularity. 115 // To compensate for that, each next shadow value must be increased by 2**ShadowGranularity / 116 // 2**CfiCheckGranularity. 117 uint16_t sv_step = 1 << (kShadowGranularity - kCfiCheckGranularity); 118 uint16_t sv = sv_begin; 119 for (uint16_t& s : sw) { 120 if (sv < sv_begin) { 121 // If shadow value wraps around, also fall back to unchecked. This means the binary is too 122 // large. FIXME: consider using a (slow) resolution function instead. 123 s = kUncheckedShadow; 124 continue; 125 } 126 // If there is something there already, fall back to unchecked. This may happen in rare cases 127 // with MAP_FIXED libraries. FIXME: consider using a (slow) resolution function instead. 128 s = (s == kInvalidShadow) ? sv : kUncheckedShadow; 129 sv += sv_step; 130 } 131 } 132 133 static soinfo* find_libdl(soinfo* solist) { 134 for (soinfo* si = solist; si != nullptr; si = si->next) { 135 const char* soname = si->get_soname(); 136 if (soname && strcmp(soname, "libdl.so") == 0) { 137 return si; 138 } 139 } 140 return nullptr; 141 } 142 143 static uintptr_t soinfo_find_symbol(soinfo* si, const char* s) { 144 SymbolName name(s); 145 const ElfW(Sym) * sym; 146 if (si->find_symbol_by_name(name, nullptr, &sym) && sym) { 147 return si->resolve_symbol_address(sym); 148 } 149 return 0; 150 } 151 152 uintptr_t soinfo_find_cfi_check(soinfo* si) { 153 return soinfo_find_symbol(si, "__cfi_check"); 154 } 155 156 uintptr_t CFIShadowWriter::MapShadow() { 157 void* p = 158 mmap(nullptr, kShadowSize, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0); 159 CHECK(p != MAP_FAILED); 160 return reinterpret_cast<uintptr_t>(p); 161 } 162 163 bool CFIShadowWriter::AddLibrary(soinfo* si) { 164 CHECK(shadow_start != nullptr); 165 if (si->base == 0 || si->size == 0) { 166 return true; 167 } 168 uintptr_t cfi_check = soinfo_find_cfi_check(si); 169 if (cfi_check == 0) { 170 INFO("[ CFI add 0x%zx + 0x%zx %s ]", static_cast<uintptr_t>(si->base), 171 static_cast<uintptr_t>(si->size), si->get_soname()); 172 AddUnchecked(si->base, si->base + si->size); 173 return true; 174 } 175 176 INFO("[ CFI add 0x%zx + 0x%zx %s: 0x%zx ]", static_cast<uintptr_t>(si->base), 177 static_cast<uintptr_t>(si->size), si->get_soname(), cfi_check); 178 #ifdef __arm__ 179 // Require Thumb encoding. 180 if ((cfi_check & 1UL) != 1UL) { 181 DL_ERR("__cfi_check in not a Thumb function in the library \"%s\"", si->get_soname()); 182 return false; 183 } 184 cfi_check &= ~1UL; 185 #endif 186 if ((cfi_check & (kCfiCheckAlign - 1)) != 0) { 187 DL_ERR("unaligned __cfi_check in the library \"%s\"", si->get_soname()); 188 return false; 189 } 190 Add(si->base, si->base + si->size, cfi_check); 191 return true; 192 } 193 194 // Pass the shadow mapping address to libdl.so. In return, we get an pointer to the location 195 // libdl.so uses to store the address. 196 bool CFIShadowWriter::NotifyLibDl(soinfo* solist, uintptr_t p) { 197 soinfo* libdl = find_libdl(solist); 198 if (libdl == nullptr) { 199 DL_ERR("CFI could not find libdl"); 200 return false; 201 } 202 203 uintptr_t cfi_init = soinfo_find_symbol(libdl, "__cfi_init"); 204 CHECK(cfi_init != 0); 205 shadow_start = reinterpret_cast<uintptr_t* (*)(uintptr_t)>(cfi_init)(p); 206 CHECK(shadow_start != nullptr); 207 CHECK(*shadow_start == p); 208 mprotect(shadow_start, PAGE_SIZE, PROT_READ); 209 return true; 210 } 211 212 bool CFIShadowWriter::MaybeInit(soinfo* new_si, soinfo* solist) { 213 CHECK(initial_link_done); 214 CHECK(shadow_start == nullptr); 215 // Check if CFI shadow must be initialized at this time. 216 bool found = false; 217 if (new_si == nullptr) { 218 // This is the case when we've just completed the initial link. There may have been earlier 219 // calls to MaybeInit that were skipped. Look though the entire solist. 220 for (soinfo* si = solist; si != nullptr; si = si->next) { 221 if (soinfo_find_cfi_check(si)) { 222 found = true; 223 break; 224 } 225 } 226 } else { 227 // See if the new library uses CFI. 228 found = soinfo_find_cfi_check(new_si); 229 } 230 231 // Nothing found. 232 if (!found) { 233 return true; 234 } 235 236 // Init shadow and add all currently loaded libraries (not just the new ones). 237 if (!NotifyLibDl(solist, MapShadow())) 238 return false; 239 for (soinfo* si = solist; si != nullptr; si = si->next) { 240 if (!AddLibrary(si)) 241 return false; 242 } 243 FixupVmaName(); 244 return true; 245 } 246 247 bool CFIShadowWriter::AfterLoad(soinfo* si, soinfo* solist) { 248 if (!initial_link_done) { 249 // Too early. 250 return true; 251 } 252 253 if (shadow_start == nullptr) { 254 return MaybeInit(si, solist); 255 } 256 257 // Add the new library to the CFI shadow. 258 if (!AddLibrary(si)) 259 return false; 260 FixupVmaName(); 261 return true; 262 } 263 264 void CFIShadowWriter::BeforeUnload(soinfo* si) { 265 if (shadow_start == nullptr) return; 266 if (si->base == 0 || si->size == 0) return; 267 INFO("[ CFI remove 0x%zx + 0x%zx: %s ]", static_cast<uintptr_t>(si->base), 268 static_cast<uintptr_t>(si->size), si->get_soname()); 269 AddInvalid(si->base, si->base + si->size); 270 FixupVmaName(); 271 } 272 273 bool CFIShadowWriter::InitialLinkDone(soinfo* solist) { 274 CHECK(!initial_link_done); 275 initial_link_done = true; 276 return MaybeInit(nullptr, solist); 277 } 278 279 // Find __cfi_check in the caller and let it handle the problem. Since caller_pc is likely not a 280 // valid CFI target, we can not use CFI shadow for lookup. This does not need to be fast, do the 281 // regular symbol lookup. 282 void CFIShadowWriter::CfiFail(uint64_t CallSiteTypeId, void* Ptr, void* DiagData, void* CallerPc) { 283 soinfo* si = find_containing_library(CallerPc); 284 if (!si) { 285 __builtin_trap(); 286 } 287 288 uintptr_t cfi_check = soinfo_find_cfi_check(si); 289 if (!cfi_check) { 290 __builtin_trap(); 291 } 292 293 reinterpret_cast<CFICheckFn>(cfi_check)(CallSiteTypeId, Ptr, DiagData); 294 } 295