-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Jim Meyering wrote: > Daniel J Walsh <dwalsh@xxxxxxxxxx> wrote: >> Is this acceptable to upstream? > > Hi Daniel and James, > > I tried to apply that using "git apply FILE" and that failed > due to fuzz and white-space problems. > I resorted to using "patch -p1 < FILE", which accommodated. > First step was to run "make". that passed. good ;-) > Then "make check". So did that. doubly-good. > Finally "make syntax-check". > That highlighted several problems, which I've corrected below, > so now it passes. Also, while glancing through, I stumbled across a > potential leak and fixed it. Haven't gone through it thoroughly. > > Below I've included the incremental changes to address those > problems, along with the rediff'd original. You're welcome to > fold those into your patch, in case you're up for another iteration. > > One thing I didn't address: > In the new virXPathStringLimit function, note that virXPathString > returning NULL can also mean out-of-memory (which is diagnosed by > virXPathString itself), in which case, the diagnostic from > virXPathStringLimit would be wrong. > > Also, please consider adding (or at least outlining) a few simple tests > to exercise some of the new code. At the very least, the parsing > of the new XML elements has to be exercised. Also, please update > docs/schemas/capability.rng. > > Of course, such a large change deserves more of a ChangeLog > entry and at least a little documentation. > > > From ea230077f6e8bccf085b1ec2febebc10144d44da Mon Sep 17 00:00:00 2001 > From: James Morris <jmorris@xxxxxxxxx> > Date: Tue, 17 Feb 2009 18:50:24 +0100 > Subject: [PATCH 1/5] selinux support > > --- > include/libvirt/libvirt.h | 67 +++++++++++++++ > include/libvirt/libvirt.h.in | 67 +++++++++++++++ > include/libvirt/virterror.h | 2 + > po/POTFILES.in | 2 + > python/generator.py | 2 + > qemud/Makefile.am | 1 + > qemud/remote.c | 70 ++++++++++++++++ > qemud/remote_dispatch_args.h | 1 + > qemud/remote_dispatch_prototypes.h | 14 +++ > qemud/remote_dispatch_ret.h | 2 + > qemud/remote_dispatch_table.h | 10 +++ > qemud/remote_protocol.c | 37 +++++++++ > qemud/remote_protocol.h | 37 +++++++++ > qemud/remote_protocol.x | 34 ++++++++- > src/Makefile.am | 25 +++++- > src/capabilities.c | 10 +++ > src/capabilities.h | 7 ++ > src/domain_conf.c | 51 ++++++++++++ > src/domain_conf.h | 9 ++ > src/driver.h | 8 ++ > src/libvirt.c | 64 +++++++++++++++ > src/libvirt_private.syms | 1 + > src/libvirt_public.syms | 3 +- > src/lxc_driver.c | 2 + > src/openvz_driver.c | 2 + > src/qemu_conf.h | 3 + > src/qemu_driver.c | 158 ++++++++++++++++++++++++++++++++++++ > src/remote_internal.c | 63 ++++++++++++++ > src/security.c | 133 ++++++++++++++++++++++++++++++ > src/security.h | 72 ++++++++++++++++ > src/security_selinux.c | 108 ++++++++++++++++++++++++ > src/security_selinux.h | 18 ++++ > src/storage_backend.c | 1 + > src/test.c | 2 + > src/uml_driver.c | 2 + > src/virsh.c | 26 ++++++ > src/virterror.c | 9 ++ > src/xml.c | 33 ++++++++ > src/xml.h | 4 + > tests/daemon-conf | 3 + > 40 files changed, 1159 insertions(+), 4 deletions(-) > create mode 100644 src/security.c > create mode 100644 src/security.h > create mode 100644 src/security_selinux.c > create mode 100644 src/security_selinux.h > > diff --git a/include/libvirt/libvirt.h b/include/libvirt/libvirt.h > index e32d40b..c8489e8 100644 > --- a/include/libvirt/libvirt.h > +++ b/include/libvirt/libvirt.h > @@ -111,6 +111,68 @@ typedef enum { > } virDomainCreateFlags; > > /** > + * VIR_SECURITY_LABEL_BUFLEN: > + * > + * Macro providing the maximum length of the virSecurityLabel label string. > + * Note that this value is based on that used by Labeled NFS. > + */ > +#define VIR_SECURITY_LABEL_BUFLEN (4096 + 1) > + > +/** > + * virSecurityLabel: > + * > + * a virSecurityLabel is a structure filled by virDomainGetSecurityLabel(), > + * providing the security label and associated attributes for the specified > + * domain. > + * > + */ > +typedef struct _virSecurityLabel { > + char label[VIR_SECURITY_LABEL_BUFLEN]; /* security label string */ > + int enforcing; /* 1 if security policy is being enforced for domain */ > +} virSecurityLabel; > + > +/** > + * virSecurityLabelPtr: > + * > + * a virSecurityLabelPtr is a pointer to a virSecurityLabel. > + */ > +typedef virSecurityLabel *virSecurityLabelPtr; > + > +/** > + * VIR_SECURITY_MODEL_BUFLEN: > + * > + * Macro providing the maximum length of the virSecurityModel model string. > + */ > +#define VIR_SECURITY_MODEL_BUFLEN (256 + 1) > + > +/** > + * VIR_SECURITY_DOI_BUFLEN: > + * > + * Macro providing the maximum length of the virSecurityModel doi string. > + */ > +#define VIR_SECURITY_DOI_BUFLEN (256 + 1) > + > +/** > + * virSecurityModel: > + * > + * a virSecurityModel is a structure filled by virNodeGetSecurityModel(), > + * providing the per-hypervisor security model and DOI attributes for the > + * specified domain. > + * > + */ > +typedef struct _virSecurityModel { > + char model[VIR_SECURITY_MODEL_BUFLEN]; /* security model string */ > + char doi[VIR_SECURITY_DOI_BUFLEN]; /* domain of interpetation */ > +} virSecurityModel; > + > +/** > + * virSecurityModelPtr: > + * > + * a virSecurityModelPtr is a pointer to a virSecurityModel. > + */ > +typedef virSecurityModel *virSecurityModelPtr; > + > +/** > * virNodeInfoPtr: > * > * a virNodeInfo is a structure filled by virNodeGetInfo() and providing > @@ -417,6 +479,9 @@ char * virConnectGetCapabilities (virConnectPtr conn); > > unsigned long long virNodeGetFreeMemory (virConnectPtr conn); > > +int virNodeGetSecurityModel (virConnectPtr conn, > + virSecurityModelPtr secmodel); > + > /* > * Gather list of running domains > */ > @@ -506,6 +571,8 @@ int virDomainSetMaxMemory (virDomainPtr domain, > int virDomainSetMemory (virDomainPtr domain, > unsigned long memory); > int virDomainGetMaxVcpus (virDomainPtr domain); > +int virDomainGetSecurityLabel (virDomainPtr domain, > + virSecurityLabelPtr seclabel); > > /* > * XML domain description > diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in > index af97bfd..492c06c 100644 > --- a/include/libvirt/libvirt.h.in > +++ b/include/libvirt/libvirt.h.in > @@ -111,6 +111,68 @@ typedef enum { > } virDomainCreateFlags; > > /** > + * VIR_SECURITY_LABEL_BUFLEN: > + * > + * Macro providing the maximum length of the virSecurityLabel label string. > + * Note that this value is based on that used by Labeled NFS. > + */ > +#define VIR_SECURITY_LABEL_BUFLEN (4096 + 1) > + > +/** > + * virSecurityLabel: > + * > + * a virSecurityLabel is a structure filled by virDomainGetSecurityLabel(), > + * providing the security label and associated attributes for the specified > + * domain. > + * > + */ > +typedef struct _virSecurityLabel { > + char label[VIR_SECURITY_LABEL_BUFLEN]; /* security label string */ > + int enforcing; /* 1 if security policy is being enforced for domain */ > +} virSecurityLabel; > + > +/** > + * virSecurityLabelPtr: > + * > + * a virSecurityLabelPtr is a pointer to a virSecurityLabel. > + */ > +typedef virSecurityLabel *virSecurityLabelPtr; > + > +/** > + * VIR_SECURITY_MODEL_BUFLEN: > + * > + * Macro providing the maximum length of the virSecurityModel model string. > + */ > +#define VIR_SECURITY_MODEL_BUFLEN (256 + 1) > + > +/** > + * VIR_SECURITY_DOI_BUFLEN: > + * > + * Macro providing the maximum length of the virSecurityModel doi string. > + */ > +#define VIR_SECURITY_DOI_BUFLEN (256 + 1) > + > +/** > + * virSecurityModel: > + * > + * a virSecurityModel is a structure filled by virNodeGetSecurityModel(), > + * providing the per-hypervisor security model and DOI attributes for the > + * specified domain. > + * > + */ > +typedef struct _virSecurityModel { > + char model[VIR_SECURITY_MODEL_BUFLEN]; /* security model string */ > + char doi[VIR_SECURITY_DOI_BUFLEN]; /* domain of interpetation */ > +} virSecurityModel; > + > +/** > + * virSecurityModelPtr: > + * > + * a virSecurityModelPtr is a pointer to a virSecurityModel. > + */ > +typedef virSecurityModel *virSecurityModelPtr; > + > +/** > * virNodeInfoPtr: > * > * a virNodeInfo is a structure filled by virNodeGetInfo() and providing > @@ -417,6 +479,9 @@ char * virConnectGetCapabilities (virConnectPtr conn); > > unsigned long long virNodeGetFreeMemory (virConnectPtr conn); > > +int virNodeGetSecurityModel (virConnectPtr conn, > + virSecurityModelPtr secmodel); > + > /* > * Gather list of running domains > */ > @@ -506,6 +571,8 @@ int virDomainSetMaxMemory (virDomainPtr domain, > int virDomainSetMemory (virDomainPtr domain, > unsigned long memory); > int virDomainGetMaxVcpus (virDomainPtr domain); > +int virDomainGetSecurityLabel (virDomainPtr domain, > + virSecurityLabelPtr seclabel); > > /* > * XML domain description > diff --git a/include/libvirt/virterror.h b/include/libvirt/virterror.h > index d68201f..2c3777d 100644 > --- a/include/libvirt/virterror.h > +++ b/include/libvirt/virterror.h > @@ -61,6 +61,7 @@ typedef enum { > 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; > > > @@ -154,6 +155,7 @@ typedef enum { > 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; > > /** > diff --git a/po/POTFILES.in b/po/POTFILES.in > index 7461f93..5794479 100644 > --- a/po/POTFILES.in > +++ b/po/POTFILES.in > @@ -22,6 +22,8 @@ src/proxy_internal.c > src/qemu_conf.c > src/qemu_driver.c > src/remote_internal.c > +src/security.c > +src/security_selinux.c > src/storage_backend.c > src/storage_backend_disk.c > src/storage_backend_fs.c > diff --git a/python/generator.py b/python/generator.py > index 0e8cca7..dcad499 100755 > --- a/python/generator.py > +++ b/python/generator.py > @@ -342,6 +342,8 @@ skip_function = ( > 'virCopyLastError', # Python API is called virGetLastError instead > 'virConnectOpenAuth', # Python C code is manually written > 'virDefaultErrorFunc', # Python virErrorFuncHandler impl calls this from C > + 'virDomainGetSecurityLabel', # Needs investigation... > + 'virNodeGetSecurityModel', # Needs investigation... > 'virConnectDomainEventRegister', # overridden in virConnect.py > 'virConnectDomainEventDeregister', # overridden in virConnect.py > 'virSaveLastError', # We have our own python error wrapper > diff --git a/qemud/Makefile.am b/qemud/Makefile.am > index 924e8ad..d3ab817 100644 > --- a/qemud/Makefile.am > +++ b/qemud/Makefile.am > @@ -133,6 +133,7 @@ if WITH_NODE_DEVICES > endif > endif > > +libvirtd_LDADD += ../src/libvirt_driver_security.la > libvirtd_LDADD += ../src/libvirt.la > > if HAVE_POLKIT > diff --git a/qemud/remote.c b/qemud/remote.c > index 78dda42..7a91384 100644 > --- a/qemud/remote.c > +++ b/qemud/remote.c > @@ -1345,6 +1345,76 @@ remoteDispatchDomainGetMaxVcpus (struct qemud_server *server ATTRIBUTE_UNUSED, > } > > static int > +remoteDispatchDomainGetSecurityLabel(struct qemud_server *server ATTRIBUTE_UNUSED, > + struct qemud_client *client ATTRIBUTE_UNUSED, > + virConnectPtr conn, > + remote_error *rerr, > + remote_domain_get_security_label_args *args, > + remote_domain_get_security_label_ret *ret) > +{ > + virDomainPtr dom; > + virSecurityLabel seclabel; > + > + dom = get_nonnull_domain(conn, args->dom); > + if (dom == NULL) { > + remoteDispatchConnError(rerr, conn); > + return -1; > + } > + > + memset(&seclabel, 0, sizeof seclabel); > + if (virDomainGetSecurityLabel(dom, &seclabel) == -1) { > + virDomainFree(dom); > + remoteDispatchFormatError(rerr, "%s", _("unable to get security label")); > + return -1; > + } > + > + ret->label.label_len = strlen(seclabel.label) + 1; > + if (VIR_ALLOC_N(ret->label.label_val, ret->label.label_len) < 0) { > + virDomainFree(dom); > + remoteDispatchOOMError(rerr); > + return -1; > + } > + strcpy(ret->label.label_val, seclabel.label); > + ret->enforcing = seclabel.enforcing; > + virDomainFree(dom); > + > + return 0; > +} > + > +static int > +remoteDispatchNodeGetSecurityModel(struct qemud_server *server ATTRIBUTE_UNUSED, > + struct qemud_client *client ATTRIBUTE_UNUSED, > + virConnectPtr conn, > + remote_error *rerr, > + void *args ATTRIBUTE_UNUSED, > + remote_node_get_security_model_ret *ret) > +{ > + virSecurityModel secmodel; > + > + memset(&secmodel, 0, sizeof secmodel); > + if (virNodeGetSecurityModel(conn, &secmodel) == -1) { > + remoteDispatchFormatError(rerr, "%s", _("unable to get security model")); > + return -1; > + } > + > + ret->model.model_len = strlen(secmodel.model) + 1; > + if (VIR_ALLOC_N(ret->model.model_val, ret->model.model_len) < 0) { > + remoteDispatchOOMError(rerr); > + return -1; > + } > + strcpy(ret->model.model_val, secmodel.model); > + > + ret->doi.doi_len = strlen(secmodel.doi) + 1; > + if (VIR_ALLOC_N(ret->doi.doi_val, ret->doi.doi_len) < 0) { > + remoteDispatchOOMError(rerr); > + return -1; > + } > + strcpy(ret->doi.doi_val, secmodel.doi); > + > + return 0; > +} > + > +static int > remoteDispatchDomainGetOsType (struct qemud_server *server ATTRIBUTE_UNUSED, > struct qemud_client *client ATTRIBUTE_UNUSED, > virConnectPtr conn, > diff --git a/qemud/remote_dispatch_args.h b/qemud/remote_dispatch_args.h > index a19ab79..dce14f1 100644 > --- a/qemud/remote_dispatch_args.h > +++ b/qemud/remote_dispatch_args.h > @@ -99,3 +99,4 @@ > remote_node_device_get_parent_args val_remote_node_device_get_parent_args; > remote_node_device_num_of_caps_args val_remote_node_device_num_of_caps_args; > remote_node_device_list_caps_args val_remote_node_device_list_caps_args; > + remote_domain_get_security_label_args val_remote_domain_get_security_label_args; > diff --git a/qemud/remote_dispatch_prototypes.h b/qemud/remote_dispatch_prototypes.h > index 3ffb164..bc8a899 100644 > --- a/qemud/remote_dispatch_prototypes.h > +++ b/qemud/remote_dispatch_prototypes.h > @@ -184,6 +184,13 @@ static int remoteDispatchDomainGetSchedulerType( > remote_error *err, > remote_domain_get_scheduler_type_args *args, > remote_domain_get_scheduler_type_ret *ret); > +static int remoteDispatchDomainGetSecurityLabel( > + struct qemud_server *server, > + struct qemud_client *client, > + virConnectPtr conn, > + remote_error *err, > + remote_domain_get_security_label_args *args, > + remote_domain_get_security_label_ret *ret); > static int remoteDispatchDomainGetVcpus( > struct qemud_server *server, > struct qemud_client *client, > @@ -576,6 +583,13 @@ static int remoteDispatchNodeGetInfo( > remote_error *err, > void *args, > remote_node_get_info_ret *ret); > +static int remoteDispatchNodeGetSecurityModel( > + struct qemud_server *server, > + struct qemud_client *client, > + virConnectPtr conn, > + remote_error *err, > + void *args, > + remote_node_get_security_model_ret *ret); > static int remoteDispatchNodeListDevices( > struct qemud_server *server, > struct qemud_client *client, > diff --git a/qemud/remote_dispatch_ret.h b/qemud/remote_dispatch_ret.h > index 563167f..136b1cc 100644 > --- a/qemud/remote_dispatch_ret.h > +++ b/qemud/remote_dispatch_ret.h > @@ -86,3 +86,5 @@ > remote_node_device_get_parent_ret val_remote_node_device_get_parent_ret; > remote_node_device_num_of_caps_ret val_remote_node_device_num_of_caps_ret; > remote_node_device_list_caps_ret val_remote_node_device_list_caps_ret; > + remote_domain_get_security_label_ret val_remote_domain_get_security_label_ret; > + remote_node_get_security_model_ret val_remote_node_get_security_model_ret; > diff --git a/qemud/remote_dispatch_table.h b/qemud/remote_dispatch_table.h > index 60f0e1c..6b7c9db 100644 > --- a/qemud/remote_dispatch_table.h > +++ b/qemud/remote_dispatch_table.h > @@ -592,3 +592,13 @@ > .args_filter = (xdrproc_t) xdr_remote_node_device_list_caps_args, > .ret_filter = (xdrproc_t) xdr_remote_node_device_list_caps_ret, > }, > +{ /* DomainGetSecurityLabel => 118 */ > + .fn = (dispatch_fn) remoteDispatchDomainGetSecurityLabel, > + .args_filter = (xdrproc_t) xdr_remote_domain_get_security_label_args, > + .ret_filter = (xdrproc_t) xdr_remote_domain_get_security_label_ret, > +}, > +{ /* NodeGetSecurityModel => 119 */ > + .fn = (dispatch_fn) remoteDispatchNodeGetSecurityModel, > + .args_filter = (xdrproc_t) xdr_void, > + .ret_filter = (xdrproc_t) xdr_remote_node_get_security_model_ret, > +}, > diff --git a/qemud/remote_protocol.c b/qemud/remote_protocol.c > index 249614a..a55a2dc 100644 > --- a/qemud/remote_protocol.c > +++ b/qemud/remote_protocol.c > @@ -1166,6 +1166,43 @@ xdr_remote_domain_get_max_vcpus_ret (XDR *xdrs, remote_domain_get_max_vcpus_ret > } > > bool_t > +xdr_remote_domain_get_security_label_args (XDR *xdrs, remote_domain_get_security_label_args *objp) > +{ > + > + if (!xdr_remote_nonnull_domain (xdrs, &objp->dom)) > + return FALSE; > + return TRUE; > +} > + > +bool_t > +xdr_remote_domain_get_security_label_ret (XDR *xdrs, remote_domain_get_security_label_ret *objp) > +{ > + char **objp_cpp0 = (char **) (void *) &objp->label.label_val; > + > + if (!xdr_array (xdrs, objp_cpp0, (u_int *) &objp->label.label_len, REMOTE_SECURITY_LABEL_MAX, > + sizeof (char), (xdrproc_t) xdr_char)) > + return FALSE; > + if (!xdr_int (xdrs, &objp->enforcing)) > + return FALSE; > + return TRUE; > +} > + > +bool_t > +xdr_remote_node_get_security_model_ret (XDR *xdrs, remote_node_get_security_model_ret *objp) > +{ > + char **objp_cpp1 = (char **) (void *) &objp->doi.doi_val; > + char **objp_cpp0 = (char **) (void *) &objp->model.model_val; > + > + if (!xdr_array (xdrs, objp_cpp0, (u_int *) &objp->model.model_len, REMOTE_SECURITY_MODEL_MAX, > + sizeof (char), (xdrproc_t) xdr_char)) > + return FALSE; > + if (!xdr_array (xdrs, objp_cpp1, (u_int *) &objp->doi.doi_len, REMOTE_SECURITY_DOI_MAX, > + sizeof (char), (xdrproc_t) xdr_char)) > + return FALSE; > + return TRUE; > +} > + > +bool_t > xdr_remote_domain_attach_device_args (XDR *xdrs, remote_domain_attach_device_args *objp) > { > > diff --git a/qemud/remote_protocol.h b/qemud/remote_protocol.h > index 912d8e3..e21972e 100644 > --- a/qemud/remote_protocol.h > +++ b/qemud/remote_protocol.h > @@ -38,6 +38,9 @@ typedef remote_nonnull_string *remote_string; > #define REMOTE_AUTH_TYPE_LIST_MAX 20 > #define REMOTE_DOMAIN_BLOCK_PEEK_BUFFER_MAX 65536 > #define REMOTE_DOMAIN_MEMORY_PEEK_BUFFER_MAX 65536 > +#define REMOTE_SECURITY_MODEL_MAX VIR_SECURITY_MODEL_BUFLEN > +#define REMOTE_SECURITY_LABEL_MAX VIR_SECURITY_LABEL_BUFLEN > +#define REMOTE_SECURITY_DOI_MAX VIR_SECURITY_DOI_BUFLEN > > typedef char remote_uuid[VIR_UUID_BUFLEN]; > > @@ -637,6 +640,32 @@ struct remote_domain_get_max_vcpus_ret { > }; > typedef struct remote_domain_get_max_vcpus_ret remote_domain_get_max_vcpus_ret; > > +struct remote_domain_get_security_label_args { > + remote_nonnull_domain dom; > +}; > +typedef struct remote_domain_get_security_label_args remote_domain_get_security_label_args; > + > +struct remote_domain_get_security_label_ret { > + struct { > + u_int label_len; > + char *label_val; > + } label; > + int enforcing; > +}; > +typedef struct remote_domain_get_security_label_ret remote_domain_get_security_label_ret; > + > +struct remote_node_get_security_model_ret { > + struct { > + u_int model_len; > + char *model_val; > + } model; > + struct { > + u_int doi_len; > + char *doi_val; > + } doi; > +}; > +typedef struct remote_node_get_security_model_ret remote_node_get_security_model_ret; > + > struct remote_domain_attach_device_args { > remote_nonnull_domain dom; > remote_nonnull_string xml; > @@ -1348,6 +1377,8 @@ enum remote_procedure { > REMOTE_PROC_NODE_DEVICE_GET_PARENT = 115, > REMOTE_PROC_NODE_DEVICE_NUM_OF_CAPS = 116, > REMOTE_PROC_NODE_DEVICE_LIST_CAPS = 117, > + REMOTE_PROC_DOMAIN_GET_SECURITY_LABEL = 118, > + REMOTE_PROC_NODE_GET_SECURITY_MODEL = 119, > }; > typedef enum remote_procedure remote_procedure; > > @@ -1474,6 +1505,9 @@ extern bool_t xdr_remote_domain_get_vcpus_args (XDR *, remote_domain_get_vcpus_ > extern bool_t xdr_remote_domain_get_vcpus_ret (XDR *, remote_domain_get_vcpus_ret*); > extern bool_t xdr_remote_domain_get_max_vcpus_args (XDR *, remote_domain_get_max_vcpus_args*); > extern bool_t xdr_remote_domain_get_max_vcpus_ret (XDR *, remote_domain_get_max_vcpus_ret*); > +extern bool_t xdr_remote_domain_get_security_label_args (XDR *, remote_domain_get_security_label_args*); > +extern bool_t xdr_remote_domain_get_security_label_ret (XDR *, remote_domain_get_security_label_ret*); > +extern bool_t xdr_remote_node_get_security_model_ret (XDR *, remote_node_get_security_model_ret*); > extern bool_t xdr_remote_domain_attach_device_args (XDR *, remote_domain_attach_device_args*); > extern bool_t xdr_remote_domain_detach_device_args (XDR *, remote_domain_detach_device_args*); > extern bool_t xdr_remote_domain_get_autostart_args (XDR *, remote_domain_get_autostart_args*); > @@ -1679,6 +1713,9 @@ extern bool_t xdr_remote_domain_get_vcpus_args (); > extern bool_t xdr_remote_domain_get_vcpus_ret (); > extern bool_t xdr_remote_domain_get_max_vcpus_args (); > extern bool_t xdr_remote_domain_get_max_vcpus_ret (); > +extern bool_t xdr_remote_domain_get_security_label_args (); > +extern bool_t xdr_remote_domain_get_security_label_ret (); > +extern bool_t xdr_remote_node_get_security_model_ret (); > extern bool_t xdr_remote_domain_attach_device_args (); > extern bool_t xdr_remote_domain_detach_device_args (); > extern bool_t xdr_remote_domain_get_autostart_args (); > diff --git a/qemud/remote_protocol.x b/qemud/remote_protocol.x > index 2a6035b..ec5cbbb 100644 > --- a/qemud/remote_protocol.x > +++ b/qemud/remote_protocol.x > @@ -115,6 +115,21 @@ const REMOTE_DOMAIN_BLOCK_PEEK_BUFFER_MAX = 65536; > */ > const REMOTE_DOMAIN_MEMORY_PEEK_BUFFER_MAX = 65536; > > +/* > + * Maximum length of a security model field. > + */ > +const REMOTE_SECURITY_MODEL_MAX = VIR_SECURITY_MODEL_BUFLEN; > + > +/* > + * Maximum length of a security label field. > + */ > +const REMOTE_SECURITY_LABEL_MAX = VIR_SECURITY_LABEL_BUFLEN; > + > +/* > + * Maximum length of a security DOI field. > + */ > +const REMOTE_SECURITY_DOI_MAX = VIR_SECURITY_DOI_BUFLEN; > + > /* UUID. VIR_UUID_BUFLEN definition comes from libvirt.h */ > typedef opaque remote_uuid[VIR_UUID_BUFLEN]; > > @@ -617,6 +632,20 @@ struct remote_domain_get_max_vcpus_ret { > int num; > }; > > +struct remote_domain_get_security_label_args { > + remote_nonnull_domain dom; > +}; > + > +struct remote_domain_get_security_label_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>; > +}; > + > struct remote_domain_attach_device_args { > remote_nonnull_domain dom; > remote_nonnull_string xml; > @@ -1223,7 +1252,10 @@ enum remote_procedure { > REMOTE_PROC_NODE_DEVICE_DUMP_XML = 114, > REMOTE_PROC_NODE_DEVICE_GET_PARENT = 115, > REMOTE_PROC_NODE_DEVICE_NUM_OF_CAPS = 116, > - REMOTE_PROC_NODE_DEVICE_LIST_CAPS = 117 > + REMOTE_PROC_NODE_DEVICE_LIST_CAPS = 117, > + > + REMOTE_PROC_DOMAIN_GET_SECURITY_LABEL = 118, > + REMOTE_PROC_NODE_GET_SECURITY_MODEL = 119 > }; > > /* Custom RPC structure. */ > diff --git a/src/Makefile.am b/src/Makefile.am > index 3a798d2..6f98971 100644 > --- a/src/Makefile.am > +++ b/src/Makefile.am > @@ -139,7 +139,7 @@ UML_DRIVER_SOURCES = \ > 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 > @@ -164,6 +164,12 @@ STORAGE_DRIVER_DISK_SOURCES = \ > STORAGE_HELPER_DISK_SOURCES = \ > parthelper.c > > +# Security framework and drivers for various models > +SECURITY_DRIVER_SOURCES = \ > + security.h security.c > + > +SECURITY_DRIVER_SELINUX_SOURCES = \ > + security_selinux.h security_selinux.c > > NODE_DEVICE_DRIVER_SOURCES = \ > node_device.c node_device.h > @@ -377,6 +383,19 @@ libvirt_driver_nodedev_la_LDFLAGS += -module -avoid-version > endif > endif > > +libvirt_driver_security_la_SOURCES = $(SECURITY_DRIVER_SOURCES) > +if WITH_DRIVER_MODULES > +mod_LTLIBRARIES += libvirt_driver_security.la > +else > +noinst_LTLIBRARIES += libvirt_driver_security.la > +endif > +if WITH_DRIVER_MODULES > +libvirt_driver_security_la_LDFLAGS = -module -avoid-version > +endif > + > +if HAVE_SELINUX > +libvirt_driver_security_la_SOURCES += $(SECURITY_DRIVER_SELINUX_SOURCES) > +endif > > # Add all conditional sources just in case... > EXTRA_DIST += \ > @@ -395,7 +414,9 @@ EXTRA_DIST += \ > $(STORAGE_DRIVER_DISK_SOURCES) \ > $(NODE_DEVICE_DRIVER_SOURCES) \ > $(NODE_DEVICE_DRIVER_HAL_SOURCES) \ > - $(NODE_DEVICE_DRIVER_DEVKIT_SOURCES) > + $(NODE_DEVICE_DRIVER_DEVKIT_SOURCES) \ > + $(SECURITY_DRIVER_SOURCES) \ > + $(SECURITY_DRIVER_SELINUX_SOURCES) > > # > # Build our version script. This is composed of three parts: > diff --git a/src/capabilities.c b/src/capabilities.c > index 3a23332..fb21d87 100644 > --- a/src/capabilities.c > +++ b/src/capabilities.c > @@ -150,6 +150,8 @@ 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); > VIR_FREE(caps); > } > > @@ -599,6 +601,14 @@ virCapabilitiesFormatXML(virCapsPtr 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"); > > > diff --git a/src/capabilities.h b/src/capabilities.h > index be3296c..db32291 100644 > --- a/src/capabilities.h > +++ b/src/capabilities.h > @@ -78,6 +78,12 @@ struct _virCapsHostNUMACell { > int *cpus; > }; > > +typedef struct _virCapsHostSecModel virCapsHostSecModel; > +struct _virCapsHostSecModel { > + char *model; > + char *doi; > +}; > + > typedef struct _virCapsHost virCapsHost; > typedef virCapsHost *virCapsHostPtr; > struct _virCapsHost { > @@ -90,6 +96,7 @@ struct _virCapsHost { > char **migrateTrans; > int nnumaCell; > virCapsHostNUMACellPtr *numaCell; > + virCapsHostSecModel secModel; > }; > > typedef struct _virCaps virCaps; > diff --git a/src/domain_conf.c b/src/domain_conf.c > index 622665c..4d1a951 100644 > --- a/src/domain_conf.c > +++ b/src/domain_conf.c > @@ -379,6 +379,16 @@ void virDomainDeviceDefFree(virDomainDeviceDefPtr def) > VIR_FREE(def); > } > > +void virSecurityLabelDefFree(virDomainDefPtr def); > + > +void virSecurityLabelDefFree(virDomainDefPtr def) > +{ > + if (def->seclabel.model) > + VIR_FREE(def->seclabel.model); > + if (def->seclabel.label) > + VIR_FREE(def->seclabel.label); > +} > + > void virDomainDefFree(virDomainDefPtr def) > { > unsigned int i; > @@ -437,6 +447,8 @@ void virDomainDefFree(virDomainDefPtr def) > VIR_FREE(def->cpumask); > VIR_FREE(def->emulator); > > + virSecurityLabelDefFree(def); > + > VIR_FREE(def); > } > > @@ -1818,6 +1830,34 @@ static int virDomainLifecycleParseXML(virConnectPtr conn, > 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, > @@ -2403,6 +2443,10 @@ static virDomainDefPtr virDomainDefParseXML(virConnectPtr conn, > } > VIR_FREE(nodes); > > + /* analysis of security label */ > + if (virSecurityLabelDefParseXML(conn, def, ctxt) == -1) > + goto error; > + > return def; > > no_memory: > @@ -3419,6 +3463,13 @@ char *virDomainDefFormat(virConnectPtr conn, > 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)) > diff --git a/src/domain_conf.h b/src/domain_conf.h > index b6f6b43..553b437 100644 > --- a/src/domain_conf.h > +++ b/src/domain_conf.h > @@ -407,6 +407,14 @@ struct _virDomainOSDef { > 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 */ > +}; > + > #define VIR_DOMAIN_CPUMASK_LEN 1024 > > /* Guest VM main configuration */ > @@ -464,6 +472,7 @@ struct _virDomainDef { > > /* Only 1 */ > virDomainChrDefPtr console; > + virSecurityLabelDef seclabel; > }; > > /* Guest VM runtime state */ > diff --git a/src/driver.h b/src/driver.h > index 32d4257..005ea4c 100644 > --- a/src/driver.h > +++ b/src/driver.h > @@ -181,6 +181,12 @@ typedef int > typedef int > (*virDrvDomainGetMaxVcpus) (virDomainPtr domain); > typedef int > + (*virDrvDomainGetSecurityLabel) (virDomainPtr domain, > + virSecurityLabelPtr seclabel); > +typedef int > + (*virDrvNodeGetSecurityModel) (virConnectPtr conn, > + virSecurityModelPtr secmodel); > +typedef int > (*virDrvDomainAttachDevice) (virDomainPtr domain, > const char *xml); > typedef int > @@ -361,6 +367,8 @@ struct _virDriver { > virDrvDomainPinVcpu domainPinVcpu; > virDrvDomainGetVcpus domainGetVcpus; > virDrvDomainGetMaxVcpus domainGetMaxVcpus; > + virDrvDomainGetSecurityLabel domainGetSecurityLabel; > + virDrvNodeGetSecurityModel nodeGetSecurityModel; > virDrvDomainDumpXML domainDumpXML; > virDrvListDefinedDomains listDefinedDomains; > virDrvNumOfDefinedDomains numOfDefinedDomains; > diff --git a/src/libvirt.c b/src/libvirt.c > index 038a1ac..47dac90 100644 > --- a/src/libvirt.c > +++ b/src/libvirt.c > @@ -4174,6 +4174,70 @@ error: > return -1; > } > > +/** > + * virDomainGetSecurityLabel: > + * @domain: a domain object > + * @seclabel: pointer to a virSecurityLabel structure > + * > + * Extract security label of an active domain. > + * > + * Returns 0 in case of success, -1 in case of failure, and -2 > + * if the operation is not supported (caller decides if that's > + * an error). > + */ > +int > +virDomainGetSecurityLabel(virDomainPtr domain, virSecurityLabelPtr seclabel) > +{ > + virConnectPtr conn; > + > + if (!VIR_IS_CONNECTED_DOMAIN(domain)) { > + virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__); > + return -1; > + } > + > + if (seclabel == NULL) { > + virLibDomainError(domain, VIR_ERR_INVALID_ARG, __FUNCTION__); > + return -1; > + } > + > + conn = domain->conn; > + > + if (conn->driver->domainGetSecurityLabel) > + return conn->driver->domainGetSecurityLabel(domain, seclabel); > + > + virLibConnWarning(conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); > + return -2; > +} > + > +/** > + * virNodeGetSecurityModel: > + * @conn: a connection object > + * @secmodel: pointer to a virSecurityModel structure > + * > + * Extract the security model of a hypervisor. > + * > + * Returns 0 in case of success, -1 in case of failure, and -2 if the > + * operation is not supported (caller decides if that's an error). > + */ > +int > +virNodeGetSecurityModel(virConnectPtr conn, virSecurityModelPtr secmodel) > +{ > + if (!VIR_IS_CONNECT(conn)) { > + virLibConnError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__); > + return -1; > + } > + > + if (secmodel == NULL) { > + virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__); > + return -1; > + } > + > + if (conn->driver->nodeGetSecurityModel) > + return conn->driver->nodeGetSecurityModel(conn, secmodel); > + > + virLibConnWarning(conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); > + return -2; > +} > > /** > * virDomainAttachDevice: > diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms > index 9e9b3e5..6649f69 100644 > --- a/src/libvirt_private.syms > +++ b/src/libvirt_private.syms > @@ -337,3 +337,4 @@ virXPathNode; > virXPathNodeSet; > virXPathString; > virXMLPropString; > +virXPathStringLimit; > diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms > index 1422e4c..0777d46 100644 > --- a/src/libvirt_public.syms > +++ b/src/libvirt_public.syms > @@ -244,7 +244,8 @@ LIBVIRT_0.6.0 { > virStoragePoolRef; > virStorageVolRef; > virNodeDeviceRef; > - > + virDomainGetSecurityLabel; > + virNodeGetSecurityModel; > } LIBVIRT_0.5.0; > > LIBVIRT_0.6.1 { > diff --git a/src/lxc_driver.c b/src/lxc_driver.c > index aa417a9..69fe95f 100644 > --- a/src/lxc_driver.c > +++ b/src/lxc_driver.c > @@ -1429,6 +1429,8 @@ static virDriver lxcDriver = { > NULL, /* domainPinVcpu */ > NULL, /* domainGetVcpus */ > NULL, /* domainGetMaxVcpus */ > + NULL, /* domainGetSecurityLabel */ > + NULL, /* nodeGetSecurityModel */ > lxcDomainDumpXML, /* domainDumpXML */ > lxcListDefinedDomains, /* listDefinedDomains */ > lxcNumDefinedDomains, /* numOfDefinedDomains */ > diff --git a/src/openvz_driver.c b/src/openvz_driver.c > index e004819..4a4be4c 100644 > --- a/src/openvz_driver.c > +++ b/src/openvz_driver.c > @@ -1299,6 +1299,8 @@ static virDriver openvzDriver = { > NULL, /* domainPinVcpu */ > NULL, /* domainGetVcpus */ > openvzDomainGetMaxVcpus, /* domainGetMaxVcpus */ > + NULL, /* domainGetSecurityLabel */ > + NULL, /* nodeGetSecurityModel */ > openvzDomainDumpXML, /* domainDumpXML */ > openvzListDefinedDomains, /* listDomains */ > openvzNumDefinedDomains, /* numOfDomains */ > diff --git a/src/qemu_conf.h b/src/qemu_conf.h > index 8f0193d..f2079e2 100644 > --- a/src/qemu_conf.h > +++ b/src/qemu_conf.h > @@ -33,6 +33,7 @@ > #include "domain_conf.h" > #include "domain_event.h" > #include "threads.h" > +#include "security.h" > > #define qemudDebug(fmt, ...) do {} while(0) > > @@ -83,6 +84,8 @@ struct qemud_driver { > virDomainEventQueuePtr domainEventQueue; > int domainEventTimer; > int domainEventDispatching; > + > + virSecurityDriverPtr securityDriver; > }; > > /* Status needed to reconenct to running VMs */ > diff --git a/src/qemu_driver.c b/src/qemu_driver.c > index 8bb948a..3e635aa 100644 > --- a/src/qemu_driver.c > +++ b/src/qemu_driver.c > @@ -68,6 +68,7 @@ > #include "memory.h" > #include "uuid.h" > #include "domain_conf.h" > +#include "security.h" > > #define VIR_FROM_THIS VIR_FROM_QEMU > > @@ -351,6 +352,50 @@ next: > return 0; > } > > +static int > +qemudSecurityInit(struct qemud_driver *qemud_drv) > +{ > + int ret; > + const char *doi, *model; > + virCapsPtr caps; > + virSecurityDriverPtr security_drv; > + > + ret = virSecurityDriverStartup(&security_drv); > + if (ret == -1) { > + qemudLog(QEMUD_ERR, _("Failed to start security driver")); > + return -1; > + } > + /* No security driver wanted to be enabled: just return */ > + if (ret == -2) > + return 0; > + > + qemud_drv->securityDriver = security_drv; > + doi = virSecurityDriverGetDOI(security_drv); > + model = virSecurityDriverGetModel(security_drv); > + > + qemudLog(QEMUD_DEBUG, "Initialized security driver \"%s\" with " > + "DOI \"%s\".\n", model, doi); > + > + /* > + * Add security policy host caps now that the security driver is > + * initialized. > + */ > + caps = qemud_drv->caps; > + > + caps->host.secModel.model = strdup(model); > + if (!caps->host.secModel.model) { > + qemudLog(QEMUD_ERR, _("Failed to copy secModel model: %s"), strerror(errno)); > + return -1; > + } > + > + caps->host.secModel.doi = strdup(doi); > + if (!caps->host.secModel.doi) { > + qemudLog(QEMUD_ERR, _("Failed to copy secModel DOI: %s"), strerror(errno)); > + return -1; > + } > + > + return 0; > +} > > /** > * qemudStartup: > @@ -443,6 +488,11 @@ qemudStartup(void) { > if ((qemu_driver->caps = qemudCapsInit()) == NULL) > goto out_of_memory; > > + if (qemudSecurityInit(qemu_driver) < 0) { > + qemudShutdown(); > + return -1; > + } > + > if (qemudLoadDriverConfig(qemu_driver, driverConf) < 0) { > goto error; > } > @@ -1130,6 +1180,15 @@ static int qemudNextFreeVNCPort(struct qemud_driver *driver ATTRIBUTE_UNUSED) { > return -1; > } > > +static int qemudDomainSetSecurityLabel(virConnectPtr conn, struct qemud_driver *driver, virDomainObjPtr vm) > +{ > + if (vm->def->seclabel.label != NULL) > + if (driver->securityDriver && driver->securityDriver->domainSetSecurityLabel) > + return driver->securityDriver->domainSetSecurityLabel(conn, driver->securityDriver, > + &vm->def->seclabel); > + return 0; > +} > + > static virDomainPtr qemudDomainLookupByName(virConnectPtr conn, > const char *name); > > @@ -1198,6 +1257,16 @@ static int qemudStartVMDaemon(virConnectPtr conn, > return -1; > } > > + /* > + * Set up the security label for the domain here, before doing > + * too much else. > + */ > + if (qemudDomainSetSecurityLabel(conn, driver, vm) < 0) { > + qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, > + _("Failed to set security label")); > + return -1; > + } > + > if (qemudExtractVersionInfo(emulator, > NULL, > &qemuCmdFlags) < 0) { > @@ -2755,7 +2824,94 @@ cleanup: > return ret; > } > > +static int qemudDomainGetSecurityLabel(virDomainPtr dom, virSecurityLabelPtr seclabel) > +{ > + struct qemud_driver *driver = (struct qemud_driver *)dom->conn->privateData; > + virDomainObjPtr vm; > + const char *type; > + int ret = -1; > + > + qemuDriverLock(driver); > + vm = virDomainFindByUUID(&driver->domains, dom->uuid); > + qemuDriverUnlock(driver); > + > + if (!vm) { > + char uuidstr[VIR_UUID_STRING_BUFLEN]; > + > + virUUIDFormat(dom->uuid, uuidstr); > + qemudReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_DOMAIN, > + _("no domain with matching uuid '%s'"), uuidstr); > + goto cleanup; > + } > + > + if (!(type = virDomainVirtTypeToString(vm->def->virtType))) { > + qemudReportError(dom->conn, dom, NULL, VIR_ERR_INTERNAL_ERROR, > + _("unknown virt type in domain definition '%d'"), > + vm->def->virtType); > + goto cleanup; > + } > + > + /* > + * Theoretically, the pid can be replaced during this operation and > + * return the label of a different process. If atomicity is needed, > + * further validation will be required. > + * > + * Comment from Dan Berrange: > + * > + * Well the PID as stored in the virDomainObjPtr can't be changed > + * because you've got a locked object. The OS level PID could have > + * exited, though and in extreme circumstances have cycled through all > + * PIDs back to ours. We could sanity check that our PID still exists > + * after reading the label, by checking that our FD connecting to the > + * QEMU monitor hasn't seen SIGHUP/ERR on poll(). > + */ > + if (virDomainIsActive(vm)) { > + if (driver->securityDriver && driver->securityDriver->domainGetSecurityLabel) { > + if (driver->securityDriver->domainGetSecurityLabel(dom->conn, vm, seclabel) == -1) { > + qemudReportError(dom->conn, dom, NULL, VIR_ERR_INTERNAL_ERROR, > + _("Failed to get security label")); > + goto cleanup; > + } > + } > + } > + > + ret = 0; > + > +cleanup: > + if (vm) > + virDomainObjUnlock(vm); > + return ret; > +} > + > +static int qemudNodeGetSecurityModel(virConnectPtr conn, virSecurityModelPtr secmodel) > +{ > + struct qemud_driver *driver = (struct qemud_driver *)conn->privateData; > + char *p; > + > + if (!driver->securityDriver) > + return -2; > + > + p = driver->caps->host.secModel.model; > + if (strlen(p) >= VIR_SECURITY_MODEL_BUFLEN-1) { > + qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, > + _("security model string exceeds max %d bytes"), > + VIR_SECURITY_MODEL_BUFLEN-1); > + return -1; > + } > + strcpy(secmodel->model, p); > + > + p = driver->caps->host.secModel.doi; > + if (strlen(p) >= VIR_SECURITY_DOI_BUFLEN-1) { > + qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, > + _("security DOI string exceeds max %d bytes"), > + VIR_SECURITY_DOI_BUFLEN-1); > + return -1; > + } > + strcpy(secmodel->doi, p); > + return 0; > +} > > +/* TODO: check seclabel restore */ > static int qemudDomainRestore(virConnectPtr conn, > const char *path) { > struct qemud_driver *driver = conn->privateData; > @@ -4510,6 +4666,8 @@ static virDriver qemuDriver = { > NULL, /* domainGetVcpus */ > #endif > qemudDomainGetMaxVcpus, /* domainGetMaxVcpus */ > + qemudDomainGetSecurityLabel, /* domainGetSecurityLabel */ > + qemudNodeGetSecurityModel, /* nodeGetSecurityModel */ > qemudDomainDumpXML, /* domainDumpXML */ > qemudListDefinedDomains, /* listDomains */ > qemudNumDefinedDomains, /* numOfDomains */ > diff --git a/src/remote_internal.c b/src/remote_internal.c > index eda6177..8948e67 100644 > --- a/src/remote_internal.c > +++ b/src/remote_internal.c > @@ -2295,6 +2295,67 @@ done: > return rv; > } > > +static int > +remoteDomainGetSecurityLabel (virDomainPtr domain, virSecurityLabelPtr seclabel) > +{ > + remote_domain_get_security_label_args args; > + remote_domain_get_security_label_ret ret; > + struct private_data *priv = domain->conn->privateData; > + > + make_nonnull_domain (&args.dom, domain); > + memset (&ret, 0, sizeof ret); > + if (call (domain->conn, priv, 0, REMOTE_PROC_DOMAIN_GET_SECURITY_LABEL, > + (xdrproc_t) xdr_remote_domain_get_security_label_args, (char *)&args, > + (xdrproc_t) xdr_remote_domain_get_security_label_ret, (char *)&ret) == -1) { > + return -1; > + } > + > + if (ret.label.label_val != NULL) { > + if (strlen (ret.label.label_val) >= sizeof seclabel->label) { > + errorf (domain->conn, VIR_ERR_RPC, _("security label exceeds maximum: %zd"), > + sizeof seclabel->label - 1); > + return -1; > + } > + strcpy (seclabel->label, ret.label.label_val); > + seclabel->enforcing = ret.enforcing; > + } > + > + return 0; > +} > + > +static int > +remoteNodeGetSecurityModel (virConnectPtr conn, virSecurityModelPtr secmodel) > +{ > + remote_node_get_security_model_ret ret; > + struct private_data *priv = conn->privateData; > + > + memset (&ret, 0, sizeof ret); > + if (call (conn, priv, 0, REMOTE_PROC_NODE_GET_SECURITY_MODEL, > + (xdrproc_t) xdr_void, NULL, > + (xdrproc_t) xdr_remote_node_get_security_model_ret, (char *)&ret) == -1) { > + return -1; > + } > + > + if (ret.model.model_val != NULL) { > + if (strlen (ret.model.model_val) >= sizeof secmodel->model) { > + errorf (conn, VIR_ERR_RPC, _("security model exceeds maximum: %zd"), > + sizeof secmodel->model - 1); > + return -1; > + } > + strcpy (secmodel->model, ret.model.model_val); > + } > + > + if (ret.doi.doi_val != NULL) { > + if (strlen (ret.doi.doi_val) >= sizeof secmodel->doi) { > + errorf (conn, VIR_ERR_RPC, _("security doi exceeds maximum: %zd"), > + sizeof secmodel->doi - 1); > + return -1; > + } > + strcpy (secmodel->doi, ret.doi.doi_val); > + } > + return 0; > +} > + > static char * > remoteDomainDumpXML (virDomainPtr domain, int flags) > { > @@ -6715,6 +6776,8 @@ static virDriver driver = { > .domainPinVcpu = remoteDomainPinVcpu, > .domainGetVcpus = remoteDomainGetVcpus, > .domainGetMaxVcpus = remoteDomainGetMaxVcpus, > + .domainGetSecurityLabel = remoteDomainGetSecurityLabel, > + .nodeGetSecurityModel = remoteNodeGetSecurityModel, > .domainDumpXML = remoteDomainDumpXML, > .listDefinedDomains = remoteListDefinedDomains, > .numOfDefinedDomains = remoteNumOfDefinedDomains, > diff --git a/src/security.c b/src/security.c > new file mode 100644 > index 0000000..8dd2c9f > --- /dev/null > +++ b/src/security.c > @@ -0,0 +1,133 @@ > +/* > + * 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@xxxxxxxxx> > + * > + */ > +#include <config.h> > +#include <string.h> > + > +#include "virterror_internal.h" > + > +#include "security.h" > + > +#if HAVE_SELINUX > +#include "security_selinux.h" > +#endif > + > +static virSecurityDriverStatus testSecurityDriverProbe(void) > +{ > + return SECURITY_DRIVER_DISABLE; > +} > + > +virSecurityDriver virTestSecurityDriver = { > + .name = "test", > + .probe = testSecurityDriverProbe, > +}; > + > +static virSecurityDriverPtr security_drivers[] = { > + &virTestSecurityDriver, > +#ifdef HAVE_SELINUX > + &virSELinuxSecurityDriver, > +#endif > +}; > + > +/* > + * Probe each security driver: each should perform a test to see if it > + * should be loaded, e.g. if the currently active host security mechanism > + * matches. If the probe succeeds, initialize the driver and return it. > + * > + * Returns 0 on success, and -1 on error. If no security driver wanted to > + * be enabled, then return -2 and let the caller determine what this really > + * means. > + */ > +int > +virSecurityDriverStartup(virSecurityDriverPtr * drv) > +{ > + unsigned int i; > + > + for (i = 0; i < (sizeof(security_drivers) / sizeof(security_drivers[0])); i++) { > + virSecurityDriverPtr tmp = security_drivers[i]; > + virSecurityDriverStatus ret = tmp->probe(); > + > + switch (ret) { > + 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; > +} > diff --git a/src/security.h b/src/security.h > new file mode 100644 > index 0000000..2ea9013 > --- /dev/null > +++ b/src/security.h > @@ -0,0 +1,72 @@ > +/* > + * 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@xxxxxxxxx> > + * > + */ > +#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 (*virSecurityDomainGetLabel) (virConnectPtr conn, > + virDomainObjPtr vm, > + virSecurityLabelPtr sec); > +typedef int (*virSecurityDomainSetLabel) (virConnectPtr conn, > + virSecurityDriverPtr drv, > + virSecurityLabelDefPtr secdef); > + > +struct _virSecurityDriver { > + const char *name; > + virSecurityDriverProbe probe; > + virSecurityDriverOpen open; > + virSecurityDomainGetLabel domainGetSecurityLabel; > + virSecurityDomainSetLabel domainSetSecurityLabel; > + > + /* > + * 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); > + > +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__ */ > diff --git a/src/security_selinux.c b/src/security_selinux.c > new file mode 100644 > index 0000000..65fcde7 > --- /dev/null > +++ b/src/security_selinux.c > @@ -0,0 +1,108 @@ > +/* > + * 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@xxxxxxxxx> > + * > + * SELinux security driver. > + */ > +#include <config.h> > +#include <selinux/selinux.h> > + > +#include "security.h" > +#include "security_selinux.h" > + > +#define SECURITY_SELINUX_VOID_DOI "0" > + > +static int > +SELinuxSecurityDriverProbe(void) > +{ > + return is_selinux_enabled() ? SECURITY_DRIVER_ENABLE : SECURITY_DRIVER_DISABLE; > +} > + > +static int > +SELinuxSecurityDriverOpen(virConnectPtr conn, virSecurityDriverPtr drv) > +{ > + /* > + * Where will the DOI come from? SELinux configuration, or qemu > + * configuration? For the moment, we'll just set it to "0". > + */ > + virSecurityDriverSetDOI(conn, drv, SECURITY_SELINUX_VOID_DOI); > + > + return 0; > +} > + > +static int > +SELinuxSecurityDomainGetSecurityLabel(virConnectPtr conn, > + virDomainObjPtr vm, > + virSecurityLabelPtr sec) > +{ > + security_context_t ctx; > + > + if (getpidcon(vm->pid, &ctx) == -1) { > + virSecurityReportError(conn, VIR_ERR_ERROR, _("%s: error calling " > + "getpidcon(): %s"), __func__, > + strerror(errno)); > + return -1; > + } > + > + if (strlen((char *) ctx) >= VIR_SECURITY_LABEL_BUFLEN) { > + virSecurityReportError(conn, VIR_ERR_ERROR, > + _("%s: security label exceeds " > + "maximum length: %d"), __func__, > + VIR_SECURITY_LABEL_BUFLEN - 1); > + return -1; > + } > + > + strcpy(sec->label, (char *) ctx); > + free(ctx); > + > + sec->enforcing = security_getenforce(); > + if (sec->enforcing == -1) { > + virSecurityReportError(conn, VIR_ERR_ERROR, _("%s: error calling " > + "security_getenforce(): %s"), __func__, > + strerror(errno)); > + return -1; > + } > + > + return 0; > +} > + > +static int > +SELinuxSecurityDomainSetSecurityLabel(virConnectPtr conn, > + virSecurityDriverPtr drv, > + const virSecurityLabelDefPtr secdef) > +{ > + /* TODO: verify DOI */ > + > + if (!STREQ(drv->name, secdef->model)) { > + virSecurityReportError(conn, VIR_ERR_ERROR, > + _("%s: security label driver mismatch: " > + "\'%s\' model configured for domain, but " > + "hypervisor driver is \'%s\'."), > + __func__, secdef->model, drv->name); > + return -1; > + } > + > + if (setexeccon(secdef->label) == -1) { > + virSecurityReportError(conn, VIR_ERR_ERROR, > + _("%s: unable to set security context " > + "'\%s\': %s."), __func__, secdef->label, > + strerror(errno)); > + return -1; > + } > + return 0; > +} > + > +virSecurityDriver virSELinuxSecurityDriver = { > + .name = "selinux", > + .probe = SELinuxSecurityDriverProbe, > + .open = SELinuxSecurityDriverOpen, > + .domainGetSecurityLabel = SELinuxSecurityDomainGetSecurityLabel, > + .domainSetSecurityLabel = SELinuxSecurityDomainSetSecurityLabel, > +}; > diff --git a/src/security_selinux.h b/src/security_selinux.h > new file mode 100644 > index 0000000..1e32209 > --- /dev/null > +++ b/src/security_selinux.h > @@ -0,0 +1,18 @@ > +/* > + * 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@xxxxxxxxx> > + * > + */ > +#ifndef __VIR_SECURITY_SELINUX_H__ > +#define __VIR_SECURITY_SELINUX_H__ > + > +extern virSecurityDriver virSELinuxSecurityDriver; > + > +#endif /* __VIR_SECURITY_SELINUX_H__ */ > diff --git a/src/storage_backend.c b/src/storage_backend.c > index 8408f34..787630c 100644 > --- a/src/storage_backend.c > +++ b/src/storage_backend.c > @@ -276,6 +276,7 @@ virStorageBackendUpdateVolTargetInfoFD(virConnectPtr conn, > 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, > diff --git a/src/test.c b/src/test.c > index 226fe2e..b3e6477 100644 > --- a/src/test.c > +++ b/src/test.c > @@ -3501,6 +3501,8 @@ static virDriver testDriver = { > NULL, /* domainPinVcpu */ > NULL, /* domainGetVcpus */ > NULL, /* domainGetMaxVcpus */ > + NULL, /* domainGetSecurityLabel */ > + NULL, /* nodeGetSecurityModel */ > testDomainDumpXML, /* domainDumpXML */ > testListDefinedDomains, /* listDefinedDomains */ > testNumOfDefinedDomains, /* numOfDefinedDomains */ > diff --git a/src/uml_driver.c b/src/uml_driver.c > index c5a06a2..119765b 100644 > --- a/src/uml_driver.c > +++ b/src/uml_driver.c > @@ -1854,6 +1854,8 @@ static virDriver umlDriver = { > NULL, /* domainPinVcpu */ > NULL, /* domainGetVcpus */ > NULL, /* domainGetMaxVcpus */ > + NULL, /* domainGetSecurityLabel */ > + NULL, /* nodeGetSecurityModel */ > umlDomainDumpXML, /* domainDumpXML */ > umlListDefinedDomains, /* listDomains */ > umlNumDefinedDomains, /* numOfDomains */ > diff --git a/src/virsh.c b/src/virsh.c > index 298dde0..ce39000 100644 > --- a/src/virsh.c > +++ b/src/virsh.c > @@ -978,6 +978,7 @@ static const vshCmdOptDef opts_undefine[] = { > {NULL, 0, 0, NULL} > }; > > +/* XXX MAC policy for defining & undefining domains ?? */ > static int > cmdUndefine(vshControl *ctl, const vshCmd *cmd) > { > @@ -1539,6 +1540,8 @@ cmdDominfo(vshControl *ctl, const vshCmd *cmd) > { > virDomainInfo info; > virDomainPtr dom; > + virSecurityModel secmodel; > + virSecurityLabel seclabel; > int ret = TRUE, autostart; > unsigned int id; > char *str, uuid[VIR_UUID_STRING_BUFLEN]; > @@ -1597,6 +1600,29 @@ cmdDominfo(vshControl *ctl, const vshCmd *cmd) > autostart ? _("enable") : _("disable") ); > } > > + /* Security model and label information */ > + memset(&secmodel, 0, sizeof secmodel); > + if (virNodeGetSecurityModel(ctl->conn, &secmodel) == -1) { > + virDomainFree(dom); > + return FALSE; > + } else { > + /* Only print something if a security model is active */ > + if (secmodel.model[0] != '\0') { > + vshPrint(ctl, "%-15s %s\n", _("Security model:"), secmodel.model); > + vshPrint(ctl, "%-15s %s\n", _("Security DOI:"), secmodel.doi); > + > + /* Security labels are only valid for active domains */ > + memset(&seclabel, 0, sizeof seclabel); > + if (virDomainGetSecurityLabel(dom, &seclabel) == -1) { > + virDomainFree(dom); > + return FALSE; > + } else { > + if (seclabel.label[0] != '\0') > + vshPrint(ctl, "%-15s %s (%s)\n", _("Security label:"), > + seclabel.label, seclabel.enforcing ? "enforcing" : "permissive"); > + } > + } > + } > virDomainFree(dom); > return ret; > } > diff --git a/src/virterror.c b/src/virterror.c > index 42a7cf5..8d7dc93 100644 > --- a/src/virterror.c > +++ b/src/virterror.c > @@ -151,6 +151,9 @@ static const char *virErrorDomainName(virErrorDomain domain) { > case VIR_FROM_UML: > dom = "UML "; > break; > + case VIR_FROM_SECURITY: > + dom = "Security Labeling "; > + break; > } > return(dom); > } > @@ -995,6 +998,12 @@ virErrorMsg(virErrorNumber error, const char *info) > 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); > } > diff --git a/src/xml.c b/src/xml.c > index 9c27a10..d644641 100644 > --- a/src/xml.c > +++ b/src/xml.c > @@ -77,6 +77,39 @@ virXPathString(virConnectPtr conn, > } > > /** > + * 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) { > + if (strlen(tmp) >= maxlen) { > + virXMLError(conn, VIR_ERR_INTERNAL_ERROR, > + _("\'%s\' value longer than %Zd bytes in virXPathStringLimit()"), > + xpath, maxlen); > + return NULL; > + } > + } else > + virXMLError(conn, VIR_ERR_INTERNAL_ERROR, > + _("\'%s\' missing in virXPathStringLimit()"), xpath); > + return tmp; > +} > + > +/** > * virXPathNumber: > * @xpath: the XPath string to evaluate > * @ctxt: an XPath context > diff --git a/src/xml.h b/src/xml.h > index da9d3b5..3102876 100644 > --- a/src/xml.h > +++ b/src/xml.h > @@ -17,6 +17,10 @@ int virXPathBoolean (virConnectPtr conn, > 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, > diff --git a/tests/daemon-conf b/tests/daemon-conf > index 7a53eff..42f7d32 100755 > --- a/tests/daemon-conf > +++ b/tests/daemon-conf > @@ -59,6 +59,9 @@ while :; do > -e '/^libnuma: Warning: .sys not mounted or no numa system/d' \ > err > k && mv k err > > + # Filter out this diagnostic, too. > + sed '/^Initialized security driver/d' err > k && mv k err > + > printf '%s\n\n' "remoteReadConfigFile: $f: $param_name: $msg" > expected-err > diff -u expected-err err || fail=1 > Ok, I have added your patches and make syntax-check succeeds except it does not like po_check - --- po/POTFILES.in +++ po/POTFILES.in @@ -22,8 +22,6 @@ src/qemu_conf.c src/qemu_driver.c src/remote_internal.c - -src/security.c - -src/security_selinux.c src/storage_backend.c src/storage_backend_disk.c src/storage_backend_fs.c Makefile.maint: you have changed the set of files with translatable diagnostics; apply the above patch Since these files add translations, what do I need to do to get this to pass? -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.9 (GNU/Linux) Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org iEYEARECAAYFAkmbFqQACgkQrlYvE4MpobMw5gCgi7XlYLyd7Gol7WJq4MN/s1Ek SbsAoOg6k/6McRFcZnf6BGmohCByWTlS =Hcbu -----END PGP SIGNATURE----- -- Libvir-list mailing list Libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list