Июнь 2008

«Существует два способа создания дизайна программного обеспечения. Одним из способов является сделать его настолько простым, что, очевидно, есть без недостатков. И другой способ заключается в том, чтобы сделать его настолько сложным, что есть нет очевидных недостатков.»

Профессор Хоар

Разработка надежного и безопасного программного обеспечения стало сложной задачей, главным образом из-за неуправляемой сложности программных систем, которые мы строим сегодня. Недостатки программного обеспечения имеют много причин, но наши наблюдения показывают, что они в основном приходят из двух широких источников: i) дизайн, таких как вредоносные или непреднамеренного бэкдор; и ii) осуществление, например переполнение буфера.

Для решения этих проблем, Наша исследовательская группа в оборонных исследований и развития Канады (DRDC) Валкартье впервые работал по вопросам дизайна. Прототип верификатор дизайн UML был построен. Наш подход был успешным, но мы столкнулись с двумя трудностями: i) определение интересных свойств безопасности на уровне проектирования; и ii) масштабируемость процесса проверки.

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

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

Контекст & терминология

Уровень гарантии, необходимые для выполнения приложений зависит от их контекста выполнения. Наш контекст военных, в котором конфиденциальные данные обрабатываются чувствительных приложений, работающих на распространенных операционных системах, таких как Windows и Linux и главным образом запрограммированы в C/C++ и Java. Нашей основной целью было избавиться от общих проблем безопасности, используя средства автоматизированного исходного кода проверки для C++ и Java. Для этого мы сначала исследовали ошибки и уязвимостей, возникающих от дефектов программного обеспечения. Это позволило нам создать значимые тесты для оценки производительности обнаружения и удобство использования этих инструментов.

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

Поскольку эти проблемы много сортировка, терминология необходимо классифицировать их. Ошибка тесно связана с выполнением программы и происходит, когда поведение программы отличается от «какой она должна быть»; то есть от его спецификации. Дефект лежит в коде и представляет собой набор инструкций программы, которая вызывает ошибку. Дефект может быть также отсутствие чего-либо, например, отсутствие проверки данных. И наконец уязвимость — это дефект, который вызывает ошибку, которая может быть добровольно вызвано злоумышленнику повредить выполнение программы.

Мы сосредоточились на ошибки, дефекты и уязвимостей, которые могут оказать влияние на безопасность. Чтобы быть как вообще, насколько это возможно, мы хотели их приложения. Мы определили пять ошибок, двадцать пять видов дефектов по шести категориям и три уязвимости, как показано на рисунке 1.

Рисунок 1: Ошибки, дефекты и уязвимости

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

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

Большинство дефектов не всегда будет создавать ошибки для каждого выполнения программы. Сложные условия должны быть выполнены для ошибки, чтобы случиться и входные значения играют важную роль. Кроме того многие дефекты составные и нельзя объяснить только одной программы обучения. Ниже приведен список типов дефектов, которые мы использовали для создания наших тестов:

  • сбои в памяти управления: проблемы, связанные с выделения памяти, освобождение и копировать из одного буфера в другой
  • переполнения и underrun недостатки: проблемы, связанные с переполнения или противоподкатное из массива или C++ итератора
  • недостатки указателя: проблемы, связанные с использованием неправильного указателя
  • литые недостатки: проблемы, касающиеся неправильного приведения одного типа в другой
  • прочие недостатки: проблемы, которые не вписываются в другую категорию

Ошибки в целом нежелательно, но реальная проблема уязвимости, особенно дистанционно эксплуатационные. Мы отмечали, что почти все опасные уязвимости связаны с памяти чтения или записи из границ. Уязвимости могут быть классифицированы как:

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

Проблемы с программы на C/C++

Многие дефекты и ошибки возможны из-за плохого дизайна выбора при создании языков программирования C и C++. Эти языки требуют микро управления поведение программы через Управление памятью, ошибок из-за указателями и вызывают серьезные последствия казалось бы доброкачественные ошибки, такие как переполнение буфера. Краткий перечень основных недостатков конструкции C/C++ следующим образом:

  • отсутствие безопасности типа: типобезопасный программы fail быстро как их выполнение прекращается немедленно при возникновении ошибки, а не типобезопасным языки, как C/C++ позволяют выполнение erratic программ по-прежнему
  • Арифметика указателя: позволяет программисту изменять значения указателя без ограничений, что позволяет читать и писать в любом месте в пространстве памяти процесса, а также затрудняет программы проверки
  • статические буферы: буферы в C/C++ не могут увеличиваться для размещения данных, доступ к буферу, не проверяются для границ и переполнение может перезаписать память
  • отсутствие надежного строкового типа: C не имеет собственного типа для символьных строк, что означает, что статические буферы с потенциальными проблемами переполнения используются вместо; в то время как программы на C++ могут использовать строковый тип, наши наблюдения показывают, что это редкий случай

Создатели современных языков, таких как Java, имел в виду, эти проблемы и обратился к ним. Действительно Java иммунитет к C/C++ программа здравомыслия проблемы, поскольку среда выполнения проверяет исключение при возникновении ошибки. Однако многие программы проверок исправности создают unchecked исключения и они редко поймали программистов. Многие проблемы становятся уязвимости отказа в обслуживании, поскольку исключения uncaught сбой программы.

Инструменты оценки

Мы оценили 27 инструменты для C/C++ и 37 для Java. Все эти инструменты были разбиты на три семьи: i) Программа соответствия шашки; II) выполнения тестеры; и iii) Расширенные статические анализаторы.

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

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

Расширенные статические анализаторы работают на семантику программы вместо синтаксиса. Они обычно используют формальные методы, такие как Абстрактная интерпретация или проверки модели, которые часто приводят к проблемам с масштабируемостью. Код должен быть скомпилирован в модель, и это обычно комплекс с C/C++ из-за проблем переносимости кода между компиляторами.

Наши результаты можно резюмировать как:

  • для C/C++ коммерческие инструменты на сегодняшний день являются лучшими
  • для Java есть еще много хороших бесплатных инструментов
  • Поскольку Java не застрахована от большинства проблем психического здоровья программы, которые досаждают C/C++, нет никаких точных эквивалентов средств C/C++
  • фокус Java инструментов находится на передовой практики и проблемы высокого уровня дизайна

Поскольку наша цель выявления проблем психического здоровья программы, мы сосредоточились на инструменты для C/C++ во время нашей оценки. Для нашей оценки, наши критерии были: i) точность в недостатки обнаружены против ложных срабатываний; II) масштабируемость от малых до больших программ; III) охват или осмотр каждого возможного исполнения; IV) и качество диагностического отчета в его полезности для исправления проблемы.

Предварительные тесты показали, что только три инструмента для C/C++ имеет потенциал, чтобы помочь нам в достижении нашей цели: Coverity предупреждении и PolySpace для C++ для обнаружения дефектов и Parasoft страхования ++ для обнаружения ошибок. Мы проверили эти инструменты двумя путями: i) более реальный код производства, что, насколько нам известно, работал хорошо, но был немного багги; и ii) за многих небольших специальных частей кода (синтетические тесты) содержащие конкретные дефекты программирования. Чтобы сравнить эти инструменты, все результаты должны быть преобразованы в ошибки или дефекты. Для синтетических тестов дефекты и ошибки, которые они причинили были известны заранее так было легко конвертировать все дефекты. Однако для кода производства, ничего не было известно заранее, поэтому мы решили использовать лучший результат в качестве базового. Поскольку страхования ++ лучший исполнитель, все результаты были преобразованы к ошибкам.

Результаты

Полные результаты наших синтетических тестов доступны в первоначальном документе. Трудности тестирования программ C/C++ можно резюмировать следующим образом:

  • ни одно средство не сможет обнаружить каждый вид дефекта или ошибка
  • инструменты статического анализа нужно код хорошего качества для выполнения хорошо
  • Арифметика указателя используется для чтения и записи до сложных структур данных чрезвычайно затрудняет статический анализ
  • Makefiles часто шоу пробки из-за отсутствия у них степень детализации, их число делает отладку утомительной задачей, и они часто являются сложными и требуют много зависимостей
  • расширения компилятора C/C++ сделать разбор сложных нестандартных расширений
  • использование условной компиляции с помощью директив препроцессора, которые приходят из сочетания переменных среды, файлы конфигурации и параметры добавляет сложность процесса проверки
  • файлы заголовков часто создаются или переехал файл makefile в то время как он работает
  • часто есть много различных заголовков файлов с одинаковым именем, но в разных местах

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

Инструмент ограничения и лучший сценарий использования

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

Масштабируемость также является проблемой для статических инструментов, которые должны рассмотреть (и абстрактные) всех возможных казней.

Динамические инструменты имеют противоположная проблема: они очень масштабируемым, но обеспечивают плохое покрытие с плохой тестовых случаев. Однако если вы считаете, количество тестов, необходимых для покрытия всех возможных казней с динамических инструментов, масштабируемость по-прежнему является проблемой.

Лучший сценарий использования для предотвращения Coverity, когда все приложения необходимо проанализировать и компиляции с помощью рабочего файла makefile. Размер кода приложения может быть более чем 500K строк C++ без проблем. Coverity имеет много хороших точек: i) очень хорошая интеграция с makefiles; II) использует Эдисон компилятор переднего плана, который может читать код, содержащий расширения компилятора из почти каждый большой компилятор в промышленности; III) очень масштабируемым; IV) отличная диагностика с выполнения трассировок, которые легко понять и очень полезно для исправления проблем; и iv) использует инновационные, но несвободные, анализ на основе статистического анализа и эвристики.

Лучший сценарий использования для PolySpace для C++ является анализ небольших сегментов критического кода в приложениях, где никогда не должно происходить исключения среды выполнения. Размер кода приложения должен находиться под 20K строк C++. Он использует очень тщательный анализ на основе абстрактного толкования, с которой он может обнаружить ошибки времени выполнения статически. Он имеет приятный графический интерфейс, особенно зритель модуль, который используется для анализа отчета и перемещения исходного кода. Однако ей не хватает хорошей диагностики, потому что иногда это невозможно понять, дефект найденных.

Лучший сценарий использования для Parasoft страхования ++ является для тестирования гибридных систем на основе многих разнородных компонентов. Рассмотреть вопрос о покрытии кода, он всегда должен быть интегрирован в тестовый случай ремни безопасности, которые обеспечивают покрытие хорошего кода. Так как страхования ++ является динамичным инструментом, нет никаких ограничений размера кода приложения и код плохого качества не влияет на производительность обнаружения. Застраховать ++ имеет очень хороший диагностический с диаграммы памяти и стека вызовов, которые показывают, точно, что было перезаписан. Однако как уже упоминалось, тестовые случаи должны быть тщательно указаны с хорошим покрытием стратегией.

Обсуждение

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

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

Компьютерной индустрии, как правило, внедрять новые технологии очень быстро. Выделение людских и финансовых ресурсов, принятие новых языков программирования в целом соответствует законам моды: что это новое лучшее, что в этом году? что следует использовать, чтобы оставаться прохладным и современным? Это не обязательно плохой водитель прогресса. Однако, она охватывает вредная привычка: мы редко наблюдали программист, приняв новый язык программирования, потому что он знал все ловушки его текущего языка и хотел, чтобы избежать их.

Заключение

Корень проблемы безопасности не являются неспособность механизмов безопасности. Программы C/C++ особенно проблематичным, поскольку они применять практически никаких ограничений на выполнение программ, и они подвержены уязвимости с серьезными последствиями. Однако современные языки, такие как Java, иммунитет к C/C++ проблемы и не склонны к серьезной уязвимости. Конечно, так же, как с любым языком, должны тщательно проверены и правильно реализован дизайн. Использование Java не является панацеей, и по-прежнему следует в правильной реализации механизмов безопасности.

Проверка программ C/C++ является огромной проблемой. Эти языки очень трудно проанализировать из-за многих неопределенных или нестандартных семантик, указателями и расширения компилятора языка. Мы нашли не имеющихся в настоящее время проверки инструмент, который может снизить риск достаточно значительно для чувствительных приложений. Мы рекомендуем использование современных языков программирования, таких как Java, которые свести к нулю проблемы психического здоровья программы. Однако если использование C/C++ является обязательным, рекомендуется ограничить его использование и использование инструментов проверки и серьезных случаев.

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

Доля этой статьи:

Цитируете эту статью:

Оцените содержание: 
Нет голосов были поданы еще. Скажи свое слово!

Добавить новый комментарий

Обычный текст

  • Теги HTML не разрешены.
  • Адреса электронной почты и адреса страниц включите в ссылки автоматически.
  • Строки и параграфы переносятся автоматически.