Udostępnij przez


Sprawdzanie zabezpieczeń IRP_MJ_DIRECTORY_CONTROL

Zabezpieczenia są istotne podczas przetwarzania niektórych operacji kontroli katalogu, zwłaszcza tych, które mają do czynienia z powiadomieniami o zmianie. Problem z zabezpieczeniami polega na tym, że powiadomienie o zmianie katalogu może zwracać informacje o określonych plikach, które uległy zmianie. Jeśli użytkownik nie ma uprawnień do przechodzenia ścieżki do katalogu, nie można zwrócić informacji o zmianie do użytkownika. W przeciwnym razie użytkownik ma teraz mechanizm uczenia się dodatkowych informacji o katalogu, którego użytkownik nie powinien mieć.

Obsługa powiadomienia o zmianie katalogu przez bibliotekę czasu wykonywania systemu plików umożliwia systemowi plików określenie funkcji wywołania zwrotnego na potrzeby przeprowadzania sprawdzania przechodzenia przed zwróceniem powiadomienia o zmianie katalogu. Ta funkcja wywołania zwrotnego przyjmuje dużą liczbę parametrów. W przypadku zagadnień dotyczących zabezpieczeń ważne są następujące trzy parametry:

  • NotifyContext jest kontekstem katalogu, w którym jest aktywne powiadomienie o zmianie. Będzie to parametr FsContext przekazywany do wywołania FsRtlNotifyFullChangeDirectory.

  • TargetContext jest kontekstem zmienionego pliku. Będzie to parametr TargetContext przekazywany przez system plików, gdy wywołuje FsRtlNotifyFilterReportChange.

  • SubjectContext jest kontekstem zabezpieczeń wątku żądającego powiadomienia o zmianie katalogu. Jest to kontekst zabezpieczeń podmiotu przechwycony przez system plików w czasie wywoływania powiadomienia o zmianie katalogu w FsRtlNotifyFullChangeDirectory.

Gdy wystąpi zmiana, system plików wskazuje to na bibliotekę czasu wykonywania systemu plików. Biblioteka czasu wykonywania systemu plików wywoła funkcję wywołania zwrotnego dostarczoną przez system plików, aby sprawdzić, czy obiekt wywołujący może otrzymać informacje o zmianie. Należy pamiętać, że system plików musi zarejestrować funkcję wywołania zwrotnego tylko wtedy, gdy sprawdzanie jest wymagane dla obiektu wywołującego. Dzieje się tak, jeśli obiekt wywołujący nie ma włączonej funkcji SeChangeNotifyPrivilege, zgodnie z TOKEN_HAS_TRAVERSE_PRIVILEGE w tokenie zabezpieczającym obiektu wywołującego.

Wewnątrz funkcji wywołania zwrotnego system plików musi wykonać kontrolę przechodzenia z katalogu określonego przez parametr NotifyContext do pliku, który uległ zmianie, określony przez parametr TargetContext. Poniższa przykładowa rutyna wykonuje taką kontrolę.

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

Ta rutyna może znacznie się różnić w przypadku systemów plików buforujących informacje zabezpieczające lub które mają różne struktury danych do śledzenia plików i katalogów (na przykład plików używających struktury do śledzenia łączy między plikami i katalogami). W tym przykładzie nie są brane pod uwagę linki pomocnicze systemów plików w celu uproszczenia przykładu.