>
>
>
V1010. Unchecked tainted data is used i…


V1010. Unchecked tainted data is used in expression.

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

На данный момент диагностическое правило V1010 выявляет ошибки по нескольким паттернам:

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

Рассмотрим все паттерны более подробно.

Пример подозрительного кода при использовании в индексе недостоверных данных.

size_t index = 0;
....
if (scanf("%zu", &index) == 1)
{
  ....
  DoSomething(arr[index]); // <=
}

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

Безопасный код проверяет полученное значение:

if (index < ArraySize)
  DoSomething(arr[index]);

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

char buf[1024];
char username [256];
....
if (scanf("%255s", username) == 1)
{
  if (snprintf(buf, sizeof(buf) - 1, commandFormat, username) > 0)
  {
    int exitCode = system(buf); // <=
    ....
  }
  ....
}

Этот код является уязвимым, т.к. пользовательский ввод передаётся командному интерпретатору без проверки полученных данных. Например, введя "&cmd", на Windows можно получить доступ к командному интерпретатору.

Правильный код должен осуществлять дополнительную проверку считанных данных:

if (IsValid(username))
{
  if (snprintf(buf, sizeof(buf) - 1, commandFormat, username) > 0)
  {
    int exitCode = system(buf);
    ....
  }
  ....
} 
else 
{
  printf("Invalid username: %s", username);
  ....
}

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

size_t offset = 0;
int *pArr = arr;
....
if (scanf("%zu", &offset) == 1)
{
  pArr += offset; // <=
  ....
  DoSomething(pArr);
}

В данном случае портится значение указателя 'pArr', т.к. в результате прибавления непроверенного значения 'offset' указатель может начать ссылаться за пределы массива. В результате можно испортить какие-то данные (на которые будет ссылаться 'pArr') с непредсказуемыми последствиями.

Правильный код проверяет допустимое смещение:

if (offset <= allowableOffset)
{
  pArr += offset;
  ....
  DoSomething(pArr);
}

Пример подозрительного кода с делением на недостоверные данные:

if (fscanf(stdin, "%zu", &denominator) == 1)
{
  targetVal /= denominator;
}

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

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

if (fscanf(stdin, "%zu", &denominator) == 1)
{
  if (denominator > MinDenominator && denominator < MaxDenominator)
  {
    targetVal /= denominator;
  }
}

Данная диагностика классифицируется как: