authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-05-28 12:47:10-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-05-28 12:47:10-04:00
log568dc56232d8a1bf53495dd1c742ffae383ceaab
treecc5d15a0a272ac17b50ad98eb8a22fb3131049d9
parentd1b6f29d225bbedd0afb97fce64f5d042df4d9c6
parentc518b7b8bf71ad77adc96b5c9dabea277fe3ee43
signaturelock-open Commit is signed but in an unrecognized format.

Merge branch 'LemonBoy-guard-pages-in-threads'


2 files changed, 34 insertions(+), 11 deletions(-)

std/os.zig+11-2
......@@ -1883,20 +1883,29 @@ pub fn inotify_rm_watch(inotify_fd: i32, wd: i32) void {
18831883}
18841884
18851885pub const MProtectError = error{
1886 /// The memory cannot be given the specified access. This can happen, for example, if you
1887 /// mmap(2) a file to which you have read-only access, then ask mprotect() to mark it
1888 /// PROT_WRITE.
18861889 AccessDenied,
1890
1891 /// Changing the protection of a memory region would result in the total number of map‐
1892 /// pings with distinct attributes (e.g., read versus read/write protection) exceeding the
1893 /// allowed maximum. (For example, making the protection of a range PROT_READ in the mid‐
1894 /// dle of a region currently protected as PROT_READ|PROT_WRITE would result in three map‐
1895 /// pings: two read/write mappings at each end and a read-only mapping in the middle.)
18871896 OutOfMemory,
18881897 Unexpected,
18891898};
18901899
18911900/// `memory.len` must be page-aligned.
1892pub fn mprotect(memory: [*]align(mem.page_size) u8, protection: u32) MProtectError!void {
1901pub fn mprotect(memory: []align(mem.page_size) u8, protection: u32) MProtectError!void {
18931902 assert(mem.isAligned(memory.len, mem.page_size));
18941903 switch (errno(system.mprotect(memory.ptr, memory.len, protection))) {
18951904 0 => return,
18961905 EINVAL => unreachable,
18971906 EACCES => return error.AccessDenied,
18981907 ENOMEM => return error.OutOfMemory,
1899 else => return unexpectedErrno(err),
1908 else => |err| return unexpectedErrno(err),
19001909 }
19011910}
19021911
std/thread.zig+23-9
......@@ -223,15 +223,17 @@ pub const Thread = struct {
223223 }
224224 };
225225
226 const MAP_GROWSDOWN = if (os.linux.is_the_target) os.linux.MAP_GROWSDOWN else 0;
227
226 var guard_end_offset: usize = undefined;
228227 var stack_end_offset: usize = undefined;
229228 var thread_start_offset: usize = undefined;
230229 var context_start_offset: usize = undefined;
231230 var tls_start_offset: usize = undefined;
232231 const mmap_len = blk: {
233 // First in memory will be the stack, which grows downwards.
234 var l: usize = mem.alignForward(default_stack_size, mem.page_size);
232 var l: usize = mem.page_size;
233 // Allocate a guard page right after the end of the stack region
234 guard_end_offset = l;
235 // The stack itself, which grows downwards.
236 l = mem.alignForward(l + default_stack_size, mem.page_size);
235237 stack_end_offset = l;
236238 // Above the stack, so that it can be in the same mmap call, put the Thread object.
237239 l = mem.alignForward(l, @alignOf(Thread));
......@@ -253,20 +255,32 @@ pub const Thread = struct {
253255 }
254256 break :blk l;
255257 };
258 // Map the whole stack with no rw permissions to avoid committing the
259 // whole region right away
256260 const mmap_slice = os.mmap(
257261 null,
258262 mem.alignForward(mmap_len, mem.page_size),
259 os.PROT_READ | os.PROT_WRITE,
260 os.MAP_PRIVATE | os.MAP_ANONYMOUS | MAP_GROWSDOWN,
263 os.PROT_NONE,
264 os.MAP_PRIVATE | os.MAP_ANONYMOUS,
261265 -1,
262266 0,
263267 ) catch |err| switch (err) {
264 error.MemoryMappingNotSupported => unreachable, // no file descriptor
265 error.AccessDenied => unreachable, // no file descriptor
266 error.PermissionDenied => unreachable, // no file descriptor
268 error.MemoryMappingNotSupported => unreachable,
269 error.AccessDenied => unreachable,
270 error.PermissionDenied => unreachable,
267271 else => |e| return e,
268272 };
269273 errdefer os.munmap(mmap_slice);
274
275 // Map everything but the guard page as rw
276 os.mprotect(
277 mmap_slice,
278 os.PROT_READ | os.PROT_WRITE,
279 ) catch |err| switch (err) {
280 error.AccessDenied => unreachable,
281 else => |e| return e,
282 };
283
270284 const mmap_addr = @ptrToInt(mmap_slice.ptr);
271285
272286 const thread_ptr = @alignCast(@alignOf(Thread), @intToPtr(*Thread, mmap_addr + thread_start_offset));