Re: [PATCH v3 2/4] svsm: add header with SVSM_VTPM_CMD helpers
From: Stefano Garzarella <sgarzare@redhat.com>
Date: 2025-03-12 11:47:39
Also in:
linux-integrity, lkml
On Tue, Mar 11, 2025 at 12:07:55PM +0200, Jarkko Sakkinen wrote:
On Tue, Mar 11, 2025 at 10:42:23AM +0100, Stefano Garzarella wrote:quoted
Helpers for the SVSM_VTPM_CMD calls used by the vTPM protocol defined by the AMD SVSM spec [1]. The vTPM protocol follows the Official TPM 2.0 Reference Implementation (originally by Microsoft, now part of the TCG) simulator protocol. [1] "Secure VM Service Module for SEV-SNP Guests" Publication # 58019 Revision: 1.00 Co-developed-by: James Bottomley <James.Bottomley@HansenPartnership.com> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com> Co-developed-by: Claudio Carvalho <redacted> Signed-off-by: Claudio Carvalho <redacted> Signed-off-by: Stefano Garzarella <sgarzare@redhat.com> --- v3: - renamed header and prefix to make clear it's related to the SVSM vTPM protocol - renamed fill/parse functions [Tom] - removed link to the spec because those URLs are unstable [Borislav] --- include/linux/svsm_vtpm.h | 141 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 include/linux/svsm_vtpm.hdiff --git a/include/linux/svsm_vtpm.h b/include/linux/svsm_vtpm.h new file mode 100644 index 000000000000..2ce9b1cb827e --- /dev/null +++ b/include/linux/svsm_vtpm.h@@ -0,0 +1,141 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2023 James.Bottomley@HansenPartnership.com + * Copyright (C) 2025 Red Hat, Inc. All Rights Reserved. + * + * Helpers for the SVSM_VTPM_CMD calls used by the vTPM protocol defined by the + * AMD SVSM spec [1]. + * + * The vTPM protocol follows the Official TPM 2.0 Reference Implementation + * (originally by Microsoft, now part of the TCG) simulator protocol. + * + * [1] "Secure VM Service Module for SEV-SNP Guests" + * Publication # 58019 Revision: 1.00 + */ +#ifndef _SVSM_VTPM_H_ +#define _SVSM_VTPM_H_ + +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/types.h> + +/* + * The current TCG Simulator TPM commands we support. The complete list is + * in the TcpTpmProtocol header: + * + * https://github.com/TrustedComputingGroup/TPM/blob/main/TPMCmd/Simulator/include/TpmTcpProtocol.h + */ + +#define TPM_SEND_COMMAND 8 +#define TPM_SIGNAL_CANCEL_ON 9 +#define TPM_SIGNAL_CANCEL_OFF 10 +/* + * Any platform specific commands should be placed here and should start + * at 0x8000 to avoid clashes with the TCG Simulator protocol. They should + * follow the same self describing buffer format below. + */ + +#define SVSM_VTPM_MAX_BUFFER 4096 /* max req/resp buffer size */ +Across the board below data structures: I'd svsm_vtpm_ prefix them. The rational is quite practical: it would easier to grep them later on.
I see, I'll fix in v4.
quoted
+/** + * struct tpm_req - generic request header for single word command + * + * @cmd: The command to send + */ +struct tpm_req { + u32 cmd; +} __packed;__packed is useless here.quoted
+ +/** + * struct tpm_resp - generic response header + * + * @size: The response size (zero if nothing follows) + * + * Note: most TCG Simulator commands simply return zero here with no indication + * of success or failure. + */ +struct tpm_resp { + u32 size; +} __packed;Ditto.
Ack, for both.
quoted
+ +/** + * struct tpm_send_cmd_req - Structure for a TPM_SEND_COMMAND request + * + * @hdr: The request header whit the command (must be TPM_SEND_COMMAND) + * @locality: The locality + * @inbuf_size: The size of the input buffer following + * @inbuf: A buffer of size inbuf_size + * + * Note that TCG Simulator expects @inbuf_size to be equal to the size of the + * specific TPM command, otherwise an TPM_RC_COMMAND_SIZE error is + * returned. + */ +struct tpm_send_cmd_req { + struct tpm_req hdr;Useless nesting that makes this obfuscated: you can just as well put that single field here, i.e. u32 cmd;
Yep, I see. I'll remove tpm_req and tpm_resp since for now we support only TPM_SEND_COMMAND, if in the future we will support other requests we can think of re-introduce them if needed.
quoted
+ u8 locality; + u32 inbuf_size; + u8 inbuf[];Why not just buf?
I can change in `buf` and `size`.
quoted
+} __packed;Since we don't care about TCG Simulator compatibility I'd expect that these are ordered in a way that they align nicely. E.g.
Maybe I should add in the documentation that this structure is defined
by the AMD SVSM spec.
This is where request and response for TPM_SEND_COMMAND are defined:
8.2.1 TPM_SEND_COMMAND
Execute a TPM command and return the results.
For TPM_SEND_COMMAND, platform command 8, the request buffer is
specified according to the format of the following table.
Table 16: TPM_SEND_COMMAND Request Structure
Byte Size Meaning
Offset (Bytes)
0x000 4 Platform command (8)
0x004 1 Locality (must-be-0)
0x005 4 TPM Command size (in bytes)
0x009 Variable TPM Command
The response buffer is specified according to the format of the
following table.
Table 17: TPM_SEND_COMMAND Response Structure
Byte Size Meaning
Offset (Bytes)
0x000 4 Response size (in bytes)
0x004 Variable Response
struct svsm_vtpm_request { u32 command; u16 locality; u16 buffer_size; u8 buffer[]; }; 64k should enough for any possible TPM command.quoted
+ +/** + * struct tpm_send_cmd_req - Structure for a TPM_SEND_COMMAND response + * + * @hdr: The response header whit the following size + * @outbuf: A buffer of size hdr.size + */ +struct tpm_send_cmd_resp { + struct tpm_resp hdr; + u8 outbuf[]; +} __packed;Why this does not have size? Here also __packed is useless even with the pre-existing layout, and something like svsm_tpm_response would be a factor more reasonable name.
Because it's "obfuscated" as you pointed out in the request :-)
The size is in the header, but I'll fix with something like this:
struct svsm_tpm_response {
u32 size;
u8 outbuf[];
} __packed;
quoted
+ +/** + * svsm_vtpm_fill_cmd_req() - fill a struct tpm_send_cmd_req to be sent to SVSMquoted
+ * @req: The struct tpm_send_cmd_req to fill + * @locality: The locality + * @buf: The buffer from where to copy the payload of the command + * @len: The size of the buffer + * + * Return: 0 on success, negative error code on failure. + */ +static inline int +svsm_vtpm_fill_cmd_req(struct tpm_send_cmd_req *req, u8 locality, + const u8 *buf, size_t len)svsm_vtpm_fill_request()quoted
+{ + if (len > SVSM_VTPM_MAX_BUFFER - sizeof(*req)) + return -EINVAL; + + req->hdr.cmd = TPM_SEND_COMMAND; + req->locality = locality; + req->inbuf_size = len; + + memcpy(req->inbuf, buf, len); + + return 0; +} + +/** + * svsm_vtpm_parse_cmd_resp() - Parse a struct tpm_send_cmd_resp received from + * SVSM + * @resp: The struct tpm_send_cmd_resp to parse + * @buf: The buffer where to copy the response + * @len: The size of the buffer + * + * Return: buffer size filled with the response on success, negative error + * code on failure. + */ +static inline int +svsm_vtpm_parse_cmd_resp(const struct tpm_send_cmd_resp *resp, u8 *buf, + size_t len)svsm_vtpm_parse_response()
About the naming, I added "cmd" because in the future we can support also other requests/responses different from TPM_SEND_COMMAND, like TPM_SIGNAL_HASH_DATA, TPM_REMOTE_HANDSHAKE, TPM_SET_ALTERNATIVE_RESULT as specified in the AMD SVSM spec. For now it's true that we support only TPM_SEND_COMMAND, so I can avoid `cmd`, but if we will need to support the other requests in the future, we may need to differentiate them. Would be okay to have svsm_vtpm_cmd_[request|response], svsm_vtpm_fill_cmd_request(), svsm_vtpm_parse_cmd_response() ? Or do you prefer to avoid "_cmd_"? Not a strong opinion on my side. Thanks, Stefano
quoted
+{ + if (len < resp->hdr.size) + return -E2BIG; + + if (resp->hdr.size > SVSM_VTPM_MAX_BUFFER - sizeof(*resp)) + return -EINVAL; // Invalid response from the platform TPM + + memcpy(buf, resp->outbuf, resp->hdr.size); + + return resp->hdr.size; +} + +#endif /* _SVSM_VTPM_H_ */ -- 2.48.1BR, Jarkko