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(chreBleStartScanAsync),
222 ADD_EXPORTED_C_SYMBOL(chreBleStartScanAsyncV1_9),
223 ADD_EXPORTED_C_SYMBOL(chreBleStopScanAsync),
224 ADD_EXPORTED_C_SYMBOL(chreBleStopScanAsyncV1_9),
225 ADD_EXPORTED_C_SYMBOL(chreBleReadRssiAsync),
226 ADD_EXPORTED_C_SYMBOL(chreBleGetScanStatus),
227 ADD_EXPORTED_C_SYMBOL(chreConfigureDebugDumpEvent),
228 ADD_EXPORTED_C_SYMBOL(chreConfigureHostSleepStateEvents),
229 ADD_EXPORTED_C_SYMBOL(chreConfigureNanoappInfoEvents),
230 ADD_EXPORTED_C_SYMBOL(chreDebugDumpLog),
231 ADD_EXPORTED_C_SYMBOL(chreGetApiVersion),
232 ADD_EXPORTED_C_SYMBOL(chreGetCapabilities),
233 ADD_EXPORTED_C_SYMBOL(chreGetMessageToHostMaxSize),
234 ADD_EXPORTED_C_SYMBOL(chreGetAppId),
235 ADD_EXPORTED_C_SYMBOL(chreGetInstanceId),
236 ADD_EXPORTED_C_SYMBOL(chreGetEstimatedHostTimeOffset),
237 ADD_EXPORTED_C_SYMBOL(chreGetNanoappInfoByAppId),
238 ADD_EXPORTED_C_SYMBOL(chreGetNanoappInfoByInstanceId),
239 ADD_EXPORTED_C_SYMBOL(chreGetPlatformId),
240 ADD_EXPORTED_C_SYMBOL(chreGetSensorInfo),
241 ADD_EXPORTED_C_SYMBOL(chreGetSensorSamplingStatus),
242 ADD_EXPORTED_C_SYMBOL(chreGetTime),
243 ADD_EXPORTED_C_SYMBOL(chreGetVersion),
244 ADD_EXPORTED_C_SYMBOL(chreGnssConfigurePassiveLocationListener),
245 ADD_EXPORTED_C_SYMBOL(chreGnssGetCapabilities),
246 ADD_EXPORTED_C_SYMBOL(chreGnssLocationSessionStartAsync),
247 ADD_EXPORTED_C_SYMBOL(chreGnssLocationSessionStopAsync),
248 ADD_EXPORTED_C_SYMBOL(chreGnssMeasurementSessionStartAsync),
249 ADD_EXPORTED_C_SYMBOL(chreGnssMeasurementSessionStopAsync),
250 ADD_EXPORTED_C_SYMBOL(chreHeapAlloc),
251 ADD_EXPORTED_C_SYMBOL(chreHeapFree),
252 ADD_EXPORTED_C_SYMBOL(chreIsHostAwake),
253 ADD_EXPORTED_C_SYMBOL(chreLog),
254 ADD_EXPORTED_C_SYMBOL(chreSendEvent),
255 ADD_EXPORTED_C_SYMBOL(chreSendMessageToHost),
256 ADD_EXPORTED_C_SYMBOL(chreSendMessageToHostEndpoint),
257 ADD_EXPORTED_C_SYMBOL(chreSendMessageWithPermissions),
258 ADD_EXPORTED_C_SYMBOL(chreSendReliableMessageAsync),
259 ADD_EXPORTED_C_SYMBOL(chreSensorConfigure),
260 ADD_EXPORTED_C_SYMBOL(chreSensorConfigureBiasEvents),
261 ADD_EXPORTED_C_SYMBOL(chreSensorFind),
262 ADD_EXPORTED_C_SYMBOL(chreSensorFindDefault),
263 ADD_EXPORTED_C_SYMBOL(chreSensorFlushAsync),
264 ADD_EXPORTED_C_SYMBOL(chreSensorGetThreeAxisBias),
265 ADD_EXPORTED_C_SYMBOL(chreTimerCancel),
266 ADD_EXPORTED_C_SYMBOL(chreTimerSet),
267 ADD_EXPORTED_C_SYMBOL(chreUserSettingConfigureEvents),
268 ADD_EXPORTED_C_SYMBOL(chreUserSettingGetState),
269 ADD_EXPORTED_C_SYMBOL(chreWifiConfigureScanMonitorAsync),
270 ADD_EXPORTED_C_SYMBOL(chreWifiGetCapabilities),
271 ADD_EXPORTED_C_SYMBOL(chreWifiRequestScanAsync),
272 ADD_EXPORTED_C_SYMBOL(chreWifiRequestRangingAsync),
273 ADD_EXPORTED_C_SYMBOL(chreWifiNanRequestRangingAsync),
274 ADD_EXPORTED_C_SYMBOL(chreWifiNanSubscribe),
275 ADD_EXPORTED_C_SYMBOL(chreWifiNanSubscribeCancel),
276 ADD_EXPORTED_C_SYMBOL(chreWwanGetCapabilities),
277 ADD_EXPORTED_C_SYMBOL(chreWwanGetCellInfoAsync),
278 ADD_EXPORTED_C_SYMBOL(platform_chreDebugDumpVaLog),
279 #ifdef CHRE_NANOAPP_TOKENIZED_LOGGING_SUPPORT_ENABLED
280 ADD_EXPORTED_C_SYMBOL(platform_chrePwTokenizedLog),
281 #endif // CHRE_NANOAPP_TOKENIZED_LOGGING_SUPPORT_ENABLED
282 ADD_EXPORTED_C_SYMBOL(chreConfigureHostEndpointNotifications),
283 ADD_EXPORTED_C_SYMBOL(chrePublishRpcServices),
284 ADD_EXPORTED_C_SYMBOL(chreGetHostEndpointInfo),
285 };
286 CHRE_DEPRECATED_EPILOGUE
287 // clang-format on
288
289 } // namespace
290
create(void * elfInput,bool mapIntoTcm)291 NanoappLoader *NanoappLoader::create(void *elfInput, bool mapIntoTcm) {
292 if (elfInput == nullptr) {
293 LOGE("Elf header must not be null");
294 return nullptr;
295 }
296
297 auto *loader =
298 static_cast<NanoappLoader *>(memoryAllocDram(sizeof(NanoappLoader)));
299 if (loader == nullptr) {
300 LOG_OOM();
301 return nullptr;
302 }
303 new (loader) NanoappLoader(elfInput, mapIntoTcm);
304
305 if (loader->open()) {
306 return loader;
307 }
308
309 // Call the destructor explicitly as memoryFreeDram() never calls it.
310 loader->~NanoappLoader();
311 memoryFreeDram(loader);
312 return nullptr;
313 }
314
destroy(NanoappLoader * loader)315 void NanoappLoader::destroy(NanoappLoader *loader) {
316 loader->close();
317 // TODO(b/151847750): Modify utilities to support free'ing from regions other
318 // than SRAM.
319 loader->~NanoappLoader();
320 memoryFreeDram(loader);
321 }
322
findExportedSymbol(const char * name)323 void *NanoappLoader::findExportedSymbol(const char *name) {
324 size_t nameLen = strlen(name);
325 for (size_t i = 0; i < ARRAY_SIZE(kExportedData); i++) {
326 if (nameLen == strlen(kExportedData[i].dataName) &&
327 strncmp(name, kExportedData[i].dataName, nameLen) == 0) {
328 return kExportedData[i].data;
329 }
330 }
331
332 #ifdef CHREX_SYMBOL_EXTENSIONS
333 for (size_t i = 0; i < ARRAY_SIZE(kVendorExportedData); i++) {
334 if (nameLen == strlen(kVendorExportedData[i].dataName) &&
335 strncmp(name, kVendorExportedData[i].dataName, nameLen) == 0) {
336 return kVendorExportedData[i].data;
337 }
338 }
339 #endif
340
341 return nullptr;
342 }
343
open()344 bool NanoappLoader::open() {
345 if (!copyAndVerifyHeaders()) {
346 LOGE("Failed to copy and verify elf headers");
347 } else if (!createMappings()) {
348 LOGE("Failed to create mappings");
349 } else if (!fixRelocations()) {
350 LOGE("Failed to fix relocations");
351 } else if (!resolveGot()) {
352 LOGE("Failed to resolve GOT");
353 } else {
354 // Wipe caches before calling init array to ensure initializers are not in
355 // the data cache.
356 wipeSystemCaches(reinterpret_cast<uintptr_t>(mMapping), mMemorySpan);
357 if (!callInitArray()) {
358 LOGE("Failed to perform static init");
359 } else {
360 return true;
361 }
362 }
363 freeAllocatedData();
364 return false;
365 }
366
close()367 void NanoappLoader::close() {
368 callAtexitFunctions();
369 callTerminatorArray();
370 freeAllocatedData();
371 }
372
findSymbolByName(const char * name)373 void *NanoappLoader::findSymbolByName(const char *name) {
374 for (size_t offset = 0; offset < mDynamicSymbolTableSize;
375 offset += sizeof(ElfSym)) {
376 ElfSym *currSym =
377 reinterpret_cast<ElfSym *>(mDynamicSymbolTablePtr + offset);
378 const char *symbolName = getDataName(currSym);
379
380 if (strncmp(symbolName, name, strlen(name)) == 0) {
381 return getSymbolTarget(currSym);
382 }
383 }
384 return nullptr;
385 }
386
registerAtexitFunction(struct AtExitCallback & cb)387 void NanoappLoader::registerAtexitFunction(struct AtExitCallback &cb) {
388 if (!mAtexitFunctions.push_back(cb)) {
389 LOG_OOM();
390 gStaticInitFailure = true;
391 }
392 }
393
mapBss(const ProgramHeader * hdr)394 void NanoappLoader::mapBss(const ProgramHeader *hdr) {
395 // if the memory size of this segment exceeds the file size zero fill the
396 // difference.
397 LOGV("Program Hdr mem sz: %u file size: %u", hdr->p_memsz, hdr->p_filesz);
398 if (hdr->p_memsz > hdr->p_filesz) {
399 ElfAddr endOfFile = hdr->p_vaddr + hdr->p_filesz + mLoadBias;
400 ElfAddr endOfMem = hdr->p_vaddr + hdr->p_memsz + mLoadBias;
401 if (endOfMem > endOfFile) {
402 auto deltaMem = endOfMem - endOfFile;
403 LOGV("Zeroing out %u from page %x", deltaMem, endOfFile);
404 memset(reinterpret_cast<void *>(endOfFile), 0, deltaMem);
405 }
406 }
407 }
408
callInitArray()409 bool NanoappLoader::callInitArray() {
410 bool success = true;
411 // Sets global variable used by atexit in case it's invoked as part of
412 // initializing static data.
413 gCurrentlyLoadingNanoapp = this;
414
415 // TODO(b/151847750): ELF can have other sections like .init, .preinit, .fini
416 // etc. Be sure to look for those if they end up being something that should
417 // be supported for nanoapps.
418 for (size_t i = 0; i < mNumSectionHeaders; ++i) {
419 const char *name = getSectionHeaderName(mSectionHeadersPtr[i].sh_name);
420 if (strncmp(name, kInitArrayName, strlen(kInitArrayName)) == 0) {
421 LOGV("Invoking init function");
422 uintptr_t initArray =
423 static_cast<uintptr_t>(mLoadBias + mSectionHeadersPtr[i].sh_addr);
424 uintptr_t offset = 0;
425 while (offset < mSectionHeadersPtr[i].sh_size) {
426 ElfAddr *funcPtr = reinterpret_cast<ElfAddr *>(initArray + offset);
427 uintptr_t initFunction = static_cast<uintptr_t>(*funcPtr);
428 ((void (*)())initFunction)();
429 offset += sizeof(initFunction);
430 if (gStaticInitFailure) {
431 success = false;
432 break;
433 }
434 }
435 break;
436 }
437 }
438
439 //! Reset global state so it doesn't leak into the next load.
440 gCurrentlyLoadingNanoapp = nullptr;
441 gStaticInitFailure = false;
442 return success;
443 }
444
roundDownToAlign(uintptr_t virtualAddr,size_t alignment)445 uintptr_t NanoappLoader::roundDownToAlign(uintptr_t virtualAddr,
446 size_t alignment) {
447 return alignment == 0 ? virtualAddr : virtualAddr & -alignment;
448 }
449
freeAllocatedData()450 void NanoappLoader::freeAllocatedData() {
451 if (mIsTcmBinary) {
452 nanoappBinaryFree(mMapping);
453 } else {
454 nanoappBinaryDramFree(mMapping);
455 }
456 memoryFreeDram(mSectionHeadersPtr);
457 memoryFreeDram(mSectionNamesPtr);
458 mDynamicSymbolTablePtr = nullptr;
459 mDynamicSymbolTableSize = 0;
460 }
461
verifyElfHeader()462 bool NanoappLoader::verifyElfHeader() {
463 ElfHeader *elfHeader = getElfHeader();
464 if (elfHeader != nullptr && (elfHeader->e_ident[EI_MAG0] == ELFMAG0) &&
465 (elfHeader->e_ident[EI_MAG1] == ELFMAG1) &&
466 (elfHeader->e_ident[EI_MAG2] == ELFMAG2) &&
467 (elfHeader->e_ident[EI_MAG3] == ELFMAG3) &&
468 (elfHeader->e_ehsize == sizeof(ElfHeader)) &&
469 (elfHeader->e_phentsize == sizeof(ProgramHeader)) &&
470 (elfHeader->e_shentsize == sizeof(SectionHeader)) &&
471 (elfHeader->e_shstrndx < elfHeader->e_shnum) &&
472 (elfHeader->e_version == EV_CURRENT) &&
473 (elfHeader->e_machine == CHRE_LOADER_ARCH) &&
474 (elfHeader->e_type == ET_DYN)) {
475 return true;
476 }
477 return false;
478 }
479
verifyProgramHeaders()480 bool NanoappLoader::verifyProgramHeaders() {
481 // This is a minimal check for now -
482 // there should be at least one load segment.
483 for (size_t i = 0; i < getProgramHeaderArraySize(); ++i) {
484 if (getProgramHeaderArray()[i].p_type == PT_LOAD) {
485 return true;
486 }
487 }
488 LOGE("No load segment found");
489 return false;
490 }
491
getSectionHeaderName(size_t headerOffset)492 const char *NanoappLoader::getSectionHeaderName(size_t headerOffset) {
493 if (headerOffset == 0) {
494 return "";
495 }
496
497 return &mSectionNamesPtr[headerOffset];
498 }
499
getSectionHeader(const char * headerName)500 NanoappLoader::SectionHeader *NanoappLoader::getSectionHeader(
501 const char *headerName) {
502 SectionHeader *rv = nullptr;
503 for (size_t i = 0; i < mNumSectionHeaders; ++i) {
504 const char *name = getSectionHeaderName(mSectionHeadersPtr[i].sh_name);
505 if (strncmp(name, headerName, strlen(headerName)) == 0) {
506 rv = &mSectionHeadersPtr[i];
507 break;
508 }
509 }
510 return rv;
511 }
512
getProgramHeaderArray()513 ProgramHeader *NanoappLoader::getProgramHeaderArray() {
514 return reinterpret_cast<ProgramHeader *>(mBinary + getElfHeader()->e_phoff);
515 }
516
getProgramHeaderArraySize()517 size_t NanoappLoader::getProgramHeaderArraySize() {
518 return getElfHeader()->e_phnum;
519 }
520
verifyDynamicTables()521 bool NanoappLoader::verifyDynamicTables() {
522 SectionHeader *dynamicStringTablePtr = getSectionHeader(kDynstrTableName);
523 if (dynamicStringTablePtr == nullptr) {
524 LOGE("Failed to find table %s", kDynstrTableName);
525 return false;
526 }
527 mDynamicStringTablePtr =
528 reinterpret_cast<char *>(mBinary + dynamicStringTablePtr->sh_offset);
529
530 SectionHeader *dynamicSymbolTablePtr = getSectionHeader(kDynsymTableName);
531 if (dynamicSymbolTablePtr == nullptr) {
532 LOGE("Failed to find table %s", kDynsymTableName);
533 return false;
534 }
535 mDynamicSymbolTablePtr = (mBinary + dynamicSymbolTablePtr->sh_offset);
536 mDynamicSymbolTableSize = dynamicSymbolTablePtr->sh_size;
537
538 return true;
539 }
540
copyAndVerifyHeaders()541 bool NanoappLoader::copyAndVerifyHeaders() {
542 // Verify the ELF Header
543 if (!verifyElfHeader()) {
544 LOGE("ELF header is invalid");
545 return false;
546 }
547
548 // Verify Program Headers
549 if (!verifyProgramHeaders()) {
550 LOGE("Program headers are invalid");
551 return false;
552 }
553
554 // Load Section Headers
555 ElfHeader *elfHeader = getElfHeader();
556 size_t sectionHeaderSizeBytes = sizeof(SectionHeader) * elfHeader->e_shnum;
557 mSectionHeadersPtr =
558 static_cast<SectionHeader *>(memoryAllocDram(sectionHeaderSizeBytes));
559 if (mSectionHeadersPtr == nullptr) {
560 LOG_OOM();
561 return false;
562 }
563 memcpy(mSectionHeadersPtr, (mBinary + elfHeader->e_shoff),
564 sectionHeaderSizeBytes);
565 mNumSectionHeaders = elfHeader->e_shnum;
566
567 // Load section header names
568 SectionHeader &stringSection = mSectionHeadersPtr[elfHeader->e_shstrndx];
569 size_t sectionSize = stringSection.sh_size;
570 mSectionNamesPtr = static_cast<char *>(memoryAllocDram(sectionSize));
571 if (mSectionNamesPtr == nullptr) {
572 LOG_OOM();
573 return false;
574 }
575 memcpy(mSectionNamesPtr, mBinary + stringSection.sh_offset, sectionSize);
576
577 // Verify dynamic symbol table
578 if (!verifyDynamicTables()) {
579 LOGE("Failed to verify dynamic tables");
580 return false;
581 }
582
583 return true;
584 }
585
createMappings()586 bool NanoappLoader::createMappings() {
587 // ELF needs pt_load segments to be in contiguous ascending order of
588 // virtual addresses. So the first and last segs can be used to
589 // calculate the entire address span of the image.
590 ProgramHeader *programHeaderArray = getProgramHeaderArray();
591 size_t numProgramHeaders = getProgramHeaderArraySize();
592 const ProgramHeader *first = &programHeaderArray[0];
593 const ProgramHeader *last = &programHeaderArray[numProgramHeaders - 1];
594
595 // Find first load segment
596 while (first->p_type != PT_LOAD && first <= last) {
597 ++first;
598 }
599
600 bool success = false;
601 if (first->p_type != PT_LOAD) {
602 LOGE("Unable to find any load segments in the binary");
603 } else {
604 // Verify that the first load segment has a program header
605 // first byte of a valid load segment can't be greater than the
606 // program header offset
607 bool valid =
608 (first->p_offset < getElfHeader()->e_phoff) &&
609 (first->p_filesz >= (getElfHeader()->e_phoff +
610 (numProgramHeaders * sizeof(ProgramHeader))));
611 if (!valid) {
612 LOGE("Load segment program header validation failed");
613 } else {
614 // Get the last load segment
615 while (last > first && last->p_type != PT_LOAD) --last;
616
617 size_t alignment = first->p_align;
618 size_t memorySpan = last->p_vaddr + last->p_memsz - first->p_vaddr;
619 LOGV("Nanoapp image Memory Span: %zu", memorySpan);
620
621 if (mIsTcmBinary) {
622 mMapping =
623 static_cast<uint8_t *>(nanoappBinaryAlloc(memorySpan, alignment));
624 } else {
625 mMapping = static_cast<uint8_t *>(
626 nanoappBinaryDramAlloc(memorySpan, alignment));
627 }
628
629 if (mMapping == nullptr) {
630 LOG_OOM();
631 } else {
632 LOGV("Starting location of mappings %p", mMapping);
633 mMemorySpan = memorySpan;
634
635 // Calculate the load bias using the first load segment.
636 uintptr_t adjustedFirstLoadSegAddr =
637 roundDownToAlign(first->p_vaddr, alignment);
638 mLoadBias =
639 reinterpret_cast<uintptr_t>(mMapping) - adjustedFirstLoadSegAddr;
640 LOGV("Load bias is %lu", static_cast<long unsigned int>(mLoadBias));
641
642 success = true;
643 }
644 }
645 }
646
647 if (success) {
648 // Map the remaining segments
649 for (const ProgramHeader *ph = first; ph <= last; ++ph) {
650 if (ph->p_type == PT_LOAD) {
651 ElfAddr segStart = ph->p_vaddr + mLoadBias;
652 void *startPage = reinterpret_cast<void *>(segStart);
653 void *binaryStartPage = mBinary + ph->p_offset;
654 size_t segmentLen = ph->p_filesz;
655
656 LOGV("Mapping start page %p from %p with length %zu", startPage,
657 binaryStartPage, segmentLen);
658 memcpy(startPage, binaryStartPage, segmentLen);
659 mapBss(ph);
660 } else {
661 LOGE("Non-load segment found between load segments");
662 success = false;
663 break;
664 }
665 }
666 }
667
668 return success;
669 }
670
getDynamicSymbol(size_t posInSymbolTable)671 NanoappLoader::ElfSym *NanoappLoader::getDynamicSymbol(
672 size_t posInSymbolTable) {
673 size_t numElements = mDynamicSymbolTableSize / sizeof(ElfSym);
674 CHRE_ASSERT(posInSymbolTable < numElements);
675 if (posInSymbolTable < numElements) {
676 return reinterpret_cast<ElfSym *>(
677 &mDynamicSymbolTablePtr[posInSymbolTable * sizeof(ElfSym)]);
678 }
679 LOGE("Symbol index %zu is out of bound %zu", posInSymbolTable, numElements);
680 return nullptr;
681 }
682
getDataName(const ElfSym * symbol)683 const char *NanoappLoader::getDataName(const ElfSym *symbol) {
684 return symbol == nullptr ? nullptr : &mDynamicStringTablePtr[symbol->st_name];
685 }
686
getSymbolTarget(const ElfSym * symbol)687 void *NanoappLoader::getSymbolTarget(const ElfSym *symbol) {
688 if (symbol == nullptr || symbol->st_shndx == SHN_UNDEF) {
689 return nullptr;
690 }
691 return mMapping + symbol->st_value;
692 }
693
resolveData(size_t posInSymbolTable)694 void *NanoappLoader::resolveData(size_t posInSymbolTable) {
695 const ElfSym *symbol = getDynamicSymbol(posInSymbolTable);
696 const char *dataName = getDataName(symbol);
697 void *target = nullptr;
698
699 if (dataName != nullptr) {
700 LOGV("Resolving %s", dataName);
701 target = findExportedSymbol(dataName);
702 if (target == nullptr) {
703 target = getSymbolTarget(symbol);
704 }
705 if (target == nullptr) {
706 LOGE("Unable to find %s", dataName);
707 }
708 }
709
710 return target;
711 }
712
getDynamicHeader()713 NanoappLoader::DynamicHeader *NanoappLoader::getDynamicHeader() {
714 DynamicHeader *dyn = nullptr;
715 ProgramHeader *programHeaders = getProgramHeaderArray();
716 for (size_t i = 0; i < getProgramHeaderArraySize(); ++i) {
717 if (programHeaders[i].p_type == PT_DYNAMIC) {
718 dyn = reinterpret_cast<DynamicHeader *>(programHeaders[i].p_offset +
719 mBinary);
720 break;
721 }
722 }
723 return dyn;
724 }
725
getFirstRoSegHeader()726 NanoappLoader::ProgramHeader *NanoappLoader::getFirstRoSegHeader() {
727 // return the first read only segment found
728 ProgramHeader *ro = nullptr;
729 ProgramHeader *programHeaders = getProgramHeaderArray();
730 for (size_t i = 0; i < getProgramHeaderArraySize(); ++i) {
731 if (!(programHeaders[i].p_flags & PF_W)) {
732 ro = &programHeaders[i];
733 break;
734 }
735 }
736 return ro;
737 }
738
getDynEntry(DynamicHeader * dyn,int field)739 NanoappLoader::ElfWord NanoappLoader::getDynEntry(DynamicHeader *dyn,
740 int field) {
741 ElfWord rv = 0;
742
743 while (dyn->d_tag != DT_NULL) {
744 if (dyn->d_tag == field) {
745 rv = dyn->d_un.d_val;
746 break;
747 }
748 ++dyn;
749 }
750
751 return rv;
752 }
753
fixRelocations()754 bool NanoappLoader::fixRelocations() {
755 DynamicHeader *dyn = getDynamicHeader();
756 if (dyn == nullptr) {
757 LOGE("Dynamic headers are missing from shared object");
758 }
759 if (relocateTable(dyn, DT_RELA) && relocateTable(dyn, DT_REL)) {
760 return true;
761 }
762 LOGE("Unable to resolve all symbols in the binary");
763 return false;
764 }
765
callAtexitFunctions()766 void NanoappLoader::callAtexitFunctions() {
767 while (!mAtexitFunctions.empty()) {
768 struct AtExitCallback cb = mAtexitFunctions.back();
769 if (cb.arg.has_value()) {
770 LOGV("Calling __cxa_atexit at %p, arg %p", cb.func1, cb.arg.value());
771 cb.func1(cb.arg.value());
772 } else {
773 LOGV("Calling atexit at %p", cb.func0);
774 cb.func0();
775 }
776 mAtexitFunctions.pop_back();
777 }
778 }
779
callTerminatorArray()780 void NanoappLoader::callTerminatorArray() {
781 for (size_t i = 0; i < mNumSectionHeaders; ++i) {
782 const char *name = getSectionHeaderName(mSectionHeadersPtr[i].sh_name);
783 if (strncmp(name, kFiniArrayName, strlen(kFiniArrayName)) == 0) {
784 uintptr_t finiArray =
785 static_cast<uintptr_t>(mLoadBias + mSectionHeadersPtr[i].sh_addr);
786 uintptr_t offset = 0;
787 while (offset < mSectionHeadersPtr[i].sh_size) {
788 ElfAddr *funcPtr = reinterpret_cast<ElfAddr *>(finiArray + offset);
789 uintptr_t finiFunction = static_cast<uintptr_t>(*funcPtr);
790 ((void (*)())finiFunction)();
791 offset += sizeof(finiFunction);
792 }
793 break;
794 }
795 }
796 }
797
getTokenDatabaseSectionInfo(uint32_t * offset,size_t * size)798 void NanoappLoader::getTokenDatabaseSectionInfo(uint32_t *offset,
799 size_t *size) {
800 // Find token database.
801 SectionHeader *pwTokenTableHeader = getSectionHeader(kTokenTableName);
802 if (pwTokenTableHeader != nullptr) {
803 if (pwTokenTableHeader->sh_size != 0) {
804 *size = pwTokenTableHeader->sh_size;
805 *offset = pwTokenTableHeader->sh_offset;
806 } else {
807 LOGE("Found empty token database");
808 *size = 0;
809 *offset = 0;
810 }
811 } else {
812 *size = 0;
813 *offset = 0;
814 }
815 }
816
817 } // namespace chre
818