unix: fail with ENAMETOOLONG in uv_pipe_*

Fail with ENAMETOOLONG when the name of a Unix socket exceeds
`sizeof(saddr.sun_path)`. Previously the path was just truncated,
which could result in nasty bugs, and even though that behaviour
has been always been around, it’s hard to imagine a situation in
which ending up with an incorrect path is better than not creating
a socket at all.

Refs: https://github.com/nodejs/node/pull/12601
Refs: https://github.com/nodejs/node/issues/12708
PR-URL: https://github.com/libuv/libuv/pull/1329
Reviewed-By: Santiago Gimeno <santiago.gimeno@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Saúl Ibarra Corretgé <saghul@gmail.com>
This commit is contained in:
Anna Henningsen 2017-04-28 01:25:00 +02:00 committed by Santiago Gimeno
parent 239ab6b012
commit 66319cf494
No known key found for this signature in database
GPG Key ID: F28C3C8DA33C03BE
5 changed files with 91 additions and 8 deletions

View File

@ -49,16 +49,20 @@ API
Bind the pipe to a file path (Unix) or a name (Windows).
.. note::
Paths on Unix get truncated to ``sizeof(sockaddr_un.sun_path)`` bytes, typically between
92 and 108 bytes.
If a path on Unix exceeds ``sizeof(sockaddr_un.sun_path)`` bytes, typically between
92 and 108 bytes, ``uv_pipe_bind`` will fail with ``UV_ENAMETOOLONG``.
.. versionchanged: 2.0.0 long filenames will lead to an error rather than being truncated
.. c:function:: void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle, const char* name, uv_connect_cb cb)
Connect to the Unix domain socket or the named pipe.
.. note::
Paths on Unix get truncated to ``sizeof(sockaddr_un.sun_path)`` bytes, typically between
92 and 108 bytes.
If a path on Unix exceeds ``sizeof(sockaddr_un.sun_path)`` bytes, typically between
92 and 108 bytes, ``uv_pipe_bind`` will fail with ``UV_ENAMETOOLONG``.
.. versionchanged: 2.0.0 long filenames will lead to an error rather than being truncated
.. c:function:: int uv_pipe_getsockname(const uv_pipe_t* handle, char* buffer, size_t* size)

View File

@ -45,9 +45,14 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
const char* pipe_fname;
int sockfd;
int err;
size_t name_len;
pipe_fname = NULL;
sockfd = -1;
name_len = strlen(name);
if (name_len > sizeof(saddr.sun_path) - 1)
return -ENAMETOOLONG;
/* Already bound? */
if (uv__stream_fd(handle) >= 0)
@ -67,8 +72,7 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
sockfd = err;
memset(&saddr, 0, sizeof saddr);
strncpy(saddr.sun_path, pipe_fname, sizeof(saddr.sun_path) - 1);
saddr.sun_path[sizeof(saddr.sun_path) - 1] = '\0';
memcpy(saddr.sun_path, pipe_fname, name_len);
saddr.sun_family = AF_UNIX;
if (bind(sockfd, (struct sockaddr*)&saddr, sizeof saddr)) {
@ -160,6 +164,14 @@ void uv_pipe_connect(uv_connect_t* req,
int new_sock;
int err;
int r;
size_t name_len;
name_len = strlen(name);
if (name_len > sizeof(saddr.sun_path) - 1) {
err = -ENAMETOOLONG;
goto out;
}
new_sock = (uv__stream_fd(handle) == -1);
@ -171,8 +183,7 @@ void uv_pipe_connect(uv_connect_t* req,
}
memset(&saddr, 0, sizeof saddr);
strncpy(saddr.sun_path, name, sizeof(saddr.sun_path) - 1);
saddr.sun_path[sizeof(saddr.sun_path) - 1] = '\0';
memcpy(saddr.sun_path, name, name_len);
saddr.sun_family = AF_UNIX;
do {

View File

@ -135,10 +135,16 @@ TEST_DECLARE (udp_try_send)
TEST_DECLARE (pipe_bind_error_addrinuse)
TEST_DECLARE (pipe_bind_error_addrnotavail)
TEST_DECLARE (pipe_bind_error_inval)
#ifndef _WIN32
TEST_DECLARE (pipe_bind_error_long_path)
#endif
TEST_DECLARE (pipe_connect_multiple)
TEST_DECLARE (pipe_listen_without_bind)
TEST_DECLARE (pipe_connect_bad_name)
TEST_DECLARE (pipe_connect_to_file)
#ifndef _WIN32
TEST_DECLARE (pipe_connect_to_long_path)
#endif
TEST_DECLARE (pipe_connect_on_prepare)
TEST_DECLARE (pipe_getsockname)
TEST_DECLARE (pipe_getsockname_abstract)
@ -401,6 +407,9 @@ TASK_LIST_START
TEST_ENTRY (pipe_connect_bad_name)
TEST_ENTRY (pipe_connect_to_file)
#ifndef _WIN32
TEST_ENTRY (pipe_connect_to_long_path)
#endif
TEST_ENTRY (pipe_connect_on_prepare)
TEST_ENTRY (pipe_server_close)
@ -526,6 +535,9 @@ TASK_LIST_START
TEST_ENTRY (pipe_bind_error_addrinuse)
TEST_ENTRY (pipe_bind_error_addrnotavail)
TEST_ENTRY (pipe_bind_error_inval)
#ifndef _WIN32
TEST_ENTRY (pipe_bind_error_long_path)
#endif
TEST_ENTRY (pipe_connect_multiple)
TEST_ENTRY (pipe_listen_without_bind)
TEST_ENTRY (pipe_getsockname)

View File

@ -23,6 +23,7 @@
#include "task.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef _WIN32
@ -134,3 +135,27 @@ TEST_IMPL(pipe_listen_without_bind) {
MAKE_VALGRIND_HAPPY();
return 0;
}
TEST_IMPL(pipe_bind_error_long_path) {
char path[2048];
uv_pipe_t server;
int r;
memset(path, '.', sizeof(path) - 1);
path[sizeof(path) - 1] = '\0';
r = uv_pipe_init(uv_default_loop(), &server, 0);
ASSERT(r == 0);
r = uv_pipe_bind(&server, path);
ASSERT(r == UV_ENAMETOOLONG);
uv_close((uv_handle_t*)&server, close_cb);
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
ASSERT(close_cb_called == 1);
MAKE_VALGRIND_HAPPY();
return 0;
}

View File

@ -23,6 +23,7 @@
#include "task.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef _WIN32
@ -56,6 +57,13 @@ static void connect_cb_file(uv_connect_t* connect_req, int status) {
}
static void connect_cb_long_path(uv_connect_t* connect_req, int status) {
ASSERT(status == UV_ENAMETOOLONG);
uv_close((uv_handle_t*)connect_req->handle, close_cb);
connect_cb_called++;
}
TEST_IMPL(pipe_connect_bad_name) {
uv_pipe_t client;
uv_connect_t req;
@ -93,3 +101,26 @@ TEST_IMPL(pipe_connect_to_file) {
MAKE_VALGRIND_HAPPY();
return 0;
}
TEST_IMPL(pipe_connect_to_long_path) {
char path[2048];
uv_pipe_t client;
uv_connect_t req;
int r;
memset(path, '.', sizeof(path) - 1);
path[sizeof(path) - 1] = '\0';
r = uv_pipe_init(uv_default_loop(), &client, 0);
ASSERT(r == 0);
uv_pipe_connect(&req, &client, path, connect_cb_long_path);
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
ASSERT(close_cb_called == 1);
ASSERT(connect_cb_called == 1);
MAKE_VALGRIND_HAPPY();
return 0;
}