mirror of
https://github.com/intel/llvm.git
synced 2026-01-19 01:15:50 +08:00
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
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user