Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 09 Sep 2015 05:30:03 +0900 (JST)
From:      Hiroki Sato <hrs@FreeBSD.org>
To:        net@FreeBSD.org
Subject:   PF_LOCAL support in getaddrinfo/getnameinfo
Message-ID:  <20150909.053003.1234482271945809368.hrs@allbsd.org>

next in thread | raw e-mail | index | archive | help
----Security_Multipart0(Wed_Sep__9_05_30_03_2015_796)--
Content-Type: Multipart/Mixed;
 boundary="--Next_Part(Wed_Sep__9_05_30_03_2015_346)--"
Content-Transfer-Encoding: 7bit

----Next_Part(Wed_Sep__9_05_30_03_2015_346)--
Content-Type: Text/Plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

Hi,

 Is there any problem with adding PF_LOCAL support into getaddrinfo()
 and getnameinfo()?  It was not standardized but can be implemented
 in a straight forward way (attached).

 Some old posts in mailing list archives (not for FreeBSD) said it was
 removed in glibc due to a security issue that getaddrinfo() call with
 PF_UNSPEC could create /tmp/<hostname> unintentionally when no
 hostname was resolved.  IIRC KAME's original implementation included
 this functionality, but I am not sure of why it was removed.  Does
 anyone know the reason, or other potential problems?

 In the attached patch PF_LOCAL is not used when getaddrinfo() is
 called with PF_UNSPEC, and only an absolute pathname is accepted.
 This should not have a bad side-effect for the existing programs
 which use them.

-- Hiroki

----Next_Part(Wed_Sep__9_05_30_03_2015_346)--
Content-Type: Text/X-Patch; charset=us-ascii
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="getaddrinfo_unix.20150909-1.diff"

Index: lib/libc/net/getaddrinfo.c
===================================================================
--- lib/libc/net/getaddrinfo.c	(revision 287348)
+++ lib/libc/net/getaddrinfo.c	(working copy)
@@ -137,13 +137,19 @@
 	 offsetof(struct sockaddr_in6, sin6_addr),
 	 in6_addrany, in6_loopback, 1},
 #define	N_INET 1
+#define	N_LOCAL 2
 #else
 #define	N_INET 0
+#define	N_LOCAL 1
 #endif
 	{PF_INET, sizeof(struct in_addr),
 	 sizeof(struct sockaddr_in),
 	 offsetof(struct sockaddr_in, sin_addr),
 	 in_addrany, in_loopback, 0},
+	{PF_LOCAL, sizeof(char[104]),
+	 sizeof(struct sockaddr_un),
+	 offsetof(struct sockaddr_un, sun_path),
+	 NULL, NULL, 0},
 	{0, 0, 0, 0, NULL, NULL, 0},
 };

@@ -158,9 +164,9 @@
 };

 static const struct explore explore[] = {
-#if 0
-	{ PF_LOCAL, ANY, ANY, 0x01 },
-#endif
+	{ PF_LOCAL, SOCK_DGRAM, ANY, 0x04 },
+	{ PF_LOCAL, SOCK_STREAM, ANY, 0x04 },
+	{ PF_LOCAL, SOCK_SEQPACKET, ANY, 0x04 },
 #ifdef INET6
 	{ PF_INET6, SOCK_DGRAM, IPPROTO_UDP, 0x07 },
 	{ PF_INET6, SOCK_STREAM, IPPROTO_TCP, 0x07 },
@@ -408,6 +414,7 @@
 			ERR(EAI_BADFLAGS);
 		switch (hints->ai_family) {
 		case PF_UNSPEC:
+		case PF_LOCAL:
 		case PF_INET:
 #ifdef INET6
 		case PF_INET6:
@@ -1130,6 +1137,9 @@
 	*res = NULL;
 	ai = NULL;

+	if (pai->ai_family == PF_LOCAL)
+		return (0);
+
 	/*
 	 * filter out AFs that are not supported by the kernel
 	 * XXX errno?
@@ -1172,7 +1182,7 @@
 	const struct afd *afd;
 	struct addrinfo *ai;
 	int error;
-	char pton[PTON_MAX];
+	char pton[PTON_MAX], path[PATH_MAX], *p;

 	*res = NULL;
 	ai = NULL;
@@ -1182,6 +1192,15 @@
 		return 0;

 	switch (afd->a_af) {
+	case AF_LOCAL:
+		if (hostname[0] != '/')
+			ERR(EAI_FAIL);
+		if (strlen(hostname) > afd->a_addrlen)
+			ERR(EAI_MEMORY);
+		/* NUL-termination does not need to be guaranteed. */
+		strncpy(path, hostname, afd->a_addrlen);
+		p = &path[0];
+		break;
 	case AF_INET:
 		/*
 		 * RFC3493 requires getaddrinfo() to accept AF_INET formats
@@ -1192,15 +1211,17 @@
 		 */
 		if (inet_aton(hostname, (struct in_addr *)pton) != 1)
 			return 0;
+		p = pton;
 		break;
 	default:
 		if (inet_pton(afd->a_af, hostname, pton) != 1)
 			return 0;
+		p = pton;
 		break;
 	}

 	if (pai->ai_family == afd->a_af) {
-		GET_AI(ai, afd, pton);
+		GET_AI(ai, afd, p);
 		GET_PORT(ai, servname);
 		if ((pai->ai_flags & AI_CANONNAME)) {
 			/*
@@ -1320,6 +1341,12 @@
 	memset(ai->ai_addr, 0, (size_t)afd->a_socklen);
 	ai->ai_addr->sa_len = afd->a_socklen;
 	ai->ai_addrlen = afd->a_socklen;
+	if (ai->ai_family == PF_LOCAL) {
+		size_t n = strlen(addr);
+
+		ai->ai_addrlen -= afd->a_addrlen - n;
+		ai->ai_addr->sa_len -= afd->a_addrlen - n;
+	}
 	ai->ai_addr->sa_family = ai->ai_family = afd->a_af;
 	p = (char *)(void *)(ai->ai_addr);
 	memcpy(p + afd->a_off, addr, (size_t)afd->a_addrlen);
Index: lib/libc/net/getnameinfo.c
===================================================================
--- lib/libc/net/getnameinfo.c	(revision 287404)
+++ lib/libc/net/getnameinfo.c	(working copy)
@@ -49,6 +49,7 @@

 #include <sys/types.h>
 #include <sys/socket.h>
+#include <sys/un.h>
 #include <net/if.h>
 #include <net/if_dl.h>
 #include <net/if_types.h>
@@ -72,6 +73,8 @@
 static int	getnameinfo_link(const struct sockaddr *, socklen_t, char *,
     size_t, char *, size_t, int);
 static int	hexname(const u_int8_t *, size_t, char *, size_t);
+static int	getnameinfo_un(const struct sockaddr *, socklen_t, char *,
+    size_t, char *, size_t, int);

 int
 getnameinfo(const struct sockaddr *sa, socklen_t salen,
@@ -89,6 +92,9 @@
 	case AF_LINK:
 		return getnameinfo_link(sa, salen, host, hostlen, serv,
 		    servlen, flags);
+	case AF_LOCAL:
+		return getnameinfo_un(sa, salen, host, hostlen, serv,
+		    servlen, flags);
 	default:
 		return EAI_FAMILY;
 	}
@@ -106,6 +112,8 @@
 #endif
 	{PF_INET, sizeof(struct in_addr), sizeof(struct sockaddr_in),
 		offsetof(struct sockaddr_in, sin_addr)},
+	{PF_LOCAL, sizeof(char[104]), sizeof(struct sockaddr_un),
+		offsetof(struct sockaddr_un, sun_path)},
 	{0, 0, 0},
 };

@@ -469,3 +477,39 @@
 	}
 	return 0;
 }
+
+/*
+ * getnameinfo_un():
+ * Format a pathname of UNIX IPC domain socket.
+ */
+/* ARGSUSED */
+static int
+getnameinfo_un(const struct sockaddr *sa, socklen_t salen,
+    char *host, size_t hostlen, char *serv, size_t servlen, int flags)
+{
+	const struct afd *afd;
+	size_t pathlen;
+	const char *addr;
+
+	for (afd = &afdl[0]; afd != NULL; afd++) {
+		if (afd->a_af == AF_LOCAL)
+			break;
+	}
+	if (afd == NULL)
+		return (EAI_FAIL);
+
+	if (serv != NULL && servlen > 0)
+		*serv = '\0';
+
+	pathlen = sa->sa_len - afd->a_off;
+	addr = (const char *)sa + afd->a_off;
+
+	if (pathlen + 1 > hostlen) {
+		*host = '\0';
+		return (EAI_MEMORY);
+	}
+	memcpy(host, addr, pathlen);
+	host[pathlen] = '\0';
+
+	return (0);
+}

----Next_Part(Wed_Sep__9_05_30_03_2015_346)----

----Security_Multipart0(Wed_Sep__9_05_30_03_2015_796)--
Content-Type: application/pgp-signature
Content-Transfer-Encoding: 7bit

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1

iEYEABECAAYFAlXvRUsACgkQTyzT2CeTzy1ntwCfVVjKrge/tit8wG8mxSzi6slf
+nEAn1qhOGKsve8Zx7xz8rDKeNsyEZQZ
=bzYI
-----END PGP SIGNATURE-----

----Security_Multipart0(Wed_Sep__9_05_30_03_2015_796)----



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20150909.053003.1234482271945809368.hrs>