Поделиться через


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

Виртуальный безопасный режим (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). Это позволяет более высоким виртуальным сетям обрабатывать прерывания без риска вмешательства из более низкого уровня VTL.
  • Страницы наложения. Некоторые страницы наложения поддерживаются на уровне VTL, чтобы более высокие виртуальные списки имели надежный доступ. Например, существует отдельная страница гиперкласти наложения на VTL.

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

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

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

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

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

Формат MSR для регистрации возможностей VSM выглядит следующим образом:

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

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

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

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

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

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

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

Вызов 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 требуется использование следующих регистров:

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

Входные данные возвращаемого элемента управления 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

Гипервизор предоставляет механизмы для поддержки вызовов 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;

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

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

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

Одной из необходимых защит, предоставляемых 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 выполняется как в ядре, так и в пользовательском режиме.

Таблицы дескриптора

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

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

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

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

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

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

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

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

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

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

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

Как правило, каждый VTL имеет собственные регистры управления, регистр RIP, регистр RSP и MSR. Ниже приведен список определенных регистров и MSR, которые являются частными для каждого VTL.

Частные 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 для определения общего или закрытого состояния)

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

Виртуальные библиотеки используют состояние общего доступа, чтобы сократить затраты на переключение контекстов. Состояние общего доступа также позволяет выполнять некоторые необходимые подключения между виртуальными сетями. Большинство общих регистров назначения и с плавающей запятой являются общими, как и большинство архитектурных MSR. Ниже приведен список определенных 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 — DR3
  • Состояние с плавающей запятой X87
  • Состояние XMM
  • Состояние AVX
  • XCR0 (XFEM)
  • DR6 (*зависит от типа процессора. Чтение виртуального регистра HvRegisterVsmCapabilities для определения общего или закрытого состояния)

Режим реального режима

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

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

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

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

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

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

RFLAGS. ЕСЛИ

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

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

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

Более высокие виртуальные библиотеки могут регистрироваться для получения уведомления, если они блокируют немедленную доставку прерывания на более низкий уровень 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 .

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

Более высокий уровень VTL может перехватывать доступ к определенным регистрам элементов управления. Это достигается путем установки HvX64RegisterCrInterceptControl с помощью гиперколла HvCallSetVpRegisters . Задание бита элемента управления в 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.