가상 보안 모드

VSM(가상 보안 모드)은 운영 체제 소프트웨어 내에서 새로운 보안 경계를 만들고 관리할 수 있도록 호스트 및 게스트 파티션에 제공되는 하이퍼바이저 기능 및 인식 기능 집합입니다. VSM은 Device Guard, Credential Guard, 가상 TPM 및 보호된 VM을 포함한 보안 기능을 Windows 하이퍼바이저 기능입니다. 이러한 보안 기능은 Windows 10 및 Windows Server 2016 도입되었습니다.

VSM을 사용하면 루트 및 게스트 파티션의 운영 체제 소프트웨어가 시스템 보안 자산의 스토리지 및 처리를 위해 격리된 메모리 영역을 만들 수 있습니다. 이러한 격리된 지역에 대한 액세스는 하이퍼바이저를 통해서만 제어되고 부여됩니다. 이 하이퍼바이저는 시스템의 TCB(신뢰할 수 있는 컴퓨팅 베이스)의 매우 신뢰할 수 있는 부분입니다. 하이퍼바이저는 운영 체제 소프트웨어보다 높은 권한 수준에서 실행되고 시스템 초기화 초기에 CPU MMU 및 IOMMU의 메모리 액세스 권한 제어와 같은 주요 시스템 하드웨어 리소스를 독점적으로 제어하므로 하이퍼바이저는 감독자 모드 액세스(예: CPL0)를 사용하는 운영 체제 소프트웨어(예: OS 커널 및 디바이스 드라이버)에서도 이러한 격리된 지역을 무단 액세스로부터 보호할 수 있습니다. 또는 "링 0").

이 아키텍처를 사용하면 감독자 모드에서 실행되는 일반 시스템 수준 소프트웨어(예: 커널, 드라이버 등)가 악성 소프트웨어에 의해 손상된 경우에도 하이퍼바이저로 보호되는 격리된 지역의 자산은 보안을 유지할 수 있습니다.

VTL(가상 신뢰 수준)

VSM은 VTL(가상 신뢰 수준)을 통해 격리를 달성하고 유지 관리합니다. VTL은 파티션당 및 가상 프로세서별로 사용하도록 설정되고 관리됩니다.

가상 신뢰 수준은 계층 구조이며, 더 높은 수준의 권한은 하위 수준보다 높습니다. VTL0은 최소 권한 수준이며, VTL1은 VTL0보다 더 많은 권한이 부여되고, VTL2는 VTL1보다 권한이 더 높습니다.

아키텍처적으로 최대 16개 수준의 VTL이 지원됩니다. 그러나 하이퍼바이저는 16개 미만의 VTL을 구현하도록 선택할 수 있습니다. 현재 두 개의 VTL만 구현됩니다.

typedef UINT8 HV_VTL, *PHV_VTL;

#define HV_NUM_VTLS 2
#define HV_INVALID_VTL ((HV_VTL) -1)
#define HV_VTL_ALL 0xF

각 VTL에는 고유한 메모리 액세스 보호 집합이 있습니다. 이러한 액세스 보호는 파티션의 실제 주소 공간에서 하이퍼바이저에 의해 관리되므로 파티션에서 실행되는 시스템 수준 소프트웨어에 의해 수정할 수 없습니다.

권한이 있는 VTL이 자체 메모리 보호를 적용할 수 있으므로 VTL이 많을수록 낮은 VTL로부터 메모리 영역을 효과적으로 보호할 수 있습니다. 실제로 더 낮은 VTL은 더 높은 VTL로 보호하여 격리된 메모리 영역을 보호할 수 있습니다. 예를 들어 VTL0은 VTL1에 비밀을 저장할 수 있으며 이때 VTL1만 액세스할 수 있습니다. VTL0이 손상되더라도 비밀은 안전합니다.

VTL 보호

VTL 간에 격리를 달성하기 위한 여러 패싯이 있습니다.

  • 메모리 액세스 보호: 각 VTL은 게스트 물리적 메모리 액세스 보호 집합을 유지 관리합니다. 특정 VTL에서 실행되는 소프트웨어는 이러한 보호에 따라 메모리에만 액세스할 수 있습니다.
  • 가상 프로세서 상태: 가상 프로세서는 별도의 VTL별 상태를 유지 관리합니다. 예를 들어 각 VTL은 프라이빗 VP 레지스터 집합을 정의합니다. 낮은 VTL에서 실행되는 소프트웨어는 더 높은 VTL의 프라이빗 가상 프로세서의 레지스터 상태에 액세스할 수 없습니다.
  • 인터럽트: 별도의 프로세서 상태와 함께 각 VTL에는 자체 인터럽트 하위 시스템(로컬 APIC)도 있습니다. 이렇게 하면 더 높은 VTL이 낮은 VTL의 간섭을 위험 없이 인터럽트를 처리할 수 있습니다.
  • 오버레이 페이지: 특정 오버레이 페이지는 높은 VTL이 신뢰할 수 있는 액세스 권한을 갖기 위해 VTL별로 유지 관리됩니다. 예를 들어 VTL당 별도의 하이퍼콜 오버레이 페이지가 있습니다.

VSM 검색 및 상태

VSM 기능은 AccessVsm 파티션 권한 플래그를 통해 파티션에 보급됩니다. 다음 권한이 모두 있는 파티션만 VSM: AccessVsm, AccessVpRegisters 및 AccessSynicRegs를 사용할 수 있습니다.

VSM 기능 검색

게스트는 VSM 기능에 대한 보고서에 액세스하려면 다음 모델별 레지스터를 사용해야 합니다.

MSR 주소 이름 등록 Description
0x000D0006 HV_X64_REGISTER_VSM_CAPABILITIES VSM 기능에 대해 보고합니다.

VSM 기능 등록 MSR의 형식은 다음과 같습니다.

비트 Description 특성
63 Dr6Shared 읽기
62:47 MbecVtlMask 읽기
46 DenyLowerVtlStartup 읽기
45:0 RsvdZ 읽기

Dr6Shared는 Dr6이 VTL 간의 공유 레지스터인지 여부를 게스트에게 나타냅니다.

MvecVtlMask는 게스트에게 Mbec를 사용하도록 설정할 수 있는 VTL을 나타냅니다.

DenyLowerVtlStartup은 Vtl이 낮은 VTL로 VP 재설정을 거부할 수 있는지 여부를 게스트에게 나타냅니다.

VSM 상태 등록

파티션 권한 플래그 외에도 두 개의 가상 레지스터를 사용하여 VSM 상태에 HvRegisterVsmPartitionStatusHvRegisterVsmVpStatus대한 추가 정보를 알아볼 수 있습니다.

HvRegisterVsmPartitionStatus

HvRegisterVsmPartitionStatus는 모든 VTL에서 공유되는 파티션별 읽기 전용 레지스터입니다. 이 레지스터는 파티션에 대해 사용하도록 설정된 VTL, 모드 기반 실행 컨트롤이 활성화된 VTL 및 허용되는 최대 VTL에 대한 정보를 제공합니다.

typedef union
{
    UINT64 AsUINT64;
    struct
    {
        UINT64 EnabledVtlSet : 16;
        UINT64 MaximumVtl : 4;
        UINT64 MbecEnabledVtlSet: 16;
        UINT64 ReservedZ : 28;
    };
} HV_REGISTER_VSM_PARTITION_STATUS;

HvRegisterVsmVpStatus

HvRegisterVsmVpStatus는 읽기 전용 레지스터이며 모든 VTL에서 공유됩니다. VP별 레지스터로, 각 가상 프로세서가 자체 인스턴스를 유지 관리합니다. 이 레지스터는 활성화된 VTL( 활성 상태)뿐만 아니라 VP에서 활성 상태인 MBEC 모드에 대한 정보를 제공합니다.

typedef union
{
    UINT64 AsUINT64;
    struct
    {
        UINT64 ActiveVtl : 4;
        UINT64 ActiveMbecEnabled : 1;
        UINT64 ReservedZ0 : 11;
        UINT64 EnabledVtlSet : 16;
        UINT64 ReservedZ1 : 32;
    };
} HV_REGISTER_VSM_VP_STATUS;

ActiveVtl은 현재 가상 프로세서에서 활성화된 VTL 컨텍스트의 ID입니다.

ActiveMbecEnabled는 MBEC가 현재 가상 프로세서에서 활성화되어 있음을 지정합니다.

EnabledVtlSet은 가상 프로세서에서 사용하도록 설정된 VTL의 비트맵입니다.

파티션 VTL 초기 상태

파티션이 시작되거나 다시 설정되면 VTL0에서 실행되기 시작합니다. 다른 모든 VTL은 파티션을 만들 때 비활성화됩니다.

VTL 사용

VTL 사용을 시작하려면 하위 VTL에서 다음을 시작해야 합니다.

  1. 파티션에 대상 VTL을 사용하도록 설정합니다. 이렇게 하면 VTL을 파티션에 일반적으로 사용할 수 있습니다.
  2. 하나 이상의 가상 프로세서에서 대상 VTL을 사용하도록 설정합니다. 이렇게 하면 VP에 VTL을 사용할 수 있고 초기 컨텍스트를 설정합니다. 모든 VP는 동일한 사용 VTL을 사용하는 것이 좋습니다. 일부 VP에서 VTL을 사용하도록 설정하면(전부는 아님) 예기치 않은 동작이 발생할 수 있습니다.
  3. 파티션 및 VP에 대해 VTL을 사용하도록 설정하면 EnableVtlProtection 플래그가 설정되면 액세스 보호 설정을 시작할 수 있습니다.

VTL은 연속될 필요가 없습니다.

파티션에 대상 VTL 사용

HvCallEnablePartitionVtl 하이퍼콜은 특정 파티션에 대해 VTL을 사용하도록 설정하는 데 사용됩니다. 소프트웨어가 실제로 특정 VTL에서 실행되기 전에 파티션의 가상 프로세서에서 VTL을 사용하도록 설정해야 합니다.

가상 프로세서에 대상 VTL 사용

파티션에 대해 VTL을 사용하도록 설정하면 파티션의 가상 프로세서에서 VTL을 사용하도록 설정할 수 있습니다. HvCallEnableVpVtl 하이퍼콜을 사용하여 초기 컨텍스트를 설정하는 가상 프로세서에 대한 VTL을 사용하도록 설정할 수 있습니다.

가상 프로세서에는 VTL당 하나의 "컨텍스트"가 있습니다. VTL이 전환되면 VTL의 프라이빗 상태 도 전환됩니다.

VTL 구성

VTL을 사용하도록 설정하면 동일하거나 더 높은 VTL에서 실행되는 VP에 의해 해당 구성을 변경할 수 있습니다.

파티션 구성

HvRegisterVsmPartitionConfig 레지스터를 사용하여 파티션 전체 특성을 구성할 수 있습니다. 모든 파티션에서 각 VTL(0보다 큼)에 대해 이 레지스터의 인스턴스가 하나 있습니다.

모든 VTL은 자체 HV_REGISTER_VSM_PARTITION_CONFIG 인스턴스와 낮은 VTL에 대한 인스턴스를 수정할 수 있습니다. VTL은 더 높은 VTL에 대해 이 레지스터를 수정할 수 없습니다.

typedef union
{
    UINT64 AsUINT64;
    struct
    {
        UINT64 EnableVtlProtection : 1;
        UINT64 DefaultVtlProtectionMask : 4;
        UINT64 ZeroMemoryOnReset : 1;
        UINT64 DenyLowerVtlStartup : 1;
        UINT64 ReservedZ : 2;
        UINT64 InterceptVpStartup : 1;
        UINT64 ReservedZ : 54; };
} HV_REGISTER_VSM_PARTITION_CONFIG;

이 레지스터의 필드는 아래에 설명되어 있습니다.

VTL 보호 사용

VTL을 사용하도록 설정하면 메모리 보호 적용을 시작하기 전에 EnableVtlProtection 플래그를 설정해야 합니다. 이 플래그는 한 번 쓰기입니다. 즉, 설정된 후에는 수정할 수 없습니다.

기본 보호 마스크

기본적으로 시스템은 현재 매핑된 모든 페이지와 향후 "핫 추가" 페이지에 RWX 보호를 적용합니다. 핫 추가 페이지는 크기 조정 작업 중에 파티션에 추가된 메모리를 가리킵니다.

상위 VTL은 HV_REGISTER_VSM_PARTITION_CONFIG DefaultVtlProtectionMask를 지정하여 다른 기본 메모리 보호 정책을 설정할 수 있습니다. 이 마스크는 VTL을 사용할 때 설정해야 합니다. 설정한 후에는 변경할 수 없으며 파티션 재설정에 의해서만 지워집니다.

bit Description
0 읽기
1 쓰기
2 커널 모드 실행(KMX)
3 사용자 모드 실행(UMX)

초기화할 때 메모리 0개

ZeroMemOnReset은 파티션이 다시 설정되기 전에 메모리가 0이 되는지 제어하는 비트입니다. 이 구성은 기본적으로 설정됩니다. 비트가 설정된 경우 초기화 시 파티션의 메모리가 0이 되므로 더 높은 VTL의 메모리가 더 낮은 VTL에 의해 손상될 수 없습니다. 이 비트가 지워지면 초기화 시 파티션의 메모리가 0이 되지 않습니다.

DenyLowerVtlStartup

DenyLowerVtlStartup 플래그는 하위 VTL에서 가상 프로세서를 시작하거나 다시 설정할 수 있는지 여부를 제어합니다. 여기에는 가상 프로세서(예: X64의 SIPI)와 HvCallStartVirtualProcessor 하이퍼콜을 다시 설정하는 아키텍처 방법이 포함됩니다.

InterceptVpStartup

InterceptVpStartup 플래그가 설정된 경우 가상 프로세서를 시작하거나 다시 설정하면 더 높은 VTL에 대한 절편이 생성됩니다.

하위 VTL 구성

다음 레지스터는 상위 VTL에서 낮은 VTL의 동작을 구성하는 데 사용할 수 있습니다.

typedef union
{
    UINT64 AsUINT64;
    struct
    {
        UINT64 MbecEnabled : 1;
        UINT64 TlbLocked : 1;
        UINT64 ReservedZ : 62;
    };
} HV_REGISTER_VSM_VP_SECURE_VTL_CONFIG;

각 VTL(0보다 높음)에는 자체보다 낮은 모든 VTL에 대해 이 레지스터의 인스턴스가 있습니다. 예를 들어 VTL2에는 VTL1용 인스턴스와 VTL0의 경우 두 개의 인스턴스가 있습니다.

이 레지스터의 필드는 아래에 설명되어 있습니다.

MbecEnabled

이 필드는 하위 VTL에 대해 MBEC를 사용할 수 있는지 여부를 구성합니다.

TlbLocked

이 필드는 낮은 VTL의 TLB를 잠급 수 있습니다. 이 접근 권한 값은 낮은 VTL이 더 높은 VTL을 방해할 수 있는 TLB 무효화를 발생시키는 것을 방지하는 데 사용할 수 있습니다. 이 비트를 설정하면 잠금이 해제될 때까지 하위 VTL의 모든 주소 공간 플러시 요청이 차단됩니다.

TLB의 잠금을 해제하기 위해 더 높은 VTL은 이 비트를 지울 수 있습니다. 또한 VP가 더 낮은 VTL로 돌아오면 해당 시간에 보유하고 있는 모든 TLB 잠금을 해제합니다.

VTL 항목

VP가 하위 VTL에서 더 높은 VTL로 전환되면 VTL이 "입력"됩니다. 이 문제는 다음과 같은 이유로 발생할 수 있습니다.

  1. VTL 호출: 소프트웨어가 더 높은 VTL에서 코드를 명시적으로 호출하려는 경우입니다.
  2. 보안 인터럽트: 더 높은 VTL에 대해 인터럽트가 수신되면 VP가 더 높은 VTL에 진입합니다.
  3. 보안 절편: 특정 작업은 보안 인터럽트(예: 특정 MSR에 액세스)를 트리거합니다.

VTL을 입력한 후에는 자발적으로 종료해야 합니다. 더 높은 VTL은 낮은 VTL에서 선점할 수 없습니다.

VTL 항목 이유 식별

항목에 적절하게 반응하려면 더 높은 VTL이 입력된 이유를 알아야 할 수 있습니다. 진입 이유를 구분하기 위해 VTL 항목이 HV_VP_VTL_CONTROL 구조에 포함됩니다.

VTL 호출

"VTL 호출"은 낮은 VTL이 HvCallVtlCall 하이퍼콜을 통해 더 높은 VTL(예: 더 높은 VTL을 사용하여 메모리 영역을 보호하기 위해)에 대한 항목을 시작하는 경우입니다.

VTL 호출은 VTL 스위치에서 공유 레지스터의 상태를 유지합니다. 프라이빗 레지스터는 VTL별 수준에서 유지됩니다. 이러한 제한에 대한 예외는 VTL 호출 시퀀스에 필요한 레지스터입니다. VTL 호출에는 다음 레지스터가 필요합니다.

X64 x86 Description
RCX EDX:EAX 하이퍼바이저에 대한 VTL 호출 컨트롤 입력을 지정합니다.
RAX ECX 예약됨

VTL 호출 컨트롤 입력의 모든 비트는 현재 예약되어 있습니다.

VTL 호출 제한

VTL 호출은 가장 권한 있는 프로세서 모드에서만 시작할 수 있습니다. 예를 들어 x64 시스템에서 VTL 호출은 CPL0에서만 올 수 있습니다. 시스템에서 가장 권한이 있는 프로세서 모드에서 시작된 VTL 호출은 하이퍼바이저에서 #UD 예외를 가상 프로세서에 주입합니다.

VTL 호출은 다음으로 높은 VTL로만 전환할 수 있습니다. 즉, 여러 VTL을 사용하도록 설정한 경우 호출은 VTL을 "건너뛸" 수 없습니다. 다음 작업을 수행하면 #UD 예외가 발생합니다.

  • 프로세서 모드에서 시작된 VTL 호출로, 시스템에서 가장 권한이 있는 항목(아키텍처별)입니다.
  • 실제 모드에서 VTL 호출(x86/x64)
  • 대상 VTL이 비활성화되었거나 아직 사용하도록 설정되지 않은 가상 프로세서에 대한 VTL 호출입니다.
  • 잘못된 컨트롤 입력 값이 있는 VTL 호출

VTL 종료

하위 VTL로의 전환을 "반환"으로 알려져 있습니다. VTL의 처리가 완료되면 더 낮은 VTL로 전환하기 위해 VTL 반환을 시작할 수 있습니다. VTL 반환이 발생할 수 있는 유일한 방법은 상위 VTL이 자발적으로 시작하는 경우입니다. 낮은 VTL은 더 높은 VTL을 선점할 수 없습니다.

VTL 반환

"VTL 반환"은 높은 VTL이 HvCallVtlReturn 하이퍼콜을 통해 더 낮은 VTL로 스위치를 시작하는 경우입니다. VTL 호출과 마찬가지로 프라이빗 프로세서 상태가 전환되고 공유 상태가 그대로 유지됩니다. 하위 VTL이 더 높은 VTL로 명시적으로 호출된 경우 하이퍼바이저는 VTL 호출 후에도 계속되도록 반환이 완료되기 전에 더 높은 VTL의 명령 포인터를 증가합니다.

VTL 반환 코드 시퀀스를 사용하려면 다음 레지스터를 사용해야 합니다.

X64 x86 Description
RCX EDX:EAX 하이퍼바이저에 대한 VTL 반환 컨트롤 입력을 지정합니다.
RAX ECX 예약됨

VTL 반환 컨트롤 입력의 형식은 다음과 같습니다.

비트 필드 Description
63:1 RsvdZ
0 빠른 반환 레지스터가 복원되지 않음

다음 작업은 #UD 예외를 생성합니다.

  • 가장 낮은 VTL이 현재 활성 상태일 때 VTL 반환 시도
  • 잘못된 컨트롤 입력 값으로 VTL 반환 시도
  • 시스템에서 가장 권한이 있는 프로세서 모드에서 VTL 반환 시도(아키텍처별)

빠른 반환

반환 처리의 일부로 하이퍼바이저는 HV_VP_VTL_CONTROL 구조에서 하위 VTL의 레지스터 상태를 복원할 수 있습니다. 예를 들어 보안 인터럽트를 처리한 후 더 높은 VTL은 낮은 VTL의 상태를 방해하지 않고 반환하려고 할 수 있습니다. 따라서 하이퍼바이저는 낮은 VTL의 레지스터를 VTL 컨트롤 구조에 저장된 호출 전 값으로 복원하는 메커니즘을 제공합니다.

이 동작이 필요하지 않은 경우 더 높은 VTL은 "빠른 반환"을 사용할 수 있습니다. 빠른 반환은 하이퍼바이저가 컨트롤 구조에서 레지스터 상태를 복원하지 않는 경우입니다. 이는 불필요한 처리를 방지하기 위해 가능하면 사용되어야 합니다.

이 필드는 VTL 반환 입력의 비트 0으로 설정할 수 있습니다. 0으로 설정하면 레지스터가 HV_VP_VTL_CONTROL 구조에서 복원됩니다. 이 비트를 1로 설정하면 레지스터가 복원되지 않습니다(빠른 반환).

하이퍼콜 페이지 지원

하이퍼바이저는 VTL 호출을 지원하고 하이퍼콜 페이지를 통해 반환하는 메커니즘을 제공합니다. 이 페이지에서는 VTL을 전환하는 데 필요한 특정 코드 시퀀스를 추상화합니다.

하이퍼콜 페이지에서 특정 지침을 실행하여 VTL 호출 및 반환을 실행하는 코드 시퀀스에 액세스할 수 있습니다. 호출/반환 청크는 HvRegisterVsmCodePageOffset 가상 레지스터에 의해 결정되는 하이퍼콜 페이지의 오프셋에 있습니다. 이 레지스터는 VTL당 별도의 인스턴스가 있는 읽기 전용 및 파티션 전체 레지스터입니다.

VTL은 CALL 명령을 사용하여 VTL 호출/반환을 실행할 수 있습니다. 하이퍼콜 페이지에서 올바른 위치에 대한 호출이 VTL 호출/반환을 시작합니다.

typedef union
{
    UINT64 AsUINT64;
    struct
    {
        UINT64 VtlCallOffset : 12;
        UINT64 VtlReturnOffset : 12;
        UINT64 ReservedZ : 40;
    };
} HV_REGISTER_VSM_CODE_PAGE_OFFSETS;

요약하자면 하이퍼콜 페이지를 사용하여 코드 시퀀스를 호출하는 단계는 다음과 같습니다.

  1. 하이퍼콜 페이지를 VTL의 GPA 공간에 매핑
  2. 코드 시퀀스(VTL 호출 또는 반환)에 대한 올바른 오프셋을 결정합니다.
  3. CALL을 사용하여 코드 시퀀스를 실행합니다.

메모리 액세스 보호

VSM에서 제공하는 한 가지 필요한 보호는 메모리 액세스를 격리하는 기능입니다.

VTL이 높을수록 낮은 VTL에서 허용되는 메모리 액세스 유형을 높은 수준의 제어할 수 있습니다. 특정 GPA 페이지에 대해 상위 VTL에서 지정할 수 있는 세 가지 기본 보호 유형인 읽기, 쓰기 및 eXecute가 있습니다. 다음 표에 정의되어 있습니다.

Name Description
읽기 메모리 페이지에 대한 읽기 액세스가 허용되는지 여부를 제어합니다.
쓰기 메모리 페이지에 대한 쓰기 액세스 허용 여부를 제어합니다.
Execute 메모리 페이지에 대한 명령 페치 허용 여부를 제어합니다.

이러한 세 가지는 다음과 같은 유형의 메모리 보호를 위해 결합됩니다.

  1. 액세스 권한 없음
  2. 읽기 전용, 실행 없음
  3. 읽기 전용, 실행
  4. 읽기/쓰기, 실행 없음
  5. 읽기/쓰기, 실행

"MBEC(모드 기반 실행 제어)"를 사용하도록 설정하면 사용자 및 커널 모드 실행 보호를 별도로 설정할 수 있습니다.

VTL이 높을수록 HvCallModifyVtlProtectionMask 하이퍼콜을 통해 GPA에 대한 메모리 보호를 설정할 수 있습니다.

메모리 보호 계층 구조

메모리 액세스 권한은 특정 VTL에 대한 여러 원본에서 설정할 수 있습니다. 각 VTL의 권한은 잠재적으로 호스트 파티션뿐만 아니라 여러 다른 VTL에 의해 제한될 수 있습니다. 보호가 적용되는 순서는 다음과 같습니다.

  1. 호스트에서 설정한 메모리 보호
  2. 더 높은 VTL에 의해 설정된 메모리 보호

즉, VTL 보호는 호스트 보호를 대체합니다. 상위 수준 VTL은 하위 수준 VTL을 대체합니다. VTL은 자체 메모리 액세스 권한을 설정할 수 없습니다.

규칙적인 인터페이스는 RAM을 통해 RAM이 아닌 형식을 오버레이하지 않을 것으로 예상됩니다.

메모리 액세스 위반

더 낮은 VTL에서 실행되는 VP가 더 높은 VTL에 의해 설정된 메모리 보호를 위반하려고 하면 인터셉트가 생성됩니다. 이 절편은 보호를 설정하는 더 높은 VTL에 의해 수신됩니다. 이렇게 하면 더 높은 VTL이 사례별로 위반을 처리할 수 있습니다. 예를 들어 VTL이 높을수록 오류를 반환하거나 액세스를 에뮬레이트하도록 선택할 수 있습니다.

모드 기반 실행 컨트롤(MBEC)

VTL이 낮은 VTL에 메모리 제한을 두는 경우 "실행" 권한을 부여할 때 사용자 모드와 커널 모드를 구분할 수 있습니다. 예를 들어 코드 무결성 검사가 더 높은 VTL에서 수행되는 경우 사용자 모드와 커널 모드를 구별하는 기능은 VTL이 커널 모드 애플리케이션에 대해서만 코드 무결성을 적용할 수 있음을 의미합니다.

MBEC는 기존의 세 가지 메모리 보호(읽기, 쓰기, 실행) 외에도 사용자 모드와 커널 모드를 구분하여 실행 보호를 제공합니다. 따라서 MBEC를 사용하도록 설정하면 VTL에서 다음 네 가지 유형의 메모리 보호를 설정할 수 있습니다.

Name Description
읽기 메모리 페이지에 대한 읽기 액세스가 허용되는지 여부를 제어합니다.
쓰기 메모리 페이지에 대한 쓰기 액세스 허용 여부를 제어합니다.
사용자 모드 실행(UMX) 메모리 페이지에 대해 사용자 모드에서 생성된 명령 페치를 허용할지 여부를 제어합니다. 참고: MBEC를 사용하지 않도록 설정하면 이 설정이 무시됩니다.
커널 모드 실행(UMX) 커널 모드에서 생성된 명령 인출이 메모리 페이지에 허용되는지 여부를 제어합니다. 참고: MBEC를 사용하지 않도록 설정한 경우 이 설정은 사용자 모드와 커널 모드 실행 액세스를 모두 제어합니다.

"사용자 모드 실행" 보호로 표시된 메모리는 가상 프로세서가 사용자 모드에서 실행되는 경우에만 실행될 수 있습니다. 마찬가지로 "커널 모드 실행" 메모리는 가상 프로세서가 커널 모드로 실행될 때만 실행될 수 있습니다.

KMX 및 UMX는 사용자 모드와 커널 모드 간에 실행 권한이 다르게 적용되도록 독립적으로 설정할 수 있습니다. KMX=1, UMX=0을 제외하고 UMX와 KMX의 모든 조합이 지원됩니다. 이 조합의 동작은 정의되지 않았습니다.

MBEC는 기본적으로 모든 VTL 및 가상 프로세서에 대해 사용하지 않도록 설정됩니다. MBEC를 사용하지 않도록 설정하면 커널 모드 실행 비트가 메모리 액세스 제한을 결정합니다. 따라서 MBEC를 사용하지 않도록 설정하면 KMX=1 코드는 커널 및 사용자 모드 모두에서 실행 가능합니다.

설명자 테이블

설명자 테이블에 액세스하는 모든 사용자 모드 코드는 KMX=UMX=1로 표시된 GPA 페이지에 있어야 합니다. KMX=0으로 표시된 GPA 페이지에서 설명자 테이블에 액세스하는 사용자 모드 소프트웨어는 지원되지 않으며 일반적인 보호 오류가 발생합니다.

MBEC 구성

모드 기반 실행 제어를 사용하려면 다음 두 수준에서 사용하도록 설정해야 합니다.

  1. 파티션에 대해 VTL을 사용하도록 설정한 경우 HvCallEnablePartitionVtl을 사용하여 MBEC를 사용하도록 설정해야 합니다.
  2. MBEC는 HvRegisterVsmVpSecureVtlConfig를 사용하여 VP 및 VTL별로 구성되어야 합니다.

SMEP(감독자 모드 실행 방지)와 MBEC 상호 작용

Supervisor-Mode 실행 방지(SMEP)는 일부 플랫폼에서 지원되는 프로세서 기능입니다. SMEP는 메모리 페이지에 대한 감독자 액세스 제한으로 인해 MBEC 작업에 영향을 미칠 수 있습니다. 하이퍼바이저는 SMEP와 관련된 다음 정책을 준수합니다.

  • SMEP를 게스트 OS에서 사용할 수 없는 경우(하드웨어 기능 또는 프로세서 호환성 모드 때문인지 여부) MBEC는 영향을 받지 않고 작동합니다.
  • SMEP를 사용할 수 있고 사용하도록 설정된 경우 MBEC는 영향을 받지 않고 작동합니다.
  • SMEP를 사용할 수 있고 사용하지 않도록 설정된 경우 모든 실행 제한은 KMX 컨트롤에 의해 제어됩니다. 따라서 KMX=1로 표시된 코드만 실행할 수 있습니다.

가상 프로세서 상태 격리

가상 프로세서는 각 활성 VTL에 대해 별도의 상태를 유지 관리합니다. 그러나 이 상태 중 일부는 특정 VTL에 비공개이며 나머지 상태는 모든 VTL 간에 공유됩니다.

VTL당 유지되는 상태(즉, 프라이빗 상태)는 VTL 전환에서 하이퍼바이저에 의해 저장됩니다. VTL 스위치가 시작되면 하이퍼바이저는 활성 VTL에 대한 현재 프라이빗 상태를 저장한 다음 대상 VTL의 프라이빗 상태로 전환합니다. 공유 상태는 VTL 스위치에 관계없이 활성 상태로 유지됩니다.

프라이빗 상태

일반적으로 각 VTL에는 자체 컨트롤 레지스터, RIP 레지스터, RSP 레지스터 및 MSR이 있습니다. 다음은 각 VTL에 비공개인 특정 레지스터 및 MSR의 목록입니다.

프라이빗 MSR:

  • SYSENTER_CS, SYSENTER_ESP, SYSENTER_EIP, STAR, LSTAR, CSTAR, SFMASK, EFER, PAT, KERNEL_GSBASE, FS. BASE, GS. BASE, TSC_AUX
  • HV_X64_MSR_HYPERCALL
  • HV_X64_MSR_GUEST_OS_ID
  • HV_X64_MSR_REFERENCE_TSC
  • HV_X64_MSR_APIC_FREQUENCY
  • HV_X64_MSR_EOI
  • HV_X64_MSR_ICR
  • HV_X64_MSR_TPR
  • HV_X64_MSR_APIC_ASSIST_PAGE
  • HV_X64_MSR_NPIEP_CONFIG
  • HV_X64_MSR_SIRBP
  • HV_X64_MSR_SCONTROL
  • HV_X64_MSR_SVERSION
  • HV_X64_MSR_SIEFP
  • HV_X64_MSR_SIMP
  • HV_X64_MSR_EOM
  • HV_X64_MSR_SINT0 – HV_X64_MSR_SINT15
  • HV_X64_MSR_STIMER0_CONFIG – HV_X64_MSR_STIMER3_CONFIG
  • HV_X64_MSR_STIMER0_COUNT – HV_X64_MSR_STIMER3_COUNT
  • 로컬 APIC 레지스터(CR8/TPR 포함)

프라이빗 레지스터:

  • RIP, RSP
  • RFLAGS
  • CR0, CR3, CR4
  • DR7
  • IDTR, GDTR
  • CS, DS, ES, FS, GS, SS, TR, LDTR
  • TSC
  • DR6(*프로세서 유형에 따라 다릅니다. 공유/프라이빗 상태를 확인하려면 HvRegisterVsmCapabilities 가상 레지스터를 읽습니다.

공유 상태

VTL은 컨텍스트 전환의 오버헤드를 줄이기 위해 상태를 공유합니다. 상태를 공유하면 VTL 간에 필요한 통신도 가능합니다. 대부분의 범용 및 부동 소수점 레지스터는 대부분의 아키텍처 MSR과 마찬가지로 공유됩니다. 다음은 모든 VTL 간에 공유되는 특정 MSR 및 레지스터 목록입니다.

공유 MSR:

  • HV_X64_MSR_TSC_FREQUENCY
  • HV_X64_MSR_VP_INDEX
  • HV_X64_MSR_VP_RUNTIME
  • HV_X64_MSR_RESET
  • HV_X64_MSR_TIME_REF_COUNT
  • HV_X64_MSR_GUEST_IDLE
  • HV_X64_MSR_DEBUG_DEVICE_OPTIONS
  • MTRR
  • MCG_CAP
  • MCG_STATUS

공유 레지스터:

  • Rax, Rbx, Rcx, Rdx, Rsi, Rdi, Rbp
  • CR2
  • R8 – R15
  • DR0 – DR5
  • X87 부동 소수점 상태
  • XMM 상태
  • AVX 상태
  • XCR0(XFEM)
  • DR6(*프로세서 유형에 따라 다릅니다. 공유/프라이빗 상태를 확인하려면 HvRegisterVsmCapabilities 가상 레지스터를 읽습니다.

실제 모드

0보다 큰 VTL에는 실제 모드가 지원되지 않습니다. 0보다 큰 VTL은 32비트 또는 64비트 모드에서 실행할 수 있습니다.

VTL 인터럽트 관리

가상 신뢰 수준 간에 높은 수준의 격리를 달성하기 위해 가상 보안 모드는 가상 프로세서에서 사용하도록 설정된 각 VTL에 대해 별도의 인터럽트 하위 시스템을 제공합니다. 이렇게 하면 VTL이 덜 안전한 VTL의 간섭 없이 인터럽트를 보내고 받을 수 있습니다.

각 VTL에는 가상 프로세서가 해당 특정 VTL에서 실행되는 경우에만 활성화되는 자체 인터럽트 컨트롤러가 있습니다. 가상 프로세서가 VTL 상태를 전환하면 프로세서에서 활성 상태인 인터럽트 컨트롤러도 전환됩니다.

활성 VTL보다 높은 VTL을 대상으로 하는 인터럽트는 즉시 VTL 스위치를 발생합니다. 그러면 VTL이 높을수록 인터럽트를 받을 수 있습니다. 높은 VTL이 TPR/CR8 값으로 인해 인터럽트를 받을 수 없는 경우 인터럽트는 "보류 중"으로 유지되고 VTL은 전환되지 않습니다. 보류 중인 인터럽트가 있는 VTL이 여러 개 있는 경우 가장 높은 VTL이 우선합니다(낮은 VTL에 예고 없이).

인터럽트가 낮은 VTL을 대상으로 하는 경우 다음에 가상 프로세서가 대상 VTL로 전환될 때까지 인터럽트가 전달되지 않습니다. 더 낮은 VTL을 대상으로 하는 INIT 및 시작 IPI는 더 높은 VTL을 사용하도록 설정된 가상 프로세서에서 삭제됩니다. INIT/SIPI가 차단되었으므로 HvCallStartVirtualProcessor 하이퍼콜을 사용하여 프로세서를 시작해야 합니다.

RFLAGS. 경우

VTL을 전환하기 위해 RFLAGS. IF는 보안 인터럽트가 VTL 스위치를 트리거하는지 여부에 영향을 주지 않습니다. RFLAGS인 경우 인터럽트를 마스킹하기 위해 지워진 경우 더 높은 VTL로의 인터럽트는 여전히 VTL을 더 높은 VTL로 전환합니다. 즉시 중단할지 여부를 결정할 때 더 높은 VTL의 TPR/CR8 값만 고려됩니다.

이 동작은 VTL 반환 시 보류 중인 인터럽트에도 영향을 줍니다. RFLAGS인 경우 지정된 VTL에서 인터럽트를 마스킹하기 위해 비트가 지워지고 VTL이 더 낮은 VTL로 반환되면 하이퍼바이저는 보류 중인 인터럽트를 다시 평가합니다. 이로 인해 더 높은 VTL에 대한 즉각적인 호출이 발생합니다.

가상 인터럽트 알림 지원

더 높은 VTL은 동일한 가상 프로세서의 하위 VTL에 대한 인터럽트 즉시 배달을 차단하는 경우 알림을 수신하도록 등록할 수 있습니다. VTL이 높을수록 가상 레지스터 HvRegisterVsmVina를 통해 VINA(가상 인터럽트 알림 지원)를 사용하도록 설정할 수 있습니다.

typedef union
{
    UINT64 AsUINT64;
    struct
    {
        UINT64 Vector : 8;
        UINT64 Enabled : 1;
        UINT64 AutoReset : 1;
        UINT64 AutoEoi : 1;
        UINT64 ReservedP : 53;
    };
} HV_REGISTER_VSM_VINA;

각 VP의 각 VTL에는 고유한 VINA 인스턴스와 자체 버전의 HvRegisterVsmVina가 있습니다. VINA 기능은 낮은 VTL에 대한 인터럽트가 즉시 배달될 준비가 되면 현재 활성 상태의 상위 VTL에 대한 에지 트리거 인터럽트를 생성합니다.

이 시설이 활성화될 때 발생하는 인터럽트 홍수를 방지하기 위해 VINA 시설에는 일부 제한된 상태가 포함됩니다. VINA 인터럽트를 생성하면 VINA 시설의 상태가 "Asserted"로 변경됩니다. VINA 시설과 연결된 SINT에 인터럽트 종료를 보내면 "어설션됨" 상태가 지워지지 않습니다. 어설션된 상태는 다음 두 가지 방법 중 하나로만 지울 수 있습니다.

  1. HV_VP_VTL_CONTROL 구조체 의 VinaAsserted 필드에 쓰면 상태를 수동으로 지울 수 있습니다.
  2. HvRegisterVsmVina 레지스터에서 "VTL 항목에서 자동 재설정" 옵션을 사용하도록 설정하면 VTL의 다음 항목에서 상태가 자동으로 지워집니다.

이렇게 하면 보안 VTL에서 실행되는 코드가 낮은 VTL에 대해 수신된 첫 번째 인터럽트에 대한 알림을 받을 수 있습니다. 보안 VTL이 추가 인터럽트에 대한 알림을 받고자 하는 경우 VP 지원 페이지의 VinaAsserted 필드를 지울 수 있으며 다음 새 인터럽트에 대한 알림이 표시됩니다.

보안 인터셉트

하이퍼바이저를 사용하면 더 높은 VTL이 더 낮은 VTL의 컨텍스트에서 발생하는 이벤트에 대한 인터셉트를 설치할 수 있습니다. 이렇게 하면 더 높은 VTL에서 하위 VTL 리소스에 대한 높은 수준의 제어를 제공합니다. 보안 인터셉트는 시스템 중요 리소스를 보호하고 낮은 VTL의 공격을 방지하는 데 사용할 수 있습니다.

보안 인터셉트는 더 높은 VTL에 큐에 대기되고 VTL은 VP에서 실행 가능하게 만들어집니다.

보안 인터셉트 형식

인터셉트 유형 인터셉트 적용 대상
메모리 액세스 더 높은 VTL에서 설정한 GPA 보호에 액세스하려고 시도합니다.
레지스터 액세스 제어 더 높은 VTL에서 지정한 컨트롤 레지스터 집합에 액세스하려고 시도합니다.

중첩된 인터셉트

여러 VTL은 낮은 VTL에서 동일한 이벤트에 대한 보안 인터셉트를 설치할 수 있습니다. 따라서 중첩된 인터셉트가 알림을 받을 위치를 결정하기 위한 계층 구조가 설정됩니다. 다음 목록은 인터셉트에 알림이 표시되는 순서입니다.

  1. 하위 VTL
  2. 상위 VTL

보안 인터셉트 처리

VTL에 보안 인터셉트에 대한 알림이 표시되면 하위 VTL을 계속할 수 있도록 조치를 취해야 합니다. VTL이 높을수록 예외 삽입, 액세스 에뮬레이트 또는 액세스에 프록시 제공을 비롯한 다양한 방법으로 인터셉트를 처리할 수 있습니다. 어쨌든 하위 VTL VP의 프라이빗 상태를 수정해야 하는 경우 HvCallSetVpRegisters를 사용해야 합니다.

보안 레지스터 인터셉트

VTL이 높을수록 특정 컨트롤 레지스터에 대한 액세스를 가로챌 수 있습니다. HvCallSetVpRegisters 하이퍼콜을 사용하여 HvX64RegisterCrInterceptControl을 설정하여 이 작업을 수행합니다. HvX64RegisterCrInterceptControl에서 컨트롤 비트를 설정하면 해당 컨트롤 레지스터의 모든 액세스에 대한 인터셉트가 트리거됩니다.

typedef union
{
    UINT64 AsUINT64;
    struct
    {
        UINT64 Cr0Write : 1;
        UINT64 Cr4Write : 1;
        UINT64 XCr0Write : 1;
        UINT64 IA32MiscEnableRead : 1;
        UINT64 IA32MiscEnableWrite : 1;
        UINT64 MsrLstarRead : 1;
        UINT64 MsrLstarWrite : 1;
        UINT64 MsrStarRead : 1;
        UINT64 MsrStarWrite : 1;
        UINT64 MsrCstarRead : 1;
        UINT64 MsrCstarWrite : 1;
        UINT64 ApicBaseMsrRead : 1;
        UINT64 ApicBaseMsrWrite : 1;
        UINT64 MsrEferRead : 1;
        UINT64 MsrEferWrite : 1;
        UINT64 GdtrWrite : 1;
        UINT64 IdtrWrite : 1;
        UINT64 LdtrWrite : 1;
        UINT64 TrWrite : 1;
        UINT64 MsrSysenterCsWrite : 1;
        UINT64 MsrSysenterEipWrite : 1;
        UINT64 MsrSysenterEspWrite : 1;
        UINT64 MsrSfmaskWrite : 1;
        UINT64 MsrTscAuxWrite : 1;
        UINT64 MsrSgxLaunchControlWrite : 1;
        UINT64 RsvdZ : 39;
    };
} HV_REGISTER_CR_INTERCEPT_CONTROL;

마스크 레지스터

더 세부적인 제어를 위해 컨트롤 레지스터의 하위 집합에는 해당 마스크 레지스터도 있습니다. 마스크 레지스터는 해당 컨트롤 레지스터의 하위 집합에 인터셉트를 설치하는 데 사용할 수 있습니다. 마스크 레지스터가 정의되지 않은 경우 모든 액세스(HvX64RegisterCrInterceptControl로 정의됨)가 인터셉트를 트리거합니다.

하이퍼바이저는 HvX64RegisterCrInterceptCr0Mask, HvX64RegisterCrInterceptCr4Mask 및 HvX64RegisterCrInterceptIa32MiscEnableMask 마스크 레지스터를 지원합니다.

DMA 및 디바이스

디바이스는 VTL0과 동일한 권한 수준을 효과적으로 갖습니다. VSM을 사용하도록 설정하면 디바이스에서 할당한 모든 메모리가 VTL0으로 표시됩니다. 모든 DMA 액세스는 VTL0과 동일한 권한을 갖습니다.