| 1 | //===-- guarded_pool_allocator_fuchsia.cpp ----------------------*- C++ -*-===// |
| 2 | // |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | |
| 9 | #include "gwp_asan/guarded_pool_allocator.h" |
| 10 | #include "gwp_asan/utilities.h" |
| 11 | |
| 12 | #include <assert.h> |
| 13 | #include <stdint.h> |
| 14 | #include <string.h> |
| 15 | #include <zircon/process.h> |
| 16 | #include <zircon/syscalls.h> |
| 17 | |
| 18 | namespace gwp_asan { |
| 19 | void GuardedPoolAllocator::initPRNG() { |
| 20 | _zx_cprng_draw(&getThreadLocals()->RandomState, sizeof(uint32_t)); |
| 21 | } |
| 22 | |
| 23 | void *GuardedPoolAllocator::map(size_t Size, const char *Name) const { |
| 24 | assert((Size % State.PageSize) == 0); |
| 25 | zx_handle_t Vmo; |
| 26 | zx_status_t Status = _zx_vmo_create(Size, 0, &Vmo); |
| 27 | checkWithErrorCode(Status == ZX_OK, "Failed to create Vmo" , Status); |
| 28 | _zx_object_set_property(Vmo, ZX_PROP_NAME, Name, strlen(s: Name)); |
| 29 | zx_vaddr_t Addr; |
| 30 | Status = _zx_vmar_map(_zx_vmar_root_self(), |
| 31 | ZX_VM_PERM_READ | ZX_VM_PERM_WRITE | ZX_VM_ALLOW_FAULTS, |
| 32 | 0, Vmo, 0, Size, &Addr); |
| 33 | checkWithErrorCode(Status == ZX_OK, "Vmo mapping failed" , Status); |
| 34 | _zx_handle_close(Vmo); |
| 35 | return reinterpret_cast<void *>(Addr); |
| 36 | } |
| 37 | |
| 38 | void GuardedPoolAllocator::unmap(void *Ptr, size_t Size) const { |
| 39 | assert((reinterpret_cast<uintptr_t>(Ptr) % State.PageSize) == 0); |
| 40 | assert((Size % State.PageSize) == 0); |
| 41 | zx_status_t Status = _zx_vmar_unmap(_zx_vmar_root_self(), |
| 42 | reinterpret_cast<zx_vaddr_t>(Ptr), Size); |
| 43 | checkWithErrorCode(Status == ZX_OK, "Vmo unmapping failed" , Status); |
| 44 | } |
| 45 | |
| 46 | void *GuardedPoolAllocator::reserveGuardedPool(size_t Size) { |
| 47 | assert((Size % State.PageSize) == 0); |
| 48 | zx_vaddr_t Addr; |
| 49 | const zx_status_t Status = _zx_vmar_allocate( |
| 50 | _zx_vmar_root_self(), |
| 51 | ZX_VM_CAN_MAP_READ | ZX_VM_CAN_MAP_WRITE | ZX_VM_CAN_MAP_SPECIFIC, 0, |
| 52 | Size, &GuardedPagePoolPlatformData.Vmar, &Addr); |
| 53 | checkWithErrorCode(Status == ZX_OK, |
| 54 | "Failed to reserve guarded pool allocator memory" , Status); |
| 55 | _zx_object_set_property(GuardedPagePoolPlatformData.Vmar, ZX_PROP_NAME, |
| 56 | kGwpAsanGuardPageName, strlen(s: kGwpAsanGuardPageName)); |
| 57 | return reinterpret_cast<void *>(Addr); |
| 58 | } |
| 59 | |
| 60 | void GuardedPoolAllocator::unreserveGuardedPool() { |
| 61 | const zx_handle_t Vmar = GuardedPagePoolPlatformData.Vmar; |
| 62 | assert(Vmar != ZX_HANDLE_INVALID && Vmar != _zx_vmar_root_self()); |
| 63 | zx_status_t Status = _zx_vmar_destroy(Vmar); |
| 64 | checkWithErrorCode(Status == ZX_OK, "Failed to destroy a vmar" , Status); |
| 65 | Status = _zx_handle_close(Vmar); |
| 66 | checkWithErrorCode(Status == ZX_OK, "Failed to close a vmar" , Status); |
| 67 | GuardedPagePoolPlatformData.Vmar = ZX_HANDLE_INVALID; |
| 68 | } |
| 69 | |
| 70 | void GuardedPoolAllocator::allocateInGuardedPool(void *Ptr, size_t Size) const { |
| 71 | assert((reinterpret_cast<uintptr_t>(Ptr) % State.PageSize) == 0); |
| 72 | assert((Size % State.PageSize) == 0); |
| 73 | zx_handle_t Vmo; |
| 74 | zx_status_t Status = _zx_vmo_create(Size, 0, &Vmo); |
| 75 | checkWithErrorCode(Status == ZX_OK, "Failed to create vmo" , Status); |
| 76 | _zx_object_set_property(Vmo, ZX_PROP_NAME, kGwpAsanAliveSlotName, |
| 77 | strlen(s: kGwpAsanAliveSlotName)); |
| 78 | const zx_handle_t Vmar = GuardedPagePoolPlatformData.Vmar; |
| 79 | assert(Vmar != ZX_HANDLE_INVALID && Vmar != _zx_vmar_root_self()); |
| 80 | const size_t Offset = |
| 81 | reinterpret_cast<uintptr_t>(Ptr) - State.GuardedPagePool; |
| 82 | zx_vaddr_t P; |
| 83 | Status = _zx_vmar_map(Vmar, |
| 84 | ZX_VM_PERM_READ | ZX_VM_PERM_WRITE | |
| 85 | ZX_VM_ALLOW_FAULTS | ZX_VM_SPECIFIC, |
| 86 | Offset, Vmo, 0, Size, &P); |
| 87 | checkWithErrorCode(Status == ZX_OK, "Vmo mapping failed" , Status); |
| 88 | _zx_handle_close(Vmo); |
| 89 | } |
| 90 | |
| 91 | void GuardedPoolAllocator::deallocateInGuardedPool(void *Ptr, |
| 92 | size_t Size) const { |
| 93 | assert((reinterpret_cast<uintptr_t>(Ptr) % State.PageSize) == 0); |
| 94 | assert((Size % State.PageSize) == 0); |
| 95 | const zx_handle_t Vmar = GuardedPagePoolPlatformData.Vmar; |
| 96 | assert(Vmar != ZX_HANDLE_INVALID && Vmar != _zx_vmar_root_self()); |
| 97 | const zx_status_t Status = |
| 98 | _zx_vmar_unmap(Vmar, reinterpret_cast<zx_vaddr_t>(Ptr), Size); |
| 99 | checkWithErrorCode(Status == ZX_OK, "Vmar unmapping failed" , Status); |
| 100 | } |
| 101 | |
| 102 | size_t GuardedPoolAllocator::getPlatformPageSize() { |
| 103 | return _zx_system_get_page_size(); |
| 104 | } |
| 105 | |
| 106 | void GuardedPoolAllocator::installAtFork() {} |
| 107 | } // namespace gwp_asan |
| 108 | |