exponenta event banner

CERT C: Rec. INT04-C

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

Описание

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

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

Реализация Polyspace

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

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

  • Цикл ограничен тонированным значением.

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

  • Испорченный размер массива переменной длины.

Примеры

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

Проблема

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

Риск

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

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

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

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

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

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

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

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

Пример - Используйте индекс для возврата значения буфера
#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

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

#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;
}

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

Группа: Рек. 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 Университет Карнеги Меллон, с специального разрешения от его Института программной инженерии.

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

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