[libvirt] Per-guest configurable user/group for QEMU processes

Hi, This set of patches updates the libvirt's security driver mechanism to support per-guest configurable user and group for QEMU processes running together with other security drivers, such as SELinux and AppArmor. This patches implement the changes discussed in the following thread: https://www.redhat.com/archives/libvir-list/2012-February/msg00990.html Regards, Marcelo Cerri

--- src/conf/capabilities.c | 17 ++- src/conf/capabilities.h | 6 +- src/conf/domain_audit.c | 14 ++- src/conf/domain_conf.c | 310 +++++++++++++++++++++++++++++++++++------------ src/conf/domain_conf.h | 18 +++- 5 files changed, 272 insertions(+), 93 deletions(-) diff --git a/src/conf/capabilities.c b/src/conf/capabilities.c index 542bf03..7e786c5 100644 --- a/src/conf/capabilities.c +++ b/src/conf/capabilities.c @@ -181,8 +181,13 @@ virCapabilitiesFree(virCapsPtr caps) { VIR_FREE(caps->host.migrateTrans); VIR_FREE(caps->host.arch); - VIR_FREE(caps->host.secModel.model); - VIR_FREE(caps->host.secModel.doi); + + for (i = 0; i < caps->host.nsecModels; i++) { + VIR_FREE(caps->host.secModels[i].model); + VIR_FREE(caps->host.secModels[i].doi); + } + VIR_FREE(caps->host.secModels); + virCPUDefFree(caps->host.cpu); VIR_FREE(caps); @@ -767,10 +772,12 @@ virCapabilitiesFormatXML(virCapsPtr caps) virBufferAddLit(&xml, " </topology>\n"); } - if (caps->host.secModel.model) { + for (i = 0; i < caps->host.nsecModels; i++) { virBufferAddLit(&xml, " <secmodel>\n"); - virBufferAsprintf(&xml, " <model>%s</model>\n", caps->host.secModel.model); - virBufferAsprintf(&xml, " <doi>%s</doi>\n", caps->host.secModel.doi); + virBufferAsprintf(&xml, " <model>%s</model>\n", + caps->host.secModels[i].model); + virBufferAsprintf(&xml, " <doi>%s</doi>\n", + caps->host.secModels[i].doi); virBufferAddLit(&xml, " </secmodel>\n"); } diff --git a/src/conf/capabilities.h b/src/conf/capabilities.h index 421030d..9a0092d 100644 --- a/src/conf/capabilities.h +++ b/src/conf/capabilities.h @@ -93,6 +93,7 @@ struct _virCapsHostNUMACell { }; typedef struct _virCapsHostSecModel virCapsHostSecModel; +typedef virCapsHostSecModel *virCapsHostSecModelPtr; struct _virCapsHostSecModel { char *model; char *doi; @@ -116,7 +117,10 @@ struct _virCapsHost { size_t nnumaCell; size_t nnumaCell_max; virCapsHostNUMACellPtr *numaCell; - virCapsHostSecModel secModel; + + size_t nsecModels; + virCapsHostSecModelPtr secModels; + virCPUDefPtr cpu; unsigned char host_uuid[VIR_UUID_BUFLEN]; }; diff --git a/src/conf/domain_audit.c b/src/conf/domain_audit.c index 653657b..ac296d5 100644 --- a/src/conf/domain_audit.c +++ b/src/conf/domain_audit.c @@ -619,6 +619,7 @@ virDomainAuditSecurityLabel(virDomainObjPtr vm, bool success) char uuidstr[VIR_UUID_STRING_BUFLEN]; char *vmname; const char *virt; + int i; virUUIDFormat(vm->def->uuid, uuidstr); if (!(vmname = virAuditEncode("vm", vm->def->name))) { @@ -631,11 +632,14 @@ virDomainAuditSecurityLabel(virDomainObjPtr vm, bool success) virt = "?"; } - VIR_AUDIT(VIR_AUDIT_RECORD_MACHINE_ID, success, - "virt=%s %s uuid=%s vm-ctx=%s img-ctx=%s", - virt, vmname, uuidstr, - VIR_AUDIT_STR(vm->def->seclabel.label), - VIR_AUDIT_STR(vm->def->seclabel.imagelabel)); + for (i = 0; i < vm->def->nseclabels; i++) { + VIR_AUDIT(VIR_AUDIT_RECORD_MACHINE_ID, success, + "virt=%s %s uuid=%s vm-ctx=%s img-ctx=%s model=%s", + virt, vmname, uuidstr, + VIR_AUDIT_STR(vm->def->seclabels[i]->label), + VIR_AUDIT_STR(vm->def->seclabels[i]->imagelabel), + VIR_AUDIT_STR(vm->def->seclabels[i]->model)); + } VIR_FREE(vmname); } diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 9def71d..91ffb6f 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -852,12 +852,13 @@ virDomainGraphicsListenDefClear(virDomainGraphicsListenDefPtr def) } static void -virSecurityLabelDefClear(virSecurityLabelDefPtr def) +virSecurityLabelDefFree(virSecurityLabelDefPtr def) { VIR_FREE(def->model); VIR_FREE(def->label); VIR_FREE(def->imagelabel); VIR_FREE(def->baselabel); + VIR_FREE(def); } @@ -866,6 +867,7 @@ virSecurityDeviceLabelDefFree(virSecurityDeviceLabelDefPtr def) { if (!def) return; + VIR_FREE(def->model); VIR_FREE(def->label); VIR_FREE(def); } @@ -951,7 +953,9 @@ void virDomainDiskDefFree(virDomainDiskDefPtr def) virStorageEncryptionFree(def->encryption); virDomainDeviceInfoClear(&def->info); - virSecurityDeviceLabelDefFree(def->seclabel); + for (i = 0; i < def->nseclabels; i++) + virSecurityDeviceLabelDefFree(def->seclabels[i]); + VIR_FREE(def->seclabels); for (i = 0 ; i < def->nhosts ; i++) virDomainDiskHostDefFree(&def->hosts[i]); @@ -1617,7 +1621,9 @@ void virDomainDefFree(virDomainDefPtr def) virDomainMemballoonDefFree(def->memballoon); - virSecurityLabelDefClear(&def->seclabel); + for (i = 0; i < def->nseclabels; i++) + virSecurityLabelDefFree(def->seclabels[i]); + VIR_FREE(def->seclabels); virCPUDefFree(def->cpu); @@ -3071,10 +3077,7 @@ virSecurityLabelDefParseXML(virSecurityLabelDefPtr def, { char *p; - if (virXPathNode("./seclabel", ctxt) == NULL) - return 0; - - p = virXPathStringLimit("string(./seclabel/@type)", + p = virXPathStringLimit("string(./@type)", VIR_SECURITY_LABEL_BUFLEN-1, ctxt); if (p == NULL) { def->type = VIR_DOMAIN_SECLABEL_DYNAMIC; @@ -3088,7 +3091,7 @@ virSecurityLabelDefParseXML(virSecurityLabelDefPtr def, } } - p = virXPathStringLimit("string(./seclabel/@relabel)", + p = virXPathStringLimit("string(./@relabel)", VIR_SECURITY_LABEL_BUFLEN-1, ctxt); if (p != NULL) { if (STREQ(p, "yes")) { @@ -3105,13 +3108,15 @@ virSecurityLabelDefParseXML(virSecurityLabelDefPtr def, if (def->type == VIR_DOMAIN_SECLABEL_DYNAMIC && def->norelabel) { virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED, - "%s", _("dynamic label type must use resource relabeling")); + "%s", _("dynamic label type must use " + "resource relabeling")); goto error; } if (def->type == VIR_DOMAIN_SECLABEL_NONE && !def->norelabel) { virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED, - "%s", _("resource relabeling is not compatible with 'none' label type")); + "%s", _("resource relabeling is not " + "compatible with 'none' label type")); goto error; } } else { @@ -3128,7 +3133,7 @@ virSecurityLabelDefParseXML(virSecurityLabelDefPtr def, if (def->type == VIR_DOMAIN_SECLABEL_STATIC || (!(flags & VIR_DOMAIN_XML_INACTIVE) && def->type != VIR_DOMAIN_SECLABEL_NONE)) { - p = virXPathStringLimit("string(./seclabel/label[1])", + p = virXPathStringLimit("string(./label[1])", VIR_SECURITY_LABEL_BUFLEN-1, ctxt); if (p == NULL) { virDomainReportError(VIR_ERR_XML_ERROR, @@ -3143,7 +3148,7 @@ virSecurityLabelDefParseXML(virSecurityLabelDefPtr def, if (!def->norelabel && (!(flags & VIR_DOMAIN_XML_INACTIVE) && def->type != VIR_DOMAIN_SECLABEL_NONE)) { - p = virXPathStringLimit("string(./seclabel/imagelabel[1])", + p = virXPathStringLimit("string(./imagelabel[1])", VIR_SECURITY_LABEL_BUFLEN-1, ctxt); if (p == NULL) { virDomainReportError(VIR_ERR_XML_ERROR, @@ -3155,93 +3160,166 @@ virSecurityLabelDefParseXML(virSecurityLabelDefPtr def, /* Only parse baselabel for dynamic label type */ if (def->type == VIR_DOMAIN_SECLABEL_DYNAMIC) { - p = virXPathStringLimit("string(./seclabel/baselabel[1])", + p = virXPathStringLimit("string(./baselabel[1])", VIR_SECURITY_LABEL_BUFLEN-1, ctxt); def->baselabel = p; } - /* Only parse model, if static labelling, or a base - * label is set, or doing active XML - */ - if (def->type == VIR_DOMAIN_SECLABEL_STATIC || - def->baselabel || - (!(flags & VIR_DOMAIN_XML_INACTIVE) && - def->type != VIR_DOMAIN_SECLABEL_NONE)) { - p = virXPathStringLimit("string(./seclabel/@model)", - VIR_SECURITY_MODEL_BUFLEN-1, ctxt); - if (p == NULL) { - virDomainReportError(VIR_ERR_XML_ERROR, - "%s", _("missing security model")); - goto error; - } - def->model = p; + /* TODO: check */ + /* Always parse model */ + p = virXPathStringLimit("string(./@model)", + VIR_SECURITY_MODEL_BUFLEN-1, ctxt); + if (p == NULL) { + virDomainReportError(VIR_ERR_XML_ERROR, + "%s", _("missing security model")); + goto error; } + def->model = p; return 0; error: - virSecurityLabelDefClear(def); return -1; } - static int -virSecurityDeviceLabelDefParseXML(virSecurityDeviceLabelDefPtr *def, - virSecurityLabelDefPtr vmDef, - xmlXPathContextPtr ctxt) +virSecurityLabelDefsParseXML(virDomainDefPtr def, + xmlXPathContextPtr ctxt, + unsigned int flags) { - char *p; + int i, n; + xmlNodePtr *list, saved_node; - *def = NULL; + /* Check args and save context */ + if (def == NULL || ctxt == NULL) + return 0; + saved_node = ctxt->node; - if (virXPathNode("./seclabel", ctxt) == NULL) + /* Allocate a security labels based on XML */ + if ((n = virXPathNodeSet("./seclabel", ctxt, &list)) == 0) return 0; - /* Can't use overrides if top-level doesn't allow relabeling. */ - if (vmDef && vmDef->norelabel) { - virDomainReportError(VIR_ERR_XML_ERROR, "%s", - _("label overrides require relabeling to be " - "enabled at the domain level")); + if (VIR_ALLOC_N(def->seclabels, n) < 0) { + virReportOOMError(); return -1; } + for (i = 0; i < n; i++) { + if (VIR_ALLOC(def->seclabels[i]) < 0) { + virReportOOMError(); + goto error; + } + } + + /* Parse each "seclabel" tag */ + for (i = 0; i < n; i++) { + ctxt->node = list[i]; + if (virSecurityLabelDefParseXML(def->seclabels[i], ctxt, flags)) + goto error; + } + def->nseclabels = n; + ctxt->node = saved_node; + return 0; - if (VIR_ALLOC(*def) < 0) { +error: + ctxt->node = saved_node; + for (i = 0; i < n; i++) { + virSecurityLabelDefFree(def->seclabels[i]); + } + VIR_FREE(def->seclabels); + return -1; +} + +static int +virSecurityDeviceLabelDefParseXML(virDomainDiskDefPtr def, + virSecurityLabelDefPtr *vmSeclabels, + int nvmSeclabels, xmlXPathContextPtr ctxt) +{ + int n, i, j; + xmlNodePtr *list; + virSecurityLabelDefPtr vmDef = NULL; + char *model, *relabel, *label; + + if (def == NULL) + return 0; + + if ((n = virXPathNodeSet("./seclabel", ctxt, &list)) == 0) + return 0; + + def->nseclabels = n; + if (VIR_ALLOC_N(def->seclabels, n) < 0) { virReportOOMError(); return -1; } + for (i = 0; i < n; i++) { + if (VIR_ALLOC(def->seclabels[i]) < 0) { + virReportOOMError(); + goto error; + } + } - p = virXPathStringLimit("string(./seclabel/@relabel)", - VIR_SECURITY_LABEL_BUFLEN-1, ctxt); - if (p != NULL) { - if (STREQ(p, "yes")) { - (*def)->norelabel = false; - } else if (STREQ(p, "no")) { - (*def)->norelabel = true; + for (i = 0; i < n; i++) { + /* get model associated to this override */ + model = virXMLPropString(list[i], "model"); + if (model == NULL) { + // TODO primary ? + // vmDef = ? } else { - virDomainReportError(VIR_ERR_XML_ERROR, - _("invalid security relabel value %s"), p); - VIR_FREE(p); - VIR_FREE(*def); - return -1; + /* find the security label that it's being overrided */ + for (j = 0; j < nvmSeclabels; j++) { + if (STREQ(vmSeclabels[j]->model, model)) { + vmDef = vmSeclabels[j]; + break; + } + } + VIR_FREE(model); } - VIR_FREE(p); - } else { - (*def)->norelabel = false; - } - p = virXPathStringLimit("string(./seclabel/label[1])", - VIR_SECURITY_LABEL_BUFLEN-1, ctxt); - (*def)->label = p; + /* Can't use overrides if top-level doesn't allow relabeling. */ + if (vmDef && vmDef->norelabel) { + virDomainReportError(VIR_ERR_XML_ERROR, "%s", + _("label overrides require relabeling to be " + "enabled at the domain level")); + goto error; + } - if ((*def)->label && (*def)->norelabel) { - virDomainReportError(VIR_ERR_XML_ERROR, - _("Cannot specify a label if relabelling is turned off")); - VIR_FREE((*def)->label); - VIR_FREE(*def); - return -1; - } + relabel = virXMLPropString(list[i], "relabel"); + if (relabel != NULL) { + if (STREQ(relabel, "yes")) { + def->seclabels[i]->norelabel = false; + } else if (STREQ(relabel, "no")) { + def->seclabels[i]->norelabel = true; + } else { + virDomainReportError(VIR_ERR_XML_ERROR, + _("invalid security relabel value %s"), + relabel); + VIR_FREE(relabel); + goto error; + } + VIR_FREE(relabel); + } else { + def->seclabels[i]->norelabel = false; + } + ctxt->node = list[i]; + label = virXPathStringLimit("string(./seclabel/label[1])", + VIR_SECURITY_LABEL_BUFLEN-1, ctxt); + def->seclabels[i]->label = label; + + if (label && def->seclabels[i]->norelabel) { + virDomainReportError(VIR_ERR_XML_ERROR, + _("Cannot specify a label if relabelling is " + "turned off")); + goto error; + } + } return 0; + +error: + for (i = 0; i < n; i++) { + virSecurityDeviceLabelDefFree(def->seclabels[i]); + } + VIR_FREE(def->seclabels); + return -1; } @@ -3325,7 +3403,8 @@ virDomainDiskDefParseXML(virCapsPtr caps, xmlNodePtr node, xmlXPathContextPtr ctxt, virBitmapPtr bootMap, - virSecurityLabelDefPtr vmSeclabel, + virSecurityLabelDefPtr* vmSeclabels, + int nvmSeclabels, unsigned int flags) { virDomainDiskDefPtr def; @@ -3663,9 +3742,8 @@ virDomainDiskDefParseXML(virCapsPtr caps, if (sourceNode) { xmlNodePtr saved_node = ctxt->node; ctxt->node = sourceNode; - if (virSecurityDeviceLabelDefParseXML(&def->seclabel, - vmSeclabel, - ctxt) < 0) + if (virSecurityDeviceLabelDefParseXML(def, vmSeclabels, + nvmSeclabels, ctxt) < 0) goto error; ctxt->node = saved_node; } @@ -7011,7 +7089,9 @@ virDomainDeviceDefPtr virDomainDeviceDefParse(virCapsPtr caps, if (xmlStrEqual(node->name, BAD_CAST "disk")) { dev->type = VIR_DOMAIN_DEVICE_DISK; if (!(dev->data.disk = virDomainDiskDefParseXML(caps, node, ctxt, - NULL, &def->seclabel, flags))) + NULL, def->seclabels, + def->nseclabels, + flags))) goto error; } else if (xmlStrEqual(node->name, BAD_CAST "lease")) { dev->type = VIR_DOMAIN_DEVICE_LEASE; @@ -7939,7 +8019,7 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps, /* analysis of security label, done early even though we format it * late, so devices can refer to this for defaults */ - if (virSecurityLabelDefParseXML(&def->seclabel, ctxt, flags) == -1) + if (virSecurityLabelDefsParseXML(def, ctxt, flags) == -1) goto error; /* Extract domain memory */ @@ -8538,7 +8618,8 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps, nodes[i], ctxt, bootMap, - &def->seclabel, + def->seclabels, + def->nseclabels, flags); if (!disk) goto error; @@ -10843,6 +10924,8 @@ virSecurityLabelDefFormat(virBufferPtr buf, virSecurityLabelDefPtr def) virBufferAsprintf(buf, " relabel='%s'", def->norelabel ? "no" : "yes"); +VIR_DEBUG("FMT %s: %s %s %s", def->model, def->label, def->imagelabel, def->baselabel); // TODO remove + if (def->label || def->imagelabel || def->baselabel) { virBufferAddLit(buf, ">\n"); @@ -10911,6 +10994,7 @@ virDomainDiskDefFormat(virBufferPtr buf, const char *copy_on_read = virDomainVirtioEventIdxTypeToString(def->copy_on_read); const char *startupPolicy = virDomainStartupPolicyTypeToString(def->startupPolicy); + int n; char uuidstr[VIR_UUID_STRING_BUFLEN]; if (!type) { @@ -11006,10 +11090,11 @@ virDomainDiskDefFormat(virBufferPtr buf, if (def->startupPolicy) virBufferEscapeString(buf, " startupPolicy='%s'", startupPolicy); - if (def->seclabel) { + if (def->nseclabels) { virBufferAddLit(buf, ">\n"); virBufferAdjustIndent(buf, 8); - virSecurityDeviceLabelDefFormat(buf, def->seclabel); + for (n = 0; n < def->nseclabels; n++) + virSecurityDeviceLabelDefFormat(buf, def->seclabels[n]); virBufferAdjustIndent(buf, -8); virBufferAddLit(buf, " </source>\n"); } else { @@ -11019,10 +11104,11 @@ virDomainDiskDefFormat(virBufferPtr buf, case VIR_DOMAIN_DISK_TYPE_BLOCK: virBufferEscapeString(buf, " <source dev='%s'", def->src); - if (def->seclabel) { + if (def->nseclabels) { virBufferAddLit(buf, ">\n"); virBufferAdjustIndent(buf, 8); - virSecurityDeviceLabelDefFormat(buf, def->seclabel); + for (n = 0; n < def->nseclabels; n++) + virSecurityDeviceLabelDefFormat(buf, def->seclabels[n]); virBufferAdjustIndent(buf, -8); virBufferAddLit(buf, " </source>\n"); } else { @@ -13020,7 +13106,8 @@ virDomainDefFormatInternal(virDomainDefPtr def, virBufferAddLit(buf, " </devices>\n"); virBufferAdjustIndent(buf, 2); - virSecurityLabelDefFormat(buf, &def->seclabel); + for (n = 0; n < def->nseclabels; n++) + virSecurityLabelDefFormat(buf, def->seclabels[n]); virBufferAdjustIndent(buf, -2); if (def->namespaceData && def->ns.format) { @@ -15217,3 +15304,66 @@ cleanup: VIR_FREE(xmlStr); return ret; } + +virSecurityLabelDefPtr +virDomainDefGetSecurityLabelDef(virDomainDefPtr def, const char *model) +{ + int i; + + if (def == NULL || model == NULL) + return NULL; + + for (i = 0; i < def->nseclabels; i++) { + if (def->seclabels[i]->model == NULL) + continue; + if (STREQ(def->seclabels[i]->model, model)) + return def->seclabels[i]; + } + + return virDomainDefAddSecurityLabelDef(def, model); +} + +virSecurityDeviceLabelDefPtr +virDomainDiskDefGetSecurityLabelDef(virDomainDiskDefPtr def, const char *model) +{ + int i; + + if (def == NULL) + return NULL; + + for (i = 0; i < def->nseclabels; i++) { + if (STREQ(def->seclabels[i]->model, model)) + return def->seclabels[i]; + } + return NULL; +} + +virSecurityLabelDefPtr +virDomainDefAddSecurityLabelDef(virDomainDefPtr def, const char *model) +{ + virSecurityLabelDefPtr seclabel = NULL; + + if (VIR_ALLOC(seclabel) < 0) { + virReportOOMError(); + return NULL; + } + + if (model) { + seclabel->model = strdup(model); + if (seclabel->model == NULL) { + virReportOOMError(); + virSecurityLabelDefFree(seclabel); + return NULL; + } + } + + if (VIR_EXPAND_N(def->seclabels, def->nseclabels, 1) < 0) { + virReportOOMError(); + virSecurityLabelDefFree(seclabel); + return NULL; + } + def->seclabels[def->nseclabels - 1] = seclabel; + + return seclabel; +} + diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 4c56902..49a7120 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -309,6 +309,7 @@ struct _virSecurityLabelDef { typedef struct _virSecurityDeviceLabelDef virSecurityDeviceLabelDef; typedef virSecurityDeviceLabelDef *virSecurityDeviceLabelDefPtr; struct _virSecurityDeviceLabelDef { + char *model; char *label; /* image label string */ bool norelabel; }; @@ -553,7 +554,6 @@ struct _virDomainDiskDef { int device; int bus; char *src; - virSecurityDeviceLabelDefPtr seclabel; char *dst; int tray_status; int protocol; @@ -593,6 +593,9 @@ struct _virDomainDiskDef { virStorageEncryptionPtr encryption; bool rawio_specified; int rawio; /* no = 0, yes = 1 */ + + size_t nseclabels; + virSecurityDeviceLabelDefPtr *seclabels; }; @@ -1662,8 +1665,10 @@ struct _virDomainDef { int nhubs; virDomainHubDefPtr *hubs; + size_t nseclabels; + virSecurityLabelDefPtr *seclabels; + /* Only 1 */ - virSecurityLabelDef seclabel; virDomainWatchdogDefPtr watchdog; virDomainMemballoonDefPtr memballoon; virCPUDefPtr cpu; @@ -2139,6 +2144,15 @@ virDomainState virDomainObjGetState(virDomainObjPtr obj, int *reason) ATTRIBUTE_NONNULL(1); +virSecurityLabelDefPtr +virDomainDefGetSecurityLabelDef(virDomainDefPtr def, const char *model); + +virSecurityDeviceLabelDefPtr +virDomainDiskDefGetSecurityLabelDef(virDomainDiskDefPtr def, const char *model); + +virSecurityLabelDefPtr +virDomainDefAddSecurityLabelDef(virDomainDefPtr def, const char *model); + typedef const char* (*virLifecycleToStringFunc)(int type); typedef int (*virLifecycleFromStringFunc)(const char *type); -- 1.7.1

On 21.05.2012 15:39, Marcelo Cerri wrote:
--- src/conf/capabilities.c | 17 ++- src/conf/capabilities.h | 6 +- src/conf/domain_audit.c | 14 ++- src/conf/domain_conf.c | 310 +++++++++++++++++++++++++++++++++++------------ src/conf/domain_conf.h | 18 +++- 5 files changed, 272 insertions(+), 93 deletions(-)
Needs a v2. Test driver needs to be fixed: CC libvirt_driver_test_la-test_driver.lo test/test_driver.c: In function 'testBuildCapabilities': test/test_driver.c:213:15: error: 'virCapsHost' has no member named 'secModel' test/test_driver.c:214:20: error: 'virCapsHost' has no member named 'secModel' test/test_driver.c:217:15: error: 'virCapsHost' has no member named 'secModel' test/test_driver.c:218:20: error: 'virCapsHost' has no member named 'secModel'
diff --git a/src/conf/capabilities.c b/src/conf/capabilities.c index 542bf03..7e786c5 100644 --- a/src/conf/capabilities.c +++ b/src/conf/capabilities.c @@ -181,8 +181,13 @@ virCapabilitiesFree(virCapsPtr caps) { VIR_FREE(caps->host.migrateTrans);
VIR_FREE(caps->host.arch); - VIR_FREE(caps->host.secModel.model); - VIR_FREE(caps->host.secModel.doi); + + for (i = 0; i < caps->host.nsecModels; i++) { + VIR_FREE(caps->host.secModels[i].model); + VIR_FREE(caps->host.secModels[i].doi); + } + VIR_FREE(caps->host.secModels); + virCPUDefFree(caps->host.cpu);
VIR_FREE(caps); @@ -767,10 +772,12 @@ virCapabilitiesFormatXML(virCapsPtr caps) virBufferAddLit(&xml, " </topology>\n"); }
- if (caps->host.secModel.model) { + for (i = 0; i < caps->host.nsecModels; i++) { virBufferAddLit(&xml, " <secmodel>\n"); - virBufferAsprintf(&xml, " <model>%s</model>\n", caps->host.secModel.model); - virBufferAsprintf(&xml, " <doi>%s</doi>\n", caps->host.secModel.doi); + virBufferAsprintf(&xml, " <model>%s</model>\n", + caps->host.secModels[i].model); + virBufferAsprintf(&xml, " <doi>%s</doi>\n", + caps->host.secModels[i].doi); virBufferAddLit(&xml, " </secmodel>\n"); }
diff --git a/src/conf/capabilities.h b/src/conf/capabilities.h index 421030d..9a0092d 100644 --- a/src/conf/capabilities.h +++ b/src/conf/capabilities.h @@ -93,6 +93,7 @@ struct _virCapsHostNUMACell { };
typedef struct _virCapsHostSecModel virCapsHostSecModel; +typedef virCapsHostSecModel *virCapsHostSecModelPtr; struct _virCapsHostSecModel { char *model; char *doi; @@ -116,7 +117,10 @@ struct _virCapsHost { size_t nnumaCell; size_t nnumaCell_max; virCapsHostNUMACellPtr *numaCell; - virCapsHostSecModel secModel; + + size_t nsecModels; + virCapsHostSecModelPtr secModels; + virCPUDefPtr cpu; unsigned char host_uuid[VIR_UUID_BUFLEN]; }; diff --git a/src/conf/domain_audit.c b/src/conf/domain_audit.c index 653657b..ac296d5 100644 --- a/src/conf/domain_audit.c +++ b/src/conf/domain_audit.c @@ -619,6 +619,7 @@ virDomainAuditSecurityLabel(virDomainObjPtr vm, bool success) char uuidstr[VIR_UUID_STRING_BUFLEN]; char *vmname; const char *virt; + int i;
virUUIDFormat(vm->def->uuid, uuidstr); if (!(vmname = virAuditEncode("vm", vm->def->name))) { @@ -631,11 +632,14 @@ virDomainAuditSecurityLabel(virDomainObjPtr vm, bool success) virt = "?"; }
- VIR_AUDIT(VIR_AUDIT_RECORD_MACHINE_ID, success, - "virt=%s %s uuid=%s vm-ctx=%s img-ctx=%s", - virt, vmname, uuidstr, - VIR_AUDIT_STR(vm->def->seclabel.label), - VIR_AUDIT_STR(vm->def->seclabel.imagelabel)); + for (i = 0; i < vm->def->nseclabels; i++) { + VIR_AUDIT(VIR_AUDIT_RECORD_MACHINE_ID, success, + "virt=%s %s uuid=%s vm-ctx=%s img-ctx=%s model=%s", + virt, vmname, uuidstr, + VIR_AUDIT_STR(vm->def->seclabels[i]->label), + VIR_AUDIT_STR(vm->def->seclabels[i]->imagelabel), + VIR_AUDIT_STR(vm->def->seclabels[i]->model)); + }
VIR_FREE(vmname); } diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 9def71d..91ffb6f 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -852,12 +852,13 @@ virDomainGraphicsListenDefClear(virDomainGraphicsListenDefPtr def) }
static void -virSecurityLabelDefClear(virSecurityLabelDefPtr def) +virSecurityLabelDefFree(virSecurityLabelDefPtr def) { VIR_FREE(def->model); VIR_FREE(def->label); VIR_FREE(def->imagelabel); VIR_FREE(def->baselabel); + VIR_FREE(def); }
@@ -866,6 +867,7 @@ virSecurityDeviceLabelDefFree(virSecurityDeviceLabelDefPtr def) { if (!def) return; + VIR_FREE(def->model); VIR_FREE(def->label); VIR_FREE(def); } @@ -951,7 +953,9 @@ void virDomainDiskDefFree(virDomainDiskDefPtr def) virStorageEncryptionFree(def->encryption); virDomainDeviceInfoClear(&def->info);
- virSecurityDeviceLabelDefFree(def->seclabel); + for (i = 0; i < def->nseclabels; i++) + virSecurityDeviceLabelDefFree(def->seclabels[i]); + VIR_FREE(def->seclabels);
for (i = 0 ; i < def->nhosts ; i++) virDomainDiskHostDefFree(&def->hosts[i]); @@ -1617,7 +1621,9 @@ void virDomainDefFree(virDomainDefPtr def)
virDomainMemballoonDefFree(def->memballoon);
- virSecurityLabelDefClear(&def->seclabel); + for (i = 0; i < def->nseclabels; i++) + virSecurityLabelDefFree(def->seclabels[i]); + VIR_FREE(def->seclabels);
virCPUDefFree(def->cpu);
@@ -3071,10 +3077,7 @@ virSecurityLabelDefParseXML(virSecurityLabelDefPtr def, { char *p;
Since we are returning only a boolean value here (0 vs. -1) and seems the only caller pre-allocates memory for us I wonder if we can change the prototype so we are returning virSecurityLabelDefPtr instead of int and therefore allocating return variable in here instead of doing [1]
- if (virXPathNode("./seclabel", ctxt) == NULL) - return 0; - - p = virXPathStringLimit("string(./seclabel/@type)", + p = virXPathStringLimit("string(./@type)", VIR_SECURITY_LABEL_BUFLEN-1, ctxt); if (p == NULL) { def->type = VIR_DOMAIN_SECLABEL_DYNAMIC; @@ -3088,7 +3091,7 @@ virSecurityLabelDefParseXML(virSecurityLabelDefPtr def, } }
- p = virXPathStringLimit("string(./seclabel/@relabel)", + p = virXPathStringLimit("string(./@relabel)", VIR_SECURITY_LABEL_BUFLEN-1, ctxt); if (p != NULL) { if (STREQ(p, "yes")) { @@ -3105,13 +3108,15 @@ virSecurityLabelDefParseXML(virSecurityLabelDefPtr def, if (def->type == VIR_DOMAIN_SECLABEL_DYNAMIC && def->norelabel) { virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED, - "%s", _("dynamic label type must use resource relabeling")); + "%s", _("dynamic label type must use " + "resource relabeling")); goto error; } if (def->type == VIR_DOMAIN_SECLABEL_NONE && !def->norelabel) { virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED, - "%s", _("resource relabeling is not compatible with 'none' label type")); + "%s", _("resource relabeling is not " + "compatible with 'none' label type")); goto error; } } else { @@ -3128,7 +3133,7 @@ virSecurityLabelDefParseXML(virSecurityLabelDefPtr def, if (def->type == VIR_DOMAIN_SECLABEL_STATIC || (!(flags & VIR_DOMAIN_XML_INACTIVE) && def->type != VIR_DOMAIN_SECLABEL_NONE)) { - p = virXPathStringLimit("string(./seclabel/label[1])", + p = virXPathStringLimit("string(./label[1])", VIR_SECURITY_LABEL_BUFLEN-1, ctxt); if (p == NULL) { virDomainReportError(VIR_ERR_XML_ERROR, @@ -3143,7 +3148,7 @@ virSecurityLabelDefParseXML(virSecurityLabelDefPtr def, if (!def->norelabel && (!(flags & VIR_DOMAIN_XML_INACTIVE) && def->type != VIR_DOMAIN_SECLABEL_NONE)) { - p = virXPathStringLimit("string(./seclabel/imagelabel[1])", + p = virXPathStringLimit("string(./imagelabel[1])", VIR_SECURITY_LABEL_BUFLEN-1, ctxt); if (p == NULL) { virDomainReportError(VIR_ERR_XML_ERROR, @@ -3155,93 +3160,166 @@ virSecurityLabelDefParseXML(virSecurityLabelDefPtr def,
/* Only parse baselabel for dynamic label type */ if (def->type == VIR_DOMAIN_SECLABEL_DYNAMIC) { - p = virXPathStringLimit("string(./seclabel/baselabel[1])", + p = virXPathStringLimit("string(./baselabel[1])", VIR_SECURITY_LABEL_BUFLEN-1, ctxt); def->baselabel = p; }
- /* Only parse model, if static labelling, or a base - * label is set, or doing active XML - */ - if (def->type == VIR_DOMAIN_SECLABEL_STATIC || - def->baselabel || - (!(flags & VIR_DOMAIN_XML_INACTIVE) && - def->type != VIR_DOMAIN_SECLABEL_NONE)) { - p = virXPathStringLimit("string(./seclabel/@model)", - VIR_SECURITY_MODEL_BUFLEN-1, ctxt); - if (p == NULL) { - virDomainReportError(VIR_ERR_XML_ERROR, - "%s", _("missing security model")); - goto error; - } - def->model = p; + /* TODO: check */ + /* Always parse model */ + p = virXPathStringLimit("string(./@model)", + VIR_SECURITY_MODEL_BUFLEN-1, ctxt); + if (p == NULL) { + virDomainReportError(VIR_ERR_XML_ERROR, + "%s", _("missing security model")); + goto error; } + def->model = p;
return 0;
error: - virSecurityLabelDefClear(def); return -1; }
- static int -virSecurityDeviceLabelDefParseXML(virSecurityDeviceLabelDefPtr *def, - virSecurityLabelDefPtr vmDef, - xmlXPathContextPtr ctxt) +virSecurityLabelDefsParseXML(virDomainDefPtr def, + xmlXPathContextPtr ctxt, + unsigned int flags) { - char *p; + int i, n; + xmlNodePtr *list, saved_node;
- *def = NULL; + /* Check args and save context */ + if (def == NULL || ctxt == NULL) + return 0; + saved_node = ctxt->node;
- if (virXPathNode("./seclabel", ctxt) == NULL) + /* Allocate a security labels based on XML */ + if ((n = virXPathNodeSet("./seclabel", ctxt, &list)) == 0) return 0;
- /* Can't use overrides if top-level doesn't allow relabeling. */ - if (vmDef && vmDef->norelabel) { - virDomainReportError(VIR_ERR_XML_ERROR, "%s", - _("label overrides require relabeling to be " - "enabled at the domain level")); + if (VIR_ALLOC_N(def->seclabels, n) < 0) { + virReportOOMError(); return -1; } + for (i = 0; i < n; i++) { + if (VIR_ALLOC(def->seclabels[i]) < 0) { + virReportOOMError(); + goto error; + } + }
1: this ^^. On an error NULL would be returned which means changing ...
+ + /* Parse each "seclabel" tag */ + for (i = 0; i < n; i++) { + ctxt->node = list[i]; + if (virSecurityLabelDefParseXML(def->seclabels[i], ctxt, flags))
1: this condition of course.
+ goto error; + } + def->nseclabels = n; + ctxt->node = saved_node; + return 0;
- if (VIR_ALLOC(*def) < 0) { +error: + ctxt->node = saved_node; + for (i = 0; i < n; i++) { + virSecurityLabelDefFree(def->seclabels[i]); + } + VIR_FREE(def->seclabels); + return -1; +} + +static int +virSecurityDeviceLabelDefParseXML(virDomainDiskDefPtr def, + virSecurityLabelDefPtr *vmSeclabels, + int nvmSeclabels, xmlXPathContextPtr ctxt) +{ + int n, i, j; + xmlNodePtr *list; + virSecurityLabelDefPtr vmDef = NULL; + char *model, *relabel, *label; + + if (def == NULL) + return 0; + + if ((n = virXPathNodeSet("./seclabel", ctxt, &list)) == 0) + return 0; + + def->nseclabels = n; + if (VIR_ALLOC_N(def->seclabels, n) < 0) { virReportOOMError(); return -1; } + for (i = 0; i < n; i++) { + if (VIR_ALLOC(def->seclabels[i]) < 0) { + virReportOOMError(); + goto error; + } + }
- p = virXPathStringLimit("string(./seclabel/@relabel)", - VIR_SECURITY_LABEL_BUFLEN-1, ctxt); - if (p != NULL) { - if (STREQ(p, "yes")) { - (*def)->norelabel = false; - } else if (STREQ(p, "no")) { - (*def)->norelabel = true; + for (i = 0; i < n; i++) { + /* get model associated to this override */ + model = virXMLPropString(list[i], "model"); + if (model == NULL) { + // TODO primary ? + // vmDef = ? } else { - virDomainReportError(VIR_ERR_XML_ERROR, - _("invalid security relabel value %s"), p); - VIR_FREE(p); - VIR_FREE(*def); - return -1; + /* find the security label that it's being overrided */ + for (j = 0; j < nvmSeclabels; j++) { + if (STREQ(vmSeclabels[j]->model, model)) { + vmDef = vmSeclabels[j]; + break; + } + } + VIR_FREE(model); } - VIR_FREE(p); - } else { - (*def)->norelabel = false; - }
- p = virXPathStringLimit("string(./seclabel/label[1])", - VIR_SECURITY_LABEL_BUFLEN-1, ctxt); - (*def)->label = p; + /* Can't use overrides if top-level doesn't allow relabeling. */ + if (vmDef && vmDef->norelabel) { + virDomainReportError(VIR_ERR_XML_ERROR, "%s", + _("label overrides require relabeling to be " + "enabled at the domain level")); + goto error; + }
- if ((*def)->label && (*def)->norelabel) { - virDomainReportError(VIR_ERR_XML_ERROR, - _("Cannot specify a label if relabelling is turned off")); - VIR_FREE((*def)->label); - VIR_FREE(*def); - return -1; - } + relabel = virXMLPropString(list[i], "relabel"); + if (relabel != NULL) { + if (STREQ(relabel, "yes")) { + def->seclabels[i]->norelabel = false; + } else if (STREQ(relabel, "no")) { + def->seclabels[i]->norelabel = true; + } else { + virDomainReportError(VIR_ERR_XML_ERROR, + _("invalid security relabel value %s"), + relabel); + VIR_FREE(relabel); + goto error; + } + VIR_FREE(relabel); + } else { + def->seclabels[i]->norelabel = false; + }
+ ctxt->node = list[i]; + label = virXPathStringLimit("string(./seclabel/label[1])", + VIR_SECURITY_LABEL_BUFLEN-1, ctxt); + def->seclabels[i]->label = label; + + if (label && def->seclabels[i]->norelabel) { + virDomainReportError(VIR_ERR_XML_ERROR, + _("Cannot specify a label if relabelling is " + "turned off")); + goto error; + } + } return 0; + +error: + for (i = 0; i < n; i++) { + virSecurityDeviceLabelDefFree(def->seclabels[i]); + } + VIR_FREE(def->seclabels); + return -1; }
@@ -3325,7 +3403,8 @@ virDomainDiskDefParseXML(virCapsPtr caps, xmlNodePtr node, xmlXPathContextPtr ctxt, virBitmapPtr bootMap, - virSecurityLabelDefPtr vmSeclabel, + virSecurityLabelDefPtr* vmSeclabels, + int nvmSeclabels, unsigned int flags) { virDomainDiskDefPtr def; @@ -3663,9 +3742,8 @@ virDomainDiskDefParseXML(virCapsPtr caps, if (sourceNode) { xmlNodePtr saved_node = ctxt->node; ctxt->node = sourceNode; - if (virSecurityDeviceLabelDefParseXML(&def->seclabel, - vmSeclabel, - ctxt) < 0) + if (virSecurityDeviceLabelDefParseXML(def, vmSeclabels, + nvmSeclabels, ctxt) < 0) goto error; ctxt->node = saved_node; } @@ -7011,7 +7089,9 @@ virDomainDeviceDefPtr virDomainDeviceDefParse(virCapsPtr caps, if (xmlStrEqual(node->name, BAD_CAST "disk")) { dev->type = VIR_DOMAIN_DEVICE_DISK; if (!(dev->data.disk = virDomainDiskDefParseXML(caps, node, ctxt, - NULL, &def->seclabel, flags))) + NULL, def->seclabels, + def->nseclabels, + flags))) goto error; } else if (xmlStrEqual(node->name, BAD_CAST "lease")) { dev->type = VIR_DOMAIN_DEVICE_LEASE; @@ -7939,7 +8019,7 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps,
/* analysis of security label, done early even though we format it * late, so devices can refer to this for defaults */ - if (virSecurityLabelDefParseXML(&def->seclabel, ctxt, flags) == -1) + if (virSecurityLabelDefsParseXML(def, ctxt, flags) == -1) goto error;
/* Extract domain memory */ @@ -8538,7 +8618,8 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps, nodes[i], ctxt, bootMap, - &def->seclabel, + def->seclabels, + def->nseclabels, flags); if (!disk) goto error; @@ -10843,6 +10924,8 @@ virSecurityLabelDefFormat(virBufferPtr buf, virSecurityLabelDefPtr def) virBufferAsprintf(buf, " relabel='%s'", def->norelabel ? "no" : "yes");
+VIR_DEBUG("FMT %s: %s %s %s", def->model, def->label, def->imagelabel, def->baselabel); // TODO remove + if (def->label || def->imagelabel || def->baselabel) { virBufferAddLit(buf, ">\n");
@@ -10911,6 +10994,7 @@ virDomainDiskDefFormat(virBufferPtr buf, const char *copy_on_read = virDomainVirtioEventIdxTypeToString(def->copy_on_read); const char *startupPolicy = virDomainStartupPolicyTypeToString(def->startupPolicy);
+ int n; char uuidstr[VIR_UUID_STRING_BUFLEN];
if (!type) { @@ -11006,10 +11090,11 @@ virDomainDiskDefFormat(virBufferPtr buf, if (def->startupPolicy) virBufferEscapeString(buf, " startupPolicy='%s'", startupPolicy); - if (def->seclabel) { + if (def->nseclabels) { virBufferAddLit(buf, ">\n"); virBufferAdjustIndent(buf, 8); - virSecurityDeviceLabelDefFormat(buf, def->seclabel); + for (n = 0; n < def->nseclabels; n++) + virSecurityDeviceLabelDefFormat(buf, def->seclabels[n]); virBufferAdjustIndent(buf, -8); virBufferAddLit(buf, " </source>\n"); } else { @@ -11019,10 +11104,11 @@ virDomainDiskDefFormat(virBufferPtr buf, case VIR_DOMAIN_DISK_TYPE_BLOCK: virBufferEscapeString(buf, " <source dev='%s'", def->src); - if (def->seclabel) { + if (def->nseclabels) { virBufferAddLit(buf, ">\n"); virBufferAdjustIndent(buf, 8); - virSecurityDeviceLabelDefFormat(buf, def->seclabel); + for (n = 0; n < def->nseclabels; n++) + virSecurityDeviceLabelDefFormat(buf, def->seclabels[n]); virBufferAdjustIndent(buf, -8); virBufferAddLit(buf, " </source>\n"); } else { @@ -13020,7 +13106,8 @@ virDomainDefFormatInternal(virDomainDefPtr def, virBufferAddLit(buf, " </devices>\n");
virBufferAdjustIndent(buf, 2); - virSecurityLabelDefFormat(buf, &def->seclabel); + for (n = 0; n < def->nseclabels; n++) + virSecurityLabelDefFormat(buf, def->seclabels[n]); virBufferAdjustIndent(buf, -2);
if (def->namespaceData && def->ns.format) { @@ -15217,3 +15304,66 @@ cleanup: VIR_FREE(xmlStr); return ret; } + +virSecurityLabelDefPtr +virDomainDefGetSecurityLabelDef(virDomainDefPtr def, const char *model) +{ + int i; + + if (def == NULL || model == NULL) + return NULL; + + for (i = 0; i < def->nseclabels; i++) { + if (def->seclabels[i]->model == NULL) + continue; + if (STREQ(def->seclabels[i]->model, model)) + return def->seclabels[i]; + } + + return virDomainDefAddSecurityLabelDef(def, model); +} + +virSecurityDeviceLabelDefPtr +virDomainDiskDefGetSecurityLabelDef(virDomainDiskDefPtr def, const char *model) +{ + int i; + + if (def == NULL) + return NULL; + + for (i = 0; i < def->nseclabels; i++) { + if (STREQ(def->seclabels[i]->model, model)) + return def->seclabels[i]; + } + return NULL; +} + +virSecurityLabelDefPtr +virDomainDefAddSecurityLabelDef(virDomainDefPtr def, const char *model) +{ + virSecurityLabelDefPtr seclabel = NULL; + + if (VIR_ALLOC(seclabel) < 0) { + virReportOOMError(); + return NULL; + } + + if (model) { + seclabel->model = strdup(model); + if (seclabel->model == NULL) { + virReportOOMError(); + virSecurityLabelDefFree(seclabel); + return NULL; + } + } + + if (VIR_EXPAND_N(def->seclabels, def->nseclabels, 1) < 0) { + virReportOOMError(); + virSecurityLabelDefFree(seclabel); + return NULL; + } + def->seclabels[def->nseclabels - 1] = seclabel; + + return seclabel; +} +
We don't like empty lines at the end of a file.
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 4c56902..49a7120 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -309,6 +309,7 @@ struct _virSecurityLabelDef { typedef struct _virSecurityDeviceLabelDef virSecurityDeviceLabelDef; typedef virSecurityDeviceLabelDef *virSecurityDeviceLabelDefPtr; struct _virSecurityDeviceLabelDef { + char *model; char *label; /* image label string */ bool norelabel; }; @@ -553,7 +554,6 @@ struct _virDomainDiskDef { int device; int bus; char *src; - virSecurityDeviceLabelDefPtr seclabel;
And you we need to adapt src/security/security_manager.c and security/security_selinux.c too. I know it's the next patch, but in libvirt we have this policy of 'being able to compile after each patch'. But frankly, we fail sometimes. On the other hand, it would turn this one into unbearable huge patch. So I'd say it's okay in this case. Otherwise looking good. But can't give you my ACK unless you fix the test driver. Michal

--- src/security/security_apparmor.c | 112 ++++++++++---- src/security/security_dac.c | 320 ++++++++++++++++++++++++++++++++++---- src/security/security_manager.c | 99 +++++++++--- src/security/security_manager.h | 8 +- src/security/security_selinux.c | 249 +++++++++++++++++++++--------- src/security/security_stack.c | 235 +++++++++++++++++++--------- src/security/security_stack.h | 13 ++ 7 files changed, 803 insertions(+), 233 deletions(-) diff --git a/src/security/security_apparmor.c b/src/security/security_apparmor.c index 2d05fd0..d5d41f6 100644 --- a/src/security/security_apparmor.c +++ b/src/security/security_apparmor.c @@ -262,9 +262,13 @@ reload_profile(virSecurityManagerPtr mgr, const char *fn, bool append) { - const virSecurityLabelDefPtr secdef = &def->seclabel; int rc = -1; char *profile_name = NULL; + const virSecurityLabelDefPtr secdef = virDomainDefGetSecurityLabelDef( + def, SECURITY_APPARMOR_NAME); + + if (!secdef) + return rc; if (secdef->norelabel) return 0; @@ -298,7 +302,12 @@ AppArmorSetSecurityUSBLabel(usbDevice *dev ATTRIBUTE_UNUSED, virDomainDefPtr def = ptr->def; if (reload_profile(ptr->mgr, def, file, true) < 0) { - const virSecurityLabelDefPtr secdef = &def->seclabel; + const virSecurityLabelDefPtr secdef = virDomainDefGetSecurityLabelDef( + def, SECURITY_APPARMOR_NAME); + if (!secdef) { + virReportOOMError(); + return -1; + } virSecurityReportError(VIR_ERR_INTERNAL_ERROR, _("cannot update AppArmor profile " "\'%s\'"), @@ -316,7 +325,12 @@ AppArmorSetSecurityPCILabel(pciDevice *dev ATTRIBUTE_UNUSED, virDomainDefPtr def = ptr->def; if (reload_profile(ptr->mgr, def, file, true) < 0) { - const virSecurityLabelDefPtr secdef = &def->seclabel; + const virSecurityLabelDefPtr secdef = virDomainDefGetSecurityLabelDef( + def, SECURITY_APPARMOR_NAME); + if (!secdef) { + virReportOOMError(); + return -1; + } virSecurityReportError(VIR_ERR_INTERNAL_ERROR, _("cannot update AppArmor profile " "\'%s\'"), @@ -398,18 +412,23 @@ AppArmorGenSecurityLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, { int rc = -1; char *profile_name = NULL; + virSecurityLabelDefPtr secdef = virDomainDefGetSecurityLabelDef(def, + SECURITY_APPARMOR_NAME); - if (def->seclabel.type == VIR_DOMAIN_SECLABEL_STATIC) + if (!secdef) + return -1; + + if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC) return 0; - if (def->seclabel.baselabel) { + if (secdef->baselabel) { virSecurityReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("Cannot set a base label with AppArmour")); return rc; } - if ((def->seclabel.label) || - (def->seclabel.model) || (def->seclabel.imagelabel)) { + if ((secdef->label) || + (secdef->model) || (secdef->imagelabel)) { virSecurityReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("security label already defined for VM")); @@ -419,31 +438,31 @@ AppArmorGenSecurityLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, if ((profile_name = get_profile_name(def)) == NULL) return rc; - def->seclabel.label = strndup(profile_name, strlen(profile_name)); - if (!def->seclabel.label) { + secdef->label = strndup(profile_name, strlen(profile_name)); + if (!secdef->label) { virReportOOMError(); goto clean; } /* set imagelabel the same as label (but we won't use it) */ - def->seclabel.imagelabel = strndup(profile_name, - strlen(profile_name)); - if (!def->seclabel.imagelabel) { + secdef->imagelabel = strndup(profile_name, + strlen(profile_name)); + if (!secdef->imagelabel) { virReportOOMError(); goto err; } - def->seclabel.model = strdup(SECURITY_APPARMOR_NAME); - if (!def->seclabel.model) { + secdef->model = strdup(SECURITY_APPARMOR_NAME); + if (!secdef->model) { virReportOOMError(); goto err; } /* Now that we have a label, load the profile into the kernel. */ - if (load_profile(mgr, def->seclabel.label, def, NULL, false) < 0) { + if (load_profile(mgr, secdef->label, def, NULL, false) < 0) { virSecurityReportError(VIR_ERR_INTERNAL_ERROR, _("cannot load AppArmor profile " - "\'%s\'"), def->seclabel.label); + "\'%s\'"), secdef->label); goto err; } @@ -451,9 +470,9 @@ AppArmorGenSecurityLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, goto clean; err: - VIR_FREE(def->seclabel.label); - VIR_FREE(def->seclabel.imagelabel); - VIR_FREE(def->seclabel.model); + VIR_FREE(secdef->label); + VIR_FREE(secdef->imagelabel); + VIR_FREE(secdef->model); clean: VIR_FREE(profile_name); @@ -465,7 +484,12 @@ static int AppArmorSetSecurityAllLabel(virSecurityManagerPtr mgr, virDomainDefPtr def, const char *stdin_path) { - if (def->seclabel.norelabel) + virSecurityLabelDefPtr secdef = virDomainDefGetSecurityLabelDef(def, + SECURITY_APPARMOR_NAME); + if (!secdef) + return -1; + + if (secdef->norelabel) return 0; /* Reload the profile if stdin_path is specified. Note that @@ -518,7 +542,10 @@ static int AppArmorReleaseSecurityLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, virDomainDefPtr def) { - const virSecurityLabelDefPtr secdef = &def->seclabel; + const virSecurityLabelDefPtr secdef = virDomainDefGetSecurityLabelDef(def, + SECURITY_APPARMOR_NAME); + if (!secdef) + return -1; VIR_FREE(secdef->model); VIR_FREE(secdef->label); @@ -533,8 +560,12 @@ AppArmorRestoreSecurityAllLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, virDomainDefPtr def, int migrated ATTRIBUTE_UNUSED) { - const virSecurityLabelDefPtr secdef = &def->seclabel; int rc = 0; + const virSecurityLabelDefPtr secdef = + virDomainDefGetSecurityLabelDef(def, SECURITY_APPARMOR_NAME); + + if (!secdef) + return -1; if (secdef->type == VIR_DOMAIN_SECLABEL_DYNAMIC) { if ((rc = remove_profile(secdef->label)) != 0) { @@ -552,9 +583,13 @@ AppArmorRestoreSecurityAllLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, static int AppArmorSetSecurityProcessLabel(virSecurityManagerPtr mgr, virDomainDefPtr def) { - const virSecurityLabelDefPtr secdef = &def->seclabel; int rc = -1; char *profile_name = NULL; + const virSecurityLabelDefPtr secdef = + virDomainDefGetSecurityLabelDef(def, SECURITY_APPARMOR_NAME); + + if (!secdef) + return -1; if ((profile_name = get_profile_name(def)) == NULL) return rc; @@ -621,9 +656,13 @@ static int AppArmorSetSecurityImageLabel(virSecurityManagerPtr mgr, virDomainDefPtr def, virDomainDiskDefPtr disk) { - const virSecurityLabelDefPtr secdef = &def->seclabel; int rc = -1; char *profile_name; + const virSecurityLabelDefPtr secdef = + virDomainDefGetSecurityLabelDef(def, SECURITY_APPARMOR_NAME); + + if (!secdef) + return -1; if (secdef->norelabel) return 0; @@ -666,7 +705,11 @@ static int AppArmorSecurityVerify(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, virDomainDefPtr def) { - const virSecurityLabelDefPtr secdef = &def->seclabel; + const virSecurityLabelDefPtr secdef = + virDomainDefGetSecurityLabelDef(def, SECURITY_APPARMOR_NAME); + + if (!secdef) + return -1; if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC) { if (use_apparmor() < 0 || profile_status(secdef->label, 0) < 0) { @@ -694,9 +737,13 @@ AppArmorSetSecurityHostdevLabel(virSecurityManagerPtr mgr, virDomainHostdevDefPtr dev) { - const virSecurityLabelDefPtr secdef = &def->seclabel; struct SDPDOP *ptr; int ret = -1; + const virSecurityLabelDefPtr secdef = + virDomainDefGetSecurityLabelDef(def, SECURITY_APPARMOR_NAME); + + if (!secdef) + return -1; if (secdef->norelabel) return 0; @@ -756,7 +803,12 @@ AppArmorRestoreSecurityHostdevLabel(virSecurityManagerPtr mgr, virDomainHostdevDefPtr dev ATTRIBUTE_UNUSED) { - const virSecurityLabelDefPtr secdef = &def->seclabel; + const virSecurityLabelDefPtr secdef = + virDomainDefGetSecurityLabelDef(def, SECURITY_APPARMOR_NAME); + + if (!secdef) + return -1; + if (secdef->norelabel) return 0; @@ -789,7 +841,11 @@ AppArmorSetImageFDLabel(virSecurityManagerPtr mgr, char *proc = NULL; char *fd_path = NULL; - const virSecurityLabelDefPtr secdef = &def->seclabel; + const virSecurityLabelDefPtr secdef = + virDomainDefGetSecurityLabelDef(def, SECURITY_APPARMOR_NAME); + + if (!secdef) + return -1; if (secdef->imagelabel == NULL) return 0; diff --git a/src/security/security_dac.c b/src/security/security_dac.c index 470861d..0badafb 100644 --- a/src/security/security_dac.c +++ b/src/security/security_dac.c @@ -33,6 +33,7 @@ #include "storage_file.h" #define VIR_FROM_THIS VIR_FROM_SECURITY +#define SECURITY_DAC_NAME "dac" typedef struct _virSecurityDACData virSecurityDACData; typedef virSecurityDACData *virSecurityDACDataPtr; @@ -64,6 +65,132 @@ void virSecurityDACSetDynamicOwnership(virSecurityManagerPtr mgr, priv->dynamicOwnership = dynamicOwnership; } +static +int parseIds(const char *label, uid_t *uidPtr, gid_t *gidPtr) +{ + uid_t uid; + gid_t gid; + char *endptr = NULL; + + if (label == NULL) + return -1; + + uid = strtol(label, &endptr, 10); + if (endptr == NULL || *endptr != ':') + return -1; + + gid = strtol(endptr + 1, &endptr, 10); + if (endptr == NULL || *endptr != '\0') + return -1; + + if (uidPtr) + *uidPtr = uid; + if (gidPtr) + *gidPtr = gid; + return 0; +} + +static +int virSecurityDACParseIds(virDomainDefPtr def, uid_t *uidPtr, gid_t *gidPtr) +{ + uid_t uid; + gid_t gid; + virSecurityLabelDefPtr seclabel; + + if (def == NULL) + return -1; + + seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_DAC_NAME); + if (seclabel == NULL) { + virSecurityReportError(VIR_ERR_INTERNAL_ERROR, + _("security label for DAC not found")); + return -1; + } + + if (seclabel->label && parseIds(seclabel->label, &uid, &gid)) { + virSecurityReportError(VIR_ERR_INTERNAL_ERROR, + _("failed to parse uid and gid for DAC " + "securit driver")); + return -1; + } + + if (uidPtr) + *uidPtr = uid; + if (gidPtr) + *gidPtr = gid; + + return 0; +} + +static +int virSecurityDACGetIds(virDomainDefPtr def, virSecurityDACDataPtr priv, + uid_t *uidPtr, gid_t *gidPtr) +{ + if (virSecurityDACParseIds(def, uidPtr, gidPtr) == 0) + return 0; + + if (priv) { + if (uidPtr) + *uidPtr = priv->user; + if (gidPtr) + *gidPtr = priv->group; + return 0; + } + return -1; +} + +static +int virSecurityDACParseImageIds(virDomainDefPtr def, + uid_t *uidPtr, gid_t *gidPtr) +{ + uid_t uid; + gid_t gid; + virSecurityLabelDefPtr seclabel; + + if (def == NULL) + return -1; + + seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_DAC_NAME); + if (seclabel == NULL) { + virSecurityReportError(VIR_ERR_INTERNAL_ERROR, + _("security label for DAC not found")); + return -1; + } + + if (seclabel->imagelabel + && parseIds(seclabel->imagelabel, &uid, &gid)) { + virSecurityReportError(VIR_ERR_INTERNAL_ERROR, + _("failed to parse uid and gid for DAC " + "securit driver")); + return -1; + } + + if (uidPtr) + *uidPtr = uid; + if (gidPtr) + *gidPtr = gid; + + return 0; +} + +static +int virSecurityDACGetImageIds(virDomainDefPtr def, virSecurityDACDataPtr priv, + uid_t *uidPtr, gid_t *gidPtr) +{ + if (virSecurityDACParseImageIds(def, uidPtr, gidPtr) == 0) + return 0; + + if (priv) { + if (uidPtr) + *uidPtr = priv->user; + if (gidPtr) + *gidPtr = priv->group; + return 0; + } + return -1; +} + + static virSecurityDriverStatus virSecurityDACProbe(const char *virtDriver ATTRIBUTE_UNUSED) { @@ -85,7 +212,7 @@ virSecurityDACClose(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED) static const char * virSecurityDACGetModel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED) { - return "dac"; + return SECURITY_DAC_NAME; } static const char * virSecurityDACGetDOI(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED) @@ -167,10 +294,17 @@ virSecurityDACSetSecurityFileLabel(virDomainDiskDefPtr disk ATTRIBUTE_UNUSED, size_t depth ATTRIBUTE_UNUSED, void *opaque) { - virSecurityManagerPtr mgr = opaque; + void **params = opaque; + virSecurityManagerPtr mgr = params[0]; + virDomainDefPtr def = params[1]; virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr); + uid_t user; + gid_t group; - return virSecurityDACSetOwnership(path, priv->user, priv->group); + if (virSecurityDACGetImageIds(def, priv, &user, &group)) + return -1; + + return virSecurityDACSetOwnership(path, user, group); } @@ -180,6 +314,9 @@ virSecurityDACSetSecurityImageLabel(virSecurityManagerPtr mgr, virDomainDiskDefPtr disk) { + uid_t user; + gid_t group; + void *params[2]; virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr); if (!priv->dynamicOwnership) @@ -188,12 +325,17 @@ virSecurityDACSetSecurityImageLabel(virSecurityManagerPtr mgr, if (disk->type == VIR_DOMAIN_DISK_TYPE_NETWORK) return 0; + if (virSecurityDACGetImageIds(def, priv, &user, &group)) + return -1; + + params[0] = mgr; + params[1] = def; return virDomainDiskDefForeachPath(disk, virSecurityManagerGetAllowDiskFormatProbing(mgr), false, - priv->user, priv->group, + user, group, virSecurityDACSetSecurityFileLabel, - mgr); + params); } @@ -259,10 +401,17 @@ virSecurityDACSetSecurityPCILabel(pciDevice *dev ATTRIBUTE_UNUSED, const char *file, void *opaque) { - virSecurityManagerPtr mgr = opaque; + void **params = opaque; + virSecurityManagerPtr mgr = params[0]; + virDomainDefPtr def = params[1]; virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr); + uid_t user; + gid_t group; + + if (virSecurityDACGetIds(def, priv, &user, &group)) + return -1; - return virSecurityDACSetOwnership(file, priv->user, priv->group); + return virSecurityDACSetOwnership(file, user, group); } @@ -271,18 +420,26 @@ virSecurityDACSetSecurityUSBLabel(usbDevice *dev ATTRIBUTE_UNUSED, const char *file, void *opaque) { - virSecurityManagerPtr mgr = opaque; + void **params = opaque; + virSecurityManagerPtr mgr = params[0]; + virDomainDefPtr def = params[1]; virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr); + uid_t user; + gid_t group; - return virSecurityDACSetOwnership(file, priv->user, priv->group); + if (virSecurityDACGetIds(def, priv, &user, &group)) + return -1; + + return virSecurityDACSetOwnership(file, user, group); } static int virSecurityDACSetSecurityHostdevLabel(virSecurityManagerPtr mgr, - virDomainDefPtr def ATTRIBUTE_UNUSED, + virDomainDefPtr def, virDomainHostdevDefPtr dev) { + void *params[] = {mgr, def}; virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr); int ret = -1; @@ -300,7 +457,8 @@ virSecurityDACSetSecurityHostdevLabel(virSecurityManagerPtr mgr, if (!usb) goto done; - ret = usbDeviceFileIterate(usb, virSecurityDACSetSecurityUSBLabel, mgr); + ret = usbDeviceFileIterate(usb, virSecurityDACSetSecurityUSBLabel, + params); usbFreeDevice(usb); break; } @@ -314,7 +472,8 @@ virSecurityDACSetSecurityHostdevLabel(virSecurityManagerPtr mgr, if (!pci) goto done; - ret = pciDeviceFileIterate(pci, virSecurityDACSetSecurityPCILabel, mgr); + ret = pciDeviceFileIterate(pci, virSecurityDACSetSecurityPCILabel, + params); pciFreeDevice(pci); break; @@ -404,17 +563,23 @@ done: static int virSecurityDACSetChardevLabel(virSecurityManagerPtr mgr, + virDomainDefPtr def, virDomainChrSourceDefPtr dev) { virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr); char *in = NULL, *out = NULL; int ret = -1; + uid_t user; + gid_t group; + + if (virSecurityDACGetIds(def, priv, &user, &group)) + return -1; switch (dev->type) { case VIR_DOMAIN_CHR_TYPE_DEV: case VIR_DOMAIN_CHR_TYPE_FILE: - ret = virSecurityDACSetOwnership(dev->data.file.path, priv->user, priv->group); + ret = virSecurityDACSetOwnership(dev->data.file.path, user, group); break; case VIR_DOMAIN_CHR_TYPE_PIPE: @@ -424,12 +589,12 @@ virSecurityDACSetChardevLabel(virSecurityManagerPtr mgr, goto done; } if (virFileExists(in) && virFileExists(out)) { - if ((virSecurityDACSetOwnership(in, priv->user, priv->group) < 0) || - (virSecurityDACSetOwnership(out, priv->user, priv->group) < 0)) { + if ((virSecurityDACSetOwnership(in, user, group) < 0) || + (virSecurityDACSetOwnership(out, user, group) < 0)) { goto done; } } else if (virSecurityDACSetOwnership(dev->data.file.path, - priv->user, priv->group) < 0) { + user, group) < 0) { goto done; } ret = 0; @@ -554,7 +719,7 @@ virSecurityDACSetChardevCallback(virDomainDefPtr def ATTRIBUTE_UNUSED, { virSecurityManagerPtr mgr = opaque; - return virSecurityDACSetChardevLabel(mgr, &dev->source); + return virSecurityDACSetChardevLabel(mgr, def, &dev->source); } @@ -565,6 +730,8 @@ virSecurityDACSetSecurityAllLabel(virSecurityManagerPtr mgr, { virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr); int i; + uid_t user; + gid_t group; if (!priv->dynamicOwnership) return 0; @@ -591,16 +758,15 @@ virSecurityDACSetSecurityAllLabel(virSecurityManagerPtr mgr, mgr) < 0) return -1; + if (virSecurityDACGetImageIds(def, priv, &user, &group)) + return -1; + if (def->os.kernel && - virSecurityDACSetOwnership(def->os.kernel, - priv->user, - priv->group) < 0) + virSecurityDACSetOwnership(def->os.kernel, user, group) < 0) return -1; if (def->os.initrd && - virSecurityDACSetOwnership(def->os.initrd, - priv->user, - priv->group) < 0) + virSecurityDACSetOwnership(def->os.initrd, user, group) < 0) return -1; return 0; @@ -609,12 +775,17 @@ virSecurityDACSetSecurityAllLabel(virSecurityManagerPtr mgr, static int virSecurityDACSetSavedStateLabel(virSecurityManagerPtr mgr, - virDomainDefPtr def ATTRIBUTE_UNUSED, + virDomainDefPtr def, const char *savefile) { + uid_t user; + gid_t group; virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr); - return virSecurityDACSetOwnership(savefile, priv->user, priv->group); + if (virSecurityDACGetImageIds(def, priv, &user, &group)) + return -1; + + return virSecurityDACSetOwnership(savefile, user, group); } @@ -636,12 +807,16 @@ static int virSecurityDACSetProcessLabel(virSecurityManagerPtr mgr, virDomainDefPtr def ATTRIBUTE_UNUSED) { + uid_t user; + gid_t group; virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr); - VIR_DEBUG("Dropping privileges of DEF to %u:%u", - (unsigned int) priv->user, (unsigned int) priv->group); + if (virSecurityDACGetIds(def, priv, &user, &group)) + return -1; + + VIR_DEBUG("Dropping privileges of DEF to %u:%u", user, group); - if (virSetUIDGID(priv->user, priv->group) < 0) + if (virSetUIDGID(user, group) < 0) return -1; return 0; @@ -656,9 +831,83 @@ virSecurityDACVerify(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, } static int -virSecurityDACGenLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, - virDomainDefPtr def ATTRIBUTE_UNUSED) +virSecurityDACGenLabel(virSecurityManagerPtr mgr, + virDomainDefPtr def) { + int rc = -1; + virSecurityLabelDefPtr seclabel; + virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr); + + if (mgr == NULL) { + virSecurityReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("invalid security driver")); + return rc; + } + + seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_DAC_NAME); + if (seclabel == NULL) { + return rc; + } + + if (seclabel->imagelabel) { + virSecurityReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("security image label already " + "defined for VM")); + return rc; + } + + if (seclabel->model + && STRNEQ(seclabel->model, SECURITY_DAC_NAME)) { + virSecurityReportError(VIR_ERR_INTERNAL_ERROR, + _("security label model %s is not supported " + "with selinux"), + seclabel->model); + return rc; + } + + switch(seclabel->type) { + case VIR_DOMAIN_SECLABEL_STATIC: + if (seclabel->label == NULL) { + virSecurityReportError(VIR_ERR_INTERNAL_ERROR, + _("missing label for static security " + "driver")); + return rc; + } + break; + case VIR_DOMAIN_SECLABEL_DYNAMIC: + if (asprintf(&seclabel->label, "%d:%d", priv->user, priv->group) < 0) { + virReportOOMError(); + return rc; + } + if (seclabel->label == NULL) { + virSecurityReportError(VIR_ERR_INTERNAL_ERROR, + _("cannot generate dac user and group id")); + return rc; + } + break; + case VIR_DOMAIN_SECLABEL_NONE: + /* no op */ + break; + default: + virSecurityReportError(VIR_ERR_INTERNAL_ERROR, + _("unexpected security label type '%s'"), + virDomainSeclabelTypeToString(seclabel->type)); + return rc; + } + + if (!seclabel->norelabel) { + if (seclabel->imagelabel == NULL) { + seclabel->imagelabel = strdup(seclabel->label); + if (seclabel->imagelabel == NULL) { + virSecurityReportError(VIR_ERR_INTERNAL_ERROR, + _("cannot generate dac user and group id")); + VIR_FREE(seclabel->label); + seclabel->label = NULL; + return rc; + } + } + } + return 0; } @@ -683,6 +932,15 @@ virSecurityDACGetProcessLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, pid_t pid ATTRIBUTE_UNUSED, virSecurityLabelPtr seclabel ATTRIBUTE_UNUSED) { + virSecurityLabelDefPtr secdef = + virDomainDefGetSecurityLabelDef(def, SECURITY_DAC_NAME); + + if (!secdef || !seclabel) + return -1; + + if (secdef->label) + strcpy(seclabel->label, secdef->label); + return 0; } @@ -724,7 +982,7 @@ static char *virSecurityDACGetMountOptions(virSecurityManagerPtr mgr ATTRIBUTE_U virSecurityDriver virSecurityDriverDAC = { sizeof(virSecurityDACData), - "virDAC", + SECURITY_DAC_NAME, virSecurityDACProbe, virSecurityDACOpen, diff --git a/src/security/security_manager.c b/src/security/security_manager.c index 8ec4d3e..a9ca824 100644 --- a/src/security/security_manager.c +++ b/src/security/security_manager.c @@ -68,8 +68,7 @@ static virSecurityManagerPtr virSecurityManagerNewDriver(virSecurityDriverPtr dr return mgr; } -virSecurityManagerPtr virSecurityManagerNewStack(virSecurityManagerPtr primary, - virSecurityManagerPtr secondary) +virSecurityManagerPtr virSecurityManagerNewStack(virSecurityManagerPtr primary) { virSecurityManagerPtr mgr = virSecurityManagerNewDriver(&virSecurityDriverStack, @@ -81,12 +80,19 @@ virSecurityManagerPtr virSecurityManagerNewStack(virSecurityManagerPtr primary, if (!mgr) return NULL; - virSecurityStackSetPrimary(mgr, primary); - virSecurityStackSetSecondary(mgr, secondary); + virSecurityStackAddPrimary(mgr, primary); return mgr; } +int virSecurityManagerStackAddNested(virSecurityManagerPtr stack, + virSecurityManagerPtr nested) +{ + if (!STREQ("stack", stack->drv->name)) + return -1; + return virSecurityStackAddNested(stack, nested); +} + virSecurityManagerPtr virSecurityManagerNewDAC(const char *virtDriver, uid_t user, gid_t group, @@ -308,25 +314,51 @@ int virSecurityManagerRestoreSavedStateLabel(virSecurityManagerPtr mgr, int virSecurityManagerGenLabel(virSecurityManagerPtr mgr, virDomainDefPtr vm) { - if (vm->seclabel.type == VIR_DOMAIN_SECLABEL_DEFAULT) { - if (mgr->defaultConfined) - vm->seclabel.type = VIR_DOMAIN_SECLABEL_DYNAMIC; - else - vm->seclabel.type = VIR_DOMAIN_SECLABEL_NONE; - } + int rc = 0; + size_t i; + virSecurityManagerPtr* sec_managers = NULL; + virSecurityLabelDefPtr seclabel; - if ((vm->seclabel.type == VIR_DOMAIN_SECLABEL_NONE) && - mgr->requireConfined) { - virSecurityReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Unconfined guests are not allowed on this host")); + if (mgr == NULL || mgr->drv == NULL) return -1; - } - if (mgr->drv->domainGenSecurityLabel) - return mgr->drv->domainGenSecurityLabel(mgr, vm); + if ((sec_managers = virSecurityManagerGetNested(mgr)) == NULL) + return -1; - virSecurityReportError(VIR_ERR_NO_SUPPORT, __FUNCTION__); - return -1; + for (i = 0; sec_managers[i]; i++) { + seclabel = virDomainDefGetSecurityLabelDef(vm, + sec_managers[i]->drv->name); + if (seclabel == NULL) { + rc = -1; + goto cleanup; + } + + if (seclabel->type == VIR_DOMAIN_SECLABEL_DEFAULT) { + if (sec_managers[i]->defaultConfined) + seclabel->type = VIR_DOMAIN_SECLABEL_DYNAMIC; + else + seclabel->type = VIR_DOMAIN_SECLABEL_NONE; + } + + if ((seclabel->type == VIR_DOMAIN_SECLABEL_NONE) && + sec_managers[i]->requireConfined) { + virSecurityReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Unconfined guests are not allowed on this host")); + return -1; + } + + if (!sec_managers[i]->drv->domainGenSecurityLabel) { + virSecurityReportError(VIR_ERR_NO_SUPPORT, __FUNCTION__); + } else { + rc += sec_managers[i]->drv->domainGenSecurityLabel(sec_managers[i], vm); + if (rc) + goto cleanup; + } + } + +cleanup: + VIR_FREE(sec_managers); + return rc; } int virSecurityManagerReserveLabel(virSecurityManagerPtr mgr, @@ -397,12 +429,17 @@ int virSecurityManagerSetProcessLabel(virSecurityManagerPtr mgr, int virSecurityManagerVerify(virSecurityManagerPtr mgr, virDomainDefPtr def) { - const virSecurityLabelDefPtr secdef = &def->seclabel; + virSecurityLabelDefPtr secdef; + + if (mgr == NULL || mgr->drv == NULL) + return 0; + /* NULL model == dynamic labelling, with whatever driver * is active, so we can short circuit verify check to * avoid drivers de-referencing NULLs by accident */ - if (!secdef->model) + secdef = virDomainDefGetSecurityLabelDef(def, mgr->drv->name); + if (secdef == NULL || secdef->model == NULL) return 0; if (mgr->drv->domainSecurityVerify) @@ -435,3 +472,23 @@ char *virSecurityManagerGetMountOptions(virSecurityManagerPtr mgr, */ return NULL; } + +virSecurityManagerPtr* +virSecurityManagerGetNested(virSecurityManagerPtr mgr) +{ + virSecurityManagerPtr* list = NULL; + + if (STREQ("stack", mgr->drv->name)) { + return virSecurityStackGetNested(mgr); + } + + if (VIR_ALLOC_N(list, 2) < 0) { + virReportOOMError(); + return NULL; + } + + list[0] = mgr; + list[1] = NULL; + return list; +} + diff --git a/src/security/security_manager.h b/src/security/security_manager.h index f0bf60d..f86b84d 100644 --- a/src/security/security_manager.h +++ b/src/security/security_manager.h @@ -37,8 +37,9 @@ virSecurityManagerPtr virSecurityManagerNew(const char *name, bool defaultConfined, bool requireConfined); -virSecurityManagerPtr virSecurityManagerNewStack(virSecurityManagerPtr primary, - virSecurityManagerPtr secondary); +virSecurityManagerPtr virSecurityManagerNewStack(virSecurityManagerPtr primary); +int virSecurityManagerStackAddNested(virSecurityManagerPtr stack, + virSecurityManagerPtr nested); virSecurityManagerPtr virSecurityManagerNewDAC(const char *virtDriver, uid_t user, @@ -109,4 +110,7 @@ int virSecurityManagerSetImageFDLabel(virSecurityManagerPtr mgr, int fd); char *virSecurityManagerGetMountOptions(virSecurityManagerPtr mgr, virDomainDefPtr vm); +virSecurityManagerPtr* +virSecurityManagerGetNested(virSecurityManagerPtr mgr); + #endif /* VIR_SECURITY_MANAGER_H__ */ diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c index 2b8ff19..fe318be 100644 --- a/src/security/security_selinux.c +++ b/src/security/security_selinux.c @@ -271,46 +271,52 @@ SELinuxGenSecurityLabel(virSecurityManagerPtr mgr, int c2 = 0; context_t ctx = NULL; const char *range; - virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr); + virSecurityLabelDefPtr seclabel; + virSecuritySELinuxDataPtr data; - VIR_DEBUG("SELinuxGenSecurityLabel %s", virSecurityManagerGetDriver(mgr)); - if ((def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC) && - !def->seclabel.baselabel && - def->seclabel.model) { + if (mgr == NULL) { virSecurityReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("security model already defined for VM")); + "%s", _("invalid security driver")); + return rc; + } + + seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME); + if (seclabel == NULL) { return rc; } - if (def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC && - def->seclabel.label) { + data = virSecurityManagerGetPrivateData(mgr); + + VIR_DEBUG("SELinuxGenSecurityLabel %s", virSecurityManagerGetDriver(mgr)); + if (seclabel->type == VIR_DOMAIN_SECLABEL_DYNAMIC && + seclabel->label) { virSecurityReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("security label already defined for VM")); return rc; } - if (def->seclabel.imagelabel) { + if (seclabel->imagelabel) { virSecurityReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("security image label already defined for VM")); return rc; } - if (def->seclabel.model && - STRNEQ(def->seclabel.model, SECURITY_SELINUX_NAME)) { + if (seclabel->model && + STRNEQ(seclabel->model, SECURITY_SELINUX_NAME)) { virSecurityReportError(VIR_ERR_INTERNAL_ERROR, _("security label model %s is not supported with selinux"), - def->seclabel.model); + seclabel->model); return rc; } - VIR_DEBUG("SELinuxGenSecurityLabel %d", def->seclabel.type); + VIR_DEBUG("SELinuxGenSecurityLabel %d", seclabel->type); - switch (def->seclabel.type) { + switch (seclabel->type) { case VIR_DOMAIN_SECLABEL_STATIC: - if (!(ctx = context_new(def->seclabel.label)) ) { + if (!(ctx = context_new(seclabel->label)) ) { virReportSystemError(errno, _("unable to allocate socket security context '%s'"), - def->seclabel.label); + seclabel->label); return rc; } @@ -345,11 +351,11 @@ SELinuxGenSecurityLabel(virSecurityManagerPtr mgr, } } while (mcsAdd(mcs) == -1); - def->seclabel.label = - SELinuxGenNewContext(def->seclabel.baselabel ? - def->seclabel.baselabel : + seclabel->label = + SELinuxGenNewContext(seclabel->baselabel ? + seclabel->baselabel : data->domain_context, mcs); - if (! def->seclabel.label) { + if (! seclabel->label) { virSecurityReportError(VIR_ERR_INTERNAL_ERROR, _("cannot generate selinux context for %s"), mcs); goto cleanup; @@ -363,21 +369,21 @@ SELinuxGenSecurityLabel(virSecurityManagerPtr mgr, default: virSecurityReportError(VIR_ERR_INTERNAL_ERROR, _("unexpected security label type '%s'"), - virDomainSeclabelTypeToString(def->seclabel.type)); + virDomainSeclabelTypeToString(seclabel->type)); goto cleanup; } - if (!def->seclabel.norelabel) { - def->seclabel.imagelabel = SELinuxGenNewContext(data->file_context, mcs); - if (!def->seclabel.imagelabel) { + if (!seclabel->norelabel) { + seclabel->imagelabel = SELinuxGenNewContext(data->domain_context, mcs); + if (!seclabel->imagelabel) { virSecurityReportError(VIR_ERR_INTERNAL_ERROR, _("cannot generate selinux context for %s"), mcs); goto cleanup; } } - if (!def->seclabel.model && - !(def->seclabel.model = strdup(SECURITY_SELINUX_NAME))) { + if (!seclabel->model && + !(seclabel->model = strdup(SECURITY_SELINUX_NAME))) { virReportOOMError(); goto cleanup; } @@ -386,12 +392,12 @@ SELinuxGenSecurityLabel(virSecurityManagerPtr mgr, cleanup: if (rc != 0) { - if (def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC) - VIR_FREE(def->seclabel.label); - VIR_FREE(def->seclabel.imagelabel); - if (def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC && - !def->seclabel.baselabel) - VIR_FREE(def->seclabel.model); + if (seclabel->type == VIR_DOMAIN_SECLABEL_DYNAMIC) + VIR_FREE(seclabel->label); + VIR_FREE(seclabel->imagelabel); + if (seclabel->type == VIR_DOMAIN_SECLABEL_DYNAMIC && + !seclabel->baselabel) + VIR_FREE(seclabel->model); } if (ctx) @@ -400,10 +406,10 @@ cleanup: VIR_FREE(mcs); VIR_DEBUG("model=%s label=%s imagelabel=%s baselabel=%s", - NULLSTR(def->seclabel.model), - NULLSTR(def->seclabel.label), - NULLSTR(def->seclabel.imagelabel), - NULLSTR(def->seclabel.baselabel)); + NULLSTR(seclabel->model), + NULLSTR(seclabel->label), + NULLSTR(seclabel->imagelabel), + NULLSTR(seclabel->baselabel)); return rc; } @@ -416,8 +422,14 @@ SELinuxReserveSecurityLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, security_context_t pctx; context_t ctx = NULL; const char *mcs; + virSecurityLabelDefPtr seclabel; + + seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME); + if (seclabel == NULL) { + return -1; + } - if (def->seclabel.type == VIR_DOMAIN_SECLABEL_STATIC) + if (seclabel->type == VIR_DOMAIN_SECLABEL_STATIC) return 0; if (getpidcon(pid, &pctx) == -1) { @@ -709,9 +721,16 @@ SELinuxRestoreSecurityImageLabelInt(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, virDomainDiskDefPtr disk, int migrated) { - const virSecurityLabelDefPtr secdef = &def->seclabel; + virSecurityLabelDefPtr seclabel; + virSecurityDeviceLabelDefPtr disk_seclabel; - if (secdef->norelabel || (disk->seclabel && disk->seclabel->norelabel)) + seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME); + if (seclabel == NULL) + return -1; + + disk_seclabel = virDomainDiskDefGetSecurityLabelDef(disk, + SECURITY_SELINUX_NAME); + if (seclabel->norelabel || (disk_seclabel && disk_seclabel->norelabel)) return 0; /* Don't restore labels on readoly/shared disks, because @@ -763,17 +782,21 @@ SELinuxSetSecurityFileLabel(virDomainDiskDefPtr disk, size_t depth, void *opaque) { + int ret; + virSecurityDeviceLabelDefPtr disk_seclabel; virSecuritySELinuxCallbackDataPtr cbdata = opaque; const virSecurityLabelDefPtr secdef = cbdata->secdef; - int ret; virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(cbdata->manager); - if (disk->seclabel && disk->seclabel->norelabel) + disk_seclabel = virDomainDiskDefGetSecurityLabelDef(disk, + SECURITY_SELINUX_NAME); + + if (disk_seclabel && disk_seclabel->norelabel) return 0; - if (disk->seclabel && !disk->seclabel->norelabel && - disk->seclabel->label) { - ret = SELinuxSetFilecon(path, disk->seclabel->label); + if (disk_seclabel && !disk_seclabel->norelabel && + disk_seclabel->label) { + ret = SELinuxSetFilecon(path, disk_seclabel->label); } else if (depth == 0) { if (disk->shared) { @@ -788,14 +811,14 @@ SELinuxSetSecurityFileLabel(virDomainDiskDefPtr disk, } else { ret = SELinuxSetFileconOptional(path, data->content_context); } - if (ret == 1 && !disk->seclabel) { + if (ret == 1 && !disk_seclabel) { /* If we failed to set a label, but virt_use_nfs let us * proceed anyway, then we don't need to relabel later. */ - if (VIR_ALLOC(disk->seclabel) < 0) { + if (VIR_ALLOC(disk_seclabel) < 0) { virReportOOMError(); return -1; } - disk->seclabel->norelabel = true; + disk_seclabel->norelabel = true; ret = 0; } return ret; @@ -807,11 +830,15 @@ SELinuxSetSecurityImageLabel(virSecurityManagerPtr mgr, virDomainDiskDefPtr disk) { + bool allowDiskFormatProbing; virSecuritySELinuxCallbackData cbdata; - cbdata.secdef = &def->seclabel; cbdata.manager = mgr; + cbdata.secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME); - bool allowDiskFormatProbing = virSecurityManagerGetAllowDiskFormatProbing(mgr); + allowDiskFormatProbing = virSecurityManagerGetAllowDiskFormatProbing(mgr); + + if (cbdata.secdef == NULL) + return -1; if (cbdata.secdef->norelabel) return 0; @@ -838,9 +865,12 @@ static int SELinuxSetSecurityPCILabel(pciDevice *dev ATTRIBUTE_UNUSED, const char *file, void *opaque) { + virSecurityLabelDefPtr secdef; virDomainDefPtr def = opaque; - const virSecurityLabelDefPtr secdef = &def->seclabel; + secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME); + if (secdef == NULL) + return -1; return SELinuxSetFilecon(file, secdef->imagelabel); } @@ -848,8 +878,12 @@ static int SELinuxSetSecurityUSBLabel(usbDevice *dev ATTRIBUTE_UNUSED, const char *file, void *opaque) { + virSecurityLabelDefPtr secdef; virDomainDefPtr def = opaque; - const virSecurityLabelDefPtr secdef = &def->seclabel; + + secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME); + if (secdef == NULL) + return -1; return SELinuxSetFilecon(file, secdef->imagelabel); } @@ -860,9 +894,13 @@ SELinuxSetSecurityHostdevLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, virDomainHostdevDefPtr dev) { - const virSecurityLabelDefPtr secdef = &def->seclabel; + virSecurityLabelDefPtr secdef; int ret = -1; + secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME); + if (secdef == NULL) + return -1; + if (secdef->norelabel) return 0; @@ -929,9 +967,13 @@ SELinuxRestoreSecurityHostdevLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, virDomainHostdevDefPtr dev) { - const virSecurityLabelDefPtr secdef = &def->seclabel; + virSecurityLabelDefPtr secdef; int ret = -1; + secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME); + if (secdef == NULL) + return -1; + if (secdef->norelabel) return 0; @@ -982,10 +1024,14 @@ SELinuxSetSecurityChardevLabel(virDomainDefPtr def, virDomainChrSourceDefPtr dev) { - const virSecurityLabelDefPtr secdef = &def->seclabel; + virSecurityLabelDefPtr secdef; char *in = NULL, *out = NULL; int ret = -1; + secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME); + if (secdef == NULL) + return -1; + if (secdef->norelabel) return 0; @@ -1028,10 +1074,14 @@ SELinuxRestoreSecurityChardevLabel(virDomainDefPtr def, virDomainChrSourceDefPtr dev) { - const virSecurityLabelDefPtr secdef = &def->seclabel; + virSecurityLabelDefPtr secdef; char *in = NULL, *out = NULL; int ret = -1; + secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME); + if (secdef == NULL) + return -1; + if (secdef->norelabel) return 0; @@ -1121,12 +1171,16 @@ SELinuxRestoreSecurityAllLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, virDomainDefPtr def, int migrated ATTRIBUTE_UNUSED) { - const virSecurityLabelDefPtr secdef = &def->seclabel; + virSecurityLabelDefPtr secdef; int i; int rc = 0; VIR_DEBUG("Restoring security label on %s", def->name); + secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME); + if (secdef == NULL) + return -1; + if (secdef->norelabel) return 0; @@ -1171,7 +1225,11 @@ static int SELinuxReleaseSecurityLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, virDomainDefPtr def) { - const virSecurityLabelDefPtr secdef = &def->seclabel; + virSecurityLabelDefPtr secdef; + + secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME); + if (secdef == NULL) + return -1; if (secdef->type == VIR_DOMAIN_SECLABEL_DYNAMIC) { if (secdef->label != NULL) { @@ -1196,7 +1254,11 @@ SELinuxSetSavedStateLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, virDomainDefPtr def, const char *savefile) { - const virSecurityLabelDefPtr secdef = &def->seclabel; + virSecurityLabelDefPtr secdef; + + secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME); + if (secdef == NULL) + return -1; if (secdef->norelabel) return 0; @@ -1210,7 +1272,11 @@ SELinuxRestoreSavedStateLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, virDomainDefPtr def, const char *savefile) { - const virSecurityLabelDefPtr secdef = &def->seclabel; + virSecurityLabelDefPtr secdef; + + secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME); + if (secdef == NULL) + return -1; if (secdef->norelabel) return 0; @@ -1223,7 +1289,12 @@ static int SELinuxSecurityVerify(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, virDomainDefPtr def) { - const virSecurityLabelDefPtr secdef = &def->seclabel; + virSecurityLabelDefPtr secdef; + + secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME); + if (secdef == NULL) + return -1; + if (!STREQ(virSecurityManagerGetModel(mgr), secdef->model)) { virSecurityReportError(VIR_ERR_INTERNAL_ERROR, _("security label driver mismatch: " @@ -1248,12 +1319,16 @@ SELinuxSetSecurityProcessLabel(virSecurityManagerPtr mgr, virDomainDefPtr def) { /* TODO: verify DOI */ - const virSecurityLabelDefPtr secdef = &def->seclabel; - VIR_DEBUG("SELinuxSetSecurityProcessLabel %s", secdef->label); + virSecurityLabelDefPtr secdef; - if (def->seclabel.label == NULL) + secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME); + if (secdef == NULL) + return -1; + + if (secdef->label == NULL) return 0; + VIR_DEBUG("SELinuxSetSecurityProcessLabel %s", secdef->label); if (!STREQ(virSecurityManagerGetModel(mgr), secdef->model)) { virSecurityReportError(VIR_ERR_INTERNAL_ERROR, _("security label driver mismatch: " @@ -1280,13 +1355,17 @@ SELinuxSetSecurityDaemonSocketLabel(virSecurityManagerPtr mgr, virDomainDefPtr def) { /* TODO: verify DOI */ - const virSecurityLabelDefPtr secdef = &def->seclabel; + virSecurityLabelDefPtr secdef; context_t execcon = NULL; context_t proccon = NULL; security_context_t scon = NULL; int rc = -1; - if (def->seclabel.label == NULL) + secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME); + if (secdef == NULL) + return -1; + + if (secdef->label == NULL) return 0; if (!STREQ(virSecurityManagerGetModel(mgr), secdef->model)) { @@ -1350,9 +1429,13 @@ static int SELinuxSetSecuritySocketLabel(virSecurityManagerPtr mgr, virDomainDefPtr vm) { - const virSecurityLabelDefPtr secdef = &vm->seclabel; + virSecurityLabelDefPtr secdef; int rc = -1; + secdef = virDomainDefGetSecurityLabelDef(vm, SECURITY_SELINUX_NAME); + if (secdef == NULL) + return -1; + if (secdef->label == NULL) return 0; @@ -1388,9 +1471,13 @@ SELinuxClearSecuritySocketLabel(virSecurityManagerPtr mgr, virDomainDefPtr def) { /* TODO: verify DOI */ - const virSecurityLabelDefPtr secdef = &def->seclabel; + virSecurityLabelDefPtr secdef; + + secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME); + if (secdef == NULL) + return -1; - if (def->seclabel.label == NULL) + if (secdef->label == NULL) return 0; if (!STREQ(virSecurityManagerGetModel(mgr), secdef->model)) { @@ -1466,9 +1553,13 @@ SELinuxSetSecurityAllLabel(virSecurityManagerPtr mgr, virDomainDefPtr def, const char *stdin_path) { - virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr); - const virSecurityLabelDefPtr secdef = &def->seclabel; int i; + virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr); + virSecurityLabelDefPtr secdef; + + secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME); + if (secdef == NULL) + return -1; if (secdef->norelabel) return 0; @@ -1528,7 +1619,11 @@ SELinuxSetImageFDLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, virDomainDefPtr def, int fd) { - const virSecurityLabelDefPtr secdef = &def->seclabel; + virSecurityLabelDefPtr secdef; + + secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME); + if (secdef == NULL) + return -1; if (secdef->imagelabel == NULL) return 0; @@ -1538,13 +1633,17 @@ SELinuxSetImageFDLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, static char *genImageLabel(virSecurityManagerPtr mgr, virDomainDefPtr def) { - const virSecurityLabelDefPtr secdef = &def->seclabel; + virSecurityLabelDefPtr secdef; virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr); const char *range; context_t ctx = NULL; char *label = NULL; const char *mcs = NULL; + secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME); + if (secdef == NULL) + goto cleanup; + if (secdef->label) { ctx = context_new(secdef->label); if (!ctx) { @@ -1575,7 +1674,11 @@ cleanup: static char *SELinuxGetSecurityMountOptions(virSecurityManagerPtr mgr, virDomainDefPtr def) { char *opts = NULL; - const virSecurityLabelDefPtr secdef = &def->seclabel; + virSecurityLabelDefPtr secdef; + + secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME); + if (secdef == NULL) + return NULL; if (! secdef->imagelabel) secdef->imagelabel = genImageLabel(mgr,def); diff --git a/src/security/security_stack.c b/src/security/security_stack.c index 6ecd099..dd0aebc 100644 --- a/src/security/security_stack.c +++ b/src/security/security_stack.c @@ -23,29 +23,70 @@ #include "security_stack.h" #include "virterror_internal.h" +#include "memory.h" #define VIR_FROM_THIS VIR_FROM_SECURITY typedef struct _virSecurityStackData virSecurityStackData; typedef virSecurityStackData *virSecurityStackDataPtr; +typedef struct _virSecurityStackItem virSecurityStackItem; +typedef virSecurityStackItem* virSecurityStackItemPtr; + +struct _virSecurityStackItem { + virSecurityManagerPtr securityManager; + virSecurityStackItemPtr next; +}; struct _virSecurityStackData { virSecurityManagerPtr primary; - virSecurityManagerPtr secondary; + virSecurityStackItemPtr itemsHead; }; -void virSecurityStackSetPrimary(virSecurityManagerPtr mgr, - virSecurityManagerPtr primary) +int +virSecurityStackAddPrimary(virSecurityManagerPtr mgr, + virSecurityManagerPtr primary) { virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr); + if (virSecurityStackAddNested(mgr, primary) < 0) + return -1; priv->primary = primary; + return 0; +} + +int +virSecurityStackAddNested(virSecurityManagerPtr mgr, + virSecurityManagerPtr nested) +{ + virSecurityStackItemPtr item = NULL; + virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr); + + if (VIR_ALLOC(item) < 0) { + virReportOOMError(); + return -1; + } + item->securityManager = nested; + item->next = priv->itemsHead; + priv->itemsHead = item; + return 0; +} + +virSecurityManagerPtr +virSecurityStackGetPrimary(virSecurityManagerPtr mgr) +{ + virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr); + return (priv->primary) ? priv->primary : priv->itemsHead->securityManager; +} + +void virSecurityStackSetPrimary(virSecurityManagerPtr mgr, + virSecurityManagerPtr primary) +{ + virSecurityStackAddPrimary(mgr, primary); } void virSecurityStackSetSecondary(virSecurityManagerPtr mgr, virSecurityManagerPtr secondary) { - virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr); - priv->secondary = secondary; + virSecurityStackAddNested(mgr, secondary); } static virSecurityDriverStatus @@ -64,9 +105,14 @@ static int virSecurityStackClose(virSecurityManagerPtr mgr) { virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr); + virSecurityStackItemPtr next, item = priv->itemsHead; - virSecurityManagerFree(priv->primary); - virSecurityManagerFree(priv->secondary); + while (item) { + next = item->next; + virSecurityManagerFree(item->securityManager); + VIR_FREE(item); + item = next; + } return 0; } @@ -74,17 +120,13 @@ virSecurityStackClose(virSecurityManagerPtr mgr) static const char * virSecurityStackGetModel(virSecurityManagerPtr mgr) { - virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr); - - return virSecurityManagerGetModel(priv->primary); + return virSecurityManagerGetModel(virSecurityStackGetPrimary(mgr)); } static const char * virSecurityStackGetDOI(virSecurityManagerPtr mgr) { - virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr); - - return virSecurityManagerGetDOI(priv->primary); + return virSecurityManagerGetDOI(virSecurityStackGetPrimary(mgr)); } static int @@ -92,13 +134,13 @@ virSecurityStackVerify(virSecurityManagerPtr mgr, virDomainDefPtr def) { virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr); + virSecurityStackItemPtr item = priv->itemsHead; int rc = 0; - if (virSecurityManagerVerify(priv->primary, def) < 0) - rc = -1; - - if (virSecurityManagerVerify(priv->secondary, def) < 0) - rc = -1; + for(; item; item = item->next) { + if (virSecurityManagerVerify(item->securityManager, def) < 0) + rc = -1; + } return rc; } @@ -108,12 +150,12 @@ static int virSecurityStackGenLabel(virSecurityManagerPtr mgr, virDomainDefPtr vm) { - virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr); int rc = 0; - if (virSecurityManagerGenLabel(priv->primary, vm) < 0) + if (virSecurityManagerGenLabel(virSecurityStackGetPrimary(mgr), vm) < 0) rc = -1; +// TODO #if 0 /* We don't allow secondary drivers to generate labels. * This may have to change in the future, but requires @@ -133,11 +175,12 @@ static int virSecurityStackReleaseLabel(virSecurityManagerPtr mgr, virDomainDefPtr vm) { - virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr); int rc = 0; - if (virSecurityManagerReleaseLabel(priv->primary, vm) < 0) + if (virSecurityManagerReleaseLabel(virSecurityStackGetPrimary(mgr), vm) < 0) rc = -1; + +// TODO #if 0 /* XXX See note in GenLabel */ if (virSecurityManagerReleaseLabel(priv->secondary, vm) < 0) @@ -153,11 +196,11 @@ virSecurityStackReserveLabel(virSecurityManagerPtr mgr, virDomainDefPtr vm, pid_t pid) { - virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr); int rc = 0; - if (virSecurityManagerReserveLabel(priv->primary, vm, pid) < 0) + if (virSecurityManagerReserveLabel(virSecurityStackGetPrimary(mgr), vm, pid) < 0) rc = -1; +// TODO #if 0 /* XXX See note in GenLabel */ if (virSecurityManagerReserveLabel(priv->secondary, vm, pid) < 0) @@ -174,12 +217,13 @@ virSecurityStackSetSecurityImageLabel(virSecurityManagerPtr mgr, virDomainDiskDefPtr disk) { virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr); + virSecurityStackItemPtr item = priv->itemsHead; int rc = 0; - if (virSecurityManagerSetImageLabel(priv->secondary, vm, disk) < 0) - rc = -1; - if (virSecurityManagerSetImageLabel(priv->primary, vm, disk) < 0) - rc = -1; + for (; item; item = item->next) { + if (virSecurityManagerSetImageLabel(item->securityManager, vm, disk) < 0) + rc = -1; + } return rc; } @@ -191,12 +235,13 @@ virSecurityStackRestoreSecurityImageLabel(virSecurityManagerPtr mgr, virDomainDiskDefPtr disk) { virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr); + virSecurityStackItemPtr item = priv->itemsHead; int rc = 0; - if (virSecurityManagerRestoreImageLabel(priv->secondary, vm, disk) < 0) - rc = -1; - if (virSecurityManagerRestoreImageLabel(priv->primary, vm, disk) < 0) - rc = -1; + for (; item; item = item->next) { + if (virSecurityManagerRestoreImageLabel(item->securityManager, vm, disk) < 0) + rc = -1; + } return rc; } @@ -209,12 +254,13 @@ virSecurityStackSetSecurityHostdevLabel(virSecurityManagerPtr mgr, { virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr); + virSecurityStackItemPtr item = priv->itemsHead; int rc = 0; - if (virSecurityManagerSetHostdevLabel(priv->secondary, vm, dev) < 0) - rc = -1; - if (virSecurityManagerSetHostdevLabel(priv->primary, vm, dev) < 0) - rc = -1; + for (; item; item = item->next) { + if (virSecurityManagerSetHostdevLabel(item->securityManager, vm, dev) < 0) + rc = -1; + } return rc; } @@ -226,12 +272,13 @@ virSecurityStackRestoreSecurityHostdevLabel(virSecurityManagerPtr mgr, virDomainHostdevDefPtr dev) { virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr); + virSecurityStackItemPtr item = priv->itemsHead; int rc = 0; - if (virSecurityManagerRestoreHostdevLabel(priv->secondary, vm, dev) < 0) - rc = -1; - if (virSecurityManagerRestoreHostdevLabel(priv->primary, vm, dev) < 0) - rc = -1; + for (; item; item = item->next) { + if (virSecurityManagerRestoreHostdevLabel(item->securityManager, vm, dev) < 0) + rc = -1; + } return rc; } @@ -243,12 +290,13 @@ virSecurityStackSetSecurityAllLabel(virSecurityManagerPtr mgr, const char *stdin_path) { virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr); + virSecurityStackItemPtr item = priv->itemsHead; int rc = 0; - if (virSecurityManagerSetAllLabel(priv->secondary, vm, stdin_path) < 0) - rc = -1; - if (virSecurityManagerSetAllLabel(priv->primary, vm, stdin_path) < 0) - rc = -1; + for (; item; item = item->next) { + if (virSecurityManagerSetAllLabel(item->securityManager, vm, stdin_path) < 0) + rc = -1; + } return rc; } @@ -260,12 +308,13 @@ virSecurityStackRestoreSecurityAllLabel(virSecurityManagerPtr mgr, int migrated) { virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr); + virSecurityStackItemPtr item = priv->itemsHead; int rc = 0; - if (virSecurityManagerRestoreAllLabel(priv->secondary, vm, migrated) < 0) - rc = -1; - if (virSecurityManagerRestoreAllLabel(priv->primary, vm, migrated) < 0) - rc = -1; + for (; item; item = item->next) { + if (virSecurityManagerRestoreAllLabel(item->securityManager, vm, migrated) < 0) + rc = -1; + } return rc; } @@ -277,12 +326,13 @@ virSecurityStackSetSavedStateLabel(virSecurityManagerPtr mgr, const char *savefile) { virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr); + virSecurityStackItemPtr item = priv->itemsHead; int rc = 0; - if (virSecurityManagerSetSavedStateLabel(priv->secondary, vm, savefile) < 0) - rc = -1; - if (virSecurityManagerSetSavedStateLabel(priv->primary, vm, savefile) < 0) - rc = -1; + for (; item; item = item->next) { + if (virSecurityManagerSetSavedStateLabel(item->securityManager, vm, savefile) < 0) + rc = -1; + } return rc; } @@ -294,12 +344,13 @@ virSecurityStackRestoreSavedStateLabel(virSecurityManagerPtr mgr, const char *savefile) { virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr); + virSecurityStackItemPtr item = priv->itemsHead; int rc = 0; - if (virSecurityManagerRestoreSavedStateLabel(priv->secondary, vm, savefile) < 0) - rc = -1; - if (virSecurityManagerRestoreSavedStateLabel(priv->primary, vm, savefile) < 0) - rc = -1; + for (; item; item = item->next) { + if (virSecurityManagerRestoreSavedStateLabel(item->securityManager, vm, savefile) < 0) + rc = -1; + } return rc; } @@ -310,12 +361,13 @@ virSecurityStackSetProcessLabel(virSecurityManagerPtr mgr, virDomainDefPtr vm) { virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr); + virSecurityStackItemPtr item = priv->itemsHead; int rc = 0; - if (virSecurityManagerSetProcessLabel(priv->secondary, vm) < 0) - rc = -1; - if (virSecurityManagerSetProcessLabel(priv->primary, vm) < 0) - rc = -1; + for (; item; item = item->next) { + if (virSecurityManagerSetProcessLabel(item->securityManager, vm) < 0) + rc = -1; + } return rc; } @@ -326,14 +378,14 @@ virSecurityStackGetProcessLabel(virSecurityManagerPtr mgr, pid_t pid, virSecurityLabelPtr seclabel) { - virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr); int rc = 0; +// TODO #if 0 if (virSecurityManagerGetProcessLabel(priv->secondary, vm, pid, seclabel) < 0) rc = -1; #endif - if (virSecurityManagerGetProcessLabel(priv->primary, vm, pid, seclabel) < 0) + if (virSecurityManagerGetProcessLabel(virSecurityStackGetPrimary(mgr), vm, pid, seclabel) < 0) rc = -1; return rc; @@ -345,12 +397,13 @@ virSecurityStackSetDaemonSocketLabel(virSecurityManagerPtr mgr, virDomainDefPtr vm) { virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr); + virSecurityStackItemPtr item = priv->itemsHead; int rc = 0; - if (virSecurityManagerSetDaemonSocketLabel(priv->secondary, vm) < 0) - rc = -1; - if (virSecurityManagerSetDaemonSocketLabel(priv->primary, vm) < 0) - rc = -1; + for (; item; item = item->next) { + if (virSecurityManagerSetDaemonSocketLabel(item->securityManager, vm) < 0) + rc = -1; + } return rc; } @@ -361,12 +414,13 @@ virSecurityStackSetSocketLabel(virSecurityManagerPtr mgr, virDomainDefPtr vm) { virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr); + virSecurityStackItemPtr item = priv->itemsHead; int rc = 0; - if (virSecurityManagerSetSocketLabel(priv->secondary, vm) < 0) - rc = -1; - if (virSecurityManagerSetSocketLabel(priv->primary, vm) < 0) - rc = -1; + for (; item; item = item->next) { + if (virSecurityManagerSetSocketLabel(item->securityManager, vm) < 0) + rc = -1; + } return rc; } @@ -377,12 +431,13 @@ virSecurityStackClearSocketLabel(virSecurityManagerPtr mgr, virDomainDefPtr vm) { virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr); + virSecurityStackItemPtr item = priv->itemsHead; int rc = 0; - if (virSecurityManagerClearSocketLabel(priv->secondary, vm) < 0) - rc = -1; - if (virSecurityManagerClearSocketLabel(priv->primary, vm) < 0) - rc = -1; + for (; item; item = item->next) { + if (virSecurityManagerClearSocketLabel(item->securityManager, vm) < 0) + rc = -1; + } return rc; } @@ -393,12 +448,13 @@ virSecurityStackSetImageFDLabel(virSecurityManagerPtr mgr, int fd) { virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr); + virSecurityStackItemPtr item = priv->itemsHead; int rc = 0; - if (virSecurityManagerSetImageFDLabel(priv->secondary, vm, fd) < 0) - rc = -1; - if (virSecurityManagerSetImageFDLabel(priv->primary, vm, fd) < 0) - rc = -1; + for (; item; item = item->next) { + if (virSecurityManagerSetImageFDLabel(item->securityManager, vm, fd) < 0) + rc = -1; + } return rc; } @@ -408,6 +464,29 @@ static char *virSecurityStackGetMountOptions(virSecurityManagerPtr mgr ATTRIBUTE return NULL; } +virSecurityManagerPtr* +virSecurityStackGetNested(virSecurityManagerPtr mgr) +{ + virSecurityManagerPtr *list = NULL; + virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr); + virSecurityStackItemPtr item; + int len = 0, i = 0; + + for (item = priv->itemsHead; item; item = item->next) + len++; + + if (VIR_ALLOC_N(list, len + 1) < 0) { + virReportOOMError(); + return NULL; + } + + for (item = priv->itemsHead; item; item = item->next, i++) + list[i] = item->securityManager; + list[len] = NULL; + + return list; +} + virSecurityDriver virSecurityDriverStack = { sizeof(virSecurityStackData), "stack", diff --git a/src/security/security_stack.h b/src/security/security_stack.h index bc83ff3..13a7a88 100644 --- a/src/security/security_stack.h +++ b/src/security/security_stack.h @@ -25,9 +25,22 @@ extern virSecurityDriver virSecurityDriverStack; + +int +virSecurityStackAddPrimary(virSecurityManagerPtr mgr, + virSecurityManagerPtr primary); +int +virSecurityStackAddNested(virSecurityManagerPtr mgr, + virSecurityManagerPtr nested); +virSecurityManagerPtr +virSecurityStackGetPrimary(virSecurityManagerPtr mgr); + void virSecurityStackSetPrimary(virSecurityManagerPtr mgr, virSecurityManagerPtr primary); void virSecurityStackSetSecondary(virSecurityManagerPtr mgr, virSecurityManagerPtr secondary); +virSecurityManagerPtr* +virSecurityStackGetNested(virSecurityManagerPtr mgr); + #endif /* __VIR_SECURITY_DAC */ -- 1.7.1

On 21.05.2012 15:39, Marcelo Cerri wrote:
--- src/security/security_apparmor.c | 112 ++++++++++---- src/security/security_dac.c | 320 ++++++++++++++++++++++++++++++++++---- src/security/security_manager.c | 99 +++++++++--- src/security/security_manager.h | 8 +- src/security/security_selinux.c | 249 +++++++++++++++++++++--------- src/security/security_stack.c | 235 +++++++++++++++++++--------- src/security/security_stack.h | 13 ++ 7 files changed, 803 insertions(+), 233 deletions(-)
Doesn't apply cleanly: CONFLICT (content): Merge conflict in src/security/security_dac.c However, this is caused by my earlier patch which converted security driver struct initialization to follow C99 hence conflict can be resolved easily.
diff --git a/src/security/security_apparmor.c b/src/security/security_apparmor.c index 2d05fd0..d5d41f6 100644 --- a/src/security/security_apparmor.c +++ b/src/security/security_apparmor.c @@ -262,9 +262,13 @@ reload_profile(virSecurityManagerPtr mgr, const char *fn, bool append) { - const virSecurityLabelDefPtr secdef = &def->seclabel; int rc = -1; char *profile_name = NULL; + const virSecurityLabelDefPtr secdef = virDomainDefGetSecurityLabelDef( + def, SECURITY_APPARMOR_NAME); + + if (!secdef) + return rc;
if (secdef->norelabel) return 0; @@ -298,7 +302,12 @@ AppArmorSetSecurityUSBLabel(usbDevice *dev ATTRIBUTE_UNUSED, virDomainDefPtr def = ptr->def;
if (reload_profile(ptr->mgr, def, file, true) < 0) { - const virSecurityLabelDefPtr secdef = &def->seclabel; + const virSecurityLabelDefPtr secdef = virDomainDefGetSecurityLabelDef( + def, SECURITY_APPARMOR_NAME); + if (!secdef) { + virReportOOMError(); + return -1; + } virSecurityReportError(VIR_ERR_INTERNAL_ERROR, _("cannot update AppArmor profile " "\'%s\'"), @@ -316,7 +325,12 @@ AppArmorSetSecurityPCILabel(pciDevice *dev ATTRIBUTE_UNUSED, virDomainDefPtr def = ptr->def;
if (reload_profile(ptr->mgr, def, file, true) < 0) { - const virSecurityLabelDefPtr secdef = &def->seclabel; + const virSecurityLabelDefPtr secdef = virDomainDefGetSecurityLabelDef( + def, SECURITY_APPARMOR_NAME); + if (!secdef) { + virReportOOMError(); + return -1; + } virSecurityReportError(VIR_ERR_INTERNAL_ERROR, _("cannot update AppArmor profile " "\'%s\'"), @@ -398,18 +412,23 @@ AppArmorGenSecurityLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, { int rc = -1; char *profile_name = NULL; + virSecurityLabelDefPtr secdef = virDomainDefGetSecurityLabelDef(def, + SECURITY_APPARMOR_NAME);
- if (def->seclabel.type == VIR_DOMAIN_SECLABEL_STATIC) + if (!secdef) + return -1; + + if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC) return 0;
- if (def->seclabel.baselabel) { + if (secdef->baselabel) { virSecurityReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("Cannot set a base label with AppArmour")); return rc; }
- if ((def->seclabel.label) || - (def->seclabel.model) || (def->seclabel.imagelabel)) { + if ((secdef->label) || + (secdef->model) || (secdef->imagelabel)) { virSecurityReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("security label already defined for VM")); @@ -419,31 +438,31 @@ AppArmorGenSecurityLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, if ((profile_name = get_profile_name(def)) == NULL) return rc;
- def->seclabel.label = strndup(profile_name, strlen(profile_name)); - if (!def->seclabel.label) { + secdef->label = strndup(profile_name, strlen(profile_name)); + if (!secdef->label) { virReportOOMError(); goto clean; }
/* set imagelabel the same as label (but we won't use it) */ - def->seclabel.imagelabel = strndup(profile_name, - strlen(profile_name)); - if (!def->seclabel.imagelabel) { + secdef->imagelabel = strndup(profile_name, + strlen(profile_name)); + if (!secdef->imagelabel) { virReportOOMError(); goto err; }
- def->seclabel.model = strdup(SECURITY_APPARMOR_NAME); - if (!def->seclabel.model) { + secdef->model = strdup(SECURITY_APPARMOR_NAME); + if (!secdef->model) { virReportOOMError(); goto err; }
/* Now that we have a label, load the profile into the kernel. */ - if (load_profile(mgr, def->seclabel.label, def, NULL, false) < 0) { + if (load_profile(mgr, secdef->label, def, NULL, false) < 0) { virSecurityReportError(VIR_ERR_INTERNAL_ERROR, _("cannot load AppArmor profile " - "\'%s\'"), def->seclabel.label); + "\'%s\'"), secdef->label); goto err; }
@@ -451,9 +470,9 @@ AppArmorGenSecurityLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, goto clean;
err: - VIR_FREE(def->seclabel.label); - VIR_FREE(def->seclabel.imagelabel); - VIR_FREE(def->seclabel.model); + VIR_FREE(secdef->label); + VIR_FREE(secdef->imagelabel); + VIR_FREE(secdef->model);
clean: VIR_FREE(profile_name); @@ -465,7 +484,12 @@ static int AppArmorSetSecurityAllLabel(virSecurityManagerPtr mgr, virDomainDefPtr def, const char *stdin_path) { - if (def->seclabel.norelabel) + virSecurityLabelDefPtr secdef = virDomainDefGetSecurityLabelDef(def, + SECURITY_APPARMOR_NAME); + if (!secdef) + return -1; + + if (secdef->norelabel) return 0;
/* Reload the profile if stdin_path is specified. Note that @@ -518,7 +542,10 @@ static int AppArmorReleaseSecurityLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, virDomainDefPtr def) { - const virSecurityLabelDefPtr secdef = &def->seclabel; + const virSecurityLabelDefPtr secdef = virDomainDefGetSecurityLabelDef(def, + SECURITY_APPARMOR_NAME); + if (!secdef) + return -1;
VIR_FREE(secdef->model); VIR_FREE(secdef->label); @@ -533,8 +560,12 @@ AppArmorRestoreSecurityAllLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, virDomainDefPtr def, int migrated ATTRIBUTE_UNUSED) { - const virSecurityLabelDefPtr secdef = &def->seclabel; int rc = 0; + const virSecurityLabelDefPtr secdef = + virDomainDefGetSecurityLabelDef(def, SECURITY_APPARMOR_NAME); + + if (!secdef) + return -1;
if (secdef->type == VIR_DOMAIN_SECLABEL_DYNAMIC) { if ((rc = remove_profile(secdef->label)) != 0) { @@ -552,9 +583,13 @@ AppArmorRestoreSecurityAllLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, static int AppArmorSetSecurityProcessLabel(virSecurityManagerPtr mgr, virDomainDefPtr def) { - const virSecurityLabelDefPtr secdef = &def->seclabel; int rc = -1; char *profile_name = NULL; + const virSecurityLabelDefPtr secdef = + virDomainDefGetSecurityLabelDef(def, SECURITY_APPARMOR_NAME); + + if (!secdef) + return -1;
if ((profile_name = get_profile_name(def)) == NULL) return rc; @@ -621,9 +656,13 @@ static int AppArmorSetSecurityImageLabel(virSecurityManagerPtr mgr, virDomainDefPtr def, virDomainDiskDefPtr disk) { - const virSecurityLabelDefPtr secdef = &def->seclabel; int rc = -1; char *profile_name; + const virSecurityLabelDefPtr secdef = + virDomainDefGetSecurityLabelDef(def, SECURITY_APPARMOR_NAME); + + if (!secdef) + return -1;
if (secdef->norelabel) return 0; @@ -666,7 +705,11 @@ static int AppArmorSecurityVerify(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, virDomainDefPtr def) { - const virSecurityLabelDefPtr secdef = &def->seclabel; + const virSecurityLabelDefPtr secdef = + virDomainDefGetSecurityLabelDef(def, SECURITY_APPARMOR_NAME); + + if (!secdef) + return -1;
if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC) { if (use_apparmor() < 0 || profile_status(secdef->label, 0) < 0) { @@ -694,9 +737,13 @@ AppArmorSetSecurityHostdevLabel(virSecurityManagerPtr mgr, virDomainHostdevDefPtr dev)
{ - const virSecurityLabelDefPtr secdef = &def->seclabel; struct SDPDOP *ptr; int ret = -1; + const virSecurityLabelDefPtr secdef = + virDomainDefGetSecurityLabelDef(def, SECURITY_APPARMOR_NAME); + + if (!secdef) + return -1;
if (secdef->norelabel) return 0; @@ -756,7 +803,12 @@ AppArmorRestoreSecurityHostdevLabel(virSecurityManagerPtr mgr, virDomainHostdevDefPtr dev ATTRIBUTE_UNUSED)
{ - const virSecurityLabelDefPtr secdef = &def->seclabel; + const virSecurityLabelDefPtr secdef = + virDomainDefGetSecurityLabelDef(def, SECURITY_APPARMOR_NAME); + + if (!secdef) + return -1; + if (secdef->norelabel) return 0;
@@ -789,7 +841,11 @@ AppArmorSetImageFDLabel(virSecurityManagerPtr mgr, char *proc = NULL; char *fd_path = NULL;
- const virSecurityLabelDefPtr secdef = &def->seclabel; + const virSecurityLabelDefPtr secdef = + virDomainDefGetSecurityLabelDef(def, SECURITY_APPARMOR_NAME); + + if (!secdef) + return -1;
if (secdef->imagelabel == NULL) return 0; diff --git a/src/security/security_dac.c b/src/security/security_dac.c index 470861d..0badafb 100644 --- a/src/security/security_dac.c +++ b/src/security/security_dac.c @@ -33,6 +33,7 @@ #include "storage_file.h"
#define VIR_FROM_THIS VIR_FROM_SECURITY +#define SECURITY_DAC_NAME "dac"
typedef struct _virSecurityDACData virSecurityDACData; typedef virSecurityDACData *virSecurityDACDataPtr; @@ -64,6 +65,132 @@ void virSecurityDACSetDynamicOwnership(virSecurityManagerPtr mgr, priv->dynamicOwnership = dynamicOwnership; }
+static +int parseIds(const char *label, uid_t *uidPtr, gid_t *gidPtr) +{ + uid_t uid; + gid_t gid; + char *endptr = NULL; + + if (label == NULL) + return -1; + + uid = strtol(label, &endptr, 10); + if (endptr == NULL || *endptr != ':') + return -1; + + gid = strtol(endptr + 1, &endptr, 10); + if (endptr == NULL || *endptr != '\0') + return -1; + + if (uidPtr) + *uidPtr = uid; + if (gidPtr) + *gidPtr = gid; + return 0; +} + +static +int virSecurityDACParseIds(virDomainDefPtr def, uid_t *uidPtr, gid_t *gidPtr) +{ + uid_t uid; + gid_t gid; + virSecurityLabelDefPtr seclabel; + + if (def == NULL) + return -1; + + seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_DAC_NAME); + if (seclabel == NULL) { + virSecurityReportError(VIR_ERR_INTERNAL_ERROR, + _("security label for DAC not found")); + return -1; + } + + if (seclabel->label && parseIds(seclabel->label, &uid, &gid)) { + virSecurityReportError(VIR_ERR_INTERNAL_ERROR, + _("failed to parse uid and gid for DAC " + "securit driver")); + return -1; + } + + if (uidPtr) + *uidPtr = uid; + if (gidPtr) + *gidPtr = gid; + + return 0; +} + +static +int virSecurityDACGetIds(virDomainDefPtr def, virSecurityDACDataPtr priv, + uid_t *uidPtr, gid_t *gidPtr) +{ + if (virSecurityDACParseIds(def, uidPtr, gidPtr) == 0) + return 0; + + if (priv) { + if (uidPtr) + *uidPtr = priv->user; + if (gidPtr) + *gidPtr = priv->group; + return 0; + } + return -1; +} + +static +int virSecurityDACParseImageIds(virDomainDefPtr def, + uid_t *uidPtr, gid_t *gidPtr) +{ + uid_t uid; + gid_t gid; + virSecurityLabelDefPtr seclabel; + + if (def == NULL) + return -1; + + seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_DAC_NAME); + if (seclabel == NULL) { + virSecurityReportError(VIR_ERR_INTERNAL_ERROR, + _("security label for DAC not found")); + return -1; + } + + if (seclabel->imagelabel + && parseIds(seclabel->imagelabel, &uid, &gid)) { + virSecurityReportError(VIR_ERR_INTERNAL_ERROR, + _("failed to parse uid and gid for DAC " + "securit driver")); + return -1; + } + + if (uidPtr) + *uidPtr = uid; + if (gidPtr) + *gidPtr = gid; + + return 0; +} + +static +int virSecurityDACGetImageIds(virDomainDefPtr def, virSecurityDACDataPtr priv, + uid_t *uidPtr, gid_t *gidPtr) +{ + if (virSecurityDACParseImageIds(def, uidPtr, gidPtr) == 0) + return 0; + + if (priv) { + if (uidPtr) + *uidPtr = priv->user; + if (gidPtr) + *gidPtr = priv->group; + return 0; + } + return -1; +} + + static virSecurityDriverStatus virSecurityDACProbe(const char *virtDriver ATTRIBUTE_UNUSED) { @@ -85,7 +212,7 @@ virSecurityDACClose(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED)
static const char * virSecurityDACGetModel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED) { - return "dac"; + return SECURITY_DAC_NAME; }
static const char * virSecurityDACGetDOI(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED) @@ -167,10 +294,17 @@ virSecurityDACSetSecurityFileLabel(virDomainDiskDefPtr disk ATTRIBUTE_UNUSED, size_t depth ATTRIBUTE_UNUSED, void *opaque) { - virSecurityManagerPtr mgr = opaque; + void **params = opaque; + virSecurityManagerPtr mgr = params[0]; + virDomainDefPtr def = params[1]; virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr); + uid_t user; + gid_t group;
- return virSecurityDACSetOwnership(path, priv->user, priv->group); + if (virSecurityDACGetImageIds(def, priv, &user, &group)) + return -1; + + return virSecurityDACSetOwnership(path, user, group); }
@@ -180,6 +314,9 @@ virSecurityDACSetSecurityImageLabel(virSecurityManagerPtr mgr, virDomainDiskDefPtr disk)
{ + uid_t user; + gid_t group; + void *params[2]; virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
if (!priv->dynamicOwnership) @@ -188,12 +325,17 @@ virSecurityDACSetSecurityImageLabel(virSecurityManagerPtr mgr, if (disk->type == VIR_DOMAIN_DISK_TYPE_NETWORK) return 0;
+ if (virSecurityDACGetImageIds(def, priv, &user, &group)) + return -1; + + params[0] = mgr; + params[1] = def; return virDomainDiskDefForeachPath(disk, virSecurityManagerGetAllowDiskFormatProbing(mgr), false, - priv->user, priv->group, + user, group, virSecurityDACSetSecurityFileLabel, - mgr); + params); }
@@ -259,10 +401,17 @@ virSecurityDACSetSecurityPCILabel(pciDevice *dev ATTRIBUTE_UNUSED, const char *file, void *opaque) { - virSecurityManagerPtr mgr = opaque; + void **params = opaque; + virSecurityManagerPtr mgr = params[0]; + virDomainDefPtr def = params[1]; virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr); + uid_t user; + gid_t group; + + if (virSecurityDACGetIds(def, priv, &user, &group)) + return -1;
- return virSecurityDACSetOwnership(file, priv->user, priv->group); + return virSecurityDACSetOwnership(file, user, group); }
@@ -271,18 +420,26 @@ virSecurityDACSetSecurityUSBLabel(usbDevice *dev ATTRIBUTE_UNUSED, const char *file, void *opaque) { - virSecurityManagerPtr mgr = opaque; + void **params = opaque; + virSecurityManagerPtr mgr = params[0]; + virDomainDefPtr def = params[1]; virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr); + uid_t user; + gid_t group;
- return virSecurityDACSetOwnership(file, priv->user, priv->group); + if (virSecurityDACGetIds(def, priv, &user, &group)) + return -1; + + return virSecurityDACSetOwnership(file, user, group); }
static int virSecurityDACSetSecurityHostdevLabel(virSecurityManagerPtr mgr, - virDomainDefPtr def ATTRIBUTE_UNUSED, + virDomainDefPtr def, virDomainHostdevDefPtr dev) { + void *params[] = {mgr, def}; virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr); int ret = -1;
@@ -300,7 +457,8 @@ virSecurityDACSetSecurityHostdevLabel(virSecurityManagerPtr mgr, if (!usb) goto done;
- ret = usbDeviceFileIterate(usb, virSecurityDACSetSecurityUSBLabel, mgr); + ret = usbDeviceFileIterate(usb, virSecurityDACSetSecurityUSBLabel, + params); usbFreeDevice(usb); break; } @@ -314,7 +472,8 @@ virSecurityDACSetSecurityHostdevLabel(virSecurityManagerPtr mgr, if (!pci) goto done;
- ret = pciDeviceFileIterate(pci, virSecurityDACSetSecurityPCILabel, mgr); + ret = pciDeviceFileIterate(pci, virSecurityDACSetSecurityPCILabel, + params); pciFreeDevice(pci);
break; @@ -404,17 +563,23 @@ done:
static int virSecurityDACSetChardevLabel(virSecurityManagerPtr mgr, + virDomainDefPtr def, virDomainChrSourceDefPtr dev)
{ virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr); char *in = NULL, *out = NULL; int ret = -1; + uid_t user; + gid_t group; + + if (virSecurityDACGetIds(def, priv, &user, &group)) + return -1;
switch (dev->type) { case VIR_DOMAIN_CHR_TYPE_DEV: case VIR_DOMAIN_CHR_TYPE_FILE: - ret = virSecurityDACSetOwnership(dev->data.file.path, priv->user, priv->group); + ret = virSecurityDACSetOwnership(dev->data.file.path, user, group); break;
case VIR_DOMAIN_CHR_TYPE_PIPE: @@ -424,12 +589,12 @@ virSecurityDACSetChardevLabel(virSecurityManagerPtr mgr, goto done; } if (virFileExists(in) && virFileExists(out)) { - if ((virSecurityDACSetOwnership(in, priv->user, priv->group) < 0) || - (virSecurityDACSetOwnership(out, priv->user, priv->group) < 0)) { + if ((virSecurityDACSetOwnership(in, user, group) < 0) || + (virSecurityDACSetOwnership(out, user, group) < 0)) { goto done; } } else if (virSecurityDACSetOwnership(dev->data.file.path, - priv->user, priv->group) < 0) { + user, group) < 0) { goto done; } ret = 0; @@ -554,7 +719,7 @@ virSecurityDACSetChardevCallback(virDomainDefPtr def ATTRIBUTE_UNUSED, { virSecurityManagerPtr mgr = opaque;
- return virSecurityDACSetChardevLabel(mgr, &dev->source); + return virSecurityDACSetChardevLabel(mgr, def, &dev->source); }
@@ -565,6 +730,8 @@ virSecurityDACSetSecurityAllLabel(virSecurityManagerPtr mgr, { virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr); int i; + uid_t user; + gid_t group;
if (!priv->dynamicOwnership) return 0; @@ -591,16 +758,15 @@ virSecurityDACSetSecurityAllLabel(virSecurityManagerPtr mgr, mgr) < 0) return -1;
+ if (virSecurityDACGetImageIds(def, priv, &user, &group)) + return -1; + if (def->os.kernel && - virSecurityDACSetOwnership(def->os.kernel, - priv->user, - priv->group) < 0) + virSecurityDACSetOwnership(def->os.kernel, user, group) < 0) return -1;
if (def->os.initrd && - virSecurityDACSetOwnership(def->os.initrd, - priv->user, - priv->group) < 0) + virSecurityDACSetOwnership(def->os.initrd, user, group) < 0) return -1;
return 0; @@ -609,12 +775,17 @@ virSecurityDACSetSecurityAllLabel(virSecurityManagerPtr mgr,
static int virSecurityDACSetSavedStateLabel(virSecurityManagerPtr mgr, - virDomainDefPtr def ATTRIBUTE_UNUSED, + virDomainDefPtr def, const char *savefile) { + uid_t user; + gid_t group; virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
- return virSecurityDACSetOwnership(savefile, priv->user, priv->group); + if (virSecurityDACGetImageIds(def, priv, &user, &group)) + return -1; + + return virSecurityDACSetOwnership(savefile, user, group); }
@@ -636,12 +807,16 @@ static int virSecurityDACSetProcessLabel(virSecurityManagerPtr mgr, virDomainDefPtr def ATTRIBUTE_UNUSED) { + uid_t user; + gid_t group; virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
- VIR_DEBUG("Dropping privileges of DEF to %u:%u", - (unsigned int) priv->user, (unsigned int) priv->group); + if (virSecurityDACGetIds(def, priv, &user, &group)) + return -1; + + VIR_DEBUG("Dropping privileges of DEF to %u:%u", user, group);
- if (virSetUIDGID(priv->user, priv->group) < 0) + if (virSetUIDGID(user, group) < 0) return -1;
return 0; @@ -656,9 +831,83 @@ virSecurityDACVerify(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, }
static int -virSecurityDACGenLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, - virDomainDefPtr def ATTRIBUTE_UNUSED) +virSecurityDACGenLabel(virSecurityManagerPtr mgr, + virDomainDefPtr def) { + int rc = -1; + virSecurityLabelDefPtr seclabel; + virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr); + + if (mgr == NULL) { + virSecurityReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("invalid security driver")); + return rc; + } + + seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_DAC_NAME); + if (seclabel == NULL) { + return rc; + } + + if (seclabel->imagelabel) { + virSecurityReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("security image label already " + "defined for VM")); + return rc; + } + + if (seclabel->model + && STRNEQ(seclabel->model, SECURITY_DAC_NAME)) { + virSecurityReportError(VIR_ERR_INTERNAL_ERROR, + _("security label model %s is not supported " + "with selinux"), + seclabel->model); + return rc; + } + + switch(seclabel->type) { + case VIR_DOMAIN_SECLABEL_STATIC: + if (seclabel->label == NULL) { + virSecurityReportError(VIR_ERR_INTERNAL_ERROR, + _("missing label for static security " + "driver")); + return rc; + } + break; + case VIR_DOMAIN_SECLABEL_DYNAMIC: + if (asprintf(&seclabel->label, "%d:%d", priv->user, priv->group) < 0) { + virReportOOMError(); + return rc; + } + if (seclabel->label == NULL) { + virSecurityReportError(VIR_ERR_INTERNAL_ERROR, + _("cannot generate dac user and group id")); + return rc; + } + break; + case VIR_DOMAIN_SECLABEL_NONE: + /* no op */ + break; + default: + virSecurityReportError(VIR_ERR_INTERNAL_ERROR, + _("unexpected security label type '%s'"), + virDomainSeclabelTypeToString(seclabel->type)); + return rc; + } + + if (!seclabel->norelabel) { + if (seclabel->imagelabel == NULL) { + seclabel->imagelabel = strdup(seclabel->label); + if (seclabel->imagelabel == NULL) { + virSecurityReportError(VIR_ERR_INTERNAL_ERROR, + _("cannot generate dac user and group id")); + VIR_FREE(seclabel->label); + seclabel->label = NULL; + return rc; + } + } + } + return 0; }
@@ -683,6 +932,15 @@ virSecurityDACGetProcessLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, pid_t pid ATTRIBUTE_UNUSED, virSecurityLabelPtr seclabel ATTRIBUTE_UNUSED) { + virSecurityLabelDefPtr secdef = + virDomainDefGetSecurityLabelDef(def, SECURITY_DAC_NAME); + + if (!secdef || !seclabel) + return -1; + + if (secdef->label) + strcpy(seclabel->label, secdef->label); + return 0; }
@@ -724,7 +982,7 @@ static char *virSecurityDACGetMountOptions(virSecurityManagerPtr mgr ATTRIBUTE_U
virSecurityDriver virSecurityDriverDAC = { sizeof(virSecurityDACData), - "virDAC", + SECURITY_DAC_NAME,
virSecurityDACProbe, virSecurityDACOpen, diff --git a/src/security/security_manager.c b/src/security/security_manager.c index 8ec4d3e..a9ca824 100644 --- a/src/security/security_manager.c +++ b/src/security/security_manager.c @@ -68,8 +68,7 @@ static virSecurityManagerPtr virSecurityManagerNewDriver(virSecurityDriverPtr dr return mgr; }
-virSecurityManagerPtr virSecurityManagerNewStack(virSecurityManagerPtr primary, - virSecurityManagerPtr secondary) +virSecurityManagerPtr virSecurityManagerNewStack(virSecurityManagerPtr primary) { virSecurityManagerPtr mgr = virSecurityManagerNewDriver(&virSecurityDriverStack, @@ -81,12 +80,19 @@ virSecurityManagerPtr virSecurityManagerNewStack(virSecurityManagerPtr primary, if (!mgr) return NULL;
- virSecurityStackSetPrimary(mgr, primary); - virSecurityStackSetSecondary(mgr, secondary); + virSecurityStackAddPrimary(mgr, primary);
return mgr; }
+int virSecurityManagerStackAddNested(virSecurityManagerPtr stack, + virSecurityManagerPtr nested) +{ + if (!STREQ("stack", stack->drv->name)) + return -1; + return virSecurityStackAddNested(stack, nested); +} + virSecurityManagerPtr virSecurityManagerNewDAC(const char *virtDriver, uid_t user, gid_t group, @@ -308,25 +314,51 @@ int virSecurityManagerRestoreSavedStateLabel(virSecurityManagerPtr mgr, int virSecurityManagerGenLabel(virSecurityManagerPtr mgr, virDomainDefPtr vm) { - if (vm->seclabel.type == VIR_DOMAIN_SECLABEL_DEFAULT) { - if (mgr->defaultConfined) - vm->seclabel.type = VIR_DOMAIN_SECLABEL_DYNAMIC; - else - vm->seclabel.type = VIR_DOMAIN_SECLABEL_NONE; - } + int rc = 0; + size_t i; + virSecurityManagerPtr* sec_managers = NULL; + virSecurityLabelDefPtr seclabel;
- if ((vm->seclabel.type == VIR_DOMAIN_SECLABEL_NONE) && - mgr->requireConfined) { - virSecurityReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Unconfined guests are not allowed on this host")); + if (mgr == NULL || mgr->drv == NULL) return -1; - }
- if (mgr->drv->domainGenSecurityLabel) - return mgr->drv->domainGenSecurityLabel(mgr, vm); + if ((sec_managers = virSecurityManagerGetNested(mgr)) == NULL) + return -1;
- virSecurityReportError(VIR_ERR_NO_SUPPORT, __FUNCTION__); - return -1; + for (i = 0; sec_managers[i]; i++) { + seclabel = virDomainDefGetSecurityLabelDef(vm, + sec_managers[i]->drv->name); + if (seclabel == NULL) { + rc = -1; + goto cleanup; + } + + if (seclabel->type == VIR_DOMAIN_SECLABEL_DEFAULT) { + if (sec_managers[i]->defaultConfined) + seclabel->type = VIR_DOMAIN_SECLABEL_DYNAMIC; + else + seclabel->type = VIR_DOMAIN_SECLABEL_NONE; + } + + if ((seclabel->type == VIR_DOMAIN_SECLABEL_NONE) && + sec_managers[i]->requireConfined) { + virSecurityReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Unconfined guests are not allowed on this host")); + return -1; + } + + if (!sec_managers[i]->drv->domainGenSecurityLabel) { + virSecurityReportError(VIR_ERR_NO_SUPPORT, __FUNCTION__); + } else { + rc += sec_managers[i]->drv->domainGenSecurityLabel(sec_managers[i], vm); + if (rc) + goto cleanup; + } + } + +cleanup: + VIR_FREE(sec_managers); + return rc; }
int virSecurityManagerReserveLabel(virSecurityManagerPtr mgr, @@ -397,12 +429,17 @@ int virSecurityManagerSetProcessLabel(virSecurityManagerPtr mgr, int virSecurityManagerVerify(virSecurityManagerPtr mgr, virDomainDefPtr def) { - const virSecurityLabelDefPtr secdef = &def->seclabel; + virSecurityLabelDefPtr secdef; + + if (mgr == NULL || mgr->drv == NULL) + return 0; + /* NULL model == dynamic labelling, with whatever driver * is active, so we can short circuit verify check to * avoid drivers de-referencing NULLs by accident */ - if (!secdef->model) + secdef = virDomainDefGetSecurityLabelDef(def, mgr->drv->name); + if (secdef == NULL || secdef->model == NULL) return 0;
if (mgr->drv->domainSecurityVerify) @@ -435,3 +472,23 @@ char *virSecurityManagerGetMountOptions(virSecurityManagerPtr mgr, */ return NULL; } + +virSecurityManagerPtr* +virSecurityManagerGetNested(virSecurityManagerPtr mgr) +{ + virSecurityManagerPtr* list = NULL; + + if (STREQ("stack", mgr->drv->name)) { + return virSecurityStackGetNested(mgr); + } + + if (VIR_ALLOC_N(list, 2) < 0) { + virReportOOMError(); + return NULL; + } + + list[0] = mgr; + list[1] = NULL; + return list; +} +
Again, blank newline on the EOF.
diff --git a/src/security/security_manager.h b/src/security/security_manager.h index f0bf60d..f86b84d 100644 --- a/src/security/security_manager.h +++ b/src/security/security_manager.h @@ -37,8 +37,9 @@ virSecurityManagerPtr virSecurityManagerNew(const char *name, bool defaultConfined, bool requireConfined);
-virSecurityManagerPtr virSecurityManagerNewStack(virSecurityManagerPtr primary, - virSecurityManagerPtr secondary); +virSecurityManagerPtr virSecurityManagerNewStack(virSecurityManagerPtr primary); +int virSecurityManagerStackAddNested(virSecurityManagerPtr stack, + virSecurityManagerPtr nested);
virSecurityManagerPtr virSecurityManagerNewDAC(const char *virtDriver, uid_t user, @@ -109,4 +110,7 @@ int virSecurityManagerSetImageFDLabel(virSecurityManagerPtr mgr, int fd); char *virSecurityManagerGetMountOptions(virSecurityManagerPtr mgr, virDomainDefPtr vm); +virSecurityManagerPtr* +virSecurityManagerGetNested(virSecurityManagerPtr mgr); + #endif /* VIR_SECURITY_MANAGER_H__ */ diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c index 2b8ff19..fe318be 100644 --- a/src/security/security_selinux.c +++ b/src/security/security_selinux.c @@ -271,46 +271,52 @@ SELinuxGenSecurityLabel(virSecurityManagerPtr mgr, int c2 = 0; context_t ctx = NULL; const char *range; - virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr); + virSecurityLabelDefPtr seclabel; + virSecuritySELinuxDataPtr data;
- VIR_DEBUG("SELinuxGenSecurityLabel %s", virSecurityManagerGetDriver(mgr)); - if ((def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC) && - !def->seclabel.baselabel && - def->seclabel.model) { + if (mgr == NULL) { virSecurityReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("security model already defined for VM")); + "%s", _("invalid security driver")); + return rc; + } + + seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME); + if (seclabel == NULL) { return rc; }
- if (def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC && - def->seclabel.label) { + data = virSecurityManagerGetPrivateData(mgr); + + VIR_DEBUG("SELinuxGenSecurityLabel %s", virSecurityManagerGetDriver(mgr)); + if (seclabel->type == VIR_DOMAIN_SECLABEL_DYNAMIC && + seclabel->label) { virSecurityReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("security label already defined for VM")); return rc; }
- if (def->seclabel.imagelabel) { + if (seclabel->imagelabel) { virSecurityReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("security image label already defined for VM")); return rc; }
- if (def->seclabel.model && - STRNEQ(def->seclabel.model, SECURITY_SELINUX_NAME)) { + if (seclabel->model && + STRNEQ(seclabel->model, SECURITY_SELINUX_NAME)) { virSecurityReportError(VIR_ERR_INTERNAL_ERROR, _("security label model %s is not supported with selinux"), - def->seclabel.model); + seclabel->model); return rc; }
- VIR_DEBUG("SELinuxGenSecurityLabel %d", def->seclabel.type); + VIR_DEBUG("SELinuxGenSecurityLabel %d", seclabel->type);
- switch (def->seclabel.type) { + switch (seclabel->type) { case VIR_DOMAIN_SECLABEL_STATIC: - if (!(ctx = context_new(def->seclabel.label)) ) { + if (!(ctx = context_new(seclabel->label)) ) { virReportSystemError(errno, _("unable to allocate socket security context '%s'"), - def->seclabel.label); + seclabel->label); return rc; }
@@ -345,11 +351,11 @@ SELinuxGenSecurityLabel(virSecurityManagerPtr mgr, } } while (mcsAdd(mcs) == -1);
- def->seclabel.label = - SELinuxGenNewContext(def->seclabel.baselabel ? - def->seclabel.baselabel : + seclabel->label = + SELinuxGenNewContext(seclabel->baselabel ? + seclabel->baselabel : data->domain_context, mcs); - if (! def->seclabel.label) { + if (! seclabel->label) { virSecurityReportError(VIR_ERR_INTERNAL_ERROR, _("cannot generate selinux context for %s"), mcs); goto cleanup; @@ -363,21 +369,21 @@ SELinuxGenSecurityLabel(virSecurityManagerPtr mgr, default: virSecurityReportError(VIR_ERR_INTERNAL_ERROR, _("unexpected security label type '%s'"), - virDomainSeclabelTypeToString(def->seclabel.type)); + virDomainSeclabelTypeToString(seclabel->type)); goto cleanup; }
- if (!def->seclabel.norelabel) { - def->seclabel.imagelabel = SELinuxGenNewContext(data->file_context, mcs); - if (!def->seclabel.imagelabel) { + if (!seclabel->norelabel) { + seclabel->imagelabel = SELinuxGenNewContext(data->domain_context, mcs); + if (!seclabel->imagelabel) { virSecurityReportError(VIR_ERR_INTERNAL_ERROR, _("cannot generate selinux context for %s"), mcs); goto cleanup; } }
- if (!def->seclabel.model && - !(def->seclabel.model = strdup(SECURITY_SELINUX_NAME))) { + if (!seclabel->model && + !(seclabel->model = strdup(SECURITY_SELINUX_NAME))) { virReportOOMError(); goto cleanup; } @@ -386,12 +392,12 @@ SELinuxGenSecurityLabel(virSecurityManagerPtr mgr,
cleanup: if (rc != 0) { - if (def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC) - VIR_FREE(def->seclabel.label); - VIR_FREE(def->seclabel.imagelabel); - if (def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC && - !def->seclabel.baselabel) - VIR_FREE(def->seclabel.model); + if (seclabel->type == VIR_DOMAIN_SECLABEL_DYNAMIC) + VIR_FREE(seclabel->label); + VIR_FREE(seclabel->imagelabel); + if (seclabel->type == VIR_DOMAIN_SECLABEL_DYNAMIC && + !seclabel->baselabel) + VIR_FREE(seclabel->model); }
if (ctx) @@ -400,10 +406,10 @@ cleanup: VIR_FREE(mcs);
VIR_DEBUG("model=%s label=%s imagelabel=%s baselabel=%s", - NULLSTR(def->seclabel.model), - NULLSTR(def->seclabel.label), - NULLSTR(def->seclabel.imagelabel), - NULLSTR(def->seclabel.baselabel)); + NULLSTR(seclabel->model), + NULLSTR(seclabel->label), + NULLSTR(seclabel->imagelabel), + NULLSTR(seclabel->baselabel));
return rc; } @@ -416,8 +422,14 @@ SELinuxReserveSecurityLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, security_context_t pctx; context_t ctx = NULL; const char *mcs; + virSecurityLabelDefPtr seclabel; + + seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME); + if (seclabel == NULL) { + return -1; + }
- if (def->seclabel.type == VIR_DOMAIN_SECLABEL_STATIC) + if (seclabel->type == VIR_DOMAIN_SECLABEL_STATIC) return 0;
if (getpidcon(pid, &pctx) == -1) { @@ -709,9 +721,16 @@ SELinuxRestoreSecurityImageLabelInt(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, virDomainDiskDefPtr disk, int migrated) { - const virSecurityLabelDefPtr secdef = &def->seclabel; + virSecurityLabelDefPtr seclabel; + virSecurityDeviceLabelDefPtr disk_seclabel;
- if (secdef->norelabel || (disk->seclabel && disk->seclabel->norelabel)) + seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME); + if (seclabel == NULL) + return -1; + + disk_seclabel = virDomainDiskDefGetSecurityLabelDef(disk, + SECURITY_SELINUX_NAME); + if (seclabel->norelabel || (disk_seclabel && disk_seclabel->norelabel)) return 0;
/* Don't restore labels on readoly/shared disks, because @@ -763,17 +782,21 @@ SELinuxSetSecurityFileLabel(virDomainDiskDefPtr disk, size_t depth, void *opaque) { + int ret; + virSecurityDeviceLabelDefPtr disk_seclabel; virSecuritySELinuxCallbackDataPtr cbdata = opaque; const virSecurityLabelDefPtr secdef = cbdata->secdef; - int ret; virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(cbdata->manager);
- if (disk->seclabel && disk->seclabel->norelabel) + disk_seclabel = virDomainDiskDefGetSecurityLabelDef(disk, + SECURITY_SELINUX_NAME); + + if (disk_seclabel && disk_seclabel->norelabel) return 0;
- if (disk->seclabel && !disk->seclabel->norelabel && - disk->seclabel->label) { - ret = SELinuxSetFilecon(path, disk->seclabel->label); + if (disk_seclabel && !disk_seclabel->norelabel && + disk_seclabel->label) { + ret = SELinuxSetFilecon(path, disk_seclabel->label); } else if (depth == 0) {
if (disk->shared) { @@ -788,14 +811,14 @@ SELinuxSetSecurityFileLabel(virDomainDiskDefPtr disk, } else { ret = SELinuxSetFileconOptional(path, data->content_context); } - if (ret == 1 && !disk->seclabel) { + if (ret == 1 && !disk_seclabel) { /* If we failed to set a label, but virt_use_nfs let us * proceed anyway, then we don't need to relabel later. */ - if (VIR_ALLOC(disk->seclabel) < 0) { + if (VIR_ALLOC(disk_seclabel) < 0) { virReportOOMError(); return -1; } - disk->seclabel->norelabel = true; + disk_seclabel->norelabel = true; ret = 0; } return ret; @@ -807,11 +830,15 @@ SELinuxSetSecurityImageLabel(virSecurityManagerPtr mgr, virDomainDiskDefPtr disk)
{ + bool allowDiskFormatProbing; virSecuritySELinuxCallbackData cbdata; - cbdata.secdef = &def->seclabel; cbdata.manager = mgr; + cbdata.secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
- bool allowDiskFormatProbing = virSecurityManagerGetAllowDiskFormatProbing(mgr); + allowDiskFormatProbing = virSecurityManagerGetAllowDiskFormatProbing(mgr); + + if (cbdata.secdef == NULL) + return -1;
if (cbdata.secdef->norelabel) return 0; @@ -838,9 +865,12 @@ static int SELinuxSetSecurityPCILabel(pciDevice *dev ATTRIBUTE_UNUSED, const char *file, void *opaque) { + virSecurityLabelDefPtr secdef; virDomainDefPtr def = opaque; - const virSecurityLabelDefPtr secdef = &def->seclabel;
+ secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME); + if (secdef == NULL) + return -1; return SELinuxSetFilecon(file, secdef->imagelabel); }
@@ -848,8 +878,12 @@ static int SELinuxSetSecurityUSBLabel(usbDevice *dev ATTRIBUTE_UNUSED, const char *file, void *opaque) { + virSecurityLabelDefPtr secdef; virDomainDefPtr def = opaque; - const virSecurityLabelDefPtr secdef = &def->seclabel; + + secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME); + if (secdef == NULL) + return -1;
return SELinuxSetFilecon(file, secdef->imagelabel); } @@ -860,9 +894,13 @@ SELinuxSetSecurityHostdevLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, virDomainHostdevDefPtr dev)
{ - const virSecurityLabelDefPtr secdef = &def->seclabel; + virSecurityLabelDefPtr secdef; int ret = -1;
+ secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME); + if (secdef == NULL) + return -1; + if (secdef->norelabel) return 0;
@@ -929,9 +967,13 @@ SELinuxRestoreSecurityHostdevLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, virDomainHostdevDefPtr dev)
{ - const virSecurityLabelDefPtr secdef = &def->seclabel; + virSecurityLabelDefPtr secdef; int ret = -1;
+ secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME); + if (secdef == NULL) + return -1; + if (secdef->norelabel) return 0;
@@ -982,10 +1024,14 @@ SELinuxSetSecurityChardevLabel(virDomainDefPtr def, virDomainChrSourceDefPtr dev)
{ - const virSecurityLabelDefPtr secdef = &def->seclabel; + virSecurityLabelDefPtr secdef; char *in = NULL, *out = NULL; int ret = -1;
+ secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME); + if (secdef == NULL) + return -1; + if (secdef->norelabel) return 0;
@@ -1028,10 +1074,14 @@ SELinuxRestoreSecurityChardevLabel(virDomainDefPtr def, virDomainChrSourceDefPtr dev)
{ - const virSecurityLabelDefPtr secdef = &def->seclabel; + virSecurityLabelDefPtr secdef; char *in = NULL, *out = NULL; int ret = -1;
+ secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME); + if (secdef == NULL) + return -1; + if (secdef->norelabel) return 0;
@@ -1121,12 +1171,16 @@ SELinuxRestoreSecurityAllLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, virDomainDefPtr def, int migrated ATTRIBUTE_UNUSED) { - const virSecurityLabelDefPtr secdef = &def->seclabel; + virSecurityLabelDefPtr secdef; int i; int rc = 0;
VIR_DEBUG("Restoring security label on %s", def->name);
+ secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME); + if (secdef == NULL) + return -1; + if (secdef->norelabel) return 0;
@@ -1171,7 +1225,11 @@ static int SELinuxReleaseSecurityLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, virDomainDefPtr def) { - const virSecurityLabelDefPtr secdef = &def->seclabel; + virSecurityLabelDefPtr secdef; + + secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME); + if (secdef == NULL) + return -1;
if (secdef->type == VIR_DOMAIN_SECLABEL_DYNAMIC) { if (secdef->label != NULL) { @@ -1196,7 +1254,11 @@ SELinuxSetSavedStateLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, virDomainDefPtr def, const char *savefile) { - const virSecurityLabelDefPtr secdef = &def->seclabel; + virSecurityLabelDefPtr secdef; + + secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME); + if (secdef == NULL) + return -1;
if (secdef->norelabel) return 0; @@ -1210,7 +1272,11 @@ SELinuxRestoreSavedStateLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, virDomainDefPtr def, const char *savefile) { - const virSecurityLabelDefPtr secdef = &def->seclabel; + virSecurityLabelDefPtr secdef; + + secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME); + if (secdef == NULL) + return -1;
if (secdef->norelabel) return 0; @@ -1223,7 +1289,12 @@ static int SELinuxSecurityVerify(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, virDomainDefPtr def) { - const virSecurityLabelDefPtr secdef = &def->seclabel; + virSecurityLabelDefPtr secdef; + + secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME); + if (secdef == NULL) + return -1; + if (!STREQ(virSecurityManagerGetModel(mgr), secdef->model)) { virSecurityReportError(VIR_ERR_INTERNAL_ERROR, _("security label driver mismatch: " @@ -1248,12 +1319,16 @@ SELinuxSetSecurityProcessLabel(virSecurityManagerPtr mgr, virDomainDefPtr def) { /* TODO: verify DOI */ - const virSecurityLabelDefPtr secdef = &def->seclabel; - VIR_DEBUG("SELinuxSetSecurityProcessLabel %s", secdef->label); + virSecurityLabelDefPtr secdef;
- if (def->seclabel.label == NULL) + secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME); + if (secdef == NULL) + return -1; + + if (secdef->label == NULL) return 0;
+ VIR_DEBUG("SELinuxSetSecurityProcessLabel %s", secdef->label); if (!STREQ(virSecurityManagerGetModel(mgr), secdef->model)) { virSecurityReportError(VIR_ERR_INTERNAL_ERROR, _("security label driver mismatch: " @@ -1280,13 +1355,17 @@ SELinuxSetSecurityDaemonSocketLabel(virSecurityManagerPtr mgr, virDomainDefPtr def) { /* TODO: verify DOI */ - const virSecurityLabelDefPtr secdef = &def->seclabel; + virSecurityLabelDefPtr secdef; context_t execcon = NULL; context_t proccon = NULL; security_context_t scon = NULL; int rc = -1;
- if (def->seclabel.label == NULL) + secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME); + if (secdef == NULL) + return -1; + + if (secdef->label == NULL) return 0;
if (!STREQ(virSecurityManagerGetModel(mgr), secdef->model)) { @@ -1350,9 +1429,13 @@ static int SELinuxSetSecuritySocketLabel(virSecurityManagerPtr mgr, virDomainDefPtr vm) { - const virSecurityLabelDefPtr secdef = &vm->seclabel; + virSecurityLabelDefPtr secdef; int rc = -1;
+ secdef = virDomainDefGetSecurityLabelDef(vm, SECURITY_SELINUX_NAME); + if (secdef == NULL) + return -1; + if (secdef->label == NULL) return 0;
@@ -1388,9 +1471,13 @@ SELinuxClearSecuritySocketLabel(virSecurityManagerPtr mgr, virDomainDefPtr def) { /* TODO: verify DOI */ - const virSecurityLabelDefPtr secdef = &def->seclabel; + virSecurityLabelDefPtr secdef; + + secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME); + if (secdef == NULL) + return -1;
- if (def->seclabel.label == NULL) + if (secdef->label == NULL) return 0;
if (!STREQ(virSecurityManagerGetModel(mgr), secdef->model)) { @@ -1466,9 +1553,13 @@ SELinuxSetSecurityAllLabel(virSecurityManagerPtr mgr, virDomainDefPtr def, const char *stdin_path) { - virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr); - const virSecurityLabelDefPtr secdef = &def->seclabel; int i; + virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr); + virSecurityLabelDefPtr secdef; + + secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME); + if (secdef == NULL) + return -1;
if (secdef->norelabel) return 0; @@ -1528,7 +1619,11 @@ SELinuxSetImageFDLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, virDomainDefPtr def, int fd) { - const virSecurityLabelDefPtr secdef = &def->seclabel; + virSecurityLabelDefPtr secdef; + + secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME); + if (secdef == NULL) + return -1;
if (secdef->imagelabel == NULL) return 0; @@ -1538,13 +1633,17 @@ SELinuxSetImageFDLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
static char *genImageLabel(virSecurityManagerPtr mgr, virDomainDefPtr def) { - const virSecurityLabelDefPtr secdef = &def->seclabel; + virSecurityLabelDefPtr secdef; virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr); const char *range; context_t ctx = NULL; char *label = NULL; const char *mcs = NULL;
+ secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME); + if (secdef == NULL) + goto cleanup; + if (secdef->label) { ctx = context_new(secdef->label); if (!ctx) { @@ -1575,7 +1674,11 @@ cleanup: static char *SELinuxGetSecurityMountOptions(virSecurityManagerPtr mgr, virDomainDefPtr def) { char *opts = NULL; - const virSecurityLabelDefPtr secdef = &def->seclabel; + virSecurityLabelDefPtr secdef; + + secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME); + if (secdef == NULL) + return NULL;
if (! secdef->imagelabel) secdef->imagelabel = genImageLabel(mgr,def); diff --git a/src/security/security_stack.c b/src/security/security_stack.c index 6ecd099..dd0aebc 100644 --- a/src/security/security_stack.c +++ b/src/security/security_stack.c @@ -23,29 +23,70 @@ #include "security_stack.h"
#include "virterror_internal.h" +#include "memory.h"
#define VIR_FROM_THIS VIR_FROM_SECURITY
typedef struct _virSecurityStackData virSecurityStackData; typedef virSecurityStackData *virSecurityStackDataPtr; +typedef struct _virSecurityStackItem virSecurityStackItem; +typedef virSecurityStackItem* virSecurityStackItemPtr; + +struct _virSecurityStackItem { + virSecurityManagerPtr securityManager; + virSecurityStackItemPtr next; +};
struct _virSecurityStackData { virSecurityManagerPtr primary; - virSecurityManagerPtr secondary; + virSecurityStackItemPtr itemsHead; };
-void virSecurityStackSetPrimary(virSecurityManagerPtr mgr, - virSecurityManagerPtr primary) +int +virSecurityStackAddPrimary(virSecurityManagerPtr mgr, + virSecurityManagerPtr primary) { virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr); + if (virSecurityStackAddNested(mgr, primary) < 0) + return -1; priv->primary = primary; + return 0; +} + +int +virSecurityStackAddNested(virSecurityManagerPtr mgr, + virSecurityManagerPtr nested) +{ + virSecurityStackItemPtr item = NULL; + virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr); + + if (VIR_ALLOC(item) < 0) { + virReportOOMError(); + return -1; + } + item->securityManager = nested; + item->next = priv->itemsHead; + priv->itemsHead = item; + return 0; +} + +virSecurityManagerPtr +virSecurityStackGetPrimary(virSecurityManagerPtr mgr) +{ + virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr); + return (priv->primary) ? priv->primary : priv->itemsHead->securityManager; +} + +void virSecurityStackSetPrimary(virSecurityManagerPtr mgr, + virSecurityManagerPtr primary) +{ + virSecurityStackAddPrimary(mgr, primary); }
void virSecurityStackSetSecondary(virSecurityManagerPtr mgr, virSecurityManagerPtr secondary) { - virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr); - priv->secondary = secondary; + virSecurityStackAddNested(mgr, secondary); }
static virSecurityDriverStatus @@ -64,9 +105,14 @@ static int virSecurityStackClose(virSecurityManagerPtr mgr) { virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr); + virSecurityStackItemPtr next, item = priv->itemsHead;
- virSecurityManagerFree(priv->primary); - virSecurityManagerFree(priv->secondary); + while (item) { + next = item->next; + virSecurityManagerFree(item->securityManager); + VIR_FREE(item); + item = next; + }
return 0; } @@ -74,17 +120,13 @@ virSecurityStackClose(virSecurityManagerPtr mgr) static const char * virSecurityStackGetModel(virSecurityManagerPtr mgr) { - virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr); - - return virSecurityManagerGetModel(priv->primary); + return virSecurityManagerGetModel(virSecurityStackGetPrimary(mgr)); }
static const char * virSecurityStackGetDOI(virSecurityManagerPtr mgr) { - virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr); - - return virSecurityManagerGetDOI(priv->primary); + return virSecurityManagerGetDOI(virSecurityStackGetPrimary(mgr)); }
static int @@ -92,13 +134,13 @@ virSecurityStackVerify(virSecurityManagerPtr mgr, virDomainDefPtr def) { virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr); + virSecurityStackItemPtr item = priv->itemsHead; int rc = 0;
- if (virSecurityManagerVerify(priv->primary, def) < 0) - rc = -1; - - if (virSecurityManagerVerify(priv->secondary, def) < 0) - rc = -1; + for(; item; item = item->next) { + if (virSecurityManagerVerify(item->securityManager, def) < 0) + rc = -1; + }
return rc; } @@ -108,12 +150,12 @@ static int virSecurityStackGenLabel(virSecurityManagerPtr mgr, virDomainDefPtr vm) { - virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr); int rc = 0;
- if (virSecurityManagerGenLabel(priv->primary, vm) < 0) + if (virSecurityManagerGenLabel(virSecurityStackGetPrimary(mgr), vm) < 0) rc = -1;
+// TODO #if 0 /* We don't allow secondary drivers to generate labels. * This may have to change in the future, but requires @@ -133,11 +175,12 @@ static int virSecurityStackReleaseLabel(virSecurityManagerPtr mgr, virDomainDefPtr vm) { - virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr); int rc = 0;
- if (virSecurityManagerReleaseLabel(priv->primary, vm) < 0) + if (virSecurityManagerReleaseLabel(virSecurityStackGetPrimary(mgr), vm) < 0) rc = -1; + +// TODO #if 0 /* XXX See note in GenLabel */ if (virSecurityManagerReleaseLabel(priv->secondary, vm) < 0) @@ -153,11 +196,11 @@ virSecurityStackReserveLabel(virSecurityManagerPtr mgr, virDomainDefPtr vm, pid_t pid) { - virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr); int rc = 0;
- if (virSecurityManagerReserveLabel(priv->primary, vm, pid) < 0) + if (virSecurityManagerReserveLabel(virSecurityStackGetPrimary(mgr), vm, pid) < 0) rc = -1; +// TODO #if 0 /* XXX See note in GenLabel */ if (virSecurityManagerReserveLabel(priv->secondary, vm, pid) < 0) @@ -174,12 +217,13 @@ virSecurityStackSetSecurityImageLabel(virSecurityManagerPtr mgr, virDomainDiskDefPtr disk) { virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr); + virSecurityStackItemPtr item = priv->itemsHead; int rc = 0;
- if (virSecurityManagerSetImageLabel(priv->secondary, vm, disk) < 0) - rc = -1; - if (virSecurityManagerSetImageLabel(priv->primary, vm, disk) < 0) - rc = -1; + for (; item; item = item->next) { + if (virSecurityManagerSetImageLabel(item->securityManager, vm, disk) < 0) + rc = -1; + }
return rc; } @@ -191,12 +235,13 @@ virSecurityStackRestoreSecurityImageLabel(virSecurityManagerPtr mgr, virDomainDiskDefPtr disk) { virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr); + virSecurityStackItemPtr item = priv->itemsHead; int rc = 0;
- if (virSecurityManagerRestoreImageLabel(priv->secondary, vm, disk) < 0) - rc = -1; - if (virSecurityManagerRestoreImageLabel(priv->primary, vm, disk) < 0) - rc = -1; + for (; item; item = item->next) { + if (virSecurityManagerRestoreImageLabel(item->securityManager, vm, disk) < 0) + rc = -1; + }
return rc; } @@ -209,12 +254,13 @@ virSecurityStackSetSecurityHostdevLabel(virSecurityManagerPtr mgr,
{ virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr); + virSecurityStackItemPtr item = priv->itemsHead; int rc = 0;
- if (virSecurityManagerSetHostdevLabel(priv->secondary, vm, dev) < 0) - rc = -1; - if (virSecurityManagerSetHostdevLabel(priv->primary, vm, dev) < 0) - rc = -1; + for (; item; item = item->next) { + if (virSecurityManagerSetHostdevLabel(item->securityManager, vm, dev) < 0) + rc = -1; + }
return rc; } @@ -226,12 +272,13 @@ virSecurityStackRestoreSecurityHostdevLabel(virSecurityManagerPtr mgr, virDomainHostdevDefPtr dev) { virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr); + virSecurityStackItemPtr item = priv->itemsHead; int rc = 0;
- if (virSecurityManagerRestoreHostdevLabel(priv->secondary, vm, dev) < 0) - rc = -1; - if (virSecurityManagerRestoreHostdevLabel(priv->primary, vm, dev) < 0) - rc = -1; + for (; item; item = item->next) { + if (virSecurityManagerRestoreHostdevLabel(item->securityManager, vm, dev) < 0) + rc = -1; + }
return rc; } @@ -243,12 +290,13 @@ virSecurityStackSetSecurityAllLabel(virSecurityManagerPtr mgr, const char *stdin_path) { virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr); + virSecurityStackItemPtr item = priv->itemsHead; int rc = 0;
- if (virSecurityManagerSetAllLabel(priv->secondary, vm, stdin_path) < 0) - rc = -1; - if (virSecurityManagerSetAllLabel(priv->primary, vm, stdin_path) < 0) - rc = -1; + for (; item; item = item->next) { + if (virSecurityManagerSetAllLabel(item->securityManager, vm, stdin_path) < 0) + rc = -1; + }
return rc; } @@ -260,12 +308,13 @@ virSecurityStackRestoreSecurityAllLabel(virSecurityManagerPtr mgr, int migrated) { virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr); + virSecurityStackItemPtr item = priv->itemsHead; int rc = 0;
- if (virSecurityManagerRestoreAllLabel(priv->secondary, vm, migrated) < 0) - rc = -1; - if (virSecurityManagerRestoreAllLabel(priv->primary, vm, migrated) < 0) - rc = -1; + for (; item; item = item->next) { + if (virSecurityManagerRestoreAllLabel(item->securityManager, vm, migrated) < 0) + rc = -1; + }
return rc; } @@ -277,12 +326,13 @@ virSecurityStackSetSavedStateLabel(virSecurityManagerPtr mgr, const char *savefile) { virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr); + virSecurityStackItemPtr item = priv->itemsHead; int rc = 0;
- if (virSecurityManagerSetSavedStateLabel(priv->secondary, vm, savefile) < 0) - rc = -1; - if (virSecurityManagerSetSavedStateLabel(priv->primary, vm, savefile) < 0) - rc = -1; + for (; item; item = item->next) { + if (virSecurityManagerSetSavedStateLabel(item->securityManager, vm, savefile) < 0) + rc = -1; + }
return rc; } @@ -294,12 +344,13 @@ virSecurityStackRestoreSavedStateLabel(virSecurityManagerPtr mgr, const char *savefile) { virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr); + virSecurityStackItemPtr item = priv->itemsHead; int rc = 0;
- if (virSecurityManagerRestoreSavedStateLabel(priv->secondary, vm, savefile) < 0) - rc = -1; - if (virSecurityManagerRestoreSavedStateLabel(priv->primary, vm, savefile) < 0) - rc = -1; + for (; item; item = item->next) { + if (virSecurityManagerRestoreSavedStateLabel(item->securityManager, vm, savefile) < 0) + rc = -1; + }
return rc; } @@ -310,12 +361,13 @@ virSecurityStackSetProcessLabel(virSecurityManagerPtr mgr, virDomainDefPtr vm) { virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr); + virSecurityStackItemPtr item = priv->itemsHead; int rc = 0;
- if (virSecurityManagerSetProcessLabel(priv->secondary, vm) < 0) - rc = -1; - if (virSecurityManagerSetProcessLabel(priv->primary, vm) < 0) - rc = -1; + for (; item; item = item->next) { + if (virSecurityManagerSetProcessLabel(item->securityManager, vm) < 0) + rc = -1; + }
return rc; } @@ -326,14 +378,14 @@ virSecurityStackGetProcessLabel(virSecurityManagerPtr mgr, pid_t pid, virSecurityLabelPtr seclabel) { - virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr); int rc = 0;
+// TODO #if 0 if (virSecurityManagerGetProcessLabel(priv->secondary, vm, pid, seclabel) < 0) rc = -1; #endif - if (virSecurityManagerGetProcessLabel(priv->primary, vm, pid, seclabel) < 0) + if (virSecurityManagerGetProcessLabel(virSecurityStackGetPrimary(mgr), vm, pid, seclabel) < 0) rc = -1;
return rc; @@ -345,12 +397,13 @@ virSecurityStackSetDaemonSocketLabel(virSecurityManagerPtr mgr, virDomainDefPtr vm) { virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr); + virSecurityStackItemPtr item = priv->itemsHead; int rc = 0;
- if (virSecurityManagerSetDaemonSocketLabel(priv->secondary, vm) < 0) - rc = -1; - if (virSecurityManagerSetDaemonSocketLabel(priv->primary, vm) < 0) - rc = -1; + for (; item; item = item->next) { + if (virSecurityManagerSetDaemonSocketLabel(item->securityManager, vm) < 0) + rc = -1; + }
return rc; } @@ -361,12 +414,13 @@ virSecurityStackSetSocketLabel(virSecurityManagerPtr mgr, virDomainDefPtr vm) { virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr); + virSecurityStackItemPtr item = priv->itemsHead; int rc = 0;
- if (virSecurityManagerSetSocketLabel(priv->secondary, vm) < 0) - rc = -1; - if (virSecurityManagerSetSocketLabel(priv->primary, vm) < 0) - rc = -1; + for (; item; item = item->next) { + if (virSecurityManagerSetSocketLabel(item->securityManager, vm) < 0) + rc = -1; + }
return rc; } @@ -377,12 +431,13 @@ virSecurityStackClearSocketLabel(virSecurityManagerPtr mgr, virDomainDefPtr vm) { virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr); + virSecurityStackItemPtr item = priv->itemsHead; int rc = 0;
- if (virSecurityManagerClearSocketLabel(priv->secondary, vm) < 0) - rc = -1; - if (virSecurityManagerClearSocketLabel(priv->primary, vm) < 0) - rc = -1; + for (; item; item = item->next) { + if (virSecurityManagerClearSocketLabel(item->securityManager, vm) < 0) + rc = -1; + }
return rc; } @@ -393,12 +448,13 @@ virSecurityStackSetImageFDLabel(virSecurityManagerPtr mgr, int fd) { virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr); + virSecurityStackItemPtr item = priv->itemsHead; int rc = 0;
- if (virSecurityManagerSetImageFDLabel(priv->secondary, vm, fd) < 0) - rc = -1; - if (virSecurityManagerSetImageFDLabel(priv->primary, vm, fd) < 0) - rc = -1; + for (; item; item = item->next) { + if (virSecurityManagerSetImageFDLabel(item->securityManager, vm, fd) < 0) + rc = -1; + }
return rc; } @@ -408,6 +464,29 @@ static char *virSecurityStackGetMountOptions(virSecurityManagerPtr mgr ATTRIBUTE return NULL; }
+virSecurityManagerPtr* +virSecurityStackGetNested(virSecurityManagerPtr mgr) +{ + virSecurityManagerPtr *list = NULL; + virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr); + virSecurityStackItemPtr item; + int len = 0, i = 0; + + for (item = priv->itemsHead; item; item = item->next) + len++; + + if (VIR_ALLOC_N(list, len + 1) < 0) { + virReportOOMError(); + return NULL; + } + + for (item = priv->itemsHead; item; item = item->next, i++) + list[i] = item->securityManager; + list[len] = NULL; + + return list; +} + virSecurityDriver virSecurityDriverStack = { sizeof(virSecurityStackData), "stack", diff --git a/src/security/security_stack.h b/src/security/security_stack.h index bc83ff3..13a7a88 100644 --- a/src/security/security_stack.h +++ b/src/security/security_stack.h @@ -25,9 +25,22 @@
extern virSecurityDriver virSecurityDriverStack;
+ +int +virSecurityStackAddPrimary(virSecurityManagerPtr mgr, + virSecurityManagerPtr primary); +int +virSecurityStackAddNested(virSecurityManagerPtr mgr, + virSecurityManagerPtr nested); +virSecurityManagerPtr +virSecurityStackGetPrimary(virSecurityManagerPtr mgr); + void virSecurityStackSetPrimary(virSecurityManagerPtr mgr, virSecurityManagerPtr primary); void virSecurityStackSetSecondary(virSecurityManagerPtr mgr, virSecurityManagerPtr secondary);
+virSecurityManagerPtr* +virSecurityStackGetNested(virSecurityManagerPtr mgr); + #endif /* __VIR_SECURITY_DAC */

On Mon, May 21, 2012 at 10:39:24AM -0300, Marcelo Cerri wrote:
--- src/security/security_apparmor.c | 112 ++++++++++---- src/security/security_dac.c | 320 ++++++++++++++++++++++++++++++++++---- src/security/security_manager.c | 99 +++++++++--- src/security/security_manager.h | 8 +- src/security/security_selinux.c | 249 +++++++++++++++++++++--------- src/security/security_stack.c | 235 +++++++++++++++++++--------- src/security/security_stack.h | 13 ++ 7 files changed, 803 insertions(+), 233 deletions(-)
This patch is really doing 2 different things at once: 1. It updates the code to cope with def->seclabel vs def->seclabels 2. It adds support for configurable DAC driver uid:gid labels The first set of changes need to be merged into the previous patch so that the 1st patch in this series actually compiles. This patch should then only contain the code for the DAC driver to add configurable labels. Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

--- daemon/remote.c | 49 ++++++++++++++++++++++++++++++++++++++++++ include/libvirt/libvirt.h.in | 3 ++ python/generator.py | 1 + src/libvirt.c | 49 ++++++++++++++++++++++++++++++++++++++++++ src/libvirt_private.syms | 3 ++ src/libvirt_public.syms | 1 + src/remote/remote_driver.c | 42 ++++++++++++++++++++++++++++++++++++ src/remote/remote_protocol.x | 14 ++++++++++- src/remote_protocol-structs | 1 + 9 files changed, 161 insertions(+), 2 deletions(-) diff --git a/daemon/remote.c b/daemon/remote.c index 16a8a05..03799bf 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -1341,6 +1341,55 @@ cleanup: } static int +remoteDispatchDomainGetSecurityLabelList(virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client ATTRIBUTE_UNUSED, + virNetMessagePtr msg ATTRIBUTE_UNUSED, + virNetMessageErrorPtr rerr, + remote_domain_get_security_label_list_args *args, + remote_domain_get_security_label_list_ret *ret) +{ + virDomainPtr dom = NULL; + virSecurityLabelPtr seclabel = NULL; + int rv = -1; + struct daemonClientPrivate *priv = + virNetServerClientGetPrivateData(client); + + if (!priv->conn) { + virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open")); + goto cleanup; + } + + if (!(dom = get_nonnull_domain(priv->conn, args->dom))) + goto cleanup; + + if (VIR_ALLOC(seclabel) < 0) { + virReportOOMError(); + goto cleanup; + } + + if (virDomainGetSecurityLabelList(dom, seclabel, args->nlabels) < 0) + goto cleanup; + + ret->label.label_len = strlen(seclabel->label) + 1; + if (VIR_ALLOC_N(ret->label.label_val, ret->label.label_len) < 0) { + virReportOOMError(); + goto cleanup; + } + strcpy(ret->label.label_val, seclabel->label); + ret->enforcing = seclabel->enforcing; + + rv = 0; + +cleanup: + if (rv < 0) + virNetMessageSaveError(rerr); + if (dom) + virDomainFree(dom); + VIR_FREE(seclabel); + return rv; +} + +static int remoteDispatchNodeGetSecurityModel(virNetServerPtr server ATTRIBUTE_UNUSED, virNetServerClientPtr client ATTRIBUTE_UNUSED, virNetMessagePtr msg ATTRIBUTE_UNUSED, diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index a817db8..fdcffd1 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -1539,6 +1539,9 @@ int virDomainSetMemoryFlags (virDomainPtr domain, int virDomainGetMaxVcpus (virDomainPtr domain); int virDomainGetSecurityLabel (virDomainPtr domain, virSecurityLabelPtr seclabel); +int virDomainGetSecurityLabelList (virDomainPtr domain, + virSecurityLabelPtr seclabel, + int nseclabels); typedef enum { VIR_DOMAIN_METADATA_DESCRIPTION = 0, /* Operate on <description> */ diff --git a/python/generator.py b/python/generator.py index 9530867..2753d43 100755 --- a/python/generator.py +++ b/python/generator.py @@ -446,6 +446,7 @@ skip_function = ( 'virConnectOpenAuth', # Python C code is manually written 'virDefaultErrorFunc', # Python virErrorFuncHandler impl calls this from C 'virDomainGetSecurityLabel', # Needs investigation... + 'virDomainGetSecurityLabelList', # Needs investigation... 'virNodeGetSecurityModel', # Needs investigation... 'virConnectDomainEventRegister', # overridden in virConnect.py 'virConnectDomainEventDeregister', # overridden in virConnect.py diff --git a/src/libvirt.c b/src/libvirt.c index 22fc863..9e83c05 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -9024,6 +9024,55 @@ error: } /** + * virDomainGetSecurityLabelList: + * @domain: a domain object + * @seclabels: pointer to a pre allocated array of virSecurityLabel structures + * @nseclabels: number of elements on seclabels array + * + * Extract the security labels of an active domain. The 'label' field + * in the @seclabels argument will be initialized to the empty + * string if the domain is not running under a security model. + * + * Returns 0 in case of success, -1 in case of failure + */ +int +virDomainGetSecurityLabelList(virDomainPtr domain, + virSecurityLabelPtr seclabels, + int nseclabels) +{ + virConnectPtr conn; + + VIR_DOMAIN_DEBUG(domain, "seclabels=%p", seclabels); + + if (!VIR_IS_CONNECTED_DOMAIN(domain)) { + virLibDomainError(VIR_ERR_INVALID_DOMAIN, __FUNCTION__); + virDispatchError(NULL); + return -1; + } + + if (seclabels == NULL) { + virLibDomainError(VIR_ERR_INVALID_ARG, __FUNCTION__); + goto error; + } + + conn = domain->conn; + + if (conn->driver->domainGetSecurityLabelList) { + int ret; + ret = conn->driver->domainGetSecurityLabelList(domain, seclabels, + nseclabels); + if (ret < 0) + goto error; + return ret; + } + + virLibConnError(VIR_ERR_NO_SUPPORT, __FUNCTION__); + +error: + virDispatchError(domain->conn); + return -1; +} +/** * virDomainSetMetadata: * @domain: a domain object * @type: type of description, from virDomainMetadataType diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index f5c2184..edeaae1 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -278,6 +278,7 @@ virDomainDefClearPCIAddresses; virDomainDefFormat; virDomainDefFormatInternal; virDomainDefFree; +virDomainDefGetSecurityLabelDef; virDomainDefParseFile; virDomainDefParseNode; virDomainDefParseString; @@ -943,6 +944,7 @@ virSecurityManagerClearSocketLabel; virSecurityManagerFree; virSecurityManagerGenLabel; virSecurityManagerGetDOI; +virSecurityManagerGetNested; virSecurityManagerGetModel; virSecurityManagerGetProcessLabel; virSecurityManagerNew; @@ -962,6 +964,7 @@ virSecurityManagerSetHostdevLabel; virSecurityManagerSetProcessLabel; virSecurityManagerSetSavedStateLabel; virSecurityManagerSetSocketLabel; +virSecurityManagerStackAddNested; virSecurityManagerVerify; virSecurityManagerGetMountOptions; diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index 46c13fb..2c85d22 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -527,6 +527,7 @@ LIBVIRT_0.9.10 { virDomainShutdownFlags; virStorageVolResize; virStorageVolWipePattern; + virDomainGetSecurityLabelList; } LIBVIRT_0.9.9; LIBVIRT_0.9.11 { diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index 5c87561..04b3b67 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -1858,6 +1858,47 @@ done: } static int +remoteDomainGetSecurityLabelList (virDomainPtr domain, virSecurityLabelPtr seclabel, + int nlabels ATTRIBUTE_UNUSED) +{ + remote_domain_get_security_label_list_args args; + remote_domain_get_security_label_list_ret ret; + struct private_data *priv = domain->conn->privateData; + int rv = -1; + + remoteDriverLock(priv); + + make_nonnull_domain (&args.dom, domain); + memset (&ret, 0, sizeof ret); + memset (seclabel, 0, sizeof (*seclabel)); + + if (call (domain->conn, priv, 0, REMOTE_PROC_DOMAIN_GET_SECURITY_LABEL_LIST, + (xdrproc_t) xdr_remote_domain_get_security_label_list_args, (char *)&args, + (xdrproc_t) xdr_remote_domain_get_security_label_list_ret, (char *)&ret) == -1) { + goto done; + } + + if (ret.label.label_val != NULL) { + if (strlen (ret.label.label_val) >= sizeof seclabel->label) { + remoteError(VIR_ERR_RPC, _("security label exceeds maximum: %zd"), + sizeof seclabel->label - 1); + goto cleanup; + } + strcpy (seclabel->label, ret.label.label_val); + seclabel->enforcing = ret.enforcing; + } + + rv = 0; + +cleanup: + xdr_free((xdrproc_t) xdr_remote_domain_get_security_label_list_ret, (char *)&ret); + +done: + remoteDriverUnlock(priv); + return rv; +} + +static int remoteDomainGetState(virDomainPtr domain, int *state, int *reason, @@ -5006,6 +5047,7 @@ static virDriver remote_driver = { .domainGetVcpus = remoteDomainGetVcpus, /* 0.3.0 */ .domainGetMaxVcpus = remoteDomainGetMaxVcpus, /* 0.3.0 */ .domainGetSecurityLabel = remoteDomainGetSecurityLabel, /* 0.6.1 */ + .domainGetSecurityLabelList = remoteDomainGetSecurityLabelList, /* ? */ .nodeGetSecurityModel = remoteNodeGetSecurityModel, /* 0.6.1 */ .domainGetXMLDesc = remoteDomainGetXMLDesc, /* 0.3.0 */ .domainXMLFromNative = remoteDomainXMLFromNative, /* 0.6.4 */ diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index 2d57247..d1e3692 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -1082,6 +1082,16 @@ struct remote_domain_get_security_label_ret { int enforcing; }; +struct remote_domain_get_security_label_list_args { + remote_nonnull_domain dom; + int nlabels; +}; + +struct remote_domain_get_security_label_list_ret { + char label<REMOTE_SECURITY_LABEL_MAX>; + int enforcing; +}; + struct remote_node_get_security_model_ret { char model<REMOTE_SECURITY_MODEL_MAX>; char doi<REMOTE_SECURITY_DOI_MAX>; @@ -2782,8 +2792,8 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_PM_WAKEUP = 267, /* autogen autogen */ REMOTE_PROC_DOMAIN_EVENT_TRAY_CHANGE = 268, /* autogen autogen */ REMOTE_PROC_DOMAIN_EVENT_PMWAKEUP = 269, /* autogen autogen */ - REMOTE_PROC_DOMAIN_EVENT_PMSUSPEND = 270 /* autogen autogen */ - + REMOTE_PROC_DOMAIN_EVENT_PMSUSPEND = 270, /* autogen autogen */ + REMOTE_PROC_DOMAIN_GET_SECURITY_LABEL_LIST = 271 /* skipgen skipgen priority:high */ /* * Notice how the entries are grouped in sets of 10 ? * Nice isn't it. Please keep it this way when adding more. diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs index 9b2414f..ee08e07 100644 --- a/src/remote_protocol-structs +++ b/src/remote_protocol-structs @@ -2192,4 +2192,5 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_EVENT_TRAY_CHANGE = 268, REMOTE_PROC_DOMAIN_EVENT_PMWAKEUP = 269, REMOTE_PROC_DOMAIN_EVENT_PMSUSPEND = 270, + REMOTE_PROC_DOMAIN_GET_SECURITY_LABEL_list = 271, }; -- 1.7.1

On 21.05.2012 15:39, Marcelo Cerri wrote:
--- daemon/remote.c | 49 ++++++++++++++++++++++++++++++++++++++++++ include/libvirt/libvirt.h.in | 3 ++ python/generator.py | 1 + src/libvirt.c | 49 ++++++++++++++++++++++++++++++++++++++++++ src/libvirt_private.syms | 3 ++ src/libvirt_public.syms | 1 + src/remote/remote_driver.c | 42 ++++++++++++++++++++++++++++++++++++ src/remote/remote_protocol.x | 14 ++++++++++- src/remote_protocol-structs | 1 + 9 files changed, 161 insertions(+), 2 deletions(-)
diff --git a/daemon/remote.c b/daemon/remote.c index 16a8a05..03799bf 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -1341,6 +1341,55 @@ cleanup: }
static int +remoteDispatchDomainGetSecurityLabelList(virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client ATTRIBUTE_UNUSED, + virNetMessagePtr msg ATTRIBUTE_UNUSED, + virNetMessageErrorPtr rerr, + remote_domain_get_security_label_list_args *args, + remote_domain_get_security_label_list_ret *ret) +{ + virDomainPtr dom = NULL; + virSecurityLabelPtr seclabel = NULL; + int rv = -1; + struct daemonClientPrivate *priv = + virNetServerClientGetPrivateData(client); + + if (!priv->conn) { + virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open")); + goto cleanup; + } + + if (!(dom = get_nonnull_domain(priv->conn, args->dom))) + goto cleanup; + + if (VIR_ALLOC(seclabel) < 0) { + virReportOOMError(); + goto cleanup; + } + + if (virDomainGetSecurityLabelList(dom, seclabel, args->nlabels) < 0) + goto cleanup;
Are you really allocating only one seclabel but telling virDomainGetSecurityLabelList() it has nlabels (possibly more than one)? Or am I missing something?
+ + ret->label.label_len = strlen(seclabel->label) + 1; + if (VIR_ALLOC_N(ret->label.label_val, ret->label.label_len) < 0) { + virReportOOMError(); + goto cleanup; + } + strcpy(ret->label.label_val, seclabel->label);
I would rather use virStrcpyStatic instead of strcpy().
+ ret->enforcing = seclabel->enforcing; + + rv = 0; + +cleanup: + if (rv < 0) + virNetMessageSaveError(rerr); + if (dom) + virDomainFree(dom); + VIR_FREE(seclabel); + return rv; +} + +static int remoteDispatchNodeGetSecurityModel(virNetServerPtr server ATTRIBUTE_UNUSED, virNetServerClientPtr client ATTRIBUTE_UNUSED, virNetMessagePtr msg ATTRIBUTE_UNUSED, diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index a817db8..fdcffd1 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -1539,6 +1539,9 @@ int virDomainSetMemoryFlags (virDomainPtr domain, int virDomainGetMaxVcpus (virDomainPtr domain); int virDomainGetSecurityLabel (virDomainPtr domain, virSecurityLabelPtr seclabel); +int virDomainGetSecurityLabelList (virDomainPtr domain, + virSecurityLabelPtr seclabel, + int nseclabels);
typedef enum { VIR_DOMAIN_METADATA_DESCRIPTION = 0, /* Operate on <description> */ diff --git a/python/generator.py b/python/generator.py index 9530867..2753d43 100755 --- a/python/generator.py +++ b/python/generator.py @@ -446,6 +446,7 @@ skip_function = ( 'virConnectOpenAuth', # Python C code is manually written 'virDefaultErrorFunc', # Python virErrorFuncHandler impl calls this from C 'virDomainGetSecurityLabel', # Needs investigation... + 'virDomainGetSecurityLabelList', # Needs investigation... 'virNodeGetSecurityModel', # Needs investigation... 'virConnectDomainEventRegister', # overridden in virConnect.py 'virConnectDomainEventDeregister', # overridden in virConnect.py diff --git a/src/libvirt.c b/src/libvirt.c index 22fc863..9e83c05 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -9024,6 +9024,55 @@ error: }
/** + * virDomainGetSecurityLabelList: + * @domain: a domain object + * @seclabels: pointer to a pre allocated array of virSecurityLabel structures + * @nseclabels: number of elements on seclabels array + * + * Extract the security labels of an active domain. The 'label' field + * in the @seclabels argument will be initialized to the empty + * string if the domain is not running under a security model. + * + * Returns 0 in case of success, -1 in case of failure + */ +int +virDomainGetSecurityLabelList(virDomainPtr domain, + virSecurityLabelPtr seclabels, + int nseclabels) +{ + virConnectPtr conn; + + VIR_DOMAIN_DEBUG(domain, "seclabels=%p", seclabels); + + if (!VIR_IS_CONNECTED_DOMAIN(domain)) { + virLibDomainError(VIR_ERR_INVALID_DOMAIN, __FUNCTION__); + virDispatchError(NULL); + return -1; + } + + if (seclabels == NULL) { + virLibDomainError(VIR_ERR_INVALID_ARG, __FUNCTION__); + goto error; + } + + conn = domain->conn; + + if (conn->driver->domainGetSecurityLabelList) { + int ret; + ret = conn->driver->domainGetSecurityLabelList(domain, seclabels, + nseclabels); + if (ret < 0) + goto error; + return ret; + } + + virLibConnError(VIR_ERR_NO_SUPPORT, __FUNCTION__); + +error: + virDispatchError(domain->conn); + return -1; +} +/** * virDomainSetMetadata: * @domain: a domain object * @type: type of description, from virDomainMetadataType diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index f5c2184..edeaae1 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -278,6 +278,7 @@ virDomainDefClearPCIAddresses; virDomainDefFormat; virDomainDefFormatInternal; virDomainDefFree; +virDomainDefGetSecurityLabelDef; virDomainDefParseFile; virDomainDefParseNode; virDomainDefParseString; @@ -943,6 +944,7 @@ virSecurityManagerClearSocketLabel; virSecurityManagerFree; virSecurityManagerGenLabel; virSecurityManagerGetDOI; +virSecurityManagerGetNested; virSecurityManagerGetModel; virSecurityManagerGetProcessLabel; virSecurityManagerNew; @@ -962,6 +964,7 @@ virSecurityManagerSetHostdevLabel; virSecurityManagerSetProcessLabel; virSecurityManagerSetSavedStateLabel; virSecurityManagerSetSocketLabel; +virSecurityManagerStackAddNested; virSecurityManagerVerify; virSecurityManagerGetMountOptions;
diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index 46c13fb..2c85d22 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -527,6 +527,7 @@ LIBVIRT_0.9.10 { virDomainShutdownFlags; virStorageVolResize; virStorageVolWipePattern; + virDomainGetSecurityLabelList; } LIBVIRT_0.9.9;
No, this API (symbol) wasn't introduced in 0.9.10 release. In fact, next release will be 0.9.13. Therefore you need: LIBVIRT_0.9.13 { global: virDomainGetSecurityLabelList; } LIBVIRT_0.9.11;
LIBVIRT_0.9.11 { diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index 5c87561..04b3b67 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -1858,6 +1858,47 @@ done: }
static int +remoteDomainGetSecurityLabelList (virDomainPtr domain, virSecurityLabelPtr seclabel, + int nlabels ATTRIBUTE_UNUSED) +{ + remote_domain_get_security_label_list_args args; + remote_domain_get_security_label_list_ret ret; + struct private_data *priv = domain->conn->privateData; + int rv = -1; + + remoteDriverLock(priv); + + make_nonnull_domain (&args.dom, domain); + memset (&ret, 0, sizeof ret); + memset (seclabel, 0, sizeof (*seclabel)); + + if (call (domain->conn, priv, 0, REMOTE_PROC_DOMAIN_GET_SECURITY_LABEL_LIST, + (xdrproc_t) xdr_remote_domain_get_security_label_list_args, (char *)&args, + (xdrproc_t) xdr_remote_domain_get_security_label_list_ret, (char *)&ret) == -1) { + goto done; + } + + if (ret.label.label_val != NULL) { + if (strlen (ret.label.label_val) >= sizeof seclabel->label) { + remoteError(VIR_ERR_RPC, _("security label exceeds maximum: %zd"), + sizeof seclabel->label - 1); + goto cleanup; + } + strcpy (seclabel->label, ret.label.label_val); + seclabel->enforcing = ret.enforcing; + } + + rv = 0; + +cleanup: + xdr_free((xdrproc_t) xdr_remote_domain_get_security_label_list_ret, (char *)&ret); + +done: + remoteDriverUnlock(priv); + return rv; +} + +static int remoteDomainGetState(virDomainPtr domain, int *state, int *reason, @@ -5006,6 +5047,7 @@ static virDriver remote_driver = { .domainGetVcpus = remoteDomainGetVcpus, /* 0.3.0 */ .domainGetMaxVcpus = remoteDomainGetMaxVcpus, /* 0.3.0 */ .domainGetSecurityLabel = remoteDomainGetSecurityLabel, /* 0.6.1 */ + .domainGetSecurityLabelList = remoteDomainGetSecurityLabelList, /* ? */
And then this needs to be 0.9.13 in the comment
.nodeGetSecurityModel = remoteNodeGetSecurityModel, /* 0.6.1 */ .domainGetXMLDesc = remoteDomainGetXMLDesc, /* 0.3.0 */ .domainXMLFromNative = remoteDomainXMLFromNative, /* 0.6.4 */ diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index 2d57247..d1e3692 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -1082,6 +1082,16 @@ struct remote_domain_get_security_label_ret { int enforcing; };
+struct remote_domain_get_security_label_list_args { + remote_nonnull_domain dom; + int nlabels; +}; + +struct remote_domain_get_security_label_list_ret { + char label<REMOTE_SECURITY_LABEL_MAX>; + int enforcing; +}; + struct remote_node_get_security_model_ret { char model<REMOTE_SECURITY_MODEL_MAX>; char doi<REMOTE_SECURITY_DOI_MAX>; @@ -2782,8 +2792,8 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_PM_WAKEUP = 267, /* autogen autogen */ REMOTE_PROC_DOMAIN_EVENT_TRAY_CHANGE = 268, /* autogen autogen */ REMOTE_PROC_DOMAIN_EVENT_PMWAKEUP = 269, /* autogen autogen */ - REMOTE_PROC_DOMAIN_EVENT_PMSUSPEND = 270 /* autogen autogen */ - + REMOTE_PROC_DOMAIN_EVENT_PMSUSPEND = 270, /* autogen autogen */ + REMOTE_PROC_DOMAIN_GET_SECURITY_LABEL_LIST = 271 /* skipgen skipgen priority:high */ /* * Notice how the entries are grouped in sets of 10 ? * Nice isn't it. Please keep it this way when adding more.
Well, the sets mentioned in the comment just below the lines you're changing start with [0-9]*1 not [0-9]*0. Therefore you don't want to move REMOTE_PROC_DOMAIN_EVENT_PMSUSPENDED;
diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs index 9b2414f..ee08e07 100644 --- a/src/remote_protocol-structs +++ b/src/remote_protocol-structs @@ -2192,4 +2192,5 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_EVENT_TRAY_CHANGE = 268, REMOTE_PROC_DOMAIN_EVENT_PMWAKEUP = 269, REMOTE_PROC_DOMAIN_EVENT_PMSUSPEND = 270, + REMOTE_PROC_DOMAIN_GET_SECURITY_LABEL_list = 271, };

On Mon, May 21, 2012 at 10:39:25AM -0300, Marcelo Cerri wrote:
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index a817db8..fdcffd1 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -1539,6 +1539,9 @@ int virDomainSetMemoryFlags (virDomainPtr domain, int virDomainGetMaxVcpus (virDomainPtr domain); int virDomainGetSecurityLabel (virDomainPtr domain, virSecurityLabelPtr seclabel); +int virDomainGetSecurityLabelList (virDomainPtr domain, + virSecurityLabelPtr seclabel, + int nseclabels);
Since we're introducing a more sensible virDomainListAllDomains API which pre-allocates the return array of the right size, I think we should make this API behave similarly. ie /* * @seclabels: will be auto-allocated & filled with domains' security labels. caller must free memory on return * * Return value: -1 on error, or the number of elements filled in the @seclabels parameter */ int virDomainGetSecurityLabelList(virDomainPtr domain, virSecurityLabelPtr *seclabels);
diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index 46c13fb..2c85d22 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -527,6 +527,7 @@ LIBVIRT_0.9.10 { virDomainShutdownFlags; virStorageVolResize; virStorageVolWipePattern; + virDomainGetSecurityLabelList; } LIBVIRT_0.9.9;
This needs to be in a new LIBVIRT_0.9.13 section Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

On Mon, May 21, 2012 at 10:39:25AM -0300, Marcelo Cerri wrote: The subject of this commit is a little misleading. It isn't just adding the remote API. It is defining a new public API contract and the remote protocol implementation. Please make the commit message somewhat more verbose than just the subject line, to describe what your patch is doing. Likewise for all other patches in this series, please fill out the commit message with details
--- daemon/remote.c | 49 ++++++++++++++++++++++++++++++++++++++++++ include/libvirt/libvirt.h.in | 3 ++ python/generator.py | 1 + src/libvirt.c | 49 ++++++++++++++++++++++++++++++++++++++++++ src/libvirt_private.syms | 3 ++ src/libvirt_public.syms | 1 + src/remote/remote_driver.c | 42 ++++++++++++++++++++++++++++++++++++ src/remote/remote_protocol.x | 14 ++++++++++- src/remote_protocol-structs | 1 + 9 files changed, 161 insertions(+), 2 deletions(-)
Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

--- docs/schemas/domaincommon.rng | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index 34f63c3..891c484 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -55,9 +55,9 @@ <optional> <ref name="devices"/> </optional> - <optional> + <zeroOrMore> <ref name="seclabel"/> - </optional> + </zeroOrMore>> <optional> <ref name='qemucmdline'/> </optional> -- 1.7.1

On 21.05.2012 15:39, Marcelo Cerri wrote:
--- docs/schemas/domaincommon.rng | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index 34f63c3..891c484 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -55,9 +55,9 @@ <optional> <ref name="devices"/> </optional> - <optional> + <zeroOrMore> <ref name="seclabel"/> - </optional> + </zeroOrMore>> <optional> <ref name='qemucmdline'/> </optional>
ACK Although, this may be merged with the previous patch. (See my comment to whole patchset) Michal

--- src/driver.h | 8 ++- src/qemu/qemu_conf.c | 33 ++++++++ src/qemu/qemu_conf.h | 1 + src/qemu/qemu_driver.c | 196 ++++++++++++++++++++++++++++++++++++++--------- src/qemu/qemu_process.c | 53 +++++++++---- 5 files changed, 236 insertions(+), 55 deletions(-) diff --git a/src/driver.h b/src/driver.h index 03d249b..ca4927f 100644 --- a/src/driver.h +++ b/src/driver.h @@ -305,11 +305,14 @@ typedef int int maplen); typedef int (*virDrvDomainGetMaxVcpus) (virDomainPtr domain); - typedef int - (*virDrvDomainGetSecurityLabel) (virDomainPtr domain, + (*virDrvDomainGetSecurityLabel) (virDomainPtr domain, virSecurityLabelPtr seclabel); typedef int + (*virDrvDomainGetSecurityLabelList) (virDomainPtr domain, + virSecurityLabelPtr seclabels, + int nseclabels); +typedef int (*virDrvNodeGetSecurityModel) (virConnectPtr conn, virSecurityModelPtr secmodel); typedef int @@ -911,6 +914,7 @@ struct _virDriver { virDrvDomainGetVcpus domainGetVcpus; virDrvDomainGetMaxVcpus domainGetMaxVcpus; virDrvDomainGetSecurityLabel domainGetSecurityLabel; + virDrvDomainGetSecurityLabelList domainGetSecurityLabelList; virDrvNodeGetSecurityModel nodeGetSecurityModel; virDrvDomainGetXMLDesc domainGetXMLDesc; virDrvConnectDomainXMLFromNative domainXMLFromNative; diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c index 88a04bc..5cc2071 100644 --- a/src/qemu/qemu_conf.c +++ b/src/qemu/qemu_conf.c @@ -202,6 +202,39 @@ int qemudLoadDriverConfig(struct qemud_driver *driver, } } + p = virConfGetValue (conf, "additional_security_drivers"); + CHECK_TYPE ("additional_security_driver", VIR_CONF_STRING); + if (p && p->str) { + char *it, *tok; + size_t len; + + for (len = 1, it = p->str; *it; it++) + len++; + if (VIR_ALLOC_N(driver->additionalSecurityDriverNames, len + 1) < 0) { + virReportOOMError(); + virConfFree(conf); + return -1; + } + + i = 0; + tok = it = p->str; + while (1) { + if (*it == ',' || *it == '\0') { + driver->additionalSecurityDriverNames[i] = strndup(tok, it - tok); + if (driver->additionalSecurityDriverNames == NULL) { + virReportOOMError(); + virConfFree(conf); + return -1; + } + tok = it + 1; + i++; + } + if (*it == '\0') + break; + it++; + } + } + p = virConfGetValue (conf, "security_default_confined"); CHECK_TYPE ("security_default_confined", VIR_CONF_LONG); if (p) driver->securityDefaultConfined = p->l; diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h index 482e6d3..a5867b6 100644 --- a/src/qemu/qemu_conf.h +++ b/src/qemu/qemu_conf.h @@ -117,6 +117,7 @@ struct qemud_driver { virDomainEventStatePtr domainEventState; char *securityDriverName; + char **additionalSecurityDriverNames; bool securityDefaultConfined; bool securityRequireConfined; virSecurityManagerPtr securityManager; diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index efbc421..39d9eee 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -214,36 +214,84 @@ qemuAutostartDomains(struct qemud_driver *driver) static int qemuSecurityInit(struct qemud_driver *driver) { - virSecurityManagerPtr mgr = virSecurityManagerNew(driver->securityDriverName, - QEMU_DRIVER_NAME, - driver->allowDiskFormatProbing, - driver->securityDefaultConfined, - driver->securityRequireConfined); - + char **names; + virSecurityManagerPtr mgr, nested, stack; + + /* Create primary driver */ + mgr = virSecurityManagerNew(driver->securityDriverName, + QEMU_DRIVER_NAME, + driver->allowDiskFormatProbing, + driver->securityDefaultConfined, + driver->securityRequireConfined); if (!mgr) goto error; - if (driver->privileged) { - virSecurityManagerPtr dac = virSecurityManagerNewDAC(QEMU_DRIVER_NAME, - driver->user, - driver->group, - driver->allowDiskFormatProbing, - driver->securityDefaultConfined, - driver->securityRequireConfined, - driver->dynamicOwnership); - if (!dac) + /* If a DAC driver is required or additional drivers are provived, a stack + * driver should be create to group them all */ + if (driver->privileged || driver->additionalSecurityDriverNames) { + stack = virSecurityManagerNewStack(mgr); + if (!stack) goto error; + mgr = stack; + } + + /* Loop through additional driver names and add a secudary driver to each + * one */ + if (driver->additionalSecurityDriverNames) { + names = driver->additionalSecurityDriverNames; + while (names && *names) { + if (STREQ("dac", *names)) { + /* A DAC driver has specic parameters */ + nested = virSecurityManagerNewDAC(QEMU_DRIVER_NAME, + driver->user, + driver->group, + driver->allowDiskFormatProbing, + driver->securityDefaultConfined, + driver->securityRequireConfined, + driver->dynamicOwnership); + } else { + nested = virSecurityManagerNew(*names, + QEMU_DRIVER_NAME, + driver->allowDiskFormatProbing, + driver->securityDefaultConfined, + driver->securityRequireConfined); + } + if (nested == NULL) + goto error; + if (virSecurityManagerStackAddNested(stack, nested)) + goto error; + names++; + } + } - if (!(driver->securityManager = virSecurityManagerNewStack(mgr, - dac))) { - - virSecurityManagerFree(dac); - goto error; + if (driver->privileged) { + /* When a DAC driver is required, check if there is already one in the + * additional drivers */ + names = driver->additionalSecurityDriverNames; + while (names && *names) { + if (STREQ("dac", *names)) { + break; + } + names++; + } + /* If there isn't a DAC driver, create a new one and add it to the stack + * manager */ + if (names == NULL || *names == NULL) { + nested = virSecurityManagerNewDAC(QEMU_DRIVER_NAME, + driver->user, + driver->group, + driver->allowDiskFormatProbing, + driver->securityDefaultConfined, + driver->securityRequireConfined, + driver->dynamicOwnership); + if (nested == NULL) + goto error; + if (virSecurityManagerStackAddNested(stack, nested)) + goto error; } - } else { - driver->securityManager = mgr; } + driver->securityManager = mgr; return 0; error: @@ -257,7 +305,11 @@ static virCapsPtr qemuCreateCapabilities(virCapsPtr oldcaps, struct qemud_driver *driver) { + size_t i; virCapsPtr caps; + virSecurityManagerPtr *sec_managers = NULL; + /* Security driver data */ + const char *doi, *model; /* Basic host arch / guest machine capabilities */ if (!(caps = qemuCapsInit(oldcaps))) { @@ -282,26 +334,38 @@ qemuCreateCapabilities(virCapsPtr oldcaps, goto err_exit; } - /* Security driver data */ - const char *doi, *model; + /* access sec drivers and create a sec model to each one */ + sec_managers = virSecurityManagerGetNested(driver->securityManager); + if (sec_managers == NULL) { + goto err_exit; + } + + /* calculate length */ + for (i = 0; sec_managers[i]; i++) + ; + caps->host.nsecModels = i; - doi = virSecurityManagerGetDOI(driver->securityManager); - model = virSecurityManagerGetModel(driver->securityManager); - if (STRNEQ(model, "none")) { - if (!(caps->host.secModel.model = strdup(model))) + if (VIR_ALLOC_N(caps->host.secModels, caps->host.nsecModels) < 0) + goto no_memory; + + for (i = 0; sec_managers[i]; i++) { + doi = virSecurityManagerGetDOI(sec_managers[i]); + model = virSecurityManagerGetModel(sec_managers[i]); + if (!(caps->host.secModels[i].model = strdup(model))) goto no_memory; - if (!(caps->host.secModel.doi = strdup(doi))) + if (!(caps->host.secModels[i].doi = strdup(doi))) goto no_memory; + VIR_DEBUG("Initialized caps for security driver \"%s\" with " + "DOI \"%s\"", model, doi); } - - VIR_DEBUG("Initialized caps for security driver \"%s\" with " - "DOI \"%s\"", model, doi); + VIR_FREE(sec_managers); return caps; no_memory: virReportOOMError(); err_exit: + VIR_FREE(sec_managers); virCapabilitiesFree(caps); return NULL; } @@ -3958,6 +4022,63 @@ cleanup: return ret; } +static int qemudDomainGetSecurityLabelList(virDomainPtr dom, + virSecurityLabelPtr seclabel, + int nseclabels) +{ + struct qemud_driver *driver = (struct qemud_driver *)dom->conn->privateData; + virDomainObjPtr vm; + int i, ret = -1; + + qemuDriverLock(driver); + vm = virDomainFindByUUID(&driver->domains, dom->uuid); + + memset(seclabel, 0, sizeof(*seclabel)); + + if (!vm) { + char uuidstr[VIR_UUID_STRING_BUFLEN]; + virUUIDFormat(dom->uuid, uuidstr); + qemuReportError(VIR_ERR_NO_DOMAIN, + _("no domain with matching uuid '%s'"), uuidstr); + goto cleanup; + } + + if (!virDomainVirtTypeToString(vm->def->virtType)) { + qemuReportError(VIR_ERR_INTERNAL_ERROR, + _("unknown virt type in domain definition '%d'"), + vm->def->virtType); + goto cleanup; + } + + /* + * Check the comment in qemudDomainGetSecurityLabel function. + */ + if (virDomainObjIsActive(vm)) { + virSecurityManagerPtr* mgrs = virSecurityManagerGetNested( + driver->securityManager); + if (!mgrs) + goto cleanup; + + for (i = 0; mgrs[i] && i < nseclabels; i++) { + if (virSecurityManagerGetProcessLabel(mgrs[i], vm->def, vm->pid, + seclabel) < 0) { + qemuReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("Failed to get security label")); + VIR_FREE(mgrs); + goto cleanup; + } + } + VIR_FREE(mgrs); + } + + ret = 0; + +cleanup: + if (vm) + virDomainObjUnlock(vm); + qemuDriverUnlock(driver); + return ret; +} static int qemudNodeGetSecurityModel(virConnectPtr conn, virSecurityModelPtr secmodel) { @@ -3968,12 +4089,12 @@ static int qemudNodeGetSecurityModel(virConnectPtr conn, qemuDriverLock(driver); memset(secmodel, 0, sizeof(*secmodel)); - /* NULL indicates no driver, which we treat as - * success, but simply return no data in *secmodel */ - if (driver->caps->host.secModel.model == NULL) + /* We treat no driver as success, but simply return no data in *secmodel */ + if (driver->caps->host.nsecModels == 0 || + driver->caps->host.secModels[0].model == NULL) goto cleanup; - p = driver->caps->host.secModel.model; + p = driver->caps->host.secModels[0].model; if (strlen(p) >= VIR_SECURITY_MODEL_BUFLEN-1) { qemuReportError(VIR_ERR_INTERNAL_ERROR, _("security model string exceeds max %d bytes"), @@ -3983,7 +4104,7 @@ static int qemudNodeGetSecurityModel(virConnectPtr conn, } strcpy(secmodel->model, p); - p = driver->caps->host.secModel.doi; + p = driver->caps->host.secModels[0].doi; if (strlen(p) >= VIR_SECURITY_DOI_BUFLEN-1) { qemuReportError(VIR_ERR_INTERNAL_ERROR, _("security DOI string exceeds max %d bytes"), @@ -13004,6 +13125,7 @@ static virDriver qemuDriver = { .domainGetVcpus = qemudDomainGetVcpus, /* 0.4.4 */ .domainGetMaxVcpus = qemudDomainGetMaxVcpus, /* 0.4.4 */ .domainGetSecurityLabel = qemudDomainGetSecurityLabel, /* 0.6.1 */ + .domainGetSecurityLabelList = qemudDomainGetSecurityLabelList, /* ? */ .nodeGetSecurityModel = qemudNodeGetSecurityModel, /* 0.6.1 */ .domainGetXMLDesc = qemuDomainGetXMLDesc, /* 0.2.0 */ .domainXMLFromNative = qemuDomainXMLFromNative, /* 0.6.4 */ diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 58ba5bf..59c7e0d 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -3979,12 +3979,12 @@ void qemuProcessStop(struct qemud_driver *driver, virSecurityManagerReleaseLabel(driver->securityManager, vm->def); /* Clear out dynamically assigned labels */ - if (vm->def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC) { - if (!vm->def->seclabel.baselabel) - VIR_FREE(vm->def->seclabel.model); - VIR_FREE(vm->def->seclabel.label); + for (i = 0; i < vm->def->nseclabels; i++) { + if (vm->def->seclabels[i]->type == VIR_DOMAIN_SECLABEL_DYNAMIC) { + VIR_FREE(vm->def->seclabels[i]->label); + } + VIR_FREE(vm->def->seclabels[i]->imagelabel); } - VIR_FREE(vm->def->seclabel.imagelabel); virDomainDefClearDeviceAliases(vm->def); if (!priv->persistentAddrs) { @@ -4088,6 +4088,7 @@ int qemuProcessAttach(virConnectPtr conn ATTRIBUTE_UNUSED, virDomainChrSourceDefPtr monConfig, bool monJSON) { + size_t i; char ebuf[1024]; int logfile = -1; char *timestamp; @@ -4095,6 +4096,9 @@ int qemuProcessAttach(virConnectPtr conn ATTRIBUTE_UNUSED, bool running = true; virDomainPausedReason reason; virSecurityLabelPtr seclabel = NULL; + virSecurityLabelDefPtr seclabeldef = NULL; + virSecurityManagerPtr* sec_managers; + const char *model; VIR_DEBUG("Beginning VM attach process"); @@ -4127,17 +4131,35 @@ int qemuProcessAttach(virConnectPtr conn ATTRIBUTE_UNUSED, goto no_memory; VIR_DEBUG("Detect security driver config"); - vm->def->seclabel.type = VIR_DOMAIN_SECLABEL_STATIC; - if (VIR_ALLOC(seclabel) < 0) - goto no_memory; - if (virSecurityManagerGetProcessLabel(driver->securityManager, - vm->def, vm->pid, seclabel) < 0) + sec_managers = virSecurityManagerGetNested(driver->securityManager); + if (sec_managers == NULL) { goto cleanup; - if (driver->caps->host.secModel.model && - !(vm->def->seclabel.model = strdup(driver->caps->host.secModel.model))) - goto no_memory; - if (!(vm->def->seclabel.label = strdup(seclabel->label))) - goto no_memory; + } + + for (i = 0; sec_managers[i]; i++) { + model = virSecurityManagerGetModel(sec_managers[i]); + seclabeldef = virDomainDefGetSecurityLabelDef(vm->def, model); + if (seclabeldef == NULL) { + goto cleanup; + } + seclabeldef->type = VIR_DOMAIN_SECLABEL_STATIC; + if (VIR_ALLOC(seclabel) < 0) + goto no_memory; + if (virSecurityManagerGetProcessLabel(driver->securityManager, + vm->def, vm->pid, seclabel) < 0) + goto cleanup; + + //if (driver->caps->host.secModel.model && + // !(seclabeldef.model = strdup(driver->caps->host.secModel.model))) + // goto no_memory; + if (!(seclabeldef->model = strdup(model))) + goto no_memory; + + if (!(seclabeldef->label = strdup(seclabel->label))) + goto no_memory; + VIR_FREE(seclabel); + seclabel = NULL; + } VIR_DEBUG("Creating domain log file"); if ((logfile = qemuDomainCreateLog(driver, vm, false)) < 0) @@ -4256,7 +4278,6 @@ int qemuProcessAttach(virConnectPtr conn ATTRIBUTE_UNUSED, goto cleanup; VIR_FORCE_CLOSE(logfile); - VIR_FREE(seclabel); return 0; -- 1.7.1

On 21.05.2012 15:39, Marcelo Cerri wrote:
--- src/driver.h | 8 ++- src/qemu/qemu_conf.c | 33 ++++++++ src/qemu/qemu_conf.h | 1 + src/qemu/qemu_driver.c | 196 ++++++++++++++++++++++++++++++++++++++--------- src/qemu/qemu_process.c | 53 +++++++++---- 5 files changed, 236 insertions(+), 55 deletions(-)
Changes to driver.h looks suspicious :) ...
diff --git a/src/driver.h b/src/driver.h index 03d249b..ca4927f 100644 --- a/src/driver.h +++ b/src/driver.h @@ -305,11 +305,14 @@ typedef int int maplen); typedef int (*virDrvDomainGetMaxVcpus) (virDomainPtr domain); - typedef int - (*virDrvDomainGetSecurityLabel) (virDomainPtr domain, + (*virDrvDomainGetSecurityLabel) (virDomainPtr domain, virSecurityLabelPtr seclabel); typedef int + (*virDrvDomainGetSecurityLabelList) (virDomainPtr domain, + virSecurityLabelPtr seclabels, + int nseclabels); +typedef int (*virDrvNodeGetSecurityModel) (virConnectPtr conn, virSecurityModelPtr secmodel); typedef int @@ -911,6 +914,7 @@ struct _virDriver { virDrvDomainGetVcpus domainGetVcpus; virDrvDomainGetMaxVcpus domainGetMaxVcpus; virDrvDomainGetSecurityLabel domainGetSecurityLabel; + virDrvDomainGetSecurityLabelList domainGetSecurityLabelList; virDrvNodeGetSecurityModel nodeGetSecurityModel; virDrvDomainGetXMLDesc domainGetXMLDesc; virDrvConnectDomainXMLFromNative domainXMLFromNative;
... but reasonable after all. Although it may be better to save formatting cleanups for another patch - leaving us with more easier to understand git bisects in the future.
diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c index 88a04bc..5cc2071 100644 --- a/src/qemu/qemu_conf.c +++ b/src/qemu/qemu_conf.c @@ -202,6 +202,39 @@ int qemudLoadDriverConfig(struct qemud_driver *driver, } }
+ p = virConfGetValue (conf, "additional_security_drivers"); + CHECK_TYPE ("additional_security_driver", VIR_CONF_STRING); + if (p && p->str) { + char *it, *tok; + size_t len; + + for (len = 1, it = p->str; *it; it++) + len++; + if (VIR_ALLOC_N(driver->additionalSecurityDriverNames, len + 1) < 0) { + virReportOOMError(); + virConfFree(conf); + return -1; + }
I'd say drop this ^^ ...
+ + i = 0; + tok = it = p->str; + while (1) { + if (*it == ',' || *it == '\0') { + driver->additionalSecurityDriverNames[i] = strndup(tok, it - tok);
... and expand this array only if needed.
+ if (driver->additionalSecurityDriverNames == NULL) { + virReportOOMError(); + virConfFree(conf); + return -1; + } + tok = it + 1; + i++; + } + if (*it == '\0') + break; + it++; + } + } +
p = virConfGetValue (conf, "security_default_confined"); CHECK_TYPE ("security_default_confined", VIR_CONF_LONG); if (p) driver->securityDefaultConfined = p->l; diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h index 482e6d3..a5867b6 100644 --- a/src/qemu/qemu_conf.h +++ b/src/qemu/qemu_conf.h @@ -117,6 +117,7 @@ struct qemud_driver { virDomainEventStatePtr domainEventState;
char *securityDriverName; + char **additionalSecurityDriverNames; bool securityDefaultConfined; bool securityRequireConfined; virSecurityManagerPtr securityManager; diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index efbc421..39d9eee 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -214,36 +214,84 @@ qemuAutostartDomains(struct qemud_driver *driver) static int qemuSecurityInit(struct qemud_driver *driver) { - virSecurityManagerPtr mgr = virSecurityManagerNew(driver->securityDriverName, - QEMU_DRIVER_NAME, - driver->allowDiskFormatProbing, - driver->securityDefaultConfined, - driver->securityRequireConfined); - + char **names; + virSecurityManagerPtr mgr, nested, stack; + + /* Create primary driver */ + mgr = virSecurityManagerNew(driver->securityDriverName, + QEMU_DRIVER_NAME, + driver->allowDiskFormatProbing, + driver->securityDefaultConfined, + driver->securityRequireConfined); if (!mgr) goto error;
- if (driver->privileged) { - virSecurityManagerPtr dac = virSecurityManagerNewDAC(QEMU_DRIVER_NAME, - driver->user, - driver->group, - driver->allowDiskFormatProbing, - driver->securityDefaultConfined, - driver->securityRequireConfined, - driver->dynamicOwnership); - if (!dac) + /* If a DAC driver is required or additional drivers are provived, a stack + * driver should be create to group them all */ + if (driver->privileged || driver->additionalSecurityDriverNames) { + stack = virSecurityManagerNewStack(mgr); + if (!stack) goto error; + mgr = stack; + } + + /* Loop through additional driver names and add a secudary driver to each + * one */ + if (driver->additionalSecurityDriverNames) { + names = driver->additionalSecurityDriverNames; + while (names && *names) { + if (STREQ("dac", *names)) { + /* A DAC driver has specic parameters */ + nested = virSecurityManagerNewDAC(QEMU_DRIVER_NAME, + driver->user, + driver->group, + driver->allowDiskFormatProbing, + driver->securityDefaultConfined, + driver->securityRequireConfined, + driver->dynamicOwnership); + } else { + nested = virSecurityManagerNew(*names, + QEMU_DRIVER_NAME, + driver->allowDiskFormatProbing, + driver->securityDefaultConfined, + driver->securityRequireConfined); + } + if (nested == NULL) + goto error; + if (virSecurityManagerStackAddNested(stack, nested)) + goto error; + names++; + } + }
- if (!(driver->securityManager = virSecurityManagerNewStack(mgr, - dac))) { - - virSecurityManagerFree(dac); - goto error; + if (driver->privileged) { + /* When a DAC driver is required, check if there is already one in the + * additional drivers */ + names = driver->additionalSecurityDriverNames; + while (names && *names) { + if (STREQ("dac", *names)) { + break; + } + names++; + } + /* If there isn't a DAC driver, create a new one and add it to the stack + * manager */ + if (names == NULL || *names == NULL) { + nested = virSecurityManagerNewDAC(QEMU_DRIVER_NAME, + driver->user, + driver->group, + driver->allowDiskFormatProbing, + driver->securityDefaultConfined, + driver->securityRequireConfined, + driver->dynamicOwnership); + if (nested == NULL) + goto error; + if (virSecurityManagerStackAddNested(stack, nested)) + goto error; } - } else { - driver->securityManager = mgr; }
+ driver->securityManager = mgr; return 0;
error: @@ -257,7 +305,11 @@ static virCapsPtr qemuCreateCapabilities(virCapsPtr oldcaps, struct qemud_driver *driver) { + size_t i; virCapsPtr caps; + virSecurityManagerPtr *sec_managers = NULL; + /* Security driver data */ + const char *doi, *model;
/* Basic host arch / guest machine capabilities */ if (!(caps = qemuCapsInit(oldcaps))) { @@ -282,26 +334,38 @@ qemuCreateCapabilities(virCapsPtr oldcaps, goto err_exit; }
- /* Security driver data */ - const char *doi, *model; + /* access sec drivers and create a sec model to each one */ + sec_managers = virSecurityManagerGetNested(driver->securityManager); + if (sec_managers == NULL) { + goto err_exit; + } + + /* calculate length */ + for (i = 0; sec_managers[i]; i++) + ; + caps->host.nsecModels = i;
- doi = virSecurityManagerGetDOI(driver->securityManager); - model = virSecurityManagerGetModel(driver->securityManager); - if (STRNEQ(model, "none")) { - if (!(caps->host.secModel.model = strdup(model))) + if (VIR_ALLOC_N(caps->host.secModels, caps->host.nsecModels) < 0) + goto no_memory; + + for (i = 0; sec_managers[i]; i++) { + doi = virSecurityManagerGetDOI(sec_managers[i]); + model = virSecurityManagerGetModel(sec_managers[i]); + if (!(caps->host.secModels[i].model = strdup(model))) goto no_memory; - if (!(caps->host.secModel.doi = strdup(doi))) + if (!(caps->host.secModels[i].doi = strdup(doi))) goto no_memory; + VIR_DEBUG("Initialized caps for security driver \"%s\" with " + "DOI \"%s\"", model, doi); } - - VIR_DEBUG("Initialized caps for security driver \"%s\" with " - "DOI \"%s\"", model, doi); + VIR_FREE(sec_managers);
return caps;
no_memory: virReportOOMError(); err_exit: + VIR_FREE(sec_managers); virCapabilitiesFree(caps); return NULL; } @@ -3958,6 +4022,63 @@ cleanup: return ret; }
+static int qemudDomainGetSecurityLabelList(virDomainPtr dom, + virSecurityLabelPtr seclabel, + int nseclabels) +{ + struct qemud_driver *driver = (struct qemud_driver *)dom->conn->privateData; + virDomainObjPtr vm; + int i, ret = -1; + + qemuDriverLock(driver); + vm = virDomainFindByUUID(&driver->domains, dom->uuid); +
Do we really want to hold driver locked over the whole API?
+ memset(seclabel, 0, sizeof(*seclabel)); + + if (!vm) { + char uuidstr[VIR_UUID_STRING_BUFLEN]; + virUUIDFormat(dom->uuid, uuidstr); + qemuReportError(VIR_ERR_NO_DOMAIN, + _("no domain with matching uuid '%s'"), uuidstr); + goto cleanup; + } + + if (!virDomainVirtTypeToString(vm->def->virtType)) { + qemuReportError(VIR_ERR_INTERNAL_ERROR, + _("unknown virt type in domain definition '%d'"), + vm->def->virtType); + goto cleanup; + } + + /* + * Check the comment in qemudDomainGetSecurityLabel function. + */ + if (virDomainObjIsActive(vm)) { + virSecurityManagerPtr* mgrs = virSecurityManagerGetNested( + driver->securityManager); + if (!mgrs) + goto cleanup; + + for (i = 0; mgrs[i] && i < nseclabels; i++) { + if (virSecurityManagerGetProcessLabel(mgrs[i], vm->def, vm->pid, + seclabel) < 0) { + qemuReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("Failed to get security label")); + VIR_FREE(mgrs); + goto cleanup; + } + } + VIR_FREE(mgrs); + } + + ret = 0; + +cleanup: + if (vm) + virDomainObjUnlock(vm); + qemuDriverUnlock(driver); + return ret; +} static int qemudNodeGetSecurityModel(virConnectPtr conn, virSecurityModelPtr secmodel) { @@ -3968,12 +4089,12 @@ static int qemudNodeGetSecurityModel(virConnectPtr conn, qemuDriverLock(driver); memset(secmodel, 0, sizeof(*secmodel));
- /* NULL indicates no driver, which we treat as - * success, but simply return no data in *secmodel */ - if (driver->caps->host.secModel.model == NULL) + /* We treat no driver as success, but simply return no data in *secmodel */ + if (driver->caps->host.nsecModels == 0 || + driver->caps->host.secModels[0].model == NULL) goto cleanup;
- p = driver->caps->host.secModel.model; + p = driver->caps->host.secModels[0].model; if (strlen(p) >= VIR_SECURITY_MODEL_BUFLEN-1) { qemuReportError(VIR_ERR_INTERNAL_ERROR, _("security model string exceeds max %d bytes"), @@ -3983,7 +4104,7 @@ static int qemudNodeGetSecurityModel(virConnectPtr conn, } strcpy(secmodel->model, p);
- p = driver->caps->host.secModel.doi; + p = driver->caps->host.secModels[0].doi; if (strlen(p) >= VIR_SECURITY_DOI_BUFLEN-1) { qemuReportError(VIR_ERR_INTERNAL_ERROR, _("security DOI string exceeds max %d bytes"), @@ -13004,6 +13125,7 @@ static virDriver qemuDriver = { .domainGetVcpus = qemudDomainGetVcpus, /* 0.4.4 */ .domainGetMaxVcpus = qemudDomainGetMaxVcpus, /* 0.4.4 */ .domainGetSecurityLabel = qemudDomainGetSecurityLabel, /* 0.6.1 */ + .domainGetSecurityLabelList = qemudDomainGetSecurityLabelList, /* ? */ .nodeGetSecurityModel = qemudNodeGetSecurityModel, /* 0.6.1 */ .domainGetXMLDesc = qemuDomainGetXMLDesc, /* 0.2.0 */ .domainXMLFromNative = qemuDomainXMLFromNative, /* 0.6.4 */ diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 58ba5bf..59c7e0d 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -3979,12 +3979,12 @@ void qemuProcessStop(struct qemud_driver *driver, virSecurityManagerReleaseLabel(driver->securityManager, vm->def);
/* Clear out dynamically assigned labels */ - if (vm->def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC) { - if (!vm->def->seclabel.baselabel) - VIR_FREE(vm->def->seclabel.model); - VIR_FREE(vm->def->seclabel.label); + for (i = 0; i < vm->def->nseclabels; i++) { + if (vm->def->seclabels[i]->type == VIR_DOMAIN_SECLABEL_DYNAMIC) { + VIR_FREE(vm->def->seclabels[i]->label); + } + VIR_FREE(vm->def->seclabels[i]->imagelabel); } - VIR_FREE(vm->def->seclabel.imagelabel);
virDomainDefClearDeviceAliases(vm->def); if (!priv->persistentAddrs) { @@ -4088,6 +4088,7 @@ int qemuProcessAttach(virConnectPtr conn ATTRIBUTE_UNUSED, virDomainChrSourceDefPtr monConfig, bool monJSON) { + size_t i; char ebuf[1024]; int logfile = -1; char *timestamp; @@ -4095,6 +4096,9 @@ int qemuProcessAttach(virConnectPtr conn ATTRIBUTE_UNUSED, bool running = true; virDomainPausedReason reason; virSecurityLabelPtr seclabel = NULL; + virSecurityLabelDefPtr seclabeldef = NULL; + virSecurityManagerPtr* sec_managers; + const char *model;
VIR_DEBUG("Beginning VM attach process");
@@ -4127,17 +4131,35 @@ int qemuProcessAttach(virConnectPtr conn ATTRIBUTE_UNUSED, goto no_memory;
VIR_DEBUG("Detect security driver config"); - vm->def->seclabel.type = VIR_DOMAIN_SECLABEL_STATIC; - if (VIR_ALLOC(seclabel) < 0) - goto no_memory; - if (virSecurityManagerGetProcessLabel(driver->securityManager, - vm->def, vm->pid, seclabel) < 0) + sec_managers = virSecurityManagerGetNested(driver->securityManager); + if (sec_managers == NULL) { goto cleanup; - if (driver->caps->host.secModel.model && - !(vm->def->seclabel.model = strdup(driver->caps->host.secModel.model))) - goto no_memory; - if (!(vm->def->seclabel.label = strdup(seclabel->label))) - goto no_memory; + } + + for (i = 0; sec_managers[i]; i++) { + model = virSecurityManagerGetModel(sec_managers[i]); + seclabeldef = virDomainDefGetSecurityLabelDef(vm->def, model); + if (seclabeldef == NULL) { + goto cleanup; + } + seclabeldef->type = VIR_DOMAIN_SECLABEL_STATIC; + if (VIR_ALLOC(seclabel) < 0) + goto no_memory; + if (virSecurityManagerGetProcessLabel(driver->securityManager, + vm->def, vm->pid, seclabel) < 0) + goto cleanup; + + //if (driver->caps->host.secModel.model && + // !(seclabeldef.model = strdup(driver->caps->host.secModel.model))) + // goto no_memory; + if (!(seclabeldef->model = strdup(model))) + goto no_memory; + + if (!(seclabeldef->label = strdup(seclabel->label))) + goto no_memory; + VIR_FREE(seclabel); + seclabel = NULL; + }
VIR_DEBUG("Creating domain log file"); if ((logfile = qemuDomainCreateLog(driver, vm, false)) < 0) @@ -4256,7 +4278,6 @@ int qemuProcessAttach(virConnectPtr conn ATTRIBUTE_UNUSED, goto cleanup;
VIR_FORCE_CLOSE(logfile); - VIR_FREE(seclabel);
return 0;

On Mon, May 21, 2012 at 10:39:27AM -0300, Marcelo Cerri wrote:
--- src/driver.h | 8 ++- src/qemu/qemu_conf.c | 33 ++++++++ src/qemu/qemu_conf.h | 1 + src/qemu/qemu_driver.c | 196 ++++++++++++++++++++++++++++++++++++++--------- src/qemu/qemu_process.c | 53 +++++++++---- 5 files changed, 236 insertions(+), 55 deletions(-)
diff --git a/src/driver.h b/src/driver.h index 03d249b..ca4927f 100644 --- a/src/driver.h +++ b/src/driver.h @@ -305,11 +305,14 @@ typedef int int maplen); typedef int (*virDrvDomainGetMaxVcpus) (virDomainPtr domain); - typedef int - (*virDrvDomainGetSecurityLabel) (virDomainPtr domain, + (*virDrvDomainGetSecurityLabel) (virDomainPtr domain, virSecurityLabelPtr seclabel); typedef int + (*virDrvDomainGetSecurityLabelList) (virDomainPtr domain, + virSecurityLabelPtr seclabels, + int nseclabels); +typedef int (*virDrvNodeGetSecurityModel) (virConnectPtr conn, virSecurityModelPtr secmodel); typedef int @@ -911,6 +914,7 @@ struct _virDriver { virDrvDomainGetVcpus domainGetVcpus; virDrvDomainGetMaxVcpus domainGetMaxVcpus; virDrvDomainGetSecurityLabel domainGetSecurityLabel; + virDrvDomainGetSecurityLabelList domainGetSecurityLabelList; virDrvNodeGetSecurityModel nodeGetSecurityModel; virDrvDomainGetXMLDesc domainGetXMLDesc; virDrvConnectDomainXMLFromNative domainXMLFromNative;
This part should have been in the earlier patch that introduces the new public API.
diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c index 88a04bc..5cc2071 100644 --- a/src/qemu/qemu_conf.c +++ b/src/qemu/qemu_conf.c @@ -202,6 +202,39 @@ int qemudLoadDriverConfig(struct qemud_driver *driver, } }
+ p = virConfGetValue (conf, "additional_security_drivers"); + CHECK_TYPE ("additional_security_driver", VIR_CONF_STRING);
I don't really like this. We currently have a 'security_driver' parameter, which takes a STRING. We should deprecate the old parameter and introduce a new parameter 'security_drivers' which takes a LIST of STRING. If 'security_drivers' is not set, then look for 'security_driver' as back-compat and log a warning (VIR_WARN) about its deprecation and replacement. Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

--- src/lxc/lxc_conf.c | 8 ++++++-- src/lxc/lxc_driver.c | 35 ++++++++++++++++++++--------------- 2 files changed, 26 insertions(+), 17 deletions(-) diff --git a/src/lxc/lxc_conf.c b/src/lxc/lxc_conf.c index 72547c4..807c704 100644 --- a/src/lxc/lxc_conf.c +++ b/src/lxc/lxc_conf.c @@ -134,9 +134,13 @@ virCapsPtr lxcCapsInit(lxc_driver_t *driver) doi = virSecurityManagerGetDOI(driver->securityManager); model = virSecurityManagerGetModel(driver->securityManager); if (STRNEQ(model, "none")) { - if (!(caps->host.secModel.model = strdup(model))) + /* Allocate just the primary security driver for LXC. */ + if (VIR_ALLOC(caps->host.secModels) < 0) goto no_memory; - if (!(caps->host.secModel.doi = strdup(doi))) + caps->host.nsecModels = 1; + if (!(caps->host.secModels[0].model = strdup(model))) + goto no_memory; + if (!(caps->host.secModels[0].doi = strdup(doi))) goto no_memory; } diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index 4cccd53..ffd3c9c 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -1479,10 +1479,12 @@ static int lxcVmTerminate(lxc_driver_t *driver, vm->def, false); virSecurityManagerReleaseLabel(driver->securityManager, vm->def); /* Clear out dynamically assigned labels */ - if (vm->def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC) { - VIR_FREE(vm->def->seclabel.model); - VIR_FREE(vm->def->seclabel.label); - VIR_FREE(vm->def->seclabel.imagelabel); + /* Manages just the primary sec driver for lxc */ + if (vm->def->nseclabels + && vm->def->seclabels[0]->type == VIR_DOMAIN_SECLABEL_DYNAMIC) { + VIR_FREE(vm->def->seclabels[0]->model); + VIR_FREE(vm->def->seclabels[0]->label); + VIR_FREE(vm->def->seclabels[0]->imagelabel); } if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) == 0) { @@ -1818,8 +1820,10 @@ static int lxcVmStart(virConnectPtr conn, /* If you are using a SecurityDriver with dynamic labelling, then generate a security label for isolation */ VIR_DEBUG("Generating domain security label (if required)"); - if (vm->def->seclabel.type == VIR_DOMAIN_SECLABEL_DEFAULT) - vm->def->seclabel.type = VIR_DOMAIN_SECLABEL_NONE; + if (vm->def->nseclabels + && vm->def->seclabels[0]->type == VIR_DOMAIN_SECLABEL_DEFAULT) { + vm->def->seclabels[0]->type = VIR_DOMAIN_SECLABEL_NONE; + } if (virSecurityManagerGenLabel(driver->securityManager, vm->def) < 0) { virDomainAuditSecurityLabel(vm, false); @@ -1990,10 +1994,11 @@ cleanup: vm->def, false); virSecurityManagerReleaseLabel(driver->securityManager, vm->def); /* Clear out dynamically assigned labels */ - if (vm->def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC) { - VIR_FREE(vm->def->seclabel.model); - VIR_FREE(vm->def->seclabel.label); - VIR_FREE(vm->def->seclabel.imagelabel); + if (vm->def->nseclabels + && vm->def->seclabels[0]->type == VIR_DOMAIN_SECLABEL_DYNAMIC) { + VIR_FREE(vm->def->seclabels[0]->model); + VIR_FREE(vm->def->seclabels[0]->label); + VIR_FREE(vm->def->seclabels[0]->imagelabel); } } for (i = 0 ; i < nttyFDs ; i++) @@ -2233,12 +2238,12 @@ static int lxcNodeGetSecurityModel(virConnectPtr conn, lxcDriverLock(driver); memset(secmodel, 0, sizeof(*secmodel)); - /* NULL indicates no driver, which we treat as - * success, but simply return no data in *secmodel */ - if (driver->caps->host.secModel.model == NULL) + /* we treat no driver as success, but simply return no data in *secmodel */ + if (driver->caps->host.nsecModels == 0 + || driver->caps->host.secModels[0].model == NULL) goto cleanup; - if (!virStrcpy(secmodel->model, driver->caps->host.secModel.model, + if (!virStrcpy(secmodel->model, driver->caps->host.secModels[0].model, VIR_SECURITY_MODEL_BUFLEN)) { lxcError(VIR_ERR_INTERNAL_ERROR, _("security model string exceeds max %d bytes"), @@ -2247,7 +2252,7 @@ static int lxcNodeGetSecurityModel(virConnectPtr conn, goto cleanup; } - if (!virStrcpy(secmodel->doi, driver->caps->host.secModel.doi, + if (!virStrcpy(secmodel->doi, driver->caps->host.secModels[0].doi, VIR_SECURITY_DOI_BUFLEN)) { lxcError(VIR_ERR_INTERNAL_ERROR, _("security DOI string exceeds max %d bytes"), -- 1.7.1

On 21.05.2012 15:39, Marcelo Cerri wrote:
--- src/lxc/lxc_conf.c | 8 ++++++-- src/lxc/lxc_driver.c | 35 ++++++++++++++++++++--------------- 2 files changed, 26 insertions(+), 17 deletions(-)
diff --git a/src/lxc/lxc_conf.c b/src/lxc/lxc_conf.c index 72547c4..807c704 100644 --- a/src/lxc/lxc_conf.c +++ b/src/lxc/lxc_conf.c @@ -134,9 +134,13 @@ virCapsPtr lxcCapsInit(lxc_driver_t *driver) doi = virSecurityManagerGetDOI(driver->securityManager); model = virSecurityManagerGetModel(driver->securityManager); if (STRNEQ(model, "none")) { - if (!(caps->host.secModel.model = strdup(model))) + /* Allocate just the primary security driver for LXC. */ + if (VIR_ALLOC(caps->host.secModels) < 0) goto no_memory; - if (!(caps->host.secModel.doi = strdup(doi))) + caps->host.nsecModels = 1; + if (!(caps->host.secModels[0].model = strdup(model))) + goto no_memory; + if (!(caps->host.secModels[0].doi = strdup(doi))) goto no_memory; }
diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index 4cccd53..ffd3c9c 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -1479,10 +1479,12 @@ static int lxcVmTerminate(lxc_driver_t *driver, vm->def, false); virSecurityManagerReleaseLabel(driver->securityManager, vm->def); /* Clear out dynamically assigned labels */ - if (vm->def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC) { - VIR_FREE(vm->def->seclabel.model); - VIR_FREE(vm->def->seclabel.label); - VIR_FREE(vm->def->seclabel.imagelabel); + /* Manages just the primary sec driver for lxc */ + if (vm->def->nseclabels + && vm->def->seclabels[0]->type == VIR_DOMAIN_SECLABEL_DYNAMIC) { + VIR_FREE(vm->def->seclabels[0]->model); + VIR_FREE(vm->def->seclabels[0]->label); + VIR_FREE(vm->def->seclabels[0]->imagelabel); }
I guess we want to VIR_FREE(vm->def->seclabels) and m->def->nseclabels = 0; ...
if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) == 0) { @@ -1818,8 +1820,10 @@ static int lxcVmStart(virConnectPtr conn, /* If you are using a SecurityDriver with dynamic labelling, then generate a security label for isolation */ VIR_DEBUG("Generating domain security label (if required)"); - if (vm->def->seclabel.type == VIR_DOMAIN_SECLABEL_DEFAULT) - vm->def->seclabel.type = VIR_DOMAIN_SECLABEL_NONE; + if (vm->def->nseclabels + && vm->def->seclabels[0]->type == VIR_DOMAIN_SECLABEL_DEFAULT) { + vm->def->seclabels[0]->type = VIR_DOMAIN_SECLABEL_NONE; + }
if (virSecurityManagerGenLabel(driver->securityManager, vm->def) < 0) { virDomainAuditSecurityLabel(vm, false); @@ -1990,10 +1994,11 @@ cleanup: vm->def, false); virSecurityManagerReleaseLabel(driver->securityManager, vm->def); /* Clear out dynamically assigned labels */ - if (vm->def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC) { - VIR_FREE(vm->def->seclabel.model); - VIR_FREE(vm->def->seclabel.label); - VIR_FREE(vm->def->seclabel.imagelabel); + if (vm->def->nseclabels + && vm->def->seclabels[0]->type == VIR_DOMAIN_SECLABEL_DYNAMIC) { + VIR_FREE(vm->def->seclabels[0]->model); + VIR_FREE(vm->def->seclabels[0]->label); + VIR_FREE(vm->def->seclabels[0]->imagelabel);
... and here as well.
} } for (i = 0 ; i < nttyFDs ; i++) @@ -2233,12 +2238,12 @@ static int lxcNodeGetSecurityModel(virConnectPtr conn, lxcDriverLock(driver); memset(secmodel, 0, sizeof(*secmodel));
- /* NULL indicates no driver, which we treat as - * success, but simply return no data in *secmodel */ - if (driver->caps->host.secModel.model == NULL) + /* we treat no driver as success, but simply return no data in *secmodel */ + if (driver->caps->host.nsecModels == 0 + || driver->caps->host.secModels[0].model == NULL) goto cleanup;
- if (!virStrcpy(secmodel->model, driver->caps->host.secModel.model, + if (!virStrcpy(secmodel->model, driver->caps->host.secModels[0].model, VIR_SECURITY_MODEL_BUFLEN)) { lxcError(VIR_ERR_INTERNAL_ERROR, _("security model string exceeds max %d bytes"), @@ -2247,7 +2252,7 @@ static int lxcNodeGetSecurityModel(virConnectPtr conn, goto cleanup; }
- if (!virStrcpy(secmodel->doi, driver->caps->host.secModel.doi, + if (!virStrcpy(secmodel->doi, driver->caps->host.secModels[0].doi, VIR_SECURITY_DOI_BUFLEN)) { lxcError(VIR_ERR_INTERNAL_ERROR, _("security DOI string exceeds max %d bytes"),
Otherwise looking good.

--- src/test/test_driver.c | 11 +++++++---- 1 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/test/test_driver.c b/src/test/test_driver.c index 7038741..0b595b0 100644 --- a/src/test/test_driver.c +++ b/src/test/test_driver.c @@ -210,12 +210,15 @@ testBuildCapabilities(virConnectPtr conn) { caps->privateDataAllocFunc = testDomainObjPrivateAlloc; caps->privateDataFreeFunc = testDomainObjPrivateFree; - caps->host.secModel.model = strdup("testSecurity"); - if (!caps->host.secModel.model) + caps->host.nsecModels = 1; + if (VIR_ALLOC_N(caps->host.secModels, caps->host.nsecModels) < 0) + goto no_memory; + caps->host.secModels[0].model = strdup("testSecurity"); + if (!caps->host.secModels[0].model) goto no_memory; - caps->host.secModel.doi = strdup(""); - if (!caps->host.secModel.doi) + caps->host.secModels[0].doi = strdup(""); + if (!caps->host.secModels[0].doi) goto no_memory; return caps; -- 1.7.1

On 21.05.2012 15:39, Marcelo Cerri wrote:
--- src/test/test_driver.c | 11 +++++++---- 1 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/src/test/test_driver.c b/src/test/test_driver.c index 7038741..0b595b0 100644 --- a/src/test/test_driver.c +++ b/src/test/test_driver.c @@ -210,12 +210,15 @@ testBuildCapabilities(virConnectPtr conn) { caps->privateDataAllocFunc = testDomainObjPrivateAlloc; caps->privateDataFreeFunc = testDomainObjPrivateFree;
- caps->host.secModel.model = strdup("testSecurity"); - if (!caps->host.secModel.model) + caps->host.nsecModels = 1; + if (VIR_ALLOC_N(caps->host.secModels, caps->host.nsecModels) < 0) + goto no_memory; + caps->host.secModels[0].model = strdup("testSecurity"); + if (!caps->host.secModels[0].model) goto no_memory;
- caps->host.secModel.doi = strdup(""); - if (!caps->host.secModel.doi) + caps->host.secModels[0].doi = strdup(""); + if (!caps->host.secModels[0].doi) goto no_memory;
return caps;
yeah, this is the missing part I am mentioning in the 1st patch. ACK Michal

Hi, This patch contains some small fixes to my last set of patch. Please, can you review it and provide me some feed back? Best regards, Marcelo Cerri --- src/conf/domain_conf.c | 8 +++----- src/qemu/qemu_driver.c | 6 +++--- src/security/security_dac.c | 4 ++-- src/security/security_stack.c | 4 +++- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 91ffb6f..2e186ce 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -3165,7 +3165,6 @@ virSecurityLabelDefParseXML(virSecurityLabelDefPtr def, def->baselabel = p; } - /* TODO: check */ /* Always parse model */ p = virXPathStringLimit("string(./@model)", VIR_SECURITY_MODEL_BUFLEN-1, ctxt); @@ -3261,8 +3260,9 @@ virSecurityDeviceLabelDefParseXML(virDomainDiskDefPtr def, /* get model associated to this override */ model = virXMLPropString(list[i], "model"); if (model == NULL) { - // TODO primary ? - // vmDef = ? + virDomainReportError(VIR_ERR_XML_ERROR, "%s", + _("invalid security model")); + goto error; } else { /* find the security label that it's being overrided */ for (j = 0; j < nvmSeclabels; j++) { @@ -10924,8 +10924,6 @@ virSecurityLabelDefFormat(virBufferPtr buf, virSecurityLabelDefPtr def) virBufferAsprintf(buf, " relabel='%s'", def->norelabel ? "no" : "yes"); -VIR_DEBUG("FMT %s: %s %s %s", def->model, def->label, def->imagelabel, def->baselabel); // TODO remove - if (def->label || def->imagelabel || def->baselabel) { virBufferAddLit(buf, ">\n"); diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 39d9eee..7067f4b 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -241,7 +241,7 @@ qemuSecurityInit(struct qemud_driver *driver) names = driver->additionalSecurityDriverNames; while (names && *names) { if (STREQ("dac", *names)) { - /* A DAC driver has specic parameters */ + /* A DAC driver has specific parameters */ nested = virSecurityManagerNewDAC(QEMU_DRIVER_NAME, driver->user, driver->group, @@ -274,7 +274,7 @@ qemuSecurityInit(struct qemud_driver *driver) } names++; } - /* If there isn't a DAC driver, create a new one and add it to the stack + /* If there is no DAC driver, create a new one and add it to the stack * manager */ if (names == NULL || *names == NULL) { nested = virSecurityManagerNewDAC(QEMU_DRIVER_NAME, @@ -334,7 +334,7 @@ qemuCreateCapabilities(virCapsPtr oldcaps, goto err_exit; } - /* access sec drivers and create a sec model to each one */ + /* access sec drivers and create a sec model for each one */ sec_managers = virSecurityManagerGetNested(driver->securityManager); if (sec_managers == NULL) { goto err_exit; diff --git a/src/security/security_dac.c b/src/security/security_dac.c index 0badafb..ae9ddfc 100644 --- a/src/security/security_dac.c +++ b/src/security/security_dac.c @@ -110,7 +110,7 @@ int virSecurityDACParseIds(virDomainDefPtr def, uid_t *uidPtr, gid_t *gidPtr) if (seclabel->label && parseIds(seclabel->label, &uid, &gid)) { virSecurityReportError(VIR_ERR_INTERNAL_ERROR, _("failed to parse uid and gid for DAC " - "securit driver")); + "security driver")); return -1; } @@ -161,7 +161,7 @@ int virSecurityDACParseImageIds(virDomainDefPtr def, && parseIds(seclabel->imagelabel, &uid, &gid)) { virSecurityReportError(VIR_ERR_INTERNAL_ERROR, _("failed to parse uid and gid for DAC " - "securit driver")); + "security driver")); return -1; } diff --git a/src/security/security_stack.c b/src/security/security_stack.c index dd0aebc..4cf58f8 100644 --- a/src/security/security_stack.c +++ b/src/security/security_stack.c @@ -138,8 +138,10 @@ virSecurityStackVerify(virSecurityManagerPtr mgr, int rc = 0; for(; item; item = item->next) { - if (virSecurityManagerVerify(item->securityManager, def) < 0) + if (virSecurityManagerVerify(item->securityManager, def) < 0) { rc = -1; + break; + } } return rc; -- 1.7.1

On 21.05.2012 15:39, Marcelo Cerri wrote:
Hi,
This set of patches updates the libvirt's security driver mechanism to support per-guest configurable user and group for QEMU processes running together with other security drivers, such as SELinux and AppArmor.
This patches implement the changes discussed in the following thread:
https://www.redhat.com/archives/libvir-list/2012-February/msg00990.html
Regards, Marcelo Cerri
The feature looks reasonable but I think the implementation needs a cleanup. I've pointed out some things. Overall, there are some rules which are good to follow when adding new API: http://libvirt.org/api_extension.html It's always good to prepare environment for new API - like you do in the first patch. However, the order of other patches should be slightly different. More important, we would like to compile after each patch. IOW, I'd like to see some patches split and some merged following the guide I am linking above. It's okay to add an API without driver implementation -> splitting code into {add API, remote driver impl and let libvirt throw 'unsupported' error} and {implement new API for one driver} {implement new API for second driver} etc. On the other hand, API that requires XML change shouldn't be introduced before the change itself (it's okay if they are in the same patch). I am not an security expert so I haven't looked closely on security drivers though. Okay, I did, but just for code cleanliness or obvious mistakes. I think others may give their review too. Looking forward to v2. Michal

On Mon, May 21, 2012 at 10:39:22AM -0300, Marcelo Cerri wrote:
Hi,
This set of patches updates the libvirt's security driver mechanism to support per-guest configurable user and group for QEMU processes running together with other security drivers, such as SELinux and AppArmor.
This patches implement the changes discussed in the following thread:
https://www.redhat.com/archives/libvir-list/2012-February/msg00990.html
In general this patch series needs to be re-arranged so that it will successfully compile & pass 'make check && make syntax-check' at each patch. It needs to have a cleaner split of simple no-op code refactoring, vs new functionality. Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

On Mon, Jun 11, 2012 at 04:18:21PM +0100, Daniel P. Berrange wrote:
On Mon, May 21, 2012 at 10:39:22AM -0300, Marcelo Cerri wrote:
Hi,
This set of patches updates the libvirt's security driver mechanism to support per-guest configurable user and group for QEMU processes running together with other security drivers, such as SELinux and AppArmor.
This patches implement the changes discussed in the following thread:
https://www.redhat.com/archives/libvir-list/2012-February/msg00990.html
In general this patch series needs to be re-arranged so that it will successfully compile & pass 'make check && make syntax-check' at each patch. It needs to have a cleaner split of simple no-op code refactoring, vs new functionality.
I think I'd probably recommend splitting it up thus: 1. Refactor internal virDomainDefPtr/virCapsPtr data structures to allow multiple seclabels, but only use first label. Also update all code to compile with these changes 2. Extend RNG schema to allow multiple seclabels and extend domain_conf.c XML parser / formatter to cope with mulitiple seclabels. 3. Add new API & remote protocol for getting list of security labels for the domain 4. Extend the DAC security driver to pull configurable uid/gid out of the sec label in virDomainDefPtr 5. Extend the QEMU driver to configure multiple security drivers Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|
participants (3)
-
Daniel P. Berrange
-
Marcelo Cerri
-
Michal Privoznik