Kernel: Enforce W^X when loading executables

From now on, if an executable contains segments that
want to be loaded as both writable and executable,
we refuse and abort with ENOEXEC.
This commit is contained in:
apio 2022-11-03 20:28:54 +01:00
parent 2c08de044f
commit e5b2641019

View File

@ -25,6 +25,16 @@ static const char* format_permissions(uint32_t flags)
return perms;
}
static bool can_execute_segment(int flags)
{
return flags & 1;
}
static bool can_write_segment(int flags)
{
return flags & 2;
}
ELFImage* ELFLoader::load_elf_from_filesystem(const char* filename)
{
VFS::Node* node = VFS::resolve_path(filename);
@ -90,6 +100,8 @@ ELFImage* ELFLoader::load_elf_from_vfs(VFS::Node* node)
phdr.p_filesz, phdr.p_memsz, format_permissions(phdr.p_flags));
ensure(phdr.p_vaddr);
ensure(!(can_write_segment(phdr.p_flags) && can_execute_segment(phdr.p_flags)));
uint64_t pages = Utilities::get_blocks_from_size(PAGE_SIZE, (phdr.p_vaddr % PAGE_SIZE) + phdr.p_memsz);
void* buffer = (void*)((uint64_t)MemoryManager::get_pages_at(round_down_to_nearest_page(phdr.p_vaddr),
pages, MAP_READ_WRITE) +
@ -106,8 +118,8 @@ ELFImage* ELFLoader::load_elf_from_vfs(VFS::Node* node)
VMM::switch_to_previous_user_address_space();
int new_flags = MAP_USER | MAP_AS_OWNED_BY_TASK;
if(phdr.p_flags & 2) new_flags |= MAP_READ_WRITE;
if(phdr.p_flags & 1) new_flags |= MAP_EXEC;
if (can_write_segment(phdr.p_flags)) new_flags |= MAP_READ_WRITE;
else if (can_execute_segment(phdr.p_flags)) new_flags |= MAP_EXEC;
MemoryManager::protect(buffer, pages, new_flags);
@ -181,6 +193,11 @@ long ELFLoader::check_elf_image(VFS::Node* node)
kerrorln("trying to load ELF into kernel memory");
return -ENOEXEC;
}
if (can_write_segment(phdr.p_flags) && can_execute_segment(phdr.p_flags))
{
kwarnln("executable violates W^X");
return -ENOEXEC;
}
loadable_sections++;
memusage += Utilities::get_blocks_from_size(PAGE_SIZE, phdr.p_memsz) * PAGE_SIZE;
}
@ -202,4 +219,4 @@ void ELFLoader::release_elf_image(ELFImage* image)
MemoryManager::release_pages((void*)round_down_to_nearest_page(section.base), section.pages);
}
kfree(image);
}
}