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:
parent
2c08de044f
commit
e5b2641019
@ -25,6 +25,16 @@ static const char* format_permissions(uint32_t flags)
|
|||||||
return perms;
|
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)
|
ELFImage* ELFLoader::load_elf_from_filesystem(const char* filename)
|
||||||
{
|
{
|
||||||
VFS::Node* node = VFS::resolve_path(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));
|
phdr.p_filesz, phdr.p_memsz, format_permissions(phdr.p_flags));
|
||||||
ensure(phdr.p_vaddr);
|
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);
|
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),
|
void* buffer = (void*)((uint64_t)MemoryManager::get_pages_at(round_down_to_nearest_page(phdr.p_vaddr),
|
||||||
pages, MAP_READ_WRITE) +
|
pages, MAP_READ_WRITE) +
|
||||||
@ -106,8 +118,8 @@ ELFImage* ELFLoader::load_elf_from_vfs(VFS::Node* node)
|
|||||||
VMM::switch_to_previous_user_address_space();
|
VMM::switch_to_previous_user_address_space();
|
||||||
|
|
||||||
int new_flags = MAP_USER | MAP_AS_OWNED_BY_TASK;
|
int new_flags = MAP_USER | MAP_AS_OWNED_BY_TASK;
|
||||||
if(phdr.p_flags & 2) new_flags |= MAP_READ_WRITE;
|
if (can_write_segment(phdr.p_flags)) new_flags |= MAP_READ_WRITE;
|
||||||
if(phdr.p_flags & 1) new_flags |= MAP_EXEC;
|
else if (can_execute_segment(phdr.p_flags)) new_flags |= MAP_EXEC;
|
||||||
|
|
||||||
MemoryManager::protect(buffer, pages, new_flags);
|
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");
|
kerrorln("trying to load ELF into kernel memory");
|
||||||
return -ENOEXEC;
|
return -ENOEXEC;
|
||||||
}
|
}
|
||||||
|
if (can_write_segment(phdr.p_flags) && can_execute_segment(phdr.p_flags))
|
||||||
|
{
|
||||||
|
kwarnln("executable violates W^X");
|
||||||
|
return -ENOEXEC;
|
||||||
|
}
|
||||||
loadable_sections++;
|
loadable_sections++;
|
||||||
memusage += Utilities::get_blocks_from_size(PAGE_SIZE, phdr.p_memsz) * PAGE_SIZE;
|
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);
|
MemoryManager::release_pages((void*)round_down_to_nearest_page(section.base), section.pages);
|
||||||
}
|
}
|
||||||
kfree(image);
|
kfree(image);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user