可変長バッファーの検証失敗
ドライバーは多くの場合、以下の例のように、固定ヘッダーと末尾の可変長データを含む入力バッファーを受け入れます。
typedef struct _WAIT_FOR_BUFFER {
LARGE_INTEGER Timeout;
ULONG NameLength;
BOOLEAN TimeoutSpecified;
WCHAR Name[1];
} WAIT_FOR_BUFFER, *PWAIT_FOR_BUFFER;
if (InputBufferLength < sizeof(WAIT_FOR_BUFFER)) {
IoCompleteRequest( Irp, STATUS_INVALID_PARAMETER );
return( STATUS_INVALID_PARAMETER );
}
WaitBuffer = Irp->AssociatedIrp.SystemBuffer;
if (FIELD_OFFSET(WAIT_FOR_BUFFER, Name[0]) +
WaitBuffer->NameLength > InputBufferLength) {
IoCompleteRequest( Irp, STATUS_INVALID_PARAMETER );
return( STATUS_INVALID_PARAMETER );
}
WaitBuffer->NameLength が非常に大きい ULONG 値の場合、オフセットに追加すると整数オーバーフローが発生する可能性があります。 代わりに、ドライバーは、次の例のように、InputBufferLength (バッファー サイズ) からオフセット (固定ヘッダー サイズ) を減算し、WaitBuffer->NameLength (可変長データ) に十分な空き容量が残っているかどうかをテストする必要があります。
if (InputBufferLength < sizeof(WAIT_FOR_BUFFER)) {
IoCompleteRequest( Irp, STATUS_INVALID_PARAMETER );
Return( STATUS_INVALID_PARAMETER );
}
WaitBuffer = Irp->AssociatedIrp.SystemBuffer;
if ((InputBufferLength -
FIELD_OFFSET(WAIT_FOR_BUFFER, Name[0]) <
WaitBuffer->NameLength) {
IoCompleteRequest( Irp, STATUS_INVALID_PARAMETER );
return( STATUS_INVALID_PARAMETER );
}
つまり、バッファー サイズから固定ヘッダー サイズを引いた値が、可変長データに必要なバイト数よりも少ない場合、エラーが返されます。
最初の if ステートメントでは InputBufferLength が WAIT_FOR_BUFFER のサイズより大きいことが保証されるため、上記の減算はアンダーフローできません。
より複雑なオーバーフローの問題を以下に示します。
case IOCTL_SET_VALUE:
dwSize = sizeof(SET_VALUE);
if (inputBufferLength < dwSize) {
ntStatus = STATUS_BUFFER_TOO_SMALL;
break;
}
dwSize = FIELD_OFFSET(SET_VALUE, pInfo[0]) +
pSetValue->NumEntries * sizeof(SET_VALUE_INFO);
if (inputBufferLength < dwSize) {
ntStatus = STATUS_BUFFER_TOO_SMALL;
break;
}
この例では、乗算中に整数オーバーフローが発生する可能性があります。 SET_VALUE_INFO 構造のサイズが 2 の倍数の場合、乗算中にビットが左にシフトされると、0x80000000 などの NumEntries 値がオーバーフローします。 ただし、オーバーフローによって dwSize が非常に小さく表示されるため、バッファー サイズは検証テストに合格します。 この問題を回避するため、前の例のように長さを減算し、sizeof(SET_VALUE_INFO) で除算し、結果を NumEntries と比較します。