Serenity Operating System
at portability 414 lines 15 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 <AK/StringBuilder.h> 28#include <LibELF/ELFImage.h> 29 30ELFImage::ELFImage(const u8* buffer, size_t size) 31 : m_buffer(buffer) 32 , m_size(size) 33{ 34 m_valid = parse(); 35} 36 37ELFImage::~ELFImage() 38{ 39} 40 41static const char* object_file_type_to_string(Elf32_Half type) 42{ 43 switch (type) { 44 case ET_NONE: 45 return "None"; 46 case ET_REL: 47 return "Relocatable"; 48 case ET_EXEC: 49 return "Executable"; 50 case ET_DYN: 51 return "Shared object"; 52 case ET_CORE: 53 return "Core"; 54 default: 55 return "(?)"; 56 } 57} 58 59StringView ELFImage::section_index_to_string(unsigned index) const 60{ 61 if (index == SHN_UNDEF) 62 return "Undefined"; 63 if (index >= SHN_LORESERVE) 64 return "Reserved"; 65 return section(index).name(); 66} 67 68unsigned ELFImage::symbol_count() const 69{ 70 return section(m_symbol_table_section_index).entry_count(); 71} 72 73void ELFImage::dump() const 74{ 75 dbgprintf("ELFImage{%p} {\n", this); 76 dbgprintf(" is_valid: %u\n", is_valid()); 77 78 if (!is_valid()) { 79 dbgprintf("}\n"); 80 return; 81 } 82 83 dbgprintf(" type: %s\n", object_file_type_to_string(header().e_type)); 84 dbgprintf(" machine: %u\n", header().e_machine); 85 dbgprintf(" entry: %x\n", header().e_entry); 86 dbgprintf(" shoff: %u\n", header().e_shoff); 87 dbgprintf(" shnum: %u\n", header().e_shnum); 88 dbgprintf(" phoff: %u\n", header().e_phoff); 89 dbgprintf(" phnum: %u\n", header().e_phnum); 90 dbgprintf(" shstrndx: %u\n", header().e_shstrndx); 91 92 for_each_program_header([&](const ProgramHeader& program_header) { 93 dbgprintf(" Program Header %d: {\n", program_header.index()); 94 dbgprintf(" type: %x\n", program_header.type()); 95 dbgprintf(" offset: %x\n", program_header.offset()); 96 dbgprintf(" flags: %x\n", program_header.flags()); 97 dbgprintf(" \n"); 98 dbgprintf(" }\n"); 99 }); 100 101 for (unsigned i = 0; i < header().e_shnum; ++i) { 102 auto& section = this->section(i); 103 dbgprintf(" Section %u: {\n", i); 104 dbgprintf(" name: %s\n", section.name()); 105 dbgprintf(" type: %x\n", section.type()); 106 dbgprintf(" offset: %x\n", section.offset()); 107 dbgprintf(" size: %u\n", section.size()); 108 dbgprintf(" \n"); 109 dbgprintf(" }\n"); 110 } 111 112 dbgprintf("Symbol count: %u (table is %u)\n", symbol_count(), m_symbol_table_section_index); 113 for (unsigned i = 1; i < symbol_count(); ++i) { 114 auto& sym = symbol(i); 115 dbgprintf("Symbol @%u:\n", i); 116 dbgprintf(" Name: %s\n", sym.name()); 117 dbgprintf(" In section: %s\n", section_index_to_string(sym.section_index())); 118 dbgprintf(" Value: %x\n", sym.value()); 119 dbgprintf(" Size: %u\n", sym.size()); 120 } 121 122 dbgprintf("}\n"); 123} 124 125unsigned ELFImage::section_count() const 126{ 127 return header().e_shnum; 128} 129 130unsigned ELFImage::program_header_count() const 131{ 132 return header().e_phnum; 133} 134 135bool ELFImage::parse() 136{ 137 if (!validate_elf_header(header(), m_size)) { 138 dbgputstr("ELFImage::parse(): ELF Header not valid\n"); 139 return false; 140 } 141 142 // First locate the string tables. 143 for (unsigned i = 0; i < section_count(); ++i) { 144 auto& sh = section_header(i); 145 if (sh.sh_type == SHT_SYMTAB) { 146 ASSERT(!m_symbol_table_section_index || m_symbol_table_section_index == i); 147 m_symbol_table_section_index = i; 148 } 149 if (sh.sh_type == SHT_STRTAB && i != header().e_shstrndx) { 150 if (section_header_table_string(sh.sh_name) == ELF_STRTAB) 151 m_string_table_section_index = i; 152 } 153 } 154 155 // Then create a name-to-index map. 156 for (unsigned i = 0; i < section_count(); ++i) { 157 auto& section = this->section(i); 158 m_sections.set(section.name(), move(i)); 159 } 160 161 return true; 162} 163 164StringView ELFImage::table_string(unsigned table_index, unsigned offset) const 165{ 166 auto& sh = section_header(table_index); 167 if (sh.sh_type != SHT_STRTAB) 168 return nullptr; 169 size_t computed_offset = sh.sh_offset + offset; 170 if (computed_offset >= m_size) { 171 dbgprintf("SHENANIGANS! ELFImage::table_string() computed offset outside image.\n"); 172 return {}; 173 } 174 size_t max_length = m_size - computed_offset; 175 size_t length = strnlen(raw_data(sh.sh_offset + offset), max_length); 176 return { raw_data(sh.sh_offset + offset), length }; 177} 178 179StringView ELFImage::section_header_table_string(unsigned offset) const 180{ 181 return table_string(header().e_shstrndx, offset); 182} 183 184StringView ELFImage::table_string(unsigned offset) const 185{ 186 return table_string(m_string_table_section_index, offset); 187} 188 189const char* ELFImage::raw_data(unsigned offset) const 190{ 191 return reinterpret_cast<const char*>(m_buffer) + offset; 192} 193 194const Elf32_Ehdr& ELFImage::header() const 195{ 196 return *reinterpret_cast<const Elf32_Ehdr*>(raw_data(0)); 197} 198 199const Elf32_Phdr& ELFImage::program_header_internal(unsigned index) const 200{ 201 ASSERT(index < header().e_phnum); 202 return *reinterpret_cast<const Elf32_Phdr*>(raw_data(header().e_phoff + (index * sizeof(Elf32_Phdr)))); 203} 204 205const Elf32_Shdr& ELFImage::section_header(unsigned index) const 206{ 207 ASSERT(index < header().e_shnum); 208 return *reinterpret_cast<const Elf32_Shdr*>(raw_data(header().e_shoff + (index * header().e_shentsize))); 209} 210 211const ELFImage::Symbol ELFImage::symbol(unsigned index) const 212{ 213 ASSERT(index < symbol_count()); 214 auto* raw_syms = reinterpret_cast<const Elf32_Sym*>(raw_data(section(m_symbol_table_section_index).offset())); 215 return Symbol(*this, index, raw_syms[index]); 216} 217 218const ELFImage::Section ELFImage::section(unsigned index) const 219{ 220 ASSERT(index < section_count()); 221 return Section(*this, index); 222} 223 224const ELFImage::ProgramHeader ELFImage::program_header(unsigned index) const 225{ 226 ASSERT(index < program_header_count()); 227 return ProgramHeader(*this, index); 228} 229 230const ELFImage::Relocation ELFImage::RelocationSection::relocation(unsigned index) const 231{ 232 ASSERT(index < relocation_count()); 233 auto* rels = reinterpret_cast<const Elf32_Rel*>(m_image.raw_data(offset())); 234 return Relocation(m_image, rels[index]); 235} 236 237const ELFImage::RelocationSection ELFImage::Section::relocations() const 238{ 239 StringBuilder builder; 240 builder.append(".rel"); 241 builder.append(name()); 242 243 auto relocation_section = m_image.lookup_section(builder.to_string()); 244 if (relocation_section.type() != SHT_REL) 245 return static_cast<const RelocationSection>(m_image.section(0)); 246 247#ifdef ELFIMAGE_DEBUG 248 dbgprintf("Found relocations for %s in %s\n", name(), relocation_section.name()); 249#endif 250 return static_cast<const RelocationSection>(relocation_section); 251} 252 253const ELFImage::Section ELFImage::lookup_section(const String& name) const 254{ 255 if (auto it = m_sections.find(name); it != m_sections.end()) 256 return section((*it).value); 257 return section(0); 258} 259 260bool ELFImage::validate_elf_header(const Elf32_Ehdr& elf_header, size_t file_size) 261{ 262 if (!IS_ELF(elf_header)) { 263 dbgputstr("File is not an ELF file.\n"); 264 return false; 265 } 266 267 if (ELFCLASS32 != elf_header.e_ident[EI_CLASS]) { 268 dbgputstr("File is not a 32 bit ELF file.\n"); 269 return false; 270 } 271 272 if (ELFDATA2LSB != elf_header.e_ident[EI_DATA]) { 273 dbgputstr("File is not a little endian ELF file.\n"); 274 return false; 275 } 276 277 if (EV_CURRENT != elf_header.e_ident[EI_VERSION]) { 278 dbgprintf("File has unrecognized ELF version (%d), expected (%d)!\n", elf_header.e_ident[EI_VERSION], EV_CURRENT); 279 return false; 280 } 281 282 if (ELFOSABI_SYSV != elf_header.e_ident[EI_OSABI]) { 283 dbgprintf("File has unknown OS ABI (%d), expected SYSV(0)!\n", elf_header.e_ident[EI_OSABI]); 284 return false; 285 } 286 287 if (0 != elf_header.e_ident[EI_ABIVERSION]) { 288 dbgprintf("File has unknown SYSV ABI version (%d)!\n", elf_header.e_ident[EI_ABIVERSION]); 289 return false; 290 } 291 292 if (EM_386 != elf_header.e_machine) { 293 dbgprintf("File has unknown machine (%d), expected i386 (3)!\n", elf_header.e_machine); 294 return false; 295 } 296 297 if (ET_EXEC != elf_header.e_type && ET_DYN != elf_header.e_type && ET_REL != elf_header.e_type) { 298 dbgprintf("File has unloadable ELF type (%d), expected REL (1), EXEC (2) or DYN (3)!\n", elf_header.e_type); 299 return false; 300 } 301 302 if (EV_CURRENT != elf_header.e_version) { 303 dbgprintf("File has unrecognized ELF version (%d), expected (%d)!\n", elf_header.e_version, EV_CURRENT); 304 return false; 305 } 306 307 if (sizeof(Elf32_Ehdr) != elf_header.e_ehsize) { 308 dbgprintf("File has incorrect ELF header size..? (%d), expected (%d)!\n", elf_header.e_ehsize, sizeof(Elf32_Ehdr)); 309 return false; 310 } 311 312 if (elf_header.e_phoff > file_size || elf_header.e_shoff > file_size) { 313 dbgprintf("SHENANIGANS! program header offset (%d) or section header offset (%d) are past the end of the file!\n", 314 elf_header.e_phoff, elf_header.e_shoff); 315 return false; 316 } 317 318 if (elf_header.e_phnum != 0 && elf_header.e_phoff != elf_header.e_ehsize) { 319 dbgprintf("File does not have program headers directly after the ELF header? program header offset (%d), expected (%d).\n", 320 elf_header.e_phoff, elf_header.e_ehsize); 321 return false; 322 } 323 324 if (0 != elf_header.e_flags) { 325 dbgprintf("File has incorrect ELF header flags...? (%d), expected (%d).\n", elf_header.e_flags, 0); 326 return false; 327 } 328 329 if (0 != elf_header.e_phnum && sizeof(Elf32_Phdr) != elf_header.e_phentsize) { 330 dbgprintf("File has incorrect program header size..? (%d), expected (%d).\n", elf_header.e_phentsize, sizeof(Elf32_Phdr)); 331 return false; 332 } 333 334 if (sizeof(Elf32_Shdr) != elf_header.e_shentsize) { 335 dbgprintf("File has incorrect section header size..? (%d), expected (%d).\n", elf_header.e_shentsize, sizeof(Elf32_Shdr)); 336 return false; 337 } 338 339 size_t end_of_last_program_header = elf_header.e_phoff + (elf_header.e_phnum * elf_header.e_phentsize); 340 if (end_of_last_program_header > file_size) { 341 dbgprintf("SHENANIGANS! End of last program header (%d) is past the end of the file!\n", end_of_last_program_header); 342 return false; 343 } 344 345 size_t end_of_last_section_header = elf_header.e_shoff + (elf_header.e_shnum * elf_header.e_shentsize); 346 if (end_of_last_section_header > file_size) { 347 dbgprintf("SHENANIGANS! End of last section header (%d) is past the end of the file!\n", end_of_last_section_header); 348 return false; 349 } 350 351 if (elf_header.e_shstrndx >= elf_header.e_shnum) { 352 dbgprintf("SHENANIGANS! Section header string table index (%d) is not a valid index given we have %d section headers!\n", elf_header.e_shstrndx, elf_header.e_shnum); 353 return false; 354 } 355 356 return true; 357} 358 359bool ELFImage::validate_program_headers(const Elf32_Ehdr& elf_header, size_t file_size, u8* buffer, size_t buffer_size, String& interpreter_path) 360{ 361 // Can we actually parse all the program headers in the given buffer? 362 size_t end_of_last_program_header = elf_header.e_phoff + (elf_header.e_phnum * elf_header.e_phentsize); 363 if (end_of_last_program_header > buffer_size) { 364 dbgprintf("Unable to parse program headers from buffer, buffer too small! Buffer size: %zu, End of program headers %zu\n", 365 buffer_size, end_of_last_program_header); 366 return false; 367 } 368 369 if (file_size < buffer_size) { 370 dbgputstr("We somehow read more from a file than was in the file in the first place!\n"); 371 ASSERT_NOT_REACHED(); 372 } 373 374 size_t num_program_headers = elf_header.e_phnum; 375 auto program_header_begin = (const Elf32_Phdr*)&(buffer[elf_header.e_phoff]); 376 377 for (size_t header_index = 0; header_index < num_program_headers; ++header_index) { 378 auto& program_header = program_header_begin[header_index]; 379 switch (program_header.p_type) { 380 case PT_INTERP: 381 if (ET_DYN != elf_header.e_type) { 382 dbgprintf("Found PT_INTERP header (%d) in non-DYN ELF object! What? We can't handle this!\n", header_index); 383 return false; 384 } 385 // We checked above that file_size was >= buffer size. We only care about buffer size anyway, we're trying to read this! 386 if (program_header.p_offset + program_header.p_filesz > buffer_size) { 387 dbgprintf("Found PT_INTERP header (%d), but the .interp section was not within our buffer :( Your program will not be loaded today.\n", header_index); 388 return false; 389 } 390 interpreter_path = String((const char*)&buffer[program_header.p_offset], program_header.p_filesz - 1); 391 break; 392 case PT_LOAD: 393 case PT_DYNAMIC: 394 case PT_NOTE: 395 case PT_PHDR: 396 case PT_TLS: 397 if (program_header.p_offset + program_header.p_filesz > file_size) { 398 dbgprintf("SHENANIGANS! Program header %d segment leaks beyond end of file!\n", header_index); 399 return false; 400 } 401 if ((program_header.p_flags & PF_X) && (program_header.p_flags & PF_W)) { 402 dbgprintf("SHENANIGANS! Program header %d segment is marked write and execute\n", header_index); 403 return false; 404 } 405 break; 406 default: 407 // Not handling other program header types in other code so... let's not surprise them 408 dbgprintf("Found program header (%d) of unrecognized type %d!\n", header_index, program_header.p_type); 409 ASSERT_NOT_REACHED(); 410 break; 411 } 412 } 413 return true; 414}