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