exponenta event banner

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

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

Описание

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

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

Внедрение Polyspace

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

  • Несоответствие между длиной и размером данных.

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

  • Возможное неправильное использование sizeof.

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

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

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

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

Примеры

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

Проблема

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

Риск

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

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

Этот дефект аналогичен ошибке SSL Heartbleed.

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

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

Пример - Копирование буфера данных
#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);

}
Проблема

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

Риск

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

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

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

См. примеры исправлений ниже.

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

Пример - Ошибка при использовании стандартной библиотечной памяти
#include <string.h>
#include <stdio.h>

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

  printf("Enter string:\n");
  scanf("%9s",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("%9s",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 для выделения буфера, размер буфера меньше требуемого. Недостаток буфера может привести к возникновению таких недостатков, как переполнение буфера.

  • Если используется возвращаемое значение 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 Desktop.

См. примеры исправлений ниже.

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

Пример - Ошибка процедуры использования стандартной строки библиотеки
 #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);
 }
Проблема

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

Например, при вызове функции sprintf(char* buffer, const char* format), используется постоянная строка format большего размера, чем buffer.

Риск

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

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

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

  • Если вы используете sprintf для записи отформатированных данных в строку, используйте snprintf, _snprintf или sprintf_s вместо этого для обеспечения контроля длины. В качестве альтернативы можно использовать asprintf для автоматического выделения памяти, необходимой для целевого буфера.

  • Если вы используете vsprintf для записи форматированных данных из списка переменных аргументов в строку, используйте vsnprintf или vsprintf_s вместо этого для обеспечения контроля длины.

  • Если вы используете wcscpy для копирования широкой строки используйте wcsncpy, wcslcpy, или wcscpy_s вместо этого для обеспечения контроля длины.

Другим возможным решением является увеличение размера буфера.

Пример - Переполнение буфера в 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.

Коррекция - Изменение декрементного указателя

Одной из возможных корректировок является изменение значения 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 Университет Карнеги-Меллон, веб-сайт SEI CERT-C + + © 2017 Университет Карнеги-Меллон, "Стандарт кодирования SEI CERT C - Правила разработки безопасных, Надежные и безопасные системы - 2016 Edition ", © 2016 Университет Карнеги-Меллон, и "Стандарт кодирования SEI CERT C++ - Правила разработки безопасных, Надежные и безопасные системы в C++ - 2016 Edition "© 2016 Университет Карнеги-Меллон, со специальным разрешением от его Института программного обеспечения.

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

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