Partager via


Contrôles de sécurité sur IRP_MJ_DIRECTORY_CONTROL

La sécurité est une considération lors du traitement de certaines opérations de contrôle d’annuaire, notamment celles qui traitent des notifications de modification. Le problème de sécurité est qu’une notification de modification de répertoire peut retourner des informations sur des fichiers spécifiques qui ont changé. Si l’utilisateur n’a pas le privilège de parcourir le chemin d’accès au répertoire, les informations relatives à la modification ne peuvent pas être retournées à l’utilisateur. Sinon, l’utilisateur dispose désormais d’un mécanisme permettant d’apprendre des informations supplémentaires sur l’annuaire qu’il ne doit pas avoir.

La prise en charge de la notification de changement de répertoire par la bibliothèque d’exécution du système de fichiers permet à un système de fichiers de spécifier une fonction de rappel pour effectuer une traversée case activée avant de renvoyer une notification de modification de répertoire. Cette fonction de rappel prend un grand nombre de paramètres. Pour des considérations de sécurité, les trois paramètres suivants sont importants :

  • NotifyContext est le contexte du répertoire dans lequel la notification de modification est active. Il s’agit du paramètre FsContext passé à l’appel à FsRtlNotifyFullChangeDirectory.

  • TargetContext est le contexte du fichier qui a changé. Il s’agit du paramètre TargetContext passé par le système de fichiers lorsqu’il appelle FsRtlNotifyFilterReportChange.

  • SubjectContext est le contexte de sécurité du thread demandant la notification de changement d’annuaire. Il s’agit du contexte de sécurité de l’objet capturé par le système de fichiers au moment où l’appel de notification de changement de répertoire est effectué à FsRtlNotifyFullChangeDirectory.

Lorsqu’une modification se produit, le système de fichiers l’indique à la bibliothèque d’exécution du système de fichiers. La bibliothèque d’exécution du système de fichiers appelle ensuite la fonction de rappel fournie par le système de fichiers pour vérifier que l’appelant peut recevoir des informations sur la modification. Notez que le système de fichiers n’a besoin d’inscrire une fonction de rappel que si le case activée est requis pour l’appelant. C’est le cas si SeChangeNotifyPrivilege n’est pas activé pour l’appelant, comme indiqué par le TOKEN_HAS_TRAVERSE_PRIVILEGE dans le jeton de sécurité de l’appelant.

À l’intérieur de la fonction de rappel, le système de fichiers doit effectuer une case activée du répertoire spécifié par le paramètre NotifyContext jusqu’au fichier modifié, spécifié par le paramètre TargetContext. L’exemple de routine ci-dessous effectue une telle case activée.

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;
}

Cette routine est susceptible d’être sensiblement différente pour les systèmes de fichiers qui utilisent des informations de sécurité en cache ou qui ont des structures de données différentes pour le suivi des fichiers et des répertoires (par exemple, les fichiers qui utilisent une structure pour le suivi des liens entre les fichiers et les répertoires). Les systèmes de fichiers prenant en charge les liens ne sont pas pris en compte dans cet exemple pour tenter de simplifier l’exemple.