メインコンテンツ

このページの内容は最新ではありません。最新版の英語を参照するには、ここをクリックします。

CWE Rule 14

Compiler Removal of Code to Clear Buffers

R2023a 以降

説明

ルールの説明

Sensitive memory is cleared according to the source code, but compiler optimizations leave the memory untouched when it is not read from again, aka "dead store removal."

Polyspace 実装

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

すべて展開する

問題

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

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

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

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

リスク

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

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

修正方法

メモリをスクラブするときは、コンパイラが削除できないコードを使用します。たとえば、memset ではなく、memset_sfill_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
}

チェック情報

カテゴリ: その他

バージョン履歴

R2023a で導入