bug-gnulib
[Top][All Lists]
Advanced

[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




reply via email to

[Prev in Thread] Current Thread [Next in Thread]