From 381f845287c8aef25a5351be81dfdfad055f0785 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Tue, 28 May 2019 18:26:38 +0200 Subject: [PATCH] Add a guard page for each thread --- std/thread.zig | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/std/thread.zig b/std/thread.zig index 49b2decb0..afed605b3 100644 --- a/std/thread.zig +++ b/std/thread.zig @@ -223,15 +223,17 @@ pub const Thread = struct { } }; - const MAP_GROWSDOWN = if (os.linux.is_the_target) os.linux.MAP_GROWSDOWN else 0; - + var guard_end_offset: usize = undefined; var stack_end_offset: usize = undefined; var thread_start_offset: usize = undefined; var context_start_offset: usize = undefined; var tls_start_offset: usize = undefined; const mmap_len = blk: { - // First in memory will be the stack, which grows downwards. - var l: usize = mem.alignForward(default_stack_size, mem.page_size); + var l: usize = mem.page_size; + // Allocate a guard page right after the end of the stack region + guard_end_offset = l; + // The stack itself, which grows downwards. + l = mem.alignForward(l + default_stack_size, mem.page_size); stack_end_offset = l; // Above the stack, so that it can be in the same mmap call, put the Thread object. l = mem.alignForward(l, @alignOf(Thread)); @@ -253,20 +255,33 @@ pub const Thread = struct { } break :blk l; }; + // Map the whole stack with no rw permissions to avoid committing the + // whole region right away const mmap_slice = os.mmap( null, mem.alignForward(mmap_len, mem.page_size), - os.PROT_READ | os.PROT_WRITE, - os.MAP_PRIVATE | os.MAP_ANONYMOUS | MAP_GROWSDOWN, + os.PROT_NONE, + os.MAP_PRIVATE | os.MAP_ANONYMOUS, -1, 0, ) catch |err| switch (err) { - error.MemoryMappingNotSupported => unreachable, // no file descriptor - error.AccessDenied => unreachable, // no file descriptor - error.PermissionDenied => unreachable, // no file descriptor + error.MemoryMappingNotSupported => unreachable, + error.AccessDenied => unreachable, + error.PermissionDenied => unreachable, else => |e| return e, }; errdefer os.munmap(mmap_slice); + + // Map everything but the guard page as rw + os.mprotect( + mmap_slice, + os.PROT_READ | os.PROT_WRITE, + ) catch |err| switch (err) { + error.OutOfMemory => unreachable, + error.AccessDenied => unreachable, + else => |e| return e, + }; + const mmap_addr = @ptrToInt(mmap_slice.ptr); const thread_ptr = @alignCast(@alignOf(Thread), @intToPtr(*Thread, mmap_addr + thread_start_offset));