Читаем 19 смертных грехов, угрожающих безопасности программ полностью

В Visual С++ самыми важными с этой точки зрения являются предупреждения С4018, С4389иС4244.

В gcc ищите предупреждения «warning: comparison between signed and unsigned integer expressions».

Относитесь с подозрением к директивам #pragma отключающим предупреждения, например:

...

#pragma warning(disable : 4244)

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

...

int ConcatBuffers(char *buf1, char *buf2,

size_t len1, size_t len2) {

char buf[0xFF];

if(len1 + len2) > 0xFF) return -1;

memcpy(buf, buf1, len1);

memcpy(buf + len1, buf2, len2);

// сделать что-то с buf

return 0;

}

Здесь проверяется, что суммарный размер двух входных буферов не превышает размера выходного буфера. Но если lenl равно 0x103, а 1еп2 равно 0xfffffffc, то сумма переполняет 32–разрядный регистр процессора и оказывается равной 255 (0xff), так что проверка успешно проходит. В результате memcpy попытается записать примерно 4 Гб в буфер размером всего 255 байтов!

Не вздумайте подавлять эти надоедливые предупреждения путем приведения типов. Теперь вы знаете, насколько это рискованно и как внимательно нужно все проверять. Найдите все приведения и убедитесь, что они безопасны. О приведениях и преобразованиях в языках С и С++ см. раздел «Операции приведения» выше.

Вот еще один пример:

...

int read(char* buf, size_t count) {

// Сделать что-то с памятью

}

...

while (true) {

BYTE buf[1024];

int skip = count – cbBytesRead;

if (skip > sizeof(buf))

skip = sizeof(buf);

if (read(buf, skip))

cbBytesRead += skip;

else

break;

...

В этом фрагменте значение skip сравнивается с 1024, и если оно меньше, то в буфер buf копируется skip байтов. Проблема в том, что если skip оказывается отрицательным (скажем, -2), то оно будет заведомо меньше 1024, так что функция read попытается скопировать–2 байта, а это значение, будучи представлено как целое без знака (тип size_t), равно без малого 4 Гб. Итак, read копирует 4 Гб в буфер размером 1 Кб. Печально!

Еще один источник неприятностей – это оператор new в языке С++. Он сопряжен с неявным умножением:

...

Foo *p = new Foo(N);

Если N контролируется противником, то возможно переполнение внутри operator new при вычислении выражения N * sizeof(Foo);

С#

Хотя сам язык С# и не допускает прямых обращений к памяти, но иногда программа обращается к системным вызовам, помещенным в блок, помеченный ключевым словом unsafe (при этом ее еще надо компилировать с флагом /unsafe). Любые вычисления, результат которых передается системному вызову, нужно контролировать. Для этого полезно применить ключевое слово checked или – еще лучше – соответствующий флаг компилятора. Включите его и следите, не произойдет ли исключения. Напротив, ключевое слово unchecked используйте изредка, предварительно обдумав все последствия.

Java

В языке Java прямые обращения к памяти также запрещены, поэтому он не так опасен, как C/C++. Но проявлять беспечность все же не следует: как и в C/C++, в Java нет никакой защиты от переполнения целых, и легко можно допустить логические ошибки. О том, какие существуют программные решения, см. в разделе «Искупление греха».

Visual Basic и Visual Basic .NET

Visual Basic ухитрился превратить проблему переполнения целого в проблему отказа от обслуживания – примерно такую же ситуацию мы имеем при использовании ключевого слова checked в С#. Подозрение должны вызывать те места, где программист применяет механизм перехвата для игнорирования ошибок при работе с целыми. Убедитесь, что ошибки обрабатываются правильно. Следующее предложение в программе на Visual Basic (не Visual Basic .NET) свидетельствует о лености программиста, не пожелавшего обрабатывать ошибки, возникающие во время работы программы. Нехорошо это.

...

On Error Continue

Perl

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

<p>Тестирование</p>

Если на вход подаются строки символов, попробуйте задать размеры так, чтобы вызвать ошибку. Часто это происходит, если длина строки составляет 64К или 64К – 1 байтов. Также ошибки возможны для длин, равных 127, 128, 255 и 32К плюс–минус единица. Если вам удалось подобрать тест так, что прибавление единицы к числу вызвало изменение знака или обращение в нуль, значит, вы не зря потрудились.

Перейти на страницу:

Похожие книги

Основы программирования в Linux
Основы программирования в Linux

В четвертом издании популярного руководства даны основы программирования в операционной системе Linux. Рассмотрены: использование библиотек C/C++ и стан­дартных средств разработки, организация системных вызовов, файловый ввод/вывод, взаимодействие процессов, программирование средствами командной оболочки, создание графических пользовательских интерфейсов с помощью инструментальных средств GTK+ или Qt, применение сокетов и др. Описана компиляция программ, их компоновка c библиотеками и работа с терминальным вводом/выводом. Даны приемы написания приложений в средах GNOME® и KDE®, хранения данных с использованием СУБД MySQL® и отладки программ. Книга хорошо структурирована, что делает обучение легким и быстрым. Для начинающих Linux-программистов

Нейл Мэтью , Ричард Стоунс , Татьяна Коротяева

ОС и Сети / Программирование / Книги по IT
97 этюдов для архитекторов программных систем
97 этюдов для архитекторов программных систем

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

Билл де Ора , Майкл Хайгард , Нил Форд

Программирование, программы, базы данных / Базы данных / Программирование / Книги по IT
Программист-прагматик. Путь от подмастерья к мастеру
Программист-прагматик. Путь от подмастерья к мастеру

Находясь на переднем крае программирования, книга "Программист-прагматик. Путь от подмастерья к мастеру" абстрагируется от всевозрастающей специализации и технических тонкостей разработки программ на современном уровне, чтобы исследовать суть процесса – требования к работоспособной и поддерживаемой программе, приводящей пользователей в восторг. Книга охватывает различные темы – от личной ответственности и карьерного роста до архитектурных методик, придающих программам гибкость и простоту в адаптации и повторном использовании.Прочитав эту книгу, вы научитесь:Бороться с недостатками программного обеспечения;Избегать ловушек, связанных с дублированием знания;Создавать гибкие, динамичные и адаптируемые программы;Избегать программирования в расчете на совпадение;Защищать вашу программу при помощи контрактов, утверждений и исключений;Собирать реальные требования;Осуществлять безжалостное и эффективное тестирование;Приводить в восторг ваших пользователей;Формировать команды из программистов-прагматиков и с помощью автоматизации делать ваши разработки более точными.

А. Алексашин , Дэвид Томас , Эндрю Хант

Программирование / Книги по IT