summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Base/usr/share/man/man1/crash.md2
-rw-r--r--Kernel/Process.cpp1
-rw-r--r--Kernel/VM/Region.cpp9
-rw-r--r--Kernel/VM/Region.h8
-rw-r--r--Userland/crash.cpp23
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;
}