[PATCH] lxc: Add TPM passthrough option for LXC driver

Julio Faracco posted 1 patch 3 years, 8 months ago
Test syntax-check failed
Patches applied successfully (tree, apply log)
git fetch https://github.com/patchew-project/libvirt tags/patchew/20200816161630.25490-1-jcfaracco@gmail.com
src/lxc/lxc_cgroup.c     | 27 +++++++++++++++++++
src/lxc/lxc_controller.c | 56 ++++++++++++++++++++++++++++++++++++++++
2 files changed, 83 insertions(+)
[PATCH] lxc: Add TPM passthrough option for LXC driver
Posted by Julio Faracco 3 years, 8 months ago
There is no support to use TPM for passthrough for LXC libvirt driver
this commit adds the option to use host TPM inside containers.

Signed-off-by: Julio Faracco <jcfaracco@gmail.com>
---
 src/lxc/lxc_cgroup.c     | 27 +++++++++++++++++++
 src/lxc/lxc_controller.c | 56 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 83 insertions(+)

diff --git a/src/lxc/lxc_cgroup.c b/src/lxc/lxc_cgroup.c
index d13f2adde5..955d2b4fc1 100644
--- a/src/lxc/lxc_cgroup.c
+++ b/src/lxc/lxc_cgroup.c
@@ -374,6 +374,33 @@ static int virLXCCgroupSetupDeviceACL(virDomainDefPtr def,
             return -1;
     }
 
+    for (i = 0; i < def->ntpms; i++) {
+        virDomainTPMDefPtr tpm = def->tpms[i];
+        const char *dev = NULL;
+
+        switch (tpm->type) {
+        case VIR_DOMAIN_TPM_TYPE_EMULATOR:
+        case VIR_DOMAIN_TPM_TYPE_LAST:
+            break;
+        case VIR_DOMAIN_TPM_TYPE_PASSTHROUGH:
+            dev = "/dev/tpm0";
+            break;
+        }
+
+        if (!dev)
+            continue;
+
+        if (!virFileExists(dev)) {
+            VIR_DEBUG("Ignoring non-existent device %s", dev);
+            continue;
+        }
+
+        if (virCgroupAllowDevicePath(cgroup, dev,
+                                     VIR_CGROUP_DEVICE_READ,
+                                     false) < 0)
+            return -1;
+    }
+
     VIR_DEBUG("Device ACL setup complete");
 
     return 0;
diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c
index ae6b737b60..70ca773bbf 100644
--- a/src/lxc/lxc_controller.c
+++ b/src/lxc/lxc_controller.c
@@ -1644,6 +1644,59 @@ virLXCControllerSetupHostdevSubsysUSB(virDomainDefPtr vmDef,
 }
 
 
+static int
+virLXCControllerSetupTPM(virLXCControllerPtr ctrl)
+{
+    virDomainDefPtr def = ctrl->def;
+    size_t i;
+
+    for (i = 0; i < def->ntpms; i++) {
+        virDomainTPMDefPtr tpm = def->tpms[i];
+        g_autofree char *path = NULL;
+        const char *tpm_dev = NULL;
+        struct stat sb;
+        dev_t dev;
+
+        switch (tpm->type) {
+        case VIR_DOMAIN_TPM_TYPE_EMULATOR:
+        case VIR_DOMAIN_TPM_TYPE_LAST:
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                           _("unsupported timer type (name) '%s'"),
+                           virDomainTPMBackendTypeToString(tpm->type));
+            return -1;
+        case VIR_DOMAIN_TPM_TYPE_PASSTHROUGH:
+            tpm_dev = "/dev/tpm0";
+            path = g_strdup_printf("/%s/%s.dev/%s", LXC_STATE_DIR,
+                                   def->name, "/rtc");
+            break;
+        }
+
+        if (!tpm_dev)
+            continue;
+
+        if (stat(tpm_dev, &sb) < 0) {
+            virReportSystemError(errno, _("Unable to access %s"),
+                                 tpm_dev);
+            return -1;
+        }
+
+        dev = makedev(major(sb.st_rdev), minor(sb.st_rdev));
+        if (mknod(path, S_IFCHR, dev) < 0 ||
+            chmod(path, sb.st_mode)) {
+            virReportSystemError(errno,
+                                 _("Failed to make device %s"),
+                                 path);
+            return -1;
+        }
+
+        if (lxcContainerChown(def, path) < 0)
+            return -1;
+    }
+
+    return 0;
+}
+
+
 static int
 virLXCControllerSetupHostdevCapsStorage(virDomainDefPtr vmDef,
                                         virDomainHostdevDefPtr def,
@@ -2358,6 +2411,9 @@ virLXCControllerRun(virLXCControllerPtr ctrl)
     if (virLXCControllerSetupAllHostdevs(ctrl) < 0)
         goto cleanup;
 
+    if (virLXCControllerSetupTPM(ctrl) < 0)
+        goto cleanup;
+
     if (virLXCControllerSetupFuse(ctrl) < 0)
         goto cleanup;
 
-- 
2.25.1

Re: [PATCH] lxc: Add TPM passthrough option for LXC driver
Posted by Daniel Henrique Barboza 3 years, 8 months ago

On 8/16/20 1:16 PM, Julio Faracco wrote:
> There is no support to use TPM for passthrough for LXC libvirt driver
> this commit adds the option to use host TPM inside containers.


".... for LXC libvirt driver. This commit adds the option ..."

> 
> Signed-off-by: Julio Faracco <jcfaracco@gmail.com>
> ---
>   src/lxc/lxc_cgroup.c     | 27 +++++++++++++++++++
>   src/lxc/lxc_controller.c | 56 ++++++++++++++++++++++++++++++++++++++++
>   2 files changed, 83 insertions(+)
> 
> diff --git a/src/lxc/lxc_cgroup.c b/src/lxc/lxc_cgroup.c
> index d13f2adde5..955d2b4fc1 100644
> --- a/src/lxc/lxc_cgroup.c
> +++ b/src/lxc/lxc_cgroup.c
> @@ -374,6 +374,33 @@ static int virLXCCgroupSetupDeviceACL(virDomainDefPtr def,
>               return -1;
>       }
>   
> +    for (i = 0; i < def->ntpms; i++) {
> +        virDomainTPMDefPtr tpm = def->tpms[i];
> +        const char *dev = NULL;
> +
> +        switch (tpm->type) {
> +        case VIR_DOMAIN_TPM_TYPE_EMULATOR:
> +        case VIR_DOMAIN_TPM_TYPE_LAST:
> +            break;
> +        case VIR_DOMAIN_TPM_TYPE_PASSTHROUGH:
> +            dev = "/dev/tpm0";
> +            break;
> +        }
> +
> +        if (!dev)
> +            continue;


Tou're making an assumption here that the host TPM will always be in /dev/tpm0.
This is most likely to be the case but it has some potential for backfiring.
I don't have access to an LXC env to see how much of a disaster this could
case, so I'll take your word for it.

That said, since 'dev' doesn't change value and you only about TPM PASSTHROUGH,
you can roll something like this (ps: I didn't compile it):


     for (i = 0; i < def->ntpms; i++) {
         virDomainTPMDefPtr tpm = def->tpms[i];
         const char *dev = "/dev/tpm0";

        if (tpm->type != VIR_DOMAIN_TPM_TYPE_PASSTHROUGH)
            continue;

        // if /dev/tpm0 does not exist the whole loop can be skipped
        if (!virFileExists(dev))
            break;

        if (virCgroupAllowDevicePath(cgroup, dev,
                                     VIR_CGROUP_DEVICE_READ,
                                      false) < 0)
             return -1;

         // even if there are more than one TPM passthrough dev, you just
         // care about /dev/tpm0 and you already set the cgroup for it,
         // so break out the loop.
         break;
     }




> +
> +        if (!virFileExists(dev)) {
> +            VIR_DEBUG("Ignoring non-existent device %s", dev);
> +            continue;
> +        }
> +
> +        if (virCgroupAllowDevicePath(cgroup, dev,
> +                                     VIR_CGROUP_DEVICE_READ,
> +                                     false) < 0)
> +            return -1;
> +    }
> +
>       VIR_DEBUG("Device ACL setup complete");
>   
>       return 0;
> diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c
> index ae6b737b60..70ca773bbf 100644
> --- a/src/lxc/lxc_controller.c
> +++ b/src/lxc/lxc_controller.c
> @@ -1644,6 +1644,59 @@ virLXCControllerSetupHostdevSubsysUSB(virDomainDefPtr vmDef,
>   }
>   
>   
> +static int
> +virLXCControllerSetupTPM(virLXCControllerPtr ctrl)
> +{
> +    virDomainDefPtr def = ctrl->def;
> +    size_t i;
> +
> +    for (i = 0; i < def->ntpms; i++) {
> +        virDomainTPMDefPtr tpm = def->tpms[i];
> +        g_autofree char *path = NULL;
> +        const char *tpm_dev = NULL;
> +        struct stat sb;
> +        dev_t dev;
> +
> +        switch (tpm->type) {
> +        case VIR_DOMAIN_TPM_TYPE_EMULATOR:
> +        case VIR_DOMAIN_TPM_TYPE_LAST:
> +            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
> +                           _("unsupported timer type (name) '%s'"),


I believe you meant "unsupported TPM device" instead of timer.


> +                           virDomainTPMBackendTypeToString(tpm->type));
> +            return -1;
> +        case VIR_DOMAIN_TPM_TYPE_PASSTHROUGH:
> +            tpm_dev = "/dev/tpm0";
> +            path = g_strdup_printf("/%s/%s.dev/%s", LXC_STATE_DIR,
> +                                   def->name, "/rtc");
> +            break;
> +        }
> +
> +        if (!tpm_dev)
> +            continue;


I believe this code can be simplified in a similar fashion like I mentioned
up there for virLXCCgroupSetupDeviceACL.


Thanks,


DHB