kern/178881: [patch] getifaddrs(3) does not report IPv6 addresses properly in 32-bit compatibility mode

Steve Zweep Steve.Zweep at watchguard.com
Thu May 23 20:00:00 UTC 2013


>Number:         178881
>Category:       kern
>Synopsis:       [patch] getifaddrs(3) does not report IPv6 addresses properly in 32-bit compatibility mode
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Thu May 23 20:00:00 UTC 2013
>Closed-Date:
>Last-Modified:
>Originator:     Steve Zweep
>Release:        9.1-RELEASE (amd64)
>Organization:
WatchGuard Technologies
>Environment:
FreeBSD outland2.borderware.com 9.1-RELEASE FreeBSD 9.1-RELEASE #0 r243825: Tue Dec  4 09:23:10 UTC 2012     root at farrell.cse.buffalo.edu:/usr/obj/usr/src/sys/GENERIC  amd64

>Description:
This was uncovered trying to run 32-bit Postfix on a 64-bit kernel, and subsequently verified with a simple utility which just iterates and prints the IP addresses returned from getifaddrs().

In 32-bit compatibility mode IPv4 addresses are reported correctly, but IPv6 addresses are not. The address family is reported as '0' instead of the expected 28 for AF_INET6. The same test utility works as expected when compiled as a 64-bit executable.
>How-To-Repeat:
- configure a network interface with an IPv6 address
- compile a 32-bit program which calls getifaddrs() to iterate through interface addresses
- examine the output
>Fix:
The problem appears to be in the 32-bit compatibility code in sys/net/rtsock.c which handles the NET_RT_IFLIST sysctl used by getifaddrs(). The calculated size of the sockaddr structure does not match that which the client code in getifaddrs is expecting.

I'm no expert here, but the following patch worked for me:

--- rtsock.c.orig       2013-04-15 17:01:25.000000000 -0400
+++ rtsock.c    2013-04-19 11:53:09.000000000 -0400
@@ -1157,6 +1157,13 @@
        default:
                len = sizeof(struct rt_msghdr);
        }
+
+#ifdef COMPAT_FREEBSD32
+#define SA_SIZE32(sa)  (  (!(sa) || ((struct sockaddr *)(sa))->sa_len == 0) ? \
+       sizeof(uint32_t) : \
+       1 + ( (((struct sockaddr *)(sa))->sa_len - 1) | (sizeof(uint32_t) - 1) ) )
+#endif
+
        cp0 = cp;
        if (cp0)
                cp += len;
@@ -1166,7 +1173,12 @@
                if ((sa = rtinfo->rti_info[i]) == NULL)
                        continue;
                rtinfo->rti_addrs |= (1 << i);
-               dlen = SA_SIZE(sa);
+#ifdef COMPAT_FREEBSD32
+               if (w != NULL && w->w_req->flags & SCTL_MASK32) 
+                       dlen = SA_SIZE32(sa);
+               else
+#endif
+                       dlen = SA_SIZE(sa);
                if (cp) {
                        bcopy((caddr_t)sa, cp, (unsigned)dlen);
                        cp += dlen;




>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-bugs mailing list