[llvm-branch-commits] [sanitizer] Add TryMemCpy (PR #112668)

via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Wed Oct 16 23:44:27 PDT 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-compiler-rt-sanitizer

Author: Vitaly Buka (vitalybuka)

<details>
<summary>Changes</summary>

For posix implementation is similar to
`IsAccessibleMemoryRange`, using `pipe`.

We need this because we can't rely on non-atomic
`IsAccessibleMemoryRange` + `memcpy`, as the
protection or mapping may change and we may
crash.


---
Full diff: https://github.com/llvm/llvm-project/pull/112668.diff


5 Files Affected:

- (modified) compiler-rt/lib/sanitizer_common/sanitizer_common.h (+4) 
- (modified) compiler-rt/lib/sanitizer_common/sanitizer_fuchsia.cpp (+5) 
- (modified) compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp (+38) 
- (modified) compiler-rt/lib/sanitizer_common/sanitizer_win.cpp (+5) 
- (modified) compiler-rt/lib/sanitizer_common/tests/sanitizer_posix_test.cpp (+41-4) 


``````````diff
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common.h b/compiler-rt/lib/sanitizer_common/sanitizer_common.h
index 082d2158e579bd..9b1e58f5e7a61d 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_common.h
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_common.h
@@ -268,7 +268,11 @@ class ScopedErrorReportLock {
 extern uptr stoptheworld_tracer_pid;
 extern uptr stoptheworld_tracer_ppid;
 
+// Returns true if we can read a memory range.
 bool IsAccessibleMemoryRange(uptr beg, uptr size);
+// Returns true if we can read a memory range starting at `src`, and copies
+// content into `dest`.
+bool TryMemCpy(void *dest, const void *src, uptr n);
 
 // Error report formatting.
 const char *StripPathPrefix(const char *filepath,
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_fuchsia.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_fuchsia.cpp
index 75dcf546729f6e..c2ace46c946587 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_fuchsia.cpp
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_fuchsia.cpp
@@ -444,6 +444,11 @@ bool IsAccessibleMemoryRange(uptr beg, uptr size) {
   return status == ZX_OK;
 }
 
+bool TryMemCpy(void *dest, const void *src, uptr n) {
+  // TODO: implement.
+  return false;
+}
+
 // FIXME implement on this platform.
 void GetMemoryProfile(fill_profile_f cb, uptr *stats) {}
 
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp
index f87af4bb3a5a6a..80b36efc3ef627 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp
@@ -325,6 +325,44 @@ bool IsAccessibleMemoryRange(uptr beg, uptr size) {
   return true;
 }
 
+bool TryMemCpy(void *dest, const void *src, uptr n) {
+  int sock_pair[2];
+  if (pipe(sock_pair))
+    return false;
+
+  auto cleanup = at_scope_exit([&]() {
+    internal_close(sock_pair[0]);
+    internal_close(sock_pair[1]);
+  });
+
+  SetNonBlock(sock_pair[0]);
+  SetNonBlock(sock_pair[1]);
+
+  char *d = static_cast<char *>(dest);
+  const char *s = static_cast<const char *>(src);
+
+  while (n) {
+    int e;
+    uptr w = internal_write(sock_pair[1], s, n);
+    if (internal_iserror(w, &e)) {
+      CHECK_EQ(EFAULT, e);
+      return false;
+    }
+    s += w;
+    n -= w;
+
+    while (w) {
+      uptr r = internal_read(sock_pair[0], d, w);
+      CHECK(!internal_iserror(r, &e));
+
+      d += r;
+      w -= r;
+    }
+  }
+
+  return true;
+}
+
 void PlatformPrepareForSandboxing(void *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
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_win.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_win.cpp
index 6fb947aa6d6c26..ea513d5f263fe2 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_win.cpp
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_win.cpp
@@ -968,6 +968,11 @@ bool IsAccessibleMemoryRange(uptr beg, uptr size) {
   return true;
 }
 
+bool TryMemCpy(void *dest, const void *src, uptr n) {
+  // TODO: implement.
+  return false;
+}
+
 bool SignalContext::IsStackOverflow() const {
   return (DWORD)GetType() == EXCEPTION_STACK_OVERFLOW;
 }
diff --git a/compiler-rt/lib/sanitizer_common/tests/sanitizer_posix_test.cpp b/compiler-rt/lib/sanitizer_common/tests/sanitizer_posix_test.cpp
index 9feb22221f005e..d641567d2b5964 100644
--- a/compiler-rt/lib/sanitizer_common/tests/sanitizer_posix_test.cpp
+++ b/compiler-rt/lib/sanitizer_common/tests/sanitizer_posix_test.cpp
@@ -13,11 +13,14 @@
 #include "sanitizer_common/sanitizer_platform.h"
 #if SANITIZER_POSIX
 
-#include "sanitizer_common/sanitizer_common.h"
-#include "gtest/gtest.h"
+#  include <pthread.h>
+#  include <sys/mman.h>
 
-#include <pthread.h>
-#include <sys/mman.h>
+#  include <numeric>
+
+#  include "gmock/gmock.h"
+#  include "gtest/gtest.h"
+#  include "sanitizer_common/sanitizer_common.h"
 
 namespace __sanitizer {
 
@@ -93,6 +96,40 @@ TEST(SanitizerCommon, IsAccessibleMemoryRangeLarge) {
   munmap((void *)mem, size);
 }
 
+TEST(SanitizerCommon, TryMemCpy) {
+  std::vector<char> src(10000000);
+  std::iota(src.begin(), src.end(), 123);
+  std::vector<char> dst;
+
+  using ::testing::ElementsAreArray;
+
+  dst.assign(1, 0);
+  ASSERT_TRUE(TryMemCpy(dst.data(), src.data(), dst.size()));
+  EXPECT_THAT(dst, ElementsAreArray(src.data(), dst.size()));
+
+  dst.assign(100, 0);
+  ASSERT_TRUE(TryMemCpy(dst.data(), src.data(), dst.size()));
+  EXPECT_THAT(dst, ElementsAreArray(src.data(), dst.size()));
+
+  dst.assign(534, 0);
+  ASSERT_TRUE(TryMemCpy(dst.data(), src.data(), dst.size()));
+  EXPECT_THAT(dst, ElementsAreArray(src.data(), dst.size()));
+
+  dst.assign(GetPageSize(), 0);
+  ASSERT_TRUE(TryMemCpy(dst.data(), src.data(), dst.size()));
+  EXPECT_THAT(dst, ElementsAreArray(src.data(), dst.size()));
+
+  dst.assign(src.size(), 0);
+  ASSERT_TRUE(TryMemCpy(dst.data(), src.data(), dst.size()));
+  EXPECT_THAT(dst, ElementsAreArray(src.data(), dst.size()));
+
+  dst.assign(src.size() - 1, 0);
+  ASSERT_TRUE(TryMemCpy(dst.data(), src.data(), dst.size()));
+  EXPECT_THAT(dst, ElementsAreArray(src.data(), dst.size()));
+
+  EXPECT_FALSE(TryMemCpy(dst.data(), nullptr, dst.size()));
+}
+
 }  // namespace __sanitizer
 
 #endif  // SANITIZER_POSIX

``````````

</details>


https://github.com/llvm/llvm-project/pull/112668


More information about the llvm-branch-commits mailing list