]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
rds: Calling getsockname() on unbounded socket generates seg fault
authorKa-Cheong Poon <ka-cheong.poon@oracle.com>
Mon, 18 Dec 2017 15:45:18 +0000 (07:45 -0800)
committerJack Vogel <jack.vogel@oracle.com>
Thu, 1 Feb 2018 23:08:47 +0000 (15:08 -0800)
If a socket is not yet bound, calling getsockname() should return an
unspecified address with family AF_UNSPEC as an RDS socket can be
bound to either an IPv4 or an IPv6 address.  Hence returning either
family is incorrect.  Currently, the returned address is set to an
unspecified address with family AF_INET6.  If the passed in buffer is
smaller than sizeof(struct sockaddr_in6), the app may get a
segmentation fault error.  This is similar to passing a buffer smaller
than sizeof(struct sockaddr_in) before the IPv6 changes.

Orabug: 27463484

Signed-off-by: Ka-Cheong Poon <ka-cheong.poon@oracle.com>
Reviewed-by: Darren Kenny <darren.kenny@oracle.com>
Reviewed-by: HÃ¥kon Bugge <haakon.bugge@oracle.com>
net/rds/af_rds.c

index c7b30e619bab0d5e2643a40ba60dc1c980b56abc..54be1fb5e2d7abb54a4c24eca3b26b80ff75cec9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006, 2017 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 2018 Oracle and/or its affiliates. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -173,6 +173,17 @@ static int rds_getname(struct socket *sock, struct sockaddr *uaddr,
                        *uaddr_len = sizeof(*sin6);
                }
        } else {
+               /* If socket is not yet bound, set the return address family
+                * to be AF_UNSPEC (value 0) and the address size to be that
+                * of an IPv4 address.
+                */
+               if (ipv6_addr_any(&rs->rs_bound_addr)) {
+                       sin = (struct sockaddr_in *)uaddr;
+                       memset(sin, 0, sizeof(*sin));
+                       sin->sin_family = AF_UNSPEC;
+                       *uaddr_len = sizeof(*sin);
+                       return 0;
+               }
                if (ipv6_addr_v4mapped(&rs->rs_bound_addr)) {
                        sin = (struct sockaddr_in *)uaddr;
                        memset(sin->sin_zero, 0, sizeof(sin->sin_zero));