

A tiny library to send file descriptors across processes - nkurz
https://github.com/sharvil/flingfd

======
latitude
Alternatively -

    
    
      int send_fd(int conn, int fd_to_send)
      {
      	struct msghdr msg = { 0 };
      	struct cmsghdr * hdr;
      	char buf[CMSG_SPACE(sizeof(int))];
      
      	msg.msg_control = buf;
      	msg.msg_controllen = sizeof(buf);
      
      	hdr = CMSG_FIRSTHDR(&msg);
      	hdr->cmsg_len = CMSG_LEN(sizeof(int));
      	hdr->cmsg_level = SOL_SOCKET;
      	hdr->cmsg_type = SCM_RIGHTS;
      	*(int*)CMSG_DATA(hdr) = fd_to_send;
      
      	return sendmsg(conn, &msg, 0);
      }
    

To those wondering why and when this is needed - it is useful for cases when
your primary process lacks rights required to open a file or a device (!). So
another, privileged process does the open on its behalf and sends the
resulting file descriptor to the primary process for processing.

~~~
archgoon
> So another, privileged process does the open on its behalf and sends the
> resulting file descriptor to the primary process for processing.

I must be misunderstanding something. I assume that the unprivileged process
still cannot actually read the file, otherwise you could access unauthorized
open files by going through every possible file descriptor. What processing
can the unprivileged process do? Keep track processes that have open files?

~~~
nkurz
The only part you might be missing is that the 'send_fd' command needs to be
executed by a cooperating privileged process that 'serves' the fd to the
receiver. Since the permission checks are done at the time the fd is opened
(and not repeated[1]) the receiving process has the full privileges that the
sender had: read, write, truncate, etc.

Receiving the fd via this mechanism is very different that just getting the
number of the fd. Nothing is really passed over the socket, rather behind the
scenes the kernel is remapping memory within the calling process. It's very
similar to what happens when a process 'forks' and its file descriptors are
duplicated, but with individual fd granularity.

[1] There are exceptions to this in certain device handlers that use file
interfaces, but it holds for regular files.

~~~
archgoon
Thank you (and others). I feel silly for not checking the man pages for the
macros I didn't recognize.

------
gwu78
Let us journey back in time, to the year 1995. (Technically 1.03 is from 1998,
but I'm sure that functions for passing fd's appear in every version.)

qmail-1.03:

fd.h fd_copy.c fd_copy.3 fd_move.c fd_move.3

You could find similar functions in other programs by the same author, e.g.,
ucspi-tcp, daemontools, etc.

I prefer time-tested, secure code from 1995 to the things you tend to find on
Github because this 1990's code is highly portable. It still compiles cleanly
18 years later and is not just tested on one or two systems, e.g., Linux and
OSX.

But I'm glad this made the front page. No web browser needed. No installed
scripting languages necessary. A single .c file. If only there were more like
this on Github.

------
ekimekim
A very minor gripe, but it seems weird to use the "bool success" return value
convention for one function, but the "int return, negative on error"
convention for the other.

Also there's a few places where ERRNO is going to get clobbered, eg. by
closing the socket before reporting the error back to the caller. A more
careful implementation would save errno before calling close.

Otherwise though, good simple abstraction of a relatively obscure feature.

------
spc476
I wrote something similar for sockets
([https://github.com/spc476/ipacld](https://github.com/spc476/ipacld)) but
it's Linux only, since only Linux supports passing the userid/groupid/pid of a
process across Unix domain sockets (and I use that for checking credentials).

------
justincormack
This library makes the classic error, it returns the first file descriptor
that is sent then finishes.

You can then DoS the process by sending it huge numbers of fds instead of just
one, which it will omit to close, and thus run out of file descriptors. So to
be safe you need to iterate over all the fds and close them.

------
dap
Why is it "on Linux?" Isn't it the same interface on other Unix systems (OS X,
BSD, illumos)?

~~~
bodyfour
Yeah, any modern UNIX supports the same sendmsg/SCM_RIGHTS pattern. You might
need to tweak the includes and supply your own CMSG_*() macros on some though.

Some older UNIX variants only supported the BSD4.3-style msg_accrights style
fd passing, although those are probably nearly extinct at this point.

------
chetanahuja
Can the OP please change the title to append ".. in X lines of C". It's no
longer cool to just _do_ stuff... it has to be done in an impressively small
number of lines of code to win my upvote.

------
rjzzleep
nice, i used something like this when i wanted to avoid escalating privileges
for my osx n2n client.

as far as i remember, chrome also uses this method.

alternatively you can use libancillary.

[http://www.normalesup.org/~george/comp/libancillary/](http://www.normalesup.org/~george/comp/libancillary/)

~~~
gwu78
"... my osx n2n client."

v1 or v2?

------
nly
Wayland actually provides fd passing as part of its X-like protocol / IPC
layer. Pretty nifty.

