Kernel+LibELF: Enable SMAP protection during non-syscall exec()

When loading a new executable, we now map the ELF image in kernel-only
memory and parse it there. Then we use copy_to_user() when initializing
writable regions with data from the executable.

Note that the exec() syscall still disables SMAP protection and will
require additional work. This patch only affects kernel-originated
process spawns.
This commit is contained in:
Andreas Kling 2020-01-10 06:57:18 +01:00
parent 66b0002acb
commit 197e73ee31
5 changed files with 20 additions and 10 deletions

View file

@ -165,13 +165,16 @@ Region* Process::allocate_file_backed_region(VirtualAddress vaddr, size_t size,
return &m_regions.last();
}
Region* Process::allocate_region_with_vmobject(VirtualAddress vaddr, size_t size, NonnullRefPtr<VMObject> vmobject, size_t offset_in_vmobject, const String& name, int prot)
Region* Process::allocate_region_with_vmobject(VirtualAddress vaddr, size_t size, NonnullRefPtr<VMObject> vmobject, size_t offset_in_vmobject, const String& name, int prot, bool user_accessible)
{
auto range = allocate_range(vaddr, size);
if (!range.is_valid())
return nullptr;
offset_in_vmobject &= PAGE_MASK;
m_regions.append(Region::create_user_accessible(range, move(vmobject), offset_in_vmobject, name, prot_to_region_access_flags(prot)));
if (user_accessible)
m_regions.append(Region::create_user_accessible(range, move(vmobject), offset_in_vmobject, name, prot_to_region_access_flags(prot)));
else
m_regions.append(Region::create_kernel_only(range, move(vmobject), offset_in_vmobject, name, prot_to_region_access_flags(prot)));
m_regions.last().map(page_directory());
return &m_regions.last();
}
@ -669,7 +672,7 @@ int Process::do_exec(String path, Vector<String> arguments, Vector<String> envir
ASSERT(description->inode());
auto vmobject = InodeVMObject::create_with_inode(*description->inode());
auto* region = allocate_region_with_vmobject(VirtualAddress(), metadata.size, vmobject, 0, description->absolute_path(), PROT_READ);
auto* region = allocate_region_with_vmobject(VirtualAddress(), metadata.size, vmobject, 0, description->absolute_path(), PROT_READ, false);
ASSERT(region);
// NOTE: We yank this out of 'm_regions' since we're about to manipulate the vector
@ -682,7 +685,6 @@ int Process::do_exec(String path, Vector<String> arguments, Vector<String> envir
OwnPtr<ELFLoader> loader;
{
SmapDisabler disabler;
// Okay, here comes the sleight of hand, pay close attention..
auto old_regions = move(m_regions);
m_regions.append(move(executable_region));
@ -741,9 +743,6 @@ int Process::do_exec(String path, Vector<String> arguments, Vector<String> envir
#endif
}
region->set_user_accessible(false);
region->remap();
m_elf_loader = move(loader);
m_executable = description->custody();

View file

@ -279,7 +279,7 @@ public:
bool is_superuser() const { return m_euid == 0; }
Region* allocate_region_with_vmobject(VirtualAddress, size_t, NonnullRefPtr<VMObject>, size_t offset_in_vmobject, const String& name, int prot);
Region* allocate_region_with_vmobject(VirtualAddress, size_t, NonnullRefPtr<VMObject>, size_t offset_in_vmobject, const String& name, int prot, bool user_accessible = true);
Region* allocate_file_backed_region(VirtualAddress, size_t, NonnullRefPtr<Inode>, const String& name, int prot);
Region* allocate_region(VirtualAddress, size_t, const String& name, int prot = PROT_READ | PROT_WRITE, bool commit = true);
bool deallocate_region(Region& region);

View file

@ -189,6 +189,13 @@ NonnullOwnPtr<Region> Region::create_kernel_only(const Range& range, const Strin
return region;
}
NonnullOwnPtr<Region> Region::create_kernel_only(const Range& range, NonnullRefPtr<VMObject> vmobject, size_t offset_in_vmobject, const StringView& name, u8 access)
{
auto region = make<Region>(range, move(vmobject), offset_in_vmobject, name, access);
region->m_user_accessible = false;
return region;
}
bool Region::should_cow(size_t page_index) const
{
if (m_shared)

View file

@ -30,6 +30,7 @@ public:
static NonnullOwnPtr<Region> create_user_accessible(const Range&, NonnullRefPtr<VMObject>, size_t offset_in_vmobject, const StringView& name, u8 access);
static NonnullOwnPtr<Region> create_user_accessible(const Range&, NonnullRefPtr<Inode>, const StringView& name, u8 access);
static NonnullOwnPtr<Region> create_kernel_only(const Range&, const StringView& name, u8 access);
static NonnullOwnPtr<Region> create_kernel_only(const Range&, NonnullRefPtr<VMObject>, size_t offset_in_vmobject, const StringView& name, u8 access);
~Region();

View file

@ -5,6 +5,9 @@
#ifdef KERNEL
#include <Kernel/VM/MemoryManager.h>
#define do_memcpy copy_to_user
#else
#define do_memcpy memcpy
#endif
//#define ELFLOADER_DEBUG
@ -48,7 +51,7 @@ bool ELFLoader::layout()
failed = true;
return;
}
memcpy(tls_image, program_header.raw_data(), program_header.size_in_image());
do_memcpy(tls_image, program_header.raw_data(), program_header.size_in_image());
#endif
return;
}
@ -75,7 +78,7 @@ bool ELFLoader::layout()
failed = true;
return;
}
memcpy(program_header.vaddr().as_ptr(), program_header.raw_data(), program_header.size_in_image());
do_memcpy(program_header.vaddr().as_ptr(), program_header.raw_data(), program_header.size_in_image());
} else {
auto* mapped_section = map_section_hook(
program_header.vaddr(),