IRP_MJ_DIRECTORY_CONTROL üzerinde güvenlik denetimleri

Güvenlik, özellikle değişiklik bildirimleriyle ilgilenenler olmak üzere belirli dizin denetimi işlemlerini işlerken dikkate alınması gereken bir konudur. Güvenlik sorunu, dizin değişikliği bildiriminin değiştirilen belirli dosyalar hakkında bilgi döndürebileceğidir. Kullanıcının dizin yolundan geçme ayrıcalığı yoksa, değişiklik hakkındaki bilgiler kullanıcıya döndürülemez. Aksi takdirde, kullanıcının artık dizin hakkında sahip olmaması gereken ek bilgileri öğrenmek için bir mekanizması vardır.

Dosya sistemi çalışma zamanı kitaplığı tarafından dizin değişikliği bildirimi desteği, bir dosya sisteminin bir dizin değişikliği bildirimi döndürmeden önce çapraz geçiş denetimi gerçekleştirmek için bir geri çağırma işlevi belirtmesine olanak tanır. Bu geri çağırma işlevi çok sayıda parametre alır. Güvenlikle ilgili dikkat edilmesi gerekenler için aşağıdaki üç parametre önemlidir:

  • NotifyContext, değişiklik bildiriminin etkin olduğu dizinin bağlamıdır. Bu, FsRtlNotifyFullChangeDirectoryçağrısına geçirilen FsContext parametresi olacaktır.

  • TargetContext, değiştirilen dosyanın bağlamıdır. Bu, FsRtlNotifyFilterReportChangeçağırdığında dosya sistemi tarafından geçirilen TargetContext parametresi olacaktır.

  • SubjectContext, dizin değişikliği bildirimini isteyen iş parçacığının güvenlik bağlamıdır. Bu, dosya sistemi tarafından FsRtlNotifyFullChangeDirectory dizin değişikliği bildirim çağrısı yapıldığında yakalanan konu güvenlik bağlamıdır.

Bir değişiklik olduğunda, dosya sistemi bunu dosya sistemi çalışma zamanı kitaplığına gösterir. Ardından dosya sistemi çalışma zamanı kitaplığı, çağıranın değişiklik hakkında bilgi verilip verilebileceğini doğrulamak için dosya sistemi tarafından sağlanan geri çağırma işlevini çağırır. Dosya sisteminin yalnızca çağıran için denetim gerekiyorsa geri çağırma işlevini kaydetmesi gerektiğini unutmayın. Çağıranın güvenlik belirtecindeki TOKEN_HAS_TRAVERSE_PRIVILEGE belirttiği gibi arayanda SeChangeNotifyPrivilege etkin değilse bu durum söz konusudur.

Geri çağırma işlevinin içinde, dosya sisteminin NotifyContext parametresi tarafından belirtilen dizinden, TargetContext parametresi tarafından belirtilen değiştirilen dosyaya çapraz geçiş denetimi gerçekleştirmesi gerekir. Aşağıdaki örnek yordam böyle bir denetim gerçekleştirir.

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

Bu yordam, güvenlik bilgilerini önbelleğe alan veya dosyaları ve dizinleri izlemek için farklı veri yapılarına sahip olan dosya sistemleri (örneğin, dosyalar ve dizinler arasındaki bağlantıları izlemek için bir yapı kullanan dosyalar) için önemli ölçüde farklı olabilir. Bağlantıları destekleyen dosya sistemleri, örneği basitleştirme amacıyla bu örnekte dikkate alınmaz.