警告 C6029

'function' の呼び出しでバッファー オーバーランが発生する可能性があります

バッファー長/サイズ パラメーターがチェックされていないために、呼び出された関数でバッファー オーバーランが発生する可能性があります。

解説

この警告は、コードがバッファーとサイズを受け取る関数にチェックされていないサイズを渡したことを示します。 コードでは、一部の外部ソースから読み取られたデータがバッファー サイズよりも小さいことを確認しません。 攻撃者が意図的にサイズに予想よりも大きい値を指定すると、バッファー オーバーランが発生する可能性があります。 一般に、信頼されていない外部ソースからデータを読み取る場合は必ず有効性を確認するようにします。 サイズを確認して、予想される範囲内にあることを確認するのが適切です。

コード分析名: USING_TAINTED_DATA

次のコードでは、注釈付き関数 std::fread を 2 回呼び出すと、この警告が生成されます。 このコードでは、最初の呼び出しを使用して、後の呼び出しで読み取るデータの長さを決定します。 最初の呼び出しの後、分析は信頼されていないソースからのものとしてマーク dataSize します。 そのため、コードが信頼されていない値を 2 番目 std::fread の呼び出しに渡すと、アナライザーによってこの警告が生成されます。 悪意のあるアクターがファイルを変更し、呼び出し std::fread が配列をオーバーフローさせる buffer 可能性があります。 実際のコードでは、戻り値 std::freadに基づいてエラーの回復も処理する必要があります。 わかりやすくするために、これらの例では意図的にエラー リカバリー コードを除外しています。

void processData(FILE* file)
{
    const size_t MAX_BUFFER_SIZE = 100;
    uint32_t buffer[MAX_BUFFER_SIZE]{};
    uint8_t dataSize = 0;

    // Read length data from the beginning of the file
    fread(&dataSize, sizeof(uint8_t), 1, file);
    // Read the rest of the data based on the dataSize
    fread(buffer, sizeof(uint32_t), dataSize, file);
}

この問題の修正は、データの性質と、診断をトリガーする注釈付き関数の動作によって異なります。 詳細については、その関数のドキュメントを参照してください。 簡単な修正は、2 回目の呼び出しの前にサイズをチェックすることですstd:fread。 次の例では、例外をスローして関数を終了します。 ほとんどの実際のコードでは、シナリオに固有のエラー回復戦略が代わりに用意されています。

void processData(FILE* file)
{
    const size_t MAX_BUFFER_SIZE = 100;
    uint32_t buffer[MAX_BUFFER_SIZE]{};
    uint8_t dataSize = 0;

    fread(&dataSize, sizeof(uint32_t), 1, file);

    if (dataSize > MAX_BUFFER_SIZE)
    {
        throw std::runtime_error("file data unexpected size");
    }

    fread(buffer, sizeof(uint32_t), dataSize, file);
}

同様の関数では std:fread 、コードで大量のデータを読み取る必要がある場合があります。 大きなデータを処理するには、サイズがわかってからバッファーのサイズを動的に割り当てることができます。 または、必要に応じて複数回呼び出 std:fread して、残りのデータを読み取ることもできます。 バッファーを動的に割り当てる場合は、サイズに制限を設定して、大きな値にメモリ不足の悪用が発生しないようにすることをお勧めします。 この例では、このアプローチは既に次のサイズ uint8_tで囲まれているため、使用しません。

void processDataDynamic(FILE* file)
{
    uint8_t dataSize = 0;
    fread(&dataSize, sizeof(uint8_t), 1, file);
    
    // Vector with `dataSize` default initialized objects
    std::vector<uint32_t> vecBuffer(dataSize);

    fread(&vecBuffer[0], sizeof(uint32_t), dataSize, file);
}
void processDataMultiple(FILE* file)
{
    const size_t MAX_BUFFER_SIZE = 100;
    uint32_t buffer[MAX_BUFFER_SIZE]{};
    uint8_t dataSize = 0;

    fread(&dataSize, sizeof(uint32_t), 1, file);

    while( dataSize > 0 )
    {
        size_t readSize = dataSize > MAX_BUFFER_SIZE ? MAX_BUFFER_SIZE : dataSize;
        readSize = fread(buffer, sizeof(uint32_t), readSize, file);
        dataSize = dataSize - readSize;
        // Process the data in `buffer`...
    }
}

関連項目

C++ コードの規則セット
SAL 注釈を使ってコード障害を減らす方法