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