Falha ao verificar o tamanho dos buffers
Ao lidar com IOCTLs e FSCTLs que implementam E/S em buffer, um driver deve sempre marcar os tamanhos dos buffers de entrada e saída para garantir que os buffers possam conter todos os dados solicitados. Se a solicitação especificar FILE_ANY_ACCESS, como a maioria dos IOCTLs e FSCTLs do driver, qualquer chamador que tenha um identificador para o dispositivo terá acesso a solicitações IOCTL ou FSCTL em buffer para esse dispositivo e poderá ler ou gravar dados além do final do buffer.
Tamanho do buffer de entrada
Por exemplo, suponha que o código a seguir apareça em uma rotina chamada de uma rotina dispatch e que o driver não validou os tamanhos de buffer passados no IRP:
switch (ControlCode)
...
...
case IOCTL_NEW_ADDRESS:{
tNEW_ADDRESS *pNewAddress =
pIrp->AssociatedIrp.SystemBuffer;
pDeviceContext->Addr = RtlUlongByteSwap (pNewAddress->Address);
O exemplo não marcar os tamanhos de buffer antes da instrução de atribuição (realçada). Como resultado, a referência pNewAddress-Address> na próxima linha poderá falhar se o buffer de entrada não for grande o suficiente para conter uma estrutura de tNEW_ADDRESS.
O código a seguir verifica os tamanhos de buffer, evitando o possível problema:
case IOCTL_NEW_ADDRESS: {
tNEW_ADDRESS *pNewAddress =
pIrp->AssociatedIrp.SystemBuffer;
if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength >=
sizeof(tNEW_ADDRESS)) {
pDeviceContext->Addr = RtlUlongByteSwap (pNewAddress->Address);
O código para lidar com outras E/Ss em buffer, como solicitações WMI que usam buffers de tamanho variável, pode ter erros semelhantes.
Tamanho do buffer de saída
Problemas de buffer de saída são semelhantes a problemas de buffer de entrada. Eles podem facilmente corromper o pool e os chamadores do modo de usuário podem não saber que ocorreu qualquer erro.
No exemplo a seguir, o driver não marcar o tamanho do SystemBuffer:
case IOCTL_GET_INFO: {
Info = Irp->AssociatedIrp.SystemBuffer;
Info->NumIF = NumIF;
...
...
Irp->IoStatus.Information =
NumIF*sizeof(GET_INFO_ITEM)+sizeof(ULONG);
Irp->IoStatus.Status = ntStatus;
}
Supondo que o campo NumIF do buffer do sistema especifique o número de itens de entrada, este exemplo pode definir IoStatus.Information como um valor maior que o buffer de saída e, portanto, retornar muitas informações para o código de modo de usuário. Se um aplicativo for codificado incorretamente e chamar com um buffer de saída muito pequeno, o código anterior poderá corromper o pool gravando além do final do buffer do sistema.
Lembre-se de que o gerenciador de E/S pressupõe que o valor no campo Informações é válido. Se um chamador passar um endereço válido no modo kernel para o buffer de saída e um tamanho de zero bytes, problemas graves poderão ocorrer se o driver não marcar o tamanho do buffer de saída e, portanto, encontrar o erro.