From: Marcelo Ricardo Leitner <marcelo.leit...@gmail.com>

[ Upstream commit 471e39df96b9a4c4ba88a2da9e25a126624d7a9c ]

If a socket is set ipv6only, it will still send IPv4 addresses in the
INIT and INIT_ACK packets. This potentially misleads the peer into using
them, which then would cause association termination.

The fix is to not add IPv4 addresses to ipv6only sockets.

Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Reported-by: Corey Minyard <cminy...@mvista.com>
Signed-off-by: Marcelo Ricardo Leitner <marcelo.leit...@gmail.com>
Tested-by: Corey Minyard <cminy...@mvista.com>
Signed-off-by: David S. Miller <da...@davemloft.net>
Signed-off-by: Greg Kroah-Hartman <gre...@linuxfoundation.org>
---
 include/net/sctp/constants.h | 8 +++++---
 net/sctp/associola.c         | 5 ++++-
 net/sctp/bind_addr.c         | 1 +
 net/sctp/protocol.c          | 3 ++-
 4 files changed, 12 insertions(+), 5 deletions(-)

diff --git a/include/net/sctp/constants.h b/include/net/sctp/constants.h
index 86f034b524d46..48d74674d5e95 100644
--- a/include/net/sctp/constants.h
+++ b/include/net/sctp/constants.h
@@ -361,11 +361,13 @@ enum {
         ipv4_is_anycast_6to4(a))
 
 /* Flags used for the bind address copy functions.  */
-#define SCTP_ADDR6_ALLOWED     0x00000001      /* IPv6 address is allowed by
+#define SCTP_ADDR4_ALLOWED     0x00000001      /* IPv4 address is allowed by
                                                   local sock family */
-#define SCTP_ADDR4_PEERSUPP    0x00000002      /* IPv4 address is supported by
+#define SCTP_ADDR6_ALLOWED     0x00000002      /* IPv6 address is allowed by
+                                                  local sock family */
+#define SCTP_ADDR4_PEERSUPP    0x00000004      /* IPv4 address is supported by
                                                   peer */
-#define SCTP_ADDR6_PEERSUPP    0x00000004      /* IPv6 address is supported by
+#define SCTP_ADDR6_PEERSUPP    0x00000008      /* IPv6 address is supported by
                                                   peer */
 
 /* Reasons to retransmit. */
diff --git a/net/sctp/associola.c b/net/sctp/associola.c
index f68ccd1f48609..d17708800652a 100644
--- a/net/sctp/associola.c
+++ b/net/sctp/associola.c
@@ -1593,12 +1593,15 @@ void sctp_assoc_rwnd_decrease(struct sctp_association 
*asoc, unsigned int len)
 int sctp_assoc_set_bind_addr_from_ep(struct sctp_association *asoc,
                                     enum sctp_scope scope, gfp_t gfp)
 {
+       struct sock *sk = asoc->base.sk;
        int flags;
 
        /* Use scoping rules to determine the subset of addresses from
         * the endpoint.
         */
-       flags = (PF_INET6 == asoc->base.sk->sk_family) ? SCTP_ADDR6_ALLOWED : 0;
+       flags = (PF_INET6 == sk->sk_family) ? SCTP_ADDR6_ALLOWED : 0;
+       if (!inet_v6_ipv6only(sk))
+               flags |= SCTP_ADDR4_ALLOWED;
        if (asoc->peer.ipv4_address)
                flags |= SCTP_ADDR4_PEERSUPP;
        if (asoc->peer.ipv6_address)
diff --git a/net/sctp/bind_addr.c b/net/sctp/bind_addr.c
index 7df3704982f54..38d01cfb313e5 100644
--- a/net/sctp/bind_addr.c
+++ b/net/sctp/bind_addr.c
@@ -453,6 +453,7 @@ static int sctp_copy_one_addr(struct net *net, struct 
sctp_bind_addr *dest,
                 * well as the remote peer.
                 */
                if ((((AF_INET == addr->sa.sa_family) &&
+                     (flags & SCTP_ADDR4_ALLOWED) &&
                      (flags & SCTP_ADDR4_PEERSUPP))) ||
                    (((AF_INET6 == addr->sa.sa_family) &&
                      (flags & SCTP_ADDR6_ALLOWED) &&
diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c
index 787c59d798f4b..af054f38341b9 100644
--- a/net/sctp/protocol.c
+++ b/net/sctp/protocol.c
@@ -163,7 +163,8 @@ int sctp_copy_local_addr_list(struct net *net, struct 
sctp_bind_addr *bp,
                 * sock as well as the remote peer.
                 */
                if (addr->a.sa.sa_family == AF_INET &&
-                   !(copy_flags & SCTP_ADDR4_PEERSUPP))
+                   (!(copy_flags & SCTP_ADDR4_ALLOWED) ||
+                    !(copy_flags & SCTP_ADDR4_PEERSUPP)))
                        continue;
                if (addr->a.sa.sa_family == AF_INET6 &&
                    (!(copy_flags & SCTP_ADDR6_ALLOWED) ||
-- 
2.25.1

Reply via email to