exponenta event banner

ISO/IEC TS 17961 [taintformatio]

Использование запятнанного значения для записи в объект с помощью форматированной функции ввода или вывода

Описание

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

Использование запятнанного значения для записи в объект с помощью форматированной функции ввода или вывода [1 ].

Внедрение Polyspace

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

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

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

  • Недопустимое использование стандартной библиотечной подпрограммы.

  • Недопустимое использование стандартной подпрограммы строки библиотеки.

  • Запятнанная строка NULL или строка, не являющаяся завершающей значение NULL.

  • Спецификатор затененного формата строки.

  • Недопустимое использование стандартной подпрограммы строки библиотеки.

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

Примеры

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

Проблема

Переполнение буфера из неверного спецификатора формата строки происходит, когда аргумент спецификатора формата для таких функций, как 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);
}
Проблема

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

Риск

Недопустимые аргументы стандартной библиотечной функции приводят к неопределенному поведению.

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

Исправление зависит от первопричины дефекта. Например, аргумент к printf функция может быть NULL потому что указатель был инициализирован с помощью NULL и значение инициализации не было перезаписано по определенному пути выполнения.

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

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

Пример - Вызов printf Без строки
#include <stdio.h>
#include <stdlib.h>

void print_null(void) {

  printf(NULL); 
}

Функция printf принимает только входные аргументы строки или спецификаторы формата. В этой функции входное значение равно NULL, что не является допустимой строкой.

Исправление - использовать совместимые входные аргументы

Одной из возможных корректировок является изменение входных аргументов в соответствии с требованиями стандартной библиотечной подпрограммы. В этом примере входной аргумент был изменен на символ.

#include <stdio.h>

void print_null(void) {
    char zero_val = '0';
    printf((const char*)zero_val); 
}
Проблема

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

Риск

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

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

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

char * strcpy(char * destination, const char* source);
пытается скопировать слишком много байт в целевой аргумент по сравнению с доступным буфером, ограничить исходный аргумент перед вызовом strcpy. В некоторых случаях можно использовать альтернативную функцию, чтобы избежать ошибки. Например, вместо strcpy, вы можете использовать strncpy для управления количеством скопированных байтов. См. также раздел Интерпретация результатов поиска ошибок в интерфейсе пользователя Polyspace Desktop.

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

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

Пример - Ошибка процедуры использования стандартной строки библиотеки
 #include <string.h>
 #include <stdio.h>
 
 char* Copy_String(void)
 {
  char *res;
  char gbuffer[5],text[20]="ABCDEFGHIJKL";

  res=strcpy(gbuffer,text); 
  /* Error: Size of text is less than gbuffer */

  return(res);
 }

Последовательность text больше по размеру, чем gbuffer. Поэтому функция strcpy не удается скопировать text в gbuffer.

Исправление - использовать действительные аргументы

Одной из возможных корректировок является объявление строки назначения gbuffer с размером, равным или большим, чем исходная строка text.

#include <string.h>
 #include <stdio.h>
 
 char* Copy_String(void)
 {
  char *res;
  /*Fix: gbuffer has equal or larger size than text */
  char gbuffer[20],text[20]="ABCDEFGHIJKL";

  res=strcpy(gbuffer,text);

  return(res);
 }
Проблема

Эта проблема возникает, когда строки из небезопасных источников используются в подпрограммах обработки строк, которые неявно отменяют ссылку на буфер строк, например, strcpy или sprintf.

Средство проверки не вызывает дефектов для строки, возвращенной при вызове scanf-семейные вариадные функции. Аналогично, при передаче строки с помощью %s спецификатор для printf-семейные вариадные функции.

Риск

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

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

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

Проверьте строку перед ее использованием. Проверьте, что:

  • Строка не имеет значение NULL.

  • Строка имеет нулевое окончание

  • Размер строки соответствует ожидаемому размеру.

Пример - Получение строки из входного аргумента
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define SIZE128 128
#define MAX 40
extern void print_str(const char*);
void warningMsg(void)
{
	char userstr[MAX];
	read(0,userstr,MAX);
	char str[SIZE128] = "Warning: ";
	strncat(str, userstr, SIZE128-(strlen(str)+1));
	print_str(str);
}



void errorMsg(void)
{
	char userstr[MAX];
	read(0,userstr,MAX);
	char str[SIZE128] = "Error: ";
	strncat(str, userstr, SIZE128-(strlen(str)+1));
	print_str(str);
}

В этом примере строка str сцеплен с аргументом userstr. Значение userstr неизвестно. Если размер userstr превышает доступное пространство, конкатенация переполняется.

Исправление 1 - проверка данных

Одной из возможных корректировок является проверка размера userstr и убедитесь, что строка оканчивается NULL, прежде чем использовать ее в strncat. В этом примере используется вспомогательная функция, sansitize_str, для проверки строки. Дефекты сосредоточены в этой функции.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define SIZE128 128
#define MAX 40
extern void print_str(const char*);
int sanitize_str(char* s) {
	int res = 0; 
	if (s && (strlen(s) > 0)) { // Defect only raised 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(void)
{
	char userstr[MAX];
	read(0,userstr,MAX);
	char str[SIZE128] = "Warning: ";
	if (sanitize_str(userstr))	
		strncat(str, userstr, SIZE128-(strlen(str)+1));
	print_str(str);
}
Исправление 2 - проверка данных

Другой возможной поправкой является вызов функции 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;
}
Проблема

Эта проблема возникает, когда printfФункции -style используют спецификатор формата, созданный из небезопасных источников.

Риск

При использовании элементов внешнего управления для форматирования строки могут возникнуть проблемы переполнения буфера или представления данных. Злоумышленник может использовать эти элементы форматирования строк для просмотра содержимого стека с помощью %x или запись в стек с помощью %n.

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

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

Другое возможное исправление - разрешить только ожидаемое количество аргументов. По возможности используйте функции, которые не поддерживают уязвимых %n оператор в строках формата.

Пример - Получение элементов из пользовательского ввода
#include <stdio.h>
#include <unistd.h>
#define MAX 40
void taintedstringformat(void) {
	char userstr[MAX];
	read(0,userstr,MAX);
	printf(userstr);   
}

В этом примере выполняется печать входного аргумента userstr. Строка неизвестна. Если он содержит такие элементы, как %, printf может интерпретировать userstr в виде строкового формата, а не строки, что приводит к аварийному завершению программы.

Исправление - Печать в виде строки

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

#include <stdio.h>
#include <unistd.h>
#define MAX 40
void taintedstringformat(void) {
	char userstr[MAX];
	read(0,userstr,MAX);
	printf("%.20s", userstr);;   
}
Проблема

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

Опасная функцияУровень рискаБолее безопасная функция
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;
}

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

Разрешимость: неразрешимая
Представлен в R2019a

[1] Выдержки из стандарта «ISO/IEC TS 17961 Technical Specification - 2013-11-15» воспроизводятся с согласия AFNOR. Нормативную ценность имеет только оригинальный и полный текст стандарта, опубликованный изданиями AFNOR - доступный через веб-сайт www.boutique.afnor.org.