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