Skip to content

PageProtect

Description

Change the protection of a range of pages. ptr and bytes must be page-aligned and page-sized respectively; the typical pattern is to apply this to a region returned by PageAllocator allocation (which is always page-grain).

Parameters

Name Direction Description
ptr in,out First byte of the region; must be page-aligned.
bytes in Region size; must be a multiple of the OS page size.
prot in New protection bits.

Success

Returns true. The new protection is in effect for the entire [ptr, ptr+bytes) range.

Failure

Returns false and logs the failing syscall (mprotect / VirtualProtect). The region’s protection is unchanged in the failure case.

Usage example (Cross-references)

Usage examples (Cross-references)
            size page_size = PageAllocatorPageSize(&self->page);
            size rounded   = (padded + page_size - 1) & ~(page_size - 1);
            if (!PageProtect(ptr, rounded, PAGE_PROT_NONE)) {
                LOG_ERROR("DebugAllocator: PageProtect(PROT_NONE) failed on {x}", (u64)ptr);
            }
            size rounded   = (padded + page_size - 1) & ~(page_size - 1);
            if (!PageProtect(ptr, rounded, PAGE_PROT_NONE)) {
                LOG_ERROR("DebugAllocator: PageProtect(PROT_NONE) failed on {x}", (u64)ptr);
            }
        } else {
    }
    
    bool PageProtect(void *ptr, size bytes, PageProtection prot) {
        if (!ptr || !bytes) {
            return false;
                break;
            default :
                LOG_ERROR("PageProtect: unknown protection bit {}", (u32)prot);
                return false;
        }
        DWORD old_prot = 0;
        if (!VirtualProtect(ptr, (SIZE_T)bytes, win_prot, &old_prot)) {
            LOG_ERROR("PageProtect: VirtualProtect failed (error {})", (u32)GetLastError());
            return false;
        }
                break;
            default :
                LOG_ERROR("PageProtect: unknown protection bit {}", (u32)prot);
                return false;
        }
        long ret = direct_sys3(MISRA_SYS_mprotect, (long)(u64)ptr, (long)bytes, (long)posix_prot);
        if (ret != 0) {
            LOG_SYS_ERROR(ErrnoOf((i32)ret), "PageProtect: mprotect failed");
            return false;
        }
            // off): mprotect returns -1 and the system error is recovered
            // through ErrnoOf below.
            LOG_SYS_ERROR(ErrnoOf(-1), "PageProtect: mprotect failed");
            return false;
        }
        // protection here; that would need SIGSEGV handling.)
        bool ok = true;
        ok      = ok && PageProtect(region, page_bytes, PAGE_PROT_NONE);
        ok      = ok && PageProtect(region, page_bytes, PAGE_PROT_READ_WRITE);
        ok      = ok && bytes[0] == 0xab && bytes[1] == 0xcd;
        bool ok = true;
        ok      = ok && PageProtect(region, page_bytes, PAGE_PROT_NONE);
        ok      = ok && PageProtect(region, page_bytes, PAGE_PROT_READ_WRITE);
        ok      = ok && bytes[0] == 0xab && bytes[1] == 0xcd;
        // Also exercise read-only: write before, drop to READ, restore.
        bytes[2] = 0xef;
        ok       = ok && PageProtect(region, page_bytes, PAGE_PROT_READ);
        ok       = ok && bytes[2] == 0xef;
        ok       = ok && PageProtect(region, page_bytes, PAGE_PROT_READ_WRITE);
        ok       = ok && PageProtect(region, page_bytes, PAGE_PROT_READ);
        ok       = ok && bytes[2] == 0xef;
        ok       = ok && PageProtect(region, page_bytes, PAGE_PROT_READ_WRITE);
    
        AllocatorFree(&page, region);
    
    int main(void) {
        WriteFmt("[INFO] Starting PageProtect tests\n\n");
    
        TestFunction tests[] = {
        };
    
        return run_test_suite(tests, sizeof(tests) / sizeof(tests[0]), NULL, 0, "PageProtect");
    }
Last updated on