]> granicus.if.org Git - php/commitdiff
socket: support unix paths in the abstract namespace
authorGustavo Lopes <glopes@nebm.ist.utl.pt>
Sun, 14 Jul 2013 23:51:15 +0000 (01:51 +0200)
committerGustavo Lopes <glopes@nebm.ist.utl.pt>
Mon, 15 Jul 2013 21:57:51 +0000 (23:57 +0200)
Those starting with '\0'.

ext/sockets/conversions.c
ext/sockets/sockets.c
ext/sockets/tests/socket_abstract_path.phpt [new file with mode: 0644]
ext/sockets/tests/socket_abstract_path_sendmsg.phpt [new file with mode: 0644]

index 3b58b39b706862eab65fda5244da78df467afbb1..ed55ed52fa7547078e6c77fb42058c3aaf41c5bc 100644 (file)
@@ -98,8 +98,8 @@ typedef struct {
 } field_descriptor;
 
 #define KEY_FILL_SOCKADDR "fill_sockaddr"
-#define KEY_RECVMSG_RET "recvmsg_ret"
-#define KEY_CMSG_LEN   "cmsg_len"
+#define KEY_RECVMSG_RET   "recvmsg_ret"
+#define KEY_CMSG_LEN     "cmsg_len"
 
 const struct key_value empty_key_value_list[] = {{0}};
 
@@ -667,6 +667,13 @@ static void from_zval_write_sun_path(const zval *path, char *sockaddr_un_c, ser_
                path = &lzval;
        }
 
+       /* code in this file relies on the path being nul terminated, even though
+        * this is not required, at least on linux for abstract paths. It also
+        * assumes that the path is not empty */
+       if (Z_STRLEN_P(path) == 0) {
+               do_from_zval_err(ctx, "%s", "the path is cannot be empty");
+               return;
+       }
        if (Z_STRLEN_P(path) >= sizeof(saddr->sun_path)) {
                do_from_zval_err(ctx, "the path is too long, the maximum permitted "
                                "length is %ld", sizeof(saddr->sun_path) - 1);
@@ -768,10 +775,22 @@ static void from_zval_write_sockaddr_aux(const zval *container,
                        return;
                }
                *sockaddr_ptr = accounted_ecalloc(1, sizeof(struct sockaddr_un), ctx);
-               *sockaddr_len = sizeof(struct sockaddr_un);
                if (fill_sockaddr) {
+                       struct sockaddr_un *sock_un = (struct sockaddr_un*)*sockaddr_ptr;
+
                        from_zval_write_sockaddr_un(container, (char*)*sockaddr_ptr, ctx);
                        (*sockaddr_ptr)->sa_family = AF_UNIX;
+
+                       /* calculating length is more complicated here. Giving the size of
+                        * struct sockaddr_un here and relying on the nul termination of
+                        * sun_path does not work for paths in the abstract namespace. Note
+                        * that we always assume the path is not empty and nul terminated */
+                       *sockaddr_len = offsetof(struct sockaddr_un, sun_path) +
+                                       (sock_un->sun_path[0] == '\0'
+                                       ? (1 + strlen(&sock_un->sun_path[1]))
+                                       : strlen(sock_un->sun_path));
+               } else {
+                       *sockaddr_len = sizeof(struct sockaddr_un);
                }
                break;
 
index 801af0a4dd1ab65d58c7d8d469cc646af0711893..b226d94715d1d6ff8d9334679ab5d570bd2f9694 100644 (file)
@@ -1479,7 +1479,7 @@ PHP_FUNCTION(socket_strerror)
 PHP_FUNCTION(socket_bind)
 {
        zval                                    *arg1;
-       php_sockaddr_storage    sa_storage;
+       php_sockaddr_storage    sa_storage = {0};
        struct sockaddr                 *sock_type = (struct sockaddr*) &sa_storage;
        php_socket                              *php_sock;
        char                                    *addr;
@@ -1497,10 +1497,19 @@ PHP_FUNCTION(socket_bind)
                case AF_UNIX:
                        {
                                struct sockaddr_un *sa = (struct sockaddr_un *) sock_type;
-                               memset(sa, 0, sizeof(sa_storage));
+
                                sa->sun_family = AF_UNIX;
-                               snprintf(sa->sun_path, 108, "%s", addr);
-                               retval = bind(php_sock->bsd_socket, (struct sockaddr *) sa, SUN_LEN(sa));
+
+                               if (addr_len >= sizeof(sa->sun_path)) {
+                                       php_error_docref(NULL TSRMLS_CC, E_WARNING,
+                                                       "Invalid path: too long (maximum size is %d)",
+                                                       (int)sizeof(sa->sun_path) - 1);
+                                       RETURN_FALSE;
+                               }
+                               memcpy(&sa->sun_path, addr, addr_len);
+
+                               retval = bind(php_sock->bsd_socket, (struct sockaddr *) sa,
+                                               offsetof(struct sockaddr_un, sun_path) + addr_len);
                                break;
                        }
 
@@ -1508,8 +1517,6 @@ PHP_FUNCTION(socket_bind)
                        {
                                struct sockaddr_in *sa = (struct sockaddr_in *) sock_type;
 
-                               memset(sa, 0, sizeof(sa_storage)); /* Apparently, Mac OSX needs this */
-
                                sa->sin_family = AF_INET;
                                sa->sin_port = htons((unsigned short) port);
 
@@ -1525,8 +1532,6 @@ PHP_FUNCTION(socket_bind)
                        {
                                struct sockaddr_in6 *sa = (struct sockaddr_in6 *) sock_type;
 
-                               memset(sa, 0, sizeof(sa_storage)); /* Apparently, Mac OSX needs this */
-
                                sa->sin6_family = AF_INET6;
                                sa->sin6_port = htons((unsigned short) port);
 
diff --git a/ext/sockets/tests/socket_abstract_path.phpt b/ext/sockets/tests/socket_abstract_path.phpt
new file mode 100644 (file)
index 0000000..816e5c1
--- /dev/null
@@ -0,0 +1,44 @@
+--TEST--
+Support for paths in the abstract namespace (bind, connect)
+--SKIPIF--
+<?php
+if (!extension_loaded('sockets'))
+       die('skip sockets extension not available.');
+
+if (PHP_OS != 'Linux') {
+       die('skip For Linux only');
+}
+?>
+--FILE--
+<?php
+include __DIR__."/mcast_helpers.php.inc";
+
+$path = "\x00/foo_bar";
+
+echo "creating server socket\n";
+$servers = socket_create(AF_UNIX, SOCK_STREAM, 0) or die("err");
+socket_bind($servers, $path) or die("Could not bind");
+socket_listen($servers) or die("Could not listen");
+socket_set_nonblock($servers) or die("Could not put in non-blocking mode");
+
+echo "creating client socket\n";
+$clients = socket_create(AF_UNIX, SOCK_STREAM, 0) or die("err");
+socket_connect($clients, $path) or die("Error connecting");
+
+$conns = socket_accept($servers) or die("Could not accept connection");
+
+$r = socket_sendmsg($clients, [
+       //"name" => [ "addr" => $path, ],
+       "iov" => ["test ", "thing", "\n"],
+], 0);
+var_dump($r);
+checktimeout($conns, 500);
+
+if (!socket_recv($conns, $buf, 20, 0)) die("recv");
+print_r($buf);
+?>
+--EXPECTF--
+creating server socket
+creating client socket
+int(11)
+test thing
diff --git a/ext/sockets/tests/socket_abstract_path_sendmsg.phpt b/ext/sockets/tests/socket_abstract_path_sendmsg.phpt
new file mode 100644 (file)
index 0000000..5a9275a
--- /dev/null
@@ -0,0 +1,40 @@
+--TEST--
+Support for paths in the abstract namespace (bind, sendmsg, recvmsg)
+--SKIPIF--
+<?php
+if (!extension_loaded('sockets'))
+       die('skip sockets extension not available.');
+
+if (PHP_OS != 'Linux') {
+       die('skip For Linux only');
+}
+?>
+--FILE--
+<?php
+include __DIR__."/mcast_helpers.php.inc";
+
+$path = "\x00/bar_foo";
+
+echo "creating send socket\n";
+$sends1 = socket_create(AF_UNIX, SOCK_DGRAM, 0) or die("err");
+socket_set_nonblock($sends1) or die("Could not put in non-blocking mode");
+
+echo "creating receive socket\n";
+$s = socket_create(AF_UNIX, SOCK_DGRAM, 0) or die("err");
+socket_bind($s, $path) or die("err");
+
+$r = socket_sendmsg($sends1, [
+       "name" => [ "path" => $path],
+       "iov" => ["test ", "thing", "\n"],
+], 0);
+var_dump($r);
+checktimeout($s, 500);
+
+if (!socket_recv($s, $buf, 20, 0)) die("recv");
+print_r($buf);
+?>
+--EXPECTF--
+creating send socket
+creating receive socket
+int(11)
+test thing