From 919b92d9444afb04e011a321d9dfaf810e2f230f Mon Sep 17 00:00:00 2001 From: Edy Silva Date: Tue, 17 Mar 2026 00:14:47 -0300 Subject: [PATCH] unix: support long path names in pipe.c (#5047) Continues: #4676 Fixes: #2826 --- src/unix/pipe.c | 50 +++++++++++++++++++++-------------- test/test-list.h | 2 ++ test/test-pipe-getsockname.c | 51 ++++++++++++++++++++++++++++++++++++ 3 files changed, 84 insertions(+), 19 deletions(-) diff --git a/src/unix/pipe.c b/src/unix/pipe.c index eb03a47cc..c9902095f 100644 --- a/src/unix/pipe.c +++ b/src/unix/pipe.c @@ -29,6 +29,18 @@ #include #include +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? */ 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, size_t namelen, unsigned int flags) { - struct sockaddr_un saddr; + union uv__sockaddr_un saddr; char* pipe_fname; int sockfd; int err; @@ -90,12 +102,12 @@ int uv_pipe_bind2(uv_pipe_t* handle, return UV_EINVAL; if (flags & UV_PIPE_NO_TRUNCATE) - if (namelen > sizeof(saddr.sun_path)) + if (namelen > sizeof(saddr.up.path)) return UV_EINVAL; /* Truncate long paths. Documented behavior. */ - if (namelen > sizeof(saddr.sun_path)) - namelen = sizeof(saddr.sun_path); + if (namelen > sizeof(saddr.up.path)) + namelen = sizeof(saddr.up.path); /* Already bound? */ if (uv__stream_fd(handle) >= 0) @@ -125,10 +137,10 @@ int uv_pipe_bind2(uv_pipe_t* handle, sockfd = err; memset(&saddr, 0, sizeof saddr); - memcpy(&saddr.sun_path, name, namelen); - saddr.sun_family = AF_UNIX; + memcpy(saddr.up.path, name, namelen); + saddr.sa.sa_family = AF_UNIX; - if (bind(sockfd, (struct sockaddr*)&saddr, addrlen)) { + if (bind(sockfd, &saddr.sa, addrlen)) { err = UV__ERR(errno); /* Convert ENOENT to EACCES for compatibility with Windows. */ if (err == UV_ENOENT) @@ -257,7 +269,7 @@ int uv_pipe_connect2(uv_connect_t* req, size_t namelen, unsigned int flags, uv_connect_cb cb) { - struct sockaddr_un saddr; + union uv__sockaddr_un saddr; int new_sock; int err; int r; @@ -276,12 +288,12 @@ int uv_pipe_connect2(uv_connect_t* req, return UV_EINVAL; if (flags & UV_PIPE_NO_TRUNCATE) - if (namelen > sizeof(saddr.sun_path)) + if (namelen > sizeof(saddr.up.path)) return UV_EINVAL; /* Truncate long paths. Documented behavior. */ - if (namelen > sizeof(saddr.sun_path)) - namelen = sizeof(saddr.sun_path); + if (namelen > sizeof(saddr.up.path)) + namelen = sizeof(saddr.up.path); new_sock = (uv__stream_fd(handle) == -1); @@ -293,8 +305,8 @@ int uv_pipe_connect2(uv_connect_t* req, } memset(&saddr, 0, sizeof saddr); - memcpy(&saddr.sun_path, name, namelen); - saddr.sun_family = AF_UNIX; + memcpy(saddr.up.path, name, namelen); + saddr.sa.sa_family = AF_UNIX; if (*name == '\0') addrlen = offsetof(struct sockaddr_un, sun_path) + namelen; @@ -355,7 +367,7 @@ static int uv__pipe_getsockpeername(const uv_pipe_t* handle, #else static const int is_linux = 0; #endif - struct sockaddr_un sa; + union uv__sockaddr_un sa; socklen_t addrlen; size_t slop; char* p; @@ -376,15 +388,15 @@ static int uv__pipe_getsockpeername(const uv_pipe_t* handle, } slop = 1; - if (is_linux && sa.sun_path[0] == '\0') { + if (is_linux && sa.up.path[0] == '\0') { /* Linux abstract namespace. Not zero-terminated. */ slop = 0; addrlen -= offsetof(struct sockaddr_un, sun_path); } else { - p = memchr(sa.sun_path, '\0', sizeof(sa.sun_path)); + p = memchr(sa.up.path, '\0', sizeof(sa.up.path)); if (p == NULL) - p = ARRAY_END(sa.sun_path); - addrlen = p - sa.sun_path; + p = ARRAY_END(sa.up.path); + addrlen = p - sa.up.path; } if ((size_t)addrlen + slop > *size) { @@ -392,7 +404,7 @@ static int uv__pipe_getsockpeername(const uv_pipe_t* handle, return UV_ENOBUFS; } - memcpy(buffer, sa.sun_path, addrlen); + memcpy(buffer, sa.up.path, addrlen); *size = addrlen; /* only null-terminate if it's not an abstract socket */ diff --git a/test/test-list.h b/test/test-list.h index da4bbf7da..4e8ce1aba 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -219,6 +219,7 @@ TEST_DECLARE (pipe_getsockname) TEST_DECLARE (pipe_getsockname_abstract) TEST_DECLARE (pipe_getsockname_autobind) TEST_DECLARE (pipe_getsockname_blocking) +TEST_DECLARE (pipe_getsockname_long_path) TEST_DECLARE (pipe_pending_instances) TEST_DECLARE (pipe_sendmsg) TEST_DECLARE (pipe_server_close) @@ -856,6 +857,7 @@ TASK_LIST_START TEST_ENTRY (pipe_getsockname_abstract) TEST_ENTRY (pipe_getsockname_autobind) TEST_ENTRY (pipe_getsockname_blocking) + TEST_ENTRY (pipe_getsockname_long_path) TEST_ENTRY (pipe_pending_instances) TEST_ENTRY (pipe_sendmsg) diff --git a/test/test-pipe-getsockname.c b/test/test-pipe-getsockname.c index 3be30e674..af24553c2 100644 --- a/test/test-pipe-getsockname.c +++ b/test/test-pipe-getsockname.c @@ -26,6 +26,8 @@ #include #ifndef _WIN32 +# include +# include # include /* close */ #else # include @@ -368,3 +370,52 @@ TEST_IMPL(pipe_getsockname_blocking) { MAKE_VALGRIND_HAPPY(uv_default_loop()); 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 +}