Kernel: Cleanup userspace pointer validation
This commit is contained in:
parent
35e063bdaf
commit
f3beee9874
|
|
@ -275,7 +275,6 @@ namespace Kernel
|
||||||
BAN::ErrorOr<VirtualFileSystem::File> find_relative_parent(int fd, const char* path) const;
|
BAN::ErrorOr<VirtualFileSystem::File> find_relative_parent(int fd, const char* path) const;
|
||||||
|
|
||||||
BAN::ErrorOr<void> validate_string_access(const char*);
|
BAN::ErrorOr<void> validate_string_access(const char*);
|
||||||
BAN::ErrorOr<void> validate_pointer_access_check(const void*, size_t, bool needs_write);
|
|
||||||
BAN::ErrorOr<void> validate_pointer_access(const void*, size_t, bool needs_write);
|
BAN::ErrorOr<void> validate_pointer_access(const void*, size_t, bool needs_write);
|
||||||
BAN::ErrorOr<MemoryRegion*> validate_and_pin_pointer_access(const void*, size_t, bool needs_write);
|
BAN::ErrorOr<MemoryRegion*> validate_and_pin_pointer_access(const void*, size_t, bool needs_write);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1091,6 +1091,7 @@ namespace Kernel
|
||||||
if (Thread::current().userspace_stack().contains(address))
|
if (Thread::current().userspace_stack().contains(address))
|
||||||
return Thread::current().userspace_stack().allocate_page_for_demand_paging(address);
|
return Thread::current().userspace_stack().allocate_page_for_demand_paging(address);
|
||||||
|
|
||||||
|
// FIXME: make m_mapped_regions sorted so this can be a binary search
|
||||||
for (auto& region : m_mapped_regions)
|
for (auto& region : m_mapped_regions)
|
||||||
{
|
{
|
||||||
if (!region->contains(address))
|
if (!region->contains(address))
|
||||||
|
|
@ -3563,62 +3564,64 @@ namespace Kernel
|
||||||
return validate_pointer_access(str, strlen(str) + 1, false);
|
return validate_pointer_access(str, strlen(str) + 1, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<void> Process::validate_pointer_access_check(const void* ptr, size_t size, bool needs_write)
|
|
||||||
{
|
|
||||||
ASSERT(&Process::current() == this);
|
|
||||||
|
|
||||||
const vaddr_t vaddr = reinterpret_cast<vaddr_t>(ptr);
|
|
||||||
|
|
||||||
// NOTE: detect overflow
|
|
||||||
if (vaddr + size < vaddr)
|
|
||||||
goto unauthorized_access;
|
|
||||||
|
|
||||||
// trying to access kernel space memory
|
|
||||||
if (vaddr + size > USERSPACE_END)
|
|
||||||
goto unauthorized_access;
|
|
||||||
|
|
||||||
for (const auto* thread : m_threads)
|
|
||||||
if (vaddr >= thread->userspace_stack_bottom() && vaddr + size <= thread->userspace_stack_top())
|
|
||||||
return {};
|
|
||||||
|
|
||||||
// FIXME: should we allow cross mapping access?
|
|
||||||
for (const auto& mapped_region : m_mapped_regions)
|
|
||||||
{
|
|
||||||
if (!mapped_region->contains_fully(vaddr, size))
|
|
||||||
continue;
|
|
||||||
if (needs_write && !mapped_region->writable())
|
|
||||||
goto unauthorized_access;
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
unauthorized_access:
|
|
||||||
dwarnln("process {}, thread {} attempted to make an invalid pointer access to 0x{H}->0x{H}", pid(), Thread::current().tid(), vaddr, vaddr + size);
|
|
||||||
Debug::dump_stack_trace();
|
|
||||||
MUST(sys_kill(pid(), SIGSEGV));
|
|
||||||
return BAN::Error::from_errno(EINTR);
|
|
||||||
}
|
|
||||||
|
|
||||||
BAN::ErrorOr<void> Process::validate_pointer_access(const void* ptr, size_t size, bool needs_write)
|
BAN::ErrorOr<void> Process::validate_pointer_access(const void* ptr, size_t size, bool needs_write)
|
||||||
{
|
{
|
||||||
// TODO: This seems very slow as we loop over the range twice
|
|
||||||
|
|
||||||
if (size == 0)
|
if (size == 0)
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
TRY(validate_pointer_access_check(ptr, size, needs_write));
|
const auto page_flags = (needs_write ? PageTable::Flags::ReadWrite : 0) | PageTable::Flags::Present;
|
||||||
|
|
||||||
const vaddr_t vaddr = reinterpret_cast<vaddr_t>(ptr);
|
|
||||||
|
|
||||||
// Make sure all of the pages are mapped here, so demand paging does not happen
|
// Make sure all of the pages are mapped here, so demand paging does not happen
|
||||||
// while processing syscall.
|
// while processing syscall.
|
||||||
|
|
||||||
|
const vaddr_t vaddr = reinterpret_cast<vaddr_t>(ptr);
|
||||||
const vaddr_t page_start = vaddr & PAGE_ADDR_MASK;
|
const vaddr_t page_start = vaddr & PAGE_ADDR_MASK;
|
||||||
const size_t page_count = range_page_count(vaddr, size);
|
const size_t page_count = range_page_count(vaddr, size);
|
||||||
for (size_t i = 0; i < page_count; i++)
|
for (size_t i = 0; i < page_count; i++)
|
||||||
{
|
{
|
||||||
const vaddr_t current = page_start + i * PAGE_SIZE;
|
const vaddr_t current = page_start + i * PAGE_SIZE;
|
||||||
if (page_table().get_page_flags(current) & PageTable::Flags::Present)
|
if ((page_table().get_page_flags(current) & page_flags) == page_flags)
|
||||||
continue;
|
continue;
|
||||||
TRY(Process::allocate_page_for_demand_paging(current, needs_write, false));
|
if (!TRY(Process::allocate_page_for_demand_paging(current, needs_write, false)))
|
||||||
|
{
|
||||||
|
const MemoryRegion* region_ptr = nullptr;
|
||||||
|
for (const auto& region : m_mapped_regions)
|
||||||
|
{
|
||||||
|
if (!region->contains(vaddr + i * PAGE_SIZE))
|
||||||
|
continue;
|
||||||
|
region_ptr = region.ptr();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
dwarnln("{} pid {}, tid {} made an invalid {} access to 0x{h}",
|
||||||
|
name(),
|
||||||
|
pid(),
|
||||||
|
Thread::current().tid(),
|
||||||
|
needs_write ? "write" : "read",
|
||||||
|
vaddr + i * PAGE_SIZE
|
||||||
|
);
|
||||||
|
|
||||||
|
dwarnln(" 0x{h}->0x{h}", vaddr, vaddr + size);
|
||||||
|
|
||||||
|
if (region_ptr == nullptr)
|
||||||
|
dwarnln(" no mapping covers this page");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dwarnln(" inside region 0x{h}->0x{h} {}{}{}",
|
||||||
|
region_ptr->vaddr(),
|
||||||
|
region_ptr->vaddr() + region_ptr->size(),
|
||||||
|
(region_ptr->flags() & PageTable::Flags::Present) ? 'r' : '-',
|
||||||
|
(region_ptr->flags() & PageTable::Flags::ReadWrite) ? 'w' : '-',
|
||||||
|
(region_ptr->flags() & PageTable::Flags::Execute) ? 'x' : '-'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
page_table().debug_dump();
|
||||||
|
|
||||||
|
Debug::dump_stack_trace();
|
||||||
|
MUST(sys_kill(pid(), SIGSEGV));
|
||||||
|
return BAN::Error::from_errno(EINTR);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
|
|
@ -3628,6 +3631,10 @@ unauthorized_access:
|
||||||
{
|
{
|
||||||
LockGuard _(m_process_lock);
|
LockGuard _(m_process_lock);
|
||||||
TRY(validate_pointer_access(ptr, size, needs_write));
|
TRY(validate_pointer_access(ptr, size, needs_write));
|
||||||
|
|
||||||
|
// FIXME: make stack MemoryRegion?
|
||||||
|
// FIXME: allow pinning multiple regions
|
||||||
|
|
||||||
for (auto& region : m_mapped_regions)
|
for (auto& region : m_mapped_regions)
|
||||||
{
|
{
|
||||||
if (!region->contains_fully(reinterpret_cast<vaddr_t>(ptr), size))
|
if (!region->contains_fully(reinterpret_cast<vaddr_t>(ptr), size))
|
||||||
|
|
@ -3635,7 +3642,7 @@ unauthorized_access:
|
||||||
region->pin();
|
region->pin();
|
||||||
return region.ptr();
|
return region.ptr();
|
||||||
}
|
}
|
||||||
// FIXME: Make stack MemoryRegion?
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue