[libvirt] [PATCH v5 10/20] tpm: Parse the capabilities supported by swtpm and swtpm_setup

Stefan Berger posted 20 patches 6 years, 7 months ago
There is a newer version of this series
[libvirt] [PATCH v5 10/20] tpm: Parse the capabilities supported by swtpm and swtpm_setup
Posted by Stefan Berger 6 years, 7 months ago
Run 'swtpm socket --print-capabilities' and
'swtpm_setup --print-capabilities' to get the JSON object of the
features the programs are supporting and parse them into a bitmap.

Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
---
 src/libvirt_private.syms |   2 +
 src/util/virtpm.c        | 134 +++++++++++++++++++++++++++++++++++++--
 src/util/virtpm.h        |  15 +++++
 3 files changed, 147 insertions(+), 4 deletions(-)

diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 5b3c176862..5200adae3f 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -3181,6 +3181,8 @@ virTPMEmulatorInit;
 virTPMGetSwtpm;
 virTPMGetSwtpmIoctl;
 virTPMGetSwtpmSetup;
+virTPMSwtpmFeatureTypeFromString;
+virTPMSwtpmSetupFeatureTypeFromString;
 
 
 # util/virtypedparam.h
diff --git a/src/util/virtpm.c b/src/util/virtpm.c
index e4735f9c4d..692033e899 100644
--- a/src/util/virtpm.c
+++ b/src/util/virtpm.c
@@ -27,9 +27,22 @@
 #include "viralloc.h"
 #include "virfile.h"
 #include "virtpm.h"
+#include "vircommand.h"
+#include "virbitmap.h"
+#include "virjson.h"
 
 #define VIR_FROM_THIS VIR_FROM_NONE
 
+VIR_ENUM_IMPL(virTPMSwtpmFeature,
+              VIR_TPM_SWTPM_FEATURE_LAST,
+              "cmdarg-pwd-fd",
+);
+
+VIR_ENUM_IMPL(virTPMSwtpmSetupFeature,
+              VIR_TPM_SWTPM_SETUP_FEATURE_LAST,
+              "cmdarg-pwdfile-fd",
+);
+
 /**
  * virTPMCreateCancelPath:
  * @devpath: Path to the TPM device
@@ -74,17 +87,22 @@ virTPMCreateCancelPath(const char *devpath)
 }
 
 /*
- * executables for the swtpm; to be found on the host
+ * executables for the swtpm; to be found on the host along with
+ * capabilties bitmap
  */
 static char *swtpm_path;
 static struct stat swtpm_stat;
+static virBitmapPtr swtpm_caps;
 
 static char *swtpm_setup;
 static struct stat swtpm_setup_stat;
+static virBitmapPtr swtpm_setup_caps;
 
 static char *swtpm_ioctl;
 static struct stat swtpm_ioctl_stat;
 
+typedef int (*TypeFromStringFn)(const char *);
+
 const char *
 virTPMGetSwtpm(void)
 {
@@ -109,6 +127,99 @@ virTPMGetSwtpmIoctl(void)
     return swtpm_ioctl;
 }
 
+/* virTPMExecGetCaps
+ *
+ * Execute the prepared command and parse the returned JSON object
+ * to get the capabilities supported by the executable.
+ * A JSON object like this is expected:
+ *
+ * {
+ *  "type": "swtpm",
+ *  "features": [
+ *    "cmdarg-seccomp",
+ *    "cmdarg-key-fd",
+ *    "cmdarg-pwd-fd"
+ *  ]
+ * }
+ */
+static virBitmapPtr
+virTPMExecGetCaps(virCommandPtr cmd,
+                  TypeFromStringFn typeFromStringFn)
+{
+    int exitstatus;
+    virBitmapPtr bitmap;
+    VIR_AUTOFREE(char *) outbuf = NULL;
+    VIR_AUTOPTR(virJSONValue) json = NULL;
+    virJSONValuePtr featureList;
+    virJSONValuePtr item;
+    size_t idx;
+    const char *str;
+    int typ;
+
+    virCommandSetOutputBuffer(cmd, &outbuf);
+    if (virCommandRun(cmd, &exitstatus) < 0)
+        return NULL;
+
+    if (!(bitmap = virBitmapNewEmpty()))
+        return NULL;
+
+    /* older version does not support --print-capabilties -- that's fine */
+    if (exitstatus != 0)
+        return bitmap;
+
+    json = virJSONValueFromString(outbuf);
+    if (!json)
+        goto error_bad_json;
+
+    featureList = virJSONValueObjectGetArray(json, "features");
+    if (!featureList)
+        goto error_bad_json;
+
+    if (!virJSONValueIsArray(featureList))
+        goto error_bad_json;
+
+    for (idx = 0; idx < virJSONValueArraySize(featureList); idx++) {
+        item = virJSONValueArrayGet(featureList, idx);
+        if (!item)
+            continue;
+
+        str = virJSONValueGetString(item);
+        if (!str)
+            goto error_bad_json;
+        typ = typeFromStringFn(str);
+        if (typ < 0)
+            continue;
+
+        if (virBitmapSetBitExpand(bitmap, typ) < 0)
+            goto cleanup;
+    }
+
+ cleanup:
+    return bitmap;
+
+ error_bad_json:
+    virReportError(VIR_ERR_INTERNAL_ERROR,
+                   _("Unexpected JSON format: %s"), outbuf);
+    goto cleanup;
+}
+
+static virBitmapPtr
+virTPMGetCaps(TypeFromStringFn typeFromStringFn,
+                  const char *exec, const char *param1)
+{
+    VIR_AUTOPTR(virCommand) cmd = NULL;
+
+    if (!(cmd = virCommandNew(exec)))
+        return NULL;
+
+    if (param1)
+        virCommandAddArg(cmd, param1);
+    virCommandAddArg(cmd, "--print-capabilities");
+    virCommandClearCaps(cmd);
+
+    return virTPMExecGetCaps(cmd, typeFromStringFn);
+}
+
 /*
  * virTPMEmulatorInit
  *
@@ -122,16 +233,24 @@ virTPMEmulatorInit(void)
         const char *name;
         char **path;
         struct stat *stat;
+        const char *parm;
+        virBitmapPtr *caps;
+        TypeFromStringFn typeFromStringFn;
     } prgs[] = {
         {
             .name = "swtpm",
             .path = &swtpm_path,
             .stat = &swtpm_stat,
+            .parm = "socket",
+            .caps = &swtpm_caps,
+            .typeFromStringFn = virTPMSwtpmFeatureTypeFromString,
         },
         {
             .name = "swtpm_setup",
             .path = &swtpm_setup,
             .stat = &swtpm_setup_stat,
+            .caps = &swtpm_setup_caps,
+            .typeFromStringFn = virTPMSwtpmSetupFeatureTypeFromString,
         },
         {
             .name = "swtpm_ioctl",
@@ -142,7 +261,7 @@ virTPMEmulatorInit(void)
     size_t i;
 
     for (i = 0; i < ARRAY_CARDINALITY(prgs); i++) {
-        char *path;
+        VIR_AUTOFREE(char *) path = NULL;
         bool findit = *prgs[i].path == NULL;
         struct stat statbuf;
         char *tmp;
@@ -174,18 +293,25 @@ virTPMEmulatorInit(void)
                 virReportError(VIR_ERR_INTERNAL_ERROR,
                                _("%s is not an executable"),
                                path);
-                VIR_FREE(path);
                 return -1;
             }
             if (stat(path, prgs[i].stat) < 0) {
                 virReportSystemError(errno,
                                      _("Could not stat %s"), path);
-                VIR_FREE(path);
                 return -1;
             }
             tmp = *prgs[i].path;
             *prgs[i].path = path;
             VIR_FREE(tmp);
+
+            if (prgs[i].caps) {
+                *prgs[i].caps = virTPMGetCaps(prgs[i].typeFromStringFn,
+                                              path, prgs[i].parm);
+                path = NULL;
+                if (!*prgs[i].caps)
+                    return -1;
+            }
+            path = NULL;
         }
     }
 
diff --git a/src/util/virtpm.h b/src/util/virtpm.h
index 66d55fb231..f3dc40cd68 100644
--- a/src/util/virtpm.h
+++ b/src/util/virtpm.h
@@ -26,3 +26,18 @@ const char *virTPMGetSwtpm(void);
 const char *virTPMGetSwtpmSetup(void);
 const char *virTPMGetSwtpmIoctl(void);
 int virTPMEmulatorInit(void);
+
+typedef enum {
+    VIR_TPM_SWTPM_FEATURE_CMDARG_PWD_FD,
+
+    VIR_TPM_SWTPM_FEATURE_LAST
+} virTPMSwtpmFeature;
+
+typedef enum {
+    VIR_TPM_SWTPM_SETUP_FEATURE_CMDARG_PWDFILE_FD,
+
+    VIR_TPM_SWTPM_SETUP_FEATURE_LAST
+} virTPMSwtpmSetupFeature;
+
+VIR_ENUM_DECL(virTPMSwtpmFeature);
+VIR_ENUM_DECL(virTPMSwtpmSetupFeature);
-- 
2.20.1

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCH v5 10/20] tpm: Parse the capabilities supported by swtpm and swtpm_setup
Posted by Daniel P. Berrangé 6 years, 6 months ago
On Fri, Jul 12, 2019 at 12:23:44PM -0400, Stefan Berger wrote:
> Run 'swtpm socket --print-capabilities' and
> 'swtpm_setup --print-capabilities' to get the JSON object of the
> features the programs are supporting and parse them into a bitmap.
> 
> Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
> ---
>  src/libvirt_private.syms |   2 +
>  src/util/virtpm.c        | 134 +++++++++++++++++++++++++++++++++++++--
>  src/util/virtpm.h        |  15 +++++
>  3 files changed, 147 insertions(+), 4 deletions(-)
> 
> diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
> index 5b3c176862..5200adae3f 100644
> --- a/src/libvirt_private.syms
> +++ b/src/libvirt_private.syms
> @@ -3181,6 +3181,8 @@ virTPMEmulatorInit;
>  virTPMGetSwtpm;
>  virTPMGetSwtpmIoctl;
>  virTPMGetSwtpmSetup;
> +virTPMSwtpmFeatureTypeFromString;
> +virTPMSwtpmSetupFeatureTypeFromString;
>  
>  
>  # util/virtypedparam.h
> diff --git a/src/util/virtpm.c b/src/util/virtpm.c
> index e4735f9c4d..692033e899 100644
> --- a/src/util/virtpm.c
> +++ b/src/util/virtpm.c
> @@ -27,9 +27,22 @@
>  #include "viralloc.h"
>  #include "virfile.h"
>  #include "virtpm.h"
> +#include "vircommand.h"
> +#include "virbitmap.h"
> +#include "virjson.h"
>  
>  #define VIR_FROM_THIS VIR_FROM_NONE
>  
> +VIR_ENUM_IMPL(virTPMSwtpmFeature,
> +              VIR_TPM_SWTPM_FEATURE_LAST,
> +              "cmdarg-pwd-fd",
> +);
> +
> +VIR_ENUM_IMPL(virTPMSwtpmSetupFeature,
> +              VIR_TPM_SWTPM_SETUP_FEATURE_LAST,
> +              "cmdarg-pwdfile-fd",
> +);
> +
>  /**
>   * virTPMCreateCancelPath:
>   * @devpath: Path to the TPM device
> @@ -74,17 +87,22 @@ virTPMCreateCancelPath(const char *devpath)
>  }
>  
>  /*
> - * executables for the swtpm; to be found on the host
> + * executables for the swtpm; to be found on the host along with
> + * capabilties bitmap
>   */
>  static char *swtpm_path;
>  static struct stat swtpm_stat;
> +static virBitmapPtr swtpm_caps;
>  
>  static char *swtpm_setup;
>  static struct stat swtpm_setup_stat;
> +static virBitmapPtr swtpm_setup_caps;
>  
>  static char *swtpm_ioctl;
>  static struct stat swtpm_ioctl_stat;
>  
> +typedef int (*TypeFromStringFn)(const char *);
> +
>  const char *
>  virTPMGetSwtpm(void)
>  {
> @@ -109,6 +127,99 @@ virTPMGetSwtpmIoctl(void)
>      return swtpm_ioctl;
>  }
>  
> +/* virTPMExecGetCaps
> + *
> + * Execute the prepared command and parse the returned JSON object
> + * to get the capabilities supported by the executable.
> + * A JSON object like this is expected:
> + *
> + * {
> + *  "type": "swtpm",
> + *  "features": [
> + *    "cmdarg-seccomp",
> + *    "cmdarg-key-fd",
> + *    "cmdarg-pwd-fd"
> + *  ]
> + * }
> + */
> +static virBitmapPtr
> +virTPMExecGetCaps(virCommandPtr cmd,
> +                  TypeFromStringFn typeFromStringFn)
> +{
> +    int exitstatus;
> +    virBitmapPtr bitmap;
> +    VIR_AUTOFREE(char *) outbuf = NULL;
> +    VIR_AUTOPTR(virJSONValue) json = NULL;
> +    virJSONValuePtr featureList;
> +    virJSONValuePtr item;
> +    size_t idx;
> +    const char *str;
> +    int typ;
> +
> +    virCommandSetOutputBuffer(cmd, &outbuf);
> +    if (virCommandRun(cmd, &exitstatus) < 0)
> +        return NULL;
> +
> +    if (!(bitmap = virBitmapNewEmpty()))
> +        return NULL;
> +
> +    /* older version does not support --print-capabilties -- that's fine */
> +    if (exitstatus != 0)
> +        return bitmap;

We can't distinguish from an old version that lacks --print-capabilties and
from a new version that crashed when running --print-capabilties. The latter
shouldn't happen in general, but I thin kwe ought to at least put a VIR_DEBUG
in here to make it obvious we're treating this as if we hit an old binary
when looking at logs.

> +
> +    json = virJSONValueFromString(outbuf);
> +    if (!json)
> +        goto error_bad_json;
> +
> +    featureList = virJSONValueObjectGetArray(json, "features");
> +    if (!featureList)
> +        goto error_bad_json;
> +
> +    if (!virJSONValueIsArray(featureList))
> +        goto error_bad_json;
> +
> +    for (idx = 0; idx < virJSONValueArraySize(featureList); idx++) {
> +        item = virJSONValueArrayGet(featureList, idx);
> +        if (!item)
> +            continue;
> +
> +        str = virJSONValueGetString(item);
> +        if (!str)
> +            goto error_bad_json;
> +        typ = typeFromStringFn(str);
> +        if (typ < 0)
> +            continue;
> +
> +        if (virBitmapSetBitExpand(bitmap, typ) < 0)
> +            goto cleanup;
> +    }
> +
> + cleanup:
> +    return bitmap;
> +
> + error_bad_json:
> +    virReportError(VIR_ERR_INTERNAL_ERROR,
> +                   _("Unexpected JSON format: %s"), outbuf);
> +    goto cleanup;
> +}

> @@ -142,7 +261,7 @@ virTPMEmulatorInit(void)
>      size_t i;
>  
>      for (i = 0; i < ARRAY_CARDINALITY(prgs); i++) {
> -        char *path;
> +        VIR_AUTOFREE(char *) path = NULL;
>          bool findit = *prgs[i].path == NULL;
>          struct stat statbuf;
>          char *tmp;
> @@ -174,18 +293,25 @@ virTPMEmulatorInit(void)
>                  virReportError(VIR_ERR_INTERNAL_ERROR,
>                                 _("%s is not an executable"),
>                                 path);
> -                VIR_FREE(path);
>                  return -1;
>              }
>              if (stat(path, prgs[i].stat) < 0) {
>                  virReportSystemError(errno,
>                                       _("Could not stat %s"), path);
> -                VIR_FREE(path);
>                  return -1;
>              }

If you re-post this series, just  use VIR_AUTOFREE straightaway
in the earlier patch.


With the debug line added

Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>


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 :|

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCH v5 10/20] tpm: Parse the capabilities supported by swtpm and swtpm_setup
Posted by Stefan Berger 6 years, 6 months ago
On 7/24/19 1:05 PM, Daniel P. Berrangé wrote:
> On Fri, Jul 12, 2019 at 12:23:44PM -0400, Stefan Berger wrote:
>
> If you re-post this series, just  use VIR_AUTOFREE straightaway
> in the earlier patch.


Done.

>
>
> With the debug line added


Done

>
> Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>


I'll post v6 some time tomorrow... but if you get the time to continue 
on v5, please do.


>
>
> Regards,
> Daniel

Thanks!!

    Stefan


--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list