From 0007237301586aa90f58a7cc8d7cb29a16b00470 Mon Sep 17 00:00:00 2001 From: Laine Stump Date: Mon, 19 Mar 2012 12:49:17 -0400 Subject: [PATCH] conf: forbid use of multicast mac addresses A few times libvirt users manually setting mac addresses have complained of a networking failure that ends up being due to a multicast mac address being used for a guest interface. This patch prevents that by logging an error and failing if a multicast mac address is encountered in each of the three following cases: 1) domain xml mac address. 2) network xml bridge mac address. 3) network xml dhcp/host mac address. There are several other places where a mac address can be input that aren't controlled in this manner because failure to do so has no consequences (e.g., if the address will be used to search through existing interfaces for a match). The RNG has been updated to add multiMacAddr and uniMacAddr along with the existing macAddr, and macAddr was switched to uniMacAddr where appropriate. --- docs/schemas/basictypes.rng | 17 ++++++++++++++++- docs/schemas/domaincommon.rng | 6 +++--- docs/schemas/network.rng | 4 ++-- src/conf/domain_conf.c | 8 +++++++- src/conf/network_conf.c | 33 ++++++++++++++++++++++++--------- src/libvirt_private.syms | 2 ++ src/util/virmacaddr.c | 13 +++++++++++++ src/util/virmacaddr.h | 3 ++- 8 files changed, 69 insertions(+), 17 deletions(-) diff --git a/docs/schemas/basictypes.rng b/docs/schemas/basictypes.rng index 7d7911d0a8..9dbda4a6cc 100644 --- a/docs/schemas/basictypes.rng +++ b/docs/schemas/basictypes.rng @@ -55,9 +55,24 @@ + + + + + + + + [a-fA-F0-9][02468aAcCeE](:[a-fA-F0-9]{2}){5} + + + + + [a-fA-F0-9][13579bBdDfF](:[a-fA-F0-9]{2}){5} + + - ([a-fA-F0-9]{2}:){5}[a-fA-F0-9]{2} + [a-fA-F0-9]{2}(:[a-fA-F0-9]{2}){5} diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index 5b3e5fa548..f62969193c 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -1391,7 +1391,7 @@ - + @@ -1417,7 +1417,7 @@ - + @@ -1498,7 +1498,7 @@ - + diff --git a/docs/schemas/network.rng b/docs/schemas/network.rng index 6e1002f1b5..2ae879ec47 100644 --- a/docs/schemas/network.rng +++ b/docs/schemas/network.rng @@ -57,7 +57,7 @@ - + @@ -218,7 +218,7 @@ - + diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index e6d0f4be01..d5def1c816 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -4416,11 +4416,17 @@ virDomainNetDefParseXML(virCapsPtr caps, if (macaddr) { if (virMacAddrParse((const char *)macaddr, def->mac) < 0) { - virDomainReportError(VIR_ERR_INTERNAL_ERROR, + virDomainReportError(VIR_ERR_XML_ERROR, _("unable to parse mac address '%s'"), (const char *)macaddr); goto error; } + if (virMacAddrIsMulticast(def->mac)) { + virDomainReportError(VIR_ERR_XML_ERROR, + _("expected unicast mac address, found multicast '%s'"), + (const char *)macaddr); + goto error; + } } else { virCapabilitiesGenerateMac(caps, def->mac); } diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c index 4341f11073..17dc0d3539 100644 --- a/src/conf/network_conf.c +++ b/src/conf/network_conf.c @@ -419,22 +419,30 @@ virNetworkDHCPRangeDefParseXML(const char *networkName, def->nranges++; } else if (cur->type == XML_ELEMENT_NODE && xmlStrEqual(cur->name, BAD_CAST "host")) { - char *mac, *name, *ip; + char *mac = NULL, *name = NULL, *ip; unsigned char addr[6]; virSocketAddr inaddr; mac = virXMLPropString(cur, "mac"); - if ((mac != NULL) && - (virMacAddrParse(mac, &addr[0]) != 0)) { - virNetworkReportError(VIR_ERR_INTERNAL_ERROR, - _("Cannot parse MAC address '%s' in network '%s'"), - mac, networkName); - VIR_FREE(mac); - return -1; + if (mac != NULL) { + if (virMacAddrParse(mac, &addr[0]) < 0) { + virNetworkReportError(VIR_ERR_XML_ERROR, + _("Cannot parse MAC address '%s' in network '%s'"), + mac, networkName); + VIR_FREE(mac); + return -1; + } + if (virMacAddrIsMulticast(addr)) { + virNetworkReportError(VIR_ERR_XML_ERROR, + _("expected unicast mac address, found multicast '%s' in network '%s'"), + (const char *)mac, networkName); + VIR_FREE(mac); + return -1; + } } name = virXMLPropString(cur, "name"); if ((name != NULL) && (!c_isalpha(name[0]))) { - virNetworkReportError(VIR_ERR_INTERNAL_ERROR, + virNetworkReportError(VIR_ERR_XML_ERROR, _("Cannot use name address '%s' in network '%s'"), name, networkName); VIR_FREE(mac); @@ -991,6 +999,13 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt) VIR_FREE(tmp); goto error; } + if (virMacAddrIsMulticast(def->mac)) { + virNetworkReportError(VIR_ERR_XML_ERROR, + _("Invalid multicast bridge mac address '%s' in network '%s'"), + tmp, def->name); + VIR_FREE(tmp); + goto error; + } VIR_FREE(tmp); def->mac_specified = true; } diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index e40c80eed8..9a718b412f 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1208,6 +1208,8 @@ virKeycodeValueTranslate; virMacAddrCompare; virMacAddrFormat; virMacAddrGenerate; +virMacAddrIsMulticast; +virMacAddrIsUnicast; virMacAddrParse; diff --git a/src/util/virmacaddr.c b/src/util/virmacaddr.c index 70aef56ce1..7b403979bd 100644 --- a/src/util/virmacaddr.c +++ b/src/util/virmacaddr.c @@ -126,3 +126,16 @@ void virMacAddrGenerate(const unsigned char *prefix, addr[4] = virRandomBits(8); addr[5] = virRandomBits(8); } + +/* The low order bit of the first byte is the "multicast" bit. */ +bool +virMacAddrIsMulticast(const unsigned char *addr) +{ + return !!(addr[0] & 1); +} + +bool +virMacAddrIsUnicast(const unsigned char *addr) +{ + return !(addr[0] & 1); +} diff --git a/src/util/virmacaddr.h b/src/util/virmacaddr.h index 278f41ee0c..f8d3e0c535 100644 --- a/src/util/virmacaddr.h +++ b/src/util/virmacaddr.h @@ -37,5 +37,6 @@ void virMacAddrGenerate(const unsigned char *prefix, unsigned char *addr); int virMacAddrParse(const char* str, unsigned char *addr) ATTRIBUTE_RETURN_CHECK; - +bool virMacAddrIsUnicast(const unsigned char *addr); +bool virMacAddrIsMulticast(const unsigned char *addr); #endif /* __VIR_MACADDR_H__ */