メインコンテンツ

CWE Rule 733

R2026b

Compiler Optimization Removal or Modification of Security-critical Code

R2023a 以降

説明

The developer builds a security-critical protection mechanism into the software, but the compiler optimizes the program such that the mechanism is removed or modified.

Polyspace 実装

ルール チェッカーは、"不確かなメモリのクリーン アップ" をチェックします。

例

すべて展開する

問題

この問題は、0 をメモリに書き込むことによってメモリをクリーン アップしたものの、クリーン アップ操作の後にメモリが読み取られない場合に発生します。クリーン アップ後にメモリが読み取られないため、コンパイラがコードを最適化する際にクリーン アップ操作をスキップする可能性があります。たとえば、次のコードを考えます。

void foo(){
	void* buffer = getSensitiveData();
	//...
	memset(buffer, 0, sizeof(buffer));
}
ここでは、buffer に機密データが含まれる可能性があります。memset() の呼び出しは、データをスクラブするために行われます。スクラブ後にバッファーが読み取られないため、コンパイラ最適化プロセスで memset() コマンドが無視される可能性があります。その場合、buffer 内のデータはクリーン アップされずに残されます。Polyspace® は、このような不確かなメモリのクリーン アップにフラグを設定します。以下のいずれかの条件に該当する場合、Polyspace はこの欠陥を報告しません。

  • メモリのクリーン アップ関数の戻り値が変数に代入される。

  • メモリのクリーン アップ関数がグローバル オブジェクトをスクラブする。

リスク

変数が書き込まれた後に読み取られることがないと、コンパイラがこれをデッドストアと見なす可能性があります。コンパイラはコードを最適化するために、デッドストア変数へのすべての代入を削除する可能性があります。

このようなコード最適化によって、メモリの機密情報をスクラブするコードが削除された場合、機密情報がクリーン アップされずにシステム内に残る可能性があります。攻撃者がこの機密情報にアクセスし、これを使用してコード内の保護メカニズムをさらに侵害する恐れがあります。

修正方法

メモリをスクラブするときは、コンパイラが削除できないコードを使用します。たとえば、memset ではなく、memset_s や fill_n などの安全な関数を使用します。これらの関数を使用できない古いバージョンの C または C++ を使用している場合は、コードをより新しいバージョンに更新することを検討してください。あるいは、安全な独自のメモリ スクラブ関数を実装することもできます。独自の実装を使用する場合は、コンパイルされたコードをレビューして、コンパイラがメモリ クリーン アップ操作に干渉しないことを確認してください。

例 — 機密情報が含まれるメモリをクリーン アップする際の不確かさを回避する

#include <string.h>

extern int getSensitiveData(char*, size_t);
extern int writeDB(char*, char*);
char Gbuffer[64];
void Job(char *key) {
    char buffer[64];
    if (getSensitiveData(buffer, sizeof(buffer))) {
        if (writeDB(key, buffer)) {
            // Record data
        }
    }
    (void) memset(buffer, 0, sizeof(buffer)); // Defect //Noncompliant
}

void manageGBuffer(char *key) {
    //...
    memset(Gbuffer, 0, sizeof(Gbuffer)); // No Defect
}

この例では、Job() でコマンド memset() を使用して、buffer 内のメモリをクリーン アップしています。クリーン アップ後に buffer が読み取られないため、コンパイラがコードを最適化する際に、このコードを削除する可能性があります。Polyspace はこの不確かなクリーン アップにフラグを設定します。関数 manage() では、memset() を使用してグローバル配列 Gbuffer をクリーン アップしています。このクリーン アップ操作には、Polyspace はフラグを設定しません。

修正 — 安全な関数を使用して機密情報が含まれるメモリをクリーン アップする

この欠陥を修正するには、memset_s() などの安全な保護された関数を使用して不確かなメモリをクリーン アップします。


#include <string.h>

extern int getSensitiveData(char*, size_t);
extern int writeDB(char*, char*);

void Job(char *key) {
    char buffer[64];
    if (getSensitiveData(buffer, sizeof(buffer))) {
        if (writeDB(key, buffer)) {
            // Record data
        }
    }
    memset_s(buffer, 0, sizeof(buffer)); // No Defect
}

チェック情報

カテゴリ: Behavioral Problems
PQL 名: std.cwe_native.R733

バージョン履歴

R2023a で導入