From b7c426a100191a41e0ebcb68cc5f506e268a22ea Mon Sep 17 00:00:00 2001 From: Th0rOnDoR Date: Wed, 1 Oct 2025 11:29:53 +0200 Subject: [PATCH 1/5] feat(sev-attestation): skeleton done --- tools/include/libxl.h | 5 +++++ tools/include/xenctrl.h | 1 + tools/libs/ctrl/xc_domain.c | 16 ++++++++++++++++ tools/libs/light/libxl_domain.c | 31 +++++++++++++++++++++++++++++++ tools/libs/light/libxl_x86.c | 6 +++--- tools/xl/xl.h | 1 + tools/xl/xl_cmdtable.c | 5 +++++ tools/xl/xl_misc.c | 11 +++++++++++ xen/arch/x86/coco/sev.c | 31 +++++++++++++++++++++++++++++++ xen/common/coco.c | 29 ++++++++++++++++++++++++++++- xen/include/public/hvm/coco.h | 14 ++++++++++++++ xen/include/xen/coco.h | 3 ++- 12 files changed, 148 insertions(+), 5 deletions(-) diff --git a/tools/include/libxl.h b/tools/include/libxl.h index d1d270eff14d..1d6513524ecd 100644 --- a/tools/include/libxl.h +++ b/tools/include/libxl.h @@ -3007,6 +3007,11 @@ static inline int libxl_qemu_monitor_command_0x041200(libxl_ctx *ctx, */ int libxl_clear_domid_history(libxl_ctx *ctx); +/* + * Used to retrieve for a domain using coco + */ +int libxl_domain_attestation(libxl_ctx *ctx, uint32_t domain_id, char *file); + #endif /* LIBXL_H */ /* diff --git a/tools/include/xenctrl.h b/tools/include/xenctrl.h index aae228da4450..f9efdfe84c1c 100644 --- a/tools/include/xenctrl.h +++ b/tools/include/xenctrl.h @@ -1685,6 +1685,7 @@ int xc_get_hvm_param(xc_interface *handle, uint32_t dom, int param, unsigned lon int xc_coco_platform_status(xc_interface *handle, coco_platform_status_t *status); int xc_coco_prepare_initial_mem(xc_interface *handle, coco_prepare_initial_mem_t *cmd); +int xc_coco_get_attestation(xc_interface *handle, struct coco_attestation_report_t *attestation_report); /* HVM guest pass-through */ int xc_assign_device(xc_interface *xch, diff --git a/tools/libs/ctrl/xc_domain.c b/tools/libs/ctrl/xc_domain.c index 66b6c146f4cf..1ca85660a2a5 100644 --- a/tools/libs/ctrl/xc_domain.c +++ b/tools/libs/ctrl/xc_domain.c @@ -1531,6 +1531,22 @@ int xc_coco_prepare_initial_mem(xc_interface *handle, coco_prepare_initial_mem_t xc_hypercall_buffer_free(handle, arg); return rc; } +int xc_coco_get_attestation(xc_interface *handle, struct coco_attestation_report_t *cmd) +{ + DECLARE_HYPERCALL_BUFFER(struct coco_attestation_report_t, arg); + int rc; + + arg = xc_hypercall_buffer_alloc(handle, arg, sizeof(*arg)); + if ( arg == NULL ) + return -1; + memcpy(arg, cmd, sizeof(struct coco_attestation_report_t)); + + rc = xencall2(handle->xcall, __HYPERVISOR_coco_op, XEN_COCO_attestation_report, + HYPERCALL_BUFFER_AS_ARG(arg)); + + xc_hypercall_buffer_free(handle, arg); + return rc; +} int xc_domain_setdebugging(xc_interface *xch, uint32_t domid, diff --git a/tools/libs/light/libxl_domain.c b/tools/libs/light/libxl_domain.c index dd2e5e9a1920..1b348950f75b 100644 --- a/tools/libs/light/libxl_domain.c +++ b/tools/libs/light/libxl_domain.c @@ -2621,6 +2621,37 @@ static void retrieve_domain_configuration_end(libxl__egc *egc, libxl__ao_complete(egc, ao, rc); } +int libxl_domain_attestation(libxl_ctx *ctx, uint32_t domain_id, char *file) { + //file is supposed to be valid + struct coco_attestation_report_t report; + char result[208]; + report.handle = domain_id; + report.address = &result; + report.mnonce[0] = 0x11; + report.mnonce[1] = 0x22; + report.mnonce[14] = 0xAA; + report.mnonce[15] = 0x55; + report.len = 208; + int rc; + rc = xc_coco_get_attestation(ctx->xch, &report); + + FILE *fp = fopen(file, "wb"); // open file in binary write mode + if (!fp) { + perror("fopen"); + return -1; + } + + size_t written = fwrite(&result, 1, report.len, fp); + if (written != report.len) { + perror("fwrite"); + fclose(fp); + return -1; + } + + fclose(fp); + return rc; +} + /* * Local variables: * mode: C diff --git a/tools/libs/light/libxl_x86.c b/tools/libs/light/libxl_x86.c index 8d274dbf8f0a..904c60e9aa8a 100644 --- a/tools/libs/light/libxl_x86.c +++ b/tools/libs/light/libxl_x86.c @@ -810,7 +810,7 @@ static int domain_construct_memmap(libxl__gc *gc, { e820[nr].type = XEN_HVM_MEMMAP_TYPE_SHARED_INFO; e820[nr].addr = special_region_offset; - e820[nr].size = PAGE_SIZE; + e820[nr].size = page_size; special_region_offset += e820[nr].size; nr++; @@ -818,7 +818,7 @@ static int domain_construct_memmap(libxl__gc *gc, { e820[nr].type = XEN_HVM_MEMMAP_TYPE_GRANT_TABLE; e820[nr].addr = special_region_offset; - e820[nr].size = gnttab_frame_count * PAGE_SIZE; + e820[nr].size = gnttab_frame_count * page_size; special_region_offset += e820[nr].size; nr++; } @@ -827,7 +827,7 @@ static int domain_construct_memmap(libxl__gc *gc, { e820[nr].type = XEN_HVM_MEMMAP_TYPE_GNTTAB_STATUS; e820[nr].addr = special_region_offset; - e820[nr].size = gnttab_status_frame_count * PAGE_SIZE; + e820[nr].size = gnttab_status_frame_count * page_size; special_region_offset += e820[nr].size; nr++; } diff --git a/tools/xl/xl.h b/tools/xl/xl.h index 45745f0dbbdd..517498f02ee1 100644 --- a/tools/xl/xl.h +++ b/tools/xl/xl.h @@ -217,6 +217,7 @@ int main_psr_mba_set(int argc, char **argv); int main_psr_mba_show(int argc, char **argv); #endif int main_qemu_monitor_command(int argc, char **argv); +int main_attestation(int argc, char **argv); void help(const char *command); diff --git a/tools/xl/xl_cmdtable.c b/tools/xl/xl_cmdtable.c index 06a00397184c..f44287cf6f68 100644 --- a/tools/xl/xl_cmdtable.c +++ b/tools/xl/xl_cmdtable.c @@ -641,6 +641,11 @@ const struct cmd_spec cmd_table[] = { "Issue a qemu monitor command to the device model of a domain", " ", }, + { "attestation", + &main_attestation, 0, 0, + "get attestation and put it into a file", + " ", + }, #ifdef LIBXL_HAVE_DT_OVERLAY { "dt-overlay", &main_dt_overlay, 0, 1, diff --git a/tools/xl/xl_misc.c b/tools/xl/xl_misc.c index 08f0fb6dc970..d68127dbc4a8 100644 --- a/tools/xl/xl_misc.c +++ b/tools/xl/xl_misc.c @@ -363,6 +363,17 @@ int main_config_update(int argc, char **argv) return 0; } +int main_attestation(int argc, char **argv) { + int rc = 0; + //check for segfault if wrong number of args + char *dst_file = argv[optind + 1]; + uint32_t domain_id = find_domain(argv[optind]); + //check file, open it ? + rc = libxl_domain_attestation(ctx, domain_id, dst_file); + + return rc; +} + /* * Local variables: * mode: C diff --git a/xen/arch/x86/coco/sev.c b/xen/arch/x86/coco/sev.c index b1b29ae03a83..076acae7a85a 100644 --- a/xen/arch/x86/coco/sev.c +++ b/xen/arch/x86/coco/sev.c @@ -60,6 +60,8 @@ static int sev_domain_prepare_initial_mem(struct domain *d, gfn_t gfn, size_t co mfn_t mfn, mfn_base = INVALID_MFN; size_t segment_size = 0; + flush_all(FLUSH_CACHE_WRITEBACK); + do { page = get_page_from_gfn(d, gfn_x(gfn), NULL, P2M_ALLOC); if ( unlikely(!page) ) @@ -218,10 +220,39 @@ static int sev_asid_alloc(struct domain *d, struct hvm_asid *asid) return hvm_asid_alloc_range(asid, asid_min, asid_max); } +static int sev_attestation_report(struct domain *d, struct coco_attestation_report args, void *response_buffer) { + struct sev_data_attestation_report report; + int psp_ret; + int rc; + + + report.handle = d->arch.hvm.svm.sev.asp_handle; + report.len = args.len; + report.reserved = 0; + report.address = (uint64_t) virt_to_maddr(response_buffer); + for (size_t i =0; i < 16; i++) { // or memcpy ? + report.mnonce[i] = args.mnonce[i]; + } + printk(XENLOG_DEBUG + "asp: ATTESTATION_REPORT d%d: size=%u\n", d->domain_id, args.len); + rc = sev_do_cmd(SEV_CMD_ATTESTATION_REPORT, (void *)(&report), + &psp_ret, true); + + if (!rc && !psp_ret) { + return 0; + } + printk(XENLOG_ERR "asp: failed to get ATTESTATION for d%hu: psp_ret %d\n", + d->domain_id, psp_ret); + return rc; +} + + + static struct coco_domain_ops sev_domain_ops = { .prepare_initial_mem = sev_domain_prepare_initial_mem, .domain_initialise = sev_domain_initialise, .domain_creation_finished = sev_domain_creation_finished, + .domain_attestation_report = sev_attestation_report, .domain_destroy = sev_domain_destroy, .asid_alloc = sev_asid_alloc, }; diff --git a/xen/common/coco.c b/xen/common/coco.c index d1e95dccdf16..9a3b55d914ba 100644 --- a/xen/common/coco.c +++ b/xen/common/coco.c @@ -101,6 +101,24 @@ long coco_op_prepare_initial_mem(struct coco_prepare_initial_mem arg) return rc; } +static long coco_op_get_attestation_report(struct coco_attestation_report report) { + struct domain *d; + int rc; + + char resp[208]; + d = get_domain_by_id(report.handle); + rc = d->coco_ops->domain_attestation_report(d, report, resp); + + if (!rc) { + if (copy_to_guest(report.address, &resp, 1)) { + return -EFAULT; + } + } + return rc; + +} + + long do_coco_op(unsigned int cmd, XEN_GUEST_HANDLE_PARAM(void) arg) { if ( !is_hardware_domain(current->domain) ) @@ -125,6 +143,15 @@ long do_coco_op(unsigned int cmd, XEN_GUEST_HANDLE_PARAM(void) arg) return coco_op_prepare_initial_mem(prepare_initial_mem); } + case XEN_COCO_attestation_report: + { + struct coco_attestation_report report; + if ( copy_from_guest(&report, arg, 1) ) { + return -EFAULT; + } + + return coco_op_get_attestation_report(report); + } default: return -ENOSYS; @@ -137,4 +164,4 @@ long do_sev_console_op(unsigned long c) return 0; } -__initcall(coco_init); \ No newline at end of file +__initcall(coco_init); diff --git a/xen/include/public/hvm/coco.h b/xen/include/public/hvm/coco.h index 2e23d91e1249..9b460aa0052c 100644 --- a/xen/include/public/hvm/coco.h +++ b/xen/include/public/hvm/coco.h @@ -62,4 +62,18 @@ struct coco_prepare_initial_mem { typedef struct coco_prepare_initial_mem coco_prepare_initial_mem_t; DEFINE_XEN_GUEST_HANDLE(coco_prepare_initial_mem_t); +struct coco_attestation_report { + uint32_t handle; /* IN */ + XEN_GUEST_HANDLE(void) address; /* In */ + uint8_t mnonce[16]; /* In */ + uint32_t len; /* In/Out */ +}; +struct coco_attestation_report_t { + uint32_t handle; /* IN */ + void* address; /* In */ + uint8_t mnonce[16]; /* In */ + uint32_t len; /* In/Out */ +}; +#define XEN_COCO_attestation_report 2 + #endif /* __XEN_PUBLIC_HVM_COCO_H__ */ diff --git a/xen/include/xen/coco.h b/xen/include/xen/coco.h index 2ae43995ec2b..9139e5651c4c 100644 --- a/xen/include/xen/coco.h +++ b/xen/include/xen/coco.h @@ -17,6 +17,7 @@ struct coco_domain_ops { /* HVM domain hooks */ int (*domain_initialise)(struct domain *d); int (*domain_creation_finished)(struct domain *d); + int (*domain_attestation_report)(struct domain *d, struct coco_attestation_report report, void* response_buffer); void (*domain_destroy)(struct domain *d); #ifdef CONFIG_X86 @@ -85,4 +86,4 @@ static inline void coco_domain_destroy(struct domain *d) } #endif -#endif /* _XEN_COCO_H */ \ No newline at end of file +#endif /* _XEN_COCO_H */ From 9c6ca3607a35e1afc8a64db654cc18ca98eeedc9 Mon Sep 17 00:00:00 2001 From: Th0rOnDoR Date: Wed, 1 Oct 2025 16:56:48 +0200 Subject: [PATCH 2/5] feat(sev-attestation): xl attestation options --- tools/include/libxl.h | 2 +- tools/libs/light/libxl_domain.c | 60 ++++++++++++++++++++++++--------- tools/xl/xl_misc.c | 50 +++++++++++++++++++++++---- 3 files changed, 89 insertions(+), 23 deletions(-) diff --git a/tools/include/libxl.h b/tools/include/libxl.h index 1d6513524ecd..13538f45e116 100644 --- a/tools/include/libxl.h +++ b/tools/include/libxl.h @@ -3010,7 +3010,7 @@ int libxl_clear_domid_history(libxl_ctx *ctx); /* * Used to retrieve for a domain using coco */ -int libxl_domain_attestation(libxl_ctx *ctx, uint32_t domain_id, char *file); +int libxl_domain_attestation(libxl_ctx *ctx, uint32_t domain_id, FILE *file, bool is_mmonce_file, char *mmonce); #endif /* LIBXL_H */ diff --git a/tools/libs/light/libxl_domain.c b/tools/libs/light/libxl_domain.c index 1b348950f75b..89c834d90344 100644 --- a/tools/libs/light/libxl_domain.c +++ b/tools/libs/light/libxl_domain.c @@ -2621,34 +2621,62 @@ static void retrieve_domain_configuration_end(libxl__egc *egc, libxl__ao_complete(egc, ao, rc); } -int libxl_domain_attestation(libxl_ctx *ctx, uint32_t domain_id, char *file) { - //file is supposed to be valid +static int hex_char_to_int(char c) { + if ('0' <= c && c <= '9') return c - '0'; + if ('a' <= c && c <= 'f') return c - 'a' + 10; + if ('A' <= c && c <= 'F') return c - 'A' + 10; + return -1; +} + +int libxl_domain_attestation(libxl_ctx *ctx, uint32_t domain_id, FILE *file, bool is_mmonce_file, char *mmonce) { struct coco_attestation_report_t report; char result[208]; + int rc, r; + + if (is_mmonce_file) { + int datalen = 0; + void *data = NULL; + + r = libxl_read_file_contents(ctx, mmonce, &data, &datalen); + + if (datalen != 16) { + fprintf(stderr, "Error: invalid mmonce length\n"); + return ERROR_INVAL; + } + memcpy(&report.mnonce, data, 16); + free(data); + } else { + if (strnlen(mmonce, 33) != 32) { + fprintf(stderr, "Error: invalid mmonce length\n"); + } + for (int i = 0; i < 16; i++) { + int hi = hex_char_to_int(mmonce[2*i]); + int lo = hex_char_to_int(mmonce[2*i + 1]); + + if (hi < 0 || lo < 0) { + fprintf(stderr, "Error: invalid hex character\n"); + return -1; + } + + report.mnonce[i] = (hi << 4) | lo; + } + + } + report.handle = domain_id; report.address = &result; - report.mnonce[0] = 0x11; - report.mnonce[1] = 0x22; - report.mnonce[14] = 0xAA; - report.mnonce[15] = 0x55; report.len = 208; - int rc; - rc = xc_coco_get_attestation(ctx->xch, &report); - FILE *fp = fopen(file, "wb"); // open file in binary write mode - if (!fp) { - perror("fopen"); - return -1; - } + rc = xc_coco_get_attestation(ctx->xch, &report); - size_t written = fwrite(&result, 1, report.len, fp); + size_t written = fwrite(&result, 1, report.len, file); if (written != report.len) { perror("fwrite"); - fclose(fp); + fclose(file); return -1; } - fclose(fp); + fclose(file); return rc; } diff --git a/tools/xl/xl_misc.c b/tools/xl/xl_misc.c index d68127dbc4a8..aa830e48e206 100644 --- a/tools/xl/xl_misc.c +++ b/tools/xl/xl_misc.c @@ -364,12 +364,50 @@ int main_config_update(int argc, char **argv) } int main_attestation(int argc, char **argv) { - int rc = 0; - //check for segfault if wrong number of args - char *dst_file = argv[optind + 1]; - uint32_t domain_id = find_domain(argv[optind]); - //check file, open it ? - rc = libxl_domain_attestation(ctx, domain_id, dst_file); + int rc; + FILE *dst_file = stdout; + char * mmonce = NULL; + uint32_t domain_id; + bool is_mmonce_file = false; + + int opt; + static struct option opts[] = { + {"file", 1, 0, 'f'}, + {"print", 0, 0, 'p'}, + {"mmonce", 1, 0, 'm'}, + {"mmonce-file", 1, 0, 'n'}, + COMMON_LONG_OPTS + }; + + SWITCH_FOREACH_OPT(opt, "f:pm:n:", opts, "attestation", 0) { + case 'p': + dst_file = stdout; + break; + case 'f': + dst_file = fopen(optarg, "wb"); // open file in binary write mode + if (!dst_file) { + perror("fopen"); + return -1; + } + break; + case 'm': + mmonce = optarg; + is_mmonce_file = false; + break; + case 'n': + mmonce = optarg; + is_mmonce_file = true; + break; + } + + if (mmonce == NULL) { + fprintf(stderr, "Error: no mmonce provided\n"); + return 1; + } + + domain_id = find_domain(argv[optind]); + + rc = libxl_domain_attestation(ctx, domain_id, dst_file, is_mmonce_file, mmonce); return rc; } From 548fa5ce82338249c7ea2eca7b0f8f9a4fd3800b Mon Sep 17 00:00:00 2001 From: Th0rOnDoR Date: Thu, 2 Oct 2025 17:22:07 +0200 Subject: [PATCH 3/5] fix(sev/attestation): prepare pr --- tools/libs/light/libxl_domain.c | 12 +++++++----- tools/xl/xl_cmdtable.c | 4 ++-- tools/xl/xl_misc.c | 2 +- xen/arch/x86/coco/sev.c | 10 +++++++--- xen/common/coco.c | 4 ++-- xen/include/xen/coco.h | 3 ++- 6 files changed, 21 insertions(+), 14 deletions(-) diff --git a/tools/libs/light/libxl_domain.c b/tools/libs/light/libxl_domain.c index 89c834d90344..cde716e19a9e 100644 --- a/tools/libs/light/libxl_domain.c +++ b/tools/libs/light/libxl_domain.c @@ -2669,11 +2669,13 @@ int libxl_domain_attestation(libxl_ctx *ctx, uint32_t domain_id, FILE *file, boo rc = xc_coco_get_attestation(ctx->xch, &report); - size_t written = fwrite(&result, 1, report.len, file); - if (written != report.len) { - perror("fwrite"); - fclose(file); - return -1; + if (!rc) { + size_t written = fwrite(&result, 1, report.len, file); + if (written != report.len) { + perror("fwrite"); + fclose(file); + return -1; + } } fclose(file); diff --git a/tools/xl/xl_cmdtable.c b/tools/xl/xl_cmdtable.c index f44287cf6f68..6f20966ddc54 100644 --- a/tools/xl/xl_cmdtable.c +++ b/tools/xl/xl_cmdtable.c @@ -643,8 +643,8 @@ const struct cmd_spec cmd_table[] = { }, { "attestation", &main_attestation, 0, 0, - "get attestation and put it into a file", - " ", + "request attestation for a coco and put it into a file", + " ", }, #ifdef LIBXL_HAVE_DT_OVERLAY { "dt-overlay", diff --git a/tools/xl/xl_misc.c b/tools/xl/xl_misc.c index aa830e48e206..3868308a795d 100644 --- a/tools/xl/xl_misc.c +++ b/tools/xl/xl_misc.c @@ -384,7 +384,7 @@ int main_attestation(int argc, char **argv) { dst_file = stdout; break; case 'f': - dst_file = fopen(optarg, "wb"); // open file in binary write mode + dst_file = fopen(optarg, "wb"); if (!dst_file) { perror("fopen"); return -1; diff --git a/xen/arch/x86/coco/sev.c b/xen/arch/x86/coco/sev.c index 076acae7a85a..3eb6dfa375c8 100644 --- a/xen/arch/x86/coco/sev.c +++ b/xen/arch/x86/coco/sev.c @@ -220,12 +220,13 @@ static int sev_asid_alloc(struct domain *d, struct hvm_asid *asid) return hvm_asid_alloc_range(asid, asid_min, asid_max); } -static int sev_attestation_report(struct domain *d, struct coco_attestation_report args, void *response_buffer) { +static int sev_attestation_report(struct domain *d, + struct coco_attestation_report args, void *response_buffer) { struct sev_data_attestation_report report; int psp_ret; int rc; - + //from coco struct to sev specific report.handle = d->arch.hvm.svm.sev.asp_handle; report.len = args.len; report.reserved = 0; @@ -233,16 +234,19 @@ static int sev_attestation_report(struct domain *d, struct coco_attestation_repo for (size_t i =0; i < 16; i++) { // or memcpy ? report.mnonce[i] = args.mnonce[i]; } + printk(XENLOG_DEBUG "asp: ATTESTATION_REPORT d%d: size=%u\n", d->domain_id, args.len); + rc = sev_do_cmd(SEV_CMD_ATTESTATION_REPORT, (void *)(&report), &psp_ret, true); if (!rc && !psp_ret) { return 0; } - printk(XENLOG_ERR "asp: failed to get ATTESTATION for d%hu: psp_ret %d\n", + printk(XENLOG_ERR "asp: failed to ATTESTATION for d%hu: psp_ret %d\n", d->domain_id, psp_ret); + return rc; } diff --git a/xen/common/coco.c b/xen/common/coco.c index 9a3b55d914ba..5d200f59620a 100644 --- a/xen/common/coco.c +++ b/xen/common/coco.c @@ -104,8 +104,8 @@ long coco_op_prepare_initial_mem(struct coco_prepare_initial_mem arg) static long coco_op_get_attestation_report(struct coco_attestation_report report) { struct domain *d; int rc; - char resp[208]; + d = get_domain_by_id(report.handle); rc = d->coco_ops->domain_attestation_report(d, report, resp); @@ -114,8 +114,8 @@ static long coco_op_get_attestation_report(struct coco_attestation_report report return -EFAULT; } } - return rc; + return rc; } diff --git a/xen/include/xen/coco.h b/xen/include/xen/coco.h index 9139e5651c4c..b19edf11209b 100644 --- a/xen/include/xen/coco.h +++ b/xen/include/xen/coco.h @@ -17,7 +17,8 @@ struct coco_domain_ops { /* HVM domain hooks */ int (*domain_initialise)(struct domain *d); int (*domain_creation_finished)(struct domain *d); - int (*domain_attestation_report)(struct domain *d, struct coco_attestation_report report, void* response_buffer); + int (*domain_attestation_report)(struct domain *d, + struct coco_attestation_report report, void* response_buffer); void (*domain_destroy)(struct domain *d); #ifdef CONFIG_X86 From bec4255683b2281ef446bef436455f531df1782b Mon Sep 17 00:00:00 2001 From: Th0rOnDoR Date: Mon, 6 Oct 2025 13:59:07 +0200 Subject: [PATCH 4/5] fix(sev/attestation): addresses correction for hypercall and names --- tools/include/libxl.h | 2 +- tools/include/xenctrl.h | 34 ++++++++++----------- tools/libs/ctrl/xc_domain.c | 18 ++++++----- tools/libs/light/libxl_domain.c | 27 ++++++++-------- tools/xl/xl_misc.c | 17 ++++++----- xen/arch/x86/coco/sev.c | 29 +++++++++--------- xen/arch/x86/include/asm/psp-sev.h | 3 +- xen/common/coco.c | 49 +++++++++++++++++++----------- xen/include/public/hvm/coco.h | 40 ++++++++++++++++-------- xen/include/xen/coco.h | 8 ++--- 10 files changed, 131 insertions(+), 96 deletions(-) diff --git a/tools/include/libxl.h b/tools/include/libxl.h index 13538f45e116..ed26f823fbd4 100644 --- a/tools/include/libxl.h +++ b/tools/include/libxl.h @@ -3010,7 +3010,7 @@ int libxl_clear_domid_history(libxl_ctx *ctx); /* * Used to retrieve for a domain using coco */ -int libxl_domain_attestation(libxl_ctx *ctx, uint32_t domain_id, FILE *file, bool is_mmonce_file, char *mmonce); +int libxl_domain_attestation(libxl_ctx *ctx, uint32_t domid, int file, bool is_mmonce_file, char *mmonce); #endif /* LIBXL_H */ diff --git a/tools/include/xenctrl.h b/tools/include/xenctrl.h index f9efdfe84c1c..6e589dfe0835 100644 --- a/tools/include/xenctrl.h +++ b/tools/include/xenctrl.h @@ -434,11 +434,11 @@ static inline bool dominfo_shutdown_with(const xc_domaininfo_t *info, (dominfo_shutdown_reason(info) == expected_reason); } -typedef union +typedef union { #if defined(__i386__) || defined(__x86_64__) vcpu_guest_context_x86_64_t x64; - vcpu_guest_context_x86_32_t x32; + vcpu_guest_context_x86_32_t x32; #endif vcpu_guest_context_t c; } vcpu_guest_context_any_t; @@ -735,7 +735,7 @@ int xc_domain_hvm_getcontext(xc_interface *xch, * This function returns one element of the context of a hvm domain * @parm xch a handle to an open hypervisor interface * @parm domid the domain to get information from - * @parm typecode which type of elemnt required + * @parm typecode which type of elemnt required * @parm instance which instance of the type * @parm ctxt_buf a pointer to a structure to store the execution context of * the hvm domain @@ -917,7 +917,7 @@ xc_sched_arinc653_schedule_get( * @parm xch a handle to an open hypervisor interface * @parm domid the domain id to send trigger * @parm trigger the trigger type - * @parm vcpu the vcpu number to send trigger + * @parm vcpu the vcpu number to send trigger * return 0 on success, -1 on failure */ int xc_domain_send_trigger(xc_interface *xch, @@ -938,11 +938,11 @@ int xc_domain_setdebugging(xc_interface *xch, unsigned int enable); /** - * This function audits the (top level) p2m of a domain + * This function audits the (top level) p2m of a domain * and returns the different error counts, if any. * * @parm xch a handle to an open hypervisor interface - * @parm domid the domain id whose top level p2m we + * @parm domid the domain id whose top level p2m we * want to audit * @parm orphans count of m2p entries for valid * domain pages containing an invalid value @@ -951,14 +951,14 @@ int xc_domain_setdebugging(xc_interface *xch, * @parm p2m_bad count of p2m entries for this domain * mismatching the associated m2p entry * return 0 on success, -1 on failure - * errno values on failure include: + * errno values on failure include: * -ENOSYS: not implemented * -EFAULT: could not copy results back to guest */ int xc_domain_p2m_audit(xc_interface *xch, uint32_t domid, uint64_t *orphans, - uint64_t *m2p_bad, + uint64_t *m2p_bad, uint64_t *p2m_bad); /** @@ -1093,7 +1093,7 @@ typedef int xc_evtchn_port_or_error_t; * This function allocates an unbound port. Ports are named endpoints used for * interdomain communication. This function is most useful in opening a * well-known port within a domain to receive events on. - * + * * NOTE: If you are allocating a *local* unbound port, you probably want to * use xc_evtchn_bind_unbound_port(). This function is intended for allocating * ports *only* during domain creation. @@ -1165,7 +1165,7 @@ int xc_machphys_mfn_list(xc_interface *xch, typedef struct xen_sysctl_cpuinfo xc_cpuinfo_t; int xc_getcpuinfo(xc_interface *xch, int max_cpus, - xc_cpuinfo_t *info, int *nr_cpus); + xc_cpuinfo_t *info, int *nr_cpus); int xc_domain_setmaxmem(xc_interface *xch, uint32_t domid, @@ -1398,7 +1398,7 @@ void *xc_memalign(xc_interface *xch, size_t alignment, size_t size); * as 4M superpages, or guests using PSE36). Only used for debugging. * * Translates a virtual address in the context of a given domain and - * vcpu returning the GFN containing the address (that is, an MFN for + * vcpu returning the GFN containing the address (that is, an MFN for * PV guests, a PFN for HVM guests). Returns 0 for failure. * * @parm xch a handle on an open hypervisor interface @@ -1434,7 +1434,7 @@ long xc_get_tot_pages(xc_interface *xch, uint32_t domid); /** * This function retrieves the the number of bytes available * in the heap in a specific range of address-widths and nodes. - * + * * @parm xch a handle to an open hypervisor interface * @parm domid the domain to query * @parm min_width the smallest address width to query (0 if don't care) @@ -1685,7 +1685,7 @@ int xc_get_hvm_param(xc_interface *handle, uint32_t dom, int param, unsigned lon int xc_coco_platform_status(xc_interface *handle, coco_platform_status_t *status); int xc_coco_prepare_initial_mem(xc_interface *handle, coco_prepare_initial_mem_t *cmd); -int xc_coco_get_attestation(xc_interface *handle, struct coco_attestation_report_t *attestation_report); +int xc_coco_get_attestation(xc_interface *handle, coco_attestation_report_t *report); /* HVM guest pass-through */ int xc_assign_device(xc_interface *xch, @@ -1905,8 +1905,8 @@ int xc_cpu_offline(xc_interface *xch, int cpu); int xc_smt_enable(xc_interface *xch); int xc_smt_disable(xc_interface *xch); -/* - * cpufreq para name of this structure named +/* + * cpufreq para name of this structure named * same as sysfs file name of native linux */ typedef struct xen_userspace xc_userspace_t; @@ -2018,7 +2018,7 @@ int xc_altp2m_get_vcpu_p2m_idx(xc_interface *handle, uint32_t domid, int xc_altp2m_set_visibility(xc_interface *handle, uint32_t domid, uint16_t view_id, bool visible); -/** +/** * Mem paging operations. * Paging is supported only on the x86 architecture in 64 bit mode, with * Hardware-Assisted Paging (i.e. Intel EPT, AMD NPT). Moreover, AMD NPT @@ -2034,7 +2034,7 @@ int xc_mem_paging_prep(xc_interface *xch, uint32_t domain_id, uint64_t gfn); int xc_mem_paging_load(xc_interface *xch, uint32_t domain_id, uint64_t gfn, void *buffer); -/** +/** * Access tracking operations. * Supported only on Intel EPT 64 bit processors. */ diff --git a/tools/libs/ctrl/xc_domain.c b/tools/libs/ctrl/xc_domain.c index 1ca85660a2a5..f472b7c66800 100644 --- a/tools/libs/ctrl/xc_domain.c +++ b/tools/libs/ctrl/xc_domain.c @@ -655,7 +655,7 @@ long long xc_logdirty_control(xc_interface *xch, if ( stats ) memcpy(stats, &domctl.u.shadow_op.stats, sizeof(xc_shadow_op_stats_t)); - + return (rc == 0) ? domctl.u.shadow_op.pages : rc; } @@ -1531,19 +1531,23 @@ int xc_coco_prepare_initial_mem(xc_interface *handle, coco_prepare_initial_mem_t xc_hypercall_buffer_free(handle, arg); return rc; } -int xc_coco_get_attestation(xc_interface *handle, struct coco_attestation_report_t *cmd) + +int xc_coco_get_attestation(xc_interface *handle, coco_attestation_report_t *cmd) { - DECLARE_HYPERCALL_BUFFER(struct coco_attestation_report_t, arg); + DECLARE_HYPERCALL_BUFFER(coco_attestation_report_t, arg); int rc; arg = xc_hypercall_buffer_alloc(handle, arg, sizeof(*arg)); if ( arg == NULL ) return -1; - memcpy(arg, cmd, sizeof(struct coco_attestation_report_t)); + memcpy(arg, cmd, sizeof(coco_attestation_report_t)); rc = xencall2(handle->xcall, __HYPERVISOR_coco_op, XEN_COCO_attestation_report, - HYPERCALL_BUFFER_AS_ARG(arg)); + HYPERCALL_BUFFER_AS_ARG(arg)); + if (!rc) { + memcpy(cmd, arg, sizeof(coco_attestation_report_t)); + } xc_hypercall_buffer_free(handle, arg); return rc; } @@ -2076,10 +2080,10 @@ int xc_domain_debug_control(xc_interface *xc, uint32_t domid, uint32_t sop, uint return do_domctl(xc, &domctl); } -int xc_domain_p2m_audit(xc_interface *xch, +int xc_domain_p2m_audit(xc_interface *xch, uint32_t domid, uint64_t *orphans, - uint64_t *m2p_bad, + uint64_t *m2p_bad, uint64_t *p2m_bad) { struct xen_domctl domctl = {}; diff --git a/tools/libs/light/libxl_domain.c b/tools/libs/light/libxl_domain.c index cde716e19a9e..e0ae82c2eae2 100644 --- a/tools/libs/light/libxl_domain.c +++ b/tools/libs/light/libxl_domain.c @@ -15,6 +15,8 @@ #include "libxl_osdeps.h" #include "libxl_internal.h" +#include "xenctrl.h" +#include #define PAGE_TO_MEMKB(pages) ((pages) * 4) @@ -2628,17 +2630,16 @@ static int hex_char_to_int(char c) { return -1; } -int libxl_domain_attestation(libxl_ctx *ctx, uint32_t domain_id, FILE *file, bool is_mmonce_file, char *mmonce) { - struct coco_attestation_report_t report; - char result[208]; +int libxl_domain_attestation(libxl_ctx *ctx, uint32_t domid, int file, bool is_mmonce_file, char *mmonce) { + coco_attestation_report_t report; int rc, r; - + if (is_mmonce_file) { int datalen = 0; void *data = NULL; - + r = libxl_read_file_contents(ctx, mmonce, &data, &datalen); - + if (datalen != 16) { fprintf(stderr, "Error: invalid mmonce length\n"); return ERROR_INVAL; @@ -2663,22 +2664,22 @@ int libxl_domain_attestation(libxl_ctx *ctx, uint32_t domain_id, FILE *file, boo } - report.handle = domain_id; - report.address = &result; - report.len = 208; + report.domid = domid; + report.len = 0; rc = xc_coco_get_attestation(ctx->xch, &report); if (!rc) { - size_t written = fwrite(&result, 1, report.len, file); + size_t written = write(file, &report.sev, report.len); + // the union used does not matter, we use the pointer if (written != report.len) { - perror("fwrite"); - fclose(file); + perror("write"); + close(file); return -1; } } - fclose(file); + close(file); return rc; } diff --git a/tools/xl/xl_misc.c b/tools/xl/xl_misc.c index 3868308a795d..11f8518dc386 100644 --- a/tools/xl/xl_misc.c +++ b/tools/xl/xl_misc.c @@ -12,6 +12,7 @@ * GNU Lesser General Public License for more details. */ +#include #include #include @@ -365,11 +366,11 @@ int main_config_update(int argc, char **argv) int main_attestation(int argc, char **argv) { int rc; - FILE *dst_file = stdout; + int dst_file = 1; char * mmonce = NULL; - uint32_t domain_id; + uint32_t domid; bool is_mmonce_file = false; - + int opt; static struct option opts[] = { {"file", 1, 0, 'f'}, @@ -381,12 +382,12 @@ int main_attestation(int argc, char **argv) { SWITCH_FOREACH_OPT(opt, "f:pm:n:", opts, "attestation", 0) { case 'p': - dst_file = stdout; + dst_file = 1; break; case 'f': - dst_file = fopen(optarg, "wb"); + dst_file = open(optarg, O_WRONLY | O_CREAT, 0644); if (!dst_file) { - perror("fopen"); + perror("open"); return -1; } break; @@ -405,9 +406,9 @@ int main_attestation(int argc, char **argv) { return 1; } - domain_id = find_domain(argv[optind]); + domid = find_domain(argv[optind]); - rc = libxl_domain_attestation(ctx, domain_id, dst_file, is_mmonce_file, mmonce); + rc = libxl_domain_attestation(ctx, domid, dst_file, is_mmonce_file, mmonce); return rc; } diff --git a/xen/arch/x86/coco/sev.c b/xen/arch/x86/coco/sev.c index 3eb6dfa375c8..f6ae96c6e15f 100644 --- a/xen/arch/x86/coco/sev.c +++ b/xen/arch/x86/coco/sev.c @@ -8,7 +8,7 @@ #include #include #include - + #include #include @@ -81,7 +81,7 @@ static int sev_domain_prepare_initial_mem(struct domain *d, gfn_t gfn, size_t co printk(XENLOG_DEBUG "asp: LAUNCH_UPDATE_DATA d%d: base=%"PRI_xen_pfn", size=%zx\n", d->domain_id, mfn_x(mfn_base), segment_size); - + sd_lud.reserved = 0; sd_lud.handle = d->arch.hvm.svm.sev.asp_handle; sd_lud.address = mfn_x(mfn_base) << PAGE_SHIFT; @@ -99,7 +99,7 @@ static int sev_domain_prepare_initial_mem(struct domain *d, gfn_t gfn, size_t co mfn_base = mfn; segment_size = 0; } - } + } gfn = gfn_add(gfn, 1); segment_size++; @@ -141,7 +141,7 @@ static int sev_domain_creation_finished(struct domain *d) { printk(XENLOG_ERR "asp: failed to LAUNCH_MEASURE for d%hu: psp_ret %hu, rc %ld\n", d->domain_id, psp_ret, rc); - + if (psp_ret == SEV_RET_INVALID_LEN) printk(XENLOG_ERR "asp: Expected %"PRIu32" bytes\n", sd_lm.len); return rc; @@ -221,26 +221,27 @@ static int sev_asid_alloc(struct domain *d, struct hvm_asid *asid) } static int sev_attestation_report(struct domain *d, - struct coco_attestation_report args, void *response_buffer) { + struct coco_attestation_report *args) { struct sev_data_attestation_report report; int psp_ret; int rc; //from coco struct to sev specific report.handle = d->arch.hvm.svm.sev.asp_handle; - report.len = args.len; + report.len = 208; // size of AMD-SEV attestation + args->len = 208; report.reserved = 0; - report.address = (uint64_t) virt_to_maddr(response_buffer); + report.address = (uint64_t) virt_to_maddr(&args->sev); for (size_t i =0; i < 16; i++) { // or memcpy ? - report.mnonce[i] = args.mnonce[i]; + report.mnonce[i] = args->mnonce[i]; } - - printk(XENLOG_DEBUG - "asp: ATTESTATION_REPORT d%d: size=%u\n", d->domain_id, args.len); - + + printk(XENLOG_ERR + "asp: ATTESTATION_REPORT d%d: size=%u\n", d->domain_id, args->len); + rc = sev_do_cmd(SEV_CMD_ATTESTATION_REPORT, (void *)(&report), &psp_ret, true); - + if (!rc && !psp_ret) { return 0; } @@ -275,7 +276,7 @@ static int sev_init(void) printk(XENLOG_INFO "sev: Supports up to %"PRIu32" guests\n", raw_cpu_policy.extd.max_sev_guests); - /* Enable AMD SME */ + /* Enable AMD SME */ rdmsrl(MSR_K8_SYSCFG, syscfg); if ( !(syscfg & SYSCFG_MEM_ENCRYPT) ) diff --git a/xen/arch/x86/include/asm/psp-sev.h b/xen/arch/x86/include/asm/psp-sev.h index 5bbe1ed2c068..9ad88ba6f9cd 100644 --- a/xen/arch/x86/include/asm/psp-sev.h +++ b/xen/arch/x86/include/asm/psp-sev.h @@ -512,7 +512,8 @@ struct sev_data_attestation_report { /** - * SEV platform commands + * SEV platform command} attestation; +s */ enum { SEV_FACTORY_RESET = 0, diff --git a/xen/common/coco.c b/xen/common/coco.c index 5d200f59620a..9a00a2c05b9f 100644 --- a/xen/common/coco.c +++ b/xen/common/coco.c @@ -2,7 +2,9 @@ /* * General confidential computing functions. */ - + +#include "xen/config.h" +#include "xen/lib.h" #include #include #include @@ -40,7 +42,7 @@ int __init coco_init(void) if ( coco_ops->init ) { rc = coco_ops->init(); - + if ( rc ) { printk("coco: Unable to initialize coco platform (%d)", rc); @@ -76,7 +78,7 @@ int coco_prepare_initial_memory(struct domain *d, gfn_t gfn, size_t page_count) if ( d->coco_ops->prepare_initial_mem ) return d->coco_ops->prepare_initial_mem(d, gfn, page_count); - + return 0; } @@ -87,7 +89,7 @@ long coco_op_prepare_initial_mem(struct coco_prepare_initial_mem arg) if ( !d ) return -ENOENT; - + if ( !is_coco_domain(d) ) { rc = -EOPNOTSUPP; @@ -101,19 +103,22 @@ long coco_op_prepare_initial_mem(struct coco_prepare_initial_mem arg) return rc; } -static long coco_op_get_attestation_report(struct coco_attestation_report report) { +static long coco_op_get_attestation_report(coco_attestation_report_t *report) { struct domain *d; int rc; - char resp[208]; - d = get_domain_by_id(report.handle); - rc = d->coco_ops->domain_attestation_report(d, report, resp); + d = get_domain_by_id(report->domid); - if (!rc) { - if (copy_to_guest(report.address, &resp, 1)) { - return -EFAULT; - } - } + if (!d) + return -ENOENT; + + if (!is_coco_domain(d)) + return -EOPNOTSUPP; + + if (!d->coco_ops || !d->coco_ops->domain_attestation_report) + return -EOPNOTSUPP; + + rc = d->coco_ops->domain_attestation_report(d, report); return rc; } @@ -133,7 +138,7 @@ long do_coco_op(unsigned int cmd, XEN_GUEST_HANDLE_PARAM(void) arg) return 0; } - + case XEN_COCO_prepare_initial_mem: { struct coco_prepare_initial_mem prepare_initial_mem; @@ -145,12 +150,20 @@ long do_coco_op(unsigned int cmd, XEN_GUEST_HANDLE_PARAM(void) arg) } case XEN_COCO_attestation_report: { - struct coco_attestation_report report; - if ( copy_from_guest(&report, arg, 1) ) { + coco_attestation_report_t report; + int rc = 0; + + if ( copy_from_guest(&report, arg, 1) ) return -EFAULT; - } - return coco_op_get_attestation_report(report); + rc = coco_op_get_attestation_report(&report); + if (rc) + return rc; + + if (copy_to_guest(arg, &report, 1)) + return -EFAULT; + + return 0; } default: diff --git a/xen/include/public/hvm/coco.h b/xen/include/public/hvm/coco.h index 9b460aa0052c..204adcda40d7 100644 --- a/xen/include/public/hvm/coco.h +++ b/xen/include/public/hvm/coco.h @@ -43,13 +43,14 @@ typedef struct coco_platform_status coco_platform_status_t; DEFINE_XEN_GUEST_HANDLE(coco_platform_status_t); #define XEN_COCO_prepare_initial_mem 1 +#define XEN_COCO_attestation_report 2 /** * XEN_COCO_prepare_initial_mem: Prepare early memory pages of a guest - * + * * During guest construction, the confidential computing platform may require memory * to be prepared (e.g., encrypted) before the guest is started. - * + * * After preparation, any further access to these pages is invalid, as they may be * encrypted, sealed, or tracked by the platform. */ @@ -62,18 +63,31 @@ struct coco_prepare_initial_mem { typedef struct coco_prepare_initial_mem coco_prepare_initial_mem_t; DEFINE_XEN_GUEST_HANDLE(coco_prepare_initial_mem_t); + +struct sev_attestation_report_response { + uint8_t mnonce[16]; + uint8_t launch_digest[32]; + uint32_t policy; + uint32_t sig_usage; + uint32_t sig_algo; + uint32_t reserved; + uint8_t sig[144]; +} __attribute__((packed)); + +/** + * len is the size used by the attestation + * the union is used to make sure the struct is big enough to handle all attestation + */ struct coco_attestation_report { - uint32_t handle; /* IN */ - XEN_GUEST_HANDLE(void) address; /* In */ - uint8_t mnonce[16]; /* In */ - uint32_t len; /* In/Out */ -}; -struct coco_attestation_report_t { - uint32_t handle; /* IN */ - void* address; /* In */ - uint8_t mnonce[16]; /* In */ - uint32_t len; /* In/Out */ + domid_t domid; /* IN */ + uint8_t mnonce[16]; /* IN */ + uint32_t len; /* OUT */ + union { + struct sev_attestation_report_response sev; + } /* OUT */; }; -#define XEN_COCO_attestation_report 2 +typedef struct coco_attestation_report coco_attestation_report_t; +DEFINE_XEN_GUEST_HANDLE(coco_attestation_report_t); + #endif /* __XEN_PUBLIC_HVM_COCO_H__ */ diff --git a/xen/include/xen/coco.h b/xen/include/xen/coco.h index b19edf11209b..69046316b439 100644 --- a/xen/include/xen/coco.h +++ b/xen/include/xen/coco.h @@ -12,13 +12,13 @@ extern __read_mostly struct coco_platform_status platform_status; struct coco_domain_ops { int (*prepare_initial_mem)(struct domain *d, gfn_t gfn, size_t page_count); - /* domain_creation_finished, ... */ + /* domain_creation_finished, ... */ /* HVM domain hooks */ int (*domain_initialise)(struct domain *d); int (*domain_creation_finished)(struct domain *d); - int (*domain_attestation_report)(struct domain *d, - struct coco_attestation_report report, void* response_buffer); + int (*domain_attestation_report)(struct domain *d, + struct coco_attestation_report *report); void (*domain_destroy)(struct domain *d); #ifdef CONFIG_X86 @@ -29,7 +29,7 @@ struct coco_domain_ops { struct coco_ops { const char *name; - + int (*init)(void); int (*get_platform_status)(coco_platform_status_t *status); struct coco_domain_ops *(*get_domain_ops)(struct domain *d); From a70bbe9efffcf38cb4c368ae36f3dfecacdce1d3 Mon Sep 17 00:00:00 2001 From: Th0rOnDoR Date: Mon, 6 Oct 2025 14:46:18 +0200 Subject: [PATCH 5/5] fix(sev/attestation): set default values for psp ret --- xen/arch/x86/coco/sev.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xen/arch/x86/coco/sev.c b/xen/arch/x86/coco/sev.c index f6ae96c6e15f..09b4a4cd69e8 100644 --- a/xen/arch/x86/coco/sev.c +++ b/xen/arch/x86/coco/sev.c @@ -223,8 +223,8 @@ static int sev_asid_alloc(struct domain *d, struct hvm_asid *asid) static int sev_attestation_report(struct domain *d, struct coco_attestation_report *args) { struct sev_data_attestation_report report; - int psp_ret; - int rc; + int psp_ret = 0; + int rc = 0; //from coco struct to sev specific report.handle = d->arch.hvm.svm.sev.asp_handle;