diff --git a/src/unix/pipe.c b/src/unix/pipe.c index b9dd14849..53cdeb349 100644 --- a/src/unix/pipe.c +++ b/src/unix/pipe.c @@ -52,6 +52,10 @@ int uv_pipe_init(uv_loop_t* loop, uv_pipe_t* handle, int ipc) { int uv_pipe_init_ex(uv_loop_t* loop, uv_pipe_t* handle, unsigned int flags) { int ipc = (flags & UV_PIPE_INIT_IPC) != 0; + if (flags & ~(UV_PIPE_INIT_IPC | UV_PIPE_INIT_WIN_UDS)) + return UV_EINVAL; + if (flags & UV_PIPE_INIT_WIN_UDS) + return UV_EINVAL; uv__stream_init(loop, (uv_stream_t*)handle, UV_NAMED_PIPE); handle->shutdown_req = NULL; diff --git a/src/win/pipe.c b/src/win/pipe.c index d994fe9ed..4fb9a95cc 100644 --- a/src/win/pipe.c +++ b/src/win/pipe.c @@ -35,9 +35,13 @@ #include #include +/* Runtime feature check: prefer if (UV__ENABLE_WIN_UDS_PIPE) over #ifdef + * so the compiler checks both code paths even when not enabled. */ #if defined(_WIN32) && !defined(__MINGW32__) && !defined(__MINGW64__) -#define UV__ENABLE_WIN_UDS_PIPE #include +#define UV__ENABLE_WIN_UDS_PIPE 1 +#else +#define UV__ENABLE_WIN_UDS_PIPE 0 #endif /* A zero-size buffer for use by uv_pipe_read */ @@ -126,7 +130,7 @@ static int uv__win_uds_pipe_file_exists(const char* path, int* exists) { *exists = (attrib != INVALID_FILE_ATTRIBUTES && !(attrib & FILE_ATTRIBUTE_DIRECTORY)); - free(wpath); + uv__free(wpath); return 0; } @@ -169,6 +173,10 @@ int uv_pipe_init_ex(uv_loop_t* loop, uv_pipe_t* handle, unsigned int flags) { int ipc = (flags & UV_PIPE_INIT_IPC) != 0; int uds = (flags & UV_PIPE_INIT_WIN_UDS) != 0; + /* Reject unknown flags for forwards compatibility. */ + if (flags & ~(UV_PIPE_INIT_IPC | UV_PIPE_INIT_WIN_UDS)) + return UV_EINVAL; + if (ipc && uds) { /* Unix domain socket on Windows doesn't work with IPC mode currently. */ return EINVAL; @@ -614,7 +622,7 @@ uds_pipe: } -#if defined(UV__ENABLE_WIN_UDS_PIPE) +#if UV__ENABLE_WIN_UDS_PIPE static int pipe_alloc_accept_unix_domain_socket(uv_loop_t* loop, uv_pipe_t* handle, uv_pipe_accept_t* req, const char* name, BOOL firstInstance) { int ret = 0, err = 0; @@ -639,7 +647,7 @@ static int pipe_alloc_accept_unix_domain_socket(uv_loop_t* loop, uv_pipe_t* hand } addr.sun_family = AF_UNIX; - ret = uv__strscpy(addr.sun_path, name, UNIX_PATH_MAX); + ret = uv__strscpy(addr.sun_path, name, sizeof(addr.sun_path)); if (ret < 0) { return ret; } @@ -656,6 +664,7 @@ static int pipe_alloc_accept_unix_domain_socket(uv_loop_t* loop, uv_pipe_t* hand loop->iocp, (ULONG_PTR) handle, 0) == NULL) { + closesocket(server_fd); return GetLastError(); } @@ -877,23 +886,19 @@ int uv_pipe_bind2(uv_pipe_t* handle, use_uds_pipe = (handle->flags & UV_HANDLE_WIN_UDS_PIPE) != 0; -#if !defined(UV__ENABLE_WIN_UDS_PIPE) +#if UV__ENABLE_WIN_UDS_PIPE + /* Since UDS on Windows is a new feature, always reject too-long paths + * (no truncation for backwards compatibility needed). */ + if (use_uds_pipe) { + if (namelen >= sizeof(((struct sockaddr_un*) 0)->sun_path)) + return UV_EINVAL; + } +#else if (use_uds_pipe) { return UV_ENOSYS; } #endif -#if defined(UV__ENABLE_WIN_UDS_PIPE) - if (use_uds_pipe) { - if (flags & UV_PIPE_NO_TRUNCATE) - if (namelen >= UNIX_PATH_MAX) - return UV_EINVAL; - - if (namelen >= UNIX_PATH_MAX) - namelen = UNIX_PATH_MAX - 1; - } -#endif - /* Already bound? */ if (handle->flags & UV_HANDLE_BOUND) { return UV_EINVAL; @@ -937,22 +942,22 @@ int uv_pipe_bind2(uv_pipe_t* handle, req->next_pending = NULL; } - if (!use_uds_pipe) { + if (use_uds_pipe) { + /* Use unix domain socket we save the original path name copy. */ + handle->pathname = name_copy; + name_copy = NULL; + } else { /* TODO(bnoordhuis) Add converters that take a |length| parameter. */ err = uv__convert_utf8_to_utf16(name_copy, &handle->name); uv__free(name_copy); name_copy = NULL; - } else { - /* Use unix domain socket we save the original path name copy. */ - handle->pathname = name_copy; - name_copy = NULL; } if (err) { goto error; } -#if defined(UV__ENABLE_WIN_UDS_PIPE) +#if UV__ENABLE_WIN_UDS_PIPE if (use_uds_pipe) { err = uv__win_uds_pipe_file_exists(handle->pathname, &uds_file_exists); if (err) { @@ -989,9 +994,9 @@ int uv_pipe_bind2(uv_pipe_t* handle, * If this fails then there's already a pipe server for the given pipe name. */ if (!pipe_alloc_accept_named_pipe(loop, - handle, - &handle->pipe.serv.accept_reqs[0], - TRUE)) { + handle, + &handle->pipe.serv.accept_reqs[0], + TRUE)) { err = GetLastError(); if (err == ERROR_ACCESS_DENIED) { err = UV_EADDRINUSE; @@ -1095,10 +1100,11 @@ int uv_pipe_connect2(uv_connect_t* req, HANDLE pipeHandle = INVALID_HANDLE_VALUE; DWORD duplex_flags; char* name_copy; + DWORD bytes; int use_uds_pipe; -#if defined(UV__ENABLE_WIN_UDS_PIPE) +#if UV__ENABLE_WIN_UDS_PIPE int uds_file_exists; SOCKET uds_client_fd; struct sockaddr_un uds_addr_bind = {0}; @@ -1131,25 +1137,19 @@ int uv_pipe_connect2(uv_connect_t* req, use_uds_pipe = (handle->flags & UV_HANDLE_WIN_UDS_PIPE) != 0; -#if !defined(UV__ENABLE_WIN_UDS_PIPE) +#if UV__ENABLE_WIN_UDS_PIPE + /* Since UDS on Windows is a new feature, always reject too-long paths + * (no truncation for backwards compatibility needed). */ + if (use_uds_pipe) { + if (namelen >= sizeof(((struct sockaddr_un*) 0)->sun_path)) + return UV_EINVAL; + } +#else if (use_uds_pipe) { return UV_ENOSYS; } #endif -#if defined(UV__ENABLE_WIN_UDS_PIPE) - if (use_uds_pipe) { - /* https://devblogs.microsoft.com/commandline/af_unix-comes-to-windows/ */ - /* a null-terminated UTF-8 file system path */ - if (flags & UV_PIPE_NO_TRUNCATE) - if (namelen >= UNIX_PATH_MAX) - return UV_EINVAL; - - if (namelen >= UNIX_PATH_MAX) - namelen = UNIX_PATH_MAX - 1; - } -#endif - name_copy = uv__malloc(namelen + 1); if (name_copy == NULL) { return UV_ENOMEM; @@ -1168,15 +1168,15 @@ int uv_pipe_connect2(uv_connect_t* req, } uv__pipe_connection_init(handle); - if (!use_uds_pipe) { + if (use_uds_pipe) { + /* Use unix domain socket we save the original path name copy. */ + handle->pathname = name_copy; + name_copy = NULL; + } else { /* TODO(bnoordhuis) Add converters that take a |length| parameter. */ err = uv__convert_utf8_to_utf16(name_copy, &handle->name); uv__free(name_copy); name_copy = NULL; - } else { - /* Use unix domain socket we save the original path name copy. */ - handle->pathname = name_copy; - name_copy = NULL; } if (err) { @@ -1184,7 +1184,7 @@ int uv_pipe_connect2(uv_connect_t* req, goto error; } -#if defined(UV__ENABLE_WIN_UDS_PIPE) +#if UV__ENABLE_WIN_UDS_PIPE if (use_uds_pipe) { err = uv__win_uds_pipe_file_exists(handle->pathname, &uds_file_exists); if (err) { @@ -1206,7 +1206,9 @@ int uv_pipe_connect2(uv_connect_t* req, uds_addr_bind.sun_family = AF_UNIX; /* ConnectEx need to be initially bound */ - int ret = bind(uds_client_fd, (const struct sockaddr*)&uds_addr_bind, sizeof(uds_addr_bind)); + int ret = bind(uds_client_fd, + (const struct sockaddr*) &uds_addr_bind, + sizeof(uds_addr_bind)); if (ret != 0) { err = WSAGetLastError(); closesocket(uds_client_fd); @@ -1231,11 +1233,11 @@ int uv_pipe_connect2(uv_connect_t* req, uds_addr_real.sun_path[namelen] = '\0'; ret = uv_wsa_connectex(uds_client_fd, - (const struct sockaddr *)&uds_addr_real, - sizeof(struct sockaddr_un), + (const struct sockaddr*) &uds_addr_real, + sizeof(uds_addr_real), NULL, 0, - NULL, + &bytes, &req->u.io.overlapped); if (!ret) { @@ -1446,13 +1448,13 @@ static void uv__pipe_queue_accept(uv_loop_t* loop, uv_pipe_t* handle, assert(handle->flags & UV_HANDLE_LISTENING); if (!firstInstance) { -#if defined(UV__ENABLE_WIN_UDS_PIPE) +#if UV__ENABLE_WIN_UDS_PIPE if (handle->flags & UV_HANDLE_WIN_UDS_PIPE) { uds_err = pipe_alloc_accept_unix_domain_socket( loop, handle, req, handle->pathname, FALSE); if (uds_err) { SET_REQ_ERROR(req, uds_err); - uv__insert_pending_req(loop, (uv_req_t *) req); + uv__insert_pending_req(loop, (uv_req_t*) req); handle->reqs_pending++; return; } @@ -1476,6 +1478,10 @@ uds_pipe: memset(&(req->u.io.overlapped), 0, sizeof(req->u.io.overlapped)); if (handle->flags & UV_HANDLE_WIN_UDS_PIPE) { + /* AcceptEx requires dwLocalAddressLength and dwRemoteAddressLength to be + * at least 16 bytes more than the maximum address length for the transport + * protocol in use. See MSDN AcceptEx documentation. + * https://learn.microsoft.com/en-us/windows/win32/api/mswsock/nf-mswsock-acceptex */ if (!uv_wsa_acceptex((SOCKET)handle->handle, (SOCKET)req->pipeHandle, req->accept_buffer, diff --git a/src/win/winsock.c b/src/win/winsock.c index 4e4e55e40..98da2e7c2 100644 --- a/src/win/winsock.c +++ b/src/win/winsock.c @@ -35,8 +35,8 @@ struct sockaddr_in uv_addr_ip4_any_; struct sockaddr_in6 uv_addr_ip6_any_; /* WSA function pointers */ -LPFN_ACCEPTEX uv_wsa_acceptex = NULL; -LPFN_CONNECTEX uv_wsa_connectex = NULL; +LPFN_ACCEPTEX uv_wsa_acceptex; +LPFN_CONNECTEX uv_wsa_connectex; /* diff --git a/test/test-pipe-win-uds.c b/test/test-pipe-win-uds.c index f2f8f5d7d..09fd53ec1 100644 --- a/test/test-pipe-win-uds.c +++ b/test/test-pipe-win-uds.c @@ -28,17 +28,17 @@ #define UV_SUPPORTS_WIN_UDS #endif -static int use_shutdown = 0; +static int use_shutdown; static uv_shutdown_t shutdown_client; -static int close_cb_called = 0; -static int shutdown_cb_called = 0; -static int server_connect_cb_called = 0; -static int client_connect_cb_called = 0; +static int close_cb_called; +static int shutdown_cb_called; +static int server_connect_cb_called; +static int client_connect_cb_called; static uv_pipe_t pipe_server; static uv_pipe_t pipe_client; -const char pipe_test_data[] = "send test through win uds pipe"; +static const char pipe_test_data[] = "send test through win uds pipe"; static void alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) { @@ -69,7 +69,7 @@ static void after_write_cb(uv_write_t* req, int status) { static void client_connect_cb(uv_connect_t* connect_req, int status) { uv_buf_t bufs[1]; - uv_write_t *req; + uv_write_t* req; ASSERT_EQ(status, 0); client_connect_cb_called++; @@ -116,7 +116,9 @@ static void server_connect_cb(uv_stream_t* handle, int status) { int test_pipe_win_uds() { -#if defined(UV_SUPPORTS_WIN_UDS) +#ifndef UV_SUPPORTS_WIN_UDS + RETURN_SKIP("Windows-only test"); +#endif int r; uv_fs_t fs; uv_connect_t req; @@ -157,7 +159,6 @@ int test_pipe_win_uds() { ASSERT_EQ(2, close_cb_called); ASSERT_EQ(1, server_connect_cb_called); ASSERT_EQ(1, client_connect_cb_called); -#endif MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -182,7 +183,9 @@ static void bad_name_connect_cb(uv_connect_t* connect_req, int status) { TEST_IMPL(pipe_win_uds_bad_name) { -#if defined(UV_SUPPORTS_WIN_UDS) +#ifndef UV_SUPPORTS_WIN_UDS + RETURN_SKIP("Windows-only test"); +#endif int r; uv_connect_t req; uv_pipe_t pipe_server_1; @@ -210,7 +213,6 @@ TEST_IMPL(pipe_win_uds_bad_name) { // Run the loop uv_run(uv_default_loop(), UV_RUN_DEFAULT); -#endif MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0;