From 7c2304ddc6d716883415ac883f02256db6318644 Mon Sep 17 00:00:00 2001 From: Martin Husemann Date: Mon, 30 Apr 2018 08:04:53 +0200 Subject: [PATCH 1/2] Map the stack guard page with max protection on NetBSD On NetBSD the initial mmap() protection of a mapping can not be made less restrictive with mprotect(). So when mapping a stack guard page, use the maximum protection we ever want to use, then mprotect() it to the permission we want it to have initially. --- src/libstd/sys/unix/thread.rs | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/libstd/sys/unix/thread.rs b/src/libstd/sys/unix/thread.rs index 9e3888080302..f32016ce1d62 100644 --- a/src/libstd/sys/unix/thread.rs +++ b/src/libstd/sys/unix/thread.rs @@ -326,11 +326,23 @@ pub mod guard { // Reallocate the last page of the stack. // This ensures SIGBUS will be raised on // stack overflow. - let result = mmap(stackaddr, PAGE_SIZE, PROT_NONE, - MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0); + if cfg!(target_os = "netbsd") { + let result = mmap(stackaddr, PAGE_SIZE, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0); + if result != stackaddr || result == MAP_FAILED { + panic!("failed to allocate a guard page"); + } + let result = mprotect(stackaddr, PAGE_SIZE, 0); - if result != stackaddr || result == MAP_FAILED { - panic!("failed to allocate a guard page"); + if result != 0 { + panic!("unable to protect the guard page"); + } + } else { + let result = mmap(stackaddr, PAGE_SIZE, PROT_NONE, + MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0); + if result != stackaddr || result == MAP_FAILED { + panic!("failed to allocate a guard page"); + } } let guardaddr = stackaddr as usize; From 244e24a312925779f6c62ce7d6b315fa2c120a7c Mon Sep 17 00:00:00 2001 From: Martin Husemann Date: Wed, 2 May 2018 10:00:33 +0200 Subject: [PATCH 2/2] Add comments and unify guard page setup. While currently only NetBSD seems to be affected, all systems implementing PAX MPROTECT in strict mode need this treatment, and it does not hurt others. --- src/libstd/sys/unix/thread.rs | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/src/libstd/sys/unix/thread.rs b/src/libstd/sys/unix/thread.rs index f32016ce1d62..7fdecc9c0c02 100644 --- a/src/libstd/sys/unix/thread.rs +++ b/src/libstd/sys/unix/thread.rs @@ -326,23 +326,20 @@ pub mod guard { // Reallocate the last page of the stack. // This ensures SIGBUS will be raised on // stack overflow. - if cfg!(target_os = "netbsd") { - let result = mmap(stackaddr, PAGE_SIZE, PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0); - if result != stackaddr || result == MAP_FAILED { - panic!("failed to allocate a guard page"); - } - let result = mprotect(stackaddr, PAGE_SIZE, 0); + // Systems which enforce strict PAX MPROTECT do not allow + // to mprotect() a mapping with less restrictive permissions + // than the initial mmap() used, so we mmap() here with + // read/write permissions and only then mprotect() it to + // no permissions at all. See issue #50313. + let result = mmap(stackaddr, PAGE_SIZE, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0); + if result != stackaddr || result == MAP_FAILED { + panic!("failed to allocate a guard page"); + } - if result != 0 { - panic!("unable to protect the guard page"); - } - } else { - let result = mmap(stackaddr, PAGE_SIZE, PROT_NONE, - MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0); - if result != stackaddr || result == MAP_FAILED { - panic!("failed to allocate a guard page"); - } + let result = mprotect(stackaddr, PAGE_SIZE, PROT_NONE); + if result != 0 { + panic!("failed to protect the guard page"); } let guardaddr = stackaddr as usize;