Partilhar via


Gerenciamento de Manipulações

Uma fonte significativa de problemas de segurança nos drivers é o uso de identificadores passados entre componentes de modo de usuário e de modo kernel. Há uma série de problemas conhecidos com o uso do identificador dentro do ambiente do kernel, incluindo o seguinte:

  • Um aplicativo que passa o tipo errado de identificador para um driver de kernel. O driver do kernel pode falhar ao tentar usar um objeto de evento onde um objeto de arquivo é necessário.

  • Um aplicativo que passa um identificador para um objeto para o qual ele não tem o acesso necessário. O driver do kernel pode executar uma operação que funciona porque a chamada vem do modo kernel, mesmo que o usuário não tenha permissões adequadas para fazê-lo.

  • Um aplicativo que passa um valor que não é um identificador válido em seu espaço de endereço, mas é marcado como um identificador do sistema para executar uma operação mal-intencionada contra o sistema.

  • Um aplicativo que passa um valor que não é um identificador apropriado para o objeto de dispositivo (um identificador que esse driver não criou).

Para se proteger contra esses problemas, um driver de kernel deve ser particularmente cuidadoso para garantir que os identificadores passados para ele sejam válidos. A política mais segura é criar quaisquer identificadores necessários dentro do contexto do driver. Esses identificadores, criados por drivers de kernel, devem especificar a opção OBJ_KERNEL_HANDLE, que criará um identificador válido no contexto de processo arbitrário e que só pode ser acessado a partir de um chamador de modo kernel.

Para drivers que usam alças criadas por um programa aplicativo, o uso dessas alças deve ser feito com extremo cuidado:

  • A prática recomendada é converter o identificador em um ponteiro de objeto chamando ObReferenceObjectByHandle, especificando os parâmetros AccessMode (geralmente de Irp-RequestorMode>), DesiredAccess e ObjectType, como IoFileObjectType ou ExEventObjectType.

  • Se um identificador deve ser usado diretamente dentro de uma chamada, é melhor usar as variantes Nt de funções em vez das variantes Zw de funções. Isso forçará a verificação de parâmetros e manipulará a validação pelo sistema operacional, já que o modo anterior será UserMode e, portanto, não confiável. Observe que os parâmetros passados para funções Nt que são ponteiros podem falhar na validação se o modo anterior for UserMode. As rotinas Nt e Zw retornam um parâmetro IoStatusBlock com informações de erro que você deve verificar se há erros.

  • Os erros devem ser adequadamente apreendidos, bem como usar __try e __except conforme necessário. Muitas das rotinas do gerenciador de cache (Cc), do gerenciador de memória (Mm) e da biblioteca de tempo de execução do sistema de arquivos (FsRtl) geram uma exceção quando ocorre um erro.

Nenhum driver deve confiar em identificadores ou parâmetros passados de um aplicativo de modo de usuário sem tomar as precauções apropriadas.

Observe que se a variante Nt for usada para abrir um arquivo, a variante Nt também deverá ser usada para fechar o arquivo.