From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from gate001.proxmox.com (gate001.proxmox.com [45.144.208.40]) by lore.proxmox.com (Postfix) with ESMTPS id 509741FF0AF for ; Thu, 24 Sep 2026 16:24:01 +0200 (CEST) Received: from gate001.proxmox.com (localhost.localdomain [127.0.0.1]) by gate001.proxmox.com (Proxmox) with ESMTP id 0EB3A21752; Thu, 24 Sep 2026 16:23:08 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=genua.de; s=202307; t=1790259247; bh=AWL3wJZY0M7p2HJcppbDTB5tZ3YDeQ4W8T4hQXD5wuM=; h=Date:From:To:Subject:References:In-Reply-To:From; b=D/ZQUU2P/w99vFsNHpg/JcapzUysO219C4cObYQWPjifcZIY13ogPjwPHxk20C/Tr KWsyRholcKEQmrtCHdNOv1UplkRf5qHu/xNVg2f6htszQoJE9Q1n+wJCmShbC4P0rQ 8UkUcpLHiZYmiRfOwa0u8TfAQXCSMvJKfuYgL58IXhZkm7yRl3vk0MIWGwPs5VRKRS TACjcFWKNnyAi/s9/Vu9fIdDKAXeIsk1w/DphADqdkt04np5rH+FQgrvSff9fNZSTB jTGHPEauah7jU2UiFq30M+WLP8iTnlUIXfecwvRhyDezbYN0n0CfsEQ5Ow/38k7dPs 5rPyJAJ0y89Iw== Date: Thu, 24 Sep 2026 16:14:05 +0200 From: Christian Ludwig To: Subject: [PATCH qemu-server 3/7] sev: Expose chip ID and reported TCB versions Message-ID: <7c9b5440cca3c31c9a59aed5162ea4476155a27a.1790236014.git@genua.de> References: MIME-Version: 1.0 In-Reply-To: X-Originating-IP: [192.168.217.185] X-ClientProxiedBy: kch1-mta08.win.genua.de (10.208.16.108) To kch1-mta07.win.genua.de (10.208.16.107) Content-Type: multipart/signed; protocol="application/pkcs7-signature"; micalg="sha-256"; boundary="----272F35FC88337324EFDC966B90BEAA62" X-SPAM-LEVEL: Spam detection results: 0 AWL 0.111 Adjusted score from AWL reputation of From: address DKIM_SIGNED 0.1 Message has a DKIM or DK signature, not necessarily valid DKIM_VALID -0.1 Message has at least one valid DKIM or DK signature DKIM_VALID_AU -0.1 Message has a valid DKIM or DK signature from author's domain DKIM_VALID_EF -0.1 Message has a valid DKIM or DK signature from envelope-from domain DMARC_PASS -0.1 DMARC pass policy SPF_HELO_PASS -0.001 SPF: HELO matches SPF record SPF_PASS -0.001 SPF: sender matches SPF record UNPARSEABLE_RELAY 0.001 Informational: message has unparseable relay lines Message-ID-Hash: 46CUAURAEVSBRFXDP2PUCWRQWHIY3W6U X-Message-ID-Hash: 46CUAURAEVSBRFXDP2PUCWRQWHIY3W6U X-MailFrom: christian_ludwig@genua.de X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Content-Filtered-By: Mailman/MimeDel 3.3.10 X-Mailman-Version: 3.3.10 Precedence: list List-Id: Proxmox VE development discussion List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: ------272F35FC88337324EFDC966B90BEAA62 Content-Type: text/plain; charset="us-ascii" Content-Disposition: inline Collect the SEV chip unique ID and the SNP reported TCB version. These identify the exact VCEK a remote attestation client needs to fetch from AMD's KDS for a given host, and are exposed alongside the existing capability flags. Signed-off-by: Christian Ludwig --- .../query-machine-capabilities.c | 81 ++++++++++++++++++- 1 file changed, 79 insertions(+), 2 deletions(-) diff --git a/src/query-machine-capabilities/query-machine-capabilities.c b/src/query-machine-capabilities/query-machine-capabilities.c index b7e06286..088b2683 100644 --- a/src/query-machine-capabilities/query-machine-capabilities.c +++ b/src/query-machine-capabilities/query-machine-capabilities.c @@ -6,7 +6,10 @@ #include #include #include +#include #include +#include +#include #ifdef __aarch64__ #include @@ -28,6 +31,9 @@ typedef struct { bool sev_support; bool sev_es_support; bool sev_snp_support; + uint8_t *sev_chip_id; + size_t sev_chip_id_len; + uint64_t sev_snp_reported_tcb_version; uint8_t cbitpos; uint8_t reduced_phys_bits; @@ -123,7 +129,11 @@ int read_msr(uint32_t msr_index, uint64_t *value) { void query_cpu_capabilities_sev(cpu_caps_amd_sev_t *res) { #ifdef __x86_64__ + int fd, ret; uint32_t eax, ebx, ecx, edx; + struct sev_issue_cmd cmd; + struct sev_user_data_snp_status snp_status; + struct sev_user_data_get_id2 get_id; struct { const char *path; bool *result; @@ -170,6 +180,64 @@ void query_cpu_capabilities_sev(cpu_caps_amd_sev_t *res) { res->cbitpos = ebx & 0x3f; res->reduced_phys_bits = (ebx >> 6) & 0x3f; + /* + * Get ChipId and TCB_VERSION for an Attester. + * Only necessary for SEV-SNP. + */ + if (!res->sev_snp_support) + return; + + fd = open("/dev/sev", O_RDWR); + if (fd < 0) + return; + + memset(&snp_status, 0, sizeof(snp_status)); + memset(&cmd, 0, sizeof(cmd)); + cmd.cmd = SNP_PLATFORM_STATUS; + cmd.data = (uintptr_t)&snp_status; + ret = ioctl(fd, SEV_ISSUE_CMD, &cmd); + if (ret >= 0 && cmd.error == 0) { + res->sev_snp_reported_tcb_version = snp_status.reported_tcb_version; + } else if (cmd.error != 0) { + fprintf(stderr, "SEV firmware error: 0x%x\n", cmd.error); + } + + /* + * Get ChipId. The ID length must not be assumed, so ask for it first by + * passing a zero-length buffer. That query is expected to fail with + * INVALID_LEN; the firmware reports the required length either way. + */ + memset(&get_id, 0, sizeof(get_id)); + memset(&cmd, 0, sizeof(cmd)); + cmd.cmd = SEV_GET_ID2; + cmd.data = (uintptr_t)&get_id; + ioctl(fd, SEV_ISSUE_CMD, &cmd); + if (get_id.length == 0) + goto skip_chip_id; + + res->sev_chip_id = malloc(get_id.length); + if (res->sev_chip_id == NULL) { + perror("malloc"); + goto skip_chip_id; + } + res->sev_chip_id_len = get_id.length; + + memset(&cmd, 0, sizeof(cmd)); + cmd.cmd = SEV_GET_ID2; + cmd.data = (uintptr_t)&get_id; + get_id.address = (uintptr_t)res->sev_chip_id; + get_id.length = res->sev_chip_id_len; + ret = ioctl(fd, SEV_ISSUE_CMD, &cmd); + if (ret < 0 || cmd.error != 0 || get_id.length != res->sev_chip_id_len) { + if (cmd.error != 0) + fprintf(stderr, "SEV firmware error: 0x%x\n", cmd.error); + free(res->sev_chip_id); + res->sev_chip_id = NULL; + res->sev_chip_id_len = 0; + goto skip_chip_id; + } +skip_chip_id: + close(fd); #else memset(res, 0, sizeof(*res)); #endif @@ -240,6 +308,11 @@ int main() { if (strncmp(vendor, "AuthenticAMD", 12) == 0) { cpu_caps_amd_sev_t caps_sev = { 0 }; query_cpu_capabilities_sev(&caps_sev); + char sev_chip_id[(caps_sev.sev_chip_id_len * 2) + 1]; + + memset(sev_chip_id, 0, (caps_sev.sev_chip_id_len * 2) + 1); + for (size_t i = 0; i < caps_sev.sev_chip_id_len; i++) + sprintf(&sev_chip_id[i*2], "%02x", caps_sev.sev_chip_id[i]); ret = fprintf(file, " \"amd-sev\": {" @@ -247,13 +320,17 @@ int main() { " \"reduced-phys-bits\": %u," " \"sev-support\": %s," " \"sev-support-es\": %s," - " \"sev-support-snp\": %s" + " \"sev-support-snp\": %s," + " \"sev-chip-id\": \"0x%s\"," + " \"sev-snp-tcb-version\": \"0x%016" PRIX64 "\"" " }", caps_sev.cbitpos, caps_sev.reduced_phys_bits, caps_sev.sev_support ? "true" : "false", caps_sev.sev_es_support ? "true" : "false", - caps_sev.sev_snp_support ? "true" : "false" + caps_sev.sev_snp_support ? "true" : "false", + sev_chip_id, + caps_sev.sev_snp_reported_tcb_version ); } else if (strncmp(vendor, "GenuineIntel", 12) == 0) { cpu_caps_intel_tdx_t caps_tdx; -- 2.34.1 ------272F35FC88337324EFDC966B90BEAA62--