mirror of
https://github.com/tobast/libunwind-eh_elf.git
synced 2025-01-27 02:30:30 +01:00
[PATCH] x86_64: fix mincore_validate
The detection logic introduced in 28f33c8ce0
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.
This commit is contained in:
parent
c56fb8f99e
commit
bc8698fd7e
1 changed files with 22 additions and 2 deletions
|
@ -30,6 +30,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
|
@ -81,7 +82,21 @@ static int msync_validate (void *addr, size_t len)
|
||||||
static int mincore_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 */
|
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
|
#endif
|
||||||
|
|
||||||
|
@ -94,7 +109,12 @@ tdep_init_mem_validate (void)
|
||||||
{
|
{
|
||||||
#ifdef HAVE_MINCORE
|
#ifdef HAVE_MINCORE
|
||||||
unsigned char present = 1;
|
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");
|
Debug(1, "using mincore to validate memory\n");
|
||||||
mem_validate_func = mincore_validate;
|
mem_validate_func = mincore_validate;
|
||||||
|
|
Loading…
Reference in a new issue