summaryrefslogtreecommitdiff
path: root/ext/Socket
diff options
context:
space:
mode:
authorLubomir Rintel <lkundrak@v3.sk>2009-08-31 11:45:23 +0200
committerRafael Garcia-Suarez <rgarciasuarez@gmail.com>2009-08-31 22:02:47 +0200
commit89904c08923161afd23c629d5c2c7472a09c16bb (patch)
tree29ebe50a59178ecf59cfc9e90683423aae9c9fc9 /ext/Socket
parentcdab9eb9f4a609665cca826dbf612dd2fc05a19b (diff)
downloadperl-89904c08923161afd23c629d5c2c7472a09c16bb.tar.gz
Fix unpack of abstract socket addrs with nul byte
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.
Diffstat (limited to 'ext/Socket')
-rw-r--r--ext/Socket/Socket.xs20
-rwxr-xr-x[-rw-r--r--]ext/Socket/t/Socket.t2
2 files changed, 13 insertions, 9 deletions
diff --git a/ext/Socket/Socket.xs b/ext/Socket/Socket.xs
index d46a6b9892..38202252fe 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 ac50cbefc7..9a6d31f5c9 100644..100755
--- a/ext/Socket/t/Socket.t
+++ b/ext/Socket/t/Socket.t
@@ -150,7 +150,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) {