From 95ea6a38bd9a3ca8393c7d738df8bab0ca554439 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Wed, 12 Dec 2012 11:47:19 +0000 Subject: [PATCH] Support custom 'svirt_tcg_t' context for TCG based guests The current SELinux policy only works for KVM guests, since TCG requires the 'execmem' privilege. There is a 'virt_use_execmem' boolean to turn this on globally, but that is unpleasant for users. This changes libvirt to automatically use a new 'svirt_tcg_t' context for TCG based guests. This obsoletes the previous boolean tunable and makes things 'just work(tm)' Since we can't assume we run with new enough policy, I also make us log a warning message (once only) if we find the policy lacks support. In this case we fallback to the normal label and expect users to set the boolean tunable Signed-off-by: Daniel P. Berrange (cherry picked from commit 77d3a8097480e388f1ce3129fe530f235b05f93b) --- src/security/security_selinux.c | 48 ++++++++++++++++++++++++++++++--- 1 file changed, 44 insertions(+), 4 deletions(-) diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c index 272026623e..b9f5a7b81b 100644 --- a/src/security/security_selinux.c +++ b/src/security/security_selinux.c @@ -58,6 +58,7 @@ typedef virSecuritySELinuxCallbackData *virSecuritySELinuxCallbackDataPtr; struct _virSecuritySELinuxData { char *domain_context; + char *alt_domain_context; char *file_context; char *content_context; virHashTablePtr mcs; @@ -475,8 +476,23 @@ virSecuritySELinuxQEMUInitialize(virSecurityManagerPtr mgr) } ptr = strchrnul(data->domain_context, '\n'); - if (ptr) + if (ptr && *ptr == '\n') { *ptr = '\0'; + ptr++; + if (*ptr != '\0') { + data->alt_domain_context = strdup(ptr); + if (!data->alt_domain_context) { + virReportOOMError(); + goto error; + } + ptr = strchrnul(data->alt_domain_context, '\n'); + if (ptr && *ptr == '\n') + *ptr = '\0'; + } + } + VIR_DEBUG("Loaded domain context '%s', alt domain context '%s'", + data->domain_context, NULLSTR(data->alt_domain_context)); + if (virFileReadAll(selinux_virtual_image_context_path(), 2*MAX_CONTEXT, &(data->file_context)) < 0) { virReportSystemError(errno, @@ -498,6 +514,9 @@ virSecuritySELinuxQEMUInitialize(virSecurityManagerPtr mgr) *ptr = '\0'; } + VIR_DEBUG("Loaded file context '%s', content context '%s'", + data->file_context, data->content_context); + if (!(data->mcs = virHashCreate(10, NULL))) goto error; @@ -508,6 +527,7 @@ error: selabel_close(data->label_handle); #endif VIR_FREE(data->domain_context); + VIR_FREE(data->alt_domain_context); VIR_FREE(data->file_context); VIR_FREE(data->content_context); virHashFree(data->mcs); @@ -538,6 +558,7 @@ virSecuritySELinuxGenSecurityLabel(virSecurityManagerPtr mgr, const char *range; virSecurityLabelDefPtr seclabel; virSecuritySELinuxDataPtr data; + const char *baselabel; if (mgr == NULL) { virReportError(VIR_ERR_INTERNAL_ERROR, @@ -600,10 +621,28 @@ virSecuritySELinuxGenSecurityLabel(virSecurityManagerPtr mgr, if (virSecuritySELinuxMCSAdd(mgr, mcs) < 0) goto cleanup; + baselabel = seclabel->baselabel; + if (!baselabel) { + if (def->virtType == VIR_DOMAIN_VIRT_QEMU) { + if (data->alt_domain_context == NULL) { + static bool warned = false; + if (!warned) { + VIR_WARN("SELinux policy does not define a domain type for QEMU TCG. " + "Guest startup may be denied due to missing 'execmem' privilege " + "unless the 'virt_use_execmem' policy boolean is enabled"); + warned = true; + } + baselabel = data->domain_context; + } else { + baselabel = data->alt_domain_context; + } + } else { + baselabel = data->domain_context; + } + } + seclabel->label = - virSecuritySELinuxGenNewContext(seclabel->baselabel ? - seclabel->baselabel : - data->domain_context, mcs, false); + virSecuritySELinuxGenNewContext(baselabel, mcs, false); if (!seclabel->label) { virReportError(VIR_ERR_INTERNAL_ERROR, _("cannot generate selinux context for %s"), mcs); @@ -758,6 +797,7 @@ virSecuritySELinuxSecurityDriverClose(virSecurityManagerPtr mgr) virHashFree(data->mcs); VIR_FREE(data->domain_context); + VIR_FREE(data->alt_domain_context); VIR_FREE(data->file_context); VIR_FREE(data->content_context);