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 b0f48d2b2cc7ec0e19ce0e16dc59e9169b63b0e0
parent 252b11a01e061fd17821e53a41c8451a1d2c27bd
Author: Louis Burda <quent.burda@gmail.com>
Date:   Tue, 10 Jan 2023 17:08:18 +0100

Stash fixups

Diffstat:
M.gitignore | 6+-----
MMakefile | 18+++++-------------
MREADME | 8++++++++
Acachepc/.gitignore | 3+++
Dcachepc/mmu.c | 162-------------------------------------------------------------------------------
Mcachepc/track.h | 11-----------
Mextra/.config | 3++-
7 files changed, 19 insertions(+), 192 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -1,10 +1,6 @@ build.sh push.sh .vscode -*.o.cmd -*.o -*.o.d -*.out -*.swp .cache +linux-* compile_commands.json diff --git a/Makefile b/Makefile @@ -14,8 +14,8 @@ CFLAGS = -I . -I linux/usr/include -I test -Wunused-variable -Wunknown-pragmas all: build $(BINS) clean: - $(MAKE) -C $(LINUX) SUBDIRS=arch/x86/kvm clean - $(MAKE) -C $(LINUX) SUBDIRS=crypto clean + $(MAKE) -C $(LINUX) clean M=arch/x86/kvm + $(MAKE) -C $(LINUX) clean M=crypto rm $(BINS) $(LINUX)/arch/x86/kvm/cachepc: @@ -27,16 +27,14 @@ host: git -C $(LINUX) add . git -C $(LINUX) stash git -C $(LINUX) checkout 0aaa1e5 - $(MAKE) -C $(LINUX) oldconfig - $(MAKE) -C $(LINUX) prepare - $(MAKE) -C $(LINUX) -j $(JOBS) -l $(LOAD) - $(MAKE) -C $(LINUX) -j $(JOBS) -l $(LOAD) headers + rm -f $(LINUX)/arch/x86/kvm/cachepc + $(MAKE) -C $(LINUX) -j $(JOBS) -l $(LOAD) bindeb-pkg git -C $(LINUX) checkout master git -C $(LINUX) stash pop build: $(LINUX)/arch/x86/kvm/cachepc $(MAKE) -C $(LINUX) -j $(JOBS) -l $(LOAD) M=arch/x86/kvm modules - $(MAKE) -C $(LINUX) -j $(JOBS) -l $(LOAD) M=crypto modules + #$(MAKE) -C $(LINUX) -j $(JOBS) -l $(LOAD) M=crypto modules load: sudo rmmod kvm_amd || true @@ -52,12 +50,6 @@ freq: update: git -C $(LINUX) diff 0aaa1e599bee256b3b15643bbb95e80ce7aa9be5 -G. > patch.diff -test/aes-detect_%: test/aes-detect_%.c test/aes-detect.c cachepc/uapi.h - clang -o $@ $< $(CFLAGS) -I test/libkcapi/lib -L test/libkcapi/.libs -lkcapi -static - -test/access-detect_%: test/access-detect_%.c cachepc/uapi.h - clang -o $@ $< $(CFLAGS) -static - test/%: test/%.c cachepc/uapi.h clang -o $@ $< $(CFLAGS) -fsanitize=address diff --git a/README b/README @@ -43,3 +43,11 @@ test/qemu-poc: Demonstrate that AES encryption keys can be leaked from an unmodified qemu-based linux guest. +Testing was done on a bare-metal AMD EPYC 72F3 (Family 0x19, Model 0x01). + +To successfully build and load the kvm.ko and kvm-amd.ko modules, ensure +that a host kernel debian package was built using `make host`. + +Note: because of bad decisions made in regards to version control, +the checked out commit of the modified kernel (previously the +kernel patch file) might be incorrect for older revisions. diff --git a/cachepc/.gitignore b/cachepc/.gitignore @@ -0,0 +1,3 @@ +*.o +*.o.d +*.o.cmd diff --git a/cachepc/mmu.c b/cachepc/mmu.c @@ -1,162 +0,0 @@ -#include "../cachepc/cachepc.h" -#include "../cachepc/track.h" -#include "../cachepc/event.h" -#include "svm/svm.h" - -static bool -cachepc_page_fault_handle(struct kvm_vcpu *vcpu, - struct kvm_page_fault *fault) -{ - int modes[] = { - KVM_PAGE_TRACK_EXEC, - KVM_PAGE_TRACK_ACCESS, - }; - struct cpc_fault *tmp, *alloc; - size_t count, i; - bool inst_fetch; - - /* return true if the page fault was related to tracking and should not be handled, - * return false if the page fault should be handled */ - - for (i = 0; i < 2; i++) { - if (kvm_slot_page_track_is_active(vcpu->kvm, - fault->slot, fault->gfn, modes[i])) - break; - } - if (i == 2) { - CPC_INFO("Untracked page fault (gfn:%llu err:%u)\n", - fault->gfn, fault->error_code); - return false; - } - - CPC_DBG("Tracked page fault (gfn:%llu err:%u)\n", - fault->gfn, fault->error_code); - - inst_fetch = fault->error_code & PFERR_FETCH_MASK; - CPC_DBG("Tracked page fault attrs p:%i w:%i x:%i f:%i\n", - fault->present, fault->write, fault->exec, inst_fetch); - - count = 0; - list_for_each_entry(tmp, &cachepc_faults, list) - count += 1; - - if (cachepc_track_mode == CPC_TRACK_FULL) { - CPC_INFO("Got %lu. fault gfn:%llu err:%u\n", count + 1, - fault->gfn, fault->error_code); - - cachepc_untrack_single(vcpu, fault->gfn, modes[i]); - - alloc = kmalloc(sizeof(struct cpc_fault), GFP_KERNEL); - BUG_ON(!alloc); - alloc->gfn = fault->gfn; - alloc->err = fault->error_code; - list_add_tail(&alloc->list, &cachepc_faults); - - cachepc_single_step = true; - cachepc_apic_timer = 0; - - return false; /* setup untracked page */ - } else if (cachepc_track_mode == CPC_TRACK_EXEC) { - if (!inst_fetch || !fault->present) return false; - - if (count == 1) { - return false; /* dont untrack, but 'handle' */ - } - - CPC_INFO("Got %lu. fault gfn:%llu err:%u\n", count + 1, - fault->gfn, fault->error_code); - - cachepc_untrack_single(vcpu, fault->gfn, modes[i]); - - if (modes[i] != KVM_PAGE_TRACK_EXEC) - CPC_WARN("Wrong page track mode for TRACK_EXEC"); - - alloc = kmalloc(sizeof(struct cpc_fault), GFP_KERNEL); - BUG_ON(!alloc); - alloc->gfn = fault->gfn; - alloc->err = fault->error_code; - list_add_tail(&alloc->list, &cachepc_faults); - - cachepc_single_step = true; - cachepc_apic_timer = 0; - } else if (cachepc_track_mode == CPC_TRACK_STUB) { - cachepc_send_track_step_event(&cachepc_faults); - } - - return true; -} - -bool -cachepc_spte_protect(u64 *sptep, bool pt_protect, enum kvm_page_track_mode mode) -{ - u64 spte; - - spte = *sptep; - if (!is_writable_pte(spte) && !(pt_protect && is_mmu_writable_spte(spte))) - return false; - - if (pt_protect) - spte &= ~shadow_mmu_writable_mask; - - if (mode == KVM_PAGE_TRACK_WRITE) { - spte &= ~PT_WRITABLE_MASK; - } else if (mode == KVM_PAGE_TRACK_RESET_ACCESS) { - spte &= ~PT_ACCESSED_MASK; - } else if (mode == KVM_PAGE_TRACK_ACCESS) { - spte &= ~PT_PRESENT_MASK; - spte &= ~PT_WRITABLE_MASK; - spte &= ~PT_USER_MASK; - spte |= (0x1ULL << PT64_NX_SHIFT); - } else if (mode == KVM_PAGE_TRACK_EXEC) { - spte |= (0x1ULL << PT64_NX_SHIFT); - } else if (mode == KVM_PAGE_TRACK_RESET_EXEC) { - spte &= ~(0x1ULL << PT64_NX_SHIFT); - } - - mmu_spte_update(sptep, spte); - - return true; -} -EXPORT_SYMBOL(cachepc_spte_protect); - -bool cachepc_rmap_protect(struct kvm_rmap_head *rmap_head, - bool pt_protect, enum kvm_page_track_mode mode) -{ - struct rmap_iterator iter; - bool flush; - u64 *sptep; - - flush = false; - for_each_rmap_spte(rmap_head, &iter, sptep) { - flush |= cachepc_spte_protect(sptep, pt_protect, mode); - } - - return flush; -} -EXPORT_SYMBOL(cachepc_rmap_protect); - -bool -cachepc_kvm_mmu_slot_gfn_protect(struct kvm *kvm, struct kvm_memory_slot *slot, - uint64_t gfn, int min_level, enum kvm_page_track_mode mode) -{ - struct kvm_rmap_head *rmap_head; - bool flush; - int i; - - flush = false; - - if (kvm_memslots_have_rmaps(kvm)) { - for (i = min_level; i <= KVM_MAX_HUGEPAGE_LEVEL; ++i) { - rmap_head = gfn_to_rmap(gfn, i, slot); - flush |= cachepc_rmap_protect(rmap_head, true, mode); - } - } else if (is_tdp_mmu_enabled(kvm)) { - flush |= cachepc_tdp_protect_gfn(kvm, slot, gfn, min_level, mode); - } else { - CPC_ERR("Tracking unsupported!\n"); - } - - return flush; -} -EXPORT_SYMBOL(cachepc_kvm_mmu_slot_gfn_protect); - diff --git a/cachepc/track.h b/cachepc/track.h @@ -12,17 +12,6 @@ extern struct kvm* main_vm; -/* defined in mmu.c as they rely on static mmu-internal functions */ -bool cachepc_spte_protect(u64 *sptep, - bool pt_protect, enum kvm_page_track_mode mode); -bool cachepc_rmap_protect(struct kvm_rmap_head *rmap_head, - bool pt_protect, enum kvm_page_track_mode mode); -bool cachepc_kvm_mmu_slot_gfn_protect(struct kvm *kvm, struct kvm_memory_slot *slot, - uint64_t gfn, int min_level, enum kvm_page_track_mode mode); - -bool cachepc_tdp_protect_gfn(struct kvm *kvm, struct kvm_memory_slot *slot, - gfn_t gfn, int min_level, int mode); - bool cachepc_track_single(struct kvm_vcpu *vcpu, gfn_t gfn, enum kvm_page_track_mode mode); bool cachepc_untrack_single(struct kvm_vcpu *vcpu, gfn_t gfn, diff --git a/extra/.config b/extra/.config @@ -27,6 +27,7 @@ CONFIG_THREAD_INFO_IN_TASK=y CONFIG_INIT_ENV_ARG_LIMIT=32 # CONFIG_COMPILE_TEST is not set # CONFIG_WERROR is not set +# CONFIG_UAPI_HEADER_TEST is not set CONFIG_LOCALVERSION="-snp-host-0aaa1e599bee" # CONFIG_LOCALVERSION_AUTO is not set CONFIG_BUILD_SALT="5.10.0-17-amd64" @@ -10012,7 +10013,7 @@ CONFIG_DEBUG_INFO_NONE=y CONFIG_FRAME_WARN=2048 CONFIG_STRIP_ASM_SYMS=y # CONFIG_READABLE_ASM is not set -# CONFIG_HEADERS_INSTALL is not set +CONFIG_HEADERS_INSTALL=y # CONFIG_DEBUG_SECTION_MISMATCH is not set CONFIG_SECTION_MISMATCH_WARN_ONLY=y # CONFIG_DEBUG_FORCE_FUNCTION_ALIGN_64B is not set