1*76559068SAndroid Build Coastguard Worker //===-- fuchsia.cpp ---------------------------------------------*- C++ -*-===//
2*76559068SAndroid Build Coastguard Worker //
3*76559068SAndroid Build Coastguard Worker // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*76559068SAndroid Build Coastguard Worker // See https://llvm.org/LICENSE.txt for license information.
5*76559068SAndroid Build Coastguard Worker // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*76559068SAndroid Build Coastguard Worker //
7*76559068SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
8*76559068SAndroid Build Coastguard Worker
9*76559068SAndroid Build Coastguard Worker #include "platform.h"
10*76559068SAndroid Build Coastguard Worker
11*76559068SAndroid Build Coastguard Worker #if SCUDO_FUCHSIA
12*76559068SAndroid Build Coastguard Worker
13*76559068SAndroid Build Coastguard Worker #include "common.h"
14*76559068SAndroid Build Coastguard Worker #include "mutex.h"
15*76559068SAndroid Build Coastguard Worker #include "string_utils.h"
16*76559068SAndroid Build Coastguard Worker
17*76559068SAndroid Build Coastguard Worker #include <lib/sync/mutex.h> // for sync_mutex_t
18*76559068SAndroid Build Coastguard Worker #include <stdlib.h> // for getenv()
19*76559068SAndroid Build Coastguard Worker #include <zircon/compiler.h>
20*76559068SAndroid Build Coastguard Worker #include <zircon/process.h>
21*76559068SAndroid Build Coastguard Worker #include <zircon/sanitizer.h>
22*76559068SAndroid Build Coastguard Worker #include <zircon/status.h>
23*76559068SAndroid Build Coastguard Worker #include <zircon/syscalls.h>
24*76559068SAndroid Build Coastguard Worker
25*76559068SAndroid Build Coastguard Worker namespace scudo {
26*76559068SAndroid Build Coastguard Worker
getPageSize()27*76559068SAndroid Build Coastguard Worker uptr getPageSize() { return _zx_system_get_page_size(); }
28*76559068SAndroid Build Coastguard Worker
die()29*76559068SAndroid Build Coastguard Worker void NORETURN die() { __builtin_trap(); }
30*76559068SAndroid Build Coastguard Worker
31*76559068SAndroid Build Coastguard Worker // We zero-initialize the Extra parameter of map(), make sure this is consistent
32*76559068SAndroid Build Coastguard Worker // with ZX_HANDLE_INVALID.
33*76559068SAndroid Build Coastguard Worker static_assert(ZX_HANDLE_INVALID == 0, "");
34*76559068SAndroid Build Coastguard Worker
dieOnError(zx_status_t Status,const char * FnName,uptr Size)35*76559068SAndroid Build Coastguard Worker static void NORETURN dieOnError(zx_status_t Status, const char *FnName,
36*76559068SAndroid Build Coastguard Worker uptr Size) {
37*76559068SAndroid Build Coastguard Worker ScopedString Error;
38*76559068SAndroid Build Coastguard Worker Error.append("SCUDO ERROR: %s failed with size %zuKB (%s)", FnName,
39*76559068SAndroid Build Coastguard Worker Size >> 10, zx_status_get_string(Status));
40*76559068SAndroid Build Coastguard Worker outputRaw(Error.data());
41*76559068SAndroid Build Coastguard Worker die();
42*76559068SAndroid Build Coastguard Worker }
43*76559068SAndroid Build Coastguard Worker
allocateVmar(uptr Size,MapPlatformData * Data,bool AllowNoMem)44*76559068SAndroid Build Coastguard Worker static void *allocateVmar(uptr Size, MapPlatformData *Data, bool AllowNoMem) {
45*76559068SAndroid Build Coastguard Worker // Only scenario so far.
46*76559068SAndroid Build Coastguard Worker DCHECK(Data);
47*76559068SAndroid Build Coastguard Worker DCHECK_EQ(Data->Vmar, ZX_HANDLE_INVALID);
48*76559068SAndroid Build Coastguard Worker
49*76559068SAndroid Build Coastguard Worker const zx_status_t Status = _zx_vmar_allocate(
50*76559068SAndroid Build Coastguard Worker _zx_vmar_root_self(),
51*76559068SAndroid Build Coastguard Worker ZX_VM_CAN_MAP_READ | ZX_VM_CAN_MAP_WRITE | ZX_VM_CAN_MAP_SPECIFIC, 0,
52*76559068SAndroid Build Coastguard Worker Size, &Data->Vmar, &Data->VmarBase);
53*76559068SAndroid Build Coastguard Worker if (UNLIKELY(Status != ZX_OK)) {
54*76559068SAndroid Build Coastguard Worker if (Status != ZX_ERR_NO_MEMORY || !AllowNoMem)
55*76559068SAndroid Build Coastguard Worker dieOnError(Status, "zx_vmar_allocate", Size);
56*76559068SAndroid Build Coastguard Worker return nullptr;
57*76559068SAndroid Build Coastguard Worker }
58*76559068SAndroid Build Coastguard Worker return reinterpret_cast<void *>(Data->VmarBase);
59*76559068SAndroid Build Coastguard Worker }
60*76559068SAndroid Build Coastguard Worker
map(void * Addr,uptr Size,const char * Name,uptr Flags,MapPlatformData * Data)61*76559068SAndroid Build Coastguard Worker void *map(void *Addr, uptr Size, const char *Name, uptr Flags,
62*76559068SAndroid Build Coastguard Worker MapPlatformData *Data) {
63*76559068SAndroid Build Coastguard Worker DCHECK_EQ(Size % getPageSizeCached(), 0);
64*76559068SAndroid Build Coastguard Worker const bool AllowNoMem = !!(Flags & MAP_ALLOWNOMEM);
65*76559068SAndroid Build Coastguard Worker
66*76559068SAndroid Build Coastguard Worker // For MAP_NOACCESS, just allocate a Vmar and return.
67*76559068SAndroid Build Coastguard Worker if (Flags & MAP_NOACCESS)
68*76559068SAndroid Build Coastguard Worker return allocateVmar(Size, Data, AllowNoMem);
69*76559068SAndroid Build Coastguard Worker
70*76559068SAndroid Build Coastguard Worker const zx_handle_t Vmar = (Data && Data->Vmar != ZX_HANDLE_INVALID)
71*76559068SAndroid Build Coastguard Worker ? Data->Vmar
72*76559068SAndroid Build Coastguard Worker : _zx_vmar_root_self();
73*76559068SAndroid Build Coastguard Worker
74*76559068SAndroid Build Coastguard Worker zx_status_t Status;
75*76559068SAndroid Build Coastguard Worker zx_handle_t Vmo;
76*76559068SAndroid Build Coastguard Worker uint64_t VmoSize = 0;
77*76559068SAndroid Build Coastguard Worker if (Data && Data->Vmo != ZX_HANDLE_INVALID) {
78*76559068SAndroid Build Coastguard Worker // If a Vmo was specified, it's a resize operation.
79*76559068SAndroid Build Coastguard Worker CHECK(Addr);
80*76559068SAndroid Build Coastguard Worker DCHECK(Flags & MAP_RESIZABLE);
81*76559068SAndroid Build Coastguard Worker Vmo = Data->Vmo;
82*76559068SAndroid Build Coastguard Worker VmoSize = Data->VmoSize;
83*76559068SAndroid Build Coastguard Worker Status = _zx_vmo_set_size(Vmo, VmoSize + Size);
84*76559068SAndroid Build Coastguard Worker if (Status != ZX_OK) {
85*76559068SAndroid Build Coastguard Worker if (Status != ZX_ERR_NO_MEMORY || !AllowNoMem)
86*76559068SAndroid Build Coastguard Worker dieOnError(Status, "zx_vmo_set_size", VmoSize + Size);
87*76559068SAndroid Build Coastguard Worker return nullptr;
88*76559068SAndroid Build Coastguard Worker }
89*76559068SAndroid Build Coastguard Worker } else {
90*76559068SAndroid Build Coastguard Worker // Otherwise, create a Vmo and set its name.
91*76559068SAndroid Build Coastguard Worker Status = _zx_vmo_create(Size, ZX_VMO_RESIZABLE, &Vmo);
92*76559068SAndroid Build Coastguard Worker if (UNLIKELY(Status != ZX_OK)) {
93*76559068SAndroid Build Coastguard Worker if (Status != ZX_ERR_NO_MEMORY || !AllowNoMem)
94*76559068SAndroid Build Coastguard Worker dieOnError(Status, "zx_vmo_create", Size);
95*76559068SAndroid Build Coastguard Worker return nullptr;
96*76559068SAndroid Build Coastguard Worker }
97*76559068SAndroid Build Coastguard Worker _zx_object_set_property(Vmo, ZX_PROP_NAME, Name, strlen(Name));
98*76559068SAndroid Build Coastguard Worker }
99*76559068SAndroid Build Coastguard Worker
100*76559068SAndroid Build Coastguard Worker uintptr_t P;
101*76559068SAndroid Build Coastguard Worker zx_vm_option_t MapFlags =
102*76559068SAndroid Build Coastguard Worker ZX_VM_PERM_READ | ZX_VM_PERM_WRITE | ZX_VM_ALLOW_FAULTS;
103*76559068SAndroid Build Coastguard Worker if (Addr)
104*76559068SAndroid Build Coastguard Worker DCHECK(Data);
105*76559068SAndroid Build Coastguard Worker const uint64_t Offset =
106*76559068SAndroid Build Coastguard Worker Addr ? reinterpret_cast<uintptr_t>(Addr) - Data->VmarBase : 0;
107*76559068SAndroid Build Coastguard Worker if (Offset)
108*76559068SAndroid Build Coastguard Worker MapFlags |= ZX_VM_SPECIFIC;
109*76559068SAndroid Build Coastguard Worker Status = _zx_vmar_map(Vmar, MapFlags, Offset, Vmo, VmoSize, Size, &P);
110*76559068SAndroid Build Coastguard Worker if (UNLIKELY(Status != ZX_OK)) {
111*76559068SAndroid Build Coastguard Worker if (Status != ZX_ERR_NO_MEMORY || !AllowNoMem)
112*76559068SAndroid Build Coastguard Worker dieOnError(Status, "zx_vmar_map", Size);
113*76559068SAndroid Build Coastguard Worker return nullptr;
114*76559068SAndroid Build Coastguard Worker }
115*76559068SAndroid Build Coastguard Worker
116*76559068SAndroid Build Coastguard Worker if (Flags & MAP_PRECOMMIT) {
117*76559068SAndroid Build Coastguard Worker Status = _zx_vmar_op_range(Vmar, ZX_VMAR_OP_COMMIT, P, Size,
118*76559068SAndroid Build Coastguard Worker /*buffer=*/nullptr, /*buffer_size=*/0);
119*76559068SAndroid Build Coastguard Worker }
120*76559068SAndroid Build Coastguard Worker
121*76559068SAndroid Build Coastguard Worker // No need to track the Vmo if we don't intend on resizing it. Close it.
122*76559068SAndroid Build Coastguard Worker if (Flags & MAP_RESIZABLE) {
123*76559068SAndroid Build Coastguard Worker DCHECK(Data);
124*76559068SAndroid Build Coastguard Worker if (Data->Vmo == ZX_HANDLE_INVALID)
125*76559068SAndroid Build Coastguard Worker Data->Vmo = Vmo;
126*76559068SAndroid Build Coastguard Worker else
127*76559068SAndroid Build Coastguard Worker DCHECK_EQ(Data->Vmo, Vmo);
128*76559068SAndroid Build Coastguard Worker } else {
129*76559068SAndroid Build Coastguard Worker CHECK_EQ(_zx_handle_close(Vmo), ZX_OK);
130*76559068SAndroid Build Coastguard Worker }
131*76559068SAndroid Build Coastguard Worker if (UNLIKELY(Status != ZX_OK)) {
132*76559068SAndroid Build Coastguard Worker if (Status != ZX_ERR_NO_MEMORY || !AllowNoMem)
133*76559068SAndroid Build Coastguard Worker dieOnError(Status, "zx_vmar_op_range", Size);
134*76559068SAndroid Build Coastguard Worker return nullptr;
135*76559068SAndroid Build Coastguard Worker }
136*76559068SAndroid Build Coastguard Worker
137*76559068SAndroid Build Coastguard Worker if (Data)
138*76559068SAndroid Build Coastguard Worker Data->VmoSize += Size;
139*76559068SAndroid Build Coastguard Worker
140*76559068SAndroid Build Coastguard Worker return reinterpret_cast<void *>(P);
141*76559068SAndroid Build Coastguard Worker }
142*76559068SAndroid Build Coastguard Worker
unmap(void * Addr,uptr Size,uptr Flags,MapPlatformData * Data)143*76559068SAndroid Build Coastguard Worker void unmap(void *Addr, uptr Size, uptr Flags, MapPlatformData *Data) {
144*76559068SAndroid Build Coastguard Worker if (Flags & UNMAP_ALL) {
145*76559068SAndroid Build Coastguard Worker DCHECK_NE(Data, nullptr);
146*76559068SAndroid Build Coastguard Worker const zx_handle_t Vmar = Data->Vmar;
147*76559068SAndroid Build Coastguard Worker DCHECK_NE(Vmar, _zx_vmar_root_self());
148*76559068SAndroid Build Coastguard Worker // Destroying the vmar effectively unmaps the whole mapping.
149*76559068SAndroid Build Coastguard Worker CHECK_EQ(_zx_vmar_destroy(Vmar), ZX_OK);
150*76559068SAndroid Build Coastguard Worker CHECK_EQ(_zx_handle_close(Vmar), ZX_OK);
151*76559068SAndroid Build Coastguard Worker } else {
152*76559068SAndroid Build Coastguard Worker const zx_handle_t Vmar = (Data && Data->Vmar != ZX_HANDLE_INVALID)
153*76559068SAndroid Build Coastguard Worker ? Data->Vmar
154*76559068SAndroid Build Coastguard Worker : _zx_vmar_root_self();
155*76559068SAndroid Build Coastguard Worker const zx_status_t Status =
156*76559068SAndroid Build Coastguard Worker _zx_vmar_unmap(Vmar, reinterpret_cast<uintptr_t>(Addr), Size);
157*76559068SAndroid Build Coastguard Worker if (UNLIKELY(Status != ZX_OK))
158*76559068SAndroid Build Coastguard Worker dieOnError(Status, "zx_vmar_unmap", Size);
159*76559068SAndroid Build Coastguard Worker }
160*76559068SAndroid Build Coastguard Worker if (Data) {
161*76559068SAndroid Build Coastguard Worker if (Data->Vmo != ZX_HANDLE_INVALID)
162*76559068SAndroid Build Coastguard Worker CHECK_EQ(_zx_handle_close(Data->Vmo), ZX_OK);
163*76559068SAndroid Build Coastguard Worker memset(Data, 0, sizeof(*Data));
164*76559068SAndroid Build Coastguard Worker }
165*76559068SAndroid Build Coastguard Worker }
166*76559068SAndroid Build Coastguard Worker
setMemoryPermission(UNUSED uptr Addr,UNUSED uptr Size,UNUSED uptr Flags,UNUSED MapPlatformData * Data)167*76559068SAndroid Build Coastguard Worker void setMemoryPermission(UNUSED uptr Addr, UNUSED uptr Size, UNUSED uptr Flags,
168*76559068SAndroid Build Coastguard Worker UNUSED MapPlatformData *Data) {
169*76559068SAndroid Build Coastguard Worker const zx_vm_option_t Prot =
170*76559068SAndroid Build Coastguard Worker (Flags & MAP_NOACCESS) ? 0 : (ZX_VM_PERM_READ | ZX_VM_PERM_WRITE);
171*76559068SAndroid Build Coastguard Worker DCHECK(Data);
172*76559068SAndroid Build Coastguard Worker DCHECK_NE(Data->Vmar, ZX_HANDLE_INVALID);
173*76559068SAndroid Build Coastguard Worker const zx_status_t Status = _zx_vmar_protect(Data->Vmar, Prot, Addr, Size);
174*76559068SAndroid Build Coastguard Worker if (Status != ZX_OK)
175*76559068SAndroid Build Coastguard Worker dieOnError(Status, "zx_vmar_protect", Size);
176*76559068SAndroid Build Coastguard Worker }
177*76559068SAndroid Build Coastguard Worker
releasePagesToOS(UNUSED uptr BaseAddress,uptr Offset,uptr Size,MapPlatformData * Data)178*76559068SAndroid Build Coastguard Worker void releasePagesToOS(UNUSED uptr BaseAddress, uptr Offset, uptr Size,
179*76559068SAndroid Build Coastguard Worker MapPlatformData *Data) {
180*76559068SAndroid Build Coastguard Worker // TODO: DCHECK the BaseAddress is consistent with the data in
181*76559068SAndroid Build Coastguard Worker // MapPlatformData.
182*76559068SAndroid Build Coastguard Worker DCHECK(Data);
183*76559068SAndroid Build Coastguard Worker DCHECK_NE(Data->Vmar, ZX_HANDLE_INVALID);
184*76559068SAndroid Build Coastguard Worker DCHECK_NE(Data->Vmo, ZX_HANDLE_INVALID);
185*76559068SAndroid Build Coastguard Worker const zx_status_t Status =
186*76559068SAndroid Build Coastguard Worker _zx_vmo_op_range(Data->Vmo, ZX_VMO_OP_DECOMMIT, Offset, Size, NULL, 0);
187*76559068SAndroid Build Coastguard Worker CHECK_EQ(Status, ZX_OK);
188*76559068SAndroid Build Coastguard Worker }
189*76559068SAndroid Build Coastguard Worker
getEnv(const char * Name)190*76559068SAndroid Build Coastguard Worker const char *getEnv(const char *Name) { return getenv(Name); }
191*76559068SAndroid Build Coastguard Worker
192*76559068SAndroid Build Coastguard Worker // Note: we need to flag these methods with __TA_NO_THREAD_SAFETY_ANALYSIS
193*76559068SAndroid Build Coastguard Worker // because the Fuchsia implementation of sync_mutex_t has clang thread safety
194*76559068SAndroid Build Coastguard Worker // annotations. Were we to apply proper capability annotations to the top level
195*76559068SAndroid Build Coastguard Worker // HybridMutex class itself, they would not be needed. As it stands, the
196*76559068SAndroid Build Coastguard Worker // thread analysis thinks that we are locking the mutex and accidentally leaving
197*76559068SAndroid Build Coastguard Worker // it locked on the way out.
tryLock()198*76559068SAndroid Build Coastguard Worker bool HybridMutex::tryLock() __TA_NO_THREAD_SAFETY_ANALYSIS {
199*76559068SAndroid Build Coastguard Worker // Size and alignment must be compatible between both types.
200*76559068SAndroid Build Coastguard Worker return sync_mutex_trylock(&M) == ZX_OK;
201*76559068SAndroid Build Coastguard Worker }
202*76559068SAndroid Build Coastguard Worker
lockSlow()203*76559068SAndroid Build Coastguard Worker void HybridMutex::lockSlow() __TA_NO_THREAD_SAFETY_ANALYSIS {
204*76559068SAndroid Build Coastguard Worker sync_mutex_lock(&M);
205*76559068SAndroid Build Coastguard Worker }
206*76559068SAndroid Build Coastguard Worker
unlock()207*76559068SAndroid Build Coastguard Worker void HybridMutex::unlock() __TA_NO_THREAD_SAFETY_ANALYSIS {
208*76559068SAndroid Build Coastguard Worker sync_mutex_unlock(&M);
209*76559068SAndroid Build Coastguard Worker }
210*76559068SAndroid Build Coastguard Worker
assertHeldImpl()211*76559068SAndroid Build Coastguard Worker void HybridMutex::assertHeldImpl() __TA_NO_THREAD_SAFETY_ANALYSIS {}
212*76559068SAndroid Build Coastguard Worker
getMonotonicTime()213*76559068SAndroid Build Coastguard Worker u64 getMonotonicTime() { return _zx_clock_get_monotonic(); }
getMonotonicTimeFast()214*76559068SAndroid Build Coastguard Worker u64 getMonotonicTimeFast() { return _zx_clock_get_monotonic(); }
215*76559068SAndroid Build Coastguard Worker
getNumberOfCPUs()216*76559068SAndroid Build Coastguard Worker u32 getNumberOfCPUs() { return _zx_system_get_num_cpus(); }
217*76559068SAndroid Build Coastguard Worker
getThreadID()218*76559068SAndroid Build Coastguard Worker u32 getThreadID() { return 0; }
219*76559068SAndroid Build Coastguard Worker
getRandom(void * Buffer,uptr Length,UNUSED bool Blocking)220*76559068SAndroid Build Coastguard Worker bool getRandom(void *Buffer, uptr Length, UNUSED bool Blocking) {
221*76559068SAndroid Build Coastguard Worker static_assert(MaxRandomLength <= ZX_CPRNG_DRAW_MAX_LEN, "");
222*76559068SAndroid Build Coastguard Worker if (UNLIKELY(!Buffer || !Length || Length > MaxRandomLength))
223*76559068SAndroid Build Coastguard Worker return false;
224*76559068SAndroid Build Coastguard Worker _zx_cprng_draw(Buffer, Length);
225*76559068SAndroid Build Coastguard Worker return true;
226*76559068SAndroid Build Coastguard Worker }
227*76559068SAndroid Build Coastguard Worker
outputRaw(const char * Buffer)228*76559068SAndroid Build Coastguard Worker void outputRaw(const char *Buffer) {
229*76559068SAndroid Build Coastguard Worker __sanitizer_log_write(Buffer, strlen(Buffer));
230*76559068SAndroid Build Coastguard Worker }
231*76559068SAndroid Build Coastguard Worker
setAbortMessage(const char * Message)232*76559068SAndroid Build Coastguard Worker void setAbortMessage(const char *Message) {}
233*76559068SAndroid Build Coastguard Worker
234*76559068SAndroid Build Coastguard Worker } // namespace scudo
235*76559068SAndroid Build Coastguard Worker
236*76559068SAndroid Build Coastguard Worker #endif // SCUDO_FUCHSIA
237