Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 22 Jan 2018 17:47:09 +0200
From:      Konstantin Belousov <kostikbel@gmail.com>
To:        Yuri Pankov <yuripv@icloud.com>
Cc:        Li-Wen Hsu <lwhsu@freebsd.org>, freebsd-hackers@freebsd.org
Subject:   Re: Calling getaddrinfo(3) in 32-bit binary on 64-bit host
Message-ID:  <20180122154709.GF55707@kib.kiev.ua>
In-Reply-To: <8c6dc5b5-7640-61fc-b687-08efd1e621ee@icloud.com>
References:  <CAKBkRUx14r%2B%2BZ-n64SNDd4uu=hoJv-KaXxeyUGM7f%2BDS2Ha%2BmQ@mail.gmail.com> <8c6dc5b5-7640-61fc-b687-08efd1e621ee@icloud.com>

next in thread | previous in thread | raw e-mail | index | archive | help
On Mon, Jan 22, 2018 at 02:33:12AM +0300, Yuri Pankov wrote:
> On Mon, Jan 22, 2018 at 05:14:59AM +0800, Li-Wen Hsu wrote:
> > Hi all,
> > 
> > Recently I found a strange case: calling getaddrinfo(3) cannot resolve IPv6
> > address in 32-bit binary on 64-bit host.
> > It happens on vanilla installed 11.1-R and also on r327788 snapshot build.
> > 
> > For a program like this:
> > https://gist.github.com/lwhsu/1288aa5be90b9e7da934a3e2bfc55aa3
> > 
> > It works fine when compiled as a 32-bit binary and run on a 32-bit host.
> > As expected, It is also works fine when compiled as a 64-bit binary and run
> > on a 64-bit host
> > 
> > However, when taking the 32-bit binary and run on a 64 bit system (with
> > /usr/lib32 installed),
> > getaddrinfo(3) just returns: "Non-recoverable failure in name resolution"
> 
> Apparently, it goes through addrconfig() down to getifaddrs() returning 
> bogus data for IPv6 addresses.  This most likely has to with SALIGN 
> being incorrect for 32-bit binary trying to parse route messages from 
> 64-bit kernel.  I'm not sure about proper fix here, but changing SALIGN 
> to be 7 (that is, "sizeof(long) - 1" on amd64 platform) makes your test 
> case return correct data.

Thank you for the diagnostic.  The following worked for me.
Most likely there are may be more issues, since there are more SA_SIZE()
uses from sysctl context. Also, it is probably impossible to provide
COMPAT32 for rtsock itself.

diff --git a/sys/net/rtsock.c b/sys/net/rtsock.c
index eea4cb9459d..26b888f2153 100644
--- a/sys/net/rtsock.c
+++ b/sys/net/rtsock.c
@@ -112,6 +112,12 @@ struct ifa_msghdrl32 {
 	int32_t	ifam_metric;
 	struct	if_data ifam_data;
 };
+
+#define SA_SIZE32(sa)						\
+    (  (((struct sockaddr *)(sa))->sa_len == 0) ?		\
+	sizeof(int)		:				\
+	1 + ( (((struct sockaddr *)(sa))->sa_len - 1) | (sizeof(int) - 1) ) )
+
 #endif /* COMPAT_FREEBSD32 */
 
 MALLOC_DEFINE(M_RTABLE, "routetbl", "routing tables");
@@ -1116,6 +1122,9 @@ rtsock_msg_buffer(int type, struct rt_addrinfo *rtinfo, struct walkarg *w, int *
 	struct sockaddr_storage ss;
 	struct sockaddr_in6 *sin6;
 #endif
+#ifdef COMPAT_FREEBSD32
+	bool compat32 = false;
+#endif
 
 	switch (type) {
 
@@ -1123,9 +1132,10 @@ rtsock_msg_buffer(int type, struct rt_addrinfo *rtinfo, struct walkarg *w, int *
 	case RTM_NEWADDR:
 		if (w != NULL && w->w_op == NET_RT_IFLISTL) {
 #ifdef COMPAT_FREEBSD32
-			if (w->w_req->flags & SCTL_MASK32)
+			if (w->w_req->flags & SCTL_MASK32) {
 				len = sizeof(struct ifa_msghdrl32);
-			else
+				compat32 = true;
+			} else
 #endif
 				len = sizeof(struct ifa_msghdrl);
 		} else
@@ -1139,6 +1149,7 @@ rtsock_msg_buffer(int type, struct rt_addrinfo *rtinfo, struct walkarg *w, int *
 				len = sizeof(struct if_msghdrl32);
 			else
 				len = sizeof(struct if_msghdr32);
+			compat32 = true;
 			break;
 		}
 #endif
@@ -1169,7 +1180,12 @@ rtsock_msg_buffer(int type, struct rt_addrinfo *rtinfo, struct walkarg *w, int *
 		if ((sa = rtinfo->rti_info[i]) == NULL)
 			continue;
 		rtinfo->rti_addrs |= (1 << i);
-		dlen = SA_SIZE(sa);
+#ifdef COMPAT_FREEBSD32
+		if (compat32)
+			dlen = SA_SIZE32(sa);
+		else
+#endif
+			dlen = SA_SIZE(sa);
 		if (cp != NULL && buflen >= dlen) {
 #ifdef INET6
 			if (V_deembed_scopeid && sa->sa_family == AF_INET6) {



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20180122154709.GF55707>