Make getnameinfo(3) salen requirement less strict and

document details of salen in getnameinfo(3) manual page.

getnameinfo(3) returned EAI_FAIL when salen was not equal to
the length corresponding to the value specified by sa->sa_family.
However, POSIX or RFC 3493 does not require it and RFC 4038
Sec.6.2.3 shows an example passing sizeof(struct sockaddr_storage)
to salen.

This change makes the requirement less strict by accepting
salen up to sizeof(struct sockaddr_storage).  It also includes
two more changes: one is to fix return values because both SUSv4
and RFC 3493 require EAI_FAMILY when the address length is invalid,
another is to fix sa_len dependency in PF_LOCAL.

Pointed out by:	Christophe Beauval
Reviewed by:	ae
Differential Revision:	https://reviews.freebsd.org/D14585
This commit is contained in:
Hiroki Sato 2018-03-15 13:46:28 +00:00
parent a7478ad1ce
commit 20d96999a4
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=331000
2 changed files with 33 additions and 9 deletions

View File

@ -18,7 +18,7 @@
.\"
.\" $FreeBSD$
.\"
.Dd July 28, 2016
.Dd March 15, 2018
.Dt GETNAMEINFO 3
.Os
.Sh NAME
@ -80,6 +80,20 @@ or UNIX-domain respectively
that is
.Fa salen
bytes long.
If
.Fa salen
is shorter than the length corresponding to the specified
address family or longer than
.Fn sizeof "struct sockaddr_storage" ,
it returns
.Er EAI_FAMILY .
Note that
.Va sa->sa_len
should be consistent with
.Fa salen
though the value of
.Va sa->sa_len
is not directly used in this function.
.Pp
The host and service names associated with
.Fa sa

View File

@ -124,26 +124,36 @@ getnameinfo(const struct sockaddr *sa, socklen_t salen,
afd = find_afd(sa->sa_family);
if (afd == NULL)
return (EAI_FAMILY);
/*
* getnameinfo() accepts an salen of sizeof(struct sockaddr_storage)
* at maximum as shown in RFC 4038 Sec.6.2.3.
*/
if (salen > sizeof(struct sockaddr_storage))
return (EAI_FAMILY);
switch (sa->sa_family) {
case PF_LOCAL:
/*
* PF_LOCAL uses variable sa->sa_len depending on the
* PF_LOCAL uses variable salen depending on the
* content length of sun_path. Require 1 byte in
* sun_path at least.
*/
if (salen > afd->a_socklen ||
salen <= afd->a_socklen -
if (salen <= afd->a_socklen -
sizeofmember(struct sockaddr_un, sun_path))
return (EAI_FAIL);
return (EAI_FAMILY);
else if (salen > afd->a_socklen)
salen = afd->a_socklen;
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);
if (salen < afd->a_socklen)
return (EAI_FAMILY);
else
salen = afd->a_socklen;
break;
}
@ -517,7 +527,7 @@ getnameinfo_un(const struct afd *afd,
if (serv != NULL && servlen > 0)
*serv = '\0';
if (host != NULL && hostlen > 0) {
pathlen = sa->sa_len - afd->a_off;
pathlen = salen - afd->a_off;
if (pathlen + 1 > hostlen) {
*host = '\0';