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