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
| ||
|
Date: Thu, 25 Feb 2016 19:10:59 -0800 From: Alexander Duyck <aduyck@...antis.com> To: netdev@...r.kernel.org, davem@...emloft.net, alexander.duyck@...il.com Subject: [net-next PATCH] IPv6: Use a 16 bit length field when computing a IPv6 UDP checksum This change makes it so that we only use a 16 bit length field instead of a 32 bit length field when computing a UDP checksum for IPv6. This fixes an issue found with UDP tunnels over IPv6 where the total size exceeded 65536 for a frame that was to be segmented. As a result the checksum being computed didn't match the frame data so we ended up being off by 1 for the final checksum value since we didn't cancel out the upper 16 bits of the length. The reasoning behind this is that RFC2460 states that for protocols such as UDP that carry their own length field we should use that when computing the checksum for the pseudo-header. As such we should be using a 16 bit value, not a 32 bit as is currently occurring when computing the UDP checksum for IPv6. Signed-off-by: Alexander Duyck <aduyck@...antis.com> --- I don't have the highest of confidence that this patch is the correct solution for this, however the way I see it we only have a few alternatives. For now I am using this patch to get the conversation started. There ends up really being two issues here. The first issue is that IPv4 and IPv6 GSO frames are being assembled that have a length that is greater than 65535 and the truncated value is being placed in the length fields. The problem as I see it is that I am not sure there is any definitive way to prevent this without reducing the maximum GSO size for all sources within a given network namespace. In addition I am not sure what the impact on performance would be if we were to implement such an approach. The second issue is that if we cannot prevent the first issue we really need to have a consistent way of doing the IPv4 and IPv6 checksums. The IPv4 checksum passes the length value as a short, while the IPv6 passes this value as an integer. As a result we get different behavior between the two which makes it difficult for us to put together a generic routine for handling checksums for segmentation at higher levels. include/net/ip6_checksum.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/include/net/ip6_checksum.h b/include/net/ip6_checksum.h index 1a49b73f7f6e..c55529ac12cf 100644 --- a/include/net/ip6_checksum.h +++ b/include/net/ip6_checksum.h @@ -95,6 +95,15 @@ static inline __sum16 udp_v6_check(int len, const struct in6_addr *daddr, __wsum base) { + /* RFC 2460 states that for protocols such as UDP which include + * a length in their header we should use that value when computing + * the pseudo-header instead of the total payload length minus + * extension headers. Since UDP has a length field that is only + * 16 bits in length we need to cap the length field to 16 bits to + * match what will be present in the header. + */ + len &= 0xFFFF; + return csum_ipv6_magic(saddr, daddr, len, IPPROTO_UDP, base); }
Powered by blists - more mailing lists