diff options
author | Gustavo Lopes <glopes@nebm.ist.utl.pt> | 2013-07-15 01:51:15 +0200 |
---|---|---|
committer | Gustavo Lopes <glopes@nebm.ist.utl.pt> | 2013-07-15 23:57:51 +0200 |
commit | 710150ccb7d62c87eb198e5cbb13d0f1867c176f (patch) | |
tree | 0bffb861bbaddb84eca442f5bc619f64ff4ba449 /ext/sockets | |
parent | e2744f1aa33da3afade2c454b008c0de65a72da9 (diff) | |
download | php-git-710150ccb7d62c87eb198e5cbb13d0f1867c176f.tar.gz |
socket: support unix paths in the abstract namespace
Those starting with '\0'.
Diffstat (limited to 'ext/sockets')
-rw-r--r-- | ext/sockets/conversions.c | 25 | ||||
-rw-r--r-- | ext/sockets/sockets.c | 21 | ||||
-rw-r--r-- | ext/sockets/tests/socket_abstract_path.phpt | 44 | ||||
-rw-r--r-- | ext/sockets/tests/socket_abstract_path_sendmsg.phpt | 40 |
4 files changed, 119 insertions, 11 deletions
diff --git a/ext/sockets/conversions.c b/ext/sockets/conversions.c index 3b58b39b70..ed55ed52fa 100644 --- a/ext/sockets/conversions.c +++ b/ext/sockets/conversions.c @@ -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; diff --git a/ext/sockets/sockets.c b/ext/sockets/sockets.c index 801af0a4dd..b226d94715 100644 --- a/ext/sockets/sockets.c +++ b/ext/sockets/sockets.c @@ -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 index 0000000000..816e5c11bb --- /dev/null +++ b/ext/sockets/tests/socket_abstract_path.phpt @@ -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 index 0000000000..5a9275a26b --- /dev/null +++ b/ext/sockets/tests/socket_abstract_path_sendmsg.phpt @@ -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 |