Share via


Sicherheitsüberprüfungen für IRP_MJ_DIRECTORY_CONTROL

Sicherheit ist ein Aspekt bei der Verarbeitung bestimmter Verzeichnissteuerungsvorgänge, insbesondere bei Änderungsbenachrichtigungen. Das Sicherheitsproblem besteht darin, dass eine Verzeichnisänderungsbenachrichtigung Möglicherweise Informationen zu bestimmten Dateien zurückgibt, die geändert wurden. Wenn der Benutzer nicht über die Berechtigung verfügt, den Pfad zum Verzeichnis zu durchlaufen, können keine Informationen über die Änderung an den Benutzer zurückgegeben werden. Andernfalls verfügt der Benutzer jetzt über einen Mechanismus zum Erlernen zusätzlicher Informationen über das Verzeichnis, das der Benutzer nicht besitzen sollte.

Die Unterstützung der Benachrichtigung über Verzeichnisänderungen durch die Dateisystemlaufzeitbibliothek ermöglicht es einem Dateisystem, eine Rückruffunktion für die Durchführung einer Durchlaufüberprüfung anzugeben, bevor eine Verzeichnisänderungsbenachrichtigung zurückgegeben wird. Diese Rückruffunktion akzeptiert eine große Anzahl von Parametern. Aus Sicherheitsgründen sind die folgenden drei Parameter wichtig:

  • NotifyContext ist der Kontext des Verzeichnisses, in dem die Änderungsbenachrichtigung aktiv ist. Dies ist der FsContext-Parameter , der an den Aufruf von FsRtlNotifyFullChangeDirectory übergeben wird.

  • TargetContext ist der Kontext der Datei, die geändert wurde. Dies ist der TargetContext-Parameter , der vom Dateisystem beim Aufrufen von FsRtlNotifyFilterReportChange übergeben wird.

  • SubjectContext ist der Sicherheitskontext des Threads, der die Verzeichnisänderungsbenachrichtigung anfordert. Dies ist der Sicherheitskontext des Antragstellers, der vom Dateisystem erfasst wird, wenn der Aufruf der Verzeichnisänderungsbenachrichtigung an FsRtlNotifyFullChangeDirectory erfolgt.

Wenn eine Änderung eintritt, gibt das Dateisystem dies der Laufzeitbibliothek des Dateisystems an. Die Dateisystemlaufzeitbibliothek ruft dann die vom Dateisystem bereitgestellte Rückruffunktion auf, um zu überprüfen, ob dem Aufrufer Informationen über die Änderung gegeben werden können. Beachten Sie, dass das Dateisystem nur dann eine Rückruffunktion registrieren muss, wenn die Überprüfung für den Aufrufer erforderlich ist. Dies ist der Fall, wenn für den Aufrufer SeChangeNotifyPrivilege nicht aktiviert ist, wie durch die TOKEN_HAS_TRAVERSE_PRIVILEGE im Sicherheitstoken des Aufrufers angegeben.

Innerhalb der Rückruffunktion muss das Dateisystem eine Durchlaufüberprüfung von dem durch den NotifyContext-Parameter angegebenen Verzeichnis zu der geänderten Datei durchführen, die durch den TargetContext-Parameter angegeben wird. Die folgende Beispielroutine führt eine solche Überprüfung durch.

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

Diese Routine unterscheidet sich wahrscheinlich erheblich von Dateisystemen, die Sicherheitsinformationen zwischenspeichern oder unterschiedliche Datenstrukturen für die Nachverfolgung von Dateien und Verzeichnissen aufweisen (z. B. Dateien, die eine Struktur zum Nachverfolgen von Links zwischen Dateien und Verzeichnissen verwenden). Dateisysteme, die Links unterstützen, werden in diesem Beispiel nicht berücksichtigt, um das Beispiel zu vereinfachen.