This patch extends the SELinux and DAC security handlers with support for the TPM's storage file. If the user did not provide an explicit file for TPM data storage, then a dummy-file is created in the drivers here and labeled. Athis is necessary since the creation of the TPM's QCoW2 storage file happens later. There is no code for AppArmor. I am not sure whether it needs explicit support. Obviously I haven't tested it with AppArmor. Signed-off-by: Stefan Berger --- src/security/security_dac.c | 102 ++++++++++++++++++++++++++++++++++++++++ src/security/security_selinux.c | 100 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 202 insertions(+) Index: libvirt-acl/src/security/security_selinux.c =================================================================== --- libvirt-acl.orig/src/security/security_selinux.c +++ libvirt-acl/src/security/security_selinux.c @@ -522,6 +522,94 @@ SELinuxRestoreSecurityImageLabel(virSecu static int +SELinuxSetSecurityTPMFileLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, + virDomainObjPtr vm, + virDomainTPMDefPtr tpm) +{ + int rc; + char *path; + struct stat statbuf; + FILE *f; + const virSecurityLabelDefPtr secdef = &vm->def->seclabel; + + if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC) + return 0; + + switch (tpm->type) { + case VIR_DOMAIN_TPM_TYPE_BUILTIN: + path = virDomainTPMGetStorageFilename(tpm, + vm->def->uuid); + if (stat(path, &statbuf) == -1 && errno == ENOENT) { + f = fopen(path, "w"); + VIR_FORCE_FCLOSE(f); + } + rc = SELinuxSetFilecon(path, vm->def->seclabel.imagelabel); + VIR_FREE(path); + if (rc < 0) + return -1; + break; + + case VIR_DOMAIN_TPM_TYPE_LAST: + break; + } + + return 0; +} + + +static int +SELinuxRestoreSecurityTPMFileLabelInt( + virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, + virDomainObjPtr vm, + virDomainTPMDefPtr tpm, + int migrated) +{ + int rc = 0; + char *path; + struct stat statbuf; + const virSecurityLabelDefPtr secdef = &vm->def->seclabel; + + if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC) + return 0; + + switch (tpm->type) { + case VIR_DOMAIN_TPM_TYPE_BUILTIN: + path = virDomainTPMGetStorageFilename(tpm, + vm->def->uuid); + if (stat(path, &statbuf) == 0 && statbuf.st_size == 0) + unlink(path); + + /* If we have a shared FS & doing migrated, we must not + * change ownership, because that kills access on the + * destination host which is sub-optimal for the guest + * VM's I/O attempts :-) + */ + if (migrated) { + rc = virStorageFileIsSharedFS(path); + if (rc < 0) { + VIR_FREE(path); + return -1; + } + if (rc == 1) { + VIR_DEBUG("Skipping image label restore on %s because FS is shared", + path); + VIR_FREE(path); + return 0; + } + } + rc = SELinuxRestoreSecurityFileLabel(path); + VIR_FREE(path); + break; + + case VIR_DOMAIN_TPM_TYPE_LAST: + break; + } + + return rc; +} + + +static int SELinuxSetSecurityFileLabel(virDomainDiskDefPtr disk, const char *path, size_t depth, @@ -854,6 +942,14 @@ SELinuxRestoreSecurityAllLabel(virSecuri if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC) return 0; + if (vm->def->tpm) { + if (SELinuxRestoreSecurityTPMFileLabelInt(mgr, + vm, + vm->def->tpm, + migrated) < 0) + rc = -1; + } + for (i = 0 ; i < vm->def->nhostdevs ; i++) { if (SELinuxRestoreSecurityHostdevLabel(mgr, vm, @@ -1171,6 +1267,10 @@ SELinuxSetSecurityAllLabel(virSecurityMa vm->def->hostdevs[i]) < 0) return -1; } + if (vm->def->tpm) + if (SELinuxSetSecurityTPMFileLabel(mgr, + vm, vm->def->tpm) < 0) + return -1; if (virDomainChrDefForeach(vm->def, true, Index: libvirt-acl/src/security/security_dac.c =================================================================== --- libvirt-acl.orig/src/security/security_dac.c +++ libvirt-acl/src/security/security_dac.c @@ -31,6 +31,7 @@ #include "pci.h" #include "hostusb.h" #include "storage_file.h" +#include "files.h" #define VIR_FROM_THIS VIR_FROM_SECURITY @@ -243,6 +244,94 @@ virSecurityDACRestoreSecurityImageLabel( static int +virSecurityDACSetSecurityTPMFileLabel(virSecurityManagerPtr mgr, + virDomainObjPtr vm, + virDomainTPMDefPtr tpm) +{ + int rc; + char *path; + struct stat statbuf; + FILE *f; + virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr); + + if (!priv->dynamicOwnership) + return 0; + + switch (tpm->type) { + case VIR_DOMAIN_TPM_TYPE_BUILTIN: + path = virDomainTPMGetStorageFilename(tpm, + vm->def->uuid); + if (stat(path, &statbuf) == -1 && errno == ENOENT) { + f = fopen(path, "w"); + VIR_FORCE_FCLOSE(f); + } + rc = virSecurityDACSetOwnership(path, priv->user, priv->group); + VIR_FREE(path); + if (rc < 0) + return -1; + break; + + case VIR_DOMAIN_TPM_TYPE_LAST: + break; + } + + return 0; +} + + +static int +virSecurityDACRestoreSecurityTPMFileLabelInt( + virSecurityManagerPtr mgr, + virDomainObjPtr vm, + virDomainTPMDefPtr tpm, + int migrated) +{ + int rc = 0; + char *path; + struct stat statbuf; + virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr); + + if (!priv->dynamicOwnership) + return 0; + + switch (tpm->type) { + case VIR_DOMAIN_TPM_TYPE_BUILTIN: + path = virDomainTPMGetStorageFilename(tpm, + vm->def->uuid); + if (stat(path, &statbuf) == 0 && statbuf.st_size == 0) + unlink(path); + + /* If we have a shared FS & doing migrated, we must not + * change ownership, because that kills access on the + * destination host which is sub-optimal for the guest + * VM's I/O attempts :-) + */ + if (migrated) { + rc = virStorageFileIsSharedFS(path); + if (rc < 0) { + VIR_FREE(path); + return -1; + } + if (rc == 1) { + VIR_DEBUG("Skipping image label restore on %s because FS is shared", + path); + VIR_FREE(path); + return 0; + } + } + rc = virSecurityDACRestoreSecurityFileLabel(path); + VIR_FREE(path); + break; + + case VIR_DOMAIN_TPM_TYPE_LAST: + break; + } + + return rc; +} + + +static int virSecurityDACSetSecurityPCILabel(pciDevice *dev ATTRIBUTE_UNUSED, const char *file, void *opaque) @@ -492,6 +581,14 @@ virSecurityDACRestoreSecurityAllLabel(vi VIR_DEBUG("Restoring security label on %s migrated=%d", vm->def->name, migrated); + if (vm->def->tpm) { + if (virSecurityDACRestoreSecurityTPMFileLabelInt(mgr, + vm, + vm->def->tpm, + migrated) < 0) + rc = -1; + } + for (i = 0 ; i < vm->def->nhostdevs ; i++) { if (virSecurityDACRestoreSecurityHostdevLabel(mgr, vm, @@ -561,6 +658,11 @@ virSecurityDACSetSecurityAllLabel(virSec vm->def->hostdevs[i]) < 0) return -1; } + if (vm->def->tpm) + if (virSecurityDACSetSecurityTPMFileLabel(mgr, + vm, + vm->def->tpm) < 0) + return -1; if (virDomainChrDefForeach(vm->def, true,