+Tue Mar 3 09:40:13 GMT 2009 Daniel P. Berrange <berrange@redhat.com>
+
+ Core internal driver stub for sVirt support (Jams Morris & Dan Walsh)
+ * Makefile.maint: Add virSecurityReportError as a msggen
+ function
+ * docs/schemas/capability.rng: Add <secmodel> element
+ * docs/schemas/domain.rng: Add <seclabel> element
+ * include/libvirt/virterror.h, src/virterror.c: Add
+ VIR_FROM_SECURITY and VIR_ERR_NO_SECURITY_MODEL
+ * po/POTFILES.in: Add src/security.c
+ * src/Makefile.am: Build security driver into libvirt.so
+ * src/capabilities.c, src/capabilities.h: Handling of
+ <secmodel> element / data
+ * src/domain_conf.c, src/domain_conf.h: Handling of
+ <seclabel> element / data
+ * src/libvirt_private.syms: Add virXPathStringLimit and
+ virSecurity* methods
+ * src/security.c, src/security.h: Add internal driver
+ stub impl
+ * src/storage_backend.c: TODO item about seclabel
+ * src/xml.c, src/xml.h: Add virXPathStringLimit
+
Tue Mar 3 09:25:13 GMT 2009 Daniel P. Berrange <berrange@redhat.com>
Remote protocol / RPC API for sVirt support (James Morris & Dan Walsh)
msg_gen_function += umlReportError
msg_gen_function += virConfError
msg_gen_function += virDomainReportError
+msg_gen_function += virSecurityReportError
msg_gen_function += virHashError
msg_gen_function += virLibConnError
msg_gen_function += virLibDomainError
<optional>
<ref name='topology'/>
</optional>
+ <optional>
+ <ref name='secmodel'/>
+ </optional>
+ </element>
+ </define>
+
+ <define name='secmodel'>
+ <element name='secmodel'>
+ <element name='model'>
+ <text/>
+ </element>
+ <element name='doi'>
+ <text/>
+ </element>
</element>
</define>
+
<define name='cpufeatures'>
<element name='features'>
<optional>
<optional>
<ref name='devices'/>
</optional>
+ <optional>
+ <ref name='seclabel'/>
+ </optional>
</interleave>
</element>
</define>
+ <define name='seclabel'>
+ <element name='seclabel'>
+ <attribute name='model'>
+ <text/>
+ </attribute>
+ <element name='label'>
+ <text/>
+ </element>
+ </element>
+ </define>
+
+
<define name='hvs'>
<attribute name='type'>
<choice>
VIR_FROM_UML, /* Error at the UML driver */
VIR_FROM_NODEDEV, /* Error from node device monitor */
VIR_FROM_XEN_INOTIFY, /* Error from xen inotify layer */
+ VIR_FROM_SECURITY, /* Error from security framework */
} virErrorDomain;
VIR_WAR_NO_NODE, /* failed to start node driver */
VIR_ERR_INVALID_NODE_DEVICE,/* invalid node device object */
VIR_ERR_NO_NODE_DEVICE,/* node device not found */
+ VIR_ERR_NO_SECURITY_MODEL, /* security model not found */
} virErrorNumber;
/**
src/qemu_conf.c
src/qemu_driver.c
src/remote_internal.c
+src/security.c
src/storage_backend.c
src/storage_backend_disk.c
src/storage_backend_fs.c
NETWORK_DRIVER_SOURCES = \
network_driver.h network_driver.c
-# And finally storage backend specific impls
+# Storage backend specific impls
STORAGE_DRIVER_SOURCES = \
storage_driver.h storage_driver.c \
storage_backend.h storage_backend.c
parthelper.c
+# Security framework and drivers for various models
+SECURITY_DRIVER_SOURCES = \
+ security.h security.c
+
+
NODE_DEVICE_DRIVER_SOURCES = \
node_device.c node_device.h
endif
+libvirt_driver_security_la_SOURCES = $(SECURITY_DRIVER_SOURCES)
+noinst_LTLIBRARIES += libvirt_driver_security.la
+libvirt_la_LIBADD += libvirt_driver_security.la
+
# Add all conditional sources just in case...
EXTRA_DIST += \
$(TEST_DRIVER_SOURCES) \
VIR_FREE(caps->host.migrateTrans);
VIR_FREE(caps->host.arch);
+ VIR_FREE(caps->host.secModel.model);
+ VIR_FREE(caps->host.secModel.doi);
VIR_FREE(caps);
}
virBufferAddLit(&xml, " </cells>\n");
virBufferAddLit(&xml, " </topology>\n");
}
+
+ if (caps->host.secModel.model) {
+ virBufferAddLit(&xml, " <secmodel>\n");
+ virBufferVSprintf(&xml, " <model>%s</model>\n", caps->host.secModel.model);
+ virBufferVSprintf(&xml, " <doi>%s</doi>\n", caps->host.secModel.doi);
+ virBufferAddLit(&xml, " </secmodel>\n");
+ }
+
virBufferAddLit(&xml, " </host>\n\n");
int *cpus;
};
+typedef struct _virCapsHostSecModel virCapsHostSecModel;
+struct _virCapsHostSecModel {
+ char *model;
+ char *doi;
+};
+
typedef struct _virCapsHost virCapsHost;
typedef virCapsHost *virCapsHostPtr;
struct _virCapsHost {
char **migrateTrans;
int nnumaCell;
virCapsHostNUMACellPtr *numaCell;
+ virCapsHostSecModel secModel;
};
typedef struct _virCaps virCaps;
VIR_FREE(def);
}
+void virSecurityLabelDefFree(virDomainDefPtr def);
+
+void virSecurityLabelDefFree(virDomainDefPtr def)
+{
+ VIR_FREE(def->seclabel.model);
+ VIR_FREE(def->seclabel.label);
+ VIR_FREE(def->seclabel.imagelabel);
+}
+
void virDomainDefFree(virDomainDefPtr def)
{
unsigned int i;
VIR_FREE(def->cpumask);
VIR_FREE(def->emulator);
+ virSecurityLabelDefFree(def);
+
VIR_FREE(def);
}
return 0;
}
+static int
+virSecurityLabelDefParseXML(virConnectPtr conn,
+ const virDomainDefPtr def,
+ xmlXPathContextPtr ctxt)
+{
+ char *p;
+
+ if (virXPathNode(conn, "./seclabel", ctxt) == NULL)
+ return 0;
+
+ p = virXPathStringLimit(conn, "string(./seclabel/label[1])",
+ VIR_SECURITY_LABEL_BUFLEN-1, ctxt);
+ if (p == NULL)
+ goto error;
+ def->seclabel.label = p;
+
+ p = virXPathStringLimit(conn, "string(./seclabel/@model)",
+ VIR_SECURITY_MODEL_BUFLEN-1, ctxt);
+ if (p == NULL)
+ goto error;
+ def->seclabel.model = p;
+
+ return 0;
+
+error:
+ virSecurityLabelDefFree(def);
+ return -1;
+}
virDomainDeviceDefPtr virDomainDeviceDefParse(virConnectPtr conn,
virCapsPtr caps,
}
VIR_FREE(nodes);
+ /* analysis of security label */
+ if (virSecurityLabelDefParseXML(conn, def, ctxt) == -1)
+ goto error;
+
return def;
no_memory:
goto cleanup;
virBufferAddLit(&buf, " </devices>\n");
+
+ if (def->seclabel.model) {
+ virBufferEscapeString(&buf, " <seclabel model='%s'>\n", def->seclabel.model);
+ virBufferEscapeString(&buf, " <label>%s</label>\n", def->seclabel.label);
+ virBufferAddLit(&buf, " </seclabel>\n");
+ }
+
virBufferAddLit(&buf, "</domain>\n");
if (virBufferError(&buf))
char *bootloaderArgs;
};
+/* Security configuration for domain */
+typedef struct _virSecurityLabelDef virSecurityLabelDef;
+typedef virSecurityLabelDef *virSecurityLabelDefPtr;
+struct _virSecurityLabelDef {
+ char *model; /* name of security model */
+ char *label; /* security label string */
+ char *imagelabel; /* security image label string */
+};
+
#define VIR_DOMAIN_CPUMASK_LEN 1024
/* Guest VM main configuration */
/* Only 1 */
virDomainChrDefPtr console;
+ virSecurityLabelDef seclabel;
};
/* Guest VM runtime state */
free_qparam_set;
+# security.h
+virSecurityDriverStartup;
+virSecurityDriverInit;
+virSecurityDriverSetDOI;
+virSecurityDriverGetDOI;
+virSecurityDriverGetModel;
+
+
# storage_conf.h
virStoragePoolDefFormat;
virStoragePoolDefFree;
virXPathNodeSet;
virXPathString;
virXMLPropString;
+virXPathStringLimit;
--- /dev/null
+/*
+ * Copyright (C) 2008 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * Authors:
+ * James Morris <jmorris@namei.org>
+ *
+ */
+#include <config.h>
+#include <string.h>
+
+#include "virterror_internal.h"
+
+#include "security.h"
+
+static virSecurityDriverPtr security_drivers[] = {
+ NULL
+};
+
+int
+virSecurityDriverStartup(virSecurityDriverPtr *drv,
+ const char *name)
+{
+ unsigned int i;
+
+ if (name && STREQ(name, "none"))
+ return -2;
+
+ for (i = 0; security_drivers[i] != NULL ; i++) {
+ virSecurityDriverPtr tmp = security_drivers[i];
+
+ if (name && STRNEQ(tmp->name, name))
+ continue;
+
+ switch (tmp->probe()) {
+ case SECURITY_DRIVER_ENABLE:
+ virSecurityDriverInit(tmp);
+ if (tmp->open(NULL, tmp) == -1) {
+ return -1;
+ } else {
+ *drv = tmp;
+ return 0;
+ }
+ break;
+
+ case SECURITY_DRIVER_DISABLE:
+ break;
+
+ default:
+ return -1;
+ }
+ }
+ return -2;
+}
+
+void
+virSecurityReportError(virConnectPtr conn, int code, const char *fmt, ...)
+{
+ va_list args;
+ char errorMessage[1024];
+
+ if (fmt) {
+ va_start(args, fmt);
+ vsnprintf(errorMessage, sizeof(errorMessage) - 1, fmt, args);
+ va_end(args);
+ } else
+ errorMessage[0] = '\0';
+
+ virRaiseError(conn, NULL, NULL, VIR_FROM_SECURITY, code,
+ VIR_ERR_ERROR, NULL, NULL, NULL, -1, -1, "%s",
+ errorMessage);
+}
+
+/*
+ * Helpers
+ */
+void
+virSecurityDriverInit(virSecurityDriverPtr drv)
+{
+ memset(&drv->_private, 0, sizeof drv->_private);
+}
+
+int
+virSecurityDriverSetDOI(virConnectPtr conn,
+ virSecurityDriverPtr drv,
+ const char *doi)
+{
+ if (strlen(doi) >= VIR_SECURITY_DOI_BUFLEN) {
+ virSecurityReportError(conn, VIR_ERR_ERROR,
+ _("%s: DOI \'%s\' is "
+ "longer than the maximum allowed length of %d"),
+ __func__, doi, VIR_SECURITY_DOI_BUFLEN - 1);
+ return -1;
+ }
+ strcpy(drv->_private.doi, doi);
+ return 0;
+}
+
+const char *
+virSecurityDriverGetDOI(virSecurityDriverPtr drv)
+{
+ return drv->_private.doi;
+}
+
+const char *
+virSecurityDriverGetModel(virSecurityDriverPtr drv)
+{
+ return drv->name;
+}
--- /dev/null
+/*
+ * Copyright (C) 2008 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * Authors:
+ * James Morris <jmorris@namei.org>
+ *
+ */
+#ifndef __VIR_SECURITY_H__
+#define __VIR_SECURITY_H__
+
+#include "internal.h"
+#include "domain_conf.h"
+
+/*
+ * Return values for security driver probing: the driver will determine
+ * whether it should be enabled or disabled.
+ */
+typedef enum {
+ SECURITY_DRIVER_ENABLE = 0,
+ SECURITY_DRIVER_ERROR = -1,
+ SECURITY_DRIVER_DISABLE = -2,
+} virSecurityDriverStatus;
+
+typedef struct _virSecurityDriver virSecurityDriver;
+typedef virSecurityDriver *virSecurityDriverPtr;
+typedef virSecurityDriverStatus (*virSecurityDriverProbe) (void);
+typedef int (*virSecurityDriverOpen) (virConnectPtr conn,
+ virSecurityDriverPtr drv);
+typedef int (*virSecurityDomainRestoreImageLabel) (virConnectPtr conn,
+ virDomainObjPtr vm,
+ virDomainDeviceDefPtr dev);
+typedef int (*virSecurityDomainSetImageLabel) (virConnectPtr conn,
+ virDomainObjPtr vm,
+ virDomainDeviceDefPtr dev);
+typedef int (*virSecurityDomainGenLabel) (virDomainObjPtr sec);
+typedef int (*virSecurityDomainGetLabel) (virConnectPtr conn,
+ virDomainObjPtr vm,
+ virSecurityLabelPtr sec);
+typedef int (*virSecurityDomainRestoreLabel) (virConnectPtr conn,
+ virDomainObjPtr vm);
+typedef int (*virSecurityDomainSetLabel) (virConnectPtr conn,
+ virSecurityDriverPtr drv,
+ virDomainObjPtr vm);
+
+struct _virSecurityDriver {
+ const char *name;
+ virSecurityDriverProbe probe;
+ virSecurityDriverOpen open;
+ virSecurityDomainRestoreImageLabel domainRestoreSecurityImageLabel;
+ virSecurityDomainSetImageLabel domainSetSecurityImageLabel;
+ virSecurityDomainGenLabel domainGenSecurityLabel;
+ virSecurityDomainGetLabel domainGetSecurityLabel;
+ virSecurityDomainSetLabel domainSetSecurityLabel;
+ virSecurityDomainRestoreLabel domainRestoreSecurityLabel;
+
+ /*
+ * This is internally managed driver state and should only be accessed
+ * via helpers below.
+ */
+ struct {
+ char doi[VIR_SECURITY_DOI_BUFLEN];
+ } _private;
+};
+
+/* Global methods */
+int virSecurityDriverStartup(virSecurityDriverPtr *drv,
+ const char *name);
+
+void
+virSecurityReportError(virConnectPtr conn, int code, const char *fmt, ...)
+ ATTRIBUTE_FORMAT(printf, 3, 4);
+
+/* Helpers */
+void virSecurityDriverInit(virSecurityDriverPtr drv);
+int virSecurityDriverSetDOI(virConnectPtr conn,
+ virSecurityDriverPtr drv,
+ const char *doi);
+const char *virSecurityDriverGetDOI(virSecurityDriverPtr drv);
+const char *virSecurityDriverGetModel(virSecurityDriverPtr drv);
+
+#endif /* __VIR_SECURITY_H__ */
VIR_FREE(target->perms.label);
#if HAVE_SELINUX
+ /* XXX: make this a security driver call */
if (fgetfilecon(fd, &filecon) == -1) {
if (errno != ENODATA && errno != ENOTSUP) {
virReportSystemError(conn, errno,
case VIR_FROM_UML:
dom = "UML ";
break;
+ case VIR_FROM_SECURITY:
+ dom = "Security Labeling ";
+ break;
}
return(dom);
}
else
errmsg = _("Node device not found: %s");
break;
+ case VIR_ERR_NO_SECURITY_MODEL:
+ if (info == NULL)
+ errmsg = _("Security model not found");
+ else
+ errmsg = _("Security model not found: %s");
+ break;
}
return (errmsg);
}
return (ret);
}
+/**
+ * virXPathStringLimit:
+ * @xpath: the XPath string to evaluate
+ * @maxlen: maximum length permittred string
+ * @ctxt: an XPath context
+ *
+ * Wrapper for virXPathString, which validates the length of the returned
+ * string.
+ *
+ * Returns a new string which must be deallocated by the caller or NULL if
+ * the evaluation failed.
+ */
+char *
+virXPathStringLimit(virConnectPtr conn,
+ const char *xpath,
+ size_t maxlen,
+ xmlXPathContextPtr ctxt)
+{
+ char *tmp = virXPathString(conn, xpath, ctxt);
+
+ if (tmp != NULL && strlen(tmp) >= maxlen) {
+ virXMLError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("\'%s\' value longer than %Zd bytes in virXPathStringLimit()"),
+ xpath, maxlen);
+ return NULL;
+ }
+
+ return tmp;
+}
+
/**
* virXPathNumber:
* @xpath: the XPath string to evaluate
char * virXPathString (virConnectPtr conn,
const char *xpath,
xmlXPathContextPtr ctxt);
+char * virXPathStringLimit(virConnectPtr conn,
+ const char *xpath,
+ size_t maxlen,
+ xmlXPathContextPtr ctxt);
int virXPathNumber (virConnectPtr conn,
const char *xpath,
xmlXPathContextPtr ctxt,