Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Para uma discussão geral sobre a escrita de drivers seguros, consulte Criando drivers confiáveis de Kernel-Mode.
Além de seguir práticas de codificação segura e das orientações gerais para drivers de dispositivo, os drivers de rede devem fazer o seguinte em prol da segurança:
- Todos os drivers de rede devem validar os valores que leem do registro. Especificamente, o chamador de NdisReadConfiguration ou NdisReadNetworkAddress não deve fazer suposições sobre valores lidos do registro e deve validar cada valor do Registro que ele lê. Se o chamador de NdisReadConfiguration determinar que um valor está fora dos limites, ele deverá usar um valor padrão. Se o chamador de NdisReadNetworkAddress determinar que um valor está fora dos limites, ele deverá usar o endereço MAC (controle de acesso médio) permanente ou um endereço padrão.
Problemas específicos do OID
Um driver de miniport, em suas funções MiniportOidRequest ou MiniportCoOidRequest , deve validar qualquer valor OID (identificador de objeto) que o driver seja solicitado a definir. Se o driver determinar que o valor a ser definido está fora dos limites, ele deverá falhar na solicitação definida. Para obter mais informações sobre identificadores de objeto, consulte Obtenção e configuração de informações do driver de miniport e suporte do NDIS para WMI.
Se a função MiniportOidRequest de um driver intermediário não passar uma operação definida para um driver de miniporto subjacente, a função deverá validar o valor do OID. Para obter mais informações, consulte Consulta e Definição de Operações de Driver Intermediário.
Consultar diretrizes de segurança OID
A maioria dos OIDs de Consulta pode ser emitida por qualquer aplicativo em modo de usuário no sistema. Siga estas diretrizes específicas para OIDs de Consulta.
Sempre valide se o tamanho do buffer é grande o suficiente para a saída. Qualquer manipulador de OID de consulta sem uma verificação de tamanho de buffer de saída tem um bug de segurança.
if (oid->DATA.QUERY_INFORMATION.InformationBufferLength < sizeof(ULONG)) { oid->DATA.QUERY_INFORMATION.BytesNeeded = sizeof(ULONG); return NDIS_STATUS_INVALID_LENGTH; }Sempre escreva um valor correto e mínimo em BytesWritten. É um sinal de alerta atribuir
oid->BytesWritten = oid->InformationBufferLengthda forma como o exemplo a seguir faz.// ALWAYS WRONG oid->DATA.QUERY_INFORMATION.BytesWritten = DATA.QUERY_INFORMATION.InformationBufferLength;O sistema operacional copiará os bytes "BytesWritten" de volta para um aplicativo em modo usuário. Se BytesWritten for maior que o número de bytes que o driver realmente escreveu, o sistema operacional poderá acabar copiando de volta a memória de kernel não inicializada para o usermode, o que seria uma vulnerabilidade de divulgação de informações. Em vez disso, use um código semelhante a este:
oid->DATA.QUERY_INFORMATION.BytesWritten = sizeof(ULONG);Nunca leia de volta os valores do buffer. Em alguns casos, o buffer de saída de uma OID é mapeado diretamente para um processo em modo de usuário hostil. O processo hostil pode alterar o buffer de saída depois que você tiver gravado nele. Por exemplo, o código a seguir pode ser atacado, pois um invasor pode alterar NumElements depois de escrito:
output->NumElements = 4; for (i = 0 ; i < output->NumElements ; i++) { output->Element[i] = . . .; }Para evitar ler de volta do buffer, mantenha uma cópia local. Por exemplo, para corrigir o exemplo acima, introduza uma nova variável de pilha:
ULONG num = 4; output->NumElements = num; for (i = 0 ; i < num; i++) { output->Element[i] = . . .; }Com essa abordagem, o loop for lê de volta da variável de pilha
numdo driver e não do buffer de saída. O driver também deve marcar o buffer de saída com avolatilepalavra-chave, para impedir que o compilador desfaça silenciosamente essa correção.
Definir diretrizes de segurança OID
A maioria dos OIDs definidos pode ser emitida por um aplicativo em modo de usuário em execução nos grupos de segurança de Administradores ou de Sistema. Embora sejam aplicativos geralmente confiáveis, o driver de miniporto ainda não deve permitir corrupção de memória ou injeção de código kernel. Siga estas regras específicas para Definir OIDs:
Sempre valide se a entrada é grande o suficiente. Qualquer manipulador de conjunto de OID sem uma verificação de tamanho de buffer de entrada tem uma vulnerabilidade de segurança.
if (oid->DATA.SET_INFORMATION.InformationBufferLength < sizeof(ULONG)) { return NDIS_STATUS_INVALID_LENGTH; }Sempre que validar uma OID com um offset embutido, você deve validar se o buffer resultante está dentro da carga útil da OID. Isso requer várias verificações. Por exemplo, OID_PM_ADD_WOL_PATTERN pode fornecer um padrão inserido, que precisa ser verificado. A validação correta requer verificação:
InformationBufferSize >= sizeof(NDIS_PM_PACKET_PATTERN)
PmPattern = (PNDIS_PM_PACKET_PATTERN) InformationBuffer; if (InformationBufferLength < sizeof(NDIS_PM_PACKET_PATTERN)) { Status = NDIS_STATUS_BUFFER_TOO_SHORT; *BytesNeeded = sizeof(NDIS_PM_PACKET_PATTERN); break; }Pattern->PatternOffset + Pattern->PatternSize não causa transbordamento
ULONG TotalSize = 0; if (!NT_SUCCESS(RtlUlongAdd(Pattern->PatternOffset, Pattern->PatternSize, &TotalSize) || TotalSize > InformationBufferLength) { return NDIS_STATUS_INVALID_LENGTH; }Essas duas verificações podem ser combinadas usando código como o seguinte exemplo:
ULONG TotalSize = 0; if (InformationBufferLength < sizeof(NDIS_PM_PACKET_PATTERN) || !NT_SUCCESS(RtlUlongAdd(Pattern->PatternSize, Pattern->PatternOffset, &TotalSize) || TotalSize > InformationBufferLength) { return NDIS_STATUS_INVALID_LENGTH; }InformationBuffer + Pattern->PatternOffset + Pattern->PatternLength não causa estouro
ULONG TotalSize = 0; if (!NT_SUCCESS(RtlUlongAdd(Pattern->PatternOffset, Pattern->PatternLength, &TotalSize) || (!NT_SUCCESS(RtlUlongAdd(TotalSize, InformationBuffer, &TotalSize) || TotalSize > InformationBufferLength) { return NDIS_STATUS_INVALID_LENGTH; }Pattern-PatternOffset> + Pattern-PatternLength <>= InformationBufferSize
ULONG TotalSize = 0; if(!NT_SUCCESS(RtlUlongAdd(Pattern->PatternOffset, Pattern->PatternLength, &TotalSize) || TotalSize > InformationBufferLength)) { return NDIS_STATUS_INVALID_LENGTH; }
Diretrizes de segurança Method OID
Os OIDs de método podem ser emitidos por um aplicativo em modo de usuário em execução nos grupos de segurança Administradores ou Sistema. Eles são uma combinação de um Conjunto e uma Consulta, portanto, ambas as listas anteriores de diretrizes também se aplicam a OIDs de método.
Outros problemas de segurança do driver de rede
Muitos drivers de miniporto NDIS expõem um dispositivo de controle usando NdisRegisterDeviceEx. Aqueles que fazem isso têm de auditar os seus manipuladores IOCTL, com todas as mesmas regras de segurança que um driver WDM. Para obter mais informações, consulte problemas de segurança para códigos de controle de E/S.
Os drivers de miniporto NDIS bem projetados não devem depender de serem chamados em um contexto de processo muito específico, nem interagir muito estreitamente com o modo de usuário (com IOCTLs e OIDs sendo a exceção). Seria um sinal de alerta ver um miniporto que abria identificadores no modo de usuário, realizava esperas no modo de usuário ou alocava memória contra a cota de modo de usuário. Esse código deve ser investigado.
A maioria dos drivers de miniporto NDIS não deve estar envolvida na análise de cargas de pacotes. Em alguns casos, porém, pode ser necessário. Nesse caso, esse código deve ser auditado com muito cuidado, pois o driver está analisando dados de uma fonte não confiável.
Como é padrão ao alocar memória no modo kernel, os drivers NDIS devem usar mecanismos de Opt-In do pool de NX apropriados. No WDK 8 e nas versões mais recentes, a família de funções
NdisAllocate*é incluída corretamente.