mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-24 14:45:24 +00:00
Set labelling for character devices in security drivers
When configuring serial, parallel, console or channel devices with a file, dev or pipe backend type, it is necessary 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 labeling for character devices * src/qemu/qemu_driver.c: Add character devices to cgroup ACL
This commit is contained in:
parent
bf1f3f7a36
commit
2bad82f71e
@ -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
|
static void
|
||||||
qemudReattachManagedDevice(pciDevice *dev)
|
qemudReattachManagedDevice(pciDevice *dev)
|
||||||
{
|
{
|
||||||
@ -3035,7 +3057,7 @@ static int qemuSetupDiskCgroup(virCgroupPtr cgroup,
|
|||||||
virStorageFileMetadata meta;
|
virStorageFileMetadata meta;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
VIR_DEBUG("Process path %s for disk", path);
|
VIR_DEBUG("Process path '%s' for disk", path);
|
||||||
rc = virCgroupAllowDevicePath(cgroup, path);
|
rc = virCgroupAllowDevicePath(cgroup, path);
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
/* Get this for non-block devices */
|
/* Get this for non-block devices */
|
||||||
@ -3085,7 +3107,7 @@ static int qemuTeardownDiskCgroup(virCgroupPtr cgroup,
|
|||||||
virStorageFileMetadata meta;
|
virStorageFileMetadata meta;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
VIR_DEBUG("Process path %s for disk", path);
|
VIR_DEBUG("Process path '%s' for disk", path);
|
||||||
rc = virCgroupDenyDevicePath(cgroup, path);
|
rc = virCgroupDenyDevicePath(cgroup, path);
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
/* Get this for non-block devices */
|
/* Get this for non-block devices */
|
||||||
@ -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,
|
static int qemuSetupCgroup(struct qemud_driver *driver,
|
||||||
virDomainObjPtr vm)
|
virDomainObjPtr vm)
|
||||||
{
|
{
|
||||||
@ -3191,6 +3237,12 @@ static int qemuSetupCgroup(struct qemud_driver *driver,
|
|||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (virDomainChrDefForeach(vm->def,
|
||||||
|
true,
|
||||||
|
qemuSetupChardevCgroup,
|
||||||
|
cgroup) < 0)
|
||||||
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
done:
|
done:
|
||||||
@ -3364,6 +3416,13 @@ static int qemudStartVMDaemon(virConnectPtr conn,
|
|||||||
if (qemuPrepareHostDevices(driver, vm->def) < 0)
|
if (qemuPrepareHostDevices(driver, vm->def) < 0)
|
||||||
goto cleanup;
|
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,
|
/* If you are using a SecurityDriver with dynamic labelling,
|
||||||
then generate a security label for isolation */
|
then generate a security label for isolation */
|
||||||
DEBUG0("Generating domain security label (if required)");
|
DEBUG0("Generating domain security label (if required)");
|
||||||
|
@ -327,6 +327,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
|
static int
|
||||||
qemuSecurityDACRestoreSecurityAllLabel(virDomainObjPtr vm,
|
qemuSecurityDACRestoreSecurityAllLabel(virDomainObjPtr vm,
|
||||||
int migrated)
|
int migrated)
|
||||||
@ -352,6 +446,12 @@ qemuSecurityDACRestoreSecurityAllLabel(virDomainObjPtr vm,
|
|||||||
rc = -1;
|
rc = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (virDomainChrDefForeach(vm->def,
|
||||||
|
false,
|
||||||
|
qemuSecurityDACRestoreChardevCallback,
|
||||||
|
vm) < 0)
|
||||||
|
rc = -1;
|
||||||
|
|
||||||
if (vm->def->os.kernel &&
|
if (vm->def->os.kernel &&
|
||||||
qemuSecurityDACRestoreSecurityFileLabel(vm->def->os.kernel) < 0)
|
qemuSecurityDACRestoreSecurityFileLabel(vm->def->os.kernel) < 0)
|
||||||
rc = -1;
|
rc = -1;
|
||||||
@ -364,6 +464,17 @@ qemuSecurityDACRestoreSecurityAllLabel(virDomainObjPtr vm,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
qemuSecurityDACSetChardevCallback(virDomainDefPtr def ATTRIBUTE_UNUSED,
|
||||||
|
virDomainChrDefPtr dev,
|
||||||
|
void *opaque)
|
||||||
|
{
|
||||||
|
virDomainObjPtr vm = opaque;
|
||||||
|
|
||||||
|
return qemuSecurityDACSetChardevLabel(vm, dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
qemuSecurityDACSetSecurityAllLabel(virDomainObjPtr vm, const char *stdin_path ATTRIBUTE_UNUSED)
|
qemuSecurityDACSetSecurityAllLabel(virDomainObjPtr vm, const char *stdin_path ATTRIBUTE_UNUSED)
|
||||||
{
|
{
|
||||||
@ -384,6 +495,12 @@ qemuSecurityDACSetSecurityAllLabel(virDomainObjPtr vm, const char *stdin_path AT
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (virDomainChrDefForeach(vm->def,
|
||||||
|
true,
|
||||||
|
qemuSecurityDACSetChardevCallback,
|
||||||
|
vm) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
if (vm->def->os.kernel &&
|
if (vm->def->os.kernel &&
|
||||||
qemuSecurityDACSetOwnership(vm->def->os.kernel,
|
qemuSecurityDACSetOwnership(vm->def->os.kernel,
|
||||||
driver->user,
|
driver->user,
|
||||||
|
@ -628,6 +628,101 @@ done:
|
|||||||
return ret;
|
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
|
static int
|
||||||
SELinuxRestoreSecurityAllLabel(virDomainObjPtr vm,
|
SELinuxRestoreSecurityAllLabel(virDomainObjPtr vm,
|
||||||
int migrated ATTRIBUTE_UNUSED)
|
int migrated ATTRIBUTE_UNUSED)
|
||||||
@ -652,6 +747,12 @@ SELinuxRestoreSecurityAllLabel(virDomainObjPtr vm,
|
|||||||
rc = -1;
|
rc = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (virDomainChrDefForeach(vm->def,
|
||||||
|
false,
|
||||||
|
SELinuxRestoreSecurityChardevCallback,
|
||||||
|
vm) < 0)
|
||||||
|
rc = -1;
|
||||||
|
|
||||||
if (vm->def->os.kernel &&
|
if (vm->def->os.kernel &&
|
||||||
SELinuxRestoreSecurityFileLabel(vm->def->os.kernel) < 0)
|
SELinuxRestoreSecurityFileLabel(vm->def->os.kernel) < 0)
|
||||||
rc = -1;
|
rc = -1;
|
||||||
@ -858,6 +959,18 @@ SELinuxClearSecuritySocketLabel(virSecurityDriverPtr drv,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
SELinuxSetSecurityChardevCallback(virDomainDefPtr def ATTRIBUTE_UNUSED,
|
||||||
|
virDomainChrDefPtr dev,
|
||||||
|
void *opaque)
|
||||||
|
{
|
||||||
|
virDomainObjPtr vm = opaque;
|
||||||
|
|
||||||
|
return SELinuxSetSecurityChardevLabel(vm, dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
SELinuxSetSecurityAllLabel(virDomainObjPtr vm, const char *stdin_path ATTRIBUTE_UNUSED)
|
SELinuxSetSecurityAllLabel(virDomainObjPtr vm, const char *stdin_path ATTRIBUTE_UNUSED)
|
||||||
{
|
{
|
||||||
@ -882,6 +995,12 @@ SELinuxSetSecurityAllLabel(virDomainObjPtr vm, const char *stdin_path ATTRIBUTE_
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (virDomainChrDefForeach(vm->def,
|
||||||
|
true,
|
||||||
|
SELinuxSetSecurityChardevCallback,
|
||||||
|
vm) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
if (vm->def->os.kernel &&
|
if (vm->def->os.kernel &&
|
||||||
SELinuxSetFilecon(vm->def->os.kernel, default_content_context) < 0)
|
SELinuxSetFilecon(vm->def->os.kernel, default_content_context) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -274,7 +274,7 @@ static int virCgroupSetValueStr(virCgroupPtr group,
|
|||||||
if (rc != 0)
|
if (rc != 0)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
VIR_DEBUG("Set value %s", keypath);
|
VIR_DEBUG("Set value '%s' to '%s'", keypath, value);
|
||||||
rc = virFileWriteStr(keypath, value);
|
rc = virFileWriteStr(keypath, value);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
DEBUG("Failed to write value '%s': %m", value);
|
DEBUG("Failed to write value '%s': %m", value);
|
||||||
|
Loading…
Reference in New Issue
Block a user