Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 25 Feb 2013 12:51:53 GMT
From:      Nicholas Wilson <nicholas@nicholaswilson.me.uk>
To:        freebsd-gnats-submit@FreeBSD.org
Subject:   kern/176419: [patch] socketpair support for LOCAL_PEERCRED
Message-ID:  <201302251251.r1PCprfm099546@red.freebsd.org>
Resent-Message-ID: <201302251300.r1PD01Kk089909@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help

>Number:         176419
>Category:       kern
>Synopsis:       [patch] socketpair support for LOCAL_PEERCRED
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Mon Feb 25 13:00:00 UTC 2013
>Closed-Date:
>Last-Modified:
>Originator:     Nicholas Wilson
>Release:        Release 7.4 to Release 9.1
>Organization:
>Environment:
FreeBSD EB5-FBSD-7-4-x64.realvnc.ltd 7.4-RELEASE-p9 FreeBSD 7.4-RELEASE-p9 #0: Mon Jun 11 19:47:58 UTC 2012     root@amd64-builder.daemonology.net:/usr/obj/usr/src/sys/GENERIC  amd64
>Description:
I've noticed that getpeereid/LOCAL_PEERCRED doesn't work with sockets created through socketpair, but only through actual listen/connect calls.

I'd like to suggest we support peercred for socketpair-created sockets.

Motivation:
1. All unix-domain STREAM sockets should be created equal.

2. getpeerucred on Solaris and SO_PEERCRED on Linux work fine on socketpair sockets. More relevantly, the MacOS X implementation of LOCAL_PEERCRED works with 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, 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.
>How-To-Repeat:
int main() {
  int fds[2];
  if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) exit(1);
  uid_t uid; gid_t gid;
  return getpeereid(fds[0], &uid, &gid) < 0 ? 1 : 0;
}

Expected result: does not fail
Actual result: fails
>Fix:
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).

Patch attached hopefully fixes the problem in an acceptable way. It's the responsibility of the socketpair call to provide stamp the appropriate credentials when it makes a connection (unp_connect2 doesn't know enough about the calling context to take it on itself to do this).

Patch attached. unix.4.man and getpeereid.3.man would have to be updated also.

Patch attached with submission follows:

--- 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 (so1->so_proto->pr_flags & PR_CONNREQUIRED) {
+               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);


>Release-Note:
>Audit-Trail:
>Unformatted:



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201302251251.r1PCprfm099546>