In order to avoid a race add a recvfd(int fd, int flags). flags could be O_CLOEXEC. --- lib/passfd.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- lib/passfd.h | 1 + m4/afunix.m4 | 22 +++++++++++++++++++++ modules/passfd | 1 + 4 files changed, 81 insertions(+), 1 deletions(-)
diff --git a/lib/passfd.c b/lib/passfd.c index 2f84a13..649ee0b 100644 --- a/lib/passfd.c +++ b/lib/passfd.c @@ -17,6 +17,7 @@ /* Specification. */ #include <errno.h> +#include <fcntl.h> #include <stddef.h> #include <stdlib.h> #include <string.h> @@ -33,6 +34,8 @@ #include <winsock2.h> #endif +#include "cloexec.h" + /* Sendfd sends the file descriptor fd along the socket to a process calling recvfd on the other end. @@ -81,6 +84,7 @@ sendfd (int sock, int fd) return 0; } + /* Sendfd sends the file descriptor fd along the socket to a process calling recvfd on the other end. @@ -89,12 +93,30 @@ sendfd (int sock, int fd) int recvfd (int sock) { + return recvfd2 (sock, 0); +} + + +/* Sendfd sends the file descriptor fd along the socket + to a process calling recvfd on the other end. + + return -1 in case of error, fd on success +*/ +int +recvfd2 (int sock, int flags) +{ char recv = 0; const int mone = -1; int fd; struct iovec iov[1]; struct msghdr msg; + if (flags != 0 && flags != O_CLOEXEC) + { + errno = EINVAL; + return -1; + } + /* send at least one char */ iov[0].iov_base = &recv; iov[0].iov_len = 1; @@ -107,6 +129,11 @@ recvfd (int sock) #ifdef HAVE_UNIXSOCKET_SCM_RIGHTS_BSD44_WAY struct cmsghdr *cmsg; char buf[CMSG_SPACE (sizeof (fd))]; +#ifdef HAVE_MSG_CMSG_CLOEXEC + int flags_recvmsg = (flags == O_CLOEXEC ? MSG_CMSG_CLOEXEC : 0); +#else + int flags_recvmsg = 0; +#endif msg.msg_control = buf; msg.msg_controllen = sizeof (buf); @@ -118,7 +145,7 @@ recvfd (int sock) memcpy (CMSG_DATA (cmsg), &mone, sizeof (mone)); msg.msg_controllen = cmsg->cmsg_len; - if (recvmsg (sock, &msg, 0) < 0) + if (recvmsg (sock, &msg, flags_recvmsg) < 0) return -1; cmsg = CMSG_FIRSTHDR (&msg); @@ -132,13 +159,42 @@ recvfd (int sock) } memcpy (&fd, CMSG_DATA (cmsg), sizeof (fd)); + +#ifndef HAVE_MSG_CMSG_CLOEXEC + /* set cloexec */ + if (flags == O_CLOEXEC) + { + if (set_cloexec_flag (fd, flags == O_CLOEXEC) == -1) + { + int saved_errno = errno; + (void) close (fd); + errno = saved_errno; + return -1; + } + } +#endif + return fd; + #elif HAVE_UNIXSOCKET_SCM_RIGHTS_BSD43_WAY msg.msg_accrights = &fd; msg.msg_accrightslen = sizeof (fd); if (recvmsg (sock, &msg, 0) < 0) return -1; + + /* set CLOEXEC */ + if (flags == O_CLOEXEC) + { + if (set_cloexec_flag (fd, flags == O_CLOEXEC) == -1) + { + int saved_errno = errno; + (void) close (fd); + errno = saved_errno; + return -1; + } + } return fd; + #else errno = ENOSYS; return -1; diff --git a/lib/passfd.h b/lib/passfd.h index 13eb3b1..f05afb5 100644 --- a/lib/passfd.h +++ b/lib/passfd.h @@ -18,4 +18,5 @@ #define PASSFD_H_ 1 int sendfd (int sock, int fd); int recvfd (int sock); +int recvfd2 (int sock, int flags); #endif diff --git a/m4/afunix.m4 b/m4/afunix.m4 index a88b2d4..f3f3cd9 100644 --- a/m4/afunix.m4 +++ b/m4/afunix.m4 @@ -92,5 +92,27 @@ AC_DEFUN([gl_SOCKET_AFUNIX], if test $gl_cv_socket_unix_scm_rights_bsd43_way = yes; then AC_DEFINE([HAVE_UNIXSOCKET_SCM_RIGHTS_BSD43_WAY], [1], [Define to 1 if fd could be send/received in the BSD4.3 way.]) fi + + AC_MSG_CHECKING([for UNIX domain sockets SCM_RIGHT recvmsg() MSG_CMSG_CLOEXEC flags]) + AC_CACHE_VAL([gl_cv_socket_unix_scm_rights_msg_cmsg_cloexec], + [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/types.h> +#ifdef HAVE_SYS_SOCKET_H +#include <sys/socket.h> +#endif +#ifdef HAVE_SYS_UN_H +#include <sys/un.h> +#endif +#ifdef HAVE_WINSOCK2_H +#include <winsock2.h> +#endif +]], +[[int flags; + flags = MSG_CMSG_CLOEXEC; + if (&flags) return 0;]])], + gl_cv_socket_unix_scm_rights_msg_cmsg_cloexec=yes, gl_cv_socket_unix_scm_rights_msg_cmsg_cloexec=no)]) + AC_MSG_RESULT([$gl_cv_socket_unix_scm_rights_msg_cmsg_cloexec]) + if test $gl_cv_socket_unix_scm_rights_msg_cmsg_cloexec = yes; then + AC_DEFINE([HAVE_MSG_CMSG_CLOEXEC], [1], [Define to 1 if recvmsg could be specified with MSG_CMSG_CLOEXEC.]) + fi ]) diff --git a/modules/passfd b/modules/passfd index 43922e1..f69ecf8 100644 --- a/modules/passfd +++ b/modules/passfd @@ -8,6 +8,7 @@ lib/passfd.c lib/passfd.h Depends-on: +cloexec errno sys_socket extensions -- 1.7.2.3