Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Le mode sécurisé virtuel (VSM) est un ensemble de fonctionnalités d’hyperviseur et d’éclairages offerts aux partitions hôtes et invitées qui permettent la création et la gestion de nouvelles limites de sécurité au sein du logiciel du système d’exploitation. VSM est l’installation d’hyperviseur sur laquelle les fonctionnalités de sécurité Windows, notamment Device Guard, Credential Guard, les machines virtuelles tpms virtuelles et les machines virtuelles protégées sont basées. Ces fonctionnalités de sécurité ont été introduites dans Windows 10 et Windows Server 2016.
VSM permet aux logiciels de système d’exploitation dans les partitions racine et invité de créer des régions isolées de mémoire pour le stockage et le traitement des ressources de sécurité système. L’accès à ces régions isolées est contrôlé et accordé uniquement par le biais de l’hyperviseur, qui est une partie hautement privilégiée et hautement fiable de la base de calcul approuvée (TCB) du système. Étant donné que l’hyperviseur s’exécute à un niveau de privilège supérieur au logiciel du système d’exploitation et dispose d’un contrôle exclusif des ressources matérielles du système d’exploitation telles que les contrôles d’autorisation d’accès à la mémoire dans l’initialisation du processeur et de l’IOMMU tôt dans l’initialisation du système d’exploitation, l’hyperviseur peut protéger ces régions isolées contre l’accès non autorisé, même à partir du logiciel du système d’exploitation (par exemple, noyau du système d’exploitation et pilotes de périphérique) avec un accès en mode superviseur (cpl0, par exemple, CPL0, ou « Anneau 0 »).
Avec cette architecture, même si le logiciel de niveau système normal s’exécutant en mode superviseur (par exemple, noyau, pilotes, etc.) est compromis par des logiciels malveillants, les ressources dans les régions isolées protégées par l’hyperviseur peuvent rester sécurisées.
Niveau de confiance virtuelle (VTL)
VSM obtient et gère l’isolation via les niveaux de confiance virtuelle (VTL). Les VTL sont activés et gérés à la fois par partition et par processeur virtuel.
Les niveaux de confiance virtuelle sont hiérarchiques, les niveaux supérieurs étant plus privilégiés que les niveaux inférieurs. VTL0 est le niveau le moins privilégié, avec VTL1 étant plus privilégié que VTL0, VTL2 étant plus privilégié que VTL1, etc.
Architecturalement, jusqu’à 16 niveaux de VTL sont pris en charge ; toutefois, un hyperviseur peut choisir d’implémenter moins de 16 VTL. Actuellement, seules deux VTL sont implémentées.
typedef UINT8 HV_VTL, *PHV_VTL;
#define HV_NUM_VTLS 2
#define HV_INVALID_VTL ((HV_VTL) -1)
#define HV_VTL_ALL 0xF
Chaque VTL a son propre ensemble de protections d’accès à la mémoire. Ces protections d’accès sont gérées par l’hyperviseur dans l’espace d’adressage physique d’une partition et ne peuvent donc pas être modifiées par les logiciels au niveau du système exécutés dans la partition.
Étant donné que les VTL plus privilégiés peuvent appliquer leurs propres protections de mémoire, les VTL plus élevés peuvent protéger efficacement les zones de mémoire contre les VTL inférieurs. Dans la pratique, cela permet à une durée de vie inférieure de protéger les régions de mémoire isolées en les sécurisant avec une durée de vie VTL supérieure. Par exemple, VTL0 peut stocker un secret dans VTL1, auquel point seul VTL1 peut y accéder. Même si VTL0 est compromis, le secret serait sûr.
Protections de durée de vie virtuelle
Il existe plusieurs facettes pour atteindre l’isolation entre les VTL :
- Protections d’accès à la mémoire : chaque durée de vie virtuelle gère un ensemble de protections d’accès à la mémoire physique invité. Les logiciels exécutés sur une durée de vie virtuelle particulière peuvent uniquement accéder à la mémoire conformément à ces protections.
- État du processeur virtuel : les processeurs virtuels gèrent un état distinct par VTL. Par exemple, chaque VTL définit un ensemble d’enregistrements VP privés. Les logiciels s’exécutant à une durée de vie inférieure ne peuvent pas accéder à l’état d’inscription du processeur virtuel privé supérieur.
- Interruptions : ainsi qu’un état de processeur distinct, chaque VTL possède également son propre sous-système d’interruption (APIC local sur x64, interface processeur GIC sur ARM64). Cela permet aux VTL plus élevés de traiter les interruptions sans risquer d’interférence à partir d’une durée de vie VTL inférieure.
- Pages de superposition : certaines pages de superposition sont conservées par VTL de sorte que les VTL plus élevés disposent d’un accès fiable. Par exemple, il existe une page de superposition hypercall distincte par VTL.
Détection et état VSM
La fonctionnalité VSM est annoncée pour les partitions via l’indicateur de privilège de partition AccessVsm. Seules les partitions avec tous les privilèges suivants peuvent utiliser VSM : AccessVsm, AccessVpRegisters et AccessSynicRegs.
Détection des fonctionnalités VSM
Les invités peuvent accéder à un rapport sur les fonctionnalités VSM via un registre synthétique.
Sur les plateformes x64
Sur les plateformes x64, ce registre est accessible via un MSR :
| Adresse MSR | Nom de l’inscription | Descriptif |
|---|---|---|
| 0x000D0006 | HV_X64_REGISTER_VSM_CAPABILITIES | Rapport sur les fonctionnalités VSM. |
Sur les plateformes ARM64
Sur les plateformes ARM64, ce registre est accessible via HvRegisterVsmCapabilities à l’aide de l’hypercall HvCallGetVpRegisters.
Format d’inscription
Sur les plateformes x64
| Bits | Descriptif | Attributes |
|---|---|---|
| 63 | Dr6Shared | Lire |
| 62:47 | MbecVtlMask | Lire |
| 46 | DenyLowerVtlStartup | Lire |
| 45:0 | RsvdZ | Lire |
Sur les plateformes ARM64
| Bits | Descriptif | Attributes |
|---|---|---|
| 63 | RsvdZ | Lire |
| 62:47 | MbecVtlMask | Lire |
| 46 | DenyLowerVtlStartup | Lire |
| 45:0 | RsvdZ | Lire |
Descriptions des champs
Dr6Shared (x64 uniquement) : indique à l’invité si Dr6 est un registre partagé entre les VTL.
MbecVtlMask : indique à l’invité les VTL pour lesquels MBEC peut être activé.
DenyLowerVtlStartup : indique à l’invité si une durée de vie virtuelle peut refuser une réinitialisation VP par une durée de vie VTL inférieure.
Registre d’état VSM
En plus d’un indicateur de privilège de partition, deux registres virtuels peuvent être utilisés pour en savoir plus sur l’état VSM : HvRegisterVsmPartitionStatus et HvRegisterVsmVpStatus.
HvRegisterVsmPartitionStatus
HvRegisterVsmPartitionStatus est un registre en lecture seule par partition qui est partagé entre toutes les VTL. Ce registre fournit des informations sur les VTL qui ont été activés pour la partition, sur laquelle les VTL ont activé les contrôles d’exécution en mode, ainsi que la durée de vie VTL maximale autorisée.
typedef union
{
UINT64 AsUINT64;
struct
{
UINT64 EnabledVtlSet : 16;
UINT64 MaximumVtl : 4;
UINT64 MbecEnabledVtlSet: 16;
UINT64 ReservedZ : 28;
};
} HV_REGISTER_VSM_PARTITION_STATUS;
HvRegisterVsmVpStatus
HvRegisterVsmVpStatus est un registre en lecture seule et est partagé entre toutes les VTL. Il s’agit d’un registre par VP, ce qui signifie que chaque processeur virtuel conserve sa propre instance. Ce registre fournit des informations sur les VTL qui ont été activées, qui sont actives, ainsi que le mode MBEC actif sur un 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 est l’ID du contexte VTL actuellement actif sur le processeur virtuel.
ActiveMbecEnabled spécifie que MBEC est actuellement actif sur le processeur virtuel.
EnabledVtlSet est une bitmap des VTL activées sur le processeur virtuel.
État initial de la durée de vie de partition
Lorsqu’une partition démarre ou réinitialise, elle commence à s’exécuter dans VTL0. Toutes les autres VTL sont désactivées lors de la création de la partition.
Activation de la durée de vie virtuelle
Pour commencer à utiliser une durée de vie virtuelle, une durée de vie VTL inférieure doit lancer ce qui suit :
- Activez la durée de vie virtuelle cible pour la partition. Cela rend la durée de vie VTL généralement disponible pour la partition.
- Activez la durée de vie virtuelle cible sur un ou plusieurs processeurs virtuels. Cela rend la durée de vie disponible pour un VP et définit son contexte initial. Il est recommandé que toutes les adresses virtuelles aient les mêmes VTL activées. L’activation d’une durée de vie virtuelle sur certaines adresses virtuelles (mais pas toutes) peut entraîner un comportement inattendu.
- Une fois que la durée de vie virtuelle est activée pour une partition et un VP, elle peut commencer à définir des protections d’accès une fois que l’indicateur EnableVtlProtection a été défini.
Notez que les VTL n’ont pas besoin d’être consécutifs.
Activation d’une durée de vie virtuelle cible pour une partition
L’hypercall HvCallEnablePartitionVtl est utilisé pour activer une durée de vie virtuelle pour une certaine partition. Notez que avant que le logiciel ne puisse réellement s’exécuter dans une durée de vie VTL particulière, cette durée de vie doit être activée sur les processeurs virtuels de la partition.
Activation d’une durée de vie virtuelle cible pour les processeurs virtuels
Une fois qu’une durée de vie virtuelle est activée pour une partition, elle peut être activée sur les processeurs virtuels de la partition. L’hypercall HvCallEnableVpVtl peut être utilisé pour activer des VTL pour un processeur virtuel, qui définit son contexte initial.
Les processeurs virtuels ont un « contexte » par durée de vie virtuelle. Si une durée de vie virtuelle est basculée, l’état privé de la durée de vie est également basculé.
Configuration de la durée de vie virtuelle
Une fois qu’une durée de vie virtuelle a été activée, sa configuration peut être modifiée par un VP s’exécutant à un VTL égal ou supérieur.
Partition Configuration
Les attributs à l’échelle de la partition peuvent être configurés à l’aide du registre HvRegisterVsmPartitionConfig. Il existe une instance de ce registre pour chaque durée de vie virtuelle (supérieure à 0) sur chaque partition.
Chaque VTL peut modifier sa propre instance de HV_REGISTER_VSM_PARTITION_CONFIG, ainsi que les instances pour les VTL inférieures. Les VTL peuvent ne pas modifier ce registre pour les VTL plus élevés.
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;
Les champs de ce registre sont décrits ci-dessous.
Activer les protections de durée de vie virtuelle
Une fois qu’une durée de vie virtuelle a été activée, l’indicateur EnableVtlProtection doit être défini avant de commencer à appliquer des protections de mémoire. Cet indicateur est en écriture seule, ce qui signifie qu’une fois défini, il ne peut pas être modifié.
Masque de protection par défaut
Par défaut, le système applique des protections RWX à toutes les pages actuellement mappées et toutes les futures pages « ajoutées à chaud ». Les pages ajoutées à chaud font référence à toute mémoire ajoutée à une partition pendant une opération de redimensionnement.
Une durée de vie VTL supérieure peut définir une stratégie de protection de mémoire par défaut différente en spécifiant DefaultVtlProtectionMask dans HV_REGISTER_VSM_PARTITION_CONFIG. Ce masque doit être défini au moment de l’activation de la durée de vie virtuelle. Il ne peut pas être modifié une fois qu’il est défini et n’est effacé que par une réinitialisation de partition.
| bit | Descriptif |
|---|---|
| 0 | Lire |
| 1 | Write |
| 2 | Exécution en mode noyau (KMX) |
| 3 | Exécution en mode utilisateur (UMX) |
Mémoire zéro lors de la réinitialisation
ZeroMemOnReset est un bit qui contrôle si la mémoire est zéro avant la réinitialisation d’une partition. Cette configuration est activée par défaut. Si le bit est défini, la mémoire de la partition est annulée lors de la réinitialisation afin qu’une mémoire de VTL supérieure ne puisse pas être compromise par une durée de vie VTL inférieure. Si ce bit est effacé, la mémoire de la partition n’est pas réinitialisation.
DenyLowerVtlStartup
L’indicateur DenyLowerVtlStartup contrôle si un processeur virtuel peut être démarré ou réinitialisé par des VTL inférieurs. Cela inclut des méthodes architecturales de réinitialisation d’un processeur virtuel (par exemple, SIPI sur X64) ainsi que l’hypercall HvCallStartVirtualProcessor .
InterceptVpStartup
Si l’indicateur InterceptVpStartup est défini, le démarrage ou la réinitialisation d’un processeur virtuel génère une interception à la durée de vie VTL supérieure.
Configuration des VTL inférieurs
Le registre suivant peut être utilisé par des VTL plus élevés pour configurer le comportement des VTL inférieurs :
typedef union
{
UINT64 AsUINT64;
struct
{
UINT64 MbecEnabled : 1;
UINT64 TlbLocked : 1;
UINT64 ReservedZ : 62;
};
} HV_REGISTER_VSM_VP_SECURE_VTL_CONFIG;
Chaque VTL (supérieur à 0) a une instance de ce registre pour chaque VTL inférieure à elle-même. Par exemple, VTL2 aurait deux instances de ce registre : une pour VTL1 et une seconde pour VTL0.
Les champs de ce registre sont décrits ci-dessous.
MbecEnabled
Ce champ configure si MBEC est activé pour la durée de vie virtuelle inférieure.
TlbLocked
Ce champ verrouille le TLB de la durée de vie inférieure. Cette fonctionnalité peut être utilisée pour empêcher les VTL inférieurs d’entraîner des invalidations DLB qui peuvent interférer avec une durée de vie VTL plus élevée. Lorsque ce bit est défini, toutes les demandes de vidage de l’espace d’adressage de la durée de vie inférieure sont bloquées jusqu’à ce que le verrou soit levé.
Pour déverrouiller le TLB, la durée de vie VTL la plus élevée peut effacer ce bit. En outre, une fois qu’un VP revient à une durée de vie VTL inférieure, il libère tous les verrous TLB qu’il contient à l’heure.
Entrée VTL
Une durée de vie virtuelle est « entrée » lorsqu’un VP passe d’une VTL inférieure à une durée de vie supérieure. Cela peut se produire pour les raisons suivantes :
- Appel VTL : il s’agit du moment où le logiciel souhaite appeler explicitement du code dans une durée de vie VTL supérieure.
- Interruption sécurisée : si une interruption est reçue pour une durée de vie VTL supérieure, le VP entrera dans la durée de vie VTL supérieure.
- Interception sécurisée : certaines actions déclenchent une interruption sécurisée (accès à certains MSR, par exemple).
Une fois qu’un VTL est entré, il doit quitter volontairement. Une durée de vie VTL supérieure ne peut pas être préemptée par une durée de vie VTL inférieure.
Identification de la raison de l’entrée de la durée de vie virtuelle
Pour réagir de manière appropriée à une entrée, une durée de vie VTL plus élevée peut avoir besoin de connaître la raison pour laquelle elle a été entrée. Pour distinguer les raisons d’entrée, l’entrée VTL est incluse dans la structure HV_VP_VTL_CONTROL .
Appel de durée de vie virtuelle
Un « appel de durée de vie virtuelle » est lorsqu’une durée de vie virtuelle inférieure initie une entrée dans une durée de vie VTL supérieure (par exemple, pour protéger une région de mémoire avec la durée de vie VTL supérieure) via l’hypercall HvCallVtlCall .
Les appels VTL conservent l’état des registres partagés entre les commutateurs VTL. Les registres privés sont conservés au niveau de la durée de vie par VTL. L’exception à ces restrictions est les registres/instructions requis par la séquence d’appels VTL.
Sur les plateformes x64
Les registres suivants sont requis pour un appel VTL sur x64 :
| x64 | x86 | Descriptif |
|---|---|---|
| RCX | EDX :EAX | Spécifie une entrée de contrôle d’appel de durée de vie virtuelle à l’hyperviseur |
| RAX | ECX | Réservé |
Tous les bits de l’entrée de contrôle d’appel VTL sont actuellement réservés.
Sur les plateformes ARM64
Sur les plateformes ARM64, un appel VTL est lancé à l’aide de l’instruction HVC avec la valeur 2 immédiate. L’hyperviseur décode cette valeur immédiate spécifique et le traite en tant qu’hypercall HvCallVtlCall. Aucun état d’inscription spécifique n’est requis pour l’entrée de contrôle sur ARM64.
Restrictions d’appel de durée de vie virtuelle
Les appels VTL ne peuvent être lancés qu’à partir du mode processeur le plus privilégié. Par exemple, sur les systèmes x64, un appel VTL ne peut provenir que de CPL0 et sur les systèmes ARM64 d’EL1. Un appel de durée de vie virtuelle lancé à partir d’un mode processeur, qui est tout sauf le plus privilégié sur le système entraîne l’injection d’une exception dans le processeur virtuel (#UD sur l’exception d’instruction x64 non définie sur ARM64).
Un appel de durée de vie virtuelle ne peut basculer que vers la durée de vie VTL la plus élevée suivante. En d’autres termes, s’il existe plusieurs VTL activés, un appel ne peut pas « ignorer » une durée de vie virtuelle. Les actions suivantes entraînent une exception (#UD sur x64, instruction non définie sur ARM64) :
- Un appel VTL lancé à partir d’un mode processeur, qui est tout sauf le plus privilégié sur le système (spécifique à l’architecture).
- Un appel VTL à partir du mode réel (x86/x64 uniquement)
- Un appel VTL sur un processeur virtuel sur lequel la durée de vie virtuelle cible est désactivée (ou n’a pas déjà été activée).
- Un appel VTL avec une valeur d’entrée de contrôle non valide
Sortie de la durée de vie virtuelle
Un commutateur vers une durée de vie virtuelle inférieure est appelé « retour ». Une fois qu’une durée de vie virtuelle a terminé le traitement, elle peut lancer un retour VTL afin de basculer vers une durée de vie VTL inférieure. La seule façon dont un retour VTL peut se produire est si une durée de vie VTL plus élevée en lance volontairement une. Une durée de vie VTL inférieure ne peut jamais préempter une valeur supérieure.
Retour de la durée de vie virtuelle
Un « retour de durée de vie virtuelle » est lorsqu’une durée de vie VTL supérieure lance un commutateur dans une durée de vie VTL inférieure par le biais de l’hypercall HvCallVtlReturn . Comme pour un appel VTL, l’état du processeur privé est désactivé et l’état partagé reste en place. Si la durée de vie VTL inférieure a explicitement été appelée dans la durée de vie VTL supérieure, l’hyperviseur incrémente le pointeur d’instruction de VTL supérieur avant la fin du retour afin qu’il puisse continuer après un appel VTL.
Sur les plateformes x64
Une séquence de code de retour VTL sur x64 nécessite l’utilisation des registres suivants :
| x64 | x86 | Descriptif |
|---|---|---|
| RCX | EDX :EAX | Spécifie une entrée de contrôle de retour VTL sur l’hyperviseur |
| RAX | ECX | Réservé |
Sur les plateformes ARM64
Sur les plateformes ARM64, un retour VTL est lancé à l’aide de l’instruction HVC avec la valeur 3 immédiate. L’hyperviseur décode cette valeur immédiate spécifique et le traite en tant qu’hypercall HvCallVtlReturn.
Entrée du contrôle de retour VTL
L’entrée de contrôle de retour VTL a le format suivant :
| Bits | Terrain | Descriptif |
|---|---|---|
| 63:1 | RsvdZ | |
| 0 | Retour rapide | Les registres ne sont pas restaurés |
Les actions suivantes génèrent une exception #UD :
- Tentative de retour de durée de vie virtuelle lorsque la durée de vie virtuelle la plus basse est actuellement active
- Tentative d’un retour de durée de vie virtuelle avec une valeur d’entrée de contrôle non valide
- Tentative d’un retour de durée de vie virtuelle à partir d’un mode processeur, qui est tout sauf le plus privilégié sur le système (spécifique à l’architecture)
Retour rapide
Dans le cadre du traitement d’un retour, l’hyperviseur peut restaurer l’état de registre de la durée de vie virtuelle inférieure à partir de la structure HV_VP_VTL_CONTROL . Par exemple, après le traitement d’une interruption sécurisée, une durée de vie VTL plus élevée peut souhaiter retourner sans perturber l’état du VTL inférieur. Par conséquent, l’hyperviseur fournit un mécanisme permettant simplement de restaurer les registres de VTL inférieurs sur leur valeur de pré-appel stockée dans la structure de contrôle VTL.
Si ce comportement n’est pas nécessaire, une durée de vie VTL supérieure peut utiliser un « retour rapide ». Un retour rapide est lorsque l’hyperviseur ne restaure pas l’état d’enregistrement à partir de la structure de contrôle. Cela doit être utilisé chaque fois que cela est possible pour éviter tout traitement inutile.
Ce champ peut être défini avec le bit 0 de l’entrée de retour VTL. S’il est défini sur 0, les registres sont restaurés à partir de la structure HV_VP_VTL_CONTROL. Si ce bit est défini sur 1, les registres ne sont pas restaurés (un retour rapide).
Assistance de page Hypercall (x64 uniquement)
Sur les plateformes x64, l’hyperviseur fournit des mécanismes permettant d’aider les appels VTL et de retourner via la page hypercall. Cette page extrait la séquence de code spécifique requise pour changer de VTL.
Les séquences de code permettant d’exécuter des appels VTL et des retours sont accessibles en exécutant des instructions spécifiques dans la page hypercall. Les blocs d’appel/retour se trouvent à un décalage dans la page hypercall déterminée par le registre virtuel HvRegisterVsmCodePageOffsets. Il s’agit d’un registre en lecture seule et à l’échelle de la partition, avec une instance distincte par VTL.
Une durée de vie virtuelle peut exécuter un appel/retour de durée de vie virtuelle à l’aide de l’instruction CALL. Un APPEL à l’emplacement correct dans la page hypercall lance un appel/retour de durée de vie virtuelle.
typedef union
{
UINT64 AsUINT64;
struct
{
UINT64 VtlCallOffset : 12;
UINT64 VtlReturnOffset : 12;
UINT64 ReservedZ : 40;
};
} HV_REGISTER_VSM_CODE_PAGE_OFFSETS;
Pour résumer, les étapes d’appel d’une séquence de code à l’aide de la page hypercall sur x64 sont les suivantes :
- Mapper la page hypercall dans l’espace GPA d’une durée de vie virtuelle
- Déterminez le décalage correct pour la séquence de code (appel VTL ou retour).
- Exécutez la séquence de code à l’aide de CALL.
Note: Sur les plateformes ARM64, les appels VTL et les retours sont effectués directement à l’aide de l’instruction HVC avec des valeurs immédiates spécifiques (2 pour l’appel VTL, 3 pour le retour VTL) comme décrit dans les sections VTL Call et VTL Return. Le registre HvRegisterVsmCodePageOffsets n’est pas disponible sur ARM64.
Protections d’accès à la mémoire
Une protection nécessaire fournie par VSM est la possibilité d’isoler les accès à la mémoire.
Les VTL plus élevés ont un degré élevé de contrôle sur le type d’accès à la mémoire autorisé par des VTL inférieurs. Il existe trois types de protections de base qui peuvent être spécifiés par une durée de vie VTL supérieure pour une page GPA particulière : lecture, écriture et eXecute. Celles-ci sont définies dans le tableau suivant :
| Nom | Descriptif |
|---|---|
| Lire | Contrôle si l’accès en lecture est autorisé à une page mémoire |
| Write | Contrôle si l’accès en écriture autorisé à une page mémoire est autorisé |
| Execute | Contrôle si les extractions d’instructions sont autorisées pour une page mémoire. |
Ces trois combinaisons pour les types de protection de mémoire suivants :
- Aucun accès
- En lecture seule, aucune exécution
- En lecture seule, exécutez
- Lecture/écriture, aucune exécution
- Lecture/écriture, exécution
Si le « contrôle d’exécution basé sur le mode (MBEC) » est activé, les protections d’exécution du mode utilisateur et du noyau peuvent être définies séparément.
Les VTL plus élevés peuvent définir la protection de la mémoire pour un GPA via l’hypercall HvCallModifyVtlProtectionMask .
Hiérarchie de protection de la mémoire
Les autorisations d’accès à la mémoire peuvent être définies par plusieurs sources pour une durée de vie virtuelle particulière. Les autorisations de chaque VTL peuvent potentiellement être limitées par un certain nombre d’autres VTL, ainsi que par la partition hôte. L’ordre dans lequel les protections sont appliquées est la suivante :
- Protections de la mémoire définies par l’hôte
- Protections de la mémoire définies par des VTL plus élevés
En d’autres termes, les protections VTL remplacent les protections d’hôte. Les VTL de niveau supérieur remplacent les VTL de niveau inférieur. Notez qu’une durée de vie virtuelle peut ne pas définir les autorisations d’accès à la mémoire pour elle-même.
Une interface conforme est censée ne pas superposer un type non RAM sur LA RAM.
Violations de l’accès à la mémoire
Si un VP s’exécutant à une durée de vie virtuelle inférieure tente de violer un jeu de protection de mémoire défini par une durée de vie VTL supérieure, une interception est générée. Cette interception est reçue par la durée de vie VTL supérieure qui définit la protection. Cela permet aux VTL plus élevés de traiter la violation en cas par cas. Par exemple, la durée de vie VTL supérieure peut choisir de retourner une erreur ou d’émuler l’accès.
Mode Based Execute Control (MBEC)
Lorsqu’une durée de vie virtuelle place une restriction de mémoire sur une durée de vie VTL inférieure, il peut souhaiter faire une distinction entre l’utilisateur et le mode noyau lors de l’octroi d’un privilège d’exécution. Par exemple, si des vérifications d’intégrité du code étaient effectuées dans une durée de vie VTL supérieure, la possibilité de faire la distinction entre le mode utilisateur et le mode noyau signifierait qu’une VTL pouvait appliquer l’intégrité du code uniquement pour les applications en mode noyau.
Outre les trois protections de mémoire traditionnelles (lecture, écriture, exécution), MBEC introduit une distinction entre le mode utilisateur et le mode noyau pour les protections d’exécution. Ainsi, si MBEC est activé, une durée de vie virtuelle a la possibilité de définir quatre types de protections de mémoire :
| Nom | Descriptif |
|---|---|
| Lire | Contrôle si l’accès en lecture est autorisé à une page mémoire |
| Write | Contrôle si l’accès en écriture autorisé à une page mémoire est autorisé |
| Exécution en mode utilisateur (UMX) | Contrôle si les extractions d’instructions générées en mode utilisateur sont autorisées pour une page mémoire. REMARQUE : Si MBEC est désactivé, ce paramètre est ignoré. |
| Exécution en mode noyau (KMX) | Détermine si les extractions d’instructions générées en mode noyau sont autorisées pour une page mémoire. REMARQUE : Si MBEC est désactivé, ce paramètre contrôle les accès en mode utilisateur et en mode noyau. |
La mémoire marquée avec les protections «User-Mode Execute » ne serait exécutable que lorsque le processeur virtuel s’exécute en mode utilisateur. De même, la mémoire «Kernel-Mode Exécuter » ne serait exécutable que lorsque le processeur virtuel s’exécute en mode noyau.
KMX et UMX peuvent être définis indépendamment afin que les autorisations d’exécution soient appliquées différemment entre le mode utilisateur et noyau. Toutes les combinaisons de UMX et KMX sont prises en charge, à l’exception de KMX=1, UMX=0. Le comportement de cette combinaison n’est pas défini.
MBEC est désactivé par défaut pour tous les processeurs virtuels et tous les processeurs virtuels. Lorsque MBEC est désactivé, le bit d’exécution en mode noyau détermine la restriction d’accès à la mémoire. Par conséquent, si MBEC est désactivé, le code KMX=1 est exécutable en mode noyau et utilisateur.
Tables de descripteur (x64 uniquement)
Sur les plateformes x64, tout code en mode utilisateur qui accède aux tables de descripteur doit se trouver dans des pages GPA marquées comme KMX=UMX=1. Le logiciel en mode utilisateur accédant aux tables de descripteur à partir d’une page GPA marquée KMX=0 n’est pas pris en charge et entraîne une erreur de protection générale.
ARM64 n’utilise pas de tables de descripteur de style x86 ; Les autorisations d’accès à la mémoire sont contrôlées par le biais d’entrées de table de traduction et du modèle de privilèges EL.
Configuration de MBEC
Pour utiliser le contrôle d’exécution en mode, il doit être activé à deux niveaux :
- Lorsque la durée de vie virtuelle est activée pour une partition, MBEC doit être activé à l’aide de HvCallEnablePartitionVtl
- MBEC doit être configuré sur une base par VP et par VTL, à l’aide de HvRegisterVsmVpSecureConfigVtlX.
Interaction MBEC avec la prévention de l’exécution du mode superviseur (SMEP) (x64 uniquement)
Supervisor-Mode La prévention de l’exécution (SMEP) est une fonctionnalité de processeur prise en charge sur les plateformes x64. SMEP peut avoir un impact sur l’opération de MBEC en raison de sa restriction de l’accès des superviseurs aux pages mémoire. L’hyperviseur respecte les stratégies suivantes liées à SMEP :
- Si SMEP n’est pas disponible pour le système d’exploitation invité (qu’il s’agisse de fonctionnalités matérielles ou de mode de compatibilité du processeur), MBEC n’est pas affecté.
- Si SMEP est disponible et est activé, MBEC fonctionne non affecté.
- Si SMEP est disponible et est désactivé, toutes les restrictions d’exécution sont régies par le contrôle KMX. Par conséquent, seul le code marqué KMX=1 est autorisé à s’exécuter.
Isolation de l’état du processeur virtuel
Les processeurs virtuels conservent des états distincts pour chaque durée de vie virtuelle active. Toutefois, certains de ces états sont privés à une durée de vie virtuelle particulière, et l’état restant est partagé entre toutes les VTL.
L’hyperviseur gère un contexte par VTL pour chaque processeur virtuel, stockant l’état de tous les processeurs visibles par invité qui doivent être isolés entre les VTL. Chaque VTL possède sa propre instance d’état privé, notamment les registres de contrôle, les vecteurs d’exception, les registres de configuration du système et les registres d’hyperviseur synthétiques. Ce stockage par VTL garantit une isolation complète du contexte d’exécution lors du basculement entre les niveaux de confiance.
L’état qui est conservé par VTL (a.k.a. private state) est enregistré par l’hyperviseur entre les transitions VTL. Si un commutateur de durée de vie virtuelle est lancé, l’hyperviseur enregistre l’état privé actuel de la durée de vie virtuelle active, puis bascule vers l’état privé de la durée de vie virtuelle cible. L’état partagé reste actif, quel que soit le commutateur VTL.
État privé
Chaque VTL conserve son propre contexte d’exécution complet composé des suivants :
- État d’exécution : pointeur d’instruction (PC/RIP), pointeur de pile (SP/RSP), indicateurs de processeur (PSTATE/RFLAGS)
- Registres de contrôle : configuration de la gestion de la mémoire (tables de pages, contrôles de traduction, attributs de mémoire)
- Gestion des exceptions : vecteurs d’exception/interruption, registres de syndrome d’exception, registres d’adresses d’erreur
- Configuration du système : contrôles de fonctionnalités du processeur, contrôles de débogage, configuration du minuteur
- Registres synthétiques : l’interface Hyperviseur s’inscrit spécifique à chaque VTL (page hypercall, ID de système d’exploitation invité, référence TSC, contrôleur d’interruption synthétique)
Cette isolation garantit que chaque VTL a un contrôle indépendant sur son environnement d’exécution et ne peut pas observer ou interférer avec l’état privé d’autres VTL.
Sur les plateformes x64
Sur les plateformes x64, chaque VTL gère son propre contexte d’exécution via des MSR et des registres spécifiques à l’architecture. L’hyperviseur les conserve sur les commutateurs VTL, ce qui garantit l’isolation complète de l’environnement d’exécution.
Mécanismes d’appel système de contrôle msrs privés, attributs de mémoire, fonctionnalités du processeur et interface d’hyperviseur.
MSR architecturaux :
- SYSENTER_CS, SYSENTER_ESP, SYSENTER_EIP, STAR, LSTAR, CSTAR, SFMASK, EFER, PAT, KERNEL_GSBASE, FS. BASE, GS. BASE, TSC_AUX
- Registres APIC locaux (y compris CR8/TPR)
MSR synthétiques :
- 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
Les registres privés contrôlent l’environnement d’exécution, la gestion de la mémoire et la gestion des exceptions :
- État d’exécution : RIP (pointeur d’instruction), RSP (pointeur de pile), RFLAGS (indicateurs de processeur)
- Gestion de la mémoire : CR0 (contrôle processeur), CR3 (base de table de pages), CR4 (fonctionnalités du processeur)
- Tables de descripteur : IDTR (table de descripteur d’interruption), GDTR (table de descripteur globale)
- Registres de segment : CS, DS, ES, FS, GS, SS, TR, LDTR
- Déboguer le contrôle : DR7 (registre de contrôle de débogage)
- Horodatage : TSC (compteur d’horodatage, fournissant une référence de temps indépendante par VTL)
- État du débogage : DR6 (registre d’état de débogage - dépendant du type de processeur ; lisez HvRegisterVsmCapabilities pour déterminer si partagé ou privé)
Sur les plateformes ARM64
Sur les plateformes ARM64, chaque VTL conserve son propre contexte d’inscription système complet. L’hyperviseur conserve ces registres sur les commutateurs VTL, garantissant ainsi une isolation complète de l’environnement d’exécution et d’exception.
L’état d’exécution inscrit le flux du programme de contrôle et le mode processeur :
- PC (compteur de programme), SP_EL0, SP_EL1 (pointeurs de pile)
- PSTATE (indicateurs d’état du processeur), FPCR/FPSR (contrôle/état à virgule flottante)
- ELR_EL1, SPSR_EL1 (registre de liens d’exception, état du programme enregistré)
La gestion de la mémoire et le contrôle de traduction s’inscrivent pour configurer la mémoire virtuelle :
- TTBR0_EL1, TTBR1_EL1 (registres de base de table de traduction)
- TCR_EL1 (registre de contrôle de traduction)
- MAIR_EL1 (registre d’indirection d’attribut de mémoire)
- SCTLR_EL1 (registre de contrôle système)
- CONTEXTIDR_EL1 (identificateur de contexte)
La gestion des exceptions et des interruptions enregistre le comportement des exceptions de contrôle :
- VBAR_EL1 (registre d’adresses de base vectorielle - emplacement de la table de vecteurs d’exception)
- ESR_EL1 (registre du syndrome d’exception)
- FAR_EL1 (registre d’adresses d’erreur)
- AFSR0_EL1, AFSR1_EL1 (registres d’état d’erreur auxiliaires)
La configuration système inscrit les fonctionnalités du processeur de contrôle :
- CPACR_EL1 (contrôle d’accès de coprocesseur)
- ACTLR_EL1 (registre de contrôle auxiliaire)
- AMAIR_EL1 (registre d’indirection d’attribut de mémoire auxiliaire)
- ZCR_EL1, SMCR_EL1 (configuration SVE/SME si prise en charge)
Les registres de débogage et d’analyse des performances sont VTL-private. Cela inclut tous les registres système de débogage (MDSCR_EL1, DBGBCR_EL1[], DBGBVR_EL1[], DBGWCR_EL1[], DBGWVR_EL1[], etc.) et tous les registres d’analyseur de performances (registres PMCR_EL0 et les registres PMU associés)
Registres de configuration du minuteur :
- CNTKCTL_EL1 (contrôle du minuteur de noyau)
- CNTV_CTL_EL0, CNTV_CVAL_EL0 (contrôle du minuteur virtuel et valeur de comparaison)
Registres d’identification des threads :
- TPIDR_EL0, TPIDR_EL1, TPIDRRO_EL0 (registres d’ID de thread)
Registres d’hyperviseurs synthétiques (accessibles via des hypercalls, pas directement en tant que registres système) :
- HvRegisterGuestOsId (identification du système d’exploitation invité)
- HvRegisterHypercallMsrValue (activation de l’interface hypercall)
- HvRegisterReferenceTsc (page compteur d’horodatage de référence)
- HvRegisterVpAssistPage (page d’assistance VP pour cette VTL)
- Registres du contrôleur d’interruption synthétique (SynIC)
- Registres du minuteur synthétique (Stimer0-3)
- Interface du contrôleur d’interruption local (interface processeur GIC)
Cette isolation complète de registre par VTL garantit que chaque VTL a un contrôle total sur son environnement d’exécution, la gestion de la mémoire, la gestion des exceptions et l’interface d’hyperviseur sans interférence à partir d’autres VTL.
État partagé
Les VTL partagent un certain état du processeur pour réduire la surcharge des transitions VTL et permettre une communication efficace entre les niveaux de confiance. L’état partagé inclut des registres à usage général utilisés pour le calcul et le passage de données, l’état à virgule flottante et certains registres d’état système qui n’affectent pas les limites de sécurité.
En partageant des registres à usage général sur des VTL, un appel VTL peut transmettre des paramètres directement dans les registres, et un retour VTL peut transmettre les résultats sans nécessiter de communication basée sur la mémoire. Cette conception améliore considérablement les performances des appels inter-VTL tout en conservant l’isolation de sécurité fournie par l’état privé.
Sur les plateformes x64
Sur les plateformes x64, l’état partagé inclut des registres à usage général pour le calcul, les registres d’informations système et certains registres d’état qui n’ont pas d’impact sur l’isolation de la sécurité.
Les MSR partagés fournissent des informations système et une configuration communes entre les VTL :
- 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
Les registres partagés permettent un passage et un calcul efficaces des données entre les VTL :
- General-Purpose Registres : Rax, Rbx, Rcx, Rdx, Rsi, Rdi, Rbp, R8-R15 (utilisé pour le calcul et le passage de paramètres pendant les appels VTL)
- Informations sur l’exception : CR2 (adresse linéaire d’erreur de page - partagée pour le contexte de gestion des exceptions)
- Déboguer des données : DR0-DR3 (registres d’adresses de débogage - utilisés pour les adresses de point d’arrêt)
-
Floating-Point et état vectoriel :
- État à virgule flottante X87 (calcul à virgule flottante héritée)
- État XMM (vecteurs SSE 128 bits)
- État AVX (vecteurs 256 bits)
- XCR0/XFEM (masque d’activation de fonctionnalité étendue)
- État du débogage : DR6 (registre d’état de débogage - dépendant du type de processeur ; lisez HvRegisterVsmCapabilities pour déterminer si partagé ou privé)
Sur les plateformes ARM64
Sur les plateformes ARM64, l’état partagé inclut des registres utilisés pour le calcul, le passage de données et les opérations à virgule flottante. Ce partage permet d’effectuer des appels VTL efficaces en autorisant les paramètres et les résultats à passer directement dans les registres.
Les registres partagés permettent le calcul et la communication entre les VTL :
-
General-Purpose Registres : X0-X17, X19-X28 (utilisé pour le calcul et le passage de paramètres)
- X0-X7 généralement utilisé pour les paramètres de fonction et les valeurs de retour pendant les appels VTL
- X8-X17, X19-X28 disponible pour le calcul général
- Remarque : X18 (registre de plateforme) et PC sont privés par VTL pour des raisons de sécurité
- Remarque : X29 (pointeur FP/frame), X30 (registre LR/link) et sp sont privés par VTL
-
Floating-Point et état vectoriel :
- Q0-Q31 (registres neON/virgule flottante 128 bits pour le calcul vectoriel)
- État SIMD avancé (NEON) pour les opérations vectorielles
- Remarque : L’état SVE (Z0-Z31, P0-P15, FFR) et l’état SME sont VTL-private. La partie inférieure 128 bits (registres Q) est partagée, mais les bits supérieurs des registres Z peuvent être endommagés lors des transitions VTL. Les logiciels ne doivent pas s’appuyer sur le contenu du registre Z conservé sur les commutateurs de durée de vie virtuelle.
- Remarque : l’état SPE (extension de profilage statistique) est partagé entre les VTL, à l’exception de PMBSR_EL1 qui est VTL-private
-
Registres d’informations système (en lecture seule ou non critiques pour la sécurité) :
- Inscriptions de fonctionnalités et d’identification système
- Informations de type cache et TLB
ARM64 suit le même principe que x64 : l’état de calcul général est partagé pour l’efficacité, tandis que l’état de contrôle et de configuration qui affecte les limites de sécurité reste privé à chaque durée de vie virtuelle.
Mode réel (x64 uniquement)
Le mode réel n’est pas pris en charge pour une durée de vie supérieure à 0 sur les plateformes x64. Les VTL supérieures à 0 peuvent s’exécuter en mode 32 bits ou 64 bits sur x64.
Gestion des interruptions de durée de vie virtuelle
Pour obtenir un niveau élevé d’isolation entre les niveaux de confiance virtuelle, le mode sécurisé virtuel fournit un sous-système d’interruption distinct pour chaque VTL activé sur un processeur virtuel. Cela garantit qu’une durée de vie virtuelle est en mesure d’envoyer et de recevoir des interruptions sans interférence d’une durée de vie VTL moins sécurisée.
Chaque VTL a son propre contrôleur d’interruption, qui est actif uniquement si le processeur virtuel est en cours d’exécution dans ce VTL particulier. Si un processeur virtuel bascule les états VTL, le contrôleur d’interruption actif sur le processeur est également basculé.
Sur les plateformes x64, chaque VTL a une instance APIC locale distincte. Sur les plateformes ARM64, chaque VTL a un GIC distinct.
Une interruption ciblée sur une durée de vie virtuelle supérieure à la durée de vie active entraîne un commutateur VTL immédiat. La durée de vie virtuelle supérieure peut ensuite recevoir l’interruption. Si la durée de vie VTL supérieure n’est pas en mesure de recevoir l’interruption en raison de son masque de priorité (TPR/CR8 sur x64, masque de priorité GIC sur ARM64), l’interruption est conservée en tant que « en attente » et la durée de vie virtuelle ne change pas. S’il existe plusieurs VTL avec des interruptions en attente, la durée de vie VTL la plus élevée est prioritaire (sans préavis à la durée de vie VTL inférieure).
Lorsqu’une interruption est ciblée à une durée de vie VTL inférieure, l’interruption n’est remise qu’à la prochaine transition du processeur virtuel vers la durée de vie VTL ciblée.
Sur les plateformes x64, les ADRESSES IP init et de démarrage ciblées sur une durée de vie inférieure sont supprimées sur un processeur virtuel avec une durée de vie VTL supérieure activée. Étant donné que les mécanismes de démarrage du processeur architectural peuvent être bloqués, l’hypercall HvCallStartVirtualProcessor doit être utilisé pour démarrer des processeurs.
Sur les plateformes ARM64, les méthodes d’interface PSCI (telles que CPU_ON) pour mettre en ligne les processeurs sont également bloquées lorsqu’une durée de vie virtuelle supérieure est activée. L’hypercall HvCallStartVirtualProcessor fournit un mécanisme multiplateforme cohérent pour démarrer des processeurs.
Commutateurs de masquage des interruptions et de durée de vie virtuelle
Sur les plateformes x64
À des fins de basculement de VTLs, RFLAGS. SI n’affecte pas si une interruption sécurisée déclenche un commutateur de durée de vie virtuelle. Si RFLAGS. SI est effacé pour masquer les interruptions, les interruptions dans des VTL plus élevées entraînent toujours un commutateur VTL vers une durée de vie VTL supérieure. Seule la valeur TPR/CR8 de la durée de vie supérieure est prise en compte lors de la décision d’interrompre immédiatement.
Ce comportement affecte également les interruptions en attente lors d’un retour de durée de vie virtuelle. Si rfLAGS. SI le bit est effacé pour masquer les interruptions dans une durée de vie donnée et la durée de vie virtuelle retourne (à une durée de vie VTL inférieure), l’hyperviseur réévalue les interruptions en attente. Cela entraîne un rappel immédiat à la durée de vie VTL supérieure.
Sur les plateformes ARM64
De même, les bits de masque d’interruption PSTATE (DAIF) n’affectent pas si une interruption sécurisée déclenche un commutateur VTL. Si des interruptions sont masquées via PSTATE, les interruptions ciblées sur des VTL plus élevés entraînent toujours un commutateur VTL. Seul le masque de priorité GIC de la durée de vie supérieure est pris en compte lors du choix de la remise immédiate de l’interruption.
Assistance de notification d’interruption virtuelle
Les VTL plus élevés peuvent s’inscrire pour recevoir une notification s’ils bloquent la remise immédiate d’une interruption à une durée de vie inférieure du même processeur virtuel. Les VTL plus élevés peuvent activer l’assistance de notification d’interruption virtuelle (VINA) via un registre virtuel 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;
Chaque VTL sur chaque VP a sa propre instance VINA, ainsi que sa propre version de HvRegisterVsmVina. L’installation VINA génère une interruption déclenchée par une arête à la durée de vie VTL actuellement active plus élevée lorsqu’une interruption pour la durée de vie inférieure est prête à être remise immédiatement.
Afin d’éviter une inondation d’interruptions lorsque cette installation est activée, l’installation VINA comprend un état limité. Lorsqu’une interruption VINA est générée, l’état de l’installation VINA est remplacé par « Asserted ». L’envoi d’une interruption de fin à la SINT associée à l’installation VINA ne efface pas l’état « Asserted ». L’état déclaré ne peut être effacé que de deux façons :
- L’état peut être effacé manuellement en écrivant dans le champ VinaAsserted de la structure HV_VP_VTL_CONTROL .
- L’état est automatiquement effacé lors de l’entrée suivante à la durée de vie virtuelle si l’option « Réinitialisation automatique sur l’entrée VTL » est activée dans le registre HvRegisterVsmVina.
Cela permet au code s’exécutant sur une durée de vie virtuelle sécurisée d’être simplement averti de la première interruption reçue pour une durée de vie VTL inférieure. Si une durée de vie virtuelle sécurisée souhaite être avertie d’interruptions supplémentaires, elle peut effacer le champ VinaAsserted de la page d’assistance VP et être averti de la nouvelle interruption suivante.
Intercepts sécurisés
L’hyperviseur permet à une durée de vie VTL plus élevée d’installer des intercepts pour les événements qui se produisent dans le contexte d’une durée de vie VTL inférieure. Cela donne aux VTL plus élevés un niveau de contrôle élevé sur les ressources de durée de vie inférieure. Les interceptions sécurisées peuvent être utilisées pour protéger les ressources critiques du système et empêcher les attaques contre les réseaux virtuels inférieurs.
Une interception sécurisée est mise en file d’attente vers la durée de vie VTL la plus élevée et la durée de vie de VTL est rendue exécutable sur le VP.
Types d’interception sécurisés
| Type d’interception | Intercept s’applique à |
|---|---|
| Accès à la mémoire | Tentative d’accès aux protections GPA établies par une durée de vie VTL supérieure. |
| Contrôler l’accès au registre | Tentative d’accès à un ensemble de registres de contrôle spécifiés par une durée de vie VTL supérieure. |
Intercepts imbriqués
Plusieurs VTL peuvent installer des intercepts sécurisés pour le même événement dans une durée de vie VTL inférieure. Par conséquent, une hiérarchie est établie pour décider où les intercepts imbriqués sont avertis. La liste suivante est l’ordre d’où l’interception est avertie :
- Durée de vie VTL inférieure
- Durée de vie VTL supérieure
Gestion des intercepts sécurisés
Une fois qu’une durée de vie virtuelle a été avertie d’une interception sécurisée, elle doit prendre des mesures afin que la durée de vie inférieure puisse continuer. La durée de vie VTL supérieure peut gérer l’interception de plusieurs façons, notamment : injecter une exception, simuler l’accès ou fournir un proxy à l’accès. Dans tous les cas, si l’état privé du VTL VP inférieur doit être modifié, HvCallSetVpRegisters doit être utilisé.
Intercepts de registre sécurisé (x64 uniquement)
Sur les plateformes x64, une durée de vie plus élevée peut intercepter sur les accès à certains registres de contrôle et MSR. Pour ce faire, définissez HvX64RegisterCrInterceptControl à l’aide de l’hypercall HvCallSetVpRegisters . La définition du bit de contrôle dans HvX64RegisterCrInterceptControl déclenche un intercept pour chaque accès au registre de contrôle correspondant.
Cette fonctionnalité est spécifique à x64, car elle intercepte les registres de contrôle x64 (CR0, CR4, XCR0) et x64 MSR (EFER, LSTAR, STAR, etc.). Les plateformes ARM64 peuvent prendre en charge des fonctionnalités d’interception similaires via différents mécanismes.
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;
Registres de masque
Pour permettre un contrôle plus fin, un sous-ensemble de registres de contrôle possède également des registres de masque correspondants. Les registres de masque peuvent être utilisés pour installer des intercepts sur un sous-ensemble des registres de contrôle correspondants. Lorsqu’un registre de masque n’est pas défini, tout accès (tel que défini par HvX64RegisterCrInterceptControl) déclenche un intercept.
L’hyperviseur prend en charge les registres de masque suivants : HvX64RegisterCrInterceptCr0Mask, HvX64RegisterCrInterceptCr4Mask et HvX64RegisterCrInterceptIa32MiscEnableMask.
DMA et appareils
Les appareils ont effectivement le même niveau de privilège que VTL0. Lorsque VSM est activé, toutes les mémoires allouées par l’appareil sont marquées comme VTL0. Tous les accès DMA ont les mêmes privilèges que VTL0.