Skip site navigation (1)Skip section navigation (2)
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>