ダブルフェッチ

検証後に値を再取得するダブルフェッチ

説明

利用者が変更できるメモリの値を検証した後、同じ場所から再取得して使うと、確認と使用の間に値が変わる可能性があります。

想定される影響

  • カーネルやネイティブコードの境界で、検証の回避、バッファーオーバーフロー、情報漏えいが起こるおそれがあります。

対処方法

検証するフィールドは信頼境界の内側のローカル変数に一度だけコピーし、同じ値を検証して使ってください。複数フィールドの整合性が必要なら、リクエスト全体を安全にコピーし、フィールド間の関係も検証してください。

例

変更前

c
ProbeForRead(req, sizeof(*req), 1);
if (req->len > MAX) { return; }
RtlCopyMemory(dst, req->buf, req->len);

変更後

c
ProbeForRead(req, sizeof(*req), 1);
size_t len = req->len;
if (len > MAX) { return; }
RtlCopyMemory(dst, req->buf, len);

変更前は確認したフィールドをコピー時に再取得します。変更後は長さをローカルにコピーし、確認と使用の両方でその値を使います。

長さの再取得だけをなくす抜粋です。MAXは書き込み先の容量を超えてはいけません。req->bufのポインターと実際のメモリアクセスは別途検証してください。Windowsドライバーでは、ProbeForReadと後続のユーザーメモリアクセスを例外処理で囲んでください。ProbeForReadはメモリを固定せず、他のスレッドによる変更も防ぎません。

参考資料