diff --git a/lib/std/c/windows.zig b/lib/std/c/windows.zig index 9980268869..b6ce03d21e 100644 --- a/lib/std/c/windows.zig +++ b/lib/std/c/windows.zig @@ -94,6 +94,18 @@ pub const SEEK = struct { pub const END = 2; }; +/// Basic memory protection flags +pub const PROT = struct { + /// page can not be accessed + pub const NONE = 0x0; + /// page can be read + pub const READ = 0x1; + /// page can be written + pub const WRITE = 0x2; + /// page can be executed + pub const EXEC = 0x4; +}; + pub const E = enum(u16) { /// No error occurred. SUCCESS = 0, diff --git a/lib/std/os.zig b/lib/std/os.zig index 22cdf30351..99bd9848ee 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -4226,12 +4226,30 @@ pub const MProtectError = error{ /// `memory.len` must be page-aligned. pub fn mprotect(memory: []align(mem.page_size) u8, protection: u32) MProtectError!void { assert(mem.isAligned(memory.len, mem.page_size)); - switch (errno(system.mprotect(memory.ptr, memory.len, protection))) { - .SUCCESS => return, - .INVAL => unreachable, - .ACCES => return error.AccessDenied, - .NOMEM => return error.OutOfMemory, - else => |err| return unexpectedErrno(err), + if (builtin.os.tag == .windows) { + const win_prot: windows.DWORD = switch (@truncate(u3, protection)) { + 0b000 => windows.PAGE_NOACCESS, + 0b001 => windows.PAGE_READONLY, + 0b010 => unreachable, // +w -r not allowed + 0b011 => windows.PAGE_READWRITE, + 0b100 => windows.PAGE_EXECUTE, + 0b101 => windows.PAGE_EXECUTE_READ, + 0b110 => unreachable, // +w -r not allowed + 0b111 => windows.PAGE_EXECUTE_READWRITE, + }; + var old: windows.DWORD = undefined; + windows.VirtualProtect(memory.ptr, memory.len, win_prot, &old) catch |err| switch (err) { + error.InvalidAddress => return error.AccessDenied, + error.Unexpected => return error.Unexpected, + }; + } else { + switch (errno(system.mprotect(memory.ptr, memory.len, protection))) { + .SUCCESS => return, + .INVAL => unreachable, + .ACCES => return error.AccessDenied, + .NOMEM => return error.OutOfMemory, + else => |err| return unexpectedErrno(err), + } } } diff --git a/lib/std/os/windows.zig b/lib/std/os/windows.zig index a88b911bcb..a5be06166e 100644 --- a/lib/std/os/windows.zig +++ b/lib/std/os/windows.zig @@ -1499,6 +1499,22 @@ pub fn VirtualFree(lpAddress: ?LPVOID, dwSize: usize, dwFreeType: DWORD) void { assert(kernel32.VirtualFree(lpAddress, dwSize, dwFreeType) != 0); } +pub const VirtualProtectError = error{ + InvalidAddress, + Unexpected, +}; + +pub fn VirtualProtect(lpAddress: ?LPVOID, dwSize: SIZE_T, flNewProtect: DWORD, lpflOldProtect: *DWORD) VirtualProtectError!void { + // ntdll takes an extra level of indirection here + var addr = lpAddress; + var size = dwSize; + switch (ntdll.NtProtectVirtualMemory(self_process_handle, &addr, &size, flNewProtect, lpflOldProtect)) { + .SUCCESS => {}, + .INVALID_ADDRESS => return error.InvalidAddress, + else => |st| return unexpectedStatus(st), + } +} + pub const VirtualQueryError = error{Unexpected}; pub fn VirtualQuery(lpAddress: ?LPVOID, lpBuffer: PMEMORY_BASIC_INFORMATION, dwLength: SIZE_T) VirtualQueryError!SIZE_T { diff --git a/lib/std/os/windows/ntdll.zig b/lib/std/os/windows/ntdll.zig index 5c9f5004e0..8c5260c1bc 100644 --- a/lib/std/os/windows/ntdll.zig +++ b/lib/std/os/windows/ntdll.zig @@ -291,3 +291,11 @@ pub extern "ntdll" fn RtlQueryRegistryValues( Context: ?*anyopaque, Environment: ?*anyopaque, ) callconv(WINAPI) NTSTATUS; + +pub extern "ntdll" fn NtProtectVirtualMemory( + ProcessHandle: HANDLE, + BaseAddress: *PVOID, + NumberOfBytesToProtect: *ULONG, + NewAccessProtection: ULONG, + OldAccessProtection: *ULONG, +) callconv(WINAPI) NTSTATUS;