Date: Fri, 02 Mar 2018 11:18:04 +0900 (JST) From: Hiroki Sato <hrs@FreeBSD.org> To: christophebeauval@hotmail.com Cc: freebsd-standards@freebsd.org Subject: Re: Libc getnameinfo length requirement Message-ID: <20180302.111804.1733124916347516747.hrs@allbsd.org> In-Reply-To: <VI1PR0402MB371177DFA52E8CC936FCDD00A2C60@VI1PR0402MB3711.eurprd04.prod.outlook.com> References: <VI1PR0402MB371177DFA52E8CC936FCDD00A2C60@VI1PR0402MB3711.eurprd04.prod.outlook.com>
next in thread | previous in thread | raw e-mail | index | archive | help
----Security_Multipart0(Fri_Mar__2_11_18_04_2018_403)-- Content-Type: Multipart/Mixed; boundary="--Next_Part(Fri_Mar__2_11_18_04_2018_371)--" Content-Transfer-Encoding: 7bit ----Next_Part(Fri_Mar__2_11_18_04_2018_371)-- Content-Type: Text/Plain; charset=us-ascii Content-Transfer-Encoding: 7bit Hi, Christophe Beauval <christophebeauval@hotmail.com> wrote in <VI1PR0402MB371177DFA52E8CC936FCDD00A2C60@VI1PR0402MB3711.eurprd04.prod.outlook.com>: ch> Hello all ch> ch> This message after having presented the problem below in the freenode ch> #freebsd and EFNet #bsdcode channels and being advised (amongst others) ch> to use this mailing list. ch> ch> When I got strange errors (EAI_FAIL) from getnameinfo-calls in a private ch> project, I investigated the freebsd/libc/net/getnameinfo.c source code ch> and stumbled upon the requirement (in the switch-statement at line 127) ch> that the "socklen_t salen" argument needs to be the exact same number as ch> "sizeof(struct sockaddr_in)" for the PF_INET protocol family and ch> "sizeof(struct sockaddr_in6)" for the PF_INET6 protocol family. This ch> fails when using a "sockaddr_storage" struct as first argument and tied ch> to this a "sizeof(struct sockaddr_storage)" as second argument, as can ch> be found as example in RFC 4038 on page 21 paragraph 6.2.3. For the ch> PF_LOCAL protocol family a larger "salen" than it's used struct is also ch> not allowed in that switch. ch> ch> A less strict requirement either allowing any larger size (like in ch> glibc's implementation) or at least the size of "struct ch> sockaddr_storage" (as suggested by hrs) would solve this problem. I have a patch to change getnameinfo() to accept a longer salen (attached). I do not think there is a bad side-effect or impact for backward compatibility. You can try test_getnameinfo.c to test the difference. While I'm here, I changed the return value on error because SUSv4 says EAI_FAMILY should be returned when the address length was invalid. -- Hiroki ----Next_Part(Fri_Mar__2_11_18_04_2018_371)-- Content-Type: Text/X-Patch; charset=us-ascii Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="getnameinfo.c.20180302-1.diff" Index: lib/libc/net/getnameinfo.c =================================================================== --- lib/libc/net/getnameinfo.c (revision 329060) +++ lib/libc/net/getnameinfo.c (working copy) @@ -120,6 +120,16 @@ if (sa == NULL) return (EAI_FAIL); + /* + * getnameinfo() accepts an salen longer than sa->sa_len so that + * sizeof(struct sockaddr_storage) can be specified to salen as + * shown in RFC 4018 Sec.6.2.3. Note that sa->sa_len must be + * the correct length depending on sa->sa_family. + */ + if (salen < sa->sa_len) + return (EAI_FAMILY); + if (salen > sa->sa_len) + salen = sa->sa_len; afd = find_afd(sa->sa_family); if (afd == NULL) @@ -134,16 +144,16 @@ if (salen > afd->a_socklen || salen <= afd->a_socklen - sizeofmember(struct sockaddr_un, sun_path)) - return (EAI_FAIL); + return (EAI_FAMILY); break; case PF_LINK: if (salen <= afd->a_socklen - sizeofmember(struct sockaddr_dl, sdl_data)) - return (EAI_FAIL); + return (EAI_FAMILY); break; default: if (salen != afd->a_socklen) - return (EAI_FAIL); + return (EAI_FAMILY); break; } ----Next_Part(Fri_Mar__2_11_18_04_2018_371)-- Content-Type: Text/Plain; charset=us-ascii Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="test_getnameinfo.c" #include <sys/types.h> #include <sys/socket.h> #include <netdb.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> int main(void) { struct sockaddr_storage ss; struct sockaddr *sa = (struct sockaddr *)&ss; struct sockaddr_in *sin = (struct sockaddr_in *)&ss; char hbuf[NI_MAXHOST]; int error; memset(&ss, 0, sizeof(ss)); sin->sin_family = AF_INET; sin->sin_len = sizeof(*sin); /* salen == sa->sa_len */ error = getnameinfo(sa, sa->sa_len, hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST); if (error) printf("salen == sa->sa_len: error: %s\n", gai_strerror(error)); else printf("salen == sa->sa_len: hbuf = %s\n", hbuf); /* salen > sa->sa_len */ error = getnameinfo(sa, sizeof(ss), hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST); if (error) printf("salen > sa->sa_len: error: %s\n", gai_strerror(error)); else printf("salen > sa->sa_len: hbuf = %s\n", hbuf); return (EXIT_SUCCESS); } ----Next_Part(Fri_Mar__2_11_18_04_2018_371)---- ----Security_Multipart0(Fri_Mar__2_11_18_04_2018_403)-- Content-Type: application/pgp-signature Content-Transfer-Encoding: 7bit -----BEGIN PGP SIGNATURE----- iEYEABECAAYFAlqYtFwACgkQTyzT2CeTzy3aFACfY61mz4B75vO350wdLfLvfQ+K qGMAoNEYD+jjilYMR6uwITOHfQPfKPU1 =FwBz -----END PGP SIGNATURE----- ----Security_Multipart0(Fri_Mar__2_11_18_04_2018_403)----
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20180302.111804.1733124916347516747.hrs>