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 1ffb06efd201e4d754a6295f70aecbe59152f18a
parent d8a7efe6eccefaf09c71889d808a57f4c17cbb2e
Author: Louis Burda <quent.burda@gmail.com>
Date:   Sat, 12 Nov 2022 01:41:43 +0100

Implement track mode instead of just cachepc_track_single_step

Diffstat:
Mcachepc/cachepc.h | 4+++-
Mcachepc/kvm.c | 20++++++++++----------
Mcachepc/mmu.c | 84+++++++++++++++++++++++++++++++++++++++++++++----------------------------------
Mcachepc/uapi.h | 8+++++++-
Mtest/sevstep.c | 8++++----
5 files changed, 72 insertions(+), 52 deletions(-)

diff --git a/cachepc/cachepc.h b/cachepc/cachepc.h @@ -127,11 +127,13 @@ extern bool cachepc_baseline_active; extern uint64_t cachepc_retinst; extern bool cachepc_single_step; -extern bool cachepc_track_single_step; +extern uint32_t cachepc_track_mode; extern uint32_t cachepc_apic_timer; + extern bool cachepc_inst_fault_avail; extern uint64_t cachepc_inst_fault_gfn; extern uint32_t cachepc_inst_fault_err; + extern bool cachepc_data_fault_avail; extern uint64_t cachepc_data_fault_gfn; extern uint32_t cachepc_data_fault_err; diff --git a/cachepc/kvm.c b/cachepc/kvm.c @@ -29,10 +29,10 @@ uint64_t cachepc_retinst = 0; EXPORT_SYMBOL(cachepc_retinst); bool cachepc_single_step = false; -bool cachepc_track_single_step = false; +uint32_t cachepc_track_mode = false; uint32_t cachepc_apic_timer = 0; EXPORT_SYMBOL(cachepc_single_step); -EXPORT_SYMBOL(cachepc_track_single_step); +EXPORT_SYMBOL(cachepc_track_mode); EXPORT_SYMBOL(cachepc_apic_timer); bool cachepc_inst_fault_avail = false; @@ -91,7 +91,7 @@ static int cachepc_kvm_measure_baseline_ioctl(void __user *arg_user); static int cachepc_kvm_read_baseline_ioctl(void __user *arg_user); static int cachepc_kvm_sub_baseline_ioctl(void __user *arg_user); static int cachepc_kvm_single_step_ioctl(void __user *arg_user); -static int cachepc_kvm_track_single_step_ioctl(void __user *arg_user); +static int cachepc_kvm_track_mode_ioctl(void __user *arg_user); static int cachepc_kvm_track_page_ioctl(void __user *arg_user); static int cachepc_kvm_track_all_ioctl(void __user *arg_user); @@ -478,16 +478,16 @@ cachepc_kvm_single_step_ioctl(void __user *arg_user) } int -cachepc_kvm_track_single_step_ioctl(void __user *arg_user) +cachepc_kvm_track_mode_ioctl(void __user *arg_user) { - uint32_t state; + uint32_t mode; if (!arg_user) return -EINVAL; - if (copy_from_user(&state, arg_user, sizeof(state))) + if (copy_from_user(&mode, arg_user, sizeof(mode))) return -EFAULT; - cachepc_track_single_step = state; + cachepc_track_mode = mode; return 0; } @@ -649,8 +649,8 @@ cachepc_kvm_ioctl(struct file *file, unsigned int ioctl, unsigned long arg) return cachepc_kvm_sub_baseline_ioctl(arg_user); case KVM_CPC_SINGLE_STEP: return cachepc_kvm_single_step_ioctl(arg_user); - case KVM_CPC_TRACK_SINGLE_STEP: - return cachepc_kvm_track_single_step_ioctl(arg_user); + case KVM_CPC_TRACK_MODE: + return cachepc_kvm_track_mode_ioctl(arg_user); case KVM_CPC_VMSA_READ: return cachepc_kvm_vmsa_read_ioctl(arg_user); case KVM_CPC_TRACK_PAGE: @@ -707,7 +707,7 @@ cachepc_kvm_init(void) cachepc_retinst = 0; cachepc_single_step = false; - cachepc_track_single_step = false; + cachepc_track_mode = CPC_TRACK_ACCESS; cachepc_apic_timer = 200; cachepc_data_fault_avail = false; diff --git a/cachepc/mmu.c b/cachepc/mmu.c @@ -8,44 +8,56 @@ sevstep_uspt_page_fault_handle(struct kvm_vcpu *vcpu, { int err; - if (kvm_slot_page_track_is_active(vcpu->kvm, - fault->slot, fault->gfn, KVM_PAGE_TRACK_ACCESS)) { - pr_warn("Sevstep: Tracked page fault (gfn:%llu err:%u)\n", - fault->gfn, fault->error_code); - //pr_warn("Sevstep: Tracked page fault attrs %i %i %i\n", - // fault->present, fault->write, fault->user); - - sevstep_untrack_single(vcpu, fault->gfn, KVM_PAGE_TRACK_ACCESS); - - if (cachepc_track_single_step) { - if (cachepc_single_step && cachepc_inst_fault_avail) { - /* second fault from data access */ - pr_warn("Sevstep: Got data fault gfn:%llu err:%u\n", - fault->gfn, fault->error_code); - - cachepc_data_fault_gfn = fault->gfn; - cachepc_data_fault_err = fault->error_code; - cachepc_data_fault_avail = true; - - cachepc_apic_timer = 160; - } else { - /* first fault from instruction fetch */ - pr_warn("Sevstep: Got inst fault gfn:%llu err:%u\n", - fault->gfn, fault->error_code); - - cachepc_inst_fault_gfn = fault->gfn; - cachepc_inst_fault_err = fault->error_code; - cachepc_inst_fault_avail = true; - cachepc_data_fault_avail = false; - - cachepc_single_step = true; - cachepc_apic_timer = 170; - } + if (!kvm_slot_page_track_is_active(vcpu->kvm, + fault->slot, fault->gfn, KVM_PAGE_TRACK_ACCESS)) + return; + + pr_warn("Sevstep: Tracked page fault (gfn:%llu err:%u)\n", + fault->gfn, fault->error_code); + //pr_warn("Sevstep: Tracked page fault attrs %i %i %i\n", + // fault->present, fault->write, fault->user); + + sevstep_untrack_single(vcpu, fault->gfn, KVM_PAGE_TRACK_ACCESS); + + if (cachepc_track_mode == CPC_TRACK_DATA_ACCESS) { + if (cachepc_single_step && cachepc_inst_fault_avail) { + /* second fault from data access */ + pr_warn("Sevstep: Got data fault gfn:%llu err:%u\n", + fault->gfn, fault->error_code); + + cachepc_data_fault_gfn = fault->gfn; + cachepc_data_fault_err = fault->error_code; + cachepc_data_fault_avail = true; + + cachepc_apic_timer = 160; } else { - sevstep_track_single(vcpu, fault->gfn, KVM_PAGE_TRACK_ACCESS); - if (sevstep_uspt_send_and_block(fault->gfn, fault->error_code, 0, 0)) - pr_warn("Sevstep: uspt_send_and_block failed (%d)\n", err); + /* first fault from instruction fetch */ + pr_warn("Sevstep: Got inst fault gfn:%llu err:%u\n", + fault->gfn, fault->error_code); + + cachepc_inst_fault_gfn = fault->gfn; + cachepc_inst_fault_err = fault->error_code; + cachepc_inst_fault_avail = true; + cachepc_data_fault_avail = false; + + cachepc_single_step = true; + cachepc_apic_timer = 170; + } + } else if (cachepc_track_mode == CPC_TRACK_EXEC_PAGES) { + /* TODO: skip if not exec */ + /* TODO: calculate retired instructions (save and subtract global counter) */ + if (cachepc_inst_fault_avail) { + sevstep_track_single(vcpu, cachepc_inst_fault_gfn, + KVM_PAGE_TRACK_ACCESS); } + cachepc_inst_fault_gfn = fault->gfn; + cachepc_inst_fault_err = fault->error_code; + if (sevstep_uspt_send_and_block(fault->gfn, fault->error_code, 0, 0)) + pr_warn("Sevstep: uspt_send_and_block failed (%d)\n", err); + } else if (cachepc_track_mode == CPC_TRACK_ACCESS) { + sevstep_track_single(vcpu, fault->gfn, KVM_PAGE_TRACK_ACCESS); + if (sevstep_uspt_send_and_block(fault->gfn, fault->error_code, 0, 0)) + pr_warn("Sevstep: uspt_send_and_block failed (%d)\n", err); } } diff --git a/cachepc/uapi.h b/cachepc/uapi.h @@ -31,7 +31,7 @@ #define KVM_CPC_READ_BASELINE _IOR(KVMIO, 0x27, __u64) #define KVM_CPC_SUB_BASELINE _IOR(KVMIO, 0x28, __u32) #define KVM_CPC_SINGLE_STEP _IO(KVMIO, 0x29) -#define KVM_CPC_TRACK_SINGLE_STEP _IOWR(KVMIO, 0x2A, __u32) +#define KVM_CPC_TRACK_MODE _IOWR(KVMIO, 0x2A, __u32) #define KVM_CPC_VMSA_READ _IOR(KVMIO, 0x2B, __u64) #define KVM_CPC_TRACK_PAGE _IOWR(KVMIO, 0x30, struct cpc_track_config) @@ -41,6 +41,12 @@ #define KVM_CPC_POLL_EVENT _IOWR(KVMIO, 0x34, struct cpc_track_event) #define KVM_CPC_ACK_EVENT _IOWR(KVMIO, 0x35, __u64) +enum { + CPC_TRACK_ACCESS, + CPC_TRACK_DATA_ACCESS, + CPC_TRACK_EXEC_PAGES +}; + enum kvm_page_track_mode { KVM_PAGE_TRACK_WRITE, KVM_PAGE_TRACK_ACCESS, diff --git a/test/sevstep.c b/test/sevstep.c @@ -629,7 +629,7 @@ monitor(struct kvm *kvm, bool baseline) if (!ret) { if (!baseline) { rip = sev_dbg_rip(kvm->vmfd); - printf("Event: inst:%llu data:%llu retired:%llu rip:%llu\n", + printf("Event: inst:%llu data:%llu retired:%llu rip:%lu\n", event.inst_fault_gfn, event.data_fault_gfn, event.retinst, rip); } @@ -701,9 +701,9 @@ main(int argc, const char **argv) if (ret == -1) err(1, "ioctl RESET_TRACKING"); /* Do data access stepping */ - arg = true; - ret = ioctl(kvm_dev, KVM_CPC_TRACK_SINGLE_STEP, &arg); - if (ret == -1) err(1, "ioctl TRACK_SINGLE_STEP"); + arg = CPC_TRACK_DATA_ACCESS; + ret = ioctl(kvm_dev, KVM_CPC_TRACK_MODE, &arg); + if (ret == -1) err(1, "ioctl TRACK_MODE"); /* Init page tracking */ track_mode = KVM_PAGE_TRACK_ACCESS;