Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 21 Feb 2013 14:00:47 +0000
From:      Nicholas Wilson <nicholas@nicholaswilson.me.uk>
To:        freebsd-hackers@freebsd.org
Subject:   LOCAL_PEERCRED with socketpair
Message-ID:  <CAN%2BZGEkVFqLbRMkquR3NAh3Qdv=d8Bvhqqme1JdTL70BHQ8suw@mail.gmail.com>

next in thread | raw e-mail | index | archive | help
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 =3D soconnect2(so2, so1);
                 if (error)
                        goto free4;
+       } else if (type =3D=3D SOCK_STREAM) {
+               struct unpcb *unp, *unp2;
+               unp =3D sotounpcb(so1);
+               unp2 =3D 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 |=3D UNP_HAVEPC;
+               unp2->unp_flags |=3D 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@nicholaswilson.me.uk
Site and blog: www.nicholaswilson.me.uk
6 Tribune Court, CB4 2TU
07845=E2=80=AF182898



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?CAN%2BZGEkVFqLbRMkquR3NAh3Qdv=d8Bvhqqme1JdTL70BHQ8suw>