diff options
author | Peter Collingbourne <peter@pcc.me.uk> | 2015-09-11 22:18:35 +0000 |
---|---|---|
committer | Peter Collingbourne <peter@pcc.me.uk> | 2015-09-11 22:18:35 +0000 |
commit | 69470be43161edab85b51b37b93dff25e44e4057 (patch) | |
tree | 99f0d4f20b971ed8d31b067fcf205e160f1f3dbe /test/ubsan | |
parent | 00f3423844e696819bb02b547474804b8a4f9177 (diff) |
ubsan: Implement memory permission validation for vtables.
If the pointer passed to the getVtablePrefix function was read from a freed
object, we may end up following pointers into objects on the heap and
printing bogus dynamic type names in diagnostics. However, we know that
vtable pointers will generally only point into memory mapped from object
files, not objects on the heap.
This change causes us to only follow pointers in a vtable if the vtable
and one of the virtual functions it points to appear to have appropriate
permissions (i.e. non-writable, and maybe executable), which will generally
exclude heap pointers.
Only enabled for Linux; this hasn't been tested on FreeBSD, and vtables are
writable on Mac (PR24782) so this won't work there.
Differential Revision: http://reviews.llvm.org/D12790
git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@247484 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'test/ubsan')
-rw-r--r-- | test/ubsan/TestCases/TypeCheck/vptr-bad-perms.cpp | 33 | ||||
-rw-r--r-- | test/ubsan/lit.common.cfg | 3 |
2 files changed, 36 insertions, 0 deletions
diff --git a/test/ubsan/TestCases/TypeCheck/vptr-bad-perms.cpp b/test/ubsan/TestCases/TypeCheck/vptr-bad-perms.cpp new file mode 100644 index 000000000..ad0d3b12a --- /dev/null +++ b/test/ubsan/TestCases/TypeCheck/vptr-bad-perms.cpp @@ -0,0 +1,33 @@ +// RUN: %clangxx -frtti -fsanitize=vptr -fno-sanitize-recover=vptr -g %s -O3 -o %t +// RUN: not %run %t 2>&1 | FileCheck %s + +// Tests that we consider vtable pointers in writable memory to be invalid. + +// REQUIRES: vptr-validation + +#include <string.h> + +struct A { + virtual void f(); +}; + +void A::f() {} + +struct B { + virtual void f(); +}; + +void B::f() {} + +int main() { + // Create a fake vtable for A in writable memory and copy A's vtable into it. + void *fake_vtable[3]; + A a; + void ***vtp = (void ***)&a; + memcpy(fake_vtable, *vtp - 2, sizeof(void *) * 3); + *vtp = fake_vtable + 2; + + // A's vtable is invalid because it lives in writable memory. + // CHECK: invalid vptr + reinterpret_cast<B*>(&a)->f(); +} diff --git a/test/ubsan/lit.common.cfg b/test/ubsan/lit.common.cfg index 60b0b556c..2e0a0bc77 100644 --- a/test/ubsan/lit.common.cfg +++ b/test/ubsan/lit.common.cfg @@ -77,3 +77,6 @@ if config.host_os == 'Windows': # because the test hangs or fails on one configuration and not the other. if config.target_arch.startswith('arm') == False: config.available_features.add('stable-runtime') + +if config.host_os == 'Linux': + config.available_features.add('vptr-validation') |