diff options
-rw-r--r-- | Base/usr/share/man/man1/crash.md | 2 | ||||
-rw-r--r-- | Kernel/Process.cpp | 1 | ||||
-rw-r--r-- | Kernel/VM/Region.cpp | 9 | ||||
-rw-r--r-- | Kernel/VM/Region.h | 8 | ||||
-rw-r--r-- | Userland/crash.cpp | 23 |
5 files changed, 41 insertions, 2 deletions
diff --git a/Base/usr/share/man/man1/crash.md b/Base/usr/share/man/man1/crash.md index da38a466dd..8af17a8f07 100644 --- a/Base/usr/share/man/man1/crash.md +++ b/Base/usr/share/man/man1/crash.md @@ -28,6 +28,8 @@ kinds of crashes. * `-T`: Make a syscall while using an invalid stack pointer. * `-t`: Trigger a page fault while using an invalid stack pointer. * `-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 diff --git a/Kernel/Process.cpp b/Kernel/Process.cpp index fc2946b13e..074e96896a 100644 --- a/Kernel/Process.cpp +++ b/Kernel/Process.cpp @@ -306,6 +306,7 @@ int Process::sys$mprotect(void* addr, size_t size, int prot) return -EINVAL; if (!region->is_mmap()) return -EPERM; + region->set_readable(prot & PROT_READ); region->set_writable(prot & PROT_WRITE); region->remap(); return 0; diff --git a/Kernel/VM/Region.cpp b/Kernel/VM/Region.cpp index 80e38ab08c..0bb7f6769c 100644 --- a/Kernel/VM/Region.cpp +++ b/Kernel/VM/Region.cpp @@ -191,7 +191,7 @@ void Region::remap_page(size_t index) auto& physical_page = vmobject().physical_pages()[first_page_index() + index]; ASSERT(physical_page); pte.set_physical_page_base(physical_page->paddr().get()); - pte.set_present(true); + pte.set_present(is_readable()); if (should_cow(index)) pte.set_writable(false); else @@ -239,7 +239,7 @@ void Region::map(PageDirectory& page_directory) auto& physical_page = vmobject().physical_pages()[first_page_index() + i]; if (physical_page) { 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)) pte.set_writable(false); else @@ -267,6 +267,11 @@ PageFaultResponse Region::handle_fault(const PageFault& fault) { auto page_index_in_region = page_index_from_address(fault.vaddr()); 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()) { #ifdef PAGE_FAULT_DEBUG dbgprintf("NP(inode) fault in Region{%p}[%u]\n", this, page_index_in_region); diff --git a/Kernel/VM/Region.h b/Kernel/VM/Region.h index 2c5890c7b6..bee22f9688 100644 --- a/Kernel/VM/Region.h +++ b/Kernel/VM/Region.h @@ -113,6 +113,14 @@ public: m_access &= ~Access::Write; } + void set_readable(bool b) + { + if (b) + m_access |= Access::Read; + else + m_access &= ~Access::Read; + } + void map(PageDirectory&); enum class ShouldDeallocateVirtualMemoryRange { No, diff --git a/Userland/crash.cpp b/Userland/crash.cpp index 7879cda844..6b8a00e636 100644 --- a/Userland/crash.cpp +++ b/Userland/crash.cpp @@ -26,6 +26,8 @@ int main(int argc, char** argv) InvalidStackPointerOnSyscall, InvalidStackPointerOnPageFault, SyscallFromWritableMemory, + WriteToFreedMemoryStillCachedByMalloc, + ReadFromFreedMemoryStillCachedByMalloc, }; Mode mode = SegmentationViolation; @@ -56,6 +58,10 @@ int main(int argc, char** argv) mode = InvalidStackPointerOnPageFault; else if (String(argv[1]) == "-S") mode = SyscallFromWritableMemory; + else if (String(argv[1]) == "-x") + mode = ReadFromFreedMemoryStillCachedByMalloc; + else if (String(argv[1]) == "-y") + mode = WriteToFreedMemoryStillCachedByMalloc; else print_usage_and_exit(); @@ -161,6 +167,23 @@ int main(int argc, char** argv) ((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(); return 0; } |