exponenta event banner

CERT C: STR31-C правил

Убедитесь, что в хранилище для строк достаточно места для символьных данных и пустого признака конца

Описание

Определение правила

Убедитесь, что в хранилище строк достаточно места для символьных данных и пустого признака конца. [1 ]

Внедрение Polyspace

Эта проверка проверяет наличие следующих проблем:

  • Использование опасной стандартной функции.

  • В строковом массиве отсутствует значение null.

  • Переполнение буфера из неверного спецификатора формата строки.

  • Переполнение буфера назначения при обработке строк.

Примеры

развернуть все

Проблема

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

Опасная функцияУровень рискаБолее безопасная функция
getsПо своей сути опасен - Вы не можете контролировать длину ввода с консоли.fgets
cinПо своей сути опасен - Вы не можете контролировать длину ввода с консоли.Избегайте или предваряйте вызовы cin с cin.width.
strcpyВозможно, опасно - если длина источника больше, чем длина места назначения, может произойти переполнение буфера.strncpy
stpcpyВозможно, опасно - если длина источника больше, чем длина места назначения, может произойти переполнение буфера.stpncpy
lstrcpy или StrCpyВозможно, опасно - если длина источника больше, чем длина места назначения, может произойти переполнение буфера.StringCbCopy, StringCchCopy, strncpy, strcpy_s, или strlcpy
strcatВозможно, опасно - если результат конкатенации больше целевого, может произойти переполнение буфера.strncat, strlcat, или strcat_s
lstrcat или StrCatВозможно, опасно - если результат конкатенации больше целевого, может произойти переполнение буфера.StringCbCat, StringCchCat, strncay, strcat_s, или strlcat
wcpcpyВозможно, опасно - если длина источника больше, чем длина места назначения, может произойти переполнение буфера.wcpncpy
wcscatВозможно, опасно - если результат конкатенации больше целевого, может произойти переполнение буфера.wcsncat, wcslcat, или wcncat_s
wcscpyВозможно, опасно - если длина источника больше, чем длина места назначения, может произойти переполнение буфера.wcsncpy
sprintfВозможно, опасно - если длина вывода зависит от неизвестных длин или значений, может произойти переполнение буфера.snprintf
vsprintfВозможно, опасно - если длина вывода зависит от неизвестных длин или значений, может произойти переполнение буфера.vsnprintf
Риск

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

Зафиксировать

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

См. примеры исправлений ниже.

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

Пример - использование sprintf
#include <stdio.h>
#include <string.h>
#include <iostream>

#define BUFF_SIZE 128


int dangerous_func(char *str)
{
    char dst[BUFF_SIZE];
    int r = 0;

    if (sprintf(dst, "%s", str) == 1)
    {
        r += 1;
        dst[BUFF_SIZE-1] = '\0';
    }
    
    return r;
}

В этом примере функция использует sprintf для копирования строки str кому dst. Однако, если str больше буфера, sprintf может вызвать переполнение буфера.

Коррекция - использование snprintf с размером буфера

Одной из возможных корректировок является использование snprintf и укажите размер буфера.

#include <stdio.h>
#include <string.h>
#include <iostream>

#define BUFF_SIZE 128


int dangerous_func(char *str)
{
    char dst[BUFF_SIZE];
    int r = 0;

    if (snprintf(dst, sizeof(dst), "%s", str) == 1)
    {
        r += 1;
        dst[BUFF_SIZE-1] = '\0';
    }
    
    return r;
}
Проблема

Отсутствие NULL в массиве строк возникает, когда строка не имеет достаточного места для завершения с помощью символа NULL '\0'.

Этот дефект относится только к проектам в C.

Риск

Переполнение буфера может произойти при копировании строки в массив без использования неявного пустого терминатора.

Зафиксировать

При инициализации символьного массива с литералом не указывайте границы массива.

char three[]  = "THREE";
Компилятор автоматически выделяет место для пустого терминатора. В предыдущем примере компилятор выделяет достаточное пространство для пяти символов и нулевого признака конца.

Если проблема возникает после инициализации, возможно, потребуется увеличить размер массива на единицу для учета пустого терминатора.

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

Пример - Размер массива слишком мал
void countdown(int i)
{
    static char one[5]   = "ONE";
    static char two[5]   = "TWO";
    static char three[5] = "THREE";
}

Символьный массив three имеет размер от 5 до 5 символов 'T', 'H', 'R', 'E', и 'E'. Нет места для нулевого символа в конце, поскольку three имеет размер всего пять байт.

Исправление - увеличение размера массива

Одной из возможных корректировок является изменение размера массива для пяти символов плюс нулевой символ.

void countdown(int i)
{
    static char one[5]   = "ONE";
    static char two[5]   = "TWO";
    static char three[6] = "THREE";
}
Исправление - изменение метода инициализации

Одной из возможных корректировок является инициализация строки, оставляя пустой размер массива. Этот метод инициализации обеспечивает выделение достаточного объема памяти для пяти символов и символа terminating-null.

void countdown(int i)
{
    static char one[5]   = "ONE";
    static char two[5]   = "TWO";
    static char three[]  = "THREE";
}
Проблема

Переполнение буфера из неверного спецификатора формата строки происходит, когда аргумент спецификатора формата для таких функций, как sscanf приводит к переполнению или занижению в аргументе буфера памяти.

Риск

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

Зафиксировать

Используйте спецификатор формата, совместимый с размером буфера памяти.

Пример - Переполнение буфера памяти
#include <stdio.h>

void func (char *str[]) {
    char buf[32];
    sscanf(str[1], "%33c", buf);
}

В этом примере: buf может содержать 32 char элементы. Поэтому спецификатор формата %33c вызывает переполнение буфера.

Коррекция - использовать меньшую точность в спецификаторе формата

Одной из возможных корректировок является использование меньшей точности в спецификаторе формата.

#include <stdio.h>

void func (char *str[]) {
    char buf[32];
    sscanf(str[1], "%32c", buf);
}
Проблема

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

Например, при вызове функции sprintf(char* buffer, const char* format), используется постоянная строка format большего размера, чем buffer.

Риск

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

Зафиксировать

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

  • Если вы используете sprintf для записи отформатированных данных в строку, используйте snprintf, _snprintf или sprintf_s вместо этого для обеспечения контроля длины. В качестве альтернативы можно использовать asprintf для автоматического выделения памяти, необходимой для целевого буфера.

  • Если вы используете vsprintf для записи форматированных данных из списка переменных аргументов в строку, используйте vsnprintf или vsprintf_s вместо этого для обеспечения контроля длины.

  • Если вы используете wcscpy для копирования широкой строки используйте wcsncpy, wcslcpy, или wcscpy_s вместо этого для обеспечения контроля длины.

Другим возможным решением является увеличение размера буфера.

Пример - Переполнение буфера в sprintf Использовать
#include <stdio.h>

void func(void) {
    char buffer[20];
    char *fmt_string = "This is a very long string, it does not fit in the buffer";

    sprintf(buffer, fmt_string);
}

В этом примере: buffer может содержать 20 char элементы, но fmt_string имеет больший размер.

Коррекция - использование snprintf Вместо sprintf

Одной из возможных корректировок является использование snprintf функция для обеспечения контроля длины.

#include <stdio.h>

void func(void) {
    char buffer[20];
    char *fmt_string = "This is a very long string, it does not fit in the buffer";

    snprintf(buffer, 20, fmt_string);
}

Проверить информацию

Группа: Правило 07. Символы и строки (STR)
Представлен в R2019a

[1] Данное программное обеспечение было создано компанией MathWorks и включает в себя следующие компоненты: «Веб-сайт SEI CERT-C», © 2017 Университет Карнеги-Меллон, веб-сайт SEI CERT-C + + © 2017 Университет Карнеги-Меллон, "Стандарт кодирования SEI CERT C - Правила разработки безопасных, Надежные и безопасные системы - 2016 Edition ", © 2016 Университет Карнеги-Меллон, и "Стандарт кодирования SEI CERT C++ - Правила разработки безопасных, Надежные и безопасные системы в C++ - 2016 Edition "© 2016 Университет Карнеги-Меллон, со специальным разрешением от его Института программного обеспечения.

ЛЮБОЙ МАТЕРИАЛ УНИВЕРСИТЕТА КАРНЕГИ МЕЛЛОНА И/ИЛИ ЕГО ПРОГРАММНОГО ИНЖЕНЕРНОГО ИНСТИТУТА, СОДЕРЖАЩИЙСЯ В НАСТОЯЩЕМ ДОКУМЕНТЕ, ПОСТАВЛЯЕТСЯ КАК ЕСТЬ. УНИВЕРСИТЕТ КАРНЕГИ МЕЛЛОН НЕ ДАЕТ НИКАКИХ ГАРАНТИЙ, ВЫРАЖЕННЫХ ИЛИ ПОДРАЗУМЕВАЕМЫХ, В ОТНОШЕНИИ ЛЮБЫХ ВОПРОСОВ, ВКЛЮЧАЯ, НО НЕ ОГРАНИЧИВАЯСЬ, ГАРАНТИИ ПРИГОДНОСТИ ДЛЯ ЦЕЛЕЙ ИЛИ ТОВАРНОЙ ПРИГОДНОСТИ, ИСКЛЮЧИТЕЛЬНОСТИ ИЛИ РЕЗУЛЬТАТОВ, ПОЛУЧЕННЫХ ОТ ИСПОЛЬЗОВАНИЯ УНИВЕРСИТЕТ КАРНЕГИ МЕЛЛОН НЕ ДАЕТ НИКАКИХ ГАРАНТИЙ В ОТНОШЕНИИ СВОБОДЫ ОТ ПАТЕНТА, ТОВАРНОГО ЗНАКА ИЛИ НАРУШЕНИЯ АВТОРСКИХ ПРАВ.

Данное программное обеспечение и связанная с ним документация не были рассмотрены и не одобрены Университетом Карнеги-Меллона или его Институтом разработки программного обеспечения.