mirror of
https://github.com/ziglang/zig.git
synced 2026-02-13 04:48:20 +00:00
Merge pull request #10863 from m-radomski/fix
std: validate frame-pointer address in stack walking
This commit is contained in:
commit
5f50980880
@ -123,6 +123,7 @@ pub extern "c" fn write(fd: c.fd_t, buf: [*]const u8, nbyte: usize) isize;
|
||||
pub extern "c" fn pwrite(fd: c.fd_t, buf: [*]const u8, nbyte: usize, offset: c.off_t) isize;
|
||||
pub extern "c" fn mmap(addr: ?*align(page_size) anyopaque, len: usize, prot: c_uint, flags: c_uint, fd: c.fd_t, offset: c.off_t) *anyopaque;
|
||||
pub extern "c" fn munmap(addr: *align(page_size) const anyopaque, len: usize) c_int;
|
||||
pub extern "c" fn msync(addr: *align(page_size) const anyopaque, len: usize, flags: c_int) c_int;
|
||||
pub extern "c" fn mprotect(addr: *align(page_size) anyopaque, len: usize, prot: c_uint) c_int;
|
||||
pub extern "c" fn link(oldpath: [*:0]const u8, newpath: [*:0]const u8, flags: c_int) c_int;
|
||||
pub extern "c" fn linkat(oldfd: c.fd_t, oldpath: [*:0]const u8, newfd: c.fd_t, newpath: [*:0]const u8, flags: c_int) c_int;
|
||||
|
||||
@ -636,6 +636,12 @@ pub const MAP = struct {
|
||||
pub const FAILED = @intToPtr(*anyopaque, maxInt(usize));
|
||||
};
|
||||
|
||||
pub const MSF = struct {
|
||||
pub const ASYNC = 1;
|
||||
pub const INVALIDATE = 2;
|
||||
pub const SYNC = 4;
|
||||
};
|
||||
|
||||
pub const SA = struct {
|
||||
/// take signal on signal stack
|
||||
pub const ONSTACK = 0x0001;
|
||||
|
||||
@ -185,6 +185,12 @@ pub const MAP = struct {
|
||||
pub const SIZEALIGN = 262144;
|
||||
};
|
||||
|
||||
pub const MSF = struct {
|
||||
pub const ASYNC = 1;
|
||||
pub const INVALIDATE = 2;
|
||||
pub const SYNC = 4;
|
||||
};
|
||||
|
||||
pub const W = struct {
|
||||
pub const NOHANG = 0x0001;
|
||||
pub const UNTRACED = 0x0002;
|
||||
|
||||
@ -410,6 +410,12 @@ pub const MAP = struct {
|
||||
pub const @"32BIT" = 0x00080000;
|
||||
};
|
||||
|
||||
pub const MSF = struct {
|
||||
pub const ASYNC = 1;
|
||||
pub const INVALIDATE = 2;
|
||||
pub const SYNC = 4;
|
||||
};
|
||||
|
||||
pub const W = struct {
|
||||
pub const NOHANG = 1;
|
||||
pub const UNTRACED = 2;
|
||||
|
||||
@ -30,6 +30,7 @@ pub const MAP = struct {
|
||||
/// Only used by libc to communicate failure.
|
||||
pub const FAILED = @intToPtr(*anyopaque, maxInt(usize));
|
||||
};
|
||||
pub const MSF = linux.MSF;
|
||||
pub const MMAP2_UNIT = linux.MMAP2_UNIT;
|
||||
pub const MSG = linux.MSG;
|
||||
pub const NAME_MAX = linux.NAME_MAX;
|
||||
|
||||
@ -575,6 +575,12 @@ pub const MAP = struct {
|
||||
pub const STACK = 0x2000;
|
||||
};
|
||||
|
||||
pub const MSF = struct {
|
||||
pub const ASYNC = 1;
|
||||
pub const INVALIDATE = 2;
|
||||
pub const SYNC = 4;
|
||||
};
|
||||
|
||||
pub const W = struct {
|
||||
pub const NOHANG = 0x00000001;
|
||||
pub const UNTRACED = 0x00000002;
|
||||
|
||||
@ -363,6 +363,12 @@ pub const MAP = struct {
|
||||
pub const CONCEAL = 0x8000;
|
||||
};
|
||||
|
||||
pub const MSF = struct {
|
||||
pub const ASYNC = 1;
|
||||
pub const INVALIDATE = 2;
|
||||
pub const SYNC = 4;
|
||||
};
|
||||
|
||||
pub const W = struct {
|
||||
pub const NOHANG = 1;
|
||||
pub const UNTRACED = 2;
|
||||
|
||||
@ -534,6 +534,12 @@ pub const MAP = struct {
|
||||
pub const INITDATA = 0x0800;
|
||||
};
|
||||
|
||||
pub const MSF = struct {
|
||||
pub const ASYNC = 1;
|
||||
pub const INVALIDATE = 2;
|
||||
pub const SYNC = 4;
|
||||
};
|
||||
|
||||
pub const MADV = struct {
|
||||
/// no further special treatment
|
||||
pub const NORMAL = 0;
|
||||
|
||||
@ -424,6 +424,52 @@ pub const StackIterator = struct {
|
||||
return address;
|
||||
}
|
||||
|
||||
fn isValidMemory(address: usize) bool {
|
||||
const aligned_address = address & ~@intCast(usize, (mem.page_size - 1));
|
||||
|
||||
// If the address does not span 2 pages, query only the first one
|
||||
const length: usize = if (aligned_address == address) mem.page_size else 2 * mem.page_size;
|
||||
|
||||
const aligned_memory = @intToPtr([*]align(mem.page_size) u8, aligned_address)[0..length];
|
||||
|
||||
if (native_os != .windows) {
|
||||
if (native_os != .wasi) {
|
||||
os.msync(aligned_memory, os.MSF.ASYNC) catch |err| {
|
||||
switch (err) {
|
||||
os.MSyncError.UnmappedMemory => {
|
||||
return false;
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return true;
|
||||
} else {
|
||||
const w = os.windows;
|
||||
var memory_info: w.MEMORY_BASIC_INFORMATION = undefined;
|
||||
//const memory_info_ptr = @ptrCast(w.PMEMORY_BASIC_INFORMATION, buffer);
|
||||
|
||||
// The only error this function can throw is ERROR_INVALID_PARAMETER.
|
||||
// supply an address that invalid i'll be thrown.
|
||||
const rc = w.VirtualQuery(aligned_memory.ptr, &memory_info, aligned_memory.len) catch {
|
||||
return false;
|
||||
};
|
||||
|
||||
// Result code has to be bigger than zero (number of bytes written)
|
||||
if (rc == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Free pages cannot be read, they are unmapped
|
||||
if (memory_info.State == w.MEM_FREE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
fn next_internal(self: *StackIterator) ?usize {
|
||||
const fp = if (comptime native_arch.isSPARC())
|
||||
// On SPARC the offset is positive. (!)
|
||||
@ -432,7 +478,7 @@ pub const StackIterator = struct {
|
||||
math.sub(usize, self.fp, fp_offset) catch return null;
|
||||
|
||||
// Sanity check.
|
||||
if (fp == 0 or !mem.isAligned(fp, @alignOf(usize)))
|
||||
if (fp == 0 or !mem.isAligned(fp, @alignOf(usize)) or !isValidMemory(fp))
|
||||
return null;
|
||||
|
||||
const new_fp = math.add(usize, @intToPtr(*const usize, fp).*, fp_bias) catch return null;
|
||||
|
||||
@ -88,6 +88,7 @@ pub const Kevent = system.Kevent;
|
||||
pub const LOCK = system.LOCK;
|
||||
pub const MADV = system.MADV;
|
||||
pub const MAP = system.MAP;
|
||||
pub const MSF = system.MSF;
|
||||
pub const MAX_ADDR_LEN = system.MAX_ADDR_LEN;
|
||||
pub const MMAP2_UNIT = system.MMAP2_UNIT;
|
||||
pub const MSG = system.MSG;
|
||||
@ -4016,6 +4017,19 @@ pub fn munmap(memory: []align(mem.page_size) const u8) void {
|
||||
}
|
||||
}
|
||||
|
||||
pub const MSyncError = error{
|
||||
UnmappedMemory,
|
||||
} || UnexpectedError;
|
||||
|
||||
pub fn msync(memory: []align(mem.page_size) u8, flags: i32) MSyncError!void {
|
||||
switch (errno(system.msync(memory.ptr, memory.len, flags))) {
|
||||
.SUCCESS => return,
|
||||
.NOMEM => return error.UnmappedMemory, // Unsuccessful, provided pointer does not point mapped memory
|
||||
.INVAL => unreachable, // Invalid parameters.
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
pub const AccessError = error{
|
||||
PermissionDenied,
|
||||
FileNotFound,
|
||||
|
||||
@ -406,6 +406,16 @@ pub fn mprotect(address: [*]const u8, length: usize, protection: usize) usize {
|
||||
return syscall3(.mprotect, @ptrToInt(address), length, protection);
|
||||
}
|
||||
|
||||
pub const MSF = struct {
|
||||
pub const ASYNC = 1;
|
||||
pub const INVALIDATE = 2;
|
||||
pub const SYNC = 4;
|
||||
};
|
||||
|
||||
pub fn msync(address: [*]const u8, length: usize, flags: i32) usize {
|
||||
return syscall3(.msync, @ptrToInt(address), length, @bitCast(u32, flags));
|
||||
}
|
||||
|
||||
pub fn munmap(address: [*]const u8, length: usize) usize {
|
||||
return syscall2(.munmap, @ptrToInt(address), length);
|
||||
}
|
||||
|
||||
@ -1495,6 +1495,19 @@ pub fn VirtualFree(lpAddress: ?LPVOID, dwSize: usize, dwFreeType: DWORD) void {
|
||||
assert(kernel32.VirtualFree(lpAddress, dwSize, dwFreeType) != 0);
|
||||
}
|
||||
|
||||
pub const VirtualQuerryError = error{Unexpected};
|
||||
|
||||
pub fn VirtualQuery(lpAddress: ?LPVOID, lpBuffer: PMEMORY_BASIC_INFORMATION, dwLength: SIZE_T) VirtualQuerryError!SIZE_T {
|
||||
const rc = kernel32.VirtualQuery(lpAddress, lpBuffer, dwLength);
|
||||
if (rc == 0) {
|
||||
switch (kernel32.GetLastError()) {
|
||||
else => |err| return unexpectedError(err),
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
pub const SetConsoleTextAttributeError = error{Unexpected};
|
||||
|
||||
pub fn SetConsoleTextAttribute(hConsoleOutput: HANDLE, wAttributes: WORD) SetConsoleTextAttributeError!void {
|
||||
@ -2586,6 +2599,11 @@ pub const CREATE_EVENT_MANUAL_RESET = 0x00000001;
|
||||
pub const EVENT_ALL_ACCESS = 0x1F0003;
|
||||
pub const EVENT_MODIFY_STATE = 0x0002;
|
||||
|
||||
// MEMORY_BASIC_INFORMATION.Type flags for VirtualQuery
|
||||
pub const MEM_IMAGE = 0x1000000;
|
||||
pub const MEM_MAPPED = 0x40000;
|
||||
pub const MEM_PRIVATE = 0x20000;
|
||||
|
||||
pub const PROCESS_INFORMATION = extern struct {
|
||||
hProcess: HANDLE,
|
||||
hThread: HANDLE,
|
||||
@ -2661,6 +2679,7 @@ pub const HEAP_NO_SERIALIZE = 0x00000001;
|
||||
// AllocationType values
|
||||
pub const MEM_COMMIT = 0x1000;
|
||||
pub const MEM_RESERVE = 0x2000;
|
||||
pub const MEM_FREE = 0x10000;
|
||||
pub const MEM_RESET = 0x80000;
|
||||
pub const MEM_RESET_UNDO = 0x1000000;
|
||||
pub const MEM_LARGE_PAGES = 0x20000000;
|
||||
@ -2960,6 +2979,19 @@ pub const COINIT = enum(c_int) {
|
||||
COINIT_SPEED_OVER_MEMORY = 8,
|
||||
};
|
||||
|
||||
pub const MEMORY_BASIC_INFORMATION = extern struct {
|
||||
BaseAddress: PVOID,
|
||||
AllocationBase: PVOID,
|
||||
AllocationProtect: DWORD,
|
||||
PartitionId: WORD,
|
||||
RegionSize: SIZE_T,
|
||||
State: DWORD,
|
||||
Protect: DWORD,
|
||||
Type: DWORD,
|
||||
};
|
||||
|
||||
pub const PMEMORY_BASIC_INFORMATION = *MEMORY_BASIC_INFORMATION;
|
||||
|
||||
/// > The maximum path of 32,767 characters is approximate, because the "\\?\"
|
||||
/// > prefix may be expanded to a longer string by the system at run time, and
|
||||
/// > this expansion applies to the total length.
|
||||
|
||||
@ -56,6 +56,7 @@ const LPOVERLAPPED_COMPLETION_ROUTINE = windows.LPOVERLAPPED_COMPLETION_ROUTINE;
|
||||
const UCHAR = windows.UCHAR;
|
||||
const FARPROC = windows.FARPROC;
|
||||
const INIT_ONCE_FN = windows.INIT_ONCE_FN;
|
||||
const PMEMORY_BASIC_INFORMATION = windows.PMEMORY_BASIC_INFORMATION;
|
||||
|
||||
pub extern "kernel32" fn AddVectoredExceptionHandler(First: c_ulong, Handler: ?VECTORED_EXCEPTION_HANDLER) callconv(WINAPI) ?*anyopaque;
|
||||
pub extern "kernel32" fn RemoveVectoredExceptionHandler(Handle: HANDLE) callconv(WINAPI) c_ulong;
|
||||
@ -245,6 +246,7 @@ pub extern "kernel32" fn HeapValidate(hHeap: HANDLE, dwFlags: DWORD, lpMem: ?*co
|
||||
|
||||
pub extern "kernel32" fn VirtualAlloc(lpAddress: ?LPVOID, dwSize: SIZE_T, flAllocationType: DWORD, flProtect: DWORD) callconv(WINAPI) ?LPVOID;
|
||||
pub extern "kernel32" fn VirtualFree(lpAddress: ?LPVOID, dwSize: SIZE_T, dwFreeType: DWORD) callconv(WINAPI) BOOL;
|
||||
pub extern "kernel32" fn VirtualQuery(lpAddress: ?LPVOID, lpBuffer: PMEMORY_BASIC_INFORMATION, dwLength: SIZE_T) callconv(WINAPI) SIZE_T;
|
||||
|
||||
pub extern "kernel32" fn LocalFree(hMem: HLOCAL) callconv(WINAPI) ?HLOCAL;
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user