diff --git a/Kernel/Arch/x86/common/Interrupts.cpp b/Kernel/Arch/x86/common/Interrupts.cpp index 1be7cd7632..03660e02ac 100644 --- a/Kernel/Arch/x86/common/Interrupts.cpp +++ b/Kernel/Arch/x86/common/Interrupts.cpp @@ -317,7 +317,7 @@ void page_fault_handler(TrapFrame* trap) PageFault fault { regs.exception_code, VirtualAddress { fault_address } }; auto response = MM.handle_page_fault(fault); - if (response == PageFaultResponse::ShouldCrash || response == PageFaultResponse::OutOfMemory) { + if (response == PageFaultResponse::ShouldCrash || response == PageFaultResponse::OutOfMemory || response == PageFaultResponse::BusError) { if (faulted_in_kernel && handle_safe_access_fault(regs, fault_address)) { // If this would be a ring0 (kernel) fault and the fault was triggered by // safe_memcpy, safe_strnlen, or safe_memset then we resume execution at @@ -325,6 +325,11 @@ void page_fault_handler(TrapFrame* trap) return; } + if (response == PageFaultResponse::BusError && current_thread->has_signal_handler(SIGBUS)) { + current_thread->send_urgent_signal_to_self(SIGBUS); + return; + } + if (response != PageFaultResponse::OutOfMemory && current_thread) { if (current_thread->has_signal_handler(SIGSEGV)) { current_thread->send_urgent_signal_to_self(SIGSEGV); @@ -341,7 +346,9 @@ void page_fault_handler(TrapFrame* trap) constexpr FlatPtr free_scrub_pattern = explode_byte(FREE_SCRUB_BYTE); constexpr FlatPtr kmalloc_scrub_pattern = explode_byte(KMALLOC_SCRUB_BYTE); constexpr FlatPtr kfree_scrub_pattern = explode_byte(KFREE_SCRUB_BYTE); - if ((fault_address & 0xffff0000) == (malloc_scrub_pattern & 0xffff0000)) { + if (response == PageFaultResponse::BusError) { + dbgln("Note: Address {} is an access to an undefined memory range of an Inode-backed VMObject", VirtualAddress(fault_address)); + } else if ((fault_address & 0xffff0000) == (malloc_scrub_pattern & 0xffff0000)) { dbgln("Note: Address {} looks like it may be uninitialized malloc() memory", VirtualAddress(fault_address)); } else if ((fault_address & 0xffff0000) == (free_scrub_pattern & 0xffff0000)) { dbgln("Note: Address {} looks like it may be recently free()'d memory", VirtualAddress(fault_address)); @@ -390,6 +397,8 @@ void page_fault_handler(TrapFrame* trap) } } + if (response == PageFaultResponse::BusError) + return handle_crash(regs, "Page Fault (Bus Error)", SIGBUS, false); return handle_crash(regs, "Page Fault", SIGSEGV, response == PageFaultResponse::OutOfMemory); } else if (response == PageFaultResponse::Continue) { dbgln_if(PAGE_FAULT_DEBUG, "Continuing after resolved page fault"); diff --git a/Kernel/Memory/PageFaultResponse.h b/Kernel/Memory/PageFaultResponse.h index 56297f6268..0a5c473230 100644 --- a/Kernel/Memory/PageFaultResponse.h +++ b/Kernel/Memory/PageFaultResponse.h @@ -10,6 +10,7 @@ namespace Kernel { enum class PageFaultResponse { ShouldCrash, + BusError, OutOfMemory, Continue, }; diff --git a/Kernel/Memory/Region.cpp b/Kernel/Memory/Region.cpp index a5ecc22fe6..ea042596a8 100644 --- a/Kernel/Memory/Region.cpp +++ b/Kernel/Memory/Region.cpp @@ -501,6 +501,11 @@ PageFaultResponse Region::handle_inode_fault(size_t page_index_in_region) } auto nread = result.value(); + // Note: If we received 0, it means we are at the end of file or after it, + // which means we should return bus error. + if (nread == 0) + return PageFaultResponse::BusError; + if (nread < PAGE_SIZE) { // If we read less than a page, zero out the rest to avoid leaking uninitialized data. memset(page_buffer + nread, 0, PAGE_SIZE - nread);