From 7d26524944df4a0177e39a1165b53d00cda6d3d7 Mon Sep 17 00:00:00 2001 From: Hector Cao <122458375+hector-cao@users.noreply.github.com> Date: Mon, 9 Dec 2024 09:12:26 +0100 Subject: [PATCH] add direct boot methods and UKI (#296) * add more methods to boot a TD we have different methods to boot a TD for now, we use the traditional method that consists of passing the ubuntu image to qemu however, we have other ways to boot a TD: - direct boot : by providing the kernel and initrd to qemu - UKI : by providing the Unified Kernel image (that contains the kernel and initrd) each method generates a different event log journal because the boot chain involves less or more components that generate event logs it is important to evaluate which is the best boot method to have a short and consistent event log journal to make sure that remote attestation is reliable --- .gitignore | 5 + README.md | 10 ++ guest-tools/direct-boot/README.md | 140 +++++++++++++++++++++++++ guest-tools/direct-boot/boot_direct.sh | 68 ++++++++++++ guest-tools/direct-boot/boot_uki.sh | 85 +++++++++++++++ guest-tools/image/create-td-image.sh | 1 + guest-tools/image/create-td-uki.sh | 65 ++++++++++++ guest-tools/image/create-uki.sh | 62 +++++++++++ guest-tools/image/setup.sh | 4 + 9 files changed, 440 insertions(+) create mode 100644 .gitignore create mode 100644 guest-tools/direct-boot/README.md create mode 100755 guest-tools/direct-boot/boot_direct.sh create mode 100755 guest-tools/direct-boot/boot_uki.sh create mode 100755 guest-tools/image/create-td-uki.sh create mode 100755 guest-tools/image/create-uki.sh diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..22520780 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +*.qcow2 +*.img +initrd* +uki.efi* +vmlinuz* diff --git a/README.md b/README.md index 9a373ad3..4ba9f018 100644 --- a/README.md +++ b/README.md @@ -589,6 +589,16 @@ you proceed to [step 4](#verify-itts-client-version). ``` +#### 9.1. Event log and measurements + +One of the key components remote attestation is based on is the runtime measurement values (stored in RTMRs +registers for each TD by the TDX module). These RTMR values are computed from the digests of the entries of +the TD boot event log. + +If you want to inspect the event log and RTMR values, you can use the program `tdeventlog` available in the guest. +And furthermore, to see how the boot chain can impact the contents and the size of the boot event log, please take a look at +the [boot methods section](guest-tools/direct-boot/README.md). + ## 10. Build Packages from Source diff --git a/guest-tools/direct-boot/README.md b/guest-tools/direct-boot/README.md new file mode 100644 index 00000000..2beaf8eb --- /dev/null +++ b/guest-tools/direct-boot/README.md @@ -0,0 +1,140 @@ +# TD Boot Methods + +This folder contains scripts and instructions to boot a TD using the [direct +boot](https://qemu-project.gitlab.io/qemu/system/linuxboot.html) method. + +The direct boot method is an alternative to the boot method that is being used by `tdvirsh` +to run TDs. +We will refer to the `tdvirsh` boot method as the `indirect boot` method. +With the `indirect boot` method, the boot chain involves following components: +- TDVF (virtual UEFI firmware) +- SHIM +- Grub +- Kernel + Initrd + +The `direct boot` will skip `SHIM` and `Grub` in the boot chain by providing the `Kernel` +and `Initrd` directly to `qemu`. Per consequence, the boot chain involves these components: +- TDVF (virtual UEFI firmware) +- Kernel + Initrd + +The boot chain structure is important for remote attestation since it impacts the size of +the event log journal. Indeed, each component in the boot chain generates a set of entries of the event +log journal. The more components we have in the boot chain, the more event logs we will have and the harder +is the verification of the correctness of the measurement values. + +For `direct boot`, we would like to investigate 2 ways of passing `kernel` and `initrd` to `qemu`: +- Separately using `-kernel` and `-initrd` arguments +- Bundled together as part of an [Unified Kernel Image](https://uapi-group.org/specifications/specs/unified_kernel_image/) + +### Prerequisites + +To later perform direct boot with the two direct boot variants, we need to generate following files: + +1. TD Guest Image + +The boot scripts need a guest image as the final rootfs to boot into. + +To generate this guest image, please refer to the section [Create TD Image](../../README.md#create-td-image). + +NOTE: The credentials necessary for login into the TD guest can also be found in this section. + +2. Kernel, initrd and UKI + +NOTE: the provided instructions are for `24.04` guest. + Please replace `24.04` by `24.10` if you want to work with `oracular` TD guest. + +``` +$ cd guest-tools/image +$ ./create-td-uki.sh tdx-guest-ubuntu-24.04-generic.qcow2 +``` + +This script will generate 3 files: +- `vmlinuz-24.04` : the kernel of the guest image +- `initrd.img-24.04` : the initrd of the guest image +- `uki.efi-24.04` : the Unified Kernel Image that bundles together the kernel and the initrd + +### Direct boot + +``` +$ cd guest-tools/direct-boot +$ ./boot_direct.sh 24.04 +``` + +Once you are in the guest console, you can see the event log journal by: + +``` +$ tdeventlog +``` + +Example output: + +``` +root@tdx-guest:~# tdeventlog +==== TDX Event Log Entry - 0 [0x7FBEF000] ==== +RTMR : 0 +Type : 3 (EV_NO_ACTION) +Length : 65 +Algorithms Number : 1 + Algorithms[0xC] Size: 384 +RAW DATA: ---------------------------------------------- +7FBEF000 01 00 00 00 03 00 00 00 00 00 00 00 00 00 00 00 ................ +7FBEF010 00 00 00 00 00 00 00 00 00 00 00 00 21 00 00 00 ............!... +7FBEF020 53 70 65 63 20 49 44 20 45 76 65 6E 74 30 33 00 Spec ID Event03. +7FBEF030 00 00 00 00 00 02 00 02 01 00 00 00 0C 00 30 00 ..............0. +7FBEF040 00 . +RAW DATA: ---------------------------------------------- + +... +... + +==== TDX Event Log Entry - 19 [0x7FBEF77F] ==== +RTMR : 1 +Type : 0x80000007 (EV_EFI_ACTION) +Length : 95 +Algorithms ID : 12 (TPM_ALG_SHA384) +Digest[0] : 214b0bef1379756011344877743fdc2a5382bac6e70362d624ccf3f654407c1b4badf7d8f9295dd3dabdef65b27677e0 +RAW DATA: ---------------------------------------------- +7FBEF77F 02 00 00 00 07 00 00 80 01 00 00 00 0C 00 21 4B ..............!K +7FBEF78F 0B EF 13 79 75 60 11 34 48 77 74 3F DC 2A 53 82 ...yu`.4Hwt?.*S. +7FBEF79F BA C6 E7 03 62 D6 24 CC F3 F6 54 40 7C 1B 4B AD ....b.$...T@|.K. +7FBEF7AF F7 D8 F9 29 5D D3 DA BD EF 65 B2 76 77 E0 1D 00 ...)]....e.vw... +7FBEF7BF 00 00 45 78 69 74 20 42 6F 6F 74 20 53 65 72 76 ..Exit Boot Serv +7FBEF7CF 69 63 65 73 20 49 6E 76 6F 63 61 74 69 6F 6E ices Invocation +RAW DATA: ---------------------------------------------- + +==== TDX Event Log Entry - 20 [0x7FBEF7DE] ==== +RTMR : 1 +Type : 0x80000007 (EV_EFI_ACTION) +Length : 106 +Algorithms ID : 12 (TPM_ALG_SHA384) +Digest[0] : 0a2e01c85deae718a530ad8c6d20a84009babe6c8989269e950d8cf440c6e997695e64d455c4174a652cd080f6230b74 +RAW DATA: ---------------------------------------------- +7FBEF7DE 02 00 00 00 07 00 00 80 01 00 00 00 0C 00 0A 2E ................ +7FBEF7EE 01 C8 5D EA E7 18 A5 30 AD 8C 6D 20 A8 40 09 BA ..]....0..m .@.. +7FBEF7FE BE 6C 89 89 26 9E 95 0D 8C F4 40 C6 E9 97 69 5E .l..&.....@...i^ +7FBEF80E 64 D4 55 C4 17 4A 65 2C D0 80 F6 23 0B 74 28 00 d.U..Je,...#.t(. +7FBEF81E 00 00 45 78 69 74 20 42 6F 6F 74 20 53 65 72 76 ..Exit Boot Serv +7FBEF82E 69 63 65 73 20 52 65 74 75 72 6E 65 64 20 77 69 ices Returned wi +7FBEF83E 74 68 20 53 75 63 63 65 73 73 th Success +RAW DATA: ---------------------------------------------- + + +==== Replayed RTMR values from event log ==== +rtmr_0 : a40d9875d5a7477e2d14201a27fc2aef21d9e6243ffe483262d2212cf518fd249fb0956d5d3ba30e6dca6d839c8e6212 +rtmr_1 : 8584f2ccb76201a023e8dc30ed918e40650fa96fc5c5802d78cda055a1ef8d65a0845d1ced5bb9601ed0060a5bcf8802 +rtmr_2 : 82abbec34b50b6784bd9edc785fdbfd2e49d05acbb0f1ae58c011f057b64bb6532cac5b9146bdb245992118d55d90013 +rtmr_3 : 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +``` + +### Direct boot with UKI + +Another way to do direct boot is to use the [Unified Kernel Image](https://uapi-group.org/specifications/specs/unified_kernel_image/). +UKI leads to better UEFI Secure Boot support, better supporting TPM measurements and confidential computing, and a more robust boot process. + +``` +$ cd guest-tools/direct-boot +$ ./boot_uki.sh 24.04 +``` + +Once you are in the guest console, you can see the event log journal by using `tdeventlog` as explained in the previous section. + diff --git a/guest-tools/direct-boot/boot_direct.sh b/guest-tools/direct-boot/boot_direct.sh new file mode 100755 index 00000000..40db710b --- /dev/null +++ b/guest-tools/direct-boot/boot_direct.sh @@ -0,0 +1,68 @@ +#!/bin/bash + +# This file is part of Canonical's TDX repository which includes tools +# to setup and configure a confidential computing environment +# based on Intel TDX technology. +# See the LICENSE file in the repository for the license text. + +# Copyright 2024 Canonical Ltd. +# SPDX-License-Identifier: GPL-3.0-only + +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 3, +# as published by the Free Software Foundation. +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranties +# of MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU General Public License for more details. + +SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) + +UBUNTU_VERSION=$1 +if [[ -z "${UBUNTU_VERSION}" ]]; then + echo "Usage: $0 <24.04|24.10>" + exit 1 +fi + +PROCESS_NAME=td +TDVF_FIRMWARE=/usr/share/ovmf/OVMF.fd + +KERNEL_FILE=$(realpath ${SCRIPT_DIR}/../image/vmlinuz-${UBUNTU_VERSION}) +INITRD_FILE=$(realpath ${SCRIPT_DIR}/../image/initrd.img-${UBUNTU_VERSION}) +TD_IMG=$(realpath ${SCRIPT_DIR}/../image/tdx-guest-ubuntu-${UBUNTU_VERSION}-generic.qcow2) + +if [[ ! -f "${KERNEL_FILE}" ]]; then + echo "Missing kernel file: ${KERNEL_FILE} + You can use guest-tools/image/create-td-uki.sh to generate it" + exit 1 +fi + +if [[ ! -f "${INITRD_FILE}" ]]; then + echo "Missing initrd file: ${INITRD_FILE} + You can use guest-tools/image/create-td-uki.sh to generate it" + exit 1 +fi + +if [[ ! -f "${TD_IMG}" ]]; then + echo "Missing guest image file: ${TD_IMG} + You can use guest-tools/image/create-td-image.sh to generate it" + exit 1 +fi + +set -e + +qemu-system-x86_64 -accel kvm \ + -m 2G -smp 16 \ + -name ${PROCESS_NAME},process=${PROCESS_NAME},debug-threads=on \ + -cpu host \ + -object '{"qom-type":"tdx-guest","id":"tdx","quote-generation-socket":{"type": "vsock", "cid":"2","port":"4050"}}' \ + -machine q35,kernel_irqchip=split,confidential-guest-support=tdx,hpet=off \ + -bios ${TDVF_FIRMWARE} \ + -nographic \ + -nodefaults \ + -kernel ${KERNEL_FILE} \ + -initrd ${INITRD_FILE} \ + -append "root=/dev/sda1 console=ttyS0" \ + -hda ${TD_IMG} \ + -serial stdio \ + -pidfile /tmp/tdx-demo-td-pid.pid diff --git a/guest-tools/direct-boot/boot_uki.sh b/guest-tools/direct-boot/boot_uki.sh new file mode 100755 index 00000000..e8d811ad --- /dev/null +++ b/guest-tools/direct-boot/boot_uki.sh @@ -0,0 +1,85 @@ +#!/bin/bash + +# This file is part of Canonical's TDX repository which includes tools +# to setup and configure a confidential computing environment +# based on Intel TDX technology. +# See the LICENSE file in the repository for the license text. + +# Copyright 2024 Canonical Ltd. +# SPDX-License-Identifier: GPL-3.0-only + +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 3, +# as published by the Free Software Foundation. +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranties +# of MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU General Public License for more details. + +SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) + +UBUNTU_VERSION=$1 + +if [[ -z "${UBUNTU_VERSION}" ]]; then + echo "Usage: $0 <24.04|24.10>" + exit 1 +fi + +UKI_FILE=$(realpath ${SCRIPT_DIR}/../image/uki.efi-${UBUNTU_VERSION}) +TD_IMG=$(realpath ${SCRIPT_DIR}/../image/tdx-guest-ubuntu-${UBUNTU_VERSION}-generic.qcow2) + +usage() { + cat < /dev/null + +PROCESS_NAME=td +TDVF_FIRMWARE=/usr/share/ovmf/OVMF.fd +ROOTFS_DIR=${SCRIPT_DIR}/uki_rootfs + +# sanity check +if [[ ! -f "${UKI_FILE}" ]] || [[ ! -f "${TD_IMG}" ]]; then + usage + exit 1 +fi + +set -e + +# Since the uki kernel is designed to be started by UEFI directly, +# it has to reside in the EFI partition, because without additional +# drivers UEFI can only read VFAT. +mkdir -p ${ROOTFS_DIR}/efi/boot +cp -f ${UKI_FILE} ${ROOTFS_DIR}/efi/boot/bootx64.efi + +qemu-system-x86_64 -accel kvm \ + -m 2G -smp 16 \ + -name ${PROCESS_NAME},process=${PROCESS_NAME},debug-threads=on \ + -cpu host \ + -object '{"qom-type":"tdx-guest","id":"tdx","quote-generation-socket":{"type": "vsock", "cid":"2","port":"4050"}}' \ + -machine q35,kernel_irqchip=split,confidential-guest-support=tdx,hpet=off \ + -bios ${TDVF_FIRMWARE} \ + -nographic \ + -nodefaults \ + -hda fat:rw:${ROOTFS_DIR} \ + -hdb ${TD_IMG} \ + -serial stdio \ + -pidfile /tmp/tdx-demo-td-pid.pid diff --git a/guest-tools/image/create-td-image.sh b/guest-tools/image/create-td-image.sh index cec1de78..efa2d0a3 100755 --- a/guest-tools/image/create-td-image.sh +++ b/guest-tools/image/create-td-image.sh @@ -305,6 +305,7 @@ setup_guest_image() { --copy-in ${SCRIPT_DIR}/../../setup-tdx-common:/tmp/tdx \ --copy-in ${SCRIPT_DIR}/../../setup-tdx-config:/tmp/tdx \ --copy-in ${SCRIPT_DIR}/../../attestation/:/tmp/tdx \ + --copy-in ${SCRIPT_DIR}/../../tests/lib/tdx-tools/:/tmp/tdx \ --run-command "/tmp/tdx/setup.sh" if [ $? -eq 0 ]; then ok "Run setup scripts inside the guest image" diff --git a/guest-tools/image/create-td-uki.sh b/guest-tools/image/create-td-uki.sh new file mode 100755 index 00000000..37717f8e --- /dev/null +++ b/guest-tools/image/create-td-uki.sh @@ -0,0 +1,65 @@ +#!/bin/bash + +# This file is part of Canonical's TDX repository which includes tools +# to setup and configure a confidential computing environment +# based on Intel TDX technology. +# See the LICENSE file in the repository for the license text. + +# Copyright 2024 Canonical Ltd. +# SPDX-License-Identifier: GPL-3.0-only + +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 3, +# as published by the Free Software Foundation. +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranties +# of MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU General Public License for more details. + +# This script will create a UKI (Unified Kernel Image) from the guest image + +SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd) + +TMP_GUEST_IMG="${SCRIPT_DIR}/tdx-guest-tmp.qcow2" +TMP_GUEST_FOLDER="${SCRIPT_DIR}/tdx-guest-tmp/" + +TD_GUEST_IMG=$1 +if [[ -z "${TD_GUEST_IMG}" ]]; then + echo "Usage : $0 " + exit 1 +fi + +if [ "$EUID" -eq 0 ] + then echo "Please do not run as root" + exit +fi + +cleanup() { + echo "cleanup ..." + umount ${TMP_GUEST_FOLDER} &> /dev/null + rm -rf ${TMP_GUEST_FOLDER} + rm -f ${TMP_GUEST_IMG} +} + +trap "cleanup" EXIT + +cleanup + +set -e + +# create an overlay image with guest image as a backing image +qemu-img create -f qcow2 -b ${TD_GUEST_IMG} -F qcow2 ${TMP_GUEST_IMG} + +# virt-customize does in-place customization and use host kernel +# we have to give the create-uki script the guest image kernel +virt-customize -a ${TMP_GUEST_IMG} \ + --mkdir /tmp/tdx/ \ + --copy-in ${SCRIPT_DIR}/create-uki.sh:/tmp/tdx/ \ + --run-command "/tmp/tdx/create-uki.sh" + +# retrieve files +mkdir -p ${TMP_GUEST_FOLDER} && guestmount -a ${TMP_GUEST_IMG} -i --ro ${TMP_GUEST_FOLDER} + +cp ${TMP_GUEST_FOLDER}/uki.efi* ./ +cp ${TMP_GUEST_FOLDER}/vmlinuz* ./ +cp ${TMP_GUEST_FOLDER}/initrd* ./ diff --git a/guest-tools/image/create-uki.sh b/guest-tools/image/create-uki.sh new file mode 100755 index 00000000..18e01f50 --- /dev/null +++ b/guest-tools/image/create-uki.sh @@ -0,0 +1,62 @@ +#!/bin/bash + +# This file is part of Canonical's TDX repository which includes tools +# to setup and configure a confidential computing environment +# based on Intel TDX technology. +# See the LICENSE file in the repository for the license text. + +# Copyright 2024 Canonical Ltd. +# SPDX-License-Identifier: GPL-3.0-only + +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 3, +# as published by the Free Software Foundation. +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranties +# of MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU General Public License for more details. + +# This script will create a UKI (Unified Kernel Image) using +# systemd-ukify, update-initramfs + +# if this script is executed with virt-customize, $(uname -r) +# will give the kernel version on host, so this information +# we have to look for it from /boot/ +KERNEL_VER=$(find /boot/vmlinuz-*-generic 2>&1 | \ + /usr/lib/grub/grub-sort-version -r 2>&1 | \ + gawk 'match($0 , /^\/boot\/vmlinuz-(.*)/, a) {print a[1];exit}') + +UBUNTU_VERSION=$(lsb_release -rs) + +if [[ -z "${KERNEL_VER}" ]]; then + echo "Cannot detect kernel version" + exit 1 +fi + +echo "Creating the UKI with kernel ${KERNEL_VER}" + +# the kernel commandline to put in the UKI +KERNEL_CMDLINE="console=tty1 console=ttyS0 root=/dev/sdb1" + +# use systemd-ukify to generate UKI +sudo apt install -y systemd-ukify systemd-boot-efi + +# use update-initramfs +# add kernel moules: +# - tdx_guest +echo tdx_guest | sudo tee -a /etc/initramfs-tools/modules +sudo update-initramfs -c -k ${KERNEL_VER} + +# copy the initrd +sudo cp /boot/initrd.img-${KERNEL_VER} initrd.img-${UBUNTU_VERSION} + +# copy the kernel +sudo cp /boot/vmlinuz-${KERNEL_VER} ./vmlinuz-${UBUNTU_VERSION} +sudo chmod a+rw vmlinuz-${KERNEL_VER} + +ukify build --linux=./vmlinuz-${UBUNTU_VERSION} \ + --cmdline "${KERNEL_CMDLINE}" \ + --initrd=initrd.img-${UBUNTU_VERSION} \ + --output uki.efi-${UBUNTU_VERSION} \ + --os-release '@/etc/os-release' \ + --uname ${KERNEL_VER} diff --git a/guest-tools/image/setup.sh b/guest-tools/image/setup.sh index 59f90b88..b481ba22 100755 --- a/guest-tools/image/setup.sh +++ b/guest-tools/image/setup.sh @@ -36,4 +36,8 @@ rm -f /etc/ssh/sshd_config.d/60-cloudimg-settings.conf # Enable TDX /tmp/tdx/setup-tdx-guest.sh +# Install tools +cd /tmp/tdx/tdx-tools/ +python3 -m pip install --break-system-packages ./ + rm -rf /tmp/tdx || true