Научные публикации

Контроль уязвимостей в программах с исходными текстами (анализ sqc-файлов)

Введение

Вопрос, который поднимается в данной статье, исторически связан с сертификацией программного обеспечения. Несколько лет назад команда исследователей одной из лабораторий министерства обороны испытывала программно-аппаратный комплекс связи, в состав которого входило большое число различных типов исходных файлов. Среди прочих были файлы с малораспространенным расширением «sqc». В целом название указывало на некоторую связь с языком запросов SQL, но в действительности под этим могло скрываться все что угодно, в том числе и программная закладка.

Одной из первых проверок является «контроль избыточности». Суть его, как видно из названия, заключается в том, чтобы найти те файлы, которые не составляют конечный исполняемый файл, а, следовательно, и не должны подергаться дальнейшим испытаниям. Отступая от главной темы, можно отметить, что часто этой проверке придают излишне строгий смысл: большое число специалистов считают, что такие файлы могут содержать программные закладки и поэтому их необходимо удалить. Но при более детальном рассмотрении оказывается, что удаление такой избыточности не несет никакого функционального значения: если они действительно избыточные, то они не попадут в исполняемый файл, а если были признаны таковыми ошибочно, то их удаление приведет к ошибкам компиляции. Еще один вариант – это когда файл не компилируется, но используется, допустим, как конфигурационный, или даже дополнительный, откуда считывается специальная строка, активизирующая программную закладку. Взять и удалить его – означает обречь программу на какие-то действия, которые в лучшем случае будут незаметны, а в худшем - вызовут сбой программы. Такие ошибки необходимо уметь определять на стадии дальнейшего анализа и поэтому удаление избыточности не может рассматриваться в качестве критерия безопасности программы, а исключительно для контроля предварительной проверки.

Возвращаясь к основной теме статьи, приведу пример, когда файлы были определены как подлежащие дальнейшему анализу, а в действительности оказались избыточными. Как уже было сказано выше, в проекте программно-аппаратного комплекса связи наблюдались файлы с расширением «sqc». В них, как и во все остальные файлы, был вставлен уникальный датчик, помогающий определить, попадает ли тот или иной исходный файл в исполняемый код. Подробно методика рассматривается в статье Котенко Д.А. "Контроль избыточности исходных файлов программ на основе вставки программных датчиков", здесь же имеет смысл привести её суть: во все файлы проекта вставляется уникальный датчик, который жестко привязан к конкретному файлу. В два разных файла вставляются два разных датчика. Специальной поисковой утилитой в бинарном файле обнаруживается такой датчик, и это отмечается в базе данных. В ином случае файлы помечаются как избыточные.

Модель обнаружения избыточности настолько проста, что обязательно должны были найтись исключения. К ним целесообразно отнести и данный случай: файлы «sqc» в результате такой проверки были признаны анализатором за используемые, но в действительности они таковыми не являлись. Оказалось, что данные файлы используются как промежуточные и содержат команды SQL-препроцессора, который не поддерживается стандартом языка Си. Принцип работы с ними как раз и сводится к преобразованию в Си-текст, который затем компилируется. Интересным еще оказался и тот факт, что в каталоге с исходными файлами присутствовали только sqc-файлы, но не было даже следа от Си-файлов, в которые они должны были быть преобразованы, – они автоматически удалялись системой после того как компиляция завершалась.

Таким образом, перед исследователями возник интересный пример «призрачного» исходного файла, который вроде и есть, но проконтролировать его существование невозможно, так как он существует только в течение процесса компиляции – 5-10 минут.

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

Основная часть

Постановка задачи
К исходным данным целесообразно отнести следующее. Имеется проект для некоего программно-аппаратного комплекса, подлежащего проверке. В состав исходных файлов входят тексты, написанные на языке Си, а также тексты, содержащие SQL-директивы, обрабатываемые с помощью специального препроцессора. Последовательность компиляции и сборки содержится в make-файлах, где, в частности, определена схема обработки sqc-файлов (см. рис. 1).


Рисунок 1 – Последовательность обработки файла типа «sqc»

Файл с расширением «sqc» (см. №1 на рис. 1) обрабатывается с помощью утилиты «sqlpp » (см. №4 на рис. 1) и приводится (транслируется) к виду, понятному для Си-компилятора. Полученный файл компилируется и собирается в исполняемый код. Задача ставится следующим образом: необходимо определить избыточность файлов и подготовить их к статическому анализу.

Особенностью выполнения является невозможность выполнить статический анализ над sqc-файлами т.к. они не содержат достаточной информации о функциях, переменных и линейных участках. Все эти сведения появляются после того, как файл будет транслирован при помощи SQL-препроцессора. Поэтому представляется целесообразным уточнить задачу: изменить проект таким образом, чтобы вместо sqc-файлов использовались полноценные файлы «*.c».

Другой особенностью является замена проверяемых файлов в процессе статического анализа. Более подробно о статическом анализе написано в статье [2], здесь же можно привести краткое замечание, касающееся особенности его реализации. После выделения используемых файлов и анализа реализованных в них языковых конструкций, выполняется вставка специальных датчиков, которые принципиально отличаются от рассмотренных выше. Датчики вставляются в каждый линейный участок программы и сигнализируют об их срабатывании. При завершении процесса установки датчиков необходимо собрать такую измененную версию программы, которую часто называют лабораторной версией. В большинстве случаев достаточно записать исходные файлы в каталог, откуда они попадают на вход компилятора, но если есть такие файлы как «sqc», то может произойти перезапись лабораторных Си-файлов новыми, созданными на этапе препроцессирования. Такое положение дел негативно отразится на результатах анализа и приведет к ошибочным выводам.

Методы исследований
Для того, чтобы решить поставленную задачу, необходимо произвести предварительную подготовку make-файлов. Во-первых, требуется избавиться от команд удаления Си-файлов, выполняемых после успешной компиляции. Во-вторых, внести такие изменения, чтобы файл был транслирован только один раз, а последующие компиляция производилась только с Си-файлами. Для этих целей удаляются соответствующие строчки из make-файлов и формируется база данных анализатора. В ней необходимо отразить то, чего нет в исходном наборе – файлы, полученные из «sqc» в результате трансляции, иначе анализатор будет «ошибаться», вставляя датчики и собирая сведения о функциональных объектах. Ниже представлена последовательность выполнения этих изменений.

Исходные тексты, составляющие проект программного комплекса (см. №5 на рис. 2), учитываются анализатором (см. №1 на рис. 2) в базе данных (см. №2 на рис. 2) для дальнейшего ведения учета. В базе данных (БД) формируется таблица, предусматривающая поля для сведений об уникальном номере, имени, типе файла, а также о его длине, избыточности и некоторой другой служебной информации. Более подробную структуру БД можно найти в статье Д.Б.Арефьев, В.Л.Верещагин, А.И.Галанов "Метод статического анализа по токенам упрощенного языка". Именно на данном этапе необходимо проконтролировать запись в БД не только sqc-файлов, но и их Си-аналогов. Т.е проект программного комплекса должен включать и те, и другие файлы. Для этого необходимо выполнить компиляцию проекта, предварительно проанализировав make-файлы и поместив в комментарии команды удаления полученных Си-файлов. Необходимость учитывать сами sqc-файлы вытекает из требований к испытаниям – БД должна отражать действительное положение дел, т. к. на ее основании будут сформированы отчеты, содержащие контрольные суммы для всех файлов проекта. Если перед занесением в БД удалить sqc-файлы и оставить только их Си-аналоги, то произойдет несогласование между исходным комплектом файлов и полученным в процессе работы.


Рисунок 2 – Общая схема обработки исходных текстов на ранних этапах анализа

Таким образом, в отличие от стандартных ситуаций, полный пакет исходных текстов будет получен только после первой компиляции. Вставка датчиков (см. №4 на рис. 2), выполняемая с целью контроля избыточности, осуществляется во все файлы, которые были учтены в БД. Соответственно, если в проекте имеются 2 файла, например, «A.sqc» и «A.c», то в оба будут вставлено по уникальному датчику. Наиболее логично было бы предположить, что оба эти файла должны быть отмечены как используемые. Однако, в этом случае анализатор выберет для дальнейшего анализа только те файлы, которые помечены как используемые. Анализ предполагает лексический и синтаксический разборы с последующим семантическим соотнесением найденных конструкций с конструкциями грамматики языка Си. Если отметить как «используемые» sqc-файлы, то проанализировать их не представится возможным, т.к. для успешного завершения этого процесса необходимо по меньшей мере написать грамматику SQL-препроцессора. Если же отметить только их Си-аналоги, то при формировании отчета окажется, что все sqc-файлы являются избыточными и их будет необходимо удалить из проекта, что приведет к ошибкам компиляции, т.к. в исходном наборе файлов имеются только «sqc» и нет их Си-аналогов.

В качестве решения предлагается гибкое управление флагом избыточности в БД. На этапе выделения группы файлов для статического анализа необходимо признать Си-файлы «используемыми», а «sqc» - избыточными. На другом этапе – создания отчетов – наоборот, избыточными признаются Си-файлы, а используемыми должны быть «sqc».

Общую последовательность действий можно представить в виде следующего алгоритма:

  • (1) Получение исходных текстов проекта (всех файлов, которые необходимы для успешной компиляции и сборки);
  • (2) Внесение изменений в make-файлы: комментирование строк с командами удаления Си-файлов, полученных из sqc-файлов;
  • (3) Компиляция и сборка проекта: получение полной версии исходных файлов;
  • (4) Создание копии полученной версии файлов с целью возможности обновления лабораторных версий. Это необходимо для получения каких-либо промежуточных данных, например, если файлы меняются несколько раз за исследование: один раз в них вставляются датчики контроля избыточности, в другой вставляются другие датчики, контролирующие выполнение линейных участков. Крайне важно, чтобы эти оба варианта датчиков не находились в одном файле. Для этого производится полная замена файлов из сохраненной копии;
  • (5) Регистрация всех файлов проекта в БД;
  • (6) Вставка датчиков в зарегистрированные файлы;
  • (7) Компиляция и сборка проекта: получение исполняемых файлов со вставленными в них датчиками. В качестве промежуточных результатов получим информацию об используемых sqc-файлах, поскольку существует вероятность того, что часть из них избыточна;
  • (8) Проведение анализа избыточности файлов. Запись сведений в БД;
  • (9) Внесение изменений в make-файлы: комментирование строк с командами трансляции sqc-файлов. При наличии среди sqc-файлов избыточных, необходимо учитывать это обстоятельство: оформить в качестве комментариев соответствующие команды компиляции и сборки Си-файлов;
  • (10) Замена файлов лабораторной версии оригинальными файлами. Это необходимо для того, чтобы можно было вставить датчики контроля избыточности вторично. На данном этапе необходимо контролировать не столько sqc-файлы, сколько полученные из них Си-файлы;
  • (11) Повторная вставка датчиков во все зарегистрированные файлы;
  • (12) Компиляция и сборка проекта: получение исполняемых файлов;
  • (13) Проведение анализа избыточности файлов. Запись сведений в БД. В результате будет получен набор тех файлов, которые можно анализировать по правилам языка Си;
  • (14) После того, как будет завершен статический анализ, следует создать копию БД и инвертировать флаг избыточности у sqc- и соответствующих им Си-файлов. Это позволит сформировать отчет, где будет указано, что sqc-файлы были использованы при компиляции, а Си-файлы учитываться не будут;
  • (15) Выполнить контрольную проверку: удалить все избыточные файлы, относящиеся к исходным текстам (кроме них существуют еще конфигурационные, объектные, файлы проекта и т.п.) и произвести сборку проекта. Если проект собрался без замечаний, то считаем контроль выполненным верно. В ином случае необходимо определить причину и выполнить коррективу;
  • (16) Создать отчет об избыточности файлов.

Результаты исследований
Исследования показали, что sqc-файлы, являются малозаметным компонентом системы и теоретически могут скрывать в своем составе недокументированные возможности. Описанная методика была опробована на нескольких десятках файлов, в различных проектах, работающих под операционной системой реального времени QNX 4.25. На основе полученных результатов был успешно проведен контроль избыточности во всех проектах и сформированы корректные списки файлов, подлежащих статическому и динамическому анализам. К другим результатам исследования стоит отнести невозможность автоматического разбора sqc-файлов без соответствующих им на языке Си. Это связано с тем, что даже при наличии грамматики SQL-препроцессора невозможно предугадать, каким образом будет сформирован конечный Си-файл т.к. могут различаться версии транслирующих программ. В любом случае необходимо выполнять трансляцию средствами, предоставляемыми разработчиком. В качестве варианта возможного развития следует рассматривать полную автоматизацию процесса обработки сведений в БД, файлов проекта и выдачи результатов.

Заключение

Приведенная выше методика была успешно опробована на 3-х проектах общей численностью исходных текстов более 10 000 шт., из которых объем sqc-файлов составлял 1 %. В результате был осуществлен полноценный контроль «невидимых» Си-файлов. К недостаткам метода следует отнести неполную автоматизацию процесса, которая может быть оправдана небольшим объемом исследуемых файлов. Другим недостатком является большое количество итераций, которые приходится выполнять в процессе получения исходных текстов. К достоинствам следует отнести простоту, эффективность и структурированность метода и возможность достаточно быстро автоматизировать процесс анализа.