[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH 3/4] Add a CLOEXEC recvfd
From: |
Bastien ROUCARIES |
Subject: |
[PATCH 3/4] Add a CLOEXEC recvfd |
Date: |
Mon, 7 Mar 2011 14:05:54 +0100 |
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
- [V4] Passfd, Bastien ROUCARIES, 2011/03/07
- [PATCH 2/4] sendfd, recvf pass file descriptors along Unix domain sockets, Bastien ROUCARIES, 2011/03/07
- [PATCH 4/4] Add test for passfd, Bastien ROUCARIES, 2011/03/07
- passfd on glibc, Bruno Haible, 2011/03/13
- passfd on OpenBSD, Bruno Haible, 2011/03/13
- passfd on FreeBSD, Bruno Haible, 2011/03/13