Анализ безопасности программ с помощью Intel® Static Security Analyzer

Создать новую статью

28.09.2010 07:00


Аннотация

Безопасность программных продуктов становится все более актуальной в мире цифровых технологий. Профессия специалиста по безопасности программного обеспечения становится все более востребованной и уважаемой на рынке. Неотъемлемой частью проверки программного продукта на безопасность является его тестирование с помощью инструментов статического анализа. В статье описывается работа над улучшением качества Intel® Static Security Analyzer и полученные результаты.

Об авторе

Нешляева Арина Владимировна, студентка 4-го курса физического факультета Новосибирского Государственного Университета кафедры автоматизации физико-технических исследований. Стажировку проходила в городе Новосибирске под руководством ментора Николая Ивницкого и менеджера Дмитрия Петунина.

Небольшая хронология

1 век д.н.э. – «Человеку свойственно ошибаться» (Цицерон)
1492 год — Леонардо да Винчи в одном из своих дневников приводит эскиз 13-разрядного суммирующего устройства с десятизубцовыми кольцами.
1843 год - графиня Ада Августа Лавлейс, дочка великого английского поэта Джорджа Байрона, как принято считать, написала первую в истории человечества программу для Аналитической машины.
2002 год – «80% своего времени разработчик тратит на поиск и исправление ошибок» (NIST 2002)

Все эти факты не могли не привести к появлению множества средств для верификации программного обеспечения. Немаловажное место среди всех инструментов верификации занимают статические анализаторы кода.

Статический анализ кода

Статический анализ кода (англ. static code analysis) — анализ программного обеспечения, производимый без реального выполнения исследуемых программ.
Это определение с www.wikipedia.org ни на йоту не раскрывает всей мощи работы алгоритмов статического анализа. К сожалению или к счастью, моя работа не включала в себя изучение теоретической стороны вопроса, поэтому рассмотрим эту технологию с практической точки зрения.

Преимущества использования статического анализа:

  1. Обнаружение ошибок на ранних этапах разработки
    Чем раньше найден баг, тем быстрее и дешевле его исправить:
    Cost to fix software errors
    Используя статический анализ, вы можете анализировать не только полную программу, но и ее часть, даже на самых ранних этапах разработки.
  2. Анализ всех потенциальных путей
    Статический анализ проверяет все потенциальные пути, по которым может пойти программа, включая даже те, которые не будут по каким-либо причинам включены в процесс тестирования.
  3. Безопасность
    Самое слабое место в программе - это пользовательский ввод. Статический анализ всегда напомнит вам проверить входные данные. Кроме того, он подумает за вас о безопасном межплатформенном переносе. Особенно это касается изменений в размерах различных типов данных.
  4. Репутация
    Чем устойчивее программа, тем больше пользователей она привлекает. А чем больше пользователь удовлетворен, тем выше ваша репутация, как разработчика. Статический анализ дисциплинирует и делает вас более ответственным за ошибки в коде.
  5. Удобная командная разработка
    Статический анализ помогает найти несоответствия в декларациях и определениях, в именах и типах данных в различных модулях, написанных разными людьми.
  6. Экономия времени
    Программист тратит меньше времени на обработку багов и больше - на разработку.

Постановка задачи

Инструмент статического анализа, с которым нам предстояло работать, был Intel® Static Security Analyzer. Планировалось ознакомиться с его функциональностью, проанализировать несколько open source проектов, разработать эффективные методы по его использованию. Результаты оформить в виде статей.

Intel® Static Security Analyzer

Static Security Analyzer – инструмент статического анализа для языков программирования С/С++ и FORTRAN, поддерживающий технологии OpenMP и Cilk. Он является неотъемлемой частью компилятора Intel, поэтому, используя этот компилятор, вы можете пользоваться сразу и статическим анализом. SSA поддерживает операционные системы Windows и Linux, MSVS (2005, 2008, 2010). Для работы GUI требуется Intel ® Parallel/C++ Studio XE.

SSA является частью Intel®Inspector 2011 XE. Пользовательский интерфейс позволяет просматривать список найденных проблем в коде, которые можно отсортировывать по весу, статусу (Fixed, Not Fixed, Confirmed), имени файла. Имеется панель со всевозможными фильтрами, упрощающими анализ диагностики. И окно предпросмотра кода, соответствующего диагностике.
Сообщения, выдаваемые SSA подразделяются на:

  • Critical errors – такие как переполнение буфера, неправильное использование указателей, некорректный пользовательский ввод, утечки памяти и.т.д.
  • Errors - такие как деление на ноль, неинициализированные переменные, неиспользуемый код и.т.д.
  • Warnings - например нарушение инкапсуляции в C++ классе
  • Другие recommendations – например большой аргумент, передающийся по значению.

Предложенное решение

Предлагалось проверять возможности SSA на open-source проектах (Media Player Classic, Notepad++, Mozilla Firefox, Mongo DB), анализировать полученную диагностику и создавать небольшие тесты, в случае обнаружения некорректной диагностики.
Однако стоит заметить, что вся наша работа проходила перед релизом SSA и должна была не только максимально улучшить его качество, но и раскрыть возможности SSA в глазах потенциальных пользователей.
На еженедельных митингах нашей команды мы узнали, что SSA обычно предлагают тем, кто или вообще никогда не использовал статический анализ, или использовал для этого аналогичные продукты других компаний. Поэтому в решение нашей поставленной задачи мы включили сравнение SSA с конкурентами и создание новых тестовых баз, основанных на примерах работы этих подуктов.

Процесс анализа работы SSA

  • Скачать исходники проекта
  • Разобраться со структурой проекта, попробовать его собрать. При этом возможно требуется установить какие-либо библиотеки, утилиты, sdk
  • Запустить построение статического анализа (в зависимости от размера проекта может занимать от нескольких минут до 8-10 часов)
  • Если произошла внутренняя ошибка построения (а такое бывало часто) – нужно получить стек вызовов и запостить баг
  • Если анализ прошел успешно – анализируем диагностику:
    1. Погружаемся в исследование ошибок многотысячного чужого кода
    2. При этом имеется GUI вариант, в котором удобно сортировать и фильтровать диагностику, а также переходить на строки исходного кода, вызвавших эту ошибку. И имеется текстовый файл со всей диагностикой, который необходимо «раскрасить»:
      +! – ошибки, которые разработчик приложения должен, по нашему мнению, исправить.
      ++ - правильная диагностика (корректное утверждение о программе. исправление такой диагностики остается на усмотрение разработчика приложения)
      +- - правильность диагностики зависит от алгоритма
      -+ - false positive. Так называется ситуация, когда статический анализатор пытается анализировать программу "в целом", принимая в расчет все возможные значения входных данных. При этом он может найти ошибку, которой на самом деле в данном конкретном случае нет (пример в главе «Трудности работы с SSA»)
      -- - SSA bug. Абсолютно неправильная диагностика. Ошибка в алгоритме SSA.
    3. Для диагностики, помеченной -+ и – нужно запостить баги и создать тесты.
    4. Такой «раскрашенный» файл является в каком-то роде базой знаний для данного проекта. С его помощью можно сравнивать эффективность работы различных версий SSA.

Результаты работы SSA

С помощью Source Checker мы полностью проанализировали такие проекты, как: decss (библиотека в составе Media Player Classic) (56 диагностики), Notepad ++ v5.7 (986 диагностики), 252.eon (spec 2000)(273 диагностики). Частично проанализировали WinMerge (644 диагностики). Также мы пытались построить анализ для Mozilla Firefox и MongoDB, но ничего не вышло из-за internal error (которую успели исправить только к моменту завершения нашей стажировки). Результаты анализа представлены на следующих диаграммах:

npp results252_eon resultsdecss results

Как можно видеть, SSA сообщает много интересной информации для разработчиков приложений. Полезность этой информации зависит от многих факторов:

  1. размер проекта. Чем больше анализируемый проект, тем больше в нем зависимостей и условий. Все это усложняет эффективную работу SSA, затрудняет межпроцедурный анализ.
  2. сложная вложенность функций.
  3. использование некоторых библиотечных функций SSA не знает пока о многих библиотечных функциях. Это часто приводит к загрублению в обработке их аргументов и возвращаемых значений.
  4. качество написания проекта Если проект сам по себе написан достаточно хорошо, согласно известным канонам безопасных программ (как, например, notepad ++), то в процентном соотношении SSA находит достаточно большое количество false positives по отношению к числу хорошей диагностики. И это нормально - в коде, в котором нет ошибок, статический анализатор и не должен ничего находить. Однако необходимо избавляться от false positives - это одна из главных трудностей работы с SSA (подробнее про это см. в главе "Особенности работы с SSA").

Наибольший интерес представлял анализ notepad ++. Это приложение считается достаточно стабильным, и многие пользователи используют именно его, чтобы оценить качество работы статических анализаторов.

Особенности работы с SSA

Для эффективной работы с SSA необходимо учитывать некоторые особенности его работы.
Первая – это обилие false positive.
Рассмотрим следующий пример:

struct S {
const char* name;
int id;
};
S namedArray[] = {
{"one", 1},
{"two", 2},
{"three", 3},
{"four", 4},
{"five", 5},
{"six", 6},
};
#define nrKeys sizeof(namedArray)/sizeof(S)
int _tmain(int argc, _TCHAR* argv[])
{
int i;
bool flag = false;
for (i = 0; i < nrKeys; i++) {
if (namedArray[i].id == 2)
{
flag = true;
break;
}
}
if (flag == true)
namedArray[i].id = 3;
return 0;
}

SSA диагностика:
example.cpp(26): error #12049: buffer overflow: array index of "namedArray" is possibly outside the bounds; array "namedArray" of size (0:5) can be indexed by value 6

Однако переменная i никогда не будет равна 6, т.к. namedArray[i].id = 3; (line 26) выполнится только если flag = true. А Flag может стать равным true только в цикле, т.е. I всегда <6.

Алгоритмы статического анализа не всегда способны корректно анализировать зависимость хода исполнения программы от значений различных переменных. Особую трудность вызывает работа с массивами, так как анализ области значений каждого элемента массива в отдельности приводит к огромной ресурсоемкости алгортимов. Поэтому анализ в некоторых ситуациях приходится упрощать.

Еще один пример:
 
int f(int n)
{
int j, k, arr[2];
for (k = 0; k < 2; k++)
arr[k] = 0;
if (n != 0)
{
j = n;
arr[k - 1] = 1;
}
if (arr[k - 1] != 0)
{
printf("%d\n", j);
}
return 0;
}

SSA диагностика:
example.cpp(12): error #12144: "j" is possibly uninitialized
Однако же видно, что переменная j всегда будет инициализирована.

Некоторые конкурирующие продукты в этом случае предпочитают не выдавать вообще никакой диагностики, что может привести к замалчиванию о серьезных дефектах в приложениях. SSA во многих случаях информирует разработчика о возможной проблеме. Именно с этим связан несколько повышенный объем false-positive диагностики.

Однако сравнивая SSA со статическими анализаторами, предлагаемыми другими компаниями, на различных тестах, можно сделать вывод, что продукт Intel®Static Security Analyzer возвращает большее количество сообщений, чем аналогичные продукты. Основная часть диагностики является корректными утверждениями о программе, исправление которых остается на усмотрение разработчика.

Вторая особенность – это build specification file
Для того, чтобы провести анализ приложения необходимо построить build specification file, отвечающий за порядок анализа файлов проекта. Для этого используются специальные утилиты, поставляемые вместе с SSA. Для создания build specification file достаточно выполнить стандартное построение приложения из-под прилагаемой утилиты.
Если вы модифицируете свой проект, добавляя или удаляя какой-то файл, или изменяя опции компиляции – необходимо создать новый файл спецификации, иначе анализ может быть неполным или неправильным.

И третья особенность – message suppression и filtering.
В SSA предусмотрена возможность выбора диагностики для анализа. Для этого в продукте предусмотрено два механизма. Фильтрация(filtering) сообщений и подавление сообщений (suppression). Пользовтель SSA имеет возможность отфильтровать интересующие его сообщения по следующим признакам:

  • severity - уровень важности сообщения
  • problem - тип проблемы
  • source - месторасположение проблемы в исходном коде программы
  • state - статус диагностики
  • investigated - смотреть только исследованные или неисследованные проблемы

Механизм подавления сообщений реализован с помощью статусов диагностики:

  • Confirmed - отложить
  • Fixed - проблема была исследована и исправлена
  • Not a problem - программист не считает данную диагностику проблемой и не собирается исправлять
  • Not fixed - проблема не была исправлена в предыдущем построении приложения
  • Regression - проблема была неправильно исправлена в предыдущем построении приложения.

В итоге, процесс исследования диагностики следуюший:

  1. Смотрим на описание диагностики и местоположение проблемы в коде, вызвавшим эту диагностику.
  2. Если проблема не нуждается в исправлении, устанавливаем статус "Not a problem".
  3. Если проблема нуждается в исправлении, то:
    1. Если мы хотим исправить ее сейчас, то идем в код, исправляем и переводим статус в "Fixed".
    2. Если хотим исправить ее позже, переводим статус в "Confirmed".
  4. После нового построения приложения:
    1. "New" становится "Not fixed"
    2. Если диагностика со статусом "Fixed" по прежнему присутсвует в результатах анализа, то ее статус изменяется на "Regression"
    3. Диагностики помеченные статусами "Not a problem", Confirmed не меняют своего статуса
  5. При этом:
    1. New, Not fixed, Regression являются uninvestigated
    2. Not a problem, Confirmed, Fixed are investigated

Результаты стажировки

В результате мы создали около 300 новых тестов для SSA. Мы постарались максимально улучшить качество SSA, не только анализируя эффективность его работы, но и пользовательский интерфейс.

В результате своей стажировки я написала статью на английском языке, которая включила в себя:

  • Описание преимуществ статического анализа
  • Краткий руководство по SSA
  • Трудности работы с SSA
  • Сравнение работы SSA c другими продуктами на рынке на конкретном примере

Я думаю, что задача выполнена на 100%.
Я получила огромный опыт работы с open-source проектами при их скачивании и компиляции (с помощью cmake, scons, Mozilla build).
Познакомилась с различными продуктами верификации программ, основанными на алгоримах статического анализа.
Стала опытным пользователем SSA и увеличила свои знания об интеловском компиляторе, частью которого SSA и является. Углубила свои знания языков C/C++ и приобрела навыки написания безопасных программ.
Я познакомилась с языком Perl, написав несколько скриптов для обработки диагностики.
Улучшила свой письменный и устный английский.
Работе помогала поддержка команды, подробные разъяснения ментора и кипучая деятельность нашего менеджера.

Впечатления от Летней Школы Intel

Два месяца летней школы были настолько необычными и интересными, что я могу с уверенностью сказать – они перевернули мою жизнь. Международная IT-компания – это мир, со своими законами и правилами. Здесь все прислушиваются друг к другу, и всюду царит уважение. Бесплатный кофе повышает настроение, а атмосфера офиса дарит ощущение того, что ты – часть чего-то очень важного и значительного. Все это захватывает тебя и несет на своих волнах в увлекательный мир исследований и технологий. Кроме корпоративной жизни нас ждала интереснейшая образовательная часть. В результате я очень многое узнала о продуктах Intel.

После летней стажировки я уяснила для себя одно важное правило:
Не нужно бояться сделать на шаг больше, чем нужно.

Я очень рада, что смогла попасть в Летнюю Школу. Я благодарна всем организаторам, а особенно Николаю Куртову, директору школы в Новосибирске.