ISO/IEC TS 17961 [taintformatio]

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

Описание

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

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

Реализация Polyspace

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

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

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

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

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

  • Испорченная строка со значением NULL или без значения NULL.

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

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

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

Примеры

расширить все

Проблема

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

Риск

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

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

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

Пример - переполнение буфера памяти
#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);
}
Проблема

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

Риск

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

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

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

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

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

Пример - Вызывающие 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 для управления количеством скопированных байтов. Смотрите также Результаты интерпретации Bug Finder в интерфейсе пользователя Polyspace Desktop.

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

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

Пример - Недопустимое использование стандартной строки библиотеки Стандартной программы Ошибки
 #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.

  • Строка завершена со значением 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 и убедитесь, что строка имеет нулевое значение, прежде чем использовать ее в 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
Риск

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

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

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

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

Если вы не хотите устранять проблему, добавьте комментарии к своему результату или коду, чтобы избежать другой проверки. Смотрите Адрес Результаты 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;
}

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

Решимость: Undecidable
Введенный в R2019a

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