[cfe-dev] annotating libc++ to catch buffer overflows in vector/string with asan
Marshall Clow
mclow.lists at gmail.com
Mon Nov 18 12:59:32 PST 2013
On Nov 18, 2013, at 7:25 AM, Kostya Serebryany <kcc at google.com> wrote:
> Hi Marshall, Howard,
>
> [continuing our discussion with Marshall on llvm dev meeting]
> Consider the following test case:
>
> #include <vector>
> #include <assert.h>
> typedef long T;
> int main() {
> std::vector<T> v;
> v.push_back(0);
> v.push_back(1);
> v.push_back(2);
> assert(v.capacity() >= 4);
> T *p = &v[0];
> return p[3]; // OOPS.
> }
>
> Here we have a vector with size==3 and capacity==4, and we are reading
> the element with index 3 using raw pointer arithmetic.
> Today we have no way to detect this bug. AddressSanitizer is silent because
> we still access the heap-allocated buffer within bounds.
> I propose to annotate the libc++ sources so that AddressSanitizer can catch these bugs.
> Here is a prototype of the change.
> I've only annotated __push_back_slow_path which is enough to handle the test case above.
> More methods will need to be annotated for full functionality.
> Similar annotations are possible for std::string.
> __sanitizer_annotate_contiguous_container is declared in
> compiler-rt/include/sanitizer/common_interface_defs.h
>
> --- include/vector (revision 195011)
> +++ include/vector (working copy)
> @@ -282,6 +282,15 @@
> # define _LIBCPP_ASSERT(x, m) ((void)0)
> #endif
>
> +#if __has_feature(address_sanitizer)
> +extern "C" void __sanitizer_annotate_contiguous_container(void *, void *,
> + void *, void *);
> +# define _LIBCPP_ANNOTATE_CONTIGUOUS_CONTAINER(beg, end, old_mid, new_mid) \
> + __sanitizer_annotate_contiguous_container(beg, end, old_mid, new_mid)
> +#else
> +# define _LIBCPP_ANNOTATE_CONTIGUOUS_CONTAINER(beg, end, old_mid, new_mid)
> +#endif
> +
> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
> #pragma GCC system_header
> #endif
> @@ -1525,7 +1534,12 @@
> // __v.push_back(_VSTD::forward<_Up>(__x));
> __alloc_traits::construct(__a, _VSTD::__to_raw_pointer(__v.__end_), _VSTD::forward<_Up>(__x));
> __v.__end_++;
> + if (data())
> + _LIBCPP_ANNOTATE_CONTIGUOUS_CONTAINER(
> + data(), data() + capacity(), data() + size(), data() + capacity());
> __swap_out_circular_buffer(__v);
> + _LIBCPP_ANNOTATE_CONTIGUOUS_CONTAINER(data(), data() + capacity(),
> + data() + capacity(), data() + size());
> }
>
> Running:
> % clang++ -g -O -fsanitize=address -I$HOME/llvm/projects/libcxx/include vect_oob.cc -fno-exceptions; ./a.out
> =================================================================
> ==20838==ERROR: AddressSanitizer: contiguous-container-buffer-overflow on address 0x60300000eff8 at pc 0x465455 bp 0x7fffc0e9a9f0 sp 0x7fffc0e9a9e8
> READ of size 8 at 0x60300000eff8 thread T0
> #0 0x465454 in main /tmp/vect_oob.cc:11
>
> 0x60300000eff8 is located 24 bytes inside of 32-byte region [0x60300000efe0,0x60300000f000)
> allocated by thread T0 here:
> #0 0x44f8fe in operator new(unsigned long)
> #1 0x46559d in std::__1::allocator<long>::allocate(unsigned long, void const*)
> #2 0x46559d in std::__1::allocator_traits<std::__1::allocator<long> >::allocate(std::__1::allocator<long>&, unsigned long)
> #3 0x46559d in std::__1::vector<long, std::__1::allocator<long> >::size() const
> #4 0x46559d in void std::__1::vector<long, std::__1::allocator<long> >::__push_back_slow_path<long const>(long const&)
>
>
> Do you like the idea?
Yes - very much so.
> Any comments about the prototype patch?
Yes.
1) I would implement it with inline functions other than macros.
Like this:
extern "C" void __sanitizer_annotate_contiguous_container(void *, void *, void *, void *);
void inline __annotate_contiguous container
( const void *__beg, const void *__end, const void *__old_mid, const void *new_mid )
#if __has_feature(address_sanitizer)
{ __sanitizer_annotate_contiguous_container(beg, end, old_mid, new_mid); }
#else
{}
#endif
2) I'd like more information about what __sanitizer_annotate_contiguous_container does ;-)
> Any suggestion how to test these annotations in libc++ (we need some kind of DEATH tests)?
We already have failing tests in libc++.
they are named XXXX.fail.cpp.
Getting them to fail only under ASAN will be trickier.
-- Marshall
Marshall Clow Idio Software <mailto:mclow.lists at gmail.com>
A.D. 1517: Martin Luther nails his 95 Theses to the church door and is promptly moderated down to (-1, Flamebait).
-- Yu Suzuki
More information about the cfe-dev
mailing list