Skip to content

Commit

Permalink
Added Coconut-SVSM support to invoke AMD-ES/AMD-SEV for setting up t…
Browse files Browse the repository at this point in the history
…he host, launching the guest (directly setting up snpguest in the guest VM), and performing attestation & measurement verification (using igvmmeasure vs snpguest)
  • Loading branch information
ramagali24 committed Sep 13, 2024
1 parent 4419036 commit 2332446
Showing 1 changed file with 165 additions and 22 deletions.
187 changes: 165 additions & 22 deletions tools/snp.sh
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@ GENERATED_INITRD_BIN="${SETUP_WORKING_DIR}/initrd.img"
AMDSEV_URL="https://github.com/ryansavino/AMDSEV.git"
AMDSEV_DEFAULT_BRANCH="snp-latest-fixes"
AMDSEV_NON_UPM_BRANCH="snp-non-upm"
AMDSEV_SVSM_URL="https://github.com/ramagali24/AMDSEV-SVSM.git"
AMDSEV_SVSM_BRANCH="svsm-latest"
SNPGUEST_URL="https://github.com/virtee/snpguest.git"
SNPGUEST_BRANCH="tags/v0.7.1"
NASM_SOURCE_TAR_URL="https://www.nasm.us/pub/nasm/releasebuilds/2.16.01/nasm-2.16.01.tar.gz"
Expand All @@ -116,6 +118,7 @@ usage() {
>&2 echo " stop-guests Stop all SNP guests started by this script"
>&2 echo " where OPTIONS are:"
>&2 echo " -n|--non-upm Build AMDSEV non UPM kernel (sev-snp-devel)"
>&2 echo " -s|--svsm Build coconut-svsm components, launch guest and verity attestaion & measurement"
>&2 echo " -i|--image Path to existing image file"
>&2 echo " -h|--help Usage information"

Expand Down Expand Up @@ -522,12 +525,22 @@ save_binary_paths() {
local guest_kernel=$(echo $(realpath "${SETUP_WORKING_DIR}/AMDSEV/linux/guest/vmlinuz-${guest_kernel_version}"))

# Save binary paths in source file
cat > "${SETUP_WORKING_DIR}/source-bins" <<EOF
if [ "$SVSM" = true ]; then
cat > "${SETUP_WORKING_DIR}/source-bins" <<EOF
QEMU_BIN="${SETUP_WORKING_DIR}/AMDSEV/qemu/build/qemu-system-x86_64"
OVMF_BIN="${SETUP_WORKING_DIR}/AMDSEV/ovmf/Build/AmdSev/DEBUG_GCC5/FV/OVMF.fd"
INITRD_BIN="${GENERATED_INITRD_BIN}"
KERNEL_BIN="${guest_kernel}"
EOF
else
cat > "${SETUP_WORKING_DIR}/source-bins" <<EOF
QEMU_BIN="${SETUP_WORKING_DIR}/AMDSEV/qemu/build/qemu-system-x86_64"
OVMF_BIN="${SETUP_WORKING_DIR}/AMDSEV/ovmf/Build/OvmfX64/DEBUG_GCC5/FV/OVMF.fd"
INITRD_BIN="${GENERATED_INITRD_BIN}"
KERNEL_BIN="${guest_kernel}"
IGVM_FILE="${SETUP_WORKING_DIR}/AMDSEV/svsm/bin/coconut-qemu.igvm"
EOF
fi
}

copy_launch_binaries() {
Expand All @@ -550,11 +563,19 @@ copy_launch_binaries() {
cp "${KERNEL_BIN}" "${LAUNCH_WORKING_DIR}"

# Save binary paths in source file
if [ "$SVSM" = true ]; then
cat > "${LAUNCH_WORKING_DIR}/source-bins" <<EOF
OVMF_BIN="${LAUNCH_WORKING_DIR}/$(basename "${OVMF_BIN}")"
INITRD_BIN="${LAUNCH_WORKING_DIR}/$(basename "${INITRD_BIN}")"
KERNEL_BIN="${LAUNCH_WORKING_DIR}/$(basename "${KERNEL_BIN}")"
EOF
else
cat > "${LAUNCH_WORKING_DIR}/source-bins" <<EOF
IGVM_FILE="${LAUNCH_WORKING_DIR}/$(basename "${IGVM_FILE}")"
INITRD_BIN="${LAUNCH_WORKING_DIR}/$(basename "${INITRD_BIN}")"
KERNEL_BIN="${LAUNCH_WORKING_DIR}/$(basename "${KERNEL_BIN}")"
EOF
fi
}

add_qemu_cmdline_opts() {
Expand Down Expand Up @@ -594,7 +615,7 @@ build_base_qemu_cmdline() {
add_qemu_cmdline_opts "-device virtio-net-pci,disable-legacy=on,iommu_platform=true,netdev=vmnic,romfile="

# Storage
add_qemu_cmdline_opts "-device virtio-scsi-pci,id=scsi0,disable-legacy=on,iommu_platform=true,romfile="
add_qemu_cmdline_opts "-device virtio-scsi-pci,id=scsi0,disable-legacy=on,iommu_platform=true"
add_qemu_cmdline_opts "-device scsi-hd,drive=disk0"
add_qemu_cmdline_opts "-drive if=none,id=disk0,format=qcow2,file=${IMAGE}"

Expand Down Expand Up @@ -646,9 +667,20 @@ set_acl_for_sev_device() {
echo "${setfacl_command}" | sudo tee -a "${rc_local_file}" >/dev/null
}

build_and_install_amdsev() {
build_and_install_amdsev() {

local amdsev_branch="${1:-${AMDSEV_DEFAULT_BRANCH}}"


if [ "$SVSM" = true ]; then
local amdsev_branch="${1:-${AMDSEV_DEFAULT_BRANCH}}"

else
AMDSEV_URL=${AMDSEV_SVSM_URL}
amdsev_branch="svsm-latest"
# Create directory

fi

# Create directory
mkdir -p "${SETUP_WORKING_DIR}"

Expand All @@ -664,10 +696,12 @@ build_and_install_amdsev() {
git remote set-url current "${AMDSEV_URL}"
git fetch current "${amdsev_branch}"
git checkout "current/${amdsev_branch}"


if [ "$SVSM" = true ]; then
# Based on latest AMDSEV documentation
# Delete the ovmf/ directory prior to the build step for ovmf re-initialization
[ ! -d "ovmf" ] || rm -rf "ovmf"
fi

# Build and copy files
./build.sh --package
Expand Down Expand Up @@ -786,7 +820,12 @@ setup_and_launch_guest() {
#add_qemu_cmdline_opts "-machine pc-q35-7.1"

# snp object and kernel-hashes on
add_qemu_cmdline_opts "-object sev-snp-guest,id=sev0,cbitpos=51,reduced-phys-bits=1,kernel-hashes=on"
if [ "$SVSM" = true ]; then
add_qemu_cmdline_opts "-object sev-snp-guest,id=sev0,cbitpos=51,reduced-phys-bits=1,kernel-hashes=on"
else
add_qemu_cmdline_opts "-object memory-backend-memfd,size=2G,id=mem0,share=true,prealloc=false,reserve=off"
add_qemu_cmdline_opts "-object sev-snp-guest,id=sev0,cbitpos=51,reduced-phys-bits=1,init-flags=5,igvm-file="$IGVM_FILE""
fi

# ovmf, initrd, kernel and append options
add_qemu_cmdline_opts "-bios ${OVMF_BIN}"
Expand Down Expand Up @@ -1081,22 +1120,28 @@ attest_guest() {
ssh_guest_command "sudo insmod /lib/modules/*/kernel/drivers/virt/coco/sev-guest/sev-guest.ko >/dev/null 2>&1 || true"

# Request and display the snp attestation report with random data
ssh_guest_command "sudo ./snpguest report attestation-report.bin request-data.txt --random"
ssh_guest_command "./snpguest display report attestation-report.bin"
if [ "$SVSM" = true ]; then
ssh_guest_command "sudo ./snpguest report attestation-report.bin request-data.txt --random"
else
ssh_guest_command "sudo ./$Home/snpguest/target/release/snpguest report attestation-report.bin request-data.txt --random --vmpl 3"
fi
ssh_guest_command "./$Home/snpguest/target/release/snpguest display report attestation-report.bin"

# Retrieve ark, ask, vcek (saved in ./certs)
ssh_guest_command "./snpguest fetch ca pem ${cpu_code_name} . --endorser vcek"
ssh_guest_command "./snpguest fetch vcek pem ${cpu_code_name} . attestation-report.bin"
ssh_guest_command "./$Home/snpguest/target/release/snpguest fetch ca pem ${cpu_code_name} ."
ssh_guest_command "./$Home/snpguest/target/release/snpguest fetch vcek pem ${cpu_code_name} . attestation-report.bin"

# Verifies that ARK, ASK and VCEK are all properly signed
ssh_guest_command "./snpguest verify certs ."
ssh_guest_command "./$Home/snpguest/target/release/snpguest verify certs ."

# Verifies the attestation-report trusted compute base matches vcek
ssh_guest_command "./snpguest verify attestation . attestation-report.bin"

# Use sev-snp-measure utility to calculate the expected measurement
local expected_measurement=$(generate_snp_expected_measurement)
echo -e "\nExpected Measurement (sev-snp-measure): ${expected_measurement}"
ssh_guest_command "./$Home/snpguest/target/release/snpguest verify attestation . attestation-report.bin"

if [ "$SVSM" = true ]; then

# Use sev-snp-measure utility to calculate the expected measurement
local expected_measurement=$(generate_snp_expected_measurement)
echo -e "\nExpected Measurement (sev-snp-measure): ${expected_measurement}"

# Parse the measurement out of the snp report
local snpguest_report_measurement=$(ssh_guest_command \
Expand All @@ -1107,16 +1152,102 @@ attest_guest() {

# Remove any special characters and print the value
snpguest_report_measurement=$(echo ${snpguest_report_measurement} | sed $'s/[^[:print:]\t]//g')
echo -e "Measurement from SNP Attestation Report: ${snpguest_report_measurement}\n"

# Compare the expected measurement to the guest report measurement
[[ "${expected_measurement}" == "${snpguest_report_measurement}" ]] \
&& echo -e "The expected measurement matches the snp guest report measurement!" \
|| { >&2 echo -e "FAIL: measurements do not match"; return 1; }
else
Verify_measurement
fi
}
setup_svsm_guest_attestation() {

ssh_guest_command "
# Update and install necessary packages
echo 'Updating package list...'
sudo apt-get update
echo 'Installing necessary packages...'
sudo apt-get install -y git build-essential libtss2-dev tpm2-tools
echo 'Installing Rust...'
source ""${HOME}"/.cargo/env" 2>/dev/null || true
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs -sSf | sh -s -- -y
source ""${HOME}"/.cargo/env" 2>/dev/null
"

# Check if 'snpguest' directory exists and remove it if it does
ssh_guest_command "
if [ -d \"snpguest\" ]; then
echo 'Directory snpguest exists. Removing it...'
rm -rf snpguest
else
echo 'Directory snpguest does not exist.'
fi
"

# Clone the repository and build the project
ssh_guest_command "git clone https://github.com/virtee/snpguest.git"
ssh_guest_command "cd snpguest && source \$HOME/.cargo/env && cargo build --release"
}

Verify_measurement(){

# Define the working directory and the output file
OUTPUT_FILE="$SETUP_WORKING_DIR/make_output.txt"
# Define the firmware file path
FW_FILE="$SETUP_WORKING_DIR/AMDSEV/ovmf/Build/OvmfX64/DEBUG_GCC5/FV/OVMF.fd"

cd "$SETUP_WORKING_DIR"/AMDSEV/svsm

# Run the make command and save the output to a file
FW_FILE="$FW_FILE" make &> "$OUTPUT_FILE"

# Initialize the variable for Launch Digest
launch_digest=""

# Read the output file line by line to find the Launch Digest
while IFS= read -r line; do
if [[ "$line" == *"Launch Digest:"* ]]; then
launch_digest=$(echo "$line" | awk '{print $3}')
break
fi
done < "$OUTPUT_FILE"

# Output the Launch Digest to verify
echo "Launch Digest: $launch_digest"

# Use igvmmeasure utility to calculate the expected measurement
local expected_measurement=$launch_digest
echo -e "\nExpected Measurement (igvmmeasure): ${expected_measurement}"

# Parse the measurement out of the snp report
scp_guest_command "${GUEST_USER}@localhost:$HOME/attestation-report.bin" "$SETUP_WORKING_DIR/AMDSEV/svsm"

cd "$SETUP_WORKING_DIR"/AMDSEV/svsm
# Assign the output of the hexdump command to a variable
snpguest_report_measurement=$(hexdump -s 0x90 -n 48 -v -e '48/1 "%02X"' attestation-report.bin)

# Print the variable to verify its content
echo "$snpguest_report_measurement"
echo -e "Measurement from SNP Attestation Report: ${snpguest_report_measurement}\n"

# Compare the expected measurement to the guest report measurement
[[ "${expected_measurement}" == "${snpguest_report_measurement}" ]] \
&& echo -e "The expected measurement matches the snp guest report measurement!" \
|| { >&2 echo -e "FAIL: measurements do not match"; return 1; }
if [[ "${expected_measurement}" == "${snpguest_report_measurement}" ]]; then
echo -e "The expected measurement matches the SNP guest report measurement!"
else
>&2 echo -e "FAIL: Measurements do not match"
return 1
fi
}




###############################################################################

# Main
Expand Down Expand Up @@ -1147,6 +1278,10 @@ main() {
IMAGE="${2}"
SKIP_IMAGE_CREATE=true
shift; shift
;;
-svsm)
SVSM=false
shift
;;

setup-host)
Expand Down Expand Up @@ -1223,8 +1358,11 @@ main() {

# TEMPORARY until sev-snp-measure is updated to pass in TCB kernel modifier flags
# Changes in AMDESE/linux set debug_swap on by default and affect the measurement
sudo modprobe -r kvm_amd
sudo modprobe kvm_amd debug_swap=0
if [ "$SVSM" = true ]; then
sudo modprobe -r kvm_amd
sudo modprobe kvm_amd debug_swap=0
fi


setup_and_launch_guest
wait_and_retry_command verify_snp_guest
Expand All @@ -1235,12 +1373,17 @@ main() {
;;

attest-guest)
if [ "$SVSM" = true ]; then
install_rust
install_sev_snp_measure
install_dependencies
wait_and_retry_command verify_snp_guest
setup_guest_attestation
attest_guest
else
wait_and_retry_command verify_snp_guest
setup_svsm_guest_attestation
fi
attest_guest
;;

stop-guests)
Expand Down

0 comments on commit 2332446

Please sign in to comment.