• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <dlfcn.h>
18 #include <cctype>
19 #include <cmath>
20 #include <cstring>
21 
22 #include "chre/platform/shared/nanoapp_loader.h"
23 
24 #include "ash.h"
25 #include "ash/profile.h"
26 #include "chre.h"
27 #include "chre/platform/assert.h"
28 #include "chre/platform/fatal_error.h"
29 #include "chre/platform/shared/debug_dump.h"
30 #include "chre/platform/shared/memory.h"
31 #include "chre/target_platform/platform_cache_management.h"
32 #include "chre/util/dynamic_vector.h"
33 #include "chre/util/macros.h"
34 
35 #ifdef CHRE_LOG_ATOM_EXTENSION_ENABLED
36 #include "chrex_log_atom.h"
37 #endif
38 
39 #ifdef CHREX_VOTE_ENABLED
40 #include "chrex_vote.h"
41 #endif
42 
43 #ifndef CHRE_LOADER_ARCH
44 #define CHRE_LOADER_ARCH EM_ARM
45 #endif  // CHRE_LOADER_ARCH
46 
47 namespace chre {
48 namespace {
49 
50 using ElfHeader = ElfW(Ehdr);
51 using ProgramHeader = ElfW(Phdr);
52 
53 struct ExportedData {
54   void *data;
55   const char *dataName;
56 };
57 
58 //! If non-null, a nanoapp is currently being loaded. This allows certain C
59 //! functions to access the nanoapp if called during static init.
60 NanoappLoader *gCurrentlyLoadingNanoapp = nullptr;
61 //! Indicates whether a failure occurred during static initialization.
62 bool gStaticInitFailure = false;
63 
64 // The new operator is used by singleton.h which causes the delete operator to
65 // be undefined in nanoapp binaries even though it's unused. Define this in case
66 // a nanoapp actually tries to use the operator.
deleteOverride(void * ptr)67 void deleteOverride(void *ptr) {
68   FATAL_ERROR("Nanoapp tried to free %p through delete operator", ptr);
69 }
70 
71 // From C++17, a call to the overloaded delete operator aimed at safely freeing
72 // over-aligned allocations maybe present in the nanoapp binary even though it
73 // is unused. Since all memory allocations/deallocations are managed by CHRE,
74 // signal a fatal error if the nanoapp tries to use this version of the delete
75 // operator.
deleteAlignedOverride(void * ptr,std::align_val_t alignment)76 void deleteAlignedOverride(void *ptr, std::align_val_t alignment) {
77   UNUSED_VAR(alignment);
78 
79   FATAL_ERROR("Nanoapp tried to free aligned %p via the delte operator", ptr);
80 }
81 
82 // atexit is used to register functions that must be called when a binary is
83 // removed from the system.
atexitOverride(void (* function)(void))84 int atexitOverride(void (*function)(void)) {
85   LOGV("atexit invoked with %p", function);
86   if (gCurrentlyLoadingNanoapp == nullptr) {
87     CHRE_ASSERT_LOG(false,
88                     "atexit is only supported during static initialization.");
89     return -1;
90   }
91 
92   gCurrentlyLoadingNanoapp->registerAtexitFunction(function);
93   return 0;
94 }
95 
96 // The following functions from the cmath header need to be overridden, since
97 // they're overloaded functions, and we need to specify explicit types of the
98 // template for the compiler.
frexpOverride(double value,int * exp)99 double frexpOverride(double value, int *exp) {
100   return frexp(value, exp);
101 }
102 
fmaxOverride(double x,double y)103 double fmaxOverride(double x, double y) {
104   return fmax(x, y);
105 }
106 
fminOverride(double x,double y)107 double fminOverride(double x, double y) {
108   return fmin(x, y);
109 }
110 
floorOverride(double value)111 double floorOverride(double value) {
112   return floor(value);
113 }
114 
sinOverride(double rad)115 double sinOverride(double rad) {
116   return sin(rad);
117 }
118 
asinOverride(double val)119 double asinOverride(double val) {
120   return asin(val);
121 }
122 
atan2Override(double y,double x)123 double atan2Override(double y, double x) {
124   return atan2(y, x);
125 }
126 
cosOverride(double rad)127 double cosOverride(double rad) {
128   return cos(rad);
129 }
130 
sqrtOverride(float val)131 float sqrtOverride(float val) {
132   return sqrt(val);
133 }
134 
roundOverride(double val)135 double roundOverride(double val) {
136   return round(val);
137 }
138 
139 // This function is required to be exposed to nanoapps to handle errors from
140 // invoking virtual functions.
__cxa_pure_virtual(void)141 void __cxa_pure_virtual(void) {
142   chreAbort(CHRE_ERROR /* abortCode */);
143 }
144 
145 #define ADD_EXPORTED_SYMBOL(function_name, function_string) \
146   { reinterpret_cast<void *>(function_name), function_string }
147 #define ADD_EXPORTED_C_SYMBOL(function_name) \
148   ADD_EXPORTED_SYMBOL(function_name, STRINGIFY(function_name))
149 
150 // TODO(karthikmb/stange): While this array was hand-coded for simple
151 // "hello-world" prototyping, the list of exported symbols must be
152 // generated to minimize runtime errors and build breaks.
153 // TODO(b/226455808): Allow extensions to this list via an external file
154 // clang-format off
155 // Disable deprecation warning so that deprecated symbols in the array
156 // can be exported for older nanoapps and tests.
157 CHRE_DEPRECATED_PREAMBLE
158 const ExportedData gExportedData[] = {
159     /* libmath overrides and symbols */
160     ADD_EXPORTED_SYMBOL(asinOverride, "asin"),
161     ADD_EXPORTED_SYMBOL(atan2Override, "atan2"),
162     ADD_EXPORTED_SYMBOL(cosOverride, "cos"),
163     ADD_EXPORTED_SYMBOL(floorOverride, "floor"),
164     ADD_EXPORTED_SYMBOL(fmaxOverride, "fmax"),
165     ADD_EXPORTED_SYMBOL(fminOverride, "fmin"),
166     ADD_EXPORTED_SYMBOL(frexpOverride, "frexp"),
167     ADD_EXPORTED_SYMBOL(roundOverride, "round"),
168     ADD_EXPORTED_SYMBOL(sinOverride, "sin"),
169     ADD_EXPORTED_SYMBOL(sqrtOverride, "sqrt"),
170     ADD_EXPORTED_C_SYMBOL(acosf),
171     ADD_EXPORTED_C_SYMBOL(asinf),
172     ADD_EXPORTED_C_SYMBOL(atan2f),
173     ADD_EXPORTED_C_SYMBOL(ceilf),
174     ADD_EXPORTED_C_SYMBOL(cosf),
175     ADD_EXPORTED_C_SYMBOL(expf),
176     ADD_EXPORTED_C_SYMBOL(fabsf),
177     ADD_EXPORTED_C_SYMBOL(floorf),
178     ADD_EXPORTED_C_SYMBOL(fmaxf),
179     ADD_EXPORTED_C_SYMBOL(fminf),
180     ADD_EXPORTED_C_SYMBOL(fmodf),
181     ADD_EXPORTED_C_SYMBOL(log10f),
182     ADD_EXPORTED_C_SYMBOL(log1pf),
183     ADD_EXPORTED_C_SYMBOL(log2f),
184     ADD_EXPORTED_C_SYMBOL(logf),
185     ADD_EXPORTED_C_SYMBOL(lrintf),
186     ADD_EXPORTED_C_SYMBOL(lroundf),
187     ADD_EXPORTED_C_SYMBOL(powf),
188     ADD_EXPORTED_C_SYMBOL(remainderf),
189     ADD_EXPORTED_C_SYMBOL(roundf),
190     ADD_EXPORTED_C_SYMBOL(sinf),
191     ADD_EXPORTED_C_SYMBOL(sqrtf),
192     ADD_EXPORTED_C_SYMBOL(tanf),
193     ADD_EXPORTED_C_SYMBOL(tanhf),
194     /* libc overrides and symbols */
195     ADD_EXPORTED_C_SYMBOL(__cxa_pure_virtual),
196     ADD_EXPORTED_SYMBOL(atexitOverride, "atexit"),
197     ADD_EXPORTED_SYMBOL(deleteOverride, "_ZdlPv"),
198     ADD_EXPORTED_SYMBOL(deleteAlignedOverride, "_ZdlPvSt11align_val_t"),
199     ADD_EXPORTED_C_SYMBOL(dlsym),
200     ADD_EXPORTED_C_SYMBOL(isgraph),
201     ADD_EXPORTED_C_SYMBOL(memcmp),
202     ADD_EXPORTED_C_SYMBOL(memcpy),
203     ADD_EXPORTED_C_SYMBOL(memmove),
204     ADD_EXPORTED_C_SYMBOL(memset),
205     ADD_EXPORTED_C_SYMBOL(snprintf),
206     ADD_EXPORTED_C_SYMBOL(strcmp),
207     ADD_EXPORTED_C_SYMBOL(strlen),
208     ADD_EXPORTED_C_SYMBOL(strncmp),
209     ADD_EXPORTED_C_SYMBOL(tolower),
210     /* ash symbols */
211     ADD_EXPORTED_C_SYMBOL(ashProfileInit),
212     ADD_EXPORTED_C_SYMBOL(ashProfileBegin),
213     ADD_EXPORTED_C_SYMBOL(ashProfileEnd),
214     ADD_EXPORTED_C_SYMBOL(ashLoadCalibrationParams),
215     ADD_EXPORTED_C_SYMBOL(ashSaveCalibrationParams),
216     ADD_EXPORTED_C_SYMBOL(ashSetCalibration),
217     ADD_EXPORTED_C_SYMBOL(ashLoadMultiCalibrationParams),
218     ADD_EXPORTED_C_SYMBOL(ashSaveMultiCalibrationParams),
219     ADD_EXPORTED_C_SYMBOL(ashSetMultiCalibration),
220     /* CHRE symbols */
221     ADD_EXPORTED_C_SYMBOL(chreAbort),
222     ADD_EXPORTED_C_SYMBOL(chreAudioConfigureSource),
223     ADD_EXPORTED_C_SYMBOL(chreAudioGetSource),
224     ADD_EXPORTED_C_SYMBOL(chreBleGetCapabilities),
225     ADD_EXPORTED_C_SYMBOL(chreBleGetFilterCapabilities),
226     ADD_EXPORTED_C_SYMBOL(chreBleStartScanAsync),
227     ADD_EXPORTED_C_SYMBOL(chreBleStopScanAsync),
228     ADD_EXPORTED_C_SYMBOL(chreConfigureDebugDumpEvent),
229     ADD_EXPORTED_C_SYMBOL(chreConfigureHostSleepStateEvents),
230     ADD_EXPORTED_C_SYMBOL(chreConfigureNanoappInfoEvents),
231     ADD_EXPORTED_C_SYMBOL(chreDebugDumpLog),
232     ADD_EXPORTED_C_SYMBOL(chreGetApiVersion),
233     ADD_EXPORTED_C_SYMBOL(chreGetAppId),
234     ADD_EXPORTED_C_SYMBOL(chreGetInstanceId),
235     ADD_EXPORTED_C_SYMBOL(chreGetEstimatedHostTimeOffset),
236     ADD_EXPORTED_C_SYMBOL(chreGetNanoappInfoByAppId),
237     ADD_EXPORTED_C_SYMBOL(chreGetNanoappInfoByInstanceId),
238     ADD_EXPORTED_C_SYMBOL(chreGetPlatformId),
239     ADD_EXPORTED_C_SYMBOL(chreGetSensorInfo),
240     ADD_EXPORTED_C_SYMBOL(chreGetSensorSamplingStatus),
241     ADD_EXPORTED_C_SYMBOL(chreGetTime),
242     ADD_EXPORTED_C_SYMBOL(chreGetVersion),
243     ADD_EXPORTED_C_SYMBOL(chreGnssConfigurePassiveLocationListener),
244     ADD_EXPORTED_C_SYMBOL(chreGnssGetCapabilities),
245     ADD_EXPORTED_C_SYMBOL(chreGnssLocationSessionStartAsync),
246     ADD_EXPORTED_C_SYMBOL(chreGnssLocationSessionStopAsync),
247     ADD_EXPORTED_C_SYMBOL(chreGnssMeasurementSessionStartAsync),
248     ADD_EXPORTED_C_SYMBOL(chreGnssMeasurementSessionStopAsync),
249     ADD_EXPORTED_C_SYMBOL(chreHeapAlloc),
250     ADD_EXPORTED_C_SYMBOL(chreHeapFree),
251     ADD_EXPORTED_C_SYMBOL(chreIsHostAwake),
252     ADD_EXPORTED_C_SYMBOL(chreLog),
253     ADD_EXPORTED_C_SYMBOL(chreSendEvent),
254     ADD_EXPORTED_C_SYMBOL(chreSendMessageToHost),
255     ADD_EXPORTED_C_SYMBOL(chreSendMessageToHostEndpoint),
256     ADD_EXPORTED_C_SYMBOL(chreSendMessageWithPermissions),
257     ADD_EXPORTED_C_SYMBOL(chreSensorConfigure),
258     ADD_EXPORTED_C_SYMBOL(chreSensorConfigureBiasEvents),
259     ADD_EXPORTED_C_SYMBOL(chreSensorFind),
260     ADD_EXPORTED_C_SYMBOL(chreSensorFindDefault),
261     ADD_EXPORTED_C_SYMBOL(chreSensorFlushAsync),
262     ADD_EXPORTED_C_SYMBOL(chreSensorGetThreeAxisBias),
263     ADD_EXPORTED_C_SYMBOL(chreTimerCancel),
264     ADD_EXPORTED_C_SYMBOL(chreTimerSet),
265     ADD_EXPORTED_C_SYMBOL(chreUserSettingConfigureEvents),
266     ADD_EXPORTED_C_SYMBOL(chreUserSettingGetState),
267     ADD_EXPORTED_C_SYMBOL(chreWifiConfigureScanMonitorAsync),
268     ADD_EXPORTED_C_SYMBOL(chreWifiGetCapabilities),
269     ADD_EXPORTED_C_SYMBOL(chreWifiRequestScanAsync),
270     ADD_EXPORTED_C_SYMBOL(chreWifiRequestRangingAsync),
271     ADD_EXPORTED_C_SYMBOL(chreWifiNanRequestRangingAsync),
272     ADD_EXPORTED_C_SYMBOL(chreWifiNanSubscribe),
273     ADD_EXPORTED_C_SYMBOL(chreWifiNanSubscribeCancel),
274     ADD_EXPORTED_C_SYMBOL(chreWwanGetCapabilities),
275     ADD_EXPORTED_C_SYMBOL(chreWwanGetCellInfoAsync),
276     ADD_EXPORTED_C_SYMBOL(platform_chreDebugDumpVaLog),
277     ADD_EXPORTED_C_SYMBOL(chreConfigureHostEndpointNotifications),
278     ADD_EXPORTED_C_SYMBOL(chrePublishRpcServices),
279     ADD_EXPORTED_C_SYMBOL(chreGetHostEndpointInfo),
280 #ifdef CHRE_LOG_ATOM_EXTENSION_ENABLED
281     ADD_EXPORTED_C_SYMBOL(chrexLogAtom),
282 #endif
283 #ifdef CHREX_VOTE_ENABLED
284     ADD_EXPORTED_C_SYMBOL(chrexClockRateChangeRequest),
285 #endif
286 };
287 CHRE_DEPRECATED_EPILOGUE
288 // clang-format on
289 
290 }  // namespace
291 
create(void * elfInput,bool mapIntoTcm)292 void *NanoappLoader::create(void *elfInput, bool mapIntoTcm) {
293   void *instance = nullptr;
294   NanoappLoader *loader = memoryAllocDram<NanoappLoader>(elfInput, mapIntoTcm);
295   if (loader != nullptr) {
296     if (loader->open()) {
297       instance = loader;
298     } else {
299       memoryFreeDram(loader);
300     }
301   } else {
302     LOG_OOM();
303   }
304 
305   return instance;
306 }
307 
destroy(NanoappLoader * loader)308 void NanoappLoader::destroy(NanoappLoader *loader) {
309   loader->close();
310   // TODO(b/151847750): Modify utilities to support free'ing from regions other
311   // than SRAM.
312   loader->~NanoappLoader();
313   memoryFreeDram(loader);
314 }
315 
findExportedSymbol(const char * name)316 void *NanoappLoader::findExportedSymbol(const char *name) {
317   size_t nameLen = strlen(name);
318   for (size_t i = 0; i < ARRAY_SIZE(gExportedData); i++) {
319     if (nameLen == strlen(gExportedData[i].dataName) &&
320         strncmp(name, gExportedData[i].dataName, nameLen) == 0) {
321       return gExportedData[i].data;
322     }
323   }
324 
325   LOGE("Unable to find %s", name);
326   return nullptr;
327 }
328 
open()329 bool NanoappLoader::open() {
330   bool success = false;
331   if (mBinary != nullptr) {
332     if (!copyAndVerifyHeaders()) {
333       LOGE("Failed to verify headers");
334     } else if (!createMappings()) {
335       LOGE("Failed to create mappings");
336     } else if (!fixRelocations()) {
337       LOGE("Failed to fix relocations");
338     } else if (!resolveGot()) {
339       LOGE("Failed to resolve GOT");
340     } else {
341       // Wipe caches before calling init array to ensure initializers are not in
342       // the data cache.
343       wipeSystemCaches();
344       if (!callInitArray()) {
345         LOGE("Failed to perform static init");
346       } else {
347         success = true;
348       }
349     }
350   }
351 
352   if (!success) {
353     freeAllocatedData();
354   }
355 
356   return success;
357 }
358 
close()359 void NanoappLoader::close() {
360   callAtexitFunctions();
361   callTerminatorArray();
362   freeAllocatedData();
363 }
364 
findSymbolByName(const char * name)365 void *NanoappLoader::findSymbolByName(const char *name) {
366   void *symbol = nullptr;
367   uint8_t *index = mSymbolTablePtr;
368   while (index < (mSymbolTablePtr + mSymbolTableSize)) {
369     ElfSym *currSym = reinterpret_cast<ElfSym *>(index);
370     const char *symbolName = &mStringTablePtr[currSym->st_name];
371 
372     if (strncmp(symbolName, name, strlen(name)) == 0) {
373       symbol = mMapping + currSym->st_value;
374       break;
375     }
376 
377     index += sizeof(ElfSym);
378   }
379   return symbol;
380 }
381 
registerAtexitFunction(void (* function)(void))382 void NanoappLoader::registerAtexitFunction(void (*function)(void)) {
383   if (!mAtexitFunctions.push_back(function)) {
384     LOG_OOM();
385     gStaticInitFailure = true;
386   }
387 }
388 
mapBss(const ProgramHeader * hdr)389 void NanoappLoader::mapBss(const ProgramHeader *hdr) {
390   // if the memory size of this segment exceeds the file size zero fill the
391   // difference.
392   LOGV("Program Hdr mem sz: %zu file size: %zu", hdr->p_memsz, hdr->p_filesz);
393   if (hdr->p_memsz > hdr->p_filesz) {
394     ElfAddr endOfFile = hdr->p_vaddr + hdr->p_filesz + mLoadBias;
395     ElfAddr endOfMem = hdr->p_vaddr + hdr->p_memsz + mLoadBias;
396     if (endOfMem > endOfFile) {
397       auto deltaMem = endOfMem - endOfFile;
398       LOGV("Zeroing out %zu from page %x", deltaMem, endOfFile);
399       memset(reinterpret_cast<void *>(endOfFile), 0, deltaMem);
400     }
401   }
402 }
403 
callInitArray()404 bool NanoappLoader::callInitArray() {
405   bool success = true;
406   // Sets global variable used by atexit in case it's invoked as part of
407   // initializing static data.
408   gCurrentlyLoadingNanoapp = this;
409 
410   // TODO(b/151847750): ELF can have other sections like .init, .preinit, .fini
411   // etc. Be sure to look for those if they end up being something that should
412   // be supported for nanoapps.
413   for (size_t i = 0; i < mNumSectionHeaders; ++i) {
414     const char *name = getSectionHeaderName(mSectionHeadersPtr[i].sh_name);
415     if (strncmp(name, kInitArrayName, strlen(kInitArrayName)) == 0) {
416       LOGV("Invoking init function");
417       uintptr_t initArray = reinterpret_cast<uintptr_t>(
418           mLoadBias + mSectionHeadersPtr[i].sh_addr);
419       uintptr_t offset = 0;
420       while (offset < mSectionHeadersPtr[i].sh_size) {
421         ElfAddr *funcPtr = reinterpret_cast<ElfAddr *>(initArray + offset);
422         uintptr_t initFunction = reinterpret_cast<uintptr_t>(*funcPtr);
423         ((void (*)())initFunction)();
424         offset += sizeof(initFunction);
425         if (gStaticInitFailure) {
426           success = false;
427           break;
428         }
429       }
430       break;
431     }
432   }
433 
434   //! Reset global state so it doesn't leak into the next load.
435   gCurrentlyLoadingNanoapp = nullptr;
436   gStaticInitFailure = false;
437   return success;
438 }
439 
roundDownToAlign(uintptr_t virtualAddr,size_t alignment)440 uintptr_t NanoappLoader::roundDownToAlign(uintptr_t virtualAddr,
441                                           size_t alignment) {
442   return virtualAddr & -alignment;
443 }
444 
freeAllocatedData()445 void NanoappLoader::freeAllocatedData() {
446   if (mIsTcmBinary) {
447     nanoappBinaryFree(mMapping);
448   } else {
449     nanoappBinaryDramFree(mMapping);
450   }
451   memoryFreeDram(mSectionHeadersPtr);
452   memoryFreeDram(mSectionNamesPtr);
453   memoryFreeDram(mSymbolTablePtr);
454   memoryFreeDram(mStringTablePtr);
455 }
456 
verifyElfHeader()457 bool NanoappLoader::verifyElfHeader() {
458   bool success = false;
459   ElfHeader *elfHeader = getElfHeader();
460   if (elfHeader != nullptr && (elfHeader->e_ident[EI_MAG0] == ELFMAG0) &&
461       (elfHeader->e_ident[EI_MAG1] == ELFMAG1) &&
462       (elfHeader->e_ident[EI_MAG2] == ELFMAG2) &&
463       (elfHeader->e_ident[EI_MAG3] == ELFMAG3) &&
464       (elfHeader->e_ehsize == sizeof(ElfHeader)) &&
465       (elfHeader->e_phentsize == sizeof(ProgramHeader)) &&
466       (elfHeader->e_shentsize == sizeof(SectionHeader)) &&
467       (elfHeader->e_shstrndx < elfHeader->e_shnum) &&
468       (elfHeader->e_version == EV_CURRENT) &&
469       (elfHeader->e_machine == CHRE_LOADER_ARCH) &&
470       (elfHeader->e_type == ET_DYN)) {
471     success = true;
472   }
473   return success;
474 }
475 
verifyProgramHeaders()476 bool NanoappLoader::verifyProgramHeaders() {
477   // This is a minimal check for now -
478   // there should be at least one load segment.
479   bool success = false;
480   for (size_t i = 0; i < getProgramHeaderArraySize(); ++i) {
481     if (getProgramHeaderArray()[i].p_type == PT_LOAD) {
482       success = true;
483       break;
484     }
485   }
486   return success;
487 }
488 
getSectionHeaderName(size_t headerOffset)489 const char *NanoappLoader::getSectionHeaderName(size_t headerOffset) {
490   if (headerOffset == 0) {
491     return "";
492   }
493 
494   return &mSectionNamesPtr[headerOffset];
495 }
496 
getSectionHeader(const char * headerName)497 NanoappLoader::SectionHeader *NanoappLoader::getSectionHeader(
498     const char *headerName) {
499   SectionHeader *rv = nullptr;
500   for (size_t i = 0; i < mNumSectionHeaders; ++i) {
501     const char *name = getSectionHeaderName(mSectionHeadersPtr[i].sh_name);
502     if (strncmp(name, headerName, strlen(headerName)) == 0) {
503       rv = &mSectionHeadersPtr[i];
504       break;
505     }
506   }
507   return rv;
508 }
509 
getElfHeader()510 ElfHeader *NanoappLoader::getElfHeader() {
511   return reinterpret_cast<ElfHeader *>(mBinary);
512 }
513 
getProgramHeaderArray()514 ProgramHeader *NanoappLoader::getProgramHeaderArray() {
515   ElfHeader *elfHeader = getElfHeader();
516   ProgramHeader *programHeader = nullptr;
517   if (elfHeader != nullptr) {
518     programHeader =
519         reinterpret_cast<ProgramHeader *>(mBinary + elfHeader->e_phoff);
520   }
521 
522   return programHeader;
523 }
524 
getProgramHeaderArraySize()525 size_t NanoappLoader::getProgramHeaderArraySize() {
526   ElfHeader *elfHeader = getElfHeader();
527   size_t arraySize = 0;
528   if (elfHeader != nullptr) {
529     arraySize = elfHeader->e_phnum;
530   }
531 
532   return arraySize;
533 }
534 
getDynamicStringTable()535 char *NanoappLoader::getDynamicStringTable() {
536   char *table = nullptr;
537 
538   SectionHeader *dynamicStringTablePtr = getSectionHeader(".dynstr");
539   CHRE_ASSERT(dynamicStringTablePtr != nullptr);
540   if (dynamicStringTablePtr != nullptr && mBinary != nullptr) {
541     table =
542         reinterpret_cast<char *>(mBinary + dynamicStringTablePtr->sh_offset);
543   }
544 
545   return table;
546 }
547 
getDynamicSymbolTable()548 uint8_t *NanoappLoader::getDynamicSymbolTable() {
549   uint8_t *table = nullptr;
550 
551   SectionHeader *dynamicSymbolTablePtr = getSectionHeader(".dynsym");
552   CHRE_ASSERT(dynamicSymbolTablePtr != nullptr);
553   if (dynamicSymbolTablePtr != nullptr && mBinary != nullptr) {
554     table = (mBinary + dynamicSymbolTablePtr->sh_offset);
555   }
556 
557   return table;
558 }
559 
getDynamicSymbolTableSize()560 size_t NanoappLoader::getDynamicSymbolTableSize() {
561   size_t tableSize = 0;
562 
563   SectionHeader *dynamicSymbolTablePtr = getSectionHeader(".dynsym");
564   CHRE_ASSERT(dynamicSymbolTablePtr != nullptr);
565   if (dynamicSymbolTablePtr != nullptr) {
566     tableSize = dynamicSymbolTablePtr->sh_size;
567   }
568 
569   return tableSize;
570 }
571 
verifySectionHeaders()572 bool NanoappLoader::verifySectionHeaders() {
573   bool foundSymbolTableHeader = false;
574   bool foundStringTableHeader = false;
575 
576   for (size_t i = 0; i < mNumSectionHeaders; ++i) {
577     const char *name = getSectionHeaderName(mSectionHeadersPtr[i].sh_name);
578 
579     if (strncmp(name, kSymTableName, strlen(kSymTableName)) == 0) {
580       foundSymbolTableHeader = true;
581     } else if (strncmp(name, kStrTableName, strlen(kStrTableName)) == 0) {
582       foundStringTableHeader = true;
583     }
584   }
585 
586   return foundSymbolTableHeader && foundStringTableHeader;
587 }
588 
copyAndVerifyHeaders()589 bool NanoappLoader::copyAndVerifyHeaders() {
590   size_t offset = 0;
591   bool success = false;
592   uint8_t *pDataBytes = mBinary;
593 
594   // Verify the ELF Header
595   ElfHeader *elfHeader = getElfHeader();
596   success = verifyElfHeader();
597 
598   LOGV("Verified ELF header %d", success);
599 
600   // Verify Program Headers
601   if (success) {
602     success = verifyProgramHeaders();
603   }
604 
605   LOGV("Verified Program headers %d", success);
606 
607   // Load Section Headers
608   if (success) {
609     offset = elfHeader->e_shoff;
610     size_t sectionHeaderSizeBytes = sizeof(SectionHeader) * elfHeader->e_shnum;
611     mSectionHeadersPtr =
612         static_cast<SectionHeader *>(memoryAllocDram(sectionHeaderSizeBytes));
613     if (mSectionHeadersPtr == nullptr) {
614       success = false;
615       LOG_OOM();
616     } else {
617       memcpy(mSectionHeadersPtr, (pDataBytes + offset), sectionHeaderSizeBytes);
618       mNumSectionHeaders = elfHeader->e_shnum;
619     }
620   }
621 
622   LOGV("Loaded section headers %d", success);
623 
624   // Load section header names
625   if (success) {
626     SectionHeader &stringSection = mSectionHeadersPtr[elfHeader->e_shstrndx];
627     size_t sectionSize = stringSection.sh_size;
628     mSectionNamesPtr = static_cast<char *>(memoryAllocDram(sectionSize));
629     if (mSectionNamesPtr == nullptr) {
630       LOG_OOM();
631       success = false;
632     } else {
633       memcpy(mSectionNamesPtr, mBinary + stringSection.sh_offset, sectionSize);
634     }
635   }
636 
637   LOGV("Loaded section header names %d", success);
638 
639   success = verifySectionHeaders();
640   LOGV("Verified Section headers %d", success);
641 
642   // Load symbol table
643   if (success) {
644     SectionHeader *symbolTableHeader = getSectionHeader(kSymTableName);
645     mSymbolTableSize = symbolTableHeader->sh_size;
646     if (mSymbolTableSize == 0) {
647       LOGE("No symbols to resolve");
648       success = false;
649     } else {
650       mSymbolTablePtr =
651           static_cast<uint8_t *>(memoryAllocDram(mSymbolTableSize));
652       if (mSymbolTablePtr == nullptr) {
653         LOG_OOM();
654         success = false;
655       } else {
656         memcpy(mSymbolTablePtr, mBinary + symbolTableHeader->sh_offset,
657                mSymbolTableSize);
658       }
659     }
660   }
661 
662   LOGV("Loaded symbol table %d", success);
663 
664   // Load string table
665   if (success) {
666     SectionHeader *stringTableHeader = getSectionHeader(kStrTableName);
667     size_t stringTableSize = stringTableHeader->sh_size;
668     if (mSymbolTableSize == 0) {
669       LOGE("No string table corresponding to symbols");
670       success = false;
671     } else {
672       mStringTablePtr = static_cast<char *>(memoryAllocDram(stringTableSize));
673       if (mStringTablePtr == nullptr) {
674         LOG_OOM();
675         success = false;
676       } else {
677         memcpy(mStringTablePtr, mBinary + stringTableHeader->sh_offset,
678                stringTableSize);
679       }
680     }
681   }
682 
683   LOGV("Loaded string table %d", success);
684 
685   return success;
686 }
687 
createMappings()688 bool NanoappLoader::createMappings() {
689   // ELF needs pt_load segments to be in contiguous ascending order of
690   // virtual addresses. So the first and last segs can be used to
691   // calculate the entire address span of the image.
692   ElfHeader *elfHeader = getElfHeader();
693   ProgramHeader *programHeaderArray = getProgramHeaderArray();
694   size_t numProgramHeaders = getProgramHeaderArraySize();
695   const ProgramHeader *first = &programHeaderArray[0];
696   const ProgramHeader *last = &programHeaderArray[numProgramHeaders - 1];
697 
698   // Find first load segment
699   while (first->p_type != PT_LOAD && first <= last) {
700     ++first;
701   }
702 
703   bool success = false;
704   if (first->p_type != PT_LOAD) {
705     LOGE("Unable to find any load segments in the binary");
706   } else {
707     // Verify that the first load segment has a program header
708     // first byte of a valid load segment can't be greater than the
709     // program header offset
710     bool valid =
711         (first->p_offset < elfHeader->e_phoff) &&
712         (first->p_filesz >
713          (elfHeader->e_phoff + (numProgramHeaders * sizeof(ProgramHeader))));
714     if (!valid) {
715       LOGE("Load segment program header validation failed");
716     } else {
717       // Get the last load segment
718       while (last > first && last->p_type != PT_LOAD) --last;
719 
720       size_t alignment = first->p_align;
721       size_t memorySpan = last->p_vaddr + last->p_memsz - first->p_vaddr;
722       LOGV("Nanoapp image Memory Span: %u", memorySpan);
723 
724       if (mIsTcmBinary) {
725         mMapping =
726             static_cast<uint8_t *>(nanoappBinaryAlloc(memorySpan, alignment));
727       } else {
728         mMapping = static_cast<uint8_t *>(
729             nanoappBinaryDramAlloc(memorySpan, alignment));
730       }
731 
732       if (mMapping == nullptr) {
733         LOG_OOM();
734       } else {
735         LOGV("Starting location of mappings %p", mMapping);
736 
737         // Calculate the load bias using the first load segment.
738         uintptr_t adjustedFirstLoadSegAddr =
739             roundDownToAlign(first->p_vaddr, alignment);
740         mLoadBias =
741             reinterpret_cast<uintptr_t>(mMapping) - adjustedFirstLoadSegAddr;
742         LOGV("Load bias is %" PRIu32, mLoadBias);
743 
744         success = true;
745       }
746     }
747   }
748 
749   if (success) {
750     // Map the remaining segments
751     for (const ProgramHeader *ph = first; ph <= last; ++ph) {
752       if (ph->p_type == PT_LOAD) {
753         ElfAddr segStart = ph->p_vaddr + mLoadBias;
754         void *startPage = reinterpret_cast<void *>(segStart);
755         void *binaryStartPage = mBinary + ph->p_offset;
756         size_t segmentLen = ph->p_filesz;
757 
758         LOGV("Mapping start page %p from %p with length %zu", startPage,
759              binaryStartPage, segmentLen);
760         memcpy(startPage, binaryStartPage, segmentLen);
761         mapBss(ph);
762       } else {
763         LOGE("Non-load segment found between load segments");
764         success = false;
765         break;
766       }
767     }
768   }
769 
770   return success;
771 }
772 
getDataName(size_t posInSymbolTable)773 const char *NanoappLoader::getDataName(size_t posInSymbolTable) {
774   size_t sectionSize = getDynamicSymbolTableSize();
775   uint8_t *dynamicSymbolTable = getDynamicSymbolTable();
776   size_t numElements = sectionSize / sizeof(ElfSym);
777   CHRE_ASSERT(posInSymbolTable < numElements);
778   char *dataName = nullptr;
779   if (posInSymbolTable < numElements) {
780     ElfSym *sym = reinterpret_cast<ElfSym *>(
781         &dynamicSymbolTable[posInSymbolTable * sizeof(ElfSym)]);
782     dataName = &getDynamicStringTable()[sym->st_name];
783   }
784   return dataName;
785 }
786 
resolveData(size_t posInSymbolTable)787 void *NanoappLoader::resolveData(size_t posInSymbolTable) {
788   const char *dataName = getDataName(posInSymbolTable);
789 
790   if (dataName != nullptr) {
791     LOGV("Resolving %s", dataName);
792     return findExportedSymbol(dataName);
793   }
794 
795   return nullptr;
796 }
797 
getDynamicHeader()798 NanoappLoader::DynamicHeader *NanoappLoader::getDynamicHeader() {
799   DynamicHeader *dyn = nullptr;
800   ProgramHeader *programHeaders = getProgramHeaderArray();
801   for (size_t i = 0; i < getProgramHeaderArraySize(); ++i) {
802     if (programHeaders[i].p_type == PT_DYNAMIC) {
803       dyn = reinterpret_cast<DynamicHeader *>(programHeaders[i].p_offset +
804                                               mBinary);
805       break;
806     }
807   }
808   return dyn;
809 }
810 
getFirstRoSegHeader()811 NanoappLoader::ProgramHeader *NanoappLoader::getFirstRoSegHeader() {
812   // return the first read only segment found
813   ProgramHeader *ro = nullptr;
814   ProgramHeader *programHeaders = getProgramHeaderArray();
815   for (size_t i = 0; i < getProgramHeaderArraySize(); ++i) {
816     if (!(programHeaders[i].p_flags & PF_W)) {
817       ro = &programHeaders[i];
818       break;
819     }
820   }
821   return ro;
822 }
823 
getDynEntry(DynamicHeader * dyn,int field)824 NanoappLoader::ElfWord NanoappLoader::getDynEntry(DynamicHeader *dyn,
825                                                   int field) {
826   ElfWord rv = 0;
827 
828   while (dyn->d_tag != DT_NULL) {
829     if (dyn->d_tag == field) {
830       rv = dyn->d_un.d_val;
831       break;
832     }
833     ++dyn;
834   }
835 
836   return rv;
837 }
838 
fixRelocations()839 bool NanoappLoader::fixRelocations() {
840   ElfAddr *addr;
841   DynamicHeader *dyn = getDynamicHeader();
842   ProgramHeader *roSeg = getFirstRoSegHeader();
843 
844   bool success = false;
845   if ((dyn == nullptr) || (roSeg == nullptr)) {
846     LOGE("Mandatory headers missing from shared object, aborting load");
847   } else if (getDynEntry(dyn, DT_RELA) != 0) {
848     LOGE("Elf binaries with a DT_RELA dynamic entry are unsupported");
849   } else {
850     ElfRel *reloc =
851         reinterpret_cast<ElfRel *>(mBinary + getDynEntry(dyn, DT_REL));
852     size_t relocSize = getDynEntry(dyn, DT_RELSZ);
853     size_t nRelocs = relocSize / sizeof(ElfRel);
854     LOGV("Relocation %zu entries in DT_REL table", nRelocs);
855 
856     bool resolvedAllSymbols = true;
857     size_t i;
858     for (i = 0; i < nRelocs; ++i) {
859       ElfRel *curr = &reloc[i];
860       int relocType = ELFW_R_TYPE(curr->r_info);
861       switch (relocType) {
862         case R_ARM_RELATIVE:
863           LOGV("Resolving ARM_RELATIVE at offset %" PRIx32, curr->r_offset);
864           addr = reinterpret_cast<ElfAddr *>(mMapping + curr->r_offset);
865           // TODO: When we move to DRAM allocations, we need to check if the
866           // above address is in a Read-Only section of memory, and give it
867           // temporary write permission if that is the case.
868           *addr += reinterpret_cast<uintptr_t>(mMapping);
869           break;
870 
871         case R_ARM_ABS32: {
872           LOGV("Resolving ARM_ABS32 at offset %" PRIx32, curr->r_offset);
873           addr = reinterpret_cast<ElfAddr *>(mMapping + curr->r_offset);
874           size_t posInSymbolTable = ELFW_R_SYM(curr->r_info);
875           auto *dynamicSymbolTable =
876               reinterpret_cast<ElfSym *>(getDynamicSymbolTable());
877           ElfSym *sym = &dynamicSymbolTable[posInSymbolTable];
878           *addr = reinterpret_cast<uintptr_t>(mMapping + sym->st_value);
879 
880           break;
881         }
882 
883         case R_ARM_GLOB_DAT: {
884           LOGV("Resolving type ARM_GLOB_DAT at offset %" PRIx32,
885                curr->r_offset);
886           addr = reinterpret_cast<ElfAddr *>(mMapping + curr->r_offset);
887           size_t posInSymbolTable = ELFW_R_SYM(curr->r_info);
888           void *resolved = resolveData(posInSymbolTable);
889           if (resolved == nullptr) {
890             LOGV("Failed to resolve global symbol(%d) at offset 0x%x", i,
891                  curr->r_offset);
892             resolvedAllSymbols = false;
893           }
894           // TODO: When we move to DRAM allocations, we need to check if the
895           // above address is in a Read-Only section of memory, and give it
896           // temporary write permission if that is the case.
897           *addr = reinterpret_cast<ElfAddr>(resolved);
898           break;
899         }
900 
901         case R_ARM_COPY:
902           LOGE("R_ARM_COPY is an invalid relocation for shared libraries");
903           break;
904         default:
905           LOGE("Invalid relocation type %u", relocType);
906           break;
907       }
908     }
909 
910     if (!resolvedAllSymbols) {
911       LOGE("Unable to resolve all symbols in the binary");
912     } else {
913       success = true;
914     }
915   }
916 
917   return success;
918 }
919 
resolveGot()920 bool NanoappLoader::resolveGot() {
921   ElfAddr *addr;
922   ElfRel *reloc = reinterpret_cast<ElfRel *>(
923       mMapping + getDynEntry(getDynamicHeader(), DT_JMPREL));
924   size_t relocSize = getDynEntry(getDynamicHeader(), DT_PLTRELSZ);
925   size_t nRelocs = relocSize / sizeof(ElfRel);
926   LOGV("Resolving GOT with %zu relocations", nRelocs);
927 
928   for (size_t i = 0; i < nRelocs; ++i) {
929     ElfRel *curr = &reloc[i];
930     int relocType = ELFW_R_TYPE(curr->r_info);
931 
932     switch (relocType) {
933       case R_ARM_JUMP_SLOT: {
934         LOGV("Resolving ARM_JUMP_SLOT at offset %" PRIx32, curr->r_offset);
935         addr = reinterpret_cast<ElfAddr *>(mMapping + curr->r_offset);
936         size_t posInSymbolTable = ELFW_R_SYM(curr->r_info);
937         void *resolved = resolveData(posInSymbolTable);
938         if (resolved == nullptr) {
939           LOGV("Failed to resolve symbol(%d) at offset 0x%x", i,
940                curr->r_offset);
941           return false;
942         }
943         *addr = reinterpret_cast<ElfAddr>(resolved);
944         break;
945       }
946 
947       default:
948         LOGE("Unsupported relocation type: %u for symbol %s", relocType,
949              getDataName(ELFW_R_SYM(curr->r_info)));
950         return false;
951     }
952   }
953   return true;
954 }
955 
callAtexitFunctions()956 void NanoappLoader::callAtexitFunctions() {
957   while (!mAtexitFunctions.empty()) {
958     LOGV("Calling atexit at %p", mAtexitFunctions.back());
959     mAtexitFunctions.back()();
960     mAtexitFunctions.pop_back();
961   }
962 }
963 
callTerminatorArray()964 void NanoappLoader::callTerminatorArray() {
965   for (size_t i = 0; i < mNumSectionHeaders; ++i) {
966     const char *name = getSectionHeaderName(mSectionHeadersPtr[i].sh_name);
967     if (strncmp(name, kFiniArrayName, strlen(kFiniArrayName)) == 0) {
968       uintptr_t finiArray = reinterpret_cast<uintptr_t>(
969           mLoadBias + mSectionHeadersPtr[i].sh_addr);
970       uintptr_t offset = 0;
971       while (offset < mSectionHeadersPtr[i].sh_size) {
972         ElfAddr *funcPtr = reinterpret_cast<ElfAddr *>(finiArray + offset);
973         uintptr_t finiFunction = reinterpret_cast<uintptr_t>(*funcPtr);
974         ((void (*)())finiFunction)();
975         offset += sizeof(finiFunction);
976       }
977       break;
978     }
979   }
980 }
981 
982 }  // namespace chre
983