
On 15/08/13 17:36, Daniel P. Berrange wrote:
On Thu, Aug 15, 2013 at 02:24:27AM +0530, nehaljwani wrote:
Implement RPC calls for virDomainInterfacesAddresses
daemon/remote.c * Define remoteSerializeDomainInterfacePtr, remoteDispatchDomainInterfacesAddresses
src/remote/remote_driver.c * Define remoteDomainInterfacesAddresses
src/remote/remote_protocol.x * New RPC procedure: REMOTE_PROC_DOMAIN_INTERFACES_ADDRESSES * Define structs remote_domain_ip_addr, remote_domain_interface, remote_domain_interfaces_addresses_args, remote_domain_interfaces_addresses_ret
src/remote_protocol-structs * New structs added
--- daemon/remote.c | 122 +++++++++++++++++++++++++++++++++++++++++++ src/remote/remote_driver.c | 88 +++++++++++++++++++++++++++++++ src/remote/remote_protocol.x | 30 ++++++++++- src/remote_protocol-structs | 24 +++++++++ 4 files changed, 263 insertions(+), 1 deletion(-)
diff --git a/daemon/remote.c b/daemon/remote.c index 03d5557..9d8651c 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -5025,7 +5025,129 @@ cleanup: return rv; }
+static int +remoteSerializeDomainInterfacePtr(virDomainInterfacePtr ifaces, + unsigned int ifaces_count, + remote_domain_interfaces_addresses_ret *ret) +{ + size_t i, j; + + if (VIR_ALLOC_N(ret->ifaces.ifaces_val, ifaces_count) < 0) + return -1; You *must* check upper bound of ifaces_count before allocating memory - this value is untrusted data.
+ + ret->ifaces.ifaces_len = ifaces_count; + + for (i = 0; i < ifaces_count; i++) { + virDomainInterfacePtr iface = &(ifaces[i]); + remote_domain_interface *iface_ret = &(ret->ifaces.ifaces_val[i]); + + if ((VIR_STRDUP(iface_ret->name, iface->name)) < 0) + goto no_memory; + + if (iface->hwaddr) { + char **hwaddr_p = NULL; + if (VIR_ALLOC(hwaddr_p) < 0) + goto no_memory; + if (VIR_STRDUP(*hwaddr_p, iface->hwaddr) < 0) { + VIR_FREE(hwaddr_p); + goto no_memory; + } + + iface_ret->hwaddr = hwaddr_p; + } + + if (VIR_ALLOC_N(iface_ret->ip_addrs.ip_addrs_val, + iface->ip_addrs_count) < 0) + goto no_memory; Again ip_addrs_count is untrusted data so must have an upper bound checked.
+ + iface_ret->ip_addrs.ip_addrs_len = iface->ip_addrs_count; + + for (j = 0; j < iface->ip_addrs_count; j++) { + virDomainIPAddressPtr ip_addr = &(iface->ip_addrs[j]); + remote_domain_ip_addr *ip_addr_ret = + &(iface_ret->ip_addrs.ip_addrs_val[j]); + + if (VIR_STRDUP(ip_addr_ret->addr, ip_addr->addr) < 0) + goto no_memory; + + ip_addr_ret->prefix = ip_addr->prefix; + ip_addr_ret->type = ip_addr->type; + } + } + + return 0; + +no_memory: + if (ret->ifaces.ifaces_val) { + for (i = 0; i < ifaces_count; i++) { + remote_domain_interface *iface_ret = &(ret->ifaces.ifaces_val[i]); + VIR_FREE(iface_ret->name); + VIR_FREE(iface_ret->hwaddr); + for (j = 0; j < iface_ret->ip_addrs.ip_addrs_len; j++) { + remote_domain_ip_addr *ip_addr = + &(iface_ret->ip_addrs.ip_addrs_val[j]); + VIR_FREE(ip_addr->addr); + } + VIR_FREE(iface_ret); + } + VIR_FREE(ret->ifaces.ifaces_val); + }
+ return -1; +} + +static int +remoteDispatchDomainInterfacesAddresses( + virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessagePtr msg ATTRIBUTE_UNUSED, + virNetMessageErrorPtr rerr, + remote_domain_interfaces_addresses_args *args, + remote_domain_interfaces_addresses_ret *ret) +{ + int rv = -1; + virDomainPtr dom = NULL; + virDomainInterfacePtr ifaces = NULL; + unsigned int ifaces_count = 0; + struct daemonClientPrivate *priv = + virNetServerClientGetPrivateData(client); + + if (!priv->conn) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open")); + goto cleanup; + } + + if (!(dom = get_nonnull_domain(priv->conn, args->dom))) + goto cleanup; + + if (virDomainInterfacesAddresses(dom, &ifaces, + &ifaces_count, args->flags) < 0) + goto cleanup; + + if (remoteSerializeDomainInterfacePtr(ifaces, ifaces_count, ret) < 0) + goto cleanup; + + rv = 0; + +cleanup: + if (rv < 0) + virNetMessageSaveError(rerr); + if (dom) + virDomainFree(dom); + if (ifaces) { + size_t i, j; + + for (i = 0; i < ifaces_count; i++) { + VIR_FREE(ifaces[i].name); + VIR_FREE(ifaces[i].hwaddr); + for (j = 0; j < ifaces[i].ip_addrs_count; j++) + VIR_FREE(ifaces[i].ip_addrs[j].addr); + VIR_FREE(ifaces[i].ip_addrs); + } + VIR_FREE(ifaces); + } + return rv; +}
/*----- Helpers. -----*/
+cleanup: + if (rv < 0) { + for (i = 0; i < *ifaces_count; i++) { + VIR_FREE((*ifaces)[i].name); + VIR_FREE((*ifaces)[i].hwaddr); + for (j = 0; j < (*ifaces)[i].ip_addrs_count; j++) + VIR_FREE((*ifaces)[i].ip_addrs[j].addr); + VIR_FREE((*ifaces)[i].ip_addrs); + } + VIR_FREE(*ifaces); This horrible code is repeated soo many times - just reinforces my point on the previous patch about providing a function to hide this.
+ } + xdr_free((xdrproc_t)xdr_remote_domain_interfaces_addresses_ret, + (char *) &ret); +done: + remoteDriverUnlock(priv); + return rv; +} + static void remoteDomainEventQueue(struct private_data *priv, virDomainEventPtr event) { @@ -6811,6 +6898,7 @@ static virDriver remote_driver = { .domainMigratePerform3Params = remoteDomainMigratePerform3Params, /* 1.1.0 */ .domainMigrateFinish3Params = remoteDomainMigrateFinish3Params, /* 1.1.0 */ .domainMigrateConfirm3Params = remoteDomainMigrateConfirm3Params, /* 1.1.0 */ + .domainInterfacesAddresses = remoteDomainInterfacesAddresses, /* 1.1.2 */ };
static virNetworkDriver network_driver = { diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index 7cfebdf..06929e7 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -2837,6 +2837,27 @@ struct remote_domain_event_device_removed_msg { remote_nonnull_string devAlias; };
+struct remote_domain_ip_addr { + int type; + remote_nonnull_string addr; + int prefix; +}; + +struct remote_domain_interface { + remote_nonnull_string name; + remote_string hwaddr; + remote_domain_ip_addr ip_addrs<>; Use of <> *NOT* allowed - this is a security flaw allowing the client to trigger DOS on libvirtd allocating memory. Follow the examples of other APis which set an explicit limit.
In that case, we have bug on APIs like listAllDomains too, as they use variable-length array too.