다음을 통해 공유


Variable-Length 버퍼 유효성 검사 실패

드라이버는 다음 예제와 같이 고정 헤더 및 후행 가변 길이 데이터가 있는 입력 버퍼를 수락하는 경우가 많습니다.

   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 문은 InputBufferLengthWAIT_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와 비교합니다.