From owner-freebsd-hackers@freebsd.org Mon Jan 22 15:47:22 2018 Return-Path: Delivered-To: freebsd-hackers@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 83BEFEC7512 for ; Mon, 22 Jan 2018 15:47:22 +0000 (UTC) (envelope-from kostikbel@gmail.com) Received: from kib.kiev.ua (kib.kiev.ua [IPv6:2001:470:d5e7:1::1]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 6B150815B3; Mon, 22 Jan 2018 15:47:19 +0000 (UTC) (envelope-from kostikbel@gmail.com) Received: from tom.home (kib@localhost [127.0.0.1]) by kib.kiev.ua (8.15.2/8.15.2) with ESMTPS id w0MFl9Ec050678 (version=TLSv1.2 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO); Mon, 22 Jan 2018 17:47:13 +0200 (EET) (envelope-from kostikbel@gmail.com) DKIM-Filter: OpenDKIM Filter v2.10.3 kib.kiev.ua w0MFl9Ec050678 Received: (from kostik@localhost) by tom.home (8.15.2/8.15.2/Submit) id w0MFl9I4050677; Mon, 22 Jan 2018 17:47:09 +0200 (EET) (envelope-from kostikbel@gmail.com) X-Authentication-Warning: tom.home: kostik set sender to kostikbel@gmail.com using -f Date: Mon, 22 Jan 2018 17:47:09 +0200 From: Konstantin Belousov To: Yuri Pankov Cc: Li-Wen Hsu , freebsd-hackers@freebsd.org Subject: Re: Calling getaddrinfo(3) in 32-bit binary on 64-bit host Message-ID: <20180122154709.GF55707@kib.kiev.ua> References: <8c6dc5b5-7640-61fc-b687-08efd1e621ee@icloud.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <8c6dc5b5-7640-61fc-b687-08efd1e621ee@icloud.com> User-Agent: Mutt/1.9.2 (2017-12-15) X-Spam-Status: No, score=-2.0 required=5.0 tests=ALL_TRUSTED,BAYES_00, DKIM_ADSP_CUSTOM_MED,FREEMAIL_FROM,NML_ADSP_CUSTOM_MED autolearn=no autolearn_force=no version=3.4.1 X-Spam-Checker-Version: SpamAssassin 3.4.1 (2015-04-28) on tom.home X-BeenThere: freebsd-hackers@freebsd.org X-Mailman-Version: 2.1.25 Precedence: list List-Id: Technical Discussions relating to FreeBSD List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 22 Jan 2018 15:47:22 -0000 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) {