CERT C: Rec. MEM04-C

Остерегайтесь выделений нулевой длины

Описание

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

Остерегайтесь выделений нулевой длины.[1]

Реализация Polyspace

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

  • Выделение памяти нулевой длины

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

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

Примеры

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

Проблема

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

Риск

Согласно стандарту C (C11, подпункт 7.22.3), если от функции выделения памяти запрашивается память нулевого размера, поведение определяется реализацией. В некоторых реализациях функция может вернуть NULL, и существующих защитных устройств от NULL может быть достаточно для защиты от выделения нулевой длины. В других случаях функция может вернуть область памяти, к которой не должен быть получен доступ. Попытки размежевания этой области приводят к неопределенному поведению.

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

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

Пример - Возможно, аргумент нулевого размера, чтобы malloc
#include <stdlib.h>

void  func(unsigned int size) {
    int *list = (int *)malloc(size);
    if (list == NULL) {
      /* Handle allocation error */
    }
    else {
    /* Continue processing list */
    }
}

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

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

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

#include <stdlib.h>

void  func(unsigned int size) {
    if(size == 0) {
        /* Handle zero size error */
    }
    else {
        int *list = (int *)malloc(size);
        if (list == NULL) {
          /* Handle allocation error */
        }
        else {
          /* Continue processing list */
        }
    }
}
Проблема

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

Риск

Если размер массива переменной длины равен нулю или отрицательному, может произойти неожиданное поведение, такое как переполнение стека.

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

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

  • Если вы используете параметр функции в качестве размера массива, проверяйте, что параметр положительный.

  • Если вы используете результат расчета параметра функции в качестве размера массива, проверяйте, что результат положительный.

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

Пример - Непозитивный Размер Массива
int input(void);

void add_scalar(int n, int m) {
    int r=0;
    int arr[m][n];
    for (int i=0; i<m; i++) {
        for (int j=0; j<n; j++) {
            arr[i][j] = input();
            r += arr[i][j];
        }
    }
}

void main() {
    add_scalar(2,2);
    add_scalar(-1,2);
    add_scalar(2,0);
}

В этом примере второй и третий вызовы add_scalar привести к отрицательному и нулевому размеру arr.

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

Одной из возможных коррекций является исправление или удаление вызовов, которые приводят к непозитивному размеру массива.

Проблема

Испорченный размер массива переменной длины обнаруживает массивы переменной длины (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;
}

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

Группа: Рек. 08. Управление памятью (MEM)
Введенный в R2019a

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

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

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