When running qemu:///system instance, libvirtd runs as root, but QEMU may optionally be configured to run non-root. When then saving a guest to a state file, the file is initially created as root, and thus QEMU cannot write to it. It is also missing labelling required to allow access via SELinux. * src/qemu/qemu_driver.c: Set ownership on save image before running migrate command in virDomainSave impl. Call out to security driver to set save image labelling * src/security/security_driver.h: Add driver APIs for setting and restoring saved state file labelling * src/security/security_selinux.c: Implement saved state file labelling for SELinux --- src/qemu/qemu_driver.c | 35 ++++++++++++++++++++++++++++++++--- src/security/security_driver.h | 7 +++++++ src/security/security_selinux.c | 23 +++++++++++++++++++++++ 3 files changed, 62 insertions(+), 3 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 30003e6..b023902 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -3347,6 +3347,7 @@ static int qemudDomainSave(virDomainPtr dom, char *xml = NULL; struct qemud_save_header header; int ret = -1; + int rc; virDomainEventPtr event = NULL; memset(&header, 0, sizeof(header)); @@ -3435,11 +3436,24 @@ static int qemudDomainSave(virDomainPtr dom, } fd = -1; + if (driver->privileged && + chown(path, driver->user, driver->group) < 0) { + virReportSystemError(NULL, errno, + _("unable to set ownership of '%s' to user %d:%d"), + path, driver->user, driver->group); + goto endjob; + } + + if (driver->securityDriver && + driver->securityDriver->domainSetSavedStateLabel && + driver->securityDriver->domainSetSavedStateLabel(dom->conn, vm, path) == -1) + goto endjob; + if (header.compressed == QEMUD_SAVE_FORMAT_RAW) { const char *args[] = { "cat", NULL }; qemuDomainObjPrivatePtr priv = vm->privateData; qemuDomainObjEnterMonitor(vm); - ret = qemuMonitorMigrateToCommand(priv->mon, 0, args, path); + rc = qemuMonitorMigrateToCommand(priv->mon, 0, args, path); qemuDomainObjExitMonitor(vm); } else { const char *prog = qemudSaveCompressionTypeToString(header.compressed); @@ -3450,13 +3464,28 @@ static int qemudDomainSave(virDomainPtr dom, NULL }; qemuDomainObjEnterMonitor(vm); - ret = qemuMonitorMigrateToCommand(priv->mon, 0, args, path); + rc = qemuMonitorMigrateToCommand(priv->mon, 0, args, path); qemuDomainObjExitMonitor(vm); } - if (ret < 0) + if (rc < 0) goto endjob; + if (driver->privileged && + chown(path, 0, 0) < 0) { + virReportSystemError(NULL, errno, + _("unable to set ownership of '%s' to user %d:%d"), + path, 0, 0); + goto endjob; + } + + if (driver->securityDriver && + driver->securityDriver->domainRestoreSavedStateLabel && + driver->securityDriver->domainRestoreSavedStateLabel(dom->conn, path) == -1) + goto endjob; + + ret = 0; + /* Shut it down */ qemudShutdownVMDaemon(dom->conn, driver, vm); event = virDomainEventNewFromObj(vm, diff --git a/src/security/security_driver.h b/src/security/security_driver.h index fde2978..5514962 100644 --- a/src/security/security_driver.h +++ b/src/security/security_driver.h @@ -42,6 +42,11 @@ typedef int (*virSecurityDomainRestoreHostdevLabel) (virConnectPtr conn, typedef int (*virSecurityDomainSetHostdevLabel) (virConnectPtr conn, virDomainObjPtr vm, virDomainHostdevDefPtr dev); +typedef int (*virSecurityDomainSetSavedStateLabel) (virConnectPtr conn, + virDomainObjPtr vm, + const char *savefile); +typedef int (*virSecurityDomainRestoreSavedStateLabel) (virConnectPtr conn, + const char *savefile); typedef int (*virSecurityDomainGenLabel) (virConnectPtr conn, virDomainObjPtr sec); typedef int (*virSecurityDomainReserveLabel) (virConnectPtr conn, @@ -71,6 +76,8 @@ struct _virSecurityDriver { virSecurityDomainRestoreLabel domainRestoreSecurityLabel; virSecurityDomainRestoreHostdevLabel domainRestoreSecurityHostdevLabel; virSecurityDomainSetHostdevLabel domainSetSecurityHostdevLabel; + virSecurityDomainSetSavedStateLabel domainSetSavedStateLabel; + virSecurityDomainRestoreSavedStateLabel domainRestoreSavedStateLabel; /* * This is internally managed driver state and should only be accessed diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c index 0e31077..bd838e6 100644 --- a/src/security/security_selinux.c +++ b/src/security/security_selinux.c @@ -523,6 +523,7 @@ done: return ret; } + static int SELinuxRestoreSecurityPCILabel(virConnectPtr conn, pciDevice *dev ATTRIBUTE_UNUSED, @@ -623,6 +624,26 @@ SELinuxRestoreSecurityLabel(virConnectPtr conn, return rc; } + +static int +SELinuxSetSavedStateLabel(virConnectPtr conn, + virDomainObjPtr vm, + const char *savefile) +{ + const virSecurityLabelDefPtr secdef = &vm->def->seclabel; + + return SELinuxSetFilecon(conn, savefile, secdef->imagelabel); +} + + +static int +SELinuxRestoreSavedStateLabel(virConnectPtr conn, + const char *savefile) +{ + return SELinuxRestoreSecurityFileLabel(conn, savefile); +} + + static int SELinuxSecurityVerify(virConnectPtr conn, virDomainDefPtr def) { @@ -692,4 +713,6 @@ virSecurityDriver virSELinuxSecurityDriver = { .domainSetSecurityLabel = SELinuxSetSecurityLabel, .domainSetSecurityHostdevLabel = SELinuxSetSecurityHostdevLabel, .domainRestoreSecurityHostdevLabel = SELinuxRestoreSecurityHostdevLabel, + .domainSetSavedStateLabel = SELinuxSetSavedStateLabel, + .domainRestoreSavedStateLabel = SELinuxRestoreSavedStateLabel, }; -- 1.6.2.5 -- Libvir-list mailing list Libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list