added 4 changesets to branch 'refs/remotes/pdziepak-github/aslr' old head: a6ce073ae11c9dbf311b9654e4efd38e065165a5 new head: d57105534be7e294889fd20c4b1c9ad8768cebce overview: https://github.com/pdziepak/Haiku/compare/a6ce073...d571055 ---------------------------------------------------------------------------- 65ed4fa: vm: implement B_RANDOMIZED_IMAGE_ADDRESS address specification On some 64 bit architectures program and library images have to be mapped in the lower 2 GB of the address space (due to instruction pointer relative addressing). Address specification B_RANDOMIZED_IMAGE_ADDRESS ensures that created area satisfies that requirement. 4cafc0a: runtime_loader: use long type for region delta a8f8d2c: x86_64: put user stack and team data at top of user address space d571055: vm: several improvements to VMUserAddressSpace::_InsertAreaSlot implementation * B_BASE_ADDRESS honors requested alignment * end of range is honored * B_BASE_ADDRESS reuses B_ANY_ADDRESS code [ Pawel Dziepak <pdziepak@xxxxxxxxxxx> ] ---------------------------------------------------------------------------- 6 files changed, 76 insertions(+), 92 deletions(-) headers/os/kernel/OS.h | 1 + headers/private/kernel/arch/x86/arch_kernel.h | 4 +- src/system/kernel/vm/VMUserAddressSpace.cpp | 155 ++++++++++------------ src/system/kernel/vm/VMUserAddressSpace.h | 1 + src/system/kernel/vm/vm.cpp | 1 + src/system/runtime_loader/images.cpp | 6 +- ############################################################################ Commit: 65ed4fa908cce8864aee0905014bb802857d601d Author: Pawel Dziepak <pdziepak@xxxxxxxxxxx> Date: Thu Apr 4 02:05:37 2013 UTC vm: implement B_RANDOMIZED_IMAGE_ADDRESS address specification On some 64 bit architectures program and library images have to be mapped in the lower 2 GB of the address space (due to instruction pointer relative addressing). Address specification B_RANDOMIZED_IMAGE_ADDRESS ensures that created area satisfies that requirement. ---------------------------------------------------------------------------- diff --git a/headers/os/kernel/OS.h b/headers/os/kernel/OS.h index dc91207..820b534 100644 --- a/headers/os/kernel/OS.h +++ b/headers/os/kernel/OS.h @@ -81,6 +81,7 @@ typedef struct area_info { /* B_ANY_KERNEL_BLOCK_ADDRESS 5 */ #define B_RANDOMIZED_ANY_ADDRESS 6 #define B_RANDOMIZED_BASE_ADDRESS 7 +#define B_RANDOMIZED_IMAGE_ADDRESS 8 /* area protection */ #define B_READ_AREA 1 diff --git a/src/system/kernel/vm/VMUserAddressSpace.cpp b/src/system/kernel/vm/VMUserAddressSpace.cpp index 1933eb6..ffb8b62 100644 --- a/src/system/kernel/vm/VMUserAddressSpace.cpp +++ b/src/system/kernel/vm/VMUserAddressSpace.cpp @@ -36,6 +36,7 @@ const addr_t VMUserAddressSpace::kMaxInitialRandomize = 0x20000000000ul; const addr_t VMUserAddressSpace::kMaxRandomize = 0x800000ul; const addr_t VMUserAddressSpace::kMaxInitialRandomize = 0x2000000ul; #endif +const addr_t VMUserAddressSpace::kImageEndAddress = 0x7ffffffful; /*! Verifies that an area with the given aligned base and size fits into @@ -69,6 +70,15 @@ log2(uint32_t v) } +static inline bool +is_randomized(uint32 addressSpec) +{ + return addressSpec == B_RANDOMIZED_ANY_ADDRESS + || addressSpec == B_RANDOMIZED_BASE_ADDRESS + || addressSpec == B_RANDOMIZED_IMAGE_ADDRESS; +} + + VMUserAddressSpace::VMUserAddressSpace(team_id id, addr_t base, size_t size) : VMAddressSpace(id, base, size, "address space"), @@ -183,6 +193,11 @@ VMUserAddressSpace::InsertArea(VMArea* _area, size_t size, searchEnd = fEndAddress; break; + case B_RANDOMIZED_IMAGE_ADDRESS: + searchBase = (addr_t)addressRestrictions->address; + searchEnd = min_c(fEndAddress, kImageEndAddress); + break; + default: return B_BAD_VALUE; } @@ -561,7 +576,9 @@ VMUserAddressSpace::_InsertAreaSlot(addr_t start, addr_t size, addr_t end, start = ROUNDUP(start, alignment); - if (addressSpec == B_RANDOMIZED_BASE_ADDRESS) { + if (addressSpec == B_RANDOMIZED_BASE_ADDRESS + || addressSpec == B_RANDOMIZED_IMAGE_ADDRESS) { + originalStart = start; start = _RandomizeAddress(start, end - size, alignment, true); } @@ -594,7 +611,7 @@ second_chance: addr_t nextBase = next == NULL ? end : next->Base(); if (is_valid_spot(start, alignedBase, size, nextBase)) { - if (addressSpec == B_RANDOMIZED_ANY_ADDRESS) { + if (is_randomized(addressSpec)) { alignedBase = _RandomizeAddress(alignedBase, nextBase - size, alignment); } @@ -615,7 +632,7 @@ second_chance: if (is_valid_spot(last->Base() + (last->Size() - 1), alignedBase, size, next->Base())) { - if (addressSpec == B_RANDOMIZED_ANY_ADDRESS) { + if (is_randomized(addressSpec)) { alignedBase = _RandomizeAddress(alignedBase, next->Base() - size, alignment); } @@ -637,7 +654,7 @@ second_chance: if (is_valid_spot(last->Base() + (last->Size() - 1), alignedBase, size, end)) { - if (addressSpec == B_RANDOMIZED_ANY_ADDRESS) { + if (is_randomized(addressSpec)) { alignedBase = _RandomizeAddress(alignedBase, end - size, alignment); } @@ -677,7 +694,7 @@ second_chance: && alignedBase == next->Base() && next->Size() >= size) { - if (addressSpec == B_RANDOMIZED_ANY_ADDRESS) { + if (is_randomized(addressSpec)) { alignedBase = _RandomizeAddress(next->Base(), next->Size() - size, alignment); } @@ -699,7 +716,7 @@ second_chance: // reserved area, and the reserved area will be resized // to make space - if (addressSpec == B_RANDOMIZED_ANY_ADDRESS) { + if (is_randomized(addressSpec)) { addr_t alignedNextBase = ROUNDUP(next->Base(), alignment); @@ -731,6 +748,7 @@ second_chance: case B_BASE_ADDRESS: case B_RANDOMIZED_BASE_ADDRESS: + case B_RANDOMIZED_IMAGE_ADDRESS: { // find a hole big enough for a new area beginning with "start" if (last == NULL) { @@ -765,7 +783,7 @@ second_chance: area->SetBase(start); else { start = lastEnd + 1; - if (addressSpec == B_RANDOMIZED_BASE_ADDRESS) { + if (is_randomized(addressSpec)) { addr_t spaceEnd = end; if (next != NULL) spaceEnd = next->Base(); @@ -781,7 +799,7 @@ second_chance: // we didn't find a free spot in the requested range, so we'll // try again without any restrictions - if (addressSpec != B_RANDOMIZED_BASE_ADDRESS) { + if (!is_randomized(addressSpec)) { start = fBase; addressSpec = B_ANY_ADDRESS; } else if (originalStart == 0) { diff --git a/src/system/kernel/vm/VMUserAddressSpace.h b/src/system/kernel/vm/VMUserAddressSpace.h index 0aa4261..8bd04bc 100644 --- a/src/system/kernel/vm/VMUserAddressSpace.h +++ b/src/system/kernel/vm/VMUserAddressSpace.h @@ -67,6 +67,7 @@ private: private: static const addr_t kMaxRandomize; static const addr_t kMaxInitialRandomize; + static const addr_t kImageEndAddress; VMUserAreaList fAreas; mutable VMUserArea* fAreaHint; diff --git a/src/system/kernel/vm/vm.cpp b/src/system/kernel/vm/vm.cpp index f9a2f4d..a730c0e 100644 --- a/src/system/kernel/vm/vm.cpp +++ b/src/system/kernel/vm/vm.cpp @@ -1226,6 +1226,7 @@ vm_create_anonymous_area(team_id team, const char *name, addr_t size, case B_ANY_KERNEL_BLOCK_ADDRESS: case B_RANDOMIZED_ANY_ADDRESS: case B_RANDOMIZED_BASE_ADDRESS: + case B_RANDOMIZED_IMAGE_ADDRESS: break; default: diff --git a/src/system/runtime_loader/images.cpp b/src/system/runtime_loader/images.cpp index d7323aa..21c3802 100644 --- a/src/system/runtime_loader/images.cpp +++ b/src/system/runtime_loader/images.cpp @@ -173,7 +173,7 @@ get_image_region_load_address(image_t* image, uint32 index, int32 lastDelta, if (index == 0) { // but only the first segment gets a free ride loadAddress = RLD_PROGRAM_BASE; - addressSpecifier = B_RANDOMIZED_BASE_ADDRESS; + addressSpecifier = B_RANDOMIZED_IMAGE_ADDRESS; } else { loadAddress = image->regions[index].vmstart + lastDelta; addressSpecifier = B_EXACT_ADDRESS; @@ -298,7 +298,7 @@ map_image(int fd, char const* path, image_t* image, bool fixed) addr_t loadAddress; size_t reservedSize = 0; size_t length = 0; - uint32 addressSpecifier = B_RANDOMIZED_ANY_ADDRESS; + uint32 addressSpecifier = B_RANDOMIZED_IMAGE_ADDRESS; for (uint32 i = 0; i < image->num_regions; i++) { // for BeOS compatibility: if we load an old BeOS executable, we ############################################################################ Commit: 4cafc0acab0fecc88fa5eeafef25ca587aab59d9 Author: Pawel Dziepak <pdziepak@xxxxxxxxxxx> Date: Thu Apr 4 18:54:13 2013 UTC runtime_loader: use long type for region delta ---------------------------------------------------------------------------- diff --git a/src/system/runtime_loader/images.cpp b/src/system/runtime_loader/images.cpp index 21c3802..55dcdf0 100644 --- a/src/system/runtime_loader/images.cpp +++ b/src/system/runtime_loader/images.cpp @@ -165,7 +165,7 @@ topological_sort(image_t* image, uint32 slot, image_t** initList, /*! Finds the load address and address specifier of the given image region. */ static void -get_image_region_load_address(image_t* image, uint32 index, int32 lastDelta, +get_image_region_load_address(image_t* image, uint32 index, long lastDelta, bool fixed, addr_t& loadAddress, uint32& addressSpecifier) { if (image->dynamic_ptr != 0 && !fixed) { ############################################################################ Commit: a8f8d2c057711ac2894f02e2b8704cd8b03c346f Author: Pawel Dziepak <pdziepak@xxxxxxxxxxx> Date: Thu Apr 4 18:54:56 2013 UTC x86_64: put user stack and team data at top of user address space ---------------------------------------------------------------------------- diff --git a/headers/private/kernel/arch/x86/arch_kernel.h b/headers/private/kernel/arch/x86/arch_kernel.h index 9736e09..f5d6c4d 100644 --- a/headers/private/kernel/arch/x86/arch_kernel.h +++ b/headers/private/kernel/arch/x86/arch_kernel.h @@ -48,8 +48,8 @@ #define USER_SIZE (0x800000000000 - 0x200000) #define USER_TOP (USER_BASE + (USER_SIZE - 1)) -#define KERNEL_USER_DATA_BASE 0x7fffe0000000 -#define USER_STACK_REGION 0x7ffff0000000 +#define KERNEL_USER_DATA_BASE 0x7f0000000000 +#define USER_STACK_REGION 0x7f0000000000 #define USER_STACK_REGION_SIZE ((USER_TOP - USER_STACK_REGION) + 1) ############################################################################ Commit: d57105534be7e294889fd20c4b1c9ad8768cebce Author: Pawel Dziepak <pdziepak@xxxxxxxxxxx> Date: Thu Apr 4 18:56:41 2013 UTC vm: several improvements to VMUserAddressSpace::_InsertAreaSlot implementation * B_BASE_ADDRESS honors requested alignment * end of range is honored * B_BASE_ADDRESS reuses B_ANY_ADDRESS code ---------------------------------------------------------------------------- diff --git a/src/system/kernel/vm/VMUserAddressSpace.cpp b/src/system/kernel/vm/VMUserAddressSpace.cpp index ffb8b62..9315e97 100644 --- a/src/system/kernel/vm/VMUserAddressSpace.cpp +++ b/src/system/kernel/vm/VMUserAddressSpace.cpp @@ -186,10 +186,6 @@ VMUserAddressSpace::InsertArea(VMArea* _area, size_t size, case B_ANY_KERNEL_BLOCK_ADDRESS: case B_RANDOMIZED_ANY_ADDRESS: searchBase = fBase; - // TODO: remove this again when vm86 mode is moved into the kernel - // completely (currently needs a userland address space!) - if (searchBase == USER_BASE) - searchBase = USER_BASE_ANY; searchEnd = fEndAddress; break; @@ -202,6 +198,11 @@ VMUserAddressSpace::InsertArea(VMArea* _area, size_t size, return B_BAD_VALUE; } + // TODO: remove this again when vm86 mode is moved into the kernel + // completely (currently needs a userland address space!) + if (addressRestrictions->address_specification != B_EXACT_ADDRESS) + searchBase = max_c(searchBase, USER_BASE_ANY); + status = _InsertAreaSlot(searchBase, size, searchEnd, addressRestrictions->address_specification, addressRestrictions->alignment, area, allocationFlags); @@ -603,17 +604,21 @@ second_chance: case B_ANY_KERNEL_ADDRESS: case B_ANY_KERNEL_BLOCK_ADDRESS: case B_RANDOMIZED_ANY_ADDRESS: + case B_BASE_ADDRESS: + case B_RANDOMIZED_BASE_ADDRESS: + case B_RANDOMIZED_IMAGE_ADDRESS: { // find a hole big enough for a new area if (last == NULL) { // see if we can build it at the beginning of the virtual map addr_t alignedBase = ROUNDUP(start, alignment); - addr_t nextBase = next == NULL ? end : next->Base(); + addr_t nextBase = next == NULL ? end : min_c(next->Base(), end); if (is_valid_spot(start, alignedBase, size, nextBase)) { + addr_t rangeEnd = min_c(nextBase - size, end); if (is_randomized(addressSpec)) { - alignedBase = _RandomizeAddress(alignedBase, - nextBase - size, alignment); + alignedBase = _RandomizeAddress(alignedBase, rangeEnd, + alignment); } foundSpot = true; @@ -626,15 +631,17 @@ second_chance: } // keep walking - while (next != NULL) { + while (next != NULL && next->Base() + size - 1 <= end) { addr_t alignedBase = ROUNDUP(last->Base() + last->Size(), alignment); + addr_t nextBase = min_c(end, next->Base()); if (is_valid_spot(last->Base() + (last->Size() - 1), - alignedBase, size, next->Base())) { + alignedBase, size, nextBase)) { + addr_t rangeEnd = min_c(nextBase - size, end); if (is_randomized(addressSpec)) { alignedBase = _RandomizeAddress(alignedBase, - next->Base() - size, alignment); + rangeEnd, alignment); } foundSpot = true; @@ -663,6 +670,24 @@ second_chance: foundSpot = true; area->SetBase(alignedBase); break; + } else if (addressSpec == B_BASE_ADDRESS + || addressSpec == B_RANDOMIZED_BASE_ADDRESS + || addressSpec == B_RANDOMIZED_IMAGE_ADDRESS) { + + // we didn't find a free spot in the requested range, so we'll + // try again without any restrictions + start = USER_BASE_ANY; + if (!is_randomized(addressSpec)) + addressSpec = B_ANY_ADDRESS; + else if (start == originalStart) + addressSpec = B_RANDOMIZED_ANY_ADDRESS; + else { + start = originalStart; + addressSpec = B_RANDOMIZED_BASE_ADDRESS; + } + + last = NULL; + goto second_chance; } else if (area->id != RESERVED_AREA_ID) { // We didn't find a free spot - if there are any reserved areas, // we can now test those for free space @@ -673,7 +698,8 @@ second_chance: if (next->id != RESERVED_AREA_ID) { last = next; continue; - } + } else if (next->Base() + size - 1 > end) + break; // TODO: take free space after the reserved area into // account! @@ -694,9 +720,10 @@ second_chance: && alignedBase == next->Base() && next->Size() >= size) { + addr_t rangeEnd = min_c(next->Size() - size, end); if (is_randomized(addressSpec)) { alignedBase = _RandomizeAddress(next->Base(), - next->Size() - size, alignment); + rangeEnd, alignment); } addr_t offset = alignedBase - next->Base(); @@ -711,7 +738,7 @@ second_chance: } if (is_valid_spot(next->Base(), alignedBase, size, - next->Base() + (next->Size() - 1))) { + min_c(next->Base() + next->Size() - 1, end))) { // The new area will be placed at the end of the // reserved area, and the reserved area will be resized // to make space @@ -726,8 +753,11 @@ second_chance: startRange = max_c(startRange, alignedNextBase); + addr_t rangeEnd + = min_c(next->Base() + next->Size() - size, + end); alignedBase = _RandomizeAddress(startRange, - next->Base() + next->Size() - size, alignment); + rangeEnd, alignment); } else { alignedBase = ROUNDDOWN( next->Base() + next->Size() - size, alignment); @@ -743,75 +773,8 @@ second_chance: last = next; } } - break; - } - - case B_BASE_ADDRESS: - case B_RANDOMIZED_BASE_ADDRESS: - case B_RANDOMIZED_IMAGE_ADDRESS: - { - // find a hole big enough for a new area beginning with "start" - if (last == NULL) { - // see if we can build it at the beginning of the specified - // start - if (next == NULL || next->Base() > start + (size - 1)) { - foundSpot = true; - area->SetBase(start); - break; - } - - last = next; - next = it.Next(); - } - - // keep walking - while (next != NULL) { - if (next->Base() - (last->Base() + last->Size()) >= size) { - // we found a spot (it'll be filled up below) - break; - } - - last = next; - next = it.Next(); - } - - addr_t lastEnd = last->Base() + (last->Size() - 1); - if (next != NULL || end - lastEnd >= size) { - // got a spot - foundSpot = true; - if (lastEnd < start) - area->SetBase(start); - else { - start = lastEnd + 1; - if (is_randomized(addressSpec)) { - addr_t spaceEnd = end; - if (next != NULL) - spaceEnd = next->Base(); - - start = _RandomizeAddress(lastEnd + 1, spaceEnd - size, - B_PAGE_SIZE); - } - - area->SetBase(start); - } - break; - } - // we didn't find a free spot in the requested range, so we'll - // try again without any restrictions - if (!is_randomized(addressSpec)) { - start = fBase; - addressSpec = B_ANY_ADDRESS; - } else if (originalStart == 0) { - start = fBase; - addressSpec = B_RANDOMIZED_ANY_ADDRESS; - } else { - start = originalStart; - originalStart = 0; - } - - last = NULL; - goto second_chance; + break; } case B_EXACT_ADDRESS: