unix: support long path names in pipe.c (#5047)

Continues: #4676
Fixes: #2826
This commit is contained in:
Edy Silva 2026-03-17 00:14:47 -03:00 committed by GitHub
parent 048acb509c
commit 919b92d944
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 84 additions and 19 deletions

View File

@ -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 */

View File

@ -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)

View File

@ -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
}