2. План доклада
● Ошибки доступа в память (C/C++)
● AddressSanitizer -- инструмент для
поиска ошибок
○ Что делает
○ Как работает
3. Почему С или С++ ?
● Всё написано на C или C++
○ Даже если Вы об этом не знаете
● Виртуальные машины (Java, Perl, Python)
● Базы данных (MySQL)
● Веб серверы (Apache)
● Все остальное тоже (libpng, libz, memcached)
4. C++ в Google
● Всего > 100М строк кода
○ Больше всего кода на С++
● Серверная часть
○ Mapreduce, Bigtable, Spanner, Chubby, ...
● Chrome (> 10M строк)
5. Плата за эффективность
+ "Ручное" управление памятью
- Ошибки использования памяти
* Переполнение буфера
* Использование после free
Открытые ворота для хакеров
6. Что же делать?
● Бинарная инструментация
○ Valgrind, Dr.Memory, Intel Parallel Studio, Purify,
Bounds Checker, Insure++, ...
○ Медленно (> 20x), только heap
● Отладочный malloc
○ Постраничная защита
■ electric fence, libgmalloc, Page Heap
○ Магические значения
○ Находят не всё, медленно, только heap
7. AddressSanitizer
● Инструментирующий компилятор +
библиотека
● Май 2011: первая версия
○ Май 2012: входит в LLVM 3.1
● clang -faddress_sanitizer a.c
8. Кстати: Clang, LLVM
● Компилятор C/C++ (opensource)
● Независимые модули
○ C++ frontend
○ Статический анализ, диагностика
○ Оптимизатор
○ Кодогенератор (x86, ARM, ...)
● Основной компилятор на MacOS, iOS
● Активно используется в Google
● Сопоставим с GCC по производительности
9. AddressSanitizer
● Переполнение буфера
○ Динамические объекты
○ Стековые объекты
○ Глобальные объекты
● Использование после free()
● Двойной free, пересечение параметров
memcpy, и др.
10. Самое главное
● Среднее замедление: < 2x
○ 3x-3.5x на очень больших бинарниках (кэш
инструкций)
● Клиентские приложения почти не
замедляются
○ Chrome, Firefox
11. Пример global-buffer-overflow
int global_array[100] = {-1};
int main(int argc, char **argv) {
return global_array[argc + 100]; // BOOM
}
% clang++ -O1 -faddress-sanitizer example_GlobalOutOfBounds.cc ; ./a.out
==10538== ERROR: AddressSanitizer global-buffer-overflow
READ of size 4 at 0x000000415354 thread T0
#0 0x402481 in main example_GlobalOutOfBounds.cc:3
#1 0x7f0a1c295c4d in __libc_start_main ??:0
#2 0x402379 in _start ??:0
0x000000415354 is located 4 bytes to the right of global variable 'global_array'
(0x4151c0) of size 400
12. Пример stack-buffer-overflow
int main(int argc, char **argv) {
int stack_array[100];
stack_array[1] = 0;
return stack_array[argc + 100]; } // BOOM
% clang++ -O1 -faddress-sanitizer example_StackOutOfBounds.cc; ./a.out
==10589== ERROR: AddressSanitizer stack-buffer-overflow
READ of size 4 at 0x7f5620d981b4 thread T0
#0 0x4024e8 in main example_StackOutOfBounds.cc:4
#1 0x7f5621db6c4d in __libc_start_main ??:0
#2 0x402349 in _start ??:0
Address 0x7f5620d981b4 is located at offset 436 in frame <main> of T0's stack:
This frame has 1 object(s):
[32, 432) 'stack_array'
13. Пример heap-buffer-overflow
int main(int argc, char **argv) {
int *array = new int[100];
int res = array[argc + 100]; // BOOM
delete [] array;
return res; }
% clang++ -O1 -faddress-sanitizer example_HeapOutOfBounds.cc; ./a.out
==10565== ERROR: AddressSanitizer heap-buffer-overflow
READ of size 4 at 0x7fe4b0c76214 thread T0
#0 0x40246f in main example_HeapOutOfBounds.cc:3
#1 0x7fe4b0cb4c4d in __libc_start_main ??:0
0x7fe4b0c76214 is located 4 bytes to the right of 400-byte region [0x7fe..., 0x7fe...)
allocated by thread T0 here:
#0 0x402c36 in operator new[](unsigned long) _asan_rtl_
#1 0x402422 in main example_HeapOutOfBounds.cc:3
14. Пример heap-use-after-free
int main(int argc, char **argv) {
int *array = new int[100];
delete [] array;
return array[argc]; } // BOOM
% clang++ -O1 -faddress-sanitizer example_UseAfterFree.cc; ./a.out
==30226== ERROR: AddressSanitizer heap-use-after-free
READ of size 4 at 0x7faa07fce084 thread T0
#0 0x40433c in main example_UseAfterFree.cc:4
0x7faa07fce084 is located 4 bytes inside of 400-byte region [0x7fa...,x7fa...)
freed by thread T0 here:
#0 0x4058fd in operator delete[](void*) _asan_rtl_
#1 0x404303 in main example_UseAfterFree.cc:4
previously allocated by thread T0 here:
#0 0x405579 in operator new[](unsigned long) _asan_rtl_
#1 0x4042f3 in main example_UseAfterFree.cc:2
21. Немножко ассемблера
shr $0x3,%rax # shift by 3
mov $0x100000000000,%rcx
or %rax,%rcx # add offset
cmpb $0x0,(%rcx) # load shadow
je 1f <foo+0x1f>
ud2a # generate SIGILL*
movq $0x1234,(%rdi) # original store
* May use call instead of UD2
25. Библиотека
● Ининциализация теневой памяти
● Замена malloc/free
○ Отравленные области вокруг malloc
○ Отравление памяти при free, карантин
○ Сохранение стеков malloc/free
● Перехват memset, strlen, и т.п.
● Вывод сообщений
26. Трофеи
● Chromium (включая WebKit); в первые 10 месяцев
○ heap-use-after-free: 201
○ heap-buffer-overflow: 73
○ global-buffer-overflow: 8
○ stack-buffer-overflow: 7
○ Google выплатил > $100k внешним исследователям
● Сотни ошибок в серверных приложениях Google
● Firefox, FreeType, FFmpeg, WebRTC, libjpeg-turbo
● Perl, Vim, LLVM, GCC
● MySQL
● А у Вас баги есть?
27. Есть что улучшить
● Статический анализ
○ Меньше проверок
● Инструментировать всё
○ Библиотеки, Ассемблер
● Адаптировать для ядра
● Портировать на Windows
○ Уже работает для С
28. Короче...
● AddressSanitizer:
○ Находит много ошибок в коде на C/C++
○ Очень быстрый
○ Можно использовать при тестировании
○ ... и в боевом режиме (осторожно)
○ Работает на Linux, MacOS, Android
○ Часть LLVM
○ clang.llvm.org/docs/AddressSanitizer.html
29. А еще у нас есть...
● ThreadSanitizer
○ Находит гонки (data races)
○ С++ и Go
● MemorySanitizer
○ Находит использование
неинициализированных данных (С++)
31. ASan/MSan vs Valgrind
Valgrind ASan MSan
Heap out-of-bounds YES YES NO
Stack out-of-bounds NO YES NO
Global out-of-bounds NO YES NO
Use-after-free YES YES NO
Use-after-return NO Sometimes NO
Uninitialized reads YES NO YES
CPU Overhead 10x-300x 1.5x-3x 3x