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
This commit is contained in:
Daniel P. Berrange 2009-11-11 12:07:00 +00:00
parent fedad93d9e
commit bc0010b3d1
3 changed files with 62 additions and 3 deletions

View File

@ -3347,6 +3347,7 @@ static int qemudDomainSave(virDomainPtr dom,
char *xml = NULL; char *xml = NULL;
struct qemud_save_header header; struct qemud_save_header header;
int ret = -1; int ret = -1;
int rc;
virDomainEventPtr event = NULL; virDomainEventPtr event = NULL;
memset(&header, 0, sizeof(header)); memset(&header, 0, sizeof(header));
@ -3435,11 +3436,24 @@ static int qemudDomainSave(virDomainPtr dom,
} }
fd = -1; 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) { if (header.compressed == QEMUD_SAVE_FORMAT_RAW) {
const char *args[] = { "cat", NULL }; const char *args[] = { "cat", NULL };
qemuDomainObjPrivatePtr priv = vm->privateData; qemuDomainObjPrivatePtr priv = vm->privateData;
qemuDomainObjEnterMonitor(vm); qemuDomainObjEnterMonitor(vm);
ret = qemuMonitorMigrateToCommand(priv->mon, 0, args, path); rc = qemuMonitorMigrateToCommand(priv->mon, 0, args, path);
qemuDomainObjExitMonitor(vm); qemuDomainObjExitMonitor(vm);
} else { } else {
const char *prog = qemudSaveCompressionTypeToString(header.compressed); const char *prog = qemudSaveCompressionTypeToString(header.compressed);
@ -3450,13 +3464,28 @@ static int qemudDomainSave(virDomainPtr dom,
NULL NULL
}; };
qemuDomainObjEnterMonitor(vm); qemuDomainObjEnterMonitor(vm);
ret = qemuMonitorMigrateToCommand(priv->mon, 0, args, path); rc = qemuMonitorMigrateToCommand(priv->mon, 0, args, path);
qemuDomainObjExitMonitor(vm); qemuDomainObjExitMonitor(vm);
} }
if (ret < 0) if (rc < 0)
goto endjob; 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 */ /* Shut it down */
qemudShutdownVMDaemon(dom->conn, driver, vm); qemudShutdownVMDaemon(dom->conn, driver, vm);
event = virDomainEventNewFromObj(vm, event = virDomainEventNewFromObj(vm,

View File

@ -42,6 +42,11 @@ typedef int (*virSecurityDomainRestoreHostdevLabel) (virConnectPtr conn,
typedef int (*virSecurityDomainSetHostdevLabel) (virConnectPtr conn, typedef int (*virSecurityDomainSetHostdevLabel) (virConnectPtr conn,
virDomainObjPtr vm, virDomainObjPtr vm,
virDomainHostdevDefPtr dev); 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, typedef int (*virSecurityDomainGenLabel) (virConnectPtr conn,
virDomainObjPtr sec); virDomainObjPtr sec);
typedef int (*virSecurityDomainReserveLabel) (virConnectPtr conn, typedef int (*virSecurityDomainReserveLabel) (virConnectPtr conn,
@ -71,6 +76,8 @@ struct _virSecurityDriver {
virSecurityDomainRestoreLabel domainRestoreSecurityLabel; virSecurityDomainRestoreLabel domainRestoreSecurityLabel;
virSecurityDomainRestoreHostdevLabel domainRestoreSecurityHostdevLabel; virSecurityDomainRestoreHostdevLabel domainRestoreSecurityHostdevLabel;
virSecurityDomainSetHostdevLabel domainSetSecurityHostdevLabel; virSecurityDomainSetHostdevLabel domainSetSecurityHostdevLabel;
virSecurityDomainSetSavedStateLabel domainSetSavedStateLabel;
virSecurityDomainRestoreSavedStateLabel domainRestoreSavedStateLabel;
/* /*
* This is internally managed driver state and should only be accessed * This is internally managed driver state and should only be accessed

View File

@ -523,6 +523,7 @@ done:
return ret; return ret;
} }
static int static int
SELinuxRestoreSecurityPCILabel(virConnectPtr conn, SELinuxRestoreSecurityPCILabel(virConnectPtr conn,
pciDevice *dev ATTRIBUTE_UNUSED, pciDevice *dev ATTRIBUTE_UNUSED,
@ -623,6 +624,26 @@ SELinuxRestoreSecurityLabel(virConnectPtr conn,
return rc; 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 static int
SELinuxSecurityVerify(virConnectPtr conn, virDomainDefPtr def) SELinuxSecurityVerify(virConnectPtr conn, virDomainDefPtr def)
{ {
@ -692,4 +713,6 @@ virSecurityDriver virSELinuxSecurityDriver = {
.domainSetSecurityLabel = SELinuxSetSecurityLabel, .domainSetSecurityLabel = SELinuxSetSecurityLabel,
.domainSetSecurityHostdevLabel = SELinuxSetSecurityHostdevLabel, .domainSetSecurityHostdevLabel = SELinuxSetSecurityHostdevLabel,
.domainRestoreSecurityHostdevLabel = SELinuxRestoreSecurityHostdevLabel, .domainRestoreSecurityHostdevLabel = SELinuxRestoreSecurityHostdevLabel,
.domainSetSavedStateLabel = SELinuxSetSavedStateLabel,
.domainRestoreSavedStateLabel = SELinuxRestoreSavedStateLabel,
}; };