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 df90539b9e7ee75c206d5b77d4f1b94882d090c7
parent 039144b8e7f7fb4074883e8037787d420e86f70c
Author: Louis Burda <quent.burda@gmail.com>
Date:   Wed,  1 Feb 2023 16:57:26 -0600

Add guest provisioning scripts and instructions

Diffstat:
M.gitmodules | 3+++
AAMDSEV | 1+
MREADME | 105+++++++++++++++++++++++++++++++++++++++++++++++--------------------------------
Mcachepc/macro.S | 2++
Aqemu/.gitignore | 7+++++++
Aqemu/cmdline | 1+
Aqemu/install.sh | 31+++++++++++++++++++++++++++++++
Aqemu/launch-victim.sh | 31+++++++++++++++++++++++++++++++
Aqemu/launch.sh | 17+++++++++++++++++
9 files changed, 156 insertions(+), 42 deletions(-)

diff --git a/.gitmodules b/.gitmodules @@ -4,3 +4,6 @@ [submodule "cachepc-linux"] path = linux url = git@github.com:Sinitax/cachepc-linux.git +[submodule "cachepc-AMDSEV"] + path = AMDSEV + url = git@github.com:Sinitax/cachepc-AMDSEV.git diff --git a/AMDSEV b/AMDSEV @@ -0,0 +1 @@ +Subproject commit a3c82f656a1364b11d61bf493742a3f7cb91e500 diff --git a/README b/README @@ -14,75 +14,75 @@ tests Several test-cases were used to verify parts of the exploit chain separately: test/eviction: - Demonstrate that performance counters & our setup are accurate enough - to detect a single eviction in L1 cache and infer its cache set - through PRIME+COUNT + Demonstrate that performance counters & our setup are accurate enough + to detect a single eviction in L1 cache and infer its cache set + through PRIME+COUNT test/kvm-eviction: - Demonstrate that the cache set of a memory access instruction can be - inferred in non-SEV / SEV / SEV-ES / SEV-SNP -enabled vms respectively. + Demonstrate that the cache set of a memory access instruction can be + inferred in non-SEV / SEV / SEV-ES / SEV-SNP -enabled vms respectively. test/kvm-step: - Demonstrate that SEV-SNP enabled vms can be single-stepped using local - APIC timers to interrupt the guest and increment the interrupt interval - while observing the RIP+RFLAGS ciphertext in the VMSA for changes to - detect that a single instruction has been executed. + Demonstrate that SEV-SNP enabled vms can be single-stepped using local + APIC timers to interrupt the guest and increment the interrupt interval + while observing the RIP+RFLAGS ciphertext in the VMSA for changes to + detect that a single instruction has been executed. test/kvm-pagestep: - Demonstrate that a SEV-SNP enabled vm can be quickly single-stepped - and analyzed by tracking a single page at a time. This type - of tracking creates a page-wise profile of the guests execution, - which can be used to infer what the guest is doing and to begin - fine-grained single-stepping. + Demonstrate that a SEV-SNP enabled vm can be quickly single-stepped + and analyzed by tracking a single page at a time. This type + of tracking creates a page-wise profile of the guests execution, + which can be used to infer what the guest is doing and to begin + fine-grained single-stepping. test/qemu-pagestep: - Replicate result from kvm-pagestep on a qemu-based vm running debian. + Replicate result from kvm-pagestep on a qemu-based vm running debian. test/qemu-eviction: - Replicate result from kvm-eviction on a qemu-based vm running debian - using a specially crafted guest program to signal when measurement - should take place to infer the accessed set. + Replicate result from kvm-eviction on a qemu-based vm running debian + using a specially crafted guest program to signal when measurement + should take place to infer the accessed set. test/qemu-aes: - Demonstrate that AES encryption keys can be leaked from a - modified qemu-based linux guest. + Demonstrate that AES encryption keys can be leaked from a + modified qemu-based linux guest. test/qemu-poc: - Demonstrate that AES encryption keys can be leaked from an - unmodified qemu-based linux guest. + Demonstrate that AES encryption keys can be leaked from an + unmodified qemu-based linux guest. -modes ------ +track modes +----------- The kernel module employs a few different modes of tracking described in more detail below: CPC_TRACK_FAULT_NO_RUN: - Tracks access to all guest pages and lets the guest page fault over and over - without untracking / handling any page faults. This results in a decent - baseline measurement when we dont want to step the vm. + Tracks access to all guest pages and lets the guest page fault over and over + without untracking / handling any page faults. This results in a decent + baseline measurement when we dont want to step the vm. CPC_TRACK_EXIT_EVICTION: - Set apic timer such that for any reasonably short KVM_RUN no local apic - interrupts will occur to cause exits. Good for collecting PRIME+COUNT - measurements over a clean run to a guest-invoked exit such as KVM_EXIT_HLT. + Set apic timer such that for any reasonably short KVM_RUN no local apic + interrupts will occur to cause exits. Good for collecting PRIME+COUNT + measurements over a clean run to a guest-invoked exit such as KVM_EXIT_HLT. CPC_TRACK_PAGES: - Track execution of all guest pages. While the guest is running, untrack - a single executable page at a time based on page-faults. Allows tracking - which guest pages are executed and how long using retired instructions. + Track execution of all guest pages. While the guest is running, untrack + a single executable page at a time based on page-faults. Allows tracking + which guest pages are executed and how long using retired instructions. CPC_TRACK_STEPS: - Single-step guest exection. For each step, collect either only instruction - or instruction and data page-faults. Allows tracking not only which sets were - evicted but what gfns were involved in the access. A target page can - be set, such that we will first page-step until the page is reached, - then single-step while running instructions on that page. + Single-step guest exection. For each step, collect either only instruction + or instruction and data page-faults. Allows tracking not only which sets were + evicted but what gfns were involved in the access. A target page can + be set, such that we will first page-step until the page is reached, + then single-step while running instructions on that page. -setup ------ +host setup +---------- Testing was done on a Supermicro H12SSL-i V1.01 motherboard and AMD EPYC 72F3 (Family 0x19, Model 0x01) cpu. The motherboard bios version is 2.4 and was @@ -97,8 +97,8 @@ sev-snp-devel at commmit a480a51. Install the host kernel by running: # ./install.sh -For the build to complete the following packages needed to be installed -following a clean install of debian linux-5.10.0-21: +For the build to complete the following packages were needed following +a clean install of debian linux-5.10.0-21: git build-essential flex dpkg bc rsync libelf-dev libssl-dev bison ninja-build pkg-config libglib2.0-dev libpixman-1-dev python3 coda nasm uuid-dev iasl @@ -136,6 +136,27 @@ $ cp $(AMDSEV_REPO)/linux/host/.config linux/.config $ make linux +guest setup +----------- + +Generate a guest image and install debian by running qemu/install.sh. +The virtual machine can either be controlled via vnc, or once the guest os +is installed via ssh, port forwarded to localhost:8000. + +Once debian is installed, launch the guest by running qemu/launch.sh and +copy over the compiled guest kernel packages from AMDSEV/linux on the host +and install them. Reboot the guest, make sure that `uname -r` matches +the expected version and copy that versions initrd and vmlinuz out of +/boot on the guest to qemu/ on the host. Also copy the guests /proc/cmdline +contents to qemu/cmdline on the host. + +Finally, run qemu/launch-victim.sh to launch a qemu guest ready to +be attacked. + + +troubleshooting +--------------- + In case SEV-SNP initialization fails due to a low firmware version, the firmware can be updated to v1.51 by running: diff --git a/cachepc/macro.S b/cachepc/macro.S @@ -4,6 +4,8 @@ .macro barrier mfence # memory barrier rdtsc # serializing + # mov $0x80000005, %rax + # cpuid # serializing (cpuid alone does not work) .endm # clobbers rax, rbx, rcx, rdx, (out) diff --git a/qemu/.gitignore b/qemu/.gitignore @@ -0,0 +1,7 @@ +monitor +stdout.log +*.fd +*.qcow2 +*.iso +initrd.img-* +vmlinuz-* diff --git a/qemu/cmdline b/qemu/cmdline @@ -0,0 +1 @@ +BOOT_IMAGE=/boot/vmlinuz-5.19.0-rc6-snp-guest-d9bd54fea4d2 root=UUID=a0bc580b-fe27-4aa9-b795-6bde981ba954 ro quiet diff --git a/qemu/install.sh b/qemu/install.sh @@ -0,0 +1,31 @@ +#!/bin/sh + +set -ex + +gitroot=$(git rev-parse --show-toplevel) +cd "$gitroot/qemu" + +DISK="debian11.qcow2" +DEBIANISO="debian-11.4.0-amd64-DVD-1.iso" + +if [ ! -e "$DISK" ]; then + echo "Creating guest disk.." + qemu-img create -f qcow2 "$DISK" 20G +fi + +if [ ! -e "$DEBIANISO" ]; then + echo "Downloading debian DVD image.." + wget "https://cdimage.debian.org/mirror/cdimage/archive/11.4.0/amd64/iso-dvd/debian-11.4.0-amd64-DVD-1.iso" -O "$DEBIANISO" +fi + +sudo LIBVIRT_DEBUG=1 virsh net-start default 2>&1 | grep -i warning || true + +sudo PREFIX="$gitroot/AMDSEV" "$gitroot/AMDSEV/launch-qemu.sh" \ + -hda "$DISK" \ + -console serial \ + -vnc 1 \ + -mem 2024 \ + -smp 1,cores=4,threads=2 \ + -allow-debug \ + -cdrom "$DEBIANISO" + diff --git a/qemu/launch-victim.sh b/qemu/launch-victim.sh @@ -0,0 +1,31 @@ +#!/bin/sh + +set -ex + +gitroot=$(git rev-parse --show-toplevel) +cd "$gitroot/qemu" + +if [ ! -e cmdline ]; then + echo "Missing qemu/cmdline.." + exit 1 +fi + +if [ ! -e debian11_encrypted.qcow2 ]; then + echo "Copying disk.." + rsync -a --info=progress2 debian11.qcow2 debian11_encrypted.qcow2 +fi + +sudo LIBVIRT_DEBUG=1 virsh net-start default 2>&1 | grep -i warning || true + +sudo PREFIX=$gitroot/AMDSEV $gitroot/AMDSEV/launch-qemu.sh \ + -hda debian11_encrypted.qcow2 \ + -console serial \ + -vnc 1 \ + -mem 2024 \ + -smp 1,cores=1,threads=1 \ + -allow-debug \ + -initrd initrd.img-5.19.0-rc6-snp-guest-d9bd54fea4d2 \ + -kernel vmlinuz-5.19.0-rc6-snp-guest-d9bd54fea4d2 \ + -append "$(cat cmdline)" \ + -sev-snp + diff --git a/qemu/launch.sh b/qemu/launch.sh @@ -0,0 +1,17 @@ +#!/bin/sh + +set -ex + +gitroot=$(git rev-parse --show-toplevel) +cd "$gitroot/qemu" + +sudo LIBVIRT_DEBUG=1 virsh net-start default 2>&1 | grep -i warning || true + +sudo PREFIX=$gitroot/AMDSEV $gitroot/AMDSEV/launch-qemu.sh \ + -hda debian11.qcow2 \ + -console serial \ + -vnc 1 \ + -mem 2024 \ + -smp 1,cores=4,threads=2 \ + -allow-debug +