diff --git a/headers/private/kernel/syscalls.h b/headers/private/kernel/syscalls.h index 71f4a0ed4d..43ea507567 100644 --- a/headers/private/kernel/syscalls.h +++ b/headers/private/kernel/syscalls.h @@ -229,7 +229,8 @@ extern status_t _kern_transfer_area(area_id area, void **_address, uint32 addre extern status_t _kern_set_area_protection(area_id area, uint32 newProtection); extern area_id _kern_clone_area(const char *name, void **_address, uint32 addressSpec, uint32 protection, area_id sourceArea); -extern status_t _kern_init_heap_address_range(addr_t base, addr_t size); +extern status_t _kern_reserve_heap_address_range(addr_t* _address, uint32 addressSpec, + addr_t size); area_id sys_vm_map_file(const char *name, void **address, int addr_type, addr_t size, int lock, int mapping, const char *path, off_t offset); diff --git a/headers/private/kernel/vm.h b/headers/private/kernel/vm.h index 842d643780..d3c3bb9665 100644 --- a/headers/private/kernel/vm.h +++ b/headers/private/kernel/vm.h @@ -81,7 +81,8 @@ status_t _user_transfer_area(area_id area, void **_address, uint32 addressSpec, status_t _user_set_area_protection(area_id area, uint32 newProtection); area_id _user_clone_area(const char *name, void **_address, uint32 addressSpec, uint32 protection, area_id sourceArea); -status_t _user_init_heap_address_range(addr_t base, addr_t size); +status_t _user_reserve_heap_address_range(addr_t* userAddress, uint32 addressSpec, + addr_t size); #ifdef __cplusplus } diff --git a/src/system/kernel/vm/vm.cpp b/src/system/kernel/vm/vm.cpp index a4247749bb..ca45001871 100644 --- a/src/system/kernel/vm/vm.cpp +++ b/src/system/kernel/vm/vm.cpp @@ -3468,10 +3468,33 @@ delete_area(area_id area) status_t -_user_init_heap_address_range(addr_t base, addr_t size) +_user_reserve_heap_address_range(addr_t* userAddress, uint32 addressSpec, addr_t size) { - return vm_reserve_address_range(vm_current_user_address_space_id(), (void **)&base, - B_EXACT_ADDRESS, size, RESERVED_AVOID_BASE); + // filter out some unavailable values (for userland) + switch (addressSpec) { + case B_ANY_KERNEL_ADDRESS: + case B_ANY_KERNEL_BLOCK_ADDRESS: + return B_BAD_VALUE; + } + + addr_t address; + + if (!IS_USER_ADDRESS(userAddress) + || user_memcpy(&address, userAddress, sizeof(address)) < B_OK) + return B_BAD_ADDRESS; + + status_t status = vm_reserve_address_range(vm_current_user_address_space_id(), + (void **)&address, addressSpec, size, RESERVED_AVOID_BASE); + if (status < B_OK) + return status; + + if (user_memcpy(userAddress, &address, sizeof(address)) < B_OK) { + vm_unreserve_address_range(vm_current_user_address_space_id(), + (void *)address, size); + return B_BAD_ADDRESS; + } + + return B_OK; } diff --git a/src/system/libroot/posix/malloc/arch-specific.cpp b/src/system/libroot/posix/malloc/arch-specific.cpp index 0afb82d71f..c1a7e7c6d5 100644 --- a/src/system/libroot/posix/malloc/arch-specific.cpp +++ b/src/system/libroot/posix/malloc/arch-specific.cpp @@ -83,7 +83,8 @@ __init_heap(void) // for it. They may get reclaimed by other areas, though, but the maximum // size of the heap is guaranteed until the space is really needed. sHeapBase = (void *)0x18000000; - status_t status = _kern_init_heap_address_range((addr_t)sHeapBase, 0x48000000); + status_t status = _kern_reserve_heap_address_range((addr_t *)&sHeapBase, + B_EXACT_ADDRESS, 0x48000000); sHeapArea = create_area("heap", (void **)&sHeapBase, status == B_OK ? B_EXACT_ADDRESS : B_BASE_ADDRESS,