Commit f1e07e7e authored by Jason Gunthorpe's avatar Jason Gunthorpe Committed by Greg Kroah-Hartman

sctp: Fix mangled IPv4 addresses on a IPv6 listening socket

[ Upstream commit 9302d7bb ]

sctp_v4_map_v6 was subtly writing and reading from members
of a union in a way the clobbered data it needed to read before
it read it.

Zeroing the v6 flowinfo overwrites the v4 sin_addr with 0, meaning
that every place that calls sctp_v4_map_v6 gets ::ffff:0.0.0.0 as the
result.

Reorder things to guarantee correct behaviour no matter what the
union layout is.

This impacts user space clients that open an IPv6 SCTP socket and
receive IPv4 connections. Prior to 299ee user space would see a
sockaddr with AF_INET and a correct address, after 299ee the sockaddr
is AF_INET6, but the address is wrong.

Fixes: 299ee123 (sctp: Fixup v4mapped behaviour to comply with Sock API)
Signed-off-by: default avatarJason Gunthorpe <jgunthorpe@obsidianresearch.com>
Acked-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
Acked-by: default avatarNeil Horman <nhorman@tuxdriver.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent f27dcf42
...@@ -571,11 +571,14 @@ static inline void sctp_v6_map_v4(union sctp_addr *addr) ...@@ -571,11 +571,14 @@ static inline void sctp_v6_map_v4(union sctp_addr *addr)
/* Map v4 address to v4-mapped v6 address */ /* Map v4 address to v4-mapped v6 address */
static inline void sctp_v4_map_v6(union sctp_addr *addr) static inline void sctp_v4_map_v6(union sctp_addr *addr)
{ {
__be16 port;
port = addr->v4.sin_port;
addr->v6.sin6_addr.s6_addr32[3] = addr->v4.sin_addr.s_addr;
addr->v6.sin6_port = port;
addr->v6.sin6_family = AF_INET6; addr->v6.sin6_family = AF_INET6;
addr->v6.sin6_flowinfo = 0; addr->v6.sin6_flowinfo = 0;
addr->v6.sin6_scope_id = 0; addr->v6.sin6_scope_id = 0;
addr->v6.sin6_port = addr->v4.sin_port;
addr->v6.sin6_addr.s6_addr32[3] = addr->v4.sin_addr.s_addr;
addr->v6.sin6_addr.s6_addr32[0] = 0; addr->v6.sin6_addr.s6_addr32[0] = 0;
addr->v6.sin6_addr.s6_addr32[1] = 0; addr->v6.sin6_addr.s6_addr32[1] = 0;
addr->v6.sin6_addr.s6_addr32[2] = htonl(0x0000ffff); addr->v6.sin6_addr.s6_addr32[2] = htonl(0x0000ffff);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment