Serenity Operating System
at portability 207 lines 8.1 kB view raw
1/* 2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, this 9 * list of conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above copyright notice, 12 * this list of conditions and the following disclaimer in the documentation 13 * and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#include "ELFLoader.h" 28#include <AK/Demangle.h> 29#include <AK/QuickSort.h> 30 31#ifdef KERNEL 32#include <Kernel/VM/MemoryManager.h> 33#define do_memcpy copy_to_user 34#else 35#define do_memcpy memcpy 36#endif 37 38//#define ELFLOADER_DEBUG 39 40ELFLoader::ELFLoader(const u8* buffer, size_t size) 41 : m_image(buffer, size) 42{ 43} 44 45ELFLoader::~ELFLoader() 46{ 47} 48 49bool ELFLoader::load() 50{ 51#ifdef ELFLOADER_DEBUG 52 m_image.dump(); 53#endif 54 if (!m_image.is_valid()) 55 return false; 56 57 if (!layout()) 58 return false; 59 60 return true; 61} 62 63bool ELFLoader::layout() 64{ 65 bool failed = false; 66 m_image.for_each_program_header([&](const ELFImage::ProgramHeader& program_header) { 67 if (program_header.type() == PT_TLS) { 68#ifdef KERNEL 69 auto* tls_image = tls_section_hook(program_header.size_in_memory(), program_header.alignment()); 70 if (!tls_image) { 71 failed = true; 72 return; 73 } 74 if (!m_image.is_within_image(program_header.raw_data(), program_header.size_in_image())) { 75 dbg() << "Shenanigans! ELF PT_TLS header sneaks outside of executable."; 76 failed = true; 77 return; 78 } 79 do_memcpy(tls_image, program_header.raw_data(), program_header.size_in_image()); 80#endif 81 return; 82 } 83 if (program_header.type() != PT_LOAD) 84 return; 85#ifdef ELFLOADER_DEBUG 86 kprintf("PH: V%p %u r:%u w:%u\n", program_header.vaddr().get(), program_header.size_in_memory(), program_header.is_readable(), program_header.is_writable()); 87#endif 88#ifdef KERNEL 89 if (program_header.is_writable()) { 90 auto* allocated_section = alloc_section_hook( 91 program_header.vaddr(), 92 program_header.size_in_memory(), 93 program_header.alignment(), 94 program_header.is_readable(), 95 program_header.is_writable(), 96 String::format("elf-alloc-%s%s", program_header.is_readable() ? "r" : "", program_header.is_writable() ? "w" : "")); 97 if (!allocated_section) { 98 failed = true; 99 return; 100 } 101 if (!m_image.is_within_image(program_header.raw_data(), program_header.size_in_image())) { 102 dbg() << "Shenanigans! Writable ELF PT_LOAD header sneaks outside of executable."; 103 failed = true; 104 return; 105 } 106 // It's not always the case with PIE executables (and very well shouldn't be) that the 107 // virtual address in the program header matches the one we end up giving the process. 108 // In order to copy the data image correctly into memory, we need to copy the data starting at 109 // the right initial page offset into the pages allocated for the elf_alloc-XX section. 110 // FIXME: There's an opportunity to munmap, or at least mprotect, the padding space between 111 // the .text and .data PT_LOAD sections of the executable. 112 // Accessing it would definitely be a bug. 113 auto page_offset = program_header.vaddr(); 114 page_offset.mask(~PAGE_MASK); 115 do_memcpy((u8*)allocated_section + page_offset.get(), program_header.raw_data(), program_header.size_in_image()); 116 } else { 117 auto* mapped_section = map_section_hook( 118 program_header.vaddr(), 119 program_header.size_in_memory(), 120 program_header.alignment(), 121 program_header.offset(), 122 program_header.is_readable(), 123 program_header.is_writable(), 124 program_header.is_executable(), 125 String::format("elf-map-%s%s%s", program_header.is_readable() ? "r" : "", program_header.is_writable() ? "w" : "", program_header.is_executable() ? "x" : "")); 126 if (!mapped_section) { 127 failed = true; 128 } 129 } 130#endif 131 }); 132 return !failed; 133} 134 135char* ELFLoader::symbol_ptr(const char* name) 136{ 137 char* found_ptr = nullptr; 138 m_image.for_each_symbol([&](const ELFImage::Symbol symbol) { 139 if (symbol.type() != STT_FUNC) 140 return IterationDecision::Continue; 141 if (symbol.name() == name) 142 return IterationDecision::Continue; 143 if (m_image.is_executable()) 144 found_ptr = (char*)(size_t)symbol.value(); 145 else 146 ASSERT_NOT_REACHED(); 147 return IterationDecision::Break; 148 }); 149 return found_ptr; 150} 151 152String ELFLoader::symbolicate(u32 address, u32* out_offset) const 153{ 154 if (!m_image.symbol_count()) { 155 if (out_offset) 156 *out_offset = 0; 157 return "??"; 158 } 159 SortedSymbol* sorted_symbols = nullptr; 160#ifdef KERNEL 161 if (!m_sorted_symbols_region) { 162 m_sorted_symbols_region = MM.allocate_kernel_region(PAGE_ROUND_UP(m_image.symbol_count() * sizeof(SortedSymbol)), "Sorted symbols", Kernel::Region::Access::Read | Kernel::Region::Access::Write); 163 sorted_symbols = (SortedSymbol*)m_sorted_symbols_region->vaddr().as_ptr(); 164 size_t index = 0; 165 m_image.for_each_symbol([&](auto& symbol) { 166 sorted_symbols[index++] = { symbol.value(), symbol.name() }; 167 return IterationDecision::Continue; 168 }); 169 quick_sort(sorted_symbols, sorted_symbols + m_image.symbol_count(), [](auto& a, auto& b) { 170 return a.address < b.address; 171 }); 172 } else { 173 sorted_symbols = (SortedSymbol*)m_sorted_symbols_region->vaddr().as_ptr(); 174 } 175#else 176 if (m_sorted_symbols.is_empty()) { 177 m_sorted_symbols.ensure_capacity(m_image.symbol_count()); 178 m_image.for_each_symbol([this](auto& symbol) { 179 m_sorted_symbols.append({ symbol.value(), symbol.name() }); 180 return IterationDecision::Continue; 181 }); 182 quick_sort(m_sorted_symbols.begin(), m_sorted_symbols.end(), [](auto& a, auto& b) { 183 return a.address < b.address; 184 }); 185 } 186 sorted_symbols = m_sorted_symbols.data(); 187#endif 188 189 for (size_t i = 0; i < m_image.symbol_count(); ++i) { 190 if (sorted_symbols[i].address > address) { 191 if (i == 0) { 192 if (out_offset) 193 *out_offset = 0; 194 return "!!"; 195 } 196 auto& symbol = sorted_symbols[i - 1]; 197 if (out_offset) { 198 *out_offset = address - symbol.address; 199 return demangle(symbol.name); 200 } 201 return String::format("%s +%u", demangle(symbol.name).characters(), address - symbol.address); 202 } 203 } 204 if (out_offset) 205 *out_offset = 0; 206 return "??"; 207}