unix: support long path names in pipe.c (#5047)
Continues: #4676 Fixes: #2826
This commit is contained in:
parent
048acb509c
commit
919b92d944
@ -29,6 +29,18 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
union uv__sockaddr_un {
|
||||||
|
struct sockaddr sa;
|
||||||
|
struct uv__sockaddr_un_path {
|
||||||
|
char pad[offsetof(struct sockaddr_un, sun_path)];
|
||||||
|
#ifdef SOCK_MAXADDRLEN
|
||||||
|
char path[SOCK_MAXADDRLEN - offsetof(struct sockaddr_un, sun_path)];
|
||||||
|
#else
|
||||||
|
char path[sizeof(((struct sockaddr_un*)0)->sun_path)];
|
||||||
|
#endif
|
||||||
|
} up;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/* Does the file path contain embedded nul bytes? */
|
/* Does the file path contain embedded nul bytes? */
|
||||||
static int includes_invalid_nul(const char *s, size_t n) {
|
static int includes_invalid_nul(const char *s, size_t n) {
|
||||||
@ -64,7 +76,7 @@ int uv_pipe_bind2(uv_pipe_t* handle,
|
|||||||
const char* name,
|
const char* name,
|
||||||
size_t namelen,
|
size_t namelen,
|
||||||
unsigned int flags) {
|
unsigned int flags) {
|
||||||
struct sockaddr_un saddr;
|
union uv__sockaddr_un saddr;
|
||||||
char* pipe_fname;
|
char* pipe_fname;
|
||||||
int sockfd;
|
int sockfd;
|
||||||
int err;
|
int err;
|
||||||
@ -90,12 +102,12 @@ int uv_pipe_bind2(uv_pipe_t* handle,
|
|||||||
return UV_EINVAL;
|
return UV_EINVAL;
|
||||||
|
|
||||||
if (flags & UV_PIPE_NO_TRUNCATE)
|
if (flags & UV_PIPE_NO_TRUNCATE)
|
||||||
if (namelen > sizeof(saddr.sun_path))
|
if (namelen > sizeof(saddr.up.path))
|
||||||
return UV_EINVAL;
|
return UV_EINVAL;
|
||||||
|
|
||||||
/* Truncate long paths. Documented behavior. */
|
/* Truncate long paths. Documented behavior. */
|
||||||
if (namelen > sizeof(saddr.sun_path))
|
if (namelen > sizeof(saddr.up.path))
|
||||||
namelen = sizeof(saddr.sun_path);
|
namelen = sizeof(saddr.up.path);
|
||||||
|
|
||||||
/* Already bound? */
|
/* Already bound? */
|
||||||
if (uv__stream_fd(handle) >= 0)
|
if (uv__stream_fd(handle) >= 0)
|
||||||
@ -125,10 +137,10 @@ int uv_pipe_bind2(uv_pipe_t* handle,
|
|||||||
sockfd = err;
|
sockfd = err;
|
||||||
|
|
||||||
memset(&saddr, 0, sizeof saddr);
|
memset(&saddr, 0, sizeof saddr);
|
||||||
memcpy(&saddr.sun_path, name, namelen);
|
memcpy(saddr.up.path, name, namelen);
|
||||||
saddr.sun_family = AF_UNIX;
|
saddr.sa.sa_family = AF_UNIX;
|
||||||
|
|
||||||
if (bind(sockfd, (struct sockaddr*)&saddr, addrlen)) {
|
if (bind(sockfd, &saddr.sa, addrlen)) {
|
||||||
err = UV__ERR(errno);
|
err = UV__ERR(errno);
|
||||||
/* Convert ENOENT to EACCES for compatibility with Windows. */
|
/* Convert ENOENT to EACCES for compatibility with Windows. */
|
||||||
if (err == UV_ENOENT)
|
if (err == UV_ENOENT)
|
||||||
@ -257,7 +269,7 @@ int uv_pipe_connect2(uv_connect_t* req,
|
|||||||
size_t namelen,
|
size_t namelen,
|
||||||
unsigned int flags,
|
unsigned int flags,
|
||||||
uv_connect_cb cb) {
|
uv_connect_cb cb) {
|
||||||
struct sockaddr_un saddr;
|
union uv__sockaddr_un saddr;
|
||||||
int new_sock;
|
int new_sock;
|
||||||
int err;
|
int err;
|
||||||
int r;
|
int r;
|
||||||
@ -276,12 +288,12 @@ int uv_pipe_connect2(uv_connect_t* req,
|
|||||||
return UV_EINVAL;
|
return UV_EINVAL;
|
||||||
|
|
||||||
if (flags & UV_PIPE_NO_TRUNCATE)
|
if (flags & UV_PIPE_NO_TRUNCATE)
|
||||||
if (namelen > sizeof(saddr.sun_path))
|
if (namelen > sizeof(saddr.up.path))
|
||||||
return UV_EINVAL;
|
return UV_EINVAL;
|
||||||
|
|
||||||
/* Truncate long paths. Documented behavior. */
|
/* Truncate long paths. Documented behavior. */
|
||||||
if (namelen > sizeof(saddr.sun_path))
|
if (namelen > sizeof(saddr.up.path))
|
||||||
namelen = sizeof(saddr.sun_path);
|
namelen = sizeof(saddr.up.path);
|
||||||
|
|
||||||
new_sock = (uv__stream_fd(handle) == -1);
|
new_sock = (uv__stream_fd(handle) == -1);
|
||||||
|
|
||||||
@ -293,8 +305,8 @@ int uv_pipe_connect2(uv_connect_t* req,
|
|||||||
}
|
}
|
||||||
|
|
||||||
memset(&saddr, 0, sizeof saddr);
|
memset(&saddr, 0, sizeof saddr);
|
||||||
memcpy(&saddr.sun_path, name, namelen);
|
memcpy(saddr.up.path, name, namelen);
|
||||||
saddr.sun_family = AF_UNIX;
|
saddr.sa.sa_family = AF_UNIX;
|
||||||
|
|
||||||
if (*name == '\0')
|
if (*name == '\0')
|
||||||
addrlen = offsetof(struct sockaddr_un, sun_path) + namelen;
|
addrlen = offsetof(struct sockaddr_un, sun_path) + namelen;
|
||||||
@ -355,7 +367,7 @@ static int uv__pipe_getsockpeername(const uv_pipe_t* handle,
|
|||||||
#else
|
#else
|
||||||
static const int is_linux = 0;
|
static const int is_linux = 0;
|
||||||
#endif
|
#endif
|
||||||
struct sockaddr_un sa;
|
union uv__sockaddr_un sa;
|
||||||
socklen_t addrlen;
|
socklen_t addrlen;
|
||||||
size_t slop;
|
size_t slop;
|
||||||
char* p;
|
char* p;
|
||||||
@ -376,15 +388,15 @@ static int uv__pipe_getsockpeername(const uv_pipe_t* handle,
|
|||||||
}
|
}
|
||||||
|
|
||||||
slop = 1;
|
slop = 1;
|
||||||
if (is_linux && sa.sun_path[0] == '\0') {
|
if (is_linux && sa.up.path[0] == '\0') {
|
||||||
/* Linux abstract namespace. Not zero-terminated. */
|
/* Linux abstract namespace. Not zero-terminated. */
|
||||||
slop = 0;
|
slop = 0;
|
||||||
addrlen -= offsetof(struct sockaddr_un, sun_path);
|
addrlen -= offsetof(struct sockaddr_un, sun_path);
|
||||||
} else {
|
} else {
|
||||||
p = memchr(sa.sun_path, '\0', sizeof(sa.sun_path));
|
p = memchr(sa.up.path, '\0', sizeof(sa.up.path));
|
||||||
if (p == NULL)
|
if (p == NULL)
|
||||||
p = ARRAY_END(sa.sun_path);
|
p = ARRAY_END(sa.up.path);
|
||||||
addrlen = p - sa.sun_path;
|
addrlen = p - sa.up.path;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((size_t)addrlen + slop > *size) {
|
if ((size_t)addrlen + slop > *size) {
|
||||||
@ -392,7 +404,7 @@ static int uv__pipe_getsockpeername(const uv_pipe_t* handle,
|
|||||||
return UV_ENOBUFS;
|
return UV_ENOBUFS;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(buffer, sa.sun_path, addrlen);
|
memcpy(buffer, sa.up.path, addrlen);
|
||||||
*size = addrlen;
|
*size = addrlen;
|
||||||
|
|
||||||
/* only null-terminate if it's not an abstract socket */
|
/* only null-terminate if it's not an abstract socket */
|
||||||
|
|||||||
@ -219,6 +219,7 @@ TEST_DECLARE (pipe_getsockname)
|
|||||||
TEST_DECLARE (pipe_getsockname_abstract)
|
TEST_DECLARE (pipe_getsockname_abstract)
|
||||||
TEST_DECLARE (pipe_getsockname_autobind)
|
TEST_DECLARE (pipe_getsockname_autobind)
|
||||||
TEST_DECLARE (pipe_getsockname_blocking)
|
TEST_DECLARE (pipe_getsockname_blocking)
|
||||||
|
TEST_DECLARE (pipe_getsockname_long_path)
|
||||||
TEST_DECLARE (pipe_pending_instances)
|
TEST_DECLARE (pipe_pending_instances)
|
||||||
TEST_DECLARE (pipe_sendmsg)
|
TEST_DECLARE (pipe_sendmsg)
|
||||||
TEST_DECLARE (pipe_server_close)
|
TEST_DECLARE (pipe_server_close)
|
||||||
@ -856,6 +857,7 @@ TASK_LIST_START
|
|||||||
TEST_ENTRY (pipe_getsockname_abstract)
|
TEST_ENTRY (pipe_getsockname_abstract)
|
||||||
TEST_ENTRY (pipe_getsockname_autobind)
|
TEST_ENTRY (pipe_getsockname_autobind)
|
||||||
TEST_ENTRY (pipe_getsockname_blocking)
|
TEST_ENTRY (pipe_getsockname_blocking)
|
||||||
|
TEST_ENTRY (pipe_getsockname_long_path)
|
||||||
TEST_ENTRY (pipe_pending_instances)
|
TEST_ENTRY (pipe_pending_instances)
|
||||||
TEST_ENTRY (pipe_sendmsg)
|
TEST_ENTRY (pipe_sendmsg)
|
||||||
|
|
||||||
|
|||||||
@ -26,6 +26,8 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
|
# include <sys/socket.h>
|
||||||
|
# include <sys/un.h>
|
||||||
# include <unistd.h> /* close */
|
# include <unistd.h> /* close */
|
||||||
#else
|
#else
|
||||||
# include <fcntl.h>
|
# include <fcntl.h>
|
||||||
@ -368,3 +370,52 @@ TEST_IMPL(pipe_getsockname_blocking) {
|
|||||||
MAKE_VALGRIND_HAPPY(uv_default_loop());
|
MAKE_VALGRIND_HAPPY(uv_default_loop());
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void long_path_connect_cb(uv_connect_t* req, int status) {
|
||||||
|
ASSERT_OK(status);
|
||||||
|
uv_close((uv_handle_t*) req->handle, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST_IMPL(pipe_getsockname_long_path) {
|
||||||
|
#ifndef SOCK_MAXADDRLEN
|
||||||
|
RETURN_SKIP("long unix paths not supported on this platform");
|
||||||
|
#else
|
||||||
|
uv_loop_t* loop;
|
||||||
|
size_t len;
|
||||||
|
int r;
|
||||||
|
char path[SOCK_MAXADDRLEN - offsetof(struct sockaddr_un, sun_path) + 1];
|
||||||
|
char name[SOCK_MAXADDRLEN - offsetof(struct sockaddr_un, sun_path) + 1];
|
||||||
|
|
||||||
|
loop = uv_default_loop();
|
||||||
|
ASSERT_NOT_NULL(loop);
|
||||||
|
|
||||||
|
r = uv_pipe_init(loop, &pipe_server, 0);
|
||||||
|
ASSERT_OK(r);
|
||||||
|
r = uv_pipe_init(loop, &pipe_client, 0);
|
||||||
|
ASSERT_OK(r);
|
||||||
|
|
||||||
|
memset(path, 'x', sizeof(path) - 1);
|
||||||
|
path[sizeof(path) - 1] = '\0';
|
||||||
|
|
||||||
|
r = uv_pipe_bind(&pipe_server, path);
|
||||||
|
ASSERT_OK(r);
|
||||||
|
|
||||||
|
len = sizeof(name);
|
||||||
|
r = uv_pipe_getsockname(&pipe_server, name, &len);
|
||||||
|
|
||||||
|
ASSERT_OK(r);
|
||||||
|
ASSERT_EQ(len, strlen(path));
|
||||||
|
ASSERT_MEM_EQ(path, name, len);
|
||||||
|
|
||||||
|
r = uv_listen((uv_stream_t*) &pipe_server, 0, pipe_server_connection_cb);
|
||||||
|
ASSERT_OK(r);
|
||||||
|
|
||||||
|
uv_pipe_connect(&connect_req, &pipe_client, path, long_path_connect_cb);
|
||||||
|
uv_close((uv_handle_t*) &pipe_server, NULL);
|
||||||
|
ASSERT_OK(uv_run(loop, UV_RUN_DEFAULT));
|
||||||
|
|
||||||
|
MAKE_VALGRIND_HAPPY(loop);
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user