If users try to hotplug RNG device with a backend different to
/dev/random or /dev/urandom the whole operation fails as qemu is
unable to access the device. The problem is we don't update
device CGroups during the operation.
Signed-off-by: Michal Privoznik <mprivozn(a)redhat.com>
---
src/qemu/qemu_cgroup.c | 62 +++++++++++++++++++++++++++++++++++++++----------
src/qemu/qemu_cgroup.h | 4 ++++
src/qemu/qemu_hotplug.c | 17 ++++++++++++--
3 files changed, 69 insertions(+), 14 deletions(-)
diff --git a/src/qemu/qemu_cgroup.c b/src/qemu/qemu_cgroup.c
index 1443f7e..e7ce032 100644
--- a/src/qemu/qemu_cgroup.c
+++ b/src/qemu/qemu_cgroup.c
@@ -569,6 +569,54 @@ qemuSetupFirmwareCgroup(virDomainObjPtr vm)
}
+int
+qemuSetupRNGCgroup(virDomainObjPtr vm,
+ virDomainRNGDefPtr rng)
+{
+ qemuDomainObjPrivatePtr priv = vm->privateData;
+ int rv;
+
+ if (rng->backend == VIR_DOMAIN_RNG_BACKEND_RANDOM) {
+ VIR_DEBUG("Setting Cgroup ACL for RNG device");
+ rv = virCgroupAllowDevicePath(priv->cgroup,
+ rng->source.file,
+ VIR_CGROUP_DEVICE_RW, false);
+ virDomainAuditCgroupPath(vm, priv->cgroup, "allow",
+ rng->source.file,
+ "rw", rv == 0);
+ if (rv < 0 &&
+ !virLastErrorIsSystemErrno(ENOENT))
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int
+qemuTeardownRNGCgroup(virDomainObjPtr vm,
+ virDomainRNGDefPtr rng)
+{
+ qemuDomainObjPrivatePtr priv = vm->privateData;
+ int rv;
+
+ if (rng->backend == VIR_DOMAIN_RNG_BACKEND_RANDOM) {
+ VIR_DEBUG("Setting Cgroup ACL for RNG device");
+ rv = virCgroupDenyDevicePath(priv->cgroup,
+ rng->source.file,
+ VIR_CGROUP_DEVICE_RW, false);
+ virDomainAuditCgroupPath(vm, priv->cgroup, "deny",
+ rng->source.file,
+ "rw", rv == 0);
+ if (rv < 0 &&
+ !virLastErrorIsSystemErrno(ENOENT))
+ return -1;
+ }
+
+ return 0;
+}
+
+
static int
qemuSetupDevicesCgroup(virQEMUDriverPtr driver,
virDomainObjPtr vm)
@@ -663,18 +711,8 @@ qemuSetupDevicesCgroup(virQEMUDriverPtr driver,
}
for (i = 0; i < vm->def->nrngs; i++) {
- if (vm->def->rngs[i]->backend == VIR_DOMAIN_RNG_BACKEND_RANDOM) {
- VIR_DEBUG("Setting Cgroup ACL for RNG device");
- rv = virCgroupAllowDevicePath(priv->cgroup,
- vm->def->rngs[i]->source.file,
- VIR_CGROUP_DEVICE_RW, false);
- virDomainAuditCgroupPath(vm, priv->cgroup, "allow",
- vm->def->rngs[i]->source.file,
- "rw", rv == 0);
- if (rv < 0 &&
- !virLastErrorIsSystemErrno(ENOENT))
- goto cleanup;
- }
+ if (qemuSetupRNGCgroup(vm, vm->def->rngs[i]) < 0)
+ goto cleanup;
}
ret = 0;
diff --git a/src/qemu/qemu_cgroup.h b/src/qemu/qemu_cgroup.h
index 623823e..1c3b7ff 100644
--- a/src/qemu/qemu_cgroup.h
+++ b/src/qemu/qemu_cgroup.h
@@ -43,6 +43,10 @@ int qemuSetupHostdevCgroup(virDomainObjPtr vm,
int qemuTeardownHostdevCgroup(virDomainObjPtr vm,
virDomainHostdevDefPtr dev)
ATTRIBUTE_RETURN_CHECK;
+int qemuSetupRNGCgroup(virDomainObjPtr vm,
+ virDomainRNGDefPtr rng);
+int qemuTeardownRNGCgroup(virDomainObjPtr vm,
+ virDomainRNGDefPtr rng);
int qemuConnectCgroup(virQEMUDriverPtr driver,
virDomainObjPtr vm);
int qemuSetupCgroup(virQEMUDriverPtr driver,
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index 6b3a068..b43d9dd 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -1951,6 +1951,7 @@ qemuDomainAttachRNGDevice(virConnectPtr conn,
char *tlsAlias = NULL;
char *secAlias = NULL;
bool releaseaddr = false;
+ bool teardowncgroup = false;
bool chardevAdded = false;
bool objAdded = false;
bool tlsobjAdded = false;
@@ -1996,6 +1997,10 @@ qemuDomainAttachRNGDevice(virConnectPtr conn,
goto cleanup;
}
+ if (qemuSetupRNGCgroup(vm, rng) < 0)
+ goto cleanup;
+ teardowncgroup = true;
+
if (rng->backend == VIR_DOMAIN_RNG_BACKEND_EGD)
qemuDomainPrepareChardevSourceTLS(rng->source.chardev, cfg);
@@ -2073,8 +2078,13 @@ qemuDomainAttachRNGDevice(virConnectPtr conn,
virJSONValueFree(tlsProps);
virJSONValueFree(secProps);
virJSONValueFree(props);
- if (ret < 0 && releaseaddr)
- qemuDomainReleaseDeviceAddress(vm, &rng->info, NULL);
+ if (ret < 0) {
+ if (releaseaddr)
+ qemuDomainReleaseDeviceAddress(vm, &rng->info, NULL);
+ if (teardowncgroup && qemuTeardownRNGCgroup(vm, rng) < 0)
+ VIR_WARN("Unable to remove RNG device cgroup ACL on hotplug
fail");
+ }
+
VIR_FREE(tlsAlias);
VIR_FREE(secAlias);
VIR_FREE(charAlias);
@@ -3912,6 +3922,9 @@ qemuDomainRemoveRNGDevice(virQEMUDriverPtr driver,
if (rc < 0)
goto cleanup;
+ if (qemuTeardownRNGCgroup(vm, rng) < 0)
+ VIR_WARN("Failed to remove RNG device cgroup ACL");
+
event = virDomainEventDeviceRemovedNewFromObj(vm, rng->info.alias);
qemuDomainEventQueue(driver, event);
--
2.8.4