* [PATCH v2 0/5] igvm/sev: apply the IGVM guest policy before launch
@ 2026-09-07 15:56 Luigi Leonardi
2026-09-07 15:56 ` [PATCH v2 1/5] sev: split set_guest_policy into set_guest_policy and set_id_block Luigi Leonardi
` (4 more replies)
0 siblings, 5 replies; 7+ messages in thread
From: Luigi Leonardi @ 2026-09-07 15:56 UTC (permalink / raw)
To: qemu-devel
Cc: Gerd Hoffmann, Stefano Garzarella, Ani Sinha, Paolo Bonzini,
Zhao Liu, Marcelo Tosatti, Daniel P. Berrange, kvm,
Luigi Leonardi
The guest policy from an IGVM file never actually made it to the platform
before launch. The callback that was supposed to forward it ran after
LAUNCH_START, so it did nothing and the guest was launched with the
default policy instead of the one requested by the file.
The policy is part of the attestation report, so this quietly breaks
attestation: the resulting measurement does not match what the IGVM file
was built for.
Patches 1 to 4 are cleanups needed to get there: dropping an overloaded
callback, moving the SNP ID block handling, giving the policy properties
proper accessors, and adding a way to read back the platform's current
guest policy. Patch 5 is the actual fix.
One thing worth calling out: if a policy is also passed on the command
line and it differs from the IGVM one, the command-line value takes
precedence and we print a warning instead of silently picking one over
the other.
Signed-off-by: Luigi Leonardi <leonardi@redhat.com>
---
Changes in v2:
- Rework the callback split. Now we don't have an unimplemented callback [Stefano, Gerd]
- Reject a command-line/IGVM policy that doesn't fit in the 32-bit
SEV/SEV-ES policy field instead of truncating it [Stefano]
- On a mismatch between the command-line and IGVM policy, print a warning and
keep the command-line value instead of returning an error. [Daniel,
Gerd, Stefano]
- Picked up RoB
- Rebased to latest upstream
- Link to v1: https://lore.kernel.org/qemu-devel/20260901-fix_igvm_policy-v1-0-e93a6cf8c5ac@redhat.com
---
Luigi Leonardi (5):
sev: split set_guest_policy into set_guest_policy and set_id_block
igvm: move set_id_block call into the SNP ID block directive handler
i386/sev: convert the guest policy properties to custom accessors
i386/sev: add a get_guest_policy callback
igvm/sev: forward the IGVM guest policy to the platform before launch
backends/confidential-guest-support.c | 24 +++-
backends/igvm.c | 91 ++++++------
include/system/confidential-guest-support.h | 36 +++--
include/system/igvm-internal.h | 3 -
target/i386/sev.c | 215 ++++++++++++++++++----------
5 files changed, 230 insertions(+), 139 deletions(-)
---
base-commit: cacd3462963a0a4f5bab4263ce79c2aa4b32692d
change-id: 20260831-fix_igvm_policy-0b92de52dd6a
Best regards,
--
Luigi Leonardi <leonardi@redhat.com>
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v2 1/5] sev: split set_guest_policy into set_guest_policy and set_id_block
2026-09-07 15:56 [PATCH v2 0/5] igvm/sev: apply the IGVM guest policy before launch Luigi Leonardi
@ 2026-09-07 15:56 ` Luigi Leonardi
2026-09-08 6:24 ` Ani Sinha
2026-09-07 15:56 ` [PATCH v2 2/5] igvm: move set_id_block call into the SNP ID block directive handler Luigi Leonardi
` (3 subsequent siblings)
4 siblings, 1 reply; 7+ messages in thread
From: Luigi Leonardi @ 2026-09-07 15:56 UTC (permalink / raw)
To: qemu-devel
Cc: Gerd Hoffmann, Stefano Garzarella, Ani Sinha, Paolo Bonzini,
Zhao Liu, Marcelo Tosatti, Daniel P. Berrange, kvm,
Luigi Leonardi
The set_guest_policy callback on ConfidentialGuestSupportClass mixed
two unrelated jobs: writing the guest policy bits and providing the
SEV-SNP ID block/ID auth for LAUNCH_FINISH. The two are only related
because both come from the same 'policy' section of the SEV/SEV-SNP
launch flow, but they need to be set at different times: the policy
must be in effect before LAUNCH_START, while the ID block is only
needed before LAUNCH_FINISH.
Split the combined callback into set_guest_policy(policy_type, policy,
errp) and set_id_block(id_block, id_block_size, id_auth, id_auth_size,
errp), keeping both call sites exactly where the combined callback used
to be called from. No functional change.
Signed-off-by: Luigi Leonardi <leonardi@redhat.com>
---
backends/confidential-guest-support.c | 15 ++-
backends/igvm.c | 14 ++-
include/system/confidential-guest-support.h | 28 +++---
target/i386/sev.c | 140 +++++++++++++++-------------
4 files changed, 111 insertions(+), 86 deletions(-)
diff --git a/backends/confidential-guest-support.c b/backends/confidential-guest-support.c
index 156dd15e66..d60d1f6eaa 100644
--- a/backends/confidential-guest-support.c
+++ b/backends/confidential-guest-support.c
@@ -39,16 +39,22 @@ static int set_guest_state(hwaddr gpa, uint8_t *ptr, uint64_t len,
}
static int set_guest_policy(ConfidentialGuestPolicyType policy_type,
- uint64_t policy,
- void *policy_data1, uint32_t policy_data1_size,
- void *policy_data2, uint32_t policy_data2_size,
- Error **errp)
+ uint64_t policy, Error **errp)
{
error_setg(errp,
"Setting confidential guest policy is not supported for this platform");
return -1;
}
+static int set_id_block(void *id_block, uint32_t id_block_size,
+ void *id_auth, uint32_t id_auth_size,
+ Error **errp)
+{
+ error_setg(errp,
+ "Setting ID block is not supported for this platform");
+ return -1;
+}
+
static int get_mem_map_entry(int index, ConfidentialGuestMemoryMapEntry *entry,
Error **errp)
{
@@ -65,6 +71,7 @@ static void confidential_guest_support_class_init(ObjectClass *oc,
cgsc->check_support = check_support;
cgsc->set_guest_state = set_guest_state;
cgsc->set_guest_policy = set_guest_policy;
+ cgsc->set_id_block = set_id_block;
cgsc->get_mem_map_entry = get_mem_map_entry;
}
diff --git a/backends/igvm.c b/backends/igvm.c
index 7b7bdc72b7..99304d6467 100644
--- a/backends/igvm.c
+++ b/backends/igvm.c
@@ -963,14 +963,22 @@ static int qigvm_handle_policy(QIgvm *ctx, Error **errp)
if (ctx->platform_type == IGVM_PLATFORM_TYPE_SEV_SNP) {
int id_block_len = 0;
int id_auth_len = 0;
+ int retval;
+
if (ctx->id_block) {
ctx->id_block->policy = ctx->sev_policy;
id_block_len = sizeof(struct sev_id_block);
id_auth_len = sizeof(struct sev_id_authentication);
}
- return ctx->cgsc->set_guest_policy(GUEST_POLICY_SEV, ctx->sev_policy,
- ctx->id_block, id_block_len,
- ctx->id_auth, id_auth_len, errp);
+
+ retval = ctx->cgsc->set_guest_policy(GUEST_POLICY_SEV, ctx->sev_policy,
+ errp);
+ if (retval < 0) {
+ return retval;
+ }
+
+ return ctx->cgsc->set_id_block(ctx->id_block, id_block_len,
+ ctx->id_auth, id_auth_len, errp);
}
return 0;
}
diff --git a/include/system/confidential-guest-support.h b/include/system/confidential-guest-support.h
index 5dca717308..6d35ddb97a 100644
--- a/include/system/confidential-guest-support.h
+++ b/include/system/confidential-guest-support.h
@@ -128,21 +128,23 @@ typedef struct ConfidentialGuestSupportClass {
uint16_t cpu_index, Error **errp);
/*
- * Set the guest policy. The policy can be used to configure the
- * confidential platform, such as if debug is enabled or not and can contain
- * information about expected launch measurements, signed verification of
- * guest configuration and other platform data.
- *
- * The format of the policy data is specific to each platform. For example,
- * SEV-SNP uses a policy bitfield in the 'policy' argument and provides an
- * ID block and ID authentication in the 'policy_data' parameters. The type
- * of policy data is identified by the 'policy_type' argument.
+ * Set the guest policy for the confidential platform. The policy
+ * configures properties of the guest, such as whether debug is
+ * enabled. Its format is platform-specific; for SEV/SEV-ES and
+ * SEV-SNP it is a policy bitfield. Must be called before LAUNCH_START
+ * so the policy is in effect for launch.
*/
int (*set_guest_policy)(ConfidentialGuestPolicyType policy_type,
- uint64_t policy,
- void *policy_data1, uint32_t policy_data1_size,
- void *policy_data2, uint32_t policy_data2_size,
- Error **errp);
+ uint64_t policy, Error **errp);
+
+ /*
+ * Set the SEV-SNP ID block and ID authentication block. These are
+ * passed to SNP_LAUNCH_FINISH to provide signed verification of the
+ * guest configuration.
+ */
+ int (*set_id_block)(void *id_block, uint32_t id_block_size,
+ void *id_auth, uint32_t id_auth_size,
+ Error **errp);
/*
* Iterate the system memory map, getting the entry with the given index
diff --git a/target/i386/sev.c b/target/i386/sev.c
index cc16c6b071..b53d13e2fa 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -2726,9 +2726,7 @@ static int cgs_get_mem_map_entry(int index,
}
static int cgs_set_guest_policy(ConfidentialGuestPolicyType policy_type,
- uint64_t policy, void *policy_data1,
- uint32_t policy_data1_size, void *policy_data2,
- uint32_t policy_data2_size, Error **errp)
+ uint64_t policy, Error **errp)
{
SevCommonState *sev_common = SEV_COMMON(MACHINE(qdev_get_machine())->cgs);
if (sev_common->state == SEV_STATE_UNINIT) {
@@ -2741,81 +2739,90 @@ static int cgs_set_guest_policy(ConfidentialGuestPolicyType policy_type,
policy_type);
return -1;
}
- /*
- * SEV-SNP handles policy differently. The policy flags are defined in
- * kvm_start_conf.policy and an ID block and ID auth can be provided.
- */
+
+ /* do not reset existing policy if policy was not set in IGVM */
+ if (policy == 0) {
+ return 0;
+ }
+
if (sev_snp_enabled()) {
SevSnpGuestState *sev_snp_guest =
SEV_SNP_GUEST(MACHINE(qdev_get_machine())->cgs);
- struct kvm_sev_snp_launch_finish *finish =
- &sev_snp_guest->kvm_finish_conf;
- /*
- * The policy consists of flags in 'policy' and optionally an ID block
- * and ID auth in policy_data1 and policy_data2 respectively. The ID
- * block and auth are optional so clear any previous ID block and auth
- * and set them if provided, but always set the policy flags.
- */
- g_free(sev_snp_guest->id_block);
- g_free((guchar *)finish->id_block_uaddr);
- g_free(sev_snp_guest->id_auth);
- g_free((guchar *)finish->id_auth_uaddr);
- sev_snp_guest->id_block = NULL;
- finish->id_block_uaddr = 0;
- sev_snp_guest->id_auth = NULL;
- finish->id_auth_uaddr = 0;
-
- if (policy_data1_size > 0) {
- struct sev_snp_id_authentication *id_auth =
- (struct sev_snp_id_authentication *)policy_data2;
-
- if (policy_data1_size != KVM_SEV_SNP_ID_BLOCK_SIZE) {
- error_setg(errp, "SEV: Invalid SEV-SNP ID block: incorrect size");
- return -1;
- }
- if (policy_data2_size != KVM_SEV_SNP_ID_AUTH_SIZE) {
- error_setg(errp,
- "SEV: Invalid SEV-SNP ID auth block: incorrect size");
- return -1;
- }
- assert(policy_data1 != NULL);
- assert(policy_data2 != NULL);
+ sev_snp_guest->kvm_start_conf.policy = policy;
+ } else {
+ SevGuestState *sev_guest = SEV_GUEST(MACHINE(qdev_get_machine())->cgs);
- finish->id_block_uaddr =
- (__u64)g_memdup2(policy_data1, KVM_SEV_SNP_ID_BLOCK_SIZE);
- finish->id_auth_uaddr =
- (__u64)g_memdup2(policy_data2, KVM_SEV_SNP_ID_AUTH_SIZE);
+ sev_guest->policy = policy;
+ }
+ return 0;
+}
- /*
- * Check if an author key has been provided and use that to flag
- * whether the author key is enabled. The first of the author key
- * must be non-zero to indicate the key type, which will currently
- * always be 2.
- */
- sev_snp_guest->kvm_finish_conf.auth_key_en =
- id_auth->author_key[0] ? 1 : 0;
- finish->id_block_en = 1;
- }
+static int cgs_set_id_block(void *id_block, uint32_t id_block_size,
+ void *id_auth, uint32_t id_auth_size,
+ Error **errp)
+{
+ SevCommonState *sev_common = SEV_COMMON(MACHINE(qdev_get_machine())->cgs);
+ if (sev_common->state == SEV_STATE_UNINIT) {
+ /* Pre-processing of IGVM file called from sev_common_kvm_init() */
+ return 0;
+ }
+
+ if (!sev_snp_enabled()) {
+ error_setg(errp, "SEV: ID block is only supported for SEV-SNP");
+ return -1;
+ }
- /* do not reset existing policy if policy was not set in IGVM */
- if (policy != 0) {
- sev_snp_guest->kvm_start_conf.policy = policy;
+ SevSnpGuestState *sev_snp_guest =
+ SEV_SNP_GUEST(MACHINE(qdev_get_machine())->cgs);
+ struct kvm_sev_snp_launch_finish *finish =
+ &sev_snp_guest->kvm_finish_conf;
+
+ /*
+ * Drop any ID block and ID auth from a previous pass before repopulating
+ * them, then set them only if an ID block was provided.
+ */
+ g_free(sev_snp_guest->id_block);
+ g_free((guchar *)finish->id_block_uaddr);
+ g_free(sev_snp_guest->id_auth);
+ g_free((guchar *)finish->id_auth_uaddr);
+ sev_snp_guest->id_block = NULL;
+ finish->id_block_uaddr = 0;
+ sev_snp_guest->id_auth = NULL;
+ finish->id_auth_uaddr = 0;
+
+ if (id_block_size > 0) {
+ struct sev_snp_id_authentication *auth =
+ (struct sev_snp_id_authentication *)id_auth;
+
+ if (id_block_size != KVM_SEV_SNP_ID_BLOCK_SIZE) {
+ error_setg(errp, "SEV: Invalid SEV-SNP ID block: incorrect size");
+ return -1;
}
- } else {
- SevGuestState *sev_guest = SEV_GUEST(MACHINE(qdev_get_machine())->cgs);
- /* Only the policy flags are supported for SEV and SEV-ES */
- if ((policy_data1_size > 0) || (policy_data2_size > 0) || !sev_guest) {
- error_setg(errp, "SEV: An ID block/ID auth block has been provided "
- "but SEV-SNP is not enabled");
+ if (id_auth_size != KVM_SEV_SNP_ID_AUTH_SIZE) {
+ error_setg(errp,
+ "SEV: Invalid SEV-SNP ID auth block: incorrect size");
return -1;
}
+ assert(id_block != NULL);
+ assert(id_auth != NULL);
- /* do not reset existing policy if policy was not set in IGVM */
- if (policy != 0) {
- sev_guest->policy = policy;
- }
+ finish->id_block_uaddr =
+ (__u64)g_memdup2(id_block, KVM_SEV_SNP_ID_BLOCK_SIZE);
+ finish->id_auth_uaddr =
+ (__u64)g_memdup2(id_auth, KVM_SEV_SNP_ID_AUTH_SIZE);
+
+ /*
+ * Check if an author key has been provided and use that to flag
+ * whether the author key is enabled. The first of the author key
+ * must be non-zero to indicate the key type, which will currently
+ * always be 2.
+ */
+ sev_snp_guest->kvm_finish_conf.auth_key_en =
+ auth->author_key[0] ? 1 : 0;
+ finish->id_block_en = 1;
}
+
return 0;
}
@@ -2881,6 +2888,7 @@ sev_common_instance_init(Object *obj)
cgs->set_guest_state = cgs_set_guest_state;
cgs->get_mem_map_entry = cgs_get_mem_map_entry;
cgs->set_guest_policy = cgs_set_guest_policy;
+ cgs->set_id_block = cgs_set_id_block;
cgs->can_rebuild_guest_state = true;
QTAILQ_INIT(&sev_common->launch_vmsa);
--
2.55.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH v2 2/5] igvm: move set_id_block call into the SNP ID block directive handler
2026-09-07 15:56 [PATCH v2 0/5] igvm/sev: apply the IGVM guest policy before launch Luigi Leonardi
2026-09-07 15:56 ` [PATCH v2 1/5] sev: split set_guest_policy into set_guest_policy and set_id_block Luigi Leonardi
@ 2026-09-07 15:56 ` Luigi Leonardi
2026-09-07 15:56 ` [PATCH v2 3/5] i386/sev: convert the guest policy properties to custom accessors Luigi Leonardi
` (2 subsequent siblings)
4 siblings, 0 replies; 7+ messages in thread
From: Luigi Leonardi @ 2026-09-07 15:56 UTC (permalink / raw)
To: qemu-devel
Cc: Gerd Hoffmann, Stefano Garzarella, Ani Sinha, Paolo Bonzini,
Zhao Liu, Marcelo Tosatti, Daniel P. Berrange, kvm,
Luigi Leonardi
set_id_block only makes sense when the IGVM file contains an
IGVM_VHT_SNP_ID_BLOCK directive. Move the call from qigvm_handle_policy
(which continues to handle the set_guest_policy call) into
qigvm_directive_snp_id_block, where the ID block and ID auth are
populated. This avoids a no-op call to set_id_block when no ID block
is present.
The ID block embeds the guest policy, so the policy must be known by the
time the directive is handled. Process the initialization section (which
carries the GUEST_POLICY header) before the directive section, and
copy ctx->sev_policy into the ID block in the directive handler.
Signed-off-by: Luigi Leonardi <leonardi@redhat.com>
---
backends/igvm.c | 80 ++++++++++++++++++++++++++++-----------------------------
1 file changed, 40 insertions(+), 40 deletions(-)
diff --git a/backends/igvm.c b/backends/igvm.c
index 99304d6467..521560822a 100644
--- a/backends/igvm.c
+++ b/backends/igvm.c
@@ -778,6 +778,8 @@ static int qigvm_directive_snp_id_block(QIgvm *ctx, const uint8_t *header_data,
ctx->id_block->version = IGVM_SEV_ID_BLOCK_VERSION;
memcpy(ctx->id_block->ld, igvm_id->ld, sizeof(ctx->id_block->ld));
+ ctx->id_block->policy = ctx->sev_policy;
+
ctx->id_auth->id_key_alg = igvm_id->id_key_algorithm;
assert(sizeof(igvm_id->id_key_signature) <=
sizeof(ctx->id_auth->id_block_sig));
@@ -805,6 +807,14 @@ static int qigvm_directive_snp_id_block(QIgvm *ctx, const uint8_t *header_data,
memcpy(&ctx->id_auth->author_key[76], &igvm_id->author_public_key.qy,
72);
+ if (ctx->cgsc) {
+ return ctx->cgsc->set_id_block(ctx->id_block,
+ sizeof(struct sev_id_block),
+ ctx->id_auth,
+ sizeof(struct sev_id_authentication),
+ errp);
+ }
+
return 0;
}
@@ -961,24 +971,8 @@ static int qigvm_supported_platform_compat_mask(QIgvm *ctx, Error **errp)
static int qigvm_handle_policy(QIgvm *ctx, Error **errp)
{
if (ctx->platform_type == IGVM_PLATFORM_TYPE_SEV_SNP) {
- int id_block_len = 0;
- int id_auth_len = 0;
- int retval;
-
- if (ctx->id_block) {
- ctx->id_block->policy = ctx->sev_policy;
- id_block_len = sizeof(struct sev_id_block);
- id_auth_len = sizeof(struct sev_id_authentication);
- }
-
- retval = ctx->cgsc->set_guest_policy(GUEST_POLICY_SEV, ctx->sev_policy,
- errp);
- if (retval < 0) {
- return retval;
- }
-
- return ctx->cgsc->set_id_block(ctx->id_block, id_block_len,
- ctx->id_auth, id_auth_len, errp);
+ return ctx->cgsc->set_guest_policy(GUEST_POLICY_SEV, ctx->sev_policy,
+ errp);
}
return 0;
}
@@ -1040,6 +1034,34 @@ int qigvm_process_file(IgvmCfg *cfg, MachineState *machine_state,
goto cleanup;
}
+ /*
+ * Process the initialization section first so that the guest policy is
+ * known before the directive section is handled. The SNP ID block
+ * directive embeds the guest policy into the ID block, so the policy from
+ * the guest policy initialization header must be available by then.
+ */
+ header_count =
+ igvm_header_count(ctx.cfg->file, IGVM_HEADER_SECTION_INITIALIZATION);
+ if (header_count < 0) {
+ error_setg(
+ errp,
+ "Invalid initialization header count in IGVM file. Error code: %X",
+ header_count);
+ goto cleanup;
+ }
+
+ for (ctx.current_header_index = 0;
+ ctx.current_header_index < (unsigned)header_count;
+ ctx.current_header_index++) {
+ IgvmVariableHeaderType type =
+ igvm_get_header_type(ctx.cfg->file,
+ IGVM_HEADER_SECTION_INITIALIZATION,
+ ctx.current_header_index);
+ if (qigvm_handler(&ctx, type, errp) < 0) {
+ goto cleanup;
+ }
+ }
+
header_count = igvm_header_count(ctx.cfg->file,
IGVM_HEADER_SECTION_DIRECTIVE);
if (header_count <= 0) {
@@ -1073,28 +1095,6 @@ int qigvm_process_file(IgvmCfg *cfg, MachineState *machine_state,
goto cleanup_parameters;
}
- header_count =
- igvm_header_count(ctx.cfg->file, IGVM_HEADER_SECTION_INITIALIZATION);
- if (header_count < 0) {
- error_setg(
- errp,
- "Invalid initialization header count in IGVM file. Error code: %X",
- header_count);
- goto cleanup_parameters;
- }
-
- for (ctx.current_header_index = 0;
- ctx.current_header_index < (unsigned)header_count;
- ctx.current_header_index++) {
- IgvmVariableHeaderType type =
- igvm_get_header_type(ctx.cfg->file,
- IGVM_HEADER_SECTION_INITIALIZATION,
- ctx.current_header_index);
- if (qigvm_handler(&ctx, type, errp) < 0) {
- goto cleanup_parameters;
- }
- }
-
/*
* Contiguous pages of data with compatible flags are grouped together in
* order to reduce the number of memory regions we create. Make sure the
--
2.55.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH v2 3/5] i386/sev: convert the guest policy properties to custom accessors
2026-09-07 15:56 [PATCH v2 0/5] igvm/sev: apply the IGVM guest policy before launch Luigi Leonardi
2026-09-07 15:56 ` [PATCH v2 1/5] sev: split set_guest_policy into set_guest_policy and set_id_block Luigi Leonardi
2026-09-07 15:56 ` [PATCH v2 2/5] igvm: move set_id_block call into the SNP ID block directive handler Luigi Leonardi
@ 2026-09-07 15:56 ` Luigi Leonardi
2026-09-07 15:57 ` [PATCH v2 4/5] i386/sev: add a get_guest_policy callback Luigi Leonardi
2026-09-07 15:57 ` [PATCH v2 5/5] igvm/sev: forward the IGVM guest policy to the platform before launch Luigi Leonardi
4 siblings, 0 replies; 7+ messages in thread
From: Luigi Leonardi @ 2026-09-07 15:56 UTC (permalink / raw)
To: qemu-devel
Cc: Gerd Hoffmann, Stefano Garzarella, Ani Sinha, Paolo Bonzini,
Zhao Liu, Marcelo Tosatti, Daniel P. Berrange, kvm,
Luigi Leonardi
Both SEV/SEV-ES and SEV-SNP expose a "policy" object property. The
SEV/SEV-ES one was registered as a plain uint32 pointer property, and
the SEV-SNP setter ignored the result of the visit.
Give both properties explicit getter/setter functions and check the
return value of the visit in the setters. This is preparation for
tracking whether the guest policy was set on the command line.
No functional change intended.
Reviewed-by: Ani Sinha <anisinha@redhat.com>
Signed-off-by: Luigi Leonardi <leonardi@redhat.com>
---
target/i386/sev.c | 30 +++++++++++++++++++++++++-----
1 file changed, 25 insertions(+), 5 deletions(-)
diff --git a/target/i386/sev.c b/target/i386/sev.c
index b53d13e2fa..38f97fd9b2 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -2996,6 +2996,22 @@ sev_guest_class_init(ObjectClass *oc, const void *data)
"use legacy VM type to maintain measurement compatibility with older QEMU or kernel versions.");
}
+static void
+sev_guest_get_policy(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ visit_type_uint32(v, name, &SEV_GUEST(obj)->policy, errp);
+}
+
+static void
+sev_guest_set_policy(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ if (!visit_type_uint32(v, name, &SEV_GUEST(obj)->policy, errp)) {
+ return;
+ }
+}
+
static void
sev_guest_instance_init(Object *obj)
{
@@ -3004,8 +3020,8 @@ sev_guest_instance_init(Object *obj)
sev_guest->policy = DEFAULT_GUEST_POLICY;
object_property_add_uint32_ptr(obj, "handle", &sev_guest->handle,
OBJ_PROP_FLAG_READWRITE);
- object_property_add_uint32_ptr(obj, "policy", &sev_guest->policy,
- OBJ_PROP_FLAG_READWRITE);
+ object_property_add(obj, "policy", "uint32", sev_guest_get_policy,
+ sev_guest_set_policy, NULL, NULL);
object_apply_compat_props(obj);
sev_guest->legacy_vm_type = ON_OFF_AUTO_AUTO;
@@ -3044,9 +3060,13 @@ static void
sev_snp_guest_set_policy(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- visit_type_uint64(v, name,
- (uint64_t *)&SEV_SNP_GUEST(obj)->kvm_start_conf.policy,
- errp);
+ SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(obj);
+
+ if (!visit_type_uint64(v, name,
+ (uint64_t *)&sev_snp_guest->kvm_start_conf.policy,
+ errp)) {
+ return;
+ }
}
static char *
--
2.55.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH v2 4/5] i386/sev: add a get_guest_policy callback
2026-09-07 15:56 [PATCH v2 0/5] igvm/sev: apply the IGVM guest policy before launch Luigi Leonardi
` (2 preceding siblings ...)
2026-09-07 15:56 ` [PATCH v2 3/5] i386/sev: convert the guest policy properties to custom accessors Luigi Leonardi
@ 2026-09-07 15:57 ` Luigi Leonardi
2026-09-07 15:57 ` [PATCH v2 5/5] igvm/sev: forward the IGVM guest policy to the platform before launch Luigi Leonardi
4 siblings, 0 replies; 7+ messages in thread
From: Luigi Leonardi @ 2026-09-07 15:57 UTC (permalink / raw)
To: qemu-devel
Cc: Gerd Hoffmann, Stefano Garzarella, Ani Sinha, Paolo Bonzini,
Zhao Liu, Marcelo Tosatti, Daniel P. Berrange, kvm,
Luigi Leonardi
The next patch populates the SEV-SNP ID block's policy field.
That value must be whatever policy is currently in effect on the platform
but there is no way to read it back: the policy can come either from an
IGVM GUEST_POLICY header or from the command line, and the command line
sets it directly into the SEV/SNP guest struct without going through IGVM.
Reading it back from the platform is the only source that always reflects
the value in effect, regardless of where it came from.
Add a get_guest_policy callback to ConfidentialGuestSupportClass for
this purpose. It is not yet used; the following patch wires it into the
SNP ID block population.
Signed-off-by: Luigi Leonardi <leonardi@redhat.com>
---
backends/confidential-guest-support.c | 9 +++++++++
include/system/confidential-guest-support.h | 8 ++++++++
target/i386/sev.c | 24 ++++++++++++++++++++++++
3 files changed, 41 insertions(+)
diff --git a/backends/confidential-guest-support.c b/backends/confidential-guest-support.c
index d60d1f6eaa..91701f1a5f 100644
--- a/backends/confidential-guest-support.c
+++ b/backends/confidential-guest-support.c
@@ -46,6 +46,14 @@ static int set_guest_policy(ConfidentialGuestPolicyType policy_type,
return -1;
}
+static int get_guest_policy(ConfidentialGuestPolicyType policy_type,
+ uint64_t *policy, Error **errp)
+{
+ error_setg(errp,
+ "Getting guest policy is not supported for this platform");
+ return -1;
+}
+
static int set_id_block(void *id_block, uint32_t id_block_size,
void *id_auth, uint32_t id_auth_size,
Error **errp)
@@ -71,6 +79,7 @@ static void confidential_guest_support_class_init(ObjectClass *oc,
cgsc->check_support = check_support;
cgsc->set_guest_state = set_guest_state;
cgsc->set_guest_policy = set_guest_policy;
+ cgsc->get_guest_policy = get_guest_policy;
cgsc->set_id_block = set_id_block;
cgsc->get_mem_map_entry = get_mem_map_entry;
}
diff --git a/include/system/confidential-guest-support.h b/include/system/confidential-guest-support.h
index 6d35ddb97a..27ae0a21b6 100644
--- a/include/system/confidential-guest-support.h
+++ b/include/system/confidential-guest-support.h
@@ -137,6 +137,14 @@ typedef struct ConfidentialGuestSupportClass {
int (*set_guest_policy)(ConfidentialGuestPolicyType policy_type,
uint64_t policy, Error **errp);
+ /*
+ * Get the guest policy currently configured for the confidential
+ * platform, be it from the command line or from a previous call to
+ * set_guest_policy. Its format is the same as for set_guest_policy.
+ */
+ int (*get_guest_policy)(ConfidentialGuestPolicyType policy_type,
+ uint64_t *policy, Error **errp);
+
/*
* Set the SEV-SNP ID block and ID authentication block. These are
* passed to SNP_LAUNCH_FINISH to provide signed verification of the
diff --git a/target/i386/sev.c b/target/i386/sev.c
index 38f97fd9b2..f11fdb6590 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -2758,6 +2758,29 @@ static int cgs_set_guest_policy(ConfidentialGuestPolicyType policy_type,
return 0;
}
+static int cgs_get_guest_policy(ConfidentialGuestPolicyType policy_type,
+ uint64_t *policy, Error **errp)
+{
+ SevCommonState *sev_common = SEV_COMMON(MACHINE(qdev_get_machine())->cgs);
+
+ if (policy_type != GUEST_POLICY_SEV) {
+ error_setg(errp, "SEV: Invalid guest policy type provided for SEV: %d",
+ policy_type);
+ return -1;
+ }
+
+ if (sev_snp_enabled()) {
+ SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(sev_common);
+
+ *policy = sev_snp_guest->kvm_start_conf.policy;
+ } else {
+ SevGuestState *sev_guest = SEV_GUEST(sev_common);
+
+ *policy = sev_guest->policy;
+ }
+ return 0;
+}
+
static int cgs_set_id_block(void *id_block, uint32_t id_block_size,
void *id_auth, uint32_t id_auth_size,
Error **errp)
@@ -2888,6 +2911,7 @@ sev_common_instance_init(Object *obj)
cgs->set_guest_state = cgs_set_guest_state;
cgs->get_mem_map_entry = cgs_get_mem_map_entry;
cgs->set_guest_policy = cgs_set_guest_policy;
+ cgs->get_guest_policy = cgs_get_guest_policy;
cgs->set_id_block = cgs_set_id_block;
cgs->can_rebuild_guest_state = true;
--
2.55.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH v2 5/5] igvm/sev: forward the IGVM guest policy to the platform before launch
2026-09-07 15:56 [PATCH v2 0/5] igvm/sev: apply the IGVM guest policy before launch Luigi Leonardi
` (3 preceding siblings ...)
2026-09-07 15:57 ` [PATCH v2 4/5] i386/sev: add a get_guest_policy callback Luigi Leonardi
@ 2026-09-07 15:57 ` Luigi Leonardi
4 siblings, 0 replies; 7+ messages in thread
From: Luigi Leonardi @ 2026-09-07 15:57 UTC (permalink / raw)
To: qemu-devel
Cc: Gerd Hoffmann, Stefano Garzarella, Ani Sinha, Paolo Bonzini,
Zhao Liu, Marcelo Tosatti, Daniel P. Berrange, kvm,
Luigi Leonardi
set_guest_policy was called from qigvm_handle_policy at the end of
qigvm_process_file, after LAUNCH_START had already been issued for both
SEV/SEV-ES and SEV-SNP. The guest was therefore launched with whatever
policy was already configured (the command-line value, or the platform
default if none was given) instead of the one requested by the IGVM
file, quietly breaking attestation since the policy is part of the
attestation report.
Move the call into qigvm_initialization_guest_policy, which runs while
the initialization section is processed. Because that section is now
handled during the pre-launch pass (see previous patch), the call
happens before LAUNCH_START, so the policy is in effect for launch. Drop
qigvm_handle_policy, whose only remaining job was that misplaced call.
cgs_set_guest_policy no longer special-cases SEV_STATE_UNINIT: that
guard used to skip the pre-processing pass so the policy was applied
later, but forwarding it during pre-processing, before LAUNCH_START, is
now precisely the point. The 'policy == 0 means unset' guard is dropped
too, since the call site now only fires when the IGVM file actually
provides a GUEST_POLICY header.
The command line can also set a policy. It now takes precedence: if it
differs from the IGVM one, print a warning and keep the command-line
value instead of silently overriding it. Also reject a policy that
doesn't fit in the 32-bit SEV/SEV-ES policy field instead of truncating
it.
Finally, use the get_guest_policy callback added by the previous patch
to populate the SNP ID block's policy field. The command line sets its
policy directly into the SEV/SNP guest's own struct, bypassing IGVM
entirely, so ctx->sev_policy only ever reflects a GUEST_POLICY header
and is 0 otherwise, causing SNP_LAUNCH_FINISH to reject the ID block
whenever the file relies on a command-line policy. Reading the policy
back from the platform instead always gets the value actually in
effect, regardless of its source. ctx->sev_policy is now unused and
removed.
Link: https://gitlab.com/qemu-project/qemu/-/work_items/4189
Fixes: 915b47078d ("backends/igvm: Handle policy for SEV guests")
Signed-off-by: Luigi Leonardi <leonardi@redhat.com>
---
backends/igvm.c | 27 +++++++++++----------------
include/system/igvm-internal.h | 3 ---
target/i386/sev.c | 37 +++++++++++++++++++++++++------------
3 files changed, 36 insertions(+), 31 deletions(-)
diff --git a/backends/igvm.c b/backends/igvm.c
index 521560822a..5360a2575b 100644
--- a/backends/igvm.c
+++ b/backends/igvm.c
@@ -778,8 +778,6 @@ static int qigvm_directive_snp_id_block(QIgvm *ctx, const uint8_t *header_data,
ctx->id_block->version = IGVM_SEV_ID_BLOCK_VERSION;
memcpy(ctx->id_block->ld, igvm_id->ld, sizeof(ctx->id_block->ld));
- ctx->id_block->policy = ctx->sev_policy;
-
ctx->id_auth->id_key_alg = igvm_id->id_key_algorithm;
assert(sizeof(igvm_id->id_key_signature) <=
sizeof(ctx->id_auth->id_block_sig));
@@ -808,6 +806,13 @@ static int qigvm_directive_snp_id_block(QIgvm *ctx, const uint8_t *header_data,
72);
if (ctx->cgsc) {
+ uint64_t policy;
+
+ if (ctx->cgsc->get_guest_policy(GUEST_POLICY_SEV, &policy, errp) < 0) {
+ return -1;
+ }
+ ctx->id_block->policy = policy;
+
return ctx->cgsc->set_id_block(ctx->id_block,
sizeof(struct sev_id_block),
ctx->id_auth,
@@ -867,7 +872,10 @@ static int qigvm_initialization_guest_policy(QIgvm *ctx,
(const IGVM_VHS_GUEST_POLICY *)header_data;
if (guest->compatibility_mask & ctx->compatibility_mask) {
- ctx->sev_policy = guest->policy;
+ if (ctx->cgsc) {
+ return ctx->cgsc->set_guest_policy(GUEST_POLICY_SEV,
+ guest->policy, errp);
+ }
}
return 0;
}
@@ -968,15 +976,6 @@ static int qigvm_supported_platform_compat_mask(QIgvm *ctx, Error **errp)
return 0;
}
-static int qigvm_handle_policy(QIgvm *ctx, Error **errp)
-{
- if (ctx->platform_type == IGVM_PLATFORM_TYPE_SEV_SNP) {
- return ctx->cgsc->set_guest_policy(GUEST_POLICY_SEV, ctx->sev_policy,
- errp);
- }
- return 0;
-}
-
IgvmHandle qigvm_file_init(char *filename, Error **errp)
{
IgvmHandle igvm;
@@ -1102,10 +1101,6 @@ int qigvm_process_file(IgvmCfg *cfg, MachineState *machine_state,
*/
retval = qigvm_process_mem_page(&ctx, NULL, errp);
- if (retval == 0) {
- retval = qigvm_handle_policy(&ctx, errp);
- }
-
cleanup_parameters:
QTAILQ_FOREACH(parameter, &ctx.parameter_data, next)
{
diff --git a/include/system/igvm-internal.h b/include/system/igvm-internal.h
index 9e9fa1d9af..041f77586a 100644
--- a/include/system/igvm-internal.h
+++ b/include/system/igvm-internal.h
@@ -64,9 +64,6 @@ struct QIgvm {
struct sev_id_block *id_block;
struct sev_id_authentication *id_auth;
- /* Define the guest policy for SEV guests */
- uint64_t sev_policy;
-
/* These variables keep track of contiguous page regions */
IGVM_VHS_PAGE_DATA region_prev_page_data;
uint64_t region_start;
diff --git a/target/i386/sev.c b/target/i386/sev.c
index f11fdb6590..11072b00dc 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -128,6 +128,8 @@ struct SevCommonState {
bool kernel_hashes;
uint64_t sev_features;
uint64_t supported_sev_features;
+ /* whether the guest policy was explicitly set on the command line */
+ bool policy_set;
/* runtime state */
uint8_t api_major;
@@ -2729,10 +2731,6 @@ static int cgs_set_guest_policy(ConfidentialGuestPolicyType policy_type,
uint64_t policy, Error **errp)
{
SevCommonState *sev_common = SEV_COMMON(MACHINE(qdev_get_machine())->cgs);
- if (sev_common->state == SEV_STATE_UNINIT) {
- /* Pre-processing of IGVM file called from sev_common_kvm_init() */
- return 0;
- }
if (policy_type != GUEST_POLICY_SEV) {
error_setg(errp, "SEV: Invalid guest policy type provided for SEV: %d",
@@ -2740,18 +2738,31 @@ static int cgs_set_guest_policy(ConfidentialGuestPolicyType policy_type,
return -1;
}
- /* do not reset existing policy if policy was not set in IGVM */
- if (policy == 0) {
- return 0;
- }
-
if (sev_snp_enabled()) {
- SevSnpGuestState *sev_snp_guest =
- SEV_SNP_GUEST(MACHINE(qdev_get_machine())->cgs);
+ SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(sev_common);
+
+ if (sev_common->policy_set &&
+ sev_snp_guest->kvm_start_conf.policy != policy) {
+ warn_report_once("SNP: policy mismatch between IGVM and CLI, "
+ "keeping the command-line policy");
+ return 0;
+ }
sev_snp_guest->kvm_start_conf.policy = policy;
} else {
- SevGuestState *sev_guest = SEV_GUEST(MACHINE(qdev_get_machine())->cgs);
+ SevGuestState *sev_guest = SEV_GUEST(sev_common);
+
+ if (sev_common->policy_set && sev_guest->policy != policy) {
+ warn_report_once("SEV: policy mismatch between IGVM and CLI, "
+ "keeping the command-line policy");
+ return 0;
+ }
+
+ if (policy > UINT32_MAX) {
+ error_setg(errp, "SEV: policy 0x%" PRIx64 " does not fit in the "
+ "32-bit SEV/SEV-ES guest policy field", policy);
+ return -1;
+ }
sev_guest->policy = policy;
}
@@ -3034,6 +3045,7 @@ sev_guest_set_policy(Object *obj, Visitor *v, const char *name,
if (!visit_type_uint32(v, name, &SEV_GUEST(obj)->policy, errp)) {
return;
}
+ SEV_COMMON(obj)->policy_set = true;
}
static void
@@ -3091,6 +3103,7 @@ sev_snp_guest_set_policy(Object *obj, Visitor *v, const char *name,
errp)) {
return;
}
+ SEV_COMMON(obj)->policy_set = true;
}
static char *
--
2.55.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH v2 1/5] sev: split set_guest_policy into set_guest_policy and set_id_block
2026-09-07 15:56 ` [PATCH v2 1/5] sev: split set_guest_policy into set_guest_policy and set_id_block Luigi Leonardi
@ 2026-09-08 6:24 ` Ani Sinha
0 siblings, 0 replies; 7+ messages in thread
From: Ani Sinha @ 2026-09-08 6:24 UTC (permalink / raw)
To: Luigi Leonardi
Cc: qemu-devel, Gerd Hoffmann, Stefano Garzarella, Paolo Bonzini,
Zhao Liu, Marcelo Tosatti, Daniel P. Berrange, kvm
> On 7 Sep 2026, at 9:26 PM, Luigi Leonardi <leonardi@redhat.com> wrote:
>
> The set_guest_policy callback on ConfidentialGuestSupportClass mixed
> two unrelated jobs: writing the guest policy bits and providing the
> SEV-SNP ID block/ID auth for LAUNCH_FINISH. The two are only related
> because both come from the same 'policy' section of the SEV/SEV-SNP
> launch flow, but they need to be set at different times: the policy
> must be in effect before LAUNCH_START, while the ID block is only
> needed before LAUNCH_FINISH.
>
> Split the combined callback into set_guest_policy(policy_type, policy,
> errp) and set_id_block(id_block, id_block_size, id_auth, id_auth_size,
> errp), keeping both call sites exactly where the combined callback used
> to be called from. No functional change.
LGTM.
Reviewed-by: Ani Sinha <anisinha@redhat.com>
>
> Signed-off-by: Luigi Leonardi <leonardi@redhat.com>
> ---
> backends/confidential-guest-support.c | 15 ++-
> backends/igvm.c | 14 ++-
> include/system/confidential-guest-support.h | 28 +++---
> target/i386/sev.c | 140 +++++++++++++++-------------
> 4 files changed, 111 insertions(+), 86 deletions(-)
>
> diff --git a/backends/confidential-guest-support.c b/backends/confidential-guest-support.c
> index 156dd15e66..d60d1f6eaa 100644
> --- a/backends/confidential-guest-support.c
> +++ b/backends/confidential-guest-support.c
> @@ -39,16 +39,22 @@ static int set_guest_state(hwaddr gpa, uint8_t *ptr, uint64_t len,
> }
>
> static int set_guest_policy(ConfidentialGuestPolicyType policy_type,
> - uint64_t policy,
> - void *policy_data1, uint32_t policy_data1_size,
> - void *policy_data2, uint32_t policy_data2_size,
> - Error **errp)
> + uint64_t policy, Error **errp)
> {
> error_setg(errp,
> "Setting confidential guest policy is not supported for this platform");
> return -1;
> }
>
> +static int set_id_block(void *id_block, uint32_t id_block_size,
> + void *id_auth, uint32_t id_auth_size,
> + Error **errp)
> +{
> + error_setg(errp,
> + "Setting ID block is not supported for this platform");
> + return -1;
> +}
> +
> static int get_mem_map_entry(int index, ConfidentialGuestMemoryMapEntry *entry,
> Error **errp)
> {
> @@ -65,6 +71,7 @@ static void confidential_guest_support_class_init(ObjectClass *oc,
> cgsc->check_support = check_support;
> cgsc->set_guest_state = set_guest_state;
> cgsc->set_guest_policy = set_guest_policy;
> + cgsc->set_id_block = set_id_block;
> cgsc->get_mem_map_entry = get_mem_map_entry;
> }
>
> diff --git a/backends/igvm.c b/backends/igvm.c
> index 7b7bdc72b7..99304d6467 100644
> --- a/backends/igvm.c
> +++ b/backends/igvm.c
> @@ -963,14 +963,22 @@ static int qigvm_handle_policy(QIgvm *ctx, Error **errp)
> if (ctx->platform_type == IGVM_PLATFORM_TYPE_SEV_SNP) {
> int id_block_len = 0;
> int id_auth_len = 0;
> + int retval;
> +
> if (ctx->id_block) {
> ctx->id_block->policy = ctx->sev_policy;
> id_block_len = sizeof(struct sev_id_block);
> id_auth_len = sizeof(struct sev_id_authentication);
> }
> - return ctx->cgsc->set_guest_policy(GUEST_POLICY_SEV, ctx->sev_policy,
> - ctx->id_block, id_block_len,
> - ctx->id_auth, id_auth_len, errp);
> +
> + retval = ctx->cgsc->set_guest_policy(GUEST_POLICY_SEV, ctx->sev_policy,
> + errp);
> + if (retval < 0) {
> + return retval;
> + }
> +
> + return ctx->cgsc->set_id_block(ctx->id_block, id_block_len,
> + ctx->id_auth, id_auth_len, errp);
> }
> return 0;
> }
> diff --git a/include/system/confidential-guest-support.h b/include/system/confidential-guest-support.h
> index 5dca717308..6d35ddb97a 100644
> --- a/include/system/confidential-guest-support.h
> +++ b/include/system/confidential-guest-support.h
> @@ -128,21 +128,23 @@ typedef struct ConfidentialGuestSupportClass {
> uint16_t cpu_index, Error **errp);
>
> /*
> - * Set the guest policy. The policy can be used to configure the
> - * confidential platform, such as if debug is enabled or not and can contain
> - * information about expected launch measurements, signed verification of
> - * guest configuration and other platform data.
> - *
> - * The format of the policy data is specific to each platform. For example,
> - * SEV-SNP uses a policy bitfield in the 'policy' argument and provides an
> - * ID block and ID authentication in the 'policy_data' parameters. The type
> - * of policy data is identified by the 'policy_type' argument.
> + * Set the guest policy for the confidential platform. The policy
> + * configures properties of the guest, such as whether debug is
> + * enabled. Its format is platform-specific; for SEV/SEV-ES and
> + * SEV-SNP it is a policy bitfield. Must be called before LAUNCH_START
> + * so the policy is in effect for launch.
> */
> int (*set_guest_policy)(ConfidentialGuestPolicyType policy_type,
> - uint64_t policy,
> - void *policy_data1, uint32_t policy_data1_size,
> - void *policy_data2, uint32_t policy_data2_size,
> - Error **errp);
> + uint64_t policy, Error **errp);
> +
> + /*
> + * Set the SEV-SNP ID block and ID authentication block. These are
> + * passed to SNP_LAUNCH_FINISH to provide signed verification of the
> + * guest configuration.
> + */
> + int (*set_id_block)(void *id_block, uint32_t id_block_size,
> + void *id_auth, uint32_t id_auth_size,
> + Error **errp);
>
> /*
> * Iterate the system memory map, getting the entry with the given index
> diff --git a/target/i386/sev.c b/target/i386/sev.c
> index cc16c6b071..b53d13e2fa 100644
> --- a/target/i386/sev.c
> +++ b/target/i386/sev.c
> @@ -2726,9 +2726,7 @@ static int cgs_get_mem_map_entry(int index,
> }
>
> static int cgs_set_guest_policy(ConfidentialGuestPolicyType policy_type,
> - uint64_t policy, void *policy_data1,
> - uint32_t policy_data1_size, void *policy_data2,
> - uint32_t policy_data2_size, Error **errp)
> + uint64_t policy, Error **errp)
> {
> SevCommonState *sev_common = SEV_COMMON(MACHINE(qdev_get_machine())->cgs);
> if (sev_common->state == SEV_STATE_UNINIT) {
> @@ -2741,81 +2739,90 @@ static int cgs_set_guest_policy(ConfidentialGuestPolicyType policy_type,
> policy_type);
> return -1;
> }
> - /*
> - * SEV-SNP handles policy differently. The policy flags are defined in
> - * kvm_start_conf.policy and an ID block and ID auth can be provided.
> - */
> +
> + /* do not reset existing policy if policy was not set in IGVM */
> + if (policy == 0) {
> + return 0;
> + }
> +
> if (sev_snp_enabled()) {
> SevSnpGuestState *sev_snp_guest =
> SEV_SNP_GUEST(MACHINE(qdev_get_machine())->cgs);
> - struct kvm_sev_snp_launch_finish *finish =
> - &sev_snp_guest->kvm_finish_conf;
>
> - /*
> - * The policy consists of flags in 'policy' and optionally an ID block
> - * and ID auth in policy_data1 and policy_data2 respectively. The ID
> - * block and auth are optional so clear any previous ID block and auth
> - * and set them if provided, but always set the policy flags.
> - */
> - g_free(sev_snp_guest->id_block);
> - g_free((guchar *)finish->id_block_uaddr);
> - g_free(sev_snp_guest->id_auth);
> - g_free((guchar *)finish->id_auth_uaddr);
> - sev_snp_guest->id_block = NULL;
> - finish->id_block_uaddr = 0;
> - sev_snp_guest->id_auth = NULL;
> - finish->id_auth_uaddr = 0;
> -
> - if (policy_data1_size > 0) {
> - struct sev_snp_id_authentication *id_auth =
> - (struct sev_snp_id_authentication *)policy_data2;
> -
> - if (policy_data1_size != KVM_SEV_SNP_ID_BLOCK_SIZE) {
> - error_setg(errp, "SEV: Invalid SEV-SNP ID block: incorrect size");
> - return -1;
> - }
> - if (policy_data2_size != KVM_SEV_SNP_ID_AUTH_SIZE) {
> - error_setg(errp,
> - "SEV: Invalid SEV-SNP ID auth block: incorrect size");
> - return -1;
> - }
> - assert(policy_data1 != NULL);
> - assert(policy_data2 != NULL);
> + sev_snp_guest->kvm_start_conf.policy = policy;
> + } else {
> + SevGuestState *sev_guest = SEV_GUEST(MACHINE(qdev_get_machine())->cgs);
>
> - finish->id_block_uaddr =
> - (__u64)g_memdup2(policy_data1, KVM_SEV_SNP_ID_BLOCK_SIZE);
> - finish->id_auth_uaddr =
> - (__u64)g_memdup2(policy_data2, KVM_SEV_SNP_ID_AUTH_SIZE);
> + sev_guest->policy = policy;
> + }
> + return 0;
> +}
>
> - /*
> - * Check if an author key has been provided and use that to flag
> - * whether the author key is enabled. The first of the author key
> - * must be non-zero to indicate the key type, which will currently
> - * always be 2.
> - */
> - sev_snp_guest->kvm_finish_conf.auth_key_en =
> - id_auth->author_key[0] ? 1 : 0;
> - finish->id_block_en = 1;
> - }
> +static int cgs_set_id_block(void *id_block, uint32_t id_block_size,
> + void *id_auth, uint32_t id_auth_size,
> + Error **errp)
> +{
> + SevCommonState *sev_common = SEV_COMMON(MACHINE(qdev_get_machine())->cgs);
> + if (sev_common->state == SEV_STATE_UNINIT) {
> + /* Pre-processing of IGVM file called from sev_common_kvm_init() */
> + return 0;
> + }
> +
> + if (!sev_snp_enabled()) {
> + error_setg(errp, "SEV: ID block is only supported for SEV-SNP");
> + return -1;
> + }
>
> - /* do not reset existing policy if policy was not set in IGVM */
> - if (policy != 0) {
> - sev_snp_guest->kvm_start_conf.policy = policy;
> + SevSnpGuestState *sev_snp_guest =
> + SEV_SNP_GUEST(MACHINE(qdev_get_machine())->cgs);
> + struct kvm_sev_snp_launch_finish *finish =
> + &sev_snp_guest->kvm_finish_conf;
> +
> + /*
> + * Drop any ID block and ID auth from a previous pass before repopulating
> + * them, then set them only if an ID block was provided.
> + */
> + g_free(sev_snp_guest->id_block);
> + g_free((guchar *)finish->id_block_uaddr);
> + g_free(sev_snp_guest->id_auth);
> + g_free((guchar *)finish->id_auth_uaddr);
> + sev_snp_guest->id_block = NULL;
> + finish->id_block_uaddr = 0;
> + sev_snp_guest->id_auth = NULL;
> + finish->id_auth_uaddr = 0;
> +
> + if (id_block_size > 0) {
> + struct sev_snp_id_authentication *auth =
> + (struct sev_snp_id_authentication *)id_auth;
> +
> + if (id_block_size != KVM_SEV_SNP_ID_BLOCK_SIZE) {
> + error_setg(errp, "SEV: Invalid SEV-SNP ID block: incorrect size");
> + return -1;
> }
> - } else {
> - SevGuestState *sev_guest = SEV_GUEST(MACHINE(qdev_get_machine())->cgs);
> - /* Only the policy flags are supported for SEV and SEV-ES */
> - if ((policy_data1_size > 0) || (policy_data2_size > 0) || !sev_guest) {
> - error_setg(errp, "SEV: An ID block/ID auth block has been provided "
> - "but SEV-SNP is not enabled");
> + if (id_auth_size != KVM_SEV_SNP_ID_AUTH_SIZE) {
> + error_setg(errp,
> + "SEV: Invalid SEV-SNP ID auth block: incorrect size");
> return -1;
> }
> + assert(id_block != NULL);
> + assert(id_auth != NULL);
>
> - /* do not reset existing policy if policy was not set in IGVM */
> - if (policy != 0) {
> - sev_guest->policy = policy;
> - }
> + finish->id_block_uaddr =
> + (__u64)g_memdup2(id_block, KVM_SEV_SNP_ID_BLOCK_SIZE);
> + finish->id_auth_uaddr =
> + (__u64)g_memdup2(id_auth, KVM_SEV_SNP_ID_AUTH_SIZE);
> +
> + /*
> + * Check if an author key has been provided and use that to flag
> + * whether the author key is enabled. The first of the author key
> + * must be non-zero to indicate the key type, which will currently
> + * always be 2.
> + */
> + sev_snp_guest->kvm_finish_conf.auth_key_en =
> + auth->author_key[0] ? 1 : 0;
> + finish->id_block_en = 1;
> }
> +
> return 0;
> }
>
> @@ -2881,6 +2888,7 @@ sev_common_instance_init(Object *obj)
> cgs->set_guest_state = cgs_set_guest_state;
> cgs->get_mem_map_entry = cgs_get_mem_map_entry;
> cgs->set_guest_policy = cgs_set_guest_policy;
> + cgs->set_id_block = cgs_set_id_block;
> cgs->can_rebuild_guest_state = true;
>
> QTAILQ_INIT(&sev_common->launch_vmsa);
>
> --
> 2.55.0
>
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-09-08 6:24 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-07 15:56 [PATCH v2 0/5] igvm/sev: apply the IGVM guest policy before launch Luigi Leonardi
2026-09-07 15:56 ` [PATCH v2 1/5] sev: split set_guest_policy into set_guest_policy and set_id_block Luigi Leonardi
2026-09-08 6:24 ` Ani Sinha
2026-09-07 15:56 ` [PATCH v2 2/5] igvm: move set_id_block call into the SNP ID block directive handler Luigi Leonardi
2026-09-07 15:56 ` [PATCH v2 3/5] i386/sev: convert the guest policy properties to custom accessors Luigi Leonardi
2026-09-07 15:57 ` [PATCH v2 4/5] i386/sev: add a get_guest_policy callback Luigi Leonardi
2026-09-07 15:57 ` [PATCH v2 5/5] igvm/sev: forward the IGVM guest policy to the platform before launch Luigi Leonardi
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).