exponenta event banner

CERT C: Rec. INT04-C

Ограничение целочисленных значений, полученных из запятнанных источников

Описание

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

Ограничение целочисленных значений, полученных из запятнанных источников. [1 ]

Внедрение Polyspace

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

  • Доступ к массиву с поврежденным индексом.

  • Контур, ограниченный запятнанным значением.

  • Выделение памяти с запятнанным размером.

  • Запятнанный размер массива переменной длины.

Примеры

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

Проблема

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

Риск

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

  • Underflow/underbrite буфера - запись в память перед началом буфера.

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

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

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

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

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

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

Пример - Используйте индекс для возврата значения буфера
#include <stdlib.h>
#include <stdio.h>
#define SIZE100 100
extern int tab[SIZE100];
static int tainted_int_source(void) {
  return strtol(getenv("INDEX"),NULL,10);
}
int taintedarrayindex(void) {
	int num = tainted_int_source();
    return tab[num];  
}

В этом примере индекс num получает доступ к массиву tab. Индекс num получен из небезопасного источника и функции taintedarrayindex не проверяет, num находится в диапазоне tab.

Коррекция - Проверить диапазон перед использованием

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

#include <stdlib.h>
#include <stdio.h>
#define SIZE100 100
extern int tab[SIZE100];
static int tainted_int_source(void) {
	return strtol(getenv("INDEX"),NULL,10);
}
int taintedarrayindex(void) {
	int num = tainted_int_source();
	if (num >= 0 && num < SIZE100) {
		return tab[num]; 
	} else {
		return -1;
	}
}

Проблема

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

Риск

Запятнанное значение может привести к закольцовыванию или бесконечному закольцовыванию. Злоумышленники могут использовать эту уязвимость для сбоя программы или вызвать другое непреднамеренное поведение.

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

Перед началом цикла проверьте неизвестные значения границы и итератора.

Пример - Граница контура из входного аргумента
#include<stdio.h>
enum {
    SIZE10  =  10,
    SIZE100 = 100,
    SIZE128 = 128
};

int taintedloopboundary(void) {
    int count;
    scanf("%d", &count);
    int res = 0;
    for (int i=0 ; i < count; ++i) {
        res += i;
    }
    return res;
}

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

Коррекция: Управление замкнутым контуром зажима

Одной из возможных корректировок является фиксация запятнанного контура управления. Проверка переменной запятнанного цикла count, этот пример ограничивает count до минимального значения и максимального значения с помощью встроенных функций min и max. Независимо от вводимого пользователем значения count остается в пределах известного диапазона.

#include<stdio.h>
#include<algorithm>
#define MIN 50
#define MAX 128
static  inline int max(int a, int b) { return a > b ? a : b;}
static inline int min(int a, int b) { return a < b ? a : b; }

int taintedloopboundary(void) {
	int count;
	scanf("%d", &count);
	int res = 0;
	count = max(MIN, min(count, MAX));
	for (int i=0 ; i<count ; ++i) { 
		res += i;
	} 
	return res;
}
Коррекция - контроль запятнанного контура

Другой возможной поправкой является проверка нижней границы и верхней границы запятнанной граничной переменной контура перед запуском for цикл. В этом примере проверяется низкий и высокий границы count и выполняет цикл только тогда, когда count находится в диапазоне от 0 до 127.

#include<stdio.h>

enum {
    SIZE10  =  10,
    SIZE100 = 100,
    SIZE128 = 128
};


int taintedloopboundary(void) {
    int count;
    scanf("%d", &count);
    int res = 0;

    if (count>=0 && count<SIZE128) {
        for (int i=0 ; i<count ; ++i) { 
            res += i;
        }
    }
    return res;
}
Проблема

Выделение памяти с поврежденным размером проверяет функции выделения памяти, такие как calloc или malloc, для аргументов размера из необеспеченных источников.

Риск

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

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

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

Пример - Выделение памяти с помощью ввода от пользователя
#include<stdio.h>
#include <stdlib.h>

int* bug_taintedmemoryallocsize(void) {
    size_t size;
    scanf("%zu", &size);
    int* p = (int*)malloc(size);
    return p;
}

В этом примере: malloc ассигнует size байты памяти указателя p. Переменная size поступает от пользователя программы. Его значение не проверяется и может превышать объем доступной памяти. Если size превышает количество доступных байтов, возможно сбой программы.

Исправление - Проверка размера выделяемой памяти

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

#include<stdio.h>
#include <stdlib.h>

enum {
    SIZE10  =  10,
    SIZE100 = 100,
    SIZE128 = 128
};

int* corrected_taintedmemoryallocsize(void) {
    size_t size;
    scanf("%zu", &size);
    int* p = NULL;
    if (size>0 && size<SIZE128) {          /* Fix: Check entry range before use */
        p = (int*)malloc((unsigned int)size);
    }
    return p;
}
Проблема

Запятнанный размер массива переменной длины определяет массивы переменной длины (VLA), размер которых получен из небезопасного источника.

Риск

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

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

Если размер не ограничен, VLA может привести к истощению памяти или переполнению стека.

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

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

Пример - Входной аргумент, используемый в качестве размера VLA
#include<stdio.h>
#inclule<stdlib.h>
#define LIM 40

long squaredSum(int size) {

	int tabvla[size];
	long res = 0;
	for (int i=0 ; i<LIM-1 ; ++i) {
		tabvla[i] = i*i;
		res += tabvla[i];
	}
	return res;
}
int main(){
	int size;
	scanf("%d",&size);
	//...
	long result = squaredSum(size);
	//...
	return 0;
}

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

Исправление - проверка размера VLA

Одной из возможных корректировок является проверка переменной размера перед созданием массива переменной длины. В этом примере перед созданием VLA проверяется, превышает ли размер 0 и меньше 40.

#include <stdio.h>
#include <stdlib.h>
#define LIM 40

long squaredSum(int size) {
	long res = 0;
	if (size>0 && size<LIM){
		int tabvla[size];
		for (int i=0 ; i<size || i<LIM-1 ; ++i) {
			tabvla[i] = i*i;
			res += tabvla[i];
		}
	}else{
		res = -1;
	}
	return res;
}
int main(){
	int size;
	scanf("%d",&size);
	//...
	long result = squaredSum(size);
	//...
	return 0;
}

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

Группа: Rec. 04. Целые числа (INT)
Представлен в R2019a

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

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

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