develooper Front page | perl.perl5.porters | Postings from August 2009

[PATCH] Fix unpack of abstract socket addrs with nul byte

Thread Next
From:
Lubomir Rintel
Date:
August 31, 2009 09:17
Subject:
[PATCH] Fix unpack of abstract socket addrs with nul byte
Message ID:
1251711923-811-1-git-send-email-lkundrak@v3.sk
Addresses of Linux abstract namespace sockets are not nul-terminated C
strings, but rather an arbitrary character arrays. According to unix(7)
documentation from Linux, "Null bytes in the name have  no special
significance."

unpack_sockaddr_un() was just throwing the initial nul byte away and
then treating the rest like ordinary C string when computing the length
of the address, which was wrong. This fix utilizes the length of the PV
for addresses starting with nul instead.

The regression test was extended with check for the problem.
---
 ext/Socket/Socket.xs  |   20 ++++++++++++--------
 ext/Socket/t/Socket.t |    2 +-
 2 files changed, 13 insertions(+), 9 deletions(-)

diff --git a/ext/Socket/Socket.xs b/ext/Socket/Socket.xs
index 5d36bbd..3522303 100644
--- a/ext/Socket/Socket.xs
+++ b/ext/Socket/Socket.xs
@@ -363,7 +363,7 @@ unpack_sockaddr_un(sun_sv)
 	struct sockaddr_un addr;
 	STRLEN sockaddrlen;
 	char * sun_ad = SvPVbyte(sun_sv,sockaddrlen);
-	char * e;
+	int addr_len;
 #   ifndef __linux__
 	/* On Linux sockaddrlen on sockets returned by accept, recvfrom,
 	   getpeername and getsockname is not equal to sizeof(addr). */
@@ -382,13 +382,17 @@ unpack_sockaddr_un(sun_sv)
 			addr.sun_family,
 			AF_UNIX);
 	}
-	e = (char*)addr.sun_path;
-	/* On Linux, the name of abstract unix domain sockets begins
-	 * with a '\0', so allow this. */
-	while ((*e || (e == addr.sun_path && e[1] && sockaddrlen > 1))
-		&& e < (char*)addr.sun_path + sizeof addr.sun_path)
-	    ++e;
-	ST(0) = sv_2mortal(newSVpvn(addr.sun_path, e - (char*)addr.sun_path));
+
+	if (addr.sun_path[0] == '\0') {
+		/* Linux-style abstract socket address begins with a nul
+		 * and can contain nuls. */
+		addr_len = (void *)&addr - (void *)&addr.sun_path + sockaddrlen;
+	} else {
+		for (addr_len = 0; addr.sun_path[addr_len]
+		     && addr_len < sizeof addr.sun_path; addr_len++);
+	}
+
+	ST(0) = sv_2mortal(newSVpvn(addr.sun_path, addr_len));
 #else
 	ST(0) = (SV *) not_here("unpack_sockaddr_un");
 #endif
diff --git a/ext/Socket/t/Socket.t b/ext/Socket/t/Socket.t
index b8f014b..d1e7447 100755
--- a/ext/Socket/t/Socket.t
+++ b/ext/Socket/t/Socket.t
@@ -152,7 +152,7 @@ print (($@ =~ /^Bad arg length for Socket::sockaddr_family, length is 0, should
 
 if ($^O eq 'linux') {
     # see if we can handle abstract sockets
-    my $test_abstract_socket = chr(0) . '/tmp/test-perl-socket';
+    my $test_abstract_socket = chr(0) . '/org/perl/hello'. chr(0) . 'world';
     my $addr = sockaddr_un ($test_abstract_socket);
     my ($path) = sockaddr_un ($addr);
     if ($test_abstract_socket eq $path) {
-- 
1.6.2.5


Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About