unix: remove TOCTOU issues from uv_pipe_chmod

Use fchmod() on platforms that support it on UNIX sockets. Only fall
back to chmod() on platforms that don't (macOS and the BSDs.)

Remove the stat + chmod dance from the fallback and just call chmod
directly, because that's another source of TOCTOU issues.

Fixes: https://github.com/libuv/libuv/issues/2040
This commit is contained in:
Ben Noordhuis 2025-04-07 09:34:55 +02:00
parent 745c68d4ea
commit 92f8467653

View File

@ -447,13 +447,17 @@ uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle) {
int uv_pipe_chmod(uv_pipe_t* handle, int mode) {
unsigned desired_mode;
struct stat pipe_stat;
char name_buffer[1 + UV__PATH_MAX];
int desired_mode;
size_t name_len;
int fd;
int r;
if (handle == NULL || uv__stream_fd(handle) == -1)
if (handle == NULL)
return UV_EBADF;
fd = uv__stream_fd(handle);
if (fd == -1)
return UV_EBADF;
if (mode != UV_READABLE &&
@ -461,31 +465,27 @@ int uv_pipe_chmod(uv_pipe_t* handle, int mode) {
mode != (UV_WRITABLE | UV_READABLE))
return UV_EINVAL;
/* Unfortunately fchmod does not work on all platforms, we will use chmod. */
name_len = sizeof(name_buffer);
r = uv_pipe_getsockname(handle, name_buffer, &name_len);
if (r != 0)
return r;
/* stat must be used as fstat has a bug on Darwin */
if (uv__stat(name_buffer, &pipe_stat) == -1)
return UV__ERR(errno);
desired_mode = 0;
if (mode & UV_READABLE)
desired_mode |= S_IRUSR | S_IRGRP | S_IROTH;
if (mode & UV_WRITABLE)
desired_mode |= S_IWUSR | S_IWGRP | S_IWOTH;
/* Exit early if pipe already has desired mode. */
if ((pipe_stat.st_mode & desired_mode) == desired_mode)
return 0;
/* fchmod on macOS and (Free|Net|Open)BSD does not support UNIX sockets. */
if (fchmod(fd, desired_mode))
if (errno != EINVAL)
return UV__ERR(errno);
pipe_stat.st_mode |= desired_mode;
/* Fall back to chmod. */
name_len = sizeof(name_buffer);
r = uv_pipe_getsockname(handle, name_buffer, &name_len);
if (r != 0)
return r;
r = chmod(name_buffer, pipe_stat.st_mode);
if (chmod(name_buffer, desired_mode))
return UV__ERR(errno);
return r != -1 ? 0 : UV__ERR(errno);
return 0;
}