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 "platform/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:
ShadowWrite(uint16_t * s,uint16_t * e)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     mprotect(aligned_start, aligned_end - aligned_start, PROT_READ);
60     memcpy(tmp_start, aligned_start, shadow_start - aligned_start);
61     memcpy(tmp_start + (shadow_end - aligned_start), shadow_end, aligned_end - shadow_end);
62   }
63 
begin()64   uint16_t* begin() {
65     return reinterpret_cast<uint16_t*>(tmp_start + (shadow_start - aligned_start));
66   }
67 
end()68   uint16_t* end() {
69     return reinterpret_cast<uint16_t*>(tmp_start + (shadow_end - aligned_start));
70   }
71 
~ShadowWrite()72   ~ShadowWrite() {
73     size_t size = aligned_end - aligned_start;
74     mprotect(tmp_start, size, PROT_READ);
75     void* res = mremap(tmp_start, size, size, MREMAP_MAYMOVE | MREMAP_FIXED,
76                        reinterpret_cast<void*>(aligned_start));
77     CHECK(res != MAP_FAILED);
78   }
79 };
80 
FixupVmaName()81 void CFIShadowWriter::FixupVmaName() {
82   prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, *shadow_start, kShadowSize, "cfi shadow");
83 }
84 
AddConstant(uintptr_t begin,uintptr_t end,uint16_t v)85 void CFIShadowWriter::AddConstant(uintptr_t begin, uintptr_t end, uint16_t v) {
86   uint16_t* shadow_begin = MemToShadow(begin);
87   uint16_t* shadow_end = MemToShadow(end - 1) + 1;
88 
89   ShadowWrite sw(shadow_begin, shadow_end);
90   std::fill(sw.begin(), sw.end(), v);
91 }
92 
AddUnchecked(uintptr_t begin,uintptr_t end)93 void CFIShadowWriter::AddUnchecked(uintptr_t begin, uintptr_t end) {
94   AddConstant(begin, end, kUncheckedShadow);
95 }
96 
AddInvalid(uintptr_t begin,uintptr_t end)97 void CFIShadowWriter::AddInvalid(uintptr_t begin, uintptr_t end) {
98   AddConstant(begin, end, kInvalidShadow);
99 }
100 
Add(uintptr_t begin,uintptr_t end,uintptr_t cfi_check)101 void CFIShadowWriter::Add(uintptr_t begin, uintptr_t end, uintptr_t cfi_check) {
102   CHECK((cfi_check & (kCfiCheckAlign - 1)) == 0);
103 
104   // Don't fill anything below cfi_check. We can not represent those addresses
105   // in the shadow, and must make sure at codegen to place all valid call
106   // targets above cfi_check.
107   begin = std::max(begin, cfi_check) & ~(kShadowAlign - 1);
108   uint16_t* shadow_begin = MemToShadow(begin);
109   uint16_t* shadow_end = MemToShadow(end - 1) + 1;
110 
111   ShadowWrite sw(shadow_begin, shadow_end);
112   uint16_t sv_begin = ((begin + kShadowAlign - cfi_check) >> kCfiCheckGranularity) + kRegularShadowMin;
113 
114   // With each step of the loop below, __cfi_check address computation base is increased by
115   // 2**ShadowGranularity.
116   // To compensate for that, each next shadow value must be increased by 2**ShadowGranularity /
117   // 2**CfiCheckGranularity.
118   uint16_t sv_step = 1 << (kShadowGranularity - kCfiCheckGranularity);
119   uint16_t sv = sv_begin;
120   for (uint16_t& s : sw) {
121     if (sv < sv_begin) {
122       // If shadow value wraps around, also fall back to unchecked. This means the binary is too
123       // large. FIXME: consider using a (slow) resolution function instead.
124       s = kUncheckedShadow;
125       continue;
126     }
127     // If there is something there already, fall back to unchecked. This may happen in rare cases
128     // with MAP_FIXED libraries. FIXME: consider using a (slow) resolution function instead.
129     s = (s == kInvalidShadow) ? sv : kUncheckedShadow;
130     sv += sv_step;
131   }
132 }
133 
find_libdl(soinfo * solist)134 static soinfo* find_libdl(soinfo* solist) {
135   for (soinfo* si = solist; si != nullptr; si = si->next) {
136     if (strcmp(si->get_soname(), "libdl.so") == 0) {
137       return si;
138     }
139   }
140   return nullptr;
141 }
142 
soinfo_find_symbol(soinfo * si,const char * s)143 static uintptr_t soinfo_find_symbol(soinfo* si, const char* s) {
144   SymbolName name(s);
145   if (const ElfW(Sym)* sym = si->find_symbol_by_name(name, nullptr)) {
146     return si->resolve_symbol_address(sym);
147   }
148   return 0;
149 }
150 
soinfo_find_cfi_check(soinfo * si)151 uintptr_t soinfo_find_cfi_check(soinfo* si) {
152   return soinfo_find_symbol(si, "__cfi_check");
153 }
154 
MapShadow()155 uintptr_t CFIShadowWriter::MapShadow() {
156   void* p =
157       mmap(nullptr, kShadowSize, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0);
158   CHECK(p != MAP_FAILED);
159   return reinterpret_cast<uintptr_t>(p);
160 }
161 
AddLibrary(soinfo * si)162 bool CFIShadowWriter::AddLibrary(soinfo* si) {
163   CHECK(shadow_start != nullptr);
164   if (si->base == 0 || si->size == 0) {
165     return true;
166   }
167   uintptr_t cfi_check = soinfo_find_cfi_check(si);
168   if (cfi_check == 0) {
169     INFO("[ CFI add 0x%zx + 0x%zx %s ]", static_cast<uintptr_t>(si->base),
170          static_cast<uintptr_t>(si->size), si->get_soname());
171     AddUnchecked(si->base, si->base + si->size);
172     return true;
173   }
174 
175   INFO("[ CFI add 0x%zx + 0x%zx %s: 0x%zx ]", static_cast<uintptr_t>(si->base),
176        static_cast<uintptr_t>(si->size), si->get_soname(), cfi_check);
177 #ifdef __arm__
178   // Require Thumb encoding.
179   if ((cfi_check & 1UL) != 1UL) {
180     DL_ERR("__cfi_check in not a Thumb function in the library \"%s\"", si->get_soname());
181     return false;
182   }
183   cfi_check &= ~1UL;
184 #endif
185   if ((cfi_check & (kCfiCheckAlign - 1)) != 0) {
186     DL_ERR("unaligned __cfi_check in the library \"%s\"", si->get_soname());
187     return false;
188   }
189   Add(si->base, si->base + si->size, cfi_check);
190   return true;
191 }
192 
193 // Pass the shadow mapping address to libdl.so. In return, we get an pointer to the location
194 // libdl.so uses to store the address.
NotifyLibDl(soinfo * solist,uintptr_t p)195 bool CFIShadowWriter::NotifyLibDl(soinfo* solist, uintptr_t p) {
196   soinfo* libdl = find_libdl(solist);
197   if (libdl == nullptr) {
198     DL_ERR("CFI could not find libdl");
199     return false;
200   }
201 
202   uintptr_t cfi_init = soinfo_find_symbol(libdl, "__cfi_init");
203   CHECK(cfi_init != 0);
204   shadow_start = reinterpret_cast<uintptr_t* (*)(uintptr_t)>(cfi_init)(p);
205   CHECK(shadow_start != nullptr);
206   CHECK(*shadow_start == p);
207   mprotect(shadow_start, PAGE_SIZE, PROT_READ);
208   return true;
209 }
210 
MaybeInit(soinfo * new_si,soinfo * solist)211 bool CFIShadowWriter::MaybeInit(soinfo* new_si, soinfo* solist) {
212   CHECK(initial_link_done);
213   CHECK(shadow_start == nullptr);
214   // Check if CFI shadow must be initialized at this time.
215   bool found = false;
216   if (new_si == nullptr) {
217     // This is the case when we've just completed the initial link. There may have been earlier
218     // calls to MaybeInit that were skipped. Look though the entire solist.
219     for (soinfo* si = solist; si != nullptr; si = si->next) {
220       if (soinfo_find_cfi_check(si)) {
221         found = true;
222         break;
223       }
224     }
225   } else {
226     // See if the new library uses CFI.
227     found = soinfo_find_cfi_check(new_si);
228   }
229 
230   // Nothing found.
231   if (!found) {
232     return true;
233   }
234 
235   // Init shadow and add all currently loaded libraries (not just the new ones).
236   if (!NotifyLibDl(solist, MapShadow()))
237     return false;
238   for (soinfo* si = solist; si != nullptr; si = si->next) {
239     if (!AddLibrary(si))
240       return false;
241   }
242   FixupVmaName();
243   return true;
244 }
245 
AfterLoad(soinfo * si,soinfo * solist)246 bool CFIShadowWriter::AfterLoad(soinfo* si, soinfo* solist) {
247   if (!initial_link_done) {
248     // Too early.
249     return true;
250   }
251 
252   if (shadow_start == nullptr) {
253     return MaybeInit(si, solist);
254   }
255 
256   // Add the new library to the CFI shadow.
257   if (!AddLibrary(si))
258     return false;
259   FixupVmaName();
260   return true;
261 }
262 
BeforeUnload(soinfo * si)263 void CFIShadowWriter::BeforeUnload(soinfo* si) {
264   if (shadow_start == nullptr) return;
265   if (si->base == 0 || si->size == 0) return;
266   INFO("[ CFI remove 0x%zx + 0x%zx: %s ]", static_cast<uintptr_t>(si->base),
267        static_cast<uintptr_t>(si->size), si->get_soname());
268   AddInvalid(si->base, si->base + si->size);
269   FixupVmaName();
270 }
271 
InitialLinkDone(soinfo * solist)272 bool CFIShadowWriter::InitialLinkDone(soinfo* solist) {
273   CHECK(!initial_link_done);
274   initial_link_done = true;
275   return MaybeInit(nullptr, solist);
276 }
277 
278 // Find __cfi_check in the caller and let it handle the problem. Since caller_pc is likely not a
279 // valid CFI target, we can not use CFI shadow for lookup. This does not need to be fast, do the
280 // regular symbol lookup.
CfiFail(uint64_t CallSiteTypeId,void * Ptr,void * DiagData,void * CallerPc)281 void CFIShadowWriter::CfiFail(uint64_t CallSiteTypeId, void* Ptr, void* DiagData, void* CallerPc) {
282   soinfo* si = find_containing_library(CallerPc);
283   if (!si) {
284     __builtin_trap();
285   }
286 
287   uintptr_t cfi_check = soinfo_find_cfi_check(si);
288   if (!cfi_check) {
289     __builtin_trap();
290   }
291 
292   reinterpret_cast<CFICheckFn>(cfi_check)(CallSiteTypeId, Ptr, DiagData);
293 }
294