| Index: sandbox/linux/seccomp/maps.cc
|
| diff --git a/sandbox/linux/seccomp/maps.cc b/sandbox/linux/seccomp/maps.cc
|
| index 2c64b7f5cec9c4dfd9a85794a54aeea8e037716c..f5c37c4486fa76355866916b0ae8fe98ee050f56 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
|
|
|