Виртуальный безопасный режим

Виртуальный безопасный режим (VSM) — это набор возможностей гипервизора и просвещения, предлагаемых узлам и гостевым секциям, что позволяет создавать и управлять новыми границами безопасности в программном обеспечении операционной системы. VSM — это средство гипервизора, на котором основаны функции безопасности Windows, включая Device Guard, Credential Guard, виртуальные машины и экранированные виртуальные машины. Эти функции безопасности появились в Windows 10 и Windows Server 2016.

VSM позволяет программному обеспечению операционной системы в корневых и гостевых секциях создавать изолированные регионы памяти для хранения и обработки системных ресурсов безопасности. Доступ к этим изолированным регионам контролируется и предоставляется исключительно через гипервизор, который является высоко привилегированной, высоконадежной частью доверенной вычислительной базы системы (TCB). Так как гипервизор выполняется на более высоком уровне привилегий, чем программное обеспечение операционной системы, и имеет монопольный контроль над основными аппаратными ресурсами системы, такими как управление доступом к памяти в ЦП MMU и IOMMU в начале инициализации системы, гипервизор может защитить эти изолированные регионы от несанкционированного доступа, даже от программного обеспечения операционной системы (например, драйверов ядра ОС и устройств) с доступом к режиму управления (т. е. CPL0, или "Кольцо 0").

Эта архитектура, даже если обычное программное обеспечение уровня системы, работающее в режиме руководителя (например, ядро, драйверы и т. д.), скомпрометировано вредоносным программным обеспечением, ресурсы в изолированных регионах, защищенных гипервизором, могут оставаться защищенными.

Виртуальный уровень доверия (VTL)

VSM обеспечивает и поддерживает изоляцию с помощью виртуальных уровней доверия (VTLs). Виртуальные таблицы включены и управляются как для каждого раздела, так и для каждого виртуального процессора.

Уровни виртуального доверия являются иерархическими, а более высокие уровни являются более привилегированными, чем более низкие. VTL0 является наименее привилегированным уровнем, при этом VTL1 является более привилегированным, чем VTL0, VTL2 является более привилегированным, чем VTL1 и т. д.

Архитектурно поддерживаются до 16 уровней виртуальных списков. однако гипервизор может выбрать реализацию менее 16 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. Например, VTL0 может хранить секрет в VTL1, на котором доступ к нему может получить только VTL1. Даже если VTL0 скомпрометирован, секрет будет безопасным.

Защита VTL

Существует несколько аспектов для обеспечения изоляции между виртуальными сетями:

  • Защита доступа к памяти: каждый VTL поддерживает набор защиты доступа к гостевой физической памяти. Программное обеспечение, работающее в определенном VTL, может получить доступ только к памяти в соответствии с этими средствами защиты.
  • Состояние виртуального процессора: виртуальные процессоры поддерживают отдельное состояние на VTL. Например, каждый VTL определяет набор частных регистров VP. Программное обеспечение, работающее на более низком уровне VTL, не может получить доступ к состоянию регистрации частного виртуального процессора более высокого уровня VTL.
  • Прерывания: наряду с отдельным состоянием процессора каждый VTL также имеет собственную подсистему прерываний (локальный APIC на x64, интерфейс ЦП GIC в ARM64). Это позволяет более высоким виртуальным сетям обрабатывать прерывания без риска вмешательства из более низкого уровня VTL.
  • Страницы наложения. Некоторые страницы наложения поддерживаются на уровне VTL, чтобы более высокие виртуальные списки имели надежный доступ. Например, существует отдельная страница гиперкласти наложения на VTL.

Обнаружение и состояние VSM

Функция VSM объявляется для секций с помощью флага привилегий секции AccessVsm. Только секции со всеми следующими привилегиями могут использовать VSM: AccessVsm, AccessVpRegisters и AccessSynicRegisters.

Обнаружение возможностей VSM

Гости могут получить доступ к отчету о возможностях VSM с помощью искусственного регистра.

На платформах x64

На платформах x64 этот реестр осуществляется через MSR:

АДРЕС MSR Имя регистрации Description
0x000D0006 HV_X64_REGISTER_VSM_CAPABILITIES Отчет о возможностях VSM.

На платформах ARM64

На платформах ARM64 этот регистр осуществляется через HvRegisterVsmCapabilities с помощью гиперклистеров HvCallGetVpRegisters.

Формат регистрации

На платформах x64

Биты Description Attributes
63 Dr6Shared Читайте
62:47 MbecVtlMask Читайте
46 DenyLowerVtlStartup Читайте
45:0 RsvdZ Читайте

На платформах ARM64

Биты Description Attributes
63 RsvdZ Читайте
62:47 MbecVtlMask Читайте
46 DenyLowerVtlStartup Читайте
45:0 RsvdZ Читайте

Описания полей

Dr6Shared (только x64): указывает, является ли dr6 общим регистром между виртуальными библиотеками.

MbecVtlMask: указывает гостевым виртуальным спискам, для которых можно включить MBEC.

DenyLowerVtlStartup: указывает на гостя, может ли VTL запретить сброс VP на более низком VTL.

Регистрация состояния VSM

Помимо флага привилегий секции, можно использовать два виртуальных регистра для получения дополнительных сведений о состоянии VSM: HvRegisterVsmPartitionStatus и HvRegisterVsmVpStatus.

HvRegisterVsmPartitionStatus

HvRegisterVsmPartitionStatus — это регистр только для чтения для секций, общий для всех виртуальных списков. Этот регистр содержит сведения о том, какие виртуальные библиотеки включены для секции, в которых списки виртуальных списков включены элементы управления выполнением на основе режима, а также максимальный допустимый 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 — это регистр только для чтения и общий доступ ко всем виртуальным спискам. Это регистр каждого VP, то есть каждый виртуальный процессор поддерживает свой собственный экземпляр. Этот регистр содержит сведения о том, какие виртуальные библиотеки включены, а также активный режим MBEC в VP.

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, активного в настоящее время на виртуальном процессоре.

ActiveMbecEnabled указывает, что MBEC в настоящее время активен на виртуальном процессоре.

EnabledVtlSet — это точечный рисунок виртуальных сетей, которые включены на виртуальном процессоре.

Начальное состояние секции VTL

При запуске или сбросе секции начинается в VTL0. Все остальные виртуальные библиотеки отключены при создании секции.

Включение VTL

Чтобы начать использование VTL, более низкий уровень VTL должен инициировать следующее:

  1. Включите целевой VTL для секции. Это делает VTL общедоступным для секции.
  2. Включите целевой VTL на одном или нескольких виртуальных процессорах. Это делает VTL доступным для VP и задает его начальный контекст. Рекомендуется, чтобы все виртуальные машины имели одинаковые виртуальные сети с поддержкой. Включение VTL на некоторых виртуальных машинах (но не все) может привести к неожиданному поведению.
  3. После включения VTL для секции и VP он может начать настройку защиты доступа после установки флага EnableVtlProtection.

Обратите внимание, что виртуальные библиотеки не должны быть последовательными.

Включение целевого VTL для секции

Гиперклимент HvCallEnablePartitionVtl используется для включения VTL для определенной секции. Обратите внимание, что до фактического выполнения программного обеспечения в определенном VTL необходимо включить VTL на виртуальных процессорах в разделе.

Включение целевого VTL для виртуальных процессоров

После включения VTL для секции его можно включить на виртуальных процессорах секции. Гиперколл HvCallEnableVpVtl можно использовать для включения виртуальных списков для виртуального процессора, который задает его начальный контекст.

Виртуальные процессоры имеют один "context" на VTL. Если параметр VTL переключится, частное состояние VTL также переключается.

Конфигурация VTL

После включения VTL его конфигурация может быть изменена VP, выполняющейся в равной или более поздней версии VTL.

Конфигурация секции

Атрибуты на уровне секций можно настроить с помощью регистра HvRegisterVsmPartitionConfig. Существует один экземпляр этого регистра для каждого VTL (больше 0) для каждой секции.

Каждый VTL может изменять собственный экземпляр HV_REGISTER_VSM_PARTITION_CONFIG, а также экземпляры для более низких виртуальных списков. Виртуальные библиотеки могут не изменять этот регистр для более высоких виртуальных списков.

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 может задать другую политику защиты памяти по умолчанию, указав DefaultVtlProtectionMask в HV_REGISTER_VSM_PARTITION_CONFIG. Эта маска должна быть задана во время включения VTL. Его нельзя изменить после установки и очистить только с помощью сброса секции.

Бит Description
0 Читайте
1 Напишите
2 Выполнение режима ядра (KMX)
3 Выполнение режима пользователя (UMX)

Нулевая память при сбросе

ZeroMemOnReset — это бит, который определяет, если память отсчитывается до сброса секции. Эта конфигурация включена по умолчанию. Если бит задан, память секции ноль при сбросе, чтобы более высокая память VTL не скомпрометирована более низкой VTL. Если этот бит очищается, память секции не обнуляется при сбросе.

DenyLowerVtlStartup

Флаг DenyLowerVtlStartup, если виртуальный процессор может быть запущен или сбросен с помощью более низких виртуальных списков. К ним относятся архитектурные способы сброса виртуального процессора (например, SIPI на X64), а также гиперклюзив HvCallStartVirtualProcessor .

InterceptVpStartup

Если установлен флаг InterceptVpStartup, запуск или сброс виртуального процессора создает перехват на более высокий уровень 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

Это поле настраивает, включена ли MBEC для нижнего VTL.

TlbLocked

Это поле блокирует TLB нижнего уровня VTL. Эту возможность можно использовать для предотвращения снижения количества виртуальных столов, вызывающих недопустимую балансировку нагрузки, которая может повлиять на более высокий уровень VTL. При установке этого бита все запросы на очистку пространства адресов от нижнего VTL блокируются до тех пор, пока блокировка не будет снята.

Чтобы разблокировать TLB, более высокий уровень VTL может очистить этот бит. Кроме того, когда VP возвращается в более низкую виртуальную нагрузку, он освобождает все блокировки TLB, которые он хранит в то время.

Запись VTL

VTL вводится, когда VP переключается с нижнего уровня VTL на более высокий. Это может произойти по следующим причинам:

  1. Вызов VTL: это происходит, когда программное обеспечение явно хочет вызвать код в более высоком VTL.
  2. Безопасное прерывание: если прерывание получено для более высокого уровня VTL, VP введет более высокий уровень VTL.
  3. Безопасный перехват: некоторые действия активируют безопасный прерываний (например, доступ к определенным MSR).

После ввода VTL он должен добровольно выйти. Более высокий уровень VTL не может быть преумножен более низким значением VTL.

Определение причины записи VTL

Чтобы соответствующим образом реагировать на запись, может потребоваться более высокий уровень VTL, чтобы узнать причину, по которой она была введена. Чтобы различать причины входа, запись VTL включается в структуру HV_VP_VTL_CONTROL .

Вызов VTL

Вызов VTL — это когда нижний VTL инициирует запись в более высокий уровень VTL (например, для защиты области памяти с более высоким значением VTL) через гиперквал HvCallVtlCallCall.

Вызовы VTL сохраняют состояние общих регистров в коммутаторах VTL. Частные регистры сохраняются на уровне VTL. Исключением из этих ограничений являются регистры и инструкции, необходимые последовательности вызовов VTL.

На платформах x64

Для вызова VTL на x64 требуются следующие регистры:

х64 x86 Description
RCX EDX:EAX Указывает входные данные элемента управления вызовами VTL в гипервизор
RAX ECX Зарезервировано

Все биты в входных данных управления вызовами VTL в настоящее время зарезервированы.

На платформах ARM64

На платформах ARM64 вызов VTL инициируется с помощью инструкции HVC с немедленным значением 2. Гипервизор декодирует это конкретное немедленное значение и обрабатывает его как гиперклюв HvCallVtlCall. Для входных данных элемента управления в ARM64 не требуется определенное состояние регистра.

Ограничения вызовов VTL

Вызовы VTL можно инициировать только из наиболее привилегированного режима процессора. Например, в системах x64 вызов VTL может поступать только из CPL0 и в системах ARM64 из EL1. Вызов VTL, инициированный в режиме процессора, который является любым, кроме наиболее привилегированным в системе, приводит к внедрению исключения в виртуальный процессор (#UD в x64, неопределенное исключение инструкций в ARM64).

Вызов VTL может переключаться только на следующий самый высокий уровень VTL. Другими словами, если включено несколько виртуальных списков, вызов не может пропускать VTL. Следующие действия приводят к исключению (#UD в x64, неопределенной инструкции по ARM64):

  • Вызов 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.

На платформах x64

Для последовательности возвращаемого кода VTL в x64 требуется использование следующих регистров:

х64 x86 Description
RCX EDX:EAX Указывает входные данные возвращаемого элемента управления VTL в гипервизор
RAX ECX Зарезервировано

На платформах ARM64

На платформах ARM64 возврат VTL инициируется с помощью инструкции HVC с немедленным значением 3. Гипервизор декодирует это конкретное немедленное значение и обрабатывает его как гиперквал HvCallVtlReturn.

Входные данные возвращаемого элемента управления VTL

Входные данные возвращаемого элемента управления VTL имеют следующий формат:

Биты Поле Description
63:1 RsvdZ
0 Быстрый возврат Регистры не восстанавливаются

Следующие действия создают исключение #UD:

  • Попытка возврата VTL, когда самый низкий уровень VTL в настоящее время активен
  • Попытка возврата VTL с недопустимым значением входного элемента управления
  • Попытка возврата VTL из режима процессора, который является любым, кроме наиболее привилегированным в системе (архитектура конкретной)

Быстрый возврат

В рамках обработки возврата гипервизор может восстановить состояние регистра нижнего уровня VTL из структуры HV_VP_VTL_CONTROL . Например, после обработки безопасного прерывания более высокий уровень VTL может потребоваться вернуться без нарушения состояния нижнего уровня VTL. Таким образом, гипервизор предоставляет механизм для простого восстановления регистров нижнего уровня VTL до их предварительного вызова, хранящегося в структуре управления VTL.

Если такое поведение не требуется, более высокий уровень VTL может использовать "быстрый возврат". Быстрое возвращение заключается в том, что гипервизор не восстанавливает состояние регистра из структуры управления. Это следует использовать всякий раз, когда это возможно, чтобы избежать ненужных операций обработки.

Это поле можно задать с битом 0 возвращаемого входного значения VTL. Если задано значение 0, регистры восстанавливаются из структуры HV_VP_VTL_CONTROL. Если для этого бита задано значение 1, регистры не восстанавливаются (быстрый возврат).

Поддержка страницы Hypercall (только x64)

На платформах x64 гипервизор предоставляет механизмы для поддержки вызовов VTL и возврата с помощью страницы гиперкела. Эта страница абстрагирует определенную последовательность кода, необходимую для переключения виртуальных списков.

К последовательности кода для выполнения вызовов и возврата VTL можно получить путем выполнения определенных инструкций на странице гиперкела. Блоки вызова и возврата находятся на смещение на странице гиперклава, определяемой виртуальным регистром HvRegisterVsmCodePageOffsets. Это регистр только для чтения и секционирования с отдельным экземпляром для каждого VTL.

VTL может выполнять вызов или возврат VTL с помощью инструкции CALL. Вызов к правильному расположению на странице гиперкела инициирует вызов или возврат VTL.

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

Чтобы свести к сводные данные, действия по вызову последовательности кода с помощью страницы гиперкаллов на x64 приведены следующим образом:

  1. Сопоставление страницы гиперкваля с пространством GPA VTL
  2. Определите правильное смещение для последовательности кода (вызов или возврат VTL).
  3. Выполните последовательность кода с помощью CALL.

Примечание: На платформах ARM64 вызовы и возвраты VTL выполняются непосредственно с помощью инструкции HVC с определенными непосредственными значениями (2 для вызова VTL, 3 для возврата VTL), как описано в разделах обратного вызова VTL и VTL Return. Регистрация HvRegisterVsmCodePageOffsets недоступна в ARM64.

Защита доступа к памяти

Одной из необходимых защит, предоставляемых VSM, является возможность изоляции доступа к памяти.

Более высокие виртуальные библиотеки имеют высокий уровень контроля над типом доступа к памяти, допустимым для более низких виртуальных списков. Существует три основных типа защиты, которые можно указать с помощью более высокого уровня VTL для конкретной страницы GPA: чтение, запись и eXecute. Они определены в следующей таблице:

Имя Description
Читайте Определяет, разрешен ли доступ на чтение на страницу памяти
Напишите Определяет, разрешен ли доступ на запись на страницу памяти
Execute Определяет, разрешены ли выборки инструкций для страницы памяти.

Эти три объединяются для следующих типов защиты памяти:

  1. Нет доступа
  2. Только для чтения, выполнение не выполняется
  3. Только для чтения, выполнение
  4. Чтение и запись, без выполнения
  5. Чтение и запись, выполнение

Если включен параметр "Управление выполнением на основе режима (MBEC)", то можно настроить защиту в режиме пользователя и ядра отдельно.

Более высокие виртуальные библиотеки могут задать защиту памяти для GPA через гиперклюв HvCallModifyVtlProtectionMask .

Иерархия защиты памяти

Разрешения доступа к памяти можно задать несколькими источниками для определенного VTL. Разрешения каждого VTL могут быть ограничены рядом других виртуальных списков, а также разделом узла. Порядок применения защиты выполняется следующим образом:

  1. Защита памяти, заданная узлом
  2. Защита памяти, заданная более высокими виртуальными библиотеками

Другими словами, защита VTL заменяет защиту узлов. Более высокий уровень виртуальных библиотек заменяет виртуальные списки более низкого уровня. Обратите внимание, что VTL не может задавать для себя разрешения доступа к памяти.

Ожидается, что соответствующий интерфейс не будет перекрывать тип, отличный от ОЗУ.

Нарушения доступа к памяти

Если VP, работающий на более низком уровне VTL, пытается нарушить защиту памяти, заданную более высоким значением VTL, создается перехват. Этот перехват получается более высоким значением VTL, который задает защиту. Это позволяет более высоким виртуальным сетям справиться с нарушением на основе случаев. Например, более высокий уровень VTL может возвращать ошибку или эмулировать доступ.

Элемент управления выполнением на основе режима (MBEC)

Если VTL помещает ограничение памяти на более низкое значение VTL, при предоставлении привилегий "выполнить" может потребоваться различие между режимом пользователя и ядра. Например, если проверка целостности кода выполнялась в более высоком уровне VTL, возможность различать режим пользователя и режим ядра будет означать, что VTL может применять целостность кода только для приложений в режиме ядра.

Помимо традиционных трех защиты памяти (чтение, запись, выполнение), MBEC представляет различие между пользовательским режимом и режимом ядра для выполнения защиты. Таким образом, если MBEC включен, VTL имеет возможность задать четыре типа защиты памяти:

Имя Description
Читайте Определяет, разрешен ли доступ на чтение на страницу памяти
Напишите Определяет, разрешен ли доступ на запись на страницу памяти
Выполнение режима пользователя (UMX) Определяет, разрешено ли получение инструкций в пользовательском режиме для страницы памяти. ПРИМЕЧАНИЕ. Если MBEC отключен, этот параметр игнорируется.
Выполнение режима ядра (KMX) Определяет, разрешено ли получение инструкций в режиме ядра для страницы памяти. ПРИМЕЧАНИЕ. Если MBEC отключен, этот параметр управляет доступом как в пользовательском режиме, так и в режиме ядра.

Память, помеченная защитой "User-Mode Execute", будет выполняться только в том случае, если виртуальный процессор работает в пользовательском режиме. Аналогичным образом памятьKernel-Mode Execute будет выполняться только в том случае, если виртуальный процессор работает в режиме ядра.

KMX и UMX могут быть независимо заданы таким образом, что разрешения на выполнение применяются по-разному между режимом пользователя и ядра. Поддерживаются все сочетания UMX и KMX, за исключением KMX=1, UMX=0. Поведение этого сочетания не определено.

MBEC отключен по умолчанию для всех виртуальных списков и виртуальных процессоров. При отключении MBEC бит выполнения в режиме ядра определяет ограничение доступа к памяти. Таким образом, если MBEC отключен, код KMX=1 выполняется как в ядре, так и в пользовательском режиме.

Таблицы дескриптора (только x64)

На платформах x64 любой код пользовательского режима, который обращается к таблицам дескриптора, должен находиться на страницах GPA, помеченных как KMX=UMX=1. Программное обеспечение для доступа к таблицам дескриптора в режиме пользователя со страницы GPA, помеченной KMX=0, не поддерживается и приводит к общему сбою защиты.

ARM64 не использует таблицы дескриптора в стиле x86; Разрешения доступа к памяти управляются с помощью записей таблицы перевода и модели привилегий на основе EL.

Конфигурация MBEC

Чтобы использовать элемент управления выполнением на основе режима, его необходимо включить на двух уровнях:

  1. Если VTL включен для секции, MBEC необходимо включить с помощью HvCallEnablePartitionVtl
  2. MBEC необходимо настроить на основе каждого VP и каждого VTL с помощью HvRegisterVsmVpSecureConfigVtlX.

Взаимодействие MBEC с предотвращением выполнения режима руководителя (SMEP) (только x64)

Supervisor-Mode Предотвращение выполнения (SMEP) — это функция процессора, поддерживаемая на платформах x64. SMEP может повлиять на работу MBEC из-за ограничения доступа руководителя к страницам памяти. Гипервизор соответствует следующим политикам, связанным с SMEP:

  • Если SMEP недоступен гостевой ОС (будь то из-за возможностей оборудования или режима совместимости процессора), MBEC работает без изменений.
  • Если SMEP доступен и включен, MBEC работает без изменений.
  • Если SMEP доступен и отключен, все ограничения выполнения управляются элементом управления KMX. Таким образом, будет разрешено выполнять только код, помеченный KMX=1.

Изоляция состояния виртуального процессора

Виртуальные процессоры поддерживают отдельные состояния для каждого активного VTL. Однако некоторые из этих состояний являются частными для определенного VTL, а остальные состояния являются общими для всех виртуальных списков.

Гипервизор поддерживает контекст каждого VTL для каждого виртуального процессора, сохраняя все состояние видимого гостевого процессора, которое должно быть изолировано между виртуальными библиотеками. Каждый VTL имеет собственный экземпляр частного состояния, включая регистры элементов управления, векторы исключений, регистры конфигурации системы и регистры искусственного гипервизора. Это хранилище на уровне VTL обеспечивает полную изоляцию контекста выполнения при переключении между уровнями доверия.

Состояние, которое сохраняется на VTL (a.k.a. частное состояние), сохраняется гипервизором в переходах VTL. Если коммутатор VTL инициируется, гипервизор сохраняет текущее частное состояние для активного VTL, а затем переключается на частное состояние целевого VTL. Общее состояние остается активным независимо от коммутаторов VTL.

Частное государство

Каждый VTL поддерживает собственный полный контекст выполнения, состоящий из следующих элементов:

  • Состояние выполнения: указатель инструкций (PC/RIP), указатель стека (SP/RSP), флаги процессора (PSTATE/RFLAGS)
  • Регистры элементов управления: конфигурация управления памятью (таблицы страницы, элементы управления переводом, атрибуты памяти)
  • Обработка исключений: векторы исключений и прерывания, регистры синдрома исключений, регистры адресов сбоя
  • Системная конфигурация: элементы управления функциями процессора, элементы управления отладки, настройка таймера
  • Искусственные регистры: интерфейс гипервизора регистрируется для каждого VTL (страница гиперкаллов, идентификатор гостевой ОС, ссылка на TSC, искусственный контроллер прерываний)

Эта изоляция гарантирует, что каждый VTL имеет независимый контроль над средой выполнения и не может наблюдать или вмешиваться в частное состояние других виртуальных списков.

На платформах x64

На платформах x64 каждый VTL поддерживает собственный контекст выполнения с помощью параметров MSR и регистров, относящихся к архитектуре. Гипервизор сохраняет их в коммутаторах VTL, обеспечивая полную изоляцию среды выполнения.

Механизмы вызова системы управления частными MSR , атрибуты памяти, функции процессора и интерфейс гипервизора.

Архитектурные MSR:

  • SYSENTER_CS, SYSENTER_ESP, SYSENTER_EIP, STAR, LSTAR, CSTAR, SFMASK, EFER, PAT, KERNEL_GSBASE, FS. BASE, GS. BASE, TSC_AUX
  • Локальные регистры APIC (включая CR8/TPR)

Искусственные MSR:

  • 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_VP_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

Частные регистры управляют средой выполнения, управлением памятью и обработкой исключений:

  • Состояние выполнения: RIP (указатель инструкции), RSP (указатель стека), RFLAGS (флаги процессора)
  • Управление памятью: CR0 (управление процессором), CR3 (базовая таблица страницы), CR4 (функции процессора)
  • Таблицы дескриптора: IDTR (таблица дескриптора прерываний), GDTR (глобальная таблица дескриптора)
  • Регистры сегментов: CS, DS, ES, FS, GS, SS, TR, LDTR
  • Элемент управления отладки: DR7 (регистр элемента управления отладки)
  • Метка времени: TSC (счетчик меток времени, предоставление независимой ссылки на время на VTL)
  • Состояние отладки: DR6 (регистр состояния отладки , зависящий от типа процессора; чтение HvRegisterVsmCapabilities, чтобы определить, является ли общий или закрытый)

На платформах ARM64

На платформах ARM64 каждый VTL поддерживает собственный полный контекст системного регистра. Гипервизор сохраняет эти регистры в коммутаторах VTL, обеспечивая полную изоляцию среды выполнения и исключения.

Регистры состояния выполнения управляют потоком программы и режимом процессора:

  • PC (счетчик программы), SP_EL0, SP_EL1 (указатели стека)
  • PSTATE (флаги состояния процессора), FPCR/FPSR (элемент управления и состояние с плавающей запятой)
  • ELR_EL1, SPSR_EL1 (регистрация ссылки исключения, состояние сохраненной программы)

Регистры управления памятью и переводом настраивают виртуальную память:

  • TTBR0_EL1, TTBR1_EL1 (базовые регистры таблицы перевода)
  • TCR_EL1 (регистр элемента управления переводом)
  • MAIR_EL1 (регистр косвенного обращения атрибута памяти)
  • SCTLR_EL1 (регистр системного управления)
  • CONTEXTIDR_EL1 (идентификатор контекста)

Поведение исключений и обработки прерываний управляет поведением исключений:

  • VBAR_EL1 (регистр векторных базовых адресов — расположение векторной таблицы)
  • ESR_EL1 (регистр синдрома исключений)
  • FAR_EL1 (регистр адреса сбоя)
  • AFSR0_EL1, AFSR1_EL1 (регистры состояния вспомогательного сбоя)

Системная конфигурация регистрирует функции обработчика управления:

  • CPACR_EL1 (совместное управление доступом)
  • ACTLR_EL1 (вспомогательный регистр управления)
  • AMAIR_EL1 (регистр косвенных атрибутов вспомогательной памяти)
  • ZCR_EL1, SMCR_EL1 (конфигурация SVE/SME, если она поддерживается)

Регистры отладки и мониторинга производительности являются частными. Сюда входят все регистры системы отладки (MDSCR_EL1, DBGBCR_EL1[], DBGBVR_EL1[], DBGWCR_EL1[], DBGWVR_EL1[], и т. д.) и все регистры монитора производительности (PMCR_EL0 и связанные регистры PMU)

Регистры конфигурации таймера :

  • CNTKCTL_EL1 (элемент управления таймером ядра)
  • CNTV_CTL_EL0, CNTV_CVAL_EL0 (управление виртуальным таймером и сравнение значений)

Регистры идентификации потоков :

  • TPIDR_EL0, TPIDR_EL1, TPIDRRO_EL0 (регистры идентификаторов потока)

Искусственные регистры гипервизора (доступ к ней осуществляется через гипермасштабирование, а не непосредственно как системные регистры):

  • HvRegisterGuestOsId (идентификация гостевой ОС)
  • HvRegisterHypercallMsrValue (включение интерфейса hypercall)
  • HvRegisterReferenceTsc (страница счетчика меток времени ссылки)
  • HvRegisterVpAssistPage (страница поддержки VP для этого VTL)
  • Регистры контроллера искусственных прерываний (SynIC)
  • Регистры искусственного таймера (Stimer0-3)
  • Интерфейс локального контроллера прерываний (интерфейс ЦП GIC)

Эта комплексная изоляция регистра VTL обеспечивает полный контроль над средой выполнения, управлением памятью, обработкой исключений и интерфейсом гипервизора без вмешательства других виртуальных списков.

Общее состояние

Виртуальные библиотеки используют определенное состояние процессора, чтобы сократить затраты на переходы VTL и обеспечить эффективное взаимодействие между уровнями доверия. Общее состояние включает регистры общего назначения, используемые для вычислений и передачи данных, состояния с плавающей запятой и определенных регистров состояния системы, которые не влияют на границы безопасности.

Предоставляя общий доступ к регистрам общего назначения в виртуальных библиотеках, вызов VTL может передавать параметры непосредственно в регистрах, а возврат VTL может передавать результаты обратно, не требуя обмена данными на основе памяти. Эта конструкция значительно повышает производительность меж VTL-вызовов при сохранении изоляции безопасности, предоставляемой частным состоянием.

На платформах x64

На платформах x64 общее состояние включает регистры общего назначения для вычислений, системных регистров сведений и определенных регистров состояния, которые не влияют на изоляцию безопасности.

Общие 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

Общие регистры позволяют эффективно передавать и вычислять данные в виртуальных библиотеках.

  • General-Purpose Регистры: Rax, Rbx, Rcx, Rdx, Rsi, Rdi, Rbp, R8-R15 (используется для вычисления и передачи параметров во время вызовов VTL)
  • Сведения об исключении: CR2 (линейный адрес ошибки страницы — общий для контекста обработки исключений)
  • Отладка данных: DR0-DR3 (регистры адресов отладки, используемые для адресов точки останова)
  • Floating-Point и векторное состояние:
    • Состояние с плавающей запятой X87 (устаревшие вычисления с плавающей запятой)
    • Состояние XMM (128-разрядные векторы SSE)
    • Состояние AVX (256-разрядные векторы)
    • XCR0/XFEM (расширенная маска включения функций)
  • Состояние отладки: DR6 (регистр состояния отладки , зависящий от типа процессора; чтение HvRegisterVsmCapabilities, чтобы определить, является ли общий или закрытый)

На платформах ARM64

На платформах ARM64 общее состояние включает регистры, используемые для вычислений, передачи данных и операций с плавающей запятой. Этот общий доступ позволяет эффективно вызывать VTL, позволяя передавать параметры и результаты непосредственно в регистрах.

Общие регистры позволяют выполнять вычисления и обмен данными между виртуальными сетями:

  • General-Purpose Регистры: X0-X17, X19-X28 (используется для передачи вычислений и параметров)
    • X0-X7 обычно используется для параметров функции и возвращаемых значений во время вызовов VTL
    • X8-X17, X19-X28 доступны для общих вычислений
    • Примечание. X18 (регистрация платформы) и ПК являются частными для каждого VTL по соображениям безопасности
    • Примечание. X29 (указатель FP/кадра), X30 (LR/link register), и SP являются частными для каждого VTL
  • Floating-Point и векторное состояние:
    • Q0-Q31 (128-разрядные регистры NEON/floating-point для вычислений векторов)
    • Расширенное состояние SIMD (NEON) для векторных операций
    • Примечание. Состояние SVE (Z0-Z31, P0-P15, FFR) и состояние SME являются частными. Нижняя 128-разрядная часть (регистры Q) является общим, но верхние биты регистров Z могут быть повреждены при переходах VTL. Программное обеспечение не должно полагаться на содержимое регистра Z, сохраняемое в коммутаторах VTL.
    • Примечание. Состояние SPE (расширение статистического профилирования) совместно используется между виртуальными списками, за исключением PMBSR_EL1, которые являются частными
  • Системные регистры сведений (только для чтения или некритичные для безопасности):
    • Регистры идентификации систем и компонентов
    • Сведения о типе кэша и TLB

ARM64 следует тому же принципу, что и x64: общее состояние вычислений используется для повышения эффективности, а состояние управления и конфигурации, затрагивающее границы безопасности, остается частным для каждой виртуальной сети.

Режим реального режима (только x64)

Режим реального режима не поддерживается для всех VTL, превышающих 0 на платформах x64. Виртуальные списки, превышающие 0, могут выполняться в 32-разрядном или 64-разрядном режиме в x64-разрядном режиме.

Управление прерываниями VTL

Чтобы обеспечить высокий уровень изоляции между уровнями доверия виртуальных сетей, виртуальный безопасный режим предоставляет отдельную подсистему прерываний для каждого виртуального процессора, включенного в виртуальном процессоре. Это гарантирует, что VTL может отправлять и получать прерывания без вмешательства из менее безопасного VTL.

Каждый VTL имеет собственный контроллер прерываний, который активен только в том случае, если виртуальный процессор работает в этом конкретном VTL. Если виртуальный процессор переключает состояния VTL, контроллер прерываний, активный на процессоре, также переключается.

На платформах x64 каждый VTL имеет отдельный локальный экземпляр APIC. На платформах ARM64 каждый VTL имеет отдельный GIC.

Прерывание, предназначенное для VTL, которое выше активного VTL, приведет к немедленному коммутатору VTL. Затем более высокий уровень VTL может получить прерывание. Если более высокий VTL не может получить прерывание из-за его маски приоритета (TPR/CR8 в x64, маске приоритета GIC в ARM64), прерывание сохраняется как "ожидающий" и VTL не переключается. Если существует несколько виртуальных списков с ожидающих прерываний, то самый высокий уровень VTL имеет приоритет (без уведомления о более низком уровне VTL).

Если прерывание предназначено для более низкого уровня VTL, прерывание не доставляется до следующего перехода виртуального процессора в целевой VTL.

На платформах x64 INIT и начальные IP-адреса, предназначенные для более низкого уровня VTL, удаляются на виртуальный процессор с более высокой поддержкой VTL. Так как механизмы запуска обработчика архитектуры могут быть заблокированы, гиперкадр HvCallStartVirtualProcessor следует использовать для запуска процессоров.

На платформах ARM64 методы интерфейса PSCI (например, CPU_ON) для привлечения процессоров в сети также блокируются при включении более высокого уровня VTL. Гиперкалл HvCallStartVirtualProcessor предоставляет согласованный кроссплатформенный механизм для запуска процессоров.

Маскирование прерываний и коммутаторы VTL

На платформах x64

Для переключения виртуальных списков RFLAGS. Если не влияет, активирует ли безопасный прерываний коммутатор VTL. Значение RFLAGS. ЕСЛИ очищается для маскирования прерываний, прерывания в более высоких виртуальных библиотеках по-прежнему вызывают переключение VTL на более высокий уровень VTL. При принятии решения о том, следует ли немедленно прервать, учитывается только более высокое значение TPR/CR8.

Это поведение также влияет на ожидающие прерывания при возврате VTL. Значение RFLAGS. Если бит очищается, чтобы маскировать прерывания в заданном VTL, а VTL возвращает (в более низкий VTL), гипервизор будет повторно вычислять любые ожидающие прерывания. Это приведет к немедленному вызову более высокого уровня VTL.

На платформах ARM64

Аналогичным образом биты маски прерываний PSTATE (DAIF) не влияют на то, активирует ли безопасный коммутатор прерывания. Если прерывания маскируются через PSTATE, прерывания, предназначенные для более высоких виртуальных списков, по-прежнему вызывают коммутатор VTL. При принятии решения о том, следует ли немедленно доставить прерывание, учитывается только более высокий уровень приоритета GIC.

Помощь с уведомлением о виртуальных прерываниях

Более высокие виртуальные библиотеки могут регистрироваться для получения уведомления, если они блокируют немедленную доставку прерывания на более низкий уровень VTL того же виртуального процессора. Более высокие списки виртуальных таблиц могут включить службу уведомлений о прерывании виртуальных машин (VINA) с помощью виртуального регистра HvRegisterVsmVina:

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

Каждый VTL на каждом VP имеет собственный экземпляр VINA, а также собственную версию HvRegisterVsmVina. Объект VINA создаст прерывание, активироваемое краем, для активного в настоящее время более высокого уровня VTL, когда прерывание для нижнего VTL готово к немедленной доставке.

Чтобы предотвратить наводнение прерываний, возникающих при включении этого объекта, объект VINA включает в себя некоторое ограниченное состояние. При создании прерывания VINA состояние объекта VINA изменяется на "Asserted". Отправка сквозного прерывания в SINT, связанного с объектом VINA, не очищает состояние "Asserted". Утверждаемое состояние можно очистить только одним из двух способов:

  1. Состояние можно очистить вручную, записав в поле VinaAsserted структуры HV_VP_VTL_CONTROL .
  2. Состояние автоматически очищается при следующей записи в VTL, если параметр "автозаброшен в записи VTL" включен в регистре HvRegisterVsmVina.

Это позволяет коду, работающему в безопасном VTL, просто получать уведомления о первом прерывании, полученном для более низкого уровня VTL. Если безопасный VTL хочет получать уведомления о дополнительных прерываниях, он может очистить поле VinaAsserted страницы поддержки VP, и оно будет уведомлено о следующем новом прерывании.

Безопасные перехваты

Гипервизор позволяет более высокому VTL устанавливать перехваты для событий, происходящих в контексте более низкого уровня VTL. Это обеспечивает более высокий уровень управления ресурсами более низкого уровня VTL. Безопасные перехваты можно использовать для защиты критически важных для системы ресурсов и предотвращения атак с более низкими виртуальными сетями.

Безопасный перехват помещается в очередь на более высокий уровень VTL и что VTL выполняется на VP.

Типы безопасного перехвата

Тип перехвата Перехват применяется к
Обращение к памяти Попытка получить доступ к защите GPA, установленной более высоким значением VTL.
Управление доступом к регистру Попытка получить доступ к набору регистров элементов управления, заданных более высоким значением VTL.

Вложенные перехваты

Несколько виртуальных столов могут устанавливать безопасные перехваты для одного и того же события в более низком VTL. Таким образом, иерархия устанавливается для определения того, где вложенные перехваты уведомляются. Следующий список — это порядок уведомления о перехвате:

  1. Более низкий уровень VTL
  2. Более высокий уровень VTL

Обработка безопасных перехватов

После того как VTL будет уведомлен о безопасном перехвате, необходимо принять меры, чтобы продолжить более низкую VTL. Более высокий уровень VTL может обрабатывать перехват несколькими способами, включая внедрение исключения, эмулирование доступа или предоставление прокси-сервера для доступа. В любом случае, если необходимо изменить частное состояние нижнего VTL VP, следует использовать HvCallSetVpRegisters .

Безопасные перехваты регистров (только x64)

На платформах x64 более высокий уровень VTL может перехватывать доступ к определенным регистрам управления и MSR. Это достигается путем установки HvX64RegisterCrInterceptControl с помощью гиперколла HvCallSetVpRegisters . Задание бита элемента управления в HvX64RegisterCrInterceptControl активирует перехват для каждого доступа к соответствующему регистру элемента управления.

Эта функция зависит от x64, так как она перехватывает регистры элементов управления x64 (CR0, CR4, XCR0) и x64 MSR (EFER, LSTAR, STAR и т. д.). Платформы ARM64 могут поддерживать аналогичные возможности перехвата с помощью различных механизмов.

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.