mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-22 13:45:38 +00:00
network: use dnsmasq --bind-dynamic when available
This bug resolves CVE-2012-3411, which is described in the following bugzilla report: https://bugzilla.redhat.com/show_bug.cgi?id=833033 The following report is specifically for libvirt on Fedora: https://bugzilla.redhat.com/show_bug.cgi?id=874702 In short, a dnsmasq instance run with the intention of listening for DHCP/DNS requests only on a libvirt virtual network (which is constructed using a Linux host bridge) would also answer queries sent from outside the virtualization host. This patch takes advantage of a new dnsmasq option "--bind-dynamic", which will cause the listening socket to be setup such that it will only receive those requests that actually come in via the bridge interface. In order for this behavior to actually occur, not only must "--bind-interfaces" be replaced with "--bind-dynamic", but also all "--listen-address" options must be replaced with a single "--interface" option. Fully: --bind-interfaces --except-interface lo --listen-address x.x.x.x ... (with --listen-address possibly repeated) is replaced with: --bind-dynamic --interface virbrX Of course libvirt can't use this new option if the host's dnsmasq doesn't have it, but we still want libvirt to function (because the great majority of libvirt installations, which only have mode='nat' networks using RFC1918 private address ranges (e.g. 192.168.122.0/24), are immune to this vulnerability from anywhere beyond the local subnet of the host), so we use the new dnsmasqCaps API to check if dnsmasq supports the new option and, if not, we use the "old" option style instead. In order to assure that this permissiveness doesn't lead to a vulnerable system, we do check for non-private addresses in this case, and refuse to start the network if both a) we are using the old-style options, and b) the network has a publicly routable IP address. Hopefully this will provide the proper balance of not being disruptive to those not practically affected, and making sure that those who *are* affected get their dnsmasq upgraded. (--bind-dynamic was added to dnsmasq in upstream commit 54dd393f3938fc0c19088fbd319b95e37d81a2b0, which was included in dnsmasq-2.63)
This commit is contained in:
parent
bf402e77b6
commit
753ff83a50
@ -657,7 +657,7 @@ networkBuildDnsmasqArgv(virNetworkObjPtr network,
|
||||
* Needed to ensure dnsmasq uses same algorithm for processing
|
||||
* multiple namedriver entries in /etc/resolv.conf as GLibC.
|
||||
*/
|
||||
virCommandAddArgList(cmd, "--strict-order", "--bind-interfaces", NULL);
|
||||
virCommandAddArg(cmd, "--strict-order");
|
||||
|
||||
if (network->def->domain)
|
||||
virCommandAddArgPair(cmd, "--domain", network->def->domain);
|
||||
@ -672,9 +672,60 @@ networkBuildDnsmasqArgv(virNetworkObjPtr network,
|
||||
/* *no* conf file */
|
||||
virCommandAddArg(cmd, "--conf-file=");
|
||||
|
||||
virCommandAddArgList(cmd,
|
||||
"--except-interface", "lo",
|
||||
NULL);
|
||||
if (dnsmasqCapsGet(caps, DNSMASQ_CAPS_BIND_DYNAMIC)) {
|
||||
/* using --bind-dynamic with only --interface (no
|
||||
* --listen-address) prevents dnsmasq from responding to dns
|
||||
* queries that arrive on some interface other than our bridge
|
||||
* interface (in other words, requests originating somewhere
|
||||
* other than one of the virtual guests connected directly to
|
||||
* this network). This was added in response to CVE 2012-3411.
|
||||
*/
|
||||
virCommandAddArgList(cmd,
|
||||
"--bind-dynamic",
|
||||
"--interface", network->def->bridge,
|
||||
NULL);
|
||||
} else {
|
||||
virCommandAddArgList(cmd,
|
||||
"--bind-interfaces",
|
||||
"--except-interface", "lo",
|
||||
NULL);
|
||||
/*
|
||||
* --interface does not actually work with dnsmasq < 2.47,
|
||||
* due to DAD for ipv6 addresses on the interface.
|
||||
*
|
||||
* virCommandAddArgList(cmd, "--interface", network->def->bridge, NULL);
|
||||
*
|
||||
* So listen on all defined IPv[46] addresses
|
||||
*/
|
||||
for (ii = 0;
|
||||
(tmpipdef = virNetworkDefGetIpByIndex(network->def, AF_UNSPEC, ii));
|
||||
ii++) {
|
||||
char *ipaddr = virSocketAddrFormat(&tmpipdef->address);
|
||||
|
||||
if (!ipaddr)
|
||||
goto cleanup;
|
||||
/* also part of CVE 2012-3411 - if the host's version of
|
||||
* dnsmasq doesn't have --bind-dynamic, only allow listening on
|
||||
* private/local IP addresses (see RFC1918/RFC3484/RFC4193)
|
||||
*/
|
||||
if (!virSocketAddrIsPrivate(&tmpipdef->address)) {
|
||||
unsigned long version = dnsmasqCapsGetVersion(caps);
|
||||
|
||||
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
||||
_("Publicly routable address %s is prohibited. "
|
||||
"The version of dnsmasq on this host (%d.%d) doesn't "
|
||||
"support the --bind-dynamic option, which is required "
|
||||
"for safe operation on a publicly routable subnet "
|
||||
"(see CVE-2012-3411). You must either upgrade dnsmasq, "
|
||||
"or use a private/local subnet range for this network "
|
||||
"(as described in RFC1918/RFC3484/RFC4193)."), ipaddr,
|
||||
(int)version / 1000000, (int)(version % 1000000) / 1000);
|
||||
goto cleanup;
|
||||
}
|
||||
virCommandAddArgList(cmd, "--listen-address", ipaddr, NULL);
|
||||
VIR_FREE(ipaddr);
|
||||
}
|
||||
}
|
||||
|
||||
/* If this is an isolated network, set the default route option
|
||||
* (3) to be empty to avoid setting a default route that's
|
||||
@ -740,24 +791,6 @@ networkBuildDnsmasqArgv(virNetworkObjPtr network,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* --interface does not actually work with dnsmasq < 2.47,
|
||||
* due to DAD for ipv6 addresses on the interface.
|
||||
*
|
||||
* virCommandAddArgList(cmd, "--interface", ipdef->bridge, NULL);
|
||||
*
|
||||
* So listen on all defined IPv[46] addresses
|
||||
*/
|
||||
for (ii = 0;
|
||||
(tmpipdef = virNetworkDefGetIpByIndex(network->def, AF_UNSPEC, ii));
|
||||
ii++) {
|
||||
char *ipaddr = virSocketAddrFormat(&tmpipdef->address);
|
||||
if (!ipaddr)
|
||||
goto cleanup;
|
||||
virCommandAddArgList(cmd, "--listen-address", ipaddr, NULL);
|
||||
VIR_FREE(ipaddr);
|
||||
}
|
||||
|
||||
if (ipdef) {
|
||||
for (r = 0 ; r < ipdef->nranges ; r++) {
|
||||
char *saddr = virSocketAddrFormat(&ipdef->ranges[r].start);
|
||||
|
@ -1,7 +1,8 @@
|
||||
@DNSMASQ@ --strict-order --bind-interfaces \
|
||||
@DNSMASQ@ --strict-order \
|
||||
--local=// --domain-needed --conf-file= \
|
||||
--except-interface lo --dhcp-option=3 --no-resolv \
|
||||
--bind-interfaces --except-interface lo \
|
||||
--listen-address 192.168.152.1 \
|
||||
--dhcp-option=3 --no-resolv \
|
||||
--dhcp-range 192.168.152.2,192.168.152.254 \
|
||||
--dhcp-leasefile=/var/lib/libvirt/dnsmasq/private.leases --dhcp-lease-max=253 \
|
||||
--dhcp-no-override \
|
||||
|
@ -1,4 +1,5 @@
|
||||
@DNSMASQ@ --strict-order --bind-interfaces --domain=example.com \
|
||||
@DNSMASQ@ --strict-order --domain=example.com \
|
||||
--local=/example.com/ --domain-needed \
|
||||
--conf-file= --except-interface lo --listen-address 192.168.122.1 \
|
||||
--conf-file= \
|
||||
--bind-dynamic --interface virbr0 \
|
||||
--expand-hosts --addn-hosts=/var/lib/libvirt/dnsmasq/default.addnhosts\
|
||||
|
@ -1,14 +1,13 @@
|
||||
@DNSMASQ@ \
|
||||
--strict-order \
|
||||
--bind-interfaces \
|
||||
--local=// --domain-needed --conf-file= \
|
||||
--except-interface lo \
|
||||
--srv-host=name.tcp.,,,, \
|
||||
--bind-interfaces --except-interface lo \
|
||||
--listen-address 192.168.122.1 \
|
||||
--listen-address 192.168.123.1 \
|
||||
--listen-address 2001:db8:ac10:fe01::1 \
|
||||
--listen-address 2001:db8:ac10:fd01::1 \
|
||||
--listen-address fc00:db8:ac10:fe01::1 \
|
||||
--listen-address fc00:db8:ac10:fd01::1 \
|
||||
--listen-address 10.24.10.1 \
|
||||
--srv-host=name.tcp.,,,, \
|
||||
--dhcp-range 192.168.122.2,192.168.122.254 \
|
||||
--dhcp-leasefile=/var/lib/libvirt/dnsmasq/default.leases \
|
||||
--dhcp-lease-max=253 \
|
||||
|
@ -17,9 +17,9 @@
|
||||
</ip>
|
||||
<ip family='ipv4' address='192.168.123.1' netmask='255.255.255.0'>
|
||||
</ip>
|
||||
<ip family='ipv6' address='2001:db8:ac10:fe01::1' prefix='64'>
|
||||
<ip family='ipv6' address='fc00:db8:ac10:fe01::1' prefix='64'>
|
||||
</ip>
|
||||
<ip family='ipv6' address='2001:db8:ac10:fd01::1' prefix='64'>
|
||||
<ip family='ipv6' address='fc00:db8:ac10:fd01::1' prefix='64'>
|
||||
</ip>
|
||||
<ip family='ipv4' address='10.24.10.1'>
|
||||
</ip>
|
||||
|
@ -1,14 +1,8 @@
|
||||
@DNSMASQ@ \
|
||||
--strict-order \
|
||||
--bind-interfaces \
|
||||
--local=// --domain-needed --conf-file= \
|
||||
--except-interface lo \
|
||||
--bind-dynamic --interface virbr0 \
|
||||
--srv-host=name.tcp.test-domain-name,.,1024,10,10 \
|
||||
--listen-address 192.168.122.1 \
|
||||
--listen-address 192.168.123.1 \
|
||||
--listen-address 2001:db8:ac10:fe01::1 \
|
||||
--listen-address 2001:db8:ac10:fd01::1 \
|
||||
--listen-address 10.24.10.1 \
|
||||
--dhcp-range 192.168.122.2,192.168.122.254 \
|
||||
--dhcp-leasefile=/var/lib/libvirt/dnsmasq/default.leases \
|
||||
--dhcp-lease-max=253 \
|
||||
|
@ -1,9 +1,7 @@
|
||||
@DNSMASQ@ --strict-order --bind-interfaces \
|
||||
@DNSMASQ@ --strict-order \
|
||||
--local=// --domain-needed --conf-file= \
|
||||
--except-interface lo '--txt-record=example,example value' \
|
||||
--listen-address 192.168.122.1 --listen-address 192.168.123.1 \
|
||||
--listen-address 2001:db8:ac10:fe01::1 \
|
||||
--listen-address 2001:db8:ac10:fd01::1 --listen-address 10.24.10.1 \
|
||||
--bind-dynamic --interface virbr0 \
|
||||
'--txt-record=example,example value' \
|
||||
--dhcp-range 192.168.122.2,192.168.122.254 \
|
||||
--dhcp-leasefile=/var/lib/libvirt/dnsmasq/default.leases \
|
||||
--dhcp-lease-max=253 --dhcp-no-override \
|
||||
|
@ -1,8 +1,6 @@
|
||||
@DNSMASQ@ --strict-order --bind-interfaces \
|
||||
@DNSMASQ@ --strict-order \
|
||||
--local=// --domain-needed --conf-file= \
|
||||
--except-interface lo --listen-address 192.168.122.1 \
|
||||
--listen-address 192.168.123.1 --listen-address 2001:db8:ac10:fe01::1 \
|
||||
--listen-address 2001:db8:ac10:fd01::1 --listen-address 10.24.10.1 \
|
||||
--bind-dynamic --interface virbr0 \
|
||||
--dhcp-range 192.168.122.2,192.168.122.254 \
|
||||
--dhcp-leasefile=/var/lib/libvirt/dnsmasq/default.leases \
|
||||
--dhcp-lease-max=253 --dhcp-no-override \
|
||||
|
@ -1,6 +1,6 @@
|
||||
@DNSMASQ@ --strict-order --bind-interfaces --domain=example.com \
|
||||
@DNSMASQ@ --strict-order --domain=example.com \
|
||||
--local=/example.com/ --domain-needed --conf-file= \
|
||||
--except-interface lo --listen-address 192.168.122.1 \
|
||||
--bind-interfaces --except-interface lo --listen-address 192.168.122.1 \
|
||||
--dhcp-range 192.168.122.2,192.168.122.254 \
|
||||
--dhcp-leasefile=/var/lib/libvirt/dnsmasq/netboot.leases \
|
||||
--dhcp-lease-max=253 --dhcp-no-override --expand-hosts \
|
||||
|
@ -1,6 +1,7 @@
|
||||
@DNSMASQ@ --strict-order --bind-interfaces --domain=example.com \
|
||||
@DNSMASQ@ --strict-order --domain=example.com \
|
||||
--local=/example.com/ --domain-needed --conf-file= \
|
||||
--except-interface lo --listen-address 192.168.122.1 \
|
||||
--bind-interfaces --except-interface lo \
|
||||
--listen-address 192.168.122.1 \
|
||||
--dhcp-range 192.168.122.2,192.168.122.254 \
|
||||
--dhcp-leasefile=/var/lib/libvirt/dnsmasq/netboot.leases \
|
||||
--dhcp-lease-max=253 --dhcp-no-override --expand-hosts \
|
||||
|
@ -1,4 +1,4 @@
|
||||
@DNSMASQ@ --strict-order --bind-interfaces \
|
||||
@DNSMASQ@ --strict-order \
|
||||
--local=// --domain-needed --conf-file= \
|
||||
--except-interface lo --listen-address 192.168.122.1 \
|
||||
--bind-dynamic --interface virbr1 \
|
||||
--addn-hosts=/var/lib/libvirt/dnsmasq/local.addnhosts\
|
||||
|
Loading…
Reference in New Issue
Block a user