xref: /freebsd/contrib/llvm-project/compiler-rt/lib/scudo/standalone/mem_map_linux.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
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