From 20d96999a4c7fe7e2cdf5056b8a293e266564f4a Mon Sep 17 00:00:00 2001 From: Hiroki Sato Date: Thu, 15 Mar 2018 13:46:28 +0000 Subject: [PATCH] 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 --- lib/libc/net/getnameinfo.3 | 16 +++++++++++++++- lib/libc/net/getnameinfo.c | 26 ++++++++++++++++++-------- 2 files changed, 33 insertions(+), 9 deletions(-) diff --git a/lib/libc/net/getnameinfo.3 b/lib/libc/net/getnameinfo.3 index 9e49eaccf3f1..5d5719c010c7 100644 --- a/lib/libc/net/getnameinfo.3 +++ b/lib/libc/net/getnameinfo.3 @@ -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 diff --git a/lib/libc/net/getnameinfo.c b/lib/libc/net/getnameinfo.c index b3788534c7dc..a07355fac6f9 100644 --- a/lib/libc/net/getnameinfo.c +++ b/lib/libc/net/getnameinfo.c @@ -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';