19 смертных грехов, угрожающих безопасности программ - [21]

Шрифт
Интервал

...

int a, b, c;

c = a + b;

if(a ^ b ^ c < 0)

return BAD_INPUT;

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

...

int a, b, c;

c = a * b;

if(c < 0)

return BAD_INPUT;

Даже если на входе допустимы только положительные числа, этот код все равно пропускает некоторые переполнения. Возьмем, к примеру, выражение (2 А 30 + + 1) * 8, то есть 2 А 33 + 8. После отбрасывания битов, вышедших за пределы 32 разрядов, получается 8. Это число положительно, а ошибка тем не менее есть. Безопаснее решить эту задачу, сохранив результат умножения 32–разрядных чисел в 64–разрядном, а затем проверить, равен ли хотя бы один из старших битов единице. Это и будет свидетельством переполнения.

Когда встречается подобный код:

...

unsigned a, b;

...

if (a * b < MAX) {

...

}

проще ограничить а и b значениями, произведение которых заведомо меньше МАХ. Например:

...

#include «limits.h»

#define MAX_A 10000

#define MAX_A 250

assert(UINT_MAX / MAX_A >= MAX_B); // проверим, что MAX_A и MAX_B

                                                      // достаточно малы

if (a < MAX_A && b < MAX_B) {

...

}

Если вы хотите надежно защитить свой код от переполнений целого, можете воспользоваться классом Safelnt, который написал Дэвид Лебланк (подробности в разделе «Другие ресурсы»). Но имейте в виду, что, не перехватывая исключения, возбуждаемые этим классом, вы обмениваете возможность выполнения произвольного кода на отказ от обслуживания. Вот пример использования класса Safelnt:

...

size_t CalcAllocSize(int HowMany, int Size, int HeaderLen)

{

try{

SafeInt tmp(HowMany);

return tmp * Size + SafeInt(HeaderLen);

}

catch(SafeIntException)

{

return (size_t)~0;

}

}

Целые со знаком используются в этом фрагменте только для иллюстрации; такую функцию следовало бы писать, пользуясь одним лишь типом size_t. Посмотрим, что происходит «под капотом». Прежде всего проверяется, что значение HowMany неотрицательно. Попытка присвоить отрицательное значение беззнаковой переменной типа Safelnt вызовет исключение. Затем Safelnt умножается на переменную Size типа int, при этом проверяется как переполнение, так и попадание в допустимый диапазон. Результат умножения Safelnt * int – это снова Safelnt, поэтому далее выполняется операция контролируемого сложения. Обратите внимание на приведение входного параметра типа int к типу Safelnt – отрицательная длина заголовка с точки зрения математики, может быть, и допустима, но с точки зрения здравого смысла – нет, поэтому размеры лучше представлять числами без знака. Наконец, перед возвратом величина типа Safelnt преобразуется обратно в size_t, это пустая операция. Внутри класса Safelnt выполняется много сложных проверок, но ваш код остается простым и понятным.

Если вы программируете на С#, включайте флаг /checked и применяйте unchecked–блоки только для того, чтобы отключить контроль в отдельных предложениях.

Дополнительные защитные меры

Если вы работаете с компилятором gcc, то можете задать флаг–ftrapv. В этом случае за счет обращения к различным функциям во время выполнения будут перехватываться переполнения при операциях со знаковыми и только со знаковыми целыми. Неприятность в том, что при обнаружении переполнения вызывается функция abort().

Компилятор Microsoft Visual С++ 2005 автоматически обнаруживает переполнение при вызове оператора new. Ваша программа должна перехватывать исключения std::bad_alloc, иначе произойдет аварийный останов.

Другие ресурсы

□ «Integer Handling with the С++ Safelnt Class», David LeBlanc, msdn.microsoft.com/library/default.asp?url=/library/en–us/dncode/html/ secure01142004.asp

□ «Another Look at the Safelnt Class», David LeBlanc, http://msdn.microsoft.com/ library/default.asp?url=/library/en–us/dncode/html/secure05052005.asp

□ «Reviewing Code for Integer Manipulation Vulnerabilities*, Michael Howard, http://msdn. microsoft, com/library/default.asp?url=/library/en–us/dncode/ html/ secure04102003.asp

□ «An Overlooked Construct and an Integer Overflow Redux», Michael Howard, http://msdn. microsoft, com/library/default.asp?url=/library/en–us/dncode/ html/ secure09112003.asp

□ «Expert Tips for Finding Security Defects in Your Code», Michael Howard, http://msdn.microsoft.eom/msdnmag/issues/03/l 1/SecurityCodeReview/ default.aspx

□ «Integer overflows – the next big threat», Ravind Ramesh, central.com/tech/story.asp?file=/2004/10/26/itfeature/9170256&sec=itfeature

□ DOS against Java JNDI/DNS, http://archives.neophasis.com/archives/ bugtraq/2004–11 / 0092.html

Резюме

Рекомендуется

□ Проверяйте на возможность переполнения все арифметические вычисления, в результате которых определяется размер выделяемой памяти.

□ Проверяйте на возможность переполнения все арифметические вычисления, в результате которых определяются индексы массивов.

□ Пользуйтесь целыми без знака для хранения смещений от начала массива и размеров блоков выделяемой памяти.


Рекомендуем почитать
Графика DirectX в Delphi

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


Вторая жизнь старых компьютеров

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


DirectX 8. Начинаем работу с DirectX Graphics

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


Симуляция частичной специализации

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


Обработка событий в С++

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


Питон — модули, пакеты, классы, экземпляры

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