Share via


IRP_MJ_CREATE 트래버스 권한 확인

IRP_MJ_CREATE 검사의 주요 관심사 중 하나는 호출자가 개체의 경로에 액세스할 수 있는 권한인 트래버스 권한이 있는지 여부입니다. 즉, 호출자는 dirA/dirB/file과 같은 파일 개체에 액세스할 수 있지만 해당 파일 개체의 경로(dirAdirA/dirB)를 따라 디렉터리의 내용에 액세스할 수 있는 권한이 없습니다.

기본적으로 Windows는 모든 사용자에게 트래버스 권한을 부여합니다. "사용자 권한" 상수는 ACCESS_MASK FILE_TRAVERSE 매핑되는 SeChangeNotifyPrivilege입니다. 보안 기능으로 시스템 관리자는 사용자로부터 트래버스 권한을 제거할 수 있습니다.

대부분의 호출자는 트래버스 권한을 가지므로 파일 시스템이 일반적으로 수행하는 첫 번째 검사 중 하나는 IRP 보안 컨텍스트의 AccessState-Flags> 필드에서 이 권한을 검사 것입니다.

    BOOLEAN traverseCheck = 
        !(IrpContext->IrpSp->Parameters.Create.SecurityContext->AccessState->Flags
            & TOKEN_HAS_TRAVERSE_PRIVILEGE);

파일 시스템은 플래그 를 사용하여 작업 진행 중 부여된 액세스 권한을 추적합니다. 그런 다음 파일 시스템은 액세스 상태 비트를 먼저 신속하게 검사 액세스가 이미 부여된 경우 액세스 검사 호출 비용을 방지할 수 있습니다(traverseCheck = 0).

트래버스 권한이 이전에 부여되지 않은 경우 파일 시스템은 열려 있는 파일 경로를 따라 각 디렉터리에서 검사 트래버스를 수행해야 합니다. 아래 부분 코드 조각에서 트래버스 검사 일반적으로 대부분의 보안 검사에 사용되는 일반 루틴을 사용하여 수행됩니다.


{
// accessParams is passed to the file system and is normally based
// on the fields of the same name from the IRP.

// Only one thread can be looking at this data structure in memory
// at a time (and potentially changing it), so acquire a lock on it.

    SeLockSubjectContext(
        &accessParams.AccessState->SubjectSecurityContext);

// Check whether the desired access can be granted.
// For this example, assume desiredAccess = FILE_TRAVERSE

    granted = SeAccessCheck( Fcb->SecurityDescriptor,
        &AccessParams.AccessState->SubjectSecurityContext,
        TRUE,
        AccessParams.desiredAccess,
        0,
        &Privileges,
        IoGetFileObjectGenericMapping(),
        AccessParams.AccessMode,
        &AccessParams.GrantedAccess,
        &AccessParams.status );

    // The file system uses AccessState to cache access privileges
    // that have been granted thus far along the operation's code
    // path. Update AccessState with the newly acquired Privileges.
    
    if (Privileges != NULL) {

        (void) SeAppendPrivileges(AccessParams.AccessState, Privileges );
        SeFreePrivileges( Privileges );
        Privileges = NULL;
    }

    if (granted) {
        //
        // The desired access was granted, so clear the
        // granted bits from desiredAccess. 
        //
        AccessParams.desiredAccess &= 
            ~(AccessParams.GrantedAccess | MAXIMUM_ALLOWED);
 
        if (!checkOnly) {
        //
        // The caller wants to modify the access state for this 
        // request
        //
            AccessParams.AccessState->PreviouslyGrantedAccess |= 
                AccessParams.GrantedAccess;
        }

        if (maxDesired) {

            maxDelete = 
                (BOOLEAN)(AccessParams.AccessState->PreviouslyGrantedAccess & 
                    DELETE);
            maxReadAttr = 
                (BOOLEAN)(AccessParams.AccessState->PreviouslyGrantedAccess & 
                    FILE_READ_ATTRIBUTES);
        }
        AccessParams.AccessState->RemainingDesiredAccess &= 
            ~(AccessParams.GrantedAccess | MAXIMUM_ALLOWED);
    }

    // Release the lock on the security context
    SeUnlockSubjectContext(&accessParams.AccessState->SubjectSecurityContext);  
}

이 함수는 일반 보안 검사 수행합니다. 이 함수는 다음과 같은 문제를 처리해야 합니다.

  • 검사 사용할 올바른 보안 설명자를 지정해야 합니다.

  • 보안 컨텍스트를 따라 전달해야 합니다(작업을 수행하는 엔터티의 자격 증명임).

  • 보안 검사 결과에 따라 액세스 상태를 업데이트해야 합니다.

  • MAXIMUM_ALLOWED 옵션을 고려해야 합니다( ntifs.h 참조). MAXIMUM_ALLOWED 옵션은 파일 시스템이 파일 시스템에서 허용하는 최대 액세스(예: 읽기/쓰기/삭제)에 대한 액세스를 설정하도록 지정합니다. 이 옵션은 FASTFAT 파일 시스템에서 지원되지 않으므로 MAXIMUM_ALLOWED 옵션을 사용하는 애플리케이션은 거의 없습니다. MAXIMUM_ALLOWED 옵션 비트는 FASTFAT 파일 시스템에서 인식하는 액세스 비트 중 하나가 아니므로 지정된 파일에 대한 액세스 요청을 거부합니다. MAXIMUM_ALLOWED 옵션 집합이 설정된 FASTFAT 볼륨에서 파일을 열려고 하는 애플리케이션은 요청이 실패하는 것을 발견합니다. 자세한 내용은 WDK에 포함된 FASTFAT 샘플 코드의 Acchksup.c 소스 파일에서 FatCheckFileAccess 함수를 참조하세요.

간단한 트래버스 검사 경우 요청된 액세스는 FILE_TRAVERSE, 보안 설명자는 원래IRP_MJ_CREATE IRP에서 요청한 액세스가 아니라 호출자가 트래버스하려는 디렉터리의 액세스입니다.