bug-hurd
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH] Add support to send file descriptors over Unix sockets


From: Emilio Pozuelo Monfort
Subject: [PATCH] Add support to send file descriptors over Unix sockets
Date: Tue, 27 Jul 2010 20:08:36 +0200
User-agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.10) Gecko/20100619 Icedove/3.0.5

Hi,

This patch adds support for SCM_RIGHTS to glibc. It works fine
when sending file descriptors from a socket() or a socketpair() call,
but not from e.g. an open() call, as I've mentioned in another mail.
That's not because of my patch though.

The attached testcase runs fine with the #if set to 1 (i.e. sending
socket fds).

Regards,
Emilio

>From bd70862e18ba6c2a404917bffef72de367a3b132 Mon Sep 17 00:00:00 2001
From: Emilio Pozuelo Monfort <pochu27@gmail.com>
Date: Sat, 17 Jul 2010 22:09:13 +0200
Subject: [PATCH] Add support to send file descriptors over Unix sockets

---
 sysdeps/mach/hurd/recvmsg.c |  108 +++++++++++++++++++++++++++++++++++++++++-
 sysdeps/mach/hurd/sendmsg.c |   53 ++++++++++++++++++++-
 2 files changed, 155 insertions(+), 6 deletions(-)

diff --git a/sysdeps/mach/hurd/recvmsg.c b/sysdeps/mach/hurd/recvmsg.c
index 33897b8..cda246e 100644
--- a/sysdeps/mach/hurd/recvmsg.c
+++ b/sysdeps/mach/hurd/recvmsg.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001, 2002 Free Software Foundation, Inc.
+/* Copyright (C) 2001, 2002, 2010 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -33,13 +33,37 @@ __libc_recvmsg (int fd, struct msghdr *message, int flags)
   addr_port_t aport;
   char *data = NULL;
   mach_msg_type_number_t len = 0;
-  mach_port_t *ports;
+  mach_port_t *ports, *newports;
   mach_msg_type_number_t nports = 0;
+  struct cmsghdr *cmsg;
   char *cdata = NULL;
   mach_msg_type_number_t clen = 0;
   size_t amount;
   char *buf;
-  int i;
+  int nfds, *fds;
+  int i, j;
+
+  auth_t auth;
+
+  error_t reauthenticate (mach_port_t port, mach_port_t *result)
+    {
+      error_t err;
+      mach_port_t ref;
+      if (*result != MACH_PORT_NULL)
+       return 0;
+      ref = __mach_reply_port ();
+      do
+       err = __io_reauthenticate (port, ref, MACH_MSG_TYPE_MAKE_SEND);
+      while (err == EINTR);
+      if (!err)
+       do
+         err = __auth_user_authenticate (auth,
+                                         ref, MACH_MSG_TYPE_MAKE_SEND,
+                                         result);
+       while (err == EINTR);
+      __mach_port_destroy (__mach_task_self (), ref);
+      return err;
+    }
 
   /* Find the total number of bytes to be read.  */
   amount = 0;
@@ -136,6 +160,84 @@ __libc_recvmsg (int fd, struct msghdr *message, int flags)
     message->msg_controllen = clen;
   memcpy (message->msg_control, cdata, message->msg_controllen);
 
+  /* SCM_RIGHTS ports.  */
+  if (nports > 0)
+    {
+      auth = getauth ();
+      newports = __alloca (nports * sizeof (mach_port_t));
+
+      /* Reauthenticate all ports here.  */
+      for (i = 0; i < nports; i++)
+       {
+         newports[i] = MACH_PORT_NULL;
+         err = reauthenticate (ports[i], &newports[i]);
+         __mach_port_destroy (__mach_task_self (), ports[i]);
+         if (err)
+           {
+             for (j = 0; j < i; j++)
+               __mach_port_destroy (__mach_task_self (), newports[j]);
+             for (j = i+1; j < nports; j++)
+               __mach_port_destroy (__mach_task_self (), ports[j]);
+
+             __vm_deallocate (__mach_task_self (), (vm_address_t) cdata, clen);
+             __hurd_fail (err);
+           }
+       }
+
+      j = 0;
+      for (cmsg = CMSG_FIRSTHDR (message);
+          cmsg;
+          cmsg = CMSG_NXTHDR (message, cmsg))
+       {
+         if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS)
+           {
+             fds = (int *) CMSG_DATA (cmsg);
+             nfds = (cmsg->cmsg_len - CMSG_ALIGN (sizeof (struct cmsghdr)))
+                    / sizeof (int);
+
+             for (i = 0; i < nfds && j < nports; i++)
+               {
+                 /* The fd's flags are passed in the control data.  */
+                 if ((fds[i] = _hurd_intern_fd (newports[j++], fds[i], 0))
+                     == -1)
+                   {
+                     err = errno;
+                     goto cleanup;
+                   }
+               }
+           }
+       }
+      if (j != nports)
+       /* Clean up all the file descriptors.  */
+       {
+         err = EGRATUITOUS;
+ cleanup:
+         nports = j;
+         j = 0;
+         for (cmsg = CMSG_FIRSTHDR (message);
+              cmsg;
+              cmsg = CMSG_NXTHDR (message, cmsg))
+           {
+             if (cmsg->cmsg_level == SOL_SOCKET
+                 && cmsg->cmsg_type == SCM_RIGHTS)
+               {
+                 fds = (int *) CMSG_DATA (cmsg);
+                 nfds = (cmsg->cmsg_len
+                         - CMSG_ALIGN (sizeof (struct cmsghdr)))
+                         / sizeof (int);
+                 for (i = 0; i < nfds && j < nports; i++, j++)
+                   _hurd_fd_close (_hurd_fd_get (fds[i]));
+               }
+           }
+
+         for (; j < nports; j++)
+           __mach_port_destroy (__mach_task_self (), newports[j]);
+
+         __vm_deallocate (__mach_task_self (), (vm_address_t) cdata, clen);
+         __hurd_fail (err);
+       }
+    }
+
   __vm_deallocate (__mach_task_self (), (vm_address_t) cdata, clen);
 
   return (buf - data);
diff --git a/sysdeps/mach/hurd/sendmsg.c b/sysdeps/mach/hurd/sendmsg.c
index 118fd59..7c6c666 100644
--- a/sysdeps/mach/hurd/sendmsg.c
+++ b/sysdeps/mach/hurd/sendmsg.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001,2002,2004 Free Software Foundation, Inc.
+/* Copyright (C) 2001,2002,2004,2010 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -32,6 +32,10 @@ ssize_t
 __libc_sendmsg (int fd, const struct msghdr *message, int flags)
 {
   error_t err = 0;
+  struct cmsghdr *cmsg;
+  mach_port_t *ports = NULL;
+  mach_msg_type_number_t nports = 0;
+  int *fds, nfds;
   struct sockaddr_un *addr = message->msg_name;
   socklen_t addr_len = message->msg_namelen;
   addr_port_t aport = MACH_PORT_NULL;
@@ -101,6 +105,48 @@ __libc_sendmsg (int fd, const struct msghdr *message, int 
flags)
        }
     }
 
+  /* SCM_RIGHTS support: get the number of fds to send.  */
+  for (cmsg = CMSG_FIRSTHDR (message); cmsg; cmsg = CMSG_NXTHDR (message, 
cmsg))
+    if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS)
+      nports += (cmsg->cmsg_len - CMSG_ALIGN (sizeof (struct cmsghdr)))
+               / sizeof (int);
+
+  if (nports)
+    ports = __alloca (nports * sizeof (mach_port_t));
+
+  nports = 0;
+  for (cmsg = CMSG_FIRSTHDR (message); cmsg; cmsg = CMSG_NXTHDR (message, 
cmsg))
+    {
+      if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS)
+       {
+         fds = (int *) CMSG_DATA (cmsg);
+         nfds = (cmsg->cmsg_len - CMSG_ALIGN (sizeof (struct cmsghdr)))
+                / sizeof (int);
+
+         for (i = 0; i < nfds; i++)
+           {
+             err = HURD_DPORT_USE
+               (fds[i],
+                ({
+                  err = __io_restrict_auth (port, &ports[nports++],
+                                            0, 0, 0, 0);
+                  /* We pass the flags in the control data.  */
+                  fds[i] = descriptor->flags;
+                }));
+
+             if (err)
+               {
+                 for (i = 0; i < nports - 1; i++)
+                   __mach_port_deallocate (__mach_task_self (), ports[i]);
+
+                 if (dealloc)
+                   __vm_deallocate (__mach_task_self (), data.addr, len);
+                 __hurd_fail (err);
+               }
+           }
+       }
+    }
+
   if (addr)
     {
       if (addr->sun_family == AF_LOCAL)
@@ -143,8 +189,9 @@ __libc_sendmsg (int fd, const struct msghdr *message, int 
flags)
                              /* Send the data.  */
                              err = __socket_send (port, aport,
                                                   flags, data.ptr, len,
-                                                  NULL,
-                                                  MACH_MSG_TYPE_COPY_SEND, 0,
+                                                  ports,
+                                                  MACH_MSG_TYPE_MOVE_SEND,
+                                                  nports,
                                                   message->msg_control,
                                                   message->msg_controllen,
                                                   &amount);
-- 
1.7.1

Attachment: glib-unix-fd-sendmsg-SCM_RIGHTS.c
Description: Text Data


reply via email to

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