Группа исследователей из Массачусетского технологического университета (MIT) опубликовала (PDF, 240 Кб) результаты изучения особенностей работы систем оптимизации кода современных компиляторов, способных привести к понижению безопасности приложений. В итоге, выявлены многочисленные факты, когда в процессе компиляции в машинный код из приложения исключаются некорректно написанные блоки, бессмысленные с точки зрения оптимизатора, но влияющие на безопасность.

Например, компилятор исключает неопределённые или нестабильные участки кода, которые на деле могут выступать проверками на появление нулевого указателя или выхода за границы области памяти (например, оптимизатор может заменить "data + x < data" на "x < 0" или считает всегда истинным "-k >= 0" если ранее была проверка "if (k < 0)"). В итоге, данные проверки не включаются в исполняемый файл, и безопасное на уровне исходных текстов приложение становится подвержено уязвимостям на уровне исполняемого кода. Проблеме подвержено большинство современных компиляторов, включая GCC, Clang, ICC, MSVC, open64, pathcc, suncc и т.д.

Например, оптимизатор GCC удалит вторую проверку из следующего кода:


char *buf = ...;
char *buf_end = ...;
unsigned int len = ...;
if (buf + len >= buf_end)


return;
/* len too large */
if (buf + len < buf)


return; /* overflow, buf+len wrapped around write to buf[0..len-1] */

Программист использует условие "buf + len < buf" для проверки на переполнение указателя, подразумевая, что при очень большом значении будет осуществлено переполнение размерности типа. GCC оперирует тем, что по стандарту языка C указатель не должен выходить за пределы объекта более чем на единицу, а в противном случае поведение программы не определено.

В качестве другого примера можно привести код для которого будет удалена проверка на нулевой указатель (gcc считает, что tun не может принимать значение NULL после того, как был произведен доступ к tun->sk):


struct tun_struct *tun = ...;
struct sock *sk = tun->sk;
if (!tun)

 return POLLERR; /* write to address based on tun */

Для выявления проблемных мест в коде на языках C и C++, которые могут быть удалены на стадии оптимизации, исследователями подготовлен специальный статический анализатор STACK. Изучение при помощи STACK типовых открытых проектов выявило 160 подобных проблем, из которых 32 присутствуют в ядре Linux, 3 в Mozilla, 9 в PostgreSQL, 4 в QEMU, 21 в FFmpeg, 3 в Xen, 5 в Python.

Более широкая проверка исходных текстов показала, что нестабильные блоки кода присутствуют в 3471 пакете из 8575 пакетов, доступных в репозиториях Debian. Наибольшее число выявленных проблем (59230 проблем в 2800 пакетах) связано с разыменованием нулевого указателя, 5795 проблем могут привести к переполнению буфера, 4364 к проблемам целочисленной арифметики, 3680 - проблемам с переполнением указателя. Таким образом, описанные в работе проблемы не являются единичными, а широко распространены и могут быть использованы злоумышленниками для организации атак.

Источник: http://www.opennet.ru/opennews/art.shtml?num=38293