1/* 2 * Copyright (c) 2024 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15#include "ecmascript/compiler/aot_file/elf_checker.h" 16#include <fstream> 17#include <type_traits> 18 19namespace panda::ecmascript { 20/* Check Aligned */ 21template <typename AlignType> static bool CheckAlign(void* alignPtr, size_t offset = 0) 22{ 23 if (ALLOW_UNALIGNED != 0) { 24 return true; 25 } 26 size_t ptrPos = reinterpret_cast<size_t>(alignPtr) + offset; 27 if ((ptrPos & (alignof(AlignType) - 1)) == 0) { 28 return true; 29 } else { 30 return false; 31 } 32} 33 34/* Swap LSB and MSB */ 35template <typename IntType> static void ByteSwap(IntType& x) 36{ 37 static constexpr unsigned int iByteMuskOff0 = 0xffu; 38 static constexpr unsigned int iByteMuskOff1 = iByteMuskOff0 << 8; 39 static constexpr unsigned int iByteMuskOff2 = iByteMuskOff1 << 8; 40 static constexpr unsigned int iByteMuskOff3 = iByteMuskOff2 << 8; 41 static constexpr unsigned long long llByteMuskOff0 = 0xffuLL; 42 static constexpr unsigned long long llByteMuskOff1 = llByteMuskOff0 << 8; 43 static constexpr unsigned long long llByteMuskOff2 = llByteMuskOff1 << 8; 44 static constexpr unsigned long long llByteMuskOff3 = llByteMuskOff2 << 8; 45 static constexpr unsigned long long llByteMuskOff4 = llByteMuskOff3 << 8; 46 static constexpr unsigned long long llByteMuskOff5 = llByteMuskOff4 << 8; 47 static constexpr unsigned long long llByteMuskOff6 = llByteMuskOff5 << 8; 48 static constexpr unsigned long long llByteMuskOff7 = llByteMuskOff6 << 8; 49 static constexpr unsigned int move1 = 8; // 8: move 8 bits 50 static constexpr unsigned int move2 = move1 + 8 * 2; // 8: skip one pair 51 static constexpr unsigned int move3 = move2 + 8 * 2; // 8: skip another pair 52 static constexpr unsigned int move4 = move3 + 8 * 2; // 8: skip another pair 53 switch (sizeof(IntType)) { 54 case sizeof(int8_t): 55 return; 56 case sizeof(int16_t): 57 x = IntType((((x) >> move1) & iByteMuskOff0) | 58 (((x) & iByteMuskOff0) << move1)); // 8: position to change between LSB and MSB 59 return; 60 case sizeof(int32_t): 61 x = ((((x) & iByteMuskOff3) >> move2) | (((x) & iByteMuskOff2) >> move1) | 62 (((x) & iByteMuskOff1) << move1) | (((x) & iByteMuskOff0) << move2)); 63 return; 64 case sizeof(int64_t): 65 x = ((((x) & llByteMuskOff7) >> move4) | (((x) & llByteMuskOff6) >> move3) | 66 (((x) & llByteMuskOff5) >> move2) | (((x) & llByteMuskOff4) >> move1) | 67 (((x) & llByteMuskOff3) << move1) | (((x) & llByteMuskOff2) << move2) | 68 (((x) & llByteMuskOff1) << move3) | (((x) & llByteMuskOff0) << move4)); 69 return; 70 default: 71 return; 72 } 73} 74 75/* This function requires copying memory. Avoid using it if MemMap is avalible. */ 76ElfChecker::ElfChecker(const void* data, int len) : elfLen_(len), elfErrorCode_(0), fromMmap_(false) 77{ 78 if (len <= 0 || data == nullptr) { 79 elfData_ = nullptr; 80 return; 81 } 82 elfData_ = new char[len]; 83 if (memcpy_s(elfData_, len, data, len) != 0) { 84 delete[] elfData_; 85 elfData_ = nullptr; 86 return; 87 } 88} 89 90ElfChecker::ElfChecker(const std::string& path) : elfErrorCode_(0), fromMmap_(false) 91{ 92 if (!panda::ecmascript::FileExist(path.c_str())) { 93 elfData_ = nullptr; 94 elfLen_ = 0; 95 return; 96 } 97 std::ifstream file(path, std::ios::binary | std::ios::ate); 98 if (file.is_open() == false) { 99 elfData_ = nullptr; 100 elfLen_ = 0; 101 return; 102 } 103 elfLen_ = static_cast<size_t>(file.tellg()); 104 file.seekg(0, std::ios::beg); 105 if (elfLen_ <= 0) { 106 elfData_ = nullptr; 107 return; 108 } 109 elfData_ = new char[elfLen_]; 110 file.read(elfData_, elfLen_); 111 return; 112} 113 114ElfChecker::ElfChecker(const MemMap& mem) : elfErrorCode_(0), fromMmap_(true) 115{ 116 elfData_ = reinterpret_cast<char*>(mem.GetMem()); 117 elfLen_ = mem.GetSize(); 118 if (elfLen_ == 0) { 119 elfData_ = nullptr; 120 } 121} 122 123bool ElfChecker::CheckValidElf() 124{ 125 if (elfData_ == nullptr || elfLen_ <= 0) { 126 return false; 127 } 128 Elf* elf = ElfMemory(elfData_, elfLen_); 129 if (elf == nullptr || elf->kind == ELF_KIND_NONE || CheckIfError() == false) { 130 ElfRelease(elf); 131 return false; 132 } 133 int release_num = ElfRelease(elf); 134 if (release_num != 0 || CheckIfError() == false) { 135 return false; 136 } 137 return true; 138} 139 140int ElfChecker::CheckIfError() const 141{ 142 if (elfErrorCode_ != ELF_ERR_NOERROR) { 143 return false; 144 } 145 return true; 146} 147 148void ElfChecker::SetErrorCode(int value) 149{ 150 if (value >= 0 && value < ELF_ERR_NUM) { 151 elfErrorCode_ = value; 152 } else { 153 elfErrorCode_ = ELF_ERR_UNKNOWN_ERROR; 154 } 155} 156 157ElfChecker::Elf* ElfChecker::ElfAllocate( 158 void* mapAddress, int64_t offset, size_t maxsize, ElfCommand cmd, Elf* parent, ElfKind kind, size_t extra) 159{ 160 size_t alloc_size = sizeof(Elf) + extra; 161 Elf* result = reinterpret_cast<Elf*>(new char[alloc_size]()); 162 if (result == nullptr) { 163 SetErrorCode(ELF_ERR_NOMEM); 164 } else { 165 result->kind = kind; 166 result->refCount = 1; 167 result->cmd = cmd; 168 result->startOffset = offset; 169 result->maxSize = maxsize; 170 result->mapAddress = mapAddress; 171 result->parent = parent; 172 } 173 174 return result; 175} 176 177ElfChecker::ElfKind ElfChecker::GetElfKind(void* buf) const 178{ 179 /* Could be an ELF file. */ 180 int eclass = (int)(reinterpret_cast<unsigned char*>(buf))[llvm::ELF::EI_CLASS]; 181 int data = (int)(reinterpret_cast<unsigned char*>(buf))[llvm::ELF::EI_DATA]; 182 int version = (int)(reinterpret_cast<unsigned char*>(buf))[llvm::ELF::EI_VERSION]; 183 184 if (eclass > llvm::ELF::ELFCLASSNONE && eclass <= llvm::ELF::ELFCLASS64 && data > llvm::ELF::ELFDATANONE && 185 data <= llvm::ELF::ELFDATA2MSB && version == llvm::ELF::EV_CURRENT) { 186 return ELF_KIND_ELF; 187 } 188 189 /* We do not know this file type. */ 190 return ELF_KIND_NONE; 191} 192 193/* Get the number of sections from the ELF header. */ 194template <typename FromElfHeader, typename FromElfSectionHeader, typename SizeType> 195size_t ElfChecker::GetSectionHeaderNum( 196 FromElfHeader* ehdr, size_t maxsize, unsigned char* eIdent, void* mapAddress, int64_t offset) 197{ 198 size_t result = ehdr->e_shnum; 199 if (SECUREC_UNLIKELY(result == 0) && ehdr->e_shoff != 0) { 200 if (SECUREC_UNLIKELY(ehdr->e_shoff >= maxsize) || 201 SECUREC_UNLIKELY(maxsize - ehdr->e_shoff < sizeof(FromElfSectionHeader))) { 202 return 0; 203 } 204 SizeType size; 205 FromElfSectionHeader* dest = 206 reinterpret_cast<FromElfSectionHeader*>(reinterpret_cast<char*>(mapAddress) + ehdr->e_shoff + offset); 207 if (eIdent[llvm::ELF::EI_DATA] == ELF_BYTEORDER && CheckAlign<FromElfSectionHeader>(dest) == true) { 208 /* We can directly access the memory. */ 209 size = dest->sh_size; 210 } else { 211 char* memSrc = 212 reinterpret_cast<char*>(mapAddress) + ehdr->e_shoff + offset + offsetof(FromElfSectionHeader, sh_size); 213 if (memcpy_s(&size, sizeof(size), memSrc, sizeof(SizeType)) != 0) { 214 SetErrorCode(ELF_ERR_NOMEM); 215 return 0; 216 } 217 218 if (eIdent[llvm::ELF::EI_DATA] != ELF_BYTEORDER) { 219 ByteSwap(size); 220 } 221 if (size > ~((llvm::ELF::Elf64_Word)0)) { 222 /* Invalid value, it is too large. */ 223 SetErrorCode(ELF_ERR_INVALID_ELF); 224 return 0; 225 } 226 } 227 result = size; 228 } 229 230 /* If the section headers were truncated, pretend none were there. 231 */ 232 if (ehdr->e_shoff > maxsize || maxsize - ehdr->e_shoff < sizeof(FromElfSectionHeader) * result) { 233 result = 0; 234 } 235 return result; 236} 237 238/* Get Section Header Number */ 239size_t ElfChecker::GetShnum(void* mapAddress, unsigned char* eIdent, int64_t offset, size_t maxsize) 240{ 241 union { 242 llvm::ELF::Elf32_Ehdr* e32; 243 llvm::ELF::Elf64_Ehdr* e64; 244 void* p; 245 } ehdrPtr; 246 union { 247 llvm::ELF::Elf32_Ehdr e32; 248 llvm::ELF::Elf64_Ehdr e64; 249 } ehdrMem; 250 bool is32 = eIdent[llvm::ELF::EI_CLASS] == llvm::ELF::ELFCLASS32; 251 252 if ((is32 && maxsize < sizeof(llvm::ELF::Elf32_Ehdr)) || (!is32 && maxsize < sizeof(llvm::ELF::Elf64_Ehdr))) { 253 /* Not long enough */ 254 SetErrorCode(ELF_ERR_INVALID_ELF); 255 return 0; 256 } 257 /* Make the ELF header available. */ 258 bool isAligned = (is32 ? CheckAlign<llvm::ELF::Elf32_Ehdr>(eIdent) : CheckAlign<llvm::ELF::Elf64_Ehdr>(eIdent)); 259 if (eIdent[llvm::ELF::EI_DATA] == ELF_BYTEORDER && isAligned) { 260 ehdrPtr.p = eIdent; 261 } else { 262 ehdrPtr.p = &ehdrMem; 263 if (is32) { 264 if (ALLOW_UNALIGNED) { 265 ehdrMem.e32.e_shnum = reinterpret_cast<llvm::ELF::Elf32_Ehdr*>(eIdent)->e_shnum; 266 ehdrMem.e32.e_shoff = reinterpret_cast<llvm::ELF::Elf32_Ehdr*>(eIdent)->e_shoff; 267 } else { 268 if (memcpy_s(&ehdrMem, sizeof(ehdrMem), eIdent, sizeof(llvm::ELF::Elf32_Ehdr)) != 0) { 269 SetErrorCode(ELF_ERR_NOMEM); 270 return 0; 271 }; 272 } 273 274 if (eIdent[llvm::ELF::EI_DATA] != ELF_BYTEORDER) { 275 ByteSwap(ehdrMem.e32.e_shnum); 276 ByteSwap(ehdrMem.e32.e_shoff); 277 } 278 } else { 279 if (ALLOW_UNALIGNED) { 280 ehdrMem.e64.e_shnum = reinterpret_cast<llvm::ELF::Elf64_Ehdr*>(eIdent)->e_shnum; 281 ehdrMem.e64.e_shoff = reinterpret_cast<llvm::ELF::Elf64_Ehdr*>(eIdent)->e_shoff; 282 } else { 283 if (memcpy_s(&ehdrMem, sizeof(ehdrMem), eIdent, sizeof(llvm::ELF::Elf64_Ehdr)) != 0) { 284 SetErrorCode(ELF_ERR_NOMEM); 285 return 0; 286 } 287 }; 288 289 if (eIdent[llvm::ELF::EI_DATA] != ELF_BYTEORDER) { 290 ByteSwap(ehdrMem.e64.e_shnum); 291 ByteSwap(ehdrMem.e64.e_shoff); 292 } 293 } 294 } 295 if (is32) { 296 return GetSectionHeaderNum<llvm::ELF::Elf32_Ehdr, llvm::ELF::Elf32_Shdr, llvm::ELF::Elf32_Word>( 297 ehdrPtr.e32, maxsize, eIdent, mapAddress, offset); 298 } else { 299 return GetSectionHeaderNum<llvm::ELF::Elf64_Ehdr, llvm::ELF::Elf64_Shdr, llvm::ELF::Elf64_Xword>( 300 ehdrPtr.e64, maxsize, eIdent, mapAddress, offset); 301 } 302} 303 304/* Get Details from mapAddress, */ 305template <typename ElfEhdr, typename ElfShdr, typename ElfItemField> 306ElfChecker::Elf* ElfChecker::GetElfItem(ElfItemField& elfItemField, void* mapAddress, unsigned char* eIdent, 307 int64_t offset, size_t maxSize, ElfCommand cmd, size_t scnCnt, Elf* elf) 308{ 309 /* This pointer might not be directly usable if the alignment is 310 not sufficient for the architecture. */ 311 ElfEhdr* ehdr = reinterpret_cast<ElfEhdr*>(reinterpret_cast<char*>(mapAddress) + offset); 312 if (eIdent[llvm::ELF::EI_DATA] == ELF_BYTEORDER && CheckAlign<ElfEhdr>(ehdr)) { 313 /* We can use the mmapped memory. */ 314 elfItemField.ehdr = ehdr; 315 } else { 316 if (memcpy_s(&elfItemField.elfHeaderMem, sizeof(ElfEhdr), eIdent, sizeof(ElfEhdr)) != 0) { 317 SetErrorCode(ELF_ERR_NOMEM); 318 return nullptr; 319 } 320 elfItemField.ehdr = reinterpret_cast<ElfEhdr*>(&elfItemField.elfHeaderMem); 321 if (eIdent[llvm::ELF::EI_DATA] != ELF_BYTEORDER) { 322 ByteSwap(elfItemField.elfHeaderMem.e_type); 323 ByteSwap(elfItemField.elfHeaderMem.e_machine); 324 ByteSwap(elfItemField.elfHeaderMem.e_version); 325 ByteSwap(elfItemField.elfHeaderMem.e_entry); 326 ByteSwap(elfItemField.elfHeaderMem.e_phoff); 327 ByteSwap(elfItemField.elfHeaderMem.e_shoff); 328 ByteSwap(elfItemField.elfHeaderMem.e_flags); 329 ByteSwap(elfItemField.elfHeaderMem.e_ehsize); 330 ByteSwap(elfItemField.elfHeaderMem.e_phentsize); 331 ByteSwap(elfItemField.elfHeaderMem.e_phnum); 332 ByteSwap(elfItemField.elfHeaderMem.e_shentsize); 333 ByteSwap(elfItemField.elfHeaderMem.e_shnum); 334 ByteSwap(elfItemField.elfHeaderMem.e_shstrndx); 335 } 336 } 337 auto elfSHOff = elfItemField.ehdr->e_shoff; 338 if (eIdent[llvm::ELF::EI_DATA] == ELF_BYTEORDER && cmd != ELF_CMD_READ_MMAP && 339 CheckAlign<ElfShdr>(ehdr, elfSHOff)) { 340 if (SECUREC_UNLIKELY(scnCnt > 0 && elfSHOff >= maxSize) || 341 SECUREC_UNLIKELY(maxSize - elfSHOff < scnCnt * sizeof(ElfShdr))) { 342 delete[] reinterpret_cast<char*>(elf); 343 elf = nullptr; 344 SetErrorCode(ELF_ERR_INVALID_ELF); 345 return nullptr; 346 } 347 if (scnCnt > 0) { 348 elfItemField.shdr = reinterpret_cast<ElfShdr*>(reinterpret_cast<char*>(ehdr) + elfSHOff); 349 } 350 for (size_t cnt = 0; cnt < scnCnt; ++cnt) { 351 elfItemField.sections.data()[cnt].index = cnt; 352 elfItemField.sections.data()[cnt].elf = elf; 353 if (std::is_same<ElfShdr, llvm::ELF::Elf32_Shdr>::value) { 354 elfItemField.sections.data()[cnt].shdr.e32 = 355 reinterpret_cast<llvm::ELF::Elf32_Shdr*>(&elfItemField.shdr[cnt]); 356 } else { 357 elfItemField.sections.data()[cnt].shdr.e64 = 358 reinterpret_cast<llvm::ELF::Elf64_Shdr*>(&elfItemField.shdr[cnt]); 359 } 360 361 if (SECUREC_LIKELY(elfItemField.shdr[cnt].sh_offset < maxSize) && 362 SECUREC_LIKELY(elfItemField.shdr[cnt].sh_size <= maxSize - elfItemField.shdr[cnt].sh_offset)) { 363 elfItemField.sections.data()[cnt].rawDataBase = elfItemField.sections.data()[cnt].dataBase = 364 (reinterpret_cast<char*>(mapAddress) + offset + elfItemField.shdr[cnt].sh_offset); 365 } 366 elfItemField.sections.data()[cnt].list = &elfItemField.sections; 367 368 /* If this is a section with an extended index add a 369 reference in the section which uses the extended 370 index. */ 371 if (elfItemField.shdr[cnt].sh_type == llvm::ELF::SHT_SYMTAB_SHNDX && 372 elfItemField.shdr[cnt].sh_link < scnCnt) { 373 elfItemField.sections.data()[elfItemField.shdr[cnt].sh_link] 374 .extendSectionHeaderIndex = static_cast<int>(cnt); 375 } 376 /* Set the own extendSectionHeaderIndex field in case it has not yet 377 been set. */ 378 if (elfItemField.sections.data()[cnt].extendSectionHeaderIndex == 0) { 379 elfItemField.sections.data()[cnt].extendSectionHeaderIndex = -1; 380 } 381 } 382 } else { 383 for (size_t cnt = 0; cnt < scnCnt; ++cnt) { 384 elfItemField.sections.data()[cnt].index = cnt; 385 elfItemField.sections.data()[cnt].elf = elf; 386 elfItemField.sections.data()[cnt].list = &elfItemField.sections; 387 } 388 } 389 390 /* So far only one block with sections. */ 391 elfItemField.sectionLast = &elfItemField.sections; 392 return elf; 393} 394 395/* Create descriptor for ELF file in memory. */ 396ElfChecker::Elf* ElfChecker::FileReadElf( 397 void* mapAddress, unsigned char* eIdent, int64_t offset, size_t maxSize, ElfCommand cmd, Elf* parent) 398{ 399 /* Verify the binary is of the class we can handle. */ 400 if (SECUREC_UNLIKELY((eIdent[llvm::ELF::EI_CLASS] != llvm::ELF::ELFCLASS32 && 401 eIdent[llvm::ELF::EI_CLASS] != llvm::ELF::ELFCLASS64) || 402 (eIdent[llvm::ELF::EI_DATA] != llvm::ELF::ELFDATA2LSB && 403 eIdent[llvm::ELF::EI_DATA] != llvm::ELF::ELFDATA2MSB))) { 404 /* Cannot handle this. */ 405 SetErrorCode(ELF_ERR_INVALID_ELF); 406 return nullptr; 407 } 408 409 size_t scncnt = GetShnum(mapAddress, eIdent, offset, maxSize); 410 if (CheckIfError() == false) { 411 return nullptr; 412 } 413 414 /* Check for too many sections. */ 415 if (eIdent[llvm::ELF::EI_CLASS] == llvm::ELF::ELFCLASS32) { 416 if (scncnt > SIZE_MAX / (sizeof(ElfSectionBase) + sizeof(llvm::ELF::Elf32_Shdr))) { 417 SetErrorCode(ELF_ERR_INVALID_ELF); 418 return nullptr; 419 } 420 } else if (scncnt > SIZE_MAX / (sizeof(ElfSectionBase) + sizeof(llvm::ELF::Elf64_Shdr))) { 421 SetErrorCode(ELF_ERR_INVALID_ELF); 422 return nullptr; 423 } 424 425 /* We can now allocate the memory. Even if there are no section 426 headers, we allocate space for a zeroth section in case we need it 427 later. */ 428 const size_t scnMax = (scncnt ? scncnt : (cmd == ELF_CMD_RDWR || cmd == ELF_CMD_RDWR_MMAP) ? 1 : 0); 429 Elf* elf = ElfAllocate(mapAddress, offset, maxSize, cmd, parent, ELF_KIND_ELF, scnMax * sizeof(ElfSectionBase)); 430 if (elf == nullptr) { 431 return nullptr; 432 } 433 434 ASSERT((unsigned int)scncnt == scncnt); 435 ASSERT(offsetof(Elf, state.elf32.sections) == offsetof(Elf, state.elf64.sections)); 436 elf->state.elf32.sections.cnt = scncnt; 437 elf->state.elf32.sections.max = scnMax; 438 439 /* Make the class easily available. */ 440 elf->binaryClass = eIdent[llvm::ELF::EI_CLASS]; 441 442 if (eIdent[llvm::ELF::EI_CLASS] == llvm::ELF::ELFCLASS32) { 443 return GetElfItem<llvm::ELF::Elf32_Ehdr, llvm::ELF::Elf32_Shdr, decltype(elf->state.elf32)>( 444 elf->state.elf32, mapAddress, eIdent, offset, maxSize, cmd, scncnt, elf); 445 } else { 446 return GetElfItem<llvm::ELF::Elf64_Ehdr, llvm::ELF::Elf64_Shdr, decltype(elf->state.elf64)>( 447 elf->state.elf64, mapAddress, eIdent, offset, maxSize, cmd, scncnt, elf); 448 } 449} 450 451ElfChecker::Elf* ElfChecker::ReadMmapedFile( 452 void* mapAddress, int64_t offset, size_t maxsize, ElfCommand cmd, Elf* parent) 453{ 454 unsigned char* eIdent = reinterpret_cast<unsigned char*>(mapAddress) + offset; 455 /* See what kind of object we have here. */ 456 ElfKind kind = GetElfKind(eIdent); 457 if (kind == ELF_KIND_ELF) { 458 return FileReadElf(mapAddress, eIdent, offset, maxsize, cmd, parent); 459 } else { 460 return ElfAllocate(mapAddress, offset, maxsize, cmd, parent, ELF_KIND_NONE, 0); 461 } 462} 463 464ElfChecker::Elf* ElfChecker::ElfMemory(char* image, size_t size) 465{ 466 if (image == nullptr) { 467 SetErrorCode(ELF_ERR_INVALID_OPERAND); 468 return nullptr; 469 } 470 return ReadMmapedFile(image, 0, size, ELF_CMD_READ, nullptr); 471} 472 473int ElfChecker::ElfRelease(Elf* elf) const 474{ 475 if (elf == nullptr) { 476 return 0; 477 } 478 if (elf->refCount != 0) { 479 --elf->refCount; 480 if (elf->refCount != 0) { 481 int result = elf->refCount; 482 return result; 483 } 484 } 485 Elf* parent = elf->parent; 486 delete[] reinterpret_cast<char*>(elf); 487 elf = nullptr; 488 return (parent != nullptr && parent->refCount == 0 ? ElfRelease(parent) : 0); 489} 490 491ElfChecker::~ElfChecker() 492{ 493 if (fromMmap_ == false && elfData_ != nullptr) { 494 delete[] elfData_; 495 elfData_ = nullptr; 496 } 497} 498} // namespace panda::ecmascript 499