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