On Fri, Jun 21, 2024 at 03:29:17PM +0100, Roy Hopkins wrote: > The new cgs_set_guest_policy() function is provided to receive the guest > policy flags, SNP ID block and SNP ID authentication from guest > configuration such as an IGVM file and apply it to the platform prior to > launching the guest. > > The policy is used to populate values for the existing 'policy', > 'id_block' and 'id_auth' parameters. When provided, the guest policy is > applied and the ID block configuration is used to verify the launch > measurement and signatures. The guest is only successfully started if > the expected launch measurements match the actual measurements and the > signatures are valid. > > Signed-off-by: Roy Hopkins <roy.hopk...@suse.com> > --- > target/i386/sev.h | 12 +++++++ > target/i386/sev.c | 83 +++++++++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 95 insertions(+) > > diff --git a/target/i386/sev.h b/target/i386/sev.h > index 2ccd6fe1e8..7b92102bd0 100644 > --- a/target/i386/sev.h > +++ b/target/i386/sev.h > @@ -157,6 +157,18 @@ struct QEMU_PACKED sev_es_save_area { > uint8_t fpreg_ymm[256]; > }; > > +struct QEMU_PACKED sev_snp_id_authentication { > + uint32_t id_key_alg; > + uint32_t auth_key_algo; > + uint8_t reserved[56]; > + uint8_t id_block_sig[512]; > + uint8_t id_key[1028]; > + uint8_t reserved2[60]; > + uint8_t id_key_sig[512]; > + uint8_t author_key[1028]; > + uint8_t reserved3[892]; > +}; > + > #ifdef CONFIG_SEV > bool sev_enabled(void); > bool sev_es_enabled(void); > diff --git a/target/i386/sev.c b/target/i386/sev.c > index 5d9ef745bb..688b378c42 100644 > --- a/target/i386/sev.c > +++ b/target/i386/sev.c > @@ -2446,6 +2446,88 @@ static int cgs_get_mem_map_entry(int index, > return 0; > } > > +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) > +{ > + if (policy_type != GUEST_POLICY_SEV) { > + error_setg(errp, "%s: Invalid guest policy type provided for SEV: > %d", > + __func__, 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. > + */ > + 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, "%s: Invalid SEV-SNP ID block: incorrect > size", > + __func__); > + return -1; > + } > + if (policy_data2_size != KVM_SEV_SNP_ID_AUTH_SIZE) { > + error_setg(errp, > + "%s: Invalid SEV-SNP ID auth block: incorrect > size", > + __func__); > + return -1; > + }
Perhaps add assert(policy_data1 != NULL); assert(policy_data2 != NULL); > + finish->id_block_uaddr = > + (__u64)g_malloc0(KVM_SEV_SNP_ID_BLOCK_SIZE); > + finish->id_authu_addr = > (__u64)g_malloc0(KVM_SEV_SNP_ID_AUTH_SIZE); > + memcpy((void *)finish->id_block_uaddr, policy_data1, > + KVM_SEV_SNP_ID_BLOCK_SIZE); > + memcpy((void *)finish->id_auth_uaddr, policy_data2, > + KVM_SEV_SNP_ID_AUTH_SIZE); How about using g_memdup2 ? 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); > + > + /* > + * 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; > + } > + sev_snp_guest->kvm_start_conf.policy = policy; > + } 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, "%s: An ID block/ID auth block has been > provided " > + "but SEV-SNP is not supported", __func__); Slightly more accurate to say s/is not supported/is not enabled/ > + return -1; > + } > + sev_guest->policy = policy; > + } > + return 0; > +} > + > static void > sev_common_class_init(ObjectClass *oc, void *data) > { > @@ -2484,6 +2566,7 @@ sev_common_instance_init(Object *obj) > cgs->check_support = cgs_check_support; > 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; > > QTAILQ_INIT(&sev_common->launch_vmsa); > } > -- > 2.43.0 > With regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|