LOCAL_PEERCRED with socketpair
Nicholas Wilson
nicholas at nicholaswilson.me.uk
Thu Feb 21 14:08:12 UTC 2013
Hello,
I've noticed that getpeereid/LOCAL_PEERCRED doesn't work with sockets
created through socketpair, but only through actual listen/connect calls.
I notice that in unp_connect, we stash the peercred of the thread, then
call on to unp_connect2. In kern_socketpair, we call straight through to
unp_connect2 (through pr_usrreqs->pru_connect2), so this makes sense from
the code.
I'd like to suggest we support peercred for socketpair-created sockets.
Motivation:
1. All unix-domain STREAM sockets should be created equal. We can support
it, so why shouldn't we?
2. getpeerucred on Solaris, SO_PEERCRED on Linux, and of most relevance
MacOS's implementation of LOCAL_PEERCRED all work fine on socketpair
sockets. (A point against is that AIX's getpeereid follows the BSD
behaviour of requiring a connect/listen call.) Programmers are therefore
more likely to expect it to work than not. Apart from AIX, we're the only
people not providing this capability.
3. Real-world uses. I was actually trying to sandbox a daemon with capsicum
when I ran into this, which requires a certain amount of mucking around
with file descriptor passing. Being able to establish a channel with a
socketpair, hand it to a secure daemon, and be able to check the peer's
credentials in the daemon, is a reasonable use-case.
4. Compatibility. It's not going to break old applications to make the
change.
Patch:
--- sys/kern/uipc_syscalls.c.RELEASE-9.1-243808 2013-02-21
13:37:31.778270145 +0000
+++ sys/kern/uipc_syscalls.c 2013-02-21 13:45:58.747896673 +0000
@@ -642,6 +642,19 @@
error = soconnect2(so2, so1);
if (error)
goto free4;
+ } else if (type == SOCK_STREAM) {
+ struct unpcb *unp, *unp2;
+ unp = sotounpcb(so1);
+ unp2 = sotounpcb(so2);
+ UNP_PCB_LOCK(unp);
+ UNP_PCB_LOCK(unp2);
+ cru2x(td->td_ucred, &unp->unp_peercred);
+ memcpy(&unp2->unp_peercred, &unp->unp_peercred,
+ sizeof(unp2->unp_peercred));
+ unp->unp_flags |= UNP_HAVEPC;
+ unp2->unp_flags |= UNP_HAVEPC;
+ UNP_PCB_UNLOCK(unp);
+ UNP_PCB_UNLOCK(unp2);
}
finit(fp1, FREAD | FWRITE, DTYPE_SOCKET, fp1->f_data, &socketops);
finit(fp2, FREAD | FWRITE, DTYPE_SOCKET, fp2->f_data, &socketops);
I've not looked into the FreeBSD kernel before, so the patch may be
useless! I think conceptually it's the right place to put it though.
unix.4.man and getpeereid.3.man would have to be updated also.
Best wishes,
Nicholas
-----
Nicholas Wilson: nicholas at nicholaswilson.me.uk
Site and blog: www.nicholaswilson.me.uk
6 Tribune Court, CB4 2TU
07845 182898
More information about the freebsd-hackers
mailing list