К специальному программному обеспечению (СПО), выполняющемуся в реальном масштабе времени, предъявляются жесткие с точки зрения обеспечения надежности и отказоустойчивости требования. Сокращение уязвимостей и ошибок, результатом которых может стать частичный или полный отказ системы реального времени, является трудоемкой задачей, для автоматизации которой в НИИСИ РАН были разработаны технологические средства автоматизированной генерации СПО (ТСАГ СПО). Эти средства позволяют сокращать количество уязвимостей при разработке СПО реального времени за счет применения типовых программных компонентов, входящих в состав поставляемой вместе с ТСАГ СПО библиотеки. К ним относятся синтаксические конструкции языка, утверждения и выражения вызовов функций ОC2000 [1], пакет поддержки модуля (ППМ – набор драйверов устройств, необходимых для функционирования ОС2000, например, системные часы и контроллер прерываний) и шаблоны программ реального времени.
Синтаксические конструкции языка Си, вошедшие в библиотеку, являются подмножеством Си – множества конструкций языка Си, определенного нотацией в приложении «А» стандарта языка (ISO/IEC 9899::1999). Конструкции из этого множества были проанализированы на предмет использования в базе исходных текстов СПО реального времени, имеющейся в распоряжении разработчиков ТСАГ СПО. Конструкции, найденные в базе исходных текстов более одного раза, были объединены в подмножество. Из этого подмножества исключены повторяющиеся и взаимозаменяемые конструкции. Таким образом, в библиотеку ТСАГ СПО вошло 225 конструкций языка Си.
В библиотеке присутствуют 1898 утверждений и выражений вызовов функций ОС2000 и 756 утверждений и выражений вызовов функций ППМ. В утверждениях и выражениях вызовов функций размещены дополнительная информация об аргументах, а также их значения по умолчанию.
Библиотека, в состав которой входят синтаксические конструкции языка Си (например, циклы и условия), утверждения и выражения вызовов функций ОС2000 и ППМ, является достаточной для написания программ в ТСАГ СПО. Тем не менее для сокращения уязвимостей в СПО требуется добавить в библиотеку шаблоны программ реального времени (программы работы с памятью, средствами синхронизации, прерываниями и т.д.), в которых заранее исключены потенциальные уязвимости. Использование таких шаблонов при разработке позволит увеличить надежность и отка- зоустойчивость ПО. Для того чтобы определить, какие именно шаблоны нужно включить в библиотеку, требуется составить классификацию уязвимостей, на ее основании выбрать типовые уязвимости и сделать для них шаблоны программ.
ТСАГ СПО совместно с расширенной дополнительными шаблонами библиотекой позволяет автоматизировать проверку исходных текстов разрабатываемых программ на соответствие синтаксису языка и корректное использование функций ОС2000 и ППМ, а также предоставляет возможность использования шаблонов программ реального времени, в которых устранены типовые уязвимости. Перечисленные средства сокращают количество уязвимостей и ошибок в СПО реального времени: синтаксических, семантических, ошибок синхронизации и ошибок данных.
Методы сокращения количества уязвимостей
Разработка программ в ТСАГ СПО выполняется в соответствии со стандартами унифицированного языка моделирования UML (ISO/IEC 19501:2005(E)) и расширяемого языка разметки XML [2]. По стандарту UML особенности моделируемого объекта должны изображаться графически в виде совокупности связанных между собой графических элементов.
В процессе проектирования программ ТСАГ СПО строятся диаграммы, для этого используется библиотека ТСАГ СПО. Библиотека содержит XML-документы, которые визуализируются ТСАГ СПО графическими вершинами (graphic node) типа action. XML-документы содержат представления конструкций языка программирования, утверждений и выражений вызовов функций ОС2000 и ППМ, шаблонов программ реального времени на языке XML. В XML-документах также содержатся данные, требуемые для отображения на диаграммах (количество графических вершин, отображаемый в графических вершинах текст). Все XML-документы, входящие в библиотеку ТСАГ СПО, соответствуют XML-схеме [3], разработанной на основе данных из стандарта языка программирования Си и позволяющей устанавливать синтаксическую и семантическую правильность проектируемых в ТСАГ СПО программ без предварительной компиляции. Далее по тексту будем называть эту схему XML-схемой языка Си, а XML-документы из библиотеки – заготовками UML.
Разработка программ в ТСАГ СПО выполняется с использованием диаграмм программной деятельности (ДПД), которые являются особым видом диаграмм деятельности UML. Создавая программу, разработчик копирует заготовки UML из библиотеки на ДПД и заполняет значения параметров этих заготовок. Копирование заготовки UML на ДПД может предполагать вставку заготовки UML внутрь уже имеющейся. Параметры заготовки UML задаются в диалоговом окне «Параметры группы» ДПД (см. рис. 1).
Для каждой ДПД можно построить результирующий XML-документ, объединяющий в себе заготовки UML из библиотеки, которые используются на ДПД. Порядок объединения XML-документов соответствует порядку следования заготовок UML на конкретной ДПД. ДПД считается корректной, если построенный из нее результирующий XML-документ соответствует XML-схеме языка Си. Проверка корректности ДПД выполняется в процессе генерации результирующего XML-документа из ДПД.
ТСАГ СПО представляют собой совокупность следующих взаимодействующих программных средств:
– подсистема графического интерфейса ТСАГ СПО (обеспечивает управление проектами ТСАГ СПО, а также запуск подсистем ТСАГ СПО в режиме графического интерактивного диалога);
– подсистема графического представления ВС РВ (предназначена для визуального проектирования приложений);
– подсистема текстовой поддержки графического представления вычислительных средств реального времени (предназначена для создания, редактирования и организации XML-файлов (XML-схем и XML-документов);
– подсистема генерации текстов программ в исходном виде [4] (предназначена для перевода диаграмм программной деятельности в набор файлов с текстом программ в исходном виде на языке Си).
Классификация уязвимостей
Для сбора информации об уязвимостях использовались статический анализатор clang и набор исходных текстов программ (ИТП) реального времени (ППМ для ОС2000, примеры к графической библиотеке реального времени, тесты и программы, разработанные в отделе математического обеспечения НИИСИ РАН). Статический анализатор clang после обработки исходного текста программного модуля создает протокол, в который входят общая статистика по программному модулю и детализация конкретных уязвимостей (см. листинг 1).
Листинг 1.
/home/osuser/rtos/rtos-baget-2.50.20/bsp/compile205/scsi/am53c974.c:1824:64 Warning: use of GNU old-style field designator extension
/home/osuser/rtos/rtos-baget-2.50.20/bsp/compile205/scsi/am53c974.c:337:28 Dead store: Value stored to 'temp' during its initialization is never read
/home/osuser/rtos/rtos-baget-2.50.20/bsp/compile205/scsi/am53c974.c:353:5 Dead store: Value stored to 'temp' is never read
/home/osuser/rtos/rtos-baget-2.50.20/bsp/compile205/scsi/am53c974.c:1303:6 Dead store: Value stored to 'device' is never read
3 Dead store , 1 Warning ,
4 total
Формат протокола следующий: каждая строка соответствует некоторой уязвимости, в строке содержатся информация о файле программного модуля (абсолютный путь), номер строки в исходном тексте, где найдена уязвимость, тип уязвимости и ее краткое описание. В конце протокола выводится общая статистика по обработанному програм- мному модулю. В результате анализа ИТП программой clang (204 программных модуля с исходными текстами – в общей сложности более 111 700 строк) были обнаружены типы уязвимостей (в соответствии с протоколами clang), приведенные в таблице.
В соответствии с данными из таблицы можно выделить три основных типа уязвимостей программ реального времени:
– семантические уязвимости (невыполнение условий, некорректное распределение ресурсов, выделение памяти без последующего освобождения – утечка памяти, некорректное использование типов данных, использование уязвимых функций или конструкций языка программирования);
– уязвимости, проявляющиеся при синхронизации потоков управления, например, клинчи;
– предупреждения.
Исследование семантических уязвимостей помогает понять основополагающие факторы, способствующие появлению ошибок в исходном коде. Как уже было отмечено, типичные семантические уязвимости – это ошибки работы с памятью, логические ошибки, ошибки некорректного распределения ресурсов и использование уязвимых функций стандартных библиотек языка программирования. При исследовании уязвимостей важным направлением является исследование различных входных типов данных и событий, которые приводят к ошибочному поведению программы. На основании результатов данного анализа реализуется механизм исключения ошибочного поведения программы во время выполнения. Исходной информацией для исследования уязвимостей является фактическое влияние уязвимости на выполнение программы. Следует отметить, что возможны эффекты частичного отказа (программа работает, однако не соответствует заданному алгоритму) и общего (программа не работает вследствие критической уязвимости, вызывающей зависание аппаратуры или перезагрузку ОС2000). Важно исследовать уязвимость с точки зрения защиты информации (безопасности) и целостности входных и выходных данных. Для этого решается задача поиска и идентификации уязвимости в программе, предполагающая рассмотрение результатов работы средств протоколирования и трассировщика, составление модели программы и имитационное моделирование. Рассматриваются также проблема локализации ошибок и возможность их исправления непосредственно во время выполнения программы.
Семантические уязвимости
В результате исследования ИТП было установлено, что более 70 % уязвимостей связаны с семантическими ошибками (например, неучтенное состояние данных, непредусмотренное ветвление). Частыми, но менее распространенными являются ошибки, возникающие при работе с памятью (утечка памяти, доступ к памяти по некорректным указателям). Редки ошибки синхронизации (клинчи, опережения).
Количество семантических ошибок может быть минимизировано за счет заготовок UML, в которых предусмотрены обработка условий и отсутствие зацикливаний. В них не применяются такие конструкции языка Си, как goto или switch/case. В этих заготовках предусмотрены проверка возвращаемых значений функций ОС2000 и ППМ, а также корректная инициализация аргументов этих функций (например, атрибуты потока управления). Количество ошибок доступа к памяти может быть минимизировано аналогичным способом. Например, известно, что утечки памяти зачастую вызваны отсутствием функции free() или ей подобной. В связи с этим предлагается использовать универсальную заготовку выделения динамической памяти, в состав которой, помимо maloc(), будет входить и функция free(). Количество ошибок синхронизации может быть минимизировано за счет использования шаблонов программ, в которых представлены основные способы синхронизации для систем реального времени (семафоры, очереди сообщений, таймеры и сигналы). К сожалению, такие шаблоны нельзя назвать универсальными и пригодными к применению в программах в существующем виде.
Ошибки, проявляющиеся в программах в процессе обработки пользовательских данных, можно также отнести к семантическим (зачастую это ошибки работы с памятью). Средства ТСАГ СПО могут сократить появление подобных ошибок за счет использования при проектировании расширенной дополнительными шаблонами библиотеки.
Конфигурирование ОС2000
Наиболее распространенной является ошибка инициализации ОС2000, при возникновении которой блокируется запуск прикладной программы. Например, ОС2000 сконфигурирована таким образом, что после загрузки выполняется запрос времени по сети. Если на инструментальной ЭВМ служба времени настроена корректно, целевая ЭВМ с ОС2000 физически соединена по сети с инструментальной ЭВМ, а также корректно настроены сетевые адреса, то ОС2000 успешно получит показания времени и передаст управление прикладной программе. Если разорвать соединение целевой и инструментальной ЭВМ, ОС2000 выдаст ошибку инициализации (System Init Error) и прикладная программа не будет запущена.
Конфигурация ОС2000 может являться условием переключения на ошибочное поведение программы: например, предположим, что в ОС2000 задан размер стека потока управления в 16 384 байта, а программа использует буфер для обработки данных большего объема (например, 17 000 байт). В этом случае часть данных будет утеряна или в процессе обработки появится исключение. Таким образом, процедура конфигурирования ОС2000 является важным этапом в процессе классификации и поиска ошибок.
Задача поиска уязвимости при выполнении программы
Эффекты, оказываемые уязвимостью на программу реального времени, можно разделить на две категории: вызывающие зависание программы (исключения) и приводящие к некорректной работе ее алгоритма. В ТСАГ СПО используются заготовки UML, в которых предусмотрена обработка исключений (try_begin – try_catch – try_end). Пользователю предоставляется гибкий механизм поиска, анализа и исправления ошибок, приводящих к исключениям. Следует отметить, что механизм обработки исключительных ситуаций позволяет реагировать на уязвимость на лету.
Вообще говоря, проблема поиска уязвимостей напрямую связана с эффектом, который они оказывают. Например, уязвимости, вызывающие исключения, легко выявляются, так как в командном интерпретаторе ОС2000 предусмотрены инструменты для вывода на экран состояния потока управления и вывода содержимого его стека (команды интерпретатора ОС2000 tt и ti). Программа для работы с трассами выполнения ОС2000 позволяет выявить и устранить подавляющее большинство уязвимостей, однако требует запуска непосредственно на целевой ЭВМ для получения протокола с трассами.
Важный инструмент, который позволяет сократить число уязвимостей в программах, разрабатываемых средствами ТСАГ СПО, – это библиотека UML-заготовок шаблонов программ с корректными алгоритмами и исчерпывающими комментариями, предоставляющими программисту системную информацию о специфике работы программы (функции, конструкции языка).
Примеры
Алгоритмы работы подсистемы генерации текстов программ в исходном виде, входящей в состав ТСАГ СПО, были рассмотрены в [4], в частности, функция PgenfileParse(), которая является основополагающей в данной подсистеме. В этой функции реализован алгоритм обработки XML-данных, выполняющий генерацию текста программы в исходном виде на языке Си. Функция PgenfileParse() была проанализирована статическим анализатором исходного кода clang. В результате анализа выявлены следующие уязвимости [5]:
- потенциальная возможность утечки памяти (Resource Management Bug: memory leak);
- неучтенное состояние данных (Resource Management Bug: file handle/socket leak);
- ошибки данных (Data Bug: unchecked return values).
Протокол обработки функции PgenfileParse() анализатором исходного кода clang представлен в листинге 2.
Листинг 2.
[osuser@localhost staticAnalize]$ sh staticAnalize.sh PgenfileParse.c
PgenfileParse.c:226:2 Dead store: Value stored to 'foundinline' is never read
PgenfileParse.c:246:49 Security: Call to function 'strcpy' is insecure as it does not provide bounding of the memory buffer. Replace unbounded copy functions with 'strncpy'. CWE-119
PgenfileParse.c:307:7 Security: Call to function 'strcpy' is insecure as it does not provide bounding of the memory buffer. Replace unbounded copy functions with 'strncpy'. CWE-119
PgenfileParse.c:321:3 Dead store: Value stored to 'error' is never read
PgenfileParse.c:323:38 Dead store: Value stored to 'error' is never read
PgenfileParse.c:330:6 Security: Call to function 'strcpy' is insecure as it does not provide bounding of the memory buffer. Replace unbounded copy functions with 'strncpy'. CWE-119
PgenfileParse.c:341:3 Security: Call to function 'strcpy' is insecure as it does not provide bounding of the memory buffer. Replace unbounded copy functions with 'strncpy'. CWE-119
PgenfileParse.c:357:2 Security: Call to function 'strcpy' is insecure as it does not provide bounding of the memory buffer. Replace unbounded copy functions with 'strncpy'. CWE-119
PgenfileParse.c:448:4 Dead store: Value stored to 'error' is never read
PgenfileParse.c:464:47 Logic error: Opened File never closed. Potential Resource leak
4 Dead store , 1 Logic error , 5 Security ,
10 total
На основании выявленных уязвимостей была дополнена библиотека UML-заготовок ТСАГ СПО. В ее состав включены три подгруппы заготовок: vulnerables, recommend и secure. В подгруппу заготовок vulnerables включены потенциально опасные функции библиотеки языка Си string.h.
Идея объединения уязвимых функций в подгруппу предполагает привлечение внимания программиста, уже на этапе разработки предупрежденного системой о потенциальной опасности используемых функций. В подгруппу заготовок recommend была добавлена UML-заготовка вызова функции, в которой, помимо вызова функции, выполняется анализ кода возврата этой функции.
Данная UML-заготовка составлена из вызова функции (rc = func(argList);) и условия if-then-else, которые входят в стандартную библиотеку ТСАГ СПО. Идея объединения рассмотренных заготовок в подгруппу имеет рекомендательный характер. Программист, как правило, прислушивается к рекомендациям разработчика среды проектирования, таким образом, возрастает вероятность использования рекомендуемых заготовок, в которых заложена обработка потенциальных ошибок.
В подгруппу заготовок secure была добавлена UML-заготовка безопасного вызова функции fopen(). Это составная заготовка, в которой выполняется вызов функции fopen(), анализируется код возврата этой функции и на основании анализа выполняется либо вывод диагностического сообщения об ошибке (в случае, если вызов fopen() завершился неудачей), либо вход в ветвь условия, в которой выполняются некоторые действия (например чтение) над открытым дескриптором и его последующее закрытие. Данная заготовка исключает неучтенное состояние данных, например, использование несуществующего файлового дескриптора или невыполнение закрытия файлового дескриптора после завершения операций над ним.
Функция PgenfileParse() была реализована средствами ТСАГ СПО с использованием расширенной библиотеки заготовок, рассмотренной выше. В состав проекта функции PgenfileParse() вошли 19 диаграмм программной деятельности. Принципиальная схема проекта представлена на рисунке 2.
При реализации функции PgenfileParse() использовались UML-заготовки из подгрупп vulnerables, recommend и secure. Эти заготовки включены в те места функции PgenfileParse(), где статический анализатор показал потенциальные уязвимости. Составлена Главная диаграмма программной деятельности функции PgenfileParse(), из которой был сгенерирован исходный код. При его повторной проверке статическим анализатором потенциальных уязвимостей выявлено не было (листинг 3), что подтвердило корректность использования в местах возникновения потенциальных уязвимостей UML-заготовок из подгрупп vulnerables, recommend и secure.
Листинг 3.
[osuser@localhost staticAnalize]$ sh staticAnalize.sh PgenfileParse.c
Errors not found
Сгенерированный исходный код функции PgenfileParse() был скомпилирован в составе программного модуля pgenparse.c подсистемы ге- нерации текстов программ в исходном виде. Подсистема была протестирована на предмет корректной работы, в частности, была выполнена повторная генерация исходного текста из диаграммы программной деятельности функции PgenfileParse(). Первоначально сгенерированный исходный текст и исходный текст, сгенерированный повторно, оказались идентичными (совпадение байт в байт), следовательно, изменение функции PgenfileParse() не повлияло на работу подсистемы генерации текстов программ в исходном виде.
В заключение можно отметить, что в статье были сформулированы основные классы ошибок, которые могут быть локализованы и устранены посредством использования ТСАГ СПО. В приведенном примере для устранения ошибок применена расширенная библиотека ТСАГ СПО, которая является экспериментальной и должна быть дополнена. Развитие библиотеки будет выполняться в соответствии с классификацией типов ошибок и уязвимостей, рассмотренных в данной статье.
Литература
1. Введение в ОС2000. Вопросы кибернетики. Информационная безопасность. Операционные системы реального времени. Базы данных / В.Л. Безруков, А.Н. Годунов, П.Е. Назаров [и др.]; [под. ред. В.Б. Бетелина]. М.: НИИСИ РАН, 1999. С. 76–109.
2. Extensible Markup Language (XML) 1.0 (Fourth Edition) W3C Recommendation 16 August 2006, edited in place 29 September 2006. URL: http://www.w3.org/TR/REC-xml/ (дата обращения: 07.06.2012).
3. XML Schema Part 0: Primer (Second Edition) W3C Recommendation 28 October 2004. URL: http://www.w3.org/TR/2004/ REC-xmlschema-0-20041028/ (дата обращения: 07.06.2012).
4. Нархов К.Г., Генератор текста программ в исходном виде для систем реального времени // Программные продукты и системы. 2010. № 4. С. 24–30.
5. Laune Harris, A Software Bug Taxonomy, NY: New York University personal page. URL: www.cs.nyu.edu/~lharris/content/ bugtaxonomy.html (дата обращения: 07.06.2012).