19 смертных грехов, угрожающих безопасности программ. Майкл Ховард

Чтение книги онлайн.

Читать онлайн книгу 19 смертных грехов, угрожающих безопасности программ - Майкл Ховард страница 7

19 смертных грехов, угрожающих безопасности программ - Майкл Ховард

Скачать книгу

Ей нужно указать, сколько символов свободно в буфере, а не общую длину буфера. Вот еще один распространенный код, приводящий к переполнению:

      char buf[MAX_PATH];

      sprintf(buf, "%s – %d\n", path, errno);

      Если не считать нескольких граничных случаев, функцию sprintf почти невозможно использовать безопасно. Для Microsoft Windows было выпущено извещение о критической ошибке, связанной с применением sprintf для отладочного протоколирования. Подробности см. в бюллетене MS04–011 (точная ссылка приведена в разделе «Другие ресурсы»).

      А вот еще пример:

      char buf [ 32] ;

      strncpy(buf, data, strlen(data));

      Что неверно? В последнем аргументе передана длина входного буфера, а не размер целевого буфера!

      Еще один способ столкнуться с проблемой – по ошибке считать байты вместо символов. Если вы работаете с кодировкой ASCII, то между ними нет разницы, но в кодировке Unicode один символ представляется двумя байтами. Вот пример:

      _snwprintf(wbuf, sizeof(wbuf), «%s\n», input);

      Следующее переполнение несколько интереснее:

      bool CopyStructs(InputFile* pInFile, unsigned long count)

      {

      unsigned long i;

      m_pStructs = new Structs[count];

      for(i = 0; i < count; i++)

      {

      if(!ReadFromFile(pInFile, &(m_pStructs[i])))

      break;

      }

      }

      Как здесь может возникнуть ошибка? Оператор new[] в языке С++ делает примерно то же, что такой код:

      ptr = malloc(sizeof(type) * count);

      Если значение count может поступать от пользователя, то нетрудно задать его так, чтобы при умножении возникло переполнение. Тогда будет выделен буфер гораздо меньшего размера, чем необходимо, и противник сможет его переполнить. В компиляторе С++, который будет поставляться в составе Microsoft Visual Studio 2005, реализована внутренняя проверка для недопущения такого рода ошибок. Аналогичная проблема может возникнуть во многих реализациях функции calloc, которая выполняет примерно такую же операцию. В этом и состоит коварство многих ошибок, связанных с переполнением целых чисел: опасно не само это переполнение, а вызванное им переполнение буфера. Но подробнее об этом мы расскажем в грехе 3.

      Вот как еще может возникать переполнение буфера:

      #define MAX_BUF 256

      void BadCode(char* input)

      {

      short len;

      char buf[MAX_BUF];

      len = strlen(input);

      // конечно, мы можем использовать strcpy безопасно

      if(len < MAX_BUF)

      strcpy(buf, input);

      }

      На первый взгляд, все хорошо, не так ли? Но на самом деле здесь ошибка на ошибке. Детали мы отложим до обсуждения переполнения целых числе в грехе 3, а пока заметим, что литералы всегда имеют тип signed int. Если длина входных данных (строка input) превышает 32К, то переменная len станет отрицательна, она будет расширена до типа int с сохранением знака и окажется меньше MAX_BUF, что приведет к переполнению. Еще одна ошибка возникнет, если длина строки превосходит 64К. В этом случае мы имеем ошибку усечения: len оказывается маленьким положительным числом. Основной способ исправления – объявлять переменные для хранения размеров как имеющие тип size_t. Еще одна скрытая проблема заключается в том,

Скачать книгу