When configuring serial, parallel, console or channel devices with a file, dev or pipe backend type, it is neccessary to label the file path in the security drivers. For char devices of type file, it is neccessary to pre-create (touch) the file if it does not already exist since QEMU won't be allowed todo so itself. dev/pipe configs already require the admin to pre-create before starting the guest. * src/qemu/qemu_security_dac.c: set file ownership for character devices * src/security/security_selinux.c: Set file labelling for character devices * src/qemu/qemu_driver.c: Add character devices to cgroup ACL --- src/qemu/qemu_driver.c | 59 +++++++++++++++++++ src/qemu/qemu_security_dac.c | 117 ++++++++++++++++++++++++++++++++++++++ src/security/security_selinux.c | 119 +++++++++++++++++++++++++++++++++++++++ src/util/cgroup.c | 2 +- 4 files changed, 296 insertions(+), 1 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index a7b3f25..6274d4c 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -2950,6 +2950,28 @@ qemuPrepareHostDevices(struct qemud_driver *driver, } +static int +qemuPrepareChardevDevice(virDomainDefPtr def ATTRIBUTE_UNUSED, + virDomainChrDefPtr dev, + void *opaque ATTRIBUTE_UNUSED) +{ + int fd; + if (dev->type != VIR_DOMAIN_CHR_TYPE_FILE) + return 0; + + if ((fd = open(dev->data.file.path, O_CREAT | O_APPEND, S_IRUSR|S_IWUSR)) < 0) { + virReportSystemError(errno, + _("Unable to pre-create chardev file %s"), + dev->data.file.path); + return -1; + } + + close(fd); + + return 0; +} + + static void qemudReattachManagedDevice(pciDevice *dev) { @@ -3124,6 +3146,30 @@ cleanup: } +static int qemuSetupChardevCgroup(virDomainDefPtr def, + virDomainChrDefPtr dev, + void *opaque) +{ + virCgroupPtr cgroup = opaque; + int rc; + + if (dev->type != VIR_DOMAIN_CHR_TYPE_DEV) + return 0; + + + VIR_DEBUG("Process path %s for disk", dev->data.file.path); + rc = virCgroupAllowDevicePath(cgroup, dev->data.file.path); + if (rc != 0) { + virReportSystemError(-rc, + _("Unable to allow device %s for %s"), + dev->data.file.path, def->name); + return -1; + } + + return 0; +} + + static int qemuSetupCgroup(struct qemud_driver *driver, virDomainObjPtr vm) { @@ -3191,6 +3237,12 @@ static int qemuSetupCgroup(struct qemud_driver *driver, goto cleanup; } } + + if (virDomainChrDefForeach(vm->def, + true, + qemuSetupChardevCgroup, + cgroup) < 0) + goto cleanup; } done: @@ -3364,6 +3416,13 @@ static int qemudStartVMDaemon(virConnectPtr conn, if (qemuPrepareHostDevices(driver, vm->def) < 0) goto cleanup; + DEBUG0("Preparing chr devices"); + if (virDomainChrDefForeach(vm->def, + true, + qemuPrepareChardevDevice, + NULL) < 0) + goto cleanup; + /* If you are using a SecurityDriver with dynamic labelling, then generate a security label for isolation */ DEBUG0("Generating domain security label (if required)"); diff --git a/src/qemu/qemu_security_dac.c b/src/qemu/qemu_security_dac.c index ffc9b8d..95015b0 100644 --- a/src/qemu/qemu_security_dac.c +++ b/src/qemu/qemu_security_dac.c @@ -328,6 +328,100 @@ done: static int +qemuSecurityDACSetChardevLabel(virDomainObjPtr vm, + virDomainChrDefPtr dev) + +{ + const virSecurityLabelDefPtr secdef = &vm->def->seclabel; + char *in = NULL, *out = NULL; + int ret = -1; + + if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC) + return 0; + + switch (dev->type) { + case VIR_DOMAIN_CHR_TYPE_DEV: + case VIR_DOMAIN_CHR_TYPE_FILE: + ret = qemuSecurityDACSetOwnership(dev->data.file.path, driver->user, driver->group); + break; + + case VIR_DOMAIN_CHR_TYPE_PIPE: + if ((virAsprintf(&in, "%s.in", dev->data.file.path) < 0) || + (virAsprintf(&out, "%s.out", dev->data.file.path) < 0)) { + virReportOOMError(); + goto done; + } + if ((qemuSecurityDACSetOwnership(in, driver->user, driver->group) < 0) || + (qemuSecurityDACSetOwnership(out, driver->user, driver->group) < 0)) + goto done; + ret = 0; + break; + + default: + ret = 0; + break; + } + +done: + VIR_FREE(in); + VIR_FREE(out); + return ret; +} + +static int +qemuSecurityDACRestoreChardevLabel(virDomainObjPtr vm, + virDomainChrDefPtr dev) + +{ + const virSecurityLabelDefPtr secdef = &vm->def->seclabel; + char *in = NULL, *out = NULL; + int ret = -1; + + if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC) + return 0; + + switch (dev->type) { + case VIR_DOMAIN_CHR_TYPE_DEV: + case VIR_DOMAIN_CHR_TYPE_FILE: + ret = qemuSecurityDACRestoreSecurityFileLabel(dev->data.file.path); + break; + + case VIR_DOMAIN_CHR_TYPE_PIPE: + if ((virAsprintf(&out, "%s.out", dev->data.file.path) < 0) || + (virAsprintf(&in, "%s.in", dev->data.file.path) < 0)) { + virReportOOMError(); + goto done; + } + if ((qemuSecurityDACRestoreSecurityFileLabel(out) < 0) || + (qemuSecurityDACRestoreSecurityFileLabel(in) < 0)) + goto done; + ret = 0; + break; + + default: + ret = 0; + break; + } + +done: + VIR_FREE(in); + VIR_FREE(out); + return ret; +} + + +static int +qemuSecurityDACRestoreChardevCallback(virDomainDefPtr def ATTRIBUTE_UNUSED, + virDomainChrDefPtr dev, + void *opaque) +{ + virDomainObjPtr vm = opaque; + + return qemuSecurityDACRestoreChardevLabel(vm, dev); +} + + +static int qemuSecurityDACRestoreSecurityAllLabel(virDomainObjPtr vm, int migrated) { @@ -352,6 +446,12 @@ qemuSecurityDACRestoreSecurityAllLabel(virDomainObjPtr vm, rc = -1; } + if (virDomainChrDefForeach(vm->def, + false, + qemuSecurityDACRestoreChardevCallback, + vm) < 0) + rc = -1; + if (vm->def->os.kernel && qemuSecurityDACRestoreSecurityFileLabel(vm->def->os.kernel) < 0) rc = -1; @@ -365,6 +465,17 @@ qemuSecurityDACRestoreSecurityAllLabel(virDomainObjPtr vm, static int +qemuSecurityDACSetChardevCallback(virDomainDefPtr def ATTRIBUTE_UNUSED, + virDomainChrDefPtr dev, + void *opaque) +{ + virDomainObjPtr vm = opaque; + + return qemuSecurityDACSetChardevLabel(vm, dev); +} + + +static int qemuSecurityDACSetSecurityAllLabel(virDomainObjPtr vm, const char *stdin_path ATTRIBUTE_UNUSED) { int i; @@ -384,6 +495,12 @@ qemuSecurityDACSetSecurityAllLabel(virDomainObjPtr vm, const char *stdin_path AT return -1; } + if (virDomainChrDefForeach(vm->def, + true, + qemuSecurityDACSetChardevCallback, + vm) < 0) + return -1; + if (vm->def->os.kernel && qemuSecurityDACSetOwnership(vm->def->os.kernel, driver->user, diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c index 2b43f2d..d4e2edb 100644 --- a/src/security/security_selinux.c +++ b/src/security/security_selinux.c @@ -628,6 +628,101 @@ done: return ret; } + +static int +SELinuxSetSecurityChardevLabel(virDomainObjPtr vm, + virDomainChrDefPtr dev) + +{ + const virSecurityLabelDefPtr secdef = &vm->def->seclabel; + char *in = NULL, *out = NULL; + int ret = -1; + + if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC) + return 0; + + switch (dev->type) { + case VIR_DOMAIN_CHR_TYPE_DEV: + case VIR_DOMAIN_CHR_TYPE_FILE: + ret = SELinuxSetFilecon(dev->data.file.path, secdef->imagelabel); + break; + + case VIR_DOMAIN_CHR_TYPE_PIPE: + if ((virAsprintf(&in, "%s.in", dev->data.file.path) < 0) || + (virAsprintf(&out, "%s.out", dev->data.file.path) < 0)) { + virReportOOMError(); + goto done; + } + if ((SELinuxSetFilecon(in, secdef->imagelabel) < 0) || + (SELinuxSetFilecon(out, secdef->imagelabel) < 0)) + goto done; + ret = 0; + break; + + default: + ret = 0; + break; + } + +done: + VIR_FREE(in); + VIR_FREE(out); + return ret; +} + +static int +SELinuxRestoreSecurityChardevLabel(virDomainObjPtr vm, + virDomainChrDefPtr dev) + +{ + const virSecurityLabelDefPtr secdef = &vm->def->seclabel; + char *in = NULL, *out = NULL; + int ret = -1; + + if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC) + return 0; + + switch (dev->type) { + case VIR_DOMAIN_CHR_TYPE_DEV: + case VIR_DOMAIN_CHR_TYPE_FILE: + ret = SELinuxSetFilecon(dev->data.file.path, secdef->imagelabel); + break; + + case VIR_DOMAIN_CHR_TYPE_PIPE: + if ((virAsprintf(&out, "%s.out", dev->data.file.path) < 0) || + (virAsprintf(&in, "%s.in", dev->data.file.path) < 0)) { + virReportOOMError(); + goto done; + } + if ((SELinuxRestoreSecurityFileLabel(out) < 0) || + (SELinuxRestoreSecurityFileLabel(in) < 0)) + goto done; + ret = 0; + break; + + default: + ret = 0; + break; + } + +done: + VIR_FREE(in); + VIR_FREE(out); + return ret; +} + + +static int +SELinuxRestoreSecurityChardevCallback(virDomainDefPtr def ATTRIBUTE_UNUSED, + virDomainChrDefPtr dev, + void *opaque) +{ + virDomainObjPtr vm = opaque; + + return SELinuxRestoreSecurityChardevLabel(vm, dev); +} + + static int SELinuxRestoreSecurityAllLabel(virDomainObjPtr vm, int migrated ATTRIBUTE_UNUSED) @@ -652,6 +747,12 @@ SELinuxRestoreSecurityAllLabel(virDomainObjPtr vm, rc = -1; } + if (virDomainChrDefForeach(vm->def, + false, + SELinuxRestoreSecurityChardevCallback, + vm) < 0) + rc = -1; + if (vm->def->os.kernel && SELinuxRestoreSecurityFileLabel(vm->def->os.kernel) < 0) rc = -1; @@ -858,6 +959,18 @@ SELinuxClearSecuritySocketLabel(virSecurityDriverPtr drv, return 0; } + +static int +SELinuxSetSecurityChardevCallback(virDomainDefPtr def ATTRIBUTE_UNUSED, + virDomainChrDefPtr dev, + void *opaque) +{ + virDomainObjPtr vm = opaque; + + return SELinuxSetSecurityChardevLabel(vm, dev); +} + + static int SELinuxSetSecurityAllLabel(virDomainObjPtr vm, const char *stdin_path ATTRIBUTE_UNUSED) { @@ -882,6 +995,12 @@ SELinuxSetSecurityAllLabel(virDomainObjPtr vm, const char *stdin_path ATTRIBUTE_ return -1; } + if (virDomainChrDefForeach(vm->def, + true, + SELinuxSetSecurityChardevCallback, + vm) < 0) + return -1; + if (vm->def->os.kernel && SELinuxSetFilecon(vm->def->os.kernel, default_content_context) < 0) return -1; diff --git a/src/util/cgroup.c b/src/util/cgroup.c index 35e9691..33610aa 100644 --- a/src/util/cgroup.c +++ b/src/util/cgroup.c @@ -272,7 +272,7 @@ static int virCgroupSetValueStr(virCgroupPtr group, if (rc != 0) return rc; - VIR_DEBUG("Set value %s", keypath); + VIR_DEBUG("Set value '%s' to '%s'", keypath, value); rc = virFileWriteStr(keypath, value); if (rc < 0) { DEBUG("Failed to write value '%s': %m", value); -- 1.6.6.1 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list