diff --git a/Makefile.maint b/Makefile.maint index d856469..5d03365 100644 --- a/Makefile.maint +++ b/Makefile.maint @@ -353,6 +353,7 @@ msg_gen_function += qemudReportError msg_gen_function += openvzLog msg_gen_function += openvzError msg_gen_function += virDomainReportError +msg_gen_function += virSecLabelReportError # Uncomment the following and run "make syntax-check" to see diagnostics # that are not yet marked for translation, but that need to be rewritten diff --git a/autobuild.sh b/autobuild.sh index e62926c..49d4b5d 100755 --- a/autobuild.sh +++ b/autobuild.sh @@ -14,10 +14,18 @@ rm -rf coverage #mkdir build #cd build +SELINUXENABLED=/usr/sbin/selinuxenabled + +if [ -x $SELINUXENABLED ] && $SELINUXENABLED ; then + WITH_SELINUX="--with-selinux=yes" +else + WITH_SELINUX="" +fi + ./autogen.sh --prefix="$AUTOBUILD_INSTALL_ROOT" \ --enable-test-coverage \ --enable-compile-warnings=error \ - --with-xen-proxy + --with-xen-proxy $WITH_SELINUX # If the MAKEFLAGS envvar does not yet include a -j option, # add -jN where N depends on the number of processors. diff --git a/include/libvirt/libvirt.h b/include/libvirt/libvirt.h index 35b80d0..58ded58 100644 --- a/include/libvirt/libvirt.h +++ b/include/libvirt/libvirt.h @@ -111,6 +111,53 @@ typedef enum { } virDomainCreateFlags; /** + * VIR_SECLABEL_LABEL_BUFLEN: + * + * Macro providing the maximum length of the virDomainSecLabel + * label string. Note that this value is based on that used + * by Labeled NFS. + */ +#define VIR_SECLABEL_LABEL_BUFLEN (4096 + 1) + +/** + * VIR_SECLABEL_MODEL_BUFLEN: + * + * Macro providing the maximum length of the virDomainSecLabel + * model string. + */ +#define VIR_SECLABEL_MODEL_BUFLEN (256 + 1) + +/** + * VIR_SECLABEL_POLICYTYPE_BUFLEN: + * + * Macro providing the maximum length of the virDomainSecLabel + * policy string. + */ +#define VIR_SECLABEL_POLICYTYPE_BUFLEN (256 + 1) + +/** + * virDomainSecLabel: + * + * a virDomainSecLabel is a structure filled by virDomainGetSecLabel(), + * providing the security label and associated attributes for the specified + * domain. + * + */ +typedef struct _virDomainSecLabel { + char model[VIR_SECLABEL_MODEL_BUFLEN]; /* name of security labeling model */ + char label[VIR_SECLABEL_LABEL_BUFLEN]; /* security label string */ + char policytype[VIR_SECLABEL_POLICYTYPE_BUFLEN]; /* policy type */ + int enforcing; /* 1 if security policy is being enforced for domain */ +} virDomainSecLabel; + +/** + * virDomainSecLabelPtr: + * + * a virDomainSecLabelPtr is a pointer to a virDomainSecLabel. + */ +typedef virDomainSecLabel *virDomainSecLabelPtr; + +/** * virNodeInfoPtr: * * a virNodeInfo is a structure filled by virNodeGetInfo() and providing @@ -504,6 +551,8 @@ int virDomainSetMaxMemory (virDomainPtr domain, int virDomainSetMemory (virDomainPtr domain, unsigned long memory); int virDomainGetMaxVcpus (virDomainPtr domain); +int virDomainGetSecLabel (virDomainPtr domain, + virDomainSecLabelPtr seclabel); /* * XML domain description diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index 3624367..e876c00 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -111,6 +111,53 @@ typedef enum { } virDomainCreateFlags; /** + * VIR_SECLABEL_LABEL_BUFLEN: + * + * Macro providing the maximum length of the virDomainSecLabel + * label string. Note that this value is based on that used + * by Labeled NFS. + */ +#define VIR_SECLABEL_LABEL_BUFLEN (4096 + 1) + +/** + * VIR_SECLABEL_MODEL_BUFLEN: + * + * Macro providing the maximum length of the virDomainSecLabel + * model string. + */ +#define VIR_SECLABEL_MODEL_BUFLEN (256 + 1) + +/** + * VIR_SECLABEL_POLICYTYPE_BUFLEN: + * + * Macro providing the maximum length of the virDomainSecLabel + * policy string. + */ +#define VIR_SECLABEL_POLICYTYPE_BUFLEN (256 + 1) + +/** + * virDomainSecLabel: + * + * a virDomainSecLabel is a structure filled by virDomainGetSecLabel(), + * providing the security label and associated attributes for the specified + * domain. + * + */ +typedef struct _virDomainSecLabel { + char model[VIR_SECLABEL_MODEL_BUFLEN]; /* name of security labeling model */ + char label[VIR_SECLABEL_LABEL_BUFLEN]; /* security label string */ + char policytype[VIR_SECLABEL_POLICYTYPE_BUFLEN]; /* policy type */ + int enforcing; /* 1 if security policy is being enforced for domain */ +} virDomainSecLabel; + +/** + * virDomainSecLabelPtr: + * + * a virDomainSecLabelPtr is a pointer to a virDomainSecLabel. + */ +typedef virDomainSecLabel *virDomainSecLabelPtr; + +/** * virNodeInfoPtr: * * a virNodeInfo is a structure filled by virNodeGetInfo() and providing @@ -504,6 +551,8 @@ int virDomainSetMaxMemory (virDomainPtr domain, int virDomainSetMemory (virDomainPtr domain, unsigned long memory); int virDomainGetMaxVcpus (virDomainPtr domain); +int virDomainGetSecLabel (virDomainPtr domain, + virDomainSecLabelPtr seclabel); /* * XML domain description diff --git a/include/libvirt/virterror.h b/include/libvirt/virterror.h index 8e24708..da955c2 100644 --- a/include/libvirt/virterror.h +++ b/include/libvirt/virterror.h @@ -58,6 +58,7 @@ typedef enum { VIR_FROM_STORAGE, /* Error from storage driver */ VIR_FROM_NETWORK, /* Error from network config */ VIR_FROM_DOMAIN, /* Error from domain config */ + VIR_FROM_SECLABEL, /* Error from security labeling framework */ } virErrorDomain; @@ -148,6 +149,7 @@ typedef enum { VIR_WAR_NO_STORAGE, /* failed to start storage */ VIR_ERR_NO_STORAGE_POOL, /* storage pool not found */ VIR_ERR_NO_STORAGE_VOL, /* storage pool not found */ + VIR_ERR_NO_SECLABEL_MODEL, /* security labeling model not found */ } virErrorNumber; /** diff --git a/po/POTFILES.in b/po/POTFILES.in index f671155..4a200cb 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -18,6 +18,8 @@ src/proxy_internal.c src/qemu_conf.c src/qemu_driver.c src/remote_internal.c +src/seclabel.c +src/seclabel_selinux.c src/sexpr.c src/storage_backend.c src/storage_backend_disk.c diff --git a/python/generator.py b/python/generator.py index c706b19..b95ac4f 100755 --- a/python/generator.py +++ b/python/generator.py @@ -332,6 +332,7 @@ skip_function = ( 'virCopyLastError', # Python API is called virGetLastError instead 'virConnectOpenAuth', # Python C code is manually written 'virDefaultErrorFunc', # Python virErrorFuncHandler impl calls this from C + 'virDomainGetSecLabel', # Needs investigation... ) diff --git a/qemud/remote.c b/qemud/remote.c index 72e064e..c3dc871 100644 --- a/qemud/remote.c +++ b/qemud/remote.c @@ -1248,6 +1248,61 @@ remoteDispatchDomainGetMaxVcpus (struct qemud_server *server ATTRIBUTE_UNUSED, } static int +remoteDispatchDomainGetSeclabel (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, + remote_message_header *req, + remote_domain_get_seclabel_args *args, + remote_domain_get_seclabel_ret *ret) +{ + virDomainPtr dom; + virDomainSecLabel seclabel; + CHECK_CONN(client); + + dom = get_nonnull_domain (client->conn, args->dom); + if (dom == NULL) { + remoteDispatchError (client, req, "%s", _("domain not found")); + return -2; + } + + memset (&seclabel, 0, sizeof seclabel); + + if (virDomainGetSecLabel (dom, &seclabel) == -1) { + virDomainFree (dom); + remoteDispatchError (client, req, "%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); + remoteDispatchError (client, req, "%s", strerror (errno)); + return -2; + } + strcpy(ret->label.label_val, seclabel.label); + + ret->model.model_len = strlen(seclabel.model) + 1; + if (VIR_ALLOC_N(ret->model.model_val, ret->model.model_len) < 0) { + virDomainFree (dom); + remoteDispatchError (client, req, "%s", strerror (errno)); + return -2; + } + strcpy(ret->model.model_val, seclabel.model); + + ret->policytype.policytype_len = strlen(seclabel.policytype) + 1; + if (VIR_ALLOC_N(ret->policytype.policytype_val, ret->policytype.policytype_len) < 0) { + virDomainFree (dom); + remoteDispatchError (client, req, "%s", strerror (errno)); + return -2; + } + strcpy(ret->policytype.policytype_val, seclabel.policytype); + + ret->enforcing = seclabel.enforcing; + + virDomainFree(dom); + return 0; +} + +static int remoteDispatchDomainGetOsType (struct qemud_server *server ATTRIBUTE_UNUSED, struct qemud_client *client, remote_message_header *req, diff --git a/qemud/remote_dispatch_localvars.h b/qemud/remote_dispatch_localvars.h index f46b493..fe55109 100644 --- a/qemud/remote_dispatch_localvars.h +++ b/qemud/remote_dispatch_localvars.h @@ -89,6 +89,8 @@ remote_domain_get_vcpus_ret lv_remote_domain_get_vcpus_ret; remote_domain_get_scheduler_parameters_args lv_remote_domain_get_scheduler_parameters_args; remote_domain_get_scheduler_parameters_ret lv_remote_domain_get_scheduler_parameters_ret; remote_node_get_info_ret lv_remote_node_get_info_ret; +remote_domain_get_seclabel_args lv_remote_domain_get_seclabel_args; +remote_domain_get_seclabel_ret lv_remote_domain_get_seclabel_ret; remote_network_lookup_by_name_args lv_remote_network_lookup_by_name_args; remote_network_lookup_by_name_ret lv_remote_network_lookup_by_name_ret; remote_domain_memory_peek_args lv_remote_domain_memory_peek_args; diff --git a/qemud/remote_dispatch_proc_switch.h b/qemud/remote_dispatch_proc_switch.h index 89296d7..52d1ce1 100644 --- a/qemud/remote_dispatch_proc_switch.h +++ b/qemud/remote_dispatch_proc_switch.h @@ -179,6 +179,15 @@ case REMOTE_PROC_DOMAIN_GET_SCHEDULER_TYPE: ret = (char *) &lv_remote_domain_get_scheduler_type_ret; memset (&lv_remote_domain_get_scheduler_type_ret, 0, sizeof lv_remote_domain_get_scheduler_type_ret); break; +case REMOTE_PROC_DOMAIN_GET_SECLABEL: + fn = (dispatch_fn) remoteDispatchDomainGetSeclabel; + args_filter = (xdrproc_t) xdr_remote_domain_get_seclabel_args; + args = (char *) &lv_remote_domain_get_seclabel_args; + memset (&lv_remote_domain_get_seclabel_args, 0, sizeof lv_remote_domain_get_seclabel_args); + ret_filter = (xdrproc_t) xdr_remote_domain_get_seclabel_ret; + ret = (char *) &lv_remote_domain_get_seclabel_ret; + memset (&lv_remote_domain_get_seclabel_ret, 0, sizeof lv_remote_domain_get_seclabel_ret); + break; case REMOTE_PROC_DOMAIN_GET_VCPUS: fn = (dispatch_fn) remoteDispatchDomainGetVcpus; args_filter = (xdrproc_t) xdr_remote_domain_get_vcpus_args; diff --git a/qemud/remote_dispatch_prototypes.h b/qemud/remote_dispatch_prototypes.h index 3f4eb9f..2f38611 100644 --- a/qemud/remote_dispatch_prototypes.h +++ b/qemud/remote_dispatch_prototypes.h @@ -25,6 +25,7 @@ static int remoteDispatchDomainGetMaxVcpus (struct qemud_server *server, struct static int remoteDispatchDomainGetOsType (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_domain_get_os_type_args *args, remote_domain_get_os_type_ret *ret); static int remoteDispatchDomainGetSchedulerParameters (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_domain_get_scheduler_parameters_args *args, remote_domain_get_scheduler_parameters_ret *ret); static int remoteDispatchDomainGetSchedulerType (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_domain_get_scheduler_type_args *args, remote_domain_get_scheduler_type_ret *ret); +static int remoteDispatchDomainGetSeclabel (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_domain_get_seclabel_args *args, remote_domain_get_seclabel_ret *ret); static int remoteDispatchDomainGetVcpus (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_domain_get_vcpus_args *args, remote_domain_get_vcpus_ret *ret); static int remoteDispatchDomainInterfaceStats (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_domain_interface_stats_args *args, remote_domain_interface_stats_ret *ret); static int remoteDispatchDomainLookupById (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_domain_lookup_by_id_args *args, remote_domain_lookup_by_id_ret *ret); diff --git a/qemud/remote_protocol.c b/qemud/remote_protocol.c index 33a25e1..f8ccf71 100644 --- a/qemud/remote_protocol.c +++ b/qemud/remote_protocol.c @@ -1083,6 +1083,36 @@ xdr_remote_domain_get_max_vcpus_ret (XDR *xdrs, remote_domain_get_max_vcpus_ret } bool_t +xdr_remote_domain_get_seclabel_args (XDR *xdrs, remote_domain_get_seclabel_args *objp) +{ + + if (!xdr_remote_nonnull_domain (xdrs, &objp->dom)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_domain_get_seclabel_ret (XDR *xdrs, remote_domain_get_seclabel_ret *objp) +{ + char **objp_cpp1 = (char **) (void *) &objp->label.label_val; + char **objp_cpp2 = (char **) (void *) &objp->policytype.policytype_val; + char **objp_cpp0 = (char **) (void *) &objp->model.model_val; + + if (!xdr_array (xdrs, objp_cpp0, (u_int *) &objp->model.model_len, REMOTE_SECLABEL_MODEL_MAX, + sizeof (char), (xdrproc_t) xdr_char)) + return FALSE; + if (!xdr_array (xdrs, objp_cpp1, (u_int *) &objp->label.label_len, REMOTE_SECLABEL_LABEL_MAX, + sizeof (char), (xdrproc_t) xdr_char)) + return FALSE; + if (!xdr_array (xdrs, objp_cpp2, (u_int *) &objp->policytype.policytype_len, REMOTE_SECLABEL_POLICYTYPE_MAX, + sizeof (char), (xdrproc_t) xdr_char)) + return FALSE; + if (!xdr_int (xdrs, &objp->enforcing)) + 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 0bf8b79..9a6b3ac 100644 --- a/qemud/remote_protocol.h +++ b/qemud/remote_protocol.h @@ -37,6 +37,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_SECLABEL_MODEL_MAX VIR_SECLABEL_MODEL_BUFLEN +#define REMOTE_SECLABEL_LABEL_MAX VIR_SECLABEL_LABEL_BUFLEN +#define REMOTE_SECLABEL_POLICYTYPE_MAX VIR_SECLABEL_POLICYTYPE_BUFLEN typedef char remote_uuid[VIR_UUID_BUFLEN]; @@ -589,6 +592,28 @@ 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_seclabel_args { + remote_nonnull_domain dom; +}; +typedef struct remote_domain_get_seclabel_args remote_domain_get_seclabel_args; + +struct remote_domain_get_seclabel_ret { + struct { + u_int model_len; + char *model_val; + } model; + struct { + u_int label_len; + char *label_val; + } label; + struct { + u_int policytype_len; + char *policytype_val; + } policytype; + int enforcing; +}; +typedef struct remote_domain_get_seclabel_ret remote_domain_get_seclabel_ret; + struct remote_domain_attach_device_args { remote_nonnull_domain dom; remote_nonnull_string xml; @@ -1189,6 +1214,7 @@ enum remote_procedure { REMOTE_PROC_NODE_GET_FREE_MEMORY = 102, REMOTE_PROC_DOMAIN_BLOCK_PEEK = 103, REMOTE_PROC_DOMAIN_MEMORY_PEEK = 104, + REMOTE_PROC_DOMAIN_GET_SECLABEL = 105, }; typedef enum remote_procedure remote_procedure; @@ -1308,6 +1334,8 @@ 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_seclabel_args (XDR *, remote_domain_get_seclabel_args*); +extern bool_t xdr_remote_domain_get_seclabel_ret (XDR *, remote_domain_get_seclabel_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*); @@ -1489,6 +1517,8 @@ 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_seclabel_args (); +extern bool_t xdr_remote_domain_get_seclabel_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 f1bd9ff..6170cd8 100644 --- a/qemud/remote_protocol.x +++ b/qemud/remote_protocol.x @@ -110,6 +110,21 @@ const REMOTE_DOMAIN_BLOCK_PEEK_BUFFER_MAX = 65536; */ const REMOTE_DOMAIN_MEMORY_PEEK_BUFFER_MAX = 65536; +/* + * Maximum length of a security label model field. + */ +const REMOTE_SECLABEL_MODEL_MAX = VIR_SECLABEL_MODEL_BUFLEN; + +/* + * Maximum length of a security label field. + */ +const REMOTE_SECLABEL_LABEL_MAX = VIR_SECLABEL_LABEL_BUFLEN; + +/* + * Maximum length of a security label policy type field. + */ +const REMOTE_SECLABEL_POLICYTYPE_MAX = VIR_SECLABEL_POLICYTYPE_BUFLEN; + /* UUID. VIR_UUID_BUFLEN definition comes from libvirt.h */ typedef opaque remote_uuid[VIR_UUID_BUFLEN]; @@ -577,6 +592,17 @@ struct remote_domain_get_max_vcpus_ret { int num; }; +struct remote_domain_get_seclabel_args { + remote_nonnull_domain dom; +}; + +struct remote_domain_get_seclabel_ret { + char model; + char label; + char policytype; + int enforcing; +}; + struct remote_domain_attach_device_args { remote_nonnull_domain dom; remote_nonnull_string xml; @@ -1086,7 +1112,9 @@ enum remote_procedure { REMOTE_PROC_NODE_GET_FREE_MEMORY = 102, REMOTE_PROC_DOMAIN_BLOCK_PEEK = 103, - REMOTE_PROC_DOMAIN_MEMORY_PEEK = 104 + REMOTE_PROC_DOMAIN_MEMORY_PEEK = 104, + + REMOTE_PROC_DOMAIN_GET_SECLABEL = 105 }; /* Custom RPC structure. */ diff --git a/src/Makefile.am b/src/Makefile.am index 5a769f8..758463c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -111,7 +111,7 @@ QEMU_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 @@ -132,6 +132,12 @@ STORAGE_HELPER_DISK_SOURCES = \ parthelper.c +# Security framework and drivers for various models +SECURITY_DRIVER_SOURCES = \ + seclabel.h seclabel.c + +SECURITY_DRIVER_SELINUX_SOURCES = \ + seclabel_selinux.h seclabel_selinux.c ######################### # @@ -173,6 +179,7 @@ libvirt_la_SOURCES += $(NETWORK_DRIVER_SOURCES) endif libvirt_la_SOURCES += $(STORAGE_DRIVER_SOURCES) libvirt_la_SOURCES += $(STORAGE_DRIVER_FS_SOURCES) +libvirt_la_SOURCES += $(SECURITY_DRIVER_SOURCES) if WITH_QEMU libvirt_la_SOURCES += $(QEMU_DRIVER_SOURCES) @@ -193,6 +200,10 @@ endif if WITH_STORAGE_DISK libvirt_la_SOURCES += $(STORAGE_DRIVER_DISK_SOURCES) endif + +if HAVE_SELINUX +libvirt_la_SOURCES += $(SECURITY_DRIVER_SELINUX_SOURCES) +endif endif # Add all conditional sources just in case... @@ -208,7 +219,9 @@ EXTRA_DIST += \ $(STORAGE_DRIVER_FS_SOURCES) \ $(STORAGE_DRIVER_LVM_SOURCES) \ $(STORAGE_DRIVER_ISCSI_SOURCES) \ - $(STORAGE_DRIVER_DISK_SOURCES) + $(STORAGE_DRIVER_DISK_SOURCES) \ + $(SECURITY_DRIVER_SOURCES) \ + $(SECURITY_DRIVER_SELINUX_SOURCES) libvirt_la_LIBADD = $(LIBXML_LIBS) $(GNUTLS_LIBS) $(SASL_LIBS) $(SELINUX_LIBS) \ diff --git a/src/domain_conf.c b/src/domain_conf.c index 2bade8d..5154fac 100644 --- a/src/domain_conf.c +++ b/src/domain_conf.c @@ -345,6 +345,18 @@ void virDomainDeviceDefFree(virDomainDeviceDefPtr def) VIR_FREE(def); } +void virDomainSecLabelDefFree(virDomainDefPtr def); + +void virDomainSecLabelDefFree(virDomainDefPtr def) +{ + if (def->seclabel.model) + VIR_FREE(def->seclabel.model); + if (def->seclabel.label) + VIR_FREE(def->seclabel.label); + if (def->seclabel.policytype) + VIR_FREE(def->seclabel.policytype); +} + void virDomainDefFree(virDomainDefPtr def) { unsigned int i; @@ -403,6 +415,8 @@ void virDomainDefFree(virDomainDefPtr def) VIR_FREE(def->cpumask); VIR_FREE(def->emulator); + virDomainSecLabelDefFree(def); + VIR_FREE(def); } @@ -1628,6 +1642,61 @@ static int virDomainLifecycleParseXML(virConnectPtr conn, return 0; } +static int +virDomainSecLabelDefParseXMLString(virConnectPtr conn, + const char *str, + int maxlen, + const char *name, + char **to, + xmlXPathContextPtr ctxt) +{ + char *tmp = virXPathString(conn, str, ctxt); + + if (tmp != NULL) { + if (strlen(tmp) >= maxlen) { + virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, + _("\'%s\' longer than %d characters"), + name, maxlen); + return -1; + } + *to = tmp; + } else { + virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, + _("\'%s\' missing"), name); + return -1; + } + return 0; +} + +static int +virDomainSecLabelDefParseXML(virConnectPtr conn, + const virDomainDefPtr def, + xmlXPathContextPtr ctxt) +{ + if (virXPathNode(conn, "./seclabel", ctxt) == NULL) + return 0; + + if (virDomainSecLabelDefParseXMLString(conn, "string(./seclabel/@model)", + VIR_SECLABEL_MODEL_BUFLEN-1, "model", + &def->seclabel.model, ctxt) == -1) + goto error; + + if (virDomainSecLabelDefParseXMLString(conn, "string(./seclabel/label[1])", + VIR_SECLABEL_LABEL_BUFLEN-1, "label", + &def->seclabel.label, ctxt) == -1) + goto error; + + if (virDomainSecLabelDefParseXMLString(conn, "string(./seclabel/policytype[1])", + VIR_SECLABEL_POLICYTYPE_BUFLEN-1, "policytype", + &def->seclabel.policytype, ctxt) == -1) + goto error; + + return 0; + +error: + virDomainSecLabelDefFree(def); + return -1; +} virDomainDeviceDefPtr virDomainDeviceDefParse(virConnectPtr conn, const virDomainDefPtr def, @@ -2187,6 +2256,10 @@ static virDomainDefPtr virDomainDefParseXML(virConnectPtr conn, } VIR_FREE(nodes); + /* analysis of security label */ + if (virDomainSecLabelDefParseXML(conn, def, ctxt) == -1) + goto error; + return def; no_memory: @@ -3179,6 +3252,14 @@ char *virDomainDefFormat(virConnectPtr conn, goto cleanup; virBufferAddLit(&buf, " \n"); + + if (def->seclabel.model) { + virBufferEscapeString(&buf, " \n", def->seclabel.model); + virBufferEscapeString(&buf, " \n", def->seclabel.label); + virBufferEscapeString(&buf, " %s\n", def->seclabel.policytype); + virBufferAddLit(&buf, " \n"); + } + virBufferAddLit(&buf, "\n"); if (virBufferError(&buf)) diff --git a/src/domain_conf.h b/src/domain_conf.h index 4d193f4..a8b5e01 100644 --- a/src/domain_conf.h +++ b/src/domain_conf.h @@ -389,6 +389,15 @@ struct _virDomainOSDef { char *bootloaderArgs; }; +/* Security label configuration for domain */ +typedef struct _virDomainSecLabelDef virDomainSecLabelDef; +typedef virDomainSecLabelDef *virDomainSecLabelDefPtr; +struct _virDomainSecLabelDef { + char *model; /* name of security labeling model */ + char *label; /* security label string */ + char *policytype; /* policy type */ +}; + #define VIR_DOMAIN_CPUMASK_LEN 1024 /* Guest VM main configuration */ @@ -446,6 +455,7 @@ struct _virDomainDef { /* Only 1 */ virDomainChrDefPtr console; + virDomainSecLabelDef seclabel; }; /* Guest VM runtime state */ diff --git a/src/driver.h b/src/driver.h index 0540f80..fd7ebdc 100644 --- a/src/driver.h +++ b/src/driver.h @@ -182,6 +182,9 @@ typedef int typedef int (*virDrvDomainGetMaxVcpus) (virDomainPtr domain); typedef int + (*virDrvDomainGetSecLabel) (virDomainPtr domain, + virDomainSecLabelPtr seclabel); +typedef int (*virDrvDomainAttachDevice) (virDomainPtr domain, const char *xml); typedef int @@ -330,6 +333,7 @@ struct _virDriver { virDrvDomainPinVcpu domainPinVcpu; virDrvDomainGetVcpus domainGetVcpus; virDrvDomainGetMaxVcpus domainGetMaxVcpus; + virDrvDomainGetSecLabel domainGetSecLabel; virDrvDomainDumpXML domainDumpXML; virDrvListDefinedDomains listDefinedDomains; virDrvNumOfDefinedDomains numOfDefinedDomains; diff --git a/src/libvirt.c b/src/libvirt.c index ca2675a..3b90c37 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -3228,6 +3228,41 @@ virDomainGetMaxVcpus(virDomainPtr domain) return -1; } +/** + * virDomainGetSecLabel: + * @domain: a domain object + * @vm: VM object (looked up by caller) + * @seclabel: pointer to a virDomainSecLabel structure + * + * Extract security label of an actice 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 +virDomainGetSecLabel(virDomainPtr domain, virDomainSecLabelPtr 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->domainGetSecLabel) + return conn->driver->domainGetSecLabel(domain, seclabel); + + virLibConnWarning(conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return -2; +} /** * virDomainAttachDevice: diff --git a/src/libvirt_sym.version b/src/libvirt_sym.version index 3cc4505..190abda 100644 --- a/src/libvirt_sym.version +++ b/src/libvirt_sym.version @@ -81,6 +81,8 @@ virDomainMigrate; + virDomainGetSecLabel; + virNetworkGetConnect; virConnectNumOfNetworks; virConnectListNetworks; diff --git a/src/lxc_driver.c b/src/lxc_driver.c index c598d1d..dd76a8a 100644 --- a/src/lxc_driver.c +++ b/src/lxc_driver.c @@ -1256,6 +1256,7 @@ static virDriver lxcDriver = { NULL, /* domainPinVcpu */ NULL, /* domainGetVcpus */ NULL, /* domainGetMaxVcpus */ + NULL, /* domainGetSecLabel */ lxcDomainDumpXML, /* domainDumpXML */ lxcListDefinedDomains, /* listDefinedDomains */ lxcNumDefinedDomains, /* numOfDefinedDomains */ diff --git a/src/openvz_driver.c b/src/openvz_driver.c index b82d0df..4e3fa73 100644 --- a/src/openvz_driver.c +++ b/src/openvz_driver.c @@ -990,6 +990,7 @@ static virDriver openvzDriver = { NULL, /* domainPinVcpu */ NULL, /* domainGetVcpus */ openvzDomainGetMaxVcpus, /* domainGetMaxVcpus */ + NULL, /* domainGetSecLabel */ openvzDomainDumpXML, /* domainDumpXML */ openvzListDefinedDomains, /* listDomains */ openvzNumDefinedDomains, /* numOfDomains */ diff --git a/src/qemu_conf.h b/src/qemu_conf.h index cfd7d35..db4dbc2 100644 --- a/src/qemu_conf.h +++ b/src/qemu_conf.h @@ -31,6 +31,7 @@ #include "capabilities.h" #include "network_conf.h" #include "domain_conf.h" +#include "seclabel.h" #define qemudDebug(fmt, ...) do {} while(0) @@ -63,6 +64,7 @@ struct qemud_driver { char *vncListen; virCapsPtr caps; + virSecLabelDriverPtr secLabelDriver; }; diff --git a/src/qemu_driver.c b/src/qemu_driver.c index 904fe00..2a27b93 100644 --- a/src/qemu_driver.c +++ b/src/qemu_driver.c @@ -64,6 +64,7 @@ #include "memory.h" #include "uuid.h" #include "domain_conf.h" +#include "seclabel.h" /* For storing short-lived temporary files. */ #define TEMPDIR LOCAL_STATE_DIR "/cache/libvirt" @@ -141,6 +142,30 @@ qemudAutostartConfigs(struct qemud_driver *driver) { } } +static int +qemudSecLabelInit(struct qemud_driver *qemud_drv) +{ + int ret; + virSecLabelDriverPtr seclabel_drv; + + ret = virSecLabelDriverStartup(&seclabel_drv); + if (ret == -1) { + qemudLog(QEMUD_ERR, _("Failed to start security labeling driver")); + return -1; + } + if (ret == -2) + return 0; + + qemud_drv->secLabelDriver = seclabel_drv; + + qemudLog(QEMUD_DEBUG, "Initialized security labeling driver \'%s\' with " + "policy type \'%s\' in %s mode.\n", seclabel_drv->name, + virSecLabelDriverGetPolicyType(seclabel_drv), + virSecLabelDriverGetEnforcing(seclabel_drv) ? "enforcing" : "permissive"); + + return 0; +} + /** * qemudStartup: * @@ -199,6 +224,11 @@ qemudStartup(void) { if ((qemu_driver->caps = qemudCapsInit()) == NULL) goto out_of_memory; + if (qemudSecLabelInit(qemu_driver) < 0) { + qemudShutdown(); + return -1; + } + if (qemudLoadDriverConfig(qemu_driver, driverConf) < 0) { qemudShutdown(); return -1; @@ -742,6 +772,15 @@ static int qemudNextFreeVNCPort(struct qemud_driver *driver ATTRIBUTE_UNUSED) { return -1; } +static int qemudDomainSetSecLabel(virConnectPtr conn, struct qemud_driver *driver, virDomainObjPtr vm) +{ + if (vm->def->seclabel.model != NULL) + if (driver->secLabelDriver && driver->secLabelDriver->domainSetLabel) + return driver->secLabelDriver->domainSetLabel(conn, driver->secLabelDriver, + &vm->def->seclabel); + return 0; +} + static int qemudStartVMDaemon(virConnectPtr conn, struct qemud_driver *driver, virDomainObjPtr vm, @@ -833,6 +872,16 @@ static int qemudStartVMDaemon(virConnectPtr conn, return -1; } + /* + * Set up the security label for the domain here, before doing + * too much else. + */ + if (qemudDomainSetSecLabel(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) { @@ -2098,7 +2147,47 @@ static int qemudDomainGetMaxVcpus(virDomainPtr dom) { return ret; } +static int qemudDomainGetSecLabel(virDomainPtr dom, virDomainSecLabelPtr seclabel) +{ + struct qemud_driver *driver = (struct qemud_driver *)dom->conn->privateData; + virDomainObjPtr vm = virDomainFindByUUID(&driver->domains, dom->uuid); + const char *type; + + 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); + return -1; + } + + 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); + return -1; + } + + /* + * 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. + */ + if (virDomainIsActive(vm)) { + if (driver->secLabelDriver && driver->secLabelDriver->domainGetLabel) { + if (driver->secLabelDriver->domainGetLabel(dom->conn, driver->secLabelDriver, + vm, seclabel) == -1) { + qemudReportError(dom->conn, dom, NULL, VIR_ERR_INTERNAL_ERROR, + _("Failed to get security label")); + return -1; + } + } + } + return 0; +} +/* TODO: check seclabel restore */ static int qemudDomainRestore(virConnectPtr conn, const char *path) { struct qemud_driver *driver = (struct qemud_driver *)conn->privateData; @@ -3174,6 +3263,7 @@ static virDriver qemuDriver = { NULL, /* domainGetVcpus */ #endif qemudDomainGetMaxVcpus, /* domainGetMaxVcpus */ + qemudDomainGetSecLabel, /* domainGetSecLabel */ qemudDomainDumpXML, /* domainDumpXML */ qemudListDefinedDomains, /* listDomains */ qemudNumDefinedDomains, /* numOfDomains */ diff --git a/src/remote_internal.c b/src/remote_internal.c index 35b7b4b..bfb71b2 100644 --- a/src/remote_internal.c +++ b/src/remote_internal.c @@ -1838,6 +1838,58 @@ remoteDomainGetMaxVcpus (virDomainPtr domain) return ret.num; } +static int +remoteDomainGetSecLabel (virDomainPtr domain, virDomainSecLabelPtr seclabel) +{ + remote_domain_get_seclabel_args args; + remote_domain_get_seclabel_ret ret; + int rv = 0; + GET_PRIVATE (domain->conn, -1); + + make_nonnull_domain (&args.dom, domain); + memset (&ret, 0, sizeof ret); + if (call (domain->conn, priv, 0, REMOTE_PROC_DOMAIN_GET_SECLABEL, + (xdrproc_t) xdr_remote_domain_get_seclabel_args, (char *)&args, + (xdrproc_t) xdr_remote_domain_get_seclabel_ret, (char *)&ret) == -1) { + return -1; + } + + if (ret.policytype.policytype_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); + rv = -1; + goto cleanup; + } + + if (strlen (ret.model.model_val) >= sizeof seclabel->model) { + errorf (domain->conn, VIR_ERR_RPC, _("security model exceeds maximum: %zd"), + sizeof seclabel->model - 1); + rv = -1; + goto cleanup; + } + + if (strlen (ret.policytype.policytype_val) >= sizeof seclabel->policytype) { + errorf (domain->conn, VIR_ERR_RPC, _("security policytype exceeds maximum: %zd"), + sizeof seclabel->policytype - 1); + rv = -1; + goto cleanup; + } + + strcpy (seclabel->label, ret.label.label_val); + strcpy (seclabel->model, ret.model.model_val); + strcpy (seclabel->policytype, ret.policytype.policytype_val); + seclabel->enforcing = ret.enforcing; + + cleanup: + free (ret.label.label_val); + free (ret.model.model_val); + free (ret.policytype.policytype_val); + } + + return rv; +} + static char * remoteDomainDumpXML (virDomainPtr domain, int flags) { @@ -4850,6 +4902,7 @@ static virDriver driver = { .domainPinVcpu = remoteDomainPinVcpu, .domainGetVcpus = remoteDomainGetVcpus, .domainGetMaxVcpus = remoteDomainGetMaxVcpus, + .domainGetSecLabel = remoteDomainGetSecLabel, .domainDumpXML = remoteDomainDumpXML, .listDefinedDomains = remoteListDefinedDomains, .numOfDefinedDomains = remoteNumOfDefinedDomains, diff --git a/src/seclabel.c b/src/seclabel.c new file mode 100644 index 0000000..ffe0c90 --- /dev/null +++ b/src/seclabel.c @@ -0,0 +1,130 @@ +/* + * 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 "seclabel.h" + +#if HAVE_SELINUX +#include "seclabel_selinux.h" +#endif + +static virSecLabelDriverPtr seclabel_drivers[] = { +#ifdef HAVE_SELINUX + &virSELinuxSecLabelDriver, +#endif +}; + +/* + * Probe each security labeling 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, -1 on error, and -2 on no driver found (caller + * to determine if that's an error). + */ +int +virSecLabelDriverStartup(virSecLabelDriverPtr * drv) +{ + unsigned int i; + + for (i = 0; i < (sizeof(seclabel_drivers) / sizeof(seclabel_drivers[0])); i++) { + virSecLabelDriverPtr tmp = seclabel_drivers[i]; + + if (tmp->probe()) { + virSecLabelDriverInit(tmp); + if (tmp->open(NULL, tmp) == -1) { + return -1; + } else { + *drv = tmp; + break; + } + } else + return -2; + } + return 0; +} + +void +virSecLabelReportError(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_SECLABEL, code, + VIR_ERR_ERROR, NULL, NULL, NULL, -1, -1, "%s", + errorMessage); +} + +/* + * Helpers + */ +void +virSecLabelDriverSetEnforcing(virSecLabelDriverPtr drv, int enforcing) +{ + drv->_private.enforcing = enforcing; +} + +int +virSecLabelDriverGetEnforcing(virSecLabelDriverPtr drv) +{ + return drv->_private.enforcing; +} + +void +virSecLabelDriverInit(virSecLabelDriverPtr drv) +{ + memset(&drv->_private, 0, sizeof drv->_private); +} + +int +virSecLabelDriverSetPolicyType(virConnectPtr conn, + virSecLabelDriverPtr drv, + const char *policytype) +{ + if (strlen(policytype) >= VIR_SECLABEL_POLICYTYPE_BUFLEN) { + virSecLabelReportError(conn, VIR_ERR_ERROR, + _("%s: policy type \'%s\' is " + "longer than the maximum allowed length of %d"), + __func__, policytype, + VIR_SECLABEL_POLICYTYPE_BUFLEN - 1); + return -1; + } + strcpy(drv->_private.policytype, policytype); + return 0; +} + +const char * +virSecLabelDriverGetPolicyType(virSecLabelDriverPtr drv) +{ + return drv->_private.policytype; +} + +void +virSecLabelDriverSetInitialized(virSecLabelDriverPtr drv) +{ + drv->_private.initialized = 1; +} + +const char * +virSecLabelDriverGetModel(virSecLabelDriverPtr drv) +{ + return drv->name; +} diff --git a/src/seclabel.h b/src/seclabel.h new file mode 100644 index 0000000..4dc602f --- /dev/null +++ b/src/seclabel.h @@ -0,0 +1,68 @@ +/* + * 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_SECLABEL_H__ +#define __VIR_SECLABEL_H__ + +#include "internal.h" +#include "domain_conf.h" + +typedef struct _virSecLabelDriver virSecLabelDriver; +typedef virSecLabelDriver *virSecLabelDriverPtr; +typedef int (*virSecLabelDriverProbe) (void); +typedef int (*virSecLabelDriverOpen) (virConnectPtr conn, + virSecLabelDriverPtr drv); +typedef int (*virSecLabelDomainGetLabel) (virConnectPtr conn, + virSecLabelDriverPtr drv, + virDomainObjPtr vm, + virDomainSecLabelPtr sec); +typedef int (*virSecLabelDomainSetLabel) (virConnectPtr conn, + virSecLabelDriverPtr drv, + virDomainSecLabelDefPtr secdef); + +struct _virSecLabelDriver { + const char *name; + virSecLabelDriverProbe probe; + virSecLabelDriverOpen open; + virSecLabelDomainGetLabel domainGetLabel; + virSecLabelDomainSetLabel domainSetLabel; + + /* + * This is internally managed driver state and should only be accessed + * via helpers below. + */ + struct { + int enforcing:1, initialized:1; + char policytype[VIR_SECLABEL_POLICYTYPE_BUFLEN]; + } _private; +}; + +/* Global methods */ +int virSecLabelDriverStartup(virSecLabelDriverPtr * drv); + +void +virSecLabelReportError(virConnectPtr conn, int code, const char *fmt, ...) + ATTRIBUTE_FORMAT(printf, 3, 4); + +/* Helpers */ +void virSecLabelDriverSetEnforcing(virSecLabelDriverPtr drv, + int enforcing); +int virSecLabelDriverGetEnforcing(virSecLabelDriverPtr drv); +void virSecLabelDriverInit(virSecLabelDriverPtr drv); +int virSecLabelDriverSetPolicyType(virConnectPtr conn, + virSecLabelDriverPtr drv, + const char *policytype); +const char *virSecLabelDriverGetPolicyType(virSecLabelDriverPtr drv); +void virSecLabelDriverSetInitialized(virSecLabelDriverPtr drv); +const char *virSecLabelDriverGetModel(virSecLabelDriverPtr drv); + +#endif /* __VIR_SECLABEL_H__ */ diff --git a/src/seclabel_selinux.c b/src/seclabel_selinux.c new file mode 100644 index 0000000..4c67a7f --- /dev/null +++ b/src/seclabel_selinux.c @@ -0,0 +1,132 @@ +/* + * 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 seclabel driver. + */ +#include +#include + +#include "seclabel.h" +#include "seclabel_selinux.h" + +static int +SELinuxSecLabelDriverProbe(void) +{ + return is_selinux_enabled(); +} + +static int +SELinuxSecLabelDriverOpen(virConnectPtr conn, virSecLabelDriverPtr drv) +{ + char *policytype; + int enforcing, ret; + + if (selinux_getpolicytype(&policytype) == -1) { + virSecLabelReportError(conn, VIR_ERR_ERROR, _("%s: error calling " + "selinux_getpolicytype(): %s"), __func__, + strerror(errno)); + return -1; + } + + virSecLabelDriverSetPolicyType(conn, drv, policytype); + + enforcing = security_getenforce(); + if (enforcing == -1) { + virSecLabelReportError(conn, VIR_ERR_ERROR, _("%s: error calling " + "security_getenforce(): %s"), __func__, + strerror(errno)); + ret = -1; + goto out_free; + } + + virSecLabelDriverSetEnforcing(drv, enforcing); + ret = 0; + + out_free: + free(policytype); + return ret; +} + +static int +SELinuxSecLabelDomainGetLabel(virConnectPtr conn, virSecLabelDriverPtr drv, + virDomainObjPtr vm, virDomainSecLabelPtr sec) +{ + security_context_t ctx; + const char *p; + + if (getpidcon(vm->pid, &ctx) == -1) { + virSecLabelReportError(conn, VIR_ERR_ERROR, _("%s: error calling " + "getpidcon(): %s"), __func__, + strerror(errno)); + return -1; + } + + if (strlen((char *) ctx) >= VIR_SECLABEL_LABEL_BUFLEN) { + virSecLabelReportError(conn, VIR_ERR_ERROR, + _("%s: security label exceeds " + "maximum length: %d"), __func__, + VIR_SECLABEL_LABEL_BUFLEN - 1); + return -1; + } + + strcpy(sec->label, (char *) ctx); + free(ctx); + + p = virSecLabelDriverGetModel(drv); + if (strlen(p) >= VIR_SECLABEL_MODEL_BUFLEN) { + virSecLabelReportError(conn, VIR_ERR_ERROR, + _("%s: security model exceeds " + "maximum length: %d"), __func__, + VIR_SECLABEL_MODEL_BUFLEN - 1); + return -1; + } + strcpy(sec->model, p); + + p = virSecLabelDriverGetPolicyType(drv); + if (strlen(p) >= VIR_SECLABEL_POLICYTYPE_BUFLEN) { + virSecLabelReportError(conn, VIR_ERR_ERROR, + _("%s: security polictype exceeds " + "maximum length: %d"), __func__, + VIR_SECLABEL_POLICYTYPE_BUFLEN - 1); + return -1; + } + strcpy(sec->policytype, p); + + sec->enforcing = virSecLabelDriverGetEnforcing(drv); + + return 0; +} + +static int +SELinuxSecLabelDomainSetLabel(virConnectPtr conn, virSecLabelDriverPtr drv, + const virDomainSecLabelDefPtr secdef) +{ + /* TODO: verify DOI */ + + if (drv) { /* Shut up gcc for now... */ }; + + if (setexeccon(secdef->label) == -1) { + virSecLabelReportError(conn, VIR_ERR_ERROR, + _("%s: unable to set security context " + "'\%s\': %s"), __func__, secdef->label, + strerror(errno)); + return -1; + } + return 0; +} + +virSecLabelDriver virSELinuxSecLabelDriver = { + .name = "selinux", + .probe = SELinuxSecLabelDriverProbe, + .open = SELinuxSecLabelDriverOpen, + .domainGetLabel = SELinuxSecLabelDomainGetLabel, + .domainSetLabel = SELinuxSecLabelDomainSetLabel, +}; diff --git a/src/seclabel_selinux.h b/src/seclabel_selinux.h new file mode 100644 index 0000000..20e575d --- /dev/null +++ b/src/seclabel_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 + * + */ +#ifndef __VIR_SECLABEL_SELINUX_H__ +#define __VIR_SECLABEL_SELINUX_H__ + +extern virSecLabelDriver virSELinuxSecLabelDriver; + +#endif /* __VIR_SECLABEL_SELINUX_H__ */ diff --git a/src/storage_backend.c b/src/storage_backend.c index de4efa7..df021d7 100644 --- a/src/storage_backend.c +++ b/src/storage_backend.c @@ -316,6 +316,7 @@ virStorageBackendUpdateVolInfoFD(virConnectPtr conn, VIR_FREE(vol->target.perms.label); #if HAVE_SELINUX +/* XXX: make this a security driver call */ if (fgetfilecon(fd, &filecon) == -1) { if (errno != ENODATA && errno != ENOTSUP) { virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, diff --git a/src/test.c b/src/test.c index aab74e4..d6cfd3c 100644 --- a/src/test.c +++ b/src/test.c @@ -1530,6 +1530,7 @@ static virDriver testDriver = { NULL, /* domainPinVcpu */ NULL, /* domainGetVcpus */ NULL, /* domainGetMaxVcpus */ + NULL, /* domainGetSecLabel */ testDomainDumpXML, /* domainDumpXML */ testListDefinedDomains, /* listDefinedDomains */ testNumOfDefinedDomains, /* numOfDefinedDomains */ diff --git a/src/virsh.c b/src/virsh.c index 89aa4fa..4c1208c 100644 --- a/src/virsh.c +++ b/src/virsh.c @@ -971,6 +971,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) { @@ -1542,6 +1543,7 @@ cmdDominfo(vshControl *ctl, const vshCmd *cmd) { virDomainInfo info; virDomainPtr dom; + virDomainSecLabel seclabel; int ret = TRUE, autostart; unsigned int id; char *str, uuid[VIR_UUID_STRING_BUFLEN]; @@ -1600,6 +1602,20 @@ cmdDominfo(vshControl *ctl, const vshCmd *cmd) autostart ? _("enable") : _("disable") ); } + memset(&seclabel, 0, sizeof seclabel); + + if (virDomainGetSecLabel(dom, &seclabel) == -1) + ret = FALSE; + else { + /* + * Security labels are only valid for active + * domains. + */ + if (seclabel.model[0] != '\0') + vshPrint(ctl, "%-15s %s (%s/%s/%s)\n", _("Security label:"), + seclabel.label, seclabel.model, seclabel.policytype, + seclabel.enforcing ? "enforcing" : "permissive"); + } virDomainFree(dom); return ret; } diff --git a/src/virterror.c b/src/virterror.c index 21c7339..3b4ce2c 100644 --- a/src/virterror.c +++ b/src/virterror.c @@ -310,6 +310,9 @@ virDefaultErrorFunc(virErrorPtr err) case VIR_FROM_DOMAIN: dom = "Domain Config "; break; + case VIR_FROM_SECLABEL: + dom = "Security Labeling "; + break; } if ((err->dom != NULL) && (err->code != VIR_ERR_INVALID_DOMAIN)) { @@ -719,6 +722,12 @@ __virErrorMsg(virErrorNumber error, const char *info) else errmsg = _("Failed to find a storage driver: %s"); break; + case VIR_ERR_NO_SECLABEL_MODEL: + if (info == NULL) + errmsg = _("Security labeling model not found"); + else + errmsg = _("Security labeling model not found: %s"); + break; } return (errmsg); } diff --git a/tests/daemon-conf b/tests/daemon-conf index db1f0d3..5c09315 100755 --- a/tests/daemon-conf +++ b/tests/daemon-conf @@ -41,6 +41,9 @@ while :; do # Filter out this diagnostic. sed '/^Cannot set group when not running as root$/d' err > k && mv k err + # Filter out this diagnostic, too. + sed '/^Initialized security labeling 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