[PATCH v4 06/11] conf: Add support for profile parameter on TPM emulator in domain XML

Stefan Berger posted 11 patches 1 week ago
[PATCH v4 06/11] conf: Add support for profile parameter on TPM emulator in domain XML
Posted by Stefan Berger 1 week ago
Extend the parser and XML builder with support for the profile parameter
and its remove_disabled attribute.

Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
---
 src/conf/domain_conf.c     | 36 ++++++++++++++++++++++++++++++++++++
 src/conf/domain_conf.h     |  2 ++
 src/conf/domain_validate.c |  7 +++++++
 3 files changed, 45 insertions(+)

diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index a5627ada88..7d91e3e958 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -3478,6 +3478,7 @@ void virDomainTPMDefFree(virDomainTPMDef *def)
         g_free(def->data.emulator.source_path);
         g_free(def->data.emulator.logfile);
         virBitmapFree(def->data.emulator.activePcrBanks);
+        g_free(def->data.emulator.profile_source);
         break;
     case VIR_DOMAIN_TPM_TYPE_EXTERNAL:
         virObjectUnref(def->data.external.source);
@@ -10786,6 +10787,15 @@ virDomainSmartcardDefParseXML(virDomainXMLOption *xmlopt,
  * <tpm model='tpm-tis'>
  *   <backend type='emulator' version='2.0' persistent_state='yes'>
  * </tpm>
+ *
+ * A profile for a TPM 2.0 can be added like this:
+ *
+ * <tpm model='tpm-crb'>
+ *   <backend type='emulator' version='2.0'>
+ *     <profile source='local:restricted' remove_disabled='check'/>
+ *   </backend>
+ * </tpm>
+ *
  */
 static virDomainTPMDef *
 virDomainTPMDefParseXML(virDomainXMLOption *xmlopt,
@@ -10805,6 +10815,8 @@ virDomainTPMDefParseXML(virDomainXMLOption *xmlopt,
     g_autofree xmlNodePtr *backends = NULL;
     g_autofree xmlNodePtr *nodes = NULL;
     g_autofree char *type = NULL;
+    virDomainTPMProfileRemoveDisabled profile_remove_disabled;
+    xmlNodePtr profile;
     int bank;
 
     if (!(def = virDomainTPMDefNew(xmlopt)))
@@ -10911,6 +10923,22 @@ virDomainTPMDefParseXML(virDomainXMLOption *xmlopt,
             }
             virBitmapSetBitExpand(def->data.emulator.activePcrBanks, bank);
         }
+
+        if ((profile = virXPathNode("./backend/profile[1]", ctxt))) {
+            def->data.emulator.profile_source = virXMLPropString(profile, "source");
+            if (!def->data.emulator.profile_source) {
+                virReportError(VIR_ERR_XML_ERROR, "%s", _("missing profile source"));
+                goto error;
+            }
+            if (virXMLPropEnum(profile, "remove_disabled",
+                               virDomainTPMProfileRemoveDisabledTypeFromString,
+                               VIR_XML_PROP_NONZERO,
+                               &profile_remove_disabled) < 0)
+                goto error;
+            if (profile_remove_disabled != VIR_DOMAIN_TPM_PROFILE_REMOVE_DISABLED_NONE)
+                def->data.emulator.profile_remove_disabled =
+                    virDomainTPMProfileRemoveDisabledTypeToString(profile_remove_disabled);
+        }
         break;
     case VIR_DOMAIN_TPM_TYPE_EXTERNAL:
         if (!(type = virXPathString("string(./backend/source/@type)", ctxt))) {
@@ -25106,6 +25134,14 @@ virDomainTPMDefFormat(virBuffer *buf,
                               virDomainTPMSourceTypeTypeToString(def->data.emulator.source_type));
             virBufferEscapeString(&backendChildBuf, " path='%s'/>\n", def->data.emulator.source_path);
         }
+        if (def->data.emulator.profile_source) {
+            virBufferAsprintf(&backendChildBuf, "<profile source='%s'",
+                              def->data.emulator.profile_source);
+            if (def->data.emulator.profile_remove_disabled)
+               virBufferAsprintf(&backendChildBuf, " remove_disabled='%s'",
+                                 def->data.emulator.profile_remove_disabled);
+            virBufferAddLit(&backendChildBuf, "/>\n");
+        }
         break;
     case VIR_DOMAIN_TPM_TYPE_EXTERNAL:
         if (def->data.external.source->type == VIR_DOMAIN_CHR_TYPE_UNIX) {
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index e1103c3655..bd2740af26 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -1492,6 +1492,8 @@ struct _virDomainTPMEmulatorDef {
     bool hassecretuuid;
     bool persistent_state;
     virBitmap *activePcrBanks;
+    char *profile_source; /* 'source' profile was created from */
+    const char *profile_remove_disabled;
 };
 
 struct _virDomainTPMDef {
diff --git a/src/conf/domain_validate.c b/src/conf/domain_validate.c
index b8ae9ed79d..7573430b6b 100644
--- a/src/conf/domain_validate.c
+++ b/src/conf/domain_validate.c
@@ -3026,6 +3026,13 @@ virDomainTPMDevValidate(const virDomainTPMDef *tpm)
                            virDomainTPMVersionTypeToString(VIR_DOMAIN_TPM_VERSION_2_0));
             return -1;
         }
+        if (tpm->data.emulator.profile_source &&
+            tpm->data.emulator.version != VIR_DOMAIN_TPM_VERSION_2_0) {
+            virReportError(VIR_ERR_XML_ERROR,
+                           _("<profile/> requires TPM version '%1$s'"),
+                           virDomainTPMVersionTypeToString(VIR_DOMAIN_TPM_VERSION_2_0));
+            return -1;
+        }
         break;
 
     case VIR_DOMAIN_TPM_TYPE_PASSTHROUGH:
-- 
2.47.0
Re: [PATCH v4 06/11] conf: Add support for profile parameter on TPM emulator in domain XML
Posted by Michal Prívozník 6 days, 4 hours ago
On 11/13/24 18:39, Stefan Berger wrote:
> Extend the parser and XML builder with support for the profile parameter
> and its remove_disabled attribute.
> 
> Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
> ---
>  src/conf/domain_conf.c     | 36 ++++++++++++++++++++++++++++++++++++
>  src/conf/domain_conf.h     |  2 ++
>  src/conf/domain_validate.c |  7 +++++++
>  3 files changed, 45 insertions(+)
> 
> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
> index a5627ada88..7d91e3e958 100644
> --- a/src/conf/domain_conf.c
> +++ b/src/conf/domain_conf.c
> @@ -3478,6 +3478,7 @@ void virDomainTPMDefFree(virDomainTPMDef *def)
>          g_free(def->data.emulator.source_path);
>          g_free(def->data.emulator.logfile);
>          virBitmapFree(def->data.emulator.activePcrBanks);
> +        g_free(def->data.emulator.profile_source);
>          break;
>      case VIR_DOMAIN_TPM_TYPE_EXTERNAL:
>          virObjectUnref(def->data.external.source);
> @@ -10786,6 +10787,15 @@ virDomainSmartcardDefParseXML(virDomainXMLOption *xmlopt,
>   * <tpm model='tpm-tis'>
>   *   <backend type='emulator' version='2.0' persistent_state='yes'>
>   * </tpm>
> + *
> + * A profile for a TPM 2.0 can be added like this:
> + *
> + * <tpm model='tpm-crb'>
> + *   <backend type='emulator' version='2.0'>
> + *     <profile source='local:restricted' remove_disabled='check'/>
> + *   </backend>
> + * </tpm>
> + *
>   */
>  static virDomainTPMDef *
>  virDomainTPMDefParseXML(virDomainXMLOption *xmlopt,
> @@ -10805,6 +10815,8 @@ virDomainTPMDefParseXML(virDomainXMLOption *xmlopt,
>      g_autofree xmlNodePtr *backends = NULL;
>      g_autofree xmlNodePtr *nodes = NULL;
>      g_autofree char *type = NULL;
> +    virDomainTPMProfileRemoveDisabled profile_remove_disabled;
> +    xmlNodePtr profile;
>      int bank;
>  
>      if (!(def = virDomainTPMDefNew(xmlopt)))
> @@ -10911,6 +10923,22 @@ virDomainTPMDefParseXML(virDomainXMLOption *xmlopt,
>              }
>              virBitmapSetBitExpand(def->data.emulator.activePcrBanks, bank);
>          }
> +
> +        if ((profile = virXPathNode("./backend/profile[1]", ctxt))) {
> +            def->data.emulator.profile_source = virXMLPropString(profile, "source");
> +            if (!def->data.emulator.profile_source) {
> +                virReportError(VIR_ERR_XML_ERROR, "%s", _("missing profile source"));
> +                goto error;
> +            }
> +            if (virXMLPropEnum(profile, "remove_disabled",
> +                               virDomainTPMProfileRemoveDisabledTypeFromString,
> +                               VIR_XML_PROP_NONZERO,
> +                               &profile_remove_disabled) < 0)
> +                goto error;
> +            if (profile_remove_disabled != VIR_DOMAIN_TPM_PROFILE_REMOVE_DISABLED_NONE)
> +                def->data.emulator.profile_remove_disabled =
> +                    virDomainTPMProfileRemoveDisabledTypeToString(profile_remove_disabled);
> +        }
>          break;
>      case VIR_DOMAIN_TPM_TYPE_EXTERNAL:
>          if (!(type = virXPathString("string(./backend/source/@type)", ctxt))) {
> @@ -25106,6 +25134,14 @@ virDomainTPMDefFormat(virBuffer *buf,
>                                virDomainTPMSourceTypeTypeToString(def->data.emulator.source_type));
>              virBufferEscapeString(&backendChildBuf, " path='%s'/>\n", def->data.emulator.source_path);
>          }
> +        if (def->data.emulator.profile_source) {
> +            virBufferAsprintf(&backendChildBuf, "<profile source='%s'",
> +                              def->data.emulator.profile_source);
> +            if (def->data.emulator.profile_remove_disabled)
> +               virBufferAsprintf(&backendChildBuf, " remove_disabled='%s'",
> +                                 def->data.emulator.profile_remove_disabled);
> +            virBufferAddLit(&backendChildBuf, "/>\n");

Alternatively, virXMLFormatElement() makes this simpler.

> +        }
>          break;
>      case VIR_DOMAIN_TPM_TYPE_EXTERNAL:
>          if (def->data.external.source->type == VIR_DOMAIN_CHR_TYPE_UNIX) {
> diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
> index e1103c3655..bd2740af26 100644
> --- a/src/conf/domain_conf.h
> +++ b/src/conf/domain_conf.h
> @@ -1492,6 +1492,8 @@ struct _virDomainTPMEmulatorDef {
>      bool hassecretuuid;
>      bool persistent_state;
>      virBitmap *activePcrBanks;
> +    char *profile_source; /* 'source' profile was created from */
> +    const char *profile_remove_disabled;

Why not store the enum instead of this const string?

Oh, and while at it, these two (soon three) variables can be moved into
a separate struct so that their "profile_" prefix can be dropped. E.g.

struct {
  char *source;
  virDomainTPMProfileRemoveDisabled removeDisabled;
} profile;

>  };
>  
>  struct _virDomainTPMDef {
> diff --git a/src/conf/domain_validate.c b/src/conf/domain_validate.c
> index b8ae9ed79d..7573430b6b 100644
> --- a/src/conf/domain_validate.c
> +++ b/src/conf/domain_validate.c
> @@ -3026,6 +3026,13 @@ virDomainTPMDevValidate(const virDomainTPMDef *tpm)
>                             virDomainTPMVersionTypeToString(VIR_DOMAIN_TPM_VERSION_2_0));
>              return -1;
>          }
> +        if (tpm->data.emulator.profile_source &&
> +            tpm->data.emulator.version != VIR_DOMAIN_TPM_VERSION_2_0) {
> +            virReportError(VIR_ERR_XML_ERROR,
> +                           _("<profile/> requires TPM version '%1$s'"),
> +                           virDomainTPMVersionTypeToString(VIR_DOMAIN_TPM_VERSION_2_0));
> +            return -1;
> +        }
>          break;
>  
>      case VIR_DOMAIN_TPM_TYPE_PASSTHROUGH:

Michal
Re: [PATCH v4 06/11] conf: Add support for profile parameter on TPM emulator in domain XML
Posted by Stefan Berger 5 days, 15 hours ago

On 11/15/24 4:19 AM, Michal Prívozník wrote:
> On 11/13/24 18:39, Stefan Berger wrote:

> 
>> +        }
>>           break;
>>       case VIR_DOMAIN_TPM_TYPE_EXTERNAL:
>>           if (def->data.external.source->type == VIR_DOMAIN_CHR_TYPE_UNIX) {
>> diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
>> index e1103c3655..bd2740af26 100644
>> --- a/src/conf/domain_conf.h
>> +++ b/src/conf/domain_conf.h
>> @@ -1492,6 +1492,8 @@ struct _virDomainTPMEmulatorDef {
>>       bool hassecretuuid;
>>       bool persistent_state;
>>       virBitmap *activePcrBanks;
>> +    char *profile_source; /* 'source' profile was created from */
>> +    const char *profile_remove_disabled;
> 
> Why not store the enum instead of this const string?
> 
> Oh, and while at it, these two (soon three) variables can be moved into
> a separate struct so that their "profile_" prefix can be dropped. E.g.
> 
> struct {
>    char *source;
>    virDomainTPMProfileRemoveDisabled removeDisabled;
> } profile;

Yes, all profile-related stuff together is better.

Thanks.
     Stefan