[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#988683: unblock: neutron/17.1.1-5 (CVE-2021-20267)



Package: release.debian.org
Severity: normal
User: release.debian.org@packages.debian.org
Usertags: unblock

Please unblock package neutron

[ Reason ]
Fixing CVE-2021-20267

[ Impact ]
If the patch isn't applied, cloud users can spoof IPv6 addrs.

[ Tests ]
Upstream has an extensive CI, doing both unit and functional
tests, so I'm confident it's safe.

[ Risks ]
This deals with OVS, so one got to understand the internals
of OVS to understand it.

[ Checklist ]
  [x] all changes are documented in the d/changelog
  [x] I reviewed all changes and I approve them
  [x] attach debdiff against the package in testing

[ Other info ]

unblock neutron/17.1.1-5

Cheers,

Thomas Goirand (zigo)
diff -Nru neutron-17.1.1/debian/changelog neutron-17.1.1/debian/changelog
--- neutron-17.1.1/debian/changelog	2021-04-21 17:26:26.000000000 +0200
+++ neutron-17.1.1/debian/changelog	2021-05-17 20:47:34.000000000 +0200
@@ -1,3 +1,11 @@
+neutron (2:17.1.1-5) unstable; urgency=high
+
+  * CVE-2021-20267: Anti-spoofing bypass using Open vSwitch. Applied upstream
+    patch: Restrict_IPv6_NA_and_DHCPv6_IP_and_MAC_source_addresses.patch
+    (Closes: #985104).
+
+ -- Thomas Goirand <zigo@debian.org>  Mon, 17 May 2021 20:47:34 +0200
+
 neutron (2:17.1.1-4) unstable; urgency=medium
 
   * Restore sanity in ml2_conf.ini / metadata_agent.ini generation (last
diff -Nru neutron-17.1.1/debian/patches/CVE-2021-20267_Restrict_IPv6_NA_and_DHCPv6_IP_and_MAC_source_addresses.patch neutron-17.1.1/debian/patches/CVE-2021-20267_Restrict_IPv6_NA_and_DHCPv6_IP_and_MAC_source_addresses.patch
--- neutron-17.1.1/debian/patches/CVE-2021-20267_Restrict_IPv6_NA_and_DHCPv6_IP_and_MAC_source_addresses.patch	1970-01-01 01:00:00.000000000 +0100
+++ neutron-17.1.1/debian/patches/CVE-2021-20267_Restrict_IPv6_NA_and_DHCPv6_IP_and_MAC_source_addresses.patch	2021-05-17 20:47:34.000000000 +0200
@@ -0,0 +1,164 @@
+Subject: CVE-2021-20267: Restrict IPv6 NA and DHCP(v6) IP and MAC source addresses
+ Neighbor Advertisments are used to inform other machines of the MAC
+ address to use to reach an IPv6. This commits prevents VMs from
+ pretending they are assigned IPv6 they should not use.
+ .
+ It also prevents sending UDP packets with spoofed IP or MAC even using
+ DHCP(v6) request ports.
+Co-authored-by: David Sinquin <david.sinquin@gandi.net>
+Author: Slawek Kaplonski <skaplons@redhat.com>
+Date: Mon, 29 Mar 2021 22:21:15 +0200
+Closes-bug: #1902917
+Change-Id: Iffb6643359562487414460f5a7e19a7fae9f935c
+Origin: https://review.opendev.org/c/openstack/neutron/+/791465
+Bug-Debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=985104
+Last-Update: 2021-05-17
+
+diff --git a/neutron/agent/firewall.py b/neutron/agent/firewall.py
+index f8f6615..62eee30 100644
+--- a/neutron/agent/firewall.py
++++ b/neutron/agent/firewall.py
+@@ -34,8 +34,11 @@
+ # List of ICMPv6 types that should be permitted (egress) by default.
+ ICMPV6_ALLOWED_EGRESS_TYPES = (n_const.ICMPV6_TYPE_MLD_QUERY,
+                                n_const.ICMPV6_TYPE_RS,
+-                               n_const.ICMPV6_TYPE_NS,
+-                               n_const.ICMPV6_TYPE_NA)
++                               n_const.ICMPV6_TYPE_NS)
++
++# List of ICMPv6 types that should be permitted depending on payload content
++# to avoid spoofing (egress) by default.
++ICMPV6_RESTRICTED_EGRESS_TYPES = (n_const.ICMPV6_TYPE_NA, )
+ 
+ 
+ def port_sec_enabled(port):
+diff --git a/neutron/agent/linux/openvswitch_firewall/firewall.py b/neutron/agent/linux/openvswitch_firewall/firewall.py
+index 5683b8a..e385a41 100644
+--- a/neutron/agent/linux/openvswitch_firewall/firewall.py
++++ b/neutron/agent/linux/openvswitch_firewall/firewall.py
+@@ -910,8 +910,7 @@
+         self._initialize_ingress(port)
+ 
+     def _initialize_egress_ipv6_icmp(self, port, allowed_pairs):
+-        # NOTE(slaweq): should we include also fe80::/64 (link-local) subnet
+-        # in the allowed pairs here?
++        allowed_pairs = allowed_pairs.union({(port.mac, port.lla_address)})
+         for mac_addr, ip_addr in allowed_pairs:
+             for icmp_type in firewall.ICMPV6_ALLOWED_EGRESS_TYPES:
+                 self._add_flow(
+@@ -927,6 +926,19 @@
+                     actions='resubmit(,%d)' % (
+                         ovs_consts.ACCEPTED_EGRESS_TRAFFIC_NORMAL_TABLE)
+                 )
++            for icmp_type in firewall.ICMPV6_RESTRICTED_EGRESS_TYPES:
++                self._add_flow(
++                    table=ovs_consts.BASE_EGRESS_TABLE,
++                    priority=95,
++                    in_port=port.ofport,
++                    reg_port=port.ofport,
++                    dl_type=lib_const.ETHERTYPE_IPV6,
++                    nw_proto=lib_const.PROTO_NUM_IPV6_ICMP,
++                    icmp_type=icmp_type,
++                    nd_target=ip_addr,
++                    actions='resubmit(,%d)' % (
++                        ovs_consts.ACCEPTED_EGRESS_TRAFFIC_NORMAL_TABLE)
++                )
+ 
+     def _initialize_egress_no_port_security(self, port_id, ovs_ports=None):
+         try:
+@@ -1001,9 +1013,9 @@
+         """Identify egress traffic and send it to egress base"""
+ 
+         # Apply mac/ip pairs for IPv4
+-        allowed_pairs = port.allowed_pairs_v4.union(
++        allowed_mac_ipv4_pairs = port.allowed_pairs_v4.union(
+             {(port.mac, ip_addr) for ip_addr in port.ipv4_addresses})
+-        for mac_addr, ip_addr in allowed_pairs:
++        for mac_addr, ip_addr in allowed_mac_ipv4_pairs:
+             self._add_flow(
+                 table=ovs_consts.BASE_EGRESS_TABLE,
+                 priority=95,
+@@ -1029,10 +1041,10 @@
+             )
+ 
+         # Apply mac/ip pairs for IPv6
+-        allowed_pairs = port.allowed_pairs_v6.union(
++        allowed_mac_ipv6_pairs = port.allowed_pairs_v6.union(
+             {(port.mac, ip_addr) for ip_addr in port.ipv6_addresses})
+-        self._initialize_egress_ipv6_icmp(port, allowed_pairs)
+-        for mac_addr, ip_addr in allowed_pairs:
++        self._initialize_egress_ipv6_icmp(port, allowed_mac_ipv6_pairs)
++        for mac_addr, ip_addr in allowed_mac_ipv6_pairs:
+             self._add_flow(
+                 table=ovs_consts.BASE_EGRESS_TABLE,
+                 priority=65,
+@@ -1047,21 +1059,30 @@
+             )
+ 
+         # DHCP discovery
+-        for dl_type, src_port, dst_port in (
+-                (lib_const.ETHERTYPE_IP, 68, 67),
+-                (lib_const.ETHERTYPE_IPV6, 546, 547)):
+-            self._add_flow(
+-                table=ovs_consts.BASE_EGRESS_TABLE,
+-                priority=80,
+-                reg_port=port.ofport,
+-                in_port=port.ofport,
+-                dl_type=dl_type,
+-                nw_proto=lib_const.PROTO_NUM_UDP,
+-                tp_src=src_port,
+-                tp_dst=dst_port,
+-                actions='resubmit(,{:d})'.format(
+-                    ovs_consts.ACCEPT_OR_INGRESS_TABLE)
+-            )
++        additional_ipv4_filters = [
++            {"dl_src": mac, "nw_src": ip}
++            for mac, ip in (*allowed_mac_ipv4_pairs,
++                            (port.mac, '0.0.0.0'),)]
++        additional_ipv6_filters = [
++            {"dl_src": mac, "ipv6_src": ip}
++            for mac, ip in allowed_mac_ipv6_pairs]
++        for dl_type, src_port, dst_port, filters_list in (
++                (lib_const.ETHERTYPE_IP, 68, 67, additional_ipv4_filters),
++                (lib_const.ETHERTYPE_IPV6, 546, 547, additional_ipv6_filters)):
++            for additional_filters in filters_list:
++                self._add_flow(
++                    table=ovs_consts.BASE_EGRESS_TABLE,
++                    priority=80,
++                    reg_port=port.ofport,
++                    in_port=port.ofport,
++                    dl_type=dl_type,
++                    **additional_filters,
++                    nw_proto=lib_const.PROTO_NUM_UDP,
++                    tp_src=src_port,
++                    tp_dst=dst_port,
++                    actions='resubmit(,{:d})'.format(
++                        ovs_consts.ACCEPT_OR_INGRESS_TABLE)
++                )
+         # Ban dhcp service running on an instance
+         for dl_type, src_port, dst_port in (
+                 (lib_const.ETHERTYPE_IP, 67, 68),
+diff --git a/neutron/tests/unit/agent/linux/openvswitch_firewall/test_firewall.py b/neutron/tests/unit/agent/linux/openvswitch_firewall/test_firewall.py
+index f674112..8e07e51 100644
+--- a/neutron/tests/unit/agent/linux/openvswitch_firewall/test_firewall.py
++++ b/neutron/tests/unit/agent/linux/openvswitch_firewall/test_firewall.py
+@@ -1039,6 +1039,19 @@
+                     ipv6_src='2003::1',
+                     actions='resubmit(,%d)' % (
+                         ovs_consts.ACCEPTED_EGRESS_TRAFFIC_NORMAL_TABLE)))
++        for icmp_type in agent_firewall.ICMPV6_RESTRICTED_EGRESS_TYPES:
++            expected_calls.append(
++                mock.call(
++                    table=ovs_consts.BASE_EGRESS_TABLE,
++                    priority=95,
++                    in_port=TESTING_VLAN_TAG,
++                    reg5=TESTING_VLAN_TAG,
++                    dl_type='0x86dd',
++                    nw_proto=constants.PROTO_NUM_IPV6_ICMP,
++                    icmp_type=icmp_type,
++                    nd_target='2003::1',
++                    actions='resubmit(,%d)' % (
++                        ovs_consts.ACCEPTED_EGRESS_TRAFFIC_NORMAL_TABLE)))
+         self.mock_bridge.br.add_flow.assert_has_calls(expected_calls)
+ 
+     def test_process_trusted_ports_caches_port_id(self):
diff -Nru neutron-17.1.1/debian/patches/series neutron-17.1.1/debian/patches/series
--- neutron-17.1.1/debian/patches/series	2021-04-21 17:26:26.000000000 +0200
+++ neutron-17.1.1/debian/patches/series	2021-05-17 20:47:34.000000000 +0200
@@ -1 +1,2 @@
 Floating_IP_s_for_routed_networks.patch
+CVE-2021-20267_Restrict_IPv6_NA_and_DHCPv6_IP_and_MAC_source_addresses.patch

Reply to: