• 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 "chre.h"
25 #include "chre/platform/assert.h"
26 #include "chre/platform/fatal_error.h"
27 #include "chre/platform/shared/debug_dump.h"
28 #include "chre/platform/shared/memory.h"
29 #include "chre/platform/shared/nanoapp/tokenized_log.h"
30 #include "chre/platform/shared/platform_cache_management.h"
31 #include "chre/util/dynamic_vector.h"
32 #include "chre/util/macros.h"
33 
34 #ifdef CHREX_SYMBOL_EXTENSIONS
35 #include "chre/extensions/platform/symbol_list.h"
36 #endif
37 
38 #ifndef CHRE_LOADER_ARCH
39 #define CHRE_LOADER_ARCH EM_ARM
40 #endif  // CHRE_LOADER_ARCH
41 
42 namespace chre {
43 namespace {
44 
45 using ElfHeader = ElfW(Ehdr);
46 using ProgramHeader = ElfW(Phdr);
47 
48 struct ExportedData {
49   void *data;
50   const char *dataName;
51 };
52 
53 //! If non-null, a nanoapp is currently being loaded. This allows certain C
54 //! functions to access the nanoapp if called during static init.
55 NanoappLoader *gCurrentlyLoadingNanoapp = nullptr;
56 //! Indicates whether a failure occurred during static initialization.
57 bool gStaticInitFailure = false;
58 
deleteOpOverride(void *,unsigned int size)59 void deleteOpOverride(void * /* ptr */, unsigned int size) {
60   FATAL_ERROR("Nanoapp: delete(void *, unsigned int) override : sz = %u", size);
61 }
62 
63 #ifdef __clang__
deleteOp2Override(void *)64 void deleteOp2Override(void *) {
65   FATAL_ERROR("Nanoapp: delete(void *)");
66 }
67 #endif
68 
atexitInternal(struct AtExitCallback & cb)69 int atexitInternal(struct AtExitCallback &cb) {
70   if (gCurrentlyLoadingNanoapp == nullptr) {
71     CHRE_ASSERT_LOG(false,
72                     "atexit is only supported during static initialization.");
73     return -1;
74   }
75 
76   gCurrentlyLoadingNanoapp->registerAtexitFunction(cb);
77   return 0;
78 }
79 
80 // atexit is used to register functions that must be called when a binary is
81 // removed from the system. The call back function has an arg (void *)
cxaAtexitOverride(void (* func)(void *),void * arg,void * dso)82 int cxaAtexitOverride(void (*func)(void *), void *arg, void *dso) {
83   LOGV("__cxa_atexit invoked with %p, %p, %p", func, arg, dso);
84   struct AtExitCallback cb(func, arg);
85   atexitInternal(cb);
86   return 0;
87 }
88 
89 // The call back function has no arg.
atexitOverride(void (* func)(void))90 int atexitOverride(void (*func)(void)) {
91   LOGV("atexit invoked with %p", func);
92   struct AtExitCallback cb(func);
93   atexitInternal(cb);
94   return 0;
95 }
96 
97 // The following functions from the cmath header need to be overridden, since
98 // they're overloaded functions, and we need to specify explicit types of the
99 // template for the compiler.
frexpOverride(double value,int * exp)100 double frexpOverride(double value, int *exp) {
101   return frexp(value, exp);
102 }
103 
fmaxOverride(double x,double y)104 double fmaxOverride(double x, double y) {
105   return fmax(x, y);
106 }
107 
fminOverride(double x,double y)108 double fminOverride(double x, double y) {
109   return fmin(x, y);
110 }
111 
floorOverride(double value)112 double floorOverride(double value) {
113   return floor(value);
114 }
115 
ceilOverride(double value)116 double ceilOverride(double value) {
117   return ceil(value);
118 }
119 
sinOverride(double rad)120 double sinOverride(double rad) {
121   return sin(rad);
122 }
123 
asinOverride(double val)124 double asinOverride(double val) {
125   return asin(val);
126 }
127 
atan2Override(double y,double x)128 double atan2Override(double y, double x) {
129   return atan2(y, x);
130 }
131 
cosOverride(double rad)132 double cosOverride(double rad) {
133   return cos(rad);
134 }
135 
sqrtOverride(double val)136 double sqrtOverride(double val) {
137   return sqrt(val);
138 }
139 
roundOverride(double val)140 double roundOverride(double val) {
141   return round(val);
142 }
143 
144 // This function is required to be exposed to nanoapps to handle errors from
145 // invoking virtual functions.
__cxa_pure_virtual(void)146 void __cxa_pure_virtual(void) {
147   chreAbort(CHRE_ERROR /* abortCode */);
148 }
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 // clang-format off
154 // Disable deprecation warning so that deprecated symbols in the array
155 // can be exported for older nanoapps and tests.
156 CHRE_DEPRECATED_PREAMBLE
157 const ExportedData kExportedData[] = {
158     /* libmath overrides and symbols */
159     ADD_EXPORTED_SYMBOL(asinOverride, "asin"),
160     ADD_EXPORTED_SYMBOL(atan2Override, "atan2"),
161     ADD_EXPORTED_SYMBOL(cosOverride, "cos"),
162     ADD_EXPORTED_SYMBOL(floorOverride, "floor"),
163     ADD_EXPORTED_SYMBOL(ceilOverride, "ceil"),
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(ldexpf),
182     ADD_EXPORTED_C_SYMBOL(log10f),
183     ADD_EXPORTED_C_SYMBOL(log1pf),
184     ADD_EXPORTED_C_SYMBOL(log2f),
185     ADD_EXPORTED_C_SYMBOL(logf),
186     ADD_EXPORTED_C_SYMBOL(lrintf),
187     ADD_EXPORTED_C_SYMBOL(lroundf),
188     ADD_EXPORTED_C_SYMBOL(powf),
189     ADD_EXPORTED_C_SYMBOL(remainderf),
190     ADD_EXPORTED_C_SYMBOL(roundf),
191     ADD_EXPORTED_C_SYMBOL(sinf),
192     ADD_EXPORTED_C_SYMBOL(sqrtf),
193     ADD_EXPORTED_C_SYMBOL(tanf),
194     ADD_EXPORTED_C_SYMBOL(tanhf),
195     /* libc overrides and symbols */
196     ADD_EXPORTED_C_SYMBOL(__cxa_pure_virtual),
197     ADD_EXPORTED_SYMBOL(cxaAtexitOverride, "__cxa_atexit"),
198     ADD_EXPORTED_SYMBOL(atexitOverride, "atexit"),
199     ADD_EXPORTED_SYMBOL(deleteOpOverride, "_ZdlPvj"),
200 #ifdef __clang__
201     ADD_EXPORTED_SYMBOL(deleteOp2Override, "_ZdlPv"),
202 #endif
203     ADD_EXPORTED_C_SYMBOL(dlsym),
204     ADD_EXPORTED_C_SYMBOL(isgraph),
205     ADD_EXPORTED_C_SYMBOL(memcmp),
206     ADD_EXPORTED_C_SYMBOL(memcpy),
207     ADD_EXPORTED_C_SYMBOL(memmove),
208     ADD_EXPORTED_C_SYMBOL(memset),
209     ADD_EXPORTED_C_SYMBOL(snprintf),
210     ADD_EXPORTED_C_SYMBOL(strcmp),
211     ADD_EXPORTED_C_SYMBOL(strlen),
212     ADD_EXPORTED_C_SYMBOL(strncmp),
213     ADD_EXPORTED_C_SYMBOL(tolower),
214     /* CHRE symbols */
215     ADD_EXPORTED_C_SYMBOL(chreAbort),
216     ADD_EXPORTED_C_SYMBOL(chreAudioConfigureSource),
217     ADD_EXPORTED_C_SYMBOL(chreAudioGetSource),
218     ADD_EXPORTED_C_SYMBOL(chreBleGetCapabilities),
219     ADD_EXPORTED_C_SYMBOL(chreBleGetFilterCapabilities),
220     ADD_EXPORTED_C_SYMBOL(chreBleFlushAsync),
221     ADD_EXPORTED_C_SYMBOL(chreBleGetScanStatus),
222     ADD_EXPORTED_C_SYMBOL(chreBleReadRssiAsync),
223     ADD_EXPORTED_C_SYMBOL(chreBleSocketAccept),
224     ADD_EXPORTED_C_SYMBOL(chreBleSocketSend),
225     ADD_EXPORTED_C_SYMBOL(chreBleStartScanAsync),
226     ADD_EXPORTED_C_SYMBOL(chreBleStartScanAsyncV1_9),
227     ADD_EXPORTED_C_SYMBOL(chreBleStopScanAsync),
228     ADD_EXPORTED_C_SYMBOL(chreBleStopScanAsyncV1_9),
229     ADD_EXPORTED_C_SYMBOL(chreConfigureDebugDumpEvent),
230     ADD_EXPORTED_C_SYMBOL(chreConfigureHostSleepStateEvents),
231     ADD_EXPORTED_C_SYMBOL(chreConfigureNanoappInfoEvents),
232     ADD_EXPORTED_C_SYMBOL(chreDebugDumpLog),
233     ADD_EXPORTED_C_SYMBOL(chreGetApiVersion),
234     ADD_EXPORTED_C_SYMBOL(chreGetCapabilities),
235     ADD_EXPORTED_C_SYMBOL(chreGetMessageToHostMaxSize),
236     ADD_EXPORTED_C_SYMBOL(chreGetAppId),
237     ADD_EXPORTED_C_SYMBOL(chreGetInstanceId),
238     ADD_EXPORTED_C_SYMBOL(chreGetEstimatedHostTimeOffset),
239     ADD_EXPORTED_C_SYMBOL(chreGetNanoappInfoByAppId),
240     ADD_EXPORTED_C_SYMBOL(chreGetNanoappInfoByInstanceId),
241     ADD_EXPORTED_C_SYMBOL(chreGetPlatformId),
242     ADD_EXPORTED_C_SYMBOL(chreGetSensorInfo),
243     ADD_EXPORTED_C_SYMBOL(chreGetSensorSamplingStatus),
244     ADD_EXPORTED_C_SYMBOL(chreGetTime),
245     ADD_EXPORTED_C_SYMBOL(chreGetVersion),
246     ADD_EXPORTED_C_SYMBOL(chreGnssConfigurePassiveLocationListener),
247     ADD_EXPORTED_C_SYMBOL(chreGnssGetCapabilities),
248     ADD_EXPORTED_C_SYMBOL(chreGnssLocationSessionStartAsync),
249     ADD_EXPORTED_C_SYMBOL(chreGnssLocationSessionStopAsync),
250     ADD_EXPORTED_C_SYMBOL(chreGnssMeasurementSessionStartAsync),
251     ADD_EXPORTED_C_SYMBOL(chreGnssMeasurementSessionStopAsync),
252     ADD_EXPORTED_C_SYMBOL(chreHeapAlloc),
253     ADD_EXPORTED_C_SYMBOL(chreHeapFree),
254     ADD_EXPORTED_C_SYMBOL(chreIsHostAwake),
255     ADD_EXPORTED_C_SYMBOL(chreLog),
256 #ifdef CHRE_MESSAGE_ROUTER_SUPPORT_ENABLED
257     ADD_EXPORTED_C_SYMBOL(chreMsgConfigureEndpointReadyEvents),
258     ADD_EXPORTED_C_SYMBOL(chreMsgConfigureServiceReadyEvents),
259     ADD_EXPORTED_C_SYMBOL(chreMsgGetEndpointInfo),
260     ADD_EXPORTED_C_SYMBOL(chreMsgPublishServices),
261     ADD_EXPORTED_C_SYMBOL(chreMsgSend),
262     ADD_EXPORTED_C_SYMBOL(chreMsgSessionCloseAsync),
263     ADD_EXPORTED_C_SYMBOL(chreMsgSessionGetInfo),
264     ADD_EXPORTED_C_SYMBOL(chreMsgSessionOpenAsync),
265 #endif  // CHRE_MESSAGE_ROUTER_SUPPORT_ENABLED
266     ADD_EXPORTED_C_SYMBOL(chreSendEvent),
267     ADD_EXPORTED_C_SYMBOL(chreSendMessageToHost),
268     ADD_EXPORTED_C_SYMBOL(chreSendMessageToHostEndpoint),
269     ADD_EXPORTED_C_SYMBOL(chreSendMessageWithPermissions),
270     ADD_EXPORTED_C_SYMBOL(chreSendReliableMessageAsync),
271     ADD_EXPORTED_C_SYMBOL(chreSensorConfigure),
272     ADD_EXPORTED_C_SYMBOL(chreSensorConfigureBiasEvents),
273     ADD_EXPORTED_C_SYMBOL(chreSensorFind),
274     ADD_EXPORTED_C_SYMBOL(chreSensorFindDefault),
275     ADD_EXPORTED_C_SYMBOL(chreSensorFlushAsync),
276     ADD_EXPORTED_C_SYMBOL(chreSensorGetThreeAxisBias),
277     ADD_EXPORTED_C_SYMBOL(chreTimerCancel),
278     ADD_EXPORTED_C_SYMBOL(chreTimerSet),
279     ADD_EXPORTED_C_SYMBOL(chreUserSettingConfigureEvents),
280     ADD_EXPORTED_C_SYMBOL(chreUserSettingGetState),
281     ADD_EXPORTED_C_SYMBOL(chreWifiConfigureScanMonitorAsync),
282     ADD_EXPORTED_C_SYMBOL(chreWifiGetCapabilities),
283     ADD_EXPORTED_C_SYMBOL(chreWifiRequestScanAsync),
284     ADD_EXPORTED_C_SYMBOL(chreWifiRequestRangingAsync),
285     ADD_EXPORTED_C_SYMBOL(chreWifiNanRequestRangingAsync),
286     ADD_EXPORTED_C_SYMBOL(chreWifiNanSubscribe),
287     ADD_EXPORTED_C_SYMBOL(chreWifiNanSubscribeCancel),
288     ADD_EXPORTED_C_SYMBOL(chreWwanGetCapabilities),
289     ADD_EXPORTED_C_SYMBOL(chreWwanGetCellInfoAsync),
290     ADD_EXPORTED_C_SYMBOL(platform_chreDebugDumpVaLog),
291 #ifdef CHRE_NANOAPP_TOKENIZED_LOGGING_SUPPORT_ENABLED
292     ADD_EXPORTED_C_SYMBOL(platform_chrePwTokenizedLog),
293 #endif // CHRE_NANOAPP_TOKENIZED_LOGGING_SUPPORT_ENABLED
294     ADD_EXPORTED_C_SYMBOL(chreConfigureHostEndpointNotifications),
295     ADD_EXPORTED_C_SYMBOL(chrePublishRpcServices),
296     ADD_EXPORTED_C_SYMBOL(chreGetHostEndpointInfo),
297 };
298 CHRE_DEPRECATED_EPILOGUE
299 // clang-format on
300 
301 }  // namespace
302 
create(void * elfInput,bool mapIntoTcm)303 NanoappLoader *NanoappLoader::create(void *elfInput, bool mapIntoTcm) {
304   if (elfInput == nullptr) {
305     LOGE("Elf header must not be null");
306     return nullptr;
307   }
308 
309   auto *loader =
310       static_cast<NanoappLoader *>(memoryAllocDram(sizeof(NanoappLoader)));
311   if (loader == nullptr) {
312     LOG_OOM();
313     return nullptr;
314   }
315   new (loader) NanoappLoader(elfInput, mapIntoTcm);
316 
317   if (loader->open()) {
318     return loader;
319   }
320 
321   // Call the destructor explicitly as memoryFreeDram() never calls it.
322   loader->~NanoappLoader();
323   memoryFreeDram(loader);
324   return nullptr;
325 }
326 
destroy(NanoappLoader * loader)327 void NanoappLoader::destroy(NanoappLoader *loader) {
328   loader->close();
329   // TODO(b/151847750): Modify utilities to support free'ing from regions other
330   // than SRAM.
331   loader->~NanoappLoader();
332   memoryFreeDram(loader);
333 }
334 
findExportedSymbol(const char * name)335 void *NanoappLoader::findExportedSymbol(const char *name) {
336   size_t nameLen = strlen(name);
337   for (size_t i = 0; i < ARRAY_SIZE(kExportedData); i++) {
338     if (nameLen == strlen(kExportedData[i].dataName) &&
339         strncmp(name, kExportedData[i].dataName, nameLen) == 0) {
340       return kExportedData[i].data;
341     }
342   }
343 
344 #ifdef CHREX_SYMBOL_EXTENSIONS
345   for (size_t i = 0; i < ARRAY_SIZE(kVendorExportedData); i++) {
346     if (nameLen == strlen(kVendorExportedData[i].dataName) &&
347         strncmp(name, kVendorExportedData[i].dataName, nameLen) == 0) {
348       return kVendorExportedData[i].data;
349     }
350   }
351 #endif
352 
353   return nullptr;
354 }
355 
open()356 bool NanoappLoader::open() {
357   if (!copyAndVerifyHeaders()) {
358     LOGE("Failed to copy and verify elf headers");
359   } else if (!createMappings()) {
360     LOGE("Failed to create mappings");
361   } else if (!fixRelocations()) {
362     LOGE("Failed to fix relocations");
363   } else if (!resolveGot()) {
364     LOGE("Failed to resolve GOT");
365   } else {
366     // Wipe caches before calling init array to ensure initializers are not in
367     // the data cache.
368     wipeSystemCaches(reinterpret_cast<uintptr_t>(mMapping), mMemorySpan);
369     if (!callInitArray()) {
370       LOGE("Failed to perform static init");
371     } else {
372       return true;
373     }
374   }
375   freeAllocatedData();
376   return false;
377 }
378 
close()379 void NanoappLoader::close() {
380   callAtexitFunctions();
381   callTerminatorArray();
382   freeAllocatedData();
383 }
384 
findSymbolByName(const char * name)385 void *NanoappLoader::findSymbolByName(const char *name) {
386   for (size_t offset = 0; offset < mDynamicSymbolTableSize;
387        offset += sizeof(ElfSym)) {
388     ElfSym *currSym =
389         reinterpret_cast<ElfSym *>(mDynamicSymbolTablePtr + offset);
390     const char *symbolName = getDataName(currSym);
391 
392     if (strncmp(symbolName, name, strlen(name)) == 0) {
393       return getSymbolTarget(currSym);
394     }
395   }
396   return nullptr;
397 }
398 
registerAtexitFunction(struct AtExitCallback & cb)399 void NanoappLoader::registerAtexitFunction(struct AtExitCallback &cb) {
400   if (!mAtexitFunctions.push_back(cb)) {
401     LOG_OOM();
402     gStaticInitFailure = true;
403   }
404 }
405 
mapBss(const ProgramHeader * hdr)406 void NanoappLoader::mapBss(const ProgramHeader *hdr) {
407   // if the memory size of this segment exceeds the file size zero fill the
408   // difference.
409   LOGV("Program Hdr mem sz: %u file size: %u", hdr->p_memsz, hdr->p_filesz);
410   if (hdr->p_memsz > hdr->p_filesz) {
411     ElfAddr endOfFile = hdr->p_vaddr + hdr->p_filesz + mLoadBias;
412     ElfAddr endOfMem = hdr->p_vaddr + hdr->p_memsz + mLoadBias;
413     if (endOfMem > endOfFile) {
414       auto deltaMem = endOfMem - endOfFile;
415       LOGV("Zeroing out %u from page %x", deltaMem, endOfFile);
416       memset(reinterpret_cast<void *>(endOfFile), 0, deltaMem);
417     }
418   }
419 }
420 
callInitArray()421 bool NanoappLoader::callInitArray() {
422   bool success = true;
423   // Sets global variable used by atexit in case it's invoked as part of
424   // initializing static data.
425   gCurrentlyLoadingNanoapp = this;
426 
427   // TODO(b/151847750): ELF can have other sections like .init, .preinit, .fini
428   // etc. Be sure to look for those if they end up being something that should
429   // be supported for nanoapps.
430   for (size_t i = 0; i < mNumSectionHeaders; ++i) {
431     const char *name = getSectionHeaderName(mSectionHeadersPtr[i].sh_name);
432     if (strncmp(name, kInitArrayName, strlen(kInitArrayName)) == 0) {
433       LOGV("Invoking init function");
434       uintptr_t initArray =
435           static_cast<uintptr_t>(mLoadBias + mSectionHeadersPtr[i].sh_addr);
436       uintptr_t offset = 0;
437       while (offset < mSectionHeadersPtr[i].sh_size) {
438         ElfAddr *funcPtr = reinterpret_cast<ElfAddr *>(initArray + offset);
439         uintptr_t initFunction = static_cast<uintptr_t>(*funcPtr);
440         ((void (*)())initFunction)();
441         offset += sizeof(initFunction);
442         if (gStaticInitFailure) {
443           success = false;
444           break;
445         }
446       }
447       break;
448     }
449   }
450 
451   //! Reset global state so it doesn't leak into the next load.
452   gCurrentlyLoadingNanoapp = nullptr;
453   gStaticInitFailure = false;
454   return success;
455 }
456 
roundDownToAlign(uintptr_t virtualAddr,size_t alignment)457 uintptr_t NanoappLoader::roundDownToAlign(uintptr_t virtualAddr,
458                                           size_t alignment) {
459   return alignment == 0 ? virtualAddr : virtualAddr & -alignment;
460 }
461 
freeAllocatedData()462 void NanoappLoader::freeAllocatedData() {
463   if (mIsTcmBinary) {
464     nanoappBinaryFree(mMapping);
465   } else {
466     nanoappBinaryDramFree(mMapping);
467   }
468   memoryFreeDram(mSectionHeadersPtr);
469   memoryFreeDram(mSectionNamesPtr);
470   mDynamicSymbolTablePtr = nullptr;
471   mDynamicSymbolTableSize = 0;
472 }
473 
verifyElfHeader()474 bool NanoappLoader::verifyElfHeader() {
475   ElfHeader *elfHeader = getElfHeader();
476   if (elfHeader != nullptr && (elfHeader->e_ident[EI_MAG0] == ELFMAG0) &&
477       (elfHeader->e_ident[EI_MAG1] == ELFMAG1) &&
478       (elfHeader->e_ident[EI_MAG2] == ELFMAG2) &&
479       (elfHeader->e_ident[EI_MAG3] == ELFMAG3) &&
480       (elfHeader->e_ehsize == sizeof(ElfHeader)) &&
481       (elfHeader->e_phentsize == sizeof(ProgramHeader)) &&
482       (elfHeader->e_shentsize == sizeof(SectionHeader)) &&
483       (elfHeader->e_shstrndx < elfHeader->e_shnum) &&
484       (elfHeader->e_version == EV_CURRENT) &&
485       (elfHeader->e_machine == CHRE_LOADER_ARCH) &&
486       (elfHeader->e_type == ET_DYN)) {
487     return true;
488   }
489   return false;
490 }
491 
verifyProgramHeaders()492 bool NanoappLoader::verifyProgramHeaders() {
493   // This is a minimal check for now -
494   // there should be at least one load segment.
495   for (size_t i = 0; i < getProgramHeaderArraySize(); ++i) {
496     if (getProgramHeaderArray()[i].p_type == PT_LOAD) {
497       return true;
498     }
499   }
500   LOGE("No load segment found");
501   return false;
502 }
503 
getSectionHeaderName(size_t headerOffset)504 const char *NanoappLoader::getSectionHeaderName(size_t headerOffset) {
505   if (headerOffset == 0) {
506     return "";
507   }
508 
509   return &mSectionNamesPtr[headerOffset];
510 }
511 
getSectionHeader(const char * headerName)512 NanoappLoader::SectionHeader *NanoappLoader::getSectionHeader(
513     const char *headerName) {
514   SectionHeader *rv = nullptr;
515   for (size_t i = 0; i < mNumSectionHeaders; ++i) {
516     const char *name = getSectionHeaderName(mSectionHeadersPtr[i].sh_name);
517     if (strncmp(name, headerName, strlen(headerName)) == 0) {
518       rv = &mSectionHeadersPtr[i];
519       break;
520     }
521   }
522   return rv;
523 }
524 
getProgramHeaderArray()525 ProgramHeader *NanoappLoader::getProgramHeaderArray() {
526   return reinterpret_cast<ProgramHeader *>(mBinary + getElfHeader()->e_phoff);
527 }
528 
getProgramHeaderArraySize()529 size_t NanoappLoader::getProgramHeaderArraySize() {
530   return getElfHeader()->e_phnum;
531 }
532 
verifyDynamicTables()533 bool NanoappLoader::verifyDynamicTables() {
534   SectionHeader *dynamicStringTablePtr = getSectionHeader(kDynstrTableName);
535   if (dynamicStringTablePtr == nullptr) {
536     LOGE("Failed to find table %s", kDynstrTableName);
537     return false;
538   }
539   mDynamicStringTablePtr =
540       reinterpret_cast<char *>(mBinary + dynamicStringTablePtr->sh_offset);
541 
542   SectionHeader *dynamicSymbolTablePtr = getSectionHeader(kDynsymTableName);
543   if (dynamicSymbolTablePtr == nullptr) {
544     LOGE("Failed to find table %s", kDynsymTableName);
545     return false;
546   }
547   mDynamicSymbolTablePtr = (mBinary + dynamicSymbolTablePtr->sh_offset);
548   mDynamicSymbolTableSize = dynamicSymbolTablePtr->sh_size;
549 
550   return true;
551 }
552 
copyAndVerifyHeaders()553 bool NanoappLoader::copyAndVerifyHeaders() {
554   // Verify the ELF Header
555   if (!verifyElfHeader()) {
556     LOGE("ELF header is invalid");
557     return false;
558   }
559 
560   // Verify Program Headers
561   if (!verifyProgramHeaders()) {
562     LOGE("Program headers are invalid");
563     return false;
564   }
565 
566   // Load Section Headers
567   ElfHeader *elfHeader = getElfHeader();
568   size_t sectionHeaderSizeBytes = sizeof(SectionHeader) * elfHeader->e_shnum;
569   mSectionHeadersPtr =
570       static_cast<SectionHeader *>(memoryAllocDram(sectionHeaderSizeBytes));
571   if (mSectionHeadersPtr == nullptr) {
572     LOG_OOM();
573     return false;
574   }
575   memcpy(mSectionHeadersPtr, (mBinary + elfHeader->e_shoff),
576          sectionHeaderSizeBytes);
577   mNumSectionHeaders = elfHeader->e_shnum;
578 
579   // Load section header names
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     return false;
586   }
587   memcpy(mSectionNamesPtr, mBinary + stringSection.sh_offset, sectionSize);
588 
589   // Verify dynamic symbol table
590   if (!verifyDynamicTables()) {
591     LOGE("Failed to verify dynamic tables");
592     return false;
593   }
594 
595   return true;
596 }
597 
createMappings()598 bool NanoappLoader::createMappings() {
599   // ELF needs pt_load segments to be in contiguous ascending order of
600   // virtual addresses. So the first and last segs can be used to
601   // calculate the entire address span of the image.
602   ProgramHeader *programHeaderArray = getProgramHeaderArray();
603   size_t numProgramHeaders = getProgramHeaderArraySize();
604   const ProgramHeader *first = &programHeaderArray[0];
605   const ProgramHeader *last = &programHeaderArray[numProgramHeaders - 1];
606 
607   // Find first load segment
608   while (first->p_type != PT_LOAD && first <= last) {
609     ++first;
610   }
611 
612   bool success = false;
613   if (first->p_type != PT_LOAD) {
614     LOGE("Unable to find any load segments in the binary");
615   } else {
616     // Verify that the first load segment has a program header
617     // first byte of a valid load segment can't be greater than the
618     // program header offset
619     bool valid =
620         (first->p_offset < getElfHeader()->e_phoff) &&
621         (first->p_filesz >= (getElfHeader()->e_phoff +
622                              (numProgramHeaders * sizeof(ProgramHeader))));
623     if (!valid) {
624       LOGE("Load segment program header validation failed");
625     } else {
626       // Get the last load segment
627       while (last > first && last->p_type != PT_LOAD) --last;
628 
629       size_t alignment = first->p_align;
630       size_t memorySpan = last->p_vaddr + last->p_memsz - first->p_vaddr;
631       LOGV("Nanoapp image Memory Span: %zu", memorySpan);
632 
633       if (mIsTcmBinary) {
634         mMapping =
635             static_cast<uint8_t *>(nanoappBinaryAlloc(memorySpan, alignment));
636       } else {
637         mMapping = static_cast<uint8_t *>(
638             nanoappBinaryDramAlloc(memorySpan, alignment));
639       }
640 
641       if (mMapping == nullptr) {
642         LOG_OOM();
643       } else {
644         LOGV("Starting location of mappings %p", mMapping);
645         mMemorySpan = memorySpan;
646 
647         // Calculate the load bias using the first load segment.
648         uintptr_t adjustedFirstLoadSegAddr =
649             roundDownToAlign(first->p_vaddr, alignment);
650         mLoadBias =
651             reinterpret_cast<uintptr_t>(mMapping) - adjustedFirstLoadSegAddr;
652         LOGV("Load bias is %lu", static_cast<long unsigned int>(mLoadBias));
653 
654         success = true;
655       }
656     }
657   }
658 
659   if (success) {
660     // Map the remaining segments
661     for (const ProgramHeader *ph = first; ph <= last; ++ph) {
662       if (ph->p_type == PT_LOAD) {
663         ElfAddr segStart = ph->p_vaddr + mLoadBias;
664         void *startPage = reinterpret_cast<void *>(segStart);
665         void *binaryStartPage = mBinary + ph->p_offset;
666         size_t segmentLen = ph->p_filesz;
667 
668         LOGV("Mapping start page %p from %p with length %zu", startPage,
669              binaryStartPage, segmentLen);
670         memcpy(startPage, binaryStartPage, segmentLen);
671         mapBss(ph);
672       } else {
673         LOGE("Non-load segment found between load segments");
674         success = false;
675         break;
676       }
677     }
678   }
679 
680   return success;
681 }
682 
getDynamicSymbol(size_t posInSymbolTable)683 NanoappLoader::ElfSym *NanoappLoader::getDynamicSymbol(
684     size_t posInSymbolTable) {
685   size_t numElements = mDynamicSymbolTableSize / sizeof(ElfSym);
686   CHRE_ASSERT(posInSymbolTable < numElements);
687   if (posInSymbolTable < numElements) {
688     return reinterpret_cast<ElfSym *>(
689         &mDynamicSymbolTablePtr[posInSymbolTable * sizeof(ElfSym)]);
690   }
691   LOGE("Symbol index %zu is out of bound %zu", posInSymbolTable, numElements);
692   return nullptr;
693 }
694 
getDataName(const ElfSym * symbol)695 const char *NanoappLoader::getDataName(const ElfSym *symbol) {
696   return symbol == nullptr ? nullptr : &mDynamicStringTablePtr[symbol->st_name];
697 }
698 
getSymbolTarget(const ElfSym * symbol)699 void *NanoappLoader::getSymbolTarget(const ElfSym *symbol) {
700   if (symbol == nullptr || symbol->st_shndx == SHN_UNDEF) {
701     return nullptr;
702   }
703   return mMapping + symbol->st_value;
704 }
705 
resolveData(size_t posInSymbolTable)706 void *NanoappLoader::resolveData(size_t posInSymbolTable) {
707   const ElfSym *symbol = getDynamicSymbol(posInSymbolTable);
708   const char *dataName = getDataName(symbol);
709   void *target = nullptr;
710 
711   if (dataName != nullptr) {
712     LOGV("Resolving %s", dataName);
713     target = findExportedSymbol(dataName);
714     if (target == nullptr) {
715       target = getSymbolTarget(symbol);
716     }
717     if (target == nullptr) {
718       LOGE("Unable to find %s", dataName);
719     }
720   }
721 
722   return target;
723 }
724 
getDynamicHeader()725 NanoappLoader::DynamicHeader *NanoappLoader::getDynamicHeader() {
726   DynamicHeader *dyn = nullptr;
727   ProgramHeader *programHeaders = getProgramHeaderArray();
728   for (size_t i = 0; i < getProgramHeaderArraySize(); ++i) {
729     if (programHeaders[i].p_type == PT_DYNAMIC) {
730       dyn = reinterpret_cast<DynamicHeader *>(programHeaders[i].p_offset +
731                                               mBinary);
732       break;
733     }
734   }
735   return dyn;
736 }
737 
getFirstRoSegHeader()738 NanoappLoader::ProgramHeader *NanoappLoader::getFirstRoSegHeader() {
739   // return the first read only segment found
740   ProgramHeader *ro = nullptr;
741   ProgramHeader *programHeaders = getProgramHeaderArray();
742   for (size_t i = 0; i < getProgramHeaderArraySize(); ++i) {
743     if (!(programHeaders[i].p_flags & PF_W)) {
744       ro = &programHeaders[i];
745       break;
746     }
747   }
748   return ro;
749 }
750 
getDynEntry(DynamicHeader * dyn,int field)751 NanoappLoader::ElfWord NanoappLoader::getDynEntry(DynamicHeader *dyn,
752                                                   int field) {
753   ElfWord rv = 0;
754 
755   while (dyn->d_tag != DT_NULL) {
756     if (dyn->d_tag == field) {
757       rv = dyn->d_un.d_val;
758       break;
759     }
760     ++dyn;
761   }
762 
763   return rv;
764 }
765 
fixRelocations()766 bool NanoappLoader::fixRelocations() {
767   DynamicHeader *dyn = getDynamicHeader();
768   if (dyn == nullptr) {
769     LOGE("Dynamic headers are missing from shared object");
770   }
771   if (relocateTable(dyn, DT_RELA) && relocateTable(dyn, DT_REL)) {
772     return true;
773   }
774   LOGE("Unable to resolve all symbols in the binary");
775   return false;
776 }
777 
callAtexitFunctions()778 void NanoappLoader::callAtexitFunctions() {
779   while (!mAtexitFunctions.empty()) {
780     struct AtExitCallback cb = mAtexitFunctions.back();
781     if (cb.arg.has_value()) {
782       LOGV("Calling __cxa_atexit at %p, arg %p", cb.func1, cb.arg.value());
783       cb.func1(cb.arg.value());
784     } else {
785       LOGV("Calling atexit at %p", cb.func0);
786       cb.func0();
787     }
788     mAtexitFunctions.pop_back();
789   }
790 }
791 
callTerminatorArray()792 void NanoappLoader::callTerminatorArray() {
793   for (size_t i = 0; i < mNumSectionHeaders; ++i) {
794     const char *name = getSectionHeaderName(mSectionHeadersPtr[i].sh_name);
795     if (strncmp(name, kFiniArrayName, strlen(kFiniArrayName)) == 0) {
796       uintptr_t finiArray =
797           static_cast<uintptr_t>(mLoadBias + mSectionHeadersPtr[i].sh_addr);
798       uintptr_t offset = 0;
799       while (offset < mSectionHeadersPtr[i].sh_size) {
800         ElfAddr *funcPtr = reinterpret_cast<ElfAddr *>(finiArray + offset);
801         uintptr_t finiFunction = static_cast<uintptr_t>(*funcPtr);
802         ((void (*)())finiFunction)();
803         offset += sizeof(finiFunction);
804       }
805       break;
806     }
807   }
808 }
809 
getTokenDatabaseSectionInfo(uint32_t * offset,size_t * size)810 void NanoappLoader::getTokenDatabaseSectionInfo(uint32_t *offset,
811                                                 size_t *size) {
812   // Find token database.
813   SectionHeader *pwTokenTableHeader = getSectionHeader(kTokenTableName);
814   if (pwTokenTableHeader != nullptr) {
815     if (pwTokenTableHeader->sh_size != 0) {
816       *size = pwTokenTableHeader->sh_size;
817       *offset = pwTokenTableHeader->sh_offset;
818     } else {
819       LOGE("Found empty token database");
820       *size = 0;
821       *offset = 0;
822     }
823   } else {
824     *size = 0;
825     *offset = 0;
826   }
827 }
828 
829 }  // namespace chre
830