diff options
author | Alexey Samsonov <vonosmas@gmail.com> | 2014-09-17 17:56:15 +0000 |
---|---|---|
committer | Alexey Samsonov <vonosmas@gmail.com> | 2014-09-17 17:56:15 +0000 |
commit | 1947bf99217a233bc7f147de19738f77845ec8b8 (patch) | |
tree | beb627e464b6661ede6ac5bbb56cc31350b0e9b9 | |
parent | d122211e60ec211e6cb0fb435ae2e6d38e1e5fda (diff) | |
download | bcm5719-llvm-1947bf99217a233bc7f147de19738f77845ec8b8.tar.gz bcm5719-llvm-1947bf99217a233bc7f147de19738f77845ec8b8.zip |
PR20721: Don't let UBSan print inaccessible memory
Summary:
UBSan needs to check if memory snippet it's going to print resides
in addressable memory. Similar check might be helpful in ASan with
dump_instruction_bytes option (see http://reviews.llvm.org/D5167).
Instead of scanning /proc/self/maps manually, delegate this check to
the OS kernel: try to write this memory in a syscall and assume that
memory is inaccessible if the syscall failed (e.g. with EFAULT).
Fixes PR20721.
Test Plan: compiler-rt test suite
Reviewers: eugenis, glider
Reviewed By: glider
Subscribers: emaste, ygribov, llvm-commits, glider, rsmith
Differential Revision: http://reviews.llvm.org/D5253
llvm-svn: 217971
6 files changed, 63 insertions, 1 deletions
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common.h b/compiler-rt/lib/sanitizer_common/sanitizer_common.h index b265f297d8d..c85264aef88 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_common.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common.h @@ -167,6 +167,8 @@ uptr ReadFileToBuffer(const char *file_name, char **buff, void *MapFileToMemory(const char *file_name, uptr *buff_size); void *MapWritableFileToMemory(void *addr, uptr size, uptr fd, uptr offset); +bool IsAccessibleMemoryRange(uptr beg, uptr size); + // Error report formatting. const char *StripPathPrefix(const char *filepath, const char *strip_file_prefix); diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cc b/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cc index be613fe5600..12a8ff179bb 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cc @@ -166,6 +166,28 @@ void InstallDeadlySignalHandlers(SignalHandlerType handler) { } #endif // SANITIZER_GO +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; +} + } // namespace __sanitizer #endif // SANITIZER_POSIX diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_win.cc b/compiler-rt/lib/sanitizer_common/sanitizer_win.cc index 9d578fe2c99..4ecfe850e46 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_win.cc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_win.cc @@ -522,6 +522,11 @@ bool IsDeadlySignal(int signum) { return false; } +bool IsAccessibleMemoryRange(uptr beg, uptr size) { + // FIXME: Actually implement this function. + return true; +} + } // namespace __sanitizer #endif // _WIN32 diff --git a/compiler-rt/lib/sanitizer_common/tests/sanitizer_posix_test.cc b/compiler-rt/lib/sanitizer_common/tests/sanitizer_posix_test.cc index 035899c8302..56ce416141f 100644 --- a/compiler-rt/lib/sanitizer_common/tests/sanitizer_posix_test.cc +++ b/compiler-rt/lib/sanitizer_common/tests/sanitizer_posix_test.cc @@ -18,6 +18,7 @@ #include "gtest/gtest.h" #include <pthread.h> +#include <sys/mman.h> namespace __sanitizer { @@ -57,6 +58,23 @@ TEST(SanitizerCommon, PthreadDestructorIterations) { EXPECT_FALSE(destructor_executed); } +TEST(SanitizerCommon, IsAccessibleMemoryRange) { + const int page_size = GetPageSize(); + uptr mem = (uptr)mmap(0, 3 * page_size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON, -1, 0); + // Protect the middle page. + mprotect((void *)(mem + page_size), page_size, PROT_NONE); + EXPECT_TRUE(IsAccessibleMemoryRange(mem, page_size - 1)); + EXPECT_TRUE(IsAccessibleMemoryRange(mem, page_size)); + EXPECT_FALSE(IsAccessibleMemoryRange(mem, page_size + 1)); + EXPECT_TRUE(IsAccessibleMemoryRange(mem + page_size - 1, 1)); + EXPECT_FALSE(IsAccessibleMemoryRange(mem + page_size - 1, 2)); + EXPECT_FALSE(IsAccessibleMemoryRange(mem + 2 * page_size - 1, 1)); + EXPECT_TRUE(IsAccessibleMemoryRange(mem + 2 * page_size, page_size)); + EXPECT_FALSE(IsAccessibleMemoryRange(mem, 3 * page_size)); + EXPECT_FALSE(IsAccessibleMemoryRange(0x0, 2)); +} + } // namespace __sanitizer #endif // SANITIZER_POSIX diff --git a/compiler-rt/lib/ubsan/ubsan_diag.cc b/compiler-rt/lib/ubsan/ubsan_diag.cc index 4a03aa38577..ea2fa9b4424 100644 --- a/compiler-rt/lib/ubsan/ubsan_diag.cc +++ b/compiler-rt/lib/ubsan/ubsan_diag.cc @@ -222,9 +222,13 @@ static void renderMemorySnippet(const Decorator &Decor, MemoryLocation Loc, Min = __sanitizer::Min(Max - BytesToShow, OrigMin); Max = addNoOverflow(Min, BytesToShow); + if (!IsAccessibleMemoryRange(Min, Max - Min)) { + Printf("<memory cannot be printed>\n"); + return; + } + // Emit data. for (uptr P = Min; P != Max; ++P) { - // FIXME: Check that the address is readable before printing it. unsigned char C = *reinterpret_cast<const unsigned char*>(P); Printf("%s%02x", (P % 8 == 0) ? " " : " ", C); } diff --git a/compiler-rt/test/ubsan/TestCases/TypeCheck/misaligned.cpp b/compiler-rt/test/ubsan/TestCases/TypeCheck/misaligned.cpp index e319b76e04b..a31384019fa 100644 --- a/compiler-rt/test/ubsan/TestCases/TypeCheck/misaligned.cpp +++ b/compiler-rt/test/ubsan/TestCases/TypeCheck/misaligned.cpp @@ -8,6 +8,9 @@ // RUN: %run %t n1 2>&1 | FileCheck %s --check-prefix=CHECK-NEW // RUN: UBSAN_OPTIONS=print_stacktrace=1 %run %t l1 2>&1 | FileCheck %s --check-prefix=CHECK-LOAD --check-prefix=CHECK-%os-STACK-LOAD +// RUN: %clangxx -fsanitize=alignment -fno-sanitize-recover %s -O3 -o %t +// RUN: not %run %t w1 2>&1 | FileCheck %s --check-prefix=CHECK-WILD + #include <new> struct S { @@ -23,6 +26,8 @@ int main(int, char **argv) { int *p = (int*)&c[4 + argv[1][1] - '0']; S *s = (S*)p; + void *wild = reinterpret_cast<void *>(0x123L); + (void)*p; // ok! switch (argv[1][0]) { @@ -74,5 +79,11 @@ int main(int, char **argv) { // CHECK-NEW-NEXT: {{^ 00 00 00 01 02 03 04 05}} // CHECK-NEW-NEXT: {{^ \^}} return (new (s) S)->k && 0; + + case 'w': + // CHECK-WILD: misaligned.cpp:[[@LINE+3]]:35: runtime error: member access within misaligned address 0x000000000123 for type 'S', which requires 4 byte alignment + // CHECK-WILD-NEXT: 0x000000000123: note: pointer points here + // CHECK-WILD-NEXT: <memory cannot be printed> + return static_cast<S*>(wild)->k; } } |