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 17, 2024
1 parent 4419036 commit bb710f8
Showing 1 changed file with 164 additions and 42 deletions.
206 changes: 164 additions & 42 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-fixes"
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 verify attestaion & measurement"
>&2 echo " -i|--image Path to existing image file"
>&2 echo " -h|--help Usage information"

Expand Down Expand Up @@ -522,12 +525,17 @@ 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
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
if [ "$SVSM" = true ]; then
echo "IGVM_FILE=\"${SETUP_WORKING_DIR}/AMDSEV/svsm/bin/coconut-qemu.igvm\"" >> "${SETUP_WORKING_DIR}/source-bins"
else
echo "OVMF_BIN=\"${SETUP_WORKING_DIR}/AMDSEV/ovmf/Build/AmdSev/DEBUG_GCC5/FV/OVMF.fd\"" >> "${SETUP_WORKING_DIR}/source-bins"
fi
}

copy_launch_binaries() {
Expand All @@ -545,16 +553,25 @@ copy_launch_binaries() {

# Copy the setup generated bins to the guest launch directory
# initrd is copied after the first guest boot and is scp-ed off
cp "${OVMF_BIN}" "${LAUNCH_WORKING_DIR}"
if [ "$SVSM" = true ]; then
cp "${IGVM_FILE}" "${LAUNCH_WORKING_DIR}"
else
cp "${OVMF_BIN}" "${LAUNCH_WORKING_DIR}"
fi
#cp "${INITRD_BIN}" "${LAUNCH_WORKING_DIR}"
cp "${KERNEL_BIN}" "${LAUNCH_WORKING_DIR}"

# Save binary paths in source file

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
if [ "$SVSM" = true ]; then
echo "IGVM_FILE=\"${LAUNCH_WORKING_DIR}/$(basename "${IGVM_FILE}")\"" >> "${LAUNCH_WORKING_DIR}/source-bins"
else
echo "OVMF_BIN=\"${LAUNCH_WORKING_DIR}/$(basename "${OVMF_BIN}")\"" >> "${LAUNCH_WORKING_DIR}/source-bins"
fi
}

add_qemu_cmdline_opts() {
Expand Down Expand Up @@ -646,9 +663,16 @@ 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
AMDSEV_URL=${AMDSEV_SVSM_URL}
amdsev_branch="svsm-latest-fixes"
else
local amdsev_branch="${1:-${AMDSEV_DEFAULT_BRANCH}}"
fi
# Create directory
mkdir -p "${SETUP_WORKING_DIR}"

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

# Based on latest AMDSEV documentation
# Delete the ovmf/ directory prior to the build step for ovmf re-initialization
[ ! -d "ovmf" ] || rm -rf "ovmf"


# Build and copy files
./build.sh --package
Expand Down Expand Up @@ -786,7 +811,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 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""
else
add_qemu_cmdline_opts "-object sev-snp-guest,id=sev0,cbitpos=51,reduced-phys-bits=1,kernel-hashes=on"
fi

# ovmf, initrd, kernel and append options
add_qemu_cmdline_opts "-bios ${OVMF_BIN}"
Expand Down Expand Up @@ -1026,7 +1056,7 @@ get_cpu_code_name() {
esac
}

generate_snp_expected_measurement() {
generate_snp_expected_measurement() {
# Get ovmf, kernel, initrd paths
# Get vcpu type and kernel append command line
local ovmf_path=$(cat "${QEMU_CMDLINE_FILE}" \
Expand Down Expand Up @@ -1073,48 +1103,130 @@ generate_snp_expected_measurement() {
{ >&2 echo -e "sev-snp-measure return value is empty"; return 1; }
echo ${measurement}
}

attest_guest() {
local cpu_code_name=$(get_cpu_code_name)

# Install the sev-guest module
ssh_guest_command "sudo insmod /lib/modules/*/kernel/drivers/virt/coco/sev-guest/sev-guest.ko >/dev/null 2>&1 || true"
local cpu_code_name=$(get_cpu_code_name)

# 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"
# Install the sev-guest module
ssh_guest_command "sudo insmod /lib/modules/*/kernel/drivers/virt/coco/sev-guest/sev-guest.ko >/dev/null 2>&1 || true"

# 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"
# Request and display the snp attestation report with random data
ssh_guest_command "sudo ./snpguest report attestation-report.bin request-data.txt --random $( [ \"$SVSM\" = true ] && echo '--vmpl 3' )"
ssh_guest_command "./snpguest display report attestation-report.bin"

# Verifies that ARK, ASK and VCEK are all properly signed
ssh_guest_command "./snpguest verify certs ."
# Retrieve ark, ask, vcek (saved in ./certs)
ssh_guest_command "./snpguest fetch ca pem ${cpu_code_name} ."
ssh_guest_command "./snpguest fetch vcek pem ${cpu_code_name} . attestation-report.bin"

# Verifies the attestation-report trusted compute base matches vcek
ssh_guest_command "./snpguest verify attestation . attestation-report.bin"
# Verifies that ARK, ASK and VCEK are all properly signed
ssh_guest_command "./snpguest verify certs ."

# 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}"
# Verifies the attestation-report trusted compute base matches vcek
ssh_guest_command "./snpguest verify attestation . attestation-report.bin"

# Parse the measurement out of the snp report
local snpguest_report_measurement=$(ssh_guest_command \
"./snpguest display report attestation-report.bin \
| tr '\n' ' ' \
| sed \"s|.*Measurement:\(.*\)Host Data.*|\1\n|g\" \
| sed \"s| ||g\"")
# Use appropriate measurement function based on SVSM
if [ "$SVSM" = true ]; then
local expected_measurement=$(generate_svsm_expected_measurement)
echo -e "\nExpected Measurement (igvmmeasure): ${expected_measurement}"
else
local expected_measurement=$(generate_snp_expected_measurement)
echo -e "\nExpected Measurement (sev-snp-measure): ${expected_measurement}"
fi

# 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"
# Parse the measurement out of the snp report
local snpguest_report_measurement=$(ssh_guest_command \
"./snpguest display report attestation-report.bin | \
tr '\n' ' ' | \
sed 's|.*Measurement:\(.*\)Host Data.*|\1|g' | \
sed 's| ||g'")

# 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
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
}

# 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; }
setup_svsm_guest_attestation() {
ssh_guest_command <<'EOF'
# 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
# Install Rust
echo 'Installing Rust...'
source "$HOME/.cargo/env" 2>/dev/null || true
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
source "$HOME/.cargo/env" 2>/dev/null
# Create the 'tools' directory if it does not exist
if [ ! -d "tools" ]; then
echo 'Directory tools does not exist. Creating it...'
mkdir tools
else
echo 'Directory tools already exists.'
fi
# Change to 'tools' directory
cd tools || { echo 'Failed to change directory to tools'; exit 1; }
# Check if 'snpguest' directory exists and remove it if it does
if [ -d "snpguest" ]; then
echo 'Directory snpguest exists. Removing it...'
rm -rf snpguest
else
echo 'Directory snpguest does not exist.'
fi
# Clone the repository into the 'tools' directory
git clone https://github.com/virtee/snpguest.git
# Build the project inside the 'snpguest' directory
cd snpguest || { echo 'Failed to change directory to snpguest'; exit 1; }
source "$HOME/.cargo/env"
cargo build --release
# Copy the built binary to the home directory
cp target/release/snpguest "$HOME/"
EOF
}

generate_svsm_expected_measurement() {
# Change directory to where igvmmeasure is located
if ! cd "$SETUP_WORKING_DIR/AMDSEV/svsm/target/x86_64-unknown-linux-gnu/debug"; then
echo 'Failed to change directory'
exit 1
fi

# Run the igvmmeasure command and capture its output
local output
if ! output=$(./igvmmeasure --check-kvm "$SETUP_WORKING_DIR/AMDSEV/svsm/bin/coconut-qemu.igvm" measure 2>&1); then
echo 'Failed to run igvmmeasure'
echo "Output: $output"
exit 1
fi

# Extract the Launch Digest from the output
local svsm_measurement
svsm_measurement=$(echo "$output" | awk '/Launch Digest:/ {print $3}')

# Check if measurement was extracted
if [ -z "$svsm_measurement" ]; then
echo 'Failed to extract measurement'
echo "Output: $output"
exit 1
fi

echo ${svsm_measurement}
}


###############################################################################
Expand Down Expand Up @@ -1148,6 +1260,10 @@ main() {
SKIP_IMAGE_CREATE=true
shift; shift
;;
-s|--svsm)
SVSM=true
shift
;;

setup-host)
COMMAND="setup-host"
Expand Down Expand Up @@ -1182,7 +1298,7 @@ main() {
;;
esac
done

# Set SETUP_WORKING_DIR for non-upm
if ! $UPM; then
SETUP_WORKING_DIR="${SETUP_WORKING_DIR}/non-upm"
Expand Down Expand Up @@ -1223,9 +1339,10 @@ 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

setup_and_launch_guest
wait_and_retry_command verify_snp_guest

Expand All @@ -1235,12 +1352,17 @@ main() {
;;

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

stop-guests)
Expand Down

0 comments on commit bb710f8

Please sign in to comment.