보안은 특정 디렉터리 제어 작업, 특히 변경 알림을 처리하는 작업을 처리할 때 고려해야 합니다. 보안 문제는 디렉터리 변경 알림이 변경된 특정 파일에 대한 정보를 반환할 수 있다는 것입니다. 사용자에게 디렉터리 경로를 트래버스할 권한이 없는 경우 변경 내용에 대한 정보를 사용자에게 반환할 수 없습니다. 그렇지 않으면 이제 사용자에게는 사용자가 갖지 않아야 하는 디렉터리에 대한 추가 정보를 학습하는 메커니즘이 있습니다.
파일 시스템 런타임 라이브러리에서 디렉터리 변경 알림을 지원하면 파일 시스템에서 디렉터리 변경 알림을 반환하기 전에 트래버스 검사를 수행하기 위한 콜백 함수를 지정할 수 있습니다. 이 콜백 함수는 많은 수의 매개 변수를 사용합니다. 보안 고려 사항의 경우 다음 세 가지 매개 변수가 중요합니다.
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;
}
이 루틴은 보안 정보를 캐시하거나 파일 및 디렉터리를 추적하기 위한 데이터 구조가 다른 파일 시스템(예: 파일과 디렉터리 간의 링크를 추적하는 데 구조를 사용하는 파일)과 크게 다를 수 있습니다. 링크를 지원하는 파일 시스템은 예제를 간소화하기 위해 이 샘플에서 고려되지 않습니다.