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 44namespace scudo { 45 46static 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 81bool 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 91void 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 108bool 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 116void 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 122void 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 129bool 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 141void ReservedMemoryLinux::releaseImpl() { 142 if (munmap(reinterpret_cast<void *>(getBase()), getCapacity()) != 0) 143 reportUnmapError(getBase(), getCapacity()); 144} 145 146ReservedMemoryLinux::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