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