[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [PATCH] Add support to send file descriptors over Unix sockets
From: |
Emilio Pozuelo Monfort |
Subject: |
Re: [PATCH] Add support to send file descriptors over Unix sockets |
Date: |
Wed, 11 Aug 2010 19:02:12 +0200 |
User-agent: |
Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.11) Gecko/20100805 Icedove/3.0.6 |
Hi,
On 01/08/10 21:02, Carl Fredrik Hammar wrote:
> On Tue, Jul 27, 2010 at 08:08:36PM +0200, Emilio Pozuelo Monfort wrote:
>>
>> 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.
>
> OK, I feel I could have been bit more thorough with this review
> but I found plenty of things to keep you busy none the less. ;-)
> First, a couple of overall points.
>
> What about CTTYs? To be honest, I don't know much about them myself.
> They sound like something very process specific so I don't *think* we need
> to transfer anything, but do we need to set them to something on receive?
> I don't have time to investigate further ATM. Could you investigate,
> and e.g. see what happens in Linux?
I haven't done anything in this regard per Roland and Samuel's replies.
> Another thing that crossed my mind is what'll happen if SCM_CREDS is
> also sent in the future? Because it also involves port, your code will
> fail because of the j != nports test. I think this is acceptable for
> now since the current code just fail silently anyway.
Right now we don't support it so if you send it won't fail. When we add
SCM_CREDS support, the patch that adds it can change that check (e.g.
using an nrights and an ncreds variables), so I believe it's fine for now.
>> The attached testcase runs fine with the #if set to 1 (i.e. sending
>> socket fds).
>
> Could you also make use of the sent fds so we can be absolutely sure
> it works?
Good idea. I've done so in the attached testcase, writing an int in one
socket and reading it on the other, and it works fine.
> I also just realized that you'll have to restore fds[i] at least on EINTR,
> so the caller can retry, but you might as well do it on all errors to
> be safe. Also, don't forget to comment tricky requirements like this.
Sorry, I don't understand what you mean here.
Regards,
Emilio
>From 1b911148009f696717da0b676d6d10af85d5aefb 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 | 73 ++++++++++++++++++++++++-----
2 files changed, 166 insertions(+), 15 deletions(-)
diff --git a/sysdeps/mach/hurd/recvmsg.c b/sysdeps/mach/hurd/recvmsg.c
index 33897b8..0935c79 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,35 @@ __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;
+ 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 +158,86 @@ __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++)
+ {
+ err = reauthenticate (ports[i], &newports[i]);
+ __mach_port_deallocate (__mach_task_self (), ports[i]);
+ if (err)
+ {
+ for (j = 0; j < i; j++)
+ __mach_port_deallocate (__mach_task_self (), newports[j]);
+ for (j = i+1; j < nports; j++)
+ __mach_port_deallocate (__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. */
+ fds[i] = _hurd_intern_fd (newports[j++], fds[i], 0);
+ if (fds[i] == -1)
+ {
+ err = errno;
+ goto cleanup;
+ }
+ }
+ }
+ }
+
+ if (j != nports)
+ err = EGRATUITOUS;
+
+ if (err)
+ cleanup:
+ {
+ /* Clean up all the file descriptors. */
+ 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_deallocate (__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..fb8dd2d 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;
@@ -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,46 @@ __libc_sendmsg (int fd, const struct msghdr *message, int
flags)
}
}
+ /* SCM_RIGHTS support: get the number of fds to send. */
+ 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)
+ {
+ 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;
+ }));
+
+ if (err)
+ goto out;
+ }
+ }
+ }
+
if (addr)
{
if (addr->sun_family == AF_LOCAL)
@@ -110,9 +155,8 @@ __libc_sendmsg (int fd, const struct msghdr *message, int
flags)
file_t file = __file_name_lookup (addr->sun_path, 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);
@@ -120,11 +164,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;
@@ -143,8 +183,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);
@@ -153,11 +194,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)
--
1.7.1
glib-unix-fd-sendmsg-SCM_RIGHTS.c
Description: Text Data