/* This Source Code Form is subject to the terms of the Mozilla Public *License,v.2.0.IfacopyoftheMPLwasnotdistributedwiththis *file,Youcanobtainoneathttp://mozilla.org/MPL/2.0/.
*/
#ifdef _WIN32 # include <windows.h> #else # include <sys/types.h> # include <unistd.h> # include <sys/wait.h>
# include <sys/mman.h> # ifndef MAP_ANON # ifdef MAP_ANONYMOUS # define MAP_ANON MAP_ANONYMOUS # else # error "Don't know how to get anonymous memory" # endif # endif #endif
#define SIZxPTR ((int)(sizeof(uintptr_t) * 2))
/* This program assumes that a whole number of return instructions fit into *32bits,andthat32-bitalignmentissufficientforabranchdestination. *Forarchitectureswherethisisnottrue,fiddlingwithRETURN_INSTR_TYPE *canbeenough.
*/
#ifdefined __i386__ || defined __x86_64__ || defined __i386 || \ defined __x86_64 || defined _M_IX86 || defined _M_AMD64 # define RETURN_INSTR 0xC3C3C3C3 /* ret; ret; ret; ret */
#elifdefined __arm__ || defined _M_ARM # define RETURN_INSTR 0xE12FFF1E /* bx lr */
// PPC has its own style of CPU-id #defines. There is no Windows for // PPC as far as I know, so no _M_ variant. #elifdefined _ARCH_PPC || defined _ARCH_PWR || defined _ARCH_PWR2 # define RETURN_INSTR 0x4E800020 /* blr */
#elifdefined __mips # define RETURN_INSTR 0x03e00008 /* jr ra */
# ifdef __MIPSEL /* On mipsel, jr ra needs to be followed by a nop.
0x03e00008 as a 64 bits integer just does that */ # define RETURN_INSTR_TYPE uint64_t # endif
static uintptr_t ReservePoisonArea() { if (sizeof(uintptr_t) == 8) { // Use the hardware-inaccessible region. // We have to avoid 64-bit constants and shifts by 32 bits, since this // code is compiled in 32-bit mode, although it is never executed there.
uintptr_t result =
(((uintptr_t(0x7FFFFFFFu) << 31) << 1 | uintptr_t(0xF0DEAFFFu)) &
~uintptr_t(PageSize() - 1));
printf("INFO | poison area assumed at 0x%.*" PRIxPTR "\n", SIZxPTR, result); return result;
}
// First see if we can allocate the preferred poison address from the OS.
uintptr_t candidate = (0xF0DEAFFF & ~(PageSize() - 1)); void* result = ReserveRegion(candidate, false); if (result == reinterpret_cast<void*>(candidate)) { // success - inaccessible page allocated
printf("INFO | poison area allocated at 0x%.*" PRIxPTR " (preferred addr)\n",
SIZxPTR, reinterpret_cast<uintptr_t>(result)); return candidate;
}
// That didn't work, so see if the preferred address is within a range // of permanently inacessible memory. if (ProbeRegion(candidate)) { // success - selected page cannot be usable memory if (result != MAP_FAILED) {
ReleaseRegion(result);
}
printf("INFO | poison area assumed at 0x%.*" PRIxPTR " (preferred addr)\n",
SIZxPTR, candidate); return candidate;
}
// The preferred address is already in use. Did the OS give us a // consolation prize? if (result != MAP_FAILED) {
uintptr_t ures = reinterpret_cast<uintptr_t>(result);
printf("INFO | poison area allocated at 0x%.*" PRIxPTR " (consolation prize)\n",
SIZxPTR, ures); return ures;
}
// It didn't, so try to allocate again, without any constraint on // the address.
result = ReserveRegion(0, false); if (result != MAP_FAILED) {
uintptr_t ures = reinterpret_cast<uintptr_t>(result);
printf("INFO | poison area allocated at 0x%.*" PRIxPTR " (fallback)\n",
SIZxPTR, ures); return ures;
}
printf("ERROR | no usable poison area found\n"); return0;
}
/* The "positive control" area confirms that we can allocate a page with the *propercharacteristics.
*/ static uintptr_t ReservePositiveControl() { void* result = ReserveRegion(0, false); if (result == MAP_FAILED) {
printf("ERROR | allocating positive control | %s\n", LastErrMsg()); return0;
}
printf("INFO | positive control allocated at 0x%.*" PRIxPTR "\n", SIZxPTR,
(uintptr_t)result); return (uintptr_t)result;
}
/* The "negative control" area confirms that our probe logic does detect a *pagethatisreadable,writable,orexecutable.
*/ static uintptr_t ReserveNegativeControl() { void* result = ReserveRegion(0, true); if (result == MAP_FAILED) {
printf("ERROR | allocating negative control | %s\n", LastErrMsg()); return0;
}
// Fill the page with return instructions.
RETURN_INSTR_TYPE* p = reinterpret_cast<RETURN_INSTR_TYPE*>(result);
RETURN_INSTR_TYPE* limit = reinterpret_cast<RETURN_INSTR_TYPE*>(
reinterpret_cast<char*>(result) + PageSize()); while (p < limit) {
*p++ = RETURN_INSTR;
}
// Now mark it executable as well as readable and writable. // (mmap(PROT_EXEC) may fail when applied to anonymous memory.)
if (MakeRegionExecutable(result)) {
ReleaseRegion(result); return0;
}
printf("INFO | negative control allocated at 0x%.*" PRIxPTR "\n", SIZxPTR,
(uintptr_t)result); return (uintptr_t)result;
}
uintptr_t ncontrol = ReserveNegativeControl(); if (!ncontrol) { #if (defined __aarch64__ || defined _M_ARM64) && defined(XP_DARWIN) // Apple silicon doesn't support W+X pages, so if we didn't manage to setup // the negative page on Apple Silicon then skip that part of the test.
printf("TEST-SKIP | making negative control executable | %s\n",
LastErrMsg()); #else
printf("ERROR | making negative control executable | %s\n", LastErrMsg()); return2; #endif
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.