From 0ef3f65e34e4046eaee2ccfb329baaeb5b5191ac Mon Sep 17 00:00:00 2001 From: Simon Evans Date: Sat, 14 Jan 2017 23:18:53 +0000 Subject: [PATCH] [runtime] StaticBinaryELF safety fixes --- stdlib/public/runtime/StaticBinaryELF.cpp | 55 ++++++++++++++--------- 1 file changed, 34 insertions(+), 21 deletions(-) diff --git a/stdlib/public/runtime/StaticBinaryELF.cpp b/stdlib/public/runtime/StaticBinaryELF.cpp index e61570f279f..5b3a0a84309 100644 --- a/stdlib/public/runtime/StaticBinaryELF.cpp +++ b/stdlib/public/runtime/StaticBinaryELF.cpp @@ -17,7 +17,10 @@ #if defined(__ELF__) && defined(__linux__) #include "ImageInspection.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" +#include "swift/Basic/Lazy.h" +#include #include #include #include @@ -25,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -54,7 +58,7 @@ typedef Elf32_Section Elf_Section; #define ELF_ST_TYPE(x) ELF32_ST_TYPE(x) #endif -extern const Elf_Ehdr __ehdr_start; +extern const Elf_Ehdr elfHeader asm("__ehdr_start"); class StaticBinaryELF { @@ -70,6 +74,7 @@ private: if (fd < 0 || offset + length > fileSize) { mapping = nullptr; mapLength = 0; + diff = 0; return; } long pageSize = sysconf(_SC_PAGESIZE); @@ -78,7 +83,7 @@ private: off_t alignedOffset = offset & pageMask; diff = (offset - alignedOffset); mapLength = diff + length; - mapping = mmap(nullptr, mapLength, PROT_READ, MAP_SHARED, fd, + mapping = mmap(nullptr, mapLength, PROT_READ, MAP_PRIVATE, fd, alignedOffset); if (mapping == MAP_FAILED) { mapping = nullptr; @@ -87,8 +92,11 @@ private: } template - T data() { - return reinterpret_cast(reinterpret_cast(mapping) + diff); + const ArrayRef data() { + size_t elements = (mapLength - diff) / sizeof(T); + const T *data = reinterpret_cast(reinterpret_cast(mapping) + + diff); + return ArrayRef(data, elements); } ~Mapping() { @@ -99,7 +107,6 @@ private: }; string fullPathName; - const Elf_Ehdr *elfHeader = &__ehdr_start; const Elf_Phdr *programHeaders = nullptr; const Elf_Shdr *symbolTable = nullptr; const Elf_Shdr *stringTable = nullptr; @@ -109,18 +116,21 @@ private: public: StaticBinaryELF() { - programHeaders = reinterpret_cast(elfHeader + - elfHeader->e_phoff); + getExecutablePathName(); + programHeaders = reinterpret_cast(getauxval(AT_PHDR)); + if (programHeaders == nullptr) { + return; + } // If a interpreter is set in the program headers then this is a // dynamic executable and therefore not valid. - for (size_t idx = 0; idx < elfHeader->e_phnum; idx++) { + for (size_t idx = 0; idx < elfHeader.e_phnum; idx++) { if (programHeaders[idx].p_type == PT_INTERP) { + programHeaders = nullptr; return; } } - getExecutablePathName(); if (!fullPathName.empty()) { mmapExecutable(); } @@ -140,7 +150,7 @@ public: if (programHeaders) { auto searchAddr = reinterpret_cast(addr); - for (size_t idx = 0; idx < elfHeader->e_phnum; idx++) { + for (size_t idx = 0; idx < elfHeader.e_phnum; idx++) { auto header = &programHeaders[idx]; if (header->p_type == PT_LOAD && searchAddr >= header->p_vaddr && searchAddr <= (header->p_vaddr + header->p_memsz)) { @@ -155,10 +165,9 @@ public: const Elf_Sym *findSymbol(const void *addr) { if (symbolTable) { auto searchAddr = reinterpret_cast(addr); - auto entries = symbolTable->sh_size / symbolTable->sh_entsize; - auto symbols = symbolTableData->data(); + const ArrayRef symbols = symbolTableData->data(); - for (decltype(entries) idx = 0; idx < entries; idx++) { + for (size_t idx = 0; idx < symbols.size(); idx++) { auto symbol = &symbols[idx]; if (ELF_ST_TYPE(symbol->st_info) == STT_FUNC && searchAddr >= symbol->st_value @@ -172,7 +181,8 @@ public: const char *symbolName(const Elf_Sym *symbol) { if (stringTable && symbol->st_name < stringTable->sh_size) { - return stringTableData->data() + symbol->st_name; + const ArrayRef strings = stringTableData->data(); + return &strings[symbol->st_name]; } return nullptr; } @@ -184,7 +194,7 @@ private: // file anyway. Dont use /proc/self/exe as the symlink will be removed // if the main thread terminates - see proc(5). void getExecutablePathName() { - uintptr_t address = (uintptr_t)&__ehdr_start; + uintptr_t address = (uintptr_t)&elfHeader; FILE *fp = fopen("/proc/self/maps", "r"); if (!fp) { @@ -242,12 +252,13 @@ private: } // Map in the section headers. - size_t sectionHeadersSize = (elfHeader->e_shentsize * elfHeader->e_shnum); - sectionHeaders = new Mapping(fd, buf.st_size, elfHeader->e_shoff, + size_t sectionHeadersSize = (elfHeader.e_shentsize * elfHeader.e_shnum); + sectionHeaders = new Mapping(fd, buf.st_size, elfHeader.e_shoff, sectionHeadersSize); if (sectionHeaders->mapping) { auto section = findSectionHeader(SHT_SYMTAB); if (section) { + assert(section->sh_entsize == sizeof(Elf_Sym)); symbolTableData = new Mapping(fd, buf.st_size, section->sh_offset, section->sh_size); if (symbolTableData->mapping) { @@ -270,9 +281,9 @@ private: // Find the section header of a specified type in the section headers table. const Elf_Shdr *findSectionHeader(Elf_Word sectionType) { if (sectionHeaders && sectionHeaders->mapping) { - auto headers = sectionHeaders->data(); - for (size_t idx = 0; idx < elfHeader->e_shnum; idx++) { - if (idx == elfHeader->e_shstrndx) { + const ArrayRef headers = sectionHeaders->data(); + for (size_t idx = 0; idx < elfHeader.e_shnum; idx++) { + if (idx == elfHeader.e_shstrndx) { continue; } auto header = &headers[idx]; @@ -292,11 +303,13 @@ private: }; +static swift::Lazy TheBinary; + int swift::lookupSymbol(const void *address, SymbolInfo *info) { // The pointers returned point into the mmap()'d binary so keep the // object once instantiated. - static auto binary = StaticBinaryELF(); + auto &binary = TheBinary.get(); info->fileName = binary.getPathName(); info->baseAddress = binary.getSectionLoadAddress(address);