[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
glib-unix-fd-sendmsg-SCM_RIGHTS.c
Description: Text Data
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [PATCH] Add support to send file descriptors over Unix sockets,
Emilio Pozuelo Monfort <=