From 710150ccb7d62c87eb198e5cbb13d0f1867c176f Mon Sep 17 00:00:00 2001 From: Gustavo Lopes Date: Mon, 15 Jul 2013 01:51:15 +0200 Subject: [PATCH] socket: support unix paths in the abstract namespace Those starting with '\0'. --- ext/sockets/conversions.c | 25 +++++++++-- ext/sockets/sockets.c | 21 +++++---- ext/sockets/tests/socket_abstract_path.phpt | 44 +++++++++++++++++++ .../tests/socket_abstract_path_sendmsg.phpt | 40 +++++++++++++++++ 4 files changed, 119 insertions(+), 11 deletions(-) create mode 100644 ext/sockets/tests/socket_abstract_path.phpt create mode 100644 ext/sockets/tests/socket_abstract_path_sendmsg.phpt 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-- + +--FILE-- + [ "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-- + +--FILE-- + [ "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 -- 2.40.0