hv: keylocker: Support keylocker backup MSRs for Guest VM

The logical processor scoped IWKey can be copied to or from a
platform-scope storage copy called IWKeyBackup. Copying IWKey to
IWKeyBackup is called ‘backing up IWKey’ and copying from IWKeyBackup to
IWKey is called ‘restoring IWKey’.

IWKeyBackup and the path between it and IWKey are protected against
software and simple hardware attacks. This means that IWKeyBackup can be
used to distribute an IWKey within the logical processors in a platform
in a protected manner.

Linux keylocker implementation uses this feature, so they are
introduced by this patch.

Tracked-On: #5695
Signed-off-by: Shuo A Liu <shuo.a.liu@intel.com>
Acked-by: Eddie Dong <eddie.dong@intel.com>
This commit is contained in:
Shuo A Liu 2020-08-24 20:16:11 +08:00 committed by wenlingz
parent 38cd5b481d
commit d4aaf99d86
6 changed files with 95 additions and 1 deletions

View File

@ -270,6 +270,7 @@ static void vcpu_reset_internal(struct acrn_vcpu *vcpu, enum reset_mode mode)
}
init_iwkey(vcpu);
vcpu->arch.iwkey_copy_status = 0UL;
}
struct acrn_vcpu *get_running_vcpu(uint16_t pcpu_id)

View File

@ -468,6 +468,7 @@ int32_t create_vm(uint16_t vm_id, uint64_t pcpu_bitmap, struct acrn_vm_config *v
spinlock_init(&vm->vlapic_mode_lock);
spinlock_init(&vm->ept_lock);
spinlock_init(&vm->emul_mmio_lock);
spinlock_init(&vm->arch_vm.iwkey_backup_lock);
vm->arch_vm.vlapic_mode = VM_VLAPIC_XAPIC;
vm->intr_inject_delay_delta = 0UL;
@ -717,6 +718,7 @@ int32_t reset_vm(struct acrn_vm *vm)
reset_vioapics(vm);
destroy_secure_world(vm, false);
vm->sworld_control.flag.active = 0UL;
vm->arch_vm.iwkey_backup_status = 0UL;
vm->state = VM_CREATED;
return ret;

View File

@ -61,6 +61,12 @@ static const uint32_t emulated_guest_msrs[NUM_GUEST_MSRS] = {
MSR_IA32_XSS,
/* KeyLocker backup MSRs */
MSR_IA32_COPY_LOCAL_TO_PLATFORM,
MSR_IA32_COPY_PLATFORM_TO_LOCAL,
MSR_IA32_COPY_STATUS,
MSR_IA32_IWKEY_BACKUP_STATUS,
MSR_TEST_CTL,
};
@ -402,6 +408,17 @@ static int32_t write_pat_msr(struct acrn_vcpu *vcpu, uint64_t value)
return ret;
}
/**
* @pre vcpu != NULL
*/
bool is_iwkey_backup_support(struct acrn_vcpu *vcpu)
{
uint32_t eax = 0x19U, ebx = 0U, ecx = 0U, edx = 0U;
guest_cpuid(vcpu, &eax, &ebx, &ecx, &edx);
return (ebx & CPUID_EBX_KL_BACKUP_MSR) == CPUID_EBX_KL_BACKUP_MSR;
}
/**
* @pre vcpu != NULL
*/
@ -516,6 +533,24 @@ int32_t rdmsr_vmexit_handler(struct acrn_vcpu *vcpu)
}
break;
}
case MSR_IA32_COPY_STATUS:
{
if (is_iwkey_backup_support(vcpu)) {
v = vcpu->arch.iwkey_copy_status;
} else {
err = -EACCES;
}
break;
}
case MSR_IA32_IWKEY_BACKUP_STATUS:
{
if (is_iwkey_backup_support(vcpu)) {
v = vcpu->vm->arch_vm.iwkey_backup_status;
} else {
err = -EACCES;
}
break;
}
case MSR_TEST_CTL:
{
/* If has MSR_TEST_CTL, give emulated value
@ -842,6 +877,40 @@ int32_t wrmsr_vmexit_handler(struct acrn_vcpu *vcpu)
}
break;
}
case MSR_IA32_COPY_LOCAL_TO_PLATFORM:
{
if ((v == 0x1UL) && is_iwkey_backup_support(vcpu)) {
vcpu->vm->arch_vm.iwkey_backup_status = 0UL;
spinlock_obtain(&vcpu->vm->arch_vm.iwkey_backup_lock);
vcpu->vm->arch_vm.iwkey_backup = vcpu->arch.IWKey;
spinlock_release(&vcpu->vm->arch_vm.iwkey_backup_lock);
/*
* Keylocker spec 0.76 Table 4-1:
* 'Backup/restore valid' bit and 'IWKeyBackup consumed' bit
*/
vcpu->vm->arch_vm.iwkey_backup_status = 0x9UL;
vcpu->arch.iwkey_copy_status = 1UL;
} else {
err = -EINVAL;
}
break;
}
case MSR_IA32_COPY_PLATFORM_TO_LOCAL:
{
if ((v == 0x1UL) && is_iwkey_backup_support(vcpu) &&
(vcpu->vm->arch_vm.iwkey_backup_status == 0x9UL)) {
spinlock_obtain(&vcpu->vm->arch_vm.iwkey_backup_lock);
vcpu->arch.IWKey = vcpu->vm->arch_vm.iwkey_backup;
spinlock_release(&vcpu->vm->arch_vm.iwkey_backup_lock);
/* Load the new iwkey for this vcpu */
get_cpu_var(whose_iwkey) = NULL;
load_iwkey(vcpu);
vcpu->arch.iwkey_copy_status = 1UL;
} else {
err = -EINVAL;
}
break;
}
case MSR_TEST_CTL:
{
/* If VM has MSR_TEST_CTL, ignore write operation

View File

@ -171,7 +171,7 @@ enum reset_mode;
#define SECURE_WORLD 1
#define NUM_WORLD_MSRS 2U
#define NUM_COMMON_MSRS 17U
#define NUM_COMMON_MSRS 21U
#define NUM_GUEST_MSRS (NUM_WORLD_MSRS + NUM_COMMON_MSRS)
#define EOI_EXIT_BITMAP_SIZE 256U
@ -270,6 +270,12 @@ struct acrn_vcpu_arch {
/* Keylocker */
struct iwkey IWKey;
bool cr4_kl_enabled;
/*
* Keylocker spec 4.4:
* Bit 0 - Status of most recent copy to or from IWKeyBackup.
* Bit 63:1 - Reserved.
*/
uint64_t iwkey_copy_status;
} __aligned(PAGE_SIZE);
struct acrn_vm;

View File

@ -116,6 +116,18 @@ struct vm_arch {
#endif
enum vm_vlapic_mode vlapic_mode; /* Represents vLAPIC mode across vCPUs*/
/*
* Keylocker spec 4.5:
* Bit 0 - Backup/restore valid.
* Bit 1 - Reserved.
* Bit 2 - Backup key storage read/write error.
* Bit 3 - IWKeyBackup consumed.
* Bit 63:4 - Reserved.
*/
uint64_t iwkey_backup_status;
spinlock_t iwkey_backup_lock; /* Spin-lock used to protect internal key backup/restore */
struct iwkey iwkey_backup;
/* reference to virtual platform to come here (as needed) */
} __aligned(PAGE_SIZE);

View File

@ -353,6 +353,10 @@
#define MSR_IA32_L2_MASK_BASE 0x00000D10U
#define MSR_IA32_MBA_MASK_BASE 0x00000D50U
#define MSR_IA32_BNDCFGS 0x00000D90U
#define MSR_IA32_COPY_LOCAL_TO_PLATFORM 0x00000D91U
#define MSR_IA32_COPY_PLATFORM_TO_LOCAL 0x00000D92U
#define MSR_IA32_COPY_STATUS 0x00000990U
#define MSR_IA32_IWKEY_BACKUP_STATUS 0x00000991U
#define MSR_IA32_EFER 0xC0000080U
#define MSR_IA32_STAR 0xC0000081U
#define MSR_IA32_LSTAR 0xC0000082U