1 //===-- sanitizer_posix.cc ------------------------------------------------===//
2 //
3 // This file is distributed under the University of Illinois Open Source
4 // License. See LICENSE.TXT for details.
5 //
6 //===----------------------------------------------------------------------===//
7 //
8 // This file is shared between AddressSanitizer and ThreadSanitizer
9 // run-time libraries and implements POSIX-specific functions from
10 // sanitizer_posix.h.
11 //===----------------------------------------------------------------------===//
12 
13 #include "sanitizer_platform.h"
14 
15 #if SANITIZER_POSIX
16 
17 #include "sanitizer_common.h"
18 #include "sanitizer_file.h"
19 #include "sanitizer_libc.h"
20 #include "sanitizer_posix.h"
21 #include "sanitizer_procmaps.h"
22 
23 #include <errno.h>
24 #include <fcntl.h>
25 #include <signal.h>
26 #include <sys/mman.h>
27 
28 #if SANITIZER_FREEBSD
29 // The MAP_NORESERVE define has been removed in FreeBSD 11.x, and even before
30 // that, it was never implemented.  So just define it to zero.
31 #undef  MAP_NORESERVE
32 #define MAP_NORESERVE 0
33 #endif
34 
35 namespace __sanitizer {
36 
37 // ------------- sanitizer_common.h
GetMmapGranularity()38 uptr GetMmapGranularity() {
39   return GetPageSize();
40 }
41 
MmapOrDie(uptr size,const char * mem_type,bool raw_report)42 void *MmapOrDie(uptr size, const char *mem_type, bool raw_report) {
43   size = RoundUpTo(size, GetPageSizeCached());
44   uptr res = internal_mmap(nullptr, size,
45                            PROT_READ | PROT_WRITE,
46                            MAP_PRIVATE | MAP_ANON, -1, 0);
47   int reserrno;
48   if (UNLIKELY(internal_iserror(res, &reserrno)))
49     ReportMmapFailureAndDie(size, mem_type, "allocate", reserrno, raw_report);
50   IncreaseTotalMmap(size);
51   return (void *)res;
52 }
53 
UnmapOrDie(void * addr,uptr size)54 void UnmapOrDie(void *addr, uptr size) {
55   if (!addr || !size) return;
56   uptr res = internal_munmap(addr, size);
57   if (UNLIKELY(internal_iserror(res))) {
58     Report("ERROR: %s failed to deallocate 0x%zx (%zd) bytes at address %p\n",
59            SanitizerToolName, size, size, addr);
60     CHECK("unable to unmap" && 0);
61   }
62   DecreaseTotalMmap(size);
63 }
64 
MmapOrDieOnFatalError(uptr size,const char * mem_type)65 void *MmapOrDieOnFatalError(uptr size, const char *mem_type) {
66   size = RoundUpTo(size, GetPageSizeCached());
67   uptr res = internal_mmap(nullptr, size,
68                            PROT_READ | PROT_WRITE,
69                            MAP_PRIVATE | MAP_ANON, -1, 0);
70   int reserrno;
71   if (UNLIKELY(internal_iserror(res, &reserrno))) {
72     if (reserrno == ENOMEM)
73       return nullptr;
74     ReportMmapFailureAndDie(size, mem_type, "allocate", reserrno);
75   }
76   IncreaseTotalMmap(size);
77   return (void *)res;
78 }
79 
80 // We want to map a chunk of address space aligned to 'alignment'.
81 // We do it by mapping a bit more and then unmapping redundant pieces.
82 // We probably can do it with fewer syscalls in some OS-dependent way.
MmapAlignedOrDieOnFatalError(uptr size,uptr alignment,const char * mem_type)83 void *MmapAlignedOrDieOnFatalError(uptr size, uptr alignment,
84                                    const char *mem_type) {
85   CHECK(IsPowerOfTwo(size));
86   CHECK(IsPowerOfTwo(alignment));
87   uptr map_size = size + alignment;
88   uptr map_res = (uptr)MmapOrDieOnFatalError(map_size, mem_type);
89   if (UNLIKELY(!map_res))
90     return nullptr;
91   uptr map_end = map_res + map_size;
92   uptr res = map_res;
93   if (!IsAligned(res, alignment)) {
94     res = (map_res + alignment - 1) & ~(alignment - 1);
95     UnmapOrDie((void*)map_res, res - map_res);
96   }
97   uptr end = res + size;
98   if (end != map_end)
99     UnmapOrDie((void*)end, map_end - end);
100   return (void*)res;
101 }
102 
MmapNoReserveOrDie(uptr size,const char * mem_type)103 void *MmapNoReserveOrDie(uptr size, const char *mem_type) {
104   uptr PageSize = GetPageSizeCached();
105   uptr p = internal_mmap(nullptr,
106                          RoundUpTo(size, PageSize),
107                          PROT_READ | PROT_WRITE,
108                          MAP_PRIVATE | MAP_ANON | MAP_NORESERVE,
109                          -1, 0);
110   int reserrno;
111   if (UNLIKELY(internal_iserror(p, &reserrno)))
112     ReportMmapFailureAndDie(size, mem_type, "allocate noreserve", reserrno);
113   IncreaseTotalMmap(size);
114   return (void *)p;
115 }
116 
MmapFixedImpl(uptr fixed_addr,uptr size,bool tolerate_enomem)117 void *MmapFixedImpl(uptr fixed_addr, uptr size, bool tolerate_enomem) {
118   uptr PageSize = GetPageSizeCached();
119   uptr p = internal_mmap((void*)(fixed_addr & ~(PageSize - 1)),
120       RoundUpTo(size, PageSize),
121       PROT_READ | PROT_WRITE,
122       MAP_PRIVATE | MAP_ANON | MAP_FIXED,
123       -1, 0);
124   int reserrno;
125   if (UNLIKELY(internal_iserror(p, &reserrno))) {
126     if (tolerate_enomem && reserrno == ENOMEM)
127       return nullptr;
128     char mem_type[40];
129     internal_snprintf(mem_type, sizeof(mem_type), "memory at address 0x%zx",
130                       fixed_addr);
131     ReportMmapFailureAndDie(size, mem_type, "allocate", reserrno);
132   }
133   IncreaseTotalMmap(size);
134   return (void *)p;
135 }
136 
MmapFixedOrDie(uptr fixed_addr,uptr size)137 void *MmapFixedOrDie(uptr fixed_addr, uptr size) {
138   return MmapFixedImpl(fixed_addr, size, false /*tolerate_enomem*/);
139 }
140 
MmapFixedOrDieOnFatalError(uptr fixed_addr,uptr size)141 void *MmapFixedOrDieOnFatalError(uptr fixed_addr, uptr size) {
142   return MmapFixedImpl(fixed_addr, size, true /*tolerate_enomem*/);
143 }
144 
MprotectNoAccess(uptr addr,uptr size)145 bool MprotectNoAccess(uptr addr, uptr size) {
146   return 0 == internal_mprotect((void*)addr, size, PROT_NONE);
147 }
148 
MprotectReadOnly(uptr addr,uptr size)149 bool MprotectReadOnly(uptr addr, uptr size) {
150   return 0 == internal_mprotect((void *)addr, size, PROT_READ);
151 }
152 
153 #if !SANITIZER_MAC
MprotectMallocZones(void * addr,int prot)154 void MprotectMallocZones(void *addr, int prot) {}
155 #endif
156 
OpenFile(const char * filename,FileAccessMode mode,error_t * errno_p)157 fd_t OpenFile(const char *filename, FileAccessMode mode, error_t *errno_p) {
158   int flags;
159   switch (mode) {
160     case RdOnly: flags = O_RDONLY; break;
161     case WrOnly: flags = O_WRONLY | O_CREAT | O_TRUNC; break;
162     case RdWr: flags = O_RDWR | O_CREAT; break;
163   }
164   fd_t res = internal_open(filename, flags, 0660);
165   if (internal_iserror(res, errno_p))
166     return kInvalidFd;
167   return res;
168 }
169 
CloseFile(fd_t fd)170 void CloseFile(fd_t fd) {
171   internal_close(fd);
172 }
173 
ReadFromFile(fd_t fd,void * buff,uptr buff_size,uptr * bytes_read,error_t * error_p)174 bool ReadFromFile(fd_t fd, void *buff, uptr buff_size, uptr *bytes_read,
175                   error_t *error_p) {
176   uptr res = internal_read(fd, buff, buff_size);
177   if (internal_iserror(res, error_p))
178     return false;
179   if (bytes_read)
180     *bytes_read = res;
181   return true;
182 }
183 
WriteToFile(fd_t fd,const void * buff,uptr buff_size,uptr * bytes_written,error_t * error_p)184 bool WriteToFile(fd_t fd, const void *buff, uptr buff_size, uptr *bytes_written,
185                  error_t *error_p) {
186   uptr res = internal_write(fd, buff, buff_size);
187   if (internal_iserror(res, error_p))
188     return false;
189   if (bytes_written)
190     *bytes_written = res;
191   return true;
192 }
193 
RenameFile(const char * oldpath,const char * newpath,error_t * error_p)194 bool RenameFile(const char *oldpath, const char *newpath, error_t *error_p) {
195   uptr res = internal_rename(oldpath, newpath);
196   return !internal_iserror(res, error_p);
197 }
198 
MapFileToMemory(const char * file_name,uptr * buff_size)199 void *MapFileToMemory(const char *file_name, uptr *buff_size) {
200   fd_t fd = OpenFile(file_name, RdOnly);
201   CHECK(fd != kInvalidFd);
202   uptr fsize = internal_filesize(fd);
203   CHECK_NE(fsize, (uptr)-1);
204   CHECK_GT(fsize, 0);
205   *buff_size = RoundUpTo(fsize, GetPageSizeCached());
206   uptr map = internal_mmap(nullptr, *buff_size, PROT_READ, MAP_PRIVATE, fd, 0);
207   return internal_iserror(map) ? nullptr : (void *)map;
208 }
209 
MapWritableFileToMemory(void * addr,uptr size,fd_t fd,OFF_T offset)210 void *MapWritableFileToMemory(void *addr, uptr size, fd_t fd, OFF_T offset) {
211   uptr flags = MAP_SHARED;
212   if (addr) flags |= MAP_FIXED;
213   uptr p = internal_mmap(addr, size, PROT_READ | PROT_WRITE, flags, fd, offset);
214   int mmap_errno = 0;
215   if (internal_iserror(p, &mmap_errno)) {
216     Printf("could not map writable file (%d, %lld, %zu): %zd, errno: %d\n",
217            fd, (long long)offset, size, p, mmap_errno);
218     return nullptr;
219   }
220   return (void *)p;
221 }
222 
IntervalsAreSeparate(uptr start1,uptr end1,uptr start2,uptr end2)223 static inline bool IntervalsAreSeparate(uptr start1, uptr end1,
224                                         uptr start2, uptr end2) {
225   CHECK(start1 <= end1);
226   CHECK(start2 <= end2);
227   return (end1 < start2) || (end2 < start1);
228 }
229 
230 // FIXME: this is thread-unsafe, but should not cause problems most of the time.
231 // When the shadow is mapped only a single thread usually exists (plus maybe
232 // several worker threads on Mac, which aren't expected to map big chunks of
233 // memory).
MemoryRangeIsAvailable(uptr range_start,uptr range_end)234 bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) {
235   MemoryMappingLayout proc_maps(/*cache_enabled*/true);
236   MemoryMappedSegment segment;
237   while (proc_maps.Next(&segment)) {
238     if (segment.start == segment.end) continue;  // Empty range.
239     CHECK_NE(0, segment.end);
240     if (!IntervalsAreSeparate(segment.start, segment.end - 1, range_start,
241                               range_end))
242       return false;
243   }
244   return true;
245 }
246 
DumpProcessMap()247 void DumpProcessMap() {
248   MemoryMappingLayout proc_maps(/*cache_enabled*/true);
249   const sptr kBufSize = 4095;
250   char *filename = (char*)MmapOrDie(kBufSize, __func__);
251   MemoryMappedSegment segment(filename, kBufSize);
252   Report("Process memory map follows:\n");
253   while (proc_maps.Next(&segment)) {
254     Printf("\t%p-%p\t%s\n", (void *)segment.start, (void *)segment.end,
255            segment.filename);
256   }
257   Report("End of process memory map.\n");
258   UnmapOrDie(filename, kBufSize);
259 }
260 
GetPwd()261 const char *GetPwd() {
262   return GetEnv("PWD");
263 }
264 
IsPathSeparator(const char c)265 bool IsPathSeparator(const char c) {
266   return c == '/';
267 }
268 
IsAbsolutePath(const char * path)269 bool IsAbsolutePath(const char *path) {
270   return path != nullptr && IsPathSeparator(path[0]);
271 }
272 
Write(const char * buffer,uptr length)273 void ReportFile::Write(const char *buffer, uptr length) {
274   SpinMutexLock l(mu);
275   static const char *kWriteError =
276       "ReportFile::Write() can't output requested buffer!\n";
277   ReopenIfNecessary();
278   if (length != internal_write(fd, buffer, length)) {
279     internal_write(fd, kWriteError, internal_strlen(kWriteError));
280     Die();
281   }
282 }
283 
GetCodeRangeForFile(const char * module,uptr * start,uptr * end)284 bool GetCodeRangeForFile(const char *module, uptr *start, uptr *end) {
285   MemoryMappingLayout proc_maps(/*cache_enabled*/false);
286   InternalScopedString buff(kMaxPathLength);
287   MemoryMappedSegment segment(buff.data(), kMaxPathLength);
288   while (proc_maps.Next(&segment)) {
289     if (segment.IsExecutable() &&
290         internal_strcmp(module, segment.filename) == 0) {
291       *start = segment.start;
292       *end = segment.end;
293       return true;
294     }
295   }
296   return false;
297 }
298 
GetAddress() const299 uptr SignalContext::GetAddress() const {
300   auto si = static_cast<const siginfo_t *>(siginfo);
301   return (uptr)si->si_addr;
302 }
303 
IsMemoryAccess() const304 bool SignalContext::IsMemoryAccess() const {
305   auto si = static_cast<const siginfo_t *>(siginfo);
306   return si->si_signo == SIGSEGV;
307 }
308 
GetType() const309 int SignalContext::GetType() const {
310   return static_cast<const siginfo_t *>(siginfo)->si_signo;
311 }
312 
Describe() const313 const char *SignalContext::Describe() const {
314   switch (GetType()) {
315     case SIGFPE:
316       return "FPE";
317     case SIGILL:
318       return "ILL";
319     case SIGABRT:
320       return "ABRT";
321     case SIGSEGV:
322       return "SEGV";
323     case SIGBUS:
324       return "BUS";
325   }
326   return "UNKNOWN SIGNAL";
327 }
328 
329 } // namespace __sanitizer
330 
331 #endif // SANITIZER_POSIX
332