From bc8698fd7ed13a629a8ec3cb2a89bd74f9d8b5c0 Mon Sep 17 00:00:00 2001 From: Giuseppe Ottaviano Date: Sun, 20 Mar 2016 00:28:03 +0000 Subject: [PATCH] [PATCH] x86_64: fix mincore_validate The detection logic introduced in 28f33c8ce0b654cf31d6beda9a612870662f3c56 is broken, because it tests mincore using an address that is almost certainly not page-aligned. straces confirms that msync is used all the time. This patch fixes the logic by page-aligning the test pointer. strace now shows that mincore is actually used. Furthermore, the return value of mincore is not sufficient to assess whether the address can be safely dereferenced: we should also check that the pages are mapped, through the passed mvec array. This patch also adds this verification. Tested on a system where unwinding a stack across a JNI boundary would cause sporadic segfaults; no more crashes were observed after the patch. --- src/x86_64/Ginit.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/src/x86_64/Ginit.c b/src/x86_64/Ginit.c index 6e9d4fe9..78275762 100644 --- a/src/x86_64/Ginit.c +++ b/src/x86_64/Ginit.c @@ -30,6 +30,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #endif +#include #include #include #include @@ -81,7 +82,21 @@ static int msync_validate (void *addr, size_t len) static int mincore_validate (void *addr, size_t len) { unsigned char mvec[2]; /* Unaligned access may cross page boundary */ - return mincore (addr, len, mvec); + size_t i; + + /* mincore could fail with EAGAIN but we conservatively return -1 + instead of looping. */ + if (mincore (addr, len, mvec) != 0) + { + return -1; + } + + for (i = 0; i < (len + PAGE_SIZE - 1) / PAGE_SIZE; i++) + { + if (!(mvec[i] & 1)) return -1; + } + + return 0; } #endif @@ -94,7 +109,12 @@ tdep_init_mem_validate (void) { #ifdef HAVE_MINCORE unsigned char present = 1; - if (mincore (&present, 1, &present) == 0) + unw_word_t addr = PAGE_START((unw_word_t)&present); + unsigned char mvec[1]; + int ret; + while ((ret = mincore ((void*)addr, PAGE_SIZE, mvec)) == -1 && + errno == EAGAIN) {} + if (ret == 0 && (mvec[0] & 1)) { Debug(1, "using mincore to validate memory\n"); mem_validate_func = mincore_validate;