[libvirt] [PATCH v3 1/2] security: introduce virSecurityManagerCheckAllLabel function

We do have a check for valid per-domain security model, however we still do permit an invalid security model for a domain's device (those which are specified with <source> element). This patch introduces a new function virSecurityManagerCheckAllLabel which compares user specified security model against currently registered security drivers. That being said, it also permits 'none' being specified as a device security model. Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1165485 --- src/libvirt_private.syms | 1 + src/lxc/lxc_process.c | 3 ++ src/qemu/qemu_process.c | 6 +++ src/security/security_manager.c | 89 +++++++++++++++++++++++++++++++++++++++++ src/security/security_manager.h | 2 + 5 files changed, 101 insertions(+) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 645aef1..e98e813 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -955,6 +955,7 @@ virSecurityDriverLookup; # security/security_manager.h +virSecurityManagerCheckAllLabel; virSecurityManagerClearSocketLabel; virSecurityManagerGenLabel; virSecurityManagerGetBaseLabel; diff --git a/src/lxc/lxc_process.c b/src/lxc/lxc_process.c index 19ea7f3..52b7f41 100644 --- a/src/lxc/lxc_process.c +++ b/src/lxc/lxc_process.c @@ -1135,6 +1135,9 @@ int virLXCProcessStart(virConnectPtr conn, vm->def->seclabels[0]->type == VIR_DOMAIN_SECLABEL_DEFAULT) vm->def->seclabels[0]->type = VIR_DOMAIN_SECLABEL_NONE; + if (virSecurityManagerCheckAllLabel(driver->securityManager, vm->def) < 0) + goto cleanup; + if (virSecurityManagerGenLabel(driver->securityManager, vm->def) < 0) { virDomainAuditSecurityLabel(vm, false); goto cleanup; diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 43a64a1..1d4e957 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -4488,6 +4488,10 @@ int qemuProcessStart(virConnectPtr conn, NULL) < 0) goto cleanup; + VIR_DEBUG("Checking domain and device security labels"); + if (virSecurityManagerCheckAllLabel(driver->securityManager, vm->def) < 0) + goto cleanup; + /* If you are using a SecurityDriver with dynamic labelling, then generate a security label for isolation */ VIR_DEBUG("Generating domain security label (if required)"); @@ -5488,6 +5492,8 @@ int qemuProcessAttach(virConnectPtr conn ATTRIBUTE_UNUSED, } } + if (virSecurityManagerCheckAllLabel(driver->securityManager, vm->def) < 0) + goto error; if (virSecurityManagerGenLabel(driver->securityManager, vm->def) < 0) goto error; diff --git a/src/security/security_manager.c b/src/security/security_manager.c index 302f54d..68ed85b 100644 --- a/src/security/security_manager.c +++ b/src/security/security_manager.c @@ -703,6 +703,95 @@ virSecurityManagerReleaseLabel(virSecurityManagerPtr mgr, } +static int virSecurityManagerCheckSecurityModel(char *secmodel, + void *opaque) +{ + size_t i; + virSecurityManagerPtr mgr = opaque; + virSecurityManagerPtr *sec_managers = NULL; + + if ((sec_managers = virSecurityManagerGetNested(mgr)) == NULL) + return -1; + + if (STREQ_NULLABLE(secmodel, "none")) + return 0; + + for (i = 0; sec_managers[i]; i++) { + if (STREQ_NULLABLE(secmodel, + sec_managers[i]->drv->name)) { + return 0; + } + } + + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("Unable to find security driver for model %s"), + secmodel); + return -1; +} + + +static int +virSecurityManagerCheckSecurityDiskLabel(virDomainDiskDefPtr disk, + void *opaque) +{ + size_t i; + + for (i = 0; i < disk->src->nseclabels; i++) { + if (virSecurityManagerCheckSecurityModel(disk->src->seclabels[i]->model, + opaque) < 0) + return -1; + } + + return 0; +} + + +static int +virSecurityManagerCheckSecurityChardevLabel(virDomainChrDefPtr dev, + void *opaque) +{ + size_t i; + + for (i = 0; i < dev->nseclabels; i++) { + if (virSecurityManagerCheckSecurityModel(dev->seclabels[i]->model, + opaque) < 0) + return -1; + } + + return 0; +} + + +static int +virSecurityManagerCheckSecurityChardevCallback(virDomainDefPtr def ATTRIBUTE_UNUSED, + virDomainChrDefPtr dev, + void *opaque) +{ + return virSecurityManagerCheckSecurityChardevLabel(dev, opaque); +} + + +int virSecurityManagerCheckAllLabel(virSecurityManagerPtr mgr, + virDomainDefPtr vm) +{ + size_t i; + + for (i = 0; i < vm->ndisks; i++) { + if (virSecurityManagerCheckSecurityDiskLabel(vm->disks[i], + mgr) < 0) + return -1; + } + + if (virDomainChrDefForeach(vm, + true, + virSecurityManagerCheckSecurityChardevCallback, + mgr) < 0) + return -1; + + return 0; +} + + int virSecurityManagerSetAllLabel(virSecurityManagerPtr mgr, virDomainDefPtr vm, diff --git a/src/security/security_manager.h b/src/security/security_manager.h index 156f882..13468db 100644 --- a/src/security/security_manager.h +++ b/src/security/security_manager.h @@ -111,6 +111,8 @@ int virSecurityManagerReserveLabel(virSecurityManagerPtr mgr, pid_t pid); int virSecurityManagerReleaseLabel(virSecurityManagerPtr mgr, virDomainDefPtr sec); +int virSecurityManagerCheckAllLabel(virSecurityManagerPtr mgr, + virDomainDefPtr sec); int virSecurityManagerSetAllLabel(virSecurityManagerPtr mgr, virDomainDefPtr sec, const char *stdin_path); -- 1.9.3

if (mgr == NULL || mgr->drv == NULL) return ret; This check isn't really necessary, security manager cannot be a NULL pointer as it is either selinux (by default) or 'none', if no other driver is set in the config. Even with no config file driver name yields 'none'. The other hunk checks for domain's security model validity, but we should also check devices' security model as well, therefore this hunk is moved into a separate function which is called by virSecurityManagerCheckAllLabel that checks both the domain's security model and devices' security model. https://bugzilla.redhat.com/show_bug.cgi?id=1165485 --- src/security/security_manager.c | 41 ++++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/src/security/security_manager.c b/src/security/security_manager.c index 68ed85b..68d2279 100644 --- a/src/security/security_manager.c +++ b/src/security/security_manager.c @@ -576,33 +576,15 @@ virSecurityManagerGenLabel(virSecurityManagerPtr mgr, virDomainDefPtr vm) { int ret = -1; - size_t i, j; + size_t i; virSecurityManagerPtr* sec_managers = NULL; virSecurityLabelDefPtr seclabel; bool generated = false; - if (mgr == NULL || mgr->drv == NULL) - return ret; - if ((sec_managers = virSecurityManagerGetNested(mgr)) == NULL) return ret; virObjectLock(mgr); - for (i = 0; i < vm->nseclabels; i++) { - if (!vm->seclabels[i]->model) - continue; - - for (j = 0; sec_managers[j]; j++) - if (STREQ(vm->seclabels[i]->model, sec_managers[j]->drv->name)) - break; - - if (!sec_managers[j]) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, - _("Unable to find security driver for label %s"), - vm->seclabels[i]->model); - goto cleanup; - } - } for (i = 0; sec_managers[i]; i++) { generated = false; @@ -731,6 +713,22 @@ static int virSecurityManagerCheckSecurityModel(char *secmodel, static int +virSecurityManagerCheckSecurityDomainLabel(virDomainDefPtr def, + void *opaque) +{ + size_t i; + + for (i = 0; i < def->nseclabels; i++) { + if (virSecurityManagerCheckSecurityModel(def->seclabels[i]->model, + opaque) < 0) + return -1; + } + + return 0; +} + + +static int virSecurityManagerCheckSecurityDiskLabel(virDomainDiskDefPtr disk, void *opaque) { @@ -776,6 +774,11 @@ int virSecurityManagerCheckAllLabel(virSecurityManagerPtr mgr, { size_t i; + /* first check per-domain seclabels */ + if (virSecurityManagerCheckSecurityDomainLabel(vm, mgr) < 0) + return -1; + + /* second check per-device seclabels */ for (i = 0; i < vm->ndisks; i++) { if (virSecurityManagerCheckSecurityDiskLabel(vm->disks[i], mgr) < 0) -- 1.9.3

On Thu, Feb 12, 2015 at 06:32:41PM +0100, Erik Skultety wrote:
if (mgr == NULL || mgr->drv == NULL) return ret;
This check isn't really necessary, security manager cannot be a NULL pointer as it is either selinux (by default) or 'none', if no other driver is set in the config. Even with no config file driver name yields 'none'.
The other hunk checks for domain's security model validity, but we should also check devices' security model as well, therefore this hunk is moved into a separate function which is called by virSecurityManagerCheckAllLabel that checks both the domain's security model and devices' security model.
https://bugzilla.redhat.com/show_bug.cgi?id=1165485 --- src/security/security_manager.c | 41 ++++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 19 deletions(-)
ACK
@@ -731,6 +713,22 @@ static int virSecurityManagerCheckSecurityModel(char *secmodel,
static int +virSecurityManagerCheckSecurityDomainLabel(virDomainDefPtr def, + void *opaque)
Same comments as for v1 regarding the use of void and the repeating extra word.
@@ -776,6 +774,11 @@ int virSecurityManagerCheckAllLabel(virSecurityManagerPtr mgr, { size_t i;
+ /* first check per-domain seclabels */
These comments don't seem very helpful - a function named CheckDomainLabel should do exactly that. I fixed the nits and pushed the patch. Jan

On Thu, Feb 12, 2015 at 06:32:40PM +0100, Erik Skultety wrote:
We do have a check for valid per-domain security model, however we still do permit an invalid security model for a domain's device (those which are specified with <source> element). This patch introduces a new function virSecurityManagerCheckAllLabel which compares user specified security model against currently registered security drivers. That being said, it also permits 'none' being specified as a device security model.
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1165485 --- src/libvirt_private.syms | 1 + src/lxc/lxc_process.c | 3 ++ src/qemu/qemu_process.c | 6 +++ src/security/security_manager.c | 89 +++++++++++++++++++++++++++++++++++++++++ src/security/security_manager.h | 2 + 5 files changed, 101 insertions(+)
ACK
+static int virSecurityManagerCheckSecurityModel(char *secmodel, + void *opaque)
Only callbacks should use void *opaque. The redundant 'Security' occurs twice in the function names. I fixed the parameter types, and removed the extra word to save some screen space and pushed the patch. Jan
participants (2)
-
Erik Skultety
-
Ján Tomko