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: <ecf16770431c8b30782e3443085641eb685aa5f9.camel@alliedtelesis.co.nz>
Date: Wed, 10 Apr 2024 22:59:47 +0000
From: Paul Davey <Paul.Davey@...iedtelesis.co.nz>
To: "netdev@...r.kernel.org" <netdev@...r.kernel.org>
CC: "steffen.klassert@...unet.com" <steffen.klassert@...unet.com>
Subject: combination of dot1q tagging and gro esp offload appears to corrupt
 esp transport mode traffic

Hi,

I have observed a what I believe is a bug in IPSec esp4 transport mode
with gro enabled in the presence of 802.1Q tagged packets.
However I am not sure what the best course of action is to resolve the
problem.

I believe the issue occurs with the following chain of key events:

1) An ESP transport mode packet containing an 802.1Q tag is received
   on a network interface with GRO enabled.
2) dev_gro_receive will find the ETH_P_8021Q packet offload and call
   vlan_gro_receive which determines the inner ether type and
   continues the gro handler chain
3) the gro handlers eventually reach esp4_gro_receive which looks up
   the xfrm state from the spi and submits the skb to xfrm_input after
   setting the XFRM_GRO flag in xfrm_offload flags.
4) xfrm4_transport_input removes the encapsulation header by moving
   the network header forward to just before the decrypted payload
   content.
5) xfrm4_tranport_finish adjusts new network header protocol, pushes
   skb to include new network header and updates total length and
   updates checksum
6) xfrm4_tranport_finish checks if XFRM_GRO was set in the
   xfrm_offload flags and if so calls skb_mac_header_rebuild.
7) skb_mac_header_rebuild moves the mac header from it's original
   position to just before the new network header.  
   However mac_len is still the original ethernet mac length and the
   mac header still contains ETH_P_8021Q as the ethertype, resulting
   in a packet claiming to be 802.1Q but starting with an IP header
   with no TCI or inner ethertype.
8) skb is queued on the xfrm napi instance for reception
9) skb is processed by skb_vlan_untag in __netif_receive_skb_core as
   skb->protocol is a VLAN ethertype.
10) skb_vlan_untag removes the "vlan tag" leaving an skb with
    skb->protocol set to the total length from the IP header and
    missing the start of the IP header and any ethertype.
11) This skb is obviously not recognised as IP and not sent the
    expected destination, instead usually received as ETH_P_802_2 if
    the IP datagram was short enough.

It appears the load bearing kernel configs for this to happen would be
CONFIG_VLAN_8021Q as this would gate the presence of vlan_gro_receive
and CONFIG_INET_ESP_OFFLOAD or CONFIG_INET6_ESP_OFFLOAD as this will
gate the esp4_gro_receive or esp6_gro_receive paths and setting of
XFRM_GRO flag.

generic-receive-offload needs to be enabled on the underlying
receiving interface.

I have reproduced this on 6.8.2 using an ipsec protected l2tp tunnel
over an 802.1Q tagging interface between a vm and the host machine.

The tunnel mode encapsulation removal code seems to avoid this issue
by forcing the skb->protocol to ETH_P_IP or ETH_P_IPV6 and also
setting this in the mac header if present.

I would appreciate any advice on how to go about fixing this issue.

Reproduction setup below the line, substitute interface names as
necessary.

Thanks,
Paul Davey

---

DUT:

ip link set eth0 up
ip link add link eth0 eth0.10 type vlan id 10
ip addr add 10.0.1.1/24 dev eth0.10
ip link set up dev eth0.10

ip l2tp add tunnel remote 10.0.1.2 local 10.0.1.1 tunnel_id 1 \
peer_tunnel_id 2 encap udp udp_sport 5000 udp_dport 5001
ip l2tp add session name l2tp1 tunnel_id 1 session_id 1 \
peer_session_id 2 

ip link show l2tp1
ip addr add 10.1.0.1/24 dev l2tp1
ip link set l2tp1 up

ip xfrm policy add src 10.0.1.1 dst 10.0.1.2 proto udp sport 5000 \
dport 5001 dir out tmpl src 0.0.0.0 dst 0.0.0.0 proto esp spi 0x100 \
mode transport reqid 1
ip xfrm policy add src 10.0.1.2 dst 10.0.1.1 proto udp sport 5001 \
dport 5000 dir in tmpl src 0.0.0.0 dst 0.0.0.0 proto esp \
mode transport reqid 1

ip xfrm state add src 10.0.1.1 dst 10.0.1.2 proto esp spi 0x100 \
reqid 1 mode transport replay-window 1 flag esn \
aead "rfc4106(gcm(aes))" 0x8516687c549c3921da3e57b2503851095000f090 128
ip xfrm state add src 10.0.1.2 dst 10.0.1.1 proto esp spi 0x101 \
reqid 1 mode transport replay-window 1 flag esn \
aead "rfc4106(gcm(aes))" 0x8516687c549c3921da3e57b2503851095000f090 128

# Corrupted packets can be seen here as strange 802.3LLC frames 
# on vlan 1280
tcpdump -e -i eth0

Link-Partner:

ip link add link tap0 tap0.10 type vlan id 10
ip addr add 10.0.1.2/24 dev tap0.10
ip link set up dev tap0.10

ip l2tp add tunnel remote 10.0.1.1 local 10.0.1.2 tunnel_id 2 \
peer_tunnel_id 1 encap udp udp_sport 5001 udp_dport 5000
ip l2tp add session name l2tp2 tunnel_id 2 session_id 2 \
peer_session_id 1

ip addr add dev l2tp2 10.1.0.2/24
ip link set l2tp2 up

ip xfrm policy add src 10.0.1.1 dst 10.0.1.2 proto udp sport 5000 \
dport 5001 dir in tmpl src 0.0.0.0 dst 0.0.0.0 proto esp \
mode transport reqid 1
ip xfrm policy add src 10.0.1.2 dst 10.0.1.1 proto udp sport 5001 \
dport 5000 dir out tmpl src 0.0.0.0 dst 0.0.0.0 proto esp spi 0x101 \
mode transport reqid 1

ip xfrm state add src 10.0.1.1 dst 10.0.1.2 proto esp spi 0x100 \
reqid 1 mode transport replay-window 1 flag esn \
aead "rfc4106(gcm(aes))" 0x8516687c549c3921da3e57b2503851095000f090 128
ip xfrm state add src 10.0.1.2 dst 10.0.1.1 proto esp spi 0x101 \
reqid 1 mode transport replay-window 1 flag esn \
aead "rfc4106(gcm(aes))" 0x8516687c549c3921da3e57b2503851095000f090 128

# This will show Destination Host Unreachable as ARP in l2tp is never
# received on the DUT
ping 10.1.0.1

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ