unix: set close-on-exec flag on received fds
Set the close-on-exec flag on file descriptors that we've received with recvmsg() so we don't leak them when calling fork() afterwards. On Linux, we use the MSG_CMSG_CLOEXEC flag when supported (2.6.23 and up.) On older Linux versions and other platforms, we walk the received file descriptors and set the close-on-exec flag for each fd manually. That won't entirely avoid race conditions when other threads call fork() or clone() but at least we're less likely to leak file descriptors now.
This commit is contained in:
parent
86b5c1ef1c
commit
e9f75fb146
@ -542,6 +542,44 @@ int uv__dup(int fd) {
|
||||
}
|
||||
|
||||
|
||||
ssize_t uv__recvmsg(int fd, struct msghdr* msg, int flags) {
|
||||
struct cmsghdr* cmsg;
|
||||
ssize_t rc;
|
||||
int* pfd;
|
||||
int* end;
|
||||
#if defined(__linux__)
|
||||
static int no_msg_cmsg_cloexec;
|
||||
if (no_msg_cmsg_cloexec == 0) {
|
||||
rc = recvmsg(fd, msg, flags | 0x40000000); /* MSG_CMSG_CLOEXEC */
|
||||
if (rc != -1)
|
||||
return rc;
|
||||
if (errno != EINVAL)
|
||||
return -errno;
|
||||
rc = recvmsg(fd, msg, flags);
|
||||
if (rc == -1)
|
||||
return -errno;
|
||||
no_msg_cmsg_cloexec = 1;
|
||||
} else {
|
||||
rc = recvmsg(fd, msg, flags);
|
||||
}
|
||||
#else
|
||||
rc = recvmsg(fd, msg, flags);
|
||||
#endif
|
||||
if (rc == -1)
|
||||
return -errno;
|
||||
if (msg->msg_controllen == 0)
|
||||
return rc;
|
||||
for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; cmsg = CMSG_NXTHDR(msg, cmsg))
|
||||
if (cmsg->cmsg_type == SCM_RIGHTS)
|
||||
for (pfd = (int*) CMSG_DATA(cmsg),
|
||||
end = (int*) ((char*) cmsg + cmsg->cmsg_len);
|
||||
pfd < end;
|
||||
pfd += 1)
|
||||
uv__cloexec(*pfd, 1);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
int uv_cwd(char* buffer, size_t size) {
|
||||
if (buffer == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
@ -139,6 +139,7 @@ int uv__close(int fd);
|
||||
int uv__cloexec(int fd, int set);
|
||||
int uv__socket(int domain, int type, int protocol);
|
||||
int uv__dup(int fd);
|
||||
ssize_t uv__recvmsg(int fd, struct msghdr *msg, int flags);
|
||||
void uv__make_close_pending(uv_handle_t* handle);
|
||||
|
||||
void uv__io_init(uv__io_t* w, uv__io_cb cb, int fd);
|
||||
|
||||
@ -1007,7 +1007,7 @@ static void uv__read(uv_stream_t* stream) {
|
||||
msg.msg_control = (void*) cmsg_space;
|
||||
|
||||
do {
|
||||
nread = recvmsg(uv__stream_fd(stream), &msg, 0);
|
||||
nread = uv__recvmsg(uv__stream_fd(stream), &msg, 0);
|
||||
}
|
||||
while (nread < 0 && errno == EINTR);
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user