* [RFC PATCH 0/3] Retrieve SNP attestation from SVSM
@ 2023-06-07 15:06 Dov Murik
2023-06-07 15:06 ` [RFC PATCH 1/3] x86/sev: Add __svsm_msr_protocol_2() which returns register values Dov Murik
` (2 more replies)
0 siblings, 3 replies; 6+ messages in thread
From: Dov Murik @ 2023-06-07 15:06 UTC (permalink / raw)
To: linux-coco
Cc: Dov Murik, Tobin Feldman-Fitzthum, James Bottomley,
Claudio Carvalho
This is an initial attempt to allow userspace to fetch attestation
report from SVSM on SNP. It was tested with AMD's linux-svsm to which
we added support for the attestation protocol. The kernel patches in
this series only expose the SVSM_ATTEST_SERVICES function, for now.
The request for the attestation report is exposed to userspace as a new
ioctl call (SNP_SVSM_ATTEST_SERVICES) on /dev/sev-guest. It returns the
VMPL0 attestation report, the services manifest, and the host
certificate chain, according to the SVSM spec.
Note that the existing SNP_GET_REPORT and SNP_GET_EXT_REPORT calls still
work under SVSM, as long as a VMPL1 report is requested.
This series should be applied on top of AMD's SVSM guest tree:
https://github.com/AMDESE/linux/tree/svsm-preview-guest
The SVSM code which supports the attestation protocol is in:
https://github.com/svsm-vtpm/linux-svsm/tree/attestation-protocol-v2
(as of writing, it hasn't yet been merged to AMD's linux-svsm.)
Dov Murik (3):
x86/sev: Add __svsm_msr_protocol_2() which returns register values
x86/sev: Add snp_svsm_attest_services()
virt: sevguest: Add support to get attestation report from SVSM
arch/x86/include/asm/sev.h | 26 ++++++++
arch/x86/kernel/sev-shared.c | 49 ++++++++++++++
arch/x86/kernel/sev.c | 46 +++++++++++++
drivers/virt/coco/sevguest/sevguest.c | 95 +++++++++++++++++++++++++++
include/uapi/linux/sev-guest.h | 34 ++++++++++
5 files changed, 250 insertions(+)
--
2.35.3
^ permalink raw reply [flat|nested] 6+ messages in thread
* [RFC PATCH 1/3] x86/sev: Add __svsm_msr_protocol_2() which returns register values
2023-06-07 15:06 [RFC PATCH 0/3] Retrieve SNP attestation from SVSM Dov Murik
@ 2023-06-07 15:06 ` Dov Murik
2023-06-07 15:06 ` [RFC PATCH 2/3] x86/sev: Add snp_svsm_attest_services() Dov Murik
2023-06-07 15:06 ` [RFC PATCH 3/3] virt: sevguest: Add support to get attestation report from SVSM Dov Murik
2 siblings, 0 replies; 6+ messages in thread
From: Dov Murik @ 2023-06-07 15:06 UTC (permalink / raw)
To: linux-coco
Cc: Dov Murik, Tobin Feldman-Fitzthum, James Bottomley,
Claudio Carvalho
Existing function __svsm_msr_protocol() performs an SVSM call but
returns only the value of rax.
Complex SVSM calls (like SVSM_ATTEST_SERVICES) may return several
values: in rax, rcx, rdx, r8, and r9. The new call allows callers to
get all these values.
Signed-off-by: Dov Murik <dovmurik@linux.ibm.com>
---
arch/x86/kernel/sev-shared.c | 49 ++++++++++++++++++++++++++++++++++++
1 file changed, 49 insertions(+)
diff --git a/arch/x86/kernel/sev-shared.c b/arch/x86/kernel/sev-shared.c
index d989b1add933..1e4960cf1e6e 100644
--- a/arch/x86/kernel/sev-shared.c
+++ b/arch/x86/kernel/sev-shared.c
@@ -115,6 +115,55 @@ static int __svsm_msr_protocol(struct svsm_caa *caa, u64 rax, u64 rcx, u64 rdx,
return ret;
}
+static int __svsm_msr_protocol_2(struct svsm_caa *caa, u64 *rax, u64 *rcx, u64 *rdx,
+ u64 *r8, u64 *r9)
+{
+ u64 val, resp;
+ u8 pending;
+ int ret;
+ u64 rax_ret, rcx_ret, rdx_ret, r8_ret, r9_ret;
+
+ val = sev_es_rd_ghcb_msr();
+
+ sev_es_wr_ghcb_msr(GHCB_MSR_VMPL_REQ_LEVEL(0));
+
+ asm volatile("mov %8, %%r8\n\t"
+ "mov %9, %%r9\n\t"
+ "movb $1, %10\n\t"
+ "rep; vmmcall\n\t"
+ "mov %%r8, %3\n\t"
+ "mov %%r9, %4\n\t"
+ : "=a" (rax_ret), "=c" (rcx_ret), "=d" (rdx_ret), "=r" (r8_ret), "=r" (r9_ret)
+ : "a" (*rax), "c" (*rcx), "d" (*rdx), "r" (*r8), "r" (*r9),
+ "m" (caa->call_pending) : );
+
+ resp = sev_es_rd_ghcb_msr();
+
+ sev_es_wr_ghcb_msr(val);
+ ret = (int)rax_ret;
+
+ pending = 0;
+ asm volatile("xchgb %0, %1" : "+r" (pending) : "m" (caa->call_pending) : "memory");
+ if (pending)
+ ret = -EINVAL;
+
+ if (GHCB_RESP_CODE(resp) != GHCB_MSR_VMPL_RESP)
+ ret = -EINVAL;
+
+ if (GHCB_MSR_VMPL_RESP_VAL(resp) != 0)
+ ret = -EINVAL;
+
+ if (ret != -EINVAL) {
+ *rax = rax_ret;
+ *rcx = rcx_ret;
+ *rdx = rdx_ret;
+ *r8 = r8_ret;
+ *r9 = r9_ret;
+ }
+
+ return ret;
+}
+
static bool __init sev_es_check_cpu_features(void)
{
if (!has_cpuflag(X86_FEATURE_RDRAND)) {
--
2.35.3
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [RFC PATCH 2/3] x86/sev: Add snp_svsm_attest_services()
2023-06-07 15:06 [RFC PATCH 0/3] Retrieve SNP attestation from SVSM Dov Murik
2023-06-07 15:06 ` [RFC PATCH 1/3] x86/sev: Add __svsm_msr_protocol_2() which returns register values Dov Murik
@ 2023-06-07 15:06 ` Dov Murik
2023-06-07 15:06 ` [RFC PATCH 3/3] virt: sevguest: Add support to get attestation report from SVSM Dov Murik
2 siblings, 0 replies; 6+ messages in thread
From: Dov Murik @ 2023-06-07 15:06 UTC (permalink / raw)
To: linux-coco
Cc: Dov Murik, Tobin Feldman-Fitzthum, James Bottomley,
Claudio Carvalho
Allow retrieving SNP attestation report from SVSM.
Signed-off-by: Dov Murik <dovmurik@linux.ibm.com>
---
arch/x86/include/asm/sev.h | 26 +++++++++++++++++++++
arch/x86/kernel/sev.c | 46 ++++++++++++++++++++++++++++++++++++++
2 files changed, 72 insertions(+)
diff --git a/arch/x86/include/asm/sev.h b/arch/x86/include/asm/sev.h
index c6835bd7af95..5abc8f0e4823 100644
--- a/arch/x86/include/asm/sev.h
+++ b/arch/x86/include/asm/sev.h
@@ -177,6 +177,21 @@ struct svsm_pvalidate_call {
struct svsm_pvalidate_entry entry[];
};
+struct svsm_attest_services_call {
+ u64 report_address;
+ u32 report_size;
+ u8 reserved_1[4];
+ u64 nonce_address;
+ u16 nonce_size;
+ u8 reserved_2[6];
+ u64 services_manifest_address;
+ u16 services_manifest_size;
+ u8 reserved_3[4];
+ u64 certs_address;
+ u16 certs_size;
+ u8 reserved_4[4];
+};
+
#ifdef CONFIG_AMD_MEM_ENCRYPT
extern struct static_key_false sev_es_enable_key;
extern void __sev_es_ist_enter(struct pt_regs *regs);
@@ -246,6 +261,10 @@ bool snp_init(struct boot_params *bp);
void snp_abort(void);
int snp_issue_guest_request(u64 exit_code, struct snp_req_data *input, unsigned long *fw_err);
int snp_get_vmpl(void);
+int snp_svsm_attest_services(void *nonce, u32 nonce_size,
+ void *report, u32 *report_size,
+ void *services_manifest, u32 *services_manifest_size,
+ void *certs, u32 *certs_size);
#else
static inline void sev_es_ist_enter(struct pt_regs *regs) { }
static inline void sev_es_ist_exit(void) { }
@@ -271,6 +290,13 @@ static inline int snp_issue_guest_request(u64 exit_code, struct snp_req_data *in
return -ENOTTY;
}
static inline int snp_get_vmpl(void) { return 0; }
+static inline int snp_svsm_attest_services(void *nonce, u32 nonce_size,
+ void *report, u32 *report_size,
+ void *services_manifest, u32 *services_manifest_size,
+ void *certs, u32 *certs_size)
+{
+ return 0;
+}
#endif
#endif
diff --git a/arch/x86/kernel/sev.c b/arch/x86/kernel/sev.c
index 6fe742b31c4e..1a2dd58a485e 100644
--- a/arch/x86/kernel/sev.c
+++ b/arch/x86/kernel/sev.c
@@ -606,6 +606,52 @@ static void __base_pvalidate_pages(unsigned long vaddr, unsigned int npages, boo
}
}
+int snp_svsm_attest_services(void *nonce, u32 nonce_size, void *report,
+ u32 *report_size, void *services_manifest,
+ u32 *services_manifest_size, void *certs,
+ u32 *certs_size)
+{
+ struct svsm_caa *this_caa;
+ unsigned long flags;
+ int ret;
+ struct svsm_attest_services_call *svsm_call;
+ unsigned long svsm_call_gpa;
+ u64 function = (u64)1 << 32 | (u64)0;
+ u64 rax, rcx, rdx, r8, r9;
+
+ local_irq_save(flags);
+
+ this_caa = this_cpu_read(svsm_caa);
+
+ svsm_call = (struct svsm_attest_services_call *)this_caa->svsm_buffer;
+ svsm_call_gpa = __pa(this_caa) + offsetof(struct svsm_caa, svsm_buffer);
+
+ memset(this_caa->svsm_buffer, 0, sizeof(*this_caa->svsm_buffer));
+ svsm_call->report_address = __pa(report);
+ svsm_call->report_size = *report_size;
+ svsm_call->nonce_address = __pa(nonce);
+ svsm_call->nonce_size = nonce_size;
+ svsm_call->services_manifest_address = __pa(services_manifest);
+ svsm_call->services_manifest_size = *services_manifest_size;
+ svsm_call->certs_address = __pa(certs);
+ svsm_call->certs_size = *certs_size;
+
+ rax = function;
+ rcx = svsm_call_gpa;
+ rdx = 0;
+ r8 = 0;
+ r9 = 0;
+ ret = __svsm_msr_protocol_2(this_caa, &rax, &rcx, &rdx, &r8, &r9);
+
+ local_irq_restore(flags);
+
+ *report_size = r8;
+ *services_manifest_size = rcx;
+ *certs_size = rdx;
+ return ret;
+}
+EXPORT_SYMBOL_GPL(snp_svsm_attest_services);
+
static void __svsm_pvalidate_pages(struct svsm_caa *caa, unsigned long caa_gpa,
unsigned long paddr, unsigned int npages, bool validate)
{
--
2.35.3
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [RFC PATCH 3/3] virt: sevguest: Add support to get attestation report from SVSM
2023-06-07 15:06 [RFC PATCH 0/3] Retrieve SNP attestation from SVSM Dov Murik
2023-06-07 15:06 ` [RFC PATCH 1/3] x86/sev: Add __svsm_msr_protocol_2() which returns register values Dov Murik
2023-06-07 15:06 ` [RFC PATCH 2/3] x86/sev: Add snp_svsm_attest_services() Dov Murik
@ 2023-06-07 15:06 ` Dov Murik
2023-06-07 16:23 ` Daniel P. Berrangé
2 siblings, 1 reply; 6+ messages in thread
From: Dov Murik @ 2023-06-07 15:06 UTC (permalink / raw)
To: linux-coco
Cc: Dov Murik, Tobin Feldman-Fitzthum, James Bottomley,
Claudio Carvalho
Expose SNP_SVSM_ATTEST_SERVICES ioctl function which allows userspace to
retrieve SNP attestation report.
Signed-off-by: Dov Murik <dovmurik@linux.ibm.com>
---
drivers/virt/coco/sevguest/sevguest.c | 95 +++++++++++++++++++++++++++
include/uapi/linux/sev-guest.h | 34 ++++++++++
2 files changed, 129 insertions(+)
diff --git a/drivers/virt/coco/sevguest/sevguest.c b/drivers/virt/coco/sevguest/sevguest.c
index 0c6d1d05b9e7..a1c4acec679f 100644
--- a/drivers/virt/coco/sevguest/sevguest.c
+++ b/drivers/virt/coco/sevguest/sevguest.c
@@ -510,6 +510,97 @@ static int get_ext_report(struct snp_guest_dev *snp_dev, struct snp_guest_reques
return ret;
}
+static int call_svsm_attest_services(struct snp_guest_dev *snp_dev,
+ struct snp_guest_request_ioctl *arg)
+{
+ struct snp_svsm_attest_services_req req;
+ struct snp_svsm_attest_services_resp *resp;
+ int ret;
+ struct page *page;
+ u8 *nonce, *report, *services_manifest, *certs;
+ u32 report_size, services_manifest_size, certs_size;
+
+ if (!arg->req_data || !arg->resp_data)
+ return -EINVAL;
+
+ if (copy_from_user(&req, (void __user *)arg->req_data, sizeof(req)))
+ return -EFAULT;
+
+ if (!access_ok(req.certs_address, req.certs_len))
+ return -EFAULT;
+
+ /*
+ * Since we're allocating 32 bytes, the buffer is ensured to not cross
+ * a page boundary.
+ */
+ nonce = kzalloc(sizeof(req.nonce), GFP_KERNEL_ACCOUNT);
+ if (!nonce)
+ return -EFAULT;
+ memcpy(nonce, req.nonce, sizeof(req.nonce));
+
+ /* The report buffer passed to SVSM must be 4KB aligned */
+ page = alloc_pages(GFP_KERNEL_ACCOUNT, get_order(sizeof(resp->report)));
+ if (IS_ERR(page)) {
+ ret = -EFAULT;
+ goto free_nonce;
+ }
+ report = page_address(page);
+ report_size = sizeof(resp->report);
+
+ /* The services manifest buffer passed to SVSM must be 4KB aligned */
+ page = alloc_pages(GFP_KERNEL_ACCOUNT,
+ get_order(sizeof(resp->services_manifest)));
+ if (IS_ERR(page)) {
+ ret = -EFAULT;
+ goto free_report;
+ }
+ services_manifest = page_address(page);
+ services_manifest_size = sizeof(resp->services_manifest);
+
+ /* The certificates buffer passed to SVSM must be 4KB aligned */
+ page = alloc_pages(GFP_KERNEL_ACCOUNT, get_order(req.certs_len));
+ if (IS_ERR(page)) {
+ ret = -EFAULT;
+ goto free_manifest;
+ }
+ certs = page_address(page);
+ certs_size = req.certs_len;
+
+ ret = snp_svsm_attest_services(nonce, sizeof(req.nonce), report,
+ &report_size, services_manifest,
+ &services_manifest_size, certs,
+ &certs_size);
+ if (ret)
+ goto free_certs;
+
+ if (copy_to_user((void __user *)req.certs_address, certs,
+ req.certs_len)) {
+ ret = -EFAULT;
+ goto free_certs;
+ }
+ resp = kzalloc(sizeof(*resp), GFP_KERNEL_ACCOUNT);
+ resp->report_len = report_size;
+ resp->services_manifest_len = services_manifest_size;
+ resp->certs_len = certs_size;
+ memcpy(resp->services_manifest, services_manifest,
+ sizeof(services_manifest_size));
+ memcpy(resp->report, report, sizeof(report_size));
+ if (copy_to_user((void __user *)arg->resp_data, resp, sizeof(*resp)))
+ ret = -EFAULT;
+ kfree(resp);
+
+free_certs:
+ free_pages((unsigned long)certs, get_order(req.certs_len));
+free_manifest:
+ free_pages((unsigned long)services_manifest,
+ get_order(sizeof(resp->services_manifest)));
+free_report:
+ free_pages((unsigned long)report, get_order(sizeof(resp->report)));
+free_nonce:
+ kfree(nonce);
+ return ret;
+}
+
static long snp_guest_ioctl(struct file *file, unsigned int ioctl, unsigned long arg)
{
struct snp_guest_dev *snp_dev = to_snp_dev(file);
@@ -545,6 +636,9 @@ static long snp_guest_ioctl(struct file *file, unsigned int ioctl, unsigned long
case SNP_GET_EXT_REPORT:
ret = get_ext_report(snp_dev, &input);
break;
+ case SNP_SVSM_ATTEST_SERVICES:
+ ret = call_svsm_attest_services(snp_dev, &input);
+ break;
default:
break;
}
@@ -703,6 +797,7 @@ static int __init snp_guest_probe(struct platform_device *pdev)
goto e_free_cert_data;
dev_info(dev, "Initialized SNP guest driver (using vmpck_id %d)\n", vmpck_id);
+ //do_svsm_attest(dev);
return 0;
e_free_cert_data:
diff --git a/include/uapi/linux/sev-guest.h b/include/uapi/linux/sev-guest.h
index 256aaeff7e65..60caf767e024 100644
--- a/include/uapi/linux/sev-guest.h
+++ b/include/uapi/linux/sev-guest.h
@@ -66,6 +66,36 @@ struct snp_ext_report_req {
__u32 certs_len;
};
+struct snp_svsm_attest_services_req {
+ /* nonce that should be included in the report */
+ __u8 nonce[32];
+
+ /* where to copy the certificate blob */
+ __u64 certs_address;
+
+ /* length of the certificate buffer */
+ __u32 certs_len;
+};
+
+struct snp_svsm_attest_services_resp {
+ /* length of the returned attestation report */
+ __u32 report_len;
+
+ /* length of the returned services manifest */
+ __u32 services_manifest_len;
+
+ /* length of the returned certificates blob */
+ __u32 certs_len;
+
+ __u8 rsvd[4];
+
+ /* services manifest */
+ __u8 services_manifest[1024];
+
+ /* attestation report, see SEV-SNP spec for the format */
+ __u8 report[3000];
+};
+
#define SNP_GUEST_REQ_IOC_TYPE 'S'
/* Get SNP attestation report */
@@ -77,4 +107,8 @@ struct snp_ext_report_req {
/* Get SNP extended report as defined in the GHCB specification version 2. */
#define SNP_GET_EXT_REPORT _IOWR(SNP_GUEST_REQ_IOC_TYPE, 0x2, struct snp_guest_request_ioctl)
+/* Get SVSM attest services report as defined in the SVSM specification */
+#define SNP_SVSM_ATTEST_SERVICES \
+ _IOWR(SNP_GUEST_REQ_IOC_TYPE, 0x3, struct snp_guest_request_ioctl)
+
#endif /* __UAPI_LINUX_SEV_GUEST_H_ */
--
2.35.3
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [RFC PATCH 3/3] virt: sevguest: Add support to get attestation report from SVSM
2023-06-07 15:06 ` [RFC PATCH 3/3] virt: sevguest: Add support to get attestation report from SVSM Dov Murik
@ 2023-06-07 16:23 ` Daniel P. Berrangé
2023-06-07 17:05 ` Dov Murik
0 siblings, 1 reply; 6+ messages in thread
From: Daniel P. Berrangé @ 2023-06-07 16:23 UTC (permalink / raw)
To: Dov Murik
Cc: linux-coco, Tobin Feldman-Fitzthum, James Bottomley,
Claudio Carvalho
On Wed, Jun 07, 2023 at 06:06:46PM +0300, Dov Murik wrote:
> Expose SNP_SVSM_ATTEST_SERVICES ioctl function which allows userspace to
> retrieve SNP attestation report.
>
> Signed-off-by: Dov Murik <dovmurik@linux.ibm.com>
> ---
> drivers/virt/coco/sevguest/sevguest.c | 95 +++++++++++++++++++++++++++
> include/uapi/linux/sev-guest.h | 34 ++++++++++
> 2 files changed, 129 insertions(+)
Appreciate it is just an RFC right now, but the ioctl will eventually
need documenting at Documentation/virt/coco/sev-guest.rst
With regards,
Daniel
--
|: https://berrange.com -o- https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org -o- https://fstop138.berrange.com :|
|: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [RFC PATCH 3/3] virt: sevguest: Add support to get attestation report from SVSM
2023-06-07 16:23 ` Daniel P. Berrangé
@ 2023-06-07 17:05 ` Dov Murik
0 siblings, 0 replies; 6+ messages in thread
From: Dov Murik @ 2023-06-07 17:05 UTC (permalink / raw)
To: Daniel P. Berrangé
Cc: linux-coco, Tobin Feldman-Fitzthum, James Bottomley,
Claudio Carvalho, Dov Murik
Thanks Daniel.
On 07/06/2023 19:23, Daniel P. Berrangé wrote:
> On Wed, Jun 07, 2023 at 06:06:46PM +0300, Dov Murik wrote:
>> Expose SNP_SVSM_ATTEST_SERVICES ioctl function which allows userspace to
>> retrieve SNP attestation report.
>>
>> Signed-off-by: Dov Murik <dovmurik@linux.ibm.com>
>> ---
>> drivers/virt/coco/sevguest/sevguest.c | 95 +++++++++++++++++++++++++++
>> include/uapi/linux/sev-guest.h | 34 ++++++++++
>> 2 files changed, 129 insertions(+)
>
> Appreciate it is just an RFC right now, but the ioctl will eventually
> need documenting at Documentation/virt/coco/sev-guest.rst
>
You're right. Currently I developed this to help me test the SVSM
implementation of the attestation protocol. I'm sure there are other
debug leftovers in this series...
It was easy for me to add another function to the existing driver
(sev-guest), but maybe there's a benefit to separating this to a new
virt/coco/svsm-guest driver with its own ioctls, and autoload it when
kernel is running under SVSM.
I'll leave these options open; main focus should remain on SVSM itself
and its near future development directions.
-Dov
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2023-06-07 17:12 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-06-07 15:06 [RFC PATCH 0/3] Retrieve SNP attestation from SVSM Dov Murik
2023-06-07 15:06 ` [RFC PATCH 1/3] x86/sev: Add __svsm_msr_protocol_2() which returns register values Dov Murik
2023-06-07 15:06 ` [RFC PATCH 2/3] x86/sev: Add snp_svsm_attest_services() Dov Murik
2023-06-07 15:06 ` [RFC PATCH 3/3] virt: sevguest: Add support to get attestation report from SVSM Dov Murik
2023-06-07 16:23 ` Daniel P. Berrangé
2023-06-07 17:05 ` Dov Murik
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).