1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 13:57:35 +00:00

Kernel: Crash on memory access in non-readable regions

This patch makes it possible to make memory regions non-readable.
This is enforced using the "present" bit in the page tables.
A process that hits an not-present page fault in a non-readable
region will be crashed.
This commit is contained in:
Andreas Kling 2019-12-02 19:14:16 +01:00
parent ddd5411472
commit f41ae755ec
5 changed files with 41 additions and 2 deletions

View file

@ -28,6 +28,8 @@ kinds of crashes.
* `-T`: Make a syscall while using an invalid stack pointer. * `-T`: Make a syscall while using an invalid stack pointer.
* `-t`: Trigger a page fault while using an invalid stack pointer. * `-t`: Trigger a page fault while using an invalid stack pointer.
* `-S`: Make a syscall from writeable memory. * `-S`: Make a syscall from writeable memory.
* `-x`: Read from recently freed memory. (Tests an opportunistic malloc guard.)
* `-y`: Write to recently freed memory. (Tests an opportunistic malloc guard.)
## Examples ## Examples

View file

@ -306,6 +306,7 @@ int Process::sys$mprotect(void* addr, size_t size, int prot)
return -EINVAL; return -EINVAL;
if (!region->is_mmap()) if (!region->is_mmap())
return -EPERM; return -EPERM;
region->set_readable(prot & PROT_READ);
region->set_writable(prot & PROT_WRITE); region->set_writable(prot & PROT_WRITE);
region->remap(); region->remap();
return 0; return 0;

View file

@ -191,7 +191,7 @@ void Region::remap_page(size_t index)
auto& physical_page = vmobject().physical_pages()[first_page_index() + index]; auto& physical_page = vmobject().physical_pages()[first_page_index() + index];
ASSERT(physical_page); ASSERT(physical_page);
pte.set_physical_page_base(physical_page->paddr().get()); pte.set_physical_page_base(physical_page->paddr().get());
pte.set_present(true); pte.set_present(is_readable());
if (should_cow(index)) if (should_cow(index))
pte.set_writable(false); pte.set_writable(false);
else else
@ -239,7 +239,7 @@ void Region::map(PageDirectory& page_directory)
auto& physical_page = vmobject().physical_pages()[first_page_index() + i]; auto& physical_page = vmobject().physical_pages()[first_page_index() + i];
if (physical_page) { if (physical_page) {
pte.set_physical_page_base(physical_page->paddr().get()); pte.set_physical_page_base(physical_page->paddr().get());
pte.set_present(true); // FIXME: Maybe we should use the is_readable flag here? pte.set_present(is_readable());
if (should_cow(i)) if (should_cow(i))
pte.set_writable(false); pte.set_writable(false);
else else
@ -267,6 +267,11 @@ PageFaultResponse Region::handle_fault(const PageFault& fault)
{ {
auto page_index_in_region = page_index_from_address(fault.vaddr()); auto page_index_in_region = page_index_from_address(fault.vaddr());
if (fault.type() == PageFault::Type::PageNotPresent) { if (fault.type() == PageFault::Type::PageNotPresent) {
if (!is_readable()) {
dbgprintf("NP(non-readable) fault in Region{%p}[%u]\n", this, page_index_in_region);
return PageFaultResponse::ShouldCrash;
}
if (vmobject().is_inode()) { if (vmobject().is_inode()) {
#ifdef PAGE_FAULT_DEBUG #ifdef PAGE_FAULT_DEBUG
dbgprintf("NP(inode) fault in Region{%p}[%u]\n", this, page_index_in_region); dbgprintf("NP(inode) fault in Region{%p}[%u]\n", this, page_index_in_region);

View file

@ -113,6 +113,14 @@ public:
m_access &= ~Access::Write; m_access &= ~Access::Write;
} }
void set_readable(bool b)
{
if (b)
m_access |= Access::Read;
else
m_access &= ~Access::Read;
}
void map(PageDirectory&); void map(PageDirectory&);
enum class ShouldDeallocateVirtualMemoryRange { enum class ShouldDeallocateVirtualMemoryRange {
No, No,

View file

@ -26,6 +26,8 @@ int main(int argc, char** argv)
InvalidStackPointerOnSyscall, InvalidStackPointerOnSyscall,
InvalidStackPointerOnPageFault, InvalidStackPointerOnPageFault,
SyscallFromWritableMemory, SyscallFromWritableMemory,
WriteToFreedMemoryStillCachedByMalloc,
ReadFromFreedMemoryStillCachedByMalloc,
}; };
Mode mode = SegmentationViolation; Mode mode = SegmentationViolation;
@ -56,6 +58,10 @@ int main(int argc, char** argv)
mode = InvalidStackPointerOnPageFault; mode = InvalidStackPointerOnPageFault;
else if (String(argv[1]) == "-S") else if (String(argv[1]) == "-S")
mode = SyscallFromWritableMemory; mode = SyscallFromWritableMemory;
else if (String(argv[1]) == "-x")
mode = ReadFromFreedMemoryStillCachedByMalloc;
else if (String(argv[1]) == "-y")
mode = WriteToFreedMemoryStillCachedByMalloc;
else else
print_usage_and_exit(); print_usage_and_exit();
@ -161,6 +167,23 @@ int main(int argc, char** argv)
((void(*)())buffer)(); ((void(*)())buffer)();
} }
if (mode == ReadFromFreedMemoryStillCachedByMalloc) {
auto* ptr = (u8*)malloc(1024);
free(ptr);
dbgprintf("ptr = %p\n", ptr);
volatile auto foo = *ptr;
(void)foo;
ASSERT_NOT_REACHED();
}
if (mode == WriteToFreedMemoryStillCachedByMalloc) {
auto* ptr = (u8*)malloc(1024);
free(ptr);
dbgprintf("ptr = %p\n", ptr);
*ptr = 'x';
ASSERT_NOT_REACHED();
}
ASSERT_NOT_REACHED(); ASSERT_NOT_REACHED();
return 0; return 0;
} }