[ubsan] Fix a faulty memory accessibility check
The dynamic type check needs to inspect vtables, but could crash if it encounters a vtable pointer to inaccessible memory. In the first attempt to fix the issue (r304437), we performed a memory accessibility check on the wrong range of memory. This should *really* fix the problem. Patch by Max Moroz! Differential Revision: https://reviews.llvm.org/D34215 llvm-svn: 305489
This commit is contained in:
parent
00a970a84b
commit
f7e804157e
|
@ -197,9 +197,9 @@ struct VtablePrefix {
|
|||
};
|
||||
VtablePrefix *getVtablePrefix(void *Vtable) {
|
||||
VtablePrefix *Vptr = reinterpret_cast<VtablePrefix*>(Vtable);
|
||||
if (!IsAccessibleMemoryRange((uptr)Vptr, sizeof(VtablePrefix)))
|
||||
return nullptr;
|
||||
VtablePrefix *Prefix = Vptr - 1;
|
||||
if (!IsAccessibleMemoryRange((uptr)Prefix, sizeof(VtablePrefix)))
|
||||
return nullptr;
|
||||
if (!Prefix->TypeInfo)
|
||||
// This can't possibly be a valid vtable.
|
||||
return nullptr;
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
// RUN: %clangxx -std=c++11 -frtti -fsanitize=vptr -g %s -O3 -o %t
|
||||
// RUN: %run %t &> %t.log
|
||||
// RUN: cat %t.log | not count 0 && FileCheck --input-file %t.log %s || cat %t.log | count 0
|
||||
|
||||
// REQUIRES: cxxabi
|
||||
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
|
||||
class Base {
|
||||
public:
|
||||
int i;
|
||||
virtual void print() {}
|
||||
};
|
||||
|
||||
class Derived : public Base {
|
||||
public:
|
||||
void print() {}
|
||||
};
|
||||
|
||||
|
||||
int main() {
|
||||
int page_size = getpagesize();
|
||||
|
||||
void *non_accessible = mmap(nullptr, page_size, PROT_NONE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
|
||||
if (non_accessible == MAP_FAILED)
|
||||
return 0;
|
||||
|
||||
void *accessible = mmap((char*)non_accessible + page_size, page_size,
|
||||
PROT_READ | PROT_WRITE,
|
||||
MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
if (accessible == MAP_FAILED)
|
||||
return 0;
|
||||
|
||||
char *c = new char[sizeof(Derived)];
|
||||
|
||||
// The goal is to trigger a condition when Vptr points to accessible memory,
|
||||
// but VptrPrefix does not. That has been triggering SIGSEGV in UBSan code.
|
||||
void **vtable_ptr = reinterpret_cast<void **>(c);
|
||||
*vtable_ptr = (void*)accessible;
|
||||
|
||||
Derived *list = (Derived *)c;
|
||||
|
||||
// CHECK: PR33221.cpp:[[@LINE+2]]:19: runtime error: member access within address {{.*}} which does not point to an object of type 'Base'
|
||||
// CHECK-NEXT: invalid vptr
|
||||
int foo = list->i;
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
def getRoot(config):
|
||||
if not config.parent:
|
||||
return config
|
||||
return getRoot(config.parent)
|
||||
|
||||
root = getRoot(config)
|
||||
|
||||
if root.host_os not in ['Linux']:
|
||||
config.unsupported = True
|
|
@ -18,7 +18,7 @@ public:
|
|||
|
||||
int main() {
|
||||
char *c = new char[sizeof(Derived)];
|
||||
memset((void *)c, 0, sizeof(Derived));
|
||||
memset((void *)c, 0xFF, sizeof(Derived));
|
||||
Derived *list = (Derived *)c;
|
||||
|
||||
// CHECK: PR33221.cpp:[[@LINE+2]]:19: runtime error: member access within address {{.*}} which does not point to an object of type 'Base'
|
||||
|
|
Loading…
Reference in New Issue