Verificando se há privilégios de passagem no IRP_MJ_CREATE
Uma das principais preocupações IRP_MJ_CREATE verifica se o chamador tem privilégio de passagem, que é o direito de acessar o caminho para um objeto. Ou seja, um chamador pode ter acesso a um objeto de arquivo como dirA/dirB/file, mas não tem permissão para acessar o conteúdo dos diretórios ao longo do caminho desse objeto de arquivo (dirA e dirA/dirB).
Por padrão, o Windows concede privilégio de passagem a todos os usuários. A constante "Direito do Usuário" é SeChangeNotifyPrivilege, que é mapeada para FILE_TRAVERSE em um ACCESS_MASK. Como um recurso de segurança, os administradores do sistema podem remover o privilégio de passagem de um usuário.
Como a maioria dos chamadores tem privilégio de passagem, uma das primeiras verificações que o sistema de arquivos normalmente faz é marcar para esse privilégio no campo AccessState-Flags> do contexto de segurança do IRP:
BOOLEAN traverseCheck =
!(IrpContext->IrpSp->Parameters.Create.SecurityContext->AccessState->Flags
& TOKEN_HAS_TRAVERSE_PRIVILEGE);
O sistema de arquivos usa Sinalizadores para rastrear quais direitos de acesso foram concedidos no andamento de uma operação. O sistema de arquivos pode marcar rapidamente os bits de estado de acesso primeiro e evitar a despesa de um acesso marcar chamada se o acesso já tiver sido concedido (traverseCheck = 0).
Se o privilégio de passagem não tiver sido concedido anteriormente, o sistema de arquivos deverá fazer uma passagem marcar em cada diretório ao longo do caminho para o arquivo que está sendo aberto. No snippet de código parcial abaixo, a marcar de passagem é feita usando uma rotina genérica, normalmente usada para a maioria das verificações de segurança:
{
// accessParams is passed to the file system and is normally based
// on the fields of the same name from the IRP.
// Only one thread can be looking at this data structure in memory
// at a time (and potentially changing it), so acquire a lock on it.
SeLockSubjectContext(
&accessParams.AccessState->SubjectSecurityContext);
// Check whether the desired access can be granted.
// For this example, assume desiredAccess = FILE_TRAVERSE
granted = SeAccessCheck( Fcb->SecurityDescriptor,
&AccessParams.AccessState->SubjectSecurityContext,
TRUE,
AccessParams.desiredAccess,
0,
&Privileges,
IoGetFileObjectGenericMapping(),
AccessParams.AccessMode,
&AccessParams.GrantedAccess,
&AccessParams.status );
// The file system uses AccessState to cache access privileges
// that have been granted thus far along the operation's code
// path. Update AccessState with the newly acquired Privileges.
if (Privileges != NULL) {
(void) SeAppendPrivileges(AccessParams.AccessState, Privileges );
SeFreePrivileges( Privileges );
Privileges = NULL;
}
if (granted) {
//
// The desired access was granted, so clear the
// granted bits from desiredAccess.
//
AccessParams.desiredAccess &=
~(AccessParams.GrantedAccess | MAXIMUM_ALLOWED);
if (!checkOnly) {
//
// The caller wants to modify the access state for this
// request
//
AccessParams.AccessState->PreviouslyGrantedAccess |=
AccessParams.GrantedAccess;
}
if (maxDesired) {
maxDelete =
(BOOLEAN)(AccessParams.AccessState->PreviouslyGrantedAccess &
DELETE);
maxReadAttr =
(BOOLEAN)(AccessParams.AccessState->PreviouslyGrantedAccess &
FILE_READ_ATTRIBUTES);
}
AccessParams.AccessState->RemainingDesiredAccess &=
~(AccessParams.GrantedAccess | MAXIMUM_ALLOWED);
}
// Release the lock on the security context
SeUnlockSubjectContext(&accessParams.AccessState->SubjectSecurityContext);
}
Essa função executa uma marcar de segurança genérica. Essa função deve lidar com os seguintes problemas ao fazer isso:
Ele deve especificar o descritor de segurança correto a ser usado para o marcar.
Ele deve passar o contexto de segurança (essas são as credenciais da entidade que está executando a operação).
Ele deve atualizar o estado de acesso com base nos resultados da marcar de segurança.
Ele deve considerar a opção MAXIMUM_ALLOWED (consulte ntifs.h). A opção MAXIMUM_ALLOWED especifica que o sistema de arquivos deve definir o acesso ao máximo possível de acesso permitido pelo sistema de arquivos (leitura/gravação/exclusão, por exemplo). Pouquíssimos aplicativos usam a opção MAXIMUM_ALLOWED porque essa opção não tem suporte no sistema de arquivos FASTFAT. Como o bit de opção MAXIMUM_ALLOWED não é um dos bits de acesso que o sistema de arquivos FASTFAT reconhece, ele rejeita solicitações de acesso ao arquivo determinado. Um aplicativo que tenta abrir um arquivo em um volume FASTFAT com o conjunto de opções MAXIMUM_ALLOWED descobrirá que a solicitação falha. Para obter detalhes, consulte a função FatCheckFileAccess no arquivo de origem Acchksup.c do código de exemplo FASTFAT que o WDK contém.
Observe que, para uma passagem simples marcar, o acesso solicitado seria FILE_TRAVERSE e o descritor de segurança seria o do diretório pelo qual o chamador está tentando atravessar, não o acesso solicitado do IRP IRP_MJ_CREATE original.