diff options
Diffstat (limited to 'sandbox/linux/seccomp/maps.cc')
-rw-r--r-- | sandbox/linux/seccomp/maps.cc | 66 |
1 files changed, 54 insertions, 12 deletions
diff --git a/sandbox/linux/seccomp/maps.cc b/sandbox/linux/seccomp/maps.cc index 2c64b7f..f5c37c4 100644 --- a/sandbox/linux/seccomp/maps.cc +++ b/sandbox/linux/seccomp/maps.cc @@ -150,20 +150,38 @@ std::string Maps::Iterator::name() const { return getIterator()->first; } -char* Maps::allocNearAddr(char* addr, size_t size, int prot) const { +// Test whether a line ends with "[stack]"; used for identifying the +// stack entry of /proc/self/maps. +static bool isStackLine(char* buf, char* end) { + char* ptr = buf; + for ( ; *ptr != '\n' && ptr < end; ++ptr) + ; + if (ptr < end && ptr - 7 > buf) { + return (memcmp(ptr - 7, "[stack]", 7) == 0); + } + return false; +} + +char* Maps::allocNearAddr(char* addr_target, size_t size, int prot) const { // We try to allocate memory within 1.5GB of a target address. This means, // we will be able to perform relative 32bit jumps from the target address. + const unsigned long kMaxDistance = 1536 << 20; + // In most of the code below, we just care about the numeric value of + // the address. + const long addr = reinterpret_cast<long>(addr_target); size = (size + 4095) & ~4095; Sandbox::SysCalls sys; if (sys.lseek(proc_self_maps_, 0, SEEK_SET)) { return NULL; } + // Iterate through lines of /proc/self/maps to consider each mapped + // region one at a time, looking for a gap between regions to allocate. char buf[256] = { 0 }; int len = 0, rc = 1; bool long_line = false; unsigned long gap_start = 0x10000; - char *new_addr; + void* new_addr; do { if (rc > 0) { do { @@ -177,20 +195,44 @@ char* Maps::allocNearAddr(char* addr, size_t size, int prot) const { char *ptr = buf; if (!long_line) { long_line = true; - unsigned long start = strtoul(ptr, &ptr, 16); - unsigned long stop = strtoul(ptr + 1, &ptr, 16); - if (start - gap_start >= size) { - if (reinterpret_cast<long>(addr) - static_cast<long>(start) >= 0) { - if (reinterpret_cast<long>(addr) - (start - size) < (1536 << 20)) { + // Maps lines have the form "<start address>-<end address> ... <name>". + unsigned long gap_end = strtoul(ptr, &ptr, 16); + unsigned long map_end = strtoul(ptr + 1, &ptr, 16); + + // gap_start to gap_end now covers the region of empty space before + // the current line. Now we try to see if there's a place within the + // gap we can use. + + if (gap_end - gap_start >= size) { + // Is the gap before our target address? + if (addr - static_cast<long>(gap_end) >= 0) { + if (addr - (gap_end - size) < kMaxDistance) { + unsigned long position; + if (isStackLine(ptr, buf + len)) { + // If we're adjacent to the stack, try to stay away from + // the GROWS_DOWN region. Pick the farthest away region that + // is still within the gap. + + if (addr < kMaxDistance || // Underflow protection. + addr - kMaxDistance < gap_start) { + position = gap_start; + } else { + position = addr - kMaxDistance; + } + } else { + // Otherwise, take the end of the region. + position = gap_end - size; + } new_addr = reinterpret_cast<char *>(sys.MMAP - (reinterpret_cast<void *>(start - size), size, prot, + (reinterpret_cast<void *>(position), size, prot, MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, -1, 0)); if (new_addr != MAP_FAILED) { goto done; } } - } else if (gap_start + size - reinterpret_cast<long>(addr) < - (1536 << 20)) { + } else if (gap_start + size - addr < kMaxDistance) { + // Gap is after the address. Above checks that we can wrap around + // through 0 to a space we'd use. new_addr = reinterpret_cast<char *>(sys.MMAP (reinterpret_cast<void *>(gap_start), size, prot, MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, -1 ,0)); @@ -199,7 +241,7 @@ char* Maps::allocNearAddr(char* addr, size_t size, int prot) const { } } } - gap_start = stop; + gap_start = map_end; } for (;;) { if (!*ptr || *ptr++ == '\n') { @@ -213,7 +255,7 @@ char* Maps::allocNearAddr(char* addr, size_t size, int prot) const { } while (len || long_line); new_addr = NULL; done: - return new_addr; + return reinterpret_cast<char*>(new_addr); } } // namespace |