CERT C: Rule ARR30-C

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

Описание

Управляйте определением

Не формируйте или используйте за пределы индексы массивов или указатели. [1]

Реализация Polyspace

Это средство проверки проверяет на эти проблемы:

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

  • Доступ к указателю за пределы.

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

  • Использование испорченного указателя.

  • Указатель разыменовывает с испорченным смещением.

Примеры

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

Проблема

Доступ к массиву за пределы происходит, когда индекс массива выходит за пределы области значений [0...array_size-1] во время доступа к массиву.

Риск

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

Фиксация

Фиксация зависит от первопричины дефекта. Например, вы получили доступ к массиву в цикле, и одна из этих ситуаций произошла:

  • Верхняя граница цикла является слишком большой.

  • Вы использовали индекс массива, который совпадает с индексом цикла вместо того, чтобы быть тем меньше, чем индекс цикла.

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

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

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

Смотрите примеры мер ниже.

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

Пример - доступ к массиву за пределы ошибка

#include <stdio.h>

void fibonacci(void)
{
    int i;
    int fib[10];
 
    for (i = 0; i < 10; i++) 
       {
        if (i < 2) 
            fib[i] = 1;
         else 
            fib[i] = fib[i-1] + fib[i-2];
       }

    printf("The 10-th Fibonacci number is %i .\n", fib[i]);   
    /* Defect: Value of i is greater than allowed value of 9 */
}

Массив fib присвоен размер 10. Индекс массива для fib позволил значения [0,1,2,...,9]. Переменная i имеет значение 10, когда оно выходит из for- цикл. Поэтому printf оператор пытается получить доступ к fib[10] через i.

Коррекция — сохраняет индекс массива в границах массивов

Одна возможная коррекция должна распечатать fib[i-1] вместо fib[i] после for- цикл.

#include <stdio.h>

void fibonacci(void)
{
   int i;
   int fib[10];

   for (i = 0; i < 10; i++) 
    {
        if (i < 2) 
            fib[i] = 1;
        else 
            fib[i] = fib[i-1] + fib[i-2];
    }

    /* Fix: Print fib[9] instead of fib[10] */
    printf("The 10-th Fibonacci number is %i .\n", fib[i-1]); 
}

printf доступы к оператору fib[9] вместо fib[10].

Проблема

Доступ к указателю за пределы происходит, когда указатель разыменовывается вне его границ.

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

Риск

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

Фиксация

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

  • Верхняя граница цикла является слишком большой.

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

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

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

Смотрите примеры мер ниже.

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

Пример - доступ к Указателю за пределы ошибка

int* Initialize(void)
{
 int arr[10];
 int *ptr=arr;

 for (int i=0; i<=9;i++)
   {
    ptr++;
    *ptr=i;
    /* Defect: ptr out of bounds for i=9 */
   }

 return(arr);
}

ptr присвоен адрес arr это указывает на блок памяти размера 10*sizeof(int). В for- цикл, ptr постепенно увеличивается 10 раз. В последней итерации цикла, ptr точки вне блока памяти, присвоенного ему. Поэтому это не может быть разыменовано.

Коррекция — указатель проверки остается внутри границ

Одна возможная коррекция должна инвертировать порядок шага и разыменовать ptr.

int* Initialize(void)
{
 int arr[10];
 int *ptr=arr;

 for (int i=0; i<=9;i++)
     {
      /* Fix: Dereference pointer before increment */
      *ptr=i;
      ptr++;
     }

 return(arr);
}

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

Проблема

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

Риск

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

  • Недостаточное наполнение буфера / подписывает — пишущий в память перед началом буфера.

  • Переполнение буфера — пишущий в память после конца буфера.

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

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

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

Фиксация

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

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

#define SIZE100 100
extern int tab[SIZE100];

int taintedarrayindex(int num) {
    return tab[num];  
}

В этом примере, индекс num получает доступ к массиву tab. Функция не проверяет, чтобы видеть если num в области значений tab.

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

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

#define SIZE100 100
extern int tab[SIZE100];

int taintedarrayindex(int num) {
    if (num >= 0 && num < SIZE100) {
           return tab[num]; 
    } else {
        return -9999;
    }
}

Проблема

Использование испорченного дефекта указателя повышено когда:

  • Испорченный Нулевой указатель — указатель не подтвержден против NULL.

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

Примечание

На одном указателе ваш код может иметь экземпляры Использования испорченного указателя, Указатель разыменовывают с испорченным смещением, и Испорченным NULL или не пустой отключенной строкой. Средство поиска ошибки повышает только первый испорченный дефект указателя, который оно находит.

Риск

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

  • Измените переменные состояния критической программы.

  • Заставьте свою программу отказывать.

  • Выполните нежелательный код.

Если указатель разыменовывается, чтобы читать, атакующий может:

  • Считайте уязвимые данные.

  • Заставьте свою программу отказывать.

  • Измените переменную программы к неожиданному значению.

Фиксация

Избегайте использования указателей из внешних источников.

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

  • Проверяйте, что указатель не является ПУСТЫМ.

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

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

Пример - функция, которая разыменовывает внешний указатель

void taintedptr(int* p, int i) {
    *p = i; 
}

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

Коррекция — избегает использования внешних указателей

Одна возможная коррекция должна избежать указателей из внешних источников.

int *taintedptr(int i) {
    /* Use heap memory allocated in the application */ 
    int *p = (int *)malloc(sizeof (int)); 
    if (p != NULL) { /* Check for success */
        *p = i;
    }
return p;
}

Коррекция — указатель проверки

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

#include <stdlib.h>

int* sanitize_ptr(int* p) {
    int* res = NULL;
    if (p && *p) { /* Tainted pointer detected here, used as "firewall" */
        /* Pointer is not null and dereference ok */
        res = p;
    }
    return res;
}
void taintedptr(int* p, int i) {
    p = sanitize_ptr(p);
    if (p) {
        *p = i;
    }
}

Проблема

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

Эта проверка фокусируется на динамически выделенных буферах. Для статических буферных смещений смотрите Array access with tainted index.

Риск

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

  • Недостаточное наполнение буфера / подписывает, или пишущий в память перед началом буфера.

  • Переполнение буфера, или пишущий в память после конца буфера.

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

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

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

Фиксация

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

Пример - разыменовывает массив указателей

#include <stdlib.h>

enum {
    SIZE10  =  10,
    SIZE100 = 100,
    SIZE128 = 128
};
extern void read_pint(int*);

int taintedptroffset(int i) {
    int* pint = (int*)calloc(SIZE10, sizeof(int));
    int c = 0;
    if(pint) {
        /* Filling array */
        read_pint(pint);
        c = pint[i];
        free(pint);
    }
    return c;
}

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

Коррекция — индекс проверки прежде разыменовывает

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

#include <stdlib.h>

enum {
    SIZE10  =  10,
    SIZE100 = 100,
    SIZE128 = 128
};
extern void read_pint(int*);

int taintedptroffset(int i) {
    int* pint = (int*)calloc(SIZE10, sizeof(int));
    int c = 0;
    if (pint) {
        /* Filling array */
        read_pint(pint);
        if (i>0 && i<SIZE10) {
            c = pint[i];
        }
        free(pint);
    }
    return c;
}

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

Группа: правило 06. Массивы (ARR)

Введенный в R2019a


[1]  Это программное обеспечение было создано MathWorks, включающим фрагменты: “Веб-сайт SEI CERT-C”, © 2017 Carnegie Mellon University, веб-сайт SEI CERT-C © 2017 Carnegie Mellon University”, CERT SEI C Кодирование Стандарта – Правил для Разработки безопасных, Надежных и Защищенных систем – 2 016 Выпусков”, © 2016 Carnegie Mellon University, and “CERT SEI Стандарт Кодирования C++ – Правил для Разработки безопасных, Надежных и Защищенных систем на C++ – 2 016 Выпусков” © 2016 Carnegie Mellon University, со специальным разрешением от его Института программной инженерии.

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

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