status_t ElfFile::_LoadFile(const char* fileName) { typedef typename ElfClass::Ehdr Ehdr; typedef typename ElfClass::Phdr Phdr; typedef typename ElfClass::Shdr Shdr; // read the elf header Ehdr elfHeader; ssize_t bytesRead = pread(fFD, &elfHeader, sizeof(elfHeader), 0); if (bytesRead != (ssize_t)sizeof(elfHeader)) return bytesRead < 0 ? errno : B_ERROR; // check the ELF header if (!_CheckRange(0, sizeof(elfHeader)) || !_CheckElfHeader<ElfClass>(elfHeader)) { WARNING("\"%s\": Not a valid ELF file\n", fileName); return B_BAD_DATA; } fType = Get(elfHeader.e_type); fMachine = Get(elfHeader.e_machine); if (Get(elfHeader.e_shnum) > 0) { // check section header table values uint64 sectionHeadersOffset = Get(elfHeader.e_shoff); size_t sectionHeaderSize = Get(elfHeader.e_shentsize); int sectionCount = Get(elfHeader.e_shnum); size_t sectionHeaderTableSize = sectionHeaderSize * sectionCount; if (!_CheckRange(sectionHeadersOffset, sectionHeaderTableSize)) { WARNING("\"%s\": Invalid ELF header\n", fileName); return B_BAD_DATA; } // read the section header table uint8* sectionHeaderTable = (uint8*)malloc(sectionHeaderTableSize); if (sectionHeaderTable == NULL) return B_NO_MEMORY; MemoryDeleter sectionHeaderTableDeleter(sectionHeaderTable); bytesRead = pread(fFD, sectionHeaderTable, sectionHeaderTableSize, sectionHeadersOffset); if (bytesRead != (ssize_t)sectionHeaderTableSize) return bytesRead < 0 ? errno : B_ERROR; // check and get the section header string section Shdr* stringSectionHeader = (Shdr*)(sectionHeaderTable + Get(elfHeader.e_shstrndx) * sectionHeaderSize); if (!_CheckRange(Get(stringSectionHeader->sh_offset), Get(stringSectionHeader->sh_size))) { WARNING("\"%s\": Invalid string section header\n", fileName); return B_BAD_DATA; } size_t sectionStringSize = Get(stringSectionHeader->sh_size); ElfSection* sectionStringSection = new(std::nothrow) ElfSection( ".shstrtab", Get(stringSectionHeader->sh_type),fFD, Get(stringSectionHeader->sh_offset), sectionStringSize, Get(stringSectionHeader->sh_addr), Get(stringSectionHeader->sh_flags), Get(stringSectionHeader->sh_link)); if (sectionStringSection == NULL) return B_NO_MEMORY; if (!fSections.AddItem(sectionStringSection)) { delete sectionStringSection; return B_NO_MEMORY; } status_t error = sectionStringSection->Load(); if (error != B_OK) return error; const char* sectionStrings = (const char*)sectionStringSection->Data(); // read the other sections for (int i = 0; i < sectionCount; i++) { Shdr* sectionHeader = (Shdr*)(sectionHeaderTable + i * sectionHeaderSize); // skip invalid sections and the section header string section const char* name = sectionStrings + Get(sectionHeader->sh_name); if (Get(sectionHeader->sh_name) >= sectionStringSize || !_CheckRange(Get(sectionHeader->sh_offset), Get(sectionHeader->sh_size)) || i == Get(elfHeader.e_shstrndx)) { continue; } // create an ElfSection ElfSection* section = new(std::nothrow) ElfSection(name, Get(sectionHeader->sh_type), fFD, Get(sectionHeader->sh_offset), Get(sectionHeader->sh_size), Get(sectionHeader->sh_addr), Get(sectionHeader->sh_flags), Get(sectionHeader->sh_link)); if (section == NULL) return B_NO_MEMORY; if (!fSections.AddItem(section)) { delete section; return B_NO_MEMORY; } } } if (Get(elfHeader.e_phnum) > 0) { // check program header table values uint64 programHeadersOffset = Get(elfHeader.e_phoff); size_t programHeaderSize = Get(elfHeader.e_phentsize); int segmentCount = Get(elfHeader.e_phnum); size_t programHeaderTableSize = programHeaderSize * segmentCount; if (!_CheckRange(programHeadersOffset, programHeaderTableSize)) { WARNING("\"%s\": Invalid ELF header\n", fileName); return B_BAD_DATA; } // read the program header table uint8* programHeaderTable = (uint8*)malloc(programHeaderTableSize); if (programHeaderTable == NULL) return B_NO_MEMORY; MemoryDeleter programHeaderTableDeleter(programHeaderTable); bytesRead = pread(fFD, programHeaderTable, programHeaderTableSize, programHeadersOffset); if (bytesRead != (ssize_t)programHeaderTableSize) return bytesRead < 0 ? errno : B_ERROR; // read the program headers and create ElfSegment objects for (int i = 0; i < segmentCount; i++) { Phdr* programHeader = (Phdr*)(programHeaderTable + i * programHeaderSize); // skip invalid program headers if (Get(programHeader->p_filesz) > 0 && !_CheckRange(Get(programHeader->p_offset), Get(programHeader->p_filesz))) { continue; } // create an ElfSegment ElfSegment* segment = new(std::nothrow) ElfSegment( Get(programHeader->p_type), Get(programHeader->p_offset), Get(programHeader->p_filesz), Get(programHeader->p_vaddr), Get(programHeader->p_memsz), Get(programHeader->p_flags)); if (segment == NULL) return B_NO_MEMORY; if (!fSegments.AddItem(segment)) { delete segment; return B_NO_MEMORY; } } } return B_OK; }
status_t ElfFile::Init(const char* fileName) { // open file fFD = open(fileName, O_RDONLY); if (fFD < 0) { WARNING("Failed to open \"%s\": %s\n", fileName, strerror(errno)); return errno; } // stat() file to get its size struct stat st; if (fstat(fFD, &st) < 0) { WARNING("Failed to stat \"%s\": %s\n", fileName, strerror(errno)); return errno; } fFileSize = st.st_size; // read the elf header fElfHeader = (Elf32_Ehdr*)malloc(sizeof(Elf32_Ehdr)); if (fElfHeader == NULL) return B_NO_MEMORY; ssize_t bytesRead = pread(fFD, fElfHeader, sizeof(Elf32_Ehdr), 0); if (bytesRead != (ssize_t)sizeof(Elf32_Ehdr)) return bytesRead < 0 ? errno : B_ERROR; // check the ELF header if (!_CheckRange(0, sizeof(Elf32_Ehdr)) || !_CheckElfHeader()) { WARNING("\"%s\": Not an ELF file\n", fileName); return B_BAD_DATA; } // check section header table values off_t sectionHeadersOffset = fElfHeader->e_shoff; size_t sectionHeaderSize = fElfHeader->e_shentsize; int sectionCount = fElfHeader->e_shnum; size_t sectionHeaderTableSize = sectionHeaderSize * sectionCount; if (!_CheckRange(sectionHeadersOffset, sectionHeaderTableSize)) { WARNING("\"%s\": Invalid ELF header\n", fileName); return B_BAD_DATA; } // read the section header table uint8* sectionHeaderTable = (uint8*)malloc(sectionHeaderTableSize); if (sectionHeaderTable == NULL) return B_NO_MEMORY; MemoryDeleter sectionHeaderTableDeleter(sectionHeaderTable); bytesRead = pread(fFD, sectionHeaderTable, sectionHeaderTableSize, sectionHeadersOffset); if (bytesRead != (ssize_t)sectionHeaderTableSize) return bytesRead < 0 ? errno : B_ERROR; // check and get the section header string section Elf32_Shdr* stringSectionHeader = (Elf32_Shdr*)(sectionHeaderTable + fElfHeader->e_shstrndx * sectionHeaderSize); if (!_CheckRange(stringSectionHeader->sh_offset, stringSectionHeader->sh_size)) { WARNING("\"%s\": Invalid string section header\n", fileName); return B_BAD_DATA; } size_t sectionStringSize = stringSectionHeader->sh_size; ElfSection* sectionStringSection = new(std::nothrow) ElfSection(".shstrtab", fFD, stringSectionHeader->sh_offset, sectionStringSize, stringSectionHeader->sh_addr, stringSectionHeader->sh_flags); if (sectionStringSection == NULL) return B_NO_MEMORY; fSections.Add(sectionStringSection); status_t error = sectionStringSection->Load(); if (error != B_OK) return error; const char* sectionStrings = (const char*)sectionStringSection->Data(); // read the other sections for (int i = 0; i < sectionCount; i++) { Elf32_Shdr* sectionHeader = (Elf32_Shdr*)(sectionHeaderTable + i * sectionHeaderSize); // skip invalid sections and the section header string section const char* name = sectionStrings + sectionHeader->sh_name; if (sectionHeader->sh_name >= sectionStringSize || !_CheckRange(sectionHeader->sh_offset, sectionHeader->sh_size) || i == fElfHeader->e_shstrndx) { continue; } // create an ElfSection ElfSection* section = new(std::nothrow) ElfSection(name, fFD, sectionHeader->sh_offset, sectionHeader->sh_size, sectionHeader->sh_addr, sectionHeader->sh_flags); if (section == NULL) return B_NO_MEMORY; fSections.Add(section); } // check program header table values off_t programHeadersOffset = fElfHeader->e_phoff; size_t programHeaderSize = fElfHeader->e_phentsize; int segmentCount = fElfHeader->e_phnum; size_t programHeaderTableSize = programHeaderSize * segmentCount; if (!_CheckRange(programHeadersOffset, programHeaderTableSize)) { WARNING("\"%s\": Invalid ELF header\n", fileName); return B_BAD_DATA; } // read the program header table uint8* programHeaderTable = (uint8*)malloc(programHeaderTableSize); if (programHeaderTable == NULL) return B_NO_MEMORY; MemoryDeleter programHeaderTableDeleter(programHeaderTable); bytesRead = pread(fFD, programHeaderTable, programHeaderTableSize, programHeadersOffset); if (bytesRead != (ssize_t)programHeaderTableSize) return bytesRead < 0 ? errno : B_ERROR; // read the program headers and create ElfSegment objects for (int i = 0; i < segmentCount; i++) { Elf32_Phdr* programHeader = (Elf32_Phdr*)(programHeaderTable + i * programHeaderSize); // skip program headers we aren't interested in or that are invalid if (programHeader->p_type != PT_LOAD || programHeader->p_filesz == 0 || programHeader->p_memsz == 0 || !_CheckRange(programHeader->p_offset, programHeader->p_filesz)) { continue; } // create an ElfSegment ElfSegment* segment = new(std::nothrow) ElfSegment( programHeader->p_offset, programHeader->p_filesz, programHeader->p_vaddr, programHeader->p_memsz, (programHeader->p_flags & PF_WRITE) != 0); if (segment == NULL) return B_NO_MEMORY; fSegments.Add(segment); } return B_OK; }