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