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