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


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

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

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

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

Уровень доверия (VTL)

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

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

Так как более привилегированные списки виртуальных машин могут применять собственные средства защиты памяти, более высокие виртуальные списки могут эффективно защищать области памяти от более низких виртуальных списков. На практике это позволяет более низкому сроку жизни защищать изолированные области памяти, обеспечивая их более высоким сроком жизни. Например, VTL0 может хранить секрет в VTL1, в котором только VTL1 может получить к нему доступ. Даже если VTL0 скомпрометирован, секрет будет безопасным.

Защита от VTL

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

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

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

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

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

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

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

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

Bits Описание Атрибуты
63 Dr6Shared Чтение
62:47 MbecVtlMask Чтение
46 DenyLowerVtlStartup Чтение
45:0 RsvdZ Чтение

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

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

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

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

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

HvRegisterVsmPartitionStatus

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

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 и задает его начальный контекст. Рекомендуется, чтобы все виртуальные ip-адреса имели одинаковые списки VT. Включение VTL на некоторых виртуальных машинах (но не все) может привести к неожиданному поведению.
  3. После включения VTL для секции и VP он может начать настройку защиты доступа после установки флага EnableVtlProtection.

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

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

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

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

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

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

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

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

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

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

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

bit Описание
0 Чтение
1 запись
2 Выполнение режима ядра (KMX)
3 Выполнение пользовательского режима (UMX)

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

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

DenyLowerVtlStartup

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

InterceptVpStartup

Если установлен флаг InterceptVpStartup, запуск или сброс виртуального процессора создает перехват до более высокого срока жизни.

Настройка более низких списков виртуальных столов

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

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 для более низкого срока жизни.

TlbLocked

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

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

Запись VTL

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

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

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

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

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

Вызов VTL

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

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

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

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

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

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

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

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

Выход из VTL

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

Возврат VTL

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

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

X64 x86 Описание
RCX EDX:EAX Указывает входные данные обратного элемента управления VTL для низкоуровневой оболочки.
RAX ECX Зарезервированное

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

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

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

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

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

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

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

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

Поддержка страницы hypercall

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Управление выполнением на основе режима (MBEC)

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

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

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

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

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 с помощью HvRegisterVsmVpSecureVtlConfig.

Взаимодействие 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 register, RSP register и 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 — DR5
  • Состояние с плавающей запятой 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. IP-адреса INIT и запуска, предназначенные для меньшего срока жизни, удаляются на виртуальном процессоре с более высоким значением VTL. Так как inIT/SIPI заблокирован, для запуска процессоров следует использовать гиперколл HvCallStartVirtualProcessor .

RFLAGS. ЕСЛИ

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

Это поведение также влияет на ожидающие прерывания при возвращении VTL. Значение RFLAGS. Если бит очищается для маскирования прерываний в заданном 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;

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

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

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

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

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

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

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

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

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

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

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

  1. Нижний срок жизни
  2. Более высокий срок жизни

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

После того как 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.