mem_map_linux.cpp 4.1 KB

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