ユーザー領域のアドレス参照エラー
IRP をサポートするドライバーでも、高速 I/O 操作を行う場合でも、使用を試みる前に、ユーザー空間内の任意のアドレスを検証する必要があります。 I/O マネージャーは、このようなアドレスを検証せず、ドライバーに渡されるバッファーに埋め込まれているポインターも検証しません。
METHOD_NEITHER IOCTL と FSCTL で渡されたアドレスを検証できない
I/O マネージャーは、METHOD_NEITHER IOCTL と FSCTL の検証を一切行いません。 ユーザー空間アドレスが有効であることを確認するには、ドライバーで ProbeForRead ルーチンと ProbeForWrite ルーチンを使用し、try/except ブロック内のすべてのバッファー参照を囲む必要があります。
次の例では、ドライバーは Type3InputBuffer で渡された値が有効なアドレスを表すと想定しています。
case IOCTL_GET_HANDLER:
{
PULONG EntryPoint;
EntryPoint =
IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
*EntryPoint = (ULONG)DriverEntryPoint;
...
}
次のコードでは、この問題が回避されます。
case IOCTL_GET_HANDLER:
{
PULONG_PTR EntryPoint;
EntryPoint =
IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
try
{
if (Irp->RequestorMode != KernelMode)
{
ProbeForWrite(EntryPoint,
sizeof(ULONG_PTR),
TYPE_ALIGNMENT(ULONG_PTR));
}
*EntryPoint = (ULONG_PTR)DriverEntryPoint;
}
except(EXCEPTION_EXECUTE_HANDLER)
{
...
}
...
}
また、正しいコードでは、ULONG ではなく DriverEntryPoint が ULONG_PTR にキャストされることにも注意してください。 この変更により、64 ビット Windows 環境で使用できます。
バッファー内の I/O 要求に埋め込まれたポインターを検証できない
多くの場合、ドライバーは、次の例のように、バッファー内の要求にポインターを埋め込みます。
struct ret_buf
{
void *arg; // Pointer embedded in request
int rval;
};
pBuf = Irp->AssociatedIrp.SystemBuffer;
...
arg = pBuf->arg; // Fetch the embedded pointer
...
// If the arg pointer is not valid, the following
// statement can corrupt the system:
RtlMoveMemory(arg, &info, sizeof(info));
この例では、ドライバーは、前に説明した METHOD_NEITHER IOCTL の場合と同じ方法で、try/except ブロックで囲まれた ProbeXxx ルーチンを使用して、埋め込みポインターを検証する必要があります。 ポインターを埋め込むことでドライバーは追加情報を返すことができますが、ドライバーは相対オフセットまたは可変長バッファーを使用して、同じ結果をより効率的に実現できます。
try/except ブロックを使用して無効なアドレスを処理する方法の詳細については、「例外処理」を参照してください。