メインコンテンツ

CWE Rule 822

Untrusted Pointer Dereference

R2023b 以降

説明

ルールの説明

The program obtains a value from an untrusted source, converts this value to a pointer, and dereferences the resulting pointer.

Polyspace 実装

ルール チェッカーは以下の問題をチェックします。

  • 汚染された NULL 文字列または非 NULL 終端文字列

  • 汚染されたポインターの使用

すべて展開する

問題

この問題は、strcpysprintf などの文字列バッファーを暗黙的にデリファレンスする文字列操作ルーチンで、セキュリティで保護されていないソースからの文字列が使用された場合に発生します。

汚染された NULL 文字列または非 NULL 終端文字列では、scanf ファミリの可変個引数関数の呼び出しから返された文字列に関する欠陥が報告されません。同様に、文字列と一緒に %s 指定子を printf ファミリの可変個引数関数に渡した場合も欠陥は報告されません。

リスク

文字列がセキュリティで保護されないソースに由来している場合、攻撃者により文字列が操作されている可能性や、文字列ポインターが異なるメモリ位置に向けられている可能性があります。

文字列が NULL である場合、文字列ルーチンは文字列をデリファレンスできず、プログラムがクラッシュする原因となります。文字列が null で終了しない場合、文字列ルーチンでは文字列がいつ終了するかわからない可能性があります。このエラーは範囲外への書き込みの原因となり、バッファー オーバーフローを引き起こします。

修正方法

文字列は、使用する前に検証します。以下についてチェックします。

  • 文字列が NULL でない。

  • 文字列が null で終了している。

  • 文字列のサイズが、必要なサイズと一致している。

チェッカーの拡張

既定では、Polyspace® は外部ソースからのデータは汚染されていると仮定します。Polyspace 解析での汚染のソースを参照してください。Polyspace 解析の現在のスコープ以外から発生したすべてのデータを汚染されたものと見なすには、コマンド ライン オプション [-consider-analysis-perimeter-as-trust-boundary] を使用します。

例 — 文字列を入力から取得
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define SIZE128 128
#define MAX 40
extern void print_str(const char*);
void warningMsg(void)
{
	char userstr[MAX];
	read(0,userstr,MAX);
	char str[SIZE128] = "Warning: ";
	strncat(str, userstr, SIZE128-(strlen(str)+1));//Noncompliant //Noncompliant
	print_str(str);
}


この例では、文字列 str は引数 userstr と連結しています。userstr の値は不明です。userstr のサイズが使用可能なスペースより大きい場合、この連結はオーバーフローします。

修正 — データを検証

1 つの修正方法として、strncat で使用する前に、userstr のサイズをチェックして、文字列が必ず null で終了するようにします。この例では、補助関数 sansitize_str を使用して文字列を検証しています。欠陥はこの関数に集中しています。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define SIZE128 128
#define MAX 40
extern void print_str(const char*);
int sanitize_str(char* s) {
	int res = 0; 
	if (s && (strlen(s) > 0)) { // Noncompliant-TAINTED_STRING only flagged here //Noncompliant
		// - string is not null
		// - string has a positive and limited size
		// - TAINTED_STRING on strlen used as a firewall
		res = 1;
	}
	return res; 
}
void warningMsg(void)
{
	char userstr[MAX];
	read(0,userstr,MAX);
	char str[SIZE128] = "Warning: ";
	if (sanitize_str(userstr))	
		strncat(str, userstr, SIZE128-(strlen(str)+1));
	print_str(str);
}
修正 — データを検証

別の修正方法として、特定の文字列を含む関数 errorMsg および warningMsg を呼び出します。

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

#define SIZE128 128

extern void print_str(const char*);

void warningMsg(char* userstr)
{
    char str[SIZE128] = "Warning: ";
    strncat(str, userstr, SIZE128-(strlen(str)+1));
    print_str(str);
}

void errorMsg(char* userstr)
{
  char str[SIZE128] = "Error: ";
  strncat(str, userstr, SIZE128-(strlen(str)+1));
  print_str(str);
}

int manageSensorValue(int sensorValue) {
  int ret = sensorValue;
  if ( sensorValue < 0 ) {
    errorMsg("sensor value should be positive");
    exit(1);
  } else if ( sensorValue > 50 ) {
    warningMsg("sensor value greater than 50 (applying threshold)...");
    sensorValue = 50;
  }
  
  return sensorValue;
}
問題

この問題は、以下の場合に発生します。

  • 汚染された NULL ポインター — セキュリティで保護されていないソースから取得したポインターが NULL に対し検証されていない。

  • 汚染されたサイズ ポインター — セキュリティで保護されていないポインターが指しているメモリ ゾーンのサイズが検証されていない。

メモ

単一のポインターについて、コードに汚染されたポインターの使用汚染されたオフセットによるポインターのデリファレンス汚染された NULL 文字列または非 NULL 終端文字列の各インスタンスが含まれることがあります。Bug Finder では、最初に見つかった汚染されたポインターの欠陥のみが報告されます。

リスク

攻撃者は、予期しないメモリ位置を指すポインターをプログラムに与えることが可能です。ポインターのデリファレンスにより書き込みを行う場合、攻撃者は次のことができます。

  • 重要なプログラムの状態変数を変更する。

  • プログラムをクラッシュさせる。

  • 望ましくないコードを実行する。

ポインターのデリファレンスにより読み取りを行う場合、攻撃者は次のことができます。

  • 機密データを読み取る。

  • プログラムをクラッシュさせる。

  • プログラム変数を予期しない値に変更する。

修正方法

外部ソースに由来するポインターの使用を避けます。

または、外部ソースを信頼する場合、デリファレンスする前にポインターをサニタイズします。個別のサニタイズ関数で以下を実行します。

  • ポインターが NULL ではないことをチェック。

  • メモリ位置のサイズをチェック (可能な場合)。この 2 番目のチェックは、ポインターが指すデータのサイズがプログラムに必要なサイズと一致するかどうかを検証します。

サニタイズ関数の本体には、この欠陥がまだ表示されます。ただし、サニタイズ関数を使用する場合は、欠陥は複数回ではなく 1 回だけ表示されます。後のレビューでコード注釈を使用して、この欠陥を正当化し非表示にできます。詳細は、以下を参照してください。

チェッカーの拡張

既定では、Polyspace は外部ソースからのデータは汚染されていると仮定します。Polyspace 解析での汚染のソースを参照してください。Polyspace 解析の現在のスコープ以外から発生したすべてのデータを汚染されたものと見なすには、コマンド ライン オプション [-consider-analysis-perimeter-as-trust-boundary] を使用します。

例 — 外部ポインターをデリファレンスする関数
#include<stdlib.h>
void taintedptr(void) {
	char *p = getenv("ARG");
	char x = *(p+10);//Noncompliant   //Noncompliant
}

この例では、ポインター *p が不明なサイズの文字列を指しています。デリファレンス操作中に、ポインターが null になったり、不明なメモリを指したりすることがあり、これがセグメンテーション違反につながる可能性があります。

修正 — ポインターをチェック

1 つの修正方法として、ポインターを使用する前にサニタイズします。この例では、デリファレンスする前にポインターが nullptr かどうかをチェックします。

#include<stdlib.h>
#include <string.h> 
void taintedptr(void) {
	char *p = getenv("ARG");
	if(p!=NULL && strlen(p)>10)
	{
	char x = *(p+10);
	}
}

チェック情報

カテゴリ: Pointer Issues

バージョン履歴

R2023b で導入