authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-02-13 16:17:40-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-02-13 16:17:40-05:00
log5f50980880181774de83dab3294ddeb0a121d6f2
tree7ee889d4aa02db1c576451c968f3b099c362ce8f
parentf73044dae598da2b84bff7977be5a8e02093902a
parent65299c37d1b4b4395616d6f86b5f064000951cf6
signature Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #10863 from m-radomski/fix

std: validate frame-pointer address in stack walking

13 files changed, 143 insertions(+), 1 deletions(-)

lib/std/c.zig+1
...@@ -123,6 +123,7 @@ pub extern "c" fn write(fd: c.fd_t, buf: [*]const u8, nbyte: usize) isize;...@@ -123,6 +123,7 @@ pub extern "c" fn write(fd: c.fd_t, buf: [*]const u8, nbyte: usize) isize;
123pub extern "c" fn pwrite(fd: c.fd_t, buf: [*]const u8, nbyte: usize, offset: c.off_t) isize;123pub extern "c" fn pwrite(fd: c.fd_t, buf: [*]const u8, nbyte: usize, offset: c.off_t) isize;
124pub 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;124pub 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;
125pub extern "c" fn munmap(addr: *align(page_size) const anyopaque, len: usize) c_int;125pub extern "c" fn munmap(addr: *align(page_size) const anyopaque, len: usize) c_int;
126pub extern "c" fn msync(addr: *align(page_size) const anyopaque, len: usize, flags: c_int) c_int;
126pub extern "c" fn mprotect(addr: *align(page_size) anyopaque, len: usize, prot: c_uint) c_int;127pub extern "c" fn mprotect(addr: *align(page_size) anyopaque, len: usize, prot: c_uint) c_int;
127pub extern "c" fn link(oldpath: [*:0]const u8, newpath: [*:0]const u8, flags: c_int) c_int;128pub extern "c" fn link(oldpath: [*:0]const u8, newpath: [*:0]const u8, flags: c_int) c_int;
128pub 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;129pub 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;
lib/std/c/darwin.zig+6
...@@ -636,6 +636,12 @@ pub const MAP = struct {...@@ -636,6 +636,12 @@ pub const MAP = struct {
636 pub const FAILED = @intToPtr(*anyopaque, maxInt(usize));636 pub const FAILED = @intToPtr(*anyopaque, maxInt(usize));
637};637};
638638
639pub const MSF = struct {
640 pub const ASYNC = 1;
641 pub const INVALIDATE = 2;
642 pub const SYNC = 4;
643};
644
639pub const SA = struct {645pub const SA = struct {
640 /// take signal on signal stack646 /// take signal on signal stack
641 pub const ONSTACK = 0x0001;647 pub const ONSTACK = 0x0001;
lib/std/c/dragonfly.zig+6
...@@ -185,6 +185,12 @@ pub const MAP = struct {...@@ -185,6 +185,12 @@ pub const MAP = struct {
185 pub const SIZEALIGN = 262144;185 pub const SIZEALIGN = 262144;
186};186};
187187
188pub const MSF = struct {
189 pub const ASYNC = 1;
190 pub const INVALIDATE = 2;
191 pub const SYNC = 4;
192};
193
188pub const W = struct {194pub const W = struct {
189 pub const NOHANG = 0x0001;195 pub const NOHANG = 0x0001;
190 pub const UNTRACED = 0x0002;196 pub const UNTRACED = 0x0002;
lib/std/c/freebsd.zig+6
...@@ -410,6 +410,12 @@ pub const MAP = struct {...@@ -410,6 +410,12 @@ pub const MAP = struct {
410 pub const @"32BIT" = 0x00080000;410 pub const @"32BIT" = 0x00080000;
411};411};
412412
413pub const MSF = struct {
414 pub const ASYNC = 1;
415 pub const INVALIDATE = 2;
416 pub const SYNC = 4;
417};
418
413pub const W = struct {419pub const W = struct {
414 pub const NOHANG = 1;420 pub const NOHANG = 1;
415 pub const UNTRACED = 2;421 pub const UNTRACED = 2;
lib/std/c/linux.zig+1
...@@ -30,6 +30,7 @@ pub const MAP = struct {...@@ -30,6 +30,7 @@ pub const MAP = struct {
30 /// Only used by libc to communicate failure.30 /// Only used by libc to communicate failure.
31 pub const FAILED = @intToPtr(*anyopaque, maxInt(usize));31 pub const FAILED = @intToPtr(*anyopaque, maxInt(usize));
32};32};
33pub const MSF = linux.MSF;
33pub const MMAP2_UNIT = linux.MMAP2_UNIT;34pub const MMAP2_UNIT = linux.MMAP2_UNIT;
34pub const MSG = linux.MSG;35pub const MSG = linux.MSG;
35pub const NAME_MAX = linux.NAME_MAX;36pub const NAME_MAX = linux.NAME_MAX;
lib/std/c/netbsd.zig+6
...@@ -575,6 +575,12 @@ pub const MAP = struct {...@@ -575,6 +575,12 @@ pub const MAP = struct {
575 pub const STACK = 0x2000;575 pub const STACK = 0x2000;
576};576};
577577
578pub const MSF = struct {
579 pub const ASYNC = 1;
580 pub const INVALIDATE = 2;
581 pub const SYNC = 4;
582};
583
578pub const W = struct {584pub const W = struct {
579 pub const NOHANG = 0x00000001;585 pub const NOHANG = 0x00000001;
580 pub const UNTRACED = 0x00000002;586 pub const UNTRACED = 0x00000002;
lib/std/c/openbsd.zig+6
...@@ -363,6 +363,12 @@ pub const MAP = struct {...@@ -363,6 +363,12 @@ pub const MAP = struct {
363 pub const CONCEAL = 0x8000;363 pub const CONCEAL = 0x8000;
364};364};
365365
366pub const MSF = struct {
367 pub const ASYNC = 1;
368 pub const INVALIDATE = 2;
369 pub const SYNC = 4;
370};
371
366pub const W = struct {372pub const W = struct {
367 pub const NOHANG = 1;373 pub const NOHANG = 1;
368 pub const UNTRACED = 2;374 pub const UNTRACED = 2;
lib/std/c/solaris.zig+6
...@@ -534,6 +534,12 @@ pub const MAP = struct {...@@ -534,6 +534,12 @@ pub const MAP = struct {
534 pub const INITDATA = 0x0800;534 pub const INITDATA = 0x0800;
535};535};
536536
537pub const MSF = struct {
538 pub const ASYNC = 1;
539 pub const INVALIDATE = 2;
540 pub const SYNC = 4;
541};
542
537pub const MADV = struct {543pub const MADV = struct {
538 /// no further special treatment544 /// no further special treatment
539 pub const NORMAL = 0;545 pub const NORMAL = 0;
lib/std/debug.zig+47-1
...@@ -424,6 +424,52 @@ pub const StackIterator = struct {...@@ -424,6 +424,52 @@ pub const StackIterator = struct {
424 return address;424 return address;
425 }425 }
426426
427 fn isValidMemory(address: usize) bool {
428 const aligned_address = address & ~@intCast(usize, (mem.page_size - 1));
429
430 // If the address does not span 2 pages, query only the first one
431 const length: usize = if (aligned_address == address) mem.page_size else 2 * mem.page_size;
432
433 const aligned_memory = @intToPtr([*]align(mem.page_size) u8, aligned_address)[0..length];
434
435 if (native_os != .windows) {
436 if (native_os != .wasi) {
437 os.msync(aligned_memory, os.MSF.ASYNC) catch |err| {
438 switch (err) {
439 os.MSyncError.UnmappedMemory => {
440 return false;
441 },
442 else => unreachable,
443 }
444 };
445 }
446
447 return true;
448 } else {
449 const w = os.windows;
450 var memory_info: w.MEMORY_BASIC_INFORMATION = undefined;
451 //const memory_info_ptr = @ptrCast(w.PMEMORY_BASIC_INFORMATION, buffer);
452
453 // The only error this function can throw is ERROR_INVALID_PARAMETER.
454 // supply an address that invalid i'll be thrown.
455 const rc = w.VirtualQuery(aligned_memory.ptr, &memory_info, aligned_memory.len) catch {
456 return false;
457 };
458
459 // Result code has to be bigger than zero (number of bytes written)
460 if (rc == 0) {
461 return false;
462 }
463
464 // Free pages cannot be read, they are unmapped
465 if (memory_info.State == w.MEM_FREE) {
466 return false;
467 }
468
469 return true;
470 }
471 }
472
427 fn next_internal(self: *StackIterator) ?usize {473 fn next_internal(self: *StackIterator) ?usize {
428 const fp = if (comptime native_arch.isSPARC())474 const fp = if (comptime native_arch.isSPARC())
429 // On SPARC the offset is positive. (!)475 // On SPARC the offset is positive. (!)
...@@ -432,7 +478,7 @@ pub const StackIterator = struct {...@@ -432,7 +478,7 @@ pub const StackIterator = struct {
432 math.sub(usize, self.fp, fp_offset) catch return null;478 math.sub(usize, self.fp, fp_offset) catch return null;
433479
434 // Sanity check.480 // Sanity check.
435 if (fp == 0 or !mem.isAligned(fp, @alignOf(usize)))481 if (fp == 0 or !mem.isAligned(fp, @alignOf(usize)) or !isValidMemory(fp))
436 return null;482 return null;
437483
438 const new_fp = math.add(usize, @intToPtr(*const usize, fp).*, fp_bias) catch return null;484 const new_fp = math.add(usize, @intToPtr(*const usize, fp).*, fp_bias) catch return null;
lib/std/os.zig+14
...@@ -88,6 +88,7 @@ pub const Kevent = system.Kevent;...@@ -88,6 +88,7 @@ pub const Kevent = system.Kevent;
88pub const LOCK = system.LOCK;88pub const LOCK = system.LOCK;
89pub const MADV = system.MADV;89pub const MADV = system.MADV;
90pub const MAP = system.MAP;90pub const MAP = system.MAP;
91pub const MSF = system.MSF;
91pub const MAX_ADDR_LEN = system.MAX_ADDR_LEN;92pub const MAX_ADDR_LEN = system.MAX_ADDR_LEN;
92pub const MMAP2_UNIT = system.MMAP2_UNIT;93pub const MMAP2_UNIT = system.MMAP2_UNIT;
93pub const MSG = system.MSG;94pub const MSG = system.MSG;
...@@ -4016,6 +4017,19 @@ pub fn munmap(memory: []align(mem.page_size) const u8) void {...@@ -4016,6 +4017,19 @@ pub fn munmap(memory: []align(mem.page_size) const u8) void {
4016 }4017 }
4017}4018}
40184019
4020pub const MSyncError = error{
4021 UnmappedMemory,
4022} || UnexpectedError;
4023
4024pub fn msync(memory: []align(mem.page_size) u8, flags: i32) MSyncError!void {
4025 switch (errno(system.msync(memory.ptr, memory.len, flags))) {
4026 .SUCCESS => return,
4027 .NOMEM => return error.UnmappedMemory, // Unsuccessful, provided pointer does not point mapped memory
4028 .INVAL => unreachable, // Invalid parameters.
4029 else => unreachable,
4030 }
4031}
4032
4019pub const AccessError = error{4033pub const AccessError = error{
4020 PermissionDenied,4034 PermissionDenied,
4021 FileNotFound,4035 FileNotFound,
lib/std/os/linux.zig+10
...@@ -406,6 +406,16 @@ pub fn mprotect(address: [*]const u8, length: usize, protection: usize) usize {...@@ -406,6 +406,16 @@ pub fn mprotect(address: [*]const u8, length: usize, protection: usize) usize {
406 return syscall3(.mprotect, @ptrToInt(address), length, protection);406 return syscall3(.mprotect, @ptrToInt(address), length, protection);
407}407}
408408
409pub const MSF = struct {
410 pub const ASYNC = 1;
411 pub const INVALIDATE = 2;
412 pub const SYNC = 4;
413};
414
415pub fn msync(address: [*]const u8, length: usize, flags: i32) usize {
416 return syscall3(.msync, @ptrToInt(address), length, @bitCast(u32, flags));
417}
418
409pub fn munmap(address: [*]const u8, length: usize) usize {419pub fn munmap(address: [*]const u8, length: usize) usize {
410 return syscall2(.munmap, @ptrToInt(address), length);420 return syscall2(.munmap, @ptrToInt(address), length);
411}421}
lib/std/os/windows.zig+32
...@@ -1495,6 +1495,19 @@ pub fn VirtualFree(lpAddress: ?LPVOID, dwSize: usize, dwFreeType: DWORD) void {...@@ -1495,6 +1495,19 @@ pub fn VirtualFree(lpAddress: ?LPVOID, dwSize: usize, dwFreeType: DWORD) void {
1495 assert(kernel32.VirtualFree(lpAddress, dwSize, dwFreeType) != 0);1495 assert(kernel32.VirtualFree(lpAddress, dwSize, dwFreeType) != 0);
1496}1496}
14971497
1498pub const VirtualQuerryError = error{Unexpected};
1499
1500pub fn VirtualQuery(lpAddress: ?LPVOID, lpBuffer: PMEMORY_BASIC_INFORMATION, dwLength: SIZE_T) VirtualQuerryError!SIZE_T {
1501 const rc = kernel32.VirtualQuery(lpAddress, lpBuffer, dwLength);
1502 if (rc == 0) {
1503 switch (kernel32.GetLastError()) {
1504 else => |err| return unexpectedError(err),
1505 }
1506 }
1507
1508 return rc;
1509}
1510
1498pub const SetConsoleTextAttributeError = error{Unexpected};1511pub const SetConsoleTextAttributeError = error{Unexpected};
14991512
1500pub fn SetConsoleTextAttribute(hConsoleOutput: HANDLE, wAttributes: WORD) SetConsoleTextAttributeError!void {1513pub fn SetConsoleTextAttribute(hConsoleOutput: HANDLE, wAttributes: WORD) SetConsoleTextAttributeError!void {
...@@ -2586,6 +2599,11 @@ pub const CREATE_EVENT_MANUAL_RESET = 0x00000001;...@@ -2586,6 +2599,11 @@ pub const CREATE_EVENT_MANUAL_RESET = 0x00000001;
2586pub const EVENT_ALL_ACCESS = 0x1F0003;2599pub const EVENT_ALL_ACCESS = 0x1F0003;
2587pub const EVENT_MODIFY_STATE = 0x0002;2600pub const EVENT_MODIFY_STATE = 0x0002;
25882601
2602// MEMORY_BASIC_INFORMATION.Type flags for VirtualQuery
2603pub const MEM_IMAGE = 0x1000000;
2604pub const MEM_MAPPED = 0x40000;
2605pub const MEM_PRIVATE = 0x20000;
2606
2589pub const PROCESS_INFORMATION = extern struct {2607pub const PROCESS_INFORMATION = extern struct {
2590 hProcess: HANDLE,2608 hProcess: HANDLE,
2591 hThread: HANDLE,2609 hThread: HANDLE,
...@@ -2661,6 +2679,7 @@ pub const HEAP_NO_SERIALIZE = 0x00000001;...@@ -2661,6 +2679,7 @@ pub const HEAP_NO_SERIALIZE = 0x00000001;
2661// AllocationType values2679// AllocationType values
2662pub const MEM_COMMIT = 0x1000;2680pub const MEM_COMMIT = 0x1000;
2663pub const MEM_RESERVE = 0x2000;2681pub const MEM_RESERVE = 0x2000;
2682pub const MEM_FREE = 0x10000;
2664pub const MEM_RESET = 0x80000;2683pub const MEM_RESET = 0x80000;
2665pub const MEM_RESET_UNDO = 0x1000000;2684pub const MEM_RESET_UNDO = 0x1000000;
2666pub const MEM_LARGE_PAGES = 0x20000000;2685pub const MEM_LARGE_PAGES = 0x20000000;
...@@ -2960,6 +2979,19 @@ pub const COINIT = enum(c_int) {...@@ -2960,6 +2979,19 @@ pub const COINIT = enum(c_int) {
2960 COINIT_SPEED_OVER_MEMORY = 8,2979 COINIT_SPEED_OVER_MEMORY = 8,
2961};2980};
29622981
2982pub const MEMORY_BASIC_INFORMATION = extern struct {
2983 BaseAddress: PVOID,
2984 AllocationBase: PVOID,
2985 AllocationProtect: DWORD,
2986 PartitionId: WORD,
2987 RegionSize: SIZE_T,
2988 State: DWORD,
2989 Protect: DWORD,
2990 Type: DWORD,
2991};
2992
2993pub const PMEMORY_BASIC_INFORMATION = *MEMORY_BASIC_INFORMATION;
2994
2963/// > The maximum path of 32,767 characters is approximate, because the "\\?\"2995/// > The maximum path of 32,767 characters is approximate, because the "\\?\"
2964/// > prefix may be expanded to a longer string by the system at run time, and2996/// > prefix may be expanded to a longer string by the system at run time, and
2965/// > this expansion applies to the total length.2997/// > this expansion applies to the total length.
lib/std/os/windows/kernel32.zig+2
...@@ -56,6 +56,7 @@ const LPOVERLAPPED_COMPLETION_ROUTINE = windows.LPOVERLAPPED_COMPLETION_ROUTINE;...@@ -56,6 +56,7 @@ const LPOVERLAPPED_COMPLETION_ROUTINE = windows.LPOVERLAPPED_COMPLETION_ROUTINE;
56const UCHAR = windows.UCHAR;56const UCHAR = windows.UCHAR;
57const FARPROC = windows.FARPROC;57const FARPROC = windows.FARPROC;
58const INIT_ONCE_FN = windows.INIT_ONCE_FN;58const INIT_ONCE_FN = windows.INIT_ONCE_FN;
59const PMEMORY_BASIC_INFORMATION = windows.PMEMORY_BASIC_INFORMATION;
5960
60pub extern "kernel32" fn AddVectoredExceptionHandler(First: c_ulong, Handler: ?VECTORED_EXCEPTION_HANDLER) callconv(WINAPI) ?*anyopaque;61pub extern "kernel32" fn AddVectoredExceptionHandler(First: c_ulong, Handler: ?VECTORED_EXCEPTION_HANDLER) callconv(WINAPI) ?*anyopaque;
61pub extern "kernel32" fn RemoveVectoredExceptionHandler(Handle: HANDLE) callconv(WINAPI) c_ulong;62pub 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...@@ -245,6 +246,7 @@ pub extern "kernel32" fn HeapValidate(hHeap: HANDLE, dwFlags: DWORD, lpMem: ?*co
245246
246pub extern "kernel32" fn VirtualAlloc(lpAddress: ?LPVOID, dwSize: SIZE_T, flAllocationType: DWORD, flProtect: DWORD) callconv(WINAPI) ?LPVOID;247pub extern "kernel32" fn VirtualAlloc(lpAddress: ?LPVOID, dwSize: SIZE_T, flAllocationType: DWORD, flProtect: DWORD) callconv(WINAPI) ?LPVOID;
247pub extern "kernel32" fn VirtualFree(lpAddress: ?LPVOID, dwSize: SIZE_T, dwFreeType: DWORD) callconv(WINAPI) BOOL;248pub extern "kernel32" fn VirtualFree(lpAddress: ?LPVOID, dwSize: SIZE_T, dwFreeType: DWORD) callconv(WINAPI) BOOL;
249pub extern "kernel32" fn VirtualQuery(lpAddress: ?LPVOID, lpBuffer: PMEMORY_BASIC_INFORMATION, dwLength: SIZE_T) callconv(WINAPI) SIZE_T;
248250
249pub extern "kernel32" fn LocalFree(hMem: HLOCAL) callconv(WINAPI) ?HLOCAL;251pub extern "kernel32" fn LocalFree(hMem: HLOCAL) callconv(WINAPI) ?HLOCAL;
250252