added 1 changeset to branch 'refs/remotes/pdziepak-github/aslr' old head: fe9b18223abc0c92e2bbf3d80df8dfaf22e680a8 new head: ff6d12fc57686c163088393ed8d9ca5d5a366086 overview: https://github.com/pdziepak/Haiku/compare/fe9b182...ff6d12f ---------------------------------------------------------------------------- ff6d12f: vm: implement B_RAND_BASE_ADDRESS address spec B_RAND_BASE_ADDRESS is basically B_BASE_ADDRESS with non-deterministic created area's base address. Initial start address is randomized and then the algorithm looks for a large enough free space in the interval [randomized start, end]. If it fails then the search is repeated in the interval [original start, randomized start]. In case it also fails the algorithm falls back to B_ANY_ADDRESS (B_RAND_ANY_ADDRESS when it is implemented) just like B_BASE_ADDRESS does. Randomization range is limited by kMaxRandomize and kMaxInitialRandomize. [ Pawel Dziepak <pdziepak@xxxxxxxxxxx> ] ---------------------------------------------------------------------------- Commit: ff6d12fc57686c163088393ed8d9ca5d5a366086 Author: Pawel Dziepak <pdziepak@xxxxxxxxxxx> Date: Mon Feb 25 21:40:05 2013 UTC ---------------------------------------------------------------------------- 4 files changed, 106 insertions(+), 4 deletions(-) headers/os/kernel/OS.h | 3 + src/system/kernel/vm/VMUserAddressSpace.cpp | 100 +++++++++++++++++++++++- src/system/kernel/vm/VMUserAddressSpace.h | 6 ++ src/system/kernel/vm/vm.cpp | 1 + ---------------------------------------------------------------------------- diff --git a/headers/os/kernel/OS.h b/headers/os/kernel/OS.h index d5441da..1398451 100644 --- a/headers/os/kernel/OS.h +++ b/headers/os/kernel/OS.h @@ -78,6 +78,9 @@ typedef struct area_info { #define B_BASE_ADDRESS 2 #define B_CLONE_ADDRESS 3 #define B_ANY_KERNEL_ADDRESS 4 +/* B_ANY_KERNEL_BLOCK_ADDRESS 5 */ +/* B_RAND_ANY_ADDRESS 6 */ +#define B_RAND_BASE_ADDRESS 7 /* area protection */ #define B_READ_AREA 1 diff --git a/src/system/kernel/vm/VMUserAddressSpace.cpp b/src/system/kernel/vm/VMUserAddressSpace.cpp index 32730a4..3d014a1 100644 --- a/src/system/kernel/vm/VMUserAddressSpace.cpp +++ b/src/system/kernel/vm/VMUserAddressSpace.cpp @@ -137,6 +137,7 @@ VMUserAddressSpace::InsertArea(VMArea* _area, size_t size, break; case B_BASE_ADDRESS: + case B_RAND_BASE_ADDRESS: searchBase = (addr_t)addressRestrictions->address; searchEnd = fEndAddress; break; @@ -450,6 +451,73 @@ VMUserAddressSpace::_InsertAreaIntoReservedRegion(addr_t start, size_t size, } +/* http://graphics.stanford.edu/~seander/bithacks.html */ +static int +log2(uint32_t v) +{ + static const int multiply_debruijn_bit_position[32] = + { + 0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30, + 8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31 + }; + + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + + return multiply_debruijn_bit_position[(uint32_t)(v * 0x07c4acddu) >> 27]; +} + + +#ifdef B_HAIKU_64_BIT +const addr_t VMUserAddressSpace::kMaxRandomize = 0x8000000000ul; +const addr_t VMUserAddressSpace::kMaxInitialRandomize = 0x20000000000ul; +#else +const addr_t VMUserAddressSpace::kMaxRandomize = 0x800000ul; +const addr_t VMUserAddressSpace::kMaxInitialRandomize = 0x2000000ul; +#endif + + +addr_t +VMUserAddressSpace::_RandomizeAddress(addr_t start, addr_t end, bool initial) +{ + const int rand_shift = log2(RAND_MAX) + 1; + int shift = 0; + + if (start == end) + return start; + +#ifdef B_HAIKU_64_BIT + uint64_t random = 0; + + while (shift < 64) { + random |= (uint64_t)rand() << shift; + shift += rand_shift; + } +#else + uint32_t random = 0; + + while (shift < 32) { + random |= (uint32_t)rand() << shift; + shift += rand_shift; + } +#endif + + addr_t range = end - start; + if (initial) + range = min_c(range, kMaxInitialRandomize); + else + range = min_c(range, kMaxRandomize); + + random %= range; + random &= ~0xffful; + + return start + random; +} + + /*! Must be called with this address space's write lock held */ status_t VMUserAddressSpace::_InsertAreaSlot(addr_t start, addr_t size, addr_t end, @@ -459,6 +527,7 @@ VMUserAddressSpace::_InsertAreaSlot(addr_t start, addr_t size, addr_t end, VMUserArea* last = NULL; VMUserArea* next; bool foundSpot = false; + addr_t originalStart = 0; TRACE(("VMUserAddressSpace::_InsertAreaSlot: address space %p, start " "0x%lx, size %ld, end 0x%lx, addressSpec %" B_PRIu32 ", area %p\n", @@ -489,6 +558,11 @@ VMUserAddressSpace::_InsertAreaSlot(addr_t start, addr_t size, addr_t end, alignment <<= 1; } + if (addressSpec == B_RAND_BASE_ADDRESS) { + originalStart = start; + start = _RandomizeAddress(start, end - size, true); + } + start = ROUNDUP(start, alignment); // walk up to the spot where we should start searching @@ -614,6 +688,7 @@ second_chance: } case B_BASE_ADDRESS: + case B_RAND_BASE_ADDRESS: { // find a hole big enough for a new area beginning with "start" if (last == NULL) { @@ -646,15 +721,32 @@ second_chance: foundSpot = true; if (lastEnd < start) area->SetBase(start); - else - area->SetBase(lastEnd + 1); + else { + start = lastEnd + 1; + if (addressSpec == B_RAND_BASE_ADDRESS) { + addr_t spaceEnd = end; + if (next != NULL) + spaceEnd = next->Base(); + + start = _RandomizeAddress(lastEnd + 1, spaceEnd - size, + false); + } + + area->SetBase(start); + } break; } // we didn't find a free spot in the requested range, so we'll // try again without any restrictions - start = fBase; - addressSpec = B_ANY_ADDRESS; + if (addressSpec == B_RAND_BASE_ADDRESS && originalStart != 0) { + start = fBase; + addressSpec = B_ANY_ADDRESS; + } else { + start = originalStart; + originalStart = 0; + } + last = NULL; goto second_chance; } diff --git a/src/system/kernel/vm/VMUserAddressSpace.h b/src/system/kernel/vm/VMUserAddressSpace.h index fe5d37c..d24dc61 100644 --- a/src/system/kernel/vm/VMUserAddressSpace.h +++ b/src/system/kernel/vm/VMUserAddressSpace.h @@ -53,6 +53,9 @@ public: virtual void Dump() const; private: + static addr_t _RandomizeAddress(addr_t start, addr_t end, + bool initial); + status_t _InsertAreaIntoReservedRegion(addr_t start, size_t size, VMUserArea* area, uint32 allocationFlags); @@ -62,6 +65,9 @@ private: uint32 allocationFlags); private: + static const addr_t kMaxRandomize; + static const addr_t kMaxInitialRandomize; + VMUserAreaList fAreas; mutable VMUserArea* fAreaHint; }; diff --git a/src/system/kernel/vm/vm.cpp b/src/system/kernel/vm/vm.cpp index 6e809b6..d2e77c2 100644 --- a/src/system/kernel/vm/vm.cpp +++ b/src/system/kernel/vm/vm.cpp @@ -1219,6 +1219,7 @@ vm_create_anonymous_area(team_id team, const char *name, addr_t size, case B_BASE_ADDRESS: case B_ANY_KERNEL_ADDRESS: case B_ANY_KERNEL_BLOCK_ADDRESS: + case B_RAND_BASE_ADDRESS: break; default: