diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index e2ca00df85..43bbdef8f1 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1326,6 +1326,7 @@ virSecurityManagerRestoreImageLabel; virSecurityManagerRestoreInputLabel; virSecurityManagerRestoreMemoryLabel; virSecurityManagerRestoreSavedStateLabel; +virSecurityManagerRestoreTPMLabels; virSecurityManagerSetAllLabel; virSecurityManagerSetChardevLabel; virSecurityManagerSetChildProcessLabel; @@ -1340,6 +1341,7 @@ virSecurityManagerSetProcessLabel; virSecurityManagerSetSavedStateLabel; virSecurityManagerSetSocketLabel; virSecurityManagerSetTapFDLabel; +virSecurityManagerSetTPMLabels; virSecurityManagerStackAddNested; virSecurityManagerTransactionAbort; virSecurityManagerTransactionCommit; diff --git a/src/qemu/qemu_security.c b/src/qemu/qemu_security.c index 2aced22d2d..af3be42854 100644 --- a/src/qemu/qemu_security.c +++ b/src/qemu/qemu_security.c @@ -424,3 +424,72 @@ qemuSecurityRestoreChardevLabel(virQEMUDriverPtr driver, virSecurityManagerTransactionAbort(driver->securityManager); return ret; } + + +/* + * qemuSecurityStartTPMEmulator: + * + * @driver: the QEMU driver + * @def: the domain definition + * @cmd: the command to run + * @uid: the uid to run the emulator + * @gid: the gid to run the emulator + * @existstatus: pointer to int returning exit status of process + * @cmdret: pointer to int returning result of virCommandRun + * + * Start the TPM emulator with approriate labels. Apply security + * labels to files first. + * This function returns -1 on security setup error, 0 if all the + * setup was done properly. In case the virCommand failed to run + * 0 is returned but cmdret is set appropriately with the process + * exitstatus also set. + */ +int +qemuSecurityStartTPMEmulator(virQEMUDriverPtr driver, + virDomainDefPtr def, + virCommandPtr cmd, + uid_t uid, + gid_t gid, + int *exitstatus, + int *cmdret) +{ + int ret = -1; + + if (virSecurityManagerSetTPMLabels(driver->securityManager, + def) < 0) + goto cleanup; + + if (virSecurityManagerSetChildProcessLabel(driver->securityManager, + def, cmd) < 0) + goto cleanup; + + if (virSecurityManagerPreFork(driver->securityManager) < 0) + goto cleanup; + + ret = 0; + /* make sure we run this with the appropriate user */ + virCommandSetUID(cmd, uid); + virCommandSetGID(cmd, gid); + + *cmdret = virCommandRun(cmd, exitstatus); + + virSecurityManagerPostFork(driver->securityManager); + + if (*cmdret < 0) + goto cleanup; + + return 0; + + cleanup: + virSecurityManagerRestoreTPMLabels(driver->securityManager, def); + + return ret; +} + + +void +qemuSecurityCleanupTPMEmulator(virQEMUDriverPtr driver, + virDomainDefPtr def) +{ + virSecurityManagerRestoreTPMLabels(driver->securityManager, def); +} diff --git a/src/qemu/qemu_security.h b/src/qemu/qemu_security.h index d54ce6fead..a189b63828 100644 --- a/src/qemu/qemu_security.h +++ b/src/qemu/qemu_security.h @@ -84,6 +84,17 @@ int qemuSecurityRestoreChardevLabel(virQEMUDriverPtr driver, virDomainObjPtr vm, virDomainChrDefPtr chr); +int qemuSecurityStartTPMEmulator(virQEMUDriverPtr driver, + virDomainDefPtr def, + virCommandPtr cmd, + uid_t uid, + gid_t gid, + int *exitstatus, + int *cmdret); + +void qemuSecurityCleanupTPMEmulator(virQEMUDriverPtr driver, + virDomainDefPtr def); + /* Please note that for these APIs there is no wrapper yet. Do NOT blindly add * new APIs here. If an API can touch a /dev file add a proper wrapper instead. */ diff --git a/src/qemu/qemu_tpm.c b/src/qemu/qemu_tpm.c index 69d7698198..6897bbf482 100644 --- a/src/qemu/qemu_tpm.c +++ b/src/qemu/qemu_tpm.c @@ -29,6 +29,7 @@ #include "qemu_extdevice.h" #include "qemu_domain.h" +#include "qemu_security.h" #include "conf/domain_conf.h" #include "vircommand.h" @@ -654,11 +655,12 @@ qemuExtTPMStartEmulator(virQEMUDriverPtr driver, { int ret = -1; virCommandPtr cmd = NULL; - int exitstatus; + int exitstatus = 0; char *errbuf = NULL; virQEMUDriverConfigPtr cfg; virDomainTPMDefPtr tpm = def->tpm; char *shortName = virDomainDefGetShortName(def); + int cmdret = 0; if (!shortName) return -1; @@ -679,7 +681,12 @@ qemuExtTPMStartEmulator(virQEMUDriverPtr driver, virCommandSetErrorBuffer(cmd, &errbuf); - if (virCommandRun(cmd, &exitstatus) < 0 || exitstatus != 0) { + if (qemuSecurityStartTPMEmulator(driver, def, cmd, + cfg->swtpm_user, cfg->swtpm_group, + &exitstatus, &cmdret) < 0) + goto cleanup; + + if (cmdret < 0 || exitstatus != 0) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not start 'swtpm'. exitstatus: %d, " "error: %s"), exitstatus, errbuf); @@ -734,6 +741,7 @@ qemuExtTPMStop(virQEMUDriverPtr driver, goto cleanup; qemuTPMEmulatorStop(cfg->swtpmStateDir, shortName); + qemuSecurityCleanupTPMEmulator(driver, def); break; case VIR_DOMAIN_TPM_TYPE_PASSTHROUGH: case VIR_DOMAIN_TPM_TYPE_LAST: diff --git a/src/security/security_driver.h b/src/security/security_driver.h index 95e7c4de07..cbf0ecff6e 100644 --- a/src/security/security_driver.h +++ b/src/security/security_driver.h @@ -149,6 +149,10 @@ typedef int (*virSecurityDomainRestoreChardevLabel) (virSecurityManagerPtr mgr, virDomainDefPtr def, virDomainChrSourceDefPtr dev_source, bool chardevStdioLogd); +typedef int (*virSecurityDomainSetTPMLabels) (virSecurityManagerPtr mgr, + virDomainDefPtr def); +typedef int (*virSecurityDomainRestoreTPMLabels) (virSecurityManagerPtr mgr, + virDomainDefPtr def); struct _virSecurityDriver { @@ -213,6 +217,9 @@ struct _virSecurityDriver { virSecurityDomainSetChardevLabel domainSetSecurityChardevLabel; virSecurityDomainRestoreChardevLabel domainRestoreSecurityChardevLabel; + + virSecurityDomainSetTPMLabels domainSetSecurityTPMLabels; + virSecurityDomainRestoreTPMLabels domainRestoreSecurityTPMLabels; }; virSecurityDriverPtr virSecurityDriverLookup(const char *name, diff --git a/src/security/security_manager.c b/src/security/security_manager.c index 71f7f59b9c..8683ad7d36 100644 --- a/src/security/security_manager.c +++ b/src/security/security_manager.c @@ -1204,3 +1204,39 @@ virSecurityManagerRestoreChardevLabel(virSecurityManagerPtr mgr, virReportUnsupportedError(); return -1; } + + +int +virSecurityManagerSetTPMLabels(virSecurityManagerPtr mgr, + virDomainDefPtr vm) +{ + int ret; + + if (mgr->drv->domainSetSecurityTPMLabels) { + virObjectLock(mgr); + ret = mgr->drv->domainSetSecurityTPMLabels(mgr, vm); + virObjectUnlock(mgr); + + return ret; + } + + return 0; +} + + +int +virSecurityManagerRestoreTPMLabels(virSecurityManagerPtr mgr, + virDomainDefPtr vm) +{ + int ret; + + if (mgr->drv->domainRestoreSecurityTPMLabels) { + virObjectLock(mgr); + ret = mgr->drv->domainRestoreSecurityTPMLabels(mgr, vm); + virObjectUnlock(mgr); + + return ret; + } + + return 0; +} diff --git a/src/security/security_manager.h b/src/security/security_manager.h index c36a8b488f..e772b6165e 100644 --- a/src/security/security_manager.h +++ b/src/security/security_manager.h @@ -194,4 +194,10 @@ int virSecurityManagerRestoreChardevLabel(virSecurityManagerPtr mgr, virDomainChrSourceDefPtr dev_source, bool chardevStdioLogd); +int virSecurityManagerSetTPMLabels(virSecurityManagerPtr mgr, + virDomainDefPtr vm); + +int virSecurityManagerRestoreTPMLabels(virSecurityManagerPtr mgr, + virDomainDefPtr vm); + #endif /* VIR_SECURITY_MANAGER_H__ */ diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c index 92e84155d1..96944d0202 100644 --- a/src/security/security_selinux.c +++ b/src/security/security_selinux.c @@ -3048,6 +3048,167 @@ virSecuritySELinuxDomainSetPathLabel(virSecurityManagerPtr mgr, return virSecuritySELinuxSetFilecon(mgr, path, seclabel->imagelabel); } + +/* + * virSecuritySELinuxSetFileLabels: + * + * @mgr: the virSecurityManager + * @path: path to a directory or a file + * @seclabel: the security label + * + * Set the file labels on the given path; if the path is a directory + * we label all files found there, including the directory itself, + * otherwise we just label the file. + */ +static int +virSecuritySELinuxSetFileLabels(virSecurityManagerPtr mgr, + const char *path, + virSecurityLabelDefPtr seclabel) +{ + int ret = 0; + struct dirent *ent; + char *filename = NULL; + DIR *dir; + + if ((ret = virSecuritySELinuxSetFilecon(mgr, path, seclabel->imagelabel))) + return ret; + + if (!virFileIsDir(path)) + return 0; + + if (virDirOpen(&dir, path) < 0) + return -1; + + while ((ret = virDirRead(dir, &ent, path)) > 0) { + if (ent->d_type != DT_REG) + continue; + + if (virAsprintf(&filename, "%s/%s", path, ent->d_name) < 0) { + ret = -1; + break; + } + ret = virSecuritySELinuxSetFilecon(mgr, filename, + seclabel->imagelabel); + VIR_FREE(filename); + if (ret < 0) + break; + } + if (ret < 0) + virReportSystemError(errno, _("Unable to label files under %s"), + path); + + virDirClose(&dir); + + return ret; +} + + +/* + * virSecuritySELinuxRestoreFileLabels: + * + * @mgr: the virSecurityManager + * @path: path to a directory or a file + * + * Restore the file labels on the given path; if the path is a directory + * we restore all file labels found there, including the label of the + * directory itself, otherwise we just restore the label on the file. + */ +static int +virSecuritySELinuxRestoreFileLabels(virSecurityManagerPtr mgr, + const char *path) +{ + int ret = 0; + struct dirent *ent; + char *filename = NULL; + DIR *dir; + + if ((ret = virSecuritySELinuxRestoreFileLabel(mgr, path))) + return ret; + + if (!virFileIsDir(path)) + return 0; + + if (virDirOpen(&dir, path) < 0) + return -1; + + while ((ret = virDirRead(dir, &ent, path)) > 0) { + if (ent->d_type != DT_REG) + continue; + + if (virAsprintf(&filename, "%s/%s", path, ent->d_name) < 0) { + ret = -1; + break; + } + ret = virSecuritySELinuxRestoreFileLabel(mgr, filename); + VIR_FREE(filename); + if (ret < 0) + break; + } + if (ret < 0) + virReportSystemError(errno, _("Unable to restore file labels under %s"), + path); + + virDirClose(&dir); + + return ret; +} + + +static int +virSecuritySELinuxSetTPMLabels(virSecurityManagerPtr mgr, + virDomainDefPtr def) +{ + int ret = 0; + virSecurityLabelDefPtr seclabel; + + seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME); + if (seclabel == NULL) + return 0; + + switch (def->tpm->type) { + case VIR_DOMAIN_TPM_TYPE_PASSTHROUGH: + break; + case VIR_DOMAIN_TPM_TYPE_EMULATOR: + ret = virSecuritySELinuxSetFileLabels( + mgr, def->tpm->data.emulator.storagepath, + seclabel); + if (ret == 0 && def->tpm->data.emulator.logfile) + ret = virSecuritySELinuxSetFileLabels( + mgr, def->tpm->data.emulator.logfile, + seclabel); + break; + case VIR_DOMAIN_TPM_TYPE_LAST: + break; + } + + return ret; +} + + +static int +virSecuritySELinuxRestoreTPMLabels(virSecurityManagerPtr mgr, + virDomainDefPtr def) +{ + int ret = 0; + + switch (def->tpm->type) { + case VIR_DOMAIN_TPM_TYPE_PASSTHROUGH: + break; + case VIR_DOMAIN_TPM_TYPE_EMULATOR: + ret = virSecuritySELinuxRestoreFileLabels( + mgr, def->tpm->data.emulator.storagepath); + if (ret == 0 && def->tpm->data.emulator.logfile) + ret = virSecuritySELinuxRestoreFileLabels( + mgr, def->tpm->data.emulator.logfile); + break; + case VIR_DOMAIN_TPM_TYPE_LAST: + break; + } + + return ret; +} + + virSecurityDriver virSecurityDriverSELinux = { .privateDataLen = sizeof(virSecuritySELinuxData), .name = SECURITY_SELINUX_NAME, @@ -3107,4 +3268,7 @@ virSecurityDriver virSecurityDriverSELinux = { .domainSetSecurityChardevLabel = virSecuritySELinuxSetChardevLabel, .domainRestoreSecurityChardevLabel = virSecuritySELinuxRestoreChardevLabel, + + .domainSetSecurityTPMLabels = virSecuritySELinuxSetTPMLabels, + .domainRestoreSecurityTPMLabels = virSecuritySELinuxRestoreTPMLabels, }; diff --git a/src/security/security_stack.c b/src/security/security_stack.c index 9615f9f972..e37a681293 100644 --- a/src/security/security_stack.c +++ b/src/security/security_stack.c @@ -760,6 +760,43 @@ virSecurityStackDomainRestoreChardevLabel(virSecurityManagerPtr mgr, return rc; } + +static int +virSecurityStackSetTPMLabels(virSecurityManagerPtr mgr, + virDomainDefPtr vm) +{ + virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr); + virSecurityStackItemPtr item = priv->itemsHead; + int rc = 0; + + for (; item; item = item->next) { + if (virSecurityManagerSetTPMLabels(item->securityManager, + vm) < 0) + rc = -1; + } + + return rc; +} + + +static int +virSecurityStackRestoreTPMLabels(virSecurityManagerPtr mgr, + virDomainDefPtr vm) +{ + virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr); + virSecurityStackItemPtr item = priv->itemsHead; + int rc = 0; + + for (; item; item = item->next) { + if (virSecurityManagerRestoreTPMLabels(item->securityManager, + vm) < 0) + rc = -1; + } + + return rc; +} + + virSecurityDriver virSecurityDriverStack = { .privateDataLen = sizeof(virSecurityStackData), .name = "stack", @@ -822,4 +859,7 @@ virSecurityDriver virSecurityDriverStack = { .domainSetSecurityChardevLabel = virSecurityStackDomainSetChardevLabel, .domainRestoreSecurityChardevLabel = virSecurityStackDomainRestoreChardevLabel, + + .domainSetSecurityTPMLabels = virSecurityStackSetTPMLabels, + .domainRestoreSecurityTPMLabels = virSecurityStackRestoreTPMLabels, };