diff -up libvirt-0.6.0/include/libvirt/libvirt.h.in.svirt libvirt-0.6.0/include/libvirt/libvirt.h.in --- libvirt-0.6.0/include/libvirt/libvirt.h.in.svirt 2009-01-20 08:48:27.000000000 -0500 +++ libvirt-0.6.0/include/libvirt/libvirt.h.in 2009-02-17 10:07:06.215686000 -0500 @@ -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 * virConnectGetCap unsigned long long virNodeGetFreeMemory (virConnectPtr conn); +int virNodeGetSecurityModel (virConnectPtr conn, + virSecurityModelPtr secmodel); + /* * Gather list of running domains */ @@ -506,6 +571,8 @@ int virDomainSetMaxM int virDomainSetMemory (virDomainPtr domain, unsigned long memory); int virDomainGetMaxVcpus (virDomainPtr domain); +int virDomainGetSecurityLabel (virDomainPtr domain, + virSecurityLabelPtr seclabel); /* * XML domain description diff -up libvirt-0.6.0/include/libvirt/libvirt.h.svirt libvirt-0.6.0/include/libvirt/libvirt.h --- libvirt-0.6.0/include/libvirt/libvirt.h.svirt 2009-01-31 04:20:10.000000000 -0500 +++ libvirt-0.6.0/include/libvirt/libvirt.h 2009-02-17 10:07:32.421570000 -0500 @@ -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 * virConnectGetCap unsigned long long virNodeGetFreeMemory (virConnectPtr conn); +int virNodeGetSecurityModel (virConnectPtr conn, + virSecurityModelPtr secmodel); + /* * Gather list of running domains */ @@ -506,6 +571,8 @@ int virDomainSetMaxM int virDomainSetMemory (virDomainPtr domain, unsigned long memory); int virDomainGetMaxVcpus (virDomainPtr domain); +int virDomainGetSecurityLabel (virDomainPtr domain, + virSecurityLabelPtr seclabel); /* * XML domain description diff -up libvirt-0.6.0/include/libvirt/virterror.h.svirt libvirt-0.6.0/include/libvirt/virterror.h --- libvirt-0.6.0/include/libvirt/virterror.h.svirt 2008-11-25 08:42:33.000000000 -0500 +++ libvirt-0.6.0/include/libvirt/virterror.h 2009-02-17 10:07:06.223677000 -0500 @@ -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 -up libvirt-0.6.0/po/POTFILES.in.svirt libvirt-0.6.0/po/POTFILES.in --- libvirt-0.6.0/po/POTFILES.in.svirt 2009-01-31 04:04:17.000000000 -0500 +++ libvirt-0.6.0/po/POTFILES.in 2009-02-17 10:07:06.226679000 -0500 @@ -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 -up libvirt-0.6.0/python/generator.py.svirt libvirt-0.6.0/python/generator.py --- libvirt-0.6.0/python/generator.py.svirt 2008-11-21 07:47:32.000000000 -0500 +++ libvirt-0.6.0/python/generator.py 2009-02-17 10:07:06.230676000 -0500 @@ -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 ) diff -up libvirt-0.6.0/qemud/Makefile.am.svirt libvirt-0.6.0/qemud/Makefile.am --- libvirt-0.6.0/qemud/Makefile.am.svirt 2009-01-31 04:04:17.000000000 -0500 +++ libvirt-0.6.0/qemud/Makefile.am 2009-02-17 10:07:06.237678000 -0500 @@ -130,6 +130,7 @@ libvirtd_LDADD += ../src/libvirt_driver_ endif endif +libvirtd_LDADD += ../src/libvirt_driver_security.la libvirtd_LDADD += ../src/libvirt.la if HAVE_POLKIT diff -up libvirt-0.6.0/qemud/remote.c.svirt libvirt-0.6.0/qemud/remote.c --- libvirt-0.6.0/qemud/remote.c.svirt 2009-01-31 04:04:17.000000000 -0500 +++ libvirt-0.6.0/qemud/remote.c 2009-02-17 10:07:06.246680000 -0500 @@ -1340,6 +1340,76 @@ remoteDispatchDomainGetMaxVcpus (struct } 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 -up libvirt-0.6.0/qemud/remote_dispatch_args.h.svirt libvirt-0.6.0/qemud/remote_dispatch_args.h --- libvirt-0.6.0/qemud/remote_dispatch_args.h.svirt 2008-12-19 09:00:02.000000000 -0500 +++ libvirt-0.6.0/qemud/remote_dispatch_args.h 2009-02-17 10:07:06.250678000 -0500 @@ -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 -up libvirt-0.6.0/qemud/remote_dispatch_prototypes.h.svirt libvirt-0.6.0/qemud/remote_dispatch_prototypes.h --- libvirt-0.6.0/qemud/remote_dispatch_prototypes.h.svirt 2008-12-19 09:00:02.000000000 -0500 +++ libvirt-0.6.0/qemud/remote_dispatch_prototypes.h 2009-02-17 10:07:06.255676000 -0500 @@ -184,6 +184,13 @@ static int remoteDispatchDomainGetSchedu 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 -up libvirt-0.6.0/qemud/remote_dispatch_ret.h.svirt libvirt-0.6.0/qemud/remote_dispatch_ret.h --- libvirt-0.6.0/qemud/remote_dispatch_ret.h.svirt 2008-12-19 09:00:02.000000000 -0500 +++ libvirt-0.6.0/qemud/remote_dispatch_ret.h 2009-02-17 10:07:06.259676000 -0500 @@ -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 -up libvirt-0.6.0/qemud/remote_dispatch_table.h.svirt libvirt-0.6.0/qemud/remote_dispatch_table.h --- libvirt-0.6.0/qemud/remote_dispatch_table.h.svirt 2008-12-19 09:00:02.000000000 -0500 +++ libvirt-0.6.0/qemud/remote_dispatch_table.h 2009-02-17 10:07:06.263676000 -0500 @@ -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 -up libvirt-0.6.0/qemud/remote_protocol.c.svirt libvirt-0.6.0/qemud/remote_protocol.c --- libvirt-0.6.0/qemud/remote_protocol.c.svirt 2009-01-31 04:04:17.000000000 -0500 +++ libvirt-0.6.0/qemud/remote_protocol.c 2009-02-17 10:07:06.268676000 -0500 @@ -1166,6 +1166,43 @@ xdr_remote_domain_get_max_vcpus_ret (XDR } 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 -up libvirt-0.6.0/qemud/remote_protocol.h.svirt libvirt-0.6.0/qemud/remote_protocol.h --- libvirt-0.6.0/qemud/remote_protocol.h.svirt 2009-01-31 04:04:17.000000000 -0500 +++ libvirt-0.6.0/qemud/remote_protocol.h 2009-02-17 10:07:06.274679000 -0500 @@ -38,6 +38,9 @@ typedef remote_nonnull_string *remote_st #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_vcp 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_vcpu 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 -up libvirt-0.6.0/qemud/remote_protocol.x.svirt libvirt-0.6.0/qemud/remote_protocol.x --- libvirt-0.6.0/qemud/remote_protocol.x.svirt 2008-12-19 07:51:11.000000000 -0500 +++ libvirt-0.6.0/qemud/remote_protocol.x 2009-02-17 10:07:06.279676000 -0500 @@ -115,6 +115,21 @@ const REMOTE_DOMAIN_BLOCK_PEEK_BUFFER_MA */ 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; + int enforcing; +}; + +struct remote_node_get_security_model_ret { + char model; + char doi; +}; + 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 -up libvirt-0.6.0/src/capabilities.c.svirt libvirt-0.6.0/src/capabilities.c --- libvirt-0.6.0/src/capabilities.c.svirt 2009-01-31 04:04:17.000000000 -0500 +++ libvirt-0.6.0/src/capabilities.c 2009-02-17 10:07:06.285678000 -0500 @@ -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, " \n"); virBufferAddLit(&xml, " \n"); } + + if (caps->host.secModel.model) { + virBufferAddLit(&xml, " \n"); + virBufferVSprintf(&xml, " %s\n", caps->host.secModel.model); + virBufferVSprintf(&xml, " %s\n", caps->host.secModel.doi); + virBufferAddLit(&xml, " \n"); + } + virBufferAddLit(&xml, " \n\n"); diff -up libvirt-0.6.0/src/capabilities.h.svirt libvirt-0.6.0/src/capabilities.h --- libvirt-0.6.0/src/capabilities.h.svirt 2009-01-31 04:04:17.000000000 -0500 +++ libvirt-0.6.0/src/capabilities.h 2009-02-17 10:07:06.292677000 -0500 @@ -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 -up libvirt-0.6.0/src/domain_conf.c.svirt libvirt-0.6.0/src/domain_conf.c --- libvirt-0.6.0/src/domain_conf.c.svirt 2009-02-17 10:07:06.195708000 -0500 +++ libvirt-0.6.0/src/domain_conf.c 2009-02-17 10:07:06.300677000 -0500 @@ -379,6 +379,16 @@ void virDomainDeviceDefFree(virDomainDev 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 de VIR_FREE(def->cpumask); VIR_FREE(def->emulator); + virSecurityLabelDefFree(def); + VIR_FREE(def); } @@ -1818,6 +1830,34 @@ static int virDomainLifecycleParseXML(vi 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 virDomainDefParse } VIR_FREE(nodes); + /* analysis of security label */ + if (virSecurityLabelDefParseXML(conn, def, ctxt) == -1) + goto error; + return def; no_memory: @@ -3420,6 +3464,13 @@ char *virDomainDefFormat(virConnectPtr c goto cleanup; virBufferAddLit(&buf, " \n"); + + if (def->seclabel.model) { + virBufferEscapeString(&buf, " \n", def->seclabel.model); + virBufferEscapeString(&buf, " \n", def->seclabel.label); + virBufferAddLit(&buf, " \n"); + } + virBufferAddLit(&buf, "\n"); if (virBufferError(&buf)) diff -up libvirt-0.6.0/src/domain_conf.h.svirt libvirt-0.6.0/src/domain_conf.h --- libvirt-0.6.0/src/domain_conf.h.svirt 2009-01-31 04:04:17.000000000 -0500 +++ libvirt-0.6.0/src/domain_conf.h 2009-02-17 10:07:06.307676000 -0500 @@ -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 -up libvirt-0.6.0/src/driver.h.svirt libvirt-0.6.0/src/driver.h --- libvirt-0.6.0/src/driver.h.svirt 2008-12-19 07:51:11.000000000 -0500 +++ libvirt-0.6.0/src/driver.h 2009-02-17 10:07:06.313676000 -0500 @@ -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 -up libvirt-0.6.0/src/libvirt.c.svirt libvirt-0.6.0/src/libvirt.c --- libvirt-0.6.0/src/libvirt.c.svirt 2009-01-31 04:04:17.000000000 -0500 +++ libvirt-0.6.0/src/libvirt.c 2009-02-17 10:07:06.332683000 -0500 @@ -4156,6 +4156,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 -up libvirt-0.6.0/src/libvirt_private.syms.svirt libvirt-0.6.0/src/libvirt_private.syms --- libvirt-0.6.0/src/libvirt_private.syms.svirt 2009-01-31 04:04:17.000000000 -0500 +++ libvirt-0.6.0/src/libvirt_private.syms 2009-02-17 10:36:52.867582000 -0500 @@ -334,3 +334,4 @@ virXPathNode; virXPathNodeSet; virXPathString; virXMLPropString; +virXPathStringLimit; diff -up libvirt-0.6.0/src/libvirt_public.syms.svirt libvirt-0.6.0/src/libvirt_public.syms --- libvirt-0.6.0/src/libvirt_public.syms.svirt 2009-01-20 08:48:28.000000000 -0500 +++ libvirt-0.6.0/src/libvirt_public.syms 2009-02-17 10:37:09.630287000 -0500 @@ -244,7 +244,8 @@ LIBVIRT_0.6.0 { virStoragePoolRef; virStorageVolRef; virNodeDeviceRef; - + virDomainGetSecurityLabel; + virNodeGetSecurityModel; } LIBVIRT_0.5.0; # .... define new API here using predicted next version number .... diff -up libvirt-0.6.0/src/lxc_driver.c.svirt libvirt-0.6.0/src/lxc_driver.c --- libvirt-0.6.0/src/lxc_driver.c.svirt 2009-01-31 04:04:17.000000000 -0500 +++ libvirt-0.6.0/src/lxc_driver.c 2009-02-17 10:07:06.339677000 -0500 @@ -1430,6 +1430,8 @@ static virDriver lxcDriver = { NULL, /* domainPinVcpu */ NULL, /* domainGetVcpus */ NULL, /* domainGetMaxVcpus */ + NULL, /* domainGetSecurityLabel */ + NULL, /* nodeGetSecurityModel */ lxcDomainDumpXML, /* domainDumpXML */ lxcListDefinedDomains, /* listDefinedDomains */ lxcNumDefinedDomains, /* numOfDefinedDomains */ diff -up libvirt-0.6.0/src/Makefile.am.svirt libvirt-0.6.0/src/Makefile.am --- libvirt-0.6.0/src/Makefile.am.svirt 2009-01-31 04:04:17.000000000 -0500 +++ libvirt-0.6.0/src/Makefile.am 2009-02-17 10:07:06.346676000 -0500 @@ -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 += -mo 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 -up libvirt-0.6.0/src/openvz_driver.c.svirt libvirt-0.6.0/src/openvz_driver.c --- libvirt-0.6.0/src/openvz_driver.c.svirt 2009-01-31 04:04:18.000000000 -0500 +++ libvirt-0.6.0/src/openvz_driver.c 2009-02-17 10:07:06.362676000 -0500 @@ -1299,6 +1299,8 @@ static virDriver openvzDriver = { NULL, /* domainPinVcpu */ NULL, /* domainGetVcpus */ openvzDomainGetMaxVcpus, /* domainGetMaxVcpus */ + NULL, /* domainGetSecurityLabel */ + NULL, /* nodeGetSecurityModel */ openvzDomainDumpXML, /* domainDumpXML */ openvzListDefinedDomains, /* listDomains */ openvzNumDefinedDomains, /* numOfDomains */ diff -up libvirt-0.6.0/src/qemu_conf.h.svirt libvirt-0.6.0/src/qemu_conf.h --- libvirt-0.6.0/src/qemu_conf.h.svirt 2009-01-31 04:04:18.000000000 -0500 +++ libvirt-0.6.0/src/qemu_conf.h 2009-02-17 10:07:06.368680000 -0500 @@ -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 -up libvirt-0.6.0/src/qemu_driver.c.svirt libvirt-0.6.0/src/qemu_driver.c --- libvirt-0.6.0/src/qemu_driver.c.svirt 2009-01-31 04:04:18.000000000 -0500 +++ libvirt-0.6.0/src/qemu_driver.c 2009-02-17 10:07:06.378682000 -0500 @@ -68,6 +68,7 @@ #include "memory.h" #include "uuid.h" #include "domain_conf.h" +#include "security.h" #define VIR_FROM_THIS VIR_FROM_QEMU @@ -383,6 +384,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: @@ -474,6 +519,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; } @@ -1111,6 +1161,15 @@ static int qemudNextFreeVNCPort(struct q 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); @@ -1178,6 +1237,16 @@ static int qemudStartVMDaemon(virConnect 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) { @@ -2721,7 +2790,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; @@ -4475,6 +4631,8 @@ static virDriver qemuDriver = { NULL, /* domainGetVcpus */ #endif qemudDomainGetMaxVcpus, /* domainGetMaxVcpus */ + qemudDomainGetSecurityLabel, /* domainGetSecurityLabel */ + qemudNodeGetSecurityModel, /* nodeGetSecurityModel */ qemudDomainDumpXML, /* domainDumpXML */ qemudListDefinedDomains, /* listDomains */ qemudNumDefinedDomains, /* numOfDomains */ diff -up libvirt-0.6.0/src/remote_internal.c.svirt libvirt-0.6.0/src/remote_internal.c --- libvirt-0.6.0/src/remote_internal.c.svirt 2009-02-17 10:07:06.207699000 -0500 +++ libvirt-0.6.0/src/remote_internal.c 2009-02-17 10:14:28.509959000 -0500 @@ -2299,6 +2299,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) { @@ -6721,6 +6782,8 @@ static virDriver driver = { .domainPinVcpu = remoteDomainPinVcpu, .domainGetVcpus = remoteDomainGetVcpus, .domainGetMaxVcpus = remoteDomainGetMaxVcpus, + .domainGetSecurityLabel = remoteDomainGetSecurityLabel, + .nodeGetSecurityModel = remoteNodeGetSecurityModel, .domainDumpXML = remoteDomainDumpXML, .listDefinedDomains = remoteListDefinedDomains, .numOfDefinedDomains = remoteNumOfDefinedDomains, diff -up /dev/null libvirt-0.6.0/src/security.c --- /dev/null 2009-02-11 16:31:53.992012235 -0500 +++ libvirt-0.6.0/src/security.c 2009-02-17 10:07:06.396676000 -0500 @@ -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 + * + */ +#include +#include + +#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 -up /dev/null libvirt-0.6.0/src/security.h --- /dev/null 2009-02-11 16:31:53.992012235 -0500 +++ libvirt-0.6.0/src/security.h 2009-02-17 10:07:06.402676000 -0500 @@ -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 + * + */ +#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 -up /dev/null libvirt-0.6.0/src/security_selinux.c --- /dev/null 2009-02-11 16:31:53.992012235 -0500 +++ libvirt-0.6.0/src/security_selinux.c 2009-02-17 10:07:06.407678000 -0500 @@ -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 + * + * SELinux security driver. + */ +#include +#include + +#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 -up /dev/null libvirt-0.6.0/src/security_selinux.h --- /dev/null 2009-02-11 16:31:53.992012235 -0500 +++ libvirt-0.6.0/src/security_selinux.h 2009-02-17 10:07:06.413677000 -0500 @@ -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 + * + */ +#ifndef __VIR_SECURITY_SELINUX_H__ +#define __VIR_SECURITY_SELINUX_H__ + +extern virSecurityDriver virSELinuxSecurityDriver; + +#endif /* __VIR_SECURITY_SELINUX_H__ */ diff -up libvirt-0.6.0/src/storage_backend.c.svirt libvirt-0.6.0/src/storage_backend.c --- libvirt-0.6.0/src/storage_backend.c.svirt 2009-01-31 04:04:18.000000000 -0500 +++ libvirt-0.6.0/src/storage_backend.c 2009-02-17 10:07:06.419677000 -0500 @@ -276,6 +276,7 @@ virStorageBackendUpdateVolTargetInfoFD(v 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 -up libvirt-0.6.0/src/test.c.svirt libvirt-0.6.0/src/test.c --- libvirt-0.6.0/src/test.c.svirt 2009-01-20 15:39:28.000000000 -0500 +++ libvirt-0.6.0/src/test.c 2009-02-17 10:07:06.428677000 -0500 @@ -3510,6 +3510,8 @@ static virDriver testDriver = { NULL, /* domainPinVcpu */ NULL, /* domainGetVcpus */ NULL, /* domainGetMaxVcpus */ + NULL, /* domainGetSecurityLabel */ + NULL, /* nodeGetSecurityModel */ testDomainDumpXML, /* domainDumpXML */ testListDefinedDomains, /* listDefinedDomains */ testNumOfDefinedDomains, /* numOfDefinedDomains */ diff -up libvirt-0.6.0/src/uml_driver.c.svirt libvirt-0.6.0/src/uml_driver.c --- libvirt-0.6.0/src/uml_driver.c.svirt 2009-01-31 04:04:18.000000000 -0500 +++ libvirt-0.6.0/src/uml_driver.c 2009-02-17 10:07:06.436676000 -0500 @@ -1852,6 +1852,8 @@ static virDriver umlDriver = { NULL, /* domainPinVcpu */ NULL, /* domainGetVcpus */ NULL, /* domainGetMaxVcpus */ + NULL, /* domainGetSecurityLabel */ + NULL, /* nodeGetSecurityModel */ umlDomainDumpXML, /* domainDumpXML */ umlListDefinedDomains, /* listDomains */ umlNumDefinedDomains, /* numOfDomains */ diff -up libvirt-0.6.0/src/virsh.c.svirt libvirt-0.6.0/src/virsh.c --- libvirt-0.6.0/src/virsh.c.svirt 2009-01-31 04:04:18.000000000 -0500 +++ libvirt-0.6.0/src/virsh.c 2009-02-17 10:07:06.447677000 -0500 @@ -954,6 +954,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) { @@ -1515,6 +1516,8 @@ cmdDominfo(vshControl *ctl, const vshCmd { virDomainInfo info; virDomainPtr dom; + virSecurityModel secmodel; + virSecurityLabel seclabel; int ret = TRUE, autostart; unsigned int id; char *str, uuid[VIR_UUID_STRING_BUFLEN]; @@ -1573,6 +1576,29 @@ cmdDominfo(vshControl *ctl, const vshCmd 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 -up libvirt-0.6.0/src/virterror.c.svirt libvirt-0.6.0/src/virterror.c --- libvirt-0.6.0/src/virterror.c.svirt 2009-01-31 04:04:18.000000000 -0500 +++ libvirt-0.6.0/src/virterror.c 2009-02-17 10:07:06.454684000 -0500 @@ -151,6 +151,9 @@ static const char *virErrorDomainName(vi case VIR_FROM_UML: dom = "UML "; break; + case VIR_FROM_SECURITY: + dom = "Security Labeling "; + break; } return(dom); } @@ -962,6 +965,12 @@ virErrorMsg(virErrorNumber error, const 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 -up libvirt-0.6.0/src/xml.c.svirt libvirt-0.6.0/src/xml.c --- libvirt-0.6.0/src/xml.c.svirt 2009-01-31 04:04:18.000000000 -0500 +++ libvirt-0.6.0/src/xml.c 2009-02-17 10:07:06.461676000 -0500 @@ -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 -up libvirt-0.6.0/src/xml.h.svirt libvirt-0.6.0/src/xml.h --- libvirt-0.6.0/src/xml.h.svirt 2008-08-12 03:13:00.000000000 -0400 +++ libvirt-0.6.0/src/xml.h 2009-02-17 10:07:06.467677000 -0500 @@ -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 -up libvirt-0.6.0/tests/daemon-conf.svirt libvirt-0.6.0/tests/daemon-conf --- libvirt-0.6.0/tests/daemon-conf.svirt 2008-12-22 08:21:49.000000000 -0500 +++ libvirt-0.6.0/tests/daemon-conf 2009-02-17 10:07:06.470678000 -0500 @@ -63,6 +63,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