다음을 통해 공유


IRP_MJ_DIRECTORY_CONTROL 보안 검사

보안은 특정 디렉터리 제어 작업, 특히 변경 알림을 처리하는 작업을 처리할 때 고려해야 합니다. 보안 문제는 디렉터리 변경 알림이 변경된 특정 파일에 대한 정보를 반환할 수 있다는 것입니다. 사용자에게 디렉터리 경로를 트래버스할 수 있는 권한이 없는 경우 변경 내용에 대한 정보를 사용자에게 반환할 수 없습니다. 그렇지 않으면 이제 사용자에게는 사용자가 갖지 않아야 하는 디렉터리에 대한 추가 정보를 학습하는 메커니즘이 있습니다.

파일 시스템 런타임 라이브러리에서 디렉터리 변경 알림을 지원하면 파일 시스템에서 디렉터리 변경 알림을 반환하기 전에 트래버스 검사 수행하기 위한 콜백 함수를 지정할 수 있습니다. 이 콜백 함수는 많은 수의 매개 변수를 사용합니다. 보안 고려 사항의 경우 다음 세 가지 매개 변수가 중요합니다.

  • NotifyContext 는 변경 알림이 활성 상태인 디렉터리의 컨텍스트입니다. FsRtlNotifyFullChangeDirectory 호출에 전달되는 FsContext 매개 변수입니다.

  • TargetContext 는 변경된 파일의 컨텍스트입니다. FsRtlNotifyFilterReportChange를 호출할 때 파일 시스템에서 전달되는 TargetContext 매개 변수입니다.

  • SubjectContext 는 디렉터리 변경 알림을 요청하는 스레드의 보안 컨텍스트입니다. FsRtlNotifyFullChangeDirectory에 대한 디렉터리 변경 알림 호출이 수행될 때 파일 시스템에서 캡처한 주체 보안 컨텍스트입니다.

변경이 발생하면 파일 시스템은 이를 파일 시스템 런타임 라이브러리에 나타냅니다. 파일 시스템 런타임 라이브러리는 파일 시스템에서 제공하는 콜백 함수를 호출하여 호출자에게 변경 내용에 대한 정보를 제공할 수 있는지 확인합니다. 호출자에게 검사 필요한 경우에만 파일 시스템에서 콜백 함수를 등록해야 합니다. 호출자의 보안 토큰에 있는 TOKEN_HAS_TRAVERSE_PRIVILEGE 표시된 대로 호출자에게 SeChangeNotifyPrivilege를 사용하도록 설정하지 않은 경우입니다.

콜백 함수 내에서 파일 시스템은 NotifyContext 매개 변수로 지정된 디렉터리에서 TargetContext 매개 변수로 지정된 변경된 파일로 검사 트래버스를 수행해야 합니다. 아래 샘플 루틴은 이러한 검사 수행합니다.

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

이 루틴은 보안 정보를 캐시하는 파일 시스템이나 파일 및 디렉터리를 추적하기 위한 데이터 구조가 다른 파일 시스템(예: 파일과 디렉터리 간의 링크를 추적하는 데 구조를 사용하는 파일)과 크게 다를 수 있습니다. 링크를 지원하는 파일 시스템은 예제를 간소화하기 위해 이 샘플에서 고려되지 않습니다.