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 4dd9fe04e1399e8629ab2a98b54db6a7dcdb0076
parent 0d4f62bcc065026390dd1f19b0bb462d07dcf9ff
Author: Louis Burda <quent.burda@gmail.com>
Date:   Sun,  5 Feb 2023 16:02:54 -0600

Fix stepping inconsistency by moving oneshot after primee

Diffstat:
Mcachepc/cachepc.c | 7+++++--
Mcachepc/cachepc.h | 7++++---
Mcachepc/const.h | 6------
Mcachepc/kvm.c | 13+++++++------
Mtest/kvm-step.c | 19+++++++++++--------
Mtest/kvm-step_guest.S | 4++++
Mtest/kvm-targetstep_guest | 4++--
Mtest/kvm-targetstep_guest.S | 10++++++++--
8 files changed, 41 insertions(+), 29 deletions(-)

diff --git a/cachepc/cachepc.c b/cachepc/cachepc.c @@ -214,7 +214,10 @@ cpc_print_msrmts(struct cpc_cl *head) void cpc_apic_oneshot_run(uint32_t interval) { + /* APIC divisor determines how much time is added per increment. + * A large divisor decreases the counter slower, which means more time + * is added for each increment, possiblpy skipping whole instructions */ native_apic_mem_write(APIC_LVTT, LOCAL_TIMER_VECTOR | APIC_LVT_TIMER_ONESHOT); - native_apic_mem_write(APIC_TDCR, CPC_APIC_TIMER_TDCR); - native_apic_mem_write(APIC_TMICT, interval / CPC_APIC_TIMER_SOFTDIV); + native_apic_mem_write(APIC_TDCR, APIC_TDR_DIV_1); + native_apic_mem_write(APIC_TMICT, interval / cpc_apic_timer_softdiv); } diff --git a/cachepc/cachepc.h b/cachepc/cachepc.h @@ -108,9 +108,10 @@ extern bool cpc_long_step; extern bool cpc_apic_oneshot; extern int32_t cpc_apic_timer; -extern uint32_t cpc_apic_timer_min; -extern uint32_t cpc_apic_timer_dec_npf; -extern uint32_t cpc_apic_timer_dec_intr; +extern int32_t cpc_apic_timer_softdiv; +extern int32_t cpc_apic_timer_min; +extern int32_t cpc_apic_timer_dec_npf; +extern int32_t cpc_apic_timer_dec_intr; extern uint32_t cpc_track_mode; extern uint64_t cpc_track_start_gfn; diff --git a/cachepc/const.h b/cachepc/const.h @@ -23,12 +23,6 @@ #define CPC_CL_PREV_OFFSET 8 #define CPC_CL_COUNT_OFFSET 16 -/* APIC divisor determines how much time is added per increment. - * A large divisor decreases the counter slower, which means more time - * is added for each increment, possiblpy skipping whole instructions */ -#define CPC_APIC_TIMER_TDCR APIC_TDR_DIV_1 -#define CPC_APIC_TIMER_SOFTDIV 1 - #define CPC_EVENT_BATCH_MAX 10000 #define CPC_LOGLVL_INFO 1 diff --git a/cachepc/kvm.c b/cachepc/kvm.c @@ -64,9 +64,11 @@ int32_t cpc_apic_timer = 0; EXPORT_SYMBOL(cpc_apic_oneshot); EXPORT_SYMBOL(cpc_apic_timer); -uint32_t cpc_apic_timer_min = 0; -uint32_t cpc_apic_timer_dec_npf = 0; -uint32_t cpc_apic_timer_dec_intr = 0; +int32_t cpc_apic_timer_softdiv = 1; +int32_t cpc_apic_timer_min = 0; +int32_t cpc_apic_timer_dec_npf = 0; +int32_t cpc_apic_timer_dec_intr = 0; +EXPORT_SYMBOL(cpc_apic_timer_softdiv); EXPORT_SYMBOL(cpc_apic_timer_min); EXPORT_SYMBOL(cpc_apic_timer_dec_npf); EXPORT_SYMBOL(cpc_apic_timer_dec_intr); @@ -481,6 +483,7 @@ cpc_track_mode_ioctl(void __user *arg_user) cpc_singlestep_reset = false; cpc_long_step = false; + cpc_apic_timer_softdiv = 3; if (sev_es_guest(vcpu->kvm)) { cpc_apic_timer_min = 200; cpc_apic_timer_dec_npf = 25; @@ -506,9 +509,6 @@ cpc_track_mode_ioctl(void __user *arg_user) cpc_track_all(vcpu, KVM_PAGE_TRACK_EXEC); break; case CPC_TRACK_STEPS: - cpc_apic_timer_min = 7000; - cpc_apic_timer_dec_npf = 50; - cpc_apic_timer_dec_intr = 100; cpc_track_steps.use_target = cfg.steps.use_target; cpc_track_steps.target_gfn = cfg.steps.target_gfn; cpc_track_steps.with_data = cfg.steps.with_data; @@ -714,6 +714,7 @@ cpc_kvm_init(void) cpc_apic_oneshot = false; cpc_apic_timer = 0; + cpc_apic_timer_softdiv = 1; cpc_apic_timer_min = 0; cpc_apic_timer_dec_npf = 0; cpc_apic_timer_dec_intr = 0; diff --git a/test/kvm-step.c b/test/kvm-step.c @@ -66,14 +66,17 @@ main(int argc, const char **argv) struct cpc_track_cfg cfg; uint64_t eventcnt; uint32_t arg; + bool with_data; int ret; - vmtype = "kvm"; - if (argc > 1) vmtype = argv[1]; - if (strcmp(vmtype, "kvm") && strcmp(vmtype, "sev") - && strcmp(vmtype, "sev-es") - && strcmp(vmtype, "sev-snp")) - errx(1, "invalid vm mode: %s", vmtype); + with_data = true; + if (argc > 1 && !strcmp(argv[1], "--exec-only")) { + with_data = false; + argc--; + argv++; + } + + parse_vmtype(argc, argv); setvbuf(stdout, NULL, _IONBF, 0); @@ -122,7 +125,7 @@ main(int argc, const char **argv) memset(&cfg, 0, sizeof(cfg)); cfg.mode = CPC_TRACK_STEPS; - cfg.steps.with_data = true; + cfg.steps.with_data = with_data; ret = ioctl(kvm_dev, KVM_CPC_TRACK_MODE, &cfg); if (ret) err(1, "KVM_CPC_TRACK_MODE"); @@ -173,7 +176,7 @@ main(int argc, const char **argv) if (ret) err(1, "KVM_CPC_ACK_EVENT"); eventcnt = 0; - while (eventcnt < 50) { + while (eventcnt < 110) { eventcnt += monitor(&kvm, false); } diff --git a/test/kvm-step_guest.S b/test/kvm-step_guest.S @@ -7,6 +7,10 @@ .code16gcc guest: +.rept 100 + nop +.endr + mov $(L1_LINESIZE * (L1_SETS + 11)), %bx movb (%bx), %bl hlt diff --git a/test/kvm-targetstep_guest b/test/kvm-targetstep_guest @@ -1 +1 @@ - -\ No newline at end of file + +\ No newline at end of file diff --git a/test/kvm-targetstep_guest.S b/test/kvm-targetstep_guest.S @@ -25,8 +25,14 @@ guest: mov $(L1_LINESIZE * (L1_SETS + 15)), %bx movb (%bx), %bl - # this should only be partially single-stepped if - # single-stepping is limited to the first page + jmp skip +.rept L1_LINESIZE * L1_SETS + nop +.endr +skip: + + # these nops should not be single-stepped + # since they are outside the target gfn .rept L1_LINESIZE * L1_SETS * 2 nop .endr