From d4aaf99d869d93a8f7b96717c5204fe92f9c5207 Mon Sep 17 00:00:00 2001 From: Shuo A Liu Date: Mon, 24 Aug 2020 20:16:11 +0800 Subject: [PATCH] hv: keylocker: Support keylocker backup MSRs for Guest VM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Acked-by: Eddie Dong --- hypervisor/arch/x86/guest/vcpu.c | 1 + hypervisor/arch/x86/guest/vm.c | 2 + hypervisor/arch/x86/guest/vmsr.c | 69 ++++++++++++++++++++++++ hypervisor/include/arch/x86/guest/vcpu.h | 8 ++- hypervisor/include/arch/x86/guest/vm.h | 12 +++++ hypervisor/include/arch/x86/msr.h | 4 ++ 6 files changed, 95 insertions(+), 1 deletion(-) diff --git a/hypervisor/arch/x86/guest/vcpu.c b/hypervisor/arch/x86/guest/vcpu.c index 56412ea77..a80cd7a5c 100644 --- a/hypervisor/arch/x86/guest/vcpu.c +++ b/hypervisor/arch/x86/guest/vcpu.c @@ -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) diff --git a/hypervisor/arch/x86/guest/vm.c b/hypervisor/arch/x86/guest/vm.c index 8f61f10ef..89900da7c 100644 --- a/hypervisor/arch/x86/guest/vm.c +++ b/hypervisor/arch/x86/guest/vm.c @@ -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; diff --git a/hypervisor/arch/x86/guest/vmsr.c b/hypervisor/arch/x86/guest/vmsr.c index cf5d6dbc3..84e564e1a 100644 --- a/hypervisor/arch/x86/guest/vmsr.c +++ b/hypervisor/arch/x86/guest/vmsr.c @@ -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 diff --git a/hypervisor/include/arch/x86/guest/vcpu.h b/hypervisor/include/arch/x86/guest/vcpu.h index 40108b8ff..6ee965672 100644 --- a/hypervisor/include/arch/x86/guest/vcpu.h +++ b/hypervisor/include/arch/x86/guest/vcpu.h @@ -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; diff --git a/hypervisor/include/arch/x86/guest/vm.h b/hypervisor/include/arch/x86/guest/vm.h index 9994295dd..bd677ffcd 100644 --- a/hypervisor/include/arch/x86/guest/vm.h +++ b/hypervisor/include/arch/x86/guest/vm.h @@ -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); diff --git a/hypervisor/include/arch/x86/msr.h b/hypervisor/include/arch/x86/msr.h index e30184da7..4ed2185a0 100644 --- a/hypervisor/include/arch/x86/msr.h +++ b/hypervisor/include/arch/x86/msr.h @@ -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