commit-hurd
[Top][All Lists]
Advanced

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

[hurd, commited] hurd: Support sending file descriptors over Unix socket


From: Samuel Thibault
Subject: [hurd, commited] hurd: Support sending file descriptors over Unix sockets
Date: Sun, 29 Dec 2019 16:35:34 +0100

From: Emilio Pozuelo Monfort <address@hidden>

---
 sysdeps/mach/hurd/recvmsg.c | 97 ++++++++++++++++++++++++++++++++++++-
 sysdeps/mach/hurd/sendmsg.c | 73 +++++++++++++++++++++++-----
 2 files changed, 157 insertions(+), 13 deletions(-)

diff --git a/sysdeps/mach/hurd/recvmsg.c b/sysdeps/mach/hurd/recvmsg.c
index bb8d8305ea..622600270a 100644
--- a/sysdeps/mach/hurd/recvmsg.c
+++ b/sysdeps/mach/hurd/recvmsg.c
@@ -32,13 +32,34 @@ __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 = NULL;
   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, *opened_fds = NULL;
+  int i, ii, j;
+  int newfds;
+
+  error_t reauthenticate (mach_port_t port, mach_port_t *result)
+    {
+      error_t err;
+      mach_port_t ref;
+      ref = __mach_reply_port ();
+      do
+       err = __io_reauthenticate (port, ref, MACH_MSG_TYPE_MAKE_SEND);
+      while (err == EINTR);
+      if (!err)
+       do
+         err = __USEPORT (AUTH, __auth_user_authenticate (port,
+                                         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;
@@ -137,9 +158,81 @@ __libc_recvmsg (int fd, struct msghdr *message, int flags)
     message->msg_controllen = clen;
   memcpy (message->msg_control, cdata, message->msg_controllen);
 
+  if (nports > 0)
+    {
+      newports = __alloca (nports * sizeof (mach_port_t));
+      opened_fds = __alloca (nports * sizeof (int));
+    }
+
+  /* This counts how many ports we processed completely.  */
+  i = 0;
+  /* This counts how many new fds we create.  */
+  newfds = 0;
+
+  for (cmsg = CMSG_FIRSTHDR (message);
+       cmsg;
+       cmsg = CMSG_NXTHDR (message, cmsg))
+  {
+    if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS)
+      {
+       /* SCM_RIGHTS support.  */
+       /* The fd's flags are passed in the control data.  */
+       int *fds = (int *) CMSG_DATA (cmsg);
+       nfds = (cmsg->cmsg_len - CMSG_ALIGN (sizeof (struct cmsghdr)))
+              / sizeof (int);
+
+       for (j = 0; j < nfds; j++)
+         {
+           err = reauthenticate (ports[i], &newports[newfds]);
+           if (err)
+             goto cleanup;
+           fds[j] = opened_fds[newfds] = _hurd_intern_fd (newports[newfds],
+                                                          fds[j], 0);
+           if (fds[j] == -1)
+             {
+               err = errno;
+               __mach_port_deallocate (__mach_task_self (), newports[newfds]);
+               goto cleanup;
+             }
+           i++;
+           newfds++;
+         }
+      }
+  }
+
+  for (i = 0; i < nports; i++)
+    __mach_port_deallocate (mach_task_self (), ports[i]);
+
   __vm_deallocate (__mach_task_self (), (vm_address_t) cdata, clen);
 
   return (buf - data);
+
+cleanup:
+  /* Clean up all the file descriptors from port 0 to i-1.  */
+  if (nports > 0)
+    {
+      ii = 0;
+      newfds = 0;
+      for (cmsg = CMSG_FIRSTHDR (message);
+          cmsg;
+          cmsg = CMSG_NXTHDR (message, cmsg))
+       {
+         if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS)
+           {
+             nfds = (cmsg->cmsg_len - CMSG_ALIGN (sizeof (struct cmsghdr)))
+                    / sizeof (int);
+             for (j = 0; j < nfds && ii < i; j++, ii++, newfds++)
+             {
+               _hurd_fd_close (_hurd_fd_get (opened_fds[newfds]));
+               __mach_port_deallocate (__mach_task_self (), newports[newfds]);
+               __mach_port_deallocate (__mach_task_self (), ports[ii]);
+             }
+           }
+       }
+    }
+
+  __vm_deallocate (__mach_task_self (), (vm_address_t) cdata, clen);
+  return __hurd_fail (err);
 }
 
 weak_alias (__libc_recvmsg, recvmsg)
diff --git a/sysdeps/mach/hurd/sendmsg.c b/sysdeps/mach/hurd/sendmsg.c
index af1b9d17a3..0c19b3223c 100644
--- a/sysdeps/mach/hurd/sendmsg.c
+++ b/sysdeps/mach/hurd/sendmsg.c
@@ -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;
@@ -44,6 +48,7 @@ __libc_sendmsg (int fd, const struct msghdr *message, int 
flags)
   mach_msg_type_number_t len;
   mach_msg_type_number_t amount;
   int dealloc = 0;
+  int socketrpc = 0;
   int i;
 
   /* Find the total number of bytes to be written.  */
@@ -101,6 +106,48 @@ __libc_sendmsg (int fd, const struct msghdr *message, int 
flags)
        }
     }
 
+  /* Allocate enough room for ports.  */
+  cmsg = CMSG_FIRSTHDR (message);
+  for (; 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)
+       {
+         /* SCM_RIGHTS support: send FDs.   */
+         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);
+                  if (! err)
+                    nports++;
+                  /* We pass the flags in the control data.  */
+                  fds[i] = descriptor->flags;
+                  err;
+                }));
+
+             if (err)
+               goto out;
+           }
+       }
+    }
+
   if (addr)
     {
       if (addr->sun_family == AF_LOCAL)
@@ -111,9 +158,8 @@ __libc_sendmsg (int fd, const struct msghdr *message, int 
flags)
          file_t file = __file_name_lookup (name, 0, 0);
          if (file == MACH_PORT_NULL)
            {
-             if (dealloc)
-               __vm_deallocate (__mach_task_self (), data.addr, len);
-             return -1;
+             err = errno;
+             goto out;
            }
          err = __ifsock_getsockaddr (file, &aport);
          __mach_port_deallocate (__mach_task_self (), file);
@@ -121,11 +167,7 @@ __libc_sendmsg (int fd, const struct msghdr *message, int 
flags)
            /* The file did not grok the ifsock protocol.  */
            err = ENOTSOCK;
          if (err)
-           {
-             if (dealloc)
-               __vm_deallocate (__mach_task_self (), data.addr, len);
-             return __hurd_fail (err);
-           }
+           goto out;
        }
       else
        err = EIEIO;
@@ -144,8 +186,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_COPY_SEND,
+                                                  nports,
                                                   message->msg_control,
                                                   message->msg_controllen,
                                                   &amount);
@@ -154,11 +197,19 @@ __libc_sendmsg (int fd, const struct msghdr *message, int 
flags)
                            }
                          err;
                        }));
+  socketrpc = 1;
+
+ out:
+  for (i = 0; i < nports; i++)
+    __mach_port_deallocate (__mach_task_self (), ports[i]);
 
   if (dealloc)
     __vm_deallocate (__mach_task_self (), data.addr, len);
 
-  return err ? __hurd_sockfail (fd, flags, err) : amount;
+  if (socketrpc)
+    return err ? __hurd_sockfail (fd, flags, err) : amount;
+  else
+    return __hurd_fail (err);
 }
 
 weak_alias (__libc_sendmsg, sendmsg)
-- 
2.24.0




reply via email to

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