Add test for guard page in test-sample, formatting fix

This commit is contained in:
3fault
2025-07-02 12:09:21 -04:00
parent 2e17f37f78
commit 68a5800c85
2 changed files with 98 additions and 1 deletions

View File

@@ -721,6 +721,101 @@ namespace
SleepEx(1, TRUE);
return executions == 2;
}
INT32 test_guard_page_seh_filter(LPVOID address, DWORD code, struct _EXCEPTION_POINTERS* ep)
{
// We are only looking for guard page exceptions.
if (code != STATUS_GUARD_PAGE_VIOLATION)
{
return EXCEPTION_CONTINUE_SEARCH;
}
// The number of defined elements in the ExceptionInformation array for
// a guard page violation should be 2.
if (ep->ExceptionRecord->NumberParameters != 2)
{
return EXCEPTION_CONTINUE_SEARCH;
}
// The ExceptionInformation array specifies additional arguments that
// describe the exception.
auto *exception_information = ep->ExceptionRecord->ExceptionInformation;
// If this value is zero, the thread attempted to read the inaccessible
// data. If this value is 1, the thread attempted to write to an
// inaccessible address.
if (exception_information[0] != 1)
{
return EXCEPTION_CONTINUE_SEARCH;
}
// The second array element specifies the virtual address of the
// inaccessible data.
if (exception_information[1] != (ULONG_PTR)address)
{
return EXCEPTION_CONTINUE_SEARCH;
}
return EXCEPTION_EXECUTE_HANDLER;
}
bool test_guard_page()
{
SYSTEM_INFO sys_info;
GetSystemInfo(&sys_info);
// Allocate a guarded memory region with the length of the system page
// size.
auto *addr = static_cast<LPBYTE>(VirtualAlloc(
nullptr,
sys_info.dwPageSize,
MEM_RESERVE | MEM_COMMIT,
PAGE_READWRITE | PAGE_GUARD
));
if (addr == nullptr)
{
puts("Failed to allocate guard page");
return false;
}
bool success = false;
// We want to access some arbitrary offset into the guarded page, to
// ensure that ExceptionInformation correctly contains the virtual
// address of the inaccessible data, not the base address of the region.
constexpr size_t offset = 10;
// Trigger a guard page violation
__try
{
addr[offset] = 255;
}
// If the filter function returns EXCEPTION_CONTINUE_SEARCH, the
// exception contains all of the correct information.
__except(test_guard_page_seh_filter(
addr + offset,
GetExceptionCode(),
GetExceptionInformation()))
{
success = true;
}
// The page guard should be lifted, so no exception should be raised.
__try {
// The previous write should not have went through, this is probably
// superflous.
if (addr[offset] == 255) {
success = false;
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
puts("Failed to read from page after guard exception!");
success = false;
}
return success;
}
}
#define RUN_TEST(func, name) \
@@ -761,6 +856,7 @@ int main(const int argc, const char* argv[])
RUN_TEST(test_tls, "TLS")
RUN_TEST(test_socket, "Socket")
RUN_TEST(test_apc, "APC")
RUN_TEST(test_guard_page, "Guard Page")
return valid ? 0 : 1;
}

View File

@@ -75,7 +75,8 @@ struct nt_memory_permission
return *this;
}
constexpr bool is_guarded() const {
constexpr bool is_guarded() const
{
return (this->extended & memory_permission_ext::guard) == memory_permission_ext::guard;
}
};