When creating new /dev/* for qemu, we do chown() and copy ACLs to
create the exact copy from the original /dev. I though that
copying SELinux labels is not necessary as SELinux will chose the
sane defaults. Surprisingly, it does not leaving namespace with
the following labels:
crw-rw-rw-. root root system_u:object_r:tmpfs_t:s0 random
crw-------. root root system_u:object_r:tmpfs_t:s0 rtc0
drwxrwxrwt. root root system_u:object_r:tmpfs_t:s0 shm
crw-rw-rw-. root root system_u:object_r:tmpfs_t:s0 urandom
As a result, domain is unable to start:
error: internal error: process exited while connecting to monitor: Error in GnuTLS
initialization: Failed to acquire random data.
qemu-kvm: cannot initialize crypto: Unable to initialize GNUTLS library: Failed to acquire
random data.
The solution is to copy the SELinux labels as well.
Reported-by: Andrea Bolognani <abologna(a)redhat.com>
Signed-off-by: Michal Privoznik <mprivozn(a)redhat.com>
---
src/qemu/qemu_domain.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 61 insertions(+)
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
index 1399dee0d..a29866673 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -63,6 +63,9 @@
#if defined(HAVE_SYS_MOUNT_H)
# include <sys/mount.h>
#endif
+#ifdef WITH_SELINUX
+# include <selinux/selinux.h>
+#endif
#include <libxml/xpathInternals.h>
@@ -6958,6 +6961,9 @@ qemuDomainCreateDevice(const char *device,
char *canonDevicePath = NULL;
struct stat sb;
int ret = -1;
+#ifdef WITH_SELINUX
+ char *tcon = NULL;
+#endif
if (virFileResolveAllLinks(device, &canonDevicePath) < 0) {
if (errno == ENOENT && allow_noent) {
@@ -7023,10 +7029,34 @@ qemuDomainCreateDevice(const char *device,
goto cleanup;
}
+#ifdef WITH_SELINUX
+ if (getfilecon_raw(canonDevicePath, &tcon) < 0 &&
+ (errno != ENOTSUP && errno != ENODATA)) {
+ virReportSystemError(errno,
+ _("Unable to get SELinux label on %s"),
canonDevicePath);
+ goto cleanup;
+ }
+
+ if (tcon &&
+ setfilecon_raw(devicePath, (VIR_SELINUX_CTX_CONST char *) tcon) < 0) {
+ VIR_WARNINGS_NO_WLOGICALOP_EQUAL_EXPR
+ if (errno != EOPNOTSUPP && errno != ENOTSUP) {
+ VIR_WARNINGS_RESET
+ virReportSystemError(errno,
+ _("Unable to set SELinux label on %s"),
+ devicePath);
+ goto cleanup;
+ }
+ }
+#endif
+
ret = 0;
cleanup:
VIR_FREE(canonDevicePath);
VIR_FREE(devicePath);
+#ifdef WITH_SELINUX
+ freecon(tcon);
+#endif
return ret;
}
@@ -7472,6 +7502,9 @@ struct qemuDomainAttachDeviceMknodData {
const char *file;
struct stat sb;
void *acl;
+#ifdef WITH_SELINUX
+ char *tcon;
+#endif
};
@@ -7515,6 +7548,19 @@ qemuDomainAttachDeviceMknodHelper(pid_t pid ATTRIBUTE_UNUSED,
goto cleanup;
}
+#ifdef WITH_SELINUX
+ if (setfilecon_raw(data->file, (VIR_SELINUX_CTX_CONST char *) data->tcon) <
0) {
+ VIR_WARNINGS_NO_WLOGICALOP_EQUAL_EXPR
+ if (errno != EOPNOTSUPP && errno != ENOTSUP) {
+ VIR_WARNINGS_RESET
+ virReportSystemError(errno,
+ _("Unable to set SELinux label on %s"),
+ data->file);
+ goto cleanup;
+ }
+ }
+#endif
+
switch ((virDomainDeviceType) data->devDef->type) {
case VIR_DOMAIN_DEVICE_DISK: {
virDomainDiskDefPtr def = data->devDef->data.disk;
@@ -7571,6 +7617,9 @@ qemuDomainAttachDeviceMknodHelper(pid_t pid ATTRIBUTE_UNUSED,
cleanup:
if (ret < 0 && delDevice)
unlink(data->file);
+#ifdef WITH_SELINUX
+ freecon(data->tcon);
+#endif
virFileFreeACLs(&data->acl);
return ret;
}
@@ -7605,6 +7654,15 @@ qemuDomainAttachDeviceMknod(virQEMUDriverPtr driver,
return ret;
}
+#ifdef WITH_SELINUX
+ if (getfilecon_raw(file, &data.tcon) < 0 &&
+ (errno != ENOTSUP && errno != ENODATA)) {
+ virReportSystemError(errno,
+ _("Unable to get SELinux label on %s"), file);
+ goto cleanup;
+ }
+#endif
+
if (virSecurityManagerPreFork(driver->securityManager) < 0)
goto cleanup;
@@ -7619,6 +7677,9 @@ qemuDomainAttachDeviceMknod(virQEMUDriverPtr driver,
ret = 0;
cleanup:
+#ifdef WITH_SELINUX
+ freecon(data.tcon);
+#endif
virFileFreeACLs(&data.acl);
return 0;
}
--
2.11.0