Verificações de segurança em IRP_MJ_DIRECTORY_CONTROL
A segurança é uma consideração ao processar determinadas operações de controle de diretório, notadamente aquelas que lidam com notificações de alteração. A preocupação de segurança é que uma notificação de alteração de diretório possa retornar informações sobre arquivos específicos que foram alterados. Se o usuário não tiver o privilégio de percorrer o caminho para o diretório, as informações sobre a alteração não poderão ser retornadas ao usuário. Caso contrário, o usuário agora tem um mecanismo para aprender informações adicionais sobre o diretório que o usuário não deve ter.
O suporte para notificação de alteração de diretório pela biblioteca de tempo de execução do sistema de arquivos permite que um sistema de arquivos especifique uma função de retorno de chamada para executar uma passagem marcar antes de retornar uma notificação de alteração de diretório. Essa função de retorno de chamada usa um grande número de parâmetros. Para considerações de segurança, os três parâmetros a seguir são importantes:
NotifyContext é o contexto do diretório em que a notificação de alteração está ativa. Esse será o parâmetro FsContext que é passado para a chamada para FsRtlNotifyFullChangeDirectory.
TargetContext é o contexto do arquivo que foi alterado. Esse será o parâmetro TargetContext passado pelo sistema de arquivos quando ele chamar FsRtlNotifyFilterReportChange.
SubjectContext é o contexto de segurança do thread que solicita a notificação de alteração de diretório. Esse é o contexto de segurança do assunto capturado pelo sistema de arquivos no momento em que a chamada de notificação de alteração de diretório é feita para FsRtlNotifyFullChangeDirectory.
Quando ocorre uma alteração, o sistema de arquivos indica isso para a biblioteca de tempo de execução do sistema de arquivos. A biblioteca de tempo de execução do sistema de arquivos chamará a função de retorno de chamada fornecida pelo sistema de arquivos para verificar se o chamador pode receber informações sobre a alteração. Observe que o sistema de arquivos só precisa registrar uma função de retorno de chamada se o marcar for necessário para o chamador. Esse é o caso se o chamador não tiver SeChangeNotifyPrivilege habilitado, conforme indicado pelo TOKEN_HAS_TRAVERSE_PRIVILEGE no token de segurança do chamador.
Dentro da função de retorno de chamada, o sistema de arquivos deve executar uma passagem marcar do diretório especificado pelo parâmetro NotifyContext para o arquivo que foi alterado, especificado pelo parâmetro TargetContext. A rotina de exemplo abaixo executa esse marcar.
BOOLEAN
FsdNotifyTraverseCheck (
IN PDIRECTORY_CONTEXT OriginalDirectoryContext,
IN PFILE_CONTEXT ModifiedDirectoryContext,
IN PSECURITY_SUBJECT_CONTEXT SubjectContext
)
{
BOOLEAN AccessGranted = TRUE;
PFILE_CONTEXT CurrentDirectoryContext;
ACCESS_MASK GrantedAccess;
NTSTATUS Status;
PPRIVILEGE_SET Privileges = NULL;
PFILE_CONTEXT TopDirectory;
//
// Nothing to do if there is no file context.
//
if (ModifiedDirectoryContext == NULL) {
return TRUE;
}
//
// If the directory that changed is the original directory,
// we can return , since the caller has access.
// Note that the directory context is unique to the specific
// open instance, while the modified directory context
// represents the per-file/directory context.
// How these data structures work in your file system will vary.
//
if (OriginalDirectoryContext->FileContext == ModifiedDirectoryContext) {
return TRUE;
}
//
// Lock the subject context.
//
SeLockSubjectContext(SubjectContext);
for( TopDirectory = OriginalDirectoryContext->FileContext,
CurrentDirectoryContext = ModifiedDirectoryContext;
CurrentDirectoryContext == TopDirectory || !AccessGranted;
CurrentDirectoryContext = CurrentDirectoryContext->ParentDirectory) {
//
// Ensure we have the current security descriptor loaded for
// this directory.
//
FsdLoadSecurity( NULL, CurrentDirectoryContext);
//
// Perform traverse check.
//
AccessGranted = SeAccessCheck(
CurrentDirectoryContext->SecurityDescriptor,
SubjectContext,
TRUE,
FILE_TRAVERSE,
0,
&Privileges,
IoGetFileObjectGenericMapping(),
UserMode,
&GrantedAccess,
&Status);
//
// At this point, exit the loop if access was not granted,
// or if the parent directory is the same as where the change
// notification was made.
//
}
//
// Unlock subject context.
//
SeUnlockSubjectContext(SubjectContext);
return AccessGranted;
}
Essa rotina provavelmente será substancialmente diferente para sistemas de arquivos que armazenam em cache informações de segurança ou que têm estruturas de dados diferentes para rastrear arquivos e diretórios (por exemplo, arquivos que usam uma estrutura para rastrear links entre arquivos e diretórios). Os sistemas de arquivos que dão suporte a links não são considerados neste exemplo na tentativa de simplificar o exemplo.