1*5f757f3fSDimitry Andric //===-- mem_map_linux.cpp ---------------------------------------*- C++ -*-===// 2*5f757f3fSDimitry Andric // 3*5f757f3fSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*5f757f3fSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*5f757f3fSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*5f757f3fSDimitry Andric // 7*5f757f3fSDimitry Andric //===----------------------------------------------------------------------===// 8*5f757f3fSDimitry Andric 9*5f757f3fSDimitry Andric #include "platform.h" 10*5f757f3fSDimitry Andric 11*5f757f3fSDimitry Andric #if SCUDO_LINUX 12*5f757f3fSDimitry Andric 13*5f757f3fSDimitry Andric #include "mem_map_linux.h" 14*5f757f3fSDimitry Andric 15*5f757f3fSDimitry Andric #include "common.h" 16*5f757f3fSDimitry Andric #include "internal_defs.h" 17*5f757f3fSDimitry Andric #include "linux.h" 18*5f757f3fSDimitry Andric #include "mutex.h" 19*5f757f3fSDimitry Andric #include "report_linux.h" 20*5f757f3fSDimitry Andric #include "string_utils.h" 21*5f757f3fSDimitry Andric 22*5f757f3fSDimitry Andric #include <errno.h> 23*5f757f3fSDimitry Andric #include <fcntl.h> 24*5f757f3fSDimitry Andric #include <linux/futex.h> 25*5f757f3fSDimitry Andric #include <sched.h> 26*5f757f3fSDimitry Andric #include <stdio.h> 27*5f757f3fSDimitry Andric #include <stdlib.h> 28*5f757f3fSDimitry Andric #include <string.h> 29*5f757f3fSDimitry Andric #include <sys/mman.h> 30*5f757f3fSDimitry Andric #include <sys/stat.h> 31*5f757f3fSDimitry Andric #include <sys/syscall.h> 32*5f757f3fSDimitry Andric #include <sys/time.h> 33*5f757f3fSDimitry Andric #include <time.h> 34*5f757f3fSDimitry Andric #include <unistd.h> 35*5f757f3fSDimitry Andric 36*5f757f3fSDimitry Andric #if SCUDO_ANDROID 37*5f757f3fSDimitry Andric // TODO(chiahungduan): Review if we still need the followings macros. 38*5f757f3fSDimitry Andric #include <sys/prctl.h> 39*5f757f3fSDimitry Andric // Definitions of prctl arguments to set a vma name in Android kernels. 40*5f757f3fSDimitry Andric #define ANDROID_PR_SET_VMA 0x53564d41 41*5f757f3fSDimitry Andric #define ANDROID_PR_SET_VMA_ANON_NAME 0 42*5f757f3fSDimitry Andric #endif 43*5f757f3fSDimitry Andric 44*5f757f3fSDimitry Andric namespace scudo { 45*5f757f3fSDimitry Andric 46*5f757f3fSDimitry Andric static void *mmapWrapper(uptr Addr, uptr Size, const char *Name, uptr Flags) { 47*5f757f3fSDimitry Andric int MmapFlags = MAP_PRIVATE | MAP_ANONYMOUS; 48*5f757f3fSDimitry Andric int MmapProt; 49*5f757f3fSDimitry Andric if (Flags & MAP_NOACCESS) { 50*5f757f3fSDimitry Andric MmapFlags |= MAP_NORESERVE; 51*5f757f3fSDimitry Andric MmapProt = PROT_NONE; 52*5f757f3fSDimitry Andric } else { 53*5f757f3fSDimitry Andric MmapProt = PROT_READ | PROT_WRITE; 54*5f757f3fSDimitry Andric } 55*5f757f3fSDimitry Andric #if defined(__aarch64__) 56*5f757f3fSDimitry Andric #ifndef PROT_MTE 57*5f757f3fSDimitry Andric #define PROT_MTE 0x20 58*5f757f3fSDimitry Andric #endif 59*5f757f3fSDimitry Andric if (Flags & MAP_MEMTAG) 60*5f757f3fSDimitry Andric MmapProt |= PROT_MTE; 61*5f757f3fSDimitry Andric #endif 62*5f757f3fSDimitry Andric if (Addr) 63*5f757f3fSDimitry Andric MmapFlags |= MAP_FIXED; 64*5f757f3fSDimitry Andric void *P = 65*5f757f3fSDimitry Andric mmap(reinterpret_cast<void *>(Addr), Size, MmapProt, MmapFlags, -1, 0); 66*5f757f3fSDimitry Andric if (P == MAP_FAILED) { 67*5f757f3fSDimitry Andric if (!(Flags & MAP_ALLOWNOMEM) || errno != ENOMEM) 68*5f757f3fSDimitry Andric reportMapError(errno == ENOMEM ? Size : 0); 69*5f757f3fSDimitry Andric return nullptr; 70*5f757f3fSDimitry Andric } 71*5f757f3fSDimitry Andric #if SCUDO_ANDROID 72*5f757f3fSDimitry Andric if (Name) 73*5f757f3fSDimitry Andric prctl(ANDROID_PR_SET_VMA, ANDROID_PR_SET_VMA_ANON_NAME, P, Size, Name); 74*5f757f3fSDimitry Andric #else 75*5f757f3fSDimitry Andric (void)Name; 76*5f757f3fSDimitry Andric #endif 77*5f757f3fSDimitry Andric 78*5f757f3fSDimitry Andric return P; 79*5f757f3fSDimitry Andric } 80*5f757f3fSDimitry Andric 81*5f757f3fSDimitry Andric bool MemMapLinux::mapImpl(uptr Addr, uptr Size, const char *Name, uptr Flags) { 82*5f757f3fSDimitry Andric void *P = mmapWrapper(Addr, Size, Name, Flags); 83*5f757f3fSDimitry Andric if (P == nullptr) 84*5f757f3fSDimitry Andric return false; 85*5f757f3fSDimitry Andric 86*5f757f3fSDimitry Andric MapBase = reinterpret_cast<uptr>(P); 87*5f757f3fSDimitry Andric MapCapacity = Size; 88*5f757f3fSDimitry Andric return true; 89*5f757f3fSDimitry Andric } 90*5f757f3fSDimitry Andric 91*5f757f3fSDimitry Andric void MemMapLinux::unmapImpl(uptr Addr, uptr Size) { 92*5f757f3fSDimitry Andric // If we unmap all the pages, also mark `MapBase` to 0 to indicate invalid 93*5f757f3fSDimitry Andric // status. 94*5f757f3fSDimitry Andric if (Size == MapCapacity) { 95*5f757f3fSDimitry Andric MapBase = MapCapacity = 0; 96*5f757f3fSDimitry Andric } else { 97*5f757f3fSDimitry Andric // This is partial unmap and is unmapping the pages from the beginning, 98*5f757f3fSDimitry Andric // shift `MapBase` to the new base. 99*5f757f3fSDimitry Andric if (MapBase == Addr) 100*5f757f3fSDimitry Andric MapBase = Addr + Size; 101*5f757f3fSDimitry Andric MapCapacity -= Size; 102*5f757f3fSDimitry Andric } 103*5f757f3fSDimitry Andric 104*5f757f3fSDimitry Andric if (munmap(reinterpret_cast<void *>(Addr), Size) != 0) 105*5f757f3fSDimitry Andric reportUnmapError(Addr, Size); 106*5f757f3fSDimitry Andric } 107*5f757f3fSDimitry Andric 108*5f757f3fSDimitry Andric bool MemMapLinux::remapImpl(uptr Addr, uptr Size, const char *Name, 109*5f757f3fSDimitry Andric uptr Flags) { 110*5f757f3fSDimitry Andric void *P = mmapWrapper(Addr, Size, Name, Flags); 111*5f757f3fSDimitry Andric if (reinterpret_cast<uptr>(P) != Addr) 112*5f757f3fSDimitry Andric reportMapError(); 113*5f757f3fSDimitry Andric return true; 114*5f757f3fSDimitry Andric } 115*5f757f3fSDimitry Andric 116*5f757f3fSDimitry Andric void MemMapLinux::setMemoryPermissionImpl(uptr Addr, uptr Size, uptr Flags) { 117*5f757f3fSDimitry Andric int Prot = (Flags & MAP_NOACCESS) ? PROT_NONE : (PROT_READ | PROT_WRITE); 118*5f757f3fSDimitry Andric if (mprotect(reinterpret_cast<void *>(Addr), Size, Prot) != 0) 119*5f757f3fSDimitry Andric reportProtectError(Addr, Size, Prot); 120*5f757f3fSDimitry Andric } 121*5f757f3fSDimitry Andric 122*5f757f3fSDimitry Andric void MemMapLinux::releaseAndZeroPagesToOSImpl(uptr From, uptr Size) { 123*5f757f3fSDimitry Andric void *Addr = reinterpret_cast<void *>(From); 124*5f757f3fSDimitry Andric 125*5f757f3fSDimitry Andric while (madvise(Addr, Size, MADV_DONTNEED) == -1 && errno == EAGAIN) { 126*5f757f3fSDimitry Andric } 127*5f757f3fSDimitry Andric } 128*5f757f3fSDimitry Andric 129*5f757f3fSDimitry Andric bool ReservedMemoryLinux::createImpl(uptr Addr, uptr Size, const char *Name, 130*5f757f3fSDimitry Andric uptr Flags) { 131*5f757f3fSDimitry Andric ReservedMemoryLinux::MemMapT MemMap; 132*5f757f3fSDimitry Andric if (!MemMap.map(Addr, Size, Name, Flags | MAP_NOACCESS)) 133*5f757f3fSDimitry Andric return false; 134*5f757f3fSDimitry Andric 135*5f757f3fSDimitry Andric MapBase = MemMap.getBase(); 136*5f757f3fSDimitry Andric MapCapacity = MemMap.getCapacity(); 137*5f757f3fSDimitry Andric 138*5f757f3fSDimitry Andric return true; 139*5f757f3fSDimitry Andric } 140*5f757f3fSDimitry Andric 141*5f757f3fSDimitry Andric void ReservedMemoryLinux::releaseImpl() { 142*5f757f3fSDimitry Andric if (munmap(reinterpret_cast<void *>(getBase()), getCapacity()) != 0) 143*5f757f3fSDimitry Andric reportUnmapError(getBase(), getCapacity()); 144*5f757f3fSDimitry Andric } 145*5f757f3fSDimitry Andric 146*5f757f3fSDimitry Andric ReservedMemoryLinux::MemMapT ReservedMemoryLinux::dispatchImpl(uptr Addr, 147*5f757f3fSDimitry Andric uptr Size) { 148*5f757f3fSDimitry Andric return ReservedMemoryLinux::MemMapT(Addr, Size); 149*5f757f3fSDimitry Andric } 150*5f757f3fSDimitry Andric 151*5f757f3fSDimitry Andric } // namespace scudo 152*5f757f3fSDimitry Andric 153*5f757f3fSDimitry Andric #endif // SCUDO_LINUX 154