]> git.proxmox.com Git - rustc.git/blobdiff - src/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cc
Imported Upstream version 1.6.0+dfsg1
[rustc.git] / src / compiler-rt / lib / sanitizer_common / sanitizer_posix_libcdep.cc
index e85995961163ae4d5bc65f7b4e974abc941e1caa..d7b9f20414cfdb44749acdf7d4f0e0baaa0f92c0 100644 (file)
 #include "sanitizer_platform.h"
 
 #if SANITIZER_POSIX
+
 #include "sanitizer_common.h"
 #include "sanitizer_flags.h"
 #include "sanitizer_platform_limits_posix.h"
+#include "sanitizer_posix.h"
+#include "sanitizer_procmaps.h"
 #include "sanitizer_stacktrace.h"
+#include "sanitizer_symbolizer.h"
 
 #include <errno.h>
+#include <fcntl.h>
 #include <pthread.h>
 #include <signal.h>
 #include <stdlib.h>
 #include <sys/mman.h>
 #include <sys/resource.h>
+#include <sys/stat.h>
 #include <sys/time.h>
 #include <sys/types.h>
 #include <unistd.h>
 
+#if SANITIZER_FREEBSD
+// The MAP_NORESERVE define has been removed in FreeBSD 11.x, and even before
+// that, it was never implemented.  So just define it to zero.
+#undef  MAP_NORESERVE
+#define MAP_NORESERVE 0
+#endif
+
 namespace __sanitizer {
 
 u32 GetUid() {
@@ -44,30 +57,61 @@ void FlushUnneededShadowMemory(uptr addr, uptr size) {
   madvise((void*)addr, size, MADV_DONTNEED);
 }
 
-void DisableCoreDumper() {
-  struct rlimit nocore;
-  nocore.rlim_cur = 0;
-  nocore.rlim_max = 0;
-  setrlimit(RLIMIT_CORE, &nocore);
+void NoHugePagesInRegion(uptr addr, uptr size) {
+#ifdef MADV_NOHUGEPAGE  // May not be defined on old systems.
+  madvise((void *)addr, size, MADV_NOHUGEPAGE);
+#endif  // MADV_NOHUGEPAGE
 }
 
-bool StackSizeIsUnlimited() {
-  struct rlimit rlim;
-  CHECK_EQ(0, getrlimit(RLIMIT_STACK, &rlim));
-  return ((uptr)rlim.rlim_cur == (uptr)-1);
+void DontDumpShadowMemory(uptr addr, uptr length) {
+#ifdef MADV_DONTDUMP
+  madvise((void *)addr, length, MADV_DONTDUMP);
+#endif
 }
 
-void SetStackSizeLimitInBytes(uptr limit) {
-  struct rlimit rlim;
-  rlim.rlim_cur = limit;
-  rlim.rlim_max = limit;
-  if (setrlimit(RLIMIT_STACK, &rlim)) {
+static rlim_t getlim(int res) {
+  rlimit rlim;
+  CHECK_EQ(0, getrlimit(res, &rlim));
+  return rlim.rlim_cur;
+}
+
+static void setlim(int res, rlim_t lim) {
+  // The following magic is to prevent clang from replacing it with memset.
+  volatile struct rlimit rlim;
+  rlim.rlim_cur = lim;
+  rlim.rlim_max = lim;
+  if (setrlimit(res, const_cast<struct rlimit *>(&rlim))) {
     Report("ERROR: %s setrlimit() failed %d\n", SanitizerToolName, errno);
     Die();
   }
+}
+
+void DisableCoreDumperIfNecessary() {
+  if (common_flags()->disable_coredump) {
+    setlim(RLIMIT_CORE, 0);
+  }
+}
+
+bool StackSizeIsUnlimited() {
+  rlim_t stack_size = getlim(RLIMIT_STACK);
+  return (stack_size == RLIM_INFINITY);
+}
+
+void SetStackSizeLimitInBytes(uptr limit) {
+  setlim(RLIMIT_STACK, (rlim_t)limit);
   CHECK(!StackSizeIsUnlimited());
 }
 
+bool AddressSpaceIsUnlimited() {
+  rlim_t as_size = getlim(RLIMIT_AS);
+  return (as_size == RLIM_INFINITY);
+}
+
+void SetAddressSpaceUnlimited() {
+  setlim(RLIMIT_AS, RLIM_INFINITY);
+  CHECK(AddressSpaceIsUnlimited());
+}
+
 void SleepForSeconds(int seconds) {
   sleep(seconds);
 }
@@ -88,8 +132,8 @@ int Atexit(void (*function)(void)) {
 #endif
 }
 
-int internal_isatty(fd_t fd) {
-  return isatty(fd);
+bool SupportsColoredOutput(fd_t fd) {
+  return isatty(fd) != 0;
 }
 
 #ifndef SANITIZER_GO
@@ -98,7 +142,7 @@ static const uptr kAltStackSize = SIGSTKSZ * 4;  // SIGSTKSZ is not enough.
 
 void SetAlternateSignalStack() {
   stack_t altstack, oldstack;
-  CHECK_EQ(0, sigaltstack(0, &oldstack));
+  CHECK_EQ(0, sigaltstack(nullptr, &oldstack));
   // If the alternate stack is already in place, do nothing.
   // Android always sets an alternate stack, but it's too small for us.
   if (!SANITIZER_ANDROID && !(oldstack.ss_flags & SS_DISABLE)) return;
@@ -109,12 +153,12 @@ void SetAlternateSignalStack() {
   altstack.ss_sp = (char*) base;
   altstack.ss_flags = 0;
   altstack.ss_size = kAltStackSize;
-  CHECK_EQ(0, sigaltstack(&altstack, 0));
+  CHECK_EQ(0, sigaltstack(&altstack, nullptr));
 }
 
 void UnsetAlternateSignalStack() {
   stack_t altstack, oldstack;
-  altstack.ss_sp = 0;
+  altstack.ss_sp = nullptr;
   altstack.ss_flags = SS_DISABLE;
   altstack.ss_size = kAltStackSize;  // Some sane value required on Darwin.
   CHECK_EQ(0, sigaltstack(&altstack, &oldstack));
@@ -129,9 +173,11 @@ static void MaybeInstallSigaction(int signum,
   struct sigaction sigact;
   internal_memset(&sigact, 0, sizeof(sigact));
   sigact.sa_sigaction = (sa_sigaction_t)handler;
-  sigact.sa_flags = SA_SIGINFO;
+  // Do not block the signal from being received in that signal's handler.
+  // Clients are responsible for handling this correctly.
+  sigact.sa_flags = SA_SIGINFO | SA_NODEFER;
   if (common_flags()->use_sigaltstack) sigact.sa_flags |= SA_ONSTACK;
-  CHECK_EQ(0, internal_sigaction(signum, &sigact, 0));
+  CHECK_EQ(0, internal_sigaction(signum, &sigact, nullptr));
   VReport(1, "Installed the sigaction for signal %d\n", signum);
 }
 
@@ -142,9 +188,137 @@ void InstallDeadlySignalHandlers(SignalHandlerType handler) {
   if (common_flags()->use_sigaltstack) SetAlternateSignalStack();
   MaybeInstallSigaction(SIGSEGV, handler);
   MaybeInstallSigaction(SIGBUS, handler);
+  MaybeInstallSigaction(SIGABRT, handler);
+  MaybeInstallSigaction(SIGFPE, handler);
 }
 #endif  // SANITIZER_GO
 
-}  // namespace __sanitizer
+bool IsAccessibleMemoryRange(uptr beg, uptr size) {
+  uptr page_size = GetPageSizeCached();
+  // Checking too large memory ranges is slow.
+  CHECK_LT(size, page_size * 10);
+  int sock_pair[2];
+  if (pipe(sock_pair))
+    return false;
+  uptr bytes_written =
+      internal_write(sock_pair[1], reinterpret_cast<void *>(beg), size);
+  int write_errno;
+  bool result;
+  if (internal_iserror(bytes_written, &write_errno)) {
+    CHECK_EQ(EFAULT, write_errno);
+    result = false;
+  } else {
+    result = (bytes_written == size);
+  }
+  internal_close(sock_pair[0]);
+  internal_close(sock_pair[1]);
+  return result;
+}
+
+void PrepareForSandboxing(__sanitizer_sandbox_arguments *args) {
+  // Some kinds of sandboxes may forbid filesystem access, so we won't be able
+  // to read the file mappings from /proc/self/maps. Luckily, neither the
+  // process will be able to load additional libraries, so it's fine to use the
+  // cached mappings.
+  MemoryMappingLayout::CacheMemoryMappings();
+  // Same for /proc/self/exe in the symbolizer.
+#if !SANITIZER_GO
+  Symbolizer::GetOrInit()->PrepareForSandboxing();
+  CovPrepareForSandboxing(args);
+#endif
+}
+
+#if SANITIZER_ANDROID
+int GetNamedMappingFd(const char *name, uptr size) {
+  return -1;
+}
+#else
+int GetNamedMappingFd(const char *name, uptr size) {
+  if (!common_flags()->decorate_proc_maps)
+    return -1;
+  char shmname[200];
+  CHECK(internal_strlen(name) < sizeof(shmname) - 10);
+  internal_snprintf(shmname, sizeof(shmname), "%zu [%s]", internal_getpid(),
+                    name);
+  int fd = shm_open(shmname, O_RDWR | O_CREAT | O_TRUNC, S_IRWXU);
+  CHECK_GE(fd, 0);
+  int res = internal_ftruncate(fd, size);
+  CHECK_EQ(0, res);
+  res = shm_unlink(shmname);
+  CHECK_EQ(0, res);
+  return fd;
+}
+#endif
+
+void *MmapFixedNoReserve(uptr fixed_addr, uptr size, const char *name) {
+  int fd = name ? GetNamedMappingFd(name, size) : -1;
+  unsigned flags = MAP_PRIVATE | MAP_FIXED | MAP_NORESERVE;
+  if (fd == -1) flags |= MAP_ANON;
+
+  uptr PageSize = GetPageSizeCached();
+  uptr p = internal_mmap((void *)(fixed_addr & ~(PageSize - 1)),
+                         RoundUpTo(size, PageSize), PROT_READ | PROT_WRITE,
+                         flags, fd, 0);
+  int reserrno;
+  if (internal_iserror(p, &reserrno))
+    Report("ERROR: %s failed to "
+           "allocate 0x%zx (%zd) bytes at address %zx (errno: %d)\n",
+           SanitizerToolName, size, size, fixed_addr, reserrno);
+  IncreaseTotalMmap(size);
+  return (void *)p;
+}
+
+void *MmapNoAccess(uptr fixed_addr, uptr size, const char *name) {
+  int fd = name ? GetNamedMappingFd(name, size) : -1;
+  unsigned flags = MAP_PRIVATE | MAP_FIXED | MAP_NORESERVE;
+  if (fd == -1) flags |= MAP_ANON;
+
+  return (void *)internal_mmap((void *)fixed_addr, size, PROT_NONE, flags, fd,
+                               0);
+}
+
+// This function is defined elsewhere if we intercepted pthread_attr_getstack.
+extern "C" {
+SANITIZER_WEAK_ATTRIBUTE int
+real_pthread_attr_getstack(void *attr, void **addr, size_t *size);
+} // extern "C"
+
+int my_pthread_attr_getstack(void *attr, void **addr, uptr *size) {
+#if !SANITIZER_GO && !SANITIZER_MAC
+  if (&real_pthread_attr_getstack)
+    return real_pthread_attr_getstack((pthread_attr_t *)attr, addr,
+                                      (size_t *)size);
+#endif
+  return pthread_attr_getstack((pthread_attr_t *)attr, addr, (size_t *)size);
+}
+
+#if !SANITIZER_GO
+void AdjustStackSize(void *attr_) {
+  pthread_attr_t *attr = (pthread_attr_t *)attr_;
+  uptr stackaddr = 0;
+  uptr stacksize = 0;
+  my_pthread_attr_getstack(attr, (void**)&stackaddr, &stacksize);
+  // GLibC will return (0 - stacksize) as the stack address in the case when
+  // stacksize is set, but stackaddr is not.
+  bool stack_set = (stackaddr != 0) && (stackaddr + stacksize != 0);
+  // We place a lot of tool data into TLS, account for that.
+  const uptr minstacksize = GetTlsSize() + 128*1024;
+  if (stacksize < minstacksize) {
+    if (!stack_set) {
+      if (stacksize != 0) {
+        VPrintf(1, "Sanitizer: increasing stacksize %zu->%zu\n", stacksize,
+                minstacksize);
+        pthread_attr_setstacksize(attr, minstacksize);
+      }
+    } else {
+      Printf("Sanitizer: pre-allocated stack size is insufficient: "
+             "%zu < %zu\n", stacksize, minstacksize);
+      Printf("Sanitizer: pthread_create is likely to fail.\n");
+    }
+  }
+}
+#endif // !SANITIZER_GO
+
+} // namespace __sanitizer
 
-#endif  // SANITIZER_POSIX
+#endif // SANITIZER_POSIX