Message ID | 20250311094225.35129-3-sgarzare@redhat.com (mailing list archive) |
---|---|
State | New |
Headers | show |
Series | Enlightened vTPM support for SVSM on SEV-SNP | expand |
On Tue, Mar 11, 2025 at 10:42:23AM +0100, Stefano Garzarella wrote: > 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 <cclaudio@linux.ibm.com> > Signed-off-by: Claudio Carvalho <cclaudio@linux.ibm.com> > 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.h > > diff --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. > +/** > + * 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. > + > +/** > + * 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. > + > +/** > + * 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; > + u8 locality; > + u32 inbuf_size; > + u8 inbuf[]; Why not just buf? > +} __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., struct svsm_vtpm_request { u32 command; u16 locality; u16 buffer_size; u8 buffer[]; }; 64k should enough for any possible TPM command. > + > +/** > + * 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. > + > +/** > + * svsm_vtpm_fill_cmd_req() - fill a struct tpm_send_cmd_req to be sent to SVSM > + * @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() > +{ > + 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() > +{ > + 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.1 > BR, Jarkko
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: >> 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 <cclaudio@linux.ibm.com> >> Signed-off-by: Claudio Carvalho <cclaudio@linux.ibm.com> >> 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.h >> >> diff --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. > >> +/** >> + * 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. > >> + >> +/** >> + * 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. > >> + >> +/** >> + * 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. > >> + u8 locality; >> + u32 inbuf_size; >> + u8 inbuf[]; > >Why not just buf? I can change in `buf` and `size`. > >> +} __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. > >> + >> +/** >> + * 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; > >> + >> +/** >> + * svsm_vtpm_fill_cmd_req() - fill a struct tpm_send_cmd_req to be sent to SVSM > >> + * @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() > >> +{ >> + 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 > >> +{ >> + 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.1 >> > >BR, Jarkko >
diff --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 */ + +/** + * struct tpm_req - generic request header for single word command + * + * @cmd: The command to send + */ +struct tpm_req { + u32 cmd; +} __packed; + +/** + * 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; + +/** + * 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; + u8 locality; + u32 inbuf_size; + u8 inbuf[]; +} __packed; + +/** + * 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; + +/** + * svsm_vtpm_fill_cmd_req() - fill a struct tpm_send_cmd_req to be sent to SVSM + * @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) +{ + 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) +{ + 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_ */