Гарантируйте, что устройство хранения данных для строк имеет достаточный пробел для символьных данных и пустого терминатора строки
Использование опасной проверки стандартной функции подсвечивает использование функций, которые являются по сути опасными или потенциально опасными данными определенными обстоятельствами. В следующей таблице перечислены возможно опасные функции, риски использования каждой функции, и что функция использовать вместо этого.
Опасная функция | Рискните уровнем | Более безопасная функция |
---|---|---|
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 Bug Finder.
Смотрите примеры мер ниже.
Если вы не хотите устранять проблему, добавьте комментарии в свой результат или код, чтобы избежать другого анализа. Смотрите Результаты Polyspace Адреса Через Исправления ошибок или Комментарии.
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
с Buffer SizeОдно возможное исправление должно использовать snprintf
вместо этого и задать buffer size.
#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; }
Missing null in string array происходит, когда строка не имеет достаточного количества пробела, чтобы отключить с нулевым символом '\0'
.
Этот дефект применяется только для проектов в C.
Переполнение буфера может произойти, если вы копируете строку в массив, не принимая неявный пустой терминатор строки.
Если вы инициализируете символьный массив с литералом, стараетесь не задавать границы массивов.
char three[] = "THREE";
Если проблема происходит после инициализации вам придется увеличить размер массива одним, чтобы составлять пустой терминатор строки.
При определенных обстоятельствах вы можете хотеть инициализировать символьный массив с последовательностью символов вместо строки. В этой ситуации добавьте комментарии в свой результат или код, чтобы избежать другого анализа. Смотрите Результаты Polyspace Адреса Через Исправления ошибок или Комментарии.
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"; }
Одно возможное исправление должно инициализировать строку путем оставления незаполненного размера массивов. Этот метод инициализации выделяет достаточно памяти для этих пяти символов и нулевого символа завершения.
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); }
Целевое переполнение буфера в обработке строк происходит, когда определенные функции обработки строк пишут в свой целевой буферный аргумент при смещении, больше, чем buffer size.
Например, при вызове функционального sprintf(char* buffer, const char* format)
, вы используете постоянную строку format
большего размера, чем buffer
.
Переполнение буфера может вызвать неожиданное поведение, такое как повреждение памяти или остановка вашей системы. Переполнение буфера также вводит риск инжекции кода.
Одно возможное решение состоит в том, чтобы использовать альтернативные функции, чтобы ограничить количество записанных символов. Например:
Если вы используете sprintf
, чтобы записать отформатированные данные в строку, используйте snprintf
, _snprintf
или sprintf_s
вместо этого, чтобы осуществить управление длиной. Также используйте asprintf
, чтобы автоматически выделить память, требуемую для целевого буфера.
Если вы используете vsprintf
, чтобы записать отформатированные данные от списка аргументов переменной до строки, используйте vsnprintf
или vsprintf_s
вместо этого, чтобы осуществить управление длиной.
Если вы используете wcscpy
, чтобы скопировать широкую строку, используйте wcsncpy
, wcslcpy
или wcscpy_s
вместо этого, чтобы осуществить управление длиной.
Другое возможное решение состоит в том, чтобы увеличить buffer size.
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); }
Испорченный NULL или не пустая отключенная строка ищет строки из небезопасных источников, которые используются в стандартных программах обработки строк, которые неявно разыменовывают буфер строки. Например, strcpy
или sprintf
.
Испорченный NULL или не пустая отключенная строка не повышает дефекта для строки, возвращенной от вызова до scanf
- семейство variadic функции. Точно так же никакой дефект не повышен, когда вы передаете строку со спецификатором %s
к printf
- семейство variadic функции.
Если вы ссылаетесь на строку с помощью формы ptr[i]
, *ptr
или адресная арифметика с указателями, Средство поиска Ошибки повышает Использование испорченного дефекта указателя вместо этого. Испорченный NULL или не пустой отключенный дефект строки повышен только, когда указатель используется в качестве строки.
Если строка из небезопасного источника, возможно, что атакующий управлял строкой или указал указатель строки на различную ячейку памяти.
Если строкой является NULL, стандартная программа строки не может разыменовать строку, заставив программу отказать. Если строка не отключена пустым указателем, строка, которую знает стандартная сила не, когда строка заканчивается. Эта ошибка может заставить вас писать за пределы, вызвав переполнение буфера.
Подтвердите строку, прежде чем вы будете использовать ее. Проверяйте что:
Строка не является ПУСТОЙ.
Строка отключена пустым указателем
Размер строки совпадает с ожидаемым размером.
#include <stdio.h> #include <string.h> #include <stdlib.h> #define SIZE128 128 extern void print_str(const char*); void warningMsg(char* userstr) { char str[SIZE128] = "Warning: "; strncat(str, userstr, SIZE128-(strlen(str)+1)); print_str(str); } void errorMsg(char* userstr) { char str[SIZE128] = "Error: "; strncat(str, userstr, SIZE128-(strlen(str)+1)); print_str(str); }
В этом примере строка str
конкатенирован с аргументом userstr
. Значение userstr
неизвестно. Если размер userstr
больше, чем доступный пробел, переполнение конкатенации.
Одно возможное исправление должно проверять размер userstr
и убедиться, что строка отключена пустым указателем перед использованием его в strncat
. Этот пример использует функцию помощника, sansitize_str
, чтобы подтвердить строку. Дефекты сконцентрированы в этой функции.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define SIZE128 128
extern void print_str(const char*);
int sanitize_str(char* s) {
int res = 0;
if (s && (strlen(s) > 0)) { // TAINTED_STRING only flagged here
// - string is not null
// - string has a positive and limited size
// - TAINTED_STRING on strlen used as a firewall
res = 1;
}
return res;
}
void warningMsg(char* userstr)
{
char str[SIZE128] = "Warning: ";
if (sanitize_str(userstr))
strncat(str, userstr, SIZE128-(strlen(str)+1));
print_str(str);
}
void errorMsg(char* userstr)
{
char str[SIZE128] = "Error: ";
if (sanitize_str(userstr))
strncat(str, userstr, SIZE128-(strlen(str)+1));
print_str(str);
}
Другое возможное исправление должно вызвать функциональный errorMsg
и warningMsg
с определенными строками.
#include <stdio.h> #include <string.h> #include <stdlib.h> #define SIZE128 128 extern void print_str(const char*); void warningMsg(char* userstr) { char str[SIZE128] = "Warning: "; strncat(str, userstr, SIZE128-(strlen(str)+1)); print_str(str); } void errorMsg(char* userstr) { char str[SIZE128] = "Error: "; strncat(str, userstr, SIZE128-(strlen(str)+1)); print_str(str); } int manageSensorValue(int sensorValue) { int ret = sensorValue; if ( sensorValue < 0 ) { errorMsg("sensor value should be positive"); exit(1); } else if ( sensorValue > 50 ) { warningMsg("sensor value greater than 50 (applying threshold)..."); sensorValue = 50; } return sensorValue; }
Группа: правило 07. Символы и строки (STR) |
[1] Это программное обеспечение было создано MathWorks, включающим фрагменты: “Веб-сайт SEI CERT-C”, © 2017 Carnegie Mellon University, веб-сайт SEI CERT-C © 2017 Carnegie Mellon University”, CERT SEI C Кодирование Стандарта – Правил для Разработки безопасных, Надежных и Защищенных систем – 2 016 Выпусков”, © 2016 Carnegie Mellon University, and “CERT SEI Стандарт Кодирования C++ – Правил для Разработки безопасных, Надежных и Защищенных систем на C++ – 2 016 Выпусков” © 2016 Carnegie Mellon University, со специальным разрешением от его Института программной инженерии.
ЛЮБОЙ МАТЕРИАЛ УНИВЕРСИТЕТА КАРНЕГИ-МЕЛЛОН И/ИЛИ ЕГО ИНСТИТУТА ПРОГРАММНОЙ ИНЖЕНЕРИИ СОДЕРЖАЛ, ЗДЕСЬ ПРЕДОСТАВЛЯЕТСЯ НА ОСНОВЕ "ASIS". УНИВЕРСИТЕТ КАРНЕГИ-МЕЛЛОН НЕ ДАЕТ ГАРАНТИЙ НИКАКОГО ВИДА, ИЛИ ВЫРАЗИЛ ИЛИ ПОДРАЗУМЕВАЛ, ОТНОСИТЕЛЬНО ЛЮБОГО ВОПРОСА ВКЛЮЧАЯ, НО НЕ ОГРАНИЧИЛ, ГАРАНТИЯ ПРИГОДНОСТИ ДЛЯ ЦЕЛИ ИЛИ ВЫСОКОГО СПРОСА, ИСКЛЮЧИТЕЛЬНОСТИ, ИЛИ ЗАКАНЧИВАЕТСЯ ПОЛУЧЕННЫЙ ИЗ ИСПОЛЬЗОВАНИЯ МАТЕРИАЛА. УНИВЕРСИТЕТ КАРНЕГИ-МЕЛЛОН НЕ ДАЕТ ГАРАНТИИ НИКАКОГО ВИДА ОТНОСИТЕЛЬНО СВОБОДЫ ОТ ПАТЕНТА, ТОВАРНОГО ЗНАКА ИЛИ НАРУШЕНИЯ АВТОРСКОГО ПРАВА.
Это программное обеспечение и сопоставленная документация не были рассмотрены, ни являются подтвержденным Университетом Карнеги-Меллон или его Институтом программной инженерии.
1. Если смысл перевода понятен, то лучше оставьте как есть и не придирайтесь к словам, синонимам и тому подобному. О вкусах не спорим.
2. Не дополняйте перевод комментариями “от себя”. В исправлении не должно появляться дополнительных смыслов и комментариев, отсутствующих в оригинале. Такие правки не получится интегрировать в алгоритме автоматического перевода.
3. Сохраняйте структуру оригинального текста - например, не разбивайте одно предложение на два.
4. Не имеет смысла однотипное исправление перевода какого-то термина во всех предложениях. Исправляйте только в одном месте. Когда Вашу правку одобрят, это исправление будет алгоритмически распространено и на другие части документации.
5. По иным вопросам, например если надо исправить заблокированное для перевода слово, обратитесь к редакторам через форму технической поддержки.