[libvirt] [PATCH] Fix save and restore with non-privileged guests and SELinux

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

On Wed, Nov 11, 2009 at 12:14:41PM +0000, Daniel P. Berrange wrote:
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 [...] + 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; + }
reusing qemuDomainSetFileOwnership() here would makes things a little bit more readable I think, maybe qemuDomainSetFileOwnership error message could be extended as provided there too, But it's cosmetic, ACK in any case, Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

On Wed, 11 Nov 2009, Daniel P. Berrange wrote:
+typedef int (*virSecurityDomainRestoreSavedStateLabel) (virConnectPtr conn, + const char *savefile); ... +static int +SELinuxRestoreSavedStateLabel(virConnectPtr conn, + const char *savefile) +{ + return SELinuxRestoreSecurityFileLabel(conn, savefile); +} + +
Can these be updated to have 'virDomainObjPtr vm ATTRIBUTE_UNUSED'? This will need to be added for the AppArmor driver support. Jamie -- Jamie Strandboge | http://www.canonical.com

On Thu, Nov 12, 2009 at 06:48:29AM -0600, Jamie Strandboge wrote:
On Wed, 11 Nov 2009, Daniel P. Berrange wrote:
+typedef int (*virSecurityDomainRestoreSavedStateLabel) (virConnectPtr conn, + const char *savefile); ... +static int +SELinuxRestoreSavedStateLabel(virConnectPtr conn, + const char *savefile) +{ + return SELinuxRestoreSecurityFileLabel(conn, savefile); +} + +
Can these be updated to have 'virDomainObjPtr vm ATTRIBUTE_UNUSED'? This will need to be added for the AppArmor driver support.
I've already committed this, but feel free to add that extra param when you implement the AppArmour version Regards, Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|
participants (3)
-
Daniel P. Berrange
-
Daniel Veillard
-
Jamie Strandboge