다음을 통해 공유


User-Space 주소 참조 오류

IRP 또는 빠른 I/O 작업을 지원하는 모든 드라이버는 사용하기 전에 사용자 공간의 주소에 대한 유효성을 검사해야 합니다. I/O 관리자는 이러한 주소의 유효성을 검사하지 않으며 드라이버에 전달된 버퍼에 포함된 포인터의 유효성을 검사하지도 않습니다.

METHOD_NEITHER IOCTL 및 FSCTL에 전달된 주소의 유효성 검사 실패

I/O 관리자는 METHOD_NEITHER IOCTL 및 FSCTL에 대해 어떠한 유효성 검사도 수행하지 않습니다. 사용자 공간 주소가 유효한지 확인하려면 드라이버는 ProbeForReadProbeForWrite 루틴을 사용하여 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)
      {
        ...
      }
      ...
   }

또한 올바른 코드는 DriverEntryPoint 를 ULONG 대신 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 블록을 사용하여 잘못된 주소를 처리하는 방법에 대한 자세한 내용은 예외 처리를 참조하세요.