[PATCH 00/15] KVM: Support Intel Key Locker

From: Robert Hoo
Date: Tue Jun 01 2021 - 04:48:09 EST


This patch set is to support KVM virtualization of Key Locker feature
[1][2].

Key Locker provides a mechanism to encrypt and decrypt data without
directly providing AES key but a "handle" instead.
Handles are essentially an encrypted form of those underlying real AES
keys. "IWKey (Internal Wrapping Key)", loaded inside CPU, inaccessible from
outside, is the key used to seal real AES Keys into handles.
Thus, a real AES Key exists in memory for only a short period of time, when
user is requesting a 'handle' from it. After that, the real AES Key can be
erased, user then uses handle, with new Key Locker instructions, to perform
AES encryption/decryption. By OS policy, usually, handles will be revoked
after reboot, then any handles that may have been stolen should no longer
be useful to the attacker after the reboot.

IWKey, is the core of this framework. It is loaded into CPU by LOADIWKEY
instruction, then inaccessible from CPU-outside anymore. LOADIWKEY is the
only Key Locker instruction that will cause VM-exit (if we set so in VM
Execution Control). When load IWKey into CPU, we can ask CPU further
randomize it, if HW supports this.
The IWKey can also be distributed among CPUs, rather than LOADIWKEY on each
CPU, by: first backup IWKey to platform specific storage, then copy it on
target CPU. The backup process is triggered by writing to MSR
IA32_COPY_LOCAL_TO_PLATFORM. The restore process is triggered by writing to
MSR IA32_COPY_PLATFORM_LOCAL.

Virtualization Design
Key Locker Spec [2] indicates virtualization limitations by current HW
implementation.
1) IWKey cannot be read from CPU after it's loaded (this is the nature of
this feature) and only 1 copy of IWKey inside 1 CPU.
2) Initial implementations may take a significant amount of time to perform
a copy of IWKeyBackup to IWKey (via a write to MSR
IA32_COPY_PLATFORM_LOCAL) so it may cause a significant performance impact
to reload IWKey after each VM exit.

Due to above reasons, virtualization design makes below decisions
1) don't expose HW randomize IWKey capability (CPUID.0x19.ECX[1]) to
guest. As such, guest IWKey cannot be preserved by VMM across vCPU switch.
(VMM cannot know what IWKey is set in physical CPU if HW randomized.)
2) guests and host can only use Key Locker feature exclusively. [4] 

The virtualization implementation is generally straight forward
1) On VM-Exit of guest 'LOADIWKEY', VMM stores the IWKey of that vCPU, and
set in physical CPU on behalf.
2) On each vCPU load/put, VMM is responsible to set IWKEY to pCPU or clear
it.
3) On guest backup local to platform operation, VMM traps the write
to MSR, and simulate the IWKey store process by store it in a KVM
scope area (kvm_arch), mark the success status in the shadow
msr_ia32_iwkey_backup_status and msr_ia32_copy_status.
4) On guest copy from platform to local operation, VMM traps the write
to MSR and simulate the process by load kvm_arch.iwkey_backup to
vCPU.iwkey; and simulate the success status in the
shadow msr_ia32_copy_status.
5) Guest read the 2 status MSRs will also be trapped and return the shadow
value.
6) Other Key Locker instructions can run without VM-Exit in non-root mode.

To the end, we don't suggest this feature to be migratable, as if so, IWKey
would have to be exposed to user space, which would further weaken this
feature's security significance.

P.S. this patch set is based on Chang's Kernel Key Locker upstream-v2
https://lore.kernel.org/lkml/20210514201508.27967-1-chang.seok.bae@xxxxxxxxx/

Patch 1 ~ 3, x86 code, which lay the foundation of following KVM patches.
Have been reviewed by Tony Luck.
Patch 4 ~ 9, KVM enabling of Key Locker.
Patch 10 ~ 15, nested VMX support for Key Locker.

[1] Intel Architecture Instruction Set Extensions Programming Reference:
https://software.intel.com/content/www/us/en/develop/download/intel-architecture-instruction-set-extensions-programming-reference.html

[2] Intel Key Locker Specification:
https://software.intel.com/content/www/us/en/develop/download/intel-key-locker-specification.html 

[3] Kernel enablement patch:
https://lore.kernel.org/lkml/20201216174146.10446-1-chang.seok.bae@xxxxxxxxx/

[4] It's possible to use Key Locker by both the guest and host, albeit with
reduced security benefits. I.e., store host IWKey in VMM scoped place
(memory/register), VMM switches host-IWKey and guest-IWKey between
VM-{Exit/Entry} by LOADIWKEY instruction.
But in this case, an adversary that can observe arbitrary VMM memory may be
able to steal both the handles and IWKey. And this case also require the
VMM to be running before the first IWKey load.

---
Change log since last RFC patch set:
* Don't loadiwkey every VM-Exit/Entry. (Sean Christopherson)
* Don't enable Tertiary VM-Exec Control if using eVMCS, as its support in
enlightened VMCS isn't ready yet. (Vitaly Kuznetsov)
* Extended BUILD_CONTROLS_SHADOW to support 64-bit variation. (Sean
Christopherson)
* Refactored patch set and other changes.


Hu, Robert (2):
kvm/vmx: Detect Tertiary VM-Execution control when setup VMCS config
kvm/vmx: dump_vmcs() reports tertiary_exec_control field as well

Robert Hoo (13):
x86/keylocker: Move KEYSRC_{SW,HW}RAND to keylocker.h
x86/cpufeatures: Define Key Locker sub feature flags
x86/feat_ctl: Add new VMX feature, Tertiary VM-Execution control and
LOADIWKEY Exiting
kvm/vmx: Extend BUILD_CONTROLS_SHADOW macro to support 64-bit
variation
kvm/vmx: Set Tertiary VM-Execution control field When init vCPU's VMCS
kvm/vmx: Add KVM support on guest Key Locker operations
kvm/cpuid: Enumerate Key Locker feature in KVM
kvm/vmx/nested: Support new IA32_VMX_PROCBASED_CTLS3 vmx capability
MSR
kvm/vmx: Implement vmx_compute_tertiary_exec_control()
kvm/vmx/vmcs12: Add Tertiary VM-Exec control field in vmcs12
kvm/vmx/nested: Support Tertiary VM-Exec control in vmcs02
kvm/vmx/nested: Support CR4.KL in nested
kvm/vmx/nested: Enable nested LOADIWKEY VM-exit

arch/x86/include/asm/cpufeatures.h | 5 +
arch/x86/include/asm/keylocker.h | 3 +
arch/x86/include/asm/kvm_host.h | 24 ++-
arch/x86/include/asm/msr-index.h | 1 +
arch/x86/include/asm/vmx.h | 9 ++
arch/x86/include/asm/vmxfeatures.h | 6 +-
arch/x86/include/uapi/asm/vmx.h | 2 +
arch/x86/kernel/cpu/feat_ctl.c | 9 ++
arch/x86/kernel/cpu/scattered.c | 5 +
arch/x86/kernel/keylocker.c | 2 -
arch/x86/kvm/cpuid.c | 26 +++-
arch/x86/kvm/reverse_cpuid.h | 32 +++-
arch/x86/kvm/vmx/capabilities.h | 9 ++
arch/x86/kvm/vmx/evmcs.c | 2 +
arch/x86/kvm/vmx/evmcs.h | 1 +
arch/x86/kvm/vmx/nested.c | 38 ++++-
arch/x86/kvm/vmx/nested.h | 7 +
arch/x86/kvm/vmx/vmcs.h | 1 +
arch/x86/kvm/vmx/vmcs12.c | 1 +
arch/x86/kvm/vmx/vmcs12.h | 4 +-
arch/x86/kvm/vmx/vmx.c | 290 ++++++++++++++++++++++++++++++++++++-
arch/x86/kvm/vmx/vmx.h | 24 +--
arch/x86/kvm/x86.c | 2 +
arch/x86/kvm/x86.h | 2 +
24 files changed, 475 insertions(+), 30 deletions(-)

--
1.8.3.1