CERT C: правило ARR38-C

Гарантируйте, что библиотечные функции не формируют недопустимые указатели

Описание

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

Гарантируйте, что библиотечные функции не формируют недопустимые указатели. [1]

Примеры

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

Описание

Не сочетайтесь между длиной данных, и размер ищет функции копирования памяти, такие как memcpy, memset или memmove. Если вы не управляете аргументом аргумента длины и буфера данных правильно, Средство поиска Ошибки повышает дефект.

Риск

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

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

Этот дефект подобен SSL ошибка Heartbleed.

Фиксация

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

Пример - буфер копии данных

#include <stdlib.h>
#include <string.h>

typedef struct buf_mem_st {
    char *data;
    size_t max;     /* size of buffer */
} BUF_MEM;

extern BUF_MEM beta;

int cpy_data(BUF_MEM *alpha)
{
    BUF_MEM *os = alpha;
    int num, length;

    if (alpha == 0x0) return 0;
    num = 0;

    length = *(unsigned short *)os->data;
    memcpy(&(beta.data[num]), os->data + 2, length);

    return(1);
}

Эта функция копирует буферный alpha в буферный beta. Однако переменная length не связана с data+2.

Исправление — длина буфера проверки

Одно возможное исправление должно проверять длину вашего буфера против максимального значения минус 2. Эта проверка гарантирует, что у вас есть достаточно пробела, чтобы скопировать данные в структуру beta.

#include <stdlib.h>
#include <string.h>

typedef struct buf_mem_st {
    char *data;
    size_t max;     /* size of buffer */
} BUF_MEM;

extern BUF_MEM beta;

int cpy_data(BUF_MEM *alpha)
{
    BUF_MEM *os = alpha;
    int num, length;

    if (alpha == 0x0) return 0;
    num = 0;

    length = *(unsigned short *)os->data;
    if (length<(os->max -2)) {
        memcpy(&(beta.data[num]), os->data + 2, length); 
    }

    return(1);

}

Описание

Недопустимое использование стандартной стандартной программы библиотеки memory происходит, когда библиотечная функция памяти вызвана недействительными аргументами. Например, функция memcpy копирует в массив, который не может разместить количество скопированных байтов.

Риск

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

Фиксация

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

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

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

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

#include <string.h>
#include <stdio.h>

char* Copy_First_Six_Letters(void)
 {
  char str1[10],str2[5];

  printf("Enter string:\n");
  scanf("%s",str1);

  memcpy(str2,str1,6); 
  /* Defect: Arguments of memcpy invalid: str2 has size < 6 */

  return str2;
 }

Размер строки, str2 равняется 5, но шесть символов строки str1 копируются в str2 с помощью функции memcpy.

Исправление — вызывает функцию с допустимыми аргументами

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

#include <string.h>
#include <stdio.h>

char* Copy_First_Six_Letters(void)
 {
  /* Fix: Declare str2 with size 6 */
  char str1[10],str2[6]; 

  printf("Enter string:\n");
  scanf("%s",str1);

  memcpy(str2,str1,6);
  return str2;
 }

Описание

Возможное неправильное употребление sizeof происходит, когда Polyspace® Bug Finder™ обнаруживает возможно непреднамеренные результаты использования оператора sizeof. Например:

  • Вы используете оператор sizeof на имени параметра массива, ожидая размер массивов. Однако имя параметра массива отдельно является указателем. Оператор sizeof возвращает размер того указателя.

  • Вы используете оператор sizeof на элементе массива, ожидая размер массивов. Однако оператор возвращает размер элемента массива.

  • Аргумент размера определенных функций, таких как strncmp или wcsncpy является неправильным, потому что вы использовали оператор sizeof ранее с возможно неправильными ожиданиями. Например:

    • В вызове функции strncmp(string1, string2, num) num получен из неправильного использования оператора sizeof на указателе.

    • В вызове функции wcsncpy(destination, source, num) num не количество широких символов, но размера в байтах, полученных при помощи оператора sizeof. Например, вы используете wcsncpy(destination, source, sizeof(destination) - 1) вместо wcsncpy(destination, source, (sizeof(desintation)/sizeof(wchar_t)) - 1).

Риск

Неправильное использование оператора sizeof может вызвать следующие проблемы:

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

  • Если вы используете возвращаемое значение оператора sizeof, чтобы выделить буфер, buffer size меньше, чем, чего вы требуете. Недостаточный буфер может привести к результирующим слабым местам, таким как переполнение буфера.

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

Фиксация

Возможные меры:

  • Не используйте оператор sizeof на имени параметра массива или элементе массива, чтобы определить размер массивов.

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

  • Используйте оператор sizeof тщательно, чтобы определить аргумент номера функций, таких как strncmp или wcsncpy. Например, для широких строковых функций, таких как wcsncpy, используйте количество широких символов в качестве аргумента вместо количества байтов.

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

#define MAX_SIZE 1024

void func(int a[MAX_SIZE]) {
    int i;

    for (i = 0; i < sizeof(a)/sizeof(int); i++)    {
        a[i] = i + 1;
    }
}

В этом примере sizeof(a) возвращает размер указателя a а не размер массивов.

Исправление — определяет размер массивов в другом отношении

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

#define MAX_SIZE 1024

void func(int a[MAX_SIZE]) {
    int i;

    for (i = 0; i < MAX_SIZE; i++)    {
        a[i] = i + 1;
    }
}

Описание

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

Риск

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

Фиксация

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

Пример - переполнение буфера памяти

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

Описание

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

Риск

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

Фиксация

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

char * strcpy(char * destination, const char* source)
попытки скопировать слишком много байтов в целевой аргумент по сравнению с доступным буфером, ограничьте исходный аргумент перед вызовом strcpy. В некоторых случаях можно использовать альтернативную функцию, чтобы избежать ошибки. Например, вместо strcpy, можно использовать strncpy, чтобы управлять количеством скопированных байтов. См. также Интерпретируют Результаты Polyspace Bug Finder.

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

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

Описание

Целевое переполнение буфера в обработке строк происходит, когда определенные функции обработки строк пишут в свой целевой буферный аргумент при смещении, больше, чем 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);
}

Описание

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

Например, для функционального sprintf(char* buffer, const char* format), вы получаете buffer из операции buffer = (char*)arr; ... buffer += offset;. arr является массивом, и offset является отрицательной величиной.

Риск

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

Фиксация

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

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

#include <stdio.h>
#define offset -2

void func(void) {
    char buffer[20];
    char *fmt_string ="Text";

    sprintf(&buffer[offset], fmt_string);     
}

В этом примере &buffer[offset] при отрицательном смещении из памяти, выделенной buffer.

Исправление — указатель изменения Decrementer

Одно возможное исправление должно изменить значение offset.

#include <stdio.h>
#define offset 2

void func(void) {
    char buffer[20];
    char *fmt_string ="Text";

    sprintf(&buffer[offset], fmt_string);     
}

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

Группа: правило 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". УНИВЕРСИТЕТ КАРНЕГИ-МЕЛЛОН НЕ ДАЕТ ГАРАНТИЙ НИКАКОГО ВИДА, ИЛИ ВЫРАЗИЛ ИЛИ ПОДРАЗУМЕВАЛ, ОТНОСИТЕЛЬНО ЛЮБОГО ВОПРОСА ВКЛЮЧАЯ, НО НЕ ОГРАНИЧИЛ, ГАРАНТИЯ ПРИГОДНОСТИ ДЛЯ ЦЕЛИ ИЛИ ВЫСОКОГО СПРОСА, ИСКЛЮЧИТЕЛЬНОСТИ, ИЛИ ЗАКАНЧИВАЕТСЯ ПОЛУЧЕННЫЙ ИЗ ИСПОЛЬЗОВАНИЯ МАТЕРИАЛА. УНИВЕРСИТЕТ КАРНЕГИ-МЕЛЛОН НЕ ДАЕТ ГАРАНТИИ НИКАКОГО ВИДА ОТНОСИТЕЛЬНО СВОБОДЫ ОТ ПАТЕНТА, ТОВАРНОГО ЗНАКА ИЛИ НАРУШЕНИЯ АВТОРСКОГО ПРАВА.

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