Thist patch updates libvirt's API to allow applications to inspect the full list of security labels of a domain. --- daemon/remote.c | 62 ++++++++++++++++++++++++++++++++++++ include/libvirt/libvirt.h.in | 2 + python/generator.py | 1 + src/driver.h | 4 ++ src/libvirt.c | 47 +++++++++++++++++++++++++++ src/libvirt_public.syms | 7 ++++ src/qemu/qemu_driver.c | 71 ++++++++++++++++++++++++++++++++++++++++++ src/remote/remote_driver.c | 46 +++++++++++++++++++++++++++ src/remote/remote_protocol.x | 18 +++++++++- src/remote_protocol-structs | 1 + 10 files changed, 257 insertions(+), 2 deletions(-) diff --git a/daemon/remote.c b/daemon/remote.c index 9334221..aef6cc1 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -1424,6 +1424,68 @@ cleanup: } static int +remoteDispatchDomainGetSecurityLabelList(virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client ATTRIBUTE_UNUSED, + virNetMessagePtr msg ATTRIBUTE_UNUSED, + virNetMessageErrorPtr rerr, + remote_domain_get_security_label_list_args *args, + remote_domain_get_security_label_list_ret *ret) +{ + virDomainPtr dom = NULL; + virSecurityLabelPtr seclabels = NULL; + int i, len, rv = -1; + struct daemonClientPrivate *priv = + virNetServerClientGetPrivateData(client); + + if (!priv->conn) { + virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open")); + goto cleanup; + } + + if (!(dom = get_nonnull_domain(priv->conn, args->dom))) + goto cleanup; + + if ((len = virDomainGetSecurityLabelList(dom, &seclabels)) < 0) { + ret->ret = len; + ret->labels.labels_len = 0; + ret->labels.labels_val = NULL; + goto done; + } + + if (VIR_ALLOC_N(ret->labels.labels_val, len) < 0) { + virReportOOMError(); + goto cleanup; + } + + for (i = 0; i < len; i++) { + size_t label_len = strlen(seclabels[i].label) + 1; + remote_domain_get_security_label_ret *cur = &ret->labels.labels_val[i]; + if (VIR_ALLOC_N(cur->label.label_val, label_len) < 0) { + virReportOOMError(); + goto cleanup; + } + if (virStrcpy(cur->label.label_val, seclabels[i].label, label_len) == NULL) { + virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("failed to copy security label")); + goto cleanup; + } + cur->label.label_len = label_len; + cur->enforcing = seclabels[i].enforcing; + } + ret->labels.labels_len = ret->ret = len; + +done: + rv = 0; + +cleanup: + if (rv < 0) + virNetMessageSaveError(rerr); + if (dom) + virDomainFree(dom); + VIR_FREE(seclabels); + return rv; +} + +static int remoteDispatchNodeGetSecurityModel(virNetServerPtr server ATTRIBUTE_UNUSED, virNetServerClientPtr client ATTRIBUTE_UNUSED, virNetMessagePtr msg ATTRIBUTE_UNUSED, diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index e34438c..eb48b99 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -1540,6 +1540,8 @@ int virDomainSetMemoryFlags (virDomainPtr domain, int virDomainGetMaxVcpus (virDomainPtr domain); int virDomainGetSecurityLabel (virDomainPtr domain, virSecurityLabelPtr seclabel); +int virDomainGetSecurityLabelList (virDomainPtr domain, + virSecurityLabelPtr* seclabels); typedef enum { VIR_DOMAIN_METADATA_DESCRIPTION = 0, /* Operate on <description> */ diff --git a/python/generator.py b/python/generator.py index 2dada6e..f3c8912 100755 --- a/python/generator.py +++ b/python/generator.py @@ -446,6 +446,7 @@ skip_function = ( 'virConnectOpenAuth', # Python C code is manually written 'virDefaultErrorFunc', # Python virErrorFuncHandler impl calls this from C 'virDomainGetSecurityLabel', # Needs investigation... + 'virDomainGetSecurityLabelList', # Needs investigation... 'virNodeGetSecurityModel', # Needs investigation... 'virConnectDomainEventRegister', # overridden in virConnect.py 'virConnectDomainEventDeregister', # overridden in virConnect.py diff --git a/src/driver.h b/src/driver.h index b3c1740..fd6a1fe 100644 --- a/src/driver.h +++ b/src/driver.h @@ -314,6 +314,9 @@ typedef int (*virDrvDomainGetSecurityLabel) (virDomainPtr domain, virSecurityLabelPtr seclabel); typedef int + (*virDrvDomainGetSecurityLabelList) (virDomainPtr domain, + virSecurityLabelPtr* seclabels); +typedef int (*virDrvNodeGetSecurityModel) (virConnectPtr conn, virSecurityModelPtr secmodel); typedef int @@ -934,6 +937,7 @@ struct _virDriver { virDrvDomainGetVcpus domainGetVcpus; virDrvDomainGetMaxVcpus domainGetMaxVcpus; virDrvDomainGetSecurityLabel domainGetSecurityLabel; + virDrvDomainGetSecurityLabelList domainGetSecurityLabelList; virDrvNodeGetSecurityModel nodeGetSecurityModel; virDrvDomainGetXMLDesc domainGetXMLDesc; virDrvConnectDomainXMLFromNative domainXMLFromNative; diff --git a/src/libvirt.c b/src/libvirt.c index df78e8a..912fd10 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -9008,6 +9008,53 @@ error: } /** + * virDomainGetSecurityLabelList: + * @domain: a domain object + * @seclabels: will be auto-allocated and filled with domains' security labels. + * Caller must free memory on return. + * + * Extract the security labels of an active domain. The 'label' field + * in the @seclabels argument will be initialized to the empty + * string if the domain is not running under a security model. + * + * Returns 0 in case of success, -1 in case of failure + */ +int +virDomainGetSecurityLabelList(virDomainPtr domain, + virSecurityLabelPtr* seclabels) +{ + virConnectPtr conn; + + VIR_DOMAIN_DEBUG(domain, "seclabels=%p", seclabels); + + if (!VIR_IS_CONNECTED_DOMAIN(domain)) { + virLibDomainError(VIR_ERR_INVALID_DOMAIN, __FUNCTION__); + virDispatchError(NULL); + return -1; + } + + if (seclabels == NULL) { + virLibDomainError(VIR_ERR_INVALID_ARG, __FUNCTION__); + goto error; + } + + conn = domain->conn; + + if (conn->driver->domainGetSecurityLabelList) { + int ret; + ret = conn->driver->domainGetSecurityLabelList(domain, seclabels); + if (ret < 0) + goto error; + return ret; + } + + virLibConnError(VIR_ERR_NO_SUPPORT, __FUNCTION__); + +error: + virDispatchError(domain->conn); + return -1; +} +/** * virDomainSetMetadata: * @domain: a domain object * @type: type of description, from virDomainMetadataType diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index 2913a81..21b83e7 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -542,6 +542,13 @@ LIBVIRT_0.9.13 { virDomainSnapshotIsCurrent; virDomainSnapshotListAllChildren; virDomainSnapshotRef; + virDomainGetSecurityLabelList; } LIBVIRT_0.9.11; +LIBVIRT_0.9.14 { + global: + virDomainGetSecurityLabelList; +} LIBVIRT_0.9.13; + + # .... define new API here using predicted next version number .... diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index f01566b..06a4e44 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -4091,6 +4091,76 @@ cleanup: return ret; } +static int qemudDomainGetSecurityLabelList(virDomainPtr dom, + virSecurityLabelPtr* seclabels) +{ + struct qemud_driver *driver = (struct qemud_driver *)dom->conn->privateData; + virDomainObjPtr vm; + int i, ret = -1; + + qemuDriverLock(driver); + vm = virDomainFindByUUID(&driver->domains, dom->uuid); + + if (!vm) { + char uuidstr[VIR_UUID_STRING_BUFLEN]; + virUUIDFormat(dom->uuid, uuidstr); + qemuReportError(VIR_ERR_NO_DOMAIN, + _("no domain with matching uuid '%s'"), uuidstr); + goto cleanup; + } + + if (!virDomainVirtTypeToString(vm->def->virtType)) { + qemuReportError(VIR_ERR_INTERNAL_ERROR, + _("unknown virt type in domain definition '%d'"), + vm->def->virtType); + goto cleanup; + } + + /* + * Check the comment in qemudDomainGetSecurityLabel function. + */ + if (!virDomainObjIsActive(vm)) { + /* No seclabels */ + *seclabels = NULL; + ret = 0; + } else { + int len = 0; + virSecurityManagerPtr* mgrs = virSecurityManagerGetNested( + driver->securityManager); + if (!mgrs) + goto cleanup; + + /* Allocate seclabels array */ + for (i = 0; mgrs[i]; i++) + len++; + + if (VIR_ALLOC_N((*seclabels), len) < 0) { + virReportOOMError(); + goto cleanup; + } + memset(*seclabels, 0, sizeof(**seclabels) * len); + + /* Fill the array */ + for (i = 0; i < len; i++) { + if (virSecurityManagerGetProcessLabel(mgrs[i], vm->def, vm->pid, + &(*seclabels)[i]) < 0) { + qemuReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("Failed to get security label")); + VIR_FREE(mgrs); + VIR_FREE(*seclabels); + goto cleanup; + } + } + ret = len; + VIR_FREE(mgrs); + } + +cleanup: + if (vm) + virDomainObjUnlock(vm); + qemuDriverUnlock(driver); + return ret; +} static int qemudNodeGetSecurityModel(virConnectPtr conn, virSecurityModelPtr secmodel) { @@ -13296,6 +13366,7 @@ static virDriver qemuDriver = { .domainGetVcpus = qemudDomainGetVcpus, /* 0.4.4 */ .domainGetMaxVcpus = qemudDomainGetMaxVcpus, /* 0.4.4 */ .domainGetSecurityLabel = qemudDomainGetSecurityLabel, /* 0.6.1 */ + .domainGetSecurityLabelList = qemudDomainGetSecurityLabelList, /* ? */ .nodeGetSecurityModel = qemudNodeGetSecurityModel, /* 0.6.1 */ .domainGetXMLDesc = qemuDomainGetXMLDesc, /* 0.2.0 */ .domainXMLFromNative = qemuDomainXMLFromNative, /* 0.6.4 */ diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index 3314f80..3c08ae9 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -1929,6 +1929,51 @@ done: } static int +remoteDomainGetSecurityLabelList (virDomainPtr domain, virSecurityLabelPtr* seclabels) +{ + remote_domain_get_security_label_list_args args; + remote_domain_get_security_label_list_ret ret; + struct private_data *priv = domain->conn->privateData; + int i, rv = -1; + + remoteDriverLock(priv); + + make_nonnull_domain (&args.dom, domain); + memset(&ret, 0, sizeof(ret)); + + if (call (domain->conn, priv, 0, REMOTE_PROC_DOMAIN_GET_SECURITY_LABEL_LIST, + (xdrproc_t) xdr_remote_domain_get_security_label_list_args, (char *)&args, + (xdrproc_t) xdr_remote_domain_get_security_label_list_ret, (char *)&ret) == -1) { + goto done; + } + + if (VIR_ALLOC_N(*seclabels, ret.labels.labels_len) < 0) + goto cleanup; + + for (i = 0; i < ret.labels.labels_len; i++) { + remote_domain_get_security_label_ret *cur = &ret.labels.labels_val[i]; + if (cur->label.label_val != NULL) { + if (strlen(cur->label.label_val) >= sizeof((*seclabels)->label)) { + remoteError(VIR_ERR_RPC, _("security label exceeds maximum: %zd"), + sizeof((*seclabels)->label) - 1); + VIR_FREE(*seclabels); + goto cleanup; + } + strcpy((*seclabels)[i].label, cur->label.label_val); + (*seclabels)[i].enforcing = cur->enforcing; + } + } + rv = ret.ret; + +cleanup: + xdr_free((xdrproc_t) xdr_remote_domain_get_security_label_list_ret, (char *)&ret); + +done: + remoteDriverUnlock(priv); + return rv; +} + +static int remoteDomainGetState(virDomainPtr domain, int *state, int *reason, @@ -5226,6 +5271,7 @@ static virDriver remote_driver = { .domainGetVcpus = remoteDomainGetVcpus, /* 0.3.0 */ .domainGetMaxVcpus = remoteDomainGetMaxVcpus, /* 0.3.0 */ .domainGetSecurityLabel = remoteDomainGetSecurityLabel, /* 0.6.1 */ + .domainGetSecurityLabelList = remoteDomainGetSecurityLabelList, /* 0.9.13 */ .nodeGetSecurityModel = remoteNodeGetSecurityModel, /* 0.6.1 */ .domainGetXMLDesc = remoteDomainGetXMLDesc, /* 0.3.0 */ .domainXMLFromNative = remoteDomainXMLFromNative, /* 0.6.4 */ diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index 8f1d9b5..27d34b1 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -169,6 +169,11 @@ const REMOTE_DOMAIN_BLOCK_PEEK_BUFFER_MAX = 1048576; const REMOTE_DOMAIN_MEMORY_PEEK_BUFFER_MAX = 1048576; /* + * Maximum length of a security label list. + */ +const REMOTE_SECURITY_LABEL_LIST_MAX=64; + +/* * Maximum length of a security model field. */ const REMOTE_SECURITY_MODEL_MAX = VIR_SECURITY_MODEL_BUFLEN; @@ -1082,6 +1087,15 @@ struct remote_domain_get_security_label_ret { int enforcing; }; +struct remote_domain_get_security_label_list_args { + remote_nonnull_domain dom; +}; + +struct remote_domain_get_security_label_list_ret { + remote_domain_get_security_label_ret labels<REMOTE_SECURITY_LABEL_LIST_MAX>; + int ret; +}; + struct remote_node_get_security_model_ret { char model<REMOTE_SECURITY_MODEL_MAX>; char doi<REMOTE_SECURITY_DOI_MAX>; @@ -2844,8 +2858,8 @@ enum remote_procedure { REMOTE_PROC_CONNECT_LIST_ALL_DOMAINS = 273, /* skipgen skipgen priority:high */ REMOTE_PROC_DOMAIN_LIST_ALL_SNAPSHOTS = 274, /* skipgen skipgen priority:high */ REMOTE_PROC_DOMAIN_SNAPSHOT_LIST_ALL_CHILDREN = 275, /* skipgen skipgen priority:high */ - REMOTE_PROC_DOMAIN_EVENT_BALLOON_CHANGE = 276 /* autogen autogen */ - + REMOTE_PROC_DOMAIN_EVENT_BALLOON_CHANGE = 276, /* autogen autogen */ + REMOTE_PROC_DOMAIN_GET_SECURITY_LABEL_LIST = 277 /* skipgen skipgen priority:high */ /* * Notice how the entries are grouped in sets of 10 ? * Nice isn't it. Please keep it this way when adding more. diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs index 511284c..fc7ba73 100644 --- a/src/remote_protocol-structs +++ b/src/remote_protocol-structs @@ -2251,4 +2251,5 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_LIST_ALL_SNAPSHOTS = 274, REMOTE_PROC_DOMAIN_SNAPSHOT_LIST_ALL_CHILDREN = 275, REMOTE_PROC_DOMAIN_EVENT_BALLOON_CHANGE = 276, + REMOTE_PROC_DOMAIN_GET_SECURITY_LABEL_list = 277, }; -- 1.7.1 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list