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:
parent
ddd5411472
commit
f41ae755ec
5 changed files with 41 additions and 2 deletions
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue