Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for vTPM and its runtime protocol #135

Merged
merged 22 commits into from
Apr 2, 2024

Conversation

cclaudio
Copy link
Member

@cclaudio cclaudio commented Oct 18, 2023

This is a sketch of how the vTPM and the vTPM protocol would work in the SVSM, for now running in CPL0.

The vTPM is initialized (manufactured) on every boot. If OVMF and the Linux guest kernel have proper tpm drivers, they should be able to communicate with the SVSM vTPM. See the section Dependencies below.

Once this is merged I can post a PR for the attestation protocol.

Dependencies

OVMF

$ git clone https://github.com/coconut-svsm/edk2.git
$ cd edk2/
$ git fetch origin pull/2/head:edk2-pr2
$ git checkout edk2-pr2
$ git submodule init
$ git submodule update

$ export PYTHON3_ENABLE=TRUE
$ export PYTHON_COMMAND=python3
$ make -j16 -C BaseTools/
$ source ./edksetup.sh --reconfig
$ build -a X64 -b DEBUG -t GCC5 -D DEBUG_ON_SERIAL_PORT -D DEBUG_VERBOSE -DTPM2_ENABLE -p OvmfPkg/OvmfPkgX64.dsc

Guest kernel:

The linux branch below is based on the PR#2 posted against the coconut-svsm/linux repository with additional two patches for the TPM platform driver.

CONFIG_TCG_PLATFORM should be enabled in the guest. The same kernel also needs to be installed on the host.

$ git clone https://github.com/cclaudio/linux.git
$ cd linux
$ git checkout svsm-host-guest-vtpm

QEMU:

Follow the instructions described in INSTALL.md to build the QEMU branch below.

$ git clone https://github.com/coconut-svsm/qemu.git
$ cd qemu
$ git fetch origin pull/2/head:qemu-pr2
$ git co qemu-pr2

How to test it

Follow the INSTALL.md to build this PR and run a QEMU guest.

During the boot you should be able to see messages from OVMF and the linux kernel like these:

Loading PEIM at 0x0007F7FC000 EntryPoint=0x0007F7FD906 Tcg2ConfigPei.efi
Found SVSM TPM
Tcg2ConfigPeimEntryPoint
Tcg2ConfigPeimEntryPoint: TPM2 detected

[...]

ReadPcr - HashAlg = 0x0004, Pcr[00], digest = 51 C3 23 DE 0C 0C 69 4F 46 01 CD D0 2B EB 58 FF 13 62 9F 74 
ReadPcr - HashAlg = 0x000B, Pcr[00], digest = FC EC B5 6A CC 30 38 62 B3 0E B3 42 C4 99 0B EB 50 B5 E0 AB 89 72 24 49 C2 D9 A7 3F 37 B0 19 FE 
ReadPcr - HashAlg = 0x000C, Pcr[00], digest = 61 93 87 2D C7 23 D5 33 E3 BB 45 FB 0A EE C1 35 48 AD DE 71 11 DF 93 A4 D7 0C B1 B5 77 CE 31 10 4A C9 DF BC B8 76 BD 07 F7 7D 2C E4 B3 F7 33 DF

[...]

[    0.907842] SEV: SNP guest platform device initialized.
[    0.910991] SEV: SNP SVSM VTPM platform device initialized
[    0.993792] tpm tpm: TPM 2.0 platform device

From guest userspace you can also install the tpm2-tools package and use it to communicate with the SVSM-vTPM (e.g. tpm2_pcrread without arguments)

@cclaudio
Copy link
Member Author

Sorry for the branch conflict. I will fix it as soon as I find a new way to get the slab item size in the function mm::alloc::layout_from_ptr(). Recently, 8fd4c80 removed the Slab pointer from SlabPageInfo.

@00xc
Copy link
Member

00xc commented Oct 18, 2023

Sorry for the branch conflict. I will fix it as soon as I find a new way to get the slab item size in the function mm::alloc::layout_from_ptr(). Recently, 8fd4c80 removed the Slab pointer from SlabPageInfo.

Feel free to revert that commit by including the slab size instead of the pointer.

src/vtpm/wrapper.rs Outdated Show resolved Hide resolved
@osteffenrh
Copy link
Contributor

A hint for building on Fedora: make sure to install these dependencies:

dnf install pkg-config m4 libtool automake autoconf autoconf-archive

@cclaudio cclaudio marked this pull request as draft November 28, 2023 13:57
@cclaudio
Copy link
Member Author

cclaudio commented Dec 7, 2023

  • Added code to cache the TPM EK in the TSS format (marshaled TPMT_PUBLIC). It needs to be provided when an attestation service is requested at runtime.
  • Reverted 8fd4c80
  • Rebased to the latest main branch

@cclaudio cclaudio force-pushed the coconut-svsm-vtpm branch 7 times, most recently from adae550 to 6b2be53 Compare January 31, 2024 06:05
@cclaudio cclaudio marked this pull request as ready for review January 31, 2024 06:10
@cclaudio
Copy link
Member Author

This PR version works with the upstream Microsoft TPM and OpenSSL. So, for testing, you only need to the OVMF and guest kernel mentioned in the PR description.

@stefano-garzarella
Copy link
Contributor

@cclaudio thanks for this great work! I'll review in the next days, in the meantime I report some building issues I'm having.

The INSTALL.md is updated in this PR to reflect the steps above.

I can't see these changes (e.g. git submodule initialization), maybe we forgot them during rebase.

I think we should also update our container image with something like this:

diff --git a/scripts/container/opensuse-rust.docker b/scripts/container/opensuse-rust.docker
index bf8a109..ad276d6 100644
--- a/scripts/container/opensuse-rust.docker
+++ b/scripts/container/opensuse-rust.docker
@@ -19,7 +19,9 @@ ARG USER_NAME user
 SHELL ["/bin/bash", "-c"]
 
 RUN zypper ref && \
-    zypper install -y system-user-mail make gcc curl && \
+    zypper install -y system-user-mail make gcc curl \
+    patterns-devel-base-devel_basis \
+    autoconf autoconf-archive pkg-config automake libopenssl-devel && \
     useradd -u $USER_ID -m $USER_NAME
 
 USER $USER_NAME

This doesn't work for me, though, because I keep seeing:

(cd /home/stefano/repos/coconut/svsm-review/libvtpm/ms-tpm-20-ref/TPMCmd && \
	sed -i '/^AX_PTHREAD/d' configure.ac && \
	./bootstrap && \
	./configure \
		CFLAGS="-static -nostdinc -fno-stack-protector -fPIE -DSIMULATION=NO -DFILE_BACKED_NV=NO -I/home/stefano/repos/coconut/svsm-review/libvtpm/libcrt/include -I/home/stefano/repos/coconut/svsm-review/libvtpm/openssl/include" \
		LIBCRYPTO_LIBS="")
Generating file lists: src.mk
Setting up build
Setting default vendor strings
checking for gcc... gcc
checking whether the C compiler works... no

I think I need some help from OpenSUSE users :-)

libvtpm/Makefile Outdated Show resolved Hide resolved
@roy-hopkins
Copy link
Collaborator

This doesn't work for me, though, because I keep seeing:

(cd /home/stefano/repos/coconut/svsm-review/libvtpm/ms-tpm-20-ref/TPMCmd && \
	sed -i '/^AX_PTHREAD/d' configure.ac && \
	./bootstrap && \
	./configure \
		CFLAGS="-static -nostdinc -fno-stack-protector -fPIE -DSIMULATION=NO -DFILE_BACKED_NV=NO -I/home/stefano/repos/coconut/svsm-review/libvtpm/libcrt/include -I/home/stefano/repos/coconut/svsm-review/libvtpm/openssl/include" \
		LIBCRYPTO_LIBS="")
Generating file lists: src.mk
Setting up build
Setting default vendor strings
checking for gcc... gcc
checking whether the C compiler works... no

I think I need some help from OpenSUSE users :-)

I also saw build errors on my dev system (not in a container). I think the error @stefano-garzarella is seeing is because the glibc static libraries are missing in the container. In order to get the build to work, I had to install the static library plus a couple of other missing dependencies:

zypper in autoconf-archive glibc-devel-static libclang13

libvtpm/Makefile Outdated Show resolved Hide resolved
@stefano-garzarella
Copy link
Contributor

stefano-garzarella commented Feb 1, 2024

@roy-hopkins yeah thanks!
Adding glibc-devel-static and git worked (partially, I have other issues related to git-workspaces and bindgen), so the final changes are something like this:

diff --git a/scripts/container/opensuse-rust.docker b/scripts/container/opensuse-rust.docker
index bf8a109..621d107 100644
--- a/scripts/container/opensuse-rust.docker
+++ b/scripts/container/opensuse-rust.docker
@@ -19,7 +19,9 @@ ARG USER_NAME user
 SHELL ["/bin/bash", "-c"]
 
 RUN zypper ref && \
-    zypper install -y system-user-mail make gcc curl && \
+    zypper install -y system-user-mail make gcc curl \
+        patterns-devel-base-devel_basis glibc-devel-static git libclang13 \
+        autoconf autoconf-archive pkg-config automake libopenssl-devel && \
     useradd -u $USER_ID -m $USER_NAME
 
 USER $USER_NAME

Edit: we also need libclang13 otherwise bindgen will fail. (@roy-hopkins already mentioned it)

libvtpm/Makefile Outdated Show resolved Hide resolved
@cclaudio
Copy link
Member Author

cclaudio commented Feb 1, 2024

Thanks @stefano-garzarella @roy-hopkins.
@stefano-garzarella I updated the PR description and will update the INSTALL.md with the Microsoft TPM build dependencies.

diff --git a/Documentation/INSTALL.md b/Documentation/INSTALL.md
index 477b4d1c93b1..487e99e16719 100644
--- a/Documentation/INSTALL.md
+++ b/Documentation/INSTALL.md
@@ -176,6 +176,14 @@ Building the SVSM itself requires:
 - `x86_64-unknown-none` target toolchain installed (`rustup target add x86_64-unknown-none`)
 - `binutils` >= 2.39
 
+Also make sure you have the Microsoft TPM build dependencies installed. On OpenSUSE
+you can do this by:
+```
+$ sudo zypper in system-user-mail make gcc curl patterns-devel-base-devel_basis \
+      glibc-devel-static git libclang13 autoconf autoconf-archive pkg-config \
+      automake libopenssl-devel
+```
+
 Then checkout the SVSM repository and build the SVSM binary:
 

@cclaudio
Copy link
Member Author

cclaudio commented Feb 5, 2024

Feedback applied

libvtpm/libcrt/src/prng/rand.c Outdated Show resolved Hide resolved
Makefile Outdated Show resolved Hide resolved
@joergroedel joergroedel self-requested a review February 13, 2024 12:43
@joergroedel joergroedel added wait-for-review PR needs for approval by reviewers needs-rebase The PR needs to be rebased to the latest upstream branch labels Feb 13, 2024
@zvonkok
Copy link

zvonkok commented Feb 15, 2024

/cc @zvonkok

cclaudio and others added 22 commits March 28, 2024 10:28
Ensure the Microsoft TPM build dependencies are installed when building the
SVSM for the github CI and using the container build script.

The INSTALL.md will be updated with the same steps in a separate patch.

Signed-off-by: Claudio Carvalho <[email protected]>
This reverts commit 8fd4c80. With that the
slab is again encoded in the SlabPageInfo and we can use it to determine
the size of an allocated memory pointer.

That is required to implement realloc() and free() wrappers for the libcrt.

Signed-off-by: Claudio Carvalho <[email protected]>
The signature of the allocate_slab_page function has been updated, now it
requires Option<VirtAddr>.

fn allocate_slab_page(&mut self, slab: Option<VirtAddr>)
-> Result<VirtAddr, AllocError>

Signed-off-by: Claudio Carvalho <[email protected]>
The functions malloc(), realloc(), calloc(), free(), abort() and serial_out()
are required to build OpenSSL and the Microsoft TPM 2.0, but they cannot be
implemented in the libcrt because memory and standard I/O codes are owned by
the SVSM rust code.

Signed-off-by: Claudio Carvalho <[email protected]>
Add the libmstpm workspace member to own the C libraries that the
Microsoft TPM depends on:
- libcrt: the libcrt.a
- OpenSSL: the libcrypto.a
- Microsoft TPM: the libplatform.a and libtpm.a

This workspace member will be used to keep self-contained all the complexity to
build the C libraries as well as generation of FFI bindings using bindgen.

Signed-off-by: Claudio Carvalho <[email protected]>
The libcrt is a subset of the musl libc that provides only the symbols
required to build the Microsoft TPM 2.0 and the OpenSSL for the SVSM.

In general, the libcrt header files are just a proxy for the libcrt.h, which
centralizes all the definitions. That's similar to what OVMF does to build
OpenSSL without having to patch missing headers.

Some libcrt functions are required at build time, but they are not called at
runtime. These functions are stubbed out in stub.c, a WARNING message is
printed if the stub is executed.

The required malloc(), realloc(), calloc(), free(), abort() and serial_out()
will be implemented in Rust.

The required rand() function uses the RDRAND instruction to get random bytes.

The time() function uses the RDTSC instruction to get the current time.

The libmstpm is compiled in quiet mode by default, but "make V=2" can be
used to show all its compilation messages.

Co-developed-by: Vikram Narayanan <[email protected]>
Signed-off-by: Vikram Narayanan <[email protected]>
Signed-off-by: Claudio Carvalho <[email protected]>
Add OpenSSL as a git submodule and build it.

As of now, the upstream Microsoft TPM 2.0 requires OpenSSL 1.1.1d or higher.
OpenSSL 3.x support is still under review upstream in a pull request.

Similar to OVMF, we also build OpenSSL 1.1.1q by providing an OpenSSL config
and disabling crypto modules that are not needed.

Later we can move to OpenSSL 3.x.

Signed-off-by: Claudio Carvalho <[email protected]>
Add the Microsoft TPM as a git submodule and build it.

The SVSM does not need the Microsoft TPM simulator, so we build only the
libplatform.a and libtpm.a.

For now we are disabling the TPM Self Test command (-DSELF_TEST=NO) as it is
failing. This issue is explained and fixed in a separate patch.

Signed-off-by: Claudio Carvalho <[email protected]>
TPM commands such as SelfTests and CreatePrimary end up calling into the
OpenSSL Elliptic Curve subsystem, but they will fail if the OpenSSL entropy
pool is empty. There are multiple ways to confirm that, for instance:

(1) when OVMF tries to run the SelfTests during boot:

TPM2Startup: TPM_RC_SUCCESS
[..]
ReadPcr: Unable to read TPM capabilities
[..]
Tpm2PcrExtend: Response Code error! 0x00000143
HashLogExtendEvent - Device Error. Disable TPM.

(2) when we try to create an ECC primary key from guest userspace:

$ tpm2_createek -c 0x81000000 -G ecc -u key.tss
[SVSM] WARN: VMPCK0 disabled!
[SVSM] ERROR: Panic: CPU[0] panicked at src/vtpm/ek.rs:78:23:
Failed to create the TPM Endorsment Key Rc(
    0x154,
)
[SVSM] ---BACKTRACE---:
[SVSM] ---END---

This patch fix that by building OpenSSL with --with-rand-seed=getrandom and
also implementing getentropy() to return entropy obtained through RDRAND.

Co-developed-by: Claudio Carvalho <[email protected]>
Signed-off-by: Claudio Carvalho <[email protected]>
Signed-off-by: Mike Rapoport <[email protected]>
Generate FFI (Foreign Functions Interface) bindings for the libmstpm symbols we
call in Rust. To avoid adding bindgen dependencies to Cargo.toml we use the
bindgen command line.

The libmstpm.h has a complete list of the C symbols we need.

Signed-off-by: Claudio Carvalho <[email protected]>
The libmstpm.a is linked against the kernel only when the mstpm cargo feature
is enabled; currently it is enabled by default.

Tracking cargo features in the Makefile doesn't seem an easy/simple task, maybe
that's why we are not doing that (Issue coconut-svsm#65). So, for now the libmstpm is
always built.

"make distclean" can be used to clean the libmstpm. Later that could be
improved by forcing the libmstpm to be built in the $OUT_DIR directory (place
in the target directory that cargo uses to build packages). With that the
libmstpm would also be cleaned when "make clean" is issued to delete the target
directory.

Signed-off-by: Claudio Carvalho <[email protected]>
Add the interfaces that a tpm backend needs to implement in order to be
supported in the SVSM:

- VtpmProtocolInterface: basic services required to perform the runtime vTPM
  protocol (added in a separate patch).

- MsTpmSimulatorInterface: define one handler for each TPM Platform Command
  supported in the vTPM protocol. It extends the VtpmProtocolInterface.

- VtpmInterface: basic TPM driver services. It extends the
  MsTpmSimulatorInterface.

Signed-off-by: Claudio Carvalho <[email protected]>
Implement the vtpm interfaces for the Microsoft TPM, they all call into the
libmstpm.

This also defines the MsTpm structure that later can be used to instatiate the
Microsoft TPM backend.

Signed-off-by: Claudio Carvalho <[email protected]>
Initialize the virtual TPM by calling the init() function of the TPM backend.

Signed-off-by: Claudio Carvalho <[email protected]>
Add a constant for the SVSM core protocol ID to improve code readability.

Signed-off-by: Claudio Carvalho <[email protected]>
The vTPM protocol is introduced in the SVSM specification v1.0 to allow other
software components (e.g. OVMF and guest kernel) to communicate with the
SVSM vTPM at runtime. It follows the Microsoft TPM 2.0 Simulator protocol.

The specification enumerates two call IDs supportted by the vTPM protocol:
1. SVSM_VTPM_QUERY: query vTPM command and features support.
2. SVSM_VTPM_CMD: Execute a TPM platform command.

As for the SVSM_VTPM_CMD, the TPM platform commands are described in
libvtpm/ms-tpm-20-ref/TPMCmd/Simulator/include/prototypes/Simulator_fp.h
e.g.:
- TPM_SIGNAL_HASH_DATA
- TPM_SEND_COMMAND
- TPM_REMOTE_HANDSHAKE
- TPM_SET_ALTERNATIVE_RESULT

This patch implements both the SVSM_VTPM_QUERY and the SVSM_VTPM_CMD call IDs.

For the SVSM_VTPM_CMD, only the TPM_SEND_COMMAND platform command is
implemented.

Signed-off-by: Claudio Carvalho <[email protected]>
Document the Microsoft TPM build requirements.

Signed-off-by: Claudio Carvalho <[email protected]>
Add the default-test cargo feature to control what features we want to enable in
the tests. The vtpm/mstpm/wrappers.rs, for example, can't run in the test
environment because its malloc() etc functions conflict with the libc standard
libraries.

Signed-off-by: Claudio Carvalho <[email protected]>
Set CARGO_HOME and add it to PATH in the Dockerfile.
This way we don't have to source the setup script every time.

Signed-off-by: Oliver Steffen <[email protected]>
Install bindgen-cli in container image.

Signed-off-by: Oliver Steffen <[email protected]>
Mention submodule initialization in the comment exlaining
how to use the container build scripts.

Signed-off-by: Oliver Steffen <[email protected]>
The file libmstpm/src/bindings.rs is auto-generated during make, however
the github CI is not building the code for the nightly tests.

This patch initializes the bindings.rs before the cargo-fmt workflow so
that it does not complain that bindings.rs does not exist.

Signed-off-by: Claudio Carvalho <[email protected]>
@cclaudio
Copy link
Member Author

rebased and fixed conflict with Makefile

@joergroedel joergroedel added in-review PR is under active review and not yet approved and removed wait-for-update PR is waiting to be updated to address review comments needs-rebase The PR needs to be rebased to the latest upstream branch labels Apr 2, 2024
@joergroedel joergroedel merged commit f4319ab into coconut-svsm:main Apr 2, 2024
3 checks passed
@joergroedel joergroedel removed the in-review PR is under active review and not yet approved label Apr 2, 2024
@joergroedel
Copy link
Member

This is merged now. Thanks @cclaudio and all the reviewers!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

10 participants