mirror of
https://github.com/RGBCube/serenity
synced 2025-07-07 20:17:34 +00:00
Lagom+LibELF: Add an ELF fuzzer, and tweak the code to survive a few minutes of fuzzing (#3071)
If a buffer smaller than Elf32_Ehdr was passed to Image, header() would do an out-of-bounds read. Make parse() check for that. Make most Image methods assert that the image is_valid(). For that to work, set m_valid early in Image::parse() instead of only at its end. Also reorder a few things so that the fuzzer doesn't hit (valid) assertions, which were harmless from a security PoV but which still allowed userspace to crash the kernel with an invalid ELF file. Make dbgprintf()s configurable at run time so that the fuzzer doesn't produce lots of logspam.
This commit is contained in:
parent
eaf7e68408
commit
00f658b984
8 changed files with 123 additions and 39 deletions
|
@ -31,99 +31,119 @@
|
|||
|
||||
namespace ELF {
|
||||
|
||||
bool validate_elf_header(const Elf32_Ehdr& elf_header, size_t file_size)
|
||||
bool validate_elf_header(const Elf32_Ehdr& elf_header, size_t file_size, bool verbose)
|
||||
{
|
||||
if (!IS_ELF(elf_header)) {
|
||||
dbgputstr("File is not an ELF file.\n");
|
||||
if (verbose)
|
||||
dbgputstr("File is not an ELF file.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ELFCLASS32 != elf_header.e_ident[EI_CLASS]) {
|
||||
dbgputstr("File is not a 32 bit ELF file.\n");
|
||||
if (verbose)
|
||||
dbgputstr("File is not a 32 bit ELF file.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ELFDATA2LSB != elf_header.e_ident[EI_DATA]) {
|
||||
dbgputstr("File is not a little endian ELF file.\n");
|
||||
if (verbose)
|
||||
dbgputstr("File is not a little endian ELF file.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (EV_CURRENT != elf_header.e_ident[EI_VERSION]) {
|
||||
dbgprintf("File has unrecognized ELF version (%d), expected (%d)!\n", elf_header.e_ident[EI_VERSION], EV_CURRENT);
|
||||
if (verbose)
|
||||
dbgprintf("File has unrecognized ELF version (%d), expected (%d)!\n", elf_header.e_ident[EI_VERSION], EV_CURRENT);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ELFOSABI_SYSV != elf_header.e_ident[EI_OSABI]) {
|
||||
dbgprintf("File has unknown OS ABI (%d), expected SYSV(0)!\n", elf_header.e_ident[EI_OSABI]);
|
||||
if (verbose)
|
||||
dbgprintf("File has unknown OS ABI (%d), expected SYSV(0)!\n", elf_header.e_ident[EI_OSABI]);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (0 != elf_header.e_ident[EI_ABIVERSION]) {
|
||||
dbgprintf("File has unknown SYSV ABI version (%d)!\n", elf_header.e_ident[EI_ABIVERSION]);
|
||||
if (verbose)
|
||||
dbgprintf("File has unknown SYSV ABI version (%d)!\n", elf_header.e_ident[EI_ABIVERSION]);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (EM_386 != elf_header.e_machine) {
|
||||
dbgprintf("File has unknown machine (%d), expected i386 (3)!\n", elf_header.e_machine);
|
||||
if (verbose)
|
||||
dbgprintf("File has unknown machine (%d), expected i386 (3)!\n", elf_header.e_machine);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ET_EXEC != elf_header.e_type && ET_DYN != elf_header.e_type && ET_REL != elf_header.e_type) {
|
||||
dbgprintf("File has unloadable ELF type (%d), expected REL (1), EXEC (2) or DYN (3)!\n", elf_header.e_type);
|
||||
if (verbose)
|
||||
dbgprintf("File has unloadable ELF type (%d), expected REL (1), EXEC (2) or DYN (3)!\n", elf_header.e_type);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (EV_CURRENT != elf_header.e_version) {
|
||||
dbgprintf("File has unrecognized ELF version (%d), expected (%d)!\n", elf_header.e_version, EV_CURRENT);
|
||||
if (verbose)
|
||||
dbgprintf("File has unrecognized ELF version (%d), expected (%d)!\n", elf_header.e_version, EV_CURRENT);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (sizeof(Elf32_Ehdr) != elf_header.e_ehsize) {
|
||||
dbgprintf("File has incorrect ELF header size..? (%d), expected (%zu)!\n", elf_header.e_ehsize, sizeof(Elf32_Ehdr));
|
||||
if (verbose)
|
||||
dbgprintf("File has incorrect ELF header size..? (%d), expected (%zu)!\n", elf_header.e_ehsize, sizeof(Elf32_Ehdr));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (elf_header.e_phoff > file_size || elf_header.e_shoff > file_size) {
|
||||
dbgprintf("SHENANIGANS! program header offset (%d) or section header offset (%d) are past the end of the file!\n",
|
||||
elf_header.e_phoff, elf_header.e_shoff);
|
||||
if (verbose) {
|
||||
dbgprintf("SHENANIGANS! program header offset (%d) or section header offset (%d) are past the end of the file!\n",
|
||||
elf_header.e_phoff, elf_header.e_shoff);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (elf_header.e_phnum != 0 && elf_header.e_phoff != elf_header.e_ehsize) {
|
||||
dbgprintf("File does not have program headers directly after the ELF header? program header offset (%d), expected (%d).\n",
|
||||
elf_header.e_phoff, elf_header.e_ehsize);
|
||||
if (verbose) {
|
||||
dbgprintf("File does not have program headers directly after the ELF header? program header offset (%d), expected (%d).\n",
|
||||
elf_header.e_phoff, elf_header.e_ehsize);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (0 != elf_header.e_flags) {
|
||||
dbgprintf("File has incorrect ELF header flags...? (%d), expected (%d).\n", elf_header.e_flags, 0);
|
||||
if (verbose)
|
||||
dbgprintf("File has incorrect ELF header flags...? (%d), expected (%d).\n", elf_header.e_flags, 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (0 != elf_header.e_phnum && sizeof(Elf32_Phdr) != elf_header.e_phentsize) {
|
||||
dbgprintf("File has incorrect program header size..? (%d), expected (%zu).\n", elf_header.e_phentsize, sizeof(Elf32_Phdr));
|
||||
if (verbose)
|
||||
dbgprintf("File has incorrect program header size..? (%d), expected (%zu).\n", elf_header.e_phentsize, sizeof(Elf32_Phdr));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (sizeof(Elf32_Shdr) != elf_header.e_shentsize) {
|
||||
dbgprintf("File has incorrect section header size..? (%d), expected (%zu).\n", elf_header.e_shentsize, sizeof(Elf32_Shdr));
|
||||
if (verbose)
|
||||
dbgprintf("File has incorrect section header size..? (%d), expected (%zu).\n", elf_header.e_shentsize, sizeof(Elf32_Shdr));
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t end_of_last_program_header = elf_header.e_phoff + (elf_header.e_phnum * elf_header.e_phentsize);
|
||||
if (end_of_last_program_header > file_size) {
|
||||
dbgprintf("SHENANIGANS! End of last program header (%zu) is past the end of the file!\n", end_of_last_program_header);
|
||||
if (verbose)
|
||||
dbgprintf("SHENANIGANS! End of last program header (%zu) is past the end of the file!\n", end_of_last_program_header);
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t end_of_last_section_header = elf_header.e_shoff + (elf_header.e_shnum * elf_header.e_shentsize);
|
||||
if (end_of_last_section_header > file_size) {
|
||||
dbgprintf("SHENANIGANS! End of last section header (%zu) is past the end of the file!\n", end_of_last_section_header);
|
||||
if (verbose)
|
||||
dbgprintf("SHENANIGANS! End of last section header (%zu) is past the end of the file!\n", end_of_last_section_header);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (elf_header.e_shstrndx >= elf_header.e_shnum) {
|
||||
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);
|
||||
if (verbose)
|
||||
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);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue